@tenphi/tasty 0.6.0 → 0.7.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.
- package/README.md +76 -15
- package/dist/config.d.ts +8 -0
- package/dist/config.js.map +1 -1
- package/dist/hooks/useStyles.js +5 -5
- package/dist/hooks/useStyles.js.map +1 -1
- package/dist/injector/injector.js +38 -25
- package/dist/injector/injector.js.map +1 -1
- package/dist/injector/sheet-manager.d.ts +12 -4
- package/dist/injector/sheet-manager.js +23 -9
- package/dist/injector/sheet-manager.js.map +1 -1
- package/dist/injector/types.d.ts +9 -0
- package/dist/properties/index.js +77 -17
- package/dist/properties/index.js.map +1 -1
- package/dist/properties/property-type-resolver.d.ts +24 -0
- package/dist/properties/property-type-resolver.js +83 -0
- package/dist/properties/property-type-resolver.js.map +1 -0
- package/dist/styles/fill.js +6 -5
- package/dist/styles/fill.js.map +1 -1
- package/dist/utils/styles.js +161 -0
- package/dist/utils/styles.js.map +1 -1
- package/dist/zero/babel.d.ts +5 -0
- package/dist/zero/babel.js +13 -7
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/extractor.js +66 -1
- package/dist/zero/extractor.js.map +1 -1
- package/docs/configuration.md +211 -0
- package/docs/debug.md +505 -0
- package/docs/injector.md +528 -0
- package/docs/styles.md +567 -0
- package/docs/tasty-static.md +376 -0
- package/docs/usage.md +643 -0
- package/package.json +5 -4
package/dist/properties/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RE_NUMBER, RE_RAW_UNIT } from "../parser/const.js";
|
|
2
2
|
|
|
3
3
|
//#region src/properties/index.ts
|
|
4
4
|
const PROPERTIES_KEY = "@properties";
|
|
@@ -88,7 +88,11 @@ function parsePropertyToken(token) {
|
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
90
90
|
* Normalize a property definition to a consistent string representation.
|
|
91
|
-
* Used for comparing definitions to detect
|
|
91
|
+
* Used for comparing definitions to detect type conflicts.
|
|
92
|
+
*
|
|
93
|
+
* Only `syntax` and `inherits` are compared — `initialValue` is intentionally
|
|
94
|
+
* excluded because different components may set different defaults for the
|
|
95
|
+
* same typed property (e.g. auto-inferred `0px` vs explicit `6px`).
|
|
92
96
|
*
|
|
93
97
|
* Keys are sorted alphabetically to ensure consistent comparison:
|
|
94
98
|
* { inherits: true, syntax: '<color>' } === { syntax: '<color>', inherits: true }
|
|
@@ -96,7 +100,6 @@ function parsePropertyToken(token) {
|
|
|
96
100
|
function normalizePropertyDefinition(def) {
|
|
97
101
|
const normalized = {};
|
|
98
102
|
if (def.inherits !== void 0) normalized.inherits = def.inherits;
|
|
99
|
-
if (def.initialValue !== void 0) normalized.initialValue = String(def.initialValue);
|
|
100
103
|
if (def.syntax !== void 0) normalized.syntax = def.syntax;
|
|
101
104
|
return JSON.stringify(normalized);
|
|
102
105
|
}
|
|
@@ -134,25 +137,82 @@ function getEffectiveDefinition(token, userDefinition) {
|
|
|
134
137
|
isValid: true
|
|
135
138
|
};
|
|
136
139
|
}
|
|
140
|
+
const UNIT_TO_SYNTAX = {};
|
|
141
|
+
const LENGTH_UNITS = [
|
|
142
|
+
"px",
|
|
143
|
+
"em",
|
|
144
|
+
"rem",
|
|
145
|
+
"vw",
|
|
146
|
+
"vh",
|
|
147
|
+
"vmin",
|
|
148
|
+
"vmax",
|
|
149
|
+
"ch",
|
|
150
|
+
"ex",
|
|
151
|
+
"cap",
|
|
152
|
+
"ic",
|
|
153
|
+
"lh",
|
|
154
|
+
"rlh",
|
|
155
|
+
"svw",
|
|
156
|
+
"svh",
|
|
157
|
+
"lvw",
|
|
158
|
+
"lvh",
|
|
159
|
+
"dvw",
|
|
160
|
+
"dvh",
|
|
161
|
+
"cqw",
|
|
162
|
+
"cqh",
|
|
163
|
+
"cqi",
|
|
164
|
+
"cqb",
|
|
165
|
+
"cqmin",
|
|
166
|
+
"cqmax"
|
|
167
|
+
];
|
|
168
|
+
const ANGLE_UNITS = [
|
|
169
|
+
"deg",
|
|
170
|
+
"rad",
|
|
171
|
+
"grad",
|
|
172
|
+
"turn"
|
|
173
|
+
];
|
|
174
|
+
const TIME_UNITS = ["ms", "s"];
|
|
175
|
+
for (const u of LENGTH_UNITS) UNIT_TO_SYNTAX[u] = {
|
|
176
|
+
syntax: "<length>",
|
|
177
|
+
initialValue: "0px"
|
|
178
|
+
};
|
|
179
|
+
UNIT_TO_SYNTAX["%"] = {
|
|
180
|
+
syntax: "<percentage>",
|
|
181
|
+
initialValue: "0%"
|
|
182
|
+
};
|
|
183
|
+
for (const u of ANGLE_UNITS) UNIT_TO_SYNTAX[u] = {
|
|
184
|
+
syntax: "<angle>",
|
|
185
|
+
initialValue: "0deg"
|
|
186
|
+
};
|
|
187
|
+
for (const u of TIME_UNITS) UNIT_TO_SYNTAX[u] = {
|
|
188
|
+
syntax: "<time>",
|
|
189
|
+
initialValue: "0s"
|
|
190
|
+
};
|
|
137
191
|
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
192
|
+
* Infer CSS @property syntax from a concrete value.
|
|
193
|
+
* Only detects numeric types: \<number\>, \<length\>, \<percentage\>, \<angle\>, \<time\>.
|
|
194
|
+
* Color properties are handled separately via the #name token convention
|
|
195
|
+
* (--name-color gets \<color\> syntax automatically in getEffectiveDefinition).
|
|
140
196
|
*
|
|
141
|
-
* @param
|
|
142
|
-
* @returns
|
|
197
|
+
* @param value - The CSS value to infer from (e.g. '10px', '1', '45deg')
|
|
198
|
+
* @returns Inferred syntax and initial value, or null if not inferable
|
|
143
199
|
*/
|
|
144
|
-
function
|
|
145
|
-
if (
|
|
146
|
-
const
|
|
147
|
-
if (!
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
200
|
+
function inferSyntaxFromValue(value) {
|
|
201
|
+
if (!value || typeof value !== "string") return null;
|
|
202
|
+
const trimmed = value.trim();
|
|
203
|
+
if (!trimmed) return null;
|
|
204
|
+
if (RE_NUMBER.test(trimmed)) return {
|
|
205
|
+
syntax: "<number>",
|
|
206
|
+
initialValue: "0"
|
|
207
|
+
};
|
|
208
|
+
const unitMatch = trimmed.match(RE_RAW_UNIT);
|
|
209
|
+
if (unitMatch) {
|
|
210
|
+
const mapping = UNIT_TO_SYNTAX[unitMatch[2]];
|
|
211
|
+
if (mapping) return mapping;
|
|
152
212
|
}
|
|
153
|
-
return
|
|
213
|
+
return null;
|
|
154
214
|
}
|
|
155
215
|
|
|
156
216
|
//#endregion
|
|
157
|
-
export {
|
|
217
|
+
export { extractLocalProperties, getEffectiveDefinition, hasLocalProperties, inferSyntaxFromValue, normalizePropertyDefinition };
|
|
158
218
|
//# sourceMappingURL=index.js.map
|
|
@@ -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 type { Styles } from '../styles/types';\nimport { getRgbValuesFromRgbaString, strToRgb } from '../utils/styles';\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 changes/conflicts.\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 // Add properties in alphabetical order\n if (def.inherits !== undefined) {\n normalized.inherits = def.inherits;\n }\n if (def.initialValue !== undefined) {\n normalized.initialValue = String(def.initialValue);\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// Color RGB Companion Helpers\n// ============================================================================\n\n/**\n * Extract RGB triplet string from a color initial value.\n * Used when auto-creating the companion `-rgb` property for color @property definitions.\n *\n * @param initialValue - The color property's initial value (e.g., 'rgb(255 255 255)', 'transparent', '#fff')\n * @returns Space-separated RGB triplet (e.g., '255 255 255'), defaults to '0 0 0'\n */\nexport function colorInitialValueToRgb(initialValue?: string | number): string {\n if (initialValue == null) return '0 0 0';\n\n const str = String(initialValue).trim();\n if (!str || str === 'transparent') return '0 0 0';\n\n const rgba = strToRgb(str);\n if (rgba) {\n const values = getRgbValuesFromRgbaString(rgba);\n if (values.length >= 3) return values.slice(0, 3).join(' ');\n }\n\n return '0 0 0';\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;;;;;;;;;AAwBH,SAAgB,4BAA4B,KAAiC;CAC3E,MAAM,aAAsC,EAAE;AAG9C,KAAI,IAAI,aAAa,OACnB,YAAW,WAAW,IAAI;AAE5B,KAAI,IAAI,iBAAiB,OACvB,YAAW,eAAe,OAAO,IAAI,aAAa;AAEpD,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;;;;;;;;;AAcH,SAAgB,uBAAuB,cAAwC;AAC7E,KAAI,gBAAgB,KAAM,QAAO;CAEjC,MAAM,MAAM,OAAO,aAAa,CAAC,MAAM;AACvC,KAAI,CAAC,OAAO,QAAQ,cAAe,QAAO;CAE1C,MAAM,OAAO,SAAS,IAAI;AAC1B,KAAI,MAAM;EACR,MAAM,SAAS,2BAA2B,KAAK;AAC/C,MAAI,OAAO,UAAU,EAAG,QAAO,OAAO,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI;;AAG7D,QAAO"}
|
|
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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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/properties/property-type-resolver.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* PropertyTypeResolver
|
|
4
|
+
*
|
|
5
|
+
* Automatically infers CSS @property types from custom property values.
|
|
6
|
+
* Supports deferred resolution for var() reference chains of arbitrary depth.
|
|
7
|
+
*/
|
|
8
|
+
declare class PropertyTypeResolver {
|
|
9
|
+
/** propName → the prop it depends on */
|
|
10
|
+
private pendingDeps;
|
|
11
|
+
/** propName → list of props waiting on it */
|
|
12
|
+
private reverseDeps;
|
|
13
|
+
/**
|
|
14
|
+
* Scan CSS declarations and auto-register @property for custom properties
|
|
15
|
+
* whose types can be inferred from their values.
|
|
16
|
+
*/
|
|
17
|
+
scanDeclarations(declarations: string, isPropertyDefined: (name: string) => boolean, registerProperty: (name: string, syntax: string, initialValue: string) => void): void;
|
|
18
|
+
private addDependency;
|
|
19
|
+
private resolve;
|
|
20
|
+
private isComplexValue;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { PropertyTypeResolver };
|
|
24
|
+
//# sourceMappingURL=property-type-resolver.d.ts.map
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { inferSyntaxFromValue } from "./index.js";
|
|
2
|
+
|
|
3
|
+
//#region src/properties/property-type-resolver.ts
|
|
4
|
+
/**
|
|
5
|
+
* PropertyTypeResolver
|
|
6
|
+
*
|
|
7
|
+
* Automatically infers CSS @property types from custom property values.
|
|
8
|
+
* Supports deferred resolution for var() reference chains of arbitrary depth.
|
|
9
|
+
*/
|
|
10
|
+
const CUSTOM_PROP_DECL = /^\s*(--[a-z0-9_-]+)\s*:\s*(.+?)\s*$/i;
|
|
11
|
+
const SINGLE_VAR_REF = /^var\((--[a-z0-9_-]+)\)$/i;
|
|
12
|
+
var PropertyTypeResolver = class {
|
|
13
|
+
/** propName → the prop it depends on */
|
|
14
|
+
pendingDeps = /* @__PURE__ */ new Map();
|
|
15
|
+
/** propName → list of props waiting on it */
|
|
16
|
+
reverseDeps = /* @__PURE__ */ new Map();
|
|
17
|
+
/**
|
|
18
|
+
* Scan CSS declarations and auto-register @property for custom properties
|
|
19
|
+
* whose types can be inferred from their values.
|
|
20
|
+
*/
|
|
21
|
+
scanDeclarations(declarations, isPropertyDefined, registerProperty) {
|
|
22
|
+
if (!declarations.includes("--")) return;
|
|
23
|
+
const parts = declarations.split(/;+/);
|
|
24
|
+
for (const part of parts) {
|
|
25
|
+
if (!part.trim()) continue;
|
|
26
|
+
const match = CUSTOM_PROP_DECL.exec(part);
|
|
27
|
+
if (!match) continue;
|
|
28
|
+
const propName = match[1];
|
|
29
|
+
const value = match[2].trim();
|
|
30
|
+
if (isPropertyDefined(propName)) continue;
|
|
31
|
+
if (propName.endsWith("-color")) {
|
|
32
|
+
registerProperty(propName, "<color>", "transparent");
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const varMatch = SINGLE_VAR_REF.exec(value);
|
|
36
|
+
if (varMatch) {
|
|
37
|
+
const depName = varMatch[1];
|
|
38
|
+
this.addDependency(propName, depName);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (this.isComplexValue(value)) continue;
|
|
42
|
+
const inferred = inferSyntaxFromValue(value);
|
|
43
|
+
if (!inferred) continue;
|
|
44
|
+
this.resolve(propName, inferred.syntax, inferred.initialValue, isPropertyDefined, registerProperty);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
addDependency(propName, depName) {
|
|
48
|
+
if (propName === depName) return;
|
|
49
|
+
this.pendingDeps.set(propName, depName);
|
|
50
|
+
let dependents = this.reverseDeps.get(depName);
|
|
51
|
+
if (!dependents) {
|
|
52
|
+
dependents = [];
|
|
53
|
+
this.reverseDeps.set(depName, dependents);
|
|
54
|
+
}
|
|
55
|
+
if (!dependents.includes(propName)) dependents.push(propName);
|
|
56
|
+
}
|
|
57
|
+
resolve(propName, syntax, initialValue, isPropertyDefined, registerProperty, resolving) {
|
|
58
|
+
if (!resolving) resolving = /* @__PURE__ */ new Set();
|
|
59
|
+
if (resolving.has(propName)) return;
|
|
60
|
+
resolving.add(propName);
|
|
61
|
+
if (!isPropertyDefined(propName)) registerProperty(propName, syntax, initialValue);
|
|
62
|
+
const dependents = this.reverseDeps.get(propName);
|
|
63
|
+
if (dependents) {
|
|
64
|
+
this.reverseDeps.delete(propName);
|
|
65
|
+
for (const dependent of dependents) {
|
|
66
|
+
this.pendingDeps.delete(dependent);
|
|
67
|
+
if (isPropertyDefined(dependent)) continue;
|
|
68
|
+
this.resolve(dependent, syntax, initialValue, isPropertyDefined, registerProperty, resolving);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
isComplexValue(value) {
|
|
73
|
+
if (value.includes("calc(")) return true;
|
|
74
|
+
const firstVar = value.indexOf("var(");
|
|
75
|
+
if (firstVar === -1) return false;
|
|
76
|
+
if (value.indexOf("var(", firstVar + 4) !== -1) return true;
|
|
77
|
+
return !SINGLE_VAR_REF.test(value);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
export { PropertyTypeResolver };
|
|
83
|
+
//# sourceMappingURL=property-type-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-type-resolver.js","names":[],"sources":["../../src/properties/property-type-resolver.ts"],"sourcesContent":["/**\n * PropertyTypeResolver\n *\n * Automatically infers CSS @property types from custom property values.\n * Supports deferred resolution for var() reference chains of arbitrary depth.\n */\n\nimport { inferSyntaxFromValue } from './index';\n\nconst CUSTOM_PROP_DECL = /^\\s*(--[a-z0-9_-]+)\\s*:\\s*(.+?)\\s*$/i;\nconst SINGLE_VAR_REF = /^var\\((--[a-z0-9_-]+)\\)$/i;\n\nexport class PropertyTypeResolver {\n /** propName → the prop it depends on */\n private pendingDeps = new Map<string, string>();\n /** propName → list of props waiting on it */\n private reverseDeps = new Map<string, string[]>();\n\n /**\n * Scan CSS declarations and auto-register @property for custom properties\n * whose types can be inferred from their values.\n */\n scanDeclarations(\n declarations: string,\n isPropertyDefined: (name: string) => boolean,\n registerProperty: (\n name: string,\n syntax: string,\n initialValue: string,\n ) => void,\n ): void {\n if (!declarations.includes('--')) return;\n\n const parts = declarations.split(/;+/);\n\n for (const part of parts) {\n if (!part.trim()) continue;\n\n const match = CUSTOM_PROP_DECL.exec(part);\n if (!match) continue;\n\n const propName = match[1];\n const value = match[2].trim();\n\n if (isPropertyDefined(propName)) continue;\n\n // Name-based: --*-color properties are always <color> (from #name tokens)\n if (propName.endsWith('-color')) {\n registerProperty(propName, '<color>', 'transparent');\n continue;\n }\n\n // Single var() reference → record dependency for deferred resolution\n const varMatch = SINGLE_VAR_REF.exec(value);\n if (varMatch) {\n const depName = varMatch[1];\n this.addDependency(propName, depName);\n continue;\n }\n\n // Skip complex expressions (calc, multiple var, etc.)\n if (this.isComplexValue(value)) continue;\n\n const inferred = inferSyntaxFromValue(value);\n if (!inferred) continue;\n\n this.resolve(\n propName,\n inferred.syntax,\n inferred.initialValue,\n isPropertyDefined,\n registerProperty,\n );\n }\n }\n\n private addDependency(propName: string, depName: string): void {\n if (propName === depName) return;\n\n this.pendingDeps.set(propName, depName);\n\n let dependents = this.reverseDeps.get(depName);\n if (!dependents) {\n dependents = [];\n this.reverseDeps.set(depName, dependents);\n }\n if (!dependents.includes(propName)) {\n dependents.push(propName);\n }\n }\n\n private resolve(\n propName: string,\n syntax: string,\n initialValue: string,\n isPropertyDefined: (name: string) => boolean,\n registerProperty: (\n name: string,\n syntax: string,\n initialValue: string,\n ) => void,\n resolving?: Set<string>,\n ): void {\n if (!resolving) resolving = new Set();\n if (resolving.has(propName)) return;\n resolving.add(propName);\n\n if (!isPropertyDefined(propName)) {\n registerProperty(propName, syntax, initialValue);\n }\n\n const dependents = this.reverseDeps.get(propName);\n if (dependents) {\n this.reverseDeps.delete(propName);\n\n for (const dependent of dependents) {\n this.pendingDeps.delete(dependent);\n\n if (isPropertyDefined(dependent)) continue;\n\n this.resolve(\n dependent,\n syntax,\n initialValue,\n isPropertyDefined,\n registerProperty,\n resolving,\n );\n }\n }\n }\n\n private isComplexValue(value: string): boolean {\n if (value.includes('calc(')) return true;\n const firstVar = value.indexOf('var(');\n if (firstVar === -1) return false;\n if (value.indexOf('var(', firstVar + 4) !== -1) return true;\n return !SINGLE_VAR_REF.test(value);\n }\n}\n"],"mappings":";;;;;;;;;AASA,MAAM,mBAAmB;AACzB,MAAM,iBAAiB;AAEvB,IAAa,uBAAb,MAAkC;;CAEhC,AAAQ,8BAAc,IAAI,KAAqB;;CAE/C,AAAQ,8BAAc,IAAI,KAAuB;;;;;CAMjD,iBACE,cACA,mBACA,kBAKM;AACN,MAAI,CAAC,aAAa,SAAS,KAAK,CAAE;EAElC,MAAM,QAAQ,aAAa,MAAM,KAAK;AAEtC,OAAK,MAAM,QAAQ,OAAO;AACxB,OAAI,CAAC,KAAK,MAAM,CAAE;GAElB,MAAM,QAAQ,iBAAiB,KAAK,KAAK;AACzC,OAAI,CAAC,MAAO;GAEZ,MAAM,WAAW,MAAM;GACvB,MAAM,QAAQ,MAAM,GAAG,MAAM;AAE7B,OAAI,kBAAkB,SAAS,CAAE;AAGjC,OAAI,SAAS,SAAS,SAAS,EAAE;AAC/B,qBAAiB,UAAU,WAAW,cAAc;AACpD;;GAIF,MAAM,WAAW,eAAe,KAAK,MAAM;AAC3C,OAAI,UAAU;IACZ,MAAM,UAAU,SAAS;AACzB,SAAK,cAAc,UAAU,QAAQ;AACrC;;AAIF,OAAI,KAAK,eAAe,MAAM,CAAE;GAEhC,MAAM,WAAW,qBAAqB,MAAM;AAC5C,OAAI,CAAC,SAAU;AAEf,QAAK,QACH,UACA,SAAS,QACT,SAAS,cACT,mBACA,iBACD;;;CAIL,AAAQ,cAAc,UAAkB,SAAuB;AAC7D,MAAI,aAAa,QAAS;AAE1B,OAAK,YAAY,IAAI,UAAU,QAAQ;EAEvC,IAAI,aAAa,KAAK,YAAY,IAAI,QAAQ;AAC9C,MAAI,CAAC,YAAY;AACf,gBAAa,EAAE;AACf,QAAK,YAAY,IAAI,SAAS,WAAW;;AAE3C,MAAI,CAAC,WAAW,SAAS,SAAS,CAChC,YAAW,KAAK,SAAS;;CAI7B,AAAQ,QACN,UACA,QACA,cACA,mBACA,kBAKA,WACM;AACN,MAAI,CAAC,UAAW,6BAAY,IAAI,KAAK;AACrC,MAAI,UAAU,IAAI,SAAS,CAAE;AAC7B,YAAU,IAAI,SAAS;AAEvB,MAAI,CAAC,kBAAkB,SAAS,CAC9B,kBAAiB,UAAU,QAAQ,aAAa;EAGlD,MAAM,aAAa,KAAK,YAAY,IAAI,SAAS;AACjD,MAAI,YAAY;AACd,QAAK,YAAY,OAAO,SAAS;AAEjC,QAAK,MAAM,aAAa,YAAY;AAClC,SAAK,YAAY,OAAO,UAAU;AAElC,QAAI,kBAAkB,UAAU,CAAE;AAElC,SAAK,QACH,WACA,QACA,cACA,mBACA,kBACA,UACD;;;;CAKP,AAAQ,eAAe,OAAwB;AAC7C,MAAI,MAAM,SAAS,QAAQ,CAAE,QAAO;EACpC,MAAM,WAAW,MAAM,QAAQ,OAAO;AACtC,MAAI,aAAa,GAAI,QAAO;AAC5B,MAAI,MAAM,QAAQ,QAAQ,WAAW,EAAE,KAAK,GAAI,QAAO;AACvD,SAAO,CAAC,eAAe,KAAK,MAAM"}
|
package/dist/styles/fill.js
CHANGED
|
@@ -10,13 +10,14 @@ function fillStyle({ fill, backgroundColor, image, backgroundImage, backgroundPo
|
|
|
10
10
|
const firstColor = parsed.groups[0]?.colors[0];
|
|
11
11
|
const secondColor = parsed.groups[0]?.colors[1];
|
|
12
12
|
result["background-color"] = firstColor || colorValue;
|
|
13
|
-
if (secondColor
|
|
14
|
-
result["--tasty-second-fill-color"] = secondColor;
|
|
15
|
-
result["background-image"] = "linear-gradient(var(--tasty-second-fill-color), var(--tasty-second-fill-color))";
|
|
16
|
-
}
|
|
13
|
+
if (secondColor) result["--tasty-second-fill-color"] = secondColor;
|
|
17
14
|
}
|
|
15
|
+
const gradientLayer = result["--tasty-second-fill-color"] ? "linear-gradient(var(--tasty-second-fill-color), var(--tasty-second-fill-color))" : null;
|
|
18
16
|
const imageValue = backgroundImage ?? image;
|
|
19
|
-
if (imageValue)
|
|
17
|
+
if (imageValue) {
|
|
18
|
+
const imgCss = parseStyle(imageValue).output || imageValue;
|
|
19
|
+
result["background-image"] = gradientLayer ? `${imgCss}, ${gradientLayer}` : imgCss;
|
|
20
|
+
} else if (gradientLayer) result["background-image"] = gradientLayer;
|
|
20
21
|
if (backgroundPosition) result["background-position"] = parseStyle(backgroundPosition).output || backgroundPosition;
|
|
21
22
|
if (backgroundSize) result["background-size"] = parseStyle(backgroundSize).output || backgroundSize;
|
|
22
23
|
if (backgroundRepeat) result["background-repeat"] = backgroundRepeat;
|
package/dist/styles/fill.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fill.js","names":[],"sources":["../../src/styles/fill.ts"],"sourcesContent":["import { parseStyle } from '../utils/styles';\n\nexport function fillStyle({\n fill,\n backgroundColor,\n image,\n backgroundImage,\n backgroundPosition,\n backgroundSize,\n backgroundRepeat,\n backgroundAttachment,\n backgroundOrigin,\n backgroundClip,\n background,\n}: {\n fill?: string;\n backgroundColor?: string;\n image?: string;\n backgroundImage?: string;\n backgroundPosition?: string;\n backgroundSize?: string;\n backgroundRepeat?: string;\n backgroundAttachment?: string;\n backgroundOrigin?: string;\n backgroundClip?: string;\n background?: string;\n}) {\n // If background is set, it overrides everything\n if (background) {\n const processed = parseStyle(background);\n return { background: processed.output || background };\n }\n\n const result: Record<string, string> = {};\n\n // Priority: backgroundColor > fill\n const colorValue = backgroundColor ?? fill;\n if (colorValue) {\n const parsed = parseStyle(colorValue);\n const firstColor = parsed.groups[0]?.colors[0];\n const secondColor = parsed.groups[0]?.colors[1];\n\n result['background-color'] = firstColor || colorValue;\n\n
|
|
1
|
+
{"version":3,"file":"fill.js","names":[],"sources":["../../src/styles/fill.ts"],"sourcesContent":["import { parseStyle } from '../utils/styles';\n\nexport function fillStyle({\n fill,\n backgroundColor,\n image,\n backgroundImage,\n backgroundPosition,\n backgroundSize,\n backgroundRepeat,\n backgroundAttachment,\n backgroundOrigin,\n backgroundClip,\n background,\n}: {\n fill?: string;\n backgroundColor?: string;\n image?: string;\n backgroundImage?: string;\n backgroundPosition?: string;\n backgroundSize?: string;\n backgroundRepeat?: string;\n backgroundAttachment?: string;\n backgroundOrigin?: string;\n backgroundClip?: string;\n background?: string;\n}) {\n // If background is set, it overrides everything\n if (background) {\n const processed = parseStyle(background);\n return { background: processed.output || background };\n }\n\n const result: Record<string, string> = {};\n\n // Priority: backgroundColor > fill\n const colorValue = backgroundColor ?? fill;\n if (colorValue) {\n const parsed = parseStyle(colorValue);\n const firstColor = parsed.groups[0]?.colors[0];\n const secondColor = parsed.groups[0]?.colors[1];\n\n result['background-color'] = firstColor || colorValue;\n\n if (secondColor) {\n result['--tasty-second-fill-color'] = secondColor;\n }\n }\n\n const gradientLayer = result['--tasty-second-fill-color']\n ? 'linear-gradient(var(--tasty-second-fill-color), var(--tasty-second-fill-color))'\n : null;\n\n // Priority: backgroundImage > image\n const imageValue = backgroundImage ?? image;\n if (imageValue) {\n const parsed = parseStyle(imageValue);\n const imgCss = parsed.output || imageValue;\n\n result['background-image'] = gradientLayer\n ? `${imgCss}, ${gradientLayer}`\n : imgCss;\n } else if (gradientLayer) {\n result['background-image'] = gradientLayer;\n }\n\n // Other background properties (pass through with parseStyle for token support)\n if (backgroundPosition) {\n result['background-position'] =\n parseStyle(backgroundPosition).output || backgroundPosition;\n }\n if (backgroundSize) {\n result['background-size'] =\n parseStyle(backgroundSize).output || backgroundSize;\n }\n if (backgroundRepeat) {\n result['background-repeat'] = backgroundRepeat;\n }\n if (backgroundAttachment) {\n result['background-attachment'] = backgroundAttachment;\n }\n if (backgroundOrigin) {\n result['background-origin'] = backgroundOrigin;\n }\n if (backgroundClip) {\n result['background-clip'] = backgroundClip;\n }\n\n if (Object.keys(result).length === 0) return;\n return result;\n}\n\nfillStyle.__lookupStyles = [\n 'fill',\n 'backgroundColor',\n 'image',\n 'backgroundImage',\n 'backgroundPosition',\n 'backgroundSize',\n 'backgroundRepeat',\n 'backgroundAttachment',\n 'backgroundOrigin',\n 'backgroundClip',\n 'background',\n];\n\nexport function svgFillStyle({ svgFill }: { svgFill?: string }) {\n if (!svgFill) return;\n\n const processed = parseStyle(svgFill);\n svgFill = processed.groups[0]?.colors[0] || svgFill;\n\n return { fill: svgFill };\n}\n\nsvgFillStyle.__lookupStyles = ['svgFill'];\n"],"mappings":";;;AAEA,SAAgB,UAAU,EACxB,MACA,iBACA,OACA,iBACA,oBACA,gBACA,kBACA,sBACA,kBACA,gBACA,cAaC;AAED,KAAI,WAEF,QAAO,EAAE,YADS,WAAW,WAAW,CACT,UAAU,YAAY;CAGvD,MAAM,SAAiC,EAAE;CAGzC,MAAM,aAAa,mBAAmB;AACtC,KAAI,YAAY;EACd,MAAM,SAAS,WAAW,WAAW;EACrC,MAAM,aAAa,OAAO,OAAO,IAAI,OAAO;EAC5C,MAAM,cAAc,OAAO,OAAO,IAAI,OAAO;AAE7C,SAAO,sBAAsB,cAAc;AAE3C,MAAI,YACF,QAAO,+BAA+B;;CAI1C,MAAM,gBAAgB,OAAO,+BACzB,oFACA;CAGJ,MAAM,aAAa,mBAAmB;AACtC,KAAI,YAAY;EAEd,MAAM,SADS,WAAW,WAAW,CACf,UAAU;AAEhC,SAAO,sBAAsB,gBACzB,GAAG,OAAO,IAAI,kBACd;YACK,cACT,QAAO,sBAAsB;AAI/B,KAAI,mBACF,QAAO,yBACL,WAAW,mBAAmB,CAAC,UAAU;AAE7C,KAAI,eACF,QAAO,qBACL,WAAW,eAAe,CAAC,UAAU;AAEzC,KAAI,iBACF,QAAO,uBAAuB;AAEhC,KAAI,qBACF,QAAO,2BAA2B;AAEpC,KAAI,iBACF,QAAO,uBAAuB;AAEhC,KAAI,eACF,QAAO,qBAAqB;AAG9B,KAAI,OAAO,KAAK,OAAO,CAAC,WAAW,EAAG;AACtC,QAAO;;AAGT,UAAU,iBAAiB;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,SAAgB,aAAa,EAAE,WAAiC;AAC9D,KAAI,CAAC,QAAS;AAGd,WADkB,WAAW,QAAQ,CACjB,OAAO,IAAI,OAAO,MAAM;AAE5C,QAAO,EAAE,MAAM,SAAS;;AAG1B,aAAa,iBAAiB,CAAC,UAAU"}
|
package/dist/utils/styles.js
CHANGED
|
@@ -200,12 +200,173 @@ function parseColor(val, ignoreError = false) {
|
|
|
200
200
|
opacity
|
|
201
201
|
};
|
|
202
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* CSS named color keywords → hex values.
|
|
205
|
+
* Lazy-initialized on first use to avoid up-front cost.
|
|
206
|
+
*/
|
|
207
|
+
let _namedColorHex = null;
|
|
208
|
+
function getNamedColorHex() {
|
|
209
|
+
if (_namedColorHex) return _namedColorHex;
|
|
210
|
+
_namedColorHex = new Map([
|
|
211
|
+
["aliceblue", "#f0f8ff"],
|
|
212
|
+
["antiquewhite", "#faebd7"],
|
|
213
|
+
["aqua", "#00ffff"],
|
|
214
|
+
["aquamarine", "#7fffd4"],
|
|
215
|
+
["azure", "#f0ffff"],
|
|
216
|
+
["beige", "#f5f5dc"],
|
|
217
|
+
["bisque", "#ffe4c4"],
|
|
218
|
+
["black", "#000000"],
|
|
219
|
+
["blanchedalmond", "#ffebcd"],
|
|
220
|
+
["blue", "#0000ff"],
|
|
221
|
+
["blueviolet", "#8a2be2"],
|
|
222
|
+
["brown", "#a52a2a"],
|
|
223
|
+
["burlywood", "#deb887"],
|
|
224
|
+
["cadetblue", "#5f9ea0"],
|
|
225
|
+
["chartreuse", "#7fff00"],
|
|
226
|
+
["chocolate", "#d2691e"],
|
|
227
|
+
["coral", "#ff7f50"],
|
|
228
|
+
["cornflowerblue", "#6495ed"],
|
|
229
|
+
["cornsilk", "#fff8dc"],
|
|
230
|
+
["crimson", "#dc143c"],
|
|
231
|
+
["cyan", "#00ffff"],
|
|
232
|
+
["darkblue", "#00008b"],
|
|
233
|
+
["darkcyan", "#008b8b"],
|
|
234
|
+
["darkgoldenrod", "#b8860b"],
|
|
235
|
+
["darkgray", "#a9a9a9"],
|
|
236
|
+
["darkgreen", "#006400"],
|
|
237
|
+
["darkgrey", "#a9a9a9"],
|
|
238
|
+
["darkkhaki", "#bdb76b"],
|
|
239
|
+
["darkmagenta", "#8b008b"],
|
|
240
|
+
["darkolivegreen", "#556b2f"],
|
|
241
|
+
["darkorange", "#ff8c00"],
|
|
242
|
+
["darkorchid", "#9932cc"],
|
|
243
|
+
["darkred", "#8b0000"],
|
|
244
|
+
["darksalmon", "#e9967a"],
|
|
245
|
+
["darkseagreen", "#8fbc8f"],
|
|
246
|
+
["darkslateblue", "#483d8b"],
|
|
247
|
+
["darkslategray", "#2f4f4f"],
|
|
248
|
+
["darkslategrey", "#2f4f4f"],
|
|
249
|
+
["darkturquoise", "#00ced1"],
|
|
250
|
+
["darkviolet", "#9400d3"],
|
|
251
|
+
["deeppink", "#ff1493"],
|
|
252
|
+
["deepskyblue", "#00bfff"],
|
|
253
|
+
["dimgray", "#696969"],
|
|
254
|
+
["dimgrey", "#696969"],
|
|
255
|
+
["dodgerblue", "#1e90ff"],
|
|
256
|
+
["firebrick", "#b22222"],
|
|
257
|
+
["floralwhite", "#fffaf0"],
|
|
258
|
+
["forestgreen", "#228b22"],
|
|
259
|
+
["fuchsia", "#ff00ff"],
|
|
260
|
+
["gainsboro", "#dcdcdc"],
|
|
261
|
+
["ghostwhite", "#f8f8ff"],
|
|
262
|
+
["gold", "#ffd700"],
|
|
263
|
+
["goldenrod", "#daa520"],
|
|
264
|
+
["gray", "#808080"],
|
|
265
|
+
["green", "#008000"],
|
|
266
|
+
["greenyellow", "#adff2f"],
|
|
267
|
+
["grey", "#808080"],
|
|
268
|
+
["honeydew", "#f0fff0"],
|
|
269
|
+
["hotpink", "#ff69b4"],
|
|
270
|
+
["indianred", "#cd5c5c"],
|
|
271
|
+
["indigo", "#4b0082"],
|
|
272
|
+
["ivory", "#fffff0"],
|
|
273
|
+
["khaki", "#f0e68c"],
|
|
274
|
+
["lavender", "#e6e6fa"],
|
|
275
|
+
["lavenderblush", "#fff0f5"],
|
|
276
|
+
["lawngreen", "#7cfc00"],
|
|
277
|
+
["lemonchiffon", "#fffacd"],
|
|
278
|
+
["lightblue", "#add8e6"],
|
|
279
|
+
["lightcoral", "#f08080"],
|
|
280
|
+
["lightcyan", "#e0ffff"],
|
|
281
|
+
["lightgoldenrodyellow", "#fafad2"],
|
|
282
|
+
["lightgray", "#d3d3d3"],
|
|
283
|
+
["lightgreen", "#90ee90"],
|
|
284
|
+
["lightgrey", "#d3d3d3"],
|
|
285
|
+
["lightpink", "#ffb6c1"],
|
|
286
|
+
["lightsalmon", "#ffa07a"],
|
|
287
|
+
["lightseagreen", "#20b2aa"],
|
|
288
|
+
["lightskyblue", "#87cefa"],
|
|
289
|
+
["lightslategray", "#778899"],
|
|
290
|
+
["lightslategrey", "#778899"],
|
|
291
|
+
["lightsteelblue", "#b0c4de"],
|
|
292
|
+
["lightyellow", "#ffffe0"],
|
|
293
|
+
["lime", "#00ff00"],
|
|
294
|
+
["limegreen", "#32cd32"],
|
|
295
|
+
["linen", "#faf0e6"],
|
|
296
|
+
["magenta", "#ff00ff"],
|
|
297
|
+
["maroon", "#800000"],
|
|
298
|
+
["mediumaquamarine", "#66cdaa"],
|
|
299
|
+
["mediumblue", "#0000cd"],
|
|
300
|
+
["mediumorchid", "#ba55d3"],
|
|
301
|
+
["mediumpurple", "#9370db"],
|
|
302
|
+
["mediumseagreen", "#3cb371"],
|
|
303
|
+
["mediumslateblue", "#7b68ee"],
|
|
304
|
+
["mediumspringgreen", "#00fa9a"],
|
|
305
|
+
["mediumturquoise", "#48d1cc"],
|
|
306
|
+
["mediumvioletred", "#c71585"],
|
|
307
|
+
["midnightblue", "#191970"],
|
|
308
|
+
["mintcream", "#f5fffa"],
|
|
309
|
+
["mistyrose", "#ffe4e1"],
|
|
310
|
+
["moccasin", "#ffe4b5"],
|
|
311
|
+
["navajowhite", "#ffdead"],
|
|
312
|
+
["navy", "#000080"],
|
|
313
|
+
["oldlace", "#fdf5e6"],
|
|
314
|
+
["olive", "#808000"],
|
|
315
|
+
["olivedrab", "#6b8e23"],
|
|
316
|
+
["orange", "#ffa500"],
|
|
317
|
+
["orangered", "#ff4500"],
|
|
318
|
+
["orchid", "#da70d6"],
|
|
319
|
+
["palegoldenrod", "#eee8aa"],
|
|
320
|
+
["palegreen", "#98fb98"],
|
|
321
|
+
["paleturquoise", "#afeeee"],
|
|
322
|
+
["palevioletred", "#db7093"],
|
|
323
|
+
["papayawhip", "#ffefd5"],
|
|
324
|
+
["peachpuff", "#ffdab9"],
|
|
325
|
+
["peru", "#cd853f"],
|
|
326
|
+
["pink", "#ffc0cb"],
|
|
327
|
+
["plum", "#dda0dd"],
|
|
328
|
+
["powderblue", "#b0e0e6"],
|
|
329
|
+
["purple", "#800080"],
|
|
330
|
+
["rebeccapurple", "#663399"],
|
|
331
|
+
["red", "#ff0000"],
|
|
332
|
+
["rosybrown", "#bc8f8f"],
|
|
333
|
+
["royalblue", "#4169e1"],
|
|
334
|
+
["saddlebrown", "#8b4513"],
|
|
335
|
+
["salmon", "#fa8072"],
|
|
336
|
+
["sandybrown", "#f4a460"],
|
|
337
|
+
["seagreen", "#2e8b57"],
|
|
338
|
+
["seashell", "#fff5ee"],
|
|
339
|
+
["sienna", "#a0522d"],
|
|
340
|
+
["silver", "#c0c0c0"],
|
|
341
|
+
["skyblue", "#87ceeb"],
|
|
342
|
+
["slateblue", "#6a5acd"],
|
|
343
|
+
["slategray", "#708090"],
|
|
344
|
+
["slategrey", "#708090"],
|
|
345
|
+
["snow", "#fffafa"],
|
|
346
|
+
["springgreen", "#00ff7f"],
|
|
347
|
+
["steelblue", "#4682b4"],
|
|
348
|
+
["tan", "#d2b48c"],
|
|
349
|
+
["teal", "#008080"],
|
|
350
|
+
["thistle", "#d8bfd8"],
|
|
351
|
+
["tomato", "#ff6347"],
|
|
352
|
+
["turquoise", "#40e0d0"],
|
|
353
|
+
["violet", "#ee82ee"],
|
|
354
|
+
["wheat", "#f5deb3"],
|
|
355
|
+
["white", "#ffffff"],
|
|
356
|
+
["whitesmoke", "#f5f5f5"],
|
|
357
|
+
["yellow", "#ffff00"],
|
|
358
|
+
["yellowgreen", "#9acd32"]
|
|
359
|
+
]);
|
|
360
|
+
return _namedColorHex;
|
|
361
|
+
}
|
|
203
362
|
function strToRgb(color, _ignoreAlpha = false) {
|
|
204
363
|
if (!color) return void 0;
|
|
205
364
|
if (color.startsWith("rgb")) return color;
|
|
206
365
|
if (color.startsWith("#")) return hexToRgb(color);
|
|
207
366
|
if (color.startsWith("okhsl(")) return okhslToRgb(color);
|
|
208
367
|
if (color.startsWith("hsl")) return hslToRgb(color);
|
|
368
|
+
const namedHex = getNamedColorHex().get(color.toLowerCase());
|
|
369
|
+
if (namedHex) return hexToRgb(namedHex);
|
|
209
370
|
return null;
|
|
210
371
|
}
|
|
211
372
|
/**
|