mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Compare commits
7 Commits
v1.3.1
...
fix-ios-gr
Author | SHA1 | Date | |
---|---|---|---|
11d65ebf1b | |||
0b1f0a7e90 | |||
38c682955a | |||
01ed87907a | |||
58ff0003f7 | |||
f143166551 | |||
cd0d7258c3 |
19
CHANGELOG.md
19
CHANGELOG.md
@ -2,6 +2,25 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [1.3.2](https://github.com/niklasvh/html2canvas/compare/v1.3.1...v1.3.2) (2021-08-15)
|
||||
|
||||
|
||||
### docs
|
||||
|
||||
* add warning for webgl cloning with preserveDrawingBuffer=false (#2661) ([01ed879](https://github.com/niklasvh/html2canvas/commit/01ed87907ad9c7688880e2c5cb8ebc22ef73a4d8)), closes [#2661](https://github.com/niklasvh/html2canvas/issues/2661)
|
||||
* include src files on www (#2660) ([58ff000](https://github.com/niklasvh/html2canvas/commit/58ff0003f77d825ac027eeec95fa80c0123eaf8f)), closes [#2660](https://github.com/niklasvh/html2canvas/issues/2660)
|
||||
|
||||
### feat
|
||||
|
||||
* add support for data-html2canvas-debug property for debugging (#2658) ([cd0d725](https://github.com/niklasvh/html2canvas/commit/cd0d7258c3a93f2989d5d9ec0244ba2763ea2d23)), closes [#2658](https://github.com/niklasvh/html2canvas/issues/2658)
|
||||
|
||||
### fix
|
||||
|
||||
* disable transition properties (#2659) ([f143166](https://github.com/niklasvh/html2canvas/commit/f1431665513e0a4636fb167a241f4a0571ba728a)), closes [#2659](https://github.com/niklasvh/html2canvas/issues/2659)
|
||||
* overflows with absolutely positioned content (#2663) ([38c6829](https://github.com/niklasvh/html2canvas/commit/38c682955a9299ca7785af71d8f251df799405b0)), closes [#2663](https://github.com/niklasvh/html2canvas/issues/2663)
|
||||
|
||||
|
||||
|
||||
## [1.3.1](https://github.com/niklasvh/html2canvas/compare/v1.3.0...v1.3.1) (2021-08-14)
|
||||
|
||||
|
||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "html2canvas",
|
||||
"version": "1.3.1",
|
||||
"version": "1.3.2",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
@ -6,7 +6,7 @@
|
||||
"module": "dist/html2canvas.esm.js",
|
||||
"typings": "dist/types/index.d.ts",
|
||||
"browser": "dist/html2canvas.js",
|
||||
"version": "1.3.1",
|
||||
"version": "1.3.2",
|
||||
"author": {
|
||||
"name": "Niklas von Hertzen",
|
||||
"email": "niklasvh@gmail.com",
|
||||
|
29
src/core/debugger.ts
Normal file
29
src/core/debugger.ts
Normal file
@ -0,0 +1,29 @@
|
||||
const elementDebuggerAttribute = 'data-html2canvas-debug';
|
||||
export const enum DebuggerType {
|
||||
NONE,
|
||||
ALL,
|
||||
CLONE,
|
||||
PARSE,
|
||||
RENDER
|
||||
}
|
||||
|
||||
const getElementDebugType = (element: Element): DebuggerType => {
|
||||
const attribute = element.getAttribute(elementDebuggerAttribute);
|
||||
switch (attribute) {
|
||||
case 'all':
|
||||
return DebuggerType.ALL;
|
||||
case 'clone':
|
||||
return DebuggerType.CLONE;
|
||||
case 'parse':
|
||||
return DebuggerType.PARSE;
|
||||
case 'render':
|
||||
return DebuggerType.RENDER;
|
||||
default:
|
||||
return DebuggerType.NONE;
|
||||
}
|
||||
};
|
||||
|
||||
export const isDebugging = (element: Element, type: Omit<DebuggerType, DebuggerType.NONE>): boolean => {
|
||||
const elementType = getElementDebugType(element);
|
||||
return elementType === DebuggerType.ALL || type === elementType;
|
||||
};
|
@ -143,7 +143,6 @@ export class CSSParsedDeclaration {
|
||||
textTransform: ReturnType<typeof textTransform.parse>;
|
||||
transform: ReturnType<typeof transform.parse>;
|
||||
transformOrigin: ReturnType<typeof transformOrigin.parse>;
|
||||
transitionDuration: ReturnType<typeof duration.parse>;
|
||||
visibility: ReturnType<typeof visibility.parse>;
|
||||
webkitTextStrokeColor: Color;
|
||||
webkitTextStrokeWidth: ReturnType<typeof webkitTextStrokeWidth.parse>;
|
||||
@ -221,7 +220,6 @@ export class CSSParsedDeclaration {
|
||||
this.textTransform = parse(context, textTransform, declaration.textTransform);
|
||||
this.transform = parse(context, transform, declaration.transform);
|
||||
this.transformOrigin = parse(context, transformOrigin, declaration.transformOrigin);
|
||||
this.transitionDuration = parse(context, duration, declaration.transitionDuration);
|
||||
this.visibility = parse(context, visibility, declaration.visibility);
|
||||
this.webkitTextStrokeColor = parse(context, webkitTextStrokeColor, declaration.webkitTextStrokeColor);
|
||||
this.webkitTextStrokeWidth = parse(context, webkitTextStrokeWidth, declaration.webkitTextStrokeWidth);
|
||||
|
@ -29,12 +29,24 @@ export const parseTextBounds = (
|
||||
if (styles.textDecorationLine.length || text.trim().length > 0) {
|
||||
if (FEATURES.SUPPORT_RANGE_BOUNDS) {
|
||||
if (!FEATURES.SUPPORT_WORD_BREAKING) {
|
||||
textBounds.push(
|
||||
new TextBounds(
|
||||
text,
|
||||
Bounds.fromDOMRectList(context, createRange(node, offset, text.length).getClientRects())
|
||||
)
|
||||
);
|
||||
const rects = createRange(node, offset, text.length).getClientRects();
|
||||
if (rects.length > 1) {
|
||||
let graphemeOffset = 0;
|
||||
splitGraphemes(text).forEach((grapheme) => {
|
||||
textBounds.push(
|
||||
new TextBounds(
|
||||
grapheme,
|
||||
Bounds.fromDOMRectList(
|
||||
context,
|
||||
createRange(node, graphemeOffset + offset, grapheme.length).getClientRects()
|
||||
)
|
||||
)
|
||||
);
|
||||
graphemeOffset += grapheme.length;
|
||||
});
|
||||
} else {
|
||||
textBounds.push(new TextBounds(text, Bounds.fromDOMRectList(context, rects)));
|
||||
}
|
||||
} else {
|
||||
textBounds.push(new TextBounds(text, getRangeBounds(context, node, offset, text.length)));
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ export enum OVERFLOW {
|
||||
VISIBLE = 0,
|
||||
HIDDEN = 1,
|
||||
SCROLL = 2,
|
||||
AUTO = 3
|
||||
CLIP = 3,
|
||||
AUTO = 4
|
||||
}
|
||||
|
||||
export const overflow: IPropertyListDescriptor<OVERFLOW[]> = {
|
||||
@ -20,6 +21,8 @@ export const overflow: IPropertyListDescriptor<OVERFLOW[]> = {
|
||||
return OVERFLOW.HIDDEN;
|
||||
case 'scroll':
|
||||
return OVERFLOW.SCROLL;
|
||||
case 'clip':
|
||||
return OVERFLOW.CLIP;
|
||||
case 'auto':
|
||||
return OVERFLOW.AUTO;
|
||||
case 'visible':
|
||||
|
@ -20,6 +20,7 @@ import {LIST_STYLE_TYPE, listStyleType} from '../css/property-descriptors/list-s
|
||||
import {CSSParsedCounterDeclaration, CSSParsedPseudoDeclaration} from '../css/index';
|
||||
import {getQuote} from '../css/property-descriptors/quotes';
|
||||
import {Context} from '../core/context';
|
||||
import {DebuggerType, isDebugging} from '../core/debugger';
|
||||
|
||||
export interface CloneOptions {
|
||||
ignoreElements?: (element: Element) => boolean;
|
||||
@ -136,6 +137,9 @@ export class DocumentCloner {
|
||||
}
|
||||
|
||||
createElementClone<T extends HTMLElement | SVGElement>(node: T): HTMLElement | SVGElement {
|
||||
if (isDebugging(node, DebuggerType.CLONE)) {
|
||||
debugger;
|
||||
}
|
||||
if (isCanvasElement(node)) {
|
||||
return this.createCanvasClone(node);
|
||||
}
|
||||
@ -190,7 +194,7 @@ export class DocumentCloner {
|
||||
img.src = canvas.toDataURL();
|
||||
return img;
|
||||
} catch (e) {
|
||||
this.context.logger.info(`Unable to clone canvas contents, canvas is tainted`);
|
||||
this.context.logger.info(`Unable to inline canvas contents, canvas is tainted`, canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,12 +209,23 @@ export class DocumentCloner {
|
||||
if (!this.options.allowTaint && ctx) {
|
||||
clonedCtx.putImageData(ctx.getImageData(0, 0, canvas.width, canvas.height), 0, 0);
|
||||
} else {
|
||||
const gl = canvas.getContext('webgl2') ?? canvas.getContext('webgl');
|
||||
if (gl) {
|
||||
const attribs = gl.getContextAttributes();
|
||||
if (attribs?.preserveDrawingBuffer === false) {
|
||||
this.context.logger.warn(
|
||||
'Unable to clone WebGL context as it has preserveDrawingBuffer=false',
|
||||
canvas
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
clonedCtx.drawImage(canvas, 0, 0);
|
||||
}
|
||||
}
|
||||
return clonedCanvas;
|
||||
} catch (e) {
|
||||
this.context.logger.info(`Unable to clone canvas as it is tainted`);
|
||||
this.context.logger.info(`Unable to clone canvas as it is tainted`, canvas);
|
||||
}
|
||||
|
||||
return clonedCanvas;
|
||||
@ -229,6 +244,7 @@ export class DocumentCloner {
|
||||
|
||||
if (window && isElementNode(node) && (isHTMLElementNode(node) || isSVGElementNode(node))) {
|
||||
const clone = this.createElementClone(node);
|
||||
clone.style.transitionProperty = 'none';
|
||||
|
||||
const style = window.getComputedStyle(node);
|
||||
const styleBefore = window.getComputedStyle(node, ':before');
|
||||
|
@ -3,32 +3,33 @@ import {TextContainer} from './text-container';
|
||||
import {Bounds, parseBounds} from '../css/layout/bounds';
|
||||
import {isHTMLElementNode} from './node-parser';
|
||||
import {Context} from '../core/context';
|
||||
import {DebuggerType, isDebugging} from '../core/debugger';
|
||||
|
||||
export const enum FLAGS {
|
||||
CREATES_STACKING_CONTEXT = 1 << 1,
|
||||
CREATES_REAL_STACKING_CONTEXT = 1 << 2,
|
||||
IS_LIST_OWNER = 1 << 3
|
||||
IS_LIST_OWNER = 1 << 3,
|
||||
DEBUG_RENDER = 1 << 4
|
||||
}
|
||||
|
||||
export class ElementContainer {
|
||||
readonly styles: CSSParsedDeclaration;
|
||||
readonly textNodes: TextContainer[];
|
||||
readonly elements: ElementContainer[];
|
||||
readonly textNodes: TextContainer[] = [];
|
||||
readonly elements: ElementContainer[] = [];
|
||||
bounds: Bounds;
|
||||
flags: number;
|
||||
flags = 0;
|
||||
|
||||
constructor(protected readonly context: Context, element: Element) {
|
||||
if (isDebugging(element, DebuggerType.PARSE)) {
|
||||
debugger;
|
||||
}
|
||||
|
||||
this.styles = new CSSParsedDeclaration(context, window.getComputedStyle(element, null));
|
||||
this.textNodes = [];
|
||||
this.elements = [];
|
||||
|
||||
if (isHTMLElementNode(element)) {
|
||||
if (this.styles.animationDuration.some((duration) => duration > 0)) {
|
||||
element.style.animationDuration = '0s';
|
||||
}
|
||||
if (this.styles.transitionDuration.some((duration) => duration > 0)) {
|
||||
element.style.transitionDuration = '0s';
|
||||
}
|
||||
|
||||
if (this.styles.transform !== null) {
|
||||
// getBoundingClientRect takes transforms into account
|
||||
@ -37,6 +38,9 @@ export class ElementContainer {
|
||||
}
|
||||
|
||||
this.bounds = parseBounds(this.context, element);
|
||||
this.flags = 0;
|
||||
|
||||
if (isDebugging(element, DebuggerType.RENDER)) {
|
||||
this.flags |= FLAGS.DEBUG_RENDER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {ElementPaint, parseStackingContexts, StackingContext} from '../stacking-context';
|
||||
import {asString, Color, isTransparent} from '../../css/types/color';
|
||||
import {ElementContainer} from '../../dom/element-container';
|
||||
import {ElementContainer, FLAGS} from '../../dom/element-container';
|
||||
import {BORDER_STYLE} from '../../css/property-descriptors/border-style';
|
||||
import {CSSParsedDeclaration} from '../../css/index';
|
||||
import {TextContainer} from '../../dom/text-container';
|
||||
@ -87,12 +87,12 @@ export class CanvasRenderer extends Renderer {
|
||||
);
|
||||
}
|
||||
|
||||
applyEffects(effects: IElementEffect[], target: EffectTarget): void {
|
||||
applyEffects(effects: IElementEffect[]): void {
|
||||
while (this._activeEffects.length) {
|
||||
this.popEffect();
|
||||
}
|
||||
|
||||
effects.filter((effect) => contains(effect.target, target)).forEach((effect) => this.applyEffect(effect));
|
||||
effects.forEach((effect) => this.applyEffect(effect));
|
||||
}
|
||||
|
||||
applyEffect(effect: IElementEffect): void {
|
||||
@ -135,6 +135,10 @@ export class CanvasRenderer extends Renderer {
|
||||
}
|
||||
|
||||
async renderNode(paint: ElementPaint): Promise<void> {
|
||||
if (contains(paint.container.flags, FLAGS.DEBUG_RENDER)) {
|
||||
debugger;
|
||||
}
|
||||
|
||||
if (paint.container.styles.isVisible()) {
|
||||
await this.renderNodeBackgroundAndBorders(paint);
|
||||
await this.renderNodeContent(paint);
|
||||
@ -289,7 +293,7 @@ export class CanvasRenderer extends Renderer {
|
||||
}
|
||||
|
||||
async renderNodeContent(paint: ElementPaint): Promise<void> {
|
||||
this.applyEffects(paint.effects, EffectTarget.CONTENT);
|
||||
this.applyEffects(paint.getEffects(EffectTarget.CONTENT));
|
||||
const container = paint.container;
|
||||
const curves = paint.curves;
|
||||
const styles = container.styles;
|
||||
@ -468,6 +472,9 @@ export class CanvasRenderer extends Renderer {
|
||||
}
|
||||
|
||||
async renderStackContent(stack: StackingContext): Promise<void> {
|
||||
if (contains(stack.element.container.flags, FLAGS.DEBUG_RENDER)) {
|
||||
debugger;
|
||||
}
|
||||
// https://www.w3.org/TR/css-position-3/#painting-order
|
||||
// 1. the background and borders of the element forming the stacking context.
|
||||
await this.renderNodeBackgroundAndBorders(stack.element);
|
||||
@ -685,7 +692,7 @@ export class CanvasRenderer extends Renderer {
|
||||
}
|
||||
|
||||
async renderNodeBackgroundAndBorders(paint: ElementPaint): Promise<void> {
|
||||
this.applyEffects(paint.effects, EffectTarget.BACKGROUND_BORDERS);
|
||||
this.applyEffects(paint.getEffects(EffectTarget.BACKGROUND_BORDERS));
|
||||
const styles = paint.container.styles;
|
||||
const hasBackground = !isTransparent(styles.backgroundColor) || styles.backgroundImage.length;
|
||||
|
||||
@ -899,7 +906,7 @@ export class CanvasRenderer extends Renderer {
|
||||
const stack = parseStackingContexts(element);
|
||||
|
||||
await this.renderStack(stack);
|
||||
this.applyEffects([], EffectTarget.BACKGROUND_BORDERS);
|
||||
this.applyEffects([]);
|
||||
return this.canvas;
|
||||
}
|
||||
}
|
||||
|
@ -20,36 +20,21 @@ export interface IElementEffect {
|
||||
export class TransformEffect implements IElementEffect {
|
||||
readonly type: EffectType = EffectType.TRANSFORM;
|
||||
readonly target: number = EffectTarget.BACKGROUND_BORDERS | EffectTarget.CONTENT;
|
||||
readonly offsetX: number;
|
||||
readonly offsetY: number;
|
||||
readonly matrix: Matrix;
|
||||
|
||||
constructor(offsetX: number, offsetY: number, matrix: Matrix) {
|
||||
this.offsetX = offsetX;
|
||||
this.offsetY = offsetY;
|
||||
this.matrix = matrix;
|
||||
}
|
||||
constructor(readonly offsetX: number, readonly offsetY: number, readonly matrix: Matrix) {}
|
||||
}
|
||||
|
||||
export class ClipEffect implements IElementEffect {
|
||||
readonly type: EffectType = EffectType.CLIP;
|
||||
readonly target: number;
|
||||
readonly path: Path[];
|
||||
|
||||
constructor(path: Path[], target: EffectTarget) {
|
||||
this.target = target;
|
||||
this.path = path;
|
||||
}
|
||||
constructor(readonly path: Path[], readonly target: EffectTarget) {}
|
||||
}
|
||||
|
||||
export class OpacityEffect implements IElementEffect {
|
||||
readonly type: EffectType = EffectType.OPACITY;
|
||||
readonly target: number = EffectTarget.BACKGROUND_BORDERS | EffectTarget.CONTENT;
|
||||
readonly opacity: number;
|
||||
|
||||
constructor(opacity: number) {
|
||||
this.opacity = opacity;
|
||||
}
|
||||
constructor(readonly opacity: number) {}
|
||||
}
|
||||
|
||||
export const isTransformEffect = (effect: IElementEffect): effect is TransformEffect =>
|
||||
|
@ -1,13 +1,14 @@
|
||||
import {ElementContainer, FLAGS} from '../dom/element-container';
|
||||
import {contains} from '../core/bitwise';
|
||||
import {BoundCurves, calculateBorderBoxPath, calculatePaddingBoxPath} from './bound-curves';
|
||||
import {ClipEffect, EffectTarget, IElementEffect, OpacityEffect, TransformEffect} from './effects';
|
||||
import {ClipEffect, EffectTarget, IElementEffect, isClipEffect, OpacityEffect, TransformEffect} from './effects';
|
||||
import {OVERFLOW} from '../css/property-descriptors/overflow';
|
||||
import {equalPath} from './path';
|
||||
import {DISPLAY} from '../css/property-descriptors/display';
|
||||
import {OLElementContainer} from '../dom/elements/ol-element-container';
|
||||
import {LIElementContainer} from '../dom/elements/li-element-container';
|
||||
import {createCounterText} from '../css/types/functions/counter';
|
||||
import {POSITION} from '../css/property-descriptors/position';
|
||||
|
||||
export class StackingContext {
|
||||
element: ElementPaint;
|
||||
@ -32,27 +33,24 @@ export class StackingContext {
|
||||
}
|
||||
|
||||
export class ElementPaint {
|
||||
container: ElementContainer;
|
||||
effects: IElementEffect[];
|
||||
curves: BoundCurves;
|
||||
readonly effects: IElementEffect[] = [];
|
||||
readonly curves: BoundCurves;
|
||||
listValue?: string;
|
||||
|
||||
constructor(element: ElementContainer, parentStack: IElementEffect[]) {
|
||||
this.container = element;
|
||||
this.effects = parentStack.slice(0);
|
||||
this.curves = new BoundCurves(element);
|
||||
if (element.styles.opacity < 1) {
|
||||
this.effects.push(new OpacityEffect(element.styles.opacity));
|
||||
constructor(readonly container: ElementContainer, readonly parent: ElementPaint | null) {
|
||||
this.curves = new BoundCurves(this.container);
|
||||
if (this.container.styles.opacity < 1) {
|
||||
this.effects.push(new OpacityEffect(this.container.styles.opacity));
|
||||
}
|
||||
|
||||
if (element.styles.transform !== null) {
|
||||
const offsetX = element.bounds.left + element.styles.transformOrigin[0].number;
|
||||
const offsetY = element.bounds.top + element.styles.transformOrigin[1].number;
|
||||
const matrix = element.styles.transform;
|
||||
if (this.container.styles.transform !== null) {
|
||||
const offsetX = this.container.bounds.left + this.container.styles.transformOrigin[0].number;
|
||||
const offsetY = this.container.bounds.top + this.container.styles.transformOrigin[1].number;
|
||||
const matrix = this.container.styles.transform;
|
||||
this.effects.push(new TransformEffect(offsetX, offsetY, matrix));
|
||||
}
|
||||
|
||||
if (element.styles.overflowX !== OVERFLOW.VISIBLE) {
|
||||
if (this.container.styles.overflowX !== OVERFLOW.VISIBLE) {
|
||||
const borderBox = calculateBorderBoxPath(this.curves);
|
||||
const paddingBox = calculatePaddingBoxPath(this.curves);
|
||||
|
||||
@ -65,16 +63,32 @@ export class ElementPaint {
|
||||
}
|
||||
}
|
||||
|
||||
getParentEffects(): IElementEffect[] {
|
||||
getEffects(target: EffectTarget): IElementEffect[] {
|
||||
let inFlow = [POSITION.ABSOLUTE, POSITION.FIXED].indexOf(this.container.styles.position) === -1;
|
||||
let parent = this.parent;
|
||||
const effects = this.effects.slice(0);
|
||||
if (this.container.styles.overflowX !== OVERFLOW.VISIBLE) {
|
||||
const borderBox = calculateBorderBoxPath(this.curves);
|
||||
const paddingBox = calculatePaddingBoxPath(this.curves);
|
||||
if (!equalPath(borderBox, paddingBox)) {
|
||||
effects.push(new ClipEffect(paddingBox, EffectTarget.BACKGROUND_BORDERS | EffectTarget.CONTENT));
|
||||
while (parent) {
|
||||
const croplessEffects = parent.effects.filter((effect) => !isClipEffect(effect));
|
||||
if (inFlow || parent.container.styles.position !== POSITION.STATIC || !parent.parent) {
|
||||
effects.unshift(...croplessEffects);
|
||||
inFlow = [POSITION.ABSOLUTE, POSITION.FIXED].indexOf(parent.container.styles.position) === -1;
|
||||
if (parent.container.styles.overflowX !== OVERFLOW.VISIBLE) {
|
||||
const borderBox = calculateBorderBoxPath(parent.curves);
|
||||
const paddingBox = calculatePaddingBoxPath(parent.curves);
|
||||
if (!equalPath(borderBox, paddingBox)) {
|
||||
effects.unshift(
|
||||
new ClipEffect(paddingBox, EffectTarget.BACKGROUND_BORDERS | EffectTarget.CONTENT)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
effects.unshift(...croplessEffects);
|
||||
}
|
||||
|
||||
parent = parent.parent;
|
||||
}
|
||||
return effects;
|
||||
|
||||
return effects.filter((effect) => contains(effect.target, target));
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +101,7 @@ const parseStackTree = (
|
||||
parent.container.elements.forEach((child) => {
|
||||
const treatAsRealStackingContext = contains(child.flags, FLAGS.CREATES_REAL_STACKING_CONTEXT);
|
||||
const createsStackingContext = contains(child.flags, FLAGS.CREATES_STACKING_CONTEXT);
|
||||
const paintContainer = new ElementPaint(child, parent.getParentEffects());
|
||||
const paintContainer = new ElementPaint(child, parent);
|
||||
if (contains(child.styles.display, DISPLAY.LIST_ITEM)) {
|
||||
listItems.push(paintContainer);
|
||||
}
|
||||
@ -182,7 +196,7 @@ const processListItems = (owner: ElementContainer, elements: ElementPaint[]) =>
|
||||
};
|
||||
|
||||
export const parseStackingContexts = (container: ElementContainer): StackingContext => {
|
||||
const paintContainer = new ElementPaint(container, []);
|
||||
const paintContainer = new ElementPaint(container, null);
|
||||
const root = new StackingContext(paintContainer);
|
||||
const listItems: ElementPaint[] = [];
|
||||
parseStackTree(paintContainer, root, root, listItems);
|
||||
|
@ -55,6 +55,11 @@
|
||||
transform: rotate(45deg)
|
||||
}
|
||||
|
||||
.transition-delay {
|
||||
transition: 1ms;
|
||||
transition-delay: 50ms;
|
||||
transform: rotate(45deg)
|
||||
}
|
||||
|
||||
div {
|
||||
float: left;
|
||||
@ -84,5 +89,9 @@
|
||||
<div class="transitioned broken">
|
||||
<p>Hello</p>
|
||||
</div>
|
||||
|
||||
<div class="transition-delay">
|
||||
<p>Hello</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -51,6 +51,9 @@
|
||||
.scroll {
|
||||
overflow: scroll;
|
||||
}
|
||||
.clip {
|
||||
overflow: clip;
|
||||
}
|
||||
.auto {
|
||||
overflow: auto;
|
||||
}
|
||||
@ -70,6 +73,10 @@
|
||||
scroll
|
||||
<p class="scroll">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec luctus pretium facilisis. Praesent rutrum eget nisl in tristique. Sed tincidunt nisl et tellus vulputate, nec rhoncus orci pretium.</p>
|
||||
</div>
|
||||
<div class="cell">
|
||||
clip
|
||||
<p class="clip">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec luctus pretium facilisis. Praesent rutrum eget nisl in tristique. Sed tincidunt nisl et tellus vulputate, nec rhoncus orci pretium.</p>
|
||||
</div>
|
||||
<div class="cell">
|
||||
auto
|
||||
<p class="auto">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec luctus pretium facilisis. Praesent rutrum eget nisl in tristique. Sed tincidunt nisl et tellus vulputate, nec rhoncus orci pretium.</p>
|
||||
@ -129,5 +136,17 @@
|
||||
</script>
|
||||
</div>
|
||||
<div class="hidden">Hidden<div style="opacity: 0.5">With opacity</div></div>
|
||||
<div class="hidden" style="height: 0px; width: 50px;">
|
||||
<div style="position: absolute; width: 50px; height: 50px; left:400px;">absolute on static parent</div>
|
||||
</div>
|
||||
<div class="hidden" style="height: 0px; width: 50px;">
|
||||
<div style="position: relative; width: 10px; height: 10px; left:400px;">relative on static parent</div>
|
||||
</div>
|
||||
<div class="hidden" style="height: 0px; width: 50px;">
|
||||
<div style="position: fixed; width: 50px; height: 50px; left:400px; top:0;">fixed on static parent</div>
|
||||
</div>
|
||||
<div class="hidden" style="height: 0px; width: 50px;position: relative;">
|
||||
<div style="position: absolute; width: 10px; height: 10px; left:400px;">absolute on relative parent</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -32,8 +32,10 @@
|
||||
"license": "MIT",
|
||||
"main": "n/a",
|
||||
"scripts": {
|
||||
"copybuild": "mkdirp public/dist && cpy ../dist/*.js public/dist",
|
||||
"build": "npm run copybuild && gatsby build",
|
||||
"copy:build": "mkdirp public/dist && cpy ../dist/*.js public/dist",
|
||||
"copy:src": "mkdirp public/src && cpy ../src/**/*.ts public/src --parents",
|
||||
"copy": "npm run copy:build && npm run copy:src",
|
||||
"build": "npm run copy && gatsby build",
|
||||
"start": "gatsby develop",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
}
|
||||
|
Reference in New Issue
Block a user