UNPKG

@wix/css-property-parser

Version:

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

208 lines (207 loc) 7.29 kB
"use strict"; // Opacity property parser // Handles parsing of CSS opacity property according to MDN specification // https://developer.mozilla.org/en-US/docs/Web/CSS/opacity Object.defineProperty(exports, "__esModule", { value: true }); exports.parse = parse; exports.toCSSValue = toCSSValue; const shared_utils_1 = require('../utils/shared-utils.cjs'); const number_1 = require('./number.cjs'); const percentage_1 = require('./percentage.cjs'); const css_variable_1 = require('./css-variable.cjs'); /** * Check if a number value is in valid opacity range (0-1) */ function isValidOpacityNumber(numberValue) { // CSS variables can't be validated at parse time if ('CSSvariable' in numberValue) { return true; } if ('expression' in numberValue) { // Allow calc expressions (can't validate at parse time) return true; } if ('keyword' in numberValue) { // Allow keywords (inherit, initial, etc.) return true; } // Check range for numeric values return numberValue.value >= 0 && numberValue.value <= 1; } /** * Check if a percentage value is in valid opacity range (0%-100%) */ function isValidOpacityPercentage(percentageValue) { // CSS variables can't be validated at parse time if ('CSSvariable' in percentageValue) { return true; } if ('expression' in percentageValue) { // Allow calc expressions (can't validate at parse time) return true; } // Check range for percentage values return percentageValue.value >= 0 && percentageValue.value <= 100; } /** * Parses a CSS opacity property string into structured components * Follows MDN specification: https://developer.mozilla.org/en-US/docs/Web/CSS/opacity */ function parse(value) { if (!value || typeof value !== 'string') { return null; } const trimmed = value.trim(); if (trimmed === '') { return null; } // CSS variables can be parsed directly if ((0, shared_utils_1.isCssVariable)(trimmed)) { return (0, css_variable_1.parse)(trimmed); } // Handle global keywords (inherit, initial, unset, revert, revert-layer) if ((0, shared_utils_1.isGlobalKeyword)(trimmed)) { return { type: 'keyword', keyword: trimmed.toLowerCase() }; } // Handle calc expressions by checking content if (trimmed.startsWith('calc(') && trimmed.endsWith(')')) { const expression = trimmed.slice(5, -1).trim(); // If calc expression contains %, treat as percentage if (expression.includes('%')) { const percentageResult = (0, percentage_1.parse)(trimmed); if (percentageResult && isValidOpacityPercentage(percentageResult)) { // Handle CSS variables if ('CSSvariable' in percentageResult) { return percentageResult; } // Return calc expression for percentage if ('expression' in percentageResult) { return { type: 'percentage', value: 0, // placeholder - actual value computed at runtime unit: '%' }; } else { return { type: 'percentage', value: percentageResult.value, unit: '%' }; } } } else { // Otherwise treat as number const numberResult = (0, number_1.parse)(trimmed); if (numberResult && isValidOpacityNumber(numberResult)) { // Handle CSS variables if ('CSSvariable' in numberResult) { return numberResult; } // Return calc expression for number if ('expression' in numberResult) { return { type: 'number', value: 0 // placeholder - actual value computed at runtime }; } else if ('keyword' in numberResult) { // Handle keyword case return { type: 'keyword', keyword: numberResult.keyword }; } else { return { type: 'number', value: numberResult.value }; } } } return null; } // Try to parse as percentage first (for explicit percentage values like "50%") if (trimmed.includes('%')) { const percentageResult = (0, percentage_1.parse)(trimmed); if (percentageResult) { // Validate percentage range (0%-100%) if (isValidOpacityPercentage(percentageResult)) { // Handle CSS variables if ('CSSvariable' in percentageResult) { return percentageResult; } if ('expression' in percentageResult) { return { type: 'percentage', value: 0, // placeholder - actual value computed at runtime unit: '%' }; } else { return { type: 'percentage', value: percentageResult.value, unit: '%' }; } } // Invalid range - return null return null; } } // Try to parse as number const numberResult = (0, number_1.parse)(trimmed); if (numberResult) { // Validate number range (0-1) if (isValidOpacityNumber(numberResult)) { // Handle CSS variables if ('CSSvariable' in numberResult) { return numberResult; } if ('expression' in numberResult) { return { type: 'number', value: 0 // placeholder - actual value computed at runtime }; } else if ('keyword' in numberResult) { // Handle keyword case return { type: 'keyword', keyword: numberResult.keyword }; } else { return { type: 'number', value: numberResult.value }; } } // Invalid range - return null return null; } return null; } /** * Converts a parsed opacity back to a CSS value string */ function toCSSValue(parsed) { if (!parsed) { return null; } // Handle CSS variables if ('CSSvariable' in parsed) { return (0, css_variable_1.toCSSValue)(parsed); } // Handle keywords if ('keyword' in parsed) { return parsed.keyword; } // Handle percentage values (has unit property) if ('unit' in parsed && parsed.unit === '%') { return `${parsed.value}%`; } // Handle number values (just value property) if ('value' in parsed && !('unit' in parsed)) { return parsed.value.toString(); } return null; }