@wix/css-property-parser
Version:
A comprehensive TypeScript library for parsing and serializing CSS property values with full MDN specification compliance
155 lines (154 loc) • 4.96 kB
JavaScript
// Shared individual border property parser
// Handles parsing of individual border shorthand properties (border-top, border-right, border-bottom, border-left)
// https://developer.mozilla.org/en-US/docs/Web/CSS/border-top
import { parse as parseLength, toCSSValue as lengthToCSSValue } from './length.js';
import { parse as parseColor, toCSSValue as colorToCSSValue } from './color.js';
import { parse as parseCSSVariable, toCSSValue as cssVariableToCSSValue } from './css-variable.js';
import { isCssVariable, isGlobalKeyword, tokenize } from '../utils/shared-utils.js';
import { BORDER_WIDTH_KEYWORDS, BORDER_STYLE_KEYWORDS } from '../types.js';
/**
* Parse border width value (length or keyword)
*/
function parseBorderWidth(value) {
if (isGlobalKeyword(value)) {
return { type: 'keyword', keyword: value.toLowerCase() };
}
if (BORDER_WIDTH_KEYWORDS.includes(value.toLowerCase())) {
return { type: 'keyword', keyword: value.toLowerCase() };
}
return parseLength(value);
}
/**
* Parse border style value
*/
function parseBorderStyle(value) {
if (isGlobalKeyword(value)) {
return { type: 'keyword', keyword: value.toLowerCase() };
}
if (BORDER_STYLE_KEYWORDS.includes(value.toLowerCase())) {
return { type: 'keyword', keyword: value.toLowerCase() };
}
return null;
}
/**
* Parse border color value
*/
function parseBorderColor(value) {
if (isGlobalKeyword(value)) {
return { type: 'keyword', keyword: value.toLowerCase() };
}
if (value.toLowerCase() === 'currentcolor') {
return { type: 'keyword', keyword: 'currentcolor' };
}
const colorResult = parseColor(value);
// Filter out CSS variables since they should be handled at the top level
if (colorResult && colorResult.type !== 'variable') {
return colorResult;
}
return null;
}
/**
* Parse individual border shorthand property value
*/
export function parseBorderIndividualProperty(value) {
if (!value || typeof value !== 'string')
return null;
const trimmed = value.trim();
if (trimmed === '')
return null;
// Handle CSS variables
if (isCssVariable(trimmed)) {
return parseCSSVariable(trimmed);
}
// Handle global keywords
if (isGlobalKeyword(trimmed)) {
return { type: 'keyword', keyword: trimmed.toLowerCase() };
}
// Tokenize the value to handle multiple parts
const tokens = tokenize(trimmed);
let width = null;
let style = null;
let color = null;
// Parse each token and assign to appropriate property
for (const token of tokens) {
// Try width first
if (!width) {
const widthResult = parseBorderWidth(token);
if (widthResult) {
width = widthResult;
continue;
}
}
// Try style
if (!style) {
const styleResult = parseBorderStyle(token);
if (styleResult) {
style = styleResult;
continue;
}
}
// Try color
if (!color) {
const colorResult = parseBorderColor(token);
if (colorResult) {
color = colorResult;
continue;
}
}
// If we get here, we have an unrecognized token
return null;
}
// Must have at least one valid component
if (!width && !style && !color) {
return null;
}
return {
type: 'border-individual',
width: width || undefined,
style: style || undefined,
color: color || undefined
};
}
/**
* Convert individual border value to CSS string
*/
export function borderIndividualToCSSValue(parsed) {
if (!parsed)
return null;
if (parsed.type === 'keyword') {
return parsed.keyword;
}
if (parsed.type === 'variable') {
return cssVariableToCSSValue(parsed);
}
if (parsed.type === 'border-individual') {
const parts = [];
if (parsed.width) {
if (parsed.width.type === 'length') {
const widthValue = lengthToCSSValue(parsed.width);
if (widthValue)
parts.push(widthValue);
}
else if (parsed.width.type === 'keyword') {
parts.push(parsed.width.keyword);
}
}
if (parsed.style) {
if (parsed.style.type === 'keyword') {
parts.push(parsed.style.keyword);
}
}
if (parsed.color) {
if (parsed.color.type === 'keyword') {
parts.push(parsed.color.keyword);
}
else {
const colorValue = colorToCSSValue(parsed.color);
if (colorValue)
parts.push(colorValue);
}
}
return parts.length > 0 ? parts.join(' ') : null;
}
return null;
}