UNPKG

@wix/css-property-parser

Version:

A comprehensive TypeScript library for parsing and serializing CSS property values with full MDN specification compliance

171 lines (170 loc) 6.02 kB
"use strict"; // Border-width property parser // Handles parsing of CSS border-width shorthand property according to MDN specification // https://developer.mozilla.org/en-US/docs/Web/CSS/border-width Object.defineProperty(exports, "__esModule", { value: true }); exports.parse = parse; exports.toCSSValue = toCSSValue; const length_1 = require('./length.cjs'); const css_variable_1 = require('./css-variable.cjs'); const shared_utils_1 = require('../utils/shared-utils.cjs'); // Import centralized types const types_1 = require('../types.cjs'); /** * Check if value is a border width keyword */ function isBorderWidthKeyword(value) { return types_1.BORDER_WIDTH_KEYWORDS.includes(value.toLowerCase()); } /** * Parse a single border width value (length or keyword) */ function parseSingleBorderWidth(value) { const trimmed = value.trim(); // Handle CSS variables in individual components if ((0, shared_utils_1.isCssVariable)(trimmed)) { return (0, css_variable_1.parse)(trimmed); } // Global keywords if ((0, shared_utils_1.isGlobalKeyword)(trimmed)) { return { type: 'keyword', keyword: trimmed.toLowerCase() }; } // Border width keywords if (isBorderWidthKeyword(trimmed)) { return { type: 'keyword', keyword: trimmed.toLowerCase() }; } // Length values (non-negative only) const lengthResult = (0, length_1.parse)(trimmed); if (lengthResult && (('value' in lengthResult && lengthResult.value >= 0) || ('expression' in lengthResult))) { return lengthResult; } return null; } /** * Parse a CSS border-width shorthand property string * Supports 1-4 values: top [right [bottom [left]]] */ function parse(value) { if (!value || typeof value !== 'string') { return null; } const trimmed = value.trim(); if (trimmed === '') { return null; } // CSS variables can be parsed directly for entire shorthand const cssVariableResult = (0, css_variable_1.parse)(trimmed); if (cssVariableResult) { return cssVariableResult; } // Handle single global keyword if ((0, shared_utils_1.isGlobalKeyword)(trimmed)) { const keyword = { type: 'keyword', keyword: trimmed.toLowerCase() }; return { borderTopWidth: keyword, borderRightWidth: keyword, borderBottomWidth: keyword, borderLeftWidth: keyword }; } // Handle single border width keyword if (isBorderWidthKeyword(trimmed)) { const keyword = { type: 'keyword', keyword: trimmed.toLowerCase() }; return { borderTopWidth: keyword, borderRightWidth: keyword, borderBottomWidth: keyword, borderLeftWidth: keyword }; } // Tokenize the value to handle multiple values const tokens = (0, shared_utils_1.tokenize)(trimmed); // Validate we have 1-4 tokens if (tokens.length === 0 || tokens.length > 4) { return null; } // Validate each token can be parsed for (const token of tokens) { const parsed = parseSingleBorderWidth(token); if (parsed === null) { return null; // Invalid token } } // Expand shorthand values to 4 values (top, right, bottom, left) using string tokens const expandedStrings = (0, shared_utils_1.expandShorthandValues)(tokens); const [topStr, rightStr, bottomStr, leftStr] = expandedStrings; // Parse each expanded value const borderTopWidth = parseSingleBorderWidth(topStr); const borderRightWidth = parseSingleBorderWidth(rightStr); const borderBottomWidth = parseSingleBorderWidth(bottomStr); const borderLeftWidth = parseSingleBorderWidth(leftStr); if (!borderTopWidth || !borderRightWidth || !borderBottomWidth || !borderLeftWidth) { return null; } // Return the expanded structure return { borderTopWidth, borderRightWidth, borderBottomWidth, borderLeftWidth }; } /** * Convert BorderWidthValue back to CSS string */ function toCSSValue(parsed) { if (!parsed) { return null; } // Handle CSS variables for entire shorthand if ('CSSvariable' in parsed) { return (0, css_variable_1.toCSSValue)(parsed); } // Handle expanded shorthand structure const borderWidthExpanded = parsed; const topValue = serializeSingleBorderWidth(borderWidthExpanded.borderTopWidth); const rightValue = serializeSingleBorderWidth(borderWidthExpanded.borderRightWidth); const bottomValue = serializeSingleBorderWidth(borderWidthExpanded.borderBottomWidth); const leftValue = serializeSingleBorderWidth(borderWidthExpanded.borderLeftWidth); if (!topValue || !rightValue || !bottomValue || !leftValue) { return null; } // Compress to shortest form if (topValue === rightValue && rightValue === bottomValue && bottomValue === leftValue) { // All same: "1px" return topValue; } else if (topValue === bottomValue && rightValue === leftValue) { // Top/bottom same, left/right same: "1px 2px" return `${topValue} ${rightValue}`; } else if (rightValue === leftValue) { // Left/right same: "1px 2px 3px" return `${topValue} ${rightValue} ${bottomValue}`; } else { // All different: "1px 2px 3px 4px" return `${topValue} ${rightValue} ${bottomValue} ${leftValue}`; } } /** * Serialize a single border width value to CSS string */ function serializeSingleBorderWidth(value) { // Handle CSS variables in components if ('CSSvariable' in value) { return (0, css_variable_1.toCSSValue)(value); } // Handle keywords if ('keyword' in value) { return value.keyword; } // Handle lengths by delegating to the length toCSSValue function const lengthValue = (0, length_1.toCSSValue)(value); if (lengthValue) { return lengthValue; } return null; }