diff --git a/packages/happy-dom/.gitignore b/packages/happy-dom/.gitignore index 188a574ae..048cacdf3 100755 --- a/packages/happy-dom/.gitignore +++ b/packages/happy-dom/.gitignore @@ -1,3 +1,4 @@ node_modules tmp -lib \ No newline at end of file +lib +.DS_Store \ No newline at end of file diff --git a/packages/happy-dom/src/css/CSSParser.ts b/packages/happy-dom/src/css/CSSParser.ts index fabebd64b..6401f0f51 100644 --- a/packages/happy-dom/src/css/CSSParser.ts +++ b/packages/happy-dom/src/css/CSSParser.ts @@ -4,7 +4,7 @@ import CSSStyleRule from './rules/CSSStyleRule'; import CSSKeyframeRule from './rules/CSSKeyframeRule'; import CSSKeyframesRule from './rules/CSSKeyframesRule'; import CSSMediaRule from './rules/CSSMediaRule'; -import CSSStyleDeclaration from './CSSStyleDeclaration'; +import CSSContainerRule from './rules/CSSContainerRule'; const COMMENT_REGEXP = /\/\*[^*]*\*\//gm; @@ -47,6 +47,14 @@ export default class CSSParser { newRule.media.appendMedium(medium.trim()); } + newRule.parentStyleSheet = parentStyleSheet; + cssRules.push(newRule); + parentRule = newRule; + } else if (selectorText.startsWith('@container')) { + const conditionalText = selectorText.replace(/@container */, ''); + const newRule = new CSSContainerRule(); + + (newRule.conditionalText) = conditionalText; newRule.parentStyleSheet = parentStyleSheet; cssRules.push(newRule); parentRule = newRule; @@ -58,7 +66,10 @@ export default class CSSParser { (parentRule).cssRules.push(newRule); parentRule = newRule; - } else if (parentRule && parentRule.type === CSSRule.MEDIA_RULE) { + } else if ( + parentRule && + (parentRule.type === CSSRule.MEDIA_RULE || parentRule.type === CSSRule.CONTAINER_RULE) + ) { const newRule = new CSSStyleRule(); (newRule.selectorText) = selectorText; newRule.parentStyleSheet = parentStyleSheet; @@ -86,10 +97,7 @@ export default class CSSParser { case CSSRule.FONT_FACE_RULE: case CSSRule.KEYFRAME_RULE: case CSSRule.STYLE_RULE: - const style = new CSSStyleDeclaration(); - style.cssText = cssText; - (style.parentRule) = parentRule; - ((parentRule).style) = style; + (parentRule)._cssText = cssText; break; } } diff --git a/packages/happy-dom/src/css/CSSRule.ts b/packages/happy-dom/src/css/CSSRule.ts index 0294ae200..5d0db44bd 100644 --- a/packages/happy-dom/src/css/CSSRule.ts +++ b/packages/happy-dom/src/css/CSSRule.ts @@ -1,22 +1,24 @@ import CSSStyleSheet from './CSSStyleSheet'; +import CSSRuleTypeEnum from './CSSRuleTypeEnum'; /** * CSSRule interface. */ export default class CSSRule { - public static STYLE_RULE = 1; - public static IMPORT_RULE = 3; - public static MEDIA_RULE = 4; - public static FONT_FACE_RULE = 5; - public static PAGE_RULE = 6; - public static KEYFRAMES_RULE = 7; - public static KEYFRAME_RULE = 8; - public static NAMESPACE_RULE = 10; - public static COUNTER_STYLE_RULE = 11; - public static SUPPORTS_RULE = 12; - public static DOCUMENT_RULE = 13; - public static FONT_FEATURE_VALUES_RULE = 14; - public static REGION_STYLE_RULE = 16; + public static CONTAINER_RULE = CSSRuleTypeEnum.containerRule; + public static STYLE_RULE = CSSRuleTypeEnum.styleRule; + public static IMPORT_RULE = CSSRuleTypeEnum.importRule; + public static MEDIA_RULE = CSSRuleTypeEnum.mediaRule; + public static FONT_FACE_RULE = CSSRuleTypeEnum.fontFaceRule; + public static PAGE_RULE = CSSRuleTypeEnum.pageRule; + public static KEYFRAMES_RULE = CSSRuleTypeEnum.keyframesRule; + public static KEYFRAME_RULE = CSSRuleTypeEnum.keyframeRule; + public static NAMESPACE_RULE = CSSRuleTypeEnum.namespaceRule; + public static COUNTER_STYLE_RULE = CSSRuleTypeEnum.counterStyleRule; + public static SUPPORTS_RULE = CSSRuleTypeEnum.supportsRule; + public static DOCUMENT_RULE = CSSRuleTypeEnum.documentRule; + public static FONT_FEATURE_VALUES_RULE = CSSRuleTypeEnum.fontFeatureValuesRule; + public static REGION_STYLE_RULE = CSSRuleTypeEnum.regionStyleRule; public parentRule: CSSRule = null; public parentStyleSheet: CSSStyleSheet = null; diff --git a/packages/happy-dom/src/css/CSSRuleTypeEnum.ts b/packages/happy-dom/src/css/CSSRuleTypeEnum.ts new file mode 100644 index 000000000..64793a109 --- /dev/null +++ b/packages/happy-dom/src/css/CSSRuleTypeEnum.ts @@ -0,0 +1,18 @@ +enum CSSRuleTypeEnum { + containerRule = 0, + styleRule = 1, + importRule = 3, + mediaRule = 4, + fontFaceRule = 5, + pageRule = 6, + keyframesRule = 7, + keyframeRule = 8, + namespaceRule = 10, + counterStyleRule = 11, + supportsRule = 12, + documentRule = 13, + fontFeatureValuesRule = 14, + regionStyleRule = 16 +} + +export default CSSRuleTypeEnum; diff --git a/packages/happy-dom/src/css/CSSStyleDeclaration.ts b/packages/happy-dom/src/css/CSSStyleDeclaration.ts deleted file mode 100644 index 5a932aa96..000000000 --- a/packages/happy-dom/src/css/CSSStyleDeclaration.ts +++ /dev/null @@ -1,5026 +0,0 @@ -import Attr from '../attribute/Attr'; -import CSSRule from './CSSRule'; - -/** - * CSS Style Declaration. - */ -export default class CSSStyleDeclaration { - public readonly length = 0; - public readonly parentRule: CSSRule = null; - private _attributes: { [k: string]: Attr } = null; - private _computedStyleElement: { isConnected: boolean } = null; - - /** - * Constructor. - * - * @param [attributes] Attributes. - * @param [computedStyleElement] Computed style element. - * @param computedStyleElement.isConnected - */ - constructor( - attributes: { [k: string]: Attr } = {}, - computedStyleElement: { isConnected: boolean } = null - ) { - const style = attributes['style']; - let index = 0; - - this._attributes = attributes; - this._computedStyleElement = computedStyleElement; - - if (style && style.value) { - const parts = style.value.split(';'); - for (const part of parts) { - if (part) { - const [name] = part.trim().split(':'); - this[index] = name; - index++; - } - } - } - - (this.length) = index; - } - - /** - * - */ - public get alignContent(): string { - return this.getPropertyValue('align-content'); - } - /** - * - */ - public set alignContent(alignContent: string) { - this.setProperty('align-content', alignContent); - } - - /** - * - */ - public get alignItems(): string { - return this.getPropertyValue('align-items'); - } - /** - * - */ - public set alignItems(alignItems: string) { - this.setProperty('align-items', alignItems); - } - - /** - * - */ - public get alignSelf(): string { - return this.getPropertyValue('align-self'); - } - /** - * - */ - public set alignSelf(alignSelf: string) { - this.setProperty('align-self', alignSelf); - } - - /** - * - */ - public get alignmentBaseline(): string { - return this.getPropertyValue('alignment-baseline'); - } - /** - * - */ - public set alignmentBaseline(alignmentBaseline: string) { - this.setProperty('alignment-baseline', alignmentBaseline); - } - - /** - * - */ - public get all(): string { - return this.getPropertyValue('all'); - } - /** - * - */ - public set all(all: string) { - this.setProperty('all', all); - } - - /** - * - */ - public get animation(): string { - return this.getPropertyValue('animation'); - } - /** - * - */ - public set animation(animation: string) { - this.setProperty('animation', animation); - } - - /** - * - */ - public get animationDelay(): string { - return this.getPropertyValue('animation-delay'); - } - /** - * - */ - public set animationDelay(animationDelay: string) { - this.setProperty('animation-delay', animationDelay); - } - - /** - * - */ - public get animationDirection(): string { - return this.getPropertyValue('animation-direction'); - } - /** - * - */ - public set animationDirection(animationDirection: string) { - this.setProperty('animation-direction', animationDirection); - } - - /** - * - */ - public get animationDuration(): string { - return this.getPropertyValue('animation-duration'); - } - /** - * - */ - public set animationDuration(animationDuration: string) { - this.setProperty('animation-duration', animationDuration); - } - - /** - * - */ - public get animationFillMode(): string { - return this.getPropertyValue('animation-fill-mode'); - } - /** - * - */ - public set animationFillMode(animationFillMode: string) { - this.setProperty('animation-fill-mode', animationFillMode); - } - - /** - * - */ - public get animationIterationCount(): string { - return this.getPropertyValue('animation-iteration-count'); - } - /** - * - */ - public set animationIterationCount(animationIterationCount: string) { - this.setProperty('animation-iteration-count', animationIterationCount); - } - - /** - * - */ - public get animationName(): string { - return this.getPropertyValue('animation-name'); - } - /** - * - */ - public set animationName(animationName: string) { - this.setProperty('animation-name', animationName); - } - - /** - * - */ - public get animationPlayState(): string { - return this.getPropertyValue('animation-play-state'); - } - /** - * - */ - public set animationPlayState(animationPlayState: string) { - this.setProperty('animation-play-state', animationPlayState); - } - - /** - * - */ - public get animationTimingFunction(): string { - return this.getPropertyValue('animation-timing-function'); - } - /** - * - */ - public set animationTimingFunction(animationTimingFunction: string) { - this.setProperty('animation-timing-function', animationTimingFunction); - } - - /** - * - */ - public get appearance(): string { - return this.getPropertyValue('appearance'); - } - /** - * - */ - public set appearance(appearance: string) { - this.setProperty('appearance', appearance); - } - - /** - * - */ - public get backdropFilter(): string { - return this.getPropertyValue('backdrop-filter'); - } - /** - * - */ - public set backdropFilter(backdropFilter: string) { - this.setProperty('backdrop-filter', backdropFilter); - } - - /** - * - */ - public get backfaceVisibility(): string { - return this.getPropertyValue('backface-visibility'); - } - /** - * - */ - public set backfaceVisibility(backfaceVisibility: string) { - this.setProperty('backface-visibility', backfaceVisibility); - } - - /** - * - */ - public get background(): string { - return this.getPropertyValue('background'); - } - /** - * - */ - public set background(background: string) { - this.setProperty('background', background); - } - - /** - * - */ - public get backgroundAttachment(): string { - return this.getPropertyValue('background-attachment'); - } - /** - * - */ - public set backgroundAttachment(backgroundAttachment: string) { - this.setProperty('background-attachment', backgroundAttachment); - } - - /** - * - */ - public get backgroundBlendMode(): string { - return this.getPropertyValue('background-blend-mode'); - } - /** - * - */ - public set backgroundBlendMode(backgroundBlendMode: string) { - this.setProperty('background-blend-mode', backgroundBlendMode); - } - - /** - * - */ - public get backgroundClip(): string { - return this.getPropertyValue('background-clip'); - } - /** - * - */ - public set backgroundClip(backgroundClip: string) { - this.setProperty('background-clip', backgroundClip); - } - - /** - * - */ - public get backgroundColor(): string { - return this.getPropertyValue('background-color'); - } - /** - * - */ - public set backgroundColor(backgroundColor: string) { - this.setProperty('background-color', backgroundColor); - } - - /** - * - */ - public get backgroundImage(): string { - return this.getPropertyValue('background-image'); - } - /** - * - */ - public set backgroundImage(backgroundImage: string) { - this.setProperty('background-image', backgroundImage); - } - - /** - * - */ - public get backgroundOrigin(): string { - return this.getPropertyValue('background-origin'); - } - /** - * - */ - public set backgroundOrigin(backgroundOrigin: string) { - this.setProperty('background-origin', backgroundOrigin); - } - - /** - * - */ - public get backgroundPosition(): string { - return this.getPropertyValue('background-position'); - } - /** - * - */ - public set backgroundPosition(backgroundPosition: string) { - this.setProperty('background-position', backgroundPosition); - } - - /** - * - */ - public get backgroundPositionX(): string { - return this.getPropertyValue('background-position-x'); - } - /** - * - */ - public set backgroundPositionX(backgroundPositionX: string) { - this.setProperty('background-position-x', backgroundPositionX); - } - - /** - * - */ - public get backgroundPositionY(): string { - return this.getPropertyValue('background-position-y'); - } - /** - * - */ - public set backgroundPositionY(backgroundPositionY: string) { - this.setProperty('background-position-y', backgroundPositionY); - } - - /** - * - */ - public get backgroundRepeat(): string { - return this.getPropertyValue('background-repeat'); - } - /** - * - */ - public set backgroundRepeat(backgroundRepeat: string) { - this.setProperty('background-repeat', backgroundRepeat); - } - - /** - * - */ - public get backgroundRepeatX(): string { - return this.getPropertyValue('background-repeat-x'); - } - /** - * - */ - public set backgroundRepeatX(backgroundRepeatX: string) { - this.setProperty('background-repeat-x', backgroundRepeatX); - } - - /** - * - */ - public get backgroundRepeatY(): string { - return this.getPropertyValue('background-repeat-y'); - } - /** - * - */ - public set backgroundRepeatY(backgroundRepeatY: string) { - this.setProperty('background-repeat-y', backgroundRepeatY); - } - - /** - * - */ - public get backgroundSize(): string { - return this.getPropertyValue('background-size'); - } - /** - * - */ - public set backgroundSize(backgroundSize: string) { - this.setProperty('background-size', backgroundSize); - } - - /** - * - */ - public get baselineShift(): string { - return this.getPropertyValue('baseline-shift'); - } - /** - * - */ - public set baselineShift(baselineShift: string) { - this.setProperty('baseline-shift', baselineShift); - } - - /** - * - */ - public get blockSize(): string { - return this.getPropertyValue('block-size'); - } - /** - * - */ - public set blockSize(blockSize: string) { - this.setProperty('block-size', blockSize); - } - - /** - * - */ - public get border(): string { - return this.getPropertyValue('border'); - } - /** - * - */ - public set border(border: string) { - this.setProperty('border', border); - } - - /** - * - */ - public get borderBlockEnd(): string { - return this.getPropertyValue('border-block-end'); - } - /** - * - */ - public set borderBlockEnd(borderBlockEnd: string) { - this.setProperty('border-block-end', borderBlockEnd); - } - - /** - * - */ - public get borderBlockEndColor(): string { - return this.getPropertyValue('border-block-end-color'); - } - /** - * - */ - public set borderBlockEndColor(borderBlockEndColor: string) { - this.setProperty('border-block-end-color', borderBlockEndColor); - } - - /** - * - */ - public get borderBlockEndStyle(): string { - return this.getPropertyValue('border-block-end-style'); - } - /** - * - */ - public set borderBlockEndStyle(borderBlockEndStyle: string) { - this.setProperty('border-block-end-style', borderBlockEndStyle); - } - - /** - * - */ - public get borderBlockEndWidth(): string { - return this.getPropertyValue('border-block-end-width'); - } - /** - * - */ - public set borderBlockEndWidth(borderBlockEndWidth: string) { - this.setProperty('border-block-end-width', borderBlockEndWidth); - } - - /** - * - */ - public get borderBlockStart(): string { - return this.getPropertyValue('border-block-start'); - } - /** - * - */ - public set borderBlockStart(borderBlockStart: string) { - this.setProperty('border-block-start', borderBlockStart); - } - - /** - * - */ - public get borderBlockStartColor(): string { - return this.getPropertyValue('border-block-start-color'); - } - /** - * - */ - public set borderBlockStartColor(borderBlockStartColor: string) { - this.setProperty('border-block-start-color', borderBlockStartColor); - } - - /** - * - */ - public get borderBlockStartStyle(): string { - return this.getPropertyValue('border-block-start-style'); - } - /** - * - */ - public set borderBlockStartStyle(borderBlockStartStyle: string) { - this.setProperty('border-block-start-style', borderBlockStartStyle); - } - - /** - * - */ - public get borderBlockStartWidth(): string { - return this.getPropertyValue('border-block-start-width'); - } - /** - * - */ - public set borderBlockStartWidth(borderBlockStartWidth: string) { - this.setProperty('border-block-start-width', borderBlockStartWidth); - } - - /** - * - */ - public get borderBottom(): string { - return this.getPropertyValue('border-bottom'); - } - /** - * - */ - public set borderBottom(borderBottom: string) { - this.setProperty('border-bottom', borderBottom); - } - - /** - * - */ - public get borderBottomColor(): string { - return this.getPropertyValue('border-bottom-color'); - } - /** - * - */ - public set borderBottomColor(borderBottomColor: string) { - this.setProperty('border-bottom-color', borderBottomColor); - } - - /** - * - */ - public get borderBottomLeftRadius(): string { - return this.getPropertyValue('border-bottom-left-radius'); - } - /** - * - */ - public set borderBottomLeftRadius(borderBottomLeftRadius: string) { - this.setProperty('border-bottom-left-radius', borderBottomLeftRadius); - } - - /** - * - */ - public get borderBottomRightRadius(): string { - return this.getPropertyValue('border-bottom-right-radius'); - } - /** - * - */ - public set borderBottomRightRadius(borderBottomRightRadius: string) { - this.setProperty('border-bottom-right-radius', borderBottomRightRadius); - } - - /** - * - */ - public get borderBottomStyle(): string { - return this.getPropertyValue('border-bottom-style'); - } - /** - * - */ - public set borderBottomStyle(borderBottomStyle: string) { - this.setProperty('border-bottom-style', borderBottomStyle); - } - - /** - * - */ - public get borderBottomWidth(): string { - return this.getPropertyValue('border-bottom-width'); - } - /** - * - */ - public set borderBottomWidth(borderBottomWidth: string) { - this.setProperty('border-bottom-width', borderBottomWidth); - } - - /** - * - */ - public get borderCollapse(): string { - return this.getPropertyValue('border-collapse'); - } - /** - * - */ - public set borderCollapse(borderCollapse: string) { - this.setProperty('border-collapse', borderCollapse); - } - - /** - * - */ - public get borderColor(): string { - return this.getPropertyValue('border-color'); - } - /** - * - */ - public set borderColor(borderColor: string) { - this.setProperty('border-color', borderColor); - } - - /** - * - */ - public get borderImage(): string { - return this.getPropertyValue('border-image'); - } - /** - * - */ - public set borderImage(borderImage: string) { - this.setProperty('border-image', borderImage); - } - - /** - * - */ - public get borderImageOutset(): string { - return this.getPropertyValue('border-image-outset'); - } - /** - * - */ - public set borderImageOutset(borderImageOutset: string) { - this.setProperty('border-image-outset', borderImageOutset); - } - - /** - * - */ - public get borderImageRepeat(): string { - return this.getPropertyValue('border-image-repeat'); - } - /** - * - */ - public set borderImageRepeat(borderImageRepeat: string) { - this.setProperty('border-image-repeat', borderImageRepeat); - } - - /** - * - */ - public get borderImageSlice(): string { - return this.getPropertyValue('border-image-slice'); - } - /** - * - */ - public set borderImageSlice(borderImageSlice: string) { - this.setProperty('border-image-slice', borderImageSlice); - } - - /** - * - */ - public get borderImageSource(): string { - return this.getPropertyValue('border-image-source'); - } - /** - * - */ - public set borderImageSource(borderImageSource: string) { - this.setProperty('border-image-source', borderImageSource); - } - - /** - * - */ - public get borderImageWidth(): string { - return this.getPropertyValue('border-image-width'); - } - /** - * - */ - public set borderImageWidth(borderImageWidth: string) { - this.setProperty('border-image-width', borderImageWidth); - } - - /** - * - */ - public get borderInlineEnd(): string { - return this.getPropertyValue('border-inline-end'); - } - /** - * - */ - public set borderInlineEnd(borderInlineEnd: string) { - this.setProperty('border-inline-end', borderInlineEnd); - } - - /** - * - */ - public get borderInlineEndColor(): string { - return this.getPropertyValue('border-inline-end-color'); - } - /** - * - */ - public set borderInlineEndColor(borderInlineEndColor: string) { - this.setProperty('border-inline-end-color', borderInlineEndColor); - } - - /** - * - */ - public get borderInlineEndStyle(): string { - return this.getPropertyValue('border-inline-end-style'); - } - /** - * - */ - public set borderInlineEndStyle(borderInlineEndStyle: string) { - this.setProperty('border-inline-end-style', borderInlineEndStyle); - } - - /** - * - */ - public get borderInlineEndWidth(): string { - return this.getPropertyValue('border-inline-end-width'); - } - /** - * - */ - public set borderInlineEndWidth(borderInlineEndWidth: string) { - this.setProperty('border-inline-end-width', borderInlineEndWidth); - } - - /** - * - */ - public get borderInlineStart(): string { - return this.getPropertyValue('border-inline-start'); - } - /** - * - */ - public set borderInlineStart(borderInlineStart: string) { - this.setProperty('border-inline-start', borderInlineStart); - } - - /** - * - */ - public get borderInlineStartColor(): string { - return this.getPropertyValue('border-inline-start-color'); - } - /** - * - */ - public set borderInlineStartColor(borderInlineStartColor: string) { - this.setProperty('border-inline-start-color', borderInlineStartColor); - } - - /** - * - */ - public get borderInlineStartStyle(): string { - return this.getPropertyValue('border-inline-start-style'); - } - /** - * - */ - public set borderInlineStartStyle(borderInlineStartStyle: string) { - this.setProperty('border-inline-start-style', borderInlineStartStyle); - } - - /** - * - */ - public get borderInlineStartWidth(): string { - return this.getPropertyValue('border-inline-start-width'); - } - /** - * - */ - public set borderInlineStartWidth(borderInlineStartWidth: string) { - this.setProperty('border-inline-start-width', borderInlineStartWidth); - } - - /** - * - */ - public get borderLeft(): string { - return this.getPropertyValue('border-left'); - } - /** - * - */ - public set borderLeft(borderLeft: string) { - this.setProperty('border-left', borderLeft); - } - - /** - * - */ - public get borderLeftColor(): string { - return this.getPropertyValue('border-left-color'); - } - /** - * - */ - public set borderLeftColor(borderLeftColor: string) { - this.setProperty('border-left-color', borderLeftColor); - } - - /** - * - */ - public get borderLeftStyle(): string { - return this.getPropertyValue('border-left-style'); - } - /** - * - */ - public set borderLeftStyle(borderLeftStyle: string) { - this.setProperty('border-left-style', borderLeftStyle); - } - - /** - * - */ - public get borderLeftWidth(): string { - return this.getPropertyValue('border-left-width'); - } - /** - * - */ - public set borderLeftWidth(borderLeftWidth: string) { - this.setProperty('border-left-width', borderLeftWidth); - } - - /** - * - */ - public get borderRadius(): string { - return this.getPropertyValue('border-radius'); - } - /** - * - */ - public set borderRadius(borderRadius: string) { - this.setProperty('border-radius', borderRadius); - } - - /** - * - */ - public get borderRight(): string { - return this.getPropertyValue('border-right'); - } - /** - * - */ - public set borderRight(borderRight: string) { - this.setProperty('border-right', borderRight); - } - - /** - * - */ - public get borderRightColor(): string { - return this.getPropertyValue('border-right-color'); - } - /** - * - */ - public set borderRightColor(borderRightColor: string) { - this.setProperty('border-right-color', borderRightColor); - } - - /** - * - */ - public get borderRightStyle(): string { - return this.getPropertyValue('border-right-style'); - } - /** - * - */ - public set borderRightStyle(borderRightStyle: string) { - this.setProperty('border-right-style', borderRightStyle); - } - - /** - * - */ - public get borderRightWidth(): string { - return this.getPropertyValue('border-right-width'); - } - /** - * - */ - public set borderRightWidth(borderRightWidth: string) { - this.setProperty('border-right-width', borderRightWidth); - } - - /** - * - */ - public get borderSpacing(): string { - return this.getPropertyValue('border-spacing'); - } - /** - * - */ - public set borderSpacing(borderSpacing: string) { - this.setProperty('border-spacing', borderSpacing); - } - - /** - * - */ - public get borderStyle(): string { - return this.getPropertyValue('border-style'); - } - /** - * - */ - public set borderStyle(borderStyle: string) { - this.setProperty('border-style', borderStyle); - } - - /** - * - */ - public get borderTop(): string { - return this.getPropertyValue('border-top'); - } - /** - * - */ - public set borderTop(borderTop: string) { - this.setProperty('border-top', borderTop); - } - - /** - * - */ - public get borderTopColor(): string { - return this.getPropertyValue('border-top-color'); - } - /** - * - */ - public set borderTopColor(borderTopColor: string) { - this.setProperty('border-top-color', borderTopColor); - } - - /** - * - */ - public get borderTopLeftRadius(): string { - return this.getPropertyValue('border-top-left-radius'); - } - /** - * - */ - public set borderTopLeftRadius(borderTopLeftRadius: string) { - this.setProperty('border-top-left-radius', borderTopLeftRadius); - } - - /** - * - */ - public get borderTopRightRadius(): string { - return this.getPropertyValue('border-top-right-radius'); - } - /** - * - */ - public set borderTopRightRadius(borderTopRightRadius: string) { - this.setProperty('border-top-right-radius', borderTopRightRadius); - } - - /** - * - */ - public get borderTopStyle(): string { - return this.getPropertyValue('border-top-style'); - } - /** - * - */ - public set borderTopStyle(borderTopStyle: string) { - this.setProperty('border-top-style', borderTopStyle); - } - - /** - * - */ - public get borderTopWidth(): string { - return this.getPropertyValue('border-top-width'); - } - /** - * - */ - public set borderTopWidth(borderTopWidth: string) { - this.setProperty('border-top-width', borderTopWidth); - } - - /** - * - */ - public get borderWidth(): string { - return this.getPropertyValue('border-width'); - } - /** - * - */ - public set borderWidth(borderWidth: string) { - this.setProperty('border-width', borderWidth); - } - - /** - * - */ - public get bottom(): string { - return this.getPropertyValue('bottom'); - } - /** - * - */ - public set bottom(bottom: string) { - this.setProperty('bottom', bottom); - } - - /** - * - */ - public get boxShadow(): string { - return this.getPropertyValue('box-shadow'); - } - /** - * - */ - public set boxShadow(boxShadow: string) { - this.setProperty('box-shadow', boxShadow); - } - - /** - * - */ - public get boxSizing(): string { - return this.getPropertyValue('box-sizing'); - } - /** - * - */ - public set boxSizing(boxSizing: string) { - this.setProperty('box-sizing', boxSizing); - } - - /** - * - */ - public get breakAfter(): string { - return this.getPropertyValue('break-after'); - } - /** - * - */ - public set breakAfter(breakAfter: string) { - this.setProperty('break-after', breakAfter); - } - - /** - * - */ - public get breakBefore(): string { - return this.getPropertyValue('break-before'); - } - /** - * - */ - public set breakBefore(breakBefore: string) { - this.setProperty('break-before', breakBefore); - } - - /** - * - */ - public get breakInside(): string { - return this.getPropertyValue('break-inside'); - } - /** - * - */ - public set breakInside(breakInside: string) { - this.setProperty('break-inside', breakInside); - } - - /** - * - */ - public get bufferedRendering(): string { - return this.getPropertyValue('buffered-rendering'); - } - /** - * - */ - public set bufferedRendering(bufferedRendering: string) { - this.setProperty('buffered-rendering', bufferedRendering); - } - - /** - * - */ - public get captionSide(): string { - return this.getPropertyValue('caption-side'); - } - /** - * - */ - public set captionSide(captionSide: string) { - this.setProperty('caption-side', captionSide); - } - - /** - * - */ - public get caretColor(): string { - return this.getPropertyValue('caret-color'); - } - /** - * - */ - public set caretColor(caretColor: string) { - this.setProperty('caret-color', caretColor); - } - - /** - * - */ - public get clear(): string { - return this.getPropertyValue('clear'); - } - /** - * - */ - public set clear(clear: string) { - this.setProperty('clear', clear); - } - - /** - * - */ - public get clip(): string { - return this.getPropertyValue('clip'); - } - /** - * - */ - public set clip(clip: string) { - this.setProperty('clip', clip); - } - - /** - * - */ - public get clipPath(): string { - return this.getPropertyValue('clip-path'); - } - /** - * - */ - public set clipPath(clipPath: string) { - this.setProperty('clip-path', clipPath); - } - - /** - * - */ - public get clipRule(): string { - return this.getPropertyValue('clip-rule'); - } - /** - * - */ - public set clipRule(clipRule: string) { - this.setProperty('clip-rule', clipRule); - } - - /** - * - */ - public get color(): string { - return this.getPropertyValue('color'); - } - /** - * - */ - public set color(color: string) { - this.setProperty('color', color); - } - - /** - * - */ - public get colorInterpolation(): string { - return this.getPropertyValue('color-interpolation'); - } - /** - * - */ - public set colorInterpolation(colorInterpolation: string) { - this.setProperty('color-interpolation', colorInterpolation); - } - - /** - * - */ - public get colorInterpolationFilters(): string { - return this.getPropertyValue('color-interpolation-filters'); - } - /** - * - */ - public set colorInterpolationFilters(colorInterpolationFilters: string) { - this.setProperty('color-interpolation-filters', colorInterpolationFilters); - } - - /** - * - */ - public get colorRendering(): string { - return this.getPropertyValue('color-rendering'); - } - /** - * - */ - public set colorRendering(colorRendering: string) { - this.setProperty('color-rendering', colorRendering); - } - - /** - * - */ - public get colorScheme(): string { - return this.getPropertyValue('color-scheme'); - } - /** - * - */ - public set colorScheme(colorScheme: string) { - this.setProperty('color-scheme', colorScheme); - } - - /** - * - */ - public get columnCount(): string { - return this.getPropertyValue('column-count'); - } - /** - * - */ - public set columnCount(columnCount: string) { - this.setProperty('column-count', columnCount); - } - - /** - * - */ - public get columnFill(): string { - return this.getPropertyValue('column-fill'); - } - /** - * - */ - public set columnFill(columnFill: string) { - this.setProperty('column-fill', columnFill); - } - - /** - * - */ - public get columnGap(): string { - return this.getPropertyValue('column-gap'); - } - /** - * - */ - public set columnGap(columnGap: string) { - this.setProperty('column-gap', columnGap); - } - - /** - * - */ - public get columnRule(): string { - return this.getPropertyValue('column-rule'); - } - /** - * - */ - public set columnRule(columnRule: string) { - this.setProperty('column-rule', columnRule); - } - - /** - * - */ - public get columnRuleColor(): string { - return this.getPropertyValue('column-rule-color'); - } - /** - * - */ - public set columnRuleColor(columnRuleColor: string) { - this.setProperty('column-rule-color', columnRuleColor); - } - - /** - * - */ - public get columnRuleStyle(): string { - return this.getPropertyValue('column-rule-style'); - } - /** - * - */ - public set columnRuleStyle(columnRuleStyle: string) { - this.setProperty('column-rule-style', columnRuleStyle); - } - - /** - * - */ - public get columnRuleWidth(): string { - return this.getPropertyValue('column-rule-width'); - } - /** - * - */ - public set columnRuleWidth(columnRuleWidth: string) { - this.setProperty('column-rule-width', columnRuleWidth); - } - - /** - * - */ - public get columnSpan(): string { - return this.getPropertyValue('column-span'); - } - /** - * - */ - public set columnSpan(columnSpan: string) { - this.setProperty('column-span', columnSpan); - } - - /** - * - */ - public get columnWidth(): string { - return this.getPropertyValue('column-width'); - } - /** - * - */ - public set columnWidth(columnWidth: string) { - this.setProperty('column-width', columnWidth); - } - - /** - * - */ - public get columns(): string { - return this.getPropertyValue('columns'); - } - /** - * - */ - public set columns(columns: string) { - this.setProperty('columns', columns); - } - - /** - * - */ - public get contain(): string { - return this.getPropertyValue('contain'); - } - /** - * - */ - public set contain(contain: string) { - this.setProperty('contain', contain); - } - - /** - * - */ - public get containIntrinsicSize(): string { - return this.getPropertyValue('contain-intrinsic-size'); - } - /** - * - */ - public set containIntrinsicSize(containIntrinsicSize: string) { - this.setProperty('contain-intrinsic-size', containIntrinsicSize); - } - - /** - * - */ - public get content(): string { - return this.getPropertyValue('content'); - } - /** - * - */ - public set content(content: string) { - this.setProperty('content', content); - } - - /** - * - */ - public get contentVisibility(): string { - return this.getPropertyValue('content-visibility'); - } - /** - * - */ - public set contentVisibility(contentVisibility: string) { - this.setProperty('content-visibility', contentVisibility); - } - - /** - * - */ - public get counterIncrement(): string { - return this.getPropertyValue('counter-increment'); - } - /** - * - */ - public set counterIncrement(counterIncrement: string) { - this.setProperty('counter-increment', counterIncrement); - } - - /** - * - */ - public get counterReset(): string { - return this.getPropertyValue('counter-reset'); - } - /** - * - */ - public set counterReset(counterReset: string) { - this.setProperty('counter-reset', counterReset); - } - - /** - * - */ - public get counterSet(): string { - return this.getPropertyValue('counter-set'); - } - /** - * - */ - public set counterSet(counterSet: string) { - this.setProperty('counter-set', counterSet); - } - - /** - * - */ - public get cssFloat(): string { - return this.getPropertyValue('css-float'); - } - /** - * - */ - public set cssFloat(cssFloat: string) { - this.setProperty('css-float', cssFloat); - } - - /** - * - */ - public get cursor(): string { - return this.getPropertyValue('cursor'); - } - /** - * - */ - public set cursor(cursor: string) { - this.setProperty('cursor', cursor); - } - - /** - * - */ - public get cx(): string { - return this.getPropertyValue('cx'); - } - /** - * - */ - public set cx(cx: string) { - this.setProperty('cx', cx); - } - - /** - * - */ - public get cy(): string { - return this.getPropertyValue('cy'); - } - /** - * - */ - public set cy(cy: string) { - this.setProperty('cy', cy); - } - - /** - * - */ - public get d(): string { - return this.getPropertyValue('d'); - } - /** - * - */ - public set d(d: string) { - this.setProperty('d', d); - } - - /** - * - */ - public get direction(): string { - return this.getPropertyValue('direction'); - } - /** - * - */ - public set direction(direction: string) { - this.setProperty('direction', direction); - } - - /** - * - */ - public get display(): string { - return this.getPropertyValue('display'); - } - /** - * - */ - public set display(display: string) { - this.setProperty('display', display); - } - - /** - * - */ - public get dominantBaseline(): string { - return this.getPropertyValue('dominant-baseline'); - } - /** - * - */ - public set dominantBaseline(dominantBaseline: string) { - this.setProperty('dominant-baseline', dominantBaseline); - } - - /** - * - */ - public get emptyCells(): string { - return this.getPropertyValue('empty-cells'); - } - /** - * - */ - public set emptyCells(emptyCells: string) { - this.setProperty('empty-cells', emptyCells); - } - - /** - * - */ - public get fill(): string { - return this.getPropertyValue('fill'); - } - /** - * - */ - public set fill(fill: string) { - this.setProperty('fill', fill); - } - - /** - * - */ - public get fillOpacity(): string { - return this.getPropertyValue('fill-opacity'); - } - /** - * - */ - public set fillOpacity(fillOpacity: string) { - this.setProperty('fill-opacity', fillOpacity); - } - - /** - * - */ - public get fillRule(): string { - return this.getPropertyValue('fill-rule'); - } - /** - * - */ - public set fillRule(fillRule: string) { - this.setProperty('fill-rule', fillRule); - } - - /** - * - */ - public get filter(): string { - return this.getPropertyValue('filter'); - } - /** - * - */ - public set filter(filter: string) { - this.setProperty('filter', filter); - } - - /** - * - */ - public get flex(): string { - return this.getPropertyValue('flex'); - } - /** - * - */ - public set flex(flex: string) { - this.setProperty('flex', flex); - } - - /** - * - */ - public get flexBasis(): string { - return this.getPropertyValue('flex-basis'); - } - /** - * - */ - public set flexBasis(flexBasis: string) { - this.setProperty('flex-basis', flexBasis); - } - - /** - * - */ - public get flexDirection(): string { - return this.getPropertyValue('flex-direction'); - } - /** - * - */ - public set flexDirection(flexDirection: string) { - this.setProperty('flex-direction', flexDirection); - } - - /** - * - */ - public get flexFlow(): string { - return this.getPropertyValue('flex-flow'); - } - /** - * - */ - public set flexFlow(flexFlow: string) { - this.setProperty('flex-flow', flexFlow); - } - - /** - * - */ - public get flexGrow(): string { - return this.getPropertyValue('flex-grow'); - } - /** - * - */ - public set flexGrow(flexGrow: string) { - this.setProperty('flex-grow', flexGrow); - } - - /** - * - */ - public get flexShrink(): string { - return this.getPropertyValue('flex-shrink'); - } - /** - * - */ - public set flexShrink(flexShrink: string) { - this.setProperty('flex-shrink', flexShrink); - } - - /** - * - */ - public get flexWrap(): string { - return this.getPropertyValue('flex-wrap'); - } - /** - * - */ - public set flexWrap(flexWrap: string) { - this.setProperty('flex-wrap', flexWrap); - } - - /** - * - */ - public get float(): string { - return this.getPropertyValue('float'); - } - /** - * - */ - public set float(float: string) { - this.setProperty('float', float); - } - - /** - * - */ - public get floodColor(): string { - return this.getPropertyValue('flood-color'); - } - /** - * - */ - public set floodColor(floodColor: string) { - this.setProperty('flood-color', floodColor); - } - - /** - * - */ - public get floodOpacity(): string { - return this.getPropertyValue('flood-opacity'); - } - /** - * - */ - public set floodOpacity(floodOpacity: string) { - this.setProperty('flood-opacity', floodOpacity); - } - - /** - * - */ - public get font(): string { - return this.getPropertyValue('font'); - } - /** - * - */ - public set font(font: string) { - this.setProperty('font', font); - } - - /** - * - */ - public get fontDisplay(): string { - return this.getPropertyValue('font-display'); - } - /** - * - */ - public set fontDisplay(fontDisplay: string) { - this.setProperty('font-display', fontDisplay); - } - - /** - * - */ - public get fontFamily(): string { - return this.getPropertyValue('font-family'); - } - /** - * - */ - public set fontFamily(fontFamily: string) { - this.setProperty('font-family', fontFamily); - } - - /** - * - */ - public get fontFeatureSettings(): string { - return this.getPropertyValue('font-feature-settings'); - } - /** - * - */ - public set fontFeatureSettings(fontFeatureSettings: string) { - this.setProperty('font-feature-settings', fontFeatureSettings); - } - - /** - * - */ - public get fontKerning(): string { - return this.getPropertyValue('font-kerning'); - } - /** - * - */ - public set fontKerning(fontKerning: string) { - this.setProperty('font-kerning', fontKerning); - } - - /** - * - */ - public get fontOpticalSizing(): string { - return this.getPropertyValue('font-optical-sizing'); - } - /** - * - */ - public set fontOpticalSizing(fontOpticalSizing: string) { - this.setProperty('font-optical-sizing', fontOpticalSizing); - } - - /** - * - */ - public get fontSize(): string { - return this.getPropertyValue('font-size'); - } - /** - * - */ - public set fontSize(fontSize: string) { - this.setProperty('font-size', fontSize); - } - - /** - * - */ - public get fontStretch(): string { - return this.getPropertyValue('font-stretch'); - } - /** - * - */ - public set fontStretch(fontStretch: string) { - this.setProperty('font-stretch', fontStretch); - } - - /** - * - */ - public get fontStyle(): string { - return this.getPropertyValue('font-style'); - } - /** - * - */ - public set fontStyle(fontStyle: string) { - this.setProperty('font-style', fontStyle); - } - - /** - * - */ - public get fontVariant(): string { - return this.getPropertyValue('font-variant'); - } - /** - * - */ - public set fontVariant(fontVariant: string) { - this.setProperty('font-variant', fontVariant); - } - - /** - * - */ - public get fontVariantCaps(): string { - return this.getPropertyValue('font-variant-caps'); - } - /** - * - */ - public set fontVariantCaps(fontVariantCaps: string) { - this.setProperty('font-variant-caps', fontVariantCaps); - } - - /** - * - */ - public get fontVariantEastAsian(): string { - return this.getPropertyValue('font-variant-east-asian'); - } - /** - * - */ - public set fontVariantEastAsian(fontVariantEastAsian: string) { - this.setProperty('font-variant-east-asian', fontVariantEastAsian); - } - - /** - * - */ - public get fontVariantLigatures(): string { - return this.getPropertyValue('font-variant-ligatures'); - } - /** - * - */ - public set fontVariantLigatures(fontVariantLigatures: string) { - this.setProperty('font-variant-ligatures', fontVariantLigatures); - } - - /** - * - */ - public get fontVariantNumeric(): string { - return this.getPropertyValue('font-variant-numeric'); - } - /** - * - */ - public set fontVariantNumeric(fontVariantNumeric: string) { - this.setProperty('font-variant-numeric', fontVariantNumeric); - } - - /** - * - */ - public get fontVariationSettings(): string { - return this.getPropertyValue('font-variation-settings'); - } - /** - * - */ - public set fontVariationSettings(fontVariationSettings: string) { - this.setProperty('font-variation-settings', fontVariationSettings); - } - - /** - * - */ - public get fontWeight(): string { - return this.getPropertyValue('font-weight'); - } - /** - * - */ - public set fontWeight(fontWeight: string) { - this.setProperty('font-weight', fontWeight); - } - - /** - * - */ - public get gap(): string { - return this.getPropertyValue('gap'); - } - /** - * - */ - public set gap(gap: string) { - this.setProperty('gap', gap); - } - - /** - * - */ - public get grid(): string { - return this.getPropertyValue('grid'); - } - /** - * - */ - public set grid(grid: string) { - this.setProperty('grid', grid); - } - - /** - * - */ - public get gridArea(): string { - return this.getPropertyValue('grid-area'); - } - /** - * - */ - public set gridArea(gridArea: string) { - this.setProperty('grid-area', gridArea); - } - - /** - * - */ - public get gridAutoColumns(): string { - return this.getPropertyValue('grid-auto-columns'); - } - /** - * - */ - public set gridAutoColumns(gridAutoColumns: string) { - this.setProperty('grid-auto-columns', gridAutoColumns); - } - - /** - * - */ - public get gridAutoFlow(): string { - return this.getPropertyValue('grid-auto-flow'); - } - /** - * - */ - public set gridAutoFlow(gridAutoFlow: string) { - this.setProperty('grid-auto-flow', gridAutoFlow); - } - - /** - * - */ - public get gridAutoRows(): string { - return this.getPropertyValue('grid-auto-rows'); - } - /** - * - */ - public set gridAutoRows(gridAutoRows: string) { - this.setProperty('grid-auto-rows', gridAutoRows); - } - - /** - * - */ - public get gridColumn(): string { - return this.getPropertyValue('grid-column'); - } - /** - * - */ - public set gridColumn(gridColumn: string) { - this.setProperty('grid-column', gridColumn); - } - - /** - * - */ - public get gridColumnEnd(): string { - return this.getPropertyValue('grid-column-end'); - } - /** - * - */ - public set gridColumnEnd(gridColumnEnd: string) { - this.setProperty('grid-column-end', gridColumnEnd); - } - - /** - * - */ - public get gridColumnGap(): string { - return this.getPropertyValue('grid-column-gap'); - } - /** - * - */ - public set gridColumnGap(gridColumnGap: string) { - this.setProperty('grid-column-gap', gridColumnGap); - } - - /** - * - */ - public get gridColumnStart(): string { - return this.getPropertyValue('grid-column-start'); - } - /** - * - */ - public set gridColumnStart(gridColumnStart: string) { - this.setProperty('grid-column-start', gridColumnStart); - } - - /** - * - */ - public get gridGap(): string { - return this.getPropertyValue('grid-gap'); - } - /** - * - */ - public set gridGap(gridGap: string) { - this.setProperty('grid-gap', gridGap); - } - - /** - * - */ - public get gridRow(): string { - return this.getPropertyValue('grid-row'); - } - /** - * - */ - public set gridRow(gridRow: string) { - this.setProperty('grid-row', gridRow); - } - - /** - * - */ - public get gridRowEnd(): string { - return this.getPropertyValue('grid-row-end'); - } - /** - * - */ - public set gridRowEnd(gridRowEnd: string) { - this.setProperty('grid-row-end', gridRowEnd); - } - - /** - * - */ - public get gridRowGap(): string { - return this.getPropertyValue('grid-row-gap'); - } - /** - * - */ - public set gridRowGap(gridRowGap: string) { - this.setProperty('grid-row-gap', gridRowGap); - } - - /** - * - */ - public get gridRowStart(): string { - return this.getPropertyValue('grid-row-start'); - } - /** - * - */ - public set gridRowStart(gridRowStart: string) { - this.setProperty('grid-row-start', gridRowStart); - } - - /** - * - */ - public get gridTemplate(): string { - return this.getPropertyValue('grid-template'); - } - /** - * - */ - public set gridTemplate(gridTemplate: string) { - this.setProperty('grid-template', gridTemplate); - } - - /** - * - */ - public get gridTemplateAreas(): string { - return this.getPropertyValue('grid-template-areas'); - } - /** - * - */ - public set gridTemplateAreas(gridTemplateAreas: string) { - this.setProperty('grid-template-areas', gridTemplateAreas); - } - - /** - * - */ - public get gridTemplateColumns(): string { - return this.getPropertyValue('grid-template-columns'); - } - /** - * - */ - public set gridTemplateColumns(gridTemplateColumns: string) { - this.setProperty('grid-template-columns', gridTemplateColumns); - } - - /** - * - */ - public get gridTemplateRows(): string { - return this.getPropertyValue('grid-template-rows'); - } - /** - * - */ - public set gridTemplateRows(gridTemplateRows: string) { - this.setProperty('grid-template-rows', gridTemplateRows); - } - - /** - * - */ - public get height(): string { - return this.getPropertyValue('height'); - } - /** - * - */ - public set height(height: string) { - this.setProperty('height', height); - } - - /** - * - */ - public get hyphens(): string { - return this.getPropertyValue('hyphens'); - } - /** - * - */ - public set hyphens(hyphens: string) { - this.setProperty('hyphens', hyphens); - } - - /** - * - */ - public get imageOrientation(): string { - return this.getPropertyValue('image-orientation'); - } - /** - * - */ - public set imageOrientation(imageOrientation: string) { - this.setProperty('image-orientation', imageOrientation); - } - - /** - * - */ - public get imageRendering(): string { - return this.getPropertyValue('image-rendering'); - } - /** - * - */ - public set imageRendering(imageRendering: string) { - this.setProperty('image-rendering', imageRendering); - } - - /** - * - */ - public get inherits(): string { - return this.getPropertyValue('inherits'); - } - /** - * - */ - public set inherits(inherits: string) { - this.setProperty('inherits', inherits); - } - - /** - * - */ - public get initialValue(): string { - return this.getPropertyValue('initial-value'); - } - /** - * - */ - public set initialValue(initialValue: string) { - this.setProperty('initial-value', initialValue); - } - - /** - * - */ - public get inlineSize(): string { - return this.getPropertyValue('inline-size'); - } - /** - * - */ - public set inlineSize(inlineSize: string) { - this.setProperty('inline-size', inlineSize); - } - - /** - * - */ - public get isolation(): string { - return this.getPropertyValue('isolation'); - } - /** - * - */ - public set isolation(isolation: string) { - this.setProperty('isolation', isolation); - } - - /** - * - */ - public get justifyContent(): string { - return this.getPropertyValue('justify-content'); - } - /** - * - */ - public set justifyContent(justifyContent: string) { - this.setProperty('justify-content', justifyContent); - } - - /** - * - */ - public get justifyItems(): string { - return this.getPropertyValue('justify-items'); - } - /** - * - */ - public set justifyItems(justifyItems: string) { - this.setProperty('justify-items', justifyItems); - } - - /** - * - */ - public get justifySelf(): string { - return this.getPropertyValue('justify-self'); - } - /** - * - */ - public set justifySelf(justifySelf: string) { - this.setProperty('justify-self', justifySelf); - } - - /** - * - */ - public get left(): string { - return this.getPropertyValue('left'); - } - /** - * - */ - public set left(left: string) { - this.setProperty('left', left); - } - - /** - * - */ - public get letterSpacing(): string { - return this.getPropertyValue('letter-spacing'); - } - /** - * - */ - public set letterSpacing(letterSpacing: string) { - this.setProperty('letter-spacing', letterSpacing); - } - - /** - * - */ - public get lightingColor(): string { - return this.getPropertyValue('lighting-color'); - } - /** - * - */ - public set lightingColor(lightingColor: string) { - this.setProperty('lighting-color', lightingColor); - } - - /** - * - */ - public get lineBreak(): string { - return this.getPropertyValue('line-break'); - } - /** - * - */ - public set lineBreak(lineBreak: string) { - this.setProperty('line-break', lineBreak); - } - - /** - * - */ - public get lineHeight(): string { - return this.getPropertyValue('line-height'); - } - /** - * - */ - public set lineHeight(lineHeight: string) { - this.setProperty('line-height', lineHeight); - } - - /** - * - */ - public get listStyle(): string { - return this.getPropertyValue('list-style'); - } - /** - * - */ - public set listStyle(listStyle: string) { - this.setProperty('list-style', listStyle); - } - - /** - * - */ - public get listStyleImage(): string { - return this.getPropertyValue('list-style-image'); - } - /** - * - */ - public set listStyleImage(listStyleImage: string) { - this.setProperty('list-style-image', listStyleImage); - } - - /** - * - */ - public get listStylePosition(): string { - return this.getPropertyValue('list-style-position'); - } - /** - * - */ - public set listStylePosition(listStylePosition: string) { - this.setProperty('list-style-position', listStylePosition); - } - - /** - * - */ - public get listStyleType(): string { - return this.getPropertyValue('list-style-type'); - } - /** - * - */ - public set listStyleType(listStyleType: string) { - this.setProperty('list-style-type', listStyleType); - } - - /** - * - */ - public get margin(): string { - return this.getPropertyValue('margin'); - } - /** - * - */ - public set margin(margin: string) { - this.setProperty('margin', margin); - } - - /** - * - */ - public get marginBlockEnd(): string { - return this.getPropertyValue('margin-block-end'); - } - /** - * - */ - public set marginBlockEnd(marginBlockEnd: string) { - this.setProperty('margin-block-end', marginBlockEnd); - } - - /** - * - */ - public get marginBlockStart(): string { - return this.getPropertyValue('margin-block-start'); - } - /** - * - */ - public set marginBlockStart(marginBlockStart: string) { - this.setProperty('margin-block-start', marginBlockStart); - } - - /** - * - */ - public get marginBottom(): string { - return this.getPropertyValue('margin-bottom'); - } - /** - * - */ - public set marginBottom(marginBottom: string) { - this.setProperty('margin-bottom', marginBottom); - } - - /** - * - */ - public get marginInlineEnd(): string { - return this.getPropertyValue('margin-inline-end'); - } - /** - * - */ - public set marginInlineEnd(marginInlineEnd: string) { - this.setProperty('margin-inline-end', marginInlineEnd); - } - - /** - * - */ - public get marginInlineStart(): string { - return this.getPropertyValue('margin-inline-start'); - } - /** - * - */ - public set marginInlineStart(marginInlineStart: string) { - this.setProperty('margin-inline-start', marginInlineStart); - } - - /** - * - */ - public get marginLeft(): string { - return this.getPropertyValue('margin-left'); - } - /** - * - */ - public set marginLeft(marginLeft: string) { - this.setProperty('margin-left', marginLeft); - } - - /** - * - */ - public get marginRight(): string { - return this.getPropertyValue('margin-right'); - } - /** - * - */ - public set marginRight(marginRight: string) { - this.setProperty('margin-right', marginRight); - } - - /** - * - */ - public get marginTop(): string { - return this.getPropertyValue('margin-top'); - } - /** - * - */ - public set marginTop(marginTop: string) { - this.setProperty('margin-top', marginTop); - } - - /** - * - */ - public get marker(): string { - return this.getPropertyValue('marker'); - } - /** - * - */ - public set marker(marker: string) { - this.setProperty('marker', marker); - } - - /** - * - */ - public get markerEnd(): string { - return this.getPropertyValue('marker-end'); - } - /** - * - */ - public set markerEnd(markerEnd: string) { - this.setProperty('marker-end', markerEnd); - } - - /** - * - */ - public get markerMid(): string { - return this.getPropertyValue('marker-mid'); - } - /** - * - */ - public set markerMid(markerMid: string) { - this.setProperty('marker-mid', markerMid); - } - - /** - * - */ - public get markerStart(): string { - return this.getPropertyValue('marker-start'); - } - /** - * - */ - public set markerStart(markerStart: string) { - this.setProperty('marker-start', markerStart); - } - - /** - * - */ - public get mask(): string { - return this.getPropertyValue('mask'); - } - /** - * - */ - public set mask(mask: string) { - this.setProperty('mask', mask); - } - - /** - * - */ - public get maskType(): string { - return this.getPropertyValue('mask-type'); - } - /** - * - */ - public set maskType(maskType: string) { - this.setProperty('mask-type', maskType); - } - - /** - * - */ - public get maxBlockSize(): string { - return this.getPropertyValue('max-block-size'); - } - /** - * - */ - public set maxBlockSize(maxBlockSize: string) { - this.setProperty('max-block-size', maxBlockSize); - } - - /** - * - */ - public get maxHeight(): string { - return this.getPropertyValue('max-height'); - } - /** - * - */ - public set maxHeight(maxHeight: string) { - this.setProperty('max-height', maxHeight); - } - - /** - * - */ - public get maxInlineSize(): string { - return this.getPropertyValue('max-inline-size'); - } - /** - * - */ - public set maxInlineSize(maxInlineSize: string) { - this.setProperty('max-inline-size', maxInlineSize); - } - - /** - * - */ - public get maxWidth(): string { - return this.getPropertyValue('max-width'); - } - /** - * - */ - public set maxWidth(maxWidth: string) { - this.setProperty('max-width', maxWidth); - } - - /** - * - */ - public get maxZoom(): string { - return this.getPropertyValue('max-zoom'); - } - /** - * - */ - public set maxZoom(maxZoom: string) { - this.setProperty('max-zoom', maxZoom); - } - - /** - * - */ - public get minBlockSize(): string { - return this.getPropertyValue('min-block-size'); - } - /** - * - */ - public set minBlockSize(minBlockSize: string) { - this.setProperty('min-block-size', minBlockSize); - } - - /** - * - */ - public get minHeight(): string { - return this.getPropertyValue('min-height'); - } - /** - * - */ - public set minHeight(minHeight: string) { - this.setProperty('min-height', minHeight); - } - - /** - * - */ - public get minInlineSize(): string { - return this.getPropertyValue('min-inline-size'); - } - /** - * - */ - public set minInlineSize(minInlineSize: string) { - this.setProperty('min-inline-size', minInlineSize); - } - - /** - * - */ - public get minWidth(): string { - return this.getPropertyValue('min-width'); - } - /** - * - */ - public set minWidth(minWidth: string) { - this.setProperty('min-width', minWidth); - } - - /** - * - */ - public get minZoom(): string { - return this.getPropertyValue('min-zoom'); - } - /** - * - */ - public set minZoom(minZoom: string) { - this.setProperty('min-zoom', minZoom); - } - - /** - * - */ - public get mixBlendMode(): string { - return this.getPropertyValue('mix-blend-mode'); - } - /** - * - */ - public set mixBlendMode(mixBlendMode: string) { - this.setProperty('mix-blend-mode', mixBlendMode); - } - - /** - * - */ - public get objectFit(): string { - return this.getPropertyValue('object-fit'); - } - /** - * - */ - public set objectFit(objectFit: string) { - this.setProperty('object-fit', objectFit); - } - - /** - * - */ - public get objectPosition(): string { - return this.getPropertyValue('object-position'); - } - /** - * - */ - public set objectPosition(objectPosition: string) { - this.setProperty('object-position', objectPosition); - } - - /** - * - */ - public get offset(): string { - return this.getPropertyValue('offset'); - } - /** - * - */ - public set offset(offset: string) { - this.setProperty('offset', offset); - } - - /** - * - */ - public get offsetDistance(): string { - return this.getPropertyValue('offset-distance'); - } - /** - * - */ - public set offsetDistance(offsetDistance: string) { - this.setProperty('offset-distance', offsetDistance); - } - - /** - * - */ - public get offsetPath(): string { - return this.getPropertyValue('offset-path'); - } - /** - * - */ - public set offsetPath(offsetPath: string) { - this.setProperty('offset-path', offsetPath); - } - - /** - * - */ - public get offsetRotate(): string { - return this.getPropertyValue('offset-rotate'); - } - /** - * - */ - public set offsetRotate(offsetRotate: string) { - this.setProperty('offset-rotate', offsetRotate); - } - - /** - * - */ - public get opacity(): string { - return this.getPropertyValue('opacity'); - } - /** - * - */ - public set opacity(opacity: string) { - this.setProperty('opacity', opacity); - } - - /** - * - */ - public get order(): string { - return this.getPropertyValue('order'); - } - /** - * - */ - public set order(order: string) { - this.setProperty('order', order); - } - - /** - * - */ - public get orientation(): string { - return this.getPropertyValue('orientation'); - } - /** - * - */ - public set orientation(orientation: string) { - this.setProperty('orientation', orientation); - } - - /** - * - */ - public get orphans(): string { - return this.getPropertyValue('orphans'); - } - /** - * - */ - public set orphans(orphans: string) { - this.setProperty('orphans', orphans); - } - - /** - * - */ - public get outline(): string { - return this.getPropertyValue('outline'); - } - /** - * - */ - public set outline(outline: string) { - this.setProperty('outline', outline); - } - - /** - * - */ - public get outlineColor(): string { - return this.getPropertyValue('outline-color'); - } - /** - * - */ - public set outlineColor(outlineColor: string) { - this.setProperty('outline-color', outlineColor); - } - - /** - * - */ - public get outlineOffset(): string { - return this.getPropertyValue('outline-offset'); - } - /** - * - */ - public set outlineOffset(outlineOffset: string) { - this.setProperty('outline-offset', outlineOffset); - } - - /** - * - */ - public get outlineStyle(): string { - return this.getPropertyValue('outline-style'); - } - /** - * - */ - public set outlineStyle(outlineStyle: string) { - this.setProperty('outline-style', outlineStyle); - } - - /** - * - */ - public get outlineWidth(): string { - return this.getPropertyValue('outline-width'); - } - /** - * - */ - public set outlineWidth(outlineWidth: string) { - this.setProperty('outline-width', outlineWidth); - } - - /** - * - */ - public get overflow(): string { - return this.getPropertyValue('overflow'); - } - /** - * - */ - public set overflow(overflow: string) { - this.setProperty('overflow', overflow); - } - - /** - * - */ - public get overflowAnchor(): string { - return this.getPropertyValue('overflow-anchor'); - } - /** - * - */ - public set overflowAnchor(overflowAnchor: string) { - this.setProperty('overflow-anchor', overflowAnchor); - } - - /** - * - */ - public get overflowWrap(): string { - return this.getPropertyValue('overflow-wrap'); - } - /** - * - */ - public set overflowWrap(overflowWrap: string) { - this.setProperty('overflow-wrap', overflowWrap); - } - - /** - * - */ - public get overflowX(): string { - return this.getPropertyValue('overflow-x'); - } - /** - * - */ - public set overflowX(overflowX: string) { - this.setProperty('overflow-x', overflowX); - } - - /** - * - */ - public get overflowY(): string { - return this.getPropertyValue('overflow-y'); - } - /** - * - */ - public set overflowY(overflowY: string) { - this.setProperty('overflow-y', overflowY); - } - - /** - * - */ - public get overscrollBehavior(): string { - return this.getPropertyValue('overscroll-behavior'); - } - /** - * - */ - public set overscrollBehavior(overscrollBehavior: string) { - this.setProperty('overscroll-behavior', overscrollBehavior); - } - - /** - * - */ - public get overscrollBehaviorBlock(): string { - return this.getPropertyValue('overscroll-behavior-block'); - } - /** - * - */ - public set overscrollBehaviorBlock(overscrollBehaviorBlock: string) { - this.setProperty('overscroll-behavior-block', overscrollBehaviorBlock); - } - - /** - * - */ - public get overscrollBehaviorInline(): string { - return this.getPropertyValue('overscroll-behavior-inline'); - } - /** - * - */ - public set overscrollBehaviorInline(overscrollBehaviorInline: string) { - this.setProperty('overscroll-behavior-inline', overscrollBehaviorInline); - } - - /** - * - */ - public get overscrollBehaviorX(): string { - return this.getPropertyValue('overscroll-behavior-x'); - } - /** - * - */ - public set overscrollBehaviorX(overscrollBehaviorX: string) { - this.setProperty('overscroll-behavior-x', overscrollBehaviorX); - } - - /** - * - */ - public get overscrollBehaviorY(): string { - return this.getPropertyValue('overscroll-behavior-y'); - } - /** - * - */ - public set overscrollBehaviorY(overscrollBehaviorY: string) { - this.setProperty('overscroll-behavior-y', overscrollBehaviorY); - } - - /** - * - */ - public get padding(): string { - return this.getPropertyValue('padding'); - } - /** - * - */ - public set padding(padding: string) { - this.setProperty('padding', padding); - } - - /** - * - */ - public get paddingBlockEnd(): string { - return this.getPropertyValue('padding-block-end'); - } - /** - * - */ - public set paddingBlockEnd(paddingBlockEnd: string) { - this.setProperty('padding-block-end', paddingBlockEnd); - } - - /** - * - */ - public get paddingBlockStart(): string { - return this.getPropertyValue('padding-block-start'); - } - /** - * - */ - public set paddingBlockStart(paddingBlockStart: string) { - this.setProperty('padding-block-start', paddingBlockStart); - } - - /** - * - */ - public get paddingBottom(): string { - return this.getPropertyValue('padding-bottom'); - } - /** - * - */ - public set paddingBottom(paddingBottom: string) { - this.setProperty('padding-bottom', paddingBottom); - } - - /** - * - */ - public get paddingInlineEnd(): string { - return this.getPropertyValue('padding-inline-end'); - } - /** - * - */ - public set paddingInlineEnd(paddingInlineEnd: string) { - this.setProperty('padding-inline-end', paddingInlineEnd); - } - - /** - * - */ - public get paddingInlineStart(): string { - return this.getPropertyValue('padding-inline-start'); - } - /** - * - */ - public set paddingInlineStart(paddingInlineStart: string) { - this.setProperty('padding-inline-start', paddingInlineStart); - } - - /** - * - */ - public get paddingLeft(): string { - return this.getPropertyValue('padding-left'); - } - /** - * - */ - public set paddingLeft(paddingLeft: string) { - this.setProperty('padding-left', paddingLeft); - } - - /** - * - */ - public get paddingRight(): string { - return this.getPropertyValue('padding-right'); - } - /** - * - */ - public set paddingRight(paddingRight: string) { - this.setProperty('padding-right', paddingRight); - } - - /** - * - */ - public get paddingTop(): string { - return this.getPropertyValue('padding-top'); - } - /** - * - */ - public set paddingTop(paddingTop: string) { - this.setProperty('padding-top', paddingTop); - } - - /** - * - */ - public get page(): string { - return this.getPropertyValue('page'); - } - /** - * - */ - public set page(page: string) { - this.setProperty('page', page); - } - - /** - * - */ - public get pageBreakAfter(): string { - return this.getPropertyValue('page-break-after'); - } - /** - * - */ - public set pageBreakAfter(pageBreakAfter: string) { - this.setProperty('page-break-after', pageBreakAfter); - } - - /** - * - */ - public get pageBreakBefore(): string { - return this.getPropertyValue('page-break-before'); - } - /** - * - */ - public set pageBreakBefore(pageBreakBefore: string) { - this.setProperty('page-break-before', pageBreakBefore); - } - - /** - * - */ - public get pageBreakInside(): string { - return this.getPropertyValue('page-break-inside'); - } - /** - * - */ - public set pageBreakInside(pageBreakInside: string) { - this.setProperty('page-break-inside', pageBreakInside); - } - - /** - * - */ - public get pageOrientation(): string { - return this.getPropertyValue('page-orientation'); - } - /** - * - */ - public set pageOrientation(pageOrientation: string) { - this.setProperty('page-orientation', pageOrientation); - } - - /** - * - */ - public get paintOrder(): string { - return this.getPropertyValue('paint-order'); - } - /** - * - */ - public set paintOrder(paintOrder: string) { - this.setProperty('paint-order', paintOrder); - } - - /** - * - */ - public get perspective(): string { - return this.getPropertyValue('perspective'); - } - /** - * - */ - public set perspective(perspective: string) { - this.setProperty('perspective', perspective); - } - - /** - * - */ - public get perspectiveOrigin(): string { - return this.getPropertyValue('perspective-origin'); - } - /** - * - */ - public set perspectiveOrigin(perspectiveOrigin: string) { - this.setProperty('perspective-origin', perspectiveOrigin); - } - - /** - * - */ - public get placeContent(): string { - return this.getPropertyValue('place-content'); - } - /** - * - */ - public set placeContent(placeContent: string) { - this.setProperty('place-content', placeContent); - } - - /** - * - */ - public get placeItems(): string { - return this.getPropertyValue('place-items'); - } - /** - * - */ - public set placeItems(placeItems: string) { - this.setProperty('place-items', placeItems); - } - - /** - * - */ - public get placeSelf(): string { - return this.getPropertyValue('place-self'); - } - /** - * - */ - public set placeSelf(placeSelf: string) { - this.setProperty('place-self', placeSelf); - } - - /** - * - */ - public get pointerEvents(): string { - return this.getPropertyValue('pointer-events'); - } - /** - * - */ - public set pointerEvents(pointerEvents: string) { - this.setProperty('pointer-events', pointerEvents); - } - - /** - * - */ - public get position(): string { - return this.getPropertyValue('position'); - } - /** - * - */ - public set position(position: string) { - this.setProperty('position', position); - } - - /** - * - */ - public get quotes(): string { - return this.getPropertyValue('quotes'); - } - /** - * - */ - public set quotes(quotes: string) { - this.setProperty('quotes', quotes); - } - - /** - * - */ - public get r(): string { - return this.getPropertyValue('r'); - } - /** - * - */ - public set r(r: string) { - this.setProperty('r', r); - } - - /** - * - */ - public get resize(): string { - return this.getPropertyValue('resize'); - } - /** - * - */ - public set resize(resize: string) { - this.setProperty('resize', resize); - } - - /** - * - */ - public get right(): string { - return this.getPropertyValue('right'); - } - /** - * - */ - public set right(right: string) { - this.setProperty('right', right); - } - - /** - * - */ - public get rowGap(): string { - return this.getPropertyValue('row-gap'); - } - /** - * - */ - public set rowGap(rowGap: string) { - this.setProperty('row-gap', rowGap); - } - - /** - * - */ - public get rubyPosition(): string { - return this.getPropertyValue('ruby-position'); - } - /** - * - */ - public set rubyPosition(rubyPosition: string) { - this.setProperty('ruby-position', rubyPosition); - } - - /** - * - */ - public get rx(): string { - return this.getPropertyValue('rx'); - } - /** - * - */ - public set rx(rx: string) { - this.setProperty('rx', rx); - } - - /** - * - */ - public get ry(): string { - return this.getPropertyValue('ry'); - } - /** - * - */ - public set ry(ry: string) { - this.setProperty('ry', ry); - } - - /** - * - */ - public get scrollBehavior(): string { - return this.getPropertyValue('scroll-behavior'); - } - /** - * - */ - public set scrollBehavior(scrollBehavior: string) { - this.setProperty('scroll-behavior', scrollBehavior); - } - - /** - * - */ - public get scrollMargin(): string { - return this.getPropertyValue('scroll-margin'); - } - /** - * - */ - public set scrollMargin(scrollMargin: string) { - this.setProperty('scroll-margin', scrollMargin); - } - - /** - * - */ - public get scrollMarginBlock(): string { - return this.getPropertyValue('scroll-margin-block'); - } - /** - * - */ - public set scrollMarginBlock(scrollMarginBlock: string) { - this.setProperty('scroll-margin-block', scrollMarginBlock); - } - - /** - * - */ - public get scrollMarginBlockEnd(): string { - return this.getPropertyValue('scroll-margin-block-end'); - } - /** - * - */ - public set scrollMarginBlockEnd(scrollMarginBlockEnd: string) { - this.setProperty('scroll-margin-block-end', scrollMarginBlockEnd); - } - - /** - * - */ - public get scrollMarginBlockStart(): string { - return this.getPropertyValue('scroll-margin-block-start'); - } - /** - * - */ - public set scrollMarginBlockStart(scrollMarginBlockStart: string) { - this.setProperty('scroll-margin-block-start', scrollMarginBlockStart); - } - - /** - * - */ - public get scrollMarginBottom(): string { - return this.getPropertyValue('scroll-margin-bottom'); - } - /** - * - */ - public set scrollMarginBottom(scrollMarginBottom: string) { - this.setProperty('scroll-margin-bottom', scrollMarginBottom); - } - - /** - * - */ - public get scrollMarginInline(): string { - return this.getPropertyValue('scroll-margin-inline'); - } - /** - * - */ - public set scrollMarginInline(scrollMarginInline: string) { - this.setProperty('scroll-margin-inline', scrollMarginInline); - } - - /** - * - */ - public get scrollMarginInlineEnd(): string { - return this.getPropertyValue('scroll-margin-inline-end'); - } - /** - * - */ - public set scrollMarginInlineEnd(scrollMarginInlineEnd: string) { - this.setProperty('scroll-margin-inline-end', scrollMarginInlineEnd); - } - - /** - * - */ - public get scrollMarginInlineStart(): string { - return this.getPropertyValue('scroll-margin-inline-start'); - } - /** - * - */ - public set scrollMarginInlineStart(scrollMarginInlineStart: string) { - this.setProperty('scroll-margin-inline-start', scrollMarginInlineStart); - } - - /** - * - */ - public get scrollMarginLeft(): string { - return this.getPropertyValue('scroll-margin-left'); - } - /** - * - */ - public set scrollMarginLeft(scrollMarginLeft: string) { - this.setProperty('scroll-margin-left', scrollMarginLeft); - } - - /** - * - */ - public get scrollMarginRight(): string { - return this.getPropertyValue('scroll-margin-right'); - } - /** - * - */ - public set scrollMarginRight(scrollMarginRight: string) { - this.setProperty('scroll-margin-right', scrollMarginRight); - } - - /** - * - */ - public get scrollMarginTop(): string { - return this.getPropertyValue('scroll-margin-top'); - } - /** - * - */ - public set scrollMarginTop(scrollMarginTop: string) { - this.setProperty('scroll-margin-top', scrollMarginTop); - } - - /** - * - */ - public get scrollPadding(): string { - return this.getPropertyValue('scroll-padding'); - } - /** - * - */ - public set scrollPadding(scrollPadding: string) { - this.setProperty('scroll-padding', scrollPadding); - } - - /** - * - */ - public get scrollPaddingBlock(): string { - return this.getPropertyValue('scroll-padding-block'); - } - /** - * - */ - public set scrollPaddingBlock(scrollPaddingBlock: string) { - this.setProperty('scroll-padding-block', scrollPaddingBlock); - } - - /** - * - */ - public get scrollPaddingBlockEnd(): string { - return this.getPropertyValue('scroll-padding-block-end'); - } - /** - * - */ - public set scrollPaddingBlockEnd(scrollPaddingBlockEnd: string) { - this.setProperty('scroll-padding-block-end', scrollPaddingBlockEnd); - } - - /** - * - */ - public get scrollPaddingBlockStart(): string { - return this.getPropertyValue('scroll-padding-block-start'); - } - /** - * - */ - public set scrollPaddingBlockStart(scrollPaddingBlockStart: string) { - this.setProperty('scroll-padding-block-start', scrollPaddingBlockStart); - } - - /** - * - */ - public get scrollPaddingBottom(): string { - return this.getPropertyValue('scroll-padding-bottom'); - } - /** - * - */ - public set scrollPaddingBottom(scrollPaddingBottom: string) { - this.setProperty('scroll-padding-bottom', scrollPaddingBottom); - } - - /** - * - */ - public get scrollPaddingInline(): string { - return this.getPropertyValue('scroll-padding-inline'); - } - /** - * - */ - public set scrollPaddingInline(scrollPaddingInline: string) { - this.setProperty('scroll-padding-inline', scrollPaddingInline); - } - - /** - * - */ - public get scrollPaddingInlineEnd(): string { - return this.getPropertyValue('scroll-padding-inline-end'); - } - /** - * - */ - public set scrollPaddingInlineEnd(scrollPaddingInlineEnd: string) { - this.setProperty('scroll-padding-inline-end', scrollPaddingInlineEnd); - } - - /** - * - */ - public get scrollPaddingInlineStart(): string { - return this.getPropertyValue('scroll-padding-inline-start'); - } - /** - * - */ - public set scrollPaddingInlineStart(scrollPaddingInlineStart: string) { - this.setProperty('scroll-padding-inline-start', scrollPaddingInlineStart); - } - - /** - * - */ - public get scrollPaddingLeft(): string { - return this.getPropertyValue('scroll-padding-left'); - } - /** - * - */ - public set scrollPaddingLeft(scrollPaddingLeft: string) { - this.setProperty('scroll-padding-left', scrollPaddingLeft); - } - - /** - * - */ - public get scrollPaddingRight(): string { - return this.getPropertyValue('scroll-padding-right'); - } - /** - * - */ - public set scrollPaddingRight(scrollPaddingRight: string) { - this.setProperty('scroll-padding-right', scrollPaddingRight); - } - - /** - * - */ - public get scrollPaddingTop(): string { - return this.getPropertyValue('scroll-padding-top'); - } - /** - * - */ - public set scrollPaddingTop(scrollPaddingTop: string) { - this.setProperty('scroll-padding-top', scrollPaddingTop); - } - - /** - * - */ - public get scrollSnapAlign(): string { - return this.getPropertyValue('scroll-snap-align'); - } - /** - * - */ - public set scrollSnapAlign(scrollSnapAlign: string) { - this.setProperty('scroll-snap-align', scrollSnapAlign); - } - - /** - * - */ - public get scrollSnapStop(): string { - return this.getPropertyValue('scroll-snap-stop'); - } - /** - * - */ - public set scrollSnapStop(scrollSnapStop: string) { - this.setProperty('scroll-snap-stop', scrollSnapStop); - } - - /** - * - */ - public get scrollSnapType(): string { - return this.getPropertyValue('scroll-snap-type'); - } - /** - * - */ - public set scrollSnapType(scrollSnapType: string) { - this.setProperty('scroll-snap-type', scrollSnapType); - } - - /** - * - */ - public get shapeImageThreshold(): string { - return this.getPropertyValue('shape-image-threshold'); - } - /** - * - */ - public set shapeImageThreshold(shapeImageThreshold: string) { - this.setProperty('shape-image-threshold', shapeImageThreshold); - } - - /** - * - */ - public get shapeMargin(): string { - return this.getPropertyValue('shape-margin'); - } - /** - * - */ - public set shapeMargin(shapeMargin: string) { - this.setProperty('shape-margin', shapeMargin); - } - - /** - * - */ - public get shapeOutside(): string { - return this.getPropertyValue('shape-outside'); - } - /** - * - */ - public set shapeOutside(shapeOutside: string) { - this.setProperty('shape-outside', shapeOutside); - } - - /** - * - */ - public get shapeRendering(): string { - return this.getPropertyValue('shape-rendering'); - } - /** - * - */ - public set shapeRendering(shapeRendering: string) { - this.setProperty('shape-rendering', shapeRendering); - } - - /** - * - */ - public get size(): string { - return this.getPropertyValue('size'); - } - /** - * - */ - public set size(size: string) { - this.setProperty('size', size); - } - - /** - * - */ - public get speak(): string { - return this.getPropertyValue('speak'); - } - /** - * - */ - public set speak(speak: string) { - this.setProperty('speak', speak); - } - - /** - * - */ - public get src(): string { - return this.getPropertyValue('src'); - } - /** - * - */ - public set src(src: string) { - this.setProperty('src', src); - } - - /** - * - */ - public get stopColor(): string { - return this.getPropertyValue('stop-color'); - } - /** - * - */ - public set stopColor(stopColor: string) { - this.setProperty('stop-color', stopColor); - } - - /** - * - */ - public get stopOpacity(): string { - return this.getPropertyValue('stop-opacity'); - } - /** - * - */ - public set stopOpacity(stopOpacity: string) { - this.setProperty('stop-opacity', stopOpacity); - } - - /** - * - */ - public get stroke(): string { - return this.getPropertyValue('stroke'); - } - /** - * - */ - public set stroke(stroke: string) { - this.setProperty('stroke', stroke); - } - - /** - * - */ - public get strokeDasharray(): string { - return this.getPropertyValue('stroke-dasharray'); - } - /** - * - */ - public set strokeDasharray(strokeDasharray: string) { - this.setProperty('stroke-dasharray', strokeDasharray); - } - - /** - * - */ - public get strokeDashoffset(): string { - return this.getPropertyValue('stroke-dashoffset'); - } - /** - * - */ - public set strokeDashoffset(strokeDashoffset: string) { - this.setProperty('stroke-dashoffset', strokeDashoffset); - } - - /** - * - */ - public get strokeLinecap(): string { - return this.getPropertyValue('stroke-linecap'); - } - /** - * - */ - public set strokeLinecap(strokeLinecap: string) { - this.setProperty('stroke-linecap', strokeLinecap); - } - - /** - * - */ - public get strokeLinejoin(): string { - return this.getPropertyValue('stroke-linejoin'); - } - /** - * - */ - public set strokeLinejoin(strokeLinejoin: string) { - this.setProperty('stroke-linejoin', strokeLinejoin); - } - - /** - * - */ - public get strokeMiterlimit(): string { - return this.getPropertyValue('stroke-miterlimit'); - } - /** - * - */ - public set strokeMiterlimit(strokeMiterlimit: string) { - this.setProperty('stroke-miterlimit', strokeMiterlimit); - } - - /** - * - */ - public get strokeOpacity(): string { - return this.getPropertyValue('stroke-opacity'); - } - /** - * - */ - public set strokeOpacity(strokeOpacity: string) { - this.setProperty('stroke-opacity', strokeOpacity); - } - - /** - * - */ - public get strokeWidth(): string { - return this.getPropertyValue('stroke-width'); - } - /** - * - */ - public set strokeWidth(strokeWidth: string) { - this.setProperty('stroke-width', strokeWidth); - } - - /** - * - */ - public get syntax(): string { - return this.getPropertyValue('syntax'); - } - /** - * - */ - public set syntax(syntax: string) { - this.setProperty('syntax', syntax); - } - - /** - * - */ - public get tabSize(): string { - return this.getPropertyValue('tab-size'); - } - /** - * - */ - public set tabSize(tabSize: string) { - this.setProperty('tab-size', tabSize); - } - - /** - * - */ - public get tableLayout(): string { - return this.getPropertyValue('table-layout'); - } - /** - * - */ - public set tableLayout(tableLayout: string) { - this.setProperty('table-layout', tableLayout); - } - - /** - * - */ - public get textAlign(): string { - return this.getPropertyValue('text-align'); - } - /** - * - */ - public set textAlign(textAlign: string) { - this.setProperty('text-align', textAlign); - } - - /** - * - */ - public get textAlignLast(): string { - return this.getPropertyValue('text-align-last'); - } - /** - * - */ - public set textAlignLast(textAlignLast: string) { - this.setProperty('text-align-last', textAlignLast); - } - - /** - * - */ - public get textAnchor(): string { - return this.getPropertyValue('text-anchor'); - } - /** - * - */ - public set textAnchor(textAnchor: string) { - this.setProperty('text-anchor', textAnchor); - } - - /** - * - */ - public get textCombineUpright(): string { - return this.getPropertyValue('text-combine-upright'); - } - /** - * - */ - public set textCombineUpright(textCombineUpright: string) { - this.setProperty('text-combine-upright', textCombineUpright); - } - - /** - * - */ - public get textDecoration(): string { - return this.getPropertyValue('text-decoration'); - } - /** - * - */ - public set textDecoration(textDecoration: string) { - this.setProperty('text-decoration', textDecoration); - } - - /** - * - */ - public get textDecorationColor(): string { - return this.getPropertyValue('text-decoration-color'); - } - /** - * - */ - public set textDecorationColor(textDecorationColor: string) { - this.setProperty('text-decoration-color', textDecorationColor); - } - - /** - * - */ - public get textDecorationLine(): string { - return this.getPropertyValue('text-decoration-line'); - } - /** - * - */ - public set textDecorationLine(textDecorationLine: string) { - this.setProperty('text-decoration-line', textDecorationLine); - } - - /** - * - */ - public get textDecorationSkipInk(): string { - return this.getPropertyValue('text-decoration-skip-ink'); - } - /** - * - */ - public set textDecorationSkipInk(textDecorationSkipInk: string) { - this.setProperty('text-decoration-skip-ink', textDecorationSkipInk); - } - - /** - * - */ - public get textDecorationStyle(): string { - return this.getPropertyValue('text-decoration-style'); - } - /** - * - */ - public set textDecorationStyle(textDecorationStyle: string) { - this.setProperty('text-decoration-style', textDecorationStyle); - } - - /** - * - */ - public get textIndent(): string { - return this.getPropertyValue('text-indent'); - } - /** - * - */ - public set textIndent(textIndent: string) { - this.setProperty('text-indent', textIndent); - } - - /** - * - */ - public get textOrientation(): string { - return this.getPropertyValue('text-orientation'); - } - /** - * - */ - public set textOrientation(textOrientation: string) { - this.setProperty('text-orientation', textOrientation); - } - - /** - * - */ - public get textOverflow(): string { - return this.getPropertyValue('text-overflow'); - } - /** - * - */ - public set textOverflow(textOverflow: string) { - this.setProperty('text-overflow', textOverflow); - } - - /** - * - */ - public get textRendering(): string { - return this.getPropertyValue('text-rendering'); - } - /** - * - */ - public set textRendering(textRendering: string) { - this.setProperty('text-rendering', textRendering); - } - - /** - * - */ - public get textShadow(): string { - return this.getPropertyValue('text-shadow'); - } - /** - * - */ - public set textShadow(textShadow: string) { - this.setProperty('text-shadow', textShadow); - } - - /** - * - */ - public get textSizeAdjust(): string { - return this.getPropertyValue('text-size-adjust'); - } - /** - * - */ - public set textSizeAdjust(textSizeAdjust: string) { - this.setProperty('text-size-adjust', textSizeAdjust); - } - - /** - * - */ - public get textTransform(): string { - return this.getPropertyValue('text-transform'); - } - /** - * - */ - public set textTransform(textTransform: string) { - this.setProperty('text-transform', textTransform); - } - - /** - * - */ - public get textUnderlinePosition(): string { - return this.getPropertyValue('text-underline-position'); - } - /** - * - */ - public set textUnderlinePosition(textUnderlinePosition: string) { - this.setProperty('text-underline-position', textUnderlinePosition); - } - - /** - * - */ - public get top(): string { - return this.getPropertyValue('top'); - } - /** - * - */ - public set top(top: string) { - this.setProperty('top', top); - } - - /** - * - */ - public get touchAction(): string { - return this.getPropertyValue('touch-action'); - } - /** - * - */ - public set touchAction(touchAction: string) { - this.setProperty('touch-action', touchAction); - } - - /** - * - */ - public get transform(): string { - return this.getPropertyValue('transform'); - } - /** - * - */ - public set transform(transform: string) { - this.setProperty('transform', transform); - } - - /** - * - */ - public get transformBox(): string { - return this.getPropertyValue('transform-box'); - } - /** - * - */ - public set transformBox(transformBox: string) { - this.setProperty('transform-box', transformBox); - } - - /** - * - */ - public get transformOrigin(): string { - return this.getPropertyValue('transform-origin'); - } - /** - * - */ - public set transformOrigin(transformOrigin: string) { - this.setProperty('transform-origin', transformOrigin); - } - - /** - * - */ - public get transformStyle(): string { - return this.getPropertyValue('transform-style'); - } - /** - * - */ - public set transformStyle(transformStyle: string) { - this.setProperty('transform-style', transformStyle); - } - - /** - * - */ - public get transition(): string { - return this.getPropertyValue('transition'); - } - /** - * - */ - public set transition(transition: string) { - this.setProperty('transition', transition); - } - - /** - * - */ - public get transitionDelay(): string { - return this.getPropertyValue('transition-delay'); - } - /** - * - */ - public set transitionDelay(transitionDelay: string) { - this.setProperty('transition-delay', transitionDelay); - } - - /** - * - */ - public get transitionDuration(): string { - return this.getPropertyValue('transition-duration'); - } - /** - * - */ - public set transitionDuration(transitionDuration: string) { - this.setProperty('transition-duration', transitionDuration); - } - - /** - * - */ - public get transitionProperty(): string { - return this.getPropertyValue('transition-property'); - } - /** - * - */ - public set transitionProperty(transitionProperty: string) { - this.setProperty('transition-property', transitionProperty); - } - - /** - * - */ - public get transitionTimingFunction(): string { - return this.getPropertyValue('transition-timing-function'); - } - /** - * - */ - public set transitionTimingFunction(transitionTimingFunction: string) { - this.setProperty('transition-timing-function', transitionTimingFunction); - } - - /** - * - */ - public get unicodeBidi(): string { - return this.getPropertyValue('unicode-bidi'); - } - /** - * - */ - public set unicodeBidi(unicodeBidi: string) { - this.setProperty('unicode-bidi', unicodeBidi); - } - - /** - * - */ - public get unicodeRange(): string { - return this.getPropertyValue('unicode-range'); - } - /** - * - */ - public set unicodeRange(unicodeRange: string) { - this.setProperty('unicode-range', unicodeRange); - } - - /** - * - */ - public get userSelect(): string { - return this.getPropertyValue('user-select'); - } - /** - * - */ - public set userSelect(userSelect: string) { - this.setProperty('user-select', userSelect); - } - - /** - * - */ - public get userZoom(): string { - return this.getPropertyValue('user-zoom'); - } - /** - * - */ - public set userZoom(userZoom: string) { - this.setProperty('user-zoom', userZoom); - } - - /** - * - */ - public get vectorEffect(): string { - return this.getPropertyValue('vector-effect'); - } - /** - * - */ - public set vectorEffect(vectorEffect: string) { - this.setProperty('vector-effect', vectorEffect); - } - - /** - * - */ - public get verticalAlign(): string { - return this.getPropertyValue('vertical-align'); - } - /** - * - */ - public set verticalAlign(verticalAlign: string) { - this.setProperty('vertical-align', verticalAlign); - } - - /** - * - */ - public get visibility(): string { - return this.getPropertyValue('visibility'); - } - /** - * - */ - public set visibility(visibility: string) { - this.setProperty('visibility', visibility); - } - - /** - * - */ - public get whiteSpace(): string { - return this.getPropertyValue('white-space'); - } - /** - * - */ - public set whiteSpace(whiteSpace: string) { - this.setProperty('white-space', whiteSpace); - } - - /** - * - */ - public get widows(): string { - return this.getPropertyValue('widows'); - } - /** - * - */ - public set widows(widows: string) { - this.setProperty('widows', widows); - } - - /** - * - */ - public get width(): string { - return this.getPropertyValue('width'); - } - /** - * - */ - public set width(width: string) { - this.setProperty('width', width); - } - - /** - * - */ - public get willChange(): string { - return this.getPropertyValue('will-change'); - } - /** - * - */ - public set willChange(willChange: string) { - this.setProperty('will-change', willChange); - } - - /** - * - */ - public get wordBreak(): string { - return this.getPropertyValue('word-break'); - } - /** - * - */ - public set wordBreak(wordBreak: string) { - this.setProperty('word-break', wordBreak); - } - - /** - * - */ - public get wordSpacing(): string { - return this.getPropertyValue('word-spacing'); - } - /** - * - */ - public set wordSpacing(wordSpacing: string) { - this.setProperty('word-spacing', wordSpacing); - } - - /** - * - */ - public get wordWrap(): string { - return this.getPropertyValue('word-wrap'); - } - /** - * - */ - public set wordWrap(wordWrap: string) { - this.setProperty('word-wrap', wordWrap); - } - - /** - * - */ - public get writingMode(): string { - return this.getPropertyValue('writing-mode'); - } - /** - * - */ - public set writingMode(writingMode: string) { - this.setProperty('writing-mode', writingMode); - } - - /** - * - */ - public get x(): string { - return this.getPropertyValue('x'); - } - /** - * - */ - public set x(x: string) { - this.setProperty('x', x); - } - - /** - * - */ - public get y(): string { - return this.getPropertyValue('y'); - } - /** - * - */ - public set y(y: string) { - this.setProperty('y', y); - } - - /** - * - */ - public get zIndex(): string { - return this.getPropertyValue('z-index'); - } - /** - * - */ - public set zIndex(zIndex: string) { - this.setProperty('z-index', zIndex); - } - - /** - * - */ - public get zoom(): string { - return this.getPropertyValue('zoom'); - } - /** - * - */ - public set zoom(zoom: string) { - this.setProperty('zoom', zoom); - } - - /** - * Returns the style decleration as a CSS text. - * - * @returns CSS text. - */ - public get cssText(): string { - const style = this._attributes['style']; - if (style && style.value) { - return style.value; - } - return ''; - } - - /** - * Sets CSS text. - * - * @param cssText CSS text. - */ - public set cssText(cssText: string) { - if (cssText) { - if (!this._attributes['style']) { - this._attributes['style'] = new Attr(); - this._attributes['style'].name = 'style'; - } - const parts = cssText.split(';'); - const newStyle = []; - let index = 0; - for (let i = 0; i < this.length; i++) { - delete this[i]; - } - for (const part of parts) { - if (part) { - const [name, value] = part.trim().split(':'); - if (value) { - newStyle.push(`${name}: ${value.trim()};`); - } else { - newStyle.push(name); - } - this[index] = name; - index++; - } - } - (this.length) = index; - this._attributes['style'].value = newStyle.join(' '); - } else { - delete this._attributes['style']; - for (let i = 0; i < this.length; i++) { - delete this[i]; - } - (this.length) = 0; - } - } - - /** - * Returns item. - * - * @param index Index. - * @returns Item. - */ - public item(index: number): string { - return this[index] || ''; - } - - /** - * Set a property. - * - * @param propertyName Property name. - * @param value Value. Must not contain "!important" as that should be set using the priority parameter. - * @param [priority] Can be "important", or an empty string. - */ - public setProperty(propertyName: string, value: string, priority = ''): void { - if (!value) { - this.removeProperty(propertyName); - return; - } - - if (!this._attributes['style']) { - this._attributes['style'] = new Attr(); - this._attributes['style'].name = 'style'; - } - - const style = this._attributes['style']; - const newStyle = []; - let index = 0; - let isExisting = false; - - if (style && style.value) { - const parts = style.value.split(';'); - for (const part of parts) { - if (part) { - const [name, existingValue] = part.trim().split(':'); - if (name === propertyName) { - newStyle.push(`${name}: ${value};`); - isExisting = true; - } else if (existingValue) { - newStyle.push(`${name}: ${existingValue.trim()};`); - } else { - newStyle.push(`${name};`); - } - - this[index] = name; - index++; - } - } - } - - if (!isExisting) { - newStyle.push(`${propertyName}: ${value}${priority ? '' + priority : ''};`); - this[index] = propertyName; - index++; - } - - this._attributes['style'].value = newStyle.join(' '); - (this.length) = index; - } - - /** - * Removes a property. - * - * @param propertyName Property name in kebab case. - * @param value Value. Must not contain "!important" as that should be set using the priority parameter. - * @param [priority] Can be "important", or an empty string. - */ - public removeProperty(propertyName: string): void { - const style = this._attributes['style']; - const newStyle = []; - let hasProperty = false; - let index = 0; - - if (style && style.value) { - const parts = style.value.split(';'); - for (const part of parts) { - if (part) { - const [name, value] = part.trim().split(':'); - if (name !== propertyName) { - newStyle.push(`${name}: ${value.trim()};`); - this[index] = name; - index++; - hasProperty = true; - } - } - } - } - - if (newStyle.length) { - this._attributes['style'].value = newStyle.join(' '); - } else { - delete this._attributes['style']; - } - - if (hasProperty) { - delete this[index]; - } - - (this.length) = index; - } - - /** - * Returns a property. - * - * @param propertyName Property name in kebab case. - * @returns Property value. - */ - public getPropertyValue(propertyName: string): string { - if (this._computedStyleElement && !this._computedStyleElement.isConnected) { - return ''; - } - - const style = this._attributes['style']; - if (style && style.value) { - const parts = style.value.split(';'); - for (const part of parts) { - if (part) { - const [name, value] = part.trim().split(':'); - if (name === propertyName) { - if (!value) { - return ''; - } - return value.trim(); - } - } - } - } - return ''; - } -} diff --git a/packages/happy-dom/src/css/CSSStyleSheet.ts b/packages/happy-dom/src/css/CSSStyleSheet.ts index 2396b31ac..5ec9943a1 100644 --- a/packages/happy-dom/src/css/CSSStyleSheet.ts +++ b/packages/happy-dom/src/css/CSSStyleSheet.ts @@ -5,7 +5,7 @@ import CSSRule from './CSSRule'; import MediaList from './MediaList'; /** - * Attr node interface. + * CSS StyleSheet. * * Reference: * https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet. @@ -16,20 +16,16 @@ export default class CSSStyleSheet { public namespaceURI: string = null; public readonly cssRules: CSSRule[] = []; - // Constructable Stylesheets is a new feature that only Blink supports: - // https://wicg.github.io/construct-stylesheets/ - // TODO: Not fully implemented. + // TODO: MediaList is not fully implemented. public media: MediaList | string; public title: string; public alternate: boolean; public disabled: boolean; + private _currentText: string = null; /** * Constructor. * - * Constructable Stylesheets is a new feature that only Blink supports: - * https://wicg.github.io/construct-stylesheets/. - * * @param [options] Options. * @param [options.media] Media. * @param [options.title] Title. @@ -51,9 +47,7 @@ export default class CSSStyleSheet { /** * Inserts a rule. * - * Constructable Stylesheets is a new feature that only Blink supports: - * https://wicg.github.io/construct-stylesheets/. - * + * @see https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule * @param rule Rule. * @param [index] Index. * @returns The newly inserterted rule's index. @@ -79,8 +73,7 @@ export default class CSSStyleSheet { DOMExceptionNameEnum.indexSizeError ); } - this.cssRules.splice(index, 0); - this.cssRules.push(rules[0]); + this.cssRules.splice(index, 0, rules[0]); return index; } @@ -94,9 +87,7 @@ export default class CSSStyleSheet { /** * Removes a rule. * - * Constructable Stylesheets is a new feature that only Blink supports: - * https://wicg.github.io/construct-stylesheets/. - * + * @see https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/deleteRule * @param index Index. */ public deleteRule(index: number): void { @@ -106,9 +97,7 @@ export default class CSSStyleSheet { /** * Replaces all CSS rules. * - * Constructable Stylesheets is a new feature that only Blink supports: - * https://wicg.github.io/construct-stylesheets/. - * + * @see https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/replace * @param text CSS text. * @returns Promise. */ @@ -119,12 +108,13 @@ export default class CSSStyleSheet { /** * Replaces all CSS rules. * - * Constructable Stylesheets is a new feature that only Blink supports: - * https://wicg.github.io/construct-stylesheets/. - * + * @see https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/replaceSync * @param text CSS text. */ public replaceSync(text: string): void { - (this.cssRules) = CSSParser.parseFromString(this, text); + if (this._currentText !== text) { + this._currentText = text; + (this.cssRules) = CSSParser.parseFromString(this, text); + } } } diff --git a/packages/happy-dom/src/css/declaration/AbstractCSSStyleDeclaration.ts b/packages/happy-dom/src/css/declaration/AbstractCSSStyleDeclaration.ts new file mode 100644 index 000000000..739a381e9 --- /dev/null +++ b/packages/happy-dom/src/css/declaration/AbstractCSSStyleDeclaration.ts @@ -0,0 +1,202 @@ +import IElement from '../../nodes/element/IElement'; +import Attr from '../../nodes/attr/Attr'; +import CSSRule from '../CSSRule'; +import DOMExceptionNameEnum from '../../exception/DOMExceptionNameEnum'; +import DOMException from '../../exception/DOMException'; +import CSSStyleDeclarationElementStyle from './utilities/CSSStyleDeclarationElementStyle'; +import CSSStyleDeclarationPropertyManager from './utilities/CSSStyleDeclarationPropertyManager'; + +/** + * CSS Style Declaration. + */ +export default abstract class AbstractCSSStyleDeclaration { + public readonly parentRule: CSSRule = null; + protected _style: CSSStyleDeclarationPropertyManager = null; + protected _ownerElement: IElement; + protected _computed: boolean; + protected _elementStyle: CSSStyleDeclarationElementStyle = null; + + /** + * Constructor. + * + * @param [ownerElement] Computed style element. + * @param [computed] Computed. + */ + constructor(ownerElement: IElement = null, computed = false) { + this._style = !ownerElement ? new CSSStyleDeclarationPropertyManager() : null; + this._ownerElement = ownerElement; + this._computed = ownerElement ? computed : false; + this._elementStyle = ownerElement + ? new CSSStyleDeclarationElementStyle(ownerElement, this._computed) + : null; + } + + /** + * Returns length. + * + * @returns Length. + */ + public get length(): number { + if (this._ownerElement) { + const style = this._elementStyle.getElementStyle(); + return style.size(); + } + + return this._style.size(); + } + + /** + * Returns the style decleration as a CSS text. + * + * @returns CSS text. + */ + public get cssText(): string { + if (this._ownerElement) { + if (this._computed) { + return ''; + } + + return this._elementStyle.getElementStyle().toString(); + } + + return this._style.toString(); + } + + /** + * Sets CSS text. + * + * @param cssText CSS text. + */ + public set cssText(cssText: string) { + if (this._computed) { + throw new DOMException( + `Failed to execute 'cssText' on 'CSSStyleDeclaration': These styles are computed, and the properties are therefore read-only.`, + DOMExceptionNameEnum.domException + ); + } + + if (this._ownerElement) { + const style = new CSSStyleDeclarationPropertyManager({ cssText }); + if (!style.size()) { + delete this._ownerElement['_attributes']['style']; + } else { + if (!this._ownerElement['_attributes']['style']) { + Attr._ownerDocument = this._ownerElement.ownerDocument; + this._ownerElement['_attributes']['style'] = new Attr(); + this._ownerElement['_attributes']['style'].name = 'style'; + } + + this._ownerElement['_attributes']['style'].value = style.toString(); + } + } else { + this._style = new CSSStyleDeclarationPropertyManager({ cssText }); + } + } + + /** + * Returns item. + * + * @param index Index. + * @returns Item. + */ + public item(index: number): string { + if (this._ownerElement) { + return this._elementStyle.getElementStyle().item(index); + } + return this._style.item(index); + } + + /** + * Set a property. + * + * @param name Property name. + * @param value Value. Must not contain "!important" as that should be set using the priority parameter. + * @param [priority] Can be "important", or an empty string. + */ + public setProperty(name: string, value: string, priority?: 'important' | '' | undefined): void { + if (this._computed) { + throw new DOMException( + `Failed to execute 'setProperty' on 'CSSStyleDeclaration': These styles are computed, and therefore the '${name}' property is read-only.`, + DOMExceptionNameEnum.domException + ); + } + + if (priority !== '' && priority !== undefined && priority !== 'important') { + return; + } + + if (!value) { + this.removeProperty(name); + } else if (this._ownerElement) { + if (!this._ownerElement['_attributes']['style']) { + Attr._ownerDocument = this._ownerElement.ownerDocument; + this._ownerElement['_attributes']['style'] = new Attr(); + this._ownerElement['_attributes']['style'].name = 'style'; + } + + const style = this._elementStyle.getElementStyle(); + style.set(name, value, !!priority); + + this._ownerElement['_attributes']['style'].value = style.toString(); + } else { + this._style.set(name, value, !!priority); + } + } + + /** + * Removes a property. + * + * @param name Property name in kebab case. + * @param value Value. Must not contain "!important" as that should be set using the priority parameter. + * @param [priority] Can be "important", or an empty string. + */ + public removeProperty(name: string): void { + if (this._computed) { + throw new DOMException( + `Failed to execute 'removeProperty' on 'CSSStyleDeclaration': These styles are computed, and therefore the '${name}' property is read-only.`, + DOMExceptionNameEnum.domException + ); + } + + if (this._ownerElement) { + const style = this._elementStyle.getElementStyle(); + style.remove(name); + const newCSSText = style.toString(); + if (newCSSText) { + this._ownerElement['_attributes']['style'].value = newCSSText; + } else { + delete this._ownerElement['_attributes']['style']; + } + } else { + this._style.remove(name); + } + } + + /** + * Returns a property. + * + * @param name Property name in kebab case. + * @returns Property value. + */ + public getPropertyValue(name: string): string { + if (this._ownerElement) { + const style = this._elementStyle.getElementStyle(); + return style.get(name)?.value || ''; + } + return this._style.get(name)?.value || ''; + } + + /** + * Returns a property. + * + * @param name Property name in kebab case. + * @returns "important" if set to be important. + */ + public getPropertyPriority(name: string): string { + if (this._ownerElement) { + const style = this._elementStyle.getElementStyle(); + return style.get(name)?.important ? 'important' : ''; + } + return this._style.get(name)?.important ? 'important' : ''; + } +} diff --git a/packages/happy-dom/src/css/declaration/CSSStyleDeclaration.ts b/packages/happy-dom/src/css/declaration/CSSStyleDeclaration.ts new file mode 100644 index 000000000..36756bc84 --- /dev/null +++ b/packages/happy-dom/src/css/declaration/CSSStyleDeclaration.ts @@ -0,0 +1,4743 @@ +import AbstractCSSStyleDeclaration from './AbstractCSSStyleDeclaration'; + +/* eslint-disable jsdoc/require-jsdoc */ + +/** + * CSS Style Declaration. + */ +export default class CSSStyleDeclaration extends AbstractCSSStyleDeclaration { + /** + * Index properties + */ + + public get 0(): string { + return this.item(0) || undefined; + } + + public get 1(): string { + return this.item(1) || undefined; + } + + public get 2(): string { + return this.item(2) || undefined; + } + + public get 3(): string { + return this.item(3) || undefined; + } + + public get 4(): string { + return this.item(4) || undefined; + } + + public get 5(): string { + return this.item(5) || undefined; + } + + public get 6(): string { + return this.item(6) || undefined; + } + + public get 7(): string { + return this.item(7) || undefined; + } + + public get 8(): string { + return this.item(8) || undefined; + } + + public get 9(): string { + return this.item(9) || undefined; + } + + public get 10(): string { + return this.item(10) || undefined; + } + + public get 11(): string { + return this.item(11) || undefined; + } + + public get 12(): string { + return this.item(12) || undefined; + } + + public get 13(): string { + return this.item(13) || undefined; + } + + public get 14(): string { + return this.item(14) || undefined; + } + + public get 15(): string { + return this.item(15) || undefined; + } + + public get 16(): string { + return this.item(16) || undefined; + } + + public get 17(): string { + return this.item(17) || undefined; + } + + public get 18(): string { + return this.item(18) || undefined; + } + + public get 19(): string { + return this.item(19) || undefined; + } + + public get 20(): string { + return this.item(20) || undefined; + } + + public get 21(): string { + return this.item(21) || undefined; + } + + public get 22(): string { + return this.item(22) || undefined; + } + + public get 23(): string { + return this.item(23) || undefined; + } + + public get 24(): string { + return this.item(24) || undefined; + } + + public get 25(): string { + return this.item(25) || undefined; + } + + public get 26(): string { + return this.item(26) || undefined; + } + + public get 27(): string { + return this.item(27) || undefined; + } + + public get 28(): string { + return this.item(28) || undefined; + } + + public get 29(): string { + return this.item(29) || undefined; + } + + public get 30(): string { + return this.item(30) || undefined; + } + + public get 31(): string { + return this.item(31) || undefined; + } + + public get 32(): string { + return this.item(32) || undefined; + } + + public get 33(): string { + return this.item(33) || undefined; + } + + public get 34(): string { + return this.item(34) || undefined; + } + + public get 35(): string { + return this.item(35) || undefined; + } + + public get 36(): string { + return this.item(36) || undefined; + } + + public get 37(): string { + return this.item(37) || undefined; + } + + public get 38(): string { + return this.item(38) || undefined; + } + + public get 39(): string { + return this.item(39) || undefined; + } + + public get 40(): string { + return this.item(40) || undefined; + } + + public get 41(): string { + return this.item(41) || undefined; + } + + public get 42(): string { + return this.item(42) || undefined; + } + + public get 43(): string { + return this.item(43) || undefined; + } + + public get 44(): string { + return this.item(44) || undefined; + } + + public get 45(): string { + return this.item(45) || undefined; + } + + public get 46(): string { + return this.item(46) || undefined; + } + + public get 47(): string { + return this.item(47) || undefined; + } + + public get 48(): string { + return this.item(48) || undefined; + } + + public get 49(): string { + return this.item(49) || undefined; + } + + public get 50(): string { + return this.item(50) || undefined; + } + + public get 51(): string { + return this.item(51) || undefined; + } + + public get 52(): string { + return this.item(52) || undefined; + } + + public get 53(): string { + return this.item(53) || undefined; + } + + public get 54(): string { + return this.item(54) || undefined; + } + + public get 55(): string { + return this.item(55) || undefined; + } + + public get 56(): string { + return this.item(56) || undefined; + } + + public get 57(): string { + return this.item(57) || undefined; + } + + public get 58(): string { + return this.item(58) || undefined; + } + + public get 59(): string { + return this.item(59) || undefined; + } + + public get 60(): string { + return this.item(60) || undefined; + } + + public get 61(): string { + return this.item(61) || undefined; + } + + public get 62(): string { + return this.item(62) || undefined; + } + + public get 63(): string { + return this.item(63) || undefined; + } + + public get 64(): string { + return this.item(64) || undefined; + } + + public get 65(): string { + return this.item(65) || undefined; + } + + public get 66(): string { + return this.item(66) || undefined; + } + + public get 67(): string { + return this.item(67) || undefined; + } + + public get 68(): string { + return this.item(68) || undefined; + } + + public get 69(): string { + return this.item(69) || undefined; + } + + public get 70(): string { + return this.item(70) || undefined; + } + + public get 71(): string { + return this.item(71) || undefined; + } + + public get 72(): string { + return this.item(72) || undefined; + } + + public get 73(): string { + return this.item(73) || undefined; + } + + public get 74(): string { + return this.item(74) || undefined; + } + + public get 75(): string { + return this.item(75) || undefined; + } + + public get 76(): string { + return this.item(76) || undefined; + } + + public get 77(): string { + return this.item(77) || undefined; + } + + public get 78(): string { + return this.item(78) || undefined; + } + + public get 79(): string { + return this.item(79) || undefined; + } + + public get 80(): string { + return this.item(80) || undefined; + } + + public get 81(): string { + return this.item(81) || undefined; + } + + public get 82(): string { + return this.item(82) || undefined; + } + + public get 83(): string { + return this.item(83) || undefined; + } + + public get 84(): string { + return this.item(84) || undefined; + } + + public get 85(): string { + return this.item(85) || undefined; + } + + public get 86(): string { + return this.item(86) || undefined; + } + + public get 87(): string { + return this.item(87) || undefined; + } + + public get 88(): string { + return this.item(88) || undefined; + } + + public get 89(): string { + return this.item(89) || undefined; + } + + public get 90(): string { + return this.item(90) || undefined; + } + + public get 91(): string { + return this.item(91) || undefined; + } + + public get 92(): string { + return this.item(92) || undefined; + } + + public get 93(): string { + return this.item(93) || undefined; + } + + public get 94(): string { + return this.item(94) || undefined; + } + + public get 95(): string { + return this.item(95) || undefined; + } + + public get 96(): string { + return this.item(96) || undefined; + } + + public get 97(): string { + return this.item(97) || undefined; + } + + public get 98(): string { + return this.item(98) || undefined; + } + + public get 99(): string { + return this.item(99) || undefined; + } + + public get 100(): string { + return this.item(100) || undefined; + } + + public get 101(): string { + return this.item(101) || undefined; + } + + public get 102(): string { + return this.item(102) || undefined; + } + + public get 103(): string { + return this.item(103) || undefined; + } + + public get 104(): string { + return this.item(104) || undefined; + } + + public get 105(): string { + return this.item(105) || undefined; + } + + public get 106(): string { + return this.item(106) || undefined; + } + + public get 107(): string { + return this.item(107) || undefined; + } + + public get 108(): string { + return this.item(108) || undefined; + } + + public get 109(): string { + return this.item(109) || undefined; + } + + public get 110(): string { + return this.item(110) || undefined; + } + + public get 111(): string { + return this.item(111) || undefined; + } + + public get 112(): string { + return this.item(112) || undefined; + } + + public get 113(): string { + return this.item(113) || undefined; + } + + public get 114(): string { + return this.item(114) || undefined; + } + + public get 115(): string { + return this.item(115) || undefined; + } + + public get 116(): string { + return this.item(116) || undefined; + } + + public get 117(): string { + return this.item(117) || undefined; + } + + public get 118(): string { + return this.item(118) || undefined; + } + + public get 119(): string { + return this.item(119) || undefined; + } + + public get 120(): string { + return this.item(120) || undefined; + } + + public get 121(): string { + return this.item(121) || undefined; + } + + public get 122(): string { + return this.item(122) || undefined; + } + + public get 123(): string { + return this.item(123) || undefined; + } + + public get 124(): string { + return this.item(124) || undefined; + } + + public get 125(): string { + return this.item(125) || undefined; + } + + public get 126(): string { + return this.item(126) || undefined; + } + + public get 127(): string { + return this.item(127) || undefined; + } + + public get 128(): string { + return this.item(128) || undefined; + } + + public get 129(): string { + return this.item(129) || undefined; + } + + public get 130(): string { + return this.item(130) || undefined; + } + + public get 131(): string { + return this.item(131) || undefined; + } + + public get 132(): string { + return this.item(132) || undefined; + } + + public get 133(): string { + return this.item(133) || undefined; + } + + public get 134(): string { + return this.item(134) || undefined; + } + + public get 135(): string { + return this.item(135) || undefined; + } + + public get 136(): string { + return this.item(136) || undefined; + } + + public get 137(): string { + return this.item(137) || undefined; + } + + public get 138(): string { + return this.item(138) || undefined; + } + + public get 139(): string { + return this.item(139) || undefined; + } + + public get 140(): string { + return this.item(140) || undefined; + } + + public get 141(): string { + return this.item(141) || undefined; + } + + public get 142(): string { + return this.item(142) || undefined; + } + + public get 143(): string { + return this.item(143) || undefined; + } + + public get 144(): string { + return this.item(144) || undefined; + } + + public get 145(): string { + return this.item(145) || undefined; + } + + public get 146(): string { + return this.item(146) || undefined; + } + + public get 147(): string { + return this.item(147) || undefined; + } + + public get 148(): string { + return this.item(148) || undefined; + } + + public get 149(): string { + return this.item(149) || undefined; + } + + public get 150(): string { + return this.item(150) || undefined; + } + + public get 151(): string { + return this.item(151) || undefined; + } + + public get 152(): string { + return this.item(152) || undefined; + } + + public get 153(): string { + return this.item(153) || undefined; + } + + public get 154(): string { + return this.item(154) || undefined; + } + + public get 155(): string { + return this.item(155) || undefined; + } + + public get 156(): string { + return this.item(156) || undefined; + } + + public get 157(): string { + return this.item(157) || undefined; + } + + public get 158(): string { + return this.item(158) || undefined; + } + + public get 159(): string { + return this.item(159) || undefined; + } + + public get 160(): string { + return this.item(160) || undefined; + } + + public get 161(): string { + return this.item(161) || undefined; + } + + public get 162(): string { + return this.item(162) || undefined; + } + + public get 163(): string { + return this.item(163) || undefined; + } + + public get 164(): string { + return this.item(164) || undefined; + } + + public get 165(): string { + return this.item(165) || undefined; + } + + public get 166(): string { + return this.item(166) || undefined; + } + + public get 167(): string { + return this.item(167) || undefined; + } + + public get 168(): string { + return this.item(168) || undefined; + } + + public get 169(): string { + return this.item(169) || undefined; + } + + public get 170(): string { + return this.item(170) || undefined; + } + + public get 171(): string { + return this.item(171) || undefined; + } + + public get 172(): string { + return this.item(172) || undefined; + } + + public get 173(): string { + return this.item(173) || undefined; + } + + public get 174(): string { + return this.item(174) || undefined; + } + + public get 175(): string { + return this.item(175) || undefined; + } + + public get 176(): string { + return this.item(176) || undefined; + } + + public get 177(): string { + return this.item(177) || undefined; + } + + public get 178(): string { + return this.item(178) || undefined; + } + + public get 179(): string { + return this.item(179) || undefined; + } + + public get 180(): string { + return this.item(180) || undefined; + } + + public get 181(): string { + return this.item(181) || undefined; + } + + public get 182(): string { + return this.item(182) || undefined; + } + + public get 183(): string { + return this.item(183) || undefined; + } + + public get 184(): string { + return this.item(184) || undefined; + } + + public get 185(): string { + return this.item(185) || undefined; + } + + public get 186(): string { + return this.item(186) || undefined; + } + + public get 187(): string { + return this.item(187) || undefined; + } + + public get 188(): string { + return this.item(188) || undefined; + } + + public get 189(): string { + return this.item(189) || undefined; + } + + public get 190(): string { + return this.item(190) || undefined; + } + + public get 191(): string { + return this.item(191) || undefined; + } + + public get 192(): string { + return this.item(192) || undefined; + } + + public get 193(): string { + return this.item(193) || undefined; + } + + public get 194(): string { + return this.item(194) || undefined; + } + + public get 195(): string { + return this.item(195) || undefined; + } + + public get 196(): string { + return this.item(196) || undefined; + } + + public get 197(): string { + return this.item(197) || undefined; + } + + public get 198(): string { + return this.item(198) || undefined; + } + + public get 199(): string { + return this.item(199) || undefined; + } + + public get 200(): string { + return this.item(200) || undefined; + } + + public get 201(): string { + return this.item(201) || undefined; + } + + public get 202(): string { + return this.item(202) || undefined; + } + + public get 203(): string { + return this.item(203) || undefined; + } + + public get 204(): string { + return this.item(204) || undefined; + } + + public get 205(): string { + return this.item(205) || undefined; + } + + public get 206(): string { + return this.item(206) || undefined; + } + + public get 207(): string { + return this.item(207) || undefined; + } + + public get 208(): string { + return this.item(208) || undefined; + } + + public get 209(): string { + return this.item(209) || undefined; + } + + public get 210(): string { + return this.item(210) || undefined; + } + + public get 211(): string { + return this.item(211) || undefined; + } + + public get 212(): string { + return this.item(212) || undefined; + } + + public get 213(): string { + return this.item(213) || undefined; + } + + public get 214(): string { + return this.item(214) || undefined; + } + + public get 215(): string { + return this.item(215) || undefined; + } + + public get 216(): string { + return this.item(216) || undefined; + } + + public get 217(): string { + return this.item(217) || undefined; + } + + public get 218(): string { + return this.item(218) || undefined; + } + + public get 219(): string { + return this.item(219) || undefined; + } + + public get 220(): string { + return this.item(220) || undefined; + } + + public get 221(): string { + return this.item(221) || undefined; + } + + public get 222(): string { + return this.item(222) || undefined; + } + + public get 223(): string { + return this.item(223) || undefined; + } + + public get 224(): string { + return this.item(224) || undefined; + } + + public get 225(): string { + return this.item(225) || undefined; + } + + public get 226(): string { + return this.item(226) || undefined; + } + + public get 227(): string { + return this.item(227) || undefined; + } + + public get 228(): string { + return this.item(228) || undefined; + } + + public get 229(): string { + return this.item(229) || undefined; + } + + public get 230(): string { + return this.item(230) || undefined; + } + + public get 231(): string { + return this.item(231) || undefined; + } + + public get 232(): string { + return this.item(232) || undefined; + } + + public get 233(): string { + return this.item(233) || undefined; + } + + public get 234(): string { + return this.item(234) || undefined; + } + + public get 235(): string { + return this.item(235) || undefined; + } + + public get 236(): string { + return this.item(236) || undefined; + } + + public get 237(): string { + return this.item(237) || undefined; + } + + public get 238(): string { + return this.item(238) || undefined; + } + + public get 239(): string { + return this.item(239) || undefined; + } + + public get 240(): string { + return this.item(240) || undefined; + } + + public get 241(): string { + return this.item(241) || undefined; + } + + public get 242(): string { + return this.item(242) || undefined; + } + + public get 243(): string { + return this.item(243) || undefined; + } + + public get 244(): string { + return this.item(244) || undefined; + } + + public get 245(): string { + return this.item(245) || undefined; + } + + public get 246(): string { + return this.item(246) || undefined; + } + + public get 247(): string { + return this.item(247) || undefined; + } + + public get 248(): string { + return this.item(248) || undefined; + } + + public get 249(): string { + return this.item(249) || undefined; + } + + public get 250(): string { + return this.item(250) || undefined; + } + + public get 251(): string { + return this.item(251) || undefined; + } + + public get 252(): string { + return this.item(252) || undefined; + } + + public get 253(): string { + return this.item(253) || undefined; + } + + public get 254(): string { + return this.item(254) || undefined; + } + + public get 255(): string { + return this.item(255) || undefined; + } + + public get 256(): string { + return this.item(256) || undefined; + } + + public get 257(): string { + return this.item(257) || undefined; + } + + public get 258(): string { + return this.item(258) || undefined; + } + + public get 259(): string { + return this.item(259) || undefined; + } + + public get 260(): string { + return this.item(260) || undefined; + } + + public get 261(): string { + return this.item(261) || undefined; + } + + public get 262(): string { + return this.item(262) || undefined; + } + + public get 263(): string { + return this.item(263) || undefined; + } + + public get 264(): string { + return this.item(264) || undefined; + } + + public get 265(): string { + return this.item(265) || undefined; + } + + public get 266(): string { + return this.item(266) || undefined; + } + + public get 267(): string { + return this.item(267) || undefined; + } + + public get 268(): string { + return this.item(268) || undefined; + } + + public get 269(): string { + return this.item(269) || undefined; + } + + public get 270(): string { + return this.item(270) || undefined; + } + + public get 271(): string { + return this.item(271) || undefined; + } + + public get 272(): string { + return this.item(272) || undefined; + } + + public get 273(): string { + return this.item(273) || undefined; + } + + public get 274(): string { + return this.item(274) || undefined; + } + + public get 275(): string { + return this.item(275) || undefined; + } + + public get 276(): string { + return this.item(276) || undefined; + } + + public get 277(): string { + return this.item(277) || undefined; + } + + public get 278(): string { + return this.item(278) || undefined; + } + + public get 279(): string { + return this.item(279) || undefined; + } + + public get 280(): string { + return this.item(280) || undefined; + } + + public get 281(): string { + return this.item(281) || undefined; + } + + public get 282(): string { + return this.item(282) || undefined; + } + + public get 283(): string { + return this.item(283) || undefined; + } + + public get 284(): string { + return this.item(284) || undefined; + } + + public get 285(): string { + return this.item(285) || undefined; + } + + public get 286(): string { + return this.item(286) || undefined; + } + + public get 287(): string { + return this.item(287) || undefined; + } + + public get 288(): string { + return this.item(288) || undefined; + } + + public get 289(): string { + return this.item(289) || undefined; + } + + public get 290(): string { + return this.item(290) || undefined; + } + + public get 291(): string { + return this.item(291) || undefined; + } + + public get 292(): string { + return this.item(292) || undefined; + } + + public get 293(): string { + return this.item(293) || undefined; + } + + public get 294(): string { + return this.item(294) || undefined; + } + + public get 295(): string { + return this.item(295) || undefined; + } + + public get 296(): string { + return this.item(296) || undefined; + } + + public get 297(): string { + return this.item(297) || undefined; + } + + public get 298(): string { + return this.item(298) || undefined; + } + + public get 299(): string { + return this.item(299) || undefined; + } + + public get 300(): string { + return this.item(300) || undefined; + } + + public get 301(): string { + return this.item(301) || undefined; + } + + public get 302(): string { + return this.item(302) || undefined; + } + + public get 303(): string { + return this.item(303) || undefined; + } + + public get 304(): string { + return this.item(304) || undefined; + } + + public get 305(): string { + return this.item(305) || undefined; + } + + public get 306(): string { + return this.item(306) || undefined; + } + + public get 307(): string { + return this.item(307) || undefined; + } + + public get 308(): string { + return this.item(308) || undefined; + } + + public get 309(): string { + return this.item(309) || undefined; + } + + public get 310(): string { + return this.item(310) || undefined; + } + + public get 311(): string { + return this.item(311) || undefined; + } + + public get 312(): string { + return this.item(312) || undefined; + } + + public get 313(): string { + return this.item(313) || undefined; + } + + public get 314(): string { + return this.item(314) || undefined; + } + + public get 315(): string { + return this.item(315) || undefined; + } + + public get 316(): string { + return this.item(316) || undefined; + } + + public get 317(): string { + return this.item(317) || undefined; + } + + public get 318(): string { + return this.item(318) || undefined; + } + + public get 319(): string { + return this.item(319) || undefined; + } + + public get 320(): string { + return this.item(320) || undefined; + } + + public get 321(): string { + return this.item(321) || undefined; + } + + public get 322(): string { + return this.item(322) || undefined; + } + + public get 323(): string { + return this.item(323) || undefined; + } + + public get 324(): string { + return this.item(324) || undefined; + } + + public get 325(): string { + return this.item(325) || undefined; + } + + public get 326(): string { + return this.item(326) || undefined; + } + + public get 327(): string { + return this.item(327) || undefined; + } + + public get 328(): string { + return this.item(328) || undefined; + } + + public get 329(): string { + return this.item(329) || undefined; + } + + public get 330(): string { + return this.item(330) || undefined; + } + + public get 331(): string { + return this.item(331) || undefined; + } + + public get 332(): string { + return this.item(332) || undefined; + } + + public get 333(): string { + return this.item(333) || undefined; + } + + public get 334(): string { + return this.item(334) || undefined; + } + + public get 335(): string { + return this.item(335) || undefined; + } + + public get 336(): string { + return this.item(336) || undefined; + } + + public get 337(): string { + return this.item(337) || undefined; + } + + public get 338(): string { + return this.item(338) || undefined; + } + + public get 339(): string { + return this.item(339) || undefined; + } + + public get 340(): string { + return this.item(340) || undefined; + } + + public get 341(): string { + return this.item(341) || undefined; + } + + public get 342(): string { + return this.item(342) || undefined; + } + + public get 343(): string { + return this.item(343) || undefined; + } + + public get 344(): string { + return this.item(344) || undefined; + } + + public get 345(): string { + return this.item(345) || undefined; + } + + public get 346(): string { + return this.item(346) || undefined; + } + + public get 347(): string { + return this.item(347) || undefined; + } + + public get 348(): string { + return this.item(348) || undefined; + } + + public get 349(): string { + return this.item(349) || undefined; + } + + public get 350(): string { + return this.item(350) || undefined; + } + + public get 351(): string { + return this.item(351) || undefined; + } + + public get 352(): string { + return this.item(352) || undefined; + } + + public get 353(): string { + return this.item(353) || undefined; + } + + public get 354(): string { + return this.item(354) || undefined; + } + + public get 355(): string { + return this.item(355) || undefined; + } + + public get 356(): string { + return this.item(356) || undefined; + } + + public get 357(): string { + return this.item(357) || undefined; + } + + public get 358(): string { + return this.item(358) || undefined; + } + + public get 359(): string { + return this.item(359) || undefined; + } + + public get 360(): string { + return this.item(360) || undefined; + } + + public get 361(): string { + return this.item(361) || undefined; + } + + public get 362(): string { + return this.item(362) || undefined; + } + + public get 363(): string { + return this.item(363) || undefined; + } + + public get 364(): string { + return this.item(364) || undefined; + } + + public get 365(): string { + return this.item(365) || undefined; + } + + public get 366(): string { + return this.item(366) || undefined; + } + + public get 367(): string { + return this.item(367) || undefined; + } + + public get 368(): string { + return this.item(368) || undefined; + } + public get 369(): string { + return this.item(369) || undefined; + } + + public get 370(): string { + return this.item(370) || undefined; + } + + public get 371(): string { + return this.item(371) || undefined; + } + + public get 372(): string { + return this.item(372) || undefined; + } + + public get 373(): string { + return this.item(373) || undefined; + } + + public get 374(): string { + return this.item(374) || undefined; + } + + public get 375(): string { + return this.item(375) || undefined; + } + + public get 376(): string { + return this.item(376) || undefined; + } + + public get 377(): string { + return this.item(377) || undefined; + } + + public get 378(): string { + return this.item(378) || undefined; + } + + public get 379(): string { + return this.item(379) || undefined; + } + + public get 380(): string { + return this.item(380) || undefined; + } + + public get 381(): string { + return this.item(381) || undefined; + } + + public get 382(): string { + return this.item(382) || undefined; + } + + public get 383(): string { + return this.item(383) || undefined; + } + + public get 384(): string { + return this.item(384) || undefined; + } + + public get 385(): string { + return this.item(385) || undefined; + } + + public get 386(): string { + return this.item(386) || undefined; + } + + public get 387(): string { + return this.item(387) || undefined; + } + + public get 388(): string { + return this.item(388) || undefined; + } + + public get 389(): string { + return this.item(389) || undefined; + } + + public get 390(): string { + return this.item(390) || undefined; + } + + public get 391(): string { + return this.item(391) || undefined; + } + + public get 392(): string { + return this.item(392) || undefined; + } + + public get 393(): string { + return this.item(393) || undefined; + } + + /** + * CSS properties + */ + + public get accentColor(): string { + return this.getPropertyValue('accent-color'); + } + + public set accentColor(value: string) { + this.setProperty('accent-color', value); + } + + public get appRegion(): string { + return this.getPropertyValue('app-region'); + } + + public set appRegion(value: string) { + this.setProperty('app-region', value); + } + + public get alignContent(): string { + return this.getPropertyValue('align-content'); + } + + public set alignContent(value: string) { + this.setProperty('align-content', value); + } + + public get alignItems(): string { + return this.getPropertyValue('align-items'); + } + + public set alignItems(value: string) { + this.setProperty('align-items', value); + } + + public get alignSelf(): string { + return this.getPropertyValue('align-self'); + } + + public set alignSelf(value: string) { + this.setProperty('align-self', value); + } + + public get alignmentBaseline(): string { + return this.getPropertyValue('alignment-baseline'); + } + + public set alignmentBaseline(value: string) { + this.setProperty('alignment-baseline', value); + } + + public get all(): string { + return this.getPropertyValue('all'); + } + + public set all(value: string) { + this.setProperty('all', value); + } + + public get animation(): string { + return this.getPropertyValue('animation'); + } + + public set animation(value: string) { + this.setProperty('animation', value); + } + + public get animationDelay(): string { + return this.getPropertyValue('animation-delay'); + } + + public set animationDelay(value: string) { + this.setProperty('animation-delay', value); + } + + public get animationDirection(): string { + return this.getPropertyValue('animation-direction'); + } + + public set animationDirection(value: string) { + this.setProperty('animation-direction', value); + } + + public get animationDuration(): string { + return this.getPropertyValue('animation-duration'); + } + + public set animationDuration(value: string) { + this.setProperty('animation-duration', value); + } + + public get animationFillMode(): string { + return this.getPropertyValue('animation-fill-mode'); + } + + public set animationFillMode(value: string) { + this.setProperty('animation-fill-mode', value); + } + + public get animationIterationCount(): string { + return this.getPropertyValue('animation-iteration-count'); + } + + public set animationIterationCount(value: string) { + this.setProperty('animation-iteration-count', value); + } + + public get animationName(): string { + return this.getPropertyValue('animation-name'); + } + + public set animationName(value: string) { + this.setProperty('animation-name', value); + } + + public get animationPlayState(): string { + return this.getPropertyValue('animation-play-state'); + } + + public set animationPlayState(value: string) { + this.setProperty('animation-play-state', value); + } + + public get animationTimingFunction(): string { + return this.getPropertyValue('animation-timing-function'); + } + + public set animationTimingFunction(value: string) { + this.setProperty('animation-timing-function', value); + } + + public get appearance(): string { + return this.getPropertyValue('appearance'); + } + + public set appearance(value: string) { + this.setProperty('appearance', value); + } + + public get backdropFilter(): string { + return this.getPropertyValue('backdrop-filter'); + } + + public set backdropFilter(value: string) { + this.setProperty('backdrop-filter', value); + } + + public get backfaceVisibility(): string { + return this.getPropertyValue('backface-visibility'); + } + + public set backfaceVisibility(value: string) { + this.setProperty('backface-visibility', value); + } + + public get background(): string { + return this.getPropertyValue('background'); + } + + public set background(value: string) { + this.setProperty('background', value); + } + + public get backgroundAttachment(): string { + return this.getPropertyValue('background-attachment'); + } + + public set backgroundAttachment(value: string) { + this.setProperty('background-attachment', value); + } + + public get backgroundBlendMode(): string { + return this.getPropertyValue('background-blend-mode'); + } + + public set backgroundBlendMode(value: string) { + this.setProperty('background-blend-mode', value); + } + + public get backgroundClip(): string { + return this.getPropertyValue('background-clip'); + } + + public set backgroundClip(value: string) { + this.setProperty('background-clip', value); + } + + public get backgroundColor(): string { + return this.getPropertyValue('background-color'); + } + + public set backgroundColor(value: string) { + this.setProperty('background-color', value); + } + + public get backgroundImage(): string { + return this.getPropertyValue('background-image'); + } + + public set backgroundImage(value: string) { + this.setProperty('background-image', value); + } + + public get backgroundOrigin(): string { + return this.getPropertyValue('background-origin'); + } + + public set backgroundOrigin(value: string) { + this.setProperty('background-origin', value); + } + + public get backgroundPosition(): string { + return this.getPropertyValue('background-position'); + } + + public set backgroundPosition(value: string) { + this.setProperty('background-position', value); + } + + public get backgroundPositionX(): string { + return this.getPropertyValue('background-position-x'); + } + + public set backgroundPositionX(value: string) { + this.setProperty('background-position-x', value); + } + + public get backgroundPositionY(): string { + return this.getPropertyValue('background-position-y'); + } + + public set backgroundPositionY(value: string) { + this.setProperty('background-position-y', value); + } + + public get backgroundRepeat(): string { + return this.getPropertyValue('background-repeat'); + } + + public set backgroundRepeat(value: string) { + this.setProperty('background-repeat', value); + } + + public get backgroundRepeatX(): string { + return this.getPropertyValue('background-repeat-x'); + } + + public set backgroundRepeatX(value: string) { + this.setProperty('background-repeat-x', value); + } + + public get backgroundRepeatY(): string { + return this.getPropertyValue('background-repeat-y'); + } + + public set backgroundRepeatY(value: string) { + this.setProperty('background-repeat-y', value); + } + + public get backgroundSize(): string { + return this.getPropertyValue('background-size'); + } + + public set backgroundSize(value: string) { + this.setProperty('background-size', value); + } + + public get baselineShift(): string { + return this.getPropertyValue('baseline-shift'); + } + + public set baselineShift(value: string) { + this.setProperty('baseline-shift', value); + } + + public get blockSize(): string { + return this.getPropertyValue('block-size'); + } + + public set blockSize(value: string) { + this.setProperty('block-size', value); + } + + public get border(): string { + return this.getPropertyValue('border'); + } + + public set border(value: string) { + this.setProperty('border', value); + } + + public get borderBlockEnd(): string { + return this.getPropertyValue('border-block-end'); + } + + public set borderBlockEnd(value: string) { + this.setProperty('border-block-end', value); + } + + public get borderBlockEndColor(): string { + return this.getPropertyValue('border-block-end-color'); + } + + public set borderBlockEndColor(value: string) { + this.setProperty('border-block-end-color', value); + } + + public get borderBlockEndStyle(): string { + return this.getPropertyValue('border-block-end-style'); + } + + public set borderBlockEndStyle(value: string) { + this.setProperty('border-block-end-style', value); + } + + public get borderBlockEndWidth(): string { + return this.getPropertyValue('border-block-end-width'); + } + + public set borderBlockEndWidth(value: string) { + this.setProperty('border-block-end-width', value); + } + + public get borderBlockStart(): string { + return this.getPropertyValue('border-block-start'); + } + + public set borderBlockStart(value: string) { + this.setProperty('border-block-start', value); + } + + public get borderBlockStartColor(): string { + return this.getPropertyValue('border-block-start-color'); + } + + public set borderBlockStartColor(value: string) { + this.setProperty('border-block-start-color', value); + } + + public get borderBlockStartStyle(): string { + return this.getPropertyValue('border-block-start-style'); + } + + public set borderBlockStartStyle(value: string) { + this.setProperty('border-block-start-style', value); + } + + public get borderBlockStartWidth(): string { + return this.getPropertyValue('border-block-start-width'); + } + + public set borderBlockStartWidth(value: string) { + this.setProperty('border-block-start-width', value); + } + + public get borderBottom(): string { + return this.getPropertyValue('border-bottom'); + } + + public set borderBottom(value: string) { + this.setProperty('border-bottom', value); + } + + public get borderBottomColor(): string { + return this.getPropertyValue('border-bottom-color'); + } + + public set borderBottomColor(value: string) { + this.setProperty('border-bottom-color', value); + } + + public get borderBottomLeftRadius(): string { + return this.getPropertyValue('border-bottom-left-radius'); + } + + public set borderBottomLeftRadius(value: string) { + this.setProperty('border-bottom-left-radius', value); + } + + public get borderBottomRightRadius(): string { + return this.getPropertyValue('border-bottom-right-radius'); + } + + public set borderBottomRightRadius(value: string) { + this.setProperty('border-bottom-right-radius', value); + } + + public get borderBottomStyle(): string { + return this.getPropertyValue('border-bottom-style'); + } + + public set borderBottomStyle(value: string) { + this.setProperty('border-bottom-style', value); + } + + public get borderBottomWidth(): string { + return this.getPropertyValue('border-bottom-width'); + } + + public set borderBottomWidth(value: string) { + this.setProperty('border-bottom-width', value); + } + + public get borderCollapse(): string { + return this.getPropertyValue('border-collapse'); + } + + public set borderCollapse(value: string) { + this.setProperty('border-collapse', value); + } + + public get borderColor(): string { + return this.getPropertyValue('border-color'); + } + + public set borderColor(value: string) { + this.setProperty('border-color', value); + } + + public get borderImage(): string { + return this.getPropertyValue('border-image'); + } + + public set borderImage(value: string) { + this.setProperty('border-image', value); + } + + public get borderImageOutset(): string { + return this.getPropertyValue('border-image-outset'); + } + + public set borderImageOutset(value: string) { + this.setProperty('border-image-outset', value); + } + + public get borderImageRepeat(): string { + return this.getPropertyValue('border-image-repeat'); + } + + public set borderImageRepeat(value: string) { + this.setProperty('border-image-repeat', value); + } + + public get borderImageSlice(): string { + return this.getPropertyValue('border-image-slice'); + } + + public set borderImageSlice(value: string) { + this.setProperty('border-image-slice', value); + } + + public get borderImageSource(): string { + return this.getPropertyValue('border-image-source'); + } + + public set borderImageSource(value: string) { + this.setProperty('border-image-source', value); + } + + public get borderImageWidth(): string { + return this.getPropertyValue('border-image-width'); + } + + public set borderImageWidth(value: string) { + this.setProperty('border-image-width', value); + } + + public get borderInlineEnd(): string { + return this.getPropertyValue('border-inline-end'); + } + + public set borderInlineEnd(value: string) { + this.setProperty('border-inline-end', value); + } + + public get borderInlineEndColor(): string { + return this.getPropertyValue('border-inline-end-color'); + } + + public set borderInlineEndColor(value: string) { + this.setProperty('border-inline-end-color', value); + } + + public get borderInlineEndStyle(): string { + return this.getPropertyValue('border-inline-end-style'); + } + + public set borderInlineEndStyle(value: string) { + this.setProperty('border-inline-end-style', value); + } + + public get borderInlineEndWidth(): string { + return this.getPropertyValue('border-inline-end-width'); + } + + public set borderInlineEndWidth(value: string) { + this.setProperty('border-inline-end-width', value); + } + + public get borderInlineStart(): string { + return this.getPropertyValue('border-inline-start'); + } + + public set borderInlineStart(value: string) { + this.setProperty('border-inline-start', value); + } + + public get borderInlineStartColor(): string { + return this.getPropertyValue('border-inline-start-color'); + } + + public set borderInlineStartColor(value: string) { + this.setProperty('border-inline-start-color', value); + } + + public get borderInlineStartStyle(): string { + return this.getPropertyValue('border-inline-start-style'); + } + + public set borderInlineStartStyle(value: string) { + this.setProperty('border-inline-start-style', value); + } + + public get borderInlineStartWidth(): string { + return this.getPropertyValue('border-inline-start-width'); + } + + public set borderInlineStartWidth(value: string) { + this.setProperty('border-inline-start-width', value); + } + + public get borderLeft(): string { + return this.getPropertyValue('border-left'); + } + + public set borderLeft(value: string) { + this.setProperty('border-left', value); + } + + public get borderLeftColor(): string { + return this.getPropertyValue('border-left-color'); + } + + public set borderLeftColor(value: string) { + this.setProperty('border-left-color', value); + } + + public get borderLeftStyle(): string { + return this.getPropertyValue('border-left-style'); + } + + public set borderLeftStyle(value: string) { + this.setProperty('border-left-style', value); + } + + public get borderLeftWidth(): string { + return this.getPropertyValue('border-left-width'); + } + + public set borderLeftWidth(value: string) { + this.setProperty('border-left-width', value); + } + + public get borderRadius(): string { + return this.getPropertyValue('border-radius'); + } + + public set borderRadius(value: string) { + this.setProperty('border-radius', value); + } + + public get borderRight(): string { + return this.getPropertyValue('border-right'); + } + + public set borderRight(value: string) { + this.setProperty('border-right', value); + } + + public get borderRightColor(): string { + return this.getPropertyValue('border-right-color'); + } + + public set borderRightColor(value: string) { + this.setProperty('border-right-color', value); + } + + public get borderRightStyle(): string { + return this.getPropertyValue('border-right-style'); + } + + public set borderRightStyle(value: string) { + this.setProperty('border-right-style', value); + } + + public get borderRightWidth(): string { + return this.getPropertyValue('border-right-width'); + } + + public set borderRightWidth(value: string) { + this.setProperty('border-right-width', value); + } + + public get borderSpacing(): string { + return this.getPropertyValue('border-spacing'); + } + + public set borderSpacing(value: string) { + this.setProperty('border-spacing', value); + } + + public get borderStyle(): string { + return this.getPropertyValue('border-style'); + } + + public set borderStyle(value: string) { + this.setProperty('border-style', value); + } + + public get borderTop(): string { + return this.getPropertyValue('border-top'); + } + + public set borderTop(value: string) { + this.setProperty('border-top', value); + } + + public get borderTopColor(): string { + return this.getPropertyValue('border-top-color'); + } + + public set borderTopColor(value: string) { + this.setProperty('border-top-color', value); + } + + public get borderTopLeftRadius(): string { + return this.getPropertyValue('border-top-left-radius'); + } + + public set borderTopLeftRadius(value: string) { + this.setProperty('border-top-left-radius', value); + } + + public get borderTopRightRadius(): string { + return this.getPropertyValue('border-top-right-radius'); + } + + public set borderTopRightRadius(value: string) { + this.setProperty('border-top-right-radius', value); + } + + public get borderTopStyle(): string { + return this.getPropertyValue('border-top-style'); + } + + public set borderTopStyle(value: string) { + this.setProperty('border-top-style', value); + } + + public get borderTopWidth(): string { + return this.getPropertyValue('border-top-width'); + } + + public set borderTopWidth(value: string) { + this.setProperty('border-top-width', value); + } + + public get borderWidth(): string { + return this.getPropertyValue('border-width'); + } + + public set borderWidth(value: string) { + this.setProperty('border-width', value); + } + + public get borderEndEndRadius(): string { + return this.getPropertyValue('border-end-end-radius'); + } + + public set borderEndEndRadius(value: string) { + this.setProperty('border-end-end-radius', value); + } + + public get borderEndStartRadius(): string { + return this.getPropertyValue('border-end-start-radius'); + } + + public set borderEndStartRadius(value: string) { + this.setProperty('border-end-start-radius', value); + } + + public get borderStartEndRadius(): string { + return this.getPropertyValue('border-start-end-radius'); + } + + public set borderStartEndRadius(value: string) { + this.setProperty('border-start-end-radius', value); + } + + public get borderStartStartRadius(): string { + return this.getPropertyValue('border-start-start-radius'); + } + + public set borderStartStartRadius(value: string) { + this.setProperty('border-start-start-radius', value); + } + + public get bottom(): string { + return this.getPropertyValue('bottom'); + } + + public set bottom(value: string) { + this.setProperty('bottom', value); + } + + public get boxShadow(): string { + return this.getPropertyValue('box-shadow'); + } + + public set boxShadow(value: string) { + this.setProperty('box-shadow', value); + } + + public get boxSizing(): string { + return this.getPropertyValue('box-sizing'); + } + + public set boxSizing(value: string) { + this.setProperty('box-sizing', value); + } + + public get breakAfter(): string { + return this.getPropertyValue('break-after'); + } + + public set breakAfter(value: string) { + this.setProperty('break-after', value); + } + + public get breakBefore(): string { + return this.getPropertyValue('break-before'); + } + + public set breakBefore(value: string) { + this.setProperty('break-before', value); + } + + public get breakInside(): string { + return this.getPropertyValue('break-inside'); + } + + public set breakInside(value: string) { + this.setProperty('break-inside', value); + } + + public get bufferedRendering(): string { + return this.getPropertyValue('buffered-rendering'); + } + + public set bufferedRendering(value: string) { + this.setProperty('buffered-rendering', value); + } + + public get captionSide(): string { + return this.getPropertyValue('caption-side'); + } + + public set captionSide(value: string) { + this.setProperty('caption-side', value); + } + + public get caretColor(): string { + return this.getPropertyValue('caret-color'); + } + + public set caretColor(value: string) { + this.setProperty('caret-color', value); + } + + public get clear(): string { + return this.getPropertyValue('clear'); + } + + public set clear(value: string) { + this.setProperty('clear', value); + } + + public get clip(): string { + return this.getPropertyValue('clip'); + } + + public set clip(value: string) { + this.setProperty('clip', value); + } + + public get clipPath(): string { + return this.getPropertyValue('clip-path'); + } + + public set clipPath(value: string) { + this.setProperty('clip-path', value); + } + + public get clipRule(): string { + return this.getPropertyValue('clip-rule'); + } + + public set clipRule(value: string) { + this.setProperty('clip-rule', value); + } + + public get color(): string { + return this.getPropertyValue('color'); + } + + public set color(value: string) { + this.setProperty('color', value); + } + + public get colorInterpolation(): string { + return this.getPropertyValue('color-interpolation'); + } + + public set colorInterpolation(value: string) { + this.setProperty('color-interpolation', value); + } + + public get colorInterpolationFilters(): string { + return this.getPropertyValue('color-interpolation-filters'); + } + + public set colorInterpolationFilters(value: string) { + this.setProperty('color-interpolation-filters', value); + } + + public get colorRendering(): string { + return this.getPropertyValue('color-rendering'); + } + + public set colorRendering(value: string) { + this.setProperty('color-rendering', value); + } + + public get colorScheme(): string { + return this.getPropertyValue('color-scheme'); + } + + public set colorScheme(value: string) { + this.setProperty('color-scheme', value); + } + + public get columnCount(): string { + return this.getPropertyValue('column-count'); + } + + public set columnCount(value: string) { + this.setProperty('column-count', value); + } + + public get columnFill(): string { + return this.getPropertyValue('column-fill'); + } + + public set columnFill(value: string) { + this.setProperty('column-fill', value); + } + + public get columnGap(): string { + return this.getPropertyValue('column-gap'); + } + + public set columnGap(value: string) { + this.setProperty('column-gap', value); + } + + public get columnRule(): string { + return this.getPropertyValue('column-rule'); + } + + public set columnRule(value: string) { + this.setProperty('column-rule', value); + } + + public get columnRuleColor(): string { + return this.getPropertyValue('column-rule-color'); + } + + public set columnRuleColor(value: string) { + this.setProperty('column-rule-color', value); + } + + public get columnRuleStyle(): string { + return this.getPropertyValue('column-rule-style'); + } + + public set columnRuleStyle(value: string) { + this.setProperty('column-rule-style', value); + } + + public get columnRuleWidth(): string { + return this.getPropertyValue('column-rule-width'); + } + + public set columnRuleWidth(value: string) { + this.setProperty('column-rule-width', value); + } + + public get columnSpan(): string { + return this.getPropertyValue('column-span'); + } + + public set columnSpan(value: string) { + this.setProperty('column-span', value); + } + + public get columnWidth(): string { + return this.getPropertyValue('column-width'); + } + + public set columnWidth(value: string) { + this.setProperty('column-width', value); + } + + public get columns(): string { + return this.getPropertyValue('columns'); + } + + public set columns(value: string) { + this.setProperty('columns', value); + } + + public get contain(): string { + return this.getPropertyValue('contain'); + } + + public set contain(value: string) { + this.setProperty('contain', value); + } + + public get containIntrinsicSize(): string { + return this.getPropertyValue('contain-intrinsic-size'); + } + + public set containIntrinsicSize(value: string) { + this.setProperty('contain-intrinsic-size', value); + } + + public get content(): string { + return this.getPropertyValue('content'); + } + + public set content(value: string) { + this.setProperty('content', value); + } + + public get contentVisibility(): string { + return this.getPropertyValue('content-visibility'); + } + + public set contentVisibility(value: string) { + this.setProperty('content-visibility', value); + } + + public get counterIncrement(): string { + return this.getPropertyValue('counter-increment'); + } + + public set counterIncrement(value: string) { + this.setProperty('counter-increment', value); + } + + public get counterReset(): string { + return this.getPropertyValue('counter-reset'); + } + + public set counterReset(value: string) { + this.setProperty('counter-reset', value); + } + + public get counterSet(): string { + return this.getPropertyValue('counter-set'); + } + + public set counterSet(value: string) { + this.setProperty('counter-set', value); + } + + public get containIntrinsicBlockSize(): string { + return this.getPropertyValue('contain-intrinsic-block-size'); + } + + public set containIntrinsicBlockSize(value: string) { + this.setProperty('contain-intrinsic-block-size', value); + } + + public get containIntrinsicHeight(): string { + return this.getPropertyValue('contain-intrinsic-height'); + } + + public set containIntrinsicHeight(value: string) { + this.setProperty('contain-intrinsic-height', value); + } + + public get containIntrinsicInlineSize(): string { + return this.getPropertyValue('contain-intrinsic-inline-size'); + } + + public set containIntrinsicInlineSize(value: string) { + this.setProperty('contain-intrinsic-inline-size', value); + } + + public get containIntrinsicWidth(): string { + return this.getPropertyValue('contain-intrinsic-width'); + } + + public set containIntrinsicWidth(value: string) { + this.setProperty('contain-intrinsic-width', value); + } + + public get cssFloat(): string { + return this.getPropertyValue('css-float'); + } + + public set cssFloat(value: string) { + this.setProperty('css-float', value); + } + + public get cursor(): string { + return this.getPropertyValue('cursor'); + } + + public set cursor(value: string) { + this.setProperty('cursor', value); + } + + public get cx(): string { + return this.getPropertyValue('cx'); + } + + public set cx(value: string) { + this.setProperty('cx', value); + } + + public get cy(): string { + return this.getPropertyValue('cy'); + } + + public set cy(value: string) { + this.setProperty('cy', value); + } + + public get d(): string { + return this.getPropertyValue('d'); + } + + public set d(value: string) { + this.setProperty('d', value); + } + + public get direction(): string { + return this.getPropertyValue('direction'); + } + + public set direction(value: string) { + this.setProperty('direction', value); + } + + public get display(): string { + return this.getPropertyValue('display'); + } + + public set display(value: string) { + this.setProperty('display', value); + } + + public get dominantBaseline(): string { + return this.getPropertyValue('dominant-baseline'); + } + + public set dominantBaseline(value: string) { + this.setProperty('dominant-baseline', value); + } + + public get emptyCells(): string { + return this.getPropertyValue('empty-cells'); + } + + public set emptyCells(value: string) { + this.setProperty('empty-cells', value); + } + + public get fill(): string { + return this.getPropertyValue('fill'); + } + + public set fill(value: string) { + this.setProperty('fill', value); + } + + public get fillOpacity(): string { + return this.getPropertyValue('fill-opacity'); + } + + public set fillOpacity(value: string) { + this.setProperty('fill-opacity', value); + } + + public get fillRule(): string { + return this.getPropertyValue('fill-rule'); + } + + public set fillRule(value: string) { + this.setProperty('fill-rule', value); + } + + public get filter(): string { + return this.getPropertyValue('filter'); + } + + public set filter(value: string) { + this.setProperty('filter', value); + } + + public get flex(): string { + return this.getPropertyValue('flex'); + } + + public set flex(value: string) { + this.setProperty('flex', value); + } + + public get flexBasis(): string { + return this.getPropertyValue('flex-basis'); + } + + public set flexBasis(value: string) { + this.setProperty('flex-basis', value); + } + + public get flexDirection(): string { + return this.getPropertyValue('flex-direction'); + } + + public set flexDirection(value: string) { + this.setProperty('flex-direction', value); + } + + public get flexFlow(): string { + return this.getPropertyValue('flex-flow'); + } + + public set flexFlow(value: string) { + this.setProperty('flex-flow', value); + } + + public get flexGrow(): string { + return this.getPropertyValue('flex-grow'); + } + + public set flexGrow(value: string) { + this.setProperty('flex-grow', value); + } + + public get flexShrink(): string { + return this.getPropertyValue('flex-shrink'); + } + + public set flexShrink(value: string) { + this.setProperty('flex-shrink', value); + } + + public get flexWrap(): string { + return this.getPropertyValue('flex-wrap'); + } + + public set flexWrap(value: string) { + this.setProperty('flex-wrap', value); + } + + public get float(): string { + return this.getPropertyValue('float'); + } + + public set float(value: string) { + this.setProperty('float', value); + } + + public get floodColor(): string { + return this.getPropertyValue('flood-color'); + } + + public set floodColor(value: string) { + this.setProperty('flood-color', value); + } + + public get floodOpacity(): string { + return this.getPropertyValue('flood-opacity'); + } + + public set floodOpacity(value: string) { + this.setProperty('flood-opacity', value); + } + + public get font(): string { + return this.getPropertyValue('font'); + } + + public set font(value: string) { + this.setProperty('font', value); + } + + public get fontDisplay(): string { + return this.getPropertyValue('font-display'); + } + + public set fontDisplay(value: string) { + this.setProperty('font-display', value); + } + + public get fontFamily(): string { + return this.getPropertyValue('font-family'); + } + + public set fontFamily(value: string) { + this.setProperty('font-family', value); + } + + public get fontFeatureSettings(): string { + return this.getPropertyValue('font-feature-settings'); + } + + public set fontFeatureSettings(value: string) { + this.setProperty('font-feature-settings', value); + } + + public get fontKerning(): string { + return this.getPropertyValue('font-kerning'); + } + + public set fontKerning(value: string) { + this.setProperty('font-kerning', value); + } + + public get fontOpticalSizing(): string { + return this.getPropertyValue('font-optical-sizing'); + } + + public set fontOpticalSizing(value: string) { + this.setProperty('font-optical-sizing', value); + } + + public get fontSize(): string { + return this.getPropertyValue('font-size'); + } + + public set fontSize(value: string) { + this.setProperty('font-size', value); + } + + public get fontStretch(): string { + return this.getPropertyValue('font-stretch'); + } + + public set fontStretch(value: string) { + this.setProperty('font-stretch', value); + } + + public get fontStyle(): string { + return this.getPropertyValue('font-style'); + } + + public set fontStyle(value: string) { + this.setProperty('font-style', value); + } + + public get fontVariant(): string { + return this.getPropertyValue('font-variant'); + } + + public set fontVariant(value: string) { + this.setProperty('font-variant', value); + } + + public get fontVariantCaps(): string { + return this.getPropertyValue('font-variant-caps'); + } + + public set fontVariantCaps(value: string) { + this.setProperty('font-variant-caps', value); + } + + public get fontVariantEastAsian(): string { + return this.getPropertyValue('font-variant-east-asian'); + } + + public set fontVariantEastAsian(value: string) { + this.setProperty('font-variant-east-asian', value); + } + + public get fontVariantLigatures(): string { + return this.getPropertyValue('font-variant-ligatures'); + } + + public set fontVariantLigatures(value: string) { + this.setProperty('font-variant-ligatures', value); + } + + public get fontVariantNumeric(): string { + return this.getPropertyValue('font-variant-numeric'); + } + + public set fontVariantNumeric(value: string) { + this.setProperty('font-variant-numeric', value); + } + + public get fontVariationSettings(): string { + return this.getPropertyValue('font-variation-settings'); + } + + public set fontVariationSettings(value: string) { + this.setProperty('font-variation-settings', value); + } + + public get fontPalette(): string { + return this.getPropertyValue('font-palette'); + } + + public set fontPalette(value: string) { + this.setProperty('font-palette', value); + } + + public get fontSynthesisSmallCaps(): string { + return this.getPropertyValue('font-synthesis-small-caps'); + } + + public set fontSynthesisSmallCaps(value: string) { + this.setProperty('font-synthesis-small-caps', value); + } + + public get fontSynthesisStyle(): string { + return this.getPropertyValue('font-synthesis-style'); + } + + public set fontSynthesisStyle(value: string) { + this.setProperty('font-synthesis-style', value); + } + + public get fontSynthesisWeight(): string { + return this.getPropertyValue('font-synthesis-weight'); + } + + public set fontSynthesisWeight(value: string) { + this.setProperty('font-synthesis-weight', value); + } + + public get fontWeight(): string { + return this.getPropertyValue('font-weight'); + } + + public set fontWeight(value: string) { + this.setProperty('font-weight', value); + } + + public get gap(): string { + return this.getPropertyValue('gap'); + } + + public set gap(value: string) { + this.setProperty('gap', value); + } + + public get grid(): string { + return this.getPropertyValue('grid'); + } + + public set grid(value: string) { + this.setProperty('grid', value); + } + + public get gridArea(): string { + return this.getPropertyValue('grid-area'); + } + + public set gridArea(value: string) { + this.setProperty('grid-area', value); + } + + public get gridAutoColumns(): string { + return this.getPropertyValue('grid-auto-columns'); + } + + public set gridAutoColumns(value: string) { + this.setProperty('grid-auto-columns', value); + } + + public get gridAutoFlow(): string { + return this.getPropertyValue('grid-auto-flow'); + } + + public set gridAutoFlow(value: string) { + this.setProperty('grid-auto-flow', value); + } + + public get gridAutoRows(): string { + return this.getPropertyValue('grid-auto-rows'); + } + + public set gridAutoRows(value: string) { + this.setProperty('grid-auto-rows', value); + } + + public get gridColumn(): string { + return this.getPropertyValue('grid-column'); + } + + public set gridColumn(value: string) { + this.setProperty('grid-column', value); + } + + public get gridColumnEnd(): string { + return this.getPropertyValue('grid-column-end'); + } + + public set gridColumnEnd(value: string) { + this.setProperty('grid-column-end', value); + } + + public get gridColumnGap(): string { + return this.getPropertyValue('grid-column-gap'); + } + + public set gridColumnGap(value: string) { + this.setProperty('grid-column-gap', value); + } + + public get gridColumnStart(): string { + return this.getPropertyValue('grid-column-start'); + } + + public set gridColumnStart(value: string) { + this.setProperty('grid-column-start', value); + } + + public get gridGap(): string { + return this.getPropertyValue('grid-gap'); + } + + public set gridGap(value: string) { + this.setProperty('grid-gap', value); + } + + public get gridRow(): string { + return this.getPropertyValue('grid-row'); + } + + public set gridRow(value: string) { + this.setProperty('grid-row', value); + } + + public get gridRowEnd(): string { + return this.getPropertyValue('grid-row-end'); + } + + public set gridRowEnd(value: string) { + this.setProperty('grid-row-end', value); + } + + public get gridRowGap(): string { + return this.getPropertyValue('grid-row-gap'); + } + + public set gridRowGap(value: string) { + this.setProperty('grid-row-gap', value); + } + + public get gridRowStart(): string { + return this.getPropertyValue('grid-row-start'); + } + + public set gridRowStart(value: string) { + this.setProperty('grid-row-start', value); + } + + public get gridTemplate(): string { + return this.getPropertyValue('grid-template'); + } + + public set gridTemplate(value: string) { + this.setProperty('grid-template', value); + } + + public get gridTemplateAreas(): string { + return this.getPropertyValue('grid-template-areas'); + } + + public set gridTemplateAreas(value: string) { + this.setProperty('grid-template-areas', value); + } + + public get gridTemplateColumns(): string { + return this.getPropertyValue('grid-template-columns'); + } + + public set gridTemplateColumns(value: string) { + this.setProperty('grid-template-columns', value); + } + + public get gridTemplateRows(): string { + return this.getPropertyValue('grid-template-rows'); + } + + public set gridTemplateRows(value: string) { + this.setProperty('grid-template-rows', value); + } + + public get height(): string { + return this.getPropertyValue('height'); + } + + public set height(value: string) { + this.setProperty('height', value); + } + + public get hyphens(): string { + return this.getPropertyValue('hyphens'); + } + + public set hyphens(value: string) { + this.setProperty('hyphens', value); + } + + public get imageOrientation(): string { + return this.getPropertyValue('image-orientation'); + } + + public set imageOrientation(value: string) { + this.setProperty('image-orientation', value); + } + + public get imageRendering(): string { + return this.getPropertyValue('image-rendering'); + } + + public set imageRendering(value: string) { + this.setProperty('image-rendering', value); + } + + public get inherits(): string { + return this.getPropertyValue('inherits'); + } + + public set inherits(value: string) { + this.setProperty('inherits', value); + } + + public get initialValue(): string { + return this.getPropertyValue('initial-value'); + } + + public set initialValue(value: string) { + this.setProperty('initial-value', value); + } + + public get inlineSize(): string { + return this.getPropertyValue('inline-size'); + } + + public set inlineSize(value: string) { + this.setProperty('inline-size', value); + } + + public get isolation(): string { + return this.getPropertyValue('isolation'); + } + + public set isolation(value: string) { + this.setProperty('isolation', value); + } + + public get insetBlockEnd(): string { + return this.getPropertyValue('inset-block-end'); + } + + public set insetBlockEnd(value: string) { + this.setProperty('inset-block-end', value); + } + + public get insetBlockStart(): string { + return this.getPropertyValue('inset-block-start'); + } + + public set insetBlockStart(value: string) { + this.setProperty('inset-block-start', value); + } + + public get insetInlineEnd(): string { + return this.getPropertyValue('inset-inline-end'); + } + + public set insetInlineEnd(value: string) { + this.setProperty('inset-inline-end', value); + } + + public get insetInlineStart(): string { + return this.getPropertyValue('inset-inline-start'); + } + + public set insetInlineStart(value: string) { + this.setProperty('inset-inline-start', value); + } + + public get justifyContent(): string { + return this.getPropertyValue('justify-content'); + } + + public set justifyContent(value: string) { + this.setProperty('justify-content', value); + } + + public get justifyItems(): string { + return this.getPropertyValue('justify-items'); + } + + public set justifyItems(value: string) { + this.setProperty('justify-items', value); + } + + public get justifySelf(): string { + return this.getPropertyValue('justify-self'); + } + + public set justifySelf(value: string) { + this.setProperty('justify-self', value); + } + + public get left(): string { + return this.getPropertyValue('left'); + } + + public set left(value: string) { + this.setProperty('left', value); + } + + public get letterSpacing(): string { + return this.getPropertyValue('letter-spacing'); + } + + public set letterSpacing(value: string) { + this.setProperty('letter-spacing', value); + } + + public get lightingColor(): string { + return this.getPropertyValue('lighting-color'); + } + + public set lightingColor(value: string) { + this.setProperty('lighting-color', value); + } + + public get lineBreak(): string { + return this.getPropertyValue('line-break'); + } + + public set lineBreak(value: string) { + this.setProperty('line-break', value); + } + + public get lineHeight(): string { + return this.getPropertyValue('line-height'); + } + + public set lineHeight(value: string) { + this.setProperty('line-height', value); + } + + public get listStyle(): string { + return this.getPropertyValue('list-style'); + } + + public set listStyle(value: string) { + this.setProperty('list-style', value); + } + + public get listStyleImage(): string { + return this.getPropertyValue('list-style-image'); + } + + public set listStyleImage(value: string) { + this.setProperty('list-style-image', value); + } + + public get listStylePosition(): string { + return this.getPropertyValue('list-style-position'); + } + + public set listStylePosition(value: string) { + this.setProperty('list-style-position', value); + } + + public get listStyleType(): string { + return this.getPropertyValue('list-style-type'); + } + + public set listStyleType(value: string) { + this.setProperty('list-style-type', value); + } + + public get margin(): string { + return this.getPropertyValue('margin'); + } + + public set margin(value: string) { + this.setProperty('margin', value); + } + + public get marginBlockEnd(): string { + return this.getPropertyValue('margin-block-end'); + } + + public set marginBlockEnd(value: string) { + this.setProperty('margin-block-end', value); + } + + public get marginBlockStart(): string { + return this.getPropertyValue('margin-block-start'); + } + + public set marginBlockStart(value: string) { + this.setProperty('margin-block-start', value); + } + + public get marginBottom(): string { + return this.getPropertyValue('margin-bottom'); + } + + public set marginBottom(value: string) { + this.setProperty('margin-bottom', value); + } + + public get marginInlineEnd(): string { + return this.getPropertyValue('margin-inline-end'); + } + + public set marginInlineEnd(value: string) { + this.setProperty('margin-inline-end', value); + } + + public get marginInlineStart(): string { + return this.getPropertyValue('margin-inline-start'); + } + + public set marginInlineStart(value: string) { + this.setProperty('margin-inline-start', value); + } + + public get marginLeft(): string { + return this.getPropertyValue('margin-left'); + } + + public set marginLeft(value: string) { + this.setProperty('margin-left', value); + } + + public get marginRight(): string { + return this.getPropertyValue('margin-right'); + } + + public set marginRight(value: string) { + this.setProperty('margin-right', value); + } + + public get marginTop(): string { + return this.getPropertyValue('margin-top'); + } + + public set marginTop(value: string) { + this.setProperty('margin-top', value); + } + + public get marker(): string { + return this.getPropertyValue('marker'); + } + + public set marker(value: string) { + this.setProperty('marker', value); + } + + public get markerEnd(): string { + return this.getPropertyValue('marker-end'); + } + + public set markerEnd(value: string) { + this.setProperty('marker-end', value); + } + + public get markerMid(): string { + return this.getPropertyValue('marker-mid'); + } + + public set markerMid(value: string) { + this.setProperty('marker-mid', value); + } + + public get markerStart(): string { + return this.getPropertyValue('marker-start'); + } + + public set markerStart(value: string) { + this.setProperty('marker-start', value); + } + + public get mask(): string { + return this.getPropertyValue('mask'); + } + + public set mask(value: string) { + this.setProperty('mask', value); + } + + public get maskType(): string { + return this.getPropertyValue('mask-type'); + } + + public set maskType(value: string) { + this.setProperty('mask-type', value); + } + + public get maxBlockSize(): string { + return this.getPropertyValue('max-block-size'); + } + + public set maxBlockSize(value: string) { + this.setProperty('max-block-size', value); + } + + public get maxHeight(): string { + return this.getPropertyValue('max-height'); + } + + public set maxHeight(value: string) { + this.setProperty('max-height', value); + } + + public get maxInlineSize(): string { + return this.getPropertyValue('max-inline-size'); + } + + public set maxInlineSize(value: string) { + this.setProperty('max-inline-size', value); + } + + public get maxWidth(): string { + return this.getPropertyValue('max-width'); + } + + public set maxWidth(value: string) { + this.setProperty('max-width', value); + } + + public get maxZoom(): string { + return this.getPropertyValue('max-zoom'); + } + + public set maxZoom(value: string) { + this.setProperty('max-zoom', value); + } + + public get minBlockSize(): string { + return this.getPropertyValue('min-block-size'); + } + + public set minBlockSize(value: string) { + this.setProperty('min-block-size', value); + } + + public get minHeight(): string { + return this.getPropertyValue('min-height'); + } + + public set minHeight(value: string) { + this.setProperty('min-height', value); + } + + public get minInlineSize(): string { + return this.getPropertyValue('min-inline-size'); + } + + public set minInlineSize(value: string) { + this.setProperty('min-inline-size', value); + } + + public get minWidth(): string { + return this.getPropertyValue('min-width'); + } + + public set minWidth(value: string) { + this.setProperty('min-width', value); + } + + public get minZoom(): string { + return this.getPropertyValue('min-zoom'); + } + + public set minZoom(value: string) { + this.setProperty('min-zoom', value); + } + + public get mixBlendMode(): string { + return this.getPropertyValue('mix-blend-mode'); + } + + public set mixBlendMode(value: string) { + this.setProperty('mix-blend-mode', value); + } + + public get objectFit(): string { + return this.getPropertyValue('object-fit'); + } + + public set objectFit(value: string) { + this.setProperty('object-fit', value); + } + + public get objectPosition(): string { + return this.getPropertyValue('object-position'); + } + + public set objectPosition(value: string) { + this.setProperty('object-position', value); + } + + public get offset(): string { + return this.getPropertyValue('offset'); + } + + public set offset(value: string) { + this.setProperty('offset', value); + } + + public get offsetDistance(): string { + return this.getPropertyValue('offset-distance'); + } + + public set offsetDistance(value: string) { + this.setProperty('offset-distance', value); + } + + public get offsetPath(): string { + return this.getPropertyValue('offset-path'); + } + + public set offsetPath(value: string) { + this.setProperty('offset-path', value); + } + + public get offsetRotate(): string { + return this.getPropertyValue('offset-rotate'); + } + + public set offsetRotate(value: string) { + this.setProperty('offset-rotate', value); + } + + public get opacity(): string { + return this.getPropertyValue('opacity'); + } + + public set opacity(value: string) { + this.setProperty('opacity', value); + } + + public get order(): string { + return this.getPropertyValue('order'); + } + + public set order(value: string) { + this.setProperty('order', value); + } + + public get orientation(): string { + return this.getPropertyValue('orientation'); + } + + public set orientation(value: string) { + this.setProperty('orientation', value); + } + + public get orphans(): string { + return this.getPropertyValue('orphans'); + } + + public set orphans(value: string) { + this.setProperty('orphans', value); + } + + public get outline(): string { + return this.getPropertyValue('outline'); + } + + public set outline(value: string) { + this.setProperty('outline', value); + } + + public get outlineColor(): string { + return this.getPropertyValue('outline-color'); + } + + public set outlineColor(value: string) { + this.setProperty('outline-color', value); + } + + public get outlineOffset(): string { + return this.getPropertyValue('outline-offset'); + } + + public set outlineOffset(value: string) { + this.setProperty('outline-offset', value); + } + + public get outlineStyle(): string { + return this.getPropertyValue('outline-style'); + } + + public set outlineStyle(value: string) { + this.setProperty('outline-style', value); + } + + public get outlineWidth(): string { + return this.getPropertyValue('outline-width'); + } + + public set outlineWidth(value: string) { + this.setProperty('outline-width', value); + } + + public get overflow(): string { + return this.getPropertyValue('overflow'); + } + + public set overflow(value: string) { + this.setProperty('overflow', value); + } + + public get overflowAnchor(): string { + return this.getPropertyValue('overflow-anchor'); + } + + public set overflowAnchor(value: string) { + this.setProperty('overflow-anchor', value); + } + + public get overflowWrap(): string { + return this.getPropertyValue('overflow-wrap'); + } + + public set overflowWrap(value: string) { + this.setProperty('overflow-wrap', value); + } + + public get overflowX(): string { + return this.getPropertyValue('overflow-x'); + } + + public set overflowX(value: string) { + this.setProperty('overflow-x', value); + } + + public get overflowY(): string { + return this.getPropertyValue('overflow-y'); + } + + public set overflowY(value: string) { + this.setProperty('overflow-y', value); + } + + public get overscrollBehavior(): string { + return this.getPropertyValue('overscroll-behavior'); + } + + public set overscrollBehavior(value: string) { + this.setProperty('overscroll-behavior', value); + } + + public get overscrollBehaviorBlock(): string { + return this.getPropertyValue('overscroll-behavior-block'); + } + + public set overscrollBehaviorBlock(value: string) { + this.setProperty('overscroll-behavior-block', value); + } + + public get overscrollBehaviorInline(): string { + return this.getPropertyValue('overscroll-behavior-inline'); + } + + public set overscrollBehaviorInline(value: string) { + this.setProperty('overscroll-behavior-inline', value); + } + + public get overscrollBehaviorX(): string { + return this.getPropertyValue('overscroll-behavior-x'); + } + + public set overscrollBehaviorX(value: string) { + this.setProperty('overscroll-behavior-x', value); + } + + public get overscrollBehaviorY(): string { + return this.getPropertyValue('overscroll-behavior-y'); + } + + public set overscrollBehaviorY(value: string) { + this.setProperty('overscroll-behavior-y', value); + } + + public get overflowClipMargin(): string { + return this.getPropertyValue('overflow-clip-margin'); + } + + public set overflowClipMargin(value: string) { + this.setProperty('overflow-clip-margin', value); + } + + public get padding(): string { + return this.getPropertyValue('padding'); + } + + public set padding(value: string) { + this.setProperty('padding', value); + } + + public get paddingBlockEnd(): string { + return this.getPropertyValue('padding-block-end'); + } + + public set paddingBlockEnd(value: string) { + this.setProperty('padding-block-end', value); + } + + public get paddingBlockStart(): string { + return this.getPropertyValue('padding-block-start'); + } + + public set paddingBlockStart(value: string) { + this.setProperty('padding-block-start', value); + } + + public get paddingBottom(): string { + return this.getPropertyValue('padding-bottom'); + } + + public set paddingBottom(value: string) { + this.setProperty('padding-bottom', value); + } + + public get paddingInlineEnd(): string { + return this.getPropertyValue('padding-inline-end'); + } + + public set paddingInlineEnd(value: string) { + this.setProperty('padding-inline-end', value); + } + + public get paddingInlineStart(): string { + return this.getPropertyValue('padding-inline-start'); + } + + public set paddingInlineStart(value: string) { + this.setProperty('padding-inline-start', value); + } + + public get paddingLeft(): string { + return this.getPropertyValue('padding-left'); + } + + public set paddingLeft(value: string) { + this.setProperty('padding-left', value); + } + + public get paddingRight(): string { + return this.getPropertyValue('padding-right'); + } + + public set paddingRight(value: string) { + this.setProperty('padding-right', value); + } + + public get paddingTop(): string { + return this.getPropertyValue('padding-top'); + } + + public set paddingTop(value: string) { + this.setProperty('padding-top', value); + } + + public get page(): string { + return this.getPropertyValue('page'); + } + + public set page(value: string) { + this.setProperty('page', value); + } + + public get pageBreakAfter(): string { + return this.getPropertyValue('page-break-after'); + } + + public set pageBreakAfter(value: string) { + this.setProperty('page-break-after', value); + } + + public get pageBreakBefore(): string { + return this.getPropertyValue('page-break-before'); + } + + public set pageBreakBefore(value: string) { + this.setProperty('page-break-before', value); + } + + public get pageBreakInside(): string { + return this.getPropertyValue('page-break-inside'); + } + + public set pageBreakInside(value: string) { + this.setProperty('page-break-inside', value); + } + + public get pageOrientation(): string { + return this.getPropertyValue('page-orientation'); + } + + public set pageOrientation(value: string) { + this.setProperty('page-orientation', value); + } + + public get paintOrder(): string { + return this.getPropertyValue('paint-order'); + } + + public set paintOrder(value: string) { + this.setProperty('paint-order', value); + } + + public get perspective(): string { + return this.getPropertyValue('perspective'); + } + + public set perspective(value: string) { + this.setProperty('perspective', value); + } + + public get perspectiveOrigin(): string { + return this.getPropertyValue('perspective-origin'); + } + + public set perspectiveOrigin(value: string) { + this.setProperty('perspective-origin', value); + } + + public get placeContent(): string { + return this.getPropertyValue('place-content'); + } + + public set placeContent(value: string) { + this.setProperty('place-content', value); + } + + public get placeItems(): string { + return this.getPropertyValue('place-items'); + } + + public set placeItems(value: string) { + this.setProperty('place-items', value); + } + + public get placeSelf(): string { + return this.getPropertyValue('place-self'); + } + + public set placeSelf(value: string) { + this.setProperty('place-self', value); + } + + public get pointerEvents(): string { + return this.getPropertyValue('pointer-events'); + } + + public set pointerEvents(value: string) { + this.setProperty('pointer-events', value); + } + + public get position(): string { + return this.getPropertyValue('position'); + } + + public set position(value: string) { + this.setProperty('position', value); + } + + public get quotes(): string { + return this.getPropertyValue('quotes'); + } + + public set quotes(value: string) { + this.setProperty('quotes', value); + } + + public get r(): string { + return this.getPropertyValue('r'); + } + + public set r(value: string) { + this.setProperty('r', value); + } + + public get resize(): string { + return this.getPropertyValue('resize'); + } + + public set resize(value: string) { + this.setProperty('resize', value); + } + + public get right(): string { + return this.getPropertyValue('right'); + } + + public set right(value: string) { + this.setProperty('right', value); + } + + public get rowGap(): string { + return this.getPropertyValue('row-gap'); + } + + public set rowGap(value: string) { + this.setProperty('row-gap', value); + } + + public get rubyPosition(): string { + return this.getPropertyValue('ruby-position'); + } + + public set rubyPosition(value: string) { + this.setProperty('ruby-position', value); + } + + public get rx(): string { + return this.getPropertyValue('rx'); + } + + public set rx(value: string) { + this.setProperty('rx', value); + } + + public get ry(): string { + return this.getPropertyValue('ry'); + } + + public set ry(value: string) { + this.setProperty('ry', value); + } + + public get scrollBehavior(): string { + return this.getPropertyValue('scroll-behavior'); + } + + public set scrollBehavior(value: string) { + this.setProperty('scroll-behavior', value); + } + + public get scrollMargin(): string { + return this.getPropertyValue('scroll-margin'); + } + + public set scrollMargin(value: string) { + this.setProperty('scroll-margin', value); + } + + public get scrollMarginBlock(): string { + return this.getPropertyValue('scroll-margin-block'); + } + + public set scrollMarginBlock(value: string) { + this.setProperty('scroll-margin-block', value); + } + + public get scrollMarginBlockEnd(): string { + return this.getPropertyValue('scroll-margin-block-end'); + } + + public set scrollMarginBlockEnd(value: string) { + this.setProperty('scroll-margin-block-end', value); + } + + public get scrollMarginBlockStart(): string { + return this.getPropertyValue('scroll-margin-block-start'); + } + + public set scrollMarginBlockStart(value: string) { + this.setProperty('scroll-margin-block-start', value); + } + + public get scrollMarginBottom(): string { + return this.getPropertyValue('scroll-margin-bottom'); + } + + public set scrollMarginBottom(value: string) { + this.setProperty('scroll-margin-bottom', value); + } + + public get scrollMarginInline(): string { + return this.getPropertyValue('scroll-margin-inline'); + } + + public set scrollMarginInline(value: string) { + this.setProperty('scroll-margin-inline', value); + } + + public get scrollMarginInlineEnd(): string { + return this.getPropertyValue('scroll-margin-inline-end'); + } + + public set scrollMarginInlineEnd(value: string) { + this.setProperty('scroll-margin-inline-end', value); + } + + public get scrollMarginInlineStart(): string { + return this.getPropertyValue('scroll-margin-inline-start'); + } + + public set scrollMarginInlineStart(value: string) { + this.setProperty('scroll-margin-inline-start', value); + } + + public get scrollMarginLeft(): string { + return this.getPropertyValue('scroll-margin-left'); + } + + public set scrollMarginLeft(value: string) { + this.setProperty('scroll-margin-left', value); + } + + public get scrollMarginRight(): string { + return this.getPropertyValue('scroll-margin-right'); + } + + public set scrollMarginRight(value: string) { + this.setProperty('scroll-margin-right', value); + } + + public get scrollMarginTop(): string { + return this.getPropertyValue('scroll-margin-top'); + } + + public set scrollMarginTop(value: string) { + this.setProperty('scroll-margin-top', value); + } + + public get scrollPadding(): string { + return this.getPropertyValue('scroll-padding'); + } + + public set scrollPadding(value: string) { + this.setProperty('scroll-padding', value); + } + + public get scrollPaddingBlock(): string { + return this.getPropertyValue('scroll-padding-block'); + } + + public set scrollPaddingBlock(value: string) { + this.setProperty('scroll-padding-block', value); + } + + public get scrollPaddingBlockEnd(): string { + return this.getPropertyValue('scroll-padding-block-end'); + } + + public set scrollPaddingBlockEnd(value: string) { + this.setProperty('scroll-padding-block-end', value); + } + + public get scrollPaddingBlockStart(): string { + return this.getPropertyValue('scroll-padding-block-start'); + } + + public set scrollPaddingBlockStart(value: string) { + this.setProperty('scroll-padding-block-start', value); + } + + public get scrollPaddingBottom(): string { + return this.getPropertyValue('scroll-padding-bottom'); + } + + public set scrollPaddingBottom(value: string) { + this.setProperty('scroll-padding-bottom', value); + } + + public get scrollPaddingInline(): string { + return this.getPropertyValue('scroll-padding-inline'); + } + + public set scrollPaddingInline(value: string) { + this.setProperty('scroll-padding-inline', value); + } + + public get scrollPaddingInlineEnd(): string { + return this.getPropertyValue('scroll-padding-inline-end'); + } + + public set scrollPaddingInlineEnd(value: string) { + this.setProperty('scroll-padding-inline-end', value); + } + + public get scrollPaddingInlineStart(): string { + return this.getPropertyValue('scroll-padding-inline-start'); + } + + public set scrollPaddingInlineStart(value: string) { + this.setProperty('scroll-padding-inline-start', value); + } + + public get scrollPaddingLeft(): string { + return this.getPropertyValue('scroll-padding-left'); + } + + public set scrollPaddingLeft(value: string) { + this.setProperty('scroll-padding-left', value); + } + + public get scrollPaddingRight(): string { + return this.getPropertyValue('scroll-padding-right'); + } + + public set scrollPaddingRight(value: string) { + this.setProperty('scroll-padding-right', value); + } + + public get scrollPaddingTop(): string { + return this.getPropertyValue('scroll-padding-top'); + } + + public set scrollPaddingTop(value: string) { + this.setProperty('scroll-padding-top', value); + } + + public get scrollSnapAlign(): string { + return this.getPropertyValue('scroll-snap-align'); + } + + public set scrollSnapAlign(value: string) { + this.setProperty('scroll-snap-align', value); + } + + public get scrollSnapStop(): string { + return this.getPropertyValue('scroll-snap-stop'); + } + + public set scrollSnapStop(value: string) { + this.setProperty('scroll-snap-stop', value); + } + + public get scrollSnapType(): string { + return this.getPropertyValue('scroll-snap-type'); + } + + public set scrollSnapType(value: string) { + this.setProperty('scroll-snap-type', value); + } + + public get shapeImageThreshold(): string { + return this.getPropertyValue('shape-image-threshold'); + } + + public set shapeImageThreshold(value: string) { + this.setProperty('shape-image-threshold', value); + } + + public get shapeMargin(): string { + return this.getPropertyValue('shape-margin'); + } + + public set shapeMargin(value: string) { + this.setProperty('shape-margin', value); + } + + public get shapeOutside(): string { + return this.getPropertyValue('shape-outside'); + } + + public set shapeOutside(value: string) { + this.setProperty('shape-outside', value); + } + + public get shapeRendering(): string { + return this.getPropertyValue('shape-rendering'); + } + + public set shapeRendering(value: string) { + this.setProperty('shape-rendering', value); + } + + public get size(): string { + return this.getPropertyValue('size'); + } + + public set size(value: string) { + this.setProperty('size', value); + } + + public get speak(): string { + return this.getPropertyValue('speak'); + } + + public set speak(value: string) { + this.setProperty('speak', value); + } + + public get src(): string { + return this.getPropertyValue('src'); + } + + public set src(value: string) { + this.setProperty('src', value); + } + + public get stopColor(): string { + return this.getPropertyValue('stop-color'); + } + + public set stopColor(value: string) { + this.setProperty('stop-color', value); + } + + public get stopOpacity(): string { + return this.getPropertyValue('stop-opacity'); + } + + public set stopOpacity(value: string) { + this.setProperty('stop-opacity', value); + } + + public get stroke(): string { + return this.getPropertyValue('stroke'); + } + + public set stroke(value: string) { + this.setProperty('stroke', value); + } + + public get strokeDasharray(): string { + return this.getPropertyValue('stroke-dasharray'); + } + + public set strokeDasharray(value: string) { + this.setProperty('stroke-dasharray', value); + } + + public get strokeDashoffset(): string { + return this.getPropertyValue('stroke-dashoffset'); + } + + public set strokeDashoffset(value: string) { + this.setProperty('stroke-dashoffset', value); + } + + public get strokeLinecap(): string { + return this.getPropertyValue('stroke-linecap'); + } + + public set strokeLinecap(value: string) { + this.setProperty('stroke-linecap', value); + } + + public get strokeLinejoin(): string { + return this.getPropertyValue('stroke-linejoin'); + } + + public set strokeLinejoin(value: string) { + this.setProperty('stroke-linejoin', value); + } + + public get strokeMiterlimit(): string { + return this.getPropertyValue('stroke-miterlimit'); + } + + public set strokeMiterlimit(value: string) { + this.setProperty('stroke-miterlimit', value); + } + + public get strokeOpacity(): string { + return this.getPropertyValue('stroke-opacity'); + } + + public set strokeOpacity(value: string) { + this.setProperty('stroke-opacity', value); + } + + public get strokeWidth(): string { + return this.getPropertyValue('stroke-width'); + } + + public set strokeWidth(value: string) { + this.setProperty('stroke-width', value); + } + + public get syntax(): string { + return this.getPropertyValue('syntax'); + } + + public set syntax(value: string) { + this.setProperty('syntax', value); + } + + public get scrollbarGutter(): string { + return this.getPropertyValue('scrollbar-gutter'); + } + + public set scrollbarGutter(value: string) { + this.setProperty('scrollbar-gutter', value); + } + + public get tabSize(): string { + return this.getPropertyValue('tab-size'); + } + + public set tabSize(value: string) { + this.setProperty('tab-size', value); + } + + public get tableLayout(): string { + return this.getPropertyValue('table-layout'); + } + + public set tableLayout(value: string) { + this.setProperty('table-layout', value); + } + + public get textAlign(): string { + return this.getPropertyValue('text-align'); + } + + public set textAlign(value: string) { + this.setProperty('text-align', value); + } + + public get textAlignLast(): string { + return this.getPropertyValue('text-align-last'); + } + + public set textAlignLast(value: string) { + this.setProperty('text-align-last', value); + } + + public get textAnchor(): string { + return this.getPropertyValue('text-anchor'); + } + + public set textAnchor(value: string) { + this.setProperty('text-anchor', value); + } + + public get textCombineUpright(): string { + return this.getPropertyValue('text-combine-upright'); + } + + public set textCombineUpright(value: string) { + this.setProperty('text-combine-upright', value); + } + + public get textDecoration(): string { + return this.getPropertyValue('text-decoration'); + } + + public set textDecoration(value: string) { + this.setProperty('text-decoration', value); + } + + public get textDecorationColor(): string { + return this.getPropertyValue('text-decoration-color'); + } + + public set textDecorationColor(value: string) { + this.setProperty('text-decoration-color', value); + } + + public get textDecorationLine(): string { + return this.getPropertyValue('text-decoration-line'); + } + + public set textDecorationLine(value: string) { + this.setProperty('text-decoration-line', value); + } + + public get textDecorationSkipInk(): string { + return this.getPropertyValue('text-decoration-skip-ink'); + } + + public set textDecorationSkipInk(value: string) { + this.setProperty('text-decoration-skip-ink', value); + } + + public get textDecorationStyle(): string { + return this.getPropertyValue('text-decoration-style'); + } + + public set textDecorationStyle(value: string) { + this.setProperty('text-decoration-style', value); + } + + public get textIndent(): string { + return this.getPropertyValue('text-indent'); + } + + public set textIndent(value: string) { + this.setProperty('text-indent', value); + } + + public get textOrientation(): string { + return this.getPropertyValue('text-orientation'); + } + + public set textOrientation(value: string) { + this.setProperty('text-orientation', value); + } + + public get textOverflow(): string { + return this.getPropertyValue('text-overflow'); + } + + public set textOverflow(value: string) { + this.setProperty('text-overflow', value); + } + + public get textRendering(): string { + return this.getPropertyValue('text-rendering'); + } + + public set textRendering(value: string) { + this.setProperty('text-rendering', value); + } + + public get textShadow(): string { + return this.getPropertyValue('text-shadow'); + } + + public set textShadow(value: string) { + this.setProperty('text-shadow', value); + } + + public get textSizeAdjust(): string { + return this.getPropertyValue('text-size-adjust'); + } + + public set textSizeAdjust(value: string) { + this.setProperty('text-size-adjust', value); + } + + public get textTransform(): string { + return this.getPropertyValue('text-transform'); + } + + public set textTransform(value: string) { + this.setProperty('text-transform', value); + } + + public get textUnderlinePosition(): string { + return this.getPropertyValue('text-underline-position'); + } + + public set textUnderlinePosition(value: string) { + this.setProperty('text-underline-position', value); + } + + public get top(): string { + return this.getPropertyValue('top'); + } + + public set top(value: string) { + this.setProperty('top', value); + } + + public get touchAction(): string { + return this.getPropertyValue('touch-action'); + } + + public set touchAction(value: string) { + this.setProperty('touch-action', value); + } + + public get transform(): string { + return this.getPropertyValue('transform'); + } + + public set transform(value: string) { + this.setProperty('transform', value); + } + + public get transformBox(): string { + return this.getPropertyValue('transform-box'); + } + + public set transformBox(value: string) { + this.setProperty('transform-box', value); + } + + public get transformOrigin(): string { + return this.getPropertyValue('transform-origin'); + } + + public set transformOrigin(value: string) { + this.setProperty('transform-origin', value); + } + + public get transformStyle(): string { + return this.getPropertyValue('transform-style'); + } + + public set transformStyle(value: string) { + this.setProperty('transform-style', value); + } + + public get transition(): string { + return this.getPropertyValue('transition'); + } + + public set transition(value: string) { + this.setProperty('transition', value); + } + + public get transitionDelay(): string { + return this.getPropertyValue('transition-delay'); + } + + public set transitionDelay(value: string) { + this.setProperty('transition-delay', value); + } + + public get transitionDuration(): string { + return this.getPropertyValue('transition-duration'); + } + + public set transitionDuration(value: string) { + this.setProperty('transition-duration', value); + } + + public get transitionProperty(): string { + return this.getPropertyValue('transition-property'); + } + + public set transitionProperty(value: string) { + this.setProperty('transition-property', value); + } + + public get transitionTimingFunction(): string { + return this.getPropertyValue('transition-timing-function'); + } + + public set transitionTimingFunction(value: string) { + this.setProperty('transition-timing-function', value); + } + + public get textEmphasisColor(): string { + return this.getPropertyValue('text-emphasis-color'); + } + + public set textEmphasisColor(value: string) { + this.setProperty('text-emphasis-color', value); + } + + public get textEmphasisPosition(): string { + return this.getPropertyValue('text-emphasis-position'); + } + + public set textEmphasisPosition(value: string) { + this.setProperty('text-emphasis-position', value); + } + + public get textEmphasisStyle(): string { + return this.getPropertyValue('text-emphasis-style'); + } + + public set textEmphasisStyle(value: string) { + this.setProperty('text-emphasis-style', value); + } + + public get unicodeBidi(): string { + return this.getPropertyValue('unicode-bidi'); + } + + public set unicodeBidi(value: string) { + this.setProperty('unicode-bidi', value); + } + + public get unicodeRange(): string { + return this.getPropertyValue('unicode-range'); + } + + public set unicodeRange(value: string) { + this.setProperty('unicode-range', value); + } + + public get userSelect(): string { + return this.getPropertyValue('user-select'); + } + + public set userSelect(value: string) { + this.setProperty('user-select', value); + } + + public get userZoom(): string { + return this.getPropertyValue('user-zoom'); + } + + public set userZoom(value: string) { + this.setProperty('user-zoom', value); + } + + public get vectorEffect(): string { + return this.getPropertyValue('vector-effect'); + } + + public set vectorEffect(value: string) { + this.setProperty('vector-effect', value); + } + + public get verticalAlign(): string { + return this.getPropertyValue('vertical-align'); + } + + public set verticalAlign(value: string) { + this.setProperty('vertical-align', value); + } + + public get visibility(): string { + return this.getPropertyValue('visibility'); + } + + public set visibility(value: string) { + this.setProperty('visibility', value); + } + + public get whiteSpace(): string { + return this.getPropertyValue('white-space'); + } + + public set whiteSpace(value: string) { + this.setProperty('white-space', value); + } + + public get widows(): string { + return this.getPropertyValue('widows'); + } + + public set widows(value: string) { + this.setProperty('widows', value); + } + + public get width(): string { + return this.getPropertyValue('width'); + } + + public set width(value: string) { + this.setProperty('width', value); + } + + public get willChange(): string { + return this.getPropertyValue('will-change'); + } + + public set willChange(value: string) { + this.setProperty('will-change', value); + } + + public get wordBreak(): string { + return this.getPropertyValue('word-break'); + } + + public set wordBreak(value: string) { + this.setProperty('word-break', value); + } + + public get wordSpacing(): string { + return this.getPropertyValue('word-spacing'); + } + + public set wordSpacing(value: string) { + this.setProperty('word-spacing', value); + } + + public get wordWrap(): string { + return this.getPropertyValue('word-wrap'); + } + + public set wordWrap(value: string) { + this.setProperty('word-wrap', value); + } + + public get writingMode(): string { + return this.getPropertyValue('writing-mode'); + } + + public set writingMode(value: string) { + this.setProperty('writing-mode', value); + } + + public get x(): string { + return this.getPropertyValue('x'); + } + + public set x(value: string) { + this.setProperty('x', value); + } + + public get y(): string { + return this.getPropertyValue('y'); + } + + public set y(value: string) { + this.setProperty('y', value); + } + + public get zIndex(): string { + return this.getPropertyValue('z-index'); + } + + public set zIndex(value: string) { + this.setProperty('z-index', value); + } + + public get zoom(): string { + return this.getPropertyValue('zoom'); + } + + public set zoom(value: string) { + this.setProperty('zoom', value); + } + + public get containerType(): string { + return this.getPropertyValue('container-type'); + } + + public set containerType(value: string) { + this.setProperty('container-type', value); + } + + public get containerName(): string { + return this.getPropertyValue('container-name'); + } + + public set containerName(value: string) { + this.setProperty('container-name', value); + } +} diff --git a/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationCSSParser.ts b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationCSSParser.ts new file mode 100644 index 000000000..f62282808 --- /dev/null +++ b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationCSSParser.ts @@ -0,0 +1,35 @@ +/** + * CSS parser. + */ +export default class CSSStyleDeclarationCSSParser { + /** + * Class construtor. + * + * @param cssText CSS string. + * @param callback Callback. + */ + public static parse( + cssText: string, + callback: (name: string, value: string, important: boolean) => void + ): void { + const parts = cssText.split(';'); + + for (const part of parts) { + if (part) { + const [name, value]: string[] = part.trim().split(':'); + if (value) { + const trimmedName = name.trim(); + const trimmedValue = value.trim(); + if (trimmedName && trimmedValue) { + const important = trimmedValue.endsWith(' !important'); + const valueWithoutImportant = trimmedValue.replace(' !important', ''); + + if (valueWithoutImportant) { + callback(trimmedName, valueWithoutImportant, important); + } + } + } + } + } + } +} diff --git a/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationElementDefaultCSS.ts b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationElementDefaultCSS.ts new file mode 100644 index 000000000..b745e01ff --- /dev/null +++ b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationElementDefaultCSS.ts @@ -0,0 +1,130 @@ +export default { + default: 'display: inline;', + A: '', + ABBR: '', + ADDRESS: 'display: block;', + AREA: '', + ARTICLE: 'display: block;', + ASIDE: 'display: block;', + AUDIO: 'display: none;', + B: '', + BASE: 'display: none;', + BDI: '', + BDO: '', + BLOCKQUAOTE: '', + BODY: 'display: block;', + TEMPLATE: 'display: none;', + FORM: 'display: block;', + INPUT: 'display: inline-block;', + TEXTAREA: 'display: inline-block;', + SCRIPT: 'display: none;', + IMG: '', + LINK: 'display: none;', + STYLE: 'display: none;', + LABEL: '', + SLOT: 'display: contents;', + SVG: '', + CIRCLE: '', + ELLIPSE: '', + LINE: '', + PATH: '', + POLYGON: '', + POLYLINE: '', + RECT: '', + STOP: '', + USE: '', + META: 'display: none;', + BLOCKQUOTE: 'display: block;', + BR: '', + BUTTON: 'display: inline-block;', + CANVAS: '', + CAPTION: 'display: table-caption;', + CITE: '', + CODE: '', + COL: 'display: table-column;', + COLGROUP: 'display: table-column-group;', + DATA: '', + DATALIST: 'display: none;', + DD: 'display: block;', + DEL: '', + DETAILS: 'display: block;', + DFN: '', + DIALOG: 'display: none;', + DIV: 'display: block;', + DL: 'display: block;', + DT: 'display: block;', + EM: '', + EMBED: '', + FIELDSET: 'display: block;', + FIGCAPTION: 'display: block;', + FIGURE: 'display: block;', + FOOTER: 'display: block;', + H1: 'display: block;', + H2: 'display: block;', + H3: 'display: block;', + H4: 'display: block;', + H5: 'display: block;', + H6: 'display: block;', + HEAD: 'display: none;', + HEADER: 'display: block;', + HGROUP: 'display: block;', + HR: 'display: block;', + HTML: 'display: block;direction: ltr;', + I: '', + IFRAME: '', + INS: '', + KBD: '', + LEGEND: 'display: block;', + LI: 'display: list-item;', + MAIN: 'display: block;', + MAP: '', + MARK: '', + MATH: '', + MENU: 'display: block;', + MENUITEM: '', + METER: 'display: inline-block;', + NAV: 'display: block;', + NOSCRIPT: '', + OBJECT: '', + OL: 'display: block;', + OPTGROUP: 'display: block;', + OPTION: 'display: block;', + OUTPUT: 'unicode-bidi: isolate;', + P: 'display: block;', + PARAM: 'display: none;', + PICTURE: '', + PRE: 'display: block;', + PROGRESS: 'display: inline-block;', + Q: '', + RB: '', + RP: 'display: none;', + RT: '', + RTC: '', + RUBY: '', + S: '', + SAMP: '', + SECTION: 'display: block;', + SELECT: 'display: inline-block;', + SMALL: '', + SOURCE: '', + SPAN: '', + STRONG: '', + SUB: '', + SUMMARY: 'display: block;', + SUP: '', + TABLE: 'display: table;', + TBODY: 'display: table-row-group;', + TD: 'display: table-cell;', + TFOOT: 'display: table-footer-group;', + TH: 'display: table-cell;', + THEAD: 'display: table-header-group;', + TIME: '', + TITLE: 'display: none;', + TR: 'display: table-row;', + TRACK: '', + U: '', + UL: 'display: block;', + VAR: '', + VIDEO: '', + WBR: '' +}; diff --git a/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationElementInheritedProperties.ts b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationElementInheritedProperties.ts new file mode 100644 index 000000000..5a587a070 --- /dev/null +++ b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationElementInheritedProperties.ts @@ -0,0 +1,39 @@ +export default { + 'border-collapse': true, + 'border-spacing': true, + 'caption-side': true, + color: true, + cursor: true, + direction: true, + 'empty-cells': true, + 'font-family': true, + 'font-size': true, + 'font-style': true, + 'font-variant': true, + 'font-weight': true, + 'font-size-adjust': true, + 'font-stretch': true, + font: true, + 'letter-spacing': true, + 'line-height': true, + 'list-style-image': true, + 'list-style-position': true, + 'list-style-type': true, + 'list-style': true, + orphans: true, + quotes: true, + 'tab-size': true, + 'text-align': true, + 'text-align-last': true, + 'text-decoration-color': true, + 'text-indent': true, + 'text-justify': true, + 'text-shadow': true, + 'text-transform': true, + visibility: true, + 'white-space': true, + widows: true, + 'word-break': true, + 'word-spacing': true, + 'word-wrap': true +}; diff --git a/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationElementStyle.ts b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationElementStyle.ts new file mode 100644 index 000000000..686ed4659 --- /dev/null +++ b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationElementStyle.ts @@ -0,0 +1,282 @@ +import IShadowRoot from '../../../nodes/shadow-root/IShadowRoot'; +import IElement from '../../../nodes/element/IElement'; +import IDocument from '../../../nodes/document/IDocument'; +import IHTMLStyleElement from '../../../nodes/html-style-element/IHTMLStyleElement'; +import INodeList from '../../../nodes/node/INodeList'; +import CSSStyleDeclarationPropertyManager from './CSSStyleDeclarationPropertyManager'; +import NodeTypeEnum from '../../../nodes/node/NodeTypeEnum'; +import CSSRuleTypeEnum from '../../CSSRuleTypeEnum'; +import CSSMediaRule from '../../rules/CSSMediaRule'; +import CSSRule from '../../CSSRule'; +import CSSStyleRule from '../../rules/CSSStyleRule'; +import CSSStyleDeclarationElementDefaultCSS from './CSSStyleDeclarationElementDefaultCSS'; +import CSSStyleDeclarationElementInheritedProperties from './CSSStyleDeclarationElementInheritedProperties'; +import CSSStyleDeclarationCSSParser from './CSSStyleDeclarationCSSParser'; + +const CSS_VARIABLE_REGEXP = /var\( *(--[^) ]+)\)/g; + +/** + * CSS Style Declaration utility + */ +export default class CSSStyleDeclarationElementStyle { + private cache: { [k: string]: CSSStyleDeclarationPropertyManager } = {}; + private element: IElement; + private computed: boolean; + + /** + * Constructor. + * + * @param element Element. + * @param [computed] Computed. + */ + constructor(element: IElement, computed = false) { + this.element = element; + this.computed = computed; + } + + /** + * Returns element style properties. + * + * @returns Element style properties. + */ + public getElementStyle(): CSSStyleDeclarationPropertyManager { + if (this.computed) { + return this.getComputedElementStyle(); + } + + const cssText = this.element['_attributes']['style']?.value; + + if (cssText) { + if (this.cache[cssText]) { + return this.cache[cssText]; + } + this.cache[cssText] = new CSSStyleDeclarationPropertyManager({ cssText }); + return this.cache[cssText]; + } + + return new CSSStyleDeclarationPropertyManager(); + } + + /** + * Returns style sheets. + * + * @param element Element. + * @returns Style sheets. + */ + private getComputedElementStyle(): CSSStyleDeclarationPropertyManager { + const documentElements: Array<{ element: IElement; cssText: string }> = []; + const parentElements: Array<{ element: IElement; cssText: string }> = []; + let styleAndElement = { + element: this.element, + cssText: '' + }; + let shadowRootElements: Array<{ element: IElement; cssText: string }> = []; + + if (!this.element.isConnected) { + return new CSSStyleDeclarationPropertyManager(); + } + + // Walks through all parent elements and stores them in an array with element and matching CSS text. + while (styleAndElement.element) { + if (styleAndElement.element.nodeType === NodeTypeEnum.elementNode) { + const rootNode = styleAndElement.element.getRootNode(); + if (rootNode.nodeType === NodeTypeEnum.documentNode) { + documentElements.unshift(<{ element: IElement; cssText: string }>styleAndElement); + } else { + shadowRootElements.unshift(<{ element: IElement; cssText: string }>styleAndElement); + } + parentElements.unshift(<{ element: IElement; cssText: string }>styleAndElement); + } + + if (styleAndElement.element === this.element.ownerDocument) { + const styleSheets = >( + this.element.ownerDocument.querySelectorAll('style,link[rel="stylesheet"]') + ); + + for (const styleSheet of styleSheets) { + const sheet = styleSheet.sheet; + if (sheet) { + this.parseCSSRules({ + elements: documentElements, + cssRules: sheet.cssRules + }); + } + } + + styleAndElement = { element: null, cssText: '' }; + } else if ((styleAndElement.element).host) { + const styleSheets = >( + (styleAndElement.element).querySelectorAll('style,link[rel="stylesheet"]') + ); + + styleAndElement = { + element: (styleAndElement.element).host, + cssText: '' + }; + + for (const styleSheet of styleSheets) { + const sheet = styleSheet.sheet; + if (sheet) { + this.parseCSSRules({ + elements: shadowRootElements, + cssRules: sheet.cssRules, + hostElement: <{ element: IElement; cssText: string }>styleAndElement + }); + } + } + shadowRootElements = []; + } else { + styleAndElement = { element: styleAndElement.element.parentNode, cssText: '' }; + } + } + + // Concatenates all parent element CSS to one string. + const targetElement = parentElements[parentElements.length - 1]; + let inheritedCSSText = CSSStyleDeclarationElementDefaultCSS.default; + + for (const parentElement of parentElements) { + if (parentElement !== targetElement) { + inheritedCSSText += + (CSSStyleDeclarationElementDefaultCSS[parentElement.element.tagName] || '') + + parentElement.cssText + + (parentElement.element['_attributes']['style']?.value || ''); + } + } + + const cssVariables: { [k: string]: string } = {}; + const properties = {}; + const targetCSSText = + (CSSStyleDeclarationElementDefaultCSS[targetElement.element.tagName] || '') + + targetElement.cssText + + (targetElement.element['_attributes']['style']?.value || ''); + const combinedCSSText = inheritedCSSText + targetCSSText; + + if (this.cache[combinedCSSText]) { + return this.cache[combinedCSSText]; + } + + // Parses the parent element CSS and stores CSS variables and inherited properties. + CSSStyleDeclarationCSSParser.parse(inheritedCSSText, (name, value, important) => { + if (name.startsWith('--')) { + const cssValue = this.getCSSValue(value, cssVariables); + if (cssValue) { + cssVariables[name] = cssValue; + } + return; + } + + if (CSSStyleDeclarationElementInheritedProperties[name]) { + const cssValue = this.getCSSValue(value, cssVariables); + if (cssValue && (!properties[name]?.important || important)) { + properties[name] = { + value: cssValue, + important + }; + } + } + }); + + // Parses the target element CSS. + CSSStyleDeclarationCSSParser.parse(targetCSSText, (name, value, important) => { + if (name.startsWith('--')) { + const cssValue = this.getCSSValue(value, cssVariables); + if (cssValue && (!properties[name]?.important || important)) { + cssVariables[name] = cssValue; + properties[name] = { + value, + important + }; + } + } else { + const cssValue = this.getCSSValue(value, cssVariables); + if (cssValue && (!properties[name]?.important || important)) { + properties[name] = { + value: cssValue, + important + }; + } + } + }); + + const propertyManager = new CSSStyleDeclarationPropertyManager(); + + for (const name of Object.keys(properties)) { + propertyManager.set(name, properties[name].value, properties[name].important); + } + + this.cache[combinedCSSText] = propertyManager; + + return propertyManager; + } + + /** + * Applies CSS text to elements. + * + * @param options Options. + * @param options.elements Elements. + * @param options.cssRules CSS rules. + * @param [options.hostElement] Host element. + * @param [options.hostElement.element] Element. + * @param [options.hostElement.cssText] CSS text. + */ + private parseCSSRules(options: { + cssRules: CSSRule[]; + elements: Array<{ element: IElement; cssText: string }>; + hostElement?: { element: IElement; cssText: string }; + }): void { + if (!options.elements.length) { + return; + } + + const defaultView = options.elements[0].element.ownerDocument.defaultView; + + for (const rule of options.cssRules) { + if (rule.type === CSSRuleTypeEnum.styleRule) { + const selectorText: string = (rule).selectorText; + if (selectorText) { + if (selectorText.startsWith(':host')) { + if (options.hostElement) { + options.hostElement.cssText += (rule)._cssText; + } + } else { + for (const element of options.elements) { + if (element.element.matches(selectorText)) { + element.cssText += (rule)._cssText; + } + } + } + } + } else if ( + rule.type === CSSRuleTypeEnum.mediaRule && + defaultView.matchMedia((rule).conditionalText).matches + ) { + this.parseCSSRules({ + elements: options.elements, + cssRules: (rule).cssRules, + hostElement: options.hostElement + }); + } + } + } + + /** + * Returns CSS value. + * + * @param value Value. + * @param cssVariables CSS variables. + * @returns CSS value. + */ + private getCSSValue(value: string, cssVariables: { [k: string]: string }): string { + const regexp = new RegExp(CSS_VARIABLE_REGEXP); + let newValue = value; + let match; + while ((match = regexp.exec(value)) !== null) { + const cssVariableValue = cssVariables[match[1]]; + if (!cssVariableValue) { + return null; + } + newValue = newValue.replace(match[0], cssVariableValue); + } + return newValue; + } +} diff --git a/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationPropertyGetParser.ts b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationPropertyGetParser.ts new file mode 100644 index 000000000..1270d51ae --- /dev/null +++ b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationPropertyGetParser.ts @@ -0,0 +1,743 @@ +import CSSStyleDeclarationValueParser from './CSSStyleDeclarationValueParser'; +import ICSSStyleDeclarationPropertyValue from './ICSSStyleDeclarationPropertyValue'; + +/** + * Computed style property parser. + */ +export default class CSSStyleDeclarationPropertyGetParser { + /** + * Returns margin. + * + * @param properties Properties. + * @returns Property value + */ + public static getMargin(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + return this.getPaddingLikeProperty( + ['margin-top', 'margin-right', 'margin-bottom', 'margin-left'], + properties + ); + } + + /** + * Returns padding. + * + * @param properties Properties. + * @returns Property value + */ + public static getPadding(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + return this.getPaddingLikeProperty( + ['padding-top', 'padding-right', 'padding-bottom', 'padding-left'], + properties + ); + } + + /** + * Returns border. + * + * @param properties Properties. + * @returns Property value + */ + public static getBorder(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + if ( + !properties['border-top-width']?.value || + properties['border-top-width']?.value !== properties['border-right-width']?.value || + properties['border-top-width']?.value !== properties['border-bottom-width']?.value || + properties['border-top-width']?.value !== properties['border-left-width']?.value || + !properties['border-top-style']?.value || + properties['border-top-style']?.value !== properties['border-right-style']?.value || + properties['border-top-style']?.value !== properties['border-bottom-style']?.value || + properties['border-top-style']?.value !== properties['border-left-style']?.value || + !properties['border-top-color']?.value || + properties['border-top-color']?.value !== properties['border-right-color']?.value || + properties['border-top-color']?.value !== properties['border-bottom-color']?.value || + properties['border-top-color']?.value !== properties['border-left-color']?.value || + !properties['border-image-source']?.value || + !properties['border-image-slice']?.value || + !properties['border-image-width']?.value || + !properties['border-image-outset']?.value || + !properties['border-image-repeat']?.value + ) { + return null; + } + + const important = + properties['border-top-width'].important && + properties['border-right-width'].important && + properties['border-bottom-width'].important && + properties['border-left-width'].important && + properties['border-top-style'].important && + properties['border-right-style'].important && + properties['border-bottom-style'].important && + properties['border-left-style'].important && + properties['border-top-color'].important && + properties['border-right-color'].important && + properties['border-bottom-color'].important && + properties['border-left-color'].important && + properties['border-image-source'].important && + properties['border-image-slice'].important && + properties['border-image-width'].important && + properties['border-image-outset'].important && + properties['border-image-repeat'].important; + + if ( + CSSStyleDeclarationValueParser.getGlobalExceptInitial(properties['border-top-width'].value) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial(properties['border-top-style'].value) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial(properties['border-top-color'].value) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial( + properties['border-image-source'].value + ) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial( + properties['border-image-slice'].value + ) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial( + properties['border-image-width'].value + ) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial( + properties['border-image-outset'].value + ) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial(properties['border-image-repeat'].value) + ) { + if ( + properties['border-top-width'].value !== properties['border-top-style'].value || + properties['border-top-width'].value !== properties['border-top-color'].value || + properties['border-top-width'].value !== properties['border-image-source'].value || + properties['border-top-width'].value !== properties['border-image-slice'].value || + properties['border-top-width'].value !== properties['border-image-width'].value || + properties['border-top-width'].value !== properties['border-image-outset'].value || + properties['border-top-width'].value !== properties['border-image-repeat'].value + ) { + return null; + } + + return { + important, + value: properties['border-top-width'].value + }; + } + + const values = []; + + if (!CSSStyleDeclarationValueParser.getInitial(properties['border-top-width'].value)) { + values.push(properties['border-top-width'].value); + } + + if (!CSSStyleDeclarationValueParser.getInitial(properties['border-top-style'].value)) { + values.push(properties['border-top-style'].value); + } + + if (!CSSStyleDeclarationValueParser.getInitial(properties['border-top-color'].value)) { + values.push(properties['border-top-color'].value); + } + + return { + important, + value: values.join(' ') + }; + } + + /** + * Returns border. + * + * @param properties Properties. + * @returns Property value + */ + public static getBorderTop(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + return this.getBorderTopRightBottomLeft('top', properties); + } + + /** + * Returns border. + * + * @param properties Properties. + * @returns Property value + */ + public static getBorderRight(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + return this.getBorderTopRightBottomLeft('right', properties); + } + + /** + * Returns border. + * + * @param properties Properties. + * @returns Property value + */ + public static getBorderBottom(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + return this.getBorderTopRightBottomLeft('bottom', properties); + } + + /** + * Returns border. + * + * @param properties Properties. + * @returns Property value + */ + public static getBorderLeft(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + return this.getBorderTopRightBottomLeft('left', properties); + } + + /** + * Returns border. + * + * @param properties Properties. + * @returns Property value + */ + public static getBorderColor(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + return this.getPaddingLikeProperty( + ['border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color'], + properties + ); + } + + /** + * Returns border. + * + * @param properties Properties. + * @returns Property value + */ + public static getBorderWidth(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + return this.getPaddingLikeProperty( + ['border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width'], + properties + ); + } + + /** + * Returns border. + * + * @param properties Properties. + * @returns Property value + */ + public static getBorderStyle(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + return this.getPaddingLikeProperty( + ['border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style'], + properties + ); + } + + /** + * Returns border radius. + * + * @param properties Properties. + * @returns Property value + */ + public static getBorderRadius(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + return this.getPaddingLikeProperty( + [ + 'border-top-left-radius', + 'border-top-right-radius', + 'border-bottom-right-radius', + 'border-bottom-left-radius' + ], + properties + ); + } + + /** + * Returns border image. + * + * @param properties Properties. + * @returns Property value + */ + public static getBorderImage(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + if ( + !properties['border-image-source']?.value || + !properties['border-image-slice']?.value || + !properties['border-image-width']?.value || + !properties['border-image-outset']?.value || + !properties['border-image-repeat']?.value + ) { + return null; + } + + const important = + properties['border-image-source'].important && + properties['border-image-slice'].important && + properties['border-image-width'].important && + properties['border-image-outset'].important && + properties['border-image-repeat'].important; + + if ( + CSSStyleDeclarationValueParser.getGlobal(properties['border-image-source'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['border-image-slice'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['border-image-width'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['border-image-outset'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['border-image-repeat'].value) + ) { + if ( + properties['border-image-source'].value !== properties['border-image-slice'].value || + properties['border-image-source'].value !== properties['border-image-width'].value || + properties['border-image-source'].value !== properties['border-image-outset'].value || + properties['border-image-source'].value !== properties['border-image-repeat'].value + ) { + return null; + } + return { + important, + value: properties['border-image-source'].value + }; + } + + return { + important, + value: `${properties['border-image-source'].value} ${properties['border-image-slice'].value} / ${properties['border-image-width'].value} / ${properties['border-image-outset'].value} ${properties['border-image-repeat'].value}` + }; + } + + /** + * Returns background. + * + * @param properties Properties. + * @returns Property value + */ + public static getBackground(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + if ( + !properties['background-image']?.value || + !properties['background-repeat']?.value || + !properties['background-attachment']?.value || + !properties['background-position-x']?.value || + !properties['background-position-y']?.value || + !properties['background-color']?.value || + !properties['background-size']?.value || + !properties['background-origin']?.value || + !properties['background-clip']?.value + ) { + return null; + } + + const important = + properties['background-image'].important && + properties['background-repeat'].important && + properties['background-attachment'].important && + properties['background-position-x'].important && + properties['background-position-y'].important && + properties['background-color'].important && + properties['background-size'].important && + properties['background-origin'].important && + properties['background-clip'].important; + + if ( + CSSStyleDeclarationValueParser.getGlobalExceptInitial(properties['background-image'].value) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial( + properties['background-repeat'].value + ) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial( + properties['background-attachment'].value + ) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial( + properties['background-position-x'].value + ) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial( + properties['background-position-y'].value + ) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial(properties['background-color'].value) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial(properties['background-size'].value) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial( + properties['background-origin'].value + ) || + CSSStyleDeclarationValueParser.getGlobalExceptInitial(properties['background-clip'].value) + ) { + if ( + properties['background-image'].value !== properties['background-repeat'].value || + properties['background-image'].value !== properties['background-attachment'].value || + properties['background-image'].value !== properties['background-position-x'].value || + properties['background-image'].value !== properties['background-position-y'].value || + properties['background-image'].value !== properties['background-color'].value || + properties['background-image'].value !== properties['background-size'].value || + properties['background-image'].value !== properties['background-origin'].value || + properties['background-image'].value !== properties['background-clip'].value + ) { + return null; + } + + return { + important, + value: properties['background-image'].value + }; + } + + const values = []; + + if (!CSSStyleDeclarationValueParser.getInitial(properties['background-image'].value)) { + values.push(properties['background-image'].value); + } + + if ( + !CSSStyleDeclarationValueParser.getInitial(properties['background-position-x'].value) && + !CSSStyleDeclarationValueParser.getInitial(properties['background-position-y'].value) && + !CSSStyleDeclarationValueParser.getInitial(properties['background-size'].value) + ) { + values.push( + `${properties['background-position-x'].value} ${properties['background-position-y'].value} / ${properties['background-size'].value}` + ); + } else if ( + !CSSStyleDeclarationValueParser.getInitial(properties['background-position-x'].value) && + !CSSStyleDeclarationValueParser.getInitial(properties['background-position-y'].value) + ) { + values.push( + `${properties['background-position-x'].value} ${properties['background-position-y'].value}` + ); + } + + if (!CSSStyleDeclarationValueParser.getInitial(properties['background-repeat'].value)) { + values.push(properties['background-repeat'].value); + } + + if (!CSSStyleDeclarationValueParser.getInitial(properties['background-attachment'].value)) { + values.push(properties['background-attachment'].value); + } + + if (!CSSStyleDeclarationValueParser.getInitial(properties['background-origin'].value)) { + values.push(properties['background-origin'].value); + } + + if (!CSSStyleDeclarationValueParser.getInitial(properties['background-clip'].value)) { + values.push(properties['background-clip'].value); + } + + if (!CSSStyleDeclarationValueParser.getInitial(properties['background-color'].value)) { + values.push(properties['background-color'].value); + } + + return { + important, + value: values.join(' ') + }; + } + + /** + * Returns background position. + * + * @param properties Properties. + * @returns Property value + */ + public static getBackgroundPosition(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + if ( + !properties['background-position-x']?.value || + !properties['background-position-y']?.value + ) { + return null; + } + + const important = + properties['background-position-x'].important && + properties['background-position-y'].important; + if ( + CSSStyleDeclarationValueParser.getGlobal(properties['background-position-x'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['background-position-y'].value) + ) { + if (properties['background-position-x'].value !== properties['background-position-y'].value) { + return null; + } + + return { + important, + value: properties['background-position-x'].value + }; + } + + const positionX = properties['background-position-x'].value.replace(/ *, */g, ',').split(','); + const positionY = properties['background-position-y'].value.replace(/ *, */g, ',').split(','); + const parts = []; + + for (let i = 0; i < positionX.length; i++) { + parts.push(`${positionX[i]} ${positionY[i]}`); + } + + return { + important, + value: parts.join(', ') + }; + } + + /** + * Returns flex. + * + * @param properties Properties. + * @returns Property value + */ + public static getFlex(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + if ( + !properties['flex-grow']?.value || + !properties['flex-shrink']?.value || + !properties['flex-basis']?.value + ) { + return null; + } + + const important = + properties['flex-grow'].important && + properties['flex-shrink'].important && + properties['flex-basis'].important; + + if ( + CSSStyleDeclarationValueParser.getGlobal(properties['flex-grow'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['flex-shrink'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['flex-basis'].value) + ) { + if ( + properties['flex-grow'].value !== properties['flex-shrink'].value || + properties['flex-grow'].value !== properties['flex-basis'].value + ) { + return null; + } + + return { + important, + value: properties['flex-grow'].value + }; + } + + return { + important, + value: `${properties['flex-grow'].value} ${properties['flex-shrink'].value} ${properties['flex-basis'].value}` + }; + } + + /** + * Returns flex. + * + * @param properties Properties. + * @returns Property value + */ + public static getFont(properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + }): ICSSStyleDeclarationPropertyValue { + if ( + !properties['font-size']?.value || + !properties['font-family']?.value || + !properties['font-weight']?.value || + !properties['font-style']?.value || + !properties['font-variant']?.value || + !properties['font-stretch']?.value || + !properties['line-height']?.value + ) { + return null; + } + + const important = + properties['font-size'].important && + properties['font-family'].important && + properties['font-weight'].important && + properties['font-style'].important && + properties['font-variant'].important && + properties['font-stretch'].important && + properties['line-height'].important; + + if ( + CSSStyleDeclarationValueParser.getGlobal(properties['font-size'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['font-family'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['font-weight'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['font-style'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['font-variant'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['font-stretch'].value) || + CSSStyleDeclarationValueParser.getGlobal(properties['line-height'].value) + ) { + if ( + properties['font-size'].value !== properties['font-family'].value || + properties['font-size'].value !== properties['font-weight'].value || + properties['font-size'].value !== properties['font-style'].value || + properties['font-size'].value !== properties['font-variant'].value || + properties['font-size'].value !== properties['font-stretch'].value || + properties['font-size'].value !== properties['line-height'].value + ) { + return null; + } + + return { + important, + value: properties['font-size'].value + }; + } + + const values = []; + + if (properties['font-style'].value !== 'normal') { + values.push(properties['font-style'].value); + } + if (properties['font-variant'].value !== 'normal') { + values.push(properties['font-variant'].value); + } + if (properties['font-weight'].value !== 'normal') { + values.push(properties['font-weight'].value); + } + if (properties['font-stretch'].value !== 'normal') { + values.push(properties['font-stretch'].value); + } + + if (properties['line-height'].value !== 'normal') { + values.push(`${properties['font-size'].value} / ${properties['line-height'].value}`); + } else { + values.push(properties['font-size'].value); + } + + values.push(properties['font-family'].value); + + return { + important, + value: values.join(' ') + }; + } + + /** + * Returns border. + * + * @param properties Properties. + * @param position + * @returns Property value + */ + private static getBorderTopRightBottomLeft( + position: 'top' | 'right' | 'bottom' | 'left', + properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + } + ): ICSSStyleDeclarationPropertyValue { + if ( + !properties[`border-${position}-width`]?.value || + !properties[`border-${position}-style`]?.value || + !properties[`border-${position}-color`]?.value + ) { + return null; + } + + const important = + properties[`border-${position}-width`].important && + properties[`border-${position}-style`].important && + properties[`border-${position}-color`].important; + + if ( + CSSStyleDeclarationValueParser.getGlobalExceptInitial( + properties[`border-${position}-width`].value + ) && + properties[`border-${position}-width`].value === + properties[`border-${position}-style`].value && + properties[`border-${position}-width`].value === properties[`border-${position}-color`].value + ) { + return { + important, + value: properties[`border-${position}-width`].value + }; + } + + const values = []; + + if (!CSSStyleDeclarationValueParser.getInitial(properties[`border-${position}-width`].value)) { + values.push(properties[`border-${position}-width`].value); + } + if (!CSSStyleDeclarationValueParser.getInitial(properties[`border-${position}-style`]?.value)) { + values.push(properties[`border-${position}-style`].value); + } + if (!CSSStyleDeclarationValueParser.getInitial(properties[`border-${position}-color`]?.value)) { + values.push(properties[`border-${position}-color`].value); + } + + return { + important, + value: values.join(' ') + }; + } + + /** + * Returns a padding like property. + * + * @param properties Properties. + * @param position + * @param propertyNames + * @returns Property value + */ + private static getPaddingLikeProperty( + propertyNames: [string, string, string, string], + properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + } + ): ICSSStyleDeclarationPropertyValue { + if ( + !properties[propertyNames[0]]?.value || + !properties[propertyNames[1]]?.value || + !properties[propertyNames[2]]?.value || + !properties[propertyNames[3]]?.value + ) { + return null; + } + + const important = + properties[propertyNames[0]].important && + properties[propertyNames[1]].important && + properties[propertyNames[2]].important && + properties[propertyNames[3]].important; + + if ( + CSSStyleDeclarationValueParser.getGlobal(properties[propertyNames[0]].value) || + CSSStyleDeclarationValueParser.getGlobal(properties[propertyNames[1]].value) || + CSSStyleDeclarationValueParser.getGlobal(properties[propertyNames[2]].value) || + CSSStyleDeclarationValueParser.getGlobal(properties[propertyNames[3]].value) + ) { + if ( + properties[propertyNames[0]].value !== properties[propertyNames[1]].value || + properties[propertyNames[0]].value !== properties[propertyNames[2]].value || + properties[propertyNames[0]].value !== properties[propertyNames[3]].value + ) { + return null; + } + return { + important, + value: properties[propertyNames[0]].value + }; + } + + const values = [properties[propertyNames[0]].value]; + + if ( + properties[propertyNames[1]].value !== properties[propertyNames[0]].value || + properties[propertyNames[2]].value !== properties[propertyNames[0]].value || + properties[propertyNames[3]].value !== properties[propertyNames[1]].value + ) { + values.push(properties[propertyNames[1]].value); + } + + if ( + properties[propertyNames[2]].value !== properties[propertyNames[0]].value || + properties[propertyNames[3]].value !== properties[propertyNames[1]].value + ) { + values.push(properties[propertyNames[2]].value); + } + + if (properties[propertyNames[3]].value !== properties[propertyNames[1]].value) { + values.push(properties[propertyNames[3]].value); + } + + return { + important, + value: values.join(' ') + }; + } +} diff --git a/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationPropertyManager.ts b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationPropertyManager.ts new file mode 100644 index 000000000..6e7b9e47d --- /dev/null +++ b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationPropertyManager.ts @@ -0,0 +1,592 @@ +import ICSSStyleDeclarationPropertyValue from './ICSSStyleDeclarationPropertyValue'; +import CSSStyleDeclarationPropertySetParser from './CSSStyleDeclarationPropertySetParser'; +import CSSStyleDeclarationValueParser from './CSSStyleDeclarationValueParser'; +import CSSStyleDeclarationPropertyGetParser from './CSSStyleDeclarationPropertyGetParser'; +import CSSStyleDeclarationCSSParser from './CSSStyleDeclarationCSSParser'; + +const TO_STRING_SHORTHAND_PROPERTIES = [ + ['margin'], + ['padding'], + ['border', ['border-width', 'border-style', 'border-color', 'border-image']], + ['border-radius'], + ['background', 'background-position'], + ['font'] +]; + +/** + * Computed this.properties property parser. + */ +export default class CSSStyleDeclarationPropertyManager { + public properties: { + [k: string]: ICSSStyleDeclarationPropertyValue; + } = {}; + private definedPropertyNames: { [k: string]: boolean } = {}; + + /** + * Class construtor. + * + * @param [options] Options. + * @param [options.cssText] CSS string. + */ + constructor(options?: { cssText?: string }) { + if (options?.cssText) { + CSSStyleDeclarationCSSParser.parse(options.cssText, (name, value, important) => { + if (important || !this.get(name)?.important) { + this.set(name, value, important); + } + }); + } + } + + /** + * Returns property value. + * + * @param name Property name. + * @returns Property value. + */ + public get(name: string): ICSSStyleDeclarationPropertyValue { + if (this.properties[name]) { + return this.properties[name]; + } + switch (name) { + case 'margin': + return CSSStyleDeclarationPropertyGetParser.getMargin(this.properties); + case 'padding': + return CSSStyleDeclarationPropertyGetParser.getPadding(this.properties); + case 'border': + return CSSStyleDeclarationPropertyGetParser.getBorder(this.properties); + case 'border-top': + return CSSStyleDeclarationPropertyGetParser.getBorderTop(this.properties); + case 'border-right': + return CSSStyleDeclarationPropertyGetParser.getBorderRight(this.properties); + case 'border-bottom': + return CSSStyleDeclarationPropertyGetParser.getBorderBottom(this.properties); + case 'border-left': + return CSSStyleDeclarationPropertyGetParser.getBorderLeft(this.properties); + case 'border-color': + return CSSStyleDeclarationPropertyGetParser.getBorderColor(this.properties); + case 'border-style': + return CSSStyleDeclarationPropertyGetParser.getBorderStyle(this.properties); + case 'border-width': + return CSSStyleDeclarationPropertyGetParser.getBorderWidth(this.properties); + case 'border-radius': + return CSSStyleDeclarationPropertyGetParser.getBorderRadius(this.properties); + case 'border-image': + return CSSStyleDeclarationPropertyGetParser.getBorderImage(this.properties); + case 'background': + return CSSStyleDeclarationPropertyGetParser.getBackground(this.properties); + case 'background-position': + return CSSStyleDeclarationPropertyGetParser.getBackgroundPosition(this.properties); + case 'flex': + return CSSStyleDeclarationPropertyGetParser.getFlex(this.properties); + case 'font': + return CSSStyleDeclarationPropertyGetParser.getFont(this.properties); + } + + return this.properties[name] || null; + } + + /** + * Removes a property. + * + * @param name Property name. + */ + public remove(name: string): void { + delete this.properties[name]; + delete this.definedPropertyNames[name]; + + switch (name) { + case 'border': + delete this.properties['border-top-width']; + delete this.properties['border-right-width']; + delete this.properties['border-bottom-width']; + delete this.properties['border-left-width']; + delete this.properties['border-top-style']; + delete this.properties['border-right-style']; + delete this.properties['border-bottom-style']; + delete this.properties['border-left-style']; + delete this.properties['border-top-color']; + delete this.properties['border-right-color']; + delete this.properties['border-bottom-color']; + delete this.properties['border-left-color']; + delete this.properties['border-image-source']; + delete this.properties['border-image-slice']; + delete this.properties['border-image-width']; + delete this.properties['border-image-outset']; + delete this.properties['border-image-repeat']; + break; + case 'border-top': + delete this.properties['border-top-width']; + delete this.properties['border-top-style']; + delete this.properties['border-top-color']; + delete this.properties['border-image-source']; + delete this.properties['border-image-slice']; + delete this.properties['border-image-width']; + delete this.properties['border-image-outset']; + delete this.properties['border-image-repeat']; + break; + case 'border-right': + delete this.properties['border-right-width']; + delete this.properties['border-right-style']; + delete this.properties['border-right-color']; + delete this.properties['border-image-source']; + delete this.properties['border-image-slice']; + delete this.properties['border-image-width']; + delete this.properties['border-image-outset']; + delete this.properties['border-image-repeat']; + break; + case 'border-bottom': + delete this.properties['border-bottom-width']; + delete this.properties['border-bottom-style']; + delete this.properties['border-bottom-color']; + delete this.properties['border-image-source']; + delete this.properties['border-image-slice']; + delete this.properties['border-image-width']; + delete this.properties['border-image-outset']; + delete this.properties['border-image-repeat']; + break; + case 'border-left': + delete this.properties['border-left-width']; + delete this.properties['border-left-style']; + delete this.properties['border-left-color']; + delete this.properties['border-image-source']; + delete this.properties['border-image-slice']; + delete this.properties['border-image-width']; + delete this.properties['border-image-outset']; + delete this.properties['border-image-repeat']; + break; + case 'border-width': + delete this.properties['border-top-width']; + delete this.properties['border-right-width']; + delete this.properties['border-bottom-width']; + delete this.properties['border-left-width']; + break; + case 'border-style': + delete this.properties['border-top-style']; + delete this.properties['border-right-style']; + delete this.properties['border-bottom-style']; + delete this.properties['border-left-style']; + break; + case 'border-color': + delete this.properties['border-top-color']; + delete this.properties['border-right-color']; + delete this.properties['border-bottom-color']; + delete this.properties['border-left-color']; + break; + case 'border-image': + delete this.properties['border-image-source']; + delete this.properties['border-image-slice']; + delete this.properties['border-image-width']; + delete this.properties['border-image-outset']; + delete this.properties['border-image-repeat']; + break; + case 'border-radius': + delete this.properties['border-top-left-radius']; + delete this.properties['border-top-right-radius']; + delete this.properties['border-bottom-right-radius']; + delete this.properties['border-bottom-left-radius']; + break; + case 'background': + delete this.properties['background-color']; + delete this.properties['background-image']; + delete this.properties['background-repeat']; + delete this.properties['background-attachment']; + delete this.properties['background-position-x']; + delete this.properties['background-position-y']; + delete this.properties['background-size']; + delete this.properties['background-origin']; + delete this.properties['background-clip']; + break; + case 'background-position': + delete this.properties['background-position-x']; + delete this.properties['background-position-y']; + break; + case 'flex': + delete this.properties['flex-grow']; + delete this.properties['flex-shrink']; + delete this.properties['flex-basis']; + break; + case 'font': + delete this.properties['font-style']; + delete this.properties['font-variant']; + delete this.properties['font-weight']; + delete this.properties['font-stretch']; + delete this.properties['font-size']; + delete this.properties['line-height']; + delete this.properties['font-family']; + break; + case 'padding': + delete this.properties['padding-top']; + delete this.properties['padding-right']; + delete this.properties['padding-bottom']; + delete this.properties['padding-left']; + break; + case 'margin': + delete this.properties['margin-top']; + delete this.properties['margin-right']; + delete this.properties['margin-bottom']; + delete this.properties['margin-left']; + break; + } + } + + /** + * Sets a property + * + * @param name Name. + * @param value Value. + * @param important Important. + */ + public set(name: string, value: string, important: boolean): void { + if (value === null) { + this.remove(name); + return; + } + + let properties = null; + + switch (name) { + case 'border': + properties = CSSStyleDeclarationPropertySetParser.getBorder(value, important); + break; + case 'border-top': + properties = CSSStyleDeclarationPropertySetParser.getBorderTop(value, important); + break; + case 'border-right': + properties = CSSStyleDeclarationPropertySetParser.getBorderRight(value, important); + break; + case 'border-bottom': + properties = CSSStyleDeclarationPropertySetParser.getBorderBottom(value, important); + break; + case 'border-left': + properties = CSSStyleDeclarationPropertySetParser.getBorderLeft(value, important); + break; + case 'border-width': + properties = CSSStyleDeclarationPropertySetParser.getBorderWidth(value, important); + break; + case 'border-style': + properties = CSSStyleDeclarationPropertySetParser.getBorderStyle(value, important); + break; + case 'border-color': + properties = CSSStyleDeclarationPropertySetParser.getBorderColor(value, important); + break; + case 'border-image': + properties = CSSStyleDeclarationPropertySetParser.getBorderImage(value, important); + break; + case 'border-image-source': + properties = CSSStyleDeclarationPropertySetParser.getBorderImageSource(value, important); + break; + case 'border-image-slice': + properties = CSSStyleDeclarationPropertySetParser.getBorderImageSlice(value, important); + break; + case 'border-image-width': + properties = CSSStyleDeclarationPropertySetParser.getBorderImageWidth(value, important); + break; + case 'border-image-outset': + properties = CSSStyleDeclarationPropertySetParser.getBorderImageOutset(value, important); + break; + case 'border-image-repeat': + properties = CSSStyleDeclarationPropertySetParser.getBorderImageRepeat(value, important); + break; + case 'border-top-width': + properties = CSSStyleDeclarationPropertySetParser.getBorderTopWidth(value, important); + break; + case 'border-right-width': + properties = CSSStyleDeclarationPropertySetParser.getBorderRightWidth(value, important); + break; + case 'border-bottom-width': + properties = CSSStyleDeclarationPropertySetParser.getBorderBottomWidth(value, important); + break; + case 'border-left-width': + properties = CSSStyleDeclarationPropertySetParser.getBorderLeftWidth(value, important); + break; + case 'border-top-color': + properties = CSSStyleDeclarationPropertySetParser.getBorderTopColor(value, important); + break; + case 'border-right-color': + properties = CSSStyleDeclarationPropertySetParser.getBorderRightColor(value, important); + break; + case 'border-bottom-color': + properties = CSSStyleDeclarationPropertySetParser.getBorderBottomColor(value, important); + break; + case 'border-left-color': + properties = CSSStyleDeclarationPropertySetParser.getBorderLeftColor(value, important); + break; + case 'border-top-style': + properties = CSSStyleDeclarationPropertySetParser.getBorderTopStyle(value, important); + break; + case 'border-right-style': + properties = CSSStyleDeclarationPropertySetParser.getBorderRightStyle(value, important); + break; + case 'border-bottom-style': + properties = CSSStyleDeclarationPropertySetParser.getBorderBottomStyle(value, important); + break; + case 'border-left-style': + properties = CSSStyleDeclarationPropertySetParser.getBorderLeftStyle(value, important); + break; + case 'border-radius': + properties = CSSStyleDeclarationPropertySetParser.getBorderRadius(value, important); + break; + case 'border-top-left-radius': + properties = CSSStyleDeclarationPropertySetParser.getBorderTopLeftRadius(value, important); + break; + case 'border-top-right-radius': + properties = CSSStyleDeclarationPropertySetParser.getBorderTopRightRadius(value, important); + break; + case 'border-bottom-right-radius': + properties = CSSStyleDeclarationPropertySetParser.getBorderBottomRightRadius( + value, + important + ); + break; + case 'border-bottom-right-radius': + properties = CSSStyleDeclarationPropertySetParser.getBorderBottomLeftRadius( + value, + important + ); + break; + case 'border-collapse': + properties = CSSStyleDeclarationPropertySetParser.getBorderCollapse(value, important); + break; + case 'clear': + properties = CSSStyleDeclarationPropertySetParser.getClear(value, important); + break; + case 'clip': + properties = CSSStyleDeclarationPropertySetParser.getClip(value, important); + break; + case 'css-float': + properties = CSSStyleDeclarationPropertySetParser.getCSSFloat(value, important); + break; + case 'float': + properties = CSSStyleDeclarationPropertySetParser.getFloat(value, important); + break; + case 'display': + properties = CSSStyleDeclarationPropertySetParser.getDisplay(value, important); + break; + case 'direction': + properties = CSSStyleDeclarationPropertySetParser.getDirection(value, important); + break; + case 'flex': + properties = CSSStyleDeclarationPropertySetParser.getFlex(value, important); + break; + case 'flex-shrink': + properties = CSSStyleDeclarationPropertySetParser.getFlexShrink(value, important); + break; + case 'flex-grow': + properties = CSSStyleDeclarationPropertySetParser.getFlexGrow(value, important); + break; + case 'flex-basis': + properties = CSSStyleDeclarationPropertySetParser.getFlexBasis(value, important); + break; + case 'padding': + properties = CSSStyleDeclarationPropertySetParser.getPadding(value, important); + break; + case 'padding-top': + properties = CSSStyleDeclarationPropertySetParser.getPaddingTop(value, important); + break; + case 'padding-right': + properties = CSSStyleDeclarationPropertySetParser.getPaddingRight(value, important); + break; + case 'padding-bottom': + properties = CSSStyleDeclarationPropertySetParser.getPaddingBottom(value, important); + break; + case 'padding-left': + properties = CSSStyleDeclarationPropertySetParser.getPaddingLeft(value, important); + break; + case 'margin': + properties = CSSStyleDeclarationPropertySetParser.getMargin(value, important); + break; + case 'margin-top': + properties = CSSStyleDeclarationPropertySetParser.getMarginTop(value, important); + break; + case 'margin-right': + properties = CSSStyleDeclarationPropertySetParser.getMarginRight(value, important); + break; + case 'margin-bottom': + properties = CSSStyleDeclarationPropertySetParser.getMarginBottom(value, important); + break; + case 'margin-left': + properties = CSSStyleDeclarationPropertySetParser.getMarginLeft(value, important); + break; + case 'background': + properties = CSSStyleDeclarationPropertySetParser.getBackground(value, important); + break; + case 'background-image': + properties = CSSStyleDeclarationPropertySetParser.getBackgroundImage(value, important); + break; + case 'background-color': + properties = CSSStyleDeclarationPropertySetParser.getBackgroundColor(value, important); + break; + case 'background-repeat': + properties = CSSStyleDeclarationPropertySetParser.getBackgroundRepeat(value, important); + break; + case 'background-attachment': + properties = CSSStyleDeclarationPropertySetParser.getBackgroundAttachment(value, important); + break; + case 'background-position': + properties = CSSStyleDeclarationPropertySetParser.getBackgroundPosition(value, important); + break; + case 'width': + properties = CSSStyleDeclarationPropertySetParser.getWidth(value, important); + break; + case 'top': + properties = CSSStyleDeclarationPropertySetParser.getTop(value, important); + break; + case 'right': + properties = CSSStyleDeclarationPropertySetParser.getRight(value, important); + break; + case 'bottom': + properties = CSSStyleDeclarationPropertySetParser.getBottom(value, important); + break; + case 'left': + properties = CSSStyleDeclarationPropertySetParser.getLeft(value, important); + break; + case 'font': + properties = CSSStyleDeclarationPropertySetParser.getFont(value, important); + break; + case 'font-style': + properties = CSSStyleDeclarationPropertySetParser.getFontStyle(value, important); + break; + case 'font-variant': + properties = CSSStyleDeclarationPropertySetParser.getFontVariant(value, important); + break; + case 'font-weight': + properties = CSSStyleDeclarationPropertySetParser.getFontWeight(value, important); + break; + case 'font-stretch': + properties = CSSStyleDeclarationPropertySetParser.getFontStretch(value, important); + break; + case 'font-size': + properties = CSSStyleDeclarationPropertySetParser.getFontSize(value, important); + break; + case 'line-height': + properties = CSSStyleDeclarationPropertySetParser.getLineHeight(value, important); + break; + case 'font-family': + properties = CSSStyleDeclarationPropertySetParser.getFontFamily(value, important); + break; + case 'color': + properties = CSSStyleDeclarationPropertySetParser.getColor(value, important); + break; + case 'flood-color': + properties = CSSStyleDeclarationPropertySetParser.getFloodColor(value, important); + break; + case 'text-transform': + properties = CSSStyleDeclarationPropertySetParser.getTextTransform(value, important); + break; + case 'visibility': + properties = CSSStyleDeclarationPropertySetParser.getVisibility(value, important); + break; + default: + const trimmedValue = value.trim(); + if (trimmedValue) { + const globalValue = CSSStyleDeclarationValueParser.getGlobal(trimmedValue); + properties = { + [name]: { value: globalValue || trimmedValue, important } + }; + } + break; + } + + if (properties !== null && Object.keys(properties).length > 0) { + this.definedPropertyNames[name] = true; + Object.assign(this.properties, properties); + } + } + + /** + * Returns a clone. + * + * @returns Clone. + */ + public clone(): CSSStyleDeclarationPropertyManager { + const _class = this.constructor; + const clone: CSSStyleDeclarationPropertyManager = new _class(); + + clone.properties = JSON.parse(JSON.stringify(this.properties)); + clone.definedPropertyNames = Object.assign({}, this.definedPropertyNames); + + return clone; + } + + /** + * Returns size. + * + * @returns Size. + */ + public size(): number { + return Object.keys(this.properties).length; + } + + /** + * Returns property name. + * + * @param index Index. + * @returns Property name. + */ + public item(index: number): string { + return Object.keys(this.properties)[index] || ''; + } + + /** + * Converts properties to string. + * + * @returns String. + */ + public toString(): string { + const result = []; + const clone = this.clone(); + const properties = {}; + + for (const shorthandPropertyGroup of TO_STRING_SHORTHAND_PROPERTIES) { + for (const shorthandProperty of shorthandPropertyGroup) { + if (Array.isArray(shorthandProperty)) { + let isMatch = false; + for (const childShorthandProperty of shorthandProperty) { + const property = clone.get(childShorthandProperty); + if (property) { + properties[childShorthandProperty] = property; + clone.remove(childShorthandProperty); + isMatch = true; + } + } + if (isMatch) { + break; + } + } else { + const property = clone.get(shorthandProperty); + if (property) { + properties[shorthandProperty] = property; + clone.remove(shorthandProperty); + break; + } + } + } + } + + for (const name of Object.keys(clone.properties)) { + properties[name] = clone.get(name); + } + + for (const definedPropertyName of Object.keys(this.definedPropertyNames)) { + const property = properties[definedPropertyName]; + if (property) { + result.push( + `${definedPropertyName}: ${property.value}${property.important ? ' !important' : ''};` + ); + delete properties[definedPropertyName]; + } + } + + for (const propertyName of Object.keys(properties)) { + const property = properties[propertyName]; + if (property) { + result.push( + `${propertyName}: ${property.value}${property.important ? ' !important' : ''};` + ); + } + } + + return result.join(' '); + } +} diff --git a/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationPropertySetParser.ts b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationPropertySetParser.ts new file mode 100644 index 000000000..9ba8c931a --- /dev/null +++ b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationPropertySetParser.ts @@ -0,0 +1,3026 @@ +import CSSStyleDeclarationValueParser from './CSSStyleDeclarationValueParser'; +import ICSSStyleDeclarationPropertyValue from './ICSSStyleDeclarationPropertyValue'; + +const RECT_REGEXP = /^rect\((.*)\)$/i; +const BORDER_STYLE = [ + 'none', + 'hidden', + 'dotted', + 'dashed', + 'solid', + 'double', + 'groove', + 'ridge', + 'inset', + 'outset' +]; +const BORDER_WIDTH = ['thin', 'medium', 'thick']; +const BORDER_COLLAPSE = ['separate', 'collapse']; +const BACKGROUND_REPEAT = ['repeat', 'repeat-x', 'repeat-y', 'no-repeat']; +const BACKGROUND_ORIGIN = ['border-box', 'padding-box', 'content-box']; +const BACKGROUND_CLIP = ['border-box', 'padding-box', 'content-box']; +const BACKGROUND_ATTACHMENT = ['scroll', 'fixed']; +const FLEX_BASIS = ['auto', 'fill', 'content']; +const CLEAR = ['none', 'left', 'right', 'both']; +const FLOAT = ['none', 'left', 'right', 'inline-start', 'inline-end']; +const SYSTEM_FONT = ['caption', 'icon', 'menu', 'message-box', 'small-caption', 'status-bar']; +const FONT_WEIGHT = ['normal', 'bold', 'bolder', 'lighter']; +const FONT_STYLE = ['normal', 'italic', 'oblique']; +const FONT_SIZE = [ + 'xx-small', + 'x-small', + 'small', + 'medium', + 'large', + 'x-large', + 'xx-large', + 'xxx-large', + 'smaller', + 'larger' +]; +const FONT_STRETCH = [ + 'ultra-condensed', + 'extra-condensed', + 'condensed', + 'semi-condensed', + 'normal', + 'semi-expanded', + 'expanded', + 'extra-expanded', + 'ultra-expanded' +]; + +const DISPLAY = [ + /* Legacy values */ + 'block', + 'inline', + 'inline-block', + 'flex', + 'inline-flex', + 'grid', + 'inline-grid', + 'flow-root', + + /* Box generation */ + 'none', + 'contents', + + /* Two-value syntax */ + 'block flow', + 'inline flow', + 'inline flow-root', + 'block flex', + 'inline flex', + 'block grid', + 'inline grid', + 'block flow-root', + + /* Other values */ + 'table', + 'table-row', + 'list-item' +]; +const BORDER_IMAGE_REPEAT = ['stretch', 'repeat', 'round', 'space']; +const TEXT_TRANSFORM = [ + 'capitalize', + 'uppercase', + 'lowercase', + 'none', + 'full-width', + 'full-size-kana' +]; +const VISIBILITY = ['visible', 'hidden', 'collapse']; + +/** + * Computed style property parser. + */ +export default class CSSStyleDeclarationPropertySetParser { + /** + * Returns border collapse. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderCollapse( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-collapse': { value: variable, important } }; + } + const lowerValue = value.toLowerCase(); + if ( + CSSStyleDeclarationValueParser.getGlobal(lowerValue) || + BORDER_COLLAPSE.includes(lowerValue) + ) { + return { 'border-collapse': { value: lowerValue, important } }; + } + return null; + } + + /** + * Returns display. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getDisplay( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { display: { value: variable, important } }; + } + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || DISPLAY.includes(lowerValue)) { + return { display: { value: lowerValue, important } }; + } + return null; + } + + /** + * Returns direction. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getDirection( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { direction: { value: variable, important } }; + } + const lowerValue = value.toLowerCase(); + if ( + CSSStyleDeclarationValueParser.getGlobal(lowerValue) || + lowerValue === 'ltr' || + lowerValue === 'rtl' + ) { + return { direction: { value: lowerValue, important } }; + } + return null; + } + + /** + * Returns width. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getWidth( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { width: { value: variable, important } }; + } + const parsedValue = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getContentMeasurement(value); + return parsedValue ? { width: { value: parsedValue, important } } : null; + } + + /** + * Returns top. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getTop( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { top: { value: variable, important } }; + } + const parsedValue = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getContentMeasurement(value); + return parsedValue ? { top: { value: parsedValue, important } } : null; + } + + /** + * Returns top. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getRight( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { right: { value: variable, important } }; + } + const parsedValue = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getContentMeasurement(value); + return parsedValue ? { right: { value: parsedValue, important } } : null; + } + + /** + * Returns top. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBottom( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { bottom: { value: variable, important } }; + } + const parsedValue = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getContentMeasurement(value); + return parsedValue ? { bottom: { value: parsedValue, important } } : null; + } + + /** + * Returns top. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getLeft( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { left: { value: variable, important } }; + } + const parsedValue = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getContentMeasurement(value); + return parsedValue ? { left: { value: parsedValue, important } } : null; + } + + /** + * Returns clear. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getClear( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { clear: { value: variable, important } }; + } + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || CLEAR.includes(lowerValue)) { + return { clear: { value: lowerValue, important } }; + } + return null; + } + + /** + * Returns clip + * + * Based on: + * https://github.com/jsdom/cssstyle/blob/master/lib/properties/clip.js + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getClip( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { clip: { value: variable, important } }; + } + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || lowerValue === 'auto') { + return { clip: { value: lowerValue, important } }; + } + const matches = lowerValue.match(RECT_REGEXP); + if (!matches) { + return null; + } + const parts = matches[1].split(/\s*,\s*/); + if (parts.length !== 4) { + return null; + } + for (const part of parts) { + if (!CSSStyleDeclarationValueParser.getMeasurement(part)) { + return null; + } + } + return { clip: { value, important } }; + } + + /** + * Returns float. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getFloat( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { float: { value: variable, important } }; + } + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || FLOAT.includes(lowerValue)) { + return { float: { value: lowerValue, important } }; + } + return null; + } + + /** + * Returns float. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getCSSFloat( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'css-float': { value: variable, important } }; + } + const float = this.getFloat(value, important); + return float ? { 'css-float': float['float'] } : null; + } + + /** + * Returns border. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getBorder( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { border: { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getBorderWidth(globalValue, important), + ...this.getBorderStyle(globalValue, important), + ...this.getBorderColor(globalValue, important), + ...this.getBorderImage(globalValue, important) + }; + } + + const properties = { + ...this.getBorderWidth('initial', important), + ...this.getBorderStyle('initial', important), + ...this.getBorderColor('initial', important), + ...this.getBorderImage('initial', important) + }; + + const parts = value.replace(/ *, */g, ',').split(/ +/); + + for (const part of parts) { + const width = this.getBorderWidth(part, important); + const style = this.getBorderStyle(part, important); + const color = this.getBorderColor(part, important); + + if (width === null && style === null && color === null) { + return null; + } + + Object.assign(properties, width, style, color); + } + + return properties; + } + + /** + * Returns border width. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderWidth( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-width': { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getBorderTopWidth(globalValue, important), + ...this.getBorderRightWidth(globalValue, important), + ...this.getBorderBottomWidth(globalValue, important), + ...this.getBorderLeftWidth(globalValue, important) + }; + } + + const parts = value.split(/ +/); + const top = this.getBorderTopWidth(parts[0], important); + const right = this.getBorderRightWidth(parts[1] || parts[0], important); + const bottom = this.getBorderBottomWidth(parts[2] || parts[0], important); + const left = this.getBorderLeftWidth(parts[3] || parts[1] || parts[0], important); + + if (!top || !right || !bottom || !left) { + return null; + } + + return { + ...top, + ...right, + ...bottom, + ...left + }; + } + /** + * Returns border style. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderStyle( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-style': { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getBorderTopStyle(globalValue, important), + ...this.getBorderRightStyle(globalValue, important), + ...this.getBorderBottomStyle(globalValue, important), + ...this.getBorderLeftStyle(globalValue, important) + }; + } + + const parts = value.split(/ +/); + const top = this.getBorderTopStyle(parts[0], important); + const right = this.getBorderRightStyle(parts[1] || parts[0], important); + const bottom = this.getBorderBottomStyle(parts[2] || parts[0], important); + const left = this.getBorderLeftStyle(parts[3] || parts[1] || parts[0], important); + + if (!top || !right || !bottom || !left) { + return null; + } + + return { + ...top, + ...right, + ...bottom, + ...left + }; + } + + /** + * Returns border color. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderColor( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-color': { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getBorderTopColor(globalValue, important), + ...this.getBorderRightColor(globalValue, important), + ...this.getBorderBottomColor(globalValue, important), + ...this.getBorderLeftColor(globalValue, important) + }; + } + + const parts = value.split(/ +/); + const top = this.getBorderTopColor(parts[0], important); + const right = this.getBorderRightColor(parts[1] || parts[0], important); + const bottom = this.getBorderBottomColor(parts[2] || parts[0], important); + const left = this.getBorderLeftColor(parts[3] || parts[1] || parts[0], important); + + if (!top || !right || !bottom || !left) { + return null; + } + + return { + ...top, + ...right, + ...bottom, + ...left + }; + } + + /** + * Returns border image. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderImage( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-image': { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getBorderImageSource(globalValue, important), + ...this.getBorderImageSlice(globalValue, important), + ...this.getBorderImageWidth(globalValue, important), + ...this.getBorderImageOutset(globalValue, important), + ...this.getBorderImageRepeat(globalValue, important) + }; + } + + let parsedValue = value.replace(/[ ]*\/[ ]*/g, '/'); + const sourceMatch = parsedValue.match(/ *([a-zA-Z-]+\([^)]*\)) */); + + if (sourceMatch) { + parsedValue = parsedValue.replace(sourceMatch[0], ''); + } + + const parts = parsedValue.split(/ +/); + + if (sourceMatch) { + parts.push(sourceMatch[1]); + } + + const properties = { + ...this.getBorderImageSource('none', important), + ...this.getBorderImageSlice('100%', important), + ...this.getBorderImageWidth('1', important), + ...this.getBorderImageOutset('0', important), + ...this.getBorderImageRepeat('stretch', important) + }; + + for (let i = 0, max = parts.length; i < max; i++) { + const part = parts[i]; + const previousPart = i > 0 ? parts[i - 1] : ''; + + if (!part.startsWith('url') && part.includes('/')) { + const [slice, width, outset] = part.split('/'); + const borderImageSlice = + this.getBorderImageSlice(`${previousPart} ${slice}`, important) || + this.getBorderImageSlice(slice, important); + const borderImageWidth = this.getBorderImageWidth(width, important); + const borderImageOutset = outset && this.getBorderImageOutset(outset, important); + + if (!borderImageSlice || !borderImageWidth || borderImageOutset === null) { + return null; + } + + Object.assign(properties, borderImageSlice, borderImageWidth, borderImageOutset); + } else { + const slice = + this.getBorderImageSlice(`${previousPart} ${part}`, important) || + this.getBorderImageSlice(part, important); + const source = this.getBorderImageSource(part, important); + const repeat = this.getBorderImageRepeat(part, important); + + if (!slice && !source && !repeat) { + return null; + } + + Object.assign(properties, slice, source, repeat); + } + } + + return properties; + } + + /** + * Returns border source. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderImageSource( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-image-source': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || lowerValue === 'none') { + return { + 'border-image-source': { + important, + value: lowerValue + } + }; + } + + const parsedValue = + CSSStyleDeclarationValueParser.getURL(value) || + CSSStyleDeclarationValueParser.getGradient(value); + + if (!parsedValue) { + return null; + } + + return { + 'border-image-source': { + important, + value: parsedValue + } + }; + } + + /** + * Returns border slice. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderImageSlice( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-image-slice': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue)) { + return { + 'border-image-slice': { + important, + value: lowerValue + } + }; + } + + if (lowerValue !== lowerValue.trim()) { + return null; + } + + const regexp = /(fill)|(calc\([^^)]+\))|([0-9]+%)|([0-9]+)/g; + const values = []; + let match; + + while ((match = regexp.exec(lowerValue))) { + const previousCharacter = lowerValue[match.index - 1]; + const nextCharacter = lowerValue[match.index + match[0].length]; + + if ( + (previousCharacter && previousCharacter !== ' ') || + (nextCharacter && nextCharacter !== ' ') + ) { + return null; + } + + const fill = match[1] && 'fill'; + const calc = match[2] && CSSStyleDeclarationValueParser.getCalc(match[2]); + const percentage = match[3] && CSSStyleDeclarationValueParser.getPercentage(match[3]); + const integer = match[4] && CSSStyleDeclarationValueParser.getInteger(match[4]); + + if (!fill && !calc && !percentage && !integer) { + return null; + } + + values.push(fill || calc || percentage || integer); + } + + if (!values.length || values.length > 4) { + return null; + } + + return { + 'border-image-slice': { + important, + value: values.join(' ') + } + }; + } + + /** + * Returns border width. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderImageWidth( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-image-width': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue)) { + return { + 'border-image-width': { + important, + value: lowerValue + } + }; + } + + const parts = lowerValue.split(/ +/); + + if (parts.length > 4) { + return null; + } + + for (const part of parts) { + if ( + !CSSStyleDeclarationValueParser.getInteger(part) && + !CSSStyleDeclarationValueParser.getAutoMeasurement(part) + ) { + return null; + } + } + + return { + 'border-image-width': { + important, + value + } + }; + } + + /** + * Returns border outset. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderImageOutset( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-image-outset': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue)) { + return { + 'border-image-outset': { + important, + value: lowerValue + } + }; + } + + const parts = value.split(/ +/); + + if (parts.length > 4) { + return null; + } + + for (const part of parts) { + if ( + !CSSStyleDeclarationValueParser.getLength(part) && + !CSSStyleDeclarationValueParser.getFloat(part) + ) { + return null; + } + } + + return { + 'border-image-outset': { + important, + value + } + }; + } + + /** + * Returns border repeat. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderImageRepeat( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-image-repeat': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue)) { + return { + 'border-image-repeat': { + important, + value: lowerValue + } + }; + } + + const parts = lowerValue.split(/ +/); + + if (parts.length > 2) { + return null; + } + + for (const part of parts) { + if (!BORDER_IMAGE_REPEAT.includes(part)) { + return null; + } + } + + return { + 'border-image-repeat': { + important, + value + } + }; + } + + /** + * Returns border width. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderTopWidth( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-top-width': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + const parsedValue = + BORDER_WIDTH.includes(lowerValue) || CSSStyleDeclarationValueParser.getGlobal(lowerValue) + ? lowerValue + : CSSStyleDeclarationValueParser.getLength(value); + if (parsedValue) { + return { + 'border-top-width': { value: parsedValue, important } + }; + } + return null; + } + + /** + * Returns border width. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderRightWidth( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-right-width': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + const parsedValue = + BORDER_WIDTH.includes(lowerValue) || CSSStyleDeclarationValueParser.getGlobal(lowerValue) + ? lowerValue + : CSSStyleDeclarationValueParser.getLength(value); + if (parsedValue) { + return { + 'border-right-width': { value: parsedValue, important } + }; + } + return null; + } + + /** + * Returns border width. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderBottomWidth( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-bottom-width': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + const parsedValue = + BORDER_WIDTH.includes(lowerValue) || CSSStyleDeclarationValueParser.getGlobal(lowerValue) + ? lowerValue + : CSSStyleDeclarationValueParser.getLength(value); + if (parsedValue) { + return { + 'border-bottom-width': { value: parsedValue, important } + }; + } + return null; + } + + /** + * Returns border width. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderLeftWidth( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-left-width': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + const parsedValue = + BORDER_WIDTH.includes(lowerValue) || CSSStyleDeclarationValueParser.getGlobal(lowerValue) + ? lowerValue + : CSSStyleDeclarationValueParser.getLength(value); + if (parsedValue) { + return { + 'border-left-width': { value: parsedValue, important } + }; + } + return null; + } + + /** + * Returns border style. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderTopStyle( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-top-style': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || BORDER_STYLE.includes(lowerValue)) { + return { + 'border-top-style': { value: lowerValue, important } + }; + } + return null; + } + + /** + * Returns border style. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderRightStyle( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-right-style': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || BORDER_STYLE.includes(lowerValue)) { + return { + 'border-right-style': { value: lowerValue, important } + }; + } + return null; + } + + /** + * Returns border style. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderBottomStyle( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-bottom-style': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || BORDER_STYLE.includes(lowerValue)) { + return { + 'border-bottom-style': { value: lowerValue, important } + }; + } + return null; + } + + /** + * Returns border style. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderLeftStyle( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-left-style': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || BORDER_STYLE.includes(lowerValue)) { + return { + 'border-left-style': { value: lowerValue, important } + }; + } + return null; + } + + /** + * Returns border color. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderTopColor( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-top-color': { value: variable, important } }; + } + + const color = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getColor(value); + return color + ? { + 'border-top-color': { value: color, important } + } + : null; + } + + /** + * Returns border color. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderRightColor( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-right-color': { value: variable, important } }; + } + + const color = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getColor(value); + return color + ? { + 'border-right-color': { value: color, important } + } + : null; + } + + /** + * Returns border color. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderBottomColor( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-bottom-color': { value: variable, important } }; + } + + const color = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getColor(value); + return color + ? { + 'border-bottom-color': { value: color, important } + } + : null; + } + + /** + * Returns border color. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBorderLeftColor( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-left-color': { value: variable, important } }; + } + + const color = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getColor(value); + return color + ? { + 'border-left-color': { value: color, important } + } + : null; + } + + /** + * Returns border radius. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getBorderRadius( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-radius': { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getBorderTopLeftRadius(globalValue, important), + ...this.getBorderTopRightRadius(globalValue, important), + ...this.getBorderBottomRightRadius(globalValue, important), + ...this.getBorderBottomLeftRadius(globalValue, important) + }; + } + + const parts = value.split(/ +/); + const topLeft = this.getBorderTopLeftRadius(parts[0], important); + const topRight = this.getBorderTopRightRadius(parts[1] || parts[0], important); + const bottomRight = this.getBorderBottomRightRadius(parts[2] || parts[0], important); + const bottomLeft = this.getBorderBottomLeftRadius(parts[3] || parts[1] || parts[0], important); + + if (!topLeft || !topRight || !bottomRight || !bottomLeft) { + return null; + } + + return { + ...topLeft, + ...topRight, + ...bottomRight, + ...bottomLeft + }; + } + + /** + * Returns border radius. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getBorderTopLeftRadius( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-top-left-radius': { value: variable, important } }; + } + + const radius = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getMeasurement(value); + return radius ? { 'border-top-left-radius': { important, value: radius } } : null; + } + + /** + * Returns border radius. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getBorderTopRightRadius( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-top-right-radius': { value: variable, important } }; + } + + const radius = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getMeasurement(value); + return radius ? { 'border-top-right-radius': { important, value: radius } } : null; + } + + /** + * Returns border radius. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getBorderBottomRightRadius( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-bottom-right-radius': { value: variable, important } }; + } + + const radius = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getMeasurement(value); + return radius ? { 'border-bottom-right-radius': { important, value: radius } } : null; + } + + /** + * Returns border radius. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getBorderBottomLeftRadius( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-bottom-left-radius': { value: variable, important } }; + } + + const radius = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getMeasurement(value); + return radius ? { 'border-bottom-left-radius': { important, value: radius } } : null; + } + + /** + * Returns border top, right, bottom or left. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getBorderTop( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-top': { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getBorderTopWidth(globalValue, important), + ...this.getBorderTopStyle(globalValue, important), + ...this.getBorderTopColor(globalValue, important) + }; + } + + const properties = { + ...this.getBorderTopWidth('initial', important), + ...this.getBorderTopStyle('initial', important), + ...this.getBorderTopColor('initial', important) + }; + + const parts = value.split(/ +/); + + for (const part of parts) { + const width = this.getBorderTopWidth(part, important); + const style = this.getBorderTopStyle(part, important); + const color = this.getBorderTopColor(part, important); + + if (width === null && style === null && color === null) { + return null; + } + + Object.assign(properties, width, style, color); + } + + return properties; + } + + /** + * Returns border top, right, bottom or left. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getBorderRight( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-right': { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getBorderRightWidth(globalValue, important), + ...this.getBorderRightStyle(globalValue, important), + ...this.getBorderRightColor(globalValue, important) + }; + } + + const properties = { + ...this.getBorderRightWidth('initial', important), + ...this.getBorderRightStyle('initial', important), + ...this.getBorderRightColor('initial', important) + }; + + const parts = value.split(/ +/); + + for (const part of parts) { + const width = this.getBorderRightWidth(part, important); + const style = this.getBorderRightStyle(part, important); + const color = this.getBorderRightColor(part, important); + + if (width === null && style === null && color === null) { + return null; + } + + Object.assign(properties, width, style, color); + } + + return properties; + } + + /** + * Returns border top, right, bottom or left. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getBorderBottom( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-bottom': { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getBorderBottomWidth(globalValue, important), + ...this.getBorderBottomStyle(globalValue, important), + ...this.getBorderBottomColor(globalValue, important) + }; + } + + const properties = { + ...this.getBorderBottomWidth('initial', important), + ...this.getBorderBottomStyle('initial', important), + ...this.getBorderBottomColor('initial', important) + }; + + const parts = value.split(/ +/); + + for (const part of parts) { + const width = this.getBorderBottomWidth(part, important); + const style = this.getBorderBottomStyle(part, important); + const color = this.getBorderBottomColor(part, important); + + if (width === null && style === null && color === null) { + return null; + } + + Object.assign(properties, width, style, color); + } + + return properties; + } + + /** + * Returns border top, right, bottom or left. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getBorderLeft( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'border-left': { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getBorderLeftWidth(globalValue, important), + ...this.getBorderLeftStyle(globalValue, important), + ...this.getBorderLeftColor(globalValue, important) + }; + } + + const properties = { + ...this.getBorderLeftWidth('initial', important), + ...this.getBorderLeftStyle('initial', important), + ...this.getBorderLeftColor('initial', important) + }; + + const parts = value.split(/ +/); + + for (const part of parts) { + const width = this.getBorderLeftWidth(part, important); + const style = this.getBorderLeftStyle(part, important); + const color = this.getBorderLeftColor(part, important); + + if (width === null && style === null && color === null) { + return null; + } + + Object.assign(properties, width, style, color); + } + + return properties; + } + + /** + * Returns padding. + * + * @param value Value. + * @param important Important. + */ + public static getPadding( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { padding: { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getPaddingTop(globalValue, important), + ...this.getPaddingRight(globalValue, important), + ...this.getPaddingBottom(globalValue, important), + ...this.getPaddingLeft(globalValue, important) + }; + } + + const parts = value.split(/ +/); + const top = this.getPaddingTop(parts[0], important); + const right = this.getPaddingRight(parts[1] || parts[0], important); + const bottom = this.getPaddingBottom(parts[2] || parts[0], important); + const left = this.getPaddingLeft(parts[3] || parts[1] || parts[0], important); + + if (!top || !right || !bottom || !left) { + return null; + } + + return { + ...top, + ...right, + ...bottom, + ...left + }; + } + + /** + * Returns padding top. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getPaddingTop( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'padding-top': { value: variable, important } }; + } + + const padding = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getMeasurement(value); + return padding ? { 'padding-top': { value: padding, important } } : null; + } + + /** + * Returns padding right. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getPaddingRight( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'padding-right': { value: variable, important } }; + } + + const padding = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getMeasurement(value); + return padding ? { 'padding-right': { value: padding, important } } : null; + } + + /** + * Returns padding bottom. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getPaddingBottom( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'padding-bottom': { value: variable, important } }; + } + + const padding = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getMeasurement(value); + return padding ? { 'padding-bottom': { value: padding, important } } : null; + } + + /** + * Returns padding left. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getPaddingLeft( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'padding-left': { value: variable, important } }; + } + + const padding = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getMeasurement(value); + return padding ? { 'padding-left': { value: padding, important } } : null; + } + + /** + * Returns margin. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getMargin( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { margin: { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getMarginTop(globalValue, important), + ...this.getMarginRight(globalValue, important), + ...this.getMarginBottom(globalValue, important), + ...this.getMarginLeft(globalValue, important) + }; + } + + const parts = value.split(/ +/); + const top = this.getMarginTop(parts[0], important); + const right = this.getMarginRight(parts[1] || parts[0], important); + const bottom = this.getMarginBottom(parts[2] || parts[0], important); + const left = this.getMarginLeft(parts[3] || parts[1] || parts[0], important); + + if (!top || !right || !bottom || !left) { + return null; + } + + return { + ...top, + ...right, + ...bottom, + ...left + }; + } + + /** + * Returns margin top. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getMarginTop( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'margin-top': { value: variable, important } }; + } + + const margin = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getAutoMeasurement(value); + return margin ? { 'margin-top': { value: margin, important } } : null; + } + + /** + * Returns margin right. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getMarginRight( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'margin-right': { value: variable, important } }; + } + + const margin = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getAutoMeasurement(value); + return margin ? { 'margin-right': { value: margin, important } } : null; + } + + /** + * Returns margin right. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getMarginBottom( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'margin-bottom': { value: variable, important } }; + } + + const margin = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getAutoMeasurement(value); + return margin ? { 'margin-bottom': { value: margin, important } } : null; + } + + /** + * Returns margin left. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getMarginLeft( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'margin-left': { value: variable, important } }; + } + + const margin = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getAutoMeasurement(value); + return margin ? { 'margin-left': { value: margin, important } } : null; + } + + /** + * Returns flex. + * + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getFlex( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { flex: { value: variable, important } }; + } + + const lowerValue = value.trim().toLowerCase(); + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getFlexGrow(globalValue, important), + ...this.getFlexShrink(globalValue, important), + ...this.getFlexBasis(globalValue, important) + }; + } + + switch (lowerValue) { + case 'none': + return { + ...this.getFlexGrow('0', important), + ...this.getFlexShrink('0', important), + ...this.getFlexBasis('auto', important) + }; + case 'auto': + return { + ...this.getFlexGrow('1', important), + ...this.getFlexShrink('1', important), + ...this.getFlexBasis('auto', important) + }; + } + + const measurement = CSSStyleDeclarationValueParser.getContentMeasurement(lowerValue); + + if (measurement) { + return { + ...this.getFlexGrow('1', important), + ...this.getFlexShrink('1', important), + ...this.getFlexBasis(measurement, important) + }; + } + + const parts = value.split(/ +/); + const flexGrow = this.getFlexGrow(parts[0], important); + const flexShrink = this.getFlexShrink(parts[1] || '1', important); + const flexBasis = this.getFlexBasis(parts[2] || '0%', important); + + if (!flexGrow || !flexShrink || !flexBasis) { + return null; + } + + return { + ...flexGrow, + ...flexShrink, + ...flexBasis + }; + } + + /** + * Returns flex basis. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getFlexBasis( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'flex-basis': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || FLEX_BASIS.includes(lowerValue)) { + return { 'flex-basis': { value: lowerValue, important } }; + } + const measurement = CSSStyleDeclarationValueParser.getContentMeasurement(lowerValue); + return measurement ? { 'flex-basis': { value: measurement, important } } : null; + } + + /** + * Returns flex shrink. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getFlexShrink( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'flex-shrink': { value: variable, important } }; + } + + const parsedValue = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getFloat(value); + return parsedValue ? { 'flex-shrink': { value: parsedValue, important } } : null; + } + + /** + * Returns flex grow. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getFlexGrow( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'flex-grow': { value: variable, important } }; + } + + const parsedValue = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getFloat(value); + return parsedValue ? { 'flex-grow': { value: parsedValue, important } } : null; + } + + /** + * Returns background. + * + * @param name Name. + * @param value Value. + * @param important Important. + * @returns Property values. + */ + public static getBackground( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { background: { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { + ...this.getBackgroundImage(globalValue, important), + ...this.getBackgroundPosition(globalValue, important), + ...this.getBackgroundSize(globalValue, important), + ...this.getBackgroundRepeat(globalValue, important), + ...this.getBackgroundAttachment(globalValue, important), + ...this.getBackgroundOrigin(globalValue, important), + ...this.getBackgroundClip(globalValue, important), + ...this.getBackgroundColor(globalValue, important) + }; + } + + const properties = { + ...this.getBackgroundImage('initial', important), + ...this.getBackgroundPosition('initial', important), + ...this.getBackgroundSize('initial', important), + ...this.getBackgroundRepeat('initial', important), + ...this.getBackgroundAttachment('initial', important), + ...this.getBackgroundOrigin('initial', important), + ...this.getBackgroundClip('initial', important), + ...this.getBackgroundColor('initial', important) + }; + + const parts = value + .replace(/[ ]*,[ ]*/g, ',') + .replace(/[ ]*\/[ ]*/g, '/') + .split(/ +/); + + const backgroundPositions = []; + + for (const part of parts) { + if (!part.startsWith('url') && part.includes('/')) { + const [position, size] = part.split('/'); + const backgroundPositionX = this.getBackgroundPositionX(position, important); + const backgroundPositionY = this.getBackgroundPositionY(position, important); + + const backgroundSize = this.getBackgroundSize(size, important); + + if ((!backgroundPositionX && !backgroundPositionY) || !backgroundSize) { + return null; + } + + if (backgroundPositionY) { + backgroundPositions.push(backgroundPositionY['background-position-y'].value); + } else if (backgroundPositionX) { + backgroundPositions.push(backgroundPositionX['background-position-x'].value); + } + + Object.assign(properties, backgroundSize); + } else { + const backgroundImage = this.getBackgroundImage(part, important); + const backgroundRepeat = this.getBackgroundRepeat(part, important); + const backgroundAttachment = this.getBackgroundAttachment(part, important); + const backgroundPositionX = this.getBackgroundPositionX(part, important); + const backgroundPositionY = this.getBackgroundPositionY(part, important); + const backgroundColor = this.getBackgroundColor(part, important); + const backgroundOrigin = this.getBackgroundOrigin(part, important); + const backgroundClip = this.getBackgroundClip(part, important); + + if ( + !backgroundImage && + !backgroundRepeat && + !backgroundAttachment && + !backgroundPositionX && + !backgroundPositionY && + !backgroundColor && + !backgroundOrigin && + !backgroundClip + ) { + return null; + } + + if (backgroundPositionX) { + backgroundPositions.push(backgroundPositionX['background-position-x'].value); + } else if (backgroundPositionY) { + backgroundPositions.push(backgroundPositionY['background-position-y'].value); + } + + Object.assign( + properties, + backgroundImage, + backgroundRepeat, + backgroundAttachment, + backgroundColor, + backgroundOrigin, + backgroundClip + ); + } + } + + if (backgroundPositions.length) { + Object.assign( + properties, + this.getBackgroundPosition(backgroundPositions.join(' '), important) + ); + } + + return properties; + } + + /** + * Returns background size. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBackgroundSize( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'background-size': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue)) { + return { 'background-size': { value: lowerValue, important } }; + } + + const imageParts = lowerValue.split(','); + const parsed = []; + + for (const imagePart of imageParts) { + const parts = imagePart.trim().split(' '); + if (parts.length !== 1 && parts.length !== 2) { + return null; + } + if (parts.length === 1) { + if ( + parts[0] !== 'cover' && + parts[0] !== 'contain' && + !CSSStyleDeclarationValueParser.getAutoMeasurement(parts[0]) + ) { + return null; + } + parsed.push(parts[0]); + } else { + if ( + !CSSStyleDeclarationValueParser.getAutoMeasurement(parts[0]) || + !CSSStyleDeclarationValueParser.getAutoMeasurement(parts[1]) + ) { + return null; + } + parsed.push(`${parts[0]} ${parts[1]}`); + } + } + if (parsed.length === 1) { + return { 'background-size': { value: parsed.join(', '), important } }; + } + return null; + } + + /** + * Returns background origin. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBackgroundOrigin( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'background-origin': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if ( + CSSStyleDeclarationValueParser.getGlobal(lowerValue) || + BACKGROUND_ORIGIN.includes(lowerValue) + ) { + return { 'background-origin': { value: lowerValue, important } }; + } + return null; + } + + /** + * Returns background clip. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBackgroundClip( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'background-clip': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if ( + CSSStyleDeclarationValueParser.getGlobal(lowerValue) || + BACKGROUND_CLIP.includes(lowerValue) + ) { + return { 'background-clip': { value: lowerValue, important } }; + } + return null; + } + + /** + * Returns background repeat. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBackgroundRepeat( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'background-repeat': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if ( + CSSStyleDeclarationValueParser.getGlobal(lowerValue) || + BACKGROUND_REPEAT.includes(lowerValue) + ) { + return { 'background-repeat': { value: lowerValue, important } }; + } + return null; + } + + /** + * Returns background attachment. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBackgroundAttachment( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'background-attachment': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if ( + CSSStyleDeclarationValueParser.getGlobal(lowerValue) || + BACKGROUND_ATTACHMENT.includes(lowerValue) + ) { + return { 'background-attachment': { value: lowerValue, important } }; + } + return null; + } + + /** + * Returns background position. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBackgroundPosition( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'background-position': { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + if (globalValue) { + return { + ...this.getBackgroundPositionX(globalValue, important), + ...this.getBackgroundPositionY(globalValue, important) + }; + } + + const imageParts = value.replace(/ *, */g, ',').split(','); + let x = ''; + let y = ''; + + for (const imagePart of imageParts) { + const parts = imagePart.trim().split(/ +/); + + if (x) { + x += ','; + y += ','; + } + + switch (parts.length) { + case 1: + if (parts[0] === 'top' || parts[0] === 'bottom') { + x += 'center'; + y += parts[0]; + } else if (parts[0] === 'left' || parts[0] === 'right') { + x += parts[0]; + y += 'center'; + } else if (parts[0] === 'center') { + x += 'center'; + y += 'center'; + } + break; + case 2: + x += parts[0] === 'top' || parts[0] === 'bottom' ? parts[1] : parts[0]; + y += parts[0] === 'top' || parts[0] === 'bottom' ? parts[0] : parts[1]; + break; + case 3: + if ( + parts[0] === 'top' || + parts[0] === 'bottom' || + parts[1] === 'left' || + parts[1] === 'right' || + parts[2] === 'left' || + parts[2] === 'right' + ) { + if (CSSStyleDeclarationValueParser.getMeasurement(parts[1])) { + x += parts[2]; + y += `${parts[0]} ${parts[1]}`; + } else { + x += `${parts[1]} ${parts[2]}`; + y += parts[0]; + } + } else { + if (CSSStyleDeclarationValueParser.getMeasurement(parts[1])) { + x += `${parts[0]} ${parts[1]}`; + y += parts[2]; + } else { + x += parts[0]; + y += `${parts[1]} ${parts[2]}`; + } + } + break; + case 4: + x += + parts[0] === 'top' || + parts[0] === 'bottom' || + parts[1] === 'top' || + parts[1] === 'bottom' + ? `${parts[2]} ${parts[3]}` + : `${parts[0]} ${parts[1]}`; + y += + parts[0] === 'top' || + parts[0] === 'bottom' || + parts[1] === 'top' || + parts[1] === 'bottom' + ? `${parts[0]} ${parts[1]}` + : `${parts[2]} ${parts[3]}`; + break; + default: + return null; + } + } + + const xValue = this.getBackgroundPositionX(x, important); + const yValue = this.getBackgroundPositionY(y, important); + + if (xValue && yValue) { + return { + ...xValue, + ...yValue + }; + } + + return null; + } + + /** + * Returns background position. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBackgroundPositionX( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'background-position-x': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue)) { + return { 'background-position-x': { value: lowerValue, important } }; + } + + const imageParts = lowerValue.replace(/ *, */g, ',').split(','); + let parsedValue = ''; + + for (const imagePart of imageParts) { + const parts = imagePart.trim().split(/ +/); + + if (parsedValue) { + parsedValue += ','; + } + + for (const part of parts) { + const measurement = CSSStyleDeclarationValueParser.getMeasurement(part); + if (!measurement && part !== 'left' && part !== 'right' && part !== 'center') { + return null; + } + + if (parsedValue) { + parsedValue += ' '; + } + + parsedValue += measurement || part; + } + } + + return { 'background-position-x': { value: parsedValue, important } }; + } + + /** + * Returns background position. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getBackgroundPositionY( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'background-position-y': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue)) { + return { 'background-position-y': { value: lowerValue, important } }; + } + + const imageParts = lowerValue.replace(/ *, */g, ',').split(','); + let parsedValue = ''; + + for (const imagePart of imageParts) { + const parts = imagePart.trim().split(/ +/); + + if (parsedValue) { + parsedValue += ','; + } + + for (const part of parts) { + const measurement = CSSStyleDeclarationValueParser.getMeasurement(part); + if (!measurement && part !== 'top' && part !== 'bottom' && part !== 'center') { + return null; + } + + if (parsedValue) { + parsedValue += ' '; + } + + parsedValue += measurement || part; + } + } + + return { 'background-position-y': { value: parsedValue, important } }; + } + + /** + * Returns background color. + * + * @param value Value. + * @param important Important. + * @returns Property value. + */ + public static getBackgroundColor( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'background-color': { value: variable, important } }; + } + + const color = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getColor(value); + + return color + ? { + ['background-color']: { important, value: color } + } + : null; + } + + /** + * Returns background image. + * + * @param value Value. + * @param important Important. + * @returns Property value. + */ + public static getBackgroundImage( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'background-image': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || lowerValue === 'none') { + return { 'background-image': { value: lowerValue, important } }; + } + + const parts = value.replace(/ *, */g, ',').split(','); + const parsed = []; + + for (const part of parts) { + const url = CSSStyleDeclarationValueParser.getURL(part.trim()); + if (!url) { + return null; + } + parsed.push(url); + } + + if (parsed.length) { + return { 'background-image': { value: parsed.join(', '), important } }; + } + + return null; + } + + /** + * Returns color. + * + * @param value Value. + * @param important Important. + * @returns Property value. + */ + public static getColor( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { color: { value: variable, important } }; + } + + const color = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getColor(value); + + return color ? { color: { important, value: color } } : null; + } + + /** + * Returns color. + * + * @param value Value. + * @param important Important. + * @returns Property value. + */ + public static getFloodColor( + value: string, + important: boolean + ): { [key: string]: ICSSStyleDeclarationPropertyValue } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'flood-color': { value: variable, important } }; + } + const color = + CSSStyleDeclarationValueParser.getGlobal(value) || + CSSStyleDeclarationValueParser.getColor(value); + + return color ? { 'flood-color': { important, value: color } } : null; + } + + /** + * Returns font. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getFont( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { font: { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue)) { + return { + ...this.getFontStyle(lowerValue, important), + ...this.getFontVariant(lowerValue, important), + ...this.getFontWeight(lowerValue, important), + ...this.getFontStretch(lowerValue, important), + ...this.getFontSize(lowerValue, important), + ...this.getLineHeight(lowerValue, important), + ...this.getFontFamily(lowerValue, important) + }; + } + + if (SYSTEM_FONT.includes(lowerValue)) { + return { font: { value: lowerValue, important } }; + } + + const properties = { + ...this.getFontStyle('normal', important), + ...this.getFontVariant('normal', important), + ...this.getFontWeight('normal', important), + ...this.getFontStretch('normal', important), + ...this.getLineHeight('normal', important) + }; + + const parts = value.replace(/ *\/ */g, '/').split(/ +/); + + for (let i = 0, max = parts.length; i < max; i++) { + const part = parts[i]; + if (part.includes('/')) { + const [size, height] = part.split('/'); + const fontSize = this.getFontSize(size, important); + const lineHeight = this.getLineHeight(height, important); + + if (!fontSize || !lineHeight) { + return null; + } + + Object.assign(properties, fontSize, lineHeight); + } else { + const fontStyle = this.getFontStyle(part, important); + const fontVariant = this.getFontVariant(part, important); + const fontWeight = this.getFontWeight(part, important); + const fontSize = this.getFontSize(part, important); + const fontStretch = this.getFontStretch(part, important); + + if (fontStyle) { + Object.assign(properties, fontStyle); + } else if (fontVariant) { + Object.assign(properties, fontVariant); + } else if (fontWeight) { + Object.assign(properties, fontWeight); + } else if (fontSize) { + Object.assign(properties, fontSize); + } else if (fontStretch) { + Object.assign(properties, fontStretch); + } else { + const fontFamilyValue = parts.slice(i).join(' '); + const fontFamily = this.getFontFamily(fontFamilyValue, important); + if (!fontFamily) { + return null; + } + Object.assign(properties, fontFamily); + break; + } + } + } + + return properties; + } + + /** + * Returns font style. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getFontStyle( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'font-style': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || FONT_STYLE.includes(lowerValue)) { + return { 'font-style': { value: lowerValue, important } }; + } + const parts = value.split(/ +/); + if (parts.length === 2 && parts[0] === 'oblique') { + const degree = CSSStyleDeclarationValueParser.getDegree(parts[1]); + return degree ? { 'font-style': { value: lowerValue, important } } : null; + } + return null; + } + + /** + * Returns font variant. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getFontVariant( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'font-variant': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + return CSSStyleDeclarationValueParser.getGlobal(lowerValue) || + lowerValue === 'normal' || + lowerValue === 'small-caps' + ? { 'font-variant': { value: lowerValue, important } } + : null; + } + + /** + * Returns font strech. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getFontStretch( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'font-stretch': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || FONT_STRETCH.includes(lowerValue)) { + return { 'font-stretch': { value: lowerValue, important } }; + } + const percentage = CSSStyleDeclarationValueParser.getPercentage(value); + return percentage ? { 'font-stretch': { value: percentage, important } } : null; + } + + /** + * Returns font weight. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getFontWeight( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'font-weight': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || FONT_WEIGHT.includes(lowerValue)) { + return { 'font-weight': { value: lowerValue, important } }; + } + const integer = CSSStyleDeclarationValueParser.getInteger(value); + return integer ? { 'font-weight': { value: integer, important } } : null; + } + + /** + * Returns font size. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getFontSize( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'font-size': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || FONT_SIZE.includes(lowerValue)) { + return { 'font-size': { value: lowerValue, important } }; + } + const measurement = CSSStyleDeclarationValueParser.getMeasurement(value); + return measurement ? { 'font-size': { value: measurement, important } } : null; + } + + /** + * Returns line height. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getLineHeight( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'line-height': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || lowerValue === 'normal') { + return { 'line-height': { value: lowerValue, important } }; + } + const lineHeight = + CSSStyleDeclarationValueParser.getFloat(value) || + CSSStyleDeclarationValueParser.getMeasurement(value); + return lineHeight ? { 'line-height': { value: lineHeight, important } } : null; + } + + /** + * Returns font family. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getFontFamily( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'font-family': { value: variable, important } }; + } + + const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); + + if (globalValue) { + return { 'font-family': { value: globalValue, important } }; + } + + const parts = value.split(','); + let parsedValue = ''; + let endWithApostroph = false; + + for (let i = 0, max = parts.length; i < max; i++) { + let trimmedPart = parts[i].trim().replace(/'/g, '"'); + + if (!trimmedPart) { + return null; + } + + if (trimmedPart.includes(' ')) { + const apostrophCount = (trimmedPart.match(/"/g) || []).length; + if ((trimmedPart[0] !== '"' || i !== 0) && apostrophCount !== 2 && apostrophCount !== 0) { + return null; + } + if (trimmedPart[0] === '"' && trimmedPart[trimmedPart.length - 1] !== '"') { + endWithApostroph = true; + } else if (trimmedPart[0] !== '"' && trimmedPart[trimmedPart.length - 1] !== '"') { + trimmedPart = `"${trimmedPart}"`; + } + } + + if (i > 0) { + parsedValue += ', '; + } + + parsedValue += trimmedPart; + } + + if (endWithApostroph) { + parsedValue += '"'; + } + + if (!parsedValue) { + return null; + } + + return { + 'font-family': { + important, + value: parsedValue + } + }; + } + + /** + * Returns font family. + * + * @param value Value. + * @param important Important. + * @returns Property values + */ + public static getTextTransform( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { 'text-transform': { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + const parsedValue = + CSSStyleDeclarationValueParser.getGlobal(lowerValue) || + (TEXT_TRANSFORM.includes(lowerValue) && lowerValue); + if (parsedValue) { + return { + 'text-transform': { value: parsedValue, important } + }; + } + return null; + } + + /** + * Returns visibility. + * + * @param value Value. + * @param important Important. + * @returns Property + */ + public static getVisibility( + value: string, + important: boolean + ): { + [key: string]: ICSSStyleDeclarationPropertyValue; + } { + const variable = CSSStyleDeclarationValueParser.getVariable(value); + if (variable) { + return { visibility: { value: variable, important } }; + } + + const lowerValue = value.toLowerCase(); + const parsedValue = + CSSStyleDeclarationValueParser.getGlobal(lowerValue) || + (VISIBILITY.includes(lowerValue) && lowerValue); + if (parsedValue) { + return { + visibility: { value: parsedValue, important } + }; + } + return null; + } +} diff --git a/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationValueParser.ts b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationValueParser.ts new file mode 100644 index 000000000..6c508a105 --- /dev/null +++ b/packages/happy-dom/src/css/declaration/utilities/CSSStyleDeclarationValueParser.ts @@ -0,0 +1,437 @@ +const COLOR_REGEXP = + /^#([0-9a-fA-F]{3,4}){1,2}$|^rgb\(([^)]*)\)$|^rgba\(([^)]*)\)$|^hsla?\(\s*(-?\d+|-?\d*.\d+)\s*,\s*(-?\d+|-?\d*.\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%\s*(,\s*(-?\d+|-?\d*.\d+)\s*)?\)/; + +const LENGTH_REGEXP = /^(0|[-+]?[0-9]*\.?[0-9]+(in|cm|em|mm|pt|pc|px|ex|rem|vh|vw|ch))$/; +const PERCENTAGE_REGEXP = /^[-+]?[0-9]*\.?[0-9]+%$/; +const DEGREE_REGEXP = /^[0-9]+deg$/; +const URL_REGEXP = /^url\(\s*([^)]*)\s*\)$/; +const INTEGER_REGEXP = /^[0-9]+$/; +const FLOAT_REGEXP = /^[0-9.]+$/; +const CALC_REGEXP = /^calc\([^^)]+\)$/; +const CSS_VARIABLE_REGEXP = /^var\( *(--[^) ]+)\)$/; +const FIT_CONTENT_REGEXP = /^fit-content\([^^)]+\)$/; +const GRADIENT_REGEXP = + /^(repeating-linear|linear|radial|repeating-radial|conic|repeating-conic)-gradient\([^)]+\)$/; +const GLOBALS = ['inherit', 'initial', 'unset', 'revert']; +const COLORS = [ + 'currentcolor', + 'transparent', + 'silver', + 'gray', + 'white', + 'maroon', + 'red', + 'purple', + 'fuchsia', + 'green', + 'lime', + 'olive', + 'yellow', + 'navy', + 'blue', + 'teal', + 'aqua', + 'antiquewhite', + 'aquamarine', + 'azure', + 'beige', + 'bisque', + 'blanchedalmond', + 'blueviolet', + 'brown', + 'burlywood', + 'cadetblue', + 'chartreuse', + 'chocolate', + 'coral', + 'cornflowerblue', + 'cornsilk', + 'crimson', + 'darkblue', + 'darkcyan', + 'darkgoldenrod', + 'darkgray', + 'darkgreen', + 'darkgrey', + 'darkkhaki', + 'darkmagenta', + 'darkolivegreen', + 'darkorange', + 'darkorchid', + 'darkred', + 'darksalmon', + 'darkseagreen', + 'darkslateblue', + 'darkslategray', + 'darkslategrey', + 'darkturquoise', + 'darkviolet', + 'deeppink', + 'deepskyblue', + 'dimgray', + 'dimgrey', + 'dodgerblue', + 'firebrick', + 'floralwhite', + 'forestgreen', + 'gainsboro', + 'ghostwhite', + 'gold', + 'goldenrod', + 'greenyellow', + 'grey', + 'honeydew', + 'hotpink', + 'indianred', + 'indigo', + 'ivory', + 'khaki', + 'lavender', + 'lavenderblush', + 'lawngreen', + 'lemonchiffon', + 'lightblue', + 'lightcoral', + 'lightcyan', + 'lightgoldenrodyellow', + 'lightgray', + 'lightgreen', + 'lightgrey', + 'lightpink', + 'lightsalmon', + 'lightseagreen', + 'lightskyblue', + 'lightslategray', + 'lightslategrey', + 'lightsteelblue', + 'lightyellow', + 'limegreen', + 'linen', + 'mediumaquamarine', + 'mediumblue', + 'mediumorchid', + 'mediumpurple', + 'mediumseagreen', + 'mediumslateblue', + 'mediumspringgreen', + 'mediumturquoise', + 'mediumvioletred', + 'midnightblue', + 'mintcream', + 'mistyrose', + 'moccasin', + 'navajowhite', + 'oldlace', + 'olivedrab', + 'orangered', + 'orchid', + 'palegoldenrod', + 'palegreen', + 'paleturquoise', + 'palevioletred', + 'papayawhip', + 'peachpuff', + 'peru', + 'pink', + 'plum', + 'powderblue', + 'rosybrown', + 'royalblue', + 'saddlebrown', + 'salmon', + 'sandybrown', + 'seagreen', + 'seashell', + 'sienna', + 'skyblue', + 'slateblue', + 'slategray', + 'slategrey', + 'snow', + 'springgreen', + 'steelblue', + 'tan', + 'thistle', + 'tomato', + 'turquoise', + 'violet', + 'wheat', + 'whitesmoke', + 'yellowgreen' +]; + +/** + * Style declaration value parser. + */ +export default class CSSStyleDeclarationValueParser { + /** + * Returns length. + * + * @param value Value. + * @returns Parsed value. + */ + public static getLength(value: string): string { + if (value === '0') { + return '0px'; + } + if (LENGTH_REGEXP.test(value)) { + return value; + } + return null; + } + + /** + * Returns percentance. + * + * @param value Value. + * @returns Parsed value. + */ + public static getPercentage(value: string): string { + if (value === '0') { + return '0%'; + } + if (PERCENTAGE_REGEXP.test(value)) { + return value; + } + return null; + } + + /** + * Returns degree. + * + * @param value Value. + * @returns Parsed value. + */ + public static getDegree(value: string): string { + if (value === '0') { + return '0deg'; + } + if (DEGREE_REGEXP.test(value)) { + return value; + } + return null; + } + + /** + * Returns calc. + * + * @param value Value. + * @returns Parsed value. + */ + public static getCalc(value: string): string { + if (CALC_REGEXP.test(value)) { + return value; + } + return null; + } + + /** + * Returns fit content. + * + * @param value Value. + * @returns Parsed value. + */ + public static getFitContent(value: string): string { + const lowerValue = value.toLowerCase(); + if ( + lowerValue === 'auto' || + lowerValue === 'max-content' || + lowerValue === 'min-content' || + lowerValue === 'fit-content' + ) { + return lowerValue; + } + if (FIT_CONTENT_REGEXP.test(lowerValue)) { + return lowerValue; + } + return null; + } + + /** + * Returns measurement. + * + * @param value Value. + * @returns Parsed value. + */ + public static getMeasurement(value: string): string { + return this.getLength(value) || this.getPercentage(value); + } + + /** + * Returns measurement or auto, min-content, max-content or fit-content. + * + * @param value Value. + * @returns Parsed value. + */ + public static getContentMeasurement(value: string): string { + return this.getFitContent(value) || this.getMeasurement(value); + } + + /** + * Returns measurement or auto, min-content, max-content or fit-content. + * + * @param value Value. + * @returns Parsed value. + */ + public static getAutoMeasurement(value: string): string { + if (value.toLocaleLowerCase() === 'auto') { + return 'auto'; + } + return this.getMeasurement(value); + } + + /** + * Returns integer. + * + * @param value Value. + * @returns Parsed value. + */ + public static getInteger(value: string): string { + if (INTEGER_REGEXP.test(value)) { + return value; + } + return null; + } + + /** + * Returns float. + * + * @param value Value. + * @returns Parsed value. + */ + public static getFloat(value: string): string { + if (FLOAT_REGEXP.test(value)) { + return value; + } + return null; + } + + /** + * Returns gradient. + * + * @param value Value. + * @returns Parsed value. + */ + public static getGradient(value: string): string { + if (GRADIENT_REGEXP.test(value)) { + return value; + } + return null; + } + + /** + * Returns color. + * + * @param value Value. + * @returns Parsed value. + */ + public static getColor(value: string): string { + const lowerValue = value.toLowerCase(); + if (COLORS.includes(lowerValue)) { + return lowerValue; + } + if (COLOR_REGEXP.test(value)) { + return value.replace(/,([^ ])/g, ', $1'); + } + return null; + } + + /** + * Returns URL. + * + * Based on: + * https://github.com/jsdom/cssstyle/blob/master/lib/parsers.js#L222 + * + * @param value Value. + * @returns Parsed value. + */ + public static getURL(value: string): string { + if (!value) { + return null; + } + + if (value.toLowerCase() === 'none') { + return 'none'; + } + + const result = URL_REGEXP.exec(value); + + if (!result) { + return null; + } + + let url = result[1]; + + if ((url[0] === '"' || url[0] === "'") && url[0] !== url[url.length - 1]) { + return null; + } + + if (url[0] === '"' || url[0] === "'") { + url = url.substring(1, url.length - 1); + } + + for (let i = 0; i < url.length; i++) { + switch (url[i]) { + case '(': + case ')': + case ' ': + case '\t': + case '\n': + case "'": + case '"': + return null; + case '\\': + i++; + break; + } + } + + return `url("${url}")`; + } + + /** + * Returns global initial value. + * + * @param value Value. + * @returns Parsed value. + */ + public static getInitial(value: string): string { + return value.toLowerCase() === 'initial' ? 'initial' : null; + } + + /** + * Returns CSS variable. + * + * @param value Value. + * @returns Parsed value. + */ + public static getVariable(value: string): string { + const cssVariableMatch = value.match(CSS_VARIABLE_REGEXP); + if (cssVariableMatch) { + return `var(${cssVariableMatch[1]})`; + } + return null; + } + + /** + * Returns global. + * + * @param value Value. + * @returns Parsed value. + */ + public static getGlobal(value: string): string { + const lowerValue = value.toLowerCase(); + return GLOBALS.includes(lowerValue) ? lowerValue : null; + } + + /** + * Returns global, unless it is not set to 'initial' as it is sometimes treated different. + * + * @param value Value. + * @returns Parsed value. + */ + public static getGlobalExceptInitial(value: string): string { + const lowerValue = value.toLowerCase(); + return lowerValue !== 'initial' && GLOBALS.includes(lowerValue) ? lowerValue : null; + } +} diff --git a/packages/happy-dom/src/css/declaration/utilities/ICSSStyleDeclarationPropertyValue.ts b/packages/happy-dom/src/css/declaration/utilities/ICSSStyleDeclarationPropertyValue.ts new file mode 100644 index 000000000..ad636ebc3 --- /dev/null +++ b/packages/happy-dom/src/css/declaration/utilities/ICSSStyleDeclarationPropertyValue.ts @@ -0,0 +1,4 @@ +export default interface ICSSStyleDeclarationPropertyValue { + readonly value: string; + readonly important: boolean; +} diff --git a/packages/happy-dom/src/css/rules/CSSContainerRule.ts b/packages/happy-dom/src/css/rules/CSSContainerRule.ts new file mode 100644 index 000000000..dc57f69dc --- /dev/null +++ b/packages/happy-dom/src/css/rules/CSSContainerRule.ts @@ -0,0 +1,23 @@ +import CSSRule from '../CSSRule'; + +/** + * CSSRule interface. + */ +export default class CSSContainerRule extends CSSRule { + public readonly type = CSSRule.CONTAINER_RULE; + public readonly cssRules: CSSRule[] = []; + public readonly conditionalText = ''; + + /** + * Returns css text. + * + * @returns CSS text. + */ + public get cssText(): string { + let cssText = ''; + for (const cssRule of this.cssRules) { + cssText += cssRule.cssText; + } + return `@container ${this.conditionalText} { ${cssText} }`; + } +} diff --git a/packages/happy-dom/src/css/rules/CSSFontFaceRule.ts b/packages/happy-dom/src/css/rules/CSSFontFaceRule.ts index fe3246f76..8c2ebfbe3 100644 --- a/packages/happy-dom/src/css/rules/CSSFontFaceRule.ts +++ b/packages/happy-dom/src/css/rules/CSSFontFaceRule.ts @@ -1,10 +1,25 @@ import CSSRule from '../CSSRule'; -import CSSStyleDeclaration from '../CSSStyleDeclaration'; +import CSSStyleDeclaration from '../declaration/CSSStyleDeclaration'; /** * CSSRule interface. */ export default class CSSFontFaceRule extends CSSRule { public readonly type = CSSRule.FONT_FACE_RULE; - public readonly style: CSSStyleDeclaration; + public _cssText = ''; + private _style: CSSStyleDeclaration = null; + + /** + * Returns style. + * + * @returns Style. + */ + public get style(): CSSStyleDeclaration { + if (!this._style) { + this._style = new CSSStyleDeclaration(); + (this._style.parentRule) = this; + this._style.cssText = this._cssText; + } + return this._style; + } } diff --git a/packages/happy-dom/src/css/rules/CSSKeyframeRule.ts b/packages/happy-dom/src/css/rules/CSSKeyframeRule.ts index 07d6dd0e6..b88711968 100644 --- a/packages/happy-dom/src/css/rules/CSSKeyframeRule.ts +++ b/packages/happy-dom/src/css/rules/CSSKeyframeRule.ts @@ -1,13 +1,28 @@ import CSSRule from '../CSSRule'; -import CSSStyleDeclaration from '../CSSStyleDeclaration'; +import CSSStyleDeclaration from '../declaration/CSSStyleDeclaration'; /** * CSSRule interface. */ export default class CSSKeyframeRule extends CSSRule { public readonly type = CSSRule.KEYFRAME_RULE; - public readonly style: CSSStyleDeclaration; public readonly keyText: string; + public _cssText = ''; + private _style: CSSStyleDeclaration = null; + + /** + * Returns style. + * + * @returns Style. + */ + public get style(): CSSStyleDeclaration { + if (!this._style) { + this._style = new CSSStyleDeclaration(); + (this._style.parentRule) = this; + this._style.cssText = this._cssText; + } + return this._style; + } /** * Returns css text. diff --git a/packages/happy-dom/src/css/rules/CSSKeyframesRule.ts b/packages/happy-dom/src/css/rules/CSSKeyframesRule.ts index af9a89874..cac17f5ea 100644 --- a/packages/happy-dom/src/css/rules/CSSKeyframesRule.ts +++ b/packages/happy-dom/src/css/rules/CSSKeyframesRule.ts @@ -1,5 +1,5 @@ import CSSRule from '../CSSRule'; -import CSSStyleDeclaration from '../CSSStyleDeclaration'; +import CSSStyleDeclaration from '../declaration/CSSStyleDeclaration'; import CSSKeyframeRule from './CSSKeyframeRule'; const CSS_RULE_REGEXP = /([^{]+){([^}]+)}/; diff --git a/packages/happy-dom/src/css/rules/CSSStyleRule.ts b/packages/happy-dom/src/css/rules/CSSStyleRule.ts index cda9019d2..517f70f42 100644 --- a/packages/happy-dom/src/css/rules/CSSStyleRule.ts +++ b/packages/happy-dom/src/css/rules/CSSStyleRule.ts @@ -1,14 +1,29 @@ import CSSRule from '../CSSRule'; -import CSSStyleDeclaration from '../CSSStyleDeclaration'; +import CSSStyleDeclaration from '../declaration/CSSStyleDeclaration'; /** * CSSRule interface. */ export default class CSSStyleRule extends CSSRule { public readonly type = CSSRule.STYLE_RULE; - public readonly style: CSSStyleDeclaration; public readonly selectorText = ''; public readonly styleMap = new Map(); + public _cssText = ''; + private _style: CSSStyleDeclaration = null; + + /** + * Returns style. + * + * @returns Style. + */ + public get style(): CSSStyleDeclaration { + if (!this._style) { + this._style = new CSSStyleDeclaration(); + (this._style.parentRule) = this; + this._style.cssText = this._cssText; + } + return this._style; + } /** * Returns css text. diff --git a/packages/happy-dom/src/event/Event.ts b/packages/happy-dom/src/event/Event.ts index 73ce1f614..956e57d4b 100644 --- a/packages/happy-dom/src/event/Event.ts +++ b/packages/happy-dom/src/event/Event.ts @@ -1,5 +1,4 @@ import IEventInit from './IEventInit'; -import EventTarget from './EventTarget'; import INode from '../nodes/node/INode'; import IWindow from '../window/IWindow'; import IShadowRoot from '../nodes/shadow-root/IShadowRoot'; @@ -10,8 +9,8 @@ import IEventTarget from './IEventTarget'; */ export default class Event { public composed = false; - public currentTarget: EventTarget = null; - public target: EventTarget = null; + public currentTarget: IEventTarget = null; + public target: IEventTarget = null; public bubbles = false; public cancelable = false; public defaultPrevented = false; diff --git a/packages/happy-dom/src/event/events/IMediaQueryListInit.ts b/packages/happy-dom/src/event/events/IMediaQueryListInit.ts new file mode 100644 index 000000000..0f202840a --- /dev/null +++ b/packages/happy-dom/src/event/events/IMediaQueryListInit.ts @@ -0,0 +1,6 @@ +import IEventInit from '../IEventInit'; + +export default interface IMediaQueryListInit extends IEventInit { + matches?: boolean; + media?: string; +} diff --git a/packages/happy-dom/src/event/events/MediaQueryListEvent.ts b/packages/happy-dom/src/event/events/MediaQueryListEvent.ts new file mode 100644 index 000000000..384269c33 --- /dev/null +++ b/packages/happy-dom/src/event/events/MediaQueryListEvent.ts @@ -0,0 +1,25 @@ +import Event from '../Event'; +import IMediaQueryListInit from './IMediaQueryListInit'; + +/** + * + */ +export default class MediaQueryListEvent extends Event { + public readonly matches: boolean = false; + public readonly media: string = ''; + + /** + * Constructor. + * + * @param type Event type. + * @param [eventInit] Event init. + */ + constructor(type: string, eventInit: IMediaQueryListInit = null) { + super(type, eventInit); + + if (eventInit) { + this.matches = eventInit.matches || false; + this.media = eventInit.media || ''; + } + } +} diff --git a/packages/happy-dom/src/exception/DOMException.ts b/packages/happy-dom/src/exception/DOMException.ts index c6728be23..c68726997 100644 --- a/packages/happy-dom/src/exception/DOMException.ts +++ b/packages/happy-dom/src/exception/DOMException.ts @@ -1,3 +1,5 @@ +import DOMExceptionNameEnum from './DOMExceptionNameEnum'; + /** * DOM Exception. * @@ -14,8 +16,6 @@ export default class DOMException extends Error { constructor(message: string, name: string = null) { super(message); - if (name) { - this.name = name; - } + this.name = name || DOMExceptionNameEnum.domException; } } diff --git a/packages/happy-dom/src/exception/DOMExceptionNameEnum.ts b/packages/happy-dom/src/exception/DOMExceptionNameEnum.ts index c5e2b94ec..08aa5cb5c 100644 --- a/packages/happy-dom/src/exception/DOMExceptionNameEnum.ts +++ b/packages/happy-dom/src/exception/DOMExceptionNameEnum.ts @@ -7,6 +7,7 @@ enum DOMExceptionNameEnum { wrongDocumentError = 'WrongDocumentError', invalidNodeTypeError = 'InvalidNodeTypeError', invalidCharacterError = 'InvalidCharacterError', - notFoundError = 'NotFoundError' + notFoundError = 'NotFoundError', + domException = 'DOMException' } export default DOMExceptionNameEnum; diff --git a/packages/happy-dom/src/file/Blob.ts b/packages/happy-dom/src/file/Blob.ts index bfcfe8842..86cf6d5a3 100644 --- a/packages/happy-dom/src/file/Blob.ts +++ b/packages/happy-dom/src/file/Blob.ts @@ -110,7 +110,6 @@ export default class Blob implements IBlob { return blob; } - /** * Returns a Promise that resolves to a ArrayBuffer. * @@ -120,8 +119,11 @@ export default class Blob implements IBlob { // Reference: // https://github.com/web-std/io/blob/c88170bf24f064adfbb3586a21fb76650ca5a9ab/packages/blob/src/blob.js#L139-L148 // https://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer + /** + * + */ public async arrayBuffer(): Promise { - return new Uint8Array(this._buffer).buffer + return new Uint8Array(this._buffer).buffer; } /** diff --git a/packages/happy-dom/src/index.ts b/packages/happy-dom/src/index.ts index be83d4675..11cb61668 100644 --- a/packages/happy-dom/src/index.ts +++ b/packages/happy-dom/src/index.ts @@ -13,7 +13,7 @@ import File from './file/File'; import FileReader from './file/FileReader'; import DOMException from './exception/DOMException'; import History from './history/History'; -import CSSStyleDeclaration from './css/CSSStyleDeclaration'; +import CSSStyleDeclaration from './css/declaration/CSSStyleDeclaration'; import Screen from './screen/Screen'; import AsyncTaskManager from './async-task-manager/AsyncTaskManager'; import NodeFilter from './tree-walker/NodeFilter'; @@ -100,6 +100,13 @@ import CustomElementRegistry from './custom-element/CustomElementRegistry'; import XMLParser from './xml-parser/XMLParser'; import XMLSerializer from './xml-serializer/XMLSerializer'; import CSSStyleSheet from './css/CSSStyleSheet'; +import CSSRule from './css/CSSRule'; +import CSSContainerRule from './css/rules/CSSContainerRule'; +import CSSFontFaceRule from './css/rules/CSSFontFaceRule'; +import CSSKeyframeRule from './css/rules/CSSKeyframeRule'; +import CSSKeyframesRule from './css/rules/CSSKeyframesRule'; +import CSSMediaRule from './css/rules/CSSMediaRule'; +import CSSStyleRule from './css/rules/CSSStyleRule'; import Storage from './storage/Storage'; import DOMRect from './nodes/element/DOMRect'; import { URLSearchParams } from 'url'; @@ -211,6 +218,13 @@ export { XMLParser, XMLSerializer, CSSStyleSheet, + CSSRule, + CSSContainerRule, + CSSFontFaceRule, + CSSKeyframeRule, + CSSKeyframesRule, + CSSMediaRule, + CSSStyleRule, Storage, DOMRect, URLSearchParams, diff --git a/packages/happy-dom/src/match-media/MediaQueryList.ts b/packages/happy-dom/src/match-media/MediaQueryList.ts index 250aa3472..175a5394e 100644 --- a/packages/happy-dom/src/match-media/MediaQueryList.ts +++ b/packages/happy-dom/src/match-media/MediaQueryList.ts @@ -1,5 +1,11 @@ import EventTarget from '../event/EventTarget'; import Event from '../event/Event'; +import IWindow from '../window/IWindow'; +import IEventListener from '../event/IEventListener'; +import MediaQueryListEvent from '../event/events/MediaQueryListEvent'; + +const MEDIA_REGEXP = + /min-width: *([0-9]+) *px|max-width: *([0-9]+) *px|min-height: *([0-9]+) *px|max-height: *([0-9]+) *px/; /** * Media Query List. @@ -8,26 +14,41 @@ import Event from '../event/Event'; * https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList. */ export default class MediaQueryList extends EventTarget { - public _matches = false; - public _media = ''; + public readonly media: string = ''; public onchange: (event: Event) => void = null; + private _ownerWindow: IWindow; /** - * Returns "true" if the document matches. + * Constructor. * - * @returns Matches. + * @param ownerWindow Window. + * @param media Media. */ - public get matches(): boolean { - return this._matches; + constructor(ownerWindow: IWindow, media: string) { + super(); + this._ownerWindow = ownerWindow; + this.media = media; } /** - * Returns the serialized media query. + * Returns "true" if the document matches. * - * @returns Serialized media query. + * @returns Matches. */ - public get media(): string { - return this._media; + public get matches(): boolean { + const match = MEDIA_REGEXP.exec(this.media); + if (match) { + if (match[1]) { + return this._ownerWindow.innerWidth >= parseInt(match[1]); + } else if (match[2]) { + return this._ownerWindow.innerWidth <= parseInt(match[2]); + } else if (match[3]) { + return this._ownerWindow.innerHeight >= parseInt(match[3]); + } else if (match[4]) { + return this._ownerWindow.innerHeight <= parseInt(match[4]); + } + } + return false; } /** @@ -49,4 +70,36 @@ export default class MediaQueryList extends EventTarget { public removeListener(callback: (event: Event) => void): void { this.removeEventListener('change', callback); } + + /** + * @override + */ + public addEventListener(type: string, listener: IEventListener | ((event: Event) => void)): void { + super.addEventListener(type, listener); + if (type === 'change') { + let matchesState = false; + const resizeListener = (): void => { + const matches = this.matches; + if (matches !== matchesState) { + matchesState = matches; + this.dispatchEvent(new MediaQueryListEvent('change', { matches, media: this.media })); + } + }; + listener['_windowResizeListener'] = resizeListener; + this._ownerWindow.addEventListener('resize', resizeListener); + } + } + + /** + * @override + */ + public removeEventListener( + type: string, + listener: IEventListener | ((event: Event) => void) + ): void { + super.removeEventListener(type, listener); + if (type === 'change' && listener['_windowResizeListener']) { + this._ownerWindow.removeEventListener('resize', listener['_windowResizeListener']); + } + } } diff --git a/packages/happy-dom/src/attribute/Attr.ts b/packages/happy-dom/src/nodes/attr/Attr.ts similarity index 73% rename from packages/happy-dom/src/attribute/Attr.ts rename to packages/happy-dom/src/nodes/attr/Attr.ts index eea007c45..6a8814121 100644 --- a/packages/happy-dom/src/attribute/Attr.ts +++ b/packages/happy-dom/src/nodes/attr/Attr.ts @@ -1,12 +1,13 @@ -import IDocument from '../nodes/document/IDocument'; -import IElement from '../nodes/element/IElement'; +import IElement from '../element/IElement'; +import Node from '../node/Node'; +import IAttr from './IAttr'; /** * Attribute node interface. * * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Attr. */ -export default class Attr { +export default class Attr extends Node implements IAttr { public value: string = null; public name: string = null; public namespaceURI: string = null; @@ -16,11 +17,6 @@ export default class Attr { */ public readonly ownerElement: IElement = null; - /** - * @deprecated - */ - public readonly ownerDocument: IDocument = null; - /** * @deprecated */ @@ -43,4 +39,11 @@ export default class Attr { public get prefix(): string { return this.name ? this.name.split(':')[0] : null; } + + /** + * @override + */ + public get textContent(): string { + return this.value; + } } diff --git a/packages/happy-dom/src/nodes/attr/IAttr.ts b/packages/happy-dom/src/nodes/attr/IAttr.ts new file mode 100644 index 000000000..aa6f01bc3 --- /dev/null +++ b/packages/happy-dom/src/nodes/attr/IAttr.ts @@ -0,0 +1,15 @@ +import IElement from '../element/IElement'; +import INode from './../node/INode'; + +/** + * Attr. + */ +export default interface IAttr extends INode { + value: string; + name: string; + namespaceURI: string; + readonly ownerElement: IElement; + readonly specified: boolean; + readonly localName: string; + readonly prefix: string; +} diff --git a/packages/happy-dom/src/nodes/child-node/ChildNodeUtility.ts b/packages/happy-dom/src/nodes/child-node/ChildNodeUtility.ts index 77bb8a386..5efb28624 100644 --- a/packages/happy-dom/src/nodes/child-node/ChildNodeUtility.ts +++ b/packages/happy-dom/src/nodes/child-node/ChildNodeUtility.ts @@ -1,3 +1,4 @@ +import DOMException from '../../exception/DOMException'; import XMLParser from '../../xml-parser/XMLParser'; import Document from '../document/Document'; import INode from '../node/INode'; @@ -29,7 +30,7 @@ export default class ChildNodeUtility { const parent = childNode.parentNode; if (!parent) { - return; + throw new DOMException('This element has no parent node.'); } for (const node of nodes) { diff --git a/packages/happy-dom/src/nodes/document/Document.ts b/packages/happy-dom/src/nodes/document/Document.ts index 2b20a0127..02f449f6b 100644 --- a/packages/happy-dom/src/nodes/document/Document.ts +++ b/packages/happy-dom/src/nodes/document/Document.ts @@ -11,7 +11,7 @@ import Event from '../../event/Event'; import DOMImplementation from '../../dom-implementation/DOMImplementation'; import ElementTag from '../../config/ElementTag'; import INodeFilter from '../../tree-walker/INodeFilter'; -import Attr from '../../attribute/Attr'; +import Attr from '../attr/Attr'; import NamespaceURI from '../../config/NamespaceURI'; import DocumentType from '../document-type/DocumentType'; import ParentNodeUtility from '../parent-node/ParentNodeUtility'; @@ -40,6 +40,7 @@ import Selection from '../../selection/Selection'; import IShadowRoot from '../shadow-root/IShadowRoot'; import Range from '../../range/Range'; import IHTMLBaseElement from '../html-base-element/IHTMLBaseElement'; +import IAttr from '../attr/IAttr'; /** * Document. @@ -716,14 +717,11 @@ export default class Document extends Node implements IDocument { /** * Creates an Attr node. * - * @param name Name. + * @param qualifiedName Name. * @returns Attribute. */ - public createAttribute(name: string): Attr { - const attribute = new Attr(); - attribute.name = name.toLowerCase(); - (attribute.ownerDocument) = this; - return attribute; + public createAttribute(qualifiedName: string): IAttr { + return this.createAttributeNS(null, qualifiedName.toLowerCase()); } /** @@ -733,12 +731,12 @@ export default class Document extends Node implements IDocument { * @param qualifiedName Qualified name. * @returns Element. */ - public createAttributeNS(namespaceURI: string, qualifiedName: string): Attr { + public createAttributeNS(namespaceURI: string, qualifiedName: string): IAttr { + Attr._ownerDocument = this; const attribute = new Attr(); attribute.namespaceURI = namespaceURI; attribute.name = qualifiedName; - (attribute.ownerDocument) = this; - return attribute; + return attribute; } /** diff --git a/packages/happy-dom/src/nodes/document/IDocument.ts b/packages/happy-dom/src/nodes/document/IDocument.ts index a1967ec27..bb5f6059d 100644 --- a/packages/happy-dom/src/nodes/document/IDocument.ts +++ b/packages/happy-dom/src/nodes/document/IDocument.ts @@ -5,7 +5,7 @@ import TreeWalker from '../../tree-walker/TreeWalker'; import Event from '../../event/Event'; import DOMImplementation from '../../dom-implementation/DOMImplementation'; import INodeFilter from '../../tree-walker/INodeFilter'; -import Attr from '../../attribute/Attr'; +import IAttr from '../attr/IAttr'; import IDocumentType from '../document-type/IDocumentType'; import IParentNode from '../parent-node/IParentNode'; import INode from '../node/INode'; @@ -125,7 +125,7 @@ export default interface IDocument extends IParentNode { * @param name Name. * @returns Attribute. */ - createAttribute(name: string): Attr; + createAttribute(name: string): IAttr; /** * Creates a namespaced Attr node. @@ -134,7 +134,7 @@ export default interface IDocument extends IParentNode { * @param qualifiedName Qualified name. * @returns Element. */ - createAttributeNS(namespaceURI: string, qualifiedName: string): Attr; + createAttributeNS(namespaceURI: string, qualifiedName: string): IAttr; /** * Imports a node. diff --git a/packages/happy-dom/src/nodes/element/Element.ts b/packages/happy-dom/src/nodes/element/Element.ts index 203b3f249..0d3809347 100644 --- a/packages/happy-dom/src/nodes/element/Element.ts +++ b/packages/happy-dom/src/nodes/element/Element.ts @@ -1,6 +1,6 @@ import Node from '../node/Node'; import ShadowRoot from '../shadow-root/ShadowRoot'; -import Attr from '../../attribute/Attr'; +import Attr from '../attr/Attr'; import DOMRect from './DOMRect'; import DOMTokenList from '../../dom-token-list/DOMTokenList'; import IDOMTokenList from '../../dom-token-list/IDOMTokenList'; @@ -26,6 +26,7 @@ import { TInsertAdjacentPositions } from './IElement'; import IText from '../text/IText'; import IDOMRectList from './IDOMRectList'; import DOMRectListFactory from './DOMRectListFactory'; +import IAttr from '../attr/IAttr'; /** * Element. @@ -46,7 +47,7 @@ export default class Element extends Node implements IElement { // Used for being able to access closed shadow roots public _shadowRoot: IShadowRoot = null; - public _attributes: { [k: string]: Attr } = {}; + public _attributes: { [k: string]: IAttr } = {}; private _classList: DOMTokenList = null; public _isValue?: string; @@ -211,7 +212,7 @@ export default class Element extends Node implements IElement { * * @returns Attributes. */ - public get attributes(): { [k: string]: Attr | number } { + public get attributes(): { [k: string | number]: IAttr } & { length: number } { const attributes = Object.values(this._attributes); return Object.assign({}, this._attributes, attributes, { length: attributes.length @@ -302,6 +303,8 @@ export default class Element extends Node implements IElement { public cloneNode(deep = false): IElement { const clone = super.cloneNode(deep); + Attr._ownerDocument = this.ownerDocument; + for (const key of Object.keys(this._attributes)) { const attr = Object.assign(new Attr(), this._attributes[key]); (attr.ownerElement) = clone; @@ -802,13 +805,13 @@ export default class Element extends Node implements IElement { * @param attribute Attribute. * @returns Replaced attribute. */ - public setAttributeNode(attribute: Attr): Attr { + public setAttributeNode(attribute: IAttr): IAttr { const name = this._getAttributeName(attribute.name); const replacedAttribute = this._attributes[name]; const oldValue = replacedAttribute ? replacedAttribute.value : null; attribute.name = name; - (attribute.ownerElement) = this; + (attribute.ownerElement) = this; (attribute.ownerDocument) = this.ownerDocument; this._attributes[name] = attribute; @@ -849,7 +852,7 @@ export default class Element extends Node implements IElement { * @param attribute Attribute. * @returns Replaced attribute. */ - public setAttributeNodeNS(attribute: Attr): Attr { + public setAttributeNodeNS(attribute: IAttr): IAttr { return this.setAttributeNode(attribute); } @@ -859,7 +862,7 @@ export default class Element extends Node implements IElement { * @param name Name. * @returns Replaced attribute. */ - public getAttributeNode(name: string): Attr { + public getAttributeNode(name: string): IAttr { return this._attributes[this._getAttributeName(name)] || null; } @@ -870,7 +873,7 @@ export default class Element extends Node implements IElement { * @param name Name. * @returns Replaced attribute. */ - public getAttributeNodeNS(namespace: string, name: string): Attr { + public getAttributeNodeNS(namespace: string, name: string): IAttr { const attributeName = this._getAttributeName(name); if ( this._attributes[attributeName] && @@ -893,7 +896,7 @@ export default class Element extends Node implements IElement { * * @param attribute Attribute. */ - public removeAttributeNode(attribute: Attr): void { + public removeAttributeNode(attribute: IAttr): void { delete this._attributes[attribute.name]; this._updateDomListIndices(); @@ -930,7 +933,7 @@ export default class Element extends Node implements IElement { * * @param attribute Attribute. */ - public removeAttributeNodeNS(attribute: Attr): void { + public removeAttributeNodeNS(attribute: IAttr): void { this.removeAttributeNode(attribute); } diff --git a/packages/happy-dom/src/nodes/element/IElement.ts b/packages/happy-dom/src/nodes/element/IElement.ts index 72c0cab6f..cdbb41370 100644 --- a/packages/happy-dom/src/nodes/element/IElement.ts +++ b/packages/happy-dom/src/nodes/element/IElement.ts @@ -1,5 +1,5 @@ import IShadowRoot from '../shadow-root/IShadowRoot'; -import Attr from '../../attribute/Attr'; +import IAttr from '../attr/IAttr'; import DOMRect from './DOMRect'; import IDOMTokenList from '../../dom-token-list/IDOMTokenList'; import INode from './../node/INode'; @@ -27,7 +27,7 @@ export default interface IElement extends IChildNode, INonDocumentTypeChildNode, slot: string; readonly nodeName: string; readonly localName: string; - readonly attributes: { [k: string]: Attr | number }; + readonly attributes: { [k: string | number]: IAttr } & { length: number }; /** * Attribute changed callback. @@ -190,7 +190,7 @@ export default interface IElement extends IChildNode, INonDocumentTypeChildNode, * @param attribute Attribute. * @returns Replaced attribute. */ - setAttributeNode(attribute: Attr): Attr; + setAttributeNode(attribute: IAttr): IAttr; /** * The setAttributeNodeNS() method adds a new Attr node to the specified element. @@ -198,7 +198,7 @@ export default interface IElement extends IChildNode, INonDocumentTypeChildNode, * @param attribute Attribute. * @returns Replaced attribute. */ - setAttributeNodeNS(attribute: Attr): Attr; + setAttributeNodeNS(attribute: IAttr): IAttr; /** * Returns an Attr node. @@ -206,7 +206,7 @@ export default interface IElement extends IChildNode, INonDocumentTypeChildNode, * @param name Name. * @returns Replaced attribute. */ - getAttributeNode(name: string): Attr; + getAttributeNode(name: string): IAttr; /** * Returns a namespaced Attr node. @@ -215,21 +215,21 @@ export default interface IElement extends IChildNode, INonDocumentTypeChildNode, * @param nodeName Node name. * @returns Replaced attribute. */ - getAttributeNodeNS(namespace: string, nodeName: string): Attr; + getAttributeNodeNS(namespace: string, nodeName: string): IAttr; /** * Removes an Attr node. * * @param attribute Attribute. */ - removeAttributeNode(attribute: Attr): void; + removeAttributeNode(attribute: IAttr): void; /** * Removes an Attr node. * * @param attribute Attribute. */ - removeAttributeNodeNS(attribute: Attr): void; + removeAttributeNodeNS(attribute: IAttr): void; /** * Clones a node. diff --git a/packages/happy-dom/src/nodes/html-element/HTMLElement.ts b/packages/happy-dom/src/nodes/html-element/HTMLElement.ts index e7bc9eb4a..5d22a05e7 100644 --- a/packages/happy-dom/src/nodes/html-element/HTMLElement.ts +++ b/packages/happy-dom/src/nodes/html-element/HTMLElement.ts @@ -1,11 +1,12 @@ import Element from '../element/Element'; import IHTMLElement from './IHTMLElement'; -import CSSStyleDeclaration from '../../css/CSSStyleDeclaration'; -import Attr from '../../attribute/Attr'; +import CSSStyleDeclaration from '../../css/declaration/CSSStyleDeclaration'; +import IAttr from '../attr/IAttr'; import FocusEvent from '../../event/events/FocusEvent'; import PointerEvent from '../../event/events/PointerEvent'; -import Node from '../node/Node'; import DatasetUtility from './DatasetUtility'; +import NodeTypeEnum from '../node/NodeTypeEnum'; +import DOMException from '../../exception/DOMException'; /** * HTML Element. @@ -54,32 +55,109 @@ export default class HTMLElement extends Element implements IHTMLElement { /** * Returns inner text, which is the rendered appearance of text. * + * @see https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute * @returns Inner text. */ public get innerText(): string { + if (!this.isConnected) { + return this.textContent; + } + let result = ''; + for (const childNode of this.childNodes) { - if (childNode instanceof HTMLElement) { - if (childNode.tagName !== 'SCRIPT' && childNode.tagName !== 'STYLE') { - result += childNode.innerText; + if (childNode.nodeType === NodeTypeEnum.elementNode) { + const childElement = childNode; + const computedStyle = this.ownerDocument.defaultView.getComputedStyle(childElement); + + if (childElement.tagName !== 'SCRIPT' && childElement.tagName !== 'STYLE') { + const display = computedStyle.display; + if (display !== 'none') { + const textTransform = computedStyle.textTransform; + + if ((display === 'block' || display === 'flex') && result) { + result += '\n'; + } + + let text = childElement.innerText; + + switch (textTransform) { + case 'uppercase': + text = text.toUpperCase(); + break; + case 'lowercase': + text = text.toLowerCase(); + break; + case 'capitalize': + text = text.replace(/(^|\s)\S/g, (l) => l.toUpperCase()); + break; + } + + result += text; + } } - } else if ( - childNode.nodeType === Node.ELEMENT_NODE || - childNode.nodeType === Node.TEXT_NODE - ) { - result += childNode.textContent; + } else if (childNode.nodeType === NodeTypeEnum.textNode) { + result += childNode.textContent.replace(/[\n\r]/, ''); } } + return result; } /** * Sets the inner text, which is the rendered appearance of text. * + * @see https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute * @param innerText Inner text. */ - public set innerText(innerText: string) { - this.textContent = innerText; + public set innerText(text: string) { + for (const child of this.childNodes.slice()) { + this.removeChild(child); + } + + const texts = text.split(/[\n\r]/); + + for (let i = 0, max = texts.length; i < max; i++) { + if (i !== 0) { + this.appendChild(this.ownerDocument.createElement('br')); + } + this.appendChild(this.ownerDocument.createTextNode(texts[i])); + } + } + + /** + * Returns outer text. + * + * @see https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute + * @returns HTML. + */ + public get outerText(): string { + return this.innerText; + } + + /** + * Sets outer text. + * + * @see https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute + * @param text Text. + */ + public set outerText(text: string) { + if (!this.parentNode) { + throw new DOMException( + "Failed to set the 'outerHTML' property on 'Element': This element has no parent node." + ); + } + + const texts = text.split(/[\n\r]/); + + for (let i = 0, max = texts.length; i < max; i++) { + if (i !== 0) { + this.parentNode.insertBefore(this.ownerDocument.createElement('br'), this); + } + this.parentNode.insertBefore(this.ownerDocument.createTextNode(texts[i]), this); + } + + this.parentNode.removeChild(this); } /** @@ -89,7 +167,7 @@ export default class HTMLElement extends Element implements IHTMLElement { */ public get style(): CSSStyleDeclaration { if (!this._style) { - this._style = new CSSStyleDeclaration(this._attributes); + this._style = new CSSStyleDeclaration(this); } return this._style; } @@ -311,7 +389,7 @@ export default class HTMLElement extends Element implements IHTMLElement { * @param attribute Attribute. * @returns Replaced attribute. */ - public setAttributeNode(attribute: Attr): Attr { + public setAttributeNode(attribute: IAttr): IAttr { const replacedAttribute = super.setAttributeNode(attribute); if (attribute.name === 'style' && this._style) { @@ -327,7 +405,7 @@ export default class HTMLElement extends Element implements IHTMLElement { * @override * @param attribute Attribute. */ - public removeAttributeNode(attribute: Attr): void { + public removeAttributeNode(attribute: IAttr): void { super.removeAttributeNode(attribute); if (attribute.name === 'style' && this._style) { diff --git a/packages/happy-dom/src/nodes/html-element/IHTMLElement.ts b/packages/happy-dom/src/nodes/html-element/IHTMLElement.ts index a88fa6e46..db6810764 100644 --- a/packages/happy-dom/src/nodes/html-element/IHTMLElement.ts +++ b/packages/happy-dom/src/nodes/html-element/IHTMLElement.ts @@ -1,4 +1,4 @@ -import CSSStyleDeclaration from '../../css/CSSStyleDeclaration'; +import CSSStyleDeclaration from '../../css/declaration/CSSStyleDeclaration'; import IElement from '../element/IElement'; /** @@ -9,6 +9,7 @@ import IElement from '../element/IElement'; */ export default interface IHTMLElement extends IElement { style: CSSStyleDeclaration; + dataset: { [key: string]: string }; tabIndex: number; offsetHeight: number; offsetWidth: number; @@ -17,6 +18,7 @@ export default interface IHTMLElement extends IElement { clientHeight: number; clientWidth: number; innerText: string; + outerText: string; /** * Triggers a click event. diff --git a/packages/happy-dom/src/nodes/html-link-element/HTMLLinkElement.ts b/packages/happy-dom/src/nodes/html-link-element/HTMLLinkElement.ts index cd753d35a..22ccefadf 100644 --- a/packages/happy-dom/src/nodes/html-link-element/HTMLLinkElement.ts +++ b/packages/happy-dom/src/nodes/html-link-element/HTMLLinkElement.ts @@ -1,4 +1,4 @@ -import Attr from '../../attribute/Attr'; +import IAttr from '../attr/IAttr'; import CSSStyleSheet from '../../css/CSSStyleSheet'; import ResourceFetchHandler from '../../fetch/ResourceFetchHandler'; import HTMLElement from '../html-element/HTMLElement'; @@ -186,7 +186,7 @@ export default class HTMLLinkElement extends HTMLElement implements IHTMLLinkEle * @param attribute Attribute. * @returns Replaced attribute. */ - public setAttributeNode(attribute: Attr): Attr { + public setAttributeNode(attribute: IAttr): IAttr { const replacedAttribute = super.setAttributeNode(attribute); const rel = this.getAttributeNS(null, 'rel'); const href = this.getAttributeNS(null, 'href'); diff --git a/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElement.ts b/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElement.ts index b3191dfe7..8115610a0 100644 --- a/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElement.ts +++ b/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElement.ts @@ -1,4 +1,4 @@ -import Attr from '../../attribute/Attr'; +import IAttr from '../attr/IAttr'; import HTMLElement from '../html-element/HTMLElement'; import IHTMLScriptElement from './IHTMLScriptElement'; import ScriptUtility from './ScriptUtility'; @@ -158,7 +158,7 @@ export default class HTMLScriptElement extends HTMLElement implements IHTMLScrip * @param attribute Attribute. * @returns Replaced attribute. */ - public setAttributeNode(attribute: Attr): Attr { + public setAttributeNode(attribute: IAttr): IAttr { const replacedAttribute = super.setAttributeNode(attribute); if (attribute.name === 'src' && attribute.value !== null && this.isConnected) { diff --git a/packages/happy-dom/src/nodes/html-style-element/HTMLStyleElement.ts b/packages/happy-dom/src/nodes/html-style-element/HTMLStyleElement.ts index f0c74ff25..335d09c4c 100644 --- a/packages/happy-dom/src/nodes/html-style-element/HTMLStyleElement.ts +++ b/packages/happy-dom/src/nodes/html-style-element/HTMLStyleElement.ts @@ -22,8 +22,8 @@ export default class HTMLStyleElement extends HTMLElement implements IHTMLStyleE } if (!this._styleSheet) { this._styleSheet = new CSSStyleSheet(); - this._styleSheet.replaceSync(this.innerText); } + this._styleSheet.replaceSync(this.textContent); return this._styleSheet; } diff --git a/packages/happy-dom/src/nodes/node/INode.ts b/packages/happy-dom/src/nodes/node/INode.ts index 535ee71d4..54d4afbd2 100644 --- a/packages/happy-dom/src/nodes/node/INode.ts +++ b/packages/happy-dom/src/nodes/node/INode.ts @@ -6,7 +6,9 @@ import NodeTypeEnum from './NodeTypeEnum'; export default interface INode extends IEventTarget { readonly ELEMENT_NODE: NodeTypeEnum; + readonly ATTRIBUTE_NODE: NodeTypeEnum; readonly TEXT_NODE: NodeTypeEnum; + readonly CDATA_SECTION_NODE: NodeTypeEnum; readonly COMMENT_NODE: NodeTypeEnum; readonly DOCUMENT_NODE: NodeTypeEnum; readonly DOCUMENT_TYPE_NODE: NodeTypeEnum; diff --git a/packages/happy-dom/src/nodes/node/Node.ts b/packages/happy-dom/src/nodes/node/Node.ts index d4ea9f648..17bd330f3 100644 --- a/packages/happy-dom/src/nodes/node/Node.ts +++ b/packages/happy-dom/src/nodes/node/Node.ts @@ -21,14 +21,18 @@ export default class Node extends EventTarget implements INode { // Public properties public static readonly ELEMENT_NODE = NodeTypeEnum.elementNode; + public static readonly ATTRIBUTE_NODE = NodeTypeEnum.attributeNode; public static readonly TEXT_NODE = NodeTypeEnum.textNode; + public static readonly CDATA_SECTION_NODE = NodeTypeEnum.cdataSectionNode; public static readonly COMMENT_NODE = NodeTypeEnum.commentNode; public static readonly DOCUMENT_NODE = NodeTypeEnum.documentNode; public static readonly DOCUMENT_TYPE_NODE = NodeTypeEnum.documentTypeNode; public static readonly DOCUMENT_FRAGMENT_NODE = NodeTypeEnum.documentFragmentNode; public static readonly PROCESSING_INSTRUCTION_NODE = NodeTypeEnum.processingInstructionNode; public readonly ELEMENT_NODE = NodeTypeEnum.elementNode; + public readonly ATTRIBUTE_NODE = NodeTypeEnum.attributeNode; public readonly TEXT_NODE = NodeTypeEnum.textNode; + public readonly CDATA_SECTION_NODE = NodeTypeEnum.cdataSectionNode; public readonly COMMENT_NODE = NodeTypeEnum.commentNode; public readonly DOCUMENT_NODE = NodeTypeEnum.documentNode; public readonly DOCUMENT_TYPE_NODE = NodeTypeEnum.documentTypeNode; @@ -58,16 +62,18 @@ export default class Node extends EventTarget implements INode { * @returns Text content. */ public get textContent(): string { + // Sub-classes should implement this method. return null; } /** * Sets text content. * - * @param textContent Text content. + * @param _textContent Text content. */ public set textContent(_textContent) { // Do nothing. + // Sub-classes should implement this method. } /** diff --git a/packages/happy-dom/src/nodes/node/NodeTypeEnum.ts b/packages/happy-dom/src/nodes/node/NodeTypeEnum.ts index 40e856e5c..29d650f26 100644 --- a/packages/happy-dom/src/nodes/node/NodeTypeEnum.ts +++ b/packages/happy-dom/src/nodes/node/NodeTypeEnum.ts @@ -1,6 +1,8 @@ enum NodeTypeEnum { elementNode = 1, + attributeNode = 2, textNode = 3, + cdataSectionNode = 4, commentNode = 8, documentNode = 9, documentTypeNode = 10, diff --git a/packages/happy-dom/src/nodes/svg-element/ISVGElement.ts b/packages/happy-dom/src/nodes/svg-element/ISVGElement.ts index 27a194859..797e98828 100644 --- a/packages/happy-dom/src/nodes/svg-element/ISVGElement.ts +++ b/packages/happy-dom/src/nodes/svg-element/ISVGElement.ts @@ -1,4 +1,4 @@ -import CSSStyleDeclaration from '../../css/CSSStyleDeclaration'; +import CSSStyleDeclaration from '../../css/declaration/CSSStyleDeclaration'; import IElement from '../element/IElement'; import ISVGSVGElement from './ISVGSVGElement'; diff --git a/packages/happy-dom/src/nodes/svg-element/SVGElement.ts b/packages/happy-dom/src/nodes/svg-element/SVGElement.ts index 483beb646..d2c904a5e 100644 --- a/packages/happy-dom/src/nodes/svg-element/SVGElement.ts +++ b/packages/happy-dom/src/nodes/svg-element/SVGElement.ts @@ -1,8 +1,8 @@ -import CSSStyleDeclaration from '../../css/CSSStyleDeclaration'; +import CSSStyleDeclaration from '../../css/declaration/CSSStyleDeclaration'; import Element from '../element/Element'; import ISVGElement from './ISVGElement'; import ISVGSVGElement from './ISVGSVGElement'; -import Attr from '../../attribute/Attr'; +import IAttr from '../attr/IAttr'; /** * SVG Element. @@ -59,7 +59,7 @@ export default class SVGElement extends Element implements ISVGElement { */ public get style(): CSSStyleDeclaration { if (!this._style) { - this._style = new CSSStyleDeclaration(this._attributes); + this._style = new CSSStyleDeclaration(this); } return this._style; } @@ -71,7 +71,7 @@ export default class SVGElement extends Element implements ISVGElement { * @param attribute Attribute. * @returns Replaced attribute. */ - public setAttributeNode(attribute: Attr): Attr { + public setAttributeNode(attribute: IAttr): IAttr { const replacedAttribute = super.setAttributeNode(attribute); if (attribute.name === 'style' && this._style) { @@ -87,7 +87,7 @@ export default class SVGElement extends Element implements ISVGElement { * @override * @param attribute Attribute. */ - public removeAttributeNode(attribute: Attr): void { + public removeAttributeNode(attribute: IAttr): void { super.removeAttributeNode(attribute); if (attribute.name === 'style' && this._style) { diff --git a/packages/happy-dom/src/window/IWindow.ts b/packages/happy-dom/src/window/IWindow.ts index b2d23151f..d3b83a911 100644 --- a/packages/happy-dom/src/window/IWindow.ts +++ b/packages/happy-dom/src/window/IWindow.ts @@ -11,7 +11,6 @@ import Element from '../nodes/element/Element'; import HTMLTemplateElement from '../nodes/html-template-element/HTMLTemplateElement'; import HTMLFormElement from '../nodes/html-form-element/HTMLFormElement'; import HTMLElement from '../nodes/html-element/HTMLElement'; -import IHTMLElement from '../nodes/html-element/IHTMLElement'; import HTMLUnknownElement from '../nodes/html-unknown-element/HTMLUnknownElement'; import HTMLInputElement from '../nodes/html-input-element/HTMLInputElement'; import HTMLTextAreaElement from '../nodes/html-text-area-element/HTMLTextAreaElement'; @@ -35,6 +34,7 @@ import CustomEvent from '../event/events/CustomEvent'; import AnimationEvent from '../event/events/AnimationEvent'; import KeyboardEvent from '../event/events/KeyboardEvent'; import ProgressEvent from '../event/events/ProgressEvent'; +import MediaQueryListEvent from '../event/events/MediaQueryListEvent'; import EventTarget from '../event/EventTarget'; import URL from '../location/URL'; import Location from '../location/Location'; @@ -48,9 +48,16 @@ import DOMException from '../exception/DOMException'; import FileReader from '../file/FileReader'; import History from '../history/History'; import CSSStyleSheet from '../css/CSSStyleSheet'; -import CSSStyleDeclaration from '../css/CSSStyleDeclaration'; +import CSSStyleDeclaration from '../css/declaration/CSSStyleDeclaration'; import CSS from '../css/CSS'; import CSSUnitValue from '../css/CSSUnitValue'; +import CSSRule from '../css/CSSRule'; +import CSSContainerRule from '../css/rules/CSSContainerRule'; +import CSSFontFaceRule from '../css/rules/CSSFontFaceRule'; +import CSSKeyframeRule from '../css/rules/CSSKeyframeRule'; +import CSSKeyframesRule from '../css/rules/CSSKeyframesRule'; +import CSSMediaRule from '../css/rules/CSSMediaRule'; +import CSSStyleRule from '../css/rules/CSSStyleRule'; import PointerEvent from '../event/events/PointerEvent'; import MouseEvent from '../event/events/MouseEvent'; import FocusEvent from '../event/events/FocusEvent'; @@ -84,8 +91,10 @@ import Range from '../range/Range'; import MediaQueryList from '../match-media/MediaQueryList'; import DOMRect from '../nodes/element/DOMRect'; import Window from './Window'; +import Attr from '../nodes/attr/Attr'; import { URLSearchParams } from 'url'; import { Performance } from 'perf_hooks'; +import IElement from '../nodes/element/IElement'; /** * Window without dependencies to server side specific packages. @@ -96,6 +105,8 @@ export default interface IWindow extends IEventTarget, NodeJS.Global { whenAsyncComplete: () => Promise; cancelAsync: () => void; asyncTaskManager: AsyncTaskManager; + setInnerWidth: (width: number) => void; + setInnerHeight: (height: number) => void; }; // Global classes @@ -115,6 +126,7 @@ export default interface IWindow extends IEventTarget, NodeJS.Global { readonly HTMLMetaElement: typeof HTMLMetaElement; readonly HTMLBaseElement: typeof HTMLBaseElement; readonly HTMLDialogElement: typeof HTMLDialogElement; + readonly Attr: typeof Attr; readonly SVGSVGElement: typeof SVGSVGElement; readonly SVGElement: typeof SVGElement; readonly Image: typeof Image; @@ -145,6 +157,7 @@ export default interface IWindow extends IEventTarget, NodeJS.Global { readonly ErrorEvent: typeof ErrorEvent; readonly StorageEvent: typeof StorageEvent; readonly ProgressEvent: typeof ProgressEvent; + readonly MediaQueryListEvent: typeof MediaQueryListEvent; readonly EventTarget: typeof EventTarget; readonly DataTransfer: typeof DataTransfer; readonly DataTransferItem: typeof DataTransferItem; @@ -168,6 +181,13 @@ export default interface IWindow extends IEventTarget, NodeJS.Global { readonly NodeList: typeof NodeList; readonly CSSUnitValue: typeof CSSUnitValue; readonly CSS: CSS; + readonly CSSRule: typeof CSSRule; + readonly CSSContainerRule: typeof CSSContainerRule; + readonly CSSFontFaceRule: typeof CSSFontFaceRule; + readonly CSSKeyframeRule: typeof CSSKeyframeRule; + readonly CSSKeyframesRule: typeof CSSKeyframesRule; + readonly CSSMediaRule: typeof CSSMediaRule; + readonly CSSStyleRule: typeof CSSStyleRule; readonly Selection: typeof Selection; readonly Navigator: typeof Navigator; readonly MimeType: typeof MimeType; @@ -217,7 +237,7 @@ export default interface IWindow extends IEventTarget, NodeJS.Global { * @param element Element. * @returns CSS style declaration. */ - getComputedStyle(element: IHTMLElement): CSSStyleDeclaration; + getComputedStyle(element: IElement): CSSStyleDeclaration; /** * Returns selection. diff --git a/packages/happy-dom/src/window/Window.ts b/packages/happy-dom/src/window/Window.ts index 95ede0e06..c70fadee4 100644 --- a/packages/happy-dom/src/window/Window.ts +++ b/packages/happy-dom/src/window/Window.ts @@ -35,6 +35,7 @@ import CustomEvent from '../event/events/CustomEvent'; import AnimationEvent from '../event/events/AnimationEvent'; import KeyboardEvent from '../event/events/KeyboardEvent'; import ProgressEvent from '../event/events/ProgressEvent'; +import MediaQueryListEvent from '../event/events/MediaQueryListEvent'; import EventTarget from '../event/EventTarget'; import URL from '../location/URL'; import Location from '../location/Location'; @@ -50,9 +51,16 @@ import DOMException from '../exception/DOMException'; import { default as FileReaderImplementation } from '../file/FileReader'; import History from '../history/History'; import CSSStyleSheet from '../css/CSSStyleSheet'; -import CSSStyleDeclaration from '../css/CSSStyleDeclaration'; +import CSSStyleDeclaration from '../css/declaration/CSSStyleDeclaration'; import CSS from '../css/CSS'; import CSSUnitValue from '../css/CSSUnitValue'; +import CSSRule from '../css/CSSRule'; +import CSSContainerRule from '../css/rules/CSSContainerRule'; +import CSSFontFaceRule from '../css/rules/CSSFontFaceRule'; +import CSSKeyframeRule from '../css/rules/CSSKeyframeRule'; +import CSSKeyframesRule from '../css/rules/CSSKeyframesRule'; +import CSSMediaRule from '../css/rules/CSSMediaRule'; +import CSSStyleRule from '../css/rules/CSSStyleRule'; import MouseEvent from '../event/events/MouseEvent'; import PointerEvent from '../event/events/PointerEvent'; import FocusEvent from '../event/events/FocusEvent'; @@ -96,6 +104,8 @@ import VM from 'vm'; import { Buffer } from 'buffer'; import Base64 from '../base64/Base64'; import IDocument from '../nodes/document/IDocument'; +import Attr from '../nodes/attr/Attr'; +import IElement from '../nodes/element/IElement'; const ORIGINAL_SET_TIMEOUT = setTimeout; const ORIGINAL_CLEAR_TIMEOUT = clearTimeout; @@ -117,7 +127,19 @@ export default class Window extends EventTarget implements IWindow { cancelAsync: (): void => { this.happyDOM.asyncTaskManager.cancelAll(); }, - asyncTaskManager: new AsyncTaskManager() + asyncTaskManager: new AsyncTaskManager(), + setInnerWidth: (width: number): void => { + if (this.innerWidth !== width) { + (this.innerWidth) = width; + this.dispatchEvent(new Event('resize')); + } + }, + setInnerHeight: (height: number): void => { + if (this.innerHeight !== height) { + (this.innerHeight) = height; + this.dispatchEvent(new Event('resize')); + } + } }; // Global classes @@ -137,6 +159,7 @@ export default class Window extends EventTarget implements IWindow { public readonly HTMLMetaElement = HTMLMetaElement; public readonly HTMLBaseElement = HTMLBaseElement; public readonly HTMLDialogElement = HTMLDialogElement; + public readonly Attr = Attr; public readonly SVGSVGElement = SVGSVGElement; public readonly SVGElement = SVGElement; public readonly Text = Text; @@ -165,6 +188,7 @@ export default class Window extends EventTarget implements IWindow { public readonly ErrorEvent = ErrorEvent; public readonly StorageEvent = StorageEvent; public readonly ProgressEvent = ProgressEvent; + public readonly MediaQueryListEvent = MediaQueryListEvent; public readonly EventTarget = EventTarget; public readonly DataTransfer = DataTransfer; public readonly DataTransferItem = DataTransferItem; @@ -185,8 +209,14 @@ export default class Window extends EventTarget implements IWindow { public readonly URLSearchParams = URLSearchParams; public readonly HTMLCollection = HTMLCollection; public readonly NodeList = NodeList; - public readonly MediaQueryList = MediaQueryList; public readonly CSSUnitValue = CSSUnitValue; + public readonly CSSRule = CSSRule; + public readonly CSSContainerRule = CSSContainerRule; + public readonly CSSFontFaceRule = CSSFontFaceRule; + public readonly CSSKeyframeRule = CSSKeyframeRule; + public readonly CSSKeyframesRule = CSSKeyframesRule; + public readonly CSSMediaRule = CSSMediaRule; + public readonly CSSStyleRule = CSSStyleRule; public readonly Selection = Selection; public readonly Navigator = Navigator; public readonly MimeType = MimeType; @@ -223,12 +253,12 @@ export default class Window extends EventTarget implements IWindow { public readonly window = this; public readonly globalThis = this; public readonly screen = new Screen(); - public readonly innerWidth = 1024; - public readonly innerHeight = 768; public readonly devicePixelRatio = 1; public readonly sessionStorage = new Storage(); public readonly localStorage = new Storage(); public readonly performance = PerfHooks.performance; + public readonly innerWidth: number; + public readonly innerHeight: number; // Node.js Globals public ArrayBuffer; @@ -301,10 +331,22 @@ export default class Window extends EventTarget implements IWindow { /** * Constructor. + * + * @param [options] Options. + * @param [options.innerWidth] Inner width. + * @param [options.innerHeight] Inner height. + * @param [options.url] URL. */ - constructor() { + constructor(options?: { innerWidth?: number; innerHeight?: number; url?: string }) { super(); + this.innerWidth = options?.innerWidth ? options.innerWidth : 0; + this.innerHeight = options?.innerHeight ? options.innerHeight : 0; + + if (options?.url) { + this.location.href = options.url; + } + this._setTimeout = ORIGINAL_SET_TIMEOUT; this._clearTimeout = ORIGINAL_CLEAR_TIMEOUT; this._setInterval = ORIGINAL_SET_INTERVAL; @@ -418,8 +460,8 @@ export default class Window extends EventTarget implements IWindow { * @param element Element. * @returns CSS style declaration. */ - public getComputedStyle(element: HTMLElement): CSSStyleDeclaration { - return new CSSStyleDeclaration(element._attributes, element); + public getComputedStyle(element: IElement): CSSStyleDeclaration { + return new CSSStyleDeclaration(element, true); } /** @@ -482,9 +524,7 @@ export default class Window extends EventTarget implements IWindow { * @returns A new MediaQueryList. */ public matchMedia(mediaQueryString: string): MediaQueryList { - const mediaQueryList = new MediaQueryList(); - mediaQueryList._media = mediaQueryString; - return mediaQueryList; + return new MediaQueryList(this, mediaQueryString); } /** diff --git a/packages/happy-dom/test/CustomElement.ts b/packages/happy-dom/test/CustomElement.ts index db3b3b4dd..f4c5b7b70 100644 --- a/packages/happy-dom/test/CustomElement.ts +++ b/packages/happy-dom/test/CustomElement.ts @@ -43,25 +43,17 @@ export default class CustomElement extends new Window().HTMLElement {
- + key1 is "${this.getAttribute('key1')}" and key2 is "${this.getAttribute( 'key2' )}". diff --git a/packages/happy-dom/test/css/CSSParser.test.ts b/packages/happy-dom/test/css/CSSParser.test.ts index 87d740391..ea9770497 100644 --- a/packages/happy-dom/test/css/CSSParser.test.ts +++ b/packages/happy-dom/test/css/CSSParser.test.ts @@ -5,6 +5,7 @@ import CSSMediaRule from '../../src/css/rules/CSSMediaRule'; import CSSParserInput from './data/CSSParserInput'; import CSSKeyframeRule from '../../src/css/rules/CSSKeyframeRule'; import CSSKeyframesRule from '../../src/css/rules/CSSKeyframesRule'; +import CSSContainerRule from '../../src/css/rules/CSSContainerRule'; describe('CSSParser', () => { describe('parseFromString()', () => { @@ -12,7 +13,7 @@ describe('CSSParser', () => { const cssStyleSheet = new CSSStyleSheet(); const cssRules = CSSParser.parseFromString(cssStyleSheet, CSSParserInput); - expect(cssRules.length).toBe(5); + expect(cssRules.length).toBe(7); // CSSStyleRule expect((cssRules[0]).parentRule).toBe(null); @@ -26,9 +27,9 @@ describe('CSSParser', () => { expect((cssRules[0]).style[0]).toBe('display'); expect((cssRules[0]).style[1]).toBe('overflow'); expect((cssRules[0]).style[2]).toBe('width'); - expect((cssRules[0]).style['display']).toBe('flex'); - expect((cssRules[0]).style['overflow']).toBe('hidden'); - expect((cssRules[0]).style['width']).toBe('100%'); + expect((cssRules[0]).style.display).toBe('flex'); + expect((cssRules[0]).style.overflow).toBe('hidden'); + expect((cssRules[0]).style.width).toBe('100%'); expect((cssRules[0]).style.cssText).toBe( 'display: flex; overflow: hidden; width: 100%;' ); @@ -38,20 +39,22 @@ describe('CSSParser', () => { expect((cssRules[1]).parentStyleSheet).toBe(cssStyleSheet); expect((cssRules[1]).selectorText).toBe('.container'); expect((cssRules[1]).cssText).toBe( - '.container { flex-grow: 1; display: flex; flex-direction: column; overflow: hidden; }' + '.container { flex-grow: 1; display: flex; flex-direction: column; overflow: hidden; --css-variable: 1px; }' ); - expect((cssRules[1]).style.length).toBe(4); + expect((cssRules[1]).style.length).toBe(5); expect((cssRules[1]).style.parentRule).toBe(cssRules[1]); expect((cssRules[1]).style[0]).toBe('flex-grow'); expect((cssRules[1]).style[1]).toBe('display'); expect((cssRules[1]).style[2]).toBe('flex-direction'); expect((cssRules[1]).style[3]).toBe('overflow'); - expect((cssRules[1]).style['flexGrow']).toBe('1'); - expect((cssRules[1]).style['display']).toBe('flex'); - expect((cssRules[1]).style['flexDirection']).toBe('column'); - expect((cssRules[1]).style['overflow']).toBe('hidden'); + expect((cssRules[1]).style[4]).toBe('--css-variable'); + expect((cssRules[1]).style.flexGrow).toBe('1'); + expect((cssRules[1]).style.display).toBe('flex'); + expect((cssRules[1]).style.flexDirection).toBe('column'); + expect((cssRules[1]).style.overflow).toBe('hidden'); + expect((cssRules[1]).style.getPropertyValue('--css-variable')).toBe('1px'); expect((cssRules[1]).style.cssText).toBe( - 'flex-grow: 1; display: flex; flex-direction: column; overflow: hidden;' + 'flex-grow: 1; display: flex; flex-direction: column; overflow: hidden; --css-variable: 1px;' ); // CSSMediaRule @@ -72,8 +75,8 @@ describe('CSSParser', () => { expect(children1[0].style.parentRule).toBe(children1[0]); expect(children1[0].style[0]).toBe('height'); expect(children1[0].style[1]).toBe('animation'); - expect(children1[0].style['height']).toBe('0.5rem'); - expect(children1[0].style['animation']).toBe('keyframes2 2s linear infinite'); + expect(children1[0].style.height).toBe('0.5rem'); + expect(children1[0].style.animation).toBe('keyframes2 2s linear infinite'); expect(children1[0].cssText).toBe( '.container { height: 0.5rem; animation: keyframes2 2s linear infinite; }' ); @@ -93,14 +96,14 @@ describe('CSSParser', () => { expect(children2[0].style.length).toBe(1); expect(children2[0].style.parentRule).toBe(children2[0]); expect(children2[0].style[0]).toBe('transform'); - expect(children2[0].style['transform']).toBe('rotate(0deg)'); + expect(children2[0].style.transform).toBe('rotate(0deg)'); expect(children2[0].cssText).toBe('from { transform: rotate(0deg); }'); expect(children2[1].parentRule).toBe(cssRules[3]); expect(children2[1].parentStyleSheet).toBe(cssStyleSheet); expect(children2[1].keyText).toBe('to'); expect(children2[1].style.length).toBe(1); expect(children2[1].style[0]).toBe('transform'); - expect(children2[1].style['transform']).toBe('rotate(360deg)'); + expect(children2[1].style.transform).toBe('rotate(360deg)'); expect(children2[1].cssText).toBe('to { transform: rotate(360deg); }'); // CSSKeyframesRule @@ -118,15 +121,49 @@ describe('CSSParser', () => { expect(children3[0].style.length).toBe(1); expect(children3[0].style.parentRule).toBe(children3[0]); expect(children3[0].style[0]).toBe('transform'); - expect(children3[0].style['transform']).toBe('rotate(0deg)'); + expect(children3[0].style.transform).toBe('rotate(0deg)'); expect(children3[0].cssText).toBe('0% { transform: rotate(0deg); }'); expect(children3[1].parentRule).toBe(cssRules[4]); expect(children3[1].parentStyleSheet).toBe(cssStyleSheet); expect(children3[1].keyText).toBe('100%'); expect(children3[1].style.length).toBe(1); expect(children3[1].style[0]).toBe('transform'); - expect(children3[1].style['transform']).toBe('rotate(360deg)'); + expect(children3[1].style.transform).toBe('rotate(360deg)'); expect(children3[1].cssText).toBe('100% { transform: rotate(360deg); }'); + + // CSSContainerRule 1 + expect((cssRules[5]).parentRule).toBe(null); + expect((cssRules[5]).parentStyleSheet).toBe(cssStyleSheet); + expect((cssRules[5]).cssText).toBe( + '@container (min-width: 36rem) { .container { color: red; } }' + ); + expect((cssRules[5]).cssRules.length).toBe(1); + const children4 = (cssRules[5]).cssRules; + expect(children4[0].parentRule).toBe(cssRules[5]); + expect(children4[0].parentStyleSheet).toBe(cssStyleSheet); + expect(children4[0].selectorText).toBe('.container'); + expect(children4[0].style.length).toBe(1); + expect(children4[0].style.parentRule).toBe(children4[0]); + expect(children4[0].style[0]).toBe('color'); + expect(children4[0].style.color).toBe('red'); + expect(children4[0].cssText).toBe('.container { color: red; }'); + + // CSSContainerRule 2 + expect((cssRules[6]).parentRule).toBe(null); + expect((cssRules[6]).parentStyleSheet).toBe(cssStyleSheet); + expect((cssRules[6]).cssText).toBe( + '@container name (min-width: 36rem) { .container { color: red; } }' + ); + expect((cssRules[6]).cssRules.length).toBe(1); + const children5 = (cssRules[6]).cssRules; + expect(children5[0].parentRule).toBe(cssRules[6]); + expect(children5[0].parentStyleSheet).toBe(cssStyleSheet); + expect(children5[0].selectorText).toBe('.container'); + expect(children5[0].style.length).toBe(1); + expect(children5[0].style.parentRule).toBe(children5[0]); + expect(children5[0].style[0]).toBe('color'); + expect(children5[0].style.color).toBe('red'); + expect(children5[0].cssText).toBe('.container { color: red; }'); }); }); }); diff --git a/packages/happy-dom/test/css/CSSStyleDeclaration.test.ts b/packages/happy-dom/test/css/CSSStyleDeclaration.test.ts deleted file mode 100644 index ee5a7294e..000000000 --- a/packages/happy-dom/test/css/CSSStyleDeclaration.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import CSSStyleDeclaration from '../../src/css/CSSStyleDeclaration'; -import CSSStyleDeclarationStyleProperties from './data/CSSStyleDeclarationStyleProperties'; -import Attr from '../../src/attribute/Attr'; - -function CAMEL_TO_KEBAB_CASE(string): string { - return string.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase(); -} - -describe('CSSStyleDeclaration', () => { - let attributes: { [k: string]: Attr } = null; - let cssStyleDeclaration: CSSStyleDeclaration = null; - - beforeEach(() => { - attributes = { style: new Attr() }; - cssStyleDeclaration = new CSSStyleDeclaration(attributes); - }); - - for (const property of CSSStyleDeclarationStyleProperties) { - describe(`get ${property}()`, () => { - it('Returns style property.', () => { - attributes.style.value = `${CAMEL_TO_KEBAB_CASE(property)}: test;`; - expect(cssStyleDeclaration[property]).toBe('test'); - }); - }); - - describe(`set ${property}()`, () => { - it('Sets style property.', () => { - cssStyleDeclaration[property] = 'test'; - expect(attributes.style.value).toBe(`${CAMEL_TO_KEBAB_CASE(property)}: test;`); - }); - }); - } - - describe('get cssText()', () => { - it('Returns CSS text.', () => { - attributes['style'] = new Attr(); - attributes['style'].name = 'style'; - attributes['style'].value = 'background: red; color: blue;'; - - expect(cssStyleDeclaration.cssText).toBe('background: red; color: blue;'); - }); - }); - - describe('set cssText()', () => { - it('Sets CSS text.', () => { - cssStyleDeclaration.cssText = 'line-height: 2; font-size: 12px; background'; - - // Test if setProperty() crashes when a single property is used in the style - cssStyleDeclaration.lineHeight = '3'; - - expect(cssStyleDeclaration.lineHeight).toBe('3'); - expect(cssStyleDeclaration.fontSize).toBe('12px'); - expect(cssStyleDeclaration.background).toBe(''); - expect(attributes['style'].value).toBe('line-height: 3; font-size: 12px; background;'); - }); - }); - - describe('item()', () => { - it('Returns an item by index.', () => { - cssStyleDeclaration.setProperty('background-color', 'green'); - expect(cssStyleDeclaration.item(0)).toBe('background-color'); - }); - }); - - describe('setProperty()', () => { - it('Sets a style property.', () => { - cssStyleDeclaration.setProperty('background-color', 'green'); - expect(attributes.style.value).toBe('background-color: green;'); - expect(cssStyleDeclaration.backgroundColor).toBe('green'); - expect(cssStyleDeclaration.length).toBe(1); - expect(cssStyleDeclaration[0]).toBe('background-color'); - }); - }); - - describe('removeProperty()', () => { - it('Removes a style property.', () => { - cssStyleDeclaration.setProperty('background-color', 'green'); - cssStyleDeclaration.removeProperty('background-color'); - expect(attributes.style).toBe(undefined); - expect(cssStyleDeclaration.backgroundColor).toBe(''); - expect(cssStyleDeclaration.length).toBe(0); - }); - }); - - describe('getPropertyValue()', () => { - it('Returns a style property.', () => { - cssStyleDeclaration.setProperty('background-color', 'green'); - expect(cssStyleDeclaration.getPropertyValue('background-color')).toBe('green'); - }); - }); -}); diff --git a/packages/happy-dom/test/css/CSSStyleSheet.test.ts b/packages/happy-dom/test/css/CSSStyleSheet.test.ts index 5aec1609a..b10f0f181 100644 --- a/packages/happy-dom/test/css/CSSStyleSheet.test.ts +++ b/packages/happy-dom/test/css/CSSStyleSheet.test.ts @@ -14,6 +14,9 @@ describe('CSSStyleSheet', () => { cssStyleSheet.insertRule('div { background-color: green }'); cssStyleSheet.insertRule('span { background-color: green }'); expect(cssStyleSheet.insertRule('button { background-color: green }', 1)).toBe(1); + expect(cssStyleSheet.cssRules[0].cssText).toBe('div { background-color: green; }'); + expect(cssStyleSheet.cssRules[1].cssText).toBe('button { background-color: green; }'); + expect(cssStyleSheet.cssRules[2].cssText).toBe('span { background-color: green; }'); }); it('Inserts a rule.', () => { diff --git a/packages/happy-dom/test/css/data/CSSParserInput.ts b/packages/happy-dom/test/css/data/CSSParserInput.ts index bed47c0ee..25f4f8a73 100644 --- a/packages/happy-dom/test/css/data/CSSParserInput.ts +++ b/packages/happy-dom/test/css/data/CSSParserInput.ts @@ -10,6 +10,7 @@ export default ` display: flex; flex-direction: column; overflow: hidden; + --css-variable: 1px; } @media screen and (max-width: 36rem) { @@ -38,4 +39,16 @@ export default ` transform: rotate(360deg); } } + + @container (min-width: 36rem) { + .container { + color: red; + } + } + + @container name (min-width: 36rem) { + .container { + color: red; + } + } `.trim(); diff --git a/packages/happy-dom/test/css/data/CSSStyleDeclarationStyleProperties.ts b/packages/happy-dom/test/css/data/CSSStyleDeclarationStyleProperties.ts deleted file mode 100644 index 60e73c3ae..000000000 --- a/packages/happy-dom/test/css/data/CSSStyleDeclarationStyleProperties.ts +++ /dev/null @@ -1,371 +0,0 @@ -export default [ - 'alignContent', - 'alignItems', - 'alignSelf', - 'alignmentBaseline', - 'all', - 'animation', - 'animationDelay', - 'animationDirection', - 'animationDuration', - 'animationFillMode', - 'animationIterationCount', - 'animationName', - 'animationPlayState', - 'animationTimingFunction', - 'appearance', - 'backdropFilter', - 'backfaceVisibility', - 'background', - 'backgroundAttachment', - 'backgroundBlendMode', - 'backgroundClip', - 'backgroundColor', - 'backgroundImage', - 'backgroundOrigin', - 'backgroundPosition', - 'backgroundPositionX', - 'backgroundPositionY', - 'backgroundRepeat', - 'backgroundRepeatX', - 'backgroundRepeatY', - 'backgroundSize', - 'baselineShift', - 'blockSize', - 'border', - 'borderBlockEnd', - 'borderBlockEndColor', - 'borderBlockEndStyle', - 'borderBlockEndWidth', - 'borderBlockStart', - 'borderBlockStartColor', - 'borderBlockStartStyle', - 'borderBlockStartWidth', - 'borderBottom', - 'borderBottomColor', - 'borderBottomLeftRadius', - 'borderBottomRightRadius', - 'borderBottomStyle', - 'borderBottomWidth', - 'borderCollapse', - 'borderColor', - 'borderImage', - 'borderImageOutset', - 'borderImageRepeat', - 'borderImageSlice', - 'borderImageSource', - 'borderImageWidth', - 'borderInlineEnd', - 'borderInlineEndColor', - 'borderInlineEndStyle', - 'borderInlineEndWidth', - 'borderInlineStart', - 'borderInlineStartColor', - 'borderInlineStartStyle', - 'borderInlineStartWidth', - 'borderLeft', - 'borderLeftColor', - 'borderLeftStyle', - 'borderLeftWidth', - 'borderRadius', - 'borderRight', - 'borderRightColor', - 'borderRightStyle', - 'borderRightWidth', - 'borderSpacing', - 'borderStyle', - 'borderTop', - 'borderTopColor', - 'borderTopLeftRadius', - 'borderTopRightRadius', - 'borderTopStyle', - 'borderTopWidth', - 'borderWidth', - 'bottom', - 'boxShadow', - 'boxSizing', - 'breakAfter', - 'breakBefore', - 'breakInside', - 'bufferedRendering', - 'captionSide', - 'caretColor', - 'clear', - 'clip', - 'clipPath', - 'clipRule', - 'color', - 'colorInterpolation', - 'colorInterpolationFilters', - 'colorRendering', - 'colorScheme', - 'columnCount', - 'columnFill', - 'columnGap', - 'columnRule', - 'columnRuleColor', - 'columnRuleStyle', - 'columnRuleWidth', - 'columnSpan', - 'columnWidth', - 'columns', - 'contain', - 'containIntrinsicSize', - 'content', - 'contentVisibility', - 'counterIncrement', - 'counterReset', - 'counterSet', - 'cssFloat', - 'cursor', - 'cx', - 'cy', - 'd', - 'direction', - 'display', - 'dominantBaseline', - 'emptyCells', - 'fill', - 'fillOpacity', - 'fillRule', - 'filter', - 'flex', - 'flexBasis', - 'flexDirection', - 'flexFlow', - 'flexGrow', - 'flexShrink', - 'flexWrap', - 'float', - 'floodColor', - 'floodOpacity', - 'font', - 'fontDisplay', - 'fontFamily', - 'fontFeatureSettings', - 'fontKerning', - 'fontOpticalSizing', - 'fontSize', - 'fontStretch', - 'fontStyle', - 'fontVariant', - 'fontVariantCaps', - 'fontVariantEastAsian', - 'fontVariantLigatures', - 'fontVariantNumeric', - 'fontVariationSettings', - 'fontWeight', - 'gap', - 'grid', - 'gridArea', - 'gridAutoColumns', - 'gridAutoFlow', - 'gridAutoRows', - 'gridColumn', - 'gridColumnEnd', - 'gridColumnGap', - 'gridColumnStart', - 'gridGap', - 'gridRow', - 'gridRowEnd', - 'gridRowGap', - 'gridRowStart', - 'gridTemplate', - 'gridTemplateAreas', - 'gridTemplateColumns', - 'gridTemplateRows', - 'height', - 'hyphens', - 'imageOrientation', - 'imageRendering', - 'inherits', - 'initialValue', - 'inlineSize', - 'isolation', - 'justifyContent', - 'justifyItems', - 'justifySelf', - 'left', - 'letterSpacing', - 'lightingColor', - 'lineBreak', - 'lineHeight', - 'listStyle', - 'listStyleImage', - 'listStylePosition', - 'listStyleType', - 'margin', - 'marginBlockEnd', - 'marginBlockStart', - 'marginBottom', - 'marginInlineEnd', - 'marginInlineStart', - 'marginLeft', - 'marginRight', - 'marginTop', - 'marker', - 'markerEnd', - 'markerMid', - 'markerStart', - 'mask', - 'maskType', - 'maxBlockSize', - 'maxHeight', - 'maxInlineSize', - 'maxWidth', - 'maxZoom', - 'minBlockSize', - 'minHeight', - 'minInlineSize', - 'minWidth', - 'minZoom', - 'mixBlendMode', - 'objectFit', - 'objectPosition', - 'offset', - 'offsetDistance', - 'offsetPath', - 'offsetRotate', - 'opacity', - 'order', - 'orientation', - 'orphans', - 'outline', - 'outlineColor', - 'outlineOffset', - 'outlineStyle', - 'outlineWidth', - 'overflow', - 'overflowAnchor', - 'overflowWrap', - 'overflowX', - 'overflowY', - 'overscrollBehavior', - 'overscrollBehaviorBlock', - 'overscrollBehaviorInline', - 'overscrollBehaviorX', - 'overscrollBehaviorY', - 'padding', - 'paddingBlockEnd', - 'paddingBlockStart', - 'paddingBottom', - 'paddingInlineEnd', - 'paddingInlineStart', - 'paddingLeft', - 'paddingRight', - 'paddingTop', - 'page', - 'pageBreakAfter', - 'pageBreakBefore', - 'pageBreakInside', - 'pageOrientation', - 'paintOrder', - 'perspective', - 'perspectiveOrigin', - 'placeContent', - 'placeItems', - 'placeSelf', - 'pointerEvents', - 'position', - 'quotes', - 'r', - 'resize', - 'right', - 'rowGap', - 'rubyPosition', - 'rx', - 'ry', - 'scrollBehavior', - 'scrollMargin', - 'scrollMarginBlock', - 'scrollMarginBlockEnd', - 'scrollMarginBlockStart', - 'scrollMarginBottom', - 'scrollMarginInline', - 'scrollMarginInlineEnd', - 'scrollMarginInlineStart', - 'scrollMarginLeft', - 'scrollMarginRight', - 'scrollMarginTop', - 'scrollPadding', - 'scrollPaddingBlock', - 'scrollPaddingBlockEnd', - 'scrollPaddingBlockStart', - 'scrollPaddingBottom', - 'scrollPaddingInline', - 'scrollPaddingInlineEnd', - 'scrollPaddingInlineStart', - 'scrollPaddingLeft', - 'scrollPaddingRight', - 'scrollPaddingTop', - 'scrollSnapAlign', - 'scrollSnapStop', - 'scrollSnapType', - 'shapeImageThreshold', - 'shapeMargin', - 'shapeOutside', - 'shapeRendering', - 'size', - 'speak', - 'src', - 'stopColor', - 'stopOpacity', - 'stroke', - 'strokeDasharray', - 'strokeDashoffset', - 'strokeLinecap', - 'strokeLinejoin', - 'strokeMiterlimit', - 'strokeOpacity', - 'strokeWidth', - 'syntax', - 'tabSize', - 'tableLayout', - 'textAlign', - 'textAlignLast', - 'textAnchor', - 'textCombineUpright', - 'textDecoration', - 'textDecorationColor', - 'textDecorationLine', - 'textDecorationSkipInk', - 'textDecorationStyle', - 'textIndent', - 'textOrientation', - 'textOverflow', - 'textRendering', - 'textShadow', - 'textSizeAdjust', - 'textTransform', - 'textUnderlinePosition', - 'top', - 'touchAction', - 'transform', - 'transformBox', - 'transformOrigin', - 'transformStyle', - 'transition', - 'transitionDelay', - 'transitionDuration', - 'transitionProperty', - 'transitionTimingFunction', - 'unicodeBidi', - 'unicodeRange', - 'userSelect', - 'userZoom', - 'vectorEffect', - 'verticalAlign', - 'visibility', - 'whiteSpace', - 'widows', - 'width', - 'willChange', - 'wordBreak', - 'wordSpacing', - 'wordWrap', - 'writingMode', - 'x', - 'y', - 'zIndex', - 'zoom' -]; diff --git a/packages/happy-dom/test/css/declaration/CSSStyleDeclaration.test.ts b/packages/happy-dom/test/css/declaration/CSSStyleDeclaration.test.ts new file mode 100644 index 000000000..749b46402 --- /dev/null +++ b/packages/happy-dom/test/css/declaration/CSSStyleDeclaration.test.ts @@ -0,0 +1,2235 @@ +import CSSStyleDeclaration from '../../../src/css/declaration/CSSStyleDeclaration'; +import Window from '../../../src/window/Window'; +import IWindow from '../../../src/window/IWindow'; +import IDocument from '../../../src/nodes/document/IDocument'; +import IElement from '../../../src/nodes/element/IElement'; + +describe('CSSStyleDeclaration', () => { + let window: IWindow; + let document: IDocument; + let element: IElement; + + beforeEach(() => { + window = new Window(); + document = window.document; + element = document.createElement('div'); + }); + + describe(`get {number}()`, () => { + it('Returns name of property when style is set on element.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', `border: 2px solid green;border-radius: 2px;font-size: 12px;`); + + expect(declaration[0]).toBe('border-top-width'); + expect(declaration[1]).toBe('border-right-width'); + expect(declaration[2]).toBe('border-bottom-width'); + expect(declaration[3]).toBe('border-left-width'); + expect(declaration[4]).toBe('border-top-style'); + expect(declaration[5]).toBe('border-right-style'); + expect(declaration[6]).toBe('border-bottom-style'); + expect(declaration[7]).toBe('border-left-style'); + expect(declaration[8]).toBe('border-top-color'); + expect(declaration[9]).toBe('border-right-color'); + expect(declaration[10]).toBe('border-bottom-color'); + expect(declaration[11]).toBe('border-left-color'); + expect(declaration[12]).toBe('border-image-source'); + expect(declaration[13]).toBe('border-image-slice'); + expect(declaration[14]).toBe('border-image-width'); + expect(declaration[15]).toBe('border-image-outset'); + expect(declaration[16]).toBe('border-image-repeat'); + expect(declaration[17]).toBe('border-top-left-radius'); + expect(declaration[18]).toBe('border-top-right-radius'); + expect(declaration[19]).toBe('border-bottom-right-radius'); + expect(declaration[20]).toBe('border-bottom-left-radius'); + expect(declaration[21]).toBe('font-size'); + expect(declaration[22]).toBe(undefined); + }); + + it('Returns name of property without element.', () => { + const declaration = new CSSStyleDeclaration(); + + declaration.border = '2px solid green'; + declaration.borderRadius = '2px'; + declaration.fontSize = '12px'; + + expect(declaration[0]).toBe('border-top-width'); + expect(declaration[1]).toBe('border-right-width'); + expect(declaration[2]).toBe('border-bottom-width'); + expect(declaration[3]).toBe('border-left-width'); + expect(declaration[4]).toBe('border-top-style'); + expect(declaration[5]).toBe('border-right-style'); + expect(declaration[6]).toBe('border-bottom-style'); + expect(declaration[7]).toBe('border-left-style'); + expect(declaration[8]).toBe('border-top-color'); + expect(declaration[9]).toBe('border-right-color'); + expect(declaration[10]).toBe('border-bottom-color'); + expect(declaration[11]).toBe('border-left-color'); + expect(declaration[12]).toBe('border-image-source'); + expect(declaration[13]).toBe('border-image-slice'); + expect(declaration[14]).toBe('border-image-width'); + expect(declaration[15]).toBe('border-image-outset'); + expect(declaration[16]).toBe('border-image-repeat'); + expect(declaration[17]).toBe('border-top-left-radius'); + expect(declaration[18]).toBe('border-top-right-radius'); + expect(declaration[19]).toBe('border-bottom-right-radius'); + expect(declaration[20]).toBe('border-bottom-left-radius'); + expect(declaration[21]).toBe('font-size'); + expect(declaration[22]).toBe(undefined); + }); + }); + + describe('get border()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border: inherit'); + + expect(declaration.border).toBe('inherit'); + expect(declaration.borderTop).toBe('inherit'); + expect(declaration.borderRight).toBe('inherit'); + expect(declaration.borderBottom).toBe('inherit'); + expect(declaration.borderLeft).toBe('inherit'); + expect(declaration.borderTopColor).toBe('inherit'); + expect(declaration.borderRightColor).toBe('inherit'); + expect(declaration.borderBottomColor).toBe('inherit'); + expect(declaration.borderLeftColor).toBe('inherit'); + expect(declaration.borderTopWidth).toBe('inherit'); + expect(declaration.borderRightWidth).toBe('inherit'); + expect(declaration.borderBottomWidth).toBe('inherit'); + expect(declaration.borderLeftWidth).toBe('inherit'); + expect(declaration.borderTopStyle).toBe('inherit'); + expect(declaration.borderRightStyle).toBe('inherit'); + expect(declaration.borderBottomStyle).toBe('inherit'); + expect(declaration.borderLeftStyle).toBe('inherit'); + expect(declaration.borderImage).toBe('inherit'); + expect(declaration.borderImageOutset).toBe('inherit'); + expect(declaration.borderImageRepeat).toBe('inherit'); + expect(declaration.borderImageSlice).toBe('inherit'); + expect(declaration.borderImageSource).toBe('inherit'); + expect(declaration.borderImageWidth).toBe('inherit'); + + element.setAttribute('style', 'border: 2px solid green'); + + expect(declaration.border).toBe('2px solid green'); + + expect(declaration.borderTop).toBe('2px solid green'); + expect(declaration.borderRight).toBe('2px solid green'); + expect(declaration.borderBottom).toBe('2px solid green'); + expect(declaration.borderLeft).toBe('2px solid green'); + + expect(declaration.borderTopColor).toBe('green'); + expect(declaration.borderTopWidth).toBe('2px'); + expect(declaration.borderTopStyle).toBe('solid'); + + expect(declaration.borderRightColor).toBe('green'); + expect(declaration.borderRightWidth).toBe('2px'); + expect(declaration.borderRightStyle).toBe('solid'); + + expect(declaration.borderBottomColor).toBe('green'); + expect(declaration.borderBottomWidth).toBe('2px'); + expect(declaration.borderBottomStyle).toBe('solid'); + + expect(declaration.borderLeftColor).toBe('green'); + expect(declaration.borderLeftWidth).toBe('2px'); + expect(declaration.borderLeftStyle).toBe('solid'); + + expect(declaration.borderImage).toBe('initial'); + expect(declaration.borderImageOutset).toBe('initial'); + expect(declaration.borderImageRepeat).toBe('initial'); + expect(declaration.borderImageSlice).toBe('initial'); + expect(declaration.borderImageSource).toBe('initial'); + expect(declaration.borderImageWidth).toBe('initial'); + + declaration.borderRight = '1px dotted red'; + + expect(element.getAttribute('style')).toBe( + 'border-width: 2px 1px 2px 2px; border-style: solid dotted solid solid; border-color: green red green green; border-image: initial;' + ); + + declaration.borderRight = '2px solid green'; + + expect(declaration.border).toBe('2px solid green'); + + declaration.borderColor = 'red'; + declaration.borderStyle = 'dotted'; + declaration.borderWidth = '1px'; + + expect(declaration.border).toBe('1px dotted red'); + + element.setAttribute('style', 'border: green solid'); + + expect(declaration.border).toBe('solid green'); + + element.setAttribute('style', 'border: 2px solid rgb(255, 255, 255)'); + + expect(declaration.border).toBe('2px solid rgb(255, 255, 255)'); + + expect(declaration.borderTop).toBe('2px solid rgb(255, 255, 255)'); + expect(declaration.borderRight).toBe('2px solid rgb(255, 255, 255)'); + expect(declaration.borderBottom).toBe('2px solid rgb(255, 255, 255)'); + expect(declaration.borderLeft).toBe('2px solid rgb(255, 255, 255)'); + + expect(declaration.borderTopColor).toBe('rgb(255, 255, 255)'); + expect(declaration.borderTopWidth).toBe('2px'); + expect(declaration.borderTopStyle).toBe('solid'); + + expect(declaration.borderRightColor).toBe('rgb(255, 255, 255)'); + expect(declaration.borderRightWidth).toBe('2px'); + expect(declaration.borderRightStyle).toBe('solid'); + + expect(declaration.borderBottomColor).toBe('rgb(255, 255, 255)'); + expect(declaration.borderBottomWidth).toBe('2px'); + expect(declaration.borderBottomStyle).toBe('solid'); + + expect(declaration.borderLeftColor).toBe('rgb(255, 255, 255)'); + expect(declaration.borderLeftWidth).toBe('2px'); + expect(declaration.borderLeftStyle).toBe('solid'); + }); + }); + + describe('get borderTop()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-top: inherit'); + + expect(declaration.borderTop).toBe('inherit'); + expect(declaration.borderTopColor).toBe('inherit'); + expect(declaration.borderTopWidth).toBe('inherit'); + expect(declaration.borderTopStyle).toBe('inherit'); + + element.setAttribute('style', 'border-top: green 2px solid'); + + expect(declaration.border).toBe(''); + + expect(declaration.borderTop).toBe('2px solid green'); + expect(declaration.borderRight).toBe(''); + expect(declaration.borderBottom).toBe(''); + expect(declaration.borderLeft).toBe(''); + expect(declaration.borderTopColor).toBe('green'); + expect(declaration.borderTopWidth).toBe('2px'); + expect(declaration.borderTopStyle).toBe('solid'); + expect(declaration.borderImage).toBe(''); + }); + }); + + describe('get borderRight()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-right: inherit'); + + expect(declaration.borderRight).toBe('inherit'); + expect(declaration.borderRightColor).toBe('inherit'); + expect(declaration.borderRightWidth).toBe('inherit'); + expect(declaration.borderRightStyle).toBe('inherit'); + + element.setAttribute('style', 'border-right: green solid 2px'); + + expect(declaration.border).toBe(''); + + expect(declaration.borderTop).toBe(''); + expect(declaration.borderRight).toBe('2px solid green'); + expect(declaration.borderBottom).toBe(''); + expect(declaration.borderLeft).toBe(''); + expect(declaration.borderRightColor).toBe('green'); + expect(declaration.borderRightWidth).toBe('2px'); + expect(declaration.borderRightStyle).toBe('solid'); + expect(declaration.borderImage).toBe(''); + }); + }); + + describe('get borderBottom()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-bottom: inherit'); + + expect(declaration.borderBottom).toBe('inherit'); + expect(declaration.borderBottomColor).toBe('inherit'); + expect(declaration.borderBottomWidth).toBe('inherit'); + expect(declaration.borderBottomStyle).toBe('inherit'); + + element.setAttribute('style', 'border-bottom: green solid 2px'); + + expect(declaration.border).toBe(''); + + expect(declaration.borderTop).toBe(''); + expect(declaration.borderRight).toBe(''); + expect(declaration.borderBottom).toBe('2px solid green'); + expect(declaration.borderLeft).toBe(''); + expect(declaration.borderBottomColor).toBe('green'); + expect(declaration.borderBottomWidth).toBe('2px'); + expect(declaration.borderBottomStyle).toBe('solid'); + expect(declaration.borderImage).toBe(''); + }); + }); + + describe('get borderLeft()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-left: inherit'); + + expect(declaration.borderLeft).toBe('inherit'); + expect(declaration.borderLeftColor).toBe('inherit'); + expect(declaration.borderLeftWidth).toBe('inherit'); + expect(declaration.borderLeftStyle).toBe('inherit'); + + element.setAttribute('style', 'border-left: green solid 2px'); + + expect(declaration.border).toBe(''); + + expect(declaration.borderTop).toBe(''); + expect(declaration.borderRight).toBe(''); + expect(declaration.borderBottom).toBe(''); + expect(declaration.borderLeft).toBe('2px solid green'); + expect(declaration.borderLeftColor).toBe('green'); + expect(declaration.borderLeftWidth).toBe('2px'); + expect(declaration.borderLeftStyle).toBe('solid'); + expect(declaration.borderImage).toBe(''); + }); + }); + + describe('get borderWidth()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-width: inherit'); + + expect(declaration.borderTopWidth).toBe('inherit'); + expect(declaration.borderRightWidth).toBe('inherit'); + expect(declaration.borderBottomWidth).toBe('inherit'); + expect(declaration.borderLeftWidth).toBe('inherit'); + + element.setAttribute('style', 'border-width: 1px 2px 3px 4px'); + + expect(declaration.borderTopWidth).toBe('1px'); + expect(declaration.borderRightWidth).toBe('2px'); + expect(declaration.borderBottomWidth).toBe('3px'); + expect(declaration.borderLeftWidth).toBe('4px'); + + element.setAttribute('style', 'border-width: 2px'); + + expect(declaration.borderTopWidth).toBe('2px'); + expect(declaration.borderRightWidth).toBe('2px'); + expect(declaration.borderBottomWidth).toBe('2px'); + expect(declaration.borderLeftWidth).toBe('2px'); + }); + }); + + describe('get borderStyle()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-style: inherit'); + + expect(declaration.borderTopStyle).toBe('inherit'); + expect(declaration.borderRightStyle).toBe('inherit'); + expect(declaration.borderBottomStyle).toBe('inherit'); + expect(declaration.borderLeftStyle).toBe('inherit'); + + element.setAttribute('style', 'border-style: none hidden dotted dashed'); + + expect(declaration.borderTopStyle).toBe('none'); + expect(declaration.borderRightStyle).toBe('hidden'); + expect(declaration.borderBottomStyle).toBe('dotted'); + expect(declaration.borderLeftStyle).toBe('dashed'); + + element.setAttribute('style', 'border-style: hidden'); + + expect(declaration.borderTopStyle).toBe('hidden'); + expect(declaration.borderRightStyle).toBe('hidden'); + expect(declaration.borderBottomStyle).toBe('hidden'); + expect(declaration.borderLeftStyle).toBe('hidden'); + }); + }); + + describe('get borderColor()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-color: inherit'); + + expect(declaration.borderTopColor).toBe('inherit'); + expect(declaration.borderRightColor).toBe('inherit'); + expect(declaration.borderBottomColor).toBe('inherit'); + expect(declaration.borderLeftColor).toBe('inherit'); + + element.setAttribute('style', 'border-color: #000 #ffffff rgba(135,200,150,0.5) blue'); + + expect(declaration.borderTopColor).toBe('#000'); + expect(declaration.borderRightColor).toBe('#ffffff'); + expect(declaration.borderBottomColor).toBe('rgba(135, 200, 150, 0.5)'); + expect(declaration.borderLeftColor).toBe('blue'); + + element.setAttribute('style', 'border-color: rgb(135,200,150)'); + + expect(declaration.borderTopColor).toBe('rgb(135, 200, 150)'); + expect(declaration.borderRightColor).toBe('rgb(135, 200, 150)'); + expect(declaration.borderBottomColor).toBe('rgb(135, 200, 150)'); + expect(declaration.borderLeftColor).toBe('rgb(135, 200, 150)'); + }); + }); + + describe('get borderImage()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-image: inherit'); + expect(declaration.borderImage).toBe('inherit'); + expect(declaration.borderImageSource).toBe('inherit'); + expect(declaration.borderImageOutset).toBe('inherit'); + expect(declaration.borderImageRepeat).toBe('inherit'); + expect(declaration.borderImageSlice).toBe('inherit'); + expect(declaration.borderImageWidth).toBe('inherit'); + + element.setAttribute( + 'style', + 'border-image: repeating-linear-gradient(30deg, #4d9f0c, #9198e5, #4d9f0c 20px) 60' + ); + + expect(declaration.borderImage).toBe( + 'repeating-linear-gradient(30deg, #4d9f0c, #9198e5, #4d9f0c 20px) 60 / 1 / 0 stretch' + ); + + element.setAttribute('style', `border-image: url('/media/examples/border-diamonds.png') 30`); + + expect(declaration.borderImage).toBe( + `url("/media/examples/border-diamonds.png") 30 / 1 / 0 stretch` + ); + + element.setAttribute( + 'style', + `border-image: url('/media/examples/border-diamonds.png') 30 / 19px round` + ); + + expect(declaration.borderImage).toBe( + `url("/media/examples/border-diamonds.png") 30 / 19px / 0 round` + ); + + element.setAttribute( + 'style', + `border-image: url("/media/examples/border-diamonds.png") 10 fill / 20px / 30px space` + ); + + expect(declaration.borderImage).toBe( + `url("/media/examples/border-diamonds.png") 10 fill / 20px / 30px space` + ); + expect(declaration.borderImageSource).toBe(`url("/media/examples/border-diamonds.png")`); + expect(declaration.borderImageOutset).toBe('30px'); + expect(declaration.borderImageRepeat).toBe('space'); + expect(declaration.borderImageSlice).toBe('10 fill'); + expect(declaration.borderImageWidth).toBe('20px'); + + element.setAttribute('style', `border-image: linear-gradient(#f6b73c, #4d9f0c) 30;`); + + expect(declaration.borderImage).toBe(`linear-gradient(#f6b73c, #4d9f0c) 30 / 1 / 0 stretch`); + }); + }); + + describe('get borderImageSource()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', `border-image-source: inherit`); + + expect(declaration.borderImageSource).toBe('inherit'); + + element.setAttribute( + 'style', + `border-image-source: url('/media/examples/border-diamonds.png')` + ); + + expect(declaration.borderImageSource).toBe(`url("/media/examples/border-diamonds.png")`); + + element.setAttribute('style', `border-image-source: NONE`); + + expect(declaration.borderImageSource).toBe(`none`); + + element.setAttribute( + 'style', + `border-image-source: repeating-linear-gradient(30deg, #4d9f0c, #9198e5, #4d9f0c 20px)` + ); + + expect(declaration.borderImageSource).toBe( + `repeating-linear-gradient(30deg, #4d9f0c, #9198e5, #4d9f0c 20px)` + ); + }); + }); + + describe('get borderImageSlice()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-image-slice: inherit'); + + expect(declaration.borderImageSlice).toBe('inherit'); + + element.setAttribute('style', 'border-image-slice: 30'); + + expect(declaration.borderImageSlice).toBe('30'); + + element.setAttribute('style', 'border-image-slice: 30 fill'); + + expect(declaration.borderImageSlice).toBe('30 fill'); + + element.setAttribute( + 'style', + 'border-image-slice: calc(50 / 184 * 100%) calc(80 / 284 * 100%) fill' + ); + + expect(declaration.borderImageSlice).toBe('calc(50 / 184 * 100%) calc(80 / 284 * 100%) fill'); + }); + }); + + describe('get borderImageWidth()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-image-width: inherit'); + + expect(declaration.borderImageWidth).toBe('inherit'); + + element.setAttribute('style', 'border-image-width: auto'); + + expect(declaration.borderImageWidth).toBe('auto'); + + element.setAttribute('style', 'border-image-width: 25%'); + + expect(declaration.borderImageWidth).toBe('25%'); + + element.setAttribute('style', 'border-image-width: 5% 2em 10% auto'); + + expect(declaration.borderImageWidth).toBe('5% 2em 10% auto'); + }); + }); + + describe('get borderImageOutset()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-image-outset: inherit'); + + expect(declaration.borderImageOutset).toBe('inherit'); + + element.setAttribute('style', 'border-image-outset: 1rem'); + + expect(declaration.borderImageOutset).toBe('1rem'); + + element.setAttribute('style', 'border-image-outset: 1 1.2'); + + expect(declaration.borderImageOutset).toBe('1 1.2'); + + element.setAttribute('style', 'border-image-outset: 7px 12em 14cm 5px'); + + expect(declaration.borderImageOutset).toBe('7px 12em 14cm 5px'); + }); + }); + + describe('get borderImageRepeat()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-image-repeat: inherit'); + + expect(declaration.borderImageRepeat).toBe('inherit'); + + element.setAttribute('style', 'border-image-repeat: stretch'); + + expect(declaration.borderImageRepeat).toBe('stretch'); + + element.setAttribute('style', 'border-image-repeat: repeat'); + + expect(declaration.borderImageRepeat).toBe('repeat'); + + element.setAttribute('style', 'border-image-repeat: round stretch'); + + expect(declaration.borderImageRepeat).toBe('round stretch'); + }); + }); + + describe('get borderTopWidth()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-top-width: inherit'); + + expect(declaration.borderTopWidth).toBe('inherit'); + + element.setAttribute('style', 'border-top-width: thick'); + + expect(declaration.borderTopWidth).toBe('thick'); + + element.setAttribute('style', 'border-top-width: 2em'); + + expect(declaration.borderTopWidth).toBe('2em'); + }); + }); + + describe('get borderRightWidth()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-right-width: inherit'); + + expect(declaration.borderRightWidth).toBe('inherit'); + + element.setAttribute('style', 'border-right-width: thick'); + + expect(declaration.borderRightWidth).toBe('thick'); + + element.setAttribute('style', 'border-right-width: 2em'); + + expect(declaration.borderRightWidth).toBe('2em'); + }); + }); + + describe('get borderBottomWidth()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-bottom-width: inherit'); + + expect(declaration.borderBottomWidth).toBe('inherit'); + + element.setAttribute('style', 'border-bottom-width: thick'); + + expect(declaration.borderBottomWidth).toBe('thick'); + + element.setAttribute('style', 'border-bottom-width: 2em'); + + expect(declaration.borderBottomWidth).toBe('2em'); + }); + }); + + describe('get borderLeftWidth()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-left-width: inherit'); + + expect(declaration.borderLeftWidth).toBe('inherit'); + + element.setAttribute('style', 'border-left-width: thick'); + + expect(declaration.borderLeftWidth).toBe('thick'); + + element.setAttribute('style', 'border-left-width: 2em'); + + expect(declaration.borderLeftWidth).toBe('2em'); + }); + }); + + describe('get borderTopColor()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-top-color: inherit'); + + expect(declaration.borderTopColor).toBe('inherit'); + + element.setAttribute('style', 'border-top-color: red'); + + expect(declaration.borderTopColor).toBe('red'); + + element.setAttribute('style', 'border-top-color: rgba(100, 100, 100, 0.5)'); + + expect(declaration.borderTopColor).toBe('rgba(100, 100, 100, 0.5)'); + }); + }); + + describe('get borderRightColor()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-right-color: inherit'); + + expect(declaration.borderRightColor).toBe('inherit'); + + element.setAttribute('style', 'border-right-color: red'); + + expect(declaration.borderRightColor).toBe('red'); + + element.setAttribute('style', 'border-right-color: rgba(100, 100, 100, 0.5)'); + + expect(declaration.borderRightColor).toBe('rgba(100, 100, 100, 0.5)'); + }); + }); + + describe('get borderBottomColor()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-bottom-color: inherit'); + + expect(declaration.borderBottomColor).toBe('inherit'); + + element.setAttribute('style', 'border-bottom-color: red'); + + expect(declaration.borderBottomColor).toBe('red'); + + element.setAttribute('style', 'border-bottom-color: rgba(100, 100, 100, 0.5)'); + + expect(declaration.borderBottomColor).toBe('rgba(100, 100, 100, 0.5)'); + }); + }); + + describe('get borderLeftColor()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-left-color: inherit'); + + expect(declaration.borderLeftColor).toBe('inherit'); + + element.setAttribute('style', 'border-left-color: red'); + + expect(declaration.borderLeftColor).toBe('red'); + + element.setAttribute('style', 'border-left-color: rgba(100, 100, 100, 0.5)'); + + expect(declaration.borderLeftColor).toBe('rgba(100, 100, 100, 0.5)'); + }); + }); + + describe('get borderTopStyle()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-top-style: inherit'); + + expect(declaration.borderTopStyle).toBe('inherit'); + + element.setAttribute('style', 'border-top-style: dotted'); + + expect(declaration.borderTopStyle).toBe('dotted'); + + element.setAttribute('style', 'border-top-style: solid'); + + expect(declaration.borderTopStyle).toBe('solid'); + }); + }); + + describe('get borderRightStyle()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-right-style: inherit'); + + expect(declaration.borderRightStyle).toBe('inherit'); + + element.setAttribute('style', 'border-right-style: dotted'); + + expect(declaration.borderRightStyle).toBe('dotted'); + + element.setAttribute('style', 'border-right-style: solid'); + + expect(declaration.borderRightStyle).toBe('solid'); + }); + }); + + describe('get borderBottomStyle()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-bottom-style: inherit'); + + expect(declaration.borderBottomStyle).toBe('inherit'); + + element.setAttribute('style', 'border-bottom-style: dotted'); + + expect(declaration.borderBottomStyle).toBe('dotted'); + + element.setAttribute('style', 'border-bottom-style: solid'); + + expect(declaration.borderBottomStyle).toBe('solid'); + }); + }); + + describe('get borderLeftStyle()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-left-style: inherit'); + + expect(declaration.borderLeftStyle).toBe('inherit'); + + element.setAttribute('style', 'border-left-style: dotted'); + + expect(declaration.borderLeftStyle).toBe('dotted'); + + element.setAttribute('style', 'border-left-style: solid'); + + expect(declaration.borderLeftStyle).toBe('solid'); + }); + }); + + describe('get borderRadius()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-radius: inherit'); + + expect(declaration.borderRadius).toBe('inherit'); + expect(declaration.borderTopLeftRadius).toBe('inherit'); + expect(declaration.borderTopRightRadius).toBe('inherit'); + expect(declaration.borderBottomRightRadius).toBe('inherit'); + expect(declaration.borderBottomLeftRadius).toBe('inherit'); + + element.setAttribute('style', 'border-radius: 1px 2px 3px 4px'); + + expect(declaration.borderRadius).toBe('1px 2px 3px 4px'); + expect(declaration.borderTopLeftRadius).toBe('1px'); + expect(declaration.borderTopRightRadius).toBe('2px'); + expect(declaration.borderBottomRightRadius).toBe('3px'); + expect(declaration.borderBottomLeftRadius).toBe('4px'); + + element.setAttribute('style', 'border-radius: 1px 2px 3px'); + + expect(declaration.borderRadius).toBe('1px 2px 3px'); + + element.setAttribute('style', 'border-radius: 1px 2px'); + + expect(declaration.borderRadius).toBe('1px 2px'); + + element.setAttribute('style', 'border-radius: 1px'); + + expect(declaration.borderRadius).toBe('1px'); + }); + }); + + describe('get borderTopLeftRadius()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-top-left-radius: inherit'); + + expect(declaration.borderTopLeftRadius).toBe('inherit'); + + element.setAttribute('style', 'border-top-left-radius: 1rem'); + + expect(declaration.borderTopLeftRadius).toBe('1rem'); + }); + }); + + describe('get borderTopRightRadius()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-top-right-radius: inherit'); + + expect(declaration.borderTopRightRadius).toBe('inherit'); + + element.setAttribute('style', 'border-top-right-radius: 1rem'); + + expect(declaration.borderTopRightRadius).toBe('1rem'); + }); + }); + + describe('get borderBottomRightRadius()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-bottom-right-radius: inherit'); + + expect(declaration.borderBottomRightRadius).toBe('inherit'); + + element.setAttribute('style', 'border-bottom-right-radius: 1rem'); + + expect(declaration.borderBottomRightRadius).toBe('1rem'); + }); + }); + + describe('get borderBottomLeftRadius()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'border-bottom-left-radius: inherit'); + + expect(declaration.borderBottomLeftRadius).toBe('inherit'); + + element.setAttribute('style', 'border-bottom-left-radius: 1rem'); + + expect(declaration.borderBottomLeftRadius).toBe('1rem'); + }); + }); + + describe('get borderCollapse()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const value of ['collapse', 'separate', 'inherit']) { + element.setAttribute('style', `border-collapse: ${value}`); + + expect(declaration.borderCollapse).toBe(value); + } + }); + }); + + describe('get clear()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const value of ['inherit', 'none', 'left', 'right', 'both']) { + element.setAttribute('style', `clear: ${value}`); + + expect(declaration.clear).toBe(value); + } + }); + }); + + describe('get clip()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'clip: inherit'); + + expect(declaration.clip).toBe('inherit'); + + element.setAttribute('style', 'clip: auto'); + + expect(declaration.clip).toBe('auto'); + + element.setAttribute('style', 'clip: rect(1px, 10em, 3rem, 2ch)'); + + expect(declaration.clip).toBe('rect(1px, 10em, 3rem, 2ch)'); + }); + }); + + describe('get cssFloat()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const value of ['inherit', 'none', 'left', 'right', 'inline-start', 'inline-end']) { + element.setAttribute('style', `css-float: ${value}`); + + expect(declaration.cssFloat).toBe(value); + } + }); + }); + + describe('get float()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const value of ['inherit', 'none', 'left', 'right', 'inline-start', 'inline-end']) { + element.setAttribute('style', `float: ${value}`); + + expect(declaration.float).toBe(value); + } + }); + }); + + describe('get display()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const value of [ + 'var(--test-variable)', + 'inherit', + 'initial', + 'revert', + 'unset', + 'block', + 'inline', + 'inline-block', + 'flex', + 'inline-flex', + 'grid', + 'inline-grid', + 'flow-root', + 'none', + 'contents', + 'block flow', + 'inline flow', + 'inline flow-root', + 'block flex', + 'inline flex', + 'block grid', + 'inline grid', + 'block flow-root', + 'table', + 'table-row', + 'list-item' + ]) { + element.setAttribute('style', `display: ${value}`); + + expect(declaration.display).toBe(value); + } + }); + }); + + describe('get direction()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const value of ['inherit', 'initial', 'revert', 'unset', 'ltr', 'rtl']) { + element.setAttribute('style', `direction: ${value}`); + + expect(declaration.direction).toBe(value); + } + }); + }); + + describe('get flex()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'flex: inherit'); + + expect(declaration.flex).toBe('inherit'); + expect(declaration.flexGrow).toBe('inherit'); + expect(declaration.flexShrink).toBe('inherit'); + expect(declaration.flexBasis).toBe('inherit'); + + element.setAttribute('style', 'flex: none'); + + expect(declaration.flex).toBe('0 0 auto'); + expect(declaration.flexGrow).toBe('0'); + expect(declaration.flexShrink).toBe('0'); + expect(declaration.flexBasis).toBe('auto'); + + element.setAttribute('style', 'flex: auto'); + + expect(declaration.flex).toBe('1 1 auto'); + expect(declaration.flexGrow).toBe('1'); + expect(declaration.flexShrink).toBe('1'); + expect(declaration.flexBasis).toBe('auto'); + + element.setAttribute('style', 'flex: fit-content(10px)'); + + expect(declaration.flex).toBe('1 1 fit-content(10px)'); + expect(declaration.flexGrow).toBe('1'); + expect(declaration.flexShrink).toBe('1'); + expect(declaration.flexBasis).toBe('fit-content(10px)'); + + element.setAttribute('style', 'flex: 3'); + + expect(declaration.flex).toBe('3 1 0%'); + expect(declaration.flexGrow).toBe('3'); + expect(declaration.flexShrink).toBe('1'); + expect(declaration.flexBasis).toBe('0%'); + + element.setAttribute('style', 'flex: 3 2'); + + expect(declaration.flex).toBe('3 2 0%'); + expect(declaration.flexGrow).toBe('3'); + expect(declaration.flexShrink).toBe('2'); + expect(declaration.flexBasis).toBe('0%'); + + element.setAttribute('style', 'flex: 3 2 min-content'); + + expect(declaration.flex).toBe('3 2 min-content'); + expect(declaration.flexGrow).toBe('3'); + expect(declaration.flexShrink).toBe('2'); + expect(declaration.flexBasis).toBe('min-content'); + + element.setAttribute('style', 'flex: 3 2 50rem'); + + expect(declaration.flex).toBe('3 2 50rem'); + expect(declaration.flexGrow).toBe('3'); + expect(declaration.flexShrink).toBe('2'); + expect(declaration.flexBasis).toBe('50rem'); + }); + }); + + describe('get flexShrink()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'flex-shrink: inherit'); + + expect(declaration.flexShrink).toBe('inherit'); + + element.setAttribute('style', 'flex-shrink: 2'); + + expect(declaration.flexShrink).toBe('2'); + + element.setAttribute('style', 'flex-shrink: 0.6'); + + expect(declaration.flexShrink).toBe('0.6'); + }); + }); + + describe('get flexGrow()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'flex-grow: inherit'); + + expect(declaration.flexGrow).toBe('inherit'); + + element.setAttribute('style', 'flex-grow: 2'); + + expect(declaration.flexGrow).toBe('2'); + + element.setAttribute('style', 'flex-grow: 0.6'); + + expect(declaration.flexGrow).toBe('0.6'); + }); + }); + + describe('get flexBasis()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'flex-basis: 10em'); + + expect(declaration.flexBasis).toBe('10em'); + + element.setAttribute('style', 'flex-basis: fit-content(10px)'); + + expect(declaration.flexBasis).toBe('fit-content(10px)'); + + for (const value of [ + 'inherit', + 'initial', + 'revert', + 'unset', + 'auto', + 'fill', + 'content', + 'max-content', + 'min-content', + 'fit-content' + ]) { + element.setAttribute('style', `flex-basis: ${value}`); + + expect(declaration.flexBasis).toBe(value); + } + }); + }); + + describe('get padding()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'padding: inherit'); + + expect(declaration.padding).toBe('inherit'); + + element.setAttribute('style', 'padding: 1px 2px 3px 4px'); + + expect(declaration.padding).toBe('1px 2px 3px 4px'); + + element.setAttribute('style', 'padding: 1px 2px 3px'); + + expect(declaration.padding).toBe('1px 2px 3px'); + + element.setAttribute('style', 'padding: 1px 2px'); + + expect(declaration.padding).toBe('1px 2px'); + + element.setAttribute('style', 'padding: 1px'); + + expect(declaration.padding).toBe('1px'); + + element.setAttribute('style', 'padding: auto'); + + expect(declaration.padding).toBe(''); + }); + }); + + describe('get paddingTop()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'padding-top: inherit'); + + expect(declaration.paddingTop).toBe('inherit'); + + element.setAttribute('style', 'padding-top: 1px'); + + expect(declaration.paddingTop).toBe('1px'); + + element.setAttribute('style', 'padding-top: 1%'); + + expect(declaration.paddingTop).toBe('1%'); + }); + }); + + describe('get paddingRight()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'padding-right: inherit'); + + expect(declaration.paddingRight).toBe('inherit'); + + element.setAttribute('style', 'padding-right: 1px'); + + expect(declaration.paddingRight).toBe('1px'); + + element.setAttribute('style', 'padding-right: 1%'); + + expect(declaration.paddingRight).toBe('1%'); + }); + }); + + describe('get paddingBottom()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'padding-bottom: inherit'); + + expect(declaration.paddingBottom).toBe('inherit'); + + element.setAttribute('style', 'padding-bottom: 1px'); + + expect(declaration.paddingBottom).toBe('1px'); + + element.setAttribute('style', 'padding-bottom: 1%'); + + expect(declaration.paddingBottom).toBe('1%'); + }); + }); + + describe('get paddingLeft()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'padding-left: inherit'); + + expect(declaration.paddingLeft).toBe('inherit'); + + element.setAttribute('style', 'padding-left: 1px'); + + expect(declaration.paddingLeft).toBe('1px'); + + element.setAttribute('style', 'padding-left: 1%'); + + expect(declaration.paddingLeft).toBe('1%'); + }); + }); + + describe('get margin()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'margin: inherit'); + + expect(declaration.margin).toBe('inherit'); + + element.setAttribute('style', 'margin: 1px 2px 3px 4px'); + + expect(declaration.margin).toBe('1px 2px 3px 4px'); + + element.setAttribute('style', 'margin: 1px 2px 3px'); + + expect(declaration.margin).toBe('1px 2px 3px'); + + element.setAttribute('style', 'margin: 1px 2px'); + + expect(declaration.margin).toBe('1px 2px'); + + element.setAttribute('style', 'margin: 1px'); + + expect(declaration.margin).toBe('1px'); + + element.setAttribute('style', 'margin: auto'); + + expect(declaration.margin).toBe('auto'); + }); + }); + + describe('get marginTop()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'margin-top: inherit'); + + expect(declaration.marginTop).toBe('inherit'); + + element.setAttribute('style', 'margin-top: 1px'); + + expect(declaration.marginTop).toBe('1px'); + + element.setAttribute('style', 'margin-top: 1%'); + + expect(declaration.marginTop).toBe('1%'); + + element.setAttribute('style', 'margin-top: auto'); + + expect(declaration.marginTop).toBe('auto'); + }); + }); + + describe('get marginRight()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'margin-right: inherit'); + + expect(declaration.marginRight).toBe('inherit'); + + element.setAttribute('style', 'margin-right: 1px'); + + expect(declaration.marginRight).toBe('1px'); + + element.setAttribute('style', 'margin-right: 1%'); + + expect(declaration.marginRight).toBe('1%'); + + element.setAttribute('style', 'margin-right: auto'); + + expect(declaration.marginRight).toBe('auto'); + }); + }); + + describe('get marginBottom()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'margin-bottom: inherit'); + + expect(declaration.marginBottom).toBe('inherit'); + + element.setAttribute('style', 'margin-bottom: 1px'); + + expect(declaration.marginBottom).toBe('1px'); + + element.setAttribute('style', 'margin-bottom: 1%'); + + expect(declaration.marginBottom).toBe('1%'); + + element.setAttribute('style', 'margin-bottom: auto'); + + expect(declaration.marginBottom).toBe('auto'); + }); + }); + + describe('get marginLeft()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'margin-left: inherit'); + + expect(declaration.marginLeft).toBe('inherit'); + + element.setAttribute('style', 'margin-left: 1px'); + + expect(declaration.marginLeft).toBe('1px'); + + element.setAttribute('style', 'margin-left: 1%'); + + expect(declaration.marginLeft).toBe('1%'); + + element.setAttribute('style', 'margin-left: auto'); + + expect(declaration.marginLeft).toBe('auto'); + }); + }); + + describe('get background()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'background: inherit'); + + expect(declaration.background).toBe('inherit'); + expect(declaration.backgroundAttachment).toBe('inherit'); + expect(declaration.backgroundClip).toBe('inherit'); + expect(declaration.backgroundColor).toBe('inherit'); + expect(declaration.backgroundImage).toBe('inherit'); + expect(declaration.backgroundPosition).toBe('inherit'); + expect(declaration.backgroundRepeat).toBe('inherit'); + expect(declaration.backgroundSize).toBe('inherit'); + + element.setAttribute('style', 'background: green'); + + expect(declaration.background).toBe('green'); + + element.setAttribute('style', 'background: rgb(255, 255, 255)'); + + expect(declaration.background).toBe('rgb(255, 255, 255)'); + + element.setAttribute('style', 'background: url("test.jpg") repeat-y'); + + expect(declaration.background).toBe('url("test.jpg") repeat-y'); + + element.setAttribute('style', 'background: border-box red'); + + expect(declaration.background).toBe('border-box border-box red'); + + element.setAttribute('style', 'background: no-repeat center/80% url("../img/image.png")'); + + expect(declaration.background).toBe('url("../img/image.png") center center / 80% no-repeat'); + + element.setAttribute( + 'style', + 'background: scroll no-repeat top center / 80% url("../img/image.png")' + ); + + expect(declaration.background).toBe( + 'url("../img/image.png") center top / 80% no-repeat scroll' + ); + }); + }); + + describe('get backgroundImage()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'background-image: inherit'); + + expect(declaration.backgroundImage).toBe('inherit'); + + element.setAttribute('style', 'background-image: url("test.jpg")'); + + expect(declaration.backgroundImage).toBe('url("test.jpg")'); + + element.setAttribute('style', 'background-image: url(test.jpg)'); + + expect(declaration.backgroundImage).toBe('url("test.jpg")'); + + element.setAttribute('style', 'background-image: url(test.jpg), url(test2.jpg)'); + + expect(declaration.backgroundImage).toBe('url("test.jpg"), url("test2.jpg")'); + }); + }); + + describe('get backgroundColor()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'background-color: inherit'); + + expect(declaration.backgroundColor).toBe('inherit'); + + element.setAttribute('style', 'background-color: red'); + + expect(declaration.backgroundColor).toBe('red'); + + element.setAttribute('style', 'background-color: rgba(0, 55, 1,0.5)'); + + expect(declaration.backgroundColor).toBe('rgba(0, 55, 1, 0.5)'); + }); + }); + + describe('get backgroundRepeat()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const repeat of [ + 'inherit', + 'initial', + 'revert', + 'unset', + 'repeat', + 'repeat-x', + 'repeat-y', + 'no-repeat' + ]) { + element.setAttribute('style', `background-repeat: ${repeat}`); + expect(declaration.backgroundRepeat).toBe(repeat); + } + }); + }); + + describe('get backgroundAttachment()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const repeat of ['inherit', 'initial', 'revert', 'unset', 'scroll', 'fixed']) { + element.setAttribute('style', `background-attachment: ${repeat}`); + expect(declaration.backgroundAttachment).toBe(repeat); + } + }); + }); + + describe('get backgroundPosition()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'background-position: inherit'); + + expect(declaration.backgroundPosition).toBe('inherit'); + + element.setAttribute('style', 'background-position: top'); + + expect(declaration.backgroundPosition).toBe('center top'); + expect(declaration.backgroundPositionX).toBe('center'); + expect(declaration.backgroundPositionY).toBe('top'); + + element.setAttribute('style', 'background-position: bottom'); + + expect(declaration.backgroundPosition).toBe('center bottom'); + expect(declaration.backgroundPositionX).toBe('center'); + expect(declaration.backgroundPositionY).toBe('bottom'); + + element.setAttribute('style', 'background-position: left'); + + expect(declaration.backgroundPosition).toBe('left center'); + expect(declaration.backgroundPositionX).toBe('left'); + expect(declaration.backgroundPositionY).toBe('center'); + + element.setAttribute('style', 'background-position: right'); + + expect(declaration.backgroundPosition).toBe('right center'); + expect(declaration.backgroundPositionX).toBe('right'); + expect(declaration.backgroundPositionY).toBe('center'); + + element.setAttribute('style', 'background-position: center'); + + expect(declaration.backgroundPosition).toBe('center center'); + expect(declaration.backgroundPositionX).toBe('center'); + expect(declaration.backgroundPositionY).toBe('center'); + + element.setAttribute('style', 'background-position: 25% 75%'); + + expect(declaration.backgroundPosition).toBe('25% 75%'); + expect(declaration.backgroundPositionX).toBe('25%'); + expect(declaration.backgroundPositionY).toBe('75%'); + + element.setAttribute('style', 'background-position: 0 0'); + + expect(declaration.backgroundPosition).toBe('0px 0px'); + expect(declaration.backgroundPositionX).toBe('0px'); + expect(declaration.backgroundPositionY).toBe('0px'); + + element.setAttribute('style', 'background-position: 1cm 2cm'); + + expect(declaration.backgroundPosition).toBe('1cm 2cm'); + expect(declaration.backgroundPositionX).toBe('1cm'); + expect(declaration.backgroundPositionY).toBe('2cm'); + + element.setAttribute('style', 'background-position: 10ch 8em'); + + expect(declaration.backgroundPosition).toBe('10ch 8em'); + expect(declaration.backgroundPositionX).toBe('10ch'); + expect(declaration.backgroundPositionY).toBe('8em'); + + element.setAttribute('style', 'background-position: 0 0, center'); + + expect(declaration.backgroundPosition).toBe('0px 0px, center center'); + expect(declaration.backgroundPositionX).toBe('0px, center'); + expect(declaration.backgroundPositionY).toBe('0px, center'); + + element.setAttribute('style', 'background-position: bottom 10px right 20px'); + + expect(declaration.backgroundPosition).toBe('right 20px bottom 10px'); + expect(declaration.backgroundPositionX).toBe('right 20px'); + expect(declaration.backgroundPositionY).toBe('bottom 10px'); + + element.setAttribute('style', 'background-position: right 20px bottom 10px'); + + expect(declaration.backgroundPosition).toBe('right 20px bottom 10px'); + expect(declaration.backgroundPositionX).toBe('right 20px'); + expect(declaration.backgroundPositionY).toBe('bottom 10px'); + + element.setAttribute('style', 'background-position: bottom 10px right'); + + expect(declaration.backgroundPosition).toBe('right bottom 10px'); + expect(declaration.backgroundPositionX).toBe('right'); + expect(declaration.backgroundPositionY).toBe('bottom 10px'); + + element.setAttribute('style', 'background-position: top right 10px'); + + expect(declaration.backgroundPosition).toBe('right 10px top'); + expect(declaration.backgroundPositionX).toBe('right 10px'); + expect(declaration.backgroundPositionY).toBe('top'); + + element.setAttribute('style', 'background-position: right 10px top'); + + expect(declaration.backgroundPosition).toBe('right 10px top'); + expect(declaration.backgroundPositionX).toBe('right 10px'); + expect(declaration.backgroundPositionY).toBe('top'); + + element.setAttribute('style', 'background-position: right top 10px'); + + expect(declaration.backgroundPosition).toBe('right top 10px'); + expect(declaration.backgroundPositionX).toBe('right'); + expect(declaration.backgroundPositionY).toBe('top 10px'); + }); + }); + + describe('get width()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'width: inherit'); + + expect(declaration.width).toBe('inherit'); + + element.setAttribute('style', 'width: 75%'); + + expect(declaration.width).toBe('75%'); + + element.setAttribute('style', 'width: 75px'); + + expect(declaration.width).toBe('75px'); + + element.setAttribute('style', 'width: fit-content(20em)'); + + expect(declaration.width).toBe('fit-content(20em)'); + }); + }); + + describe('get top()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'top: inherit'); + + expect(declaration.top).toBe('inherit'); + + element.setAttribute('style', 'top: 75%'); + + expect(declaration.top).toBe('75%'); + + element.setAttribute('style', 'top: 75px'); + + expect(declaration.top).toBe('75px'); + + element.setAttribute('style', 'top: fit-content(20em)'); + + expect(declaration.top).toBe('fit-content(20em)'); + }); + }); + + describe('get right()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'right: inherit'); + + expect(declaration.right).toBe('inherit'); + + element.setAttribute('style', 'right: 75%'); + + expect(declaration.right).toBe('75%'); + + element.setAttribute('style', 'right: 75px'); + + expect(declaration.right).toBe('75px'); + + element.setAttribute('style', 'right: fit-content(20em)'); + + expect(declaration.right).toBe('fit-content(20em)'); + }); + }); + + describe('get bottom()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'bottom: inherit'); + + expect(declaration.bottom).toBe('inherit'); + + element.setAttribute('style', 'bottom: 75%'); + + expect(declaration.bottom).toBe('75%'); + + element.setAttribute('style', 'bottom: 75px'); + + expect(declaration.bottom).toBe('75px'); + + element.setAttribute('style', 'bottom: fit-content(20em)'); + + expect(declaration.bottom).toBe('fit-content(20em)'); + }); + }); + + describe('get left()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'left: inherit'); + + expect(declaration.left).toBe('inherit'); + + element.setAttribute('style', 'left: 75%'); + + expect(declaration.left).toBe('75%'); + + element.setAttribute('style', 'left: 75px'); + + expect(declaration.left).toBe('75px'); + + element.setAttribute('style', 'left: fit-content(20em)'); + + expect(declaration.left).toBe('fit-content(20em)'); + }); + }); + + describe('get font()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', 'font: inherit'); + + expect(declaration.font).toBe('inherit'); + + element.setAttribute('style', 'font: 1.2em "Fira Sans", sans-serif'); + + expect(declaration.font).toBe('1.2em "Fira Sans", sans-serif'); + expect(declaration.fontFamily).toBe('"Fira Sans", sans-serif'); + expect(declaration.fontSize).toBe('1.2em'); + expect(declaration.fontStretch).toBe('normal'); + expect(declaration.fontStyle).toBe('normal'); + expect(declaration.fontVariant).toBe('normal'); + expect(declaration.fontWeight).toBe('normal'); + expect(declaration.lineHeight).toBe('normal'); + + element.setAttribute('style', 'font: italic 1.2em "Fira Sans", sans-serif'); + expect(declaration.font).toBe('italic 1.2em "Fira Sans", sans-serif'); + + element.setAttribute('style', 'font: 1.2em Fira Sans, sans-serif'); + expect(declaration.font).toBe('1.2em "Fira Sans", sans-serif'); + + element.setAttribute('style', 'font: 1.2em "Fira Sans, sans-serif'); + expect(declaration.font).toBe('1.2em "Fira Sans, sans-serif"'); + + element.setAttribute('style', 'font: 1.2em Fira "Sans, sans-serif'); + expect(declaration.font).toBe(''); + + element.setAttribute('style', 'font: italic small-caps bold 16px/2 cursive'); + expect(declaration.font).toBe('italic small-caps bold 16px / 2 cursive'); + + element.setAttribute('style', 'font: small-caps bold 24px/1 sans-serif'); + expect(declaration.font).toBe('small-caps bold 24px / 1 sans-serif'); + + element.setAttribute('style', 'font: caption'); + + expect(declaration.font).toBe('caption'); + }); + }); + + describe('get fontStyle()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const property of ['inherit', 'normal', 'italic', 'oblique', 'oblique 10deg']) { + element.setAttribute('style', `font-style: ${property}`); + expect(declaration.fontStyle).toBe(property); + } + }); + }); + + describe('get fontVariant()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const property of ['inherit', 'normal', 'small-caps']) { + element.setAttribute('style', `font-variant: ${property}`); + expect(declaration.fontVariant).toBe(property); + } + }); + }); + + describe('get fontWeight()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const property of [ + 'inherit', + 'normal', + 'bold', + 'bolder', + 'lighter', + '100', + '200', + '300', + '400', + '500', + '600', + '700', + '800', + '900' + ]) { + element.setAttribute('style', `font-weight: ${property}`); + expect(declaration.fontWeight).toBe(property); + } + }); + }); + + describe('get fontStretch()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const property of [ + 'inherit', + 'normal', + 'ultra-condensed', + 'extra-condensed', + 'condensed', + 'semi-condensed', + 'semi-expanded', + 'expanded', + 'extra-expanded', + 'ultra-expanded' + ]) { + element.setAttribute('style', `font-stretch: ${property}`); + expect(declaration.fontStretch).toBe(property); + } + }); + }); + + describe('get fontSize()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const property of [ + 'inherit', + 'medium', + 'xx-small', + 'x-small', + 'small', + 'large', + 'x-large', + 'xx-large', + 'smaller', + 'larger', + '10px', + '10em', + '10%' + ]) { + element.setAttribute('style', `font-size: ${property}`); + expect(declaration.fontSize).toBe(property); + } + }); + }); + + describe('get lineHeight()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const property of ['inherit', 'normal', '10px', '10em', '10%', '10']) { + element.setAttribute('style', `line-height: ${property}`); + expect(declaration.lineHeight).toBe(property); + } + }); + }); + + describe('get fontFamily()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const property of [ + 'inherit', + 'serif', + 'sans-serif', + 'cursive', + 'fantasy', + 'monospace' + ]) { + element.setAttribute('style', `font-family: ${property}`); + expect(declaration.fontFamily).toBe(property); + } + + element.setAttribute('style', 'font-family: "Fira Sans", sans-serif'); + expect(declaration.fontFamily).toBe('"Fira Sans", sans-serif'); + + element.setAttribute('style', 'font-family: Fira Sans, sans-serif'); + expect(declaration.fontFamily).toBe('"Fira Sans", sans-serif'); + + element.setAttribute('style', 'font-family: "Fira Sans, sans-serif'); + expect(declaration.fontFamily).toBe('"Fira Sans, sans-serif"'); + + element.setAttribute('style', 'font-family: Fira "Sans, sans-serif'); + expect(declaration.fontFamily).toBe(''); + }); + }); + + describe('get color()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const property of ['inherit', 'red', 'rgb(255, 0, 0)', '#ff0000']) { + element.setAttribute('style', `color: ${property}`); + expect(declaration.color).toBe(property); + } + }); + }); + + describe('get floodColor()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const property of ['inherit', 'red', 'rgb(255, 0, 0)', '#ff0000']) { + element.setAttribute('style', `flood-color: ${property}`); + expect(declaration.floodColor).toBe(property); + } + }); + }); + + describe('get textTransform()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const value of [ + 'var(--test-variable)', + 'inherit', + 'initial', + 'revert', + 'unset', + 'capitalize', + 'uppercase', + 'lowercase', + 'none', + 'full-width', + 'full-size-kana' + ]) { + element.setAttribute('style', `text-transform: ${value}`); + + expect(declaration.textTransform).toBe(value); + } + }); + }); + + describe('get visibility()', () => { + it('Returns style property.', () => { + const declaration = new CSSStyleDeclaration(element); + + for (const value of [ + 'var(--test-variable)', + 'inherit', + 'initial', + 'revert', + 'unset', + 'visible', + 'hidden', + 'collapse' + ]) { + element.setAttribute('style', `visibility: ${value}`); + + expect(declaration.visibility).toBe(value); + } + }); + }); + + describe('get length()', () => { + it('Returns length when of styles on element.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', `border: 2px solid green;border-radius: 2px;font-size: 12px;`); + + expect(declaration.length).toBe(22); + }); + + it('Returns length without element.', () => { + const declaration = new CSSStyleDeclaration(); + + declaration.border = '2px solid green'; + declaration.borderRadius = '2px'; + declaration.fontSize = '12px'; + + expect(declaration.length).toBe(22); + }); + }); + + describe('get cssText()', () => { + it('Returns CSS text when using element.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute( + 'style', + `border: green 2px solid; border-radius: 2px;font-size: 12px;` + ); + + expect(declaration.cssText).toBe( + 'border: 2px solid green; border-radius: 2px; font-size: 12px;' + ); + }); + + it('Returns CSS without element.', () => { + const declaration = new CSSStyleDeclaration(); + + declaration.border = '2px solid green'; + declaration.borderRadius = '2px'; + declaration.fontSize = '12px'; + + expect(declaration.cssText).toBe( + 'border: 2px solid green; border-radius: 2px; font-size: 12px;' + ); + }); + }); + + describe('set cssText()', () => { + it('Sets CSS text when using element.', () => { + const declaration = new CSSStyleDeclaration(element); + + declaration.cssText = 'border: 2px solid green; border-radius: 2px;font-size: 12px;'; + + expect(element.getAttribute('style')).toBe( + 'border: 2px solid green; border-radius: 2px; font-size: 12px;' + ); + }); + + it('Sets CSS text without element.', () => { + const declaration = new CSSStyleDeclaration(); + + declaration.cssText = 'border: 2px solid green; border-radius: 2px;font-size: 12px;'; + + expect(declaration.border).toBe('2px solid green'); + expect(declaration.borderRadius).toBe('2px'); + expect(declaration.fontSize).toBe('12px'); + }); + + it('Removes style property on element if empty value is sent.', () => { + const declaration = new CSSStyleDeclaration(element); + + declaration.cssText = ''; + + expect(element.getAttribute('style')).toBe(null); + }); + }); + + describe('item()', () => { + it('Returns an item by index when using element.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', `border: 2px solid green;border-radius: 2px;font-size: 12px;`); + + expect(declaration.item(0)).toBe('border-top-width'); + expect(declaration.item(1)).toBe('border-right-width'); + expect(declaration.item(2)).toBe('border-bottom-width'); + expect(declaration.item(3)).toBe('border-left-width'); + expect(declaration.item(4)).toBe('border-top-style'); + expect(declaration.item(5)).toBe('border-right-style'); + expect(declaration.item(6)).toBe('border-bottom-style'); + expect(declaration.item(7)).toBe('border-left-style'); + expect(declaration.item(8)).toBe('border-top-color'); + expect(declaration.item(9)).toBe('border-right-color'); + expect(declaration.item(10)).toBe('border-bottom-color'); + expect(declaration.item(11)).toBe('border-left-color'); + expect(declaration.item(12)).toBe('border-image-source'); + expect(declaration.item(13)).toBe('border-image-slice'); + expect(declaration.item(14)).toBe('border-image-width'); + expect(declaration.item(15)).toBe('border-image-outset'); + expect(declaration.item(16)).toBe('border-image-repeat'); + expect(declaration.item(17)).toBe('border-top-left-radius'); + expect(declaration.item(18)).toBe('border-top-right-radius'); + expect(declaration.item(19)).toBe('border-bottom-right-radius'); + expect(declaration.item(20)).toBe('border-bottom-left-radius'); + expect(declaration.item(21)).toBe('font-size'); + expect(declaration.item(22)).toBe(''); + }); + + it('Returns an item by index without element.', () => { + const declaration = new CSSStyleDeclaration(element); + + declaration.cssText = 'border: 2px solid green;border-radius: 2px;font-size: 12px;'; + + expect(declaration.item(0)).toBe('border-top-width'); + expect(declaration.item(1)).toBe('border-right-width'); + expect(declaration.item(2)).toBe('border-bottom-width'); + expect(declaration.item(3)).toBe('border-left-width'); + expect(declaration.item(4)).toBe('border-top-style'); + expect(declaration.item(5)).toBe('border-right-style'); + expect(declaration.item(6)).toBe('border-bottom-style'); + expect(declaration.item(7)).toBe('border-left-style'); + expect(declaration.item(8)).toBe('border-top-color'); + expect(declaration.item(9)).toBe('border-right-color'); + expect(declaration.item(10)).toBe('border-bottom-color'); + expect(declaration.item(11)).toBe('border-left-color'); + expect(declaration.item(12)).toBe('border-image-source'); + expect(declaration.item(13)).toBe('border-image-slice'); + expect(declaration.item(14)).toBe('border-image-width'); + expect(declaration.item(15)).toBe('border-image-outset'); + expect(declaration.item(16)).toBe('border-image-repeat'); + expect(declaration.item(17)).toBe('border-top-left-radius'); + expect(declaration.item(18)).toBe('border-top-right-radius'); + expect(declaration.item(19)).toBe('border-bottom-right-radius'); + expect(declaration.item(20)).toBe('border-bottom-left-radius'); + expect(declaration.item(21)).toBe('font-size'); + expect(declaration.item(22)).toBe(''); + }); + }); + + describe('setProperty()', () => { + it('Sets a CSS property when using element.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', `border: 2px solid green;border-radius: 2px;font-size: 12px;`); + + declaration.setProperty('background-color', 'green'); + declaration.setProperty('border-radius', '4px', 'important'); + + expect(element.getAttribute('style')).toBe( + 'border: 2px solid green; border-radius: 4px !important; font-size: 12px; background-color: green;' + ); + }); + + it('Sets a CSS property without element.', () => { + const declaration = new CSSStyleDeclaration(); + + declaration.cssText = `border: 2px solid green;border-radius: 2px;font-size: 12px;`; + declaration.setProperty('background-color', 'green'); + + expect(declaration.cssText).toBe( + 'border: 2px solid green; border-radius: 2px; font-size: 12px; background-color: green;' + ); + }); + + it('Removes style attribute on element if empty value is sent', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', `border: 2px solid green;`); + + declaration.setProperty('border', ''); + + expect(element.getAttribute('style')).toBe(null); + }); + + it('Can set a CSS variable.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', `border: 2px solid green;`); + + declaration.setProperty('--test-key', 'value'); + + expect(element.getAttribute('style')).toBe('border: 2px solid green; --test-key: value;'); + expect(declaration.getPropertyValue('--test-key')).toBe('value'); + }); + }); + + describe('removeProperty()', () => { + it('Removes a CSS property when using element.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', `border: 2px solid blue; color: red;`); + declaration.removeProperty('border'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `border-top: 2px solid blue; color: red;`); + declaration.removeProperty('border-top'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `border-right: 2px solid blue; color: red;`); + declaration.removeProperty('border-right'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `border-bottom: 2px solid blue; color: red;`); + declaration.removeProperty('border-bottom'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `border-left: 2px solid blue; color: red;`); + declaration.removeProperty('border-left'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `border-width: 2px; color: red;`); + declaration.removeProperty('border-width'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `border-style: solid; color: red;`); + declaration.removeProperty('border-style'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `border-color: blue; color: red;`); + declaration.removeProperty('border-color'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute( + 'style', + `border-image: url('/media/examples/border-diamonds.png') 30; color: red;` + ); + declaration.removeProperty('border-image'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `border-radius: 2px;color: red;`); + declaration.removeProperty('border-radius'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute( + 'style', + `background: no-repeat center/80% url("../img/image.png");color: red;` + ); + declaration.removeProperty('background'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `background-position: 25% 75%;color: red;`); + declaration.removeProperty('background-position'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `flex: 3 2 min-content;color: red;`); + declaration.removeProperty('flex'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `font: 1.2em "Fira Sans", sans-serif;color: red;`); + declaration.removeProperty('font'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `padding: 1px 2px 3px 4px;color: red;`); + declaration.removeProperty('padding'); + expect(element.getAttribute('style')).toBe('color: red;'); + + element.setAttribute('style', `margin: 1px 2px 3px 4px;color: red;`); + declaration.removeProperty('margin'); + expect(element.getAttribute('style')).toBe('color: red;'); + }); + + it('Removes a CSS property without element.', () => { + const declaration = new CSSStyleDeclaration(); + + declaration.cssText = `border: 2px solid green;border-radius: 2px;font-size: 12px;`; + declaration.removeProperty('border-radius'); + + expect(declaration.cssText).toBe('border: 2px solid green; font-size: 12px;'); + }); + + it('Removes style attribute on element if there are no CSS properties left.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', `border: 2px solid green;border-radius: 2px;`); + + declaration.removeProperty('border'); + declaration.removeProperty('border-radius'); + + expect(element.getAttribute('style')).toBe(null); + }); + }); + + describe('getPropertyValue()', () => { + it('Returns a CSS property value when using element.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', `border: 2px solid green;border-radius: 2px;font-size: 12px;`); + + expect(declaration.getPropertyValue('border')).toBe('2px solid green'); + expect(declaration.getPropertyValue('border-radius')).toBe('2px'); + expect(declaration.getPropertyValue('font-size')).toBe('12px'); + expect(declaration.getPropertyValue('background')).toBe(''); + }); + + it('Returns a CSS property without element.', () => { + const declaration = new CSSStyleDeclaration(); + + declaration.cssText = `border: 2px solid green;border-radius: 2px;font-size: 12px;`; + + expect(declaration.getPropertyValue('border')).toBe('2px solid green'); + expect(declaration.getPropertyValue('border-radius')).toBe('2px'); + expect(declaration.getPropertyValue('font-size')).toBe('12px'); + expect(declaration.getPropertyValue('background')).toBe(''); + }); + + it('Does not override important values when defined multiple times.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute( + 'style', + `text-transform: uppercase !important; text-transform: capitalize;` + ); + + expect(declaration.getPropertyValue('text-transform')).toBe('uppercase'); + expect(declaration.getPropertyPriority('text-transform')).toBe('important'); + }); + }); + + describe('getPropertyPriority()', () => { + it('Returns property priority.', () => { + const declaration = new CSSStyleDeclaration(element); + + element.setAttribute('style', `text-transform: uppercase`); + + expect(declaration.getPropertyPriority('text-transform')).toBe(''); + + element.setAttribute('style', `text-transform: uppercase !important`); + + expect(declaration.getPropertyPriority('text-transform')).toBe('important'); + }); + }); +}); diff --git a/packages/happy-dom/test/match-media/MediaQueryList.test.ts b/packages/happy-dom/test/match-media/MediaQueryList.test.ts new file mode 100644 index 000000000..c9b6cb3bf --- /dev/null +++ b/packages/happy-dom/test/match-media/MediaQueryList.test.ts @@ -0,0 +1,77 @@ +import IWindow from '../../src/window/IWindow'; +import Window from '../../src/window/Window'; +import MediaQueryList from '../../src/match-media/MediaQueryList'; +import MediaQueryListEvent from '../../src/event/events/MediaQueryListEvent'; + +describe('MediaQueryList', () => { + let window: IWindow; + + beforeEach(() => { + window = new Window({ innerWidth: 1024, innerHeight: 1024 }); + }); + + describe('get matches()', () => { + it('Handles "min-width".', () => { + expect(new MediaQueryList(window, '(min-width: 1025px)').matches).toBe(false); + expect(new MediaQueryList(window, '(min-width: 1024px)').matches).toBe(true); + }); + + it('Handles "max-width".', () => { + expect(new MediaQueryList(window, '(max-width: 1023px)').matches).toBe(false); + expect(new MediaQueryList(window, '(max-width: 1024px)').matches).toBe(true); + }); + + it('Handles "min-height".', () => { + expect(new MediaQueryList(window, '(min-height: 1025px)').matches).toBe(false); + expect(new MediaQueryList(window, '(min-height: 1024px)').matches).toBe(true); + }); + + it('Handles "max-height".', () => { + expect(new MediaQueryList(window, '(max-height: 1023px)').matches).toBe(false); + expect(new MediaQueryList(window, '(max-height: 1024px)').matches).toBe(true); + }); + }); + + describe('get media()', () => { + it('Returns media string.', () => { + const media = '(min-width: 1023px)'; + expect(new MediaQueryList(window, media).media).toBe(media); + }); + }); + + describe('addEventListener()', () => { + it('Listens for window "resize" event when sending in a "change" event.', () => { + let triggeredEvent = null; + const media = '(min-width: 1025px)'; + const mediaQueryList = new MediaQueryList(window, media); + + mediaQueryList.addEventListener('change', (event: MediaQueryListEvent): void => { + triggeredEvent = event; + }); + + expect(mediaQueryList.matches).toBe(false); + + window.happyDOM.setInnerWidth(1025); + + expect(triggeredEvent.matches).toBe(true); + expect(triggeredEvent.media).toBe(media); + }); + }); + + describe('removeEventListener()', () => { + it('Removes listener for window "resize" event when sending in a "change" event.', () => { + let triggeredEvent = null; + const mediaQueryList = new MediaQueryList(window, '(min-width: 1025px)'); + const listener = (event: MediaQueryListEvent): void => { + triggeredEvent = event; + }; + + mediaQueryList.addEventListener('change', listener); + mediaQueryList.removeEventListener('change', listener); + + window.happyDOM.setInnerWidth(1025); + + expect(triggeredEvent).toBe(null); + }); + }); +}); diff --git a/packages/happy-dom/test/nodes/document/Document.test.ts b/packages/happy-dom/test/nodes/document/Document.test.ts index 02c151f2a..7dbde0617 100644 --- a/packages/happy-dom/test/nodes/document/Document.test.ts +++ b/packages/happy-dom/test/nodes/document/Document.test.ts @@ -12,7 +12,7 @@ import Element from '../../../src/nodes/element/Element'; import Event from '../../../src/event/Event'; import SVGSVGElement from '../../../src/nodes/svg-element/SVGSVGElement'; import NamespaceURI from '../../../src/config/NamespaceURI'; -import Attr from '../../../src/attribute/Attr'; +import Attr from '../../../src/nodes/attr/Attr'; import ParentNodeUtility from '../../../src/nodes/parent-node/ParentNodeUtility'; import QuerySelector from '../../../src/query-selector/QuerySelector'; import NodeFilter from '../../../src/tree-walker/NodeFilter'; @@ -69,7 +69,8 @@ describe('Document', () => { describe('get children()', () => { it('Returns Element child nodes.', () => { document.appendChild(document.createTextNode('test')); - expect(document.children).toEqual([document.documentElement]); + expect(document.children.length).toEqual(1); + expect(document.children[0] === document.documentElement).toBe(true); }); }); @@ -89,7 +90,11 @@ describe('Document', () => { document.body.appendChild(div); - expect(Array.from(document.scripts)).toEqual([script1, script2]); + const scripts = Array.from(document.scripts); + + expect(scripts.length).toBe(2); + expect(scripts[0]).toBe(script1); + expect(scripts[1]).toBe(script2); }); }); @@ -118,7 +123,7 @@ describe('Document', () => { div.appendChild(span2); div.appendChild(text2); - expect(div.firstElementChild).toBe(span1); + expect(div.firstElementChild === span1).toBe(true); }); }); @@ -139,7 +144,7 @@ describe('Document', () => { div.appendChild(span2); div.appendChild(text2); - expect(div.lastElementChild).toBe(span2); + expect(div.lastElementChild === span2).toBe(true); }); }); @@ -223,25 +228,25 @@ describe('Document', () => { describe('get body()', () => { it('Returns element.', () => { - expect(document.body).toBe(document.children[0].children[1]); + expect(document.body === document.children[0].children[1]).toBe(true); }); }); describe('get head()', () => { it('Returns element.', () => { - expect(document.head).toBe(document.children[0].children[0]); + expect(document.head === document.children[0].children[0]).toBe(true); }); }); describe('get documentElement()', () => { it('Returns element.', () => { - expect(document.documentElement).toBe(document.children[0]); + expect(document.documentElement === document.children[0]).toBe(true); }); }); describe('get doctype()', () => { it('Returns DocumentType element.', () => { - expect(document.doctype).toBe(document.childNodes[0]); + expect(document.doctype === document.childNodes[0]).toBe(true); }); }); @@ -314,7 +319,7 @@ describe('Document', () => { }); it('Returns the first custom element that has document as root node when the focused element is nestled in multiple shadow roots.', () => { - class CustomElementA extends window.HTMLElement { + class CustomElementA extends (window).HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); @@ -328,7 +333,7 @@ describe('Document', () => { `; } } - class CustomElementB extends window.HTMLElement { + class CustomElementB extends (window).HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); @@ -363,7 +368,7 @@ describe('Document', () => { button.focus(); button.focus(); - expect(document.activeElement).toBe(customElementA); + expect(document.activeElement === customElementA).toBe(true); expect(focusCalls).toBe(1); }); }); @@ -405,8 +410,10 @@ describe('Document', () => { let isCalled = false; jest.spyOn(ParentNodeUtility, 'append').mockImplementation((parentNode, ...nodes) => { - expect(parentNode).toBe(document); - expect(nodes).toEqual([node1, node2]); + expect(parentNode === document).toBe(true); + expect(nodes.length).toBe(2); + expect(nodes[0] === node1).toBe(true); + expect(nodes[1] === node2).toBe(true); isCalled = true; }); @@ -422,8 +429,10 @@ describe('Document', () => { let isCalled = false; jest.spyOn(ParentNodeUtility, 'prepend').mockImplementation((parentNode, ...nodes) => { - expect(parentNode).toBe(document); - expect(nodes).toEqual([node1, node2]); + expect(parentNode === document).toBe(true); + expect(nodes.length).toBe(2); + expect(nodes[0] === node1).toBe(true); + expect(nodes[1] === node2).toBe(true); isCalled = true; }); @@ -441,8 +450,10 @@ describe('Document', () => { jest .spyOn(ParentNodeUtility, 'replaceChildren') .mockImplementation((parentNode, ...nodes) => { - expect(parentNode).toBe(document); - expect(nodes).toEqual([node1, node2]); + expect(parentNode === document).toBe(true); + expect(nodes.length).toBe(2); + expect(nodes[0] === node1).toBe(true); + expect(nodes[1] === node2).toBe(true); isCalled = true; }); @@ -457,12 +468,15 @@ describe('Document', () => { const expectedSelector = 'selector'; jest.spyOn(QuerySelector, 'querySelectorAll').mockImplementation((parentNode, selector) => { - expect(parentNode).toBe(document); + expect(parentNode === document).toBe(true); expect(selector).toEqual(expectedSelector); return >[element]; }); - expect(document.querySelectorAll(expectedSelector)).toEqual([element]); + const result = document.querySelectorAll(expectedSelector); + + expect(result.length).toBe(1); + expect(result[0] === element).toBe(true); }); }); @@ -472,12 +486,12 @@ describe('Document', () => { const expectedSelector = 'selector'; jest.spyOn(QuerySelector, 'querySelector').mockImplementation((parentNode, selector) => { - expect(parentNode).toBe(document); + expect(parentNode === document).toBe(true); expect(selector).toEqual(expectedSelector); return element; }); - expect(document.querySelector(expectedSelector)).toEqual(element); + expect(document.querySelector(expectedSelector) === element).toBe(true); }); }); @@ -489,12 +503,14 @@ describe('Document', () => { jest .spyOn(ParentNodeUtility, 'getElementsByClassName') .mockImplementation((parentNode, requestedClassName) => { - expect(parentNode).toBe(document); + expect(parentNode === document).toBe(true); expect(requestedClassName).toEqual(className); return >[element]; }); - expect(document.getElementsByClassName(className)).toEqual([element]); + const result = document.getElementsByClassName(className); + expect(result.length).toBe(1); + expect(result[0] === element).toBe(true); }); }); @@ -506,12 +522,14 @@ describe('Document', () => { jest .spyOn(ParentNodeUtility, 'getElementsByTagName') .mockImplementation((parentNode, requestedTagName) => { - expect(parentNode).toBe(document); + expect(parentNode === document).toBe(true); expect(requestedTagName).toEqual(tagName); return >[element]; }); - expect(document.getElementsByTagName(tagName)).toEqual([element]); + const result = document.getElementsByTagName(tagName); + expect(result.length).toBe(1); + expect(result[0] === element).toBe(true); }); }); @@ -524,13 +542,16 @@ describe('Document', () => { jest .spyOn(ParentNodeUtility, 'getElementsByTagNameNS') .mockImplementation((parentNode, requestedNamespaceURI, requestedTagName) => { - expect(parentNode).toBe(document); + expect(parentNode === document).toBe(true); expect(requestedNamespaceURI).toEqual(namespaceURI); expect(requestedTagName).toEqual(tagName); return >[element]; }); - expect(document.getElementsByTagNameNS(namespaceURI, tagName)).toEqual([element]); + const result = document.getElementsByTagNameNS(namespaceURI, tagName); + + expect(result.length).toBe(1); + expect(result[0] === element).toBe(true); }); }); @@ -542,12 +563,12 @@ describe('Document', () => { jest .spyOn(ParentNodeUtility, 'getElementById') .mockImplementation((parentNode, requestedID) => { - expect(parentNode).toBe(document); + expect(parentNode === document).toBe(true); expect(requestedID).toEqual(id); return element; }); - expect(document.getElementById(id)).toEqual(element); + expect(document.getElementById(id) === element).toBe(true); }); }); @@ -575,7 +596,9 @@ describe('Document', () => { document.appendChild(document.createComment('test')); document.appendChild(span); - expect(document.children).toEqual([div, span]); + expect(document.children.length).toBe(2); + expect(document.children[0]).toBe(div); + expect(document.children[1]).toBe(span); }); // See: https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment @@ -592,8 +615,8 @@ describe('Document', () => { document.appendChild(clone); - expect(clone.childNodes).toEqual([]); - expect(clone.children).toEqual([]); + expect(clone.childNodes.length).toBe(0); + expect(clone.children.length).toBe(0); expect(document.children.map((child) => child.outerHTML).join('')).toBe( '
Div
Span' ); @@ -616,7 +639,8 @@ describe('Document', () => { document.removeChild(div); - expect(document.children).toEqual([span]); + expect(document.children.length).toBe(1); + expect(document.children[0]).toBe(span); }); }); @@ -636,7 +660,10 @@ describe('Document', () => { document.appendChild(span); document.insertBefore(div2, div1); - expect(document.children).toEqual([div2, div1, span]); + expect(document.children.length).toBe(3); + expect(document.children[0]).toBe(div2); + expect(document.children[1]).toBe(div1); + expect(document.children[2]).toBe(span); }); // See: https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment @@ -822,43 +849,42 @@ describe('Document', () => { describe('createAttribute()', () => { it('Creates an Attr node.', () => { const attribute = document.createAttribute('KEY1'); + expect(attribute instanceof Attr).toBe(true); - expect(attribute).toEqual({ - value: null, - name: 'key1', - namespaceURI: null, - specified: true, - ownerElement: null, - ownerDocument: document - }); + + expect(attribute.value).toBe(null); + expect(attribute.name).toBe('key1'); + expect(attribute.namespaceURI).toBe(null); + expect(attribute.specified).toBe(true); + expect(attribute.ownerElement === null).toBe(true); + expect(attribute.ownerDocument === document).toBe(true); }); }); describe('createAttributeNS()', () => { it('Creates an Attr node with namespace set to HTML.', () => { const attribute = document.createAttributeNS(NamespaceURI.html, 'KEY1'); + expect(attribute instanceof Attr).toBe(true); - expect(attribute).toEqual({ - value: null, - name: 'KEY1', - namespaceURI: NamespaceURI.html, - specified: true, - ownerElement: null, - ownerDocument: document - }); + + expect(attribute.value).toBe(null); + expect(attribute.name).toBe('KEY1'); + expect(attribute.namespaceURI).toBe(NamespaceURI.html); + expect(attribute.specified).toBe(true); + expect(attribute.ownerElement === null).toBe(true); + expect(attribute.ownerDocument === document).toBe(true); }); it('Creates an Attr node with namespace set to SVG.', () => { const attribute = document.createAttributeNS(NamespaceURI.svg, 'KEY1'); expect(attribute instanceof Attr).toBe(true); - expect(attribute).toEqual({ - value: null, - name: 'KEY1', - namespaceURI: NamespaceURI.svg, - specified: true, - ownerElement: null, - ownerDocument: document - }); + + expect(attribute.value).toBe(null); + expect(attribute.name).toBe('KEY1'); + expect(attribute.namespaceURI).toBe(NamespaceURI.svg); + expect(attribute.specified).toBe(true); + expect(attribute.ownerElement === null).toBe(true); + expect(attribute.ownerDocument === document).toBe(true); }); }); @@ -911,7 +937,7 @@ describe('Document', () => { } }; const treeWalker = document.createTreeWalker(root, whatToShow, filter); - expect(treeWalker.root).toBe(root); + expect(treeWalker.root === root).toBe(true); expect(treeWalker.whatToShow).toBe(whatToShow); expect(treeWalker.filter).toBe(filter); expect(treeWalker instanceof TreeWalker).toBe(true); @@ -945,7 +971,7 @@ describe('Document', () => { const node = new Window().document.createElement('div'); const clone = document.importNode(node); expect(clone.tagName).toBe('DIV'); - expect(clone.ownerDocument).toBe(document); + expect(clone.ownerDocument === document).toBe(true); expect(clone instanceof HTMLElement).toBe(true); }); }); @@ -963,8 +989,8 @@ describe('Document', () => { const clone = document.cloneNode(false); const clone2 = document.cloneNode(true); - expect(clone.defaultView).toBe(window); - expect(clone.children).toEqual([]); + expect(clone.defaultView === window).toBe(true); + expect(clone.children.length).toBe(0); expect(clone2.children.length).toBe(1); expect(clone2.children[0].outerHTML).toBe('
'); }); @@ -979,7 +1005,7 @@ describe('Document', () => { expect(adopted.tagName).toBe('DIV'); expect(adopted instanceof HTMLElement).toBe(true); - expect(adopted.ownerDocument).toBe(document); + expect(adopted.ownerDocument === document).toBe(true); expect(originalDocument.querySelector('div')).toBe(null); }); @@ -989,7 +1015,7 @@ describe('Document', () => { expect(adopted.tagName).toBe('DIV'); expect(adopted instanceof HTMLElement).toBe(true); - expect(adopted.ownerDocument).toBe(document); + expect(adopted.ownerDocument === document).toBe(true); }); }); diff --git a/packages/happy-dom/test/nodes/element/Element.test.ts b/packages/happy-dom/test/nodes/element/Element.test.ts index 2779c2e21..7a6e78549 100644 --- a/packages/happy-dom/test/nodes/element/Element.test.ts +++ b/packages/happy-dom/test/nodes/element/Element.test.ts @@ -17,6 +17,7 @@ import Node from '../../../src/nodes/node/Node'; import IHTMLCollection from '../../../src/nodes/element/IHTMLCollection'; import IElement from '../../../src/nodes/element/IElement'; import INodeList from '../../../src/nodes/node/INodeList'; +import IAttr from '../../../src/nodes/attr/IAttr'; const NAMESPACE_URI = 'https://test.test'; @@ -44,7 +45,9 @@ describe('Element', () => { element.appendChild(div1); element.appendChild(textNode); element.appendChild(div2); - expect(element.children).toEqual([div1, div2]); + expect(element.children.length).toBe(2); + expect(element.children[0] === div1).toBe(true); + expect(element.children[1] === div2).toBe(true); }); }); @@ -241,57 +244,49 @@ describe('Element', () => { element.setAttribute('key2', 'value2'); element.setAttribute('key3', 'value3'); - expect(element.attributes).toEqual({ - '0': { - name: 'key1', - value: 'value1', - namespaceURI: null, - specified: true, - ownerElement: element, - ownerDocument: document - }, - '1': { - name: 'key2', - value: 'value2', - namespaceURI: null, - specified: true, - ownerElement: element, - ownerDocument: document - }, - '2': { - name: 'key3', - value: 'value3', - namespaceURI: null, - specified: true, - ownerElement: element, - ownerDocument: document - }, - key1: { - name: 'key1', - value: 'value1', - namespaceURI: null, - specified: true, - ownerElement: element, - ownerDocument: document - }, - key2: { - name: 'key2', - value: 'value2', - namespaceURI: null, - specified: true, - ownerElement: element, - ownerDocument: document - }, - key3: { - name: 'key3', - value: 'value3', - namespaceURI: null, - specified: true, - ownerElement: element, - ownerDocument: document - }, - length: 3 - }); + expect(element.attributes.length).toBe(3); + + expect(element.attributes[0].name).toBe('key1'); + expect(element.attributes[0].value).toBe('value1'); + expect(element.attributes[0].namespaceURI).toBe(null); + expect(element.attributes[0].specified).toBe(true); + expect(element.attributes[0].ownerElement === element).toBe(true); + expect(element.attributes[0].ownerDocument === document).toBe(true); + + expect(element.attributes[1].name).toBe('key2'); + expect(element.attributes[1].value).toBe('value2'); + expect(element.attributes[1].namespaceURI).toBe(null); + expect(element.attributes[1].specified).toBe(true); + expect(element.attributes[1].ownerElement === element).toBe(true); + expect(element.attributes[1].ownerDocument === document).toBe(true); + + expect(element.attributes[2].name).toBe('key3'); + expect(element.attributes[2].value).toBe('value3'); + expect(element.attributes[2].namespaceURI).toBe(null); + expect(element.attributes[2].specified).toBe(true); + expect(element.attributes[2].ownerElement === element).toBe(true); + expect(element.attributes[2].ownerDocument === document).toBe(true); + + expect(element.attributes.key1.name).toBe('key1'); + expect(element.attributes.key1.value).toBe('value1'); + expect(element.attributes.key1.namespaceURI).toBe(null); + expect(element.attributes.key1.specified).toBe(true); + expect(element.attributes.key1.ownerElement === element).toBe(true); + expect(element.attributes.key1.ownerDocument === document).toBe(true); + + expect(element.attributes.key2.name).toBe('key2'); + expect(element.attributes.key2.value).toBe('value2'); + expect(element.attributes.key2.namespaceURI).toBe(null); + expect(element.attributes.key2.specified).toBe(true); + expect(element.attributes.key2.ownerElement === element).toBe(true); + expect(element.attributes.key2.ownerDocument === document).toBe(true); + + expect(element.attributes.key3.name).toBe('key3'); + expect(element.attributes.key3.value).toBe('value3'); + expect(element.attributes.key3.namespaceURI).toBe(null); + expect(element.attributes.key3.specified).toBe(true); + expect(element.attributes.key3.ownerElement === element).toBe(true); + expect(element.attributes.key3.ownerDocument === document).toBe(true); }); }); @@ -320,7 +315,7 @@ describe('Element', () => { div.appendChild(span2); div.appendChild(text2); - expect(div.firstElementChild).toBe(span1); + expect(div.firstElementChild === span1).toBe(true); }); }); @@ -341,7 +336,7 @@ describe('Element', () => { div.appendChild(span2); div.appendChild(text2); - expect(div.lastElementChild).toBe(span2); + expect(div.lastElementChild === span2).toBe(true); }); }); @@ -352,7 +347,7 @@ describe('Element', () => { element.appendChild(div); jest.spyOn(XMLSerializer.prototype, 'serializeToString').mockImplementation((rootElement) => { - expect(rootElement).toBe(div); + expect(rootElement === div).toBe(true); return 'EXPECTED_HTML'; }); @@ -367,7 +362,7 @@ describe('Element', () => { jest .spyOn(XMLSerializer.prototype, 'serializeToString') .mockImplementation((rootElement, options) => { - expect(rootElement).toBe(div); + expect(rootElement === div).toBe(true); expect(options).toEqual({ includeShadowRoots: true }); return 'EXPECTED_HTML'; }); @@ -383,8 +378,10 @@ describe('Element', () => { let isCalled = false; jest.spyOn(ParentNodeUtility, 'append').mockImplementation((parentNode, ...nodes) => { - expect(parentNode).toBe(document); - expect(nodes).toEqual([node1, node2]); + expect(parentNode === document).toBe(true); + expect(nodes.length).toBe(2); + expect(nodes[0] === node1).toBe(true); + expect(nodes[1] === node2).toBe(true); isCalled = true; }); @@ -400,8 +397,10 @@ describe('Element', () => { let isCalled = false; jest.spyOn(ParentNodeUtility, 'prepend').mockImplementation((parentNode, ...nodes) => { - expect(parentNode).toBe(document); - expect(nodes).toEqual([node1, node2]); + expect(parentNode === document).toBe(true); + expect(nodes.length).toBe(2); + expect(nodes[0] === node1).toBe(true); + expect(nodes[1] === node2).toBe(true); isCalled = true; }); @@ -419,10 +418,10 @@ describe('Element', () => { const insertedNode = parent.insertAdjacentElement('beforebegin', newNode); - expect(insertedNode).toBe(newNode); - expect(parent.childNodes).toEqual([]); + expect(insertedNode === newNode).toBe(true); + expect(parent.childNodes.length).toEqual(0); expect(insertedNode.isConnected).toBe(true); - expect(document.body.childNodes[0]).toBe(newNode); + expect(document.body.childNodes[0] === newNode).toBe(true); }); it('Returns with null if cannot insert with "beforebegin".', () => { @@ -430,7 +429,7 @@ describe('Element', () => { const newNode = document.createElement('span'); const insertedNode = parent.insertAdjacentElement('beforebegin', newNode); - expect(insertedNode).toBe(null); + expect(insertedNode === null).toBe(true); expect(newNode.isConnected).toBe(false); }); @@ -445,8 +444,8 @@ describe('Element', () => { const insertedNode = parent.insertAdjacentElement('afterbegin', newNode); - expect(insertedNode).toBe(newNode); - expect(parent.childNodes[0]).toBe(insertedNode); + expect(insertedNode === newNode).toBe(true); + expect(parent.childNodes[0] === insertedNode).toBe(true); expect(insertedNode.isConnected).toBe(true); }); @@ -460,8 +459,8 @@ describe('Element', () => { const insertedNode = parent.insertAdjacentElement('beforeend', newNode); - expect(insertedNode).toBe(newNode); - expect(parent.childNodes[1]).toBe(insertedNode); + expect(insertedNode === newNode).toBe(true); + expect(parent.childNodes[1] === insertedNode).toBe(true); expect(insertedNode.isConnected).toBe(true); }); @@ -473,12 +472,12 @@ describe('Element', () => { const insertedNode = parent.insertAdjacentElement('afterend', newNode); - expect(insertedNode).toBe(newNode); - expect(parent.childNodes).toEqual([]); + expect(insertedNode === newNode).toBe(true); + expect(parent.childNodes.length).toEqual(0); expect(insertedNode.isConnected).toBe(true); - expect(document.body.childNodes[0]).toBe(parent); - expect(document.body.childNodes[1]).toBe(insertedNode); + expect(document.body.childNodes[0] === parent).toBe(true); + expect(document.body.childNodes[1] === insertedNode).toBe(true); }); it('Inserts a Node right after the reference element and returns with it.', () => { @@ -491,13 +490,13 @@ describe('Element', () => { const insertedNode = parent.insertAdjacentElement('afterend', newNode); - expect(insertedNode).toBe(newNode); - expect(parent.childNodes).toEqual([]); + expect(insertedNode === newNode).toBe(true); + expect(parent.childNodes.length).toBe(0); expect(newNode.isConnected).toBe(true); - expect(document.body.childNodes[0]).toBe(parent); - expect(document.body.childNodes[1]).toBe(insertedNode); - expect(document.body.childNodes[2]).toBe(sibling); + expect(document.body.childNodes[0] === parent).toBe(true); + expect(document.body.childNodes[1] === insertedNode).toBe(true); + expect(document.body.childNodes[2] === sibling).toBe(true); }); it('Returns with null if cannot insert with "afterend".', () => { @@ -518,7 +517,7 @@ describe('Element', () => { document.body.appendChild(parent); parent.insertAdjacentHTML('beforebegin', markup); - expect(parent.childNodes).toEqual([]); + expect(parent.childNodes.length).toBe(0); expect((document.body.childNodes[0]).outerHTML).toEqual(markup); }); @@ -532,7 +531,7 @@ describe('Element', () => { parent.insertAdjacentHTML('afterbegin', markup); expect((parent.childNodes[0]).outerHTML).toEqual(markup); - expect(parent.childNodes[1]).toBe(child); + expect(parent.childNodes[1] === child).toBe(true); }); it('Inserts the given HTML inside the reference element after the last child.', () => { @@ -544,7 +543,7 @@ describe('Element', () => { document.body.appendChild(parent); parent.insertAdjacentHTML('beforeend', markup); - expect(parent.childNodes[0]).toBe(child); + expect(parent.childNodes[0] === child).toBe(true); expect((parent.childNodes[1]).outerHTML).toEqual(markup); }); @@ -555,8 +554,8 @@ describe('Element', () => { document.body.appendChild(parent); parent.insertAdjacentHTML('afterend', markup); - expect(parent.childNodes).toEqual([]); - expect(document.body.childNodes[0]).toBe(parent); + expect(parent.childNodes.length).toEqual(0); + expect(document.body.childNodes[0] === parent).toBe(true); expect((document.body.childNodes[1]).outerHTML).toEqual(markup); }); @@ -569,10 +568,10 @@ describe('Element', () => { document.body.appendChild(sibling); parent.insertAdjacentHTML('afterend', markup); - expect(parent.childNodes).toEqual([]); - expect(document.body.childNodes[0]).toBe(parent); + expect(parent.childNodes.length).toBe(0); + expect(document.body.childNodes[0] === parent).toBe(true); expect((document.body.childNodes[1]).outerHTML).toEqual(markup); - expect(document.body.childNodes[2]).toBe(sibling); + expect(document.body.childNodes[2] === sibling).toBe(true); }); }); @@ -584,7 +583,7 @@ describe('Element', () => { document.body.appendChild(parent); parent.insertAdjacentText('beforebegin', text); - expect(parent.childNodes).toEqual([]); + expect(parent.childNodes.length).toEqual(0); expect(document.body.childNodes[0].nodeType).toBe(Node.TEXT_NODE); expect(document.body.childNodes[0].textContent).toEqual(text); }); @@ -612,7 +611,7 @@ describe('Element', () => { document.body.appendChild(parent); parent.insertAdjacentText('beforeend', text); - expect(parent.childNodes[0]).toBe(child); + expect(parent.childNodes[0] === child).toBe(true); expect(parent.childNodes[1].nodeType).toBe(Node.TEXT_NODE); expect(parent.childNodes[1].textContent).toEqual(text); }); @@ -624,8 +623,8 @@ describe('Element', () => { document.body.appendChild(parent); parent.insertAdjacentText('afterend', text); - expect(parent.childNodes).toEqual([]); - expect(document.body.childNodes[0]).toBe(parent); + expect(parent.childNodes.length).toBe(0); + expect(document.body.childNodes[0] === parent).toBe(true); expect(document.body.childNodes[1].nodeType).toBe(Node.TEXT_NODE); expect(document.body.childNodes[1].textContent).toEqual(text); }); @@ -639,11 +638,11 @@ describe('Element', () => { document.body.appendChild(sibling); parent.insertAdjacentText('afterend', text); - expect(parent.childNodes).toEqual([]); - expect(document.body.childNodes[0]).toBe(parent); + expect(parent.childNodes.length).toBe(0); + expect(document.body.childNodes[0] === parent).toBe(true); expect(document.body.childNodes[1].nodeType).toBe(Node.TEXT_NODE); expect(document.body.childNodes[1].textContent).toEqual(text); - expect(document.body.childNodes[2]).toBe(sibling); + expect(document.body.childNodes[2] === sibling).toBe(true); }); it('Does nothing is an emptry string is sent.', () => { @@ -654,9 +653,9 @@ describe('Element', () => { document.body.appendChild(sibling); parent.insertAdjacentText('afterend', ''); - expect(parent.childNodes).toEqual([]); - expect(document.body.childNodes[0]).toBe(parent); - expect(document.body.childNodes[1]).toBe(sibling); + expect(parent.childNodes.length).toBe(0); + expect(document.body.childNodes[0] === parent).toBe(true); + expect(document.body.childNodes[1] === sibling).toBe(true); }); }); @@ -750,7 +749,9 @@ describe('Element', () => { return >[element]; }); - expect(document.querySelectorAll(expectedSelector)).toEqual([element]); + const result = document.querySelectorAll(expectedSelector); + expect(result.length).toBe(1); + expect(result[0] === element).toBe(true); }); }); @@ -765,7 +766,7 @@ describe('Element', () => { return element; }); - expect(document.querySelector(expectedSelector)).toEqual(element); + expect(document.querySelector(expectedSelector) === element).toEqual(true); }); }); @@ -782,7 +783,9 @@ describe('Element', () => { return >[child]; }); - expect(element.getElementsByClassName(className)).toEqual([child]); + const result = element.getElementsByClassName(className); + expect(result.length).toBe(1); + expect(result[0] === child).toBe(true); }); }); @@ -799,7 +802,9 @@ describe('Element', () => { return >[child]; }); - expect(element.getElementsByTagName(tagName)).toEqual([child]); + const result = element.getElementsByTagName(tagName); + expect(result.length).toBe(1); + expect(result[0] === child).toBe(true); }); }); @@ -818,7 +823,9 @@ describe('Element', () => { return >[child]; }); - expect(element.getElementsByTagNameNS(namespaceURI, tagName)).toEqual([child]); + const result = element.getElementsByTagNameNS(namespaceURI, tagName); + expect(result.length).toBe(1); + expect(result[0] === child).toBe(true); }); }); @@ -898,7 +905,9 @@ describe('Element', () => { element.appendChild(document.createComment('test')); element.appendChild(span); - expect(element.children).toEqual([div, span]); + expect(element.children.length).toBe(2); + expect(element.children[0] === div).toBe(true); + expect(element.children[1] === span).toBe(true); }); // See: https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment @@ -911,8 +920,8 @@ describe('Element', () => { element.appendChild(clone); - expect(clone.childNodes).toEqual([]); - expect(clone.children).toEqual([]); + expect(clone.childNodes.length).toBe(0); + expect(clone.children.length).toBe(0); expect(element.innerHTML).toBe('
Div
Span'); }); }); @@ -945,7 +954,10 @@ describe('Element', () => { element.appendChild(span); element.insertBefore(div2, div1); - expect(element.children).toEqual([div2, div1, span]); + expect(element.children.length).toBe(3); + expect(element.children[0] === div2).toBe(true); + expect(element.children[1] === div1).toBe(true); + expect(element.children[2] === span).toBe(true); }); // See: https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment @@ -981,7 +993,7 @@ describe('Element', () => { return previousElementSibling; }); - expect(node.previousElementSibling).toBe(previousElementSibling); + expect(node.previousElementSibling === previousElementSibling).toBe(true); }); }); @@ -996,7 +1008,7 @@ describe('Element', () => { return nextElementSibling; }); - expect(node.nextElementSibling).toBe(nextElementSibling); + expect(node.nextElementSibling === nextElementSibling).toBe(true); }); }); @@ -1011,23 +1023,19 @@ describe('Element', () => { customElement.setAttribute('key2', 'value2'); customElement.setAttribute('KEY1', 'newValue'); - expect(customElement.changedAttributes).toEqual([ - { - name: 'key1', - newValue: 'value1', - oldValue: null - }, - { - name: 'key2', - newValue: 'value2', - oldValue: null - }, - { - name: 'key1', - newValue: 'newValue', - oldValue: 'value1' - } - ]); + expect(customElement.changedAttributes.length).toBe(3); + + expect(customElement.changedAttributes[0].name).toBe('key1'); + expect(customElement.changedAttributes[0].newValue).toBe('value1'); + expect(customElement.changedAttributes[0].oldValue).toBe(null); + + expect(customElement.changedAttributes[1].name).toBe('key2'); + expect(customElement.changedAttributes[1].newValue).toBe('value2'); + expect(customElement.changedAttributes[1].oldValue).toBe(null); + + expect(customElement.changedAttributes[2].name).toBe('key1'); + expect(customElement.changedAttributes[2].newValue).toBe('newValue'); + expect(customElement.changedAttributes[2].oldValue).toBe('value1'); }); it('Does not call the attribute changed callback when the attribute name is not available in the observedAttributes() getter method.', () => { @@ -1039,7 +1047,7 @@ describe('Element', () => { customElement.setAttribute('k1', 'value1'); customElement.setAttribute('k2', 'value2'); - expect(customElement.changedAttributes).toEqual([]); + expect(customElement.changedAttributes.length).toBe(0); }); }); @@ -1047,41 +1055,36 @@ describe('Element', () => { it('Sets an attribute on an element.', () => { element.setAttribute('key1', 'value1'); element.setAttribute('key2', ''); - expect(element.attributes).toEqual({ - '0': { - name: 'key1', - value: 'value1', - namespaceURI: null, - specified: true, - ownerElement: element, - ownerDocument: document - }, - '1': { - name: 'key2', - value: '', - namespaceURI: null, - specified: true, - ownerElement: element, - ownerDocument: document - }, - key1: { - name: 'key1', - value: 'value1', - namespaceURI: null, - specified: true, - ownerElement: element, - ownerDocument: document - }, - key2: { - name: 'key2', - value: '', - namespaceURI: null, - specified: true, - ownerElement: element, - ownerDocument: document - }, - length: 2 - }); + + expect(element.attributes.length).toBe(2); + + expect(element.attributes[0].name).toBe('key1'); + expect(element.attributes[0].value).toBe('value1'); + expect(element.attributes[0].namespaceURI).toBe(null); + expect(element.attributes[0].specified).toBe(true); + expect(element.attributes[0].ownerElement === element).toBe(true); + expect(element.attributes[0].ownerDocument === document).toBe(true); + + expect(element.attributes[1].name).toBe('key2'); + expect(element.attributes[1].value).toBe(''); + expect(element.attributes[1].namespaceURI).toBe(null); + expect(element.attributes[1].specified).toBe(true); + expect(element.attributes[1].ownerElement === element).toBe(true); + expect(element.attributes[1].ownerDocument === document).toBe(true); + + expect(element.attributes.key1.name).toBe('key1'); + expect(element.attributes.key1.value).toBe('value1'); + expect(element.attributes.key1.namespaceURI).toBe(null); + expect(element.attributes.key1.specified).toBe(true); + expect(element.attributes.key1.ownerElement === element).toBe(true); + expect(element.attributes.key1.ownerDocument === document).toBe(true); + + expect(element.attributes.key2.name).toBe('key2'); + expect(element.attributes.key2.value).toBe(''); + expect(element.attributes.key2.namespaceURI).toBe(null); + expect(element.attributes.key2.specified).toBe(true); + expect(element.attributes.key2.ownerElement === element).toBe(true); + expect(element.attributes.key2.ownerDocument === document).toBe(true); }); }); @@ -1089,41 +1092,36 @@ describe('Element', () => { it('Sets a namespace attribute on an element.', () => { element.setAttributeNS(NAMESPACE_URI, 'global:local1', 'value1'); element.setAttributeNS(NAMESPACE_URI, 'global:local2', ''); - expect(element.attributes).toEqual({ - '0': { - name: 'global:local1', - value: 'value1', - namespaceURI: NAMESPACE_URI, - specified: true, - ownerElement: element, - ownerDocument: document - }, - '1': { - name: 'global:local2', - value: '', - namespaceURI: NAMESPACE_URI, - specified: true, - ownerElement: element, - ownerDocument: document - }, - 'global:local1': { - name: 'global:local1', - value: 'value1', - namespaceURI: NAMESPACE_URI, - specified: true, - ownerElement: element, - ownerDocument: document - }, - 'global:local2': { - name: 'global:local2', - value: '', - namespaceURI: NAMESPACE_URI, - specified: true, - ownerElement: element, - ownerDocument: document - }, - length: 2 - }); + + expect(element.attributes.length).toBe(2); + + expect(element.attributes[0].name).toBe('global:local1'); + expect(element.attributes[0].value).toBe('value1'); + expect(element.attributes[0].namespaceURI).toBe(NAMESPACE_URI); + expect(element.attributes[0].specified).toBe(true); + expect(element.attributes[0].ownerElement === element).toBe(true); + expect(element.attributes[0].ownerDocument === document).toBe(true); + + expect(element.attributes[1].name).toBe('global:local2'); + expect(element.attributes[1].value).toBe(''); + expect(element.attributes[1].namespaceURI).toBe(NAMESPACE_URI); + expect(element.attributes[1].specified).toBe(true); + expect(element.attributes[1].ownerElement === element).toBe(true); + expect(element.attributes[1].ownerDocument === document).toBe(true); + + expect(element.attributes['global:local1'].name).toBe('global:local1'); + expect(element.attributes['global:local1'].value).toBe('value1'); + expect(element.attributes['global:local1'].namespaceURI).toBe(NAMESPACE_URI); + expect(element.attributes['global:local1'].specified).toBe(true); + expect(element.attributes['global:local1'].ownerElement === element).toBe(true); + expect(element.attributes['global:local1'].ownerDocument === document).toBe(true); + + expect(element.attributes['global:local2'].name).toBe('global:local2'); + expect(element.attributes['global:local2'].value).toBe(''); + expect(element.attributes['global:local2'].namespaceURI).toBe(NAMESPACE_URI); + expect(element.attributes['global:local2'].specified).toBe(true); + expect(element.attributes['global:local2'].ownerElement === element).toBe(true); + expect(element.attributes['global:local2'].ownerDocument === document).toBe(true); }); }); @@ -1187,7 +1185,7 @@ describe('Element', () => { element.attachShadow({ mode: 'open' }); expect(element['_shadowRoot'] instanceof ShadowRoot).toBe(true); expect(element.shadowRoot instanceof ShadowRoot).toBe(true); - expect(element.shadowRoot.ownerDocument).toBe(document); + expect(element.shadowRoot.ownerDocument === document).toBe(true); expect(element.shadowRoot.isConnected).toBe(false); document.appendChild(element); expect(element.shadowRoot.isConnected).toBe(true); @@ -1197,7 +1195,7 @@ describe('Element', () => { element.attachShadow({ mode: 'closed' }); expect(element.shadowRoot).toBe(null); expect(element['_shadowRoot'] instanceof ShadowRoot).toBe(true); - expect(element['_shadowRoot'].ownerDocument).toBe(document); + expect(element['_shadowRoot'].ownerDocument === document).toBe(true); expect(element['_shadowRoot'].isConnected).toBe(false); document.appendChild(element); expect(element['_shadowRoot'].isConnected).toBe(true); @@ -1283,7 +1281,7 @@ describe('Element', () => { expect(clone.scrollLeft).toBe(10); expect(clone.scrollTop).toBe(10); expect(clone.namespaceURI).toBe('namespaceURI'); - expect(clone.children).toEqual([]); + expect(clone.children.length).toEqual(0); expect(clone2.children.length).toBe(1); expect(clone2.children[0].outerHTML).toBe('
'); }); @@ -1301,41 +1299,35 @@ describe('Element', () => { element[method](attribute1); element[method](attribute2); - expect(element.attributes).toEqual({ - '0': { - name: 'key1', - namespaceURI: NamespaceURI.svg, - value: 'value1', - specified: true, - ownerElement: element, - ownerDocument: document - }, - '1': { - name: 'key2', - namespaceURI: null, - value: 'value2', - specified: true, - ownerElement: element, - ownerDocument: document - }, - key1: { - name: 'key1', - namespaceURI: NamespaceURI.svg, - value: 'value1', - specified: true, - ownerElement: element, - ownerDocument: document - }, - key2: { - name: 'key2', - namespaceURI: null, - value: 'value2', - specified: true, - ownerElement: element, - ownerDocument: document - }, - length: 2 - }); + expect(element.attributes.length).toBe(2); + + expect((element.attributes[0]).name).toBe('key1'); + expect((element.attributes[0]).namespaceURI).toBe(NamespaceURI.svg); + expect((element.attributes[0]).value).toBe('value1'); + expect((element.attributes[0]).specified).toBe(true); + expect((element.attributes[0]).ownerElement).toBe(element); + expect((element.attributes[0]).ownerDocument).toBe(document); + + expect((element.attributes[1]).name).toBe('key2'); + expect((element.attributes[1]).namespaceURI).toBe(null); + expect((element.attributes[1]).value).toBe('value2'); + expect((element.attributes[1]).specified).toBe(true); + expect((element.attributes[1]).ownerElement).toBe(element); + expect((element.attributes[1]).ownerDocument).toBe(document); + + expect((element.attributes.key1).name).toBe('key1'); + expect((element.attributes.key1).namespaceURI).toBe(NamespaceURI.svg); + expect((element.attributes.key1).value).toBe('value1'); + expect((element.attributes.key1).specified).toBe(true); + expect((element.attributes.key1).ownerElement).toBe(element); + expect((element.attributes.key1).ownerDocument).toBe(document); + + expect((element.attributes.key2).name).toBe('key2'); + expect((element.attributes.key2).namespaceURI).toBe(null); + expect((element.attributes.key2).value).toBe('value2'); + expect((element.attributes.key2).specified).toBe(true); + expect((element.attributes.key2).ownerElement).toBe(element); + expect((element.attributes.key2).ownerDocument).toBe(document); }); it('Sets an Attr node on an element.', () => { @@ -1349,41 +1341,35 @@ describe('Element', () => { svg[method](attribute1); svg[method](attribute2); - expect(svg.attributes).toEqual({ - '0': { - name: 'KEY1', - namespaceURI: NamespaceURI.svg, - value: 'value1', - specified: true, - ownerElement: svg, - ownerDocument: document - }, - '1': { - name: 'key2', - namespaceURI: null, - value: 'value2', - specified: true, - ownerElement: svg, - ownerDocument: document - }, - KEY1: { - name: 'KEY1', - namespaceURI: NamespaceURI.svg, - value: 'value1', - specified: true, - ownerElement: svg, - ownerDocument: document - }, - key2: { - name: 'key2', - namespaceURI: null, - value: 'value2', - specified: true, - ownerElement: svg, - ownerDocument: document - }, - length: 2 - }); + expect(svg.attributes.length).toBe(2); + + expect((svg.attributes[0]).name).toBe('KEY1'); + expect((svg.attributes[0]).namespaceURI).toBe(NamespaceURI.svg); + expect((svg.attributes[0]).value).toBe('value1'); + expect((svg.attributes[0]).specified).toBe(true); + expect((svg.attributes[0]).ownerElement).toBe(svg); + expect((svg.attributes[0]).ownerDocument).toBe(document); + + expect((svg.attributes[1]).name).toBe('key2'); + expect((svg.attributes[1]).namespaceURI).toBe(null); + expect((svg.attributes[1]).value).toBe('value2'); + expect((svg.attributes[1]).specified).toBe(true); + expect((svg.attributes[1]).ownerElement).toBe(svg); + expect((svg.attributes[1]).ownerDocument).toBe(document); + + expect((svg.attributes.KEY1).name).toBe('KEY1'); + expect((svg.attributes.KEY1).namespaceURI).toBe(NamespaceURI.svg); + expect((svg.attributes.KEY1).value).toBe('value1'); + expect((svg.attributes.KEY1).specified).toBe(true); + expect((svg.attributes.KEY1).ownerElement).toBe(svg); + expect((svg.attributes.KEY1).ownerDocument).toBe(document); + + expect((svg.attributes.key2).name).toBe('key2'); + expect((svg.attributes.key2).namespaceURI).toBe(null); + expect((svg.attributes.key2).value).toBe('value2'); + expect((svg.attributes.key2).specified).toBe(true); + expect((svg.attributes.key2).ownerElement).toBe(svg); + expect((svg.attributes.key2).ownerDocument).toBe(document); }); }); } @@ -1399,10 +1385,10 @@ describe('Element', () => { element.setAttributeNode(attribute1); element.setAttributeNode(attribute2); - expect(element.getAttributeNode('key1')).toBe(attribute1); - expect(element.getAttributeNode('key2')).toBe(attribute2); - expect(element.getAttributeNode('KEY1')).toBe(attribute1); - expect(element.getAttributeNode('KEY2')).toBe(attribute2); + expect(element.getAttributeNode('key1') === attribute1).toBe(true); + expect(element.getAttributeNode('key2') === attribute2).toBe(true); + expect(element.getAttributeNode('KEY1') === attribute1).toBe(true); + expect(element.getAttributeNode('KEY2') === attribute2).toBe(true); }); it('Returns an Attr node from an element.', () => { @@ -1416,10 +1402,10 @@ describe('Element', () => { svg.setAttributeNode(attribute1); svg.setAttributeNode(attribute2); - expect(svg.getAttributeNode('key1')).toBe(null); - expect(svg.getAttributeNode('key2')).toBe(attribute2); - expect(svg.getAttributeNode('KEY1')).toBe(attribute1); - expect(svg.getAttributeNode('KEY2')).toBe(null); + expect(svg.getAttributeNode('key1') === null).toBe(true); + expect(svg.getAttributeNode('key2') === attribute2).toBe(true); + expect(svg.getAttributeNode('KEY1') === attribute1).toBe(true); + expect(svg.getAttributeNode('KEY2') === null).toBe(true); }); }); @@ -1431,8 +1417,8 @@ describe('Element', () => { element.setAttributeNode(attribute1); - expect(element.getAttributeNodeNS(NamespaceURI.svg, 'key1')).toBe(attribute1); - expect(element.getAttributeNodeNS(NamespaceURI.svg, 'KEY1')).toBe(attribute1); + expect(element.getAttributeNodeNS(NamespaceURI.svg, 'key1') === attribute1).toBe(true); + expect(element.getAttributeNodeNS(NamespaceURI.svg, 'KEY1') === attribute1).toBe(true); }); it('Returns an Attr node from an element.', () => { @@ -1443,9 +1429,9 @@ describe('Element', () => { svg.setAttributeNode(attribute1); - expect(svg.getAttributeNodeNS(NamespaceURI.svg, 'key1')).toBe(null); - expect(svg.getAttributeNodeNS(NamespaceURI.svg, 'KEY1')).toBe(attribute1); - expect(svg.getAttributeNodeNS(NamespaceURI.svg, 'KEY2')).toBe(null); + expect(svg.getAttributeNodeNS(NamespaceURI.svg, 'key1') === null).toBe(true); + expect(svg.getAttributeNodeNS(NamespaceURI.svg, 'KEY1') === attribute1).toBe(true); + expect(svg.getAttributeNodeNS(NamespaceURI.svg, 'KEY2') === null).toBe(true); }); }); diff --git a/packages/happy-dom/test/nodes/html-element/HTMLElement.test.ts b/packages/happy-dom/test/nodes/html-element/HTMLElement.test.ts index cd6e7d620..06dc66de2 100644 --- a/packages/happy-dom/test/nodes/html-element/HTMLElement.test.ts +++ b/packages/happy-dom/test/nodes/html-element/HTMLElement.test.ts @@ -1,17 +1,19 @@ import PointerEvent from '../../../src/event/events/PointerEvent'; -import Document from '../../../src/nodes/document/Document'; +import IDocument from '../../../src/nodes/document/IDocument'; import HTMLElement from '../../../src/nodes/html-element/HTMLElement'; +import IHTMLElement from '../../../src/nodes/html-element/IHTMLElement'; +import IWindow from '../../../src/window/IWindow'; import Window from '../../../src/window/Window'; describe('HTMLElement', () => { - let window: Window = null; - let document: Document = null; - let element: HTMLElement = null; + let window: IWindow = null; + let document: IDocument = null; + let element: IHTMLElement = null; beforeEach(() => { window = new Window(); document = window.document; - element = document.createElement('div'); + element = document.createElement('div'); }); afterEach(() => { @@ -81,10 +83,10 @@ describe('HTMLElement', () => { }); describe('get innerText()', () => { - it('Returns the as the textContent property.', () => { + it('Returns the as the textContent property if element is not connected to document.', () => { const div = document.createElement('div'); const script = document.createElement('script'); - const style = document.createElement('script'); + const style = document.createElement('style'); element.appendChild(div); element.appendChild(script); element.appendChild(style); @@ -92,7 +94,35 @@ describe('HTMLElement', () => { div.appendChild(document.createTextNode('text1')); script.appendChild(document.createTextNode('var key = "value";')); style.appendChild(document.createTextNode('button { background: red; }')); - expect(element.innerText).toBe('text1text2'); + expect(element.innerText).toBe('text1var key = "value";button { background: red; }text2'); + }); + + it('Returns the as the textContent property without any line breaks if element is not connected to document.', () => { + element.innerHTML = `
The quick brown fox
Jumped over the lazy dog
`; + expect(element.innerText).toBe('The quick brown foxJumped over the lazy dog'); + }); + + it('Returns rendered text with line breaks between block and flex elements and without hidden elements being rendered if element is connected to the document.', () => { + document.body.appendChild(element); + + element.innerHTML = `
The quick brown fox
Jumped over the lazy dog
`; + expect(element.innerText).toBe('The quick brown fox\nJumped over the lazy dog'); + + element.innerHTML = `
The quick brown fox
Jumped over the lazy dog
.
`; + expect(element.innerText).toBe('The quick brown fox\nJumped over the lazy dog\n.'); + }); + + it('Returns rendered text affected by the "text-transform" CSS property.', () => { + document.body.appendChild(element); + + element.innerHTML = `
The quick brown fox
Jumped over the lazy dog`; + expect(element.innerText).toBe('The quick brown fox\nJUMPED OVER THE LAZY DOG'); + + element.innerHTML = `
The quick brown fox
JUMPED OVER THE LAZY DOG`; + expect(element.innerText).toBe('The quick brown fox\njumped over the lazy dog'); + + element.innerHTML = `
The quick brown fox
jumped over the lazy dog`; + expect(element.innerText).toBe('The quick brown fox\nJumped Over The Lazy Dog'); }); }); @@ -118,17 +148,32 @@ describe('HTMLElement', () => { describe('get style()', () => { it('Returns styles.', () => { element.setAttribute('style', 'border-radius: 2px; padding: 2px;'); - expect(element.style.length).toEqual(2); - expect(element.style[0]).toEqual('border-radius'); - expect(element.style[1]).toEqual('padding'); + + expect(element.style.length).toEqual(8); + expect(element.style[0]).toEqual('border-top-left-radius'); + expect(element.style[1]).toEqual('border-top-right-radius'); + expect(element.style[2]).toEqual('border-bottom-right-radius'); + expect(element.style[3]).toEqual('border-bottom-left-radius'); + expect(element.style[4]).toEqual('padding-top'); + expect(element.style[5]).toEqual('padding-right'); + expect(element.style[6]).toEqual('padding-bottom'); + expect(element.style[7]).toEqual('padding-left'); expect(element.style.borderRadius).toEqual('2px'); expect(element.style.padding).toEqual('2px'); expect(element.style.cssText).toEqual('border-radius: 2px; padding: 2px;'); element.setAttribute('style', 'border-radius: 4px; padding: 4px;'); - expect(element.style.length).toEqual(2); - expect(element.style[0]).toEqual('border-radius'); - expect(element.style[1]).toEqual('padding'); + + expect(element.style.length).toEqual(8); + expect(element.style[0]).toEqual('border-top-left-radius'); + expect(element.style[1]).toEqual('border-top-right-radius'); + expect(element.style[2]).toEqual('border-bottom-right-radius'); + expect(element.style[3]).toEqual('border-bottom-left-radius'); + expect(element.style[4]).toEqual('padding-top'); + expect(element.style[5]).toEqual('padding-right'); + expect(element.style[6]).toEqual('padding-bottom'); + expect(element.style[7]).toEqual('padding-left'); + expect(element.style.borderRadius).toEqual('4px'); expect(element.style.padding).toEqual('4px'); expect(element.style.cssText).toEqual('border-radius: 4px; padding: 4px;'); @@ -140,10 +185,16 @@ describe('HTMLElement', () => { element.style.borderRadius = '4rem'; element.style.backgroundColor = 'green'; - expect(element.style.length).toEqual(3); - expect(element.style[0]).toEqual('border-radius'); - expect(element.style[1]).toEqual('padding'); - expect(element.style[2]).toEqual('background-color'); + expect(element.style.length).toEqual(9); + expect(element.style[0]).toEqual('border-top-left-radius'); + expect(element.style[1]).toEqual('border-top-right-radius'); + expect(element.style[2]).toEqual('border-bottom-right-radius'); + expect(element.style[3]).toEqual('border-bottom-left-radius'); + expect(element.style[4]).toEqual('padding-top'); + expect(element.style[5]).toEqual('padding-right'); + expect(element.style[6]).toEqual('padding-bottom'); + expect(element.style[7]).toEqual('padding-left'); + expect(element.style[8]).toEqual('background-color'); expect(element.style.borderRadius).toEqual('4rem'); expect(element.style.padding).toEqual('2px'); @@ -164,10 +215,13 @@ describe('HTMLElement', () => { element.style.borderRadius = ''; element.style.backgroundColor = 'green'; - expect(element.style.length).toEqual(2); - expect(element.style[0]).toEqual('padding'); - expect(element.style[1]).toEqual('background-color'); - expect(element.style[2]).toBe(undefined); + expect(element.style.length).toEqual(5); + expect(element.style[0]).toEqual('padding-top'); + expect(element.style[1]).toEqual('padding-right'); + expect(element.style[2]).toEqual('padding-bottom'); + expect(element.style[3]).toEqual('padding-left'); + expect(element.style[4]).toEqual('background-color'); + expect(element.style[5]).toBe(undefined); expect(element.style.borderRadius).toEqual(''); expect(element.style.padding).toEqual('2px'); diff --git a/packages/happy-dom/test/nodes/html-style-element/HTMLStyleElement.test.ts b/packages/happy-dom/test/nodes/html-style-element/HTMLStyleElement.test.ts index 3efcd2a55..6cfcc960c 100644 --- a/packages/happy-dom/test/nodes/html-style-element/HTMLStyleElement.test.ts +++ b/packages/happy-dom/test/nodes/html-style-element/HTMLStyleElement.test.ts @@ -57,11 +57,20 @@ describe('HTMLStyleElement', () => { const textNode = document.createTextNode( 'body { background-color: red }\ndiv { background-color: green }' ); + element.appendChild(textNode); document.head.appendChild(element); + expect(element.sheet.cssRules.length).toBe(2); expect(element.sheet.cssRules[0].cssText).toBe('body { background-color: red; }'); expect(element.sheet.cssRules[1].cssText).toBe('div { background-color: green; }'); + + element.sheet.insertRule('html { background-color: blue }', 0); + + expect(element.sheet.cssRules.length).toBe(3); + expect(element.sheet.cssRules[0].cssText).toBe('html { background-color: blue; }'); + expect(element.sheet.cssRules[1].cssText).toBe('body { background-color: red; }'); + expect(element.sheet.cssRules[2].cssText).toBe('div { background-color: green; }'); }); }); }); diff --git a/packages/happy-dom/test/nodes/svg-element/SVGSVGElement.test.ts b/packages/happy-dom/test/nodes/svg-element/SVGSVGElement.test.ts index b6cc0e7bb..c6a8692f7 100644 --- a/packages/happy-dom/test/nodes/svg-element/SVGSVGElement.test.ts +++ b/packages/happy-dom/test/nodes/svg-element/SVGSVGElement.test.ts @@ -193,17 +193,29 @@ describe('SVGSVGElement', () => { describe('get style()', () => { it('Returns styles.', () => { element.setAttribute('style', 'border-radius: 2px; padding: 2px;'); - expect(element.style.length).toEqual(2); - expect(element.style[0]).toEqual('border-radius'); - expect(element.style[1]).toEqual('padding'); + expect(element.style.length).toEqual(8); + expect(element.style[0]).toEqual('border-top-left-radius'); + expect(element.style[1]).toEqual('border-top-right-radius'); + expect(element.style[2]).toEqual('border-bottom-right-radius'); + expect(element.style[3]).toEqual('border-bottom-left-radius'); + expect(element.style[4]).toEqual('padding-top'); + expect(element.style[5]).toEqual('padding-right'); + expect(element.style[6]).toEqual('padding-bottom'); + expect(element.style[7]).toEqual('padding-left'); expect(element.style.borderRadius).toEqual('2px'); expect(element.style.padding).toEqual('2px'); expect(element.style.cssText).toEqual('border-radius: 2px; padding: 2px;'); element.setAttribute('style', 'border-radius: 4px; padding: 4px;'); - expect(element.style.length).toEqual(2); - expect(element.style[0]).toEqual('border-radius'); - expect(element.style[1]).toEqual('padding'); + expect(element.style.length).toEqual(8); + expect(element.style[0]).toEqual('border-top-left-radius'); + expect(element.style[1]).toEqual('border-top-right-radius'); + expect(element.style[2]).toEqual('border-bottom-right-radius'); + expect(element.style[3]).toEqual('border-bottom-left-radius'); + expect(element.style[4]).toEqual('padding-top'); + expect(element.style[5]).toEqual('padding-right'); + expect(element.style[6]).toEqual('padding-bottom'); + expect(element.style[7]).toEqual('padding-left'); expect(element.style.borderRadius).toEqual('4px'); expect(element.style.padding).toEqual('4px'); expect(element.style.cssText).toEqual('border-radius: 4px; padding: 4px;'); diff --git a/packages/happy-dom/test/window/Window.test.ts b/packages/happy-dom/test/window/Window.test.ts index 5c2239e25..d2f026190 100644 --- a/packages/happy-dom/test/window/Window.test.ts +++ b/packages/happy-dom/test/window/Window.test.ts @@ -1,4 +1,4 @@ -import CSSStyleDeclaration from '../../src/css/CSSStyleDeclaration'; +import CSSStyleDeclaration from '../../src/css/declaration/CSSStyleDeclaration'; import IDocument from '../../src/nodes/document/IDocument'; import IHTMLLinkElement from '../../src/nodes/html-link-element/IHTMLLinkElement'; import IHTMLElement from '../../src/nodes/html-element/IHTMLElement'; @@ -11,6 +11,7 @@ import Headers from '../../src/fetch/Headers'; import Selection from '../../src/selection/Selection'; import DOMException from '../../src/exception/DOMException'; import DOMExceptionNameEnum from '../../src/exception/DOMExceptionNameEnum'; +import CustomElement from '../../test/CustomElement'; const MOCKED_NODE_FETCH = global['mockedModules']['node-fetch']; @@ -24,6 +25,7 @@ describe('Window', () => { MOCKED_NODE_FETCH.error = null; window = new Window(); document = window.document; + window.customElements.define('custom-element', CustomElement); }); afterEach(() => { @@ -202,19 +204,151 @@ describe('Window', () => { }); describe('getComputedStyle()', () => { + it('Handles default properties "display" and "direction".', () => { + const element = document.createElement('div'); + const computedStyle = window.getComputedStyle(element); + + window.document.body.appendChild(element); + + expect(computedStyle.direction).toBe('ltr'); + expect(computedStyle.display).toBe('block'); + }); + it('Returns a CSSStyleDeclaration object with computed styles that are live updated whenever the element styles are changed.', () => { - const element = window.document.createElement('div'); + const element = document.createElement('div'); const computedStyle = window.getComputedStyle(element); - element.style.direction = 'rtl'; + element.style.color = 'red'; expect(computedStyle instanceof CSSStyleDeclaration).toBe(true); - expect(computedStyle.direction).toBe(''); + expect(computedStyle.color).toBe(''); window.document.body.appendChild(element); - expect(computedStyle.direction).toBe('rtl'); + expect(computedStyle.color).toBe('red'); + + element.style.color = 'green'; + + expect(computedStyle.color).toBe('green'); + }); + + it('Returns a CSSStyleDeclaration object with computed styles from style sheets.', () => { + const parent = document.createElement('div'); + const element = document.createElement('span'); + const computedStyle = window.getComputedStyle(element); + const parentStyle = document.createElement('style'); + const elementStyle = document.createElement('style'); + + window.happyDOM.setInnerWidth(1024); + + parentStyle.innerHTML = ` + div { + font: 12px/1.5 "Helvetica Neue", Helvetica, Arial,sans-serif; + color: red !important; + cursor: pointer; + } + + span { + border-radius: 1px !important; + } + + @media (min-width: 1024px) { + div { + font-size: 14px; + } + } + + @media (max-width: 768px) { + div { + font-size: 20px; + } + } + `; + + elementStyle.innerHTML = ` + span { + border: 1px solid #000; + border-radius: 2px; + color: green; + cursor: default; + } + `; + + parent.appendChild(elementStyle); + parent.appendChild(element); + + document.body.appendChild(parentStyle); + document.body.appendChild(parent); + + expect(computedStyle.font).toBe('14px / 1.5 "Helvetica Neue", Helvetica, Arial, sans-serif'); + expect(computedStyle.border).toBe('1px solid #000'); + expect(computedStyle.borderRadius).toBe('1px'); + expect(computedStyle.color).toBe('red'); + expect(computedStyle.cursor).toBe('default'); + }); + + it('Returns a CSSStyleDeclaration object with computed styles from style sheets for elements in a HTMLShadowRoot.', () => { + const element = document.createElement('span'); + const elementStyle = document.createElement('style'); + const customElement = document.createElement('custom-element'); + const elementComputedStyle = window.getComputedStyle(element); + + elementStyle.innerHTML = ` + span { + color: green; + } + `; + + document.body.appendChild(elementStyle); + document.body.appendChild(element); + document.body.appendChild(customElement); + + const customElementComputedStyle = window.getComputedStyle( + customElement.shadowRoot.querySelector('span') + ); + + expect(elementComputedStyle.font).toBe(''); + expect(elementComputedStyle.color).toBe('green'); + + expect(customElementComputedStyle.color).toBe('yellow'); + expect(customElementComputedStyle.font).toBe( + '14px "Lucida Grande", Helvetica, Arial, sans-serif' + ); + }); + + it('Returns values defined by a CSS variables.', () => { + const parent = document.createElement('div'); + const element = document.createElement('span'); + const computedStyle = window.getComputedStyle(element); + const parentStyle = document.createElement('style'); + const elementStyle = document.createElement('style'); + + window.happyDOM.setInnerWidth(1024); + + parentStyle.innerHTML = ` + div { + --color-variable: #000; + --valid-variable: 1px solid var(--color-variable); + --invalid-variable: invalid; + } + `; + + elementStyle.innerHTML = ` + span { + border: var(--valid-variable); + font: var(--invalid-variable); + } + `; + + parent.appendChild(elementStyle); + parent.appendChild(element); + + document.body.appendChild(parentStyle); + document.body.appendChild(parent); + + expect(computedStyle.border).toBe('1px solid #000'); + expect(computedStyle.font).toBe(''); }); }); @@ -281,11 +415,16 @@ describe('Window', () => { describe('matchMedia()', () => { it('Returns a new MediaQueryList object that can then be used to determine if the document matches the media query string.', () => { - const mediaQueryString = '(max-width: 600px)'; + window.happyDOM.setInnerWidth(1024); + + const mediaQueryString = '(max-width: 512px)'; const mediaQueryList = window.matchMedia(mediaQueryString); expect(mediaQueryList.matches).toBe(false); expect(mediaQueryList.media).toBe(mediaQueryString); expect(mediaQueryList.onchange).toBe(null); + + expect(window.matchMedia('(max-width: 1024px)').matches).toBe(true); + expect(typeof mediaQueryList.addEventListener).toBe('function'); expect(typeof mediaQueryList.removeEventListener).toBe('function'); }); diff --git a/packages/happy-dom/test/xml-parser/XMLParser.test.ts b/packages/happy-dom/test/xml-parser/XMLParser.test.ts index c2ef811a8..13ed6562c 100644 --- a/packages/happy-dom/test/xml-parser/XMLParser.test.ts +++ b/packages/happy-dom/test/xml-parser/XMLParser.test.ts @@ -44,57 +44,79 @@ describe('XMLParser', () => { expect((root.childNodes[0]).tagName).toBe('DIV'); expect((root.childNodes[0]).id).toBe('id'); expect((root.childNodes[0]).className).toBe('class1 class2'); - expect((root.childNodes[0]).attributes).toEqual({ - '0': { - name: 'class', - value: 'class1 class2', - namespaceURI: null, - specified: true, - ownerElement: root.childNodes[0], - ownerDocument: document - }, - '1': { - name: 'id', - value: 'id', - namespaceURI: null, - specified: true, - ownerElement: root.childNodes[0], - ownerDocument: document - }, - '2': { - name: 'data-no-value', - value: '', - namespaceURI: null, - specified: true, - ownerElement: root.childNodes[0], - ownerDocument: document - }, - class: { - name: 'class', - value: 'class1 class2', - namespaceURI: null, - specified: true, - ownerElement: root.childNodes[0], - ownerDocument: document - }, - id: { - name: 'id', - value: 'id', - namespaceURI: null, - specified: true, - ownerElement: root.childNodes[0], - ownerDocument: document - }, - 'data-no-value': { - name: 'data-no-value', - value: '', - namespaceURI: null, - specified: true, - ownerElement: root.childNodes[0], - ownerDocument: document - }, - length: 3 - }); + + expect((root.childNodes[0]).attributes.length).toBe(3); + + expect((root.childNodes[0]).attributes[0].name).toBe('class'); + expect((root.childNodes[0]).attributes[0].value).toBe('class1 class2'); + expect((root.childNodes[0]).attributes[0].namespaceURI).toBe(null); + expect((root.childNodes[0]).attributes[0].specified).toBe(true); + expect( + (root.childNodes[0]).attributes[0].ownerElement === root.childNodes[0] + ).toBe(true); + expect((root.childNodes[0]).attributes[0].ownerDocument === document).toBe( + true + ); + + expect((root.childNodes[0]).attributes[1].name).toBe('id'); + expect((root.childNodes[0]).attributes[1].value).toBe('id'); + expect((root.childNodes[0]).attributes[1].namespaceURI).toBe(null); + expect((root.childNodes[0]).attributes[1].specified).toBe(true); + expect( + (root.childNodes[0]).attributes[1].ownerElement === root.childNodes[0] + ).toBe(true); + expect((root.childNodes[0]).attributes[1].ownerDocument === document).toBe( + true + ); + + expect((root.childNodes[0]).attributes[2].name).toBe('data-no-value'); + expect((root.childNodes[0]).attributes[2].value).toBe(''); + expect((root.childNodes[0]).attributes[2].namespaceURI).toBe(null); + expect((root.childNodes[0]).attributes[2].specified).toBe(true); + expect( + (root.childNodes[0]).attributes[2].ownerElement === root.childNodes[0] + ).toBe(true); + expect((root.childNodes[0]).attributes[2].ownerDocument === document).toBe( + true + ); + + expect((root.childNodes[0]).attributes.class.name).toBe('class'); + expect((root.childNodes[0]).attributes.class.value).toBe('class1 class2'); + expect((root.childNodes[0]).attributes.class.namespaceURI).toBe(null); + expect((root.childNodes[0]).attributes.class.specified).toBe(true); + expect( + (root.childNodes[0]).attributes.class.ownerElement === root.childNodes[0] + ).toBe(true); + expect((root.childNodes[0]).attributes.class.ownerDocument === document).toBe( + true + ); + + expect((root.childNodes[0]).attributes.id.name).toBe('id'); + expect((root.childNodes[0]).attributes.id.value).toBe('id'); + expect((root.childNodes[0]).attributes.id.namespaceURI).toBe(null); + expect((root.childNodes[0]).attributes.id.specified).toBe(true); + expect( + (root.childNodes[0]).attributes.id.ownerElement === root.childNodes[0] + ).toBe(true); + expect((root.childNodes[0]).attributes.id.ownerDocument === document).toBe( + true + ); + + expect((root.childNodes[0]).attributes['data-no-value'].name).toBe( + 'data-no-value' + ); + expect((root.childNodes[0]).attributes['data-no-value'].value).toBe(''); + expect((root.childNodes[0]).attributes['data-no-value'].namespaceURI).toBe( + null + ); + expect((root.childNodes[0]).attributes['data-no-value'].specified).toBe(true); + expect( + (root.childNodes[0]).attributes['data-no-value'].ownerElement === + root.childNodes[0] + ).toBe(true); + expect( + (root.childNodes[0]).attributes['data-no-value'].ownerDocument === document + ).toBe(true); }); it('Parses an entire HTML page.', () => { @@ -243,73 +265,63 @@ describe('XMLParser', () => { expect(circle.namespaceURI).toBe(NamespaceURI.svg); // Attributes should be in lower-case now as the namespace is HTML - expect(svg.attributes).toEqual({ - '0': { - name: 'viewBox', - value: '0 0 300 100', - namespaceURI: null, - specified: true, - ownerElement: svg, - ownerDocument: document - }, - '1': { - name: 'stroke', - value: 'red', - namespaceURI: null, - specified: true, - ownerElement: svg, - ownerDocument: document - }, - '2': { - name: 'fill', - value: 'grey', - namespaceURI: null, - specified: true, - ownerElement: svg, - ownerDocument: document - }, - '3': { - name: 'xmlns', - value: NamespaceURI.html, - namespaceURI: NamespaceURI.html, - specified: true, - ownerElement: svg, - ownerDocument: document - }, - viewBox: { - name: 'viewBox', - value: '0 0 300 100', - namespaceURI: null, - specified: true, - ownerElement: svg, - ownerDocument: document - }, - stroke: { - name: 'stroke', - value: 'red', - namespaceURI: null, - specified: true, - ownerElement: svg, - ownerDocument: document - }, - fill: { - name: 'fill', - value: 'grey', - namespaceURI: null, - specified: true, - ownerElement: svg, - ownerDocument: document - }, - xmlns: { - name: 'xmlns', - value: NamespaceURI.html, - namespaceURI: NamespaceURI.html, - specified: true, - ownerElement: svg, - ownerDocument: document - }, - length: 4 - }); + expect(svg.attributes.length).toBe(4); + + expect(svg.attributes[0].name).toBe('viewBox'); + expect(svg.attributes[0].value).toBe('0 0 300 100'); + expect(svg.attributes[0].namespaceURI).toBe(null); + expect(svg.attributes[0].specified).toBe(true); + expect(svg.attributes[0].ownerElement === svg).toBe(true); + expect(svg.attributes[0].ownerDocument === document).toBe(true); + + expect(svg.attributes[1].name).toBe('stroke'); + expect(svg.attributes[1].value).toBe('red'); + expect(svg.attributes[1].namespaceURI).toBe(null); + expect(svg.attributes[1].specified).toBe(true); + expect(svg.attributes[1].ownerElement === svg).toBe(true); + expect(svg.attributes[1].ownerDocument === document).toBe(true); + + expect(svg.attributes[2].name).toBe('fill'); + expect(svg.attributes[2].value).toBe('grey'); + expect(svg.attributes[2].namespaceURI).toBe(null); + expect(svg.attributes[2].specified).toBe(true); + expect(svg.attributes[2].ownerElement === svg).toBe(true); + expect(svg.attributes[2].ownerDocument === document).toBe(true); + + expect(svg.attributes[3].name).toBe('xmlns'); + expect(svg.attributes[3].value).toBe(NamespaceURI.html); + expect(svg.attributes[3].namespaceURI).toBe(NamespaceURI.html); + expect(svg.attributes[3].specified).toBe(true); + expect(svg.attributes[3].ownerElement === svg).toBe(true); + expect(svg.attributes[3].ownerDocument === document).toBe(true); + + expect(svg.attributes.viewBox.name).toBe('viewBox'); + expect(svg.attributes.viewBox.value).toBe('0 0 300 100'); + expect(svg.attributes.viewBox.namespaceURI).toBe(null); + expect(svg.attributes.viewBox.specified).toBe(true); + expect(svg.attributes.viewBox.ownerElement === svg).toBe(true); + expect(svg.attributes.viewBox.ownerDocument === document).toBe(true); + + expect(svg.attributes.stroke.name).toBe('stroke'); + expect(svg.attributes.stroke.value).toBe('red'); + expect(svg.attributes.stroke.namespaceURI).toBe(null); + expect(svg.attributes.stroke.specified).toBe(true); + expect(svg.attributes.stroke.ownerElement === svg).toBe(true); + expect(svg.attributes.stroke.ownerDocument === document).toBe(true); + + expect(svg.attributes.fill.name).toBe('fill'); + expect(svg.attributes.fill.value).toBe('grey'); + expect(svg.attributes.fill.namespaceURI).toBe(null); + expect(svg.attributes.fill.specified).toBe(true); + expect(svg.attributes.fill.ownerElement === svg).toBe(true); + expect(svg.attributes.fill.ownerDocument === document).toBe(true); + + expect(svg.attributes.xmlns.name).toBe('xmlns'); + expect(svg.attributes.xmlns.value).toBe(NamespaceURI.html); + expect(svg.attributes.xmlns.namespaceURI).toBe(NamespaceURI.html); + expect(svg.attributes.xmlns.specified).toBe(true); + expect(svg.attributes.xmlns.ownerElement === svg).toBe(true); + expect(svg.attributes.xmlns.ownerDocument === document).toBe(true); expect(new XMLSerializer().serializeToString(root).replace(/[\s]/gm, '')).toBe( ` diff --git a/packages/happy-dom/test/xml-serializer/XMLSerializer.test.ts b/packages/happy-dom/test/xml-serializer/XMLSerializer.test.ts index fe12593b8..2475c0653 100644 --- a/packages/happy-dom/test/xml-serializer/XMLSerializer.test.ts +++ b/packages/happy-dom/test/xml-serializer/XMLSerializer.test.ts @@ -161,25 +161,17 @@ describe('XMLSerializer', () => {
- + key1 is "value1" and key2 is "value2".