@tenphi/tasty 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/properties/index.ts"],"sourcesContent":["/**\n * Properties Utilities\n *\n * Utilities for extracting and processing CSS @property definitions in styles.\n * Unlike keyframes, properties are permanent once registered and don't need cleanup.\n *\n * Property names use tasty token syntax:\n * - `$name` for regular properties → `--name`\n * - `#name` for color properties → `--name-color` (auto-sets syntax: '<color>')\n */\n\nimport type { PropertyDefinition } from '../injector/types';\nimport { RE_NUMBER, RE_RAW_UNIT } from '../parser/const';\nimport type { Styles } from '../styles/types';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst PROPERTIES_KEY = '@properties';\n\n/**\n * Valid CSS custom property name pattern (after the -- prefix).\n * Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.\n */\nconst VALID_PROPERTY_NAME_PATTERN = /^[a-z_][a-z0-9-_]*$/i;\n\n// ============================================================================\n// Validation Functions\n// ============================================================================\n\n/**\n * Validate a CSS custom property name (the part after --).\n * Returns true if the name is valid for use as a CSS custom property.\n */\nexport function isValidPropertyName(name: string): boolean {\n return VALID_PROPERTY_NAME_PATTERN.test(name);\n}\n\n/**\n * Result of parsing a property token.\n */\nexport interface ParsedPropertyToken {\n /** The CSS custom property name (e.g., '--my-prop') */\n cssName: string;\n /** Whether this is a color property */\n isColor: boolean;\n /** Whether the token was valid */\n isValid: boolean;\n /** Error message if invalid */\n error?: string;\n}\n\n// ============================================================================\n// Extraction Functions\n// ============================================================================\n\n/**\n * Check if styles object has local @properties definition.\n * Fast path: single property lookup.\n */\nexport function hasLocalProperties(styles: Styles): boolean {\n return PROPERTIES_KEY in styles;\n}\n\n/**\n * Extract local @properties from styles object.\n * Returns null if no local properties (fast path).\n */\nexport function extractLocalProperties(\n styles: Styles,\n): Record<string, PropertyDefinition> | null {\n const properties = styles[PROPERTIES_KEY];\n if (!properties || typeof properties !== 'object') {\n return null;\n }\n return properties as Record<string, PropertyDefinition>;\n}\n\n// ============================================================================\n// Token Parsing Functions\n// ============================================================================\n\n/**\n * Parse a property token name and return the CSS property name and whether it's a color.\n * Supports tasty token syntax and validates the property name.\n *\n * Token formats:\n * - `$name` → { cssName: '--name', isColor: false }\n * - `#name` → { cssName: '--name-color', isColor: true }\n * - `--name` → { cssName: '--name', isColor: false } (legacy, auto-detect color by suffix)\n * - `name` → { cssName: '--name', isColor: false } (legacy)\n *\n * @param token - The property token to parse\n * @returns Parsed result with cssName, isColor, isValid, and optional error\n */\nexport function parsePropertyToken(token: string): ParsedPropertyToken {\n if (!token || typeof token !== 'string') {\n return {\n cssName: '',\n isColor: false,\n isValid: false,\n error: 'Property token must be a non-empty string',\n };\n }\n\n let name: string;\n let isColor: boolean;\n\n if (token.startsWith('$')) {\n // Regular property token: $name → --name\n name = token.slice(1);\n isColor = false;\n } else if (token.startsWith('#')) {\n // Color property token: #name → --name-color\n name = token.slice(1);\n isColor = true;\n } else if (token.startsWith('--')) {\n // Legacy format with -- prefix\n name = token.slice(2);\n isColor = token.endsWith('-color');\n } else {\n // Legacy format without prefix\n name = token;\n isColor = token.endsWith('-color');\n }\n\n // Validate the name\n if (!name) {\n return {\n cssName: '',\n isColor,\n isValid: false,\n error: 'Property name cannot be empty',\n };\n }\n\n if (!isValidPropertyName(name)) {\n return {\n cssName: '',\n isColor,\n isValid: false,\n error: `Invalid property name \"${name}\". Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.`,\n };\n }\n\n // Build the CSS custom property name\n // For #name tokens, we add -color suffix\n // For legacy formats (--name-color or name-color), the name already includes -color\n let cssName: string;\n if (token.startsWith('#')) {\n // Color token: #name → --name-color\n cssName = `--${name}-color`;\n } else {\n // All other formats: just add -- prefix\n cssName = `--${name}`;\n }\n\n return {\n cssName,\n isColor,\n isValid: true,\n };\n}\n\n// ============================================================================\n// Normalization Functions\n// ============================================================================\n\n/**\n * Normalize a property name to the CSS custom property format.\n *\n * @deprecated Use parsePropertyToken instead for proper token handling\n */\nexport function normalizePropertyName(name: string): string {\n const result = parsePropertyToken(name);\n return result.isValid ? result.cssName : `--${name}`;\n}\n\n/**\n * Normalize a property definition to a consistent string representation.\n * Used for comparing definitions to detect type conflicts.\n *\n * Only `syntax` and `inherits` are compared — `initialValue` is intentionally\n * excluded because different components may set different defaults for the\n * same typed property (e.g. auto-inferred `0px` vs explicit `6px`).\n *\n * Keys are sorted alphabetically to ensure consistent comparison:\n * { inherits: true, syntax: '<color>' } === { syntax: '<color>', inherits: true }\n */\nexport function normalizePropertyDefinition(def: PropertyDefinition): string {\n const normalized: Record<string, unknown> = {};\n\n if (def.inherits !== undefined) {\n normalized.inherits = def.inherits;\n }\n if (def.syntax !== undefined) {\n normalized.syntax = def.syntax;\n }\n\n return JSON.stringify(normalized);\n}\n\n/**\n * Result of getEffectiveDefinition.\n */\nexport interface EffectiveDefinitionResult {\n /** The CSS custom property name */\n cssName: string;\n /** The effective property definition */\n definition: PropertyDefinition;\n /** Whether this is a color property */\n isColor: boolean;\n /** Whether the token was valid */\n isValid: boolean;\n /** Error message if invalid */\n error?: string;\n}\n\n/**\n * Get the effective property definition for a token.\n * For color tokens (#name), auto-sets syntax to '<color>' and defaults initialValue to 'transparent'.\n *\n * @param token - Property token ($name, #name, --name, or plain name)\n * @param userDefinition - User-provided definition options\n * @returns Effective definition with cssName, definition, isValid, and optional error\n */\nexport function getEffectiveDefinition(\n token: string,\n userDefinition: PropertyDefinition,\n): EffectiveDefinitionResult {\n const parsed = parsePropertyToken(token);\n\n if (!parsed.isValid) {\n return {\n cssName: '',\n definition: userDefinition,\n isColor: false,\n isValid: false,\n error: parsed.error,\n };\n }\n\n if (parsed.isColor) {\n // Color properties have fixed syntax and default initialValue\n return {\n cssName: parsed.cssName,\n definition: {\n syntax: '<color>', // Always '<color>' for color tokens, cannot be overridden\n inherits: userDefinition.inherits, // Allow inherits to be customized\n initialValue: userDefinition.initialValue ?? 'transparent', // Default to transparent\n },\n isColor: true,\n isValid: true,\n };\n }\n\n // Regular properties use the definition as-is\n return {\n cssName: parsed.cssName,\n definition: userDefinition,\n isColor: false,\n isValid: true,\n };\n}\n\n// ============================================================================\n// Value Type Inference\n// ============================================================================\n\n/**\n * Result of inferring a CSS @property syntax from a value.\n */\nexport interface InferredSyntax {\n syntax: string;\n initialValue: string;\n}\n\nconst UNIT_TO_SYNTAX: Record<string, InferredSyntax> = {};\n\nconst LENGTH_UNITS = [\n 'px',\n 'em',\n 'rem',\n 'vw',\n 'vh',\n 'vmin',\n 'vmax',\n 'ch',\n 'ex',\n 'cap',\n 'ic',\n 'lh',\n 'rlh',\n 'svw',\n 'svh',\n 'lvw',\n 'lvh',\n 'dvw',\n 'dvh',\n 'cqw',\n 'cqh',\n 'cqi',\n 'cqb',\n 'cqmin',\n 'cqmax',\n];\n\nconst ANGLE_UNITS = ['deg', 'rad', 'grad', 'turn'];\nconst TIME_UNITS = ['ms', 's'];\n\nfor (const u of LENGTH_UNITS) {\n UNIT_TO_SYNTAX[u] = { syntax: '<length>', initialValue: '0px' };\n}\nUNIT_TO_SYNTAX['%'] = { syntax: '<percentage>', initialValue: '0%' };\nfor (const u of ANGLE_UNITS) {\n UNIT_TO_SYNTAX[u] = { syntax: '<angle>', initialValue: '0deg' };\n}\nfor (const u of TIME_UNITS) {\n UNIT_TO_SYNTAX[u] = { syntax: '<time>', initialValue: '0s' };\n}\n\n/**\n * Infer CSS @property syntax from a concrete value.\n * Only detects numeric types: \\<number\\>, \\<length\\>, \\<percentage\\>, \\<angle\\>, \\<time\\>.\n * Color properties are handled separately via the #name token convention\n * (--name-color gets \\<color\\> syntax automatically in getEffectiveDefinition).\n *\n * @param value - The CSS value to infer from (e.g. '10px', '1', '45deg')\n * @returns Inferred syntax and initial value, or null if not inferable\n */\nexport function inferSyntaxFromValue(value: string): InferredSyntax | null {\n if (!value || typeof value !== 'string') return null;\n\n const trimmed = value.trim();\n if (!trimmed) return null;\n\n if (RE_NUMBER.test(trimmed)) {\n return { syntax: '<number>', initialValue: '0' };\n }\n\n const unitMatch = trimmed.match(RE_RAW_UNIT);\n if (unitMatch) {\n const unit = unitMatch[2];\n const mapping = UNIT_TO_SYNTAX[unit];\n if (mapping) return mapping;\n }\n\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/properties/index.ts"],"sourcesContent":["/**\n * Properties Utilities\n *\n * Utilities for extracting and processing CSS @property definitions in styles.\n * Unlike keyframes, properties are permanent once registered and don't need cleanup.\n *\n * Property names use tasty token syntax:\n * - `$name` for regular properties → `--name`\n * - `#name` for color properties → `--name-color` (auto-sets syntax: '<color>')\n */\n\nimport type { PropertyDefinition } from '../injector/types';\nimport { RE_NUMBER, RE_RAW_UNIT } from '../parser/const';\nimport type { Styles } from '../styles/types';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst PROPERTIES_KEY = '@properties';\n\n/**\n * Valid CSS custom property name pattern (after the -- prefix).\n * Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.\n */\nconst VALID_PROPERTY_NAME_PATTERN = /^[a-z_][a-z0-9-_]*$/i;\n\n// ============================================================================\n// Validation Functions\n// ============================================================================\n\n/**\n * Validate a CSS custom property name (the part after --).\n * Returns true if the name is valid for use as a CSS custom property.\n */\nexport function isValidPropertyName(name: string): boolean {\n return VALID_PROPERTY_NAME_PATTERN.test(name);\n}\n\n/**\n * Result of parsing a property token.\n */\nexport interface ParsedPropertyToken {\n /** The CSS custom property name (e.g., '--my-prop') */\n cssName: string;\n /** Whether this is a color property */\n isColor: boolean;\n /** Whether the token was valid */\n isValid: boolean;\n /** Error message if invalid */\n error?: string;\n}\n\n// ============================================================================\n// Extraction Functions\n// ============================================================================\n\n/**\n * Check if styles object has local @properties definition.\n * Fast path: single property lookup.\n */\nexport function hasLocalProperties(styles: Styles): boolean {\n return PROPERTIES_KEY in styles;\n}\n\n/**\n * Extract local @properties from styles object.\n * Returns null if no local properties (fast path).\n */\nexport function extractLocalProperties(\n styles: Styles,\n): Record<string, PropertyDefinition> | null {\n const properties = styles[PROPERTIES_KEY];\n if (!properties || typeof properties !== 'object') {\n return null;\n }\n return properties as Record<string, PropertyDefinition>;\n}\n\n// ============================================================================\n// Token Parsing Functions\n// ============================================================================\n\n/**\n * Parse a property token name and return the CSS property name and whether it's a color.\n * Supports tasty token syntax and validates the property name.\n *\n * Token formats:\n * - `$name` → { cssName: '--name', isColor: false }\n * - `#name` → { cssName: '--name-color', isColor: true }\n * - `--name` → { cssName: '--name', isColor: false } (legacy, auto-detect color by suffix)\n * - `name` → { cssName: '--name', isColor: false } (legacy)\n *\n * @param token - The property token to parse\n * @returns Parsed result with cssName, isColor, isValid, and optional error\n */\nexport function parsePropertyToken(token: string): ParsedPropertyToken {\n if (!token || typeof token !== 'string') {\n return {\n cssName: '',\n isColor: false,\n isValid: false,\n error: 'Property token must be a non-empty string',\n };\n }\n\n let name: string;\n let isColor: boolean;\n\n if (token.startsWith('$')) {\n // Regular property token: $name → --name\n name = token.slice(1);\n isColor = false;\n } else if (token.startsWith('#')) {\n // Color property token: #name → --name-color\n name = token.slice(1);\n isColor = true;\n } else if (token.startsWith('--')) {\n // Legacy format with -- prefix\n name = token.slice(2);\n isColor = token.endsWith('-color');\n } else {\n // Legacy format without prefix\n name = token;\n isColor = token.endsWith('-color');\n }\n\n // Validate the name\n if (!name) {\n return {\n cssName: '',\n isColor,\n isValid: false,\n error: 'Property name cannot be empty',\n };\n }\n\n if (!isValidPropertyName(name)) {\n return {\n cssName: '',\n isColor,\n isValid: false,\n error: `Invalid property name \"${name}\". Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.`,\n };\n }\n\n // Build the CSS custom property name\n // For #name tokens, we add -color suffix\n // For legacy formats (--name-color or name-color), the name already includes -color\n let cssName: string;\n if (token.startsWith('#')) {\n // Color token: #name → --name-color\n cssName = `--${name}-color`;\n } else {\n // All other formats: just add -- prefix\n cssName = `--${name}`;\n }\n\n return {\n cssName,\n isColor,\n isValid: true,\n };\n}\n\n// ============================================================================\n// Normalization Functions\n// ============================================================================\n\n/**\n * Normalize a property name to the CSS custom property format.\n *\n * @deprecated Use parsePropertyToken instead for proper token handling\n */\nexport function normalizePropertyName(name: string): string {\n const result = parsePropertyToken(name);\n return result.isValid ? result.cssName : `--${name}`;\n}\n\n/**\n * Normalize a property definition to a consistent string representation.\n * Used for comparing definitions to detect type conflicts.\n *\n * Only `syntax` and `inherits` are compared — `initialValue` is intentionally\n * excluded because different components may set different defaults for the\n * same typed property (e.g. auto-inferred `0px` vs explicit `6px`).\n *\n * Keys are sorted alphabetically to ensure consistent comparison:\n * { inherits: true, syntax: '<color>' } === { syntax: '<color>', inherits: true }\n */\nexport function normalizePropertyDefinition(def: PropertyDefinition): string {\n const normalized: Record<string, unknown> = {};\n\n if (def.inherits !== undefined) {\n normalized.inherits = def.inherits;\n }\n if (def.syntax !== undefined) {\n normalized.syntax = def.syntax;\n }\n\n return JSON.stringify(normalized);\n}\n\n/**\n * Result of getEffectiveDefinition.\n */\nexport interface EffectiveDefinitionResult {\n /** The CSS custom property name */\n cssName: string;\n /** The effective property definition */\n definition: PropertyDefinition;\n /** Whether this is a color property */\n isColor: boolean;\n /** Whether the token was valid */\n isValid: boolean;\n /** Error message if invalid */\n error?: string;\n}\n\n/**\n * Get the effective property definition for a token.\n * For color tokens (#name), auto-sets syntax to '<color>' and defaults initialValue to 'transparent'.\n *\n * @param token - Property token ($name, #name, --name, or plain name)\n * @param userDefinition - User-provided definition options\n * @returns Effective definition with cssName, definition, isValid, and optional error\n */\nexport function getEffectiveDefinition(\n token: string,\n userDefinition: PropertyDefinition,\n): EffectiveDefinitionResult {\n const parsed = parsePropertyToken(token);\n\n if (!parsed.isValid) {\n return {\n cssName: '',\n definition: userDefinition,\n isColor: false,\n isValid: false,\n error: parsed.error,\n };\n }\n\n if (parsed.isColor) {\n // Color properties have fixed syntax and default initialValue\n return {\n cssName: parsed.cssName,\n definition: {\n syntax: '<color>', // Always '<color>' for color tokens, cannot be overridden\n inherits: userDefinition.inherits, // Allow inherits to be customized\n initialValue: userDefinition.initialValue ?? 'transparent', // Default to transparent\n },\n isColor: true,\n isValid: true,\n };\n }\n\n // Regular properties use the definition as-is\n return {\n cssName: parsed.cssName,\n definition: userDefinition,\n isColor: false,\n isValid: true,\n };\n}\n\n// ============================================================================\n// Value Type Inference\n// ============================================================================\n\n/**\n * Result of inferring a CSS @property syntax from a value.\n */\nexport interface InferredSyntax {\n syntax: string;\n initialValue: string;\n}\n\nconst UNIT_TO_SYNTAX: Record<string, InferredSyntax> = {};\n\nconst LENGTH_UNITS = [\n 'px',\n 'em',\n 'rem',\n 'vw',\n 'vh',\n 'vmin',\n 'vmax',\n 'ch',\n 'ex',\n 'cap',\n 'ic',\n 'lh',\n 'rlh',\n 'svw',\n 'svh',\n 'lvw',\n 'lvh',\n 'dvw',\n 'dvh',\n 'cqw',\n 'cqh',\n 'cqi',\n 'cqb',\n 'cqmin',\n 'cqmax',\n];\n\nconst ANGLE_UNITS = ['deg', 'rad', 'grad', 'turn'];\nconst TIME_UNITS = ['ms', 's'];\n\nfor (const u of LENGTH_UNITS) {\n UNIT_TO_SYNTAX[u] = { syntax: '<length>', initialValue: '0px' };\n}\nUNIT_TO_SYNTAX['%'] = { syntax: '<percentage>', initialValue: '0%' };\nfor (const u of ANGLE_UNITS) {\n UNIT_TO_SYNTAX[u] = { syntax: '<angle>', initialValue: '0deg' };\n}\nfor (const u of TIME_UNITS) {\n UNIT_TO_SYNTAX[u] = { syntax: '<time>', initialValue: '0s' };\n}\n\n/**\n * Infer CSS @property syntax from a concrete value.\n * Only detects numeric types: \\<number\\>, \\<length\\>, \\<percentage\\>, \\<angle\\>, \\<time\\>.\n * Color properties are handled separately via the #name token convention\n * (--name-color gets \\<color\\> syntax automatically in getEffectiveDefinition).\n *\n * @param value - The CSS value to infer from (e.g. '10px', '1', '45deg')\n * @returns Inferred syntax and initial value, or null if not inferable\n */\nexport function inferSyntaxFromValue(value: string): InferredSyntax | null {\n if (!value || typeof value !== 'string') return null;\n\n const trimmed = value.trim();\n if (!trimmed) return null;\n\n if (RE_NUMBER.test(trimmed)) {\n // Bare zero is ambiguous (could be <length>, <angle>, <percentage>, etc.)\n if (parseFloat(trimmed) === 0) return null;\n return { syntax: '<number>', initialValue: '0' };\n }\n\n const unitMatch = trimmed.match(RE_RAW_UNIT);\n if (unitMatch) {\n const unit = unitMatch[2];\n const mapping = UNIT_TO_SYNTAX[unit];\n if (mapping) return mapping;\n }\n\n return null;\n}\n"],"mappings":";;;AAmBA,MAAM,iBAAiB;;;;;AAMvB,MAAM,8BAA8B;;;;;AAUpC,SAAgB,oBAAoB,MAAuB;AACzD,QAAO,4BAA4B,KAAK,KAAK;;;;;;AAyB/C,SAAgB,mBAAmB,QAAyB;AAC1D,QAAO,kBAAkB;;;;;;AAO3B,SAAgB,uBACd,QAC2C;CAC3C,MAAM,aAAa,OAAO;AAC1B,KAAI,CAAC,cAAc,OAAO,eAAe,SACvC,QAAO;AAET,QAAO;;;;;;;;;;;;;;;AAoBT,SAAgB,mBAAmB,OAAoC;AACrE,KAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;EACL,SAAS;EACT,SAAS;EACT,SAAS;EACT,OAAO;EACR;CAGH,IAAI;CACJ,IAAI;AAEJ,KAAI,MAAM,WAAW,IAAI,EAAE;AAEzB,SAAO,MAAM,MAAM,EAAE;AACrB,YAAU;YACD,MAAM,WAAW,IAAI,EAAE;AAEhC,SAAO,MAAM,MAAM,EAAE;AACrB,YAAU;YACD,MAAM,WAAW,KAAK,EAAE;AAEjC,SAAO,MAAM,MAAM,EAAE;AACrB,YAAU,MAAM,SAAS,SAAS;QAC7B;AAEL,SAAO;AACP,YAAU,MAAM,SAAS,SAAS;;AAIpC,KAAI,CAAC,KACH,QAAO;EACL,SAAS;EACT;EACA,SAAS;EACT,OAAO;EACR;AAGH,KAAI,CAAC,oBAAoB,KAAK,CAC5B,QAAO;EACL,SAAS;EACT;EACA,SAAS;EACT,OAAO,0BAA0B,KAAK;EACvC;CAMH,IAAI;AACJ,KAAI,MAAM,WAAW,IAAI,CAEvB,WAAU,KAAK,KAAK;KAGpB,WAAU,KAAK;AAGjB,QAAO;EACL;EACA;EACA,SAAS;EACV;;;;;;;;;;;;;AA4BH,SAAgB,4BAA4B,KAAiC;CAC3E,MAAM,aAAsC,EAAE;AAE9C,KAAI,IAAI,aAAa,OACnB,YAAW,WAAW,IAAI;AAE5B,KAAI,IAAI,WAAW,OACjB,YAAW,SAAS,IAAI;AAG1B,QAAO,KAAK,UAAU,WAAW;;;;;;;;;;AA2BnC,SAAgB,uBACd,OACA,gBAC2B;CAC3B,MAAM,SAAS,mBAAmB,MAAM;AAExC,KAAI,CAAC,OAAO,QACV,QAAO;EACL,SAAS;EACT,YAAY;EACZ,SAAS;EACT,SAAS;EACT,OAAO,OAAO;EACf;AAGH,KAAI,OAAO,QAET,QAAO;EACL,SAAS,OAAO;EAChB,YAAY;GACV,QAAQ;GACR,UAAU,eAAe;GACzB,cAAc,eAAe,gBAAgB;GAC9C;EACD,SAAS;EACT,SAAS;EACV;AAIH,QAAO;EACL,SAAS,OAAO;EAChB,YAAY;EACZ,SAAS;EACT,SAAS;EACV;;AAeH,MAAM,iBAAiD,EAAE;AAEzD,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,cAAc;CAAC;CAAO;CAAO;CAAQ;CAAO;AAClD,MAAM,aAAa,CAAC,MAAM,IAAI;AAE9B,KAAK,MAAM,KAAK,aACd,gBAAe,KAAK;CAAE,QAAQ;CAAY,cAAc;CAAO;AAEjE,eAAe,OAAO;CAAE,QAAQ;CAAgB,cAAc;CAAM;AACpE,KAAK,MAAM,KAAK,YACd,gBAAe,KAAK;CAAE,QAAQ;CAAW,cAAc;CAAQ;AAEjE,KAAK,MAAM,KAAK,WACd,gBAAe,KAAK;CAAE,QAAQ;CAAU,cAAc;CAAM;;;;;;;;;;AAY9D,SAAgB,qBAAqB,OAAsC;AACzE,KAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;CAEhD,MAAM,UAAU,MAAM,MAAM;AAC5B,KAAI,CAAC,QAAS,QAAO;AAErB,KAAI,UAAU,KAAK,QAAQ,EAAE;AAE3B,MAAI,WAAW,QAAQ,KAAK,EAAG,QAAO;AACtC,SAAO;GAAE,QAAQ;GAAY,cAAc;GAAK;;CAGlD,MAAM,YAAY,QAAQ,MAAM,YAAY;AAC5C,KAAI,WAAW;EAEb,MAAM,UAAU,eADH,UAAU;AAEvB,MAAI,QAAS,QAAO;;AAGtB,QAAO"}
@@ -0,0 +1,32 @@
1
+ //#region src/utils/selector-transform.ts
2
+ /**
3
+ * Shared utility for transforming capitalized PascalCase element names
4
+ * in CSS selector content to `[data-element="..."]` attribute selectors.
5
+ *
6
+ * Lowercase words are treated as HTML tags and left unchanged.
7
+ */
8
+ /**
9
+ * Matches a capitalized PascalCase word at the start of the string
10
+ * or after a CSS combinator/separator character.
11
+ */
12
+ const ELEMENT_NAME_RE = /(^|[\s>+~,(])([A-Z][a-zA-Z0-9]*)/g;
13
+ /**
14
+ * Replace capitalized PascalCase words with `[data-element="Name"]` selectors.
15
+ *
16
+ * @example
17
+ * transformSelectorContent('> Field + input:checked')
18
+ * // → '> [data-element="Field"] + input:checked'
19
+ *
20
+ * transformSelectorContent('Body > Row')
21
+ * // → '[data-element="Body"] > [data-element="Row"]'
22
+ *
23
+ * transformSelectorContent('button')
24
+ * // → 'button' (lowercase = HTML tag, unchanged)
25
+ */
26
+ function transformSelectorContent(content) {
27
+ return content.replace(ELEMENT_NAME_RE, (_, prefix, name) => `${prefix}[data-element="${name}"]`);
28
+ }
29
+
30
+ //#endregion
31
+ export { transformSelectorContent };
32
+ //# sourceMappingURL=selector-transform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector-transform.js","names":[],"sources":["../../src/utils/selector-transform.ts"],"sourcesContent":["/**\n * Shared utility for transforming capitalized PascalCase element names\n * in CSS selector content to `[data-element=\"...\"]` attribute selectors.\n *\n * Lowercase words are treated as HTML tags and left unchanged.\n */\n\n/**\n * Matches a capitalized PascalCase word at the start of the string\n * or after a CSS combinator/separator character.\n */\nconst ELEMENT_NAME_RE = /(^|[\\s>+~,(])([A-Z][a-zA-Z0-9]*)/g;\n\n/**\n * Replace capitalized PascalCase words with `[data-element=\"Name\"]` selectors.\n *\n * @example\n * transformSelectorContent('> Field + input:checked')\n * // → '> [data-element=\"Field\"] + input:checked'\n *\n * transformSelectorContent('Body > Row')\n * // → '[data-element=\"Body\"] > [data-element=\"Row\"]'\n *\n * transformSelectorContent('button')\n * // → 'button' (lowercase = HTML tag, unchanged)\n */\nexport function transformSelectorContent(content: string): string {\n return content.replace(\n ELEMENT_NAME_RE,\n (_, prefix, name) => `${prefix}[data-element=\"${name}\"]`,\n );\n}\n"],"mappings":";;;;;;;;;;;AAWA,MAAM,kBAAkB;;;;;;;;;;;;;;AAexB,SAAgB,yBAAyB,SAAyB;AAChE,QAAO,QAAQ,QACb,kBACC,GAAG,QAAQ,SAAS,GAAG,OAAO,iBAAiB,KAAK,IACtD"}
@@ -74,7 +74,6 @@ declare const CUSTOM_UNITS: {
74
74
  sf: (num: number) => string;
75
75
  };
76
76
  declare const DIRECTIONS: string[];
77
- declare function getModSelector(modName: string): string;
78
77
  declare function customFunc(name: string, fn: (groups: StyleDetails[]) => string): void;
79
78
  /**
80
79
  * Get the global StyleParser instance.
@@ -174,5 +173,5 @@ declare const COMPUTE_FUNC_MAP: Record<string, (a: unknown, b?: unknown) => unkn
174
173
  declare function computeState(computeModel: ComputeModel, valueMap: (number | boolean)[] | Record<string, boolean> | ((...args: unknown[]) => unknown)): unknown;
175
174
  declare function stringifyStyles(styles: unknown): string;
176
175
  //#endregion
177
- export { COMPUTE_FUNC_MAP, CSSMap, CUSTOM_UNITS, ComputeModel, DIRECTIONS, ParsedColor, RawStyleHandler, STATE_OPERATORS, STATE_OPERATOR_LIST, StyleHandler, StyleHandlerDefinition, StyleHandlerResult, StyleMap, StylePropValue, StyleStateData, StyleStateDataList, StyleStateDataListMap, StyleStateMap, StyleValue, StyleValueStateMap, buildAtRuleContext, computeState, customFunc, extendStyles, extractStyles, filterMods, getGlobalFuncs, getGlobalParser, getGlobalPredefinedTokens, getModSelector, getRgbValuesFromRgbaString, hexToRgb, isAdvancedStateToken, normalizeColorTokenValue, parseColor, parseStateNotation, parseStyle, resetGlobalPredefinedTokens, setGlobalPredefinedTokens, strToRgb, stringifyStyles, styleStateMapToStyleStateDataList };
176
+ export { COMPUTE_FUNC_MAP, CSSMap, CUSTOM_UNITS, ComputeModel, DIRECTIONS, ParsedColor, RawStyleHandler, STATE_OPERATORS, STATE_OPERATOR_LIST, StyleHandler, StyleHandlerDefinition, StyleHandlerResult, StyleMap, StylePropValue, StyleStateData, StyleStateDataList, StyleStateDataListMap, StyleStateMap, StyleValue, StyleValueStateMap, buildAtRuleContext, computeState, customFunc, extendStyles, extractStyles, filterMods, getGlobalFuncs, getGlobalParser, getGlobalPredefinedTokens, getRgbValuesFromRgbaString, hexToRgb, isAdvancedStateToken, normalizeColorTokenValue, parseColor, parseStateNotation, parseStyle, resetGlobalPredefinedTokens, setGlobalPredefinedTokens, strToRgb, stringifyStyles, styleStateMapToStyleStateDataList };
178
177
  //# sourceMappingURL=styles.d.ts.map
@@ -55,27 +55,6 @@ const DIRECTIONS = [
55
55
  "bottom",
56
56
  "left"
57
57
  ];
58
- const MOD_NAME_CACHE = /* @__PURE__ */ new Map();
59
- function getModSelector(modName) {
60
- if (!MOD_NAME_CACHE.has(modName)) {
61
- let selector;
62
- const valueModMatch = modName.match(/^([a-z][a-z0-9-]*)(\^=|\$=|\*=|=)(.+)$/i);
63
- if (valueModMatch) {
64
- const key = valueModMatch[1];
65
- const operator = valueModMatch[2];
66
- let value = valueModMatch[3];
67
- if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) value = value.slice(1, -1);
68
- selector = `[data-${camelToKebab(key)}${operator}"${value}"]`;
69
- } else if (modName.match(/^[a-z]/)) selector = `[data-${camelToKebab(modName)}]`;
70
- else if (modName.includes(":has(")) selector = modName.replace(/:has\(([^)]+)\)/g, (match, content) => {
71
- if (/[A-Z][a-z]*[>+~]|[>+~][A-Z][a-z]*/.test(content)) console.error(`[Tasty] Invalid :has() selector syntax: "${modName}"\nCombinators (>, +, ~) must have spaces around them when used with element names.\nExample: Use ":has(Body > Row)" instead of ":has(Body>Row)"\nThis is a design choice: the parser uses simple whitespace splitting for performance.`);
72
- return `:has(${content.split(/\s+/).map((token) => /^[A-Z]/.test(token) ? `[data-element="${token}"]` : token).join(" ")})`;
73
- });
74
- else selector = modName;
75
- MOD_NAME_CACHE.set(modName, selector);
76
- }
77
- return MOD_NAME_CACHE.get(modName);
78
- }
79
58
  let __tastyParser = null;
80
59
  function getOrCreateParser() {
81
60
  if (!__tastyParser) {
@@ -747,5 +726,5 @@ function stringifyStyles(styles) {
747
726
  }
748
727
 
749
728
  //#endregion
750
- export { COMPUTE_FUNC_MAP, CUSTOM_UNITS, DIRECTIONS, STATE_OPERATORS, STATE_OPERATOR_LIST, buildAtRuleContext, computeState, customFunc, extendStyles, extractStyles, filterMods, getGlobalFuncs, getGlobalParser, getGlobalPredefinedTokens, getModSelector, getRgbValuesFromRgbaString, hexToRgb, isAdvancedStateToken, normalizeColorTokenValue, parseColor, parseStateNotation, parseStyle, resetGlobalPredefinedTokens, setGlobalPredefinedTokens, strToRgb, stringifyStyles, styleStateMapToStyleStateDataList };
729
+ export { COMPUTE_FUNC_MAP, CUSTOM_UNITS, DIRECTIONS, STATE_OPERATORS, STATE_OPERATOR_LIST, buildAtRuleContext, computeState, customFunc, extendStyles, extractStyles, filterMods, getGlobalFuncs, getGlobalParser, getGlobalPredefinedTokens, getRgbValuesFromRgbaString, hexToRgb, isAdvancedStateToken, normalizeColorTokenValue, parseColor, parseStateNotation, parseStyle, resetGlobalPredefinedTokens, setGlobalPredefinedTokens, strToRgb, stringifyStyles, styleStateMapToStyleStateDataList };
751
730
  //# sourceMappingURL=styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","names":[],"sources":["../../src/utils/styles.ts"],"sourcesContent":["import { StyleParser } from '../parser/parser';\nimport { okhslFunc } from '../plugins/okhsl-plugin';\nimport { createStateParserContext, parseAdvancedState } from '../states';\nimport type { Styles } from '../styles/types';\n\nimport { cacheWrapper } from './cache-wrapper';\nimport { camelToKebab } from './case-converter';\nimport { hslToRgb } from './hsl-to-rgb';\nimport { okhslToRgb } from './okhsl-to-rgb';\n\nimport type { ProcessedStyle, StyleDetails } from '../parser/types';\nimport type {\n AtRuleContext,\n ParsedAdvancedState,\n StateParserContext,\n} from '../states';\n\nexport type StyleValue<T = string> = T | boolean | number | null | undefined;\n\n/**\n * Normalize a color token value.\n * - Boolean `true` is converted to `'transparent'`\n * - Boolean `false` returns `null` (signals the token should be skipped)\n * - Other values are returned as-is\n *\n * @param value - The raw token value\n * @returns Normalized value or null if the token should be skipped\n */\nexport function normalizeColorTokenValue<T>(\n value: T | boolean,\n): T | 'transparent' | null {\n if (value === true) {\n return 'transparent';\n }\n if (value === false) {\n return null;\n }\n return value as T;\n}\n\nexport type StyleValueStateMap<T = string> = Record<\n string,\n StyleValue<T> | '@inherit'\n>;\n\n/**\n * Combined type for style values that can be either a direct value or a state map.\n * Use this for component props that accept style values.\n */\nexport type StylePropValue<T = string> = StyleValue<T> | StyleValueStateMap<T>;\n\nexport type ComputeModel = string | number;\n\nexport type CSSMap = { $?: string | string[] } & Record<\n string,\n string | string[]\n>;\n\nexport type StyleHandlerResult = CSSMap | CSSMap[] | void;\n\nexport type RawStyleHandler = (value: StyleValueStateMap) => StyleHandlerResult;\n\nexport type StyleHandler = RawStyleHandler & {\n __lookupStyles: string[];\n};\n\n/**\n * Handler definition forms for configure() and plugins.\n * - Function only: lookup styles inferred from key name\n * - Single property tuple: ['styleName', handler]\n * - Multi-property tuple: [['style1', 'style2'], handler]\n */\nexport type StyleHandlerDefinition =\n | RawStyleHandler\n | [string, RawStyleHandler]\n | [string[], RawStyleHandler];\n\nexport interface StyleStateData {\n model?: ComputeModel;\n tokens?: string[];\n value: StyleValue | StyleValueStateMap | StyleStateData;\n /** The list of mods to apply */\n mods: string[];\n /** The list of **not** mods to apply (e.g. `:not(:hover)`) */\n notMods: string[];\n /** Advanced states (media queries, container queries, etc.) */\n advancedStates?: ParsedAdvancedState[];\n /** At-rule context for CSS generation */\n atRuleContext?: AtRuleContext;\n /** Own mods for sub-element states (from @own()) - applied to sub-element selector */\n ownMods?: string[];\n /** Negated own mods for sub-element states */\n negatedOwnMods?: string[];\n}\n\nexport interface ParsedColor {\n color?: string;\n name?: string;\n opacity?: number;\n}\n\nexport type StyleStateDataList = StyleStateData[];\n\nexport type StyleStateDataListMap = Record<string, StyleStateDataList>;\n\nexport type StyleMap = Record<string, StyleValue | StyleValueStateMap>;\n\nexport type StyleStateMap = Record<string, StyleStateData>;\n\nconst devMode = process.env.NODE_ENV !== 'production';\n\n// Precompiled regex patterns for parseColor optimization\n// Match var(--name-color...) and extract the name, regardless of fallbacks\nconst COLOR_VAR_PATTERN = /var\\(--([a-z0-9-]+)-color/;\nconst COLOR_VAR_RGB_PATTERN = /var\\(--([a-z0-9-]+)-color-rgb/;\nconst RGB_ALPHA_PATTERN = /\\/\\s*([0-9.]+)\\)/;\nconst SIMPLE_COLOR_PATTERNS = [\n /^#[0-9a-fA-F]{3,8}$/, // Hex colors: #fff, #ffffff, #ffff, #ffffffff\n /^rgb\\(/, // RGB/RGBA functions\n /^hsl\\(/, // HSL/HSLA functions\n /^lch\\(/, // LCH color functions\n /^oklch\\(/, // OKLCH color functions\n /^okhsl\\(/, // OKHSL color functions\n /^var\\(--[a-z0-9-]+-color/, // CSS custom properties for colors\n /^currentColor$/, // CSS currentColor keyword\n /^transparent$/, // CSS transparent keyword\n];\n\n// Rate limiting for dev warnings to avoid spam\nlet colorWarningCount = 0;\nconst MAX_COLOR_WARNINGS = 10;\n\nexport const CUSTOM_UNITS = {\n r: '6px',\n cr: '10px',\n bw: '1px',\n ow: '3px',\n x: '8px',\n fs: 'var(--font-size)',\n lh: 'var(--line-height)',\n sf: function sf(num: number) {\n return `minmax(0, ${num}fr)`;\n },\n};\n\nexport const DIRECTIONS = ['top', 'right', 'bottom', 'left'];\n\nconst MOD_NAME_CACHE = new Map();\n\nexport function getModSelector(modName: string): string {\n if (!MOD_NAME_CACHE.has(modName)) {\n let selector: string;\n\n // Check if it's a shorthand value mod: key=value, key^=value, key$=value, key*=value\n // Supports: key=value, key=\"value\", key='value', and with ^=, $=, *= operators\n const valueModMatch = modName.match(\n /^([a-z][a-z0-9-]*)(\\^=|\\$=|\\*=|=)(.+)$/i,\n );\n if (valueModMatch) {\n const key = valueModMatch[1];\n const operator = valueModMatch[2];\n let value = valueModMatch[3];\n\n // Remove quotes if present\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n // Convert to full attribute selector with the appropriate operator\n selector = `[data-${camelToKebab(key)}${operator}\"${value}\"]`;\n } else if (modName.match(/^[a-z]/)) {\n // Boolean mod: convert camelCase to kebab-case\n selector = `[data-${camelToKebab(modName)}]`;\n } else {\n // Check if it contains :has() with capitalized element names\n if (modName.includes(':has(')) {\n selector = modName.replace(/:has\\(([^)]+)\\)/g, (match, content) => {\n // Validate that combinators have spaces around them\n // Check for capitalized words adjacent to combinators without spaces\n const invalidPattern = /[A-Z][a-z]*[>+~]|[>+~][A-Z][a-z]*/;\n if (invalidPattern.test(content)) {\n console.error(\n `[Tasty] Invalid :has() selector syntax: \"${modName}\"\\n` +\n `Combinators (>, +, ~) must have spaces around them when used with element names.\\n` +\n `Example: Use \":has(Body > Row)\" instead of \":has(Body>Row)\"\\n` +\n `This is a design choice: the parser uses simple whitespace splitting for performance.`,\n );\n }\n\n // Transform capitalized words to [data-element=\"...\"] selectors\n const tokens = content.split(/\\s+/);\n const transformed = tokens.map((token: string) =>\n /^[A-Z]/.test(token) ? `[data-element=\"${token}\"]` : token,\n );\n return `:has(${transformed.join(' ')})`;\n });\n } else {\n // Pass through (e.g., :hover, .class, [attr])\n selector = modName;\n }\n }\n\n MOD_NAME_CACHE.set(modName, selector);\n }\n\n return MOD_NAME_CACHE.get(modName);\n}\n\n// Lazy-initialized to break the circular dependency:\n// parser.ts → classify.ts → utils/styles.ts → parser.ts\nlet __tastyParser: StyleParser | null = null;\n\nfunction getOrCreateParser(): StyleParser {\n if (!__tastyParser) {\n __tastyParser = new StyleParser({ units: CUSTOM_UNITS });\n __tastyParser.setFuncs(__tastyFuncs);\n }\n return __tastyParser;\n}\n\n// Registry for user-provided custom functions that the parser can call.\n// It is updated through the `customFunc` helper exported below.\n// okhsl is registered as a built-in function so it works regardless of\n// tree-shaking or module initialization order.\nconst __tastyFuncs: Record<string, (groups: StyleDetails[]) => string> = {\n okhsl: okhslFunc,\n};\n\nexport function customFunc(\n name: string,\n fn: (groups: StyleDetails[]) => string,\n) {\n __tastyFuncs[name] = fn;\n getOrCreateParser().setFuncs(__tastyFuncs);\n}\n\n/**\n * Get the global StyleParser instance.\n * Used by configure() to apply parser configuration.\n */\nexport function getGlobalParser(): StyleParser {\n return getOrCreateParser();\n}\n\n/**\n * Get the current custom functions registry.\n * Used by configure() to merge with new functions.\n */\nexport function getGlobalFuncs(): Record<\n string,\n (groups: StyleDetails[]) => string\n> {\n return __tastyFuncs;\n}\n\n// ============================================================================\n// Global Predefined Tokens\n// ============================================================================\n\n/**\n * Storage for predefined tokens that are replaced during style parsing.\n * Keys are token names (with $ or # prefix), values are pre-processed CSS values.\n */\nlet __globalPredefinedTokens: Record<string, string> | null = null;\n\n/**\n * Set global predefined tokens.\n * Called from configure() after processing token values.\n * Merges with existing tokens (new tokens override existing ones with same key).\n * Keys are normalized to lowercase (parser lowercases input before classification).\n * @internal\n */\nexport function setGlobalPredefinedTokens(\n tokens: Record<string, string>,\n): void {\n // Normalize keys to lowercase for case-insensitive matching\n const normalizedTokens: Record<string, string> = {};\n for (const [key, value] of Object.entries(tokens)) {\n const lowerKey = key.toLowerCase();\n const lowerValue = value.toLowerCase();\n\n // Warn if trying to use bare #current to define other color tokens\n // #current represents currentcolor which cannot be used as a base for recursive token resolution\n // Note: #current.5 (with opacity) is allowed since it resolves to a concrete color-mix value\n if (lowerKey.startsWith('#') && lowerValue === '#current') {\n console.warn(\n `Tasty: Using #current to define color token \"${key}\" is not supported. ` +\n `The #current token represents currentcolor which cannot be used as a base for other tokens.`,\n );\n continue; // Skip this token\n }\n\n normalizedTokens[lowerKey] = value;\n }\n // Merge with existing tokens (consistent with how states, units, funcs are handled)\n __globalPredefinedTokens = __globalPredefinedTokens\n ? { ...__globalPredefinedTokens, ...normalizedTokens }\n : normalizedTokens;\n // Clear parser cache since token values affect parsing\n getOrCreateParser().clearCache();\n}\n\n/**\n * Get the current global predefined tokens.\n * Returns null if no tokens are configured.\n */\nexport function getGlobalPredefinedTokens(): Record<string, string> | null {\n return __globalPredefinedTokens;\n}\n\n/**\n * Reset global predefined tokens.\n * Used for testing.\n * @internal\n */\nexport function resetGlobalPredefinedTokens(): void {\n __globalPredefinedTokens = null;\n // Clear parser cache since token availability affects parsing\n getOrCreateParser().clearCache();\n}\n\n/**\n *\n * @param {String} value\n * @param {Number} mode\n * @returns {Object<String,String|Array>}\n */\nexport function parseStyle(value: StyleValue): ProcessedStyle {\n let str: string;\n\n if (typeof value === 'string') {\n str = value;\n } else if (typeof value === 'number') {\n str = String(value);\n } else {\n // boolean, null, undefined, objects etc. → empty string\n str = '';\n }\n\n return getOrCreateParser().process(str);\n}\n\n/**\n * Parse color. Find it value, name and opacity.\n * Optimized to avoid heavy parseStyle calls for simple color patterns.\n */\nexport function parseColor(val: string, ignoreError = false): ParsedColor {\n // Early return for non-strings or empty values\n if (typeof val !== 'string') {\n val = String(val ?? '');\n }\n\n val = val.trim();\n if (!val) return {};\n\n // Fast path: Check if it's a simple color pattern that doesn't need full parsing\n const isSimpleColor = SIMPLE_COLOR_PATTERNS.some((pattern) =>\n pattern.test(val),\n );\n\n let firstColor: string;\n if (isSimpleColor) {\n // For simple colors, use the value directly without parsing\n firstColor = val;\n } else {\n const processed = parseStyle(val);\n const extractedColor = processed.groups.find((g) => g.colors.length)\n ?.colors[0];\n\n if (!extractedColor) {\n // Rate-limited warning to avoid spam\n if (!ignoreError && devMode && colorWarningCount < MAX_COLOR_WARNINGS) {\n console.warn('CubeUIKit: unable to parse color:', val);\n colorWarningCount++;\n if (colorWarningCount === MAX_COLOR_WARNINGS) {\n console.warn(\n 'CubeUIKit: color parsing warnings will be suppressed from now on',\n );\n }\n }\n return {};\n }\n\n firstColor = extractedColor;\n }\n\n // Extract color name (if present) from variable pattern using precompiled regex\n let nameMatch = firstColor.match(COLOR_VAR_PATTERN);\n if (!nameMatch) {\n nameMatch = firstColor.match(COLOR_VAR_RGB_PATTERN);\n }\n\n let opacity: number | undefined;\n if (\n firstColor.startsWith('rgb') ||\n firstColor.startsWith('hsl') ||\n firstColor.startsWith('lch') ||\n firstColor.startsWith('oklch') ||\n firstColor.startsWith('okhsl')\n ) {\n const alphaMatch = firstColor.match(RGB_ALPHA_PATTERN);\n if (alphaMatch) {\n const v = parseFloat(alphaMatch[1]);\n if (!isNaN(v)) opacity = v * 100;\n }\n }\n\n return {\n color: firstColor,\n name: nameMatch ? nameMatch[1] : undefined,\n opacity,\n };\n}\n\n/**\n * CSS named color keywords → hex values.\n * Lazy-initialized on first use to avoid up-front cost.\n */\nlet _namedColorHex: Map<string, string> | null = null;\n\nfunction getNamedColorHex(): Map<string, string> {\n if (_namedColorHex) return _namedColorHex;\n _namedColorHex = new Map([\n ['aliceblue', '#f0f8ff'],\n ['antiquewhite', '#faebd7'],\n ['aqua', '#00ffff'],\n ['aquamarine', '#7fffd4'],\n ['azure', '#f0ffff'],\n ['beige', '#f5f5dc'],\n ['bisque', '#ffe4c4'],\n ['black', '#000000'],\n ['blanchedalmond', '#ffebcd'],\n ['blue', '#0000ff'],\n ['blueviolet', '#8a2be2'],\n ['brown', '#a52a2a'],\n ['burlywood', '#deb887'],\n ['cadetblue', '#5f9ea0'],\n ['chartreuse', '#7fff00'],\n ['chocolate', '#d2691e'],\n ['coral', '#ff7f50'],\n ['cornflowerblue', '#6495ed'],\n ['cornsilk', '#fff8dc'],\n ['crimson', '#dc143c'],\n ['cyan', '#00ffff'],\n ['darkblue', '#00008b'],\n ['darkcyan', '#008b8b'],\n ['darkgoldenrod', '#b8860b'],\n ['darkgray', '#a9a9a9'],\n ['darkgreen', '#006400'],\n ['darkgrey', '#a9a9a9'],\n ['darkkhaki', '#bdb76b'],\n ['darkmagenta', '#8b008b'],\n ['darkolivegreen', '#556b2f'],\n ['darkorange', '#ff8c00'],\n ['darkorchid', '#9932cc'],\n ['darkred', '#8b0000'],\n ['darksalmon', '#e9967a'],\n ['darkseagreen', '#8fbc8f'],\n ['darkslateblue', '#483d8b'],\n ['darkslategray', '#2f4f4f'],\n ['darkslategrey', '#2f4f4f'],\n ['darkturquoise', '#00ced1'],\n ['darkviolet', '#9400d3'],\n ['deeppink', '#ff1493'],\n ['deepskyblue', '#00bfff'],\n ['dimgray', '#696969'],\n ['dimgrey', '#696969'],\n ['dodgerblue', '#1e90ff'],\n ['firebrick', '#b22222'],\n ['floralwhite', '#fffaf0'],\n ['forestgreen', '#228b22'],\n ['fuchsia', '#ff00ff'],\n ['gainsboro', '#dcdcdc'],\n ['ghostwhite', '#f8f8ff'],\n ['gold', '#ffd700'],\n ['goldenrod', '#daa520'],\n ['gray', '#808080'],\n ['green', '#008000'],\n ['greenyellow', '#adff2f'],\n ['grey', '#808080'],\n ['honeydew', '#f0fff0'],\n ['hotpink', '#ff69b4'],\n ['indianred', '#cd5c5c'],\n ['indigo', '#4b0082'],\n ['ivory', '#fffff0'],\n ['khaki', '#f0e68c'],\n ['lavender', '#e6e6fa'],\n ['lavenderblush', '#fff0f5'],\n ['lawngreen', '#7cfc00'],\n ['lemonchiffon', '#fffacd'],\n ['lightblue', '#add8e6'],\n ['lightcoral', '#f08080'],\n ['lightcyan', '#e0ffff'],\n ['lightgoldenrodyellow', '#fafad2'],\n ['lightgray', '#d3d3d3'],\n ['lightgreen', '#90ee90'],\n ['lightgrey', '#d3d3d3'],\n ['lightpink', '#ffb6c1'],\n ['lightsalmon', '#ffa07a'],\n ['lightseagreen', '#20b2aa'],\n ['lightskyblue', '#87cefa'],\n ['lightslategray', '#778899'],\n ['lightslategrey', '#778899'],\n ['lightsteelblue', '#b0c4de'],\n ['lightyellow', '#ffffe0'],\n ['lime', '#00ff00'],\n ['limegreen', '#32cd32'],\n ['linen', '#faf0e6'],\n ['magenta', '#ff00ff'],\n ['maroon', '#800000'],\n ['mediumaquamarine', '#66cdaa'],\n ['mediumblue', '#0000cd'],\n ['mediumorchid', '#ba55d3'],\n ['mediumpurple', '#9370db'],\n ['mediumseagreen', '#3cb371'],\n ['mediumslateblue', '#7b68ee'],\n ['mediumspringgreen', '#00fa9a'],\n ['mediumturquoise', '#48d1cc'],\n ['mediumvioletred', '#c71585'],\n ['midnightblue', '#191970'],\n ['mintcream', '#f5fffa'],\n ['mistyrose', '#ffe4e1'],\n ['moccasin', '#ffe4b5'],\n ['navajowhite', '#ffdead'],\n ['navy', '#000080'],\n ['oldlace', '#fdf5e6'],\n ['olive', '#808000'],\n ['olivedrab', '#6b8e23'],\n ['orange', '#ffa500'],\n ['orangered', '#ff4500'],\n ['orchid', '#da70d6'],\n ['palegoldenrod', '#eee8aa'],\n ['palegreen', '#98fb98'],\n ['paleturquoise', '#afeeee'],\n ['palevioletred', '#db7093'],\n ['papayawhip', '#ffefd5'],\n ['peachpuff', '#ffdab9'],\n ['peru', '#cd853f'],\n ['pink', '#ffc0cb'],\n ['plum', '#dda0dd'],\n ['powderblue', '#b0e0e6'],\n ['purple', '#800080'],\n ['rebeccapurple', '#663399'],\n ['red', '#ff0000'],\n ['rosybrown', '#bc8f8f'],\n ['royalblue', '#4169e1'],\n ['saddlebrown', '#8b4513'],\n ['salmon', '#fa8072'],\n ['sandybrown', '#f4a460'],\n ['seagreen', '#2e8b57'],\n ['seashell', '#fff5ee'],\n ['sienna', '#a0522d'],\n ['silver', '#c0c0c0'],\n ['skyblue', '#87ceeb'],\n ['slateblue', '#6a5acd'],\n ['slategray', '#708090'],\n ['slategrey', '#708090'],\n ['snow', '#fffafa'],\n ['springgreen', '#00ff7f'],\n ['steelblue', '#4682b4'],\n ['tan', '#d2b48c'],\n ['teal', '#008080'],\n ['thistle', '#d8bfd8'],\n ['tomato', '#ff6347'],\n ['turquoise', '#40e0d0'],\n ['violet', '#ee82ee'],\n ['wheat', '#f5deb3'],\n ['white', '#ffffff'],\n ['whitesmoke', '#f5f5f5'],\n ['yellow', '#ffff00'],\n ['yellowgreen', '#9acd32'],\n ]);\n return _namedColorHex;\n}\n\nexport function strToRgb(\n color: string,\n _ignoreAlpha = false,\n): string | null | undefined {\n if (!color) return undefined;\n\n if (color.startsWith('rgb')) return color;\n\n if (color.startsWith('#')) return hexToRgb(color);\n\n if (color.startsWith('okhsl(')) return okhslToRgb(color);\n\n if (color.startsWith('hsl')) return hslToRgb(color);\n\n // Named CSS colors\n const namedHex = getNamedColorHex().get(color.toLowerCase());\n if (namedHex) return hexToRgb(namedHex);\n\n return null;\n}\n\n/**\n * Extract RGB values from an rgb()/rgba() string.\n * Supports all modern CSS syntax variations:\n * - Comma-separated: rgb(255, 128, 0)\n * - Space-separated: rgb(255 128 0)\n * - Fractional: rgb(128.5, 64.3, 32.1)\n * - Percentages: rgb(50%, 25%, 75%)\n * - Slash alpha notation: rgb(255 128 0 / 0.5)\n *\n * Returns array of RGB values (0-255 range), converting percentages as needed.\n */\nexport function getRgbValuesFromRgbaString(str: string): number[] {\n // Extract content inside rgb()/rgba()\n const match = str.match(/rgba?\\(([^)]+)\\)/i);\n if (!match) return [];\n\n const inner = match[1].trim();\n // Split by slash first (for alpha), then handle color components\n const [colorPart] = inner.split('/');\n // Split by comma or whitespace\n const parts = colorPart\n .trim()\n .split(/[,\\s]+/)\n .filter(Boolean);\n\n return parts.slice(0, 3).map((part) => {\n part = part.trim();\n if (part.endsWith('%')) {\n // Convert percentage to 0-255 range\n return (parseFloat(part) / 100) * 255;\n }\n return parseFloat(part);\n });\n}\n\nexport function hexToRgb(hex: string): string | null {\n const matched = hex\n .replace(\n /^#?([a-f\\d])([a-f\\d])([a-f\\d])$/i,\n (_m: string, r: string, g: string, b: string) =>\n '#' + r + r + g + g + b + b,\n )\n .substring(1)\n .match(/.{2}/g);\n\n if (!matched) return null;\n\n const rgba = matched.map(\n (x: string, i: number) => parseInt(x, 16) * (i === 3 ? 1 / 255 : 1),\n );\n\n if (rgba.some((v) => Number.isNaN(v))) {\n return null;\n }\n\n if (rgba.length >= 3) {\n return `rgb(${rgba.slice(0, 3).join(' ')}${rgba.length > 3 ? ` / ${rgba[3]}` : ''})`;\n }\n\n return null;\n}\n\nexport function filterMods(mods: string[], allowedMods: string[]): string[] {\n return mods.filter((mod) => allowedMods.includes(mod));\n}\n\nexport function extendStyles(\n defaultStyles?: Record<string, unknown> | null,\n newStyles?: Record<string, unknown> | null,\n): Record<string, unknown> {\n let styles: Record<string, unknown> = {};\n\n if (!defaultStyles) {\n if (!newStyles) {\n return styles;\n }\n } else {\n styles = Object.assign({}, defaultStyles);\n }\n\n if (newStyles) {\n Object.keys(newStyles).forEach((key) => {\n if (newStyles[key] != null) {\n styles[key] = newStyles[key];\n }\n });\n }\n\n return styles;\n}\n\n/**\n * Split properties into style and non-style properties.\n * @param props - Component prop map.\n * @param [styleList] - List of all style properties.\n * @param [defaultStyles] - Default style map of the component.\n * @param [propMap] - Props to style alias map.\n * @param [ignoreList] - A list of properties to ignore.\n */\nexport function extractStyles(\n props: Record<string, unknown>,\n styleList: readonly string[] = [],\n defaultStyles?: Styles,\n propMap?: Record<string, string>,\n ignoreList: readonly string[] = [],\n): Styles {\n const styles: Styles = {\n ...defaultStyles,\n ...(ignoreList.includes('styles')\n ? undefined\n : props.styles && typeof props.styles === 'object'\n ? (props.styles as Styles)\n : undefined),\n };\n\n Object.keys(props).forEach((prop) => {\n const propName = propMap ? propMap[prop] || prop : prop;\n const value = props[prop];\n\n if (ignoreList && ignoreList.includes(prop)) {\n // do nothing\n } else if (styleList.includes(propName)) {\n styles[propName] = value as Styles[keyof Styles];\n }\n }, {});\n\n return styles;\n}\n\n// Enhanced regex that includes advanced state patterns\n// Matches: operators, parentheses, @media(...), @(...), @root(...), @own(...), @starting, @predefined,\n// value mods, boolean mods, pseudo-classes, classes, attribute selectors\nconst STATES_REGEXP =\n /([&|!^])|([()])|(@media:[a-z]+)|(@media\\([^)]+\\))|(@root\\([^)]+\\))|(@own\\([^)]+\\))|(@\\([^)]+\\))|(@starting)|(@[A-Za-z][A-Za-z0-9-]*)|([a-z][a-z0-9-]+=(?:\"[^\"]*\"|'[^']*'|[^\\s&|!^()]+))|([a-z][a-z0-9-]+)|(:[a-z][a-z0-9-]+\\([^)]+\\)|:[a-z][a-z0-9-]+)|(\\.[a-z][a-z0-9-]+)|(\\[[^\\]]+])/gi;\n\n/**\n * Check if a token is an advanced state (starts with @)\n */\nexport function isAdvancedStateToken(token: string): boolean {\n return token.startsWith('@') || token.startsWith('!@');\n}\nexport const STATE_OPERATORS = {\n NOT: '!',\n AND: '&',\n OR: '|',\n XOR: '^',\n};\n\nexport const STATE_OPERATOR_LIST = ['!', '&', '|', '^'];\n\n/**\n * Convert state notation tokens to a compute model (string, or nested [op, lhs, rhs]).\n */\nfunction convertTokensToComputeUnits(tokens: unknown[]): unknown {\n if (tokens.length === 1) {\n return tokens[0];\n }\n\n const hasLength = (x: unknown): x is string | unknown[] =>\n typeof x === 'string' || Array.isArray(x);\n\n STATE_OPERATOR_LIST.forEach((operator) => {\n let i;\n\n while ((i = tokens.indexOf(operator)) !== -1) {\n const token = tokens[i];\n\n if (token === '!') {\n const next = tokens[i + 1];\n if (next !== undefined && hasLength(next) && next.length !== 1) {\n tokens.splice(i, 2, ['!', next]);\n } else {\n tokens.splice(i, 1);\n }\n } else {\n const prev = tokens[i - 1];\n const next = tokens[i + 1];\n if (\n prev !== undefined &&\n next !== undefined &&\n hasLength(prev) &&\n hasLength(next) &&\n prev.length !== 1 &&\n next.length !== 1\n ) {\n tokens.splice(i - 1, 3, [token, prev, next]);\n } else {\n tokens.splice(i, 1);\n }\n }\n }\n });\n\n return tokens.length === 1 ? tokens[0] : tokens;\n}\n\n/**\n * Replace commas with | only outside of parentheses.\n * This preserves commas in advanced states like @(card, w < 600px)\n */\nfunction replaceCommasOutsideParens(str: string): string {\n let result = '';\n let depth = 0;\n\n for (const char of str) {\n if (char === '(') {\n depth++;\n result += char;\n } else if (char === ')') {\n depth--;\n result += char;\n } else if (char === ',' && depth === 0) {\n // Only replace commas at the top level (outside parentheses)\n result += '|';\n } else {\n result += char;\n }\n }\n\n return result;\n}\n\n/**\n * Parse state notation and return tokens, modifiers and compute model.\n */\nfunction parseStateNotationInner(\n notation: string,\n value: StyleValue | StyleValueStateMap | StyleStateData,\n): StyleStateData {\n const tokens = replaceCommasOutsideParens(notation).match(STATES_REGEXP);\n\n if (!tokens || !tokens.length) {\n return {\n model: undefined,\n mods: [],\n notMods: [],\n tokens: [],\n value,\n };\n } else if (tokens.length === 1) {\n return {\n model: tokens[0],\n mods: tokens.slice(0),\n notMods: [],\n tokens,\n value,\n };\n }\n\n const mods: string[] = [];\n\n const operations: unknown[][] = [[]];\n let list = operations[0];\n let position = 0;\n let operation: unknown[];\n\n tokens.forEach((token) => {\n switch (token) {\n case '(':\n operation = [];\n position++;\n list = operations[position] = operation;\n break;\n case ')':\n position--;\n operations[position].push(\n convertTokensToComputeUnits(list as unknown[]),\n );\n list = operations[position];\n break;\n default:\n if (token.length > 1) {\n if (!mods.includes(token)) {\n mods.push(token);\n }\n }\n list.push(token);\n }\n });\n\n while (position) {\n position--;\n operations[position].push(convertTokensToComputeUnits(list as unknown[]));\n list = operations[position];\n }\n\n return {\n tokens,\n mods,\n notMods: [],\n model: convertTokensToComputeUnits(operations[0] as unknown[]) as\n | ComputeModel\n | undefined,\n value,\n };\n}\n\nexport const parseStateNotation = cacheWrapper(parseStateNotationInner);\n\n/**\n * Build an AtRuleContext from parsed advanced states\n */\nexport function buildAtRuleContext(\n advancedStates: ParsedAdvancedState[],\n negatedStates: Set<string>,\n): AtRuleContext | undefined {\n if (advancedStates.length === 0) return undefined;\n\n const ctx: AtRuleContext = {};\n\n for (const state of advancedStates) {\n const isNegated = negatedStates.has(state.raw);\n\n switch (state.type) {\n case 'media': {\n if (!ctx.media) ctx.media = [];\n let mediaCondition = '';\n\n if (state.mediaType) {\n // @media:print, @media:screen, etc.\n mediaCondition = state.mediaType;\n } else if (state.condition) {\n // @media(width < 920px)\n mediaCondition = `(${state.condition})`;\n }\n\n if (mediaCondition) {\n if (isNegated) {\n ctx.media.push(`not ${mediaCondition}`);\n } else {\n ctx.media.push(mediaCondition);\n }\n }\n break;\n }\n\n case 'container': {\n if (!ctx.container) ctx.container = [];\n let condition = state.condition;\n if (isNegated) {\n condition = `not (${condition})`;\n }\n ctx.container.push({\n name: state.containerName,\n condition,\n });\n break;\n }\n\n case 'root': {\n if (!ctx.rootStates) ctx.rootStates = [];\n // Parse the condition to generate the proper selector\n const rootSelector = buildRootSelector(state.condition, isNegated);\n ctx.rootStates.push(rootSelector);\n break;\n }\n\n case 'starting': {\n if (!isNegated) {\n ctx.startingStyle = true;\n }\n break;\n }\n\n // 'own' and 'predefined' are handled differently (selector-based, not at-rule)\n // 'modifier' is a regular state\n }\n }\n\n // Return undefined if no at-rules were added\n if (\n !ctx.media?.length &&\n !ctx.container?.length &&\n !ctx.rootStates?.length &&\n !ctx.startingStyle\n ) {\n return undefined;\n }\n\n return ctx;\n}\n\n/**\n * Build a root state selector from a condition\n */\nfunction buildRootSelector(condition: string, isNegated: boolean): string {\n // Handle different condition formats:\n // - theme=dark -> [data-theme=\"dark\"]\n // - .className -> .className\n // - [attr] -> [attr]\n // - booleanMod -> [data-boolean-mod]\n\n let selector: string;\n\n if (condition.startsWith('.')) {\n // Class selector\n selector = condition;\n } else if (condition.startsWith('[')) {\n // Attribute selector\n selector = condition;\n } else if (condition.includes('=')) {\n // Value mod: theme=dark -> [data-theme=\"dark\"]\n const [key, value] = condition.split('=');\n selector = `[data-${camelToKebab(key.trim())}=\"${value.trim()}\"]`;\n } else {\n // Boolean mod: camelCase -> [data-camel-case]\n selector = `[data-${camelToKebab(condition)}]`;\n }\n\n if (isNegated) {\n return `:not(${selector})`;\n }\n return selector;\n}\n\n/**\n * Parse state notation and return tokens, modifiers and compute model.\n * Enhanced to detect and extract advanced states.\n */\nexport function styleStateMapToStyleStateDataList(\n styleStateMap: StyleStateMap | StyleValue | StyleValueStateMap,\n parserContext?: StateParserContext,\n): { states: StyleStateDataList; mods: string[]; hasAdvancedStates: boolean } {\n if (typeof styleStateMap !== 'object' || !styleStateMap) {\n return {\n states: [\n {\n model: undefined,\n mods: [],\n notMods: [],\n value: styleStateMap,\n },\n ],\n mods: [],\n hasAdvancedStates: false,\n };\n }\n\n const stateDataList: StyleStateDataList = [];\n let hasAdvancedStates = false;\n\n Object.keys(styleStateMap).forEach((stateNotation) => {\n const state = parseStateNotation(\n stateNotation,\n styleStateMap[stateNotation],\n );\n\n // Check if this state contains any advanced states\n const advancedStates: ParsedAdvancedState[] = [];\n const negatedAdvancedStates = new Set<string>();\n const regularMods: string[] = [];\n const ownMods: string[] = [];\n const negatedOwnMods: string[] = [];\n\n // Scan tokens for advanced states\n if (state.tokens) {\n let isNegated = false;\n for (const token of state.tokens) {\n if (token === '!') {\n isNegated = true;\n continue;\n }\n\n if (isAdvancedStateToken(token)) {\n hasAdvancedStates = true;\n const ctx = parserContext || createStateParserContext(undefined);\n const parsed = parseAdvancedState(token, ctx);\n advancedStates.push(parsed);\n\n // Handle @own states specially - extract condition as ownMod\n if (parsed.type === 'own' && parsed.condition) {\n if (isNegated) {\n negatedOwnMods.push(parsed.condition);\n } else {\n ownMods.push(parsed.condition);\n }\n } else if (isNegated) {\n negatedAdvancedStates.add(token);\n }\n isNegated = false;\n } else if (\n token.length > 1 &&\n !['&', '|', '^', '(', ')'].includes(token)\n ) {\n regularMods.push(token);\n isNegated = false;\n } else {\n isNegated = false;\n }\n }\n }\n\n // If there are advanced states, build the atRuleContext\n if (advancedStates.length > 0) {\n state.advancedStates = advancedStates;\n state.atRuleContext = buildAtRuleContext(\n advancedStates,\n negatedAdvancedStates,\n );\n // Filter mods to only include regular mods (not advanced states)\n state.mods = regularMods;\n }\n\n // Store own mods for sub-element selector generation\n if (ownMods.length > 0) {\n state.ownMods = ownMods;\n }\n if (negatedOwnMods.length > 0) {\n state.negatedOwnMods = negatedOwnMods;\n }\n\n stateDataList.push(state);\n });\n\n stateDataList.reverse();\n\n let initialState;\n\n const allMods: string[] = stateDataList.reduce((all: string[], state) => {\n if (!state.mods.length && !state.advancedStates?.length) {\n initialState = state;\n } else {\n state.mods.forEach((mod) => {\n if (!all.includes(mod)) {\n all.push(mod);\n }\n });\n }\n\n return all;\n }, []);\n\n if (!initialState) {\n stateDataList.push({\n mods: [],\n notMods: allMods,\n value: true,\n });\n }\n\n return { states: stateDataList, mods: allMods, hasAdvancedStates };\n}\n\nexport const COMPUTE_FUNC_MAP: Record<\n string,\n (a: unknown, b?: unknown) => unknown\n> = {\n '!': (a: unknown) => !a,\n '^': (a: unknown, b?: unknown) => (a && !b) || (!a && b),\n '|': (a: unknown, b?: unknown) => a || b,\n '&': (a: unknown, b?: unknown) => a && b,\n};\n\n/**\n * Compute a result based on a model and incoming map.\n */\nexport function computeState(\n computeModel: ComputeModel,\n valueMap:\n | (number | boolean)[]\n | Record<string, boolean>\n | ((...args: unknown[]) => unknown),\n) {\n if (!computeModel) return true;\n\n const map = valueMap as Record<string | number, unknown>;\n\n if (!Array.isArray(computeModel)) {\n if (typeof valueMap === 'function') {\n return !!valueMap(computeModel);\n } else {\n return !!map[computeModel];\n }\n }\n\n const func = COMPUTE_FUNC_MAP[computeModel[0]];\n\n if (!func) {\n console.warn(\n 'CubeUIKit: unexpected compute method in the model',\n computeModel,\n );\n // return false;\n }\n\n let a: unknown = computeModel[1];\n\n if (typeof a === 'object') {\n a = !!computeState(a as unknown as ComputeModel, valueMap);\n } else if (typeof valueMap === 'function') {\n a = !!valueMap(a);\n } else {\n a = !!map[a as string | number];\n }\n\n if (computeModel.length === 2) {\n return func(a);\n }\n\n let b: unknown = computeModel[2];\n\n if (typeof b === 'object') {\n b = !!computeState(b as unknown as ComputeModel, valueMap);\n } else if (typeof valueMap === 'function') {\n b = !!valueMap(b);\n } else {\n b = !!map[b as string | number];\n }\n\n return !!func(a, b);\n}\n\nconst _innerCache = new WeakMap();\n\nexport function stringifyStyles(styles: unknown): string {\n if (styles == null || typeof styles !== 'object') return '';\n const obj = styles as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const parts: string[] = [];\n for (const k of keys) {\n const v = obj[k];\n if (v === undefined || typeof v === 'function' || typeof v === 'symbol')\n continue;\n\n const c0 = k.charCodeAt(0);\n const needsInnerSort =\n ((c0 >= 65 && c0 <= 90) || c0 === 38) &&\n v &&\n typeof v === 'object' &&\n !Array.isArray(v);\n\n let sv: string;\n if (needsInnerSort) {\n sv = _innerCache.get(v);\n if (sv === undefined) {\n const innerObj = v as Record<string, unknown>;\n const innerKeys = Object.keys(innerObj).sort();\n const innerParts: string[] = [];\n for (const ik of innerKeys) {\n const ivs = JSON.stringify(innerObj[ik]);\n if (ivs !== undefined)\n innerParts.push(JSON.stringify(ik) + ':' + ivs);\n }\n sv = '{' + innerParts.join(',') + '}';\n _innerCache.set(v, sv);\n }\n } else {\n sv = JSON.stringify(v);\n }\n parts.push(JSON.stringify(k) + ':' + sv);\n }\n return '{' + parts.join(',') + '}';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"styles.js","names":[],"sources":["../../src/utils/styles.ts"],"sourcesContent":["import { StyleParser } from '../parser/parser';\nimport { okhslFunc } from '../plugins/okhsl-plugin';\nimport { createStateParserContext, parseAdvancedState } from '../states';\nimport type { Styles } from '../styles/types';\n\nimport { cacheWrapper } from './cache-wrapper';\nimport { camelToKebab } from './case-converter';\nimport { hslToRgb } from './hsl-to-rgb';\nimport { okhslToRgb } from './okhsl-to-rgb';\n\nimport type { ProcessedStyle, StyleDetails } from '../parser/types';\nimport type {\n AtRuleContext,\n ParsedAdvancedState,\n StateParserContext,\n} from '../states';\n\nexport type StyleValue<T = string> = T | boolean | number | null | undefined;\n\n/**\n * Normalize a color token value.\n * - Boolean `true` is converted to `'transparent'`\n * - Boolean `false` returns `null` (signals the token should be skipped)\n * - Other values are returned as-is\n *\n * @param value - The raw token value\n * @returns Normalized value or null if the token should be skipped\n */\nexport function normalizeColorTokenValue<T>(\n value: T | boolean,\n): T | 'transparent' | null {\n if (value === true) {\n return 'transparent';\n }\n if (value === false) {\n return null;\n }\n return value as T;\n}\n\nexport type StyleValueStateMap<T = string> = Record<\n string,\n StyleValue<T> | '@inherit'\n>;\n\n/**\n * Combined type for style values that can be either a direct value or a state map.\n * Use this for component props that accept style values.\n */\nexport type StylePropValue<T = string> = StyleValue<T> | StyleValueStateMap<T>;\n\nexport type ComputeModel = string | number;\n\nexport type CSSMap = { $?: string | string[] } & Record<\n string,\n string | string[]\n>;\n\nexport type StyleHandlerResult = CSSMap | CSSMap[] | void;\n\nexport type RawStyleHandler = (value: StyleValueStateMap) => StyleHandlerResult;\n\nexport type StyleHandler = RawStyleHandler & {\n __lookupStyles: string[];\n};\n\n/**\n * Handler definition forms for configure() and plugins.\n * - Function only: lookup styles inferred from key name\n * - Single property tuple: ['styleName', handler]\n * - Multi-property tuple: [['style1', 'style2'], handler]\n */\nexport type StyleHandlerDefinition =\n | RawStyleHandler\n | [string, RawStyleHandler]\n | [string[], RawStyleHandler];\n\nexport interface StyleStateData {\n model?: ComputeModel;\n tokens?: string[];\n value: StyleValue | StyleValueStateMap | StyleStateData;\n /** The list of mods to apply */\n mods: string[];\n /** The list of **not** mods to apply (e.g. `:not(:hover)`) */\n notMods: string[];\n /** Advanced states (media queries, container queries, etc.) */\n advancedStates?: ParsedAdvancedState[];\n /** At-rule context for CSS generation */\n atRuleContext?: AtRuleContext;\n /** Own mods for sub-element states (from @own()) - applied to sub-element selector */\n ownMods?: string[];\n /** Negated own mods for sub-element states */\n negatedOwnMods?: string[];\n}\n\nexport interface ParsedColor {\n color?: string;\n name?: string;\n opacity?: number;\n}\n\nexport type StyleStateDataList = StyleStateData[];\n\nexport type StyleStateDataListMap = Record<string, StyleStateDataList>;\n\nexport type StyleMap = Record<string, StyleValue | StyleValueStateMap>;\n\nexport type StyleStateMap = Record<string, StyleStateData>;\n\nconst devMode = process.env.NODE_ENV !== 'production';\n\n// Precompiled regex patterns for parseColor optimization\n// Match var(--name-color...) and extract the name, regardless of fallbacks\nconst COLOR_VAR_PATTERN = /var\\(--([a-z0-9-]+)-color/;\nconst COLOR_VAR_RGB_PATTERN = /var\\(--([a-z0-9-]+)-color-rgb/;\nconst RGB_ALPHA_PATTERN = /\\/\\s*([0-9.]+)\\)/;\nconst SIMPLE_COLOR_PATTERNS = [\n /^#[0-9a-fA-F]{3,8}$/, // Hex colors: #fff, #ffffff, #ffff, #ffffffff\n /^rgb\\(/, // RGB/RGBA functions\n /^hsl\\(/, // HSL/HSLA functions\n /^lch\\(/, // LCH color functions\n /^oklch\\(/, // OKLCH color functions\n /^okhsl\\(/, // OKHSL color functions\n /^var\\(--[a-z0-9-]+-color/, // CSS custom properties for colors\n /^currentColor$/, // CSS currentColor keyword\n /^transparent$/, // CSS transparent keyword\n];\n\n// Rate limiting for dev warnings to avoid spam\nlet colorWarningCount = 0;\nconst MAX_COLOR_WARNINGS = 10;\n\nexport const CUSTOM_UNITS = {\n r: '6px',\n cr: '10px',\n bw: '1px',\n ow: '3px',\n x: '8px',\n fs: 'var(--font-size)',\n lh: 'var(--line-height)',\n sf: function sf(num: number) {\n return `minmax(0, ${num}fr)`;\n },\n};\n\nexport const DIRECTIONS = ['top', 'right', 'bottom', 'left'];\n\n// Lazy-initialized to break the circular dependency:\n// parser.ts → classify.ts → utils/styles.ts → parser.ts\nlet __tastyParser: StyleParser | null = null;\n\nfunction getOrCreateParser(): StyleParser {\n if (!__tastyParser) {\n __tastyParser = new StyleParser({ units: CUSTOM_UNITS });\n __tastyParser.setFuncs(__tastyFuncs);\n }\n return __tastyParser;\n}\n\n// Registry for user-provided custom functions that the parser can call.\n// It is updated through the `customFunc` helper exported below.\n// okhsl is registered as a built-in function so it works regardless of\n// tree-shaking or module initialization order.\nconst __tastyFuncs: Record<string, (groups: StyleDetails[]) => string> = {\n okhsl: okhslFunc,\n};\n\nexport function customFunc(\n name: string,\n fn: (groups: StyleDetails[]) => string,\n) {\n __tastyFuncs[name] = fn;\n getOrCreateParser().setFuncs(__tastyFuncs);\n}\n\n/**\n * Get the global StyleParser instance.\n * Used by configure() to apply parser configuration.\n */\nexport function getGlobalParser(): StyleParser {\n return getOrCreateParser();\n}\n\n/**\n * Get the current custom functions registry.\n * Used by configure() to merge with new functions.\n */\nexport function getGlobalFuncs(): Record<\n string,\n (groups: StyleDetails[]) => string\n> {\n return __tastyFuncs;\n}\n\n// ============================================================================\n// Global Predefined Tokens\n// ============================================================================\n\n/**\n * Storage for predefined tokens that are replaced during style parsing.\n * Keys are token names (with $ or # prefix), values are pre-processed CSS values.\n */\nlet __globalPredefinedTokens: Record<string, string> | null = null;\n\n/**\n * Set global predefined tokens.\n * Called from configure() after processing token values.\n * Merges with existing tokens (new tokens override existing ones with same key).\n * Keys are normalized to lowercase (parser lowercases input before classification).\n * @internal\n */\nexport function setGlobalPredefinedTokens(\n tokens: Record<string, string>,\n): void {\n // Normalize keys to lowercase for case-insensitive matching\n const normalizedTokens: Record<string, string> = {};\n for (const [key, value] of Object.entries(tokens)) {\n const lowerKey = key.toLowerCase();\n const lowerValue = value.toLowerCase();\n\n // Warn if trying to use bare #current to define other color tokens\n // #current represents currentcolor which cannot be used as a base for recursive token resolution\n // Note: #current.5 (with opacity) is allowed since it resolves to a concrete color-mix value\n if (lowerKey.startsWith('#') && lowerValue === '#current') {\n console.warn(\n `Tasty: Using #current to define color token \"${key}\" is not supported. ` +\n `The #current token represents currentcolor which cannot be used as a base for other tokens.`,\n );\n continue; // Skip this token\n }\n\n normalizedTokens[lowerKey] = value;\n }\n // Merge with existing tokens (consistent with how states, units, funcs are handled)\n __globalPredefinedTokens = __globalPredefinedTokens\n ? { ...__globalPredefinedTokens, ...normalizedTokens }\n : normalizedTokens;\n // Clear parser cache since token values affect parsing\n getOrCreateParser().clearCache();\n}\n\n/**\n * Get the current global predefined tokens.\n * Returns null if no tokens are configured.\n */\nexport function getGlobalPredefinedTokens(): Record<string, string> | null {\n return __globalPredefinedTokens;\n}\n\n/**\n * Reset global predefined tokens.\n * Used for testing.\n * @internal\n */\nexport function resetGlobalPredefinedTokens(): void {\n __globalPredefinedTokens = null;\n // Clear parser cache since token availability affects parsing\n getOrCreateParser().clearCache();\n}\n\n/**\n *\n * @param {String} value\n * @param {Number} mode\n * @returns {Object<String,String|Array>}\n */\nexport function parseStyle(value: StyleValue): ProcessedStyle {\n let str: string;\n\n if (typeof value === 'string') {\n str = value;\n } else if (typeof value === 'number') {\n str = String(value);\n } else {\n // boolean, null, undefined, objects etc. → empty string\n str = '';\n }\n\n return getOrCreateParser().process(str);\n}\n\n/**\n * Parse color. Find it value, name and opacity.\n * Optimized to avoid heavy parseStyle calls for simple color patterns.\n */\nexport function parseColor(val: string, ignoreError = false): ParsedColor {\n // Early return for non-strings or empty values\n if (typeof val !== 'string') {\n val = String(val ?? '');\n }\n\n val = val.trim();\n if (!val) return {};\n\n // Fast path: Check if it's a simple color pattern that doesn't need full parsing\n const isSimpleColor = SIMPLE_COLOR_PATTERNS.some((pattern) =>\n pattern.test(val),\n );\n\n let firstColor: string;\n if (isSimpleColor) {\n // For simple colors, use the value directly without parsing\n firstColor = val;\n } else {\n const processed = parseStyle(val);\n const extractedColor = processed.groups.find((g) => g.colors.length)\n ?.colors[0];\n\n if (!extractedColor) {\n // Rate-limited warning to avoid spam\n if (!ignoreError && devMode && colorWarningCount < MAX_COLOR_WARNINGS) {\n console.warn('CubeUIKit: unable to parse color:', val);\n colorWarningCount++;\n if (colorWarningCount === MAX_COLOR_WARNINGS) {\n console.warn(\n 'CubeUIKit: color parsing warnings will be suppressed from now on',\n );\n }\n }\n return {};\n }\n\n firstColor = extractedColor;\n }\n\n // Extract color name (if present) from variable pattern using precompiled regex\n let nameMatch = firstColor.match(COLOR_VAR_PATTERN);\n if (!nameMatch) {\n nameMatch = firstColor.match(COLOR_VAR_RGB_PATTERN);\n }\n\n let opacity: number | undefined;\n if (\n firstColor.startsWith('rgb') ||\n firstColor.startsWith('hsl') ||\n firstColor.startsWith('lch') ||\n firstColor.startsWith('oklch') ||\n firstColor.startsWith('okhsl')\n ) {\n const alphaMatch = firstColor.match(RGB_ALPHA_PATTERN);\n if (alphaMatch) {\n const v = parseFloat(alphaMatch[1]);\n if (!isNaN(v)) opacity = v * 100;\n }\n }\n\n return {\n color: firstColor,\n name: nameMatch ? nameMatch[1] : undefined,\n opacity,\n };\n}\n\n/**\n * CSS named color keywords → hex values.\n * Lazy-initialized on first use to avoid up-front cost.\n */\nlet _namedColorHex: Map<string, string> | null = null;\n\nfunction getNamedColorHex(): Map<string, string> {\n if (_namedColorHex) return _namedColorHex;\n _namedColorHex = new Map([\n ['aliceblue', '#f0f8ff'],\n ['antiquewhite', '#faebd7'],\n ['aqua', '#00ffff'],\n ['aquamarine', '#7fffd4'],\n ['azure', '#f0ffff'],\n ['beige', '#f5f5dc'],\n ['bisque', '#ffe4c4'],\n ['black', '#000000'],\n ['blanchedalmond', '#ffebcd'],\n ['blue', '#0000ff'],\n ['blueviolet', '#8a2be2'],\n ['brown', '#a52a2a'],\n ['burlywood', '#deb887'],\n ['cadetblue', '#5f9ea0'],\n ['chartreuse', '#7fff00'],\n ['chocolate', '#d2691e'],\n ['coral', '#ff7f50'],\n ['cornflowerblue', '#6495ed'],\n ['cornsilk', '#fff8dc'],\n ['crimson', '#dc143c'],\n ['cyan', '#00ffff'],\n ['darkblue', '#00008b'],\n ['darkcyan', '#008b8b'],\n ['darkgoldenrod', '#b8860b'],\n ['darkgray', '#a9a9a9'],\n ['darkgreen', '#006400'],\n ['darkgrey', '#a9a9a9'],\n ['darkkhaki', '#bdb76b'],\n ['darkmagenta', '#8b008b'],\n ['darkolivegreen', '#556b2f'],\n ['darkorange', '#ff8c00'],\n ['darkorchid', '#9932cc'],\n ['darkred', '#8b0000'],\n ['darksalmon', '#e9967a'],\n ['darkseagreen', '#8fbc8f'],\n ['darkslateblue', '#483d8b'],\n ['darkslategray', '#2f4f4f'],\n ['darkslategrey', '#2f4f4f'],\n ['darkturquoise', '#00ced1'],\n ['darkviolet', '#9400d3'],\n ['deeppink', '#ff1493'],\n ['deepskyblue', '#00bfff'],\n ['dimgray', '#696969'],\n ['dimgrey', '#696969'],\n ['dodgerblue', '#1e90ff'],\n ['firebrick', '#b22222'],\n ['floralwhite', '#fffaf0'],\n ['forestgreen', '#228b22'],\n ['fuchsia', '#ff00ff'],\n ['gainsboro', '#dcdcdc'],\n ['ghostwhite', '#f8f8ff'],\n ['gold', '#ffd700'],\n ['goldenrod', '#daa520'],\n ['gray', '#808080'],\n ['green', '#008000'],\n ['greenyellow', '#adff2f'],\n ['grey', '#808080'],\n ['honeydew', '#f0fff0'],\n ['hotpink', '#ff69b4'],\n ['indianred', '#cd5c5c'],\n ['indigo', '#4b0082'],\n ['ivory', '#fffff0'],\n ['khaki', '#f0e68c'],\n ['lavender', '#e6e6fa'],\n ['lavenderblush', '#fff0f5'],\n ['lawngreen', '#7cfc00'],\n ['lemonchiffon', '#fffacd'],\n ['lightblue', '#add8e6'],\n ['lightcoral', '#f08080'],\n ['lightcyan', '#e0ffff'],\n ['lightgoldenrodyellow', '#fafad2'],\n ['lightgray', '#d3d3d3'],\n ['lightgreen', '#90ee90'],\n ['lightgrey', '#d3d3d3'],\n ['lightpink', '#ffb6c1'],\n ['lightsalmon', '#ffa07a'],\n ['lightseagreen', '#20b2aa'],\n ['lightskyblue', '#87cefa'],\n ['lightslategray', '#778899'],\n ['lightslategrey', '#778899'],\n ['lightsteelblue', '#b0c4de'],\n ['lightyellow', '#ffffe0'],\n ['lime', '#00ff00'],\n ['limegreen', '#32cd32'],\n ['linen', '#faf0e6'],\n ['magenta', '#ff00ff'],\n ['maroon', '#800000'],\n ['mediumaquamarine', '#66cdaa'],\n ['mediumblue', '#0000cd'],\n ['mediumorchid', '#ba55d3'],\n ['mediumpurple', '#9370db'],\n ['mediumseagreen', '#3cb371'],\n ['mediumslateblue', '#7b68ee'],\n ['mediumspringgreen', '#00fa9a'],\n ['mediumturquoise', '#48d1cc'],\n ['mediumvioletred', '#c71585'],\n ['midnightblue', '#191970'],\n ['mintcream', '#f5fffa'],\n ['mistyrose', '#ffe4e1'],\n ['moccasin', '#ffe4b5'],\n ['navajowhite', '#ffdead'],\n ['navy', '#000080'],\n ['oldlace', '#fdf5e6'],\n ['olive', '#808000'],\n ['olivedrab', '#6b8e23'],\n ['orange', '#ffa500'],\n ['orangered', '#ff4500'],\n ['orchid', '#da70d6'],\n ['palegoldenrod', '#eee8aa'],\n ['palegreen', '#98fb98'],\n ['paleturquoise', '#afeeee'],\n ['palevioletred', '#db7093'],\n ['papayawhip', '#ffefd5'],\n ['peachpuff', '#ffdab9'],\n ['peru', '#cd853f'],\n ['pink', '#ffc0cb'],\n ['plum', '#dda0dd'],\n ['powderblue', '#b0e0e6'],\n ['purple', '#800080'],\n ['rebeccapurple', '#663399'],\n ['red', '#ff0000'],\n ['rosybrown', '#bc8f8f'],\n ['royalblue', '#4169e1'],\n ['saddlebrown', '#8b4513'],\n ['salmon', '#fa8072'],\n ['sandybrown', '#f4a460'],\n ['seagreen', '#2e8b57'],\n ['seashell', '#fff5ee'],\n ['sienna', '#a0522d'],\n ['silver', '#c0c0c0'],\n ['skyblue', '#87ceeb'],\n ['slateblue', '#6a5acd'],\n ['slategray', '#708090'],\n ['slategrey', '#708090'],\n ['snow', '#fffafa'],\n ['springgreen', '#00ff7f'],\n ['steelblue', '#4682b4'],\n ['tan', '#d2b48c'],\n ['teal', '#008080'],\n ['thistle', '#d8bfd8'],\n ['tomato', '#ff6347'],\n ['turquoise', '#40e0d0'],\n ['violet', '#ee82ee'],\n ['wheat', '#f5deb3'],\n ['white', '#ffffff'],\n ['whitesmoke', '#f5f5f5'],\n ['yellow', '#ffff00'],\n ['yellowgreen', '#9acd32'],\n ]);\n return _namedColorHex;\n}\n\nexport function strToRgb(\n color: string,\n _ignoreAlpha = false,\n): string | null | undefined {\n if (!color) return undefined;\n\n if (color.startsWith('rgb')) return color;\n\n if (color.startsWith('#')) return hexToRgb(color);\n\n if (color.startsWith('okhsl(')) return okhslToRgb(color);\n\n if (color.startsWith('hsl')) return hslToRgb(color);\n\n // Named CSS colors\n const namedHex = getNamedColorHex().get(color.toLowerCase());\n if (namedHex) return hexToRgb(namedHex);\n\n return null;\n}\n\n/**\n * Extract RGB values from an rgb()/rgba() string.\n * Supports all modern CSS syntax variations:\n * - Comma-separated: rgb(255, 128, 0)\n * - Space-separated: rgb(255 128 0)\n * - Fractional: rgb(128.5, 64.3, 32.1)\n * - Percentages: rgb(50%, 25%, 75%)\n * - Slash alpha notation: rgb(255 128 0 / 0.5)\n *\n * Returns array of RGB values (0-255 range), converting percentages as needed.\n */\nexport function getRgbValuesFromRgbaString(str: string): number[] {\n // Extract content inside rgb()/rgba()\n const match = str.match(/rgba?\\(([^)]+)\\)/i);\n if (!match) return [];\n\n const inner = match[1].trim();\n // Split by slash first (for alpha), then handle color components\n const [colorPart] = inner.split('/');\n // Split by comma or whitespace\n const parts = colorPart\n .trim()\n .split(/[,\\s]+/)\n .filter(Boolean);\n\n return parts.slice(0, 3).map((part) => {\n part = part.trim();\n if (part.endsWith('%')) {\n // Convert percentage to 0-255 range\n return (parseFloat(part) / 100) * 255;\n }\n return parseFloat(part);\n });\n}\n\nexport function hexToRgb(hex: string): string | null {\n const matched = hex\n .replace(\n /^#?([a-f\\d])([a-f\\d])([a-f\\d])$/i,\n (_m: string, r: string, g: string, b: string) =>\n '#' + r + r + g + g + b + b,\n )\n .substring(1)\n .match(/.{2}/g);\n\n if (!matched) return null;\n\n const rgba = matched.map(\n (x: string, i: number) => parseInt(x, 16) * (i === 3 ? 1 / 255 : 1),\n );\n\n if (rgba.some((v) => Number.isNaN(v))) {\n return null;\n }\n\n if (rgba.length >= 3) {\n return `rgb(${rgba.slice(0, 3).join(' ')}${rgba.length > 3 ? ` / ${rgba[3]}` : ''})`;\n }\n\n return null;\n}\n\nexport function filterMods(mods: string[], allowedMods: string[]): string[] {\n return mods.filter((mod) => allowedMods.includes(mod));\n}\n\nexport function extendStyles(\n defaultStyles?: Record<string, unknown> | null,\n newStyles?: Record<string, unknown> | null,\n): Record<string, unknown> {\n let styles: Record<string, unknown> = {};\n\n if (!defaultStyles) {\n if (!newStyles) {\n return styles;\n }\n } else {\n styles = Object.assign({}, defaultStyles);\n }\n\n if (newStyles) {\n Object.keys(newStyles).forEach((key) => {\n if (newStyles[key] != null) {\n styles[key] = newStyles[key];\n }\n });\n }\n\n return styles;\n}\n\n/**\n * Split properties into style and non-style properties.\n * @param props - Component prop map.\n * @param [styleList] - List of all style properties.\n * @param [defaultStyles] - Default style map of the component.\n * @param [propMap] - Props to style alias map.\n * @param [ignoreList] - A list of properties to ignore.\n */\nexport function extractStyles(\n props: Record<string, unknown>,\n styleList: readonly string[] = [],\n defaultStyles?: Styles,\n propMap?: Record<string, string>,\n ignoreList: readonly string[] = [],\n): Styles {\n const styles: Styles = {\n ...defaultStyles,\n ...(ignoreList.includes('styles')\n ? undefined\n : props.styles && typeof props.styles === 'object'\n ? (props.styles as Styles)\n : undefined),\n };\n\n Object.keys(props).forEach((prop) => {\n const propName = propMap ? propMap[prop] || prop : prop;\n const value = props[prop];\n\n if (ignoreList && ignoreList.includes(prop)) {\n // do nothing\n } else if (styleList.includes(propName)) {\n styles[propName] = value as Styles[keyof Styles];\n }\n }, {});\n\n return styles;\n}\n\n// Enhanced regex that includes advanced state patterns\n// Matches: operators, parentheses, @media(...), @(...), @root(...), @own(...), @starting, @predefined,\n// value mods, boolean mods, pseudo-classes, classes, attribute selectors\nconst STATES_REGEXP =\n /([&|!^])|([()])|(@media:[a-z]+)|(@media\\([^)]+\\))|(@root\\([^)]+\\))|(@own\\([^)]+\\))|(@\\([^)]+\\))|(@starting)|(@[A-Za-z][A-Za-z0-9-]*)|([a-z][a-z0-9-]+=(?:\"[^\"]*\"|'[^']*'|[^\\s&|!^()]+))|([a-z][a-z0-9-]+)|(:[a-z][a-z0-9-]+\\([^)]+\\)|:[a-z][a-z0-9-]+)|(\\.[a-z][a-z0-9-]+)|(\\[[^\\]]+])/gi;\n\n/**\n * Check if a token is an advanced state (starts with @)\n */\nexport function isAdvancedStateToken(token: string): boolean {\n return token.startsWith('@') || token.startsWith('!@');\n}\nexport const STATE_OPERATORS = {\n NOT: '!',\n AND: '&',\n OR: '|',\n XOR: '^',\n};\n\nexport const STATE_OPERATOR_LIST = ['!', '&', '|', '^'];\n\n/**\n * Convert state notation tokens to a compute model (string, or nested [op, lhs, rhs]).\n */\nfunction convertTokensToComputeUnits(tokens: unknown[]): unknown {\n if (tokens.length === 1) {\n return tokens[0];\n }\n\n const hasLength = (x: unknown): x is string | unknown[] =>\n typeof x === 'string' || Array.isArray(x);\n\n STATE_OPERATOR_LIST.forEach((operator) => {\n let i;\n\n while ((i = tokens.indexOf(operator)) !== -1) {\n const token = tokens[i];\n\n if (token === '!') {\n const next = tokens[i + 1];\n if (next !== undefined && hasLength(next) && next.length !== 1) {\n tokens.splice(i, 2, ['!', next]);\n } else {\n tokens.splice(i, 1);\n }\n } else {\n const prev = tokens[i - 1];\n const next = tokens[i + 1];\n if (\n prev !== undefined &&\n next !== undefined &&\n hasLength(prev) &&\n hasLength(next) &&\n prev.length !== 1 &&\n next.length !== 1\n ) {\n tokens.splice(i - 1, 3, [token, prev, next]);\n } else {\n tokens.splice(i, 1);\n }\n }\n }\n });\n\n return tokens.length === 1 ? tokens[0] : tokens;\n}\n\n/**\n * Replace commas with | only outside of parentheses.\n * This preserves commas in advanced states like @(card, w < 600px)\n */\nfunction replaceCommasOutsideParens(str: string): string {\n let result = '';\n let depth = 0;\n\n for (const char of str) {\n if (char === '(') {\n depth++;\n result += char;\n } else if (char === ')') {\n depth--;\n result += char;\n } else if (char === ',' && depth === 0) {\n // Only replace commas at the top level (outside parentheses)\n result += '|';\n } else {\n result += char;\n }\n }\n\n return result;\n}\n\n/**\n * Parse state notation and return tokens, modifiers and compute model.\n */\nfunction parseStateNotationInner(\n notation: string,\n value: StyleValue | StyleValueStateMap | StyleStateData,\n): StyleStateData {\n const tokens = replaceCommasOutsideParens(notation).match(STATES_REGEXP);\n\n if (!tokens || !tokens.length) {\n return {\n model: undefined,\n mods: [],\n notMods: [],\n tokens: [],\n value,\n };\n } else if (tokens.length === 1) {\n return {\n model: tokens[0],\n mods: tokens.slice(0),\n notMods: [],\n tokens,\n value,\n };\n }\n\n const mods: string[] = [];\n\n const operations: unknown[][] = [[]];\n let list = operations[0];\n let position = 0;\n let operation: unknown[];\n\n tokens.forEach((token) => {\n switch (token) {\n case '(':\n operation = [];\n position++;\n list = operations[position] = operation;\n break;\n case ')':\n position--;\n operations[position].push(\n convertTokensToComputeUnits(list as unknown[]),\n );\n list = operations[position];\n break;\n default:\n if (token.length > 1) {\n if (!mods.includes(token)) {\n mods.push(token);\n }\n }\n list.push(token);\n }\n });\n\n while (position) {\n position--;\n operations[position].push(convertTokensToComputeUnits(list as unknown[]));\n list = operations[position];\n }\n\n return {\n tokens,\n mods,\n notMods: [],\n model: convertTokensToComputeUnits(operations[0] as unknown[]) as\n | ComputeModel\n | undefined,\n value,\n };\n}\n\nexport const parseStateNotation = cacheWrapper(parseStateNotationInner);\n\n/**\n * Build an AtRuleContext from parsed advanced states\n */\nexport function buildAtRuleContext(\n advancedStates: ParsedAdvancedState[],\n negatedStates: Set<string>,\n): AtRuleContext | undefined {\n if (advancedStates.length === 0) return undefined;\n\n const ctx: AtRuleContext = {};\n\n for (const state of advancedStates) {\n const isNegated = negatedStates.has(state.raw);\n\n switch (state.type) {\n case 'media': {\n if (!ctx.media) ctx.media = [];\n let mediaCondition = '';\n\n if (state.mediaType) {\n // @media:print, @media:screen, etc.\n mediaCondition = state.mediaType;\n } else if (state.condition) {\n // @media(width < 920px)\n mediaCondition = `(${state.condition})`;\n }\n\n if (mediaCondition) {\n if (isNegated) {\n ctx.media.push(`not ${mediaCondition}`);\n } else {\n ctx.media.push(mediaCondition);\n }\n }\n break;\n }\n\n case 'container': {\n if (!ctx.container) ctx.container = [];\n let condition = state.condition;\n if (isNegated) {\n condition = `not (${condition})`;\n }\n ctx.container.push({\n name: state.containerName,\n condition,\n });\n break;\n }\n\n case 'root': {\n if (!ctx.rootStates) ctx.rootStates = [];\n // Parse the condition to generate the proper selector\n const rootSelector = buildRootSelector(state.condition, isNegated);\n ctx.rootStates.push(rootSelector);\n break;\n }\n\n case 'starting': {\n if (!isNegated) {\n ctx.startingStyle = true;\n }\n break;\n }\n\n // 'own' and 'predefined' are handled differently (selector-based, not at-rule)\n // 'modifier' is a regular state\n }\n }\n\n // Return undefined if no at-rules were added\n if (\n !ctx.media?.length &&\n !ctx.container?.length &&\n !ctx.rootStates?.length &&\n !ctx.startingStyle\n ) {\n return undefined;\n }\n\n return ctx;\n}\n\n/**\n * Build a root state selector from a condition\n */\nfunction buildRootSelector(condition: string, isNegated: boolean): string {\n // Handle different condition formats:\n // - theme=dark -> [data-theme=\"dark\"]\n // - .className -> .className\n // - [attr] -> [attr]\n // - booleanMod -> [data-boolean-mod]\n\n let selector: string;\n\n if (condition.startsWith('.')) {\n // Class selector\n selector = condition;\n } else if (condition.startsWith('[')) {\n // Attribute selector\n selector = condition;\n } else if (condition.includes('=')) {\n // Value mod: theme=dark -> [data-theme=\"dark\"]\n const [key, value] = condition.split('=');\n selector = `[data-${camelToKebab(key.trim())}=\"${value.trim()}\"]`;\n } else {\n // Boolean mod: camelCase -> [data-camel-case]\n selector = `[data-${camelToKebab(condition)}]`;\n }\n\n if (isNegated) {\n return `:not(${selector})`;\n }\n return selector;\n}\n\n/**\n * Parse state notation and return tokens, modifiers and compute model.\n * Enhanced to detect and extract advanced states.\n */\nexport function styleStateMapToStyleStateDataList(\n styleStateMap: StyleStateMap | StyleValue | StyleValueStateMap,\n parserContext?: StateParserContext,\n): { states: StyleStateDataList; mods: string[]; hasAdvancedStates: boolean } {\n if (typeof styleStateMap !== 'object' || !styleStateMap) {\n return {\n states: [\n {\n model: undefined,\n mods: [],\n notMods: [],\n value: styleStateMap,\n },\n ],\n mods: [],\n hasAdvancedStates: false,\n };\n }\n\n const stateDataList: StyleStateDataList = [];\n let hasAdvancedStates = false;\n\n Object.keys(styleStateMap).forEach((stateNotation) => {\n const state = parseStateNotation(\n stateNotation,\n styleStateMap[stateNotation],\n );\n\n // Check if this state contains any advanced states\n const advancedStates: ParsedAdvancedState[] = [];\n const negatedAdvancedStates = new Set<string>();\n const regularMods: string[] = [];\n const ownMods: string[] = [];\n const negatedOwnMods: string[] = [];\n\n // Scan tokens for advanced states\n if (state.tokens) {\n let isNegated = false;\n for (const token of state.tokens) {\n if (token === '!') {\n isNegated = true;\n continue;\n }\n\n if (isAdvancedStateToken(token)) {\n hasAdvancedStates = true;\n const ctx = parserContext || createStateParserContext(undefined);\n const parsed = parseAdvancedState(token, ctx);\n advancedStates.push(parsed);\n\n // Handle @own states specially - extract condition as ownMod\n if (parsed.type === 'own' && parsed.condition) {\n if (isNegated) {\n negatedOwnMods.push(parsed.condition);\n } else {\n ownMods.push(parsed.condition);\n }\n } else if (isNegated) {\n negatedAdvancedStates.add(token);\n }\n isNegated = false;\n } else if (\n token.length > 1 &&\n !['&', '|', '^', '(', ')'].includes(token)\n ) {\n regularMods.push(token);\n isNegated = false;\n } else {\n isNegated = false;\n }\n }\n }\n\n // If there are advanced states, build the atRuleContext\n if (advancedStates.length > 0) {\n state.advancedStates = advancedStates;\n state.atRuleContext = buildAtRuleContext(\n advancedStates,\n negatedAdvancedStates,\n );\n // Filter mods to only include regular mods (not advanced states)\n state.mods = regularMods;\n }\n\n // Store own mods for sub-element selector generation\n if (ownMods.length > 0) {\n state.ownMods = ownMods;\n }\n if (negatedOwnMods.length > 0) {\n state.negatedOwnMods = negatedOwnMods;\n }\n\n stateDataList.push(state);\n });\n\n stateDataList.reverse();\n\n let initialState;\n\n const allMods: string[] = stateDataList.reduce((all: string[], state) => {\n if (!state.mods.length && !state.advancedStates?.length) {\n initialState = state;\n } else {\n state.mods.forEach((mod) => {\n if (!all.includes(mod)) {\n all.push(mod);\n }\n });\n }\n\n return all;\n }, []);\n\n if (!initialState) {\n stateDataList.push({\n mods: [],\n notMods: allMods,\n value: true,\n });\n }\n\n return { states: stateDataList, mods: allMods, hasAdvancedStates };\n}\n\nexport const COMPUTE_FUNC_MAP: Record<\n string,\n (a: unknown, b?: unknown) => unknown\n> = {\n '!': (a: unknown) => !a,\n '^': (a: unknown, b?: unknown) => (a && !b) || (!a && b),\n '|': (a: unknown, b?: unknown) => a || b,\n '&': (a: unknown, b?: unknown) => a && b,\n};\n\n/**\n * Compute a result based on a model and incoming map.\n */\nexport function computeState(\n computeModel: ComputeModel,\n valueMap:\n | (number | boolean)[]\n | Record<string, boolean>\n | ((...args: unknown[]) => unknown),\n) {\n if (!computeModel) return true;\n\n const map = valueMap as Record<string | number, unknown>;\n\n if (!Array.isArray(computeModel)) {\n if (typeof valueMap === 'function') {\n return !!valueMap(computeModel);\n } else {\n return !!map[computeModel];\n }\n }\n\n const func = COMPUTE_FUNC_MAP[computeModel[0]];\n\n if (!func) {\n console.warn(\n 'CubeUIKit: unexpected compute method in the model',\n computeModel,\n );\n // return false;\n }\n\n let a: unknown = computeModel[1];\n\n if (typeof a === 'object') {\n a = !!computeState(a as unknown as ComputeModel, valueMap);\n } else if (typeof valueMap === 'function') {\n a = !!valueMap(a);\n } else {\n a = !!map[a as string | number];\n }\n\n if (computeModel.length === 2) {\n return func(a);\n }\n\n let b: unknown = computeModel[2];\n\n if (typeof b === 'object') {\n b = !!computeState(b as unknown as ComputeModel, valueMap);\n } else if (typeof valueMap === 'function') {\n b = !!valueMap(b);\n } else {\n b = !!map[b as string | number];\n }\n\n return !!func(a, b);\n}\n\nconst _innerCache = new WeakMap();\n\nexport function stringifyStyles(styles: unknown): string {\n if (styles == null || typeof styles !== 'object') return '';\n const obj = styles as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const parts: string[] = [];\n for (const k of keys) {\n const v = obj[k];\n if (v === undefined || typeof v === 'function' || typeof v === 'symbol')\n continue;\n\n const c0 = k.charCodeAt(0);\n const needsInnerSort =\n ((c0 >= 65 && c0 <= 90) || c0 === 38) &&\n v &&\n typeof v === 'object' &&\n !Array.isArray(v);\n\n let sv: string;\n if (needsInnerSort) {\n sv = _innerCache.get(v);\n if (sv === undefined) {\n const innerObj = v as Record<string, unknown>;\n const innerKeys = Object.keys(innerObj).sort();\n const innerParts: string[] = [];\n for (const ik of innerKeys) {\n const ivs = JSON.stringify(innerObj[ik]);\n if (ivs !== undefined)\n innerParts.push(JSON.stringify(ik) + ':' + ivs);\n }\n sv = '{' + innerParts.join(',') + '}';\n _innerCache.set(v, sv);\n }\n } else {\n sv = JSON.stringify(v);\n }\n parts.push(JSON.stringify(k) + ':' + sv);\n }\n return '{' + parts.join(',') + '}';\n}\n"],"mappings":"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"}
package/docs/usage.md CHANGED
@@ -334,6 +334,10 @@ const Custom = tasty({
334
334
  | `@parent` | Parent/ancestor element states | `@parent(hovered)` |
335
335
  | `@own` | Sub-element's own state | `@own(hovered)` |
336
336
  | `@starting` | Entry animation | `@starting` |
337
+ | `:is()` | CSS `:is()` structural pseudo-class | `:is(fieldset > label)` |
338
+ | `:has()` | CSS `:has()` relational pseudo-class | `:has(> Icon)` |
339
+ | `:not()` | CSS `:not()` negation (prefer `!:is()`) | `:not(:first-child)` |
340
+ | `:where()` | CSS `:where()` (zero specificity) | `:where(Section)` |
337
341
 
338
342
  #### `@parent(...)` — Parent Element States
339
343
 
@@ -359,7 +363,7 @@ const Highlight = tasty({
359
363
  | `@parent(.active)` | `:is(.active *)` |
360
364
  | `@parent(hovered & focused)` | `:is([data-hovered][data-focused] *)` (same ancestor) |
361
365
  | `@parent(hovered) & @parent(focused)` | `:is([data-hovered] *):is([data-focused] *)` (independent ancestors) |
362
- | `@parent(hovered \| focused)` | `:is([data-hovered] *)`, `:is([data-focused] *)` (OR variants) |
366
+ | `@parent(hovered \| focused)` | `:is([data-hovered] *, [data-focused] *)` (OR inside single wrapper) |
363
367
 
364
368
  For sub-elements, the parent check applies to the root element's ancestors:
365
369
 
@@ -377,6 +381,54 @@ const Card = tasty({
377
381
  // → .t0.t0:is([data-hovered] *) [data-element="Label"]
378
382
  ```
379
383
 
384
+ #### `:is()`, `:has()` — CSS Structural Pseudo-classes
385
+
386
+ Use CSS structural pseudo-classes directly in state keys. Capitalized words become `[data-element="..."]` selectors; lowercase words are HTML tags. A trailing combinator (`>`, `+`, `~`) is auto-completed with `*`.
387
+
388
+ `:where()` and `:not()` are also supported but rarely needed — use `:is()` and `!` negation instead.
389
+
390
+ > **Performance warning:** CSS structural pseudo-classes — especially `:has()` — can be costly for the browser to evaluate because they require inspecting the DOM tree beyond the matched element. Tasty already provides a rich, purpose-built state system (`@parent()`, `@own()`, modifiers, boolean logic) that covers the vast majority of use cases without the performance trade-off. **Prefer Tasty's built-in mechanisms and treat `:has()` / `:is()` as a last resort** for conditions that cannot be expressed any other way.
391
+
392
+ ```jsx
393
+ const Card = tasty({
394
+ styles: {
395
+ display: {
396
+ '': 'block',
397
+ ':has(> Icon)': 'grid', // has Icon as direct child
398
+ ':has(+ Icon)': 'grid', // immediately followed by an Icon sibling
399
+ ':has(~ Icon)': 'grid', // has an Icon sibling somewhere after
400
+ ':has(Icon +)': 'grid', // immediately preceded by an Icon sibling (auto-completes to `Icon + *`)
401
+ ':has(Icon ~)': 'grid', // has an Icon sibling somewhere before (auto-completes to `Icon ~ *`)
402
+ ':is(fieldset > label)': 'inline', // is a label inside a fieldset (HTML tags)
403
+ '!:has(> Icon)': 'flex', // negation: no Icon child
404
+ },
405
+ },
406
+ });
407
+ ```
408
+
409
+ | Syntax | CSS Output | Meaning |
410
+ |--------|------------|---------|
411
+ | `:has(> Icon)` | `:has(> [data-element="Icon"])` | Has Icon as direct child |
412
+ | `:has(+ Icon)` | `:has(+ [data-element="Icon"])` | Immediately followed by an Icon sibling |
413
+ | `:has(~ Icon)` | `:has(~ [data-element="Icon"])` | Has an Icon sibling somewhere after |
414
+ | `:has(Icon +)` | `:has([data-element="Icon"] + *)` | Immediately preceded by an Icon sibling |
415
+ | `:has(Icon ~)` | `:has([data-element="Icon"] ~ *)` | Has an Icon sibling somewhere before |
416
+ | `:has(>)` | `:has(> *)` | Has any direct child |
417
+ | `:is(> Field + input)` | `:is(> [data-element="Field"] + input)` | Structural match |
418
+ | `:has(button)` | `:has(button)` | HTML tag (lowercase, unchanged) |
419
+ | `!:has(> Icon)` | `:not(:has(> [data-element="Icon"]))` | Negation (use `!`) |
420
+ | `!:is(Panel)` | `:not([data-element="Panel"])` | Negation (use `!:is`) |
421
+
422
+ Combine with other states using boolean logic:
423
+
424
+ ```jsx
425
+ ':has(> Icon) & hovered' // structural + data attribute
426
+ '@parent(hovered) & :has(> Icon)' // parent check + structural
427
+ ':has(> Icon) | :has(> Button)' // OR: either sub-element present
428
+ ```
429
+
430
+ > **Nesting limit:** The state key parser supports up to 2 levels of nested parentheses inside `:is()`, `:has()`, `:not()`, and `:where()` — e.g. `:has(Input:not(:disabled))` works, but 3+ levels like `:has(:is(:not(:hover)))` will not be tokenized correctly. This covers virtually all practical use cases.
431
+
380
432
  ---
381
433
 
382
434
  ## Style Properties
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tenphi/tasty",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "A design-system-integrated styling system and DSL for concise, state-aware UI styling",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",