UNPKG

happy-dom

Version:

Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. It includes many web standards from WHATWG DOM and HTML.

1,990 lines (1,783 loc) 83 kB
import CSSStyleDeclarationValueParser from './CSSStyleDeclarationValueParser.js'; import ICSSStyleDeclarationPropertyValue from './ICSSStyleDeclarationPropertyValue.js'; const RECT_REGEXP = /^rect\((.*)\)$/i; const SPLIT_PARTS_REGEXP = /,(?=(?:(?:(?!\))[\s\S])*\()|[^\(\)]*$)/; // Split on commas that are outside of parentheses 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 letter spacing. * * @param value Value. * @param important Important. * @returns Property values */ public static getLetterSpacing( value: string, important: boolean ): { [key: string]: ICSSStyleDeclarationPropertyValue; } { const parsedValue = CSSStyleDeclarationValueParser.getVariable(value) || CSSStyleDeclarationValueParser.getGlobal(value) || CSSStyleDeclarationValueParser.getContentMeasurement(value); return parsedValue ? { 'letter-spacing': { value: parsedValue, important } } : null; } /** * Returns word spacing. * * @param value Value. * @param important Important. * @returns Property values */ public static getWordSpacing( value: string, important: boolean ): { [key: string]: ICSSStyleDeclarationPropertyValue; } { const parsedValue = CSSStyleDeclarationValueParser.getVariable(value) || CSSStyleDeclarationValueParser.getGlobal(value) || CSSStyleDeclarationValueParser.getContentMeasurement(value); return parsedValue ? { 'word-spacing': { value: parsedValue, important } } : null; } /** * Returns text indent. * * @param value Value. * @param important Important. * @returns Property values */ public static getTextIndent( value: string, important: boolean ): { [key: string]: ICSSStyleDeclarationPropertyValue; } { const parsedValue = CSSStyleDeclarationValueParser.getVariable(value) || CSSStyleDeclarationValueParser.getGlobal(value) || CSSStyleDeclarationValueParser.getContentMeasurement(value); return parsedValue ? { 'text-indent': { value: parsedValue, important } } : null; } /** * Returns width. * * @param value Value. * @param important Important. * @returns Property values */ public static getWidth( value: string, important: boolean ): { [key: string]: ICSSStyleDeclarationPropertyValue; } { const parsedValue = CSSStyleDeclarationValueParser.getVariable(value) || CSSStyleDeclarationValueParser.getGlobal(value) || CSSStyleDeclarationValueParser.getContentMeasurement(value); return parsedValue ? { width: { value: parsedValue, important } } : null; } /** * Returns height. * * @param value Value. * @param important Important. * @returns Property values */ public static getHeight( value: string, important: boolean ): { [key: string]: ICSSStyleDeclarationPropertyValue; } { const parsedValue = CSSStyleDeclarationValueParser.getVariable(value) || CSSStyleDeclarationValueParser.getGlobal(value) || CSSStyleDeclarationValueParser.getContentMeasurement(value); return parsedValue ? { height: { 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 parsedValue = CSSStyleDeclarationValueParser.getVariable(value) || 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 parsedValue = CSSStyleDeclarationValueParser.getVariable(value) || 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 parsedValue = CSSStyleDeclarationValueParser.getVariable(value) || 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 parsedValue = CSSStyleDeclarationValueParser.getVariable(value) || 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 outline. * * @param value Value. * @param important Important. * @returns Property values. */ public static getOutline( value: string, important: boolean ): { [key: string]: ICSSStyleDeclarationPropertyValue } { const variable = CSSStyleDeclarationValueParser.getVariable(value); if (variable) { return { outline: { value: variable, important } }; } const globalValue = CSSStyleDeclarationValueParser.getGlobal(value); if (globalValue) { return { ...this.getOutlineColor(globalValue, important), ...this.getOutlineStyle(globalValue, important), ...this.getOutlineWidth(globalValue, important) }; } const properties = { ...this.getOutlineColor('initial', important), ...this.getOutlineStyle('initial', important), ...this.getOutlineWidth('initial', important) }; const parts = value.split(/ +/); for (const part of parts) { const width = this.getOutlineWidth(part, important); const style = this.getOutlineStyle(part, important); const color = this.getOutlineColor(part, important); if (width === null && style === null && color === null) { return null; } Object.assign(properties, width, style, color); } return properties; } /** * Returns outline color. * * @param value Value. * @param important Important. * @returns Property values */ public static getOutlineColor( value: string, important: boolean ): { [key: string]: ICSSStyleDeclarationPropertyValue; } { const color = CSSStyleDeclarationValueParser.getVariable(value) || CSSStyleDeclarationValueParser.getGlobal(value) || CSSStyleDeclarationValueParser.getColor(value); return color ? { 'outline-color': { value: color, important } } : null; } /** * Returns outline offset. * * @param value Value. * @param important Important. * @returns Property values */ public static getOutlineOffset( value: string, important: boolean ): { [key: string]: ICSSStyleDeclarationPropertyValue; } { const parsedValue = CSSStyleDeclarationValueParser.getVariable(value) || CSSStyleDeclarationValueParser.getLength(value); return parsedValue ? { 'outline-offset': { value: parsedValue, important } } : null; } /** * Returns outline style. * * @param value Value. * @param important Important. * @returns Property values */ public static getOutlineStyle( value: string, important: boolean ): { [key: string]: ICSSStyleDeclarationPropertyValue; } { const variable = CSSStyleDeclarationValueParser.getVariable(value); if (variable) { return { 'outline-style': { value: variable, important } }; } const lowerValue = value.toLowerCase(); if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || BORDER_STYLE.includes(lowerValue)) { return { 'outline-style': { value: lowerValue, important } }; } return null; } /** * Returns outline width. * * @param value Value. * @param important Important. * @returns Property values */ public static getOutlineWidth( value: string, important: boolean ): { [key: string]: ICSSStyleDeclarationPropertyValue; } { const variable = CSSStyleDeclarationValueParser.getVariable(value); if (variable) { return { 'outline-width': { value: variable, important } }; } const lowerValue = value.toLowerCase(); const parsedValue = BORDER_WIDTH.includes(lowerValue) || CSSStyleDeclarationValueParser.getGlobal(lowerValue) ? lowerValue : CSSStyleDeclarationValueParser.getLength(value); if (parsedValue) { return { 'outline-width': { value: parsedValue, important } }; } return 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.