@tenphi/tasty 0.15.1 → 0.15.3
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/dist/config.js +4 -2
- package/dist/config.js.map +1 -1
- package/dist/tasty.d.ts +14 -9
- package/dist/tasty.js.map +1 -1
- package/dist/zero/babel.js +3 -1
- package/dist/zero/babel.js.map +1 -1
- package/package.json +1 -1
package/dist/config.js
CHANGED
|
@@ -376,8 +376,10 @@ function configure(config = {}) {
|
|
|
376
376
|
const tokenKeys = new Set(Object.keys(mergedConfigTokens));
|
|
377
377
|
for (const key of Object.keys(mergedReplaceTokens)) if (tokenKeys.has(key)) warnOnce(`token-conflict-${key}`, `[Tasty] Token "${key}" is defined in both \`tokens\` and \`replaceTokens\`. \`replaceTokens\` performs parse-time substitution, so the \`tokens\` CSS custom property will be injected but never used by Tasty styles. Remove it from one of the two.`);
|
|
378
378
|
}
|
|
379
|
-
|
|
380
|
-
|
|
379
|
+
if (config.colorSpace) {
|
|
380
|
+
setColorSpace(config.colorSpace);
|
|
381
|
+
getGlobalParser().clearCache();
|
|
382
|
+
}
|
|
381
383
|
if (Object.keys(mergedStates).length > 0) setGlobalPredefinedStates(mergedStates);
|
|
382
384
|
const parser = getGlobalParser();
|
|
383
385
|
if (config.parserCacheSize !== void 0) parser.updateOptions({ cacheSize: config.parserCacheSize });
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["/**\n * Tasty Configuration Module\n *\n * Centralizes all tasty configuration, including:\n * - Style injector settings (nonce, cleanup thresholds, etc.)\n * - Global predefined states for advanced state mapping\n * - stylesGenerated flag that locks configuration after first style generation\n *\n * Configuration must be done BEFORE any styles are generated.\n * After the first `inject()` call, configuration is locked and attempts to\n * reconfigure will emit a warning and be ignored.\n */\n\nimport { StyleInjector } from './injector/injector';\nimport { clearPipelineCache, isSelector, renderStyles } from './pipeline';\nimport { setGlobalPredefinedStates } from './states';\nimport {\n normalizeHandlerDefinition,\n registerHandler,\n resetHandlers,\n} from './styles/predefined';\nimport { resetColorSpace, setColorSpace } from './utils/color-space';\nimport { isDevEnv } from './utils/is-dev-env';\nimport {\n CUSTOM_UNITS,\n getGlobalFuncs,\n getGlobalParser,\n normalizeColorTokenValue,\n resetGlobalPredefinedTokens,\n setGlobalPredefinedTokens,\n} from './utils/styles';\n\nimport type { ColorSpace } from './utils/color-space';\n\nimport type { KeyframesSteps, PropertyDefinition } from './injector/types';\nimport type { StyleDetails, UnitHandler } from './parser/types';\nimport type { StyleResult } from './pipeline';\nimport type { TastyPlugin } from './plugins/types';\nimport type { RecipeStyles, ConfigTokens } from './styles/types';\nimport type { StyleHandlerDefinition } from './utils/styles';\n\n/**\n * Configuration options for the Tasty style system\n */\nexport interface TastyConfig {\n /** CSP nonce for style elements */\n nonce?: string;\n /** Maximum rules per stylesheet (default: 8192) */\n maxRulesPerSheet?: number;\n /** Threshold for bulk cleanup of unused styles (default: 500) */\n unusedStylesThreshold?: number;\n /** Delay before bulk cleanup in ms, ignored if idleCleanup is true (default: 5000) */\n bulkCleanupDelay?: number;\n /** Use requestIdleCallback for cleanup when available (default: true) */\n idleCleanup?: boolean;\n /** Force text injection mode, auto-detected in test environments (default: auto) */\n forceTextInjection?: boolean;\n /** Enable development mode features: performance metrics and debug info (default: auto) */\n devMode?: boolean;\n /**\n * Ratio of unused styles to delete per bulk cleanup run (0..1).\n * Defaults to 0.5 (oldest half) to reduce risk of removing styles\n * that may be restored shortly after being marked unused.\n */\n bulkCleanupBatchRatio?: number;\n /**\n * Minimum age (in ms) a style must remain unused before eligible for deletion.\n * Helps avoid races during rapid mount/unmount cycles. Default: 10000ms.\n */\n unusedStylesMinAgeMs?: number;\n /**\n * Global predefined states for advanced state mapping.\n * These are state aliases that can be used in any component.\n * Example: { '@mobile': '@media(w < 920px)', '@dark': '@root(theme=dark)' }\n */\n states?: Record<string, string>;\n /**\n * Parser LRU cache size (default: 1000).\n * Larger values improve performance for apps with many unique style values.\n */\n parserCacheSize?: number;\n /**\n * Custom units for the style parser (merged with built-in units).\n * Units transform numeric values like `2x` → `calc(2 * var(--gap))`.\n * @example { em: 'em', vw: 'vw', custom: (n) => `${n * 10}px` }\n */\n units?: Record<string, string | UnitHandler>;\n /**\n * Custom functions for the style parser (merged with existing).\n * Functions process parsed style groups and return CSS values.\n * @example { myFunc: (groups) => groups.map(g => g.output).join(' ') }\n */\n funcs?: Record<string, (groups: StyleDetails[]) => string>;\n /**\n * Color space used for decomposed color token companion variables.\n * Controls the CSS function and suffix for alpha composition.\n *\n * - `'rgb'` — suffix `-rgb`, e.g. `rgb(var(--name-color-rgb) / .5)`\n * - `'hsl'` — suffix `-hsl`, e.g. `hsl(var(--name-color-hsl) / .5)`\n * - `'oklch'` — suffix `-oklch`, e.g. `oklch(var(--name-color-oklch) / .5)`\n *\n * @default 'oklch'\n */\n colorSpace?: ColorSpace;\n /**\n * Automatically infer and register CSS @property declarations\n * from custom property values found in styles, keyframes, and global config.\n * Covers all types: \\<color\\>, \\<number\\>, \\<length\\>, \\<angle\\>, \\<percentage\\>, \\<time\\>.\n * When false, only explicitly declared @properties are registered.\n * @default true\n */\n autoPropertyTypes?: boolean;\n /**\n * Plugins that extend tasty with custom functions, units, or states.\n * Plugins are processed in order, with later plugins overriding earlier ones.\n * @example\n * ```ts\n * import { okhslPlugin } from '@tenphi/tasty';\n *\n * configure({\n * plugins: [okhslPlugin()],\n * });\n * ```\n */\n plugins?: TastyPlugin[];\n /**\n * Global keyframes definitions that can be referenced by animation names in styles.\n * Keys are animation names, values are keyframes step definitions.\n * Keyframes are only injected when actually used in styles.\n * @example\n * ```ts\n * configure({\n * keyframes: {\n * fadeIn: { from: { opacity: 0 }, to: { opacity: 1 } },\n * pulse: { '0%, 100%': { transform: 'scale(1)' }, '50%': { transform: 'scale(1.05)' } },\n * },\n * });\n * ```\n */\n keyframes?: Record<string, KeyframesSteps>;\n /**\n * Global CSS @property definitions for custom properties.\n * Keys use tasty token syntax ($name for properties, #name for colors).\n * Properties are only injected when the component using them is rendered.\n *\n * For color tokens (#name), `syntax: '<color>'` is auto-set and\n * `initialValue` defaults to `'transparent'` if not specified.\n *\n * @example\n * ```ts\n * configure({\n * properties: {\n * '$rotation': { syntax: '<angle>', initialValue: '0deg' },\n * '$scale': { syntax: '<number>', inherits: false, initialValue: 1 },\n * '#accent': { initialValue: 'purple' }, // syntax: '<color>' auto-set\n * },\n * });\n *\n * // Now use in styles - properties are registered when component renders:\n * const Spinner = tasty({\n * styles: {\n * transform: 'rotate($rotation)',\n * transition: '$$rotation 0.3s', // outputs: --rotation 0.3s\n * },\n * });\n * ```\n */\n properties?: Record<string, PropertyDefinition>;\n /**\n * Custom style handlers that transform style properties into CSS declarations.\n * Handlers replace built-in handlers for the same style name.\n * @example\n * ```ts\n * import { styleHandlers } from '@tenphi/tasty';\n *\n * configure({\n * handlers: {\n * // Override fill with custom behavior\n * fill: ({ fill }) => {\n * if (fill?.startsWith('gradient:')) {\n * return { background: fill.slice(9) };\n * }\n * return styleHandlers.fill({ fill });\n * },\n * // Add new custom style\n * elevation: ({ elevation }) => {\n * const level = parseInt(elevation) || 1;\n * return {\n * 'box-shadow': `0 ${level * 2}px ${level * 4}px rgba(0,0,0,0.1)`,\n * 'z-index': String(level * 100),\n * };\n * },\n * },\n * });\n * ```\n */\n handlers?: Record<string, StyleHandlerDefinition>;\n /**\n * Design tokens injected as CSS custom properties on `:root`.\n * Values are parsed through the Tasty DSL. Supports state maps\n * for responsive/theme-aware tokens.\n *\n * - `$name` keys become `--name` CSS custom properties\n * - `#name` keys become `--name-color` and `--name-color-{colorSpace}` properties\n *\n * Tokens are injected once when the first style is rendered.\n *\n * @example\n * ```ts\n * configure({\n * tokens: {\n * '$gap': '4px',\n * '#primary': {\n * '': '#purple',\n * '@dark': '#light-purple',\n * },\n * },\n * });\n * ```\n */\n tokens?: ConfigTokens;\n /**\n * Predefined tokens that are replaced during style parsing (parse-time substitution).\n * Use `$name` for custom properties and `#name` for color tokens.\n * Values are substituted inline before CSS generation, unlike `tokens` which\n * inject CSS custom properties on `:root`.\n *\n * For color tokens (#name), boolean `true` is converted to `transparent`.\n *\n * @example\n * ```ts\n * configure({\n * replaceTokens: {\n * $spacing: '2x',\n * '#accent': '#purple',\n * '#overlay': true, // → transparent\n * },\n * });\n *\n * // Now use in styles - tokens are replaced at parse time:\n * const Card = tasty({\n * styles: {\n * padding: '$spacing', // → calc(2 * var(--gap))\n * fill: '#accent', // → var(--purple-color)\n * },\n * });\n * ```\n */\n replaceTokens?: Record<`$${string}`, string | number | boolean> &\n Record<`#${string}`, string | number | boolean>;\n /**\n * Predefined style recipes -- named style bundles that can be applied via `recipe` style property.\n * Recipe values are flat tasty styles (no sub-element keys). They may contain base styles,\n * tokens (`$name`/`#name` definitions), local states, `@keyframes`, and `@properties`.\n *\n * Components reference recipes via: `recipe: 'name1 name2'` in their styles.\n * Use `/` to separate base recipes from post recipes: `recipe: 'base1 base2 / post1'`.\n * Use `none` to skip base recipes: `recipe: 'none / post1'`.\n * Resolution order: `base_recipes → component styles → post_recipes`.\n *\n * Recipes cannot reference other recipes.\n *\n * @example\n * ```ts\n * configure({\n * recipes: {\n * card: { padding: '4x', fill: '#surface', radius: '1r', border: true },\n * elevated: { shadow: '2x 2x 4x #shadow' },\n * },\n * });\n *\n * // Usage in styles:\n * const Card = tasty({\n * styles: {\n * recipe: 'card elevated',\n * color: '#text', // Overrides recipe values\n * },\n * });\n * ```\n */\n recipes?: Record<string, RecipeStyles>;\n}\n\n// Warnings tracking to avoid duplicates\nconst emittedWarnings = new Set<string>();\n\nconst devMode = isDevEnv();\n\n/**\n * Emit a warning only once\n */\nfunction warnOnce(key: string, message: string): void {\n if (devMode && !emittedWarnings.has(key)) {\n emittedWarnings.add(key);\n console.warn(message);\n }\n}\n\n// ============================================================================\n// Configuration State\n// ============================================================================\n\n// Track whether styles have been generated (locks configuration)\nlet stylesGenerated = false;\n\n// Current configuration (null until first configure() or auto-configured on first use)\nlet currentConfig: TastyConfig | null = null;\n\n// Global keyframes storage (null = no keyframes configured, empty object checked via hasGlobalKeyframes)\nlet globalKeyframes: Record<string, KeyframesSteps> | null = null;\n\n// Global properties storage (null = no properties configured)\nlet globalProperties: Record<string, PropertyDefinition> | null = null;\n\n// Global recipes storage (null = no recipes configured)\nlet globalRecipes: Record<string, RecipeStyles> | null = null;\n\n// Global token styles storage (injected as :root CSS custom properties)\nlet globalConfigTokens: ConfigTokens | null = null;\n\n/**\n * Internal properties required by tasty core features.\n * These are always injected when styles are first generated.\n * Keys use tasty token syntax (#name for colors, $name for other properties).\n *\n * For properties with CSS @property-compatible types (length, time, number, color),\n * an `initialValue` is provided so the property works even without a project-level token.\n */\nexport const INTERNAL_PROPERTIES: Record<string, PropertyDefinition> = {\n // Used by dual-fill feature to enable CSS transitions on the second fill color\n '#tasty-second-fill': {\n inherits: false,\n initialValue: 'transparent',\n },\n // Current color context variable (set by the color style handler).\n '#current': {\n inherits: true,\n initialValue: 'transparent',\n },\n // White and black are fundamental colors that need explicit initial values.\n '#white': {\n inherits: true,\n initialValue: 'rgb(255 255 255)',\n },\n '#black': {\n inherits: true,\n initialValue: 'rgb(0 0 0)',\n },\n\n // ---- Core design tokens used by style handlers ----\n // These provide sensible defaults so tasty works standalone without a design system.\n // Consuming projects (e.g. uikit) override these by defining tokens on :root.\n\n $gap: {\n syntax: '<length>',\n inherits: true,\n initialValue: '4px',\n },\n $radius: {\n syntax: '<length>',\n inherits: true,\n initialValue: '6px',\n },\n '$border-width': {\n syntax: '<length>',\n inherits: true,\n initialValue: '1px',\n },\n '$outline-width': {\n syntax: '<length>',\n inherits: true,\n initialValue: '3px',\n },\n $transition: {\n syntax: '<time>',\n inherits: true,\n initialValue: '80ms',\n },\n // Used by radius.ts for `radius=\"leaf\"` modifier\n '$sharp-radius': {\n syntax: '<length>',\n inherits: true,\n initialValue: '0px',\n },\n // Used by preset.ts for `preset=\"... strong\"`\n '$bold-font-weight': {\n syntax: '<number>',\n inherits: true,\n initialValue: '700',\n },\n};\n\n/**\n * Internal token defaults that cannot be expressed as CSS @property initial values\n * (e.g. font stacks, keyword colors). These are injected as :root CSS variables.\n * Consuming projects override them by setting their own tokens on :root.\n *\n * Keys are raw CSS custom property names (--name).\n */\nexport const INTERNAL_TOKENS: Record<string, string> = {\n '--font':\n 'system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\", sans-serif',\n '--monospace-font':\n 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace',\n // Default border color to the element's current text color\n '--border-color': 'currentColor',\n};\n\n// Global injector instance key\nconst GLOBAL_INJECTOR_KEY = '__TASTY_GLOBAL_INJECTOR__';\n\ninterface TastyGlobalStorage {\n [GLOBAL_INJECTOR_KEY]?: StyleInjector;\n}\n\ndeclare global {\n interface Window {\n [GLOBAL_INJECTOR_KEY]?: StyleInjector;\n }\n\n var __TASTY_GLOBAL_INJECTOR__: StyleInjector | undefined;\n}\n\n/**\n * Detect if we're running in a test environment\n */\nexport function isTestEnvironment(): boolean {\n // Check Node.js environment\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'test') {\n return true;\n }\n\n // Check for test runner globals (safely)\n if (typeof global !== 'undefined') {\n const g = global as unknown as Record<string, unknown>;\n if (g.vi || g.jest || g.expect || g.describe || g.it) {\n return true;\n }\n }\n\n // Check for jsdom environment (common in tests)\n if (\n typeof window !== 'undefined' &&\n window.navigator?.userAgent?.includes('jsdom')\n ) {\n return true;\n }\n\n // Check for other test runners\n if (typeof globalThis !== 'undefined') {\n const gt = globalThis as unknown as Record<string, unknown>;\n if (gt.vitest || gt.mocha) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Create default configuration with optional test environment detection\n */\nfunction createDefaultConfig(isTest?: boolean): TastyConfig {\n return {\n maxRulesPerSheet: 8192,\n unusedStylesThreshold: 500,\n bulkCleanupDelay: 5000,\n idleCleanup: true,\n forceTextInjection: isTest ?? false,\n devMode: isDevEnv(),\n bulkCleanupBatchRatio: 0.5,\n unusedStylesMinAgeMs: 10000,\n };\n}\n\n// ============================================================================\n// stylesGenerated Flag Management\n// ============================================================================\n\n/**\n * Mark that styles have been generated (called by injector on first inject)\n * This locks the configuration - no further changes allowed.\n * Also injects internal and global properties.\n */\nexport function markStylesGenerated(): void {\n if (stylesGenerated) return; // Already marked, skip\n\n stylesGenerated = true;\n\n const injector = getGlobalInjector();\n\n // Inject internal properties required by tasty core features\n for (const [token, definition] of Object.entries(INTERNAL_PROPERTIES)) {\n injector.property(token, definition);\n }\n\n // Inject internal token defaults as :root CSS variables.\n // Use injectGlobal (not injectRawCSS) so the rule goes through the same\n // injection path as all other tasty styles (consistent in both DOM and text/test mode).\n const internalTokenEntries = Object.entries(INTERNAL_TOKENS);\n if (internalTokenEntries.length > 0) {\n const declarations = internalTokenEntries\n .map(([name, value]) => `${name}: ${value}`)\n .join('; ');\n injector.injectGlobal([{ selector: ':root', declarations }]);\n }\n\n // Inject global properties if any were configured\n // Properties are permanent and only need to be injected once\n if (globalProperties && Object.keys(globalProperties).length > 0) {\n for (const [token, definition] of Object.entries(globalProperties)) {\n injector.property(token, definition);\n }\n }\n\n // Inject configured tokens as :root CSS custom properties\n if (globalConfigTokens && Object.keys(globalConfigTokens).length > 0) {\n const tokenRules = renderStyles(\n globalConfigTokens,\n ':root',\n ) as StyleResult[];\n if (tokenRules.length > 0) {\n injector.injectGlobal(tokenRules);\n }\n }\n}\n\n/**\n * Check if styles have been generated (configuration is locked)\n */\nexport function hasStylesGenerated(): boolean {\n return stylesGenerated;\n}\n\n/**\n * Reset styles generated flag (for testing only)\n */\nexport function resetStylesGenerated(): void {\n stylesGenerated = false;\n emittedWarnings.clear();\n}\n\n// ============================================================================\n// Global Keyframes Management\n// ============================================================================\n\nlet _hasGlobalKeyframes = false;\n\n/**\n * Check if any global keyframes are configured.\n * Uses a pre-computed flag to avoid Object.keys() allocation on every call.\n */\nexport function hasGlobalKeyframes(): boolean {\n return _hasGlobalKeyframes;\n}\n\n/**\n * Get global keyframes configuration.\n * Returns null if no keyframes configured (fast path for zero-overhead).\n */\nexport function getGlobalKeyframes(): Record<string, KeyframesSteps> | null {\n return globalKeyframes;\n}\n\n/**\n * Set global keyframes (called from configure).\n * Internal use only.\n */\nfunction setGlobalKeyframes(keyframes: Record<string, KeyframesSteps>): void {\n if (stylesGenerated) {\n warnOnce(\n 'keyframes-after-styles',\n `[Tasty] Cannot update keyframes after styles have been generated.\\n` +\n `The new keyframes will be ignored.`,\n );\n return;\n }\n globalKeyframes = keyframes;\n _hasGlobalKeyframes = Object.keys(keyframes).length > 0;\n}\n\n// ============================================================================\n// Global Properties Management\n// ============================================================================\n\n/**\n * Check if any global properties are configured.\n * Fast path: returns false if no properties were ever set.\n */\nexport function hasGlobalProperties(): boolean {\n return globalProperties !== null && Object.keys(globalProperties).length > 0;\n}\n\n/**\n * Get global properties configuration.\n * Returns null if no properties configured (fast path for zero-overhead).\n */\nexport function getGlobalProperties(): Record<\n string,\n PropertyDefinition\n> | null {\n return globalProperties;\n}\n\n/**\n * Set global properties (called from configure).\n * Internal use only.\n */\nfunction setGlobalProperties(\n properties: Record<string, PropertyDefinition>,\n): void {\n if (stylesGenerated) {\n warnOnce(\n 'properties-after-styles',\n `[Tasty] Cannot update properties after styles have been generated.\\n` +\n `The new properties will be ignored.`,\n );\n return;\n }\n globalProperties = properties;\n}\n\n// ============================================================================\n// Global Recipes Management\n// ============================================================================\n\n/**\n * Check if any global recipes are configured.\n * Fast path: returns false if no recipes were ever set.\n */\nexport function hasGlobalRecipes(): boolean {\n return globalRecipes !== null && Object.keys(globalRecipes).length > 0;\n}\n\n/**\n * Get global recipes configuration.\n * Returns null if no recipes configured (fast path for zero-overhead).\n */\nexport function getGlobalRecipes(): Record<string, RecipeStyles> | null {\n return globalRecipes;\n}\n\n/**\n * Set global recipes (called from configure).\n * Internal use only.\n */\nfunction setGlobalRecipes(recipes: Record<string, RecipeStyles>): void {\n if (stylesGenerated) {\n warnOnce(\n 'recipes-after-styles',\n `[Tasty] Cannot update recipes after styles have been generated.\\n` +\n `The new recipes will be ignored.`,\n );\n return;\n }\n\n // Dev-mode validation\n if (devMode) {\n for (const [name, recipeStyles] of Object.entries(recipes)) {\n if (name === 'none') {\n warnOnce(\n 'recipe-reserved-none',\n `[Tasty] Recipe name \"none\" is reserved. ` +\n `It is used as a keyword meaning \"no base recipes\" ` +\n `(e.g. recipe: 'none / post-recipe'). ` +\n `Choose a different name for your recipe.`,\n );\n }\n\n for (const key of Object.keys(recipeStyles)) {\n if (isSelector(key)) {\n warnOnce(\n `recipe-selector-${name}-${key}`,\n `[Tasty] Recipe \"${name}\" contains sub-element key \"${key}\". ` +\n `Recipes must be flat styles without sub-element keys. ` +\n `Remove the sub-element key from the recipe definition.`,\n );\n }\n if (key === 'recipe') {\n warnOnce(\n `recipe-recursive-${name}`,\n `[Tasty] Recipe \"${name}\" contains a \"recipe\" key. ` +\n `Recipes cannot reference other recipes. ` +\n `Use space-separated names for composition: recipe: 'base elevated'.`,\n );\n }\n }\n }\n }\n\n globalRecipes = recipes;\n}\n\n// ============================================================================\n// Global Token Styles Management\n// ============================================================================\n\n/**\n * Get global token styles for :root injection.\n * Returns null if no tokens configured.\n */\nexport function getGlobalConfigTokens(): ConfigTokens | null {\n return globalConfigTokens;\n}\n\n/**\n * Set global token styles (called from configure).\n * Internal use only.\n */\nfunction setGlobalConfigTokens(styles: ConfigTokens): void {\n if (stylesGenerated) {\n warnOnce(\n 'tokens-after-styles',\n `[Tasty] Cannot update tokens after styles have been generated.\\n` +\n `The new tokens will be ignored.`,\n );\n return;\n }\n globalConfigTokens = globalConfigTokens\n ? { ...globalConfigTokens, ...styles }\n : styles;\n}\n\n/**\n * Check if configuration is locked (styles have been generated)\n */\nexport function isConfigLocked(): boolean {\n return stylesGenerated;\n}\n\n// ============================================================================\n// Configuration API\n// ============================================================================\n\n/**\n * Configure the Tasty style system.\n *\n * Must be called BEFORE any styles are generated (before first render that uses tasty).\n * After styles are generated, configuration is locked and calls to configure() will\n * emit a warning and be ignored.\n *\n * @example\n * ```ts\n * import { configure } from '@tenphi/tasty';\n *\n * // Configure before app renders\n * configure({\n * nonce: 'abc123',\n * states: {\n * '@mobile': '@media(w < 768px)',\n * '@dark': '@root(theme=dark)',\n * },\n * });\n * ```\n */\nexport function configure(config: Partial<TastyConfig> = {}): void {\n if (stylesGenerated) {\n warnOnce(\n 'configure-after-styles',\n `[Tasty] Cannot call configure() after styles have been generated.\\n` +\n `Configuration must be done before the first render. The configuration will be ignored.`,\n );\n return;\n }\n\n // Collect merged values from plugins first, then override with direct config\n let mergedStates: Record<string, string> = {};\n let mergedUnits: Record<string, string | UnitHandler> = {};\n let mergedFuncs: Record<string, (groups: StyleDetails[]) => string> = {};\n let mergedHandlers: Record<string, StyleHandlerDefinition> = {};\n let mergedReplaceTokens: Record<string, string | number | boolean> = {};\n let mergedConfigTokens: ConfigTokens = {} as ConfigTokens;\n let mergedRecipes: Record<string, RecipeStyles> = {};\n\n // Process plugins in order\n if (config.plugins) {\n for (const plugin of config.plugins) {\n if (plugin.states) {\n mergedStates = { ...mergedStates, ...plugin.states };\n }\n if (plugin.units) {\n mergedUnits = { ...mergedUnits, ...plugin.units };\n }\n if (plugin.funcs) {\n mergedFuncs = { ...mergedFuncs, ...plugin.funcs };\n }\n if (plugin.handlers) {\n mergedHandlers = { ...mergedHandlers, ...plugin.handlers };\n }\n if (plugin.replaceTokens) {\n mergedReplaceTokens = {\n ...mergedReplaceTokens,\n ...plugin.replaceTokens,\n };\n }\n if (plugin.tokens) {\n mergedConfigTokens = { ...mergedConfigTokens, ...plugin.tokens };\n }\n if (plugin.recipes) {\n mergedRecipes = { ...mergedRecipes, ...plugin.recipes };\n }\n }\n }\n\n // Direct config overrides plugins\n if (config.states) {\n mergedStates = { ...mergedStates, ...config.states };\n }\n if (config.units) {\n mergedUnits = { ...mergedUnits, ...config.units };\n }\n if (config.funcs) {\n mergedFuncs = { ...mergedFuncs, ...config.funcs };\n }\n if (config.handlers) {\n mergedHandlers = { ...mergedHandlers, ...config.handlers };\n }\n if (config.replaceTokens) {\n mergedReplaceTokens = { ...mergedReplaceTokens, ...config.replaceTokens };\n }\n if (config.tokens) {\n mergedConfigTokens = { ...mergedConfigTokens, ...config.tokens };\n }\n if (config.recipes) {\n mergedRecipes = { ...mergedRecipes, ...config.recipes };\n }\n\n // Warn on tokens/replaceTokens key conflicts\n if (devMode) {\n const tokenKeys = new Set(Object.keys(mergedConfigTokens));\n for (const key of Object.keys(mergedReplaceTokens)) {\n if (tokenKeys.has(key)) {\n warnOnce(\n `token-conflict-${key}`,\n `[Tasty] Token \"${key}\" is defined in both \\`tokens\\` and \\`replaceTokens\\`. ` +\n `\\`replaceTokens\\` performs parse-time substitution, so the \\`tokens\\` ` +\n `CSS custom property will be injected but never used by Tasty styles. ` +\n `Remove it from one of the two.`,\n );\n }\n }\n }\n\n // Handle color space (must be set before any token processing)\n setColorSpace(config.colorSpace ?? 'oklch');\n // Color space affects parser output (e.g. #name.5 → oklch(...) vs rgb(...))\n getGlobalParser().clearCache();\n\n // Handle predefined states\n if (Object.keys(mergedStates).length > 0) {\n setGlobalPredefinedStates(mergedStates);\n }\n\n // Handle parser configuration (merge semantics - extend, not replace)\n const parser = getGlobalParser();\n\n if (config.parserCacheSize !== undefined) {\n parser.updateOptions({ cacheSize: config.parserCacheSize });\n }\n\n if (Object.keys(mergedUnits).length > 0) {\n // Merge with existing units\n const currentUnits = parser.getUnits() ?? CUSTOM_UNITS;\n parser.setUnits({ ...currentUnits, ...mergedUnits });\n }\n\n if (Object.keys(mergedFuncs).length > 0) {\n // Merge with existing funcs\n const currentFuncs = getGlobalFuncs();\n const finalFuncs = { ...currentFuncs, ...mergedFuncs };\n parser.setFuncs(finalFuncs);\n // Also update the global registry so customFunc() continues to work\n Object.assign(currentFuncs, mergedFuncs);\n }\n\n // Handle keyframes\n if (config.keyframes) {\n setGlobalKeyframes(config.keyframes);\n }\n\n // Handle properties\n if (config.properties) {\n setGlobalProperties(config.properties);\n }\n\n // Handle custom handlers\n if (Object.keys(mergedHandlers).length > 0) {\n for (const [name, definition] of Object.entries(mergedHandlers)) {\n const handler = normalizeHandlerDefinition(name, definition);\n registerHandler(handler);\n }\n }\n\n // Handle replaceTokens (parse-time substitution)\n if (Object.keys(mergedReplaceTokens).length > 0) {\n const processedTokens: Record<string, string> = {};\n for (const [key, value] of Object.entries(mergedReplaceTokens)) {\n if (key.startsWith('#')) {\n const normalized = normalizeColorTokenValue(value);\n if (normalized === null) continue;\n processedTokens[key] = String(normalized);\n } else if (value === false) {\n continue;\n } else {\n processedTokens[key] = String(value);\n }\n }\n setGlobalPredefinedTokens(processedTokens);\n }\n\n // Handle tokens (CSS custom properties on :root)\n if (Object.keys(mergedConfigTokens).length > 0) {\n setGlobalConfigTokens(mergedConfigTokens);\n }\n\n // Handle recipes\n if (Object.keys(mergedRecipes).length > 0) {\n setGlobalRecipes(mergedRecipes);\n }\n\n const {\n states: _states,\n parserCacheSize: _parserCacheSize,\n units: _units,\n funcs: _funcs,\n plugins: _plugins,\n keyframes: _keyframes,\n properties: _properties,\n handlers: _handlers,\n tokens: _tokens,\n replaceTokens: _replaceTokens,\n recipes: _recipes,\n colorSpace: _colorSpace,\n ...injectorConfig\n } = config;\n\n const fullConfig: TastyConfig = {\n ...createDefaultConfig(),\n ...currentConfig,\n ...injectorConfig,\n };\n\n // Store the config\n currentConfig = fullConfig;\n\n // Create/replace the global injector\n const storage: TastyGlobalStorage =\n typeof window !== 'undefined' ? window : globalThis;\n storage[GLOBAL_INJECTOR_KEY] = new StyleInjector(fullConfig);\n}\n\n/**\n * Get the current configuration.\n * If not configured, returns default configuration.\n */\nexport function getConfig(): TastyConfig {\n if (!currentConfig) {\n currentConfig = createDefaultConfig(isTestEnvironment());\n }\n return currentConfig;\n}\n\n/**\n * Get the global injector instance.\n * Auto-configures with defaults if not already configured.\n */\nexport function getGlobalInjector(): StyleInjector {\n const storage: TastyGlobalStorage =\n typeof window !== 'undefined' ? window : globalThis;\n\n if (!storage[GLOBAL_INJECTOR_KEY]) {\n configure();\n }\n\n return storage[GLOBAL_INJECTOR_KEY]!;\n}\n\n/**\n * Reset configuration (for testing only).\n * Clears the global injector and allows reconfiguration.\n */\nexport function resetConfig(): void {\n stylesGenerated = false;\n currentConfig = null;\n globalKeyframes = null;\n _hasGlobalKeyframes = false;\n globalProperties = null;\n globalRecipes = null;\n globalConfigTokens = null;\n resetGlobalPredefinedTokens();\n resetHandlers();\n resetColorSpace();\n clearPipelineCache();\n emittedWarnings.clear();\n\n const storage: TastyGlobalStorage =\n typeof window !== 'undefined' ? window : globalThis;\n delete storage[GLOBAL_INJECTOR_KEY];\n}\n\n// Re-export TastyConfig as StyleInjectorConfig for backward compatibility\nexport type { TastyConfig as StyleInjectorConfig };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["/**\n * Tasty Configuration Module\n *\n * Centralizes all tasty configuration, including:\n * - Style injector settings (nonce, cleanup thresholds, etc.)\n * - Global predefined states for advanced state mapping\n * - stylesGenerated flag that locks configuration after first style generation\n *\n * Configuration must be done BEFORE any styles are generated.\n * After the first `inject()` call, configuration is locked and attempts to\n * reconfigure will emit a warning and be ignored.\n */\n\nimport { StyleInjector } from './injector/injector';\nimport { clearPipelineCache, isSelector, renderStyles } from './pipeline';\nimport { setGlobalPredefinedStates } from './states';\nimport {\n normalizeHandlerDefinition,\n registerHandler,\n resetHandlers,\n} from './styles/predefined';\nimport { resetColorSpace, setColorSpace } from './utils/color-space';\nimport { isDevEnv } from './utils/is-dev-env';\nimport {\n CUSTOM_UNITS,\n getGlobalFuncs,\n getGlobalParser,\n normalizeColorTokenValue,\n resetGlobalPredefinedTokens,\n setGlobalPredefinedTokens,\n} from './utils/styles';\n\nimport type { ColorSpace } from './utils/color-space';\n\nimport type { KeyframesSteps, PropertyDefinition } from './injector/types';\nimport type { StyleDetails, UnitHandler } from './parser/types';\nimport type { StyleResult } from './pipeline';\nimport type { TastyPlugin } from './plugins/types';\nimport type { RecipeStyles, ConfigTokens } from './styles/types';\nimport type { StyleHandlerDefinition } from './utils/styles';\n\n/**\n * Configuration options for the Tasty style system\n */\nexport interface TastyConfig {\n /** CSP nonce for style elements */\n nonce?: string;\n /** Maximum rules per stylesheet (default: 8192) */\n maxRulesPerSheet?: number;\n /** Threshold for bulk cleanup of unused styles (default: 500) */\n unusedStylesThreshold?: number;\n /** Delay before bulk cleanup in ms, ignored if idleCleanup is true (default: 5000) */\n bulkCleanupDelay?: number;\n /** Use requestIdleCallback for cleanup when available (default: true) */\n idleCleanup?: boolean;\n /** Force text injection mode, auto-detected in test environments (default: auto) */\n forceTextInjection?: boolean;\n /** Enable development mode features: performance metrics and debug info (default: auto) */\n devMode?: boolean;\n /**\n * Ratio of unused styles to delete per bulk cleanup run (0..1).\n * Defaults to 0.5 (oldest half) to reduce risk of removing styles\n * that may be restored shortly after being marked unused.\n */\n bulkCleanupBatchRatio?: number;\n /**\n * Minimum age (in ms) a style must remain unused before eligible for deletion.\n * Helps avoid races during rapid mount/unmount cycles. Default: 10000ms.\n */\n unusedStylesMinAgeMs?: number;\n /**\n * Global predefined states for advanced state mapping.\n * These are state aliases that can be used in any component.\n * Example: { '@mobile': '@media(w < 920px)', '@dark': '@root(theme=dark)' }\n */\n states?: Record<string, string>;\n /**\n * Parser LRU cache size (default: 1000).\n * Larger values improve performance for apps with many unique style values.\n */\n parserCacheSize?: number;\n /**\n * Custom units for the style parser (merged with built-in units).\n * Units transform numeric values like `2x` → `calc(2 * var(--gap))`.\n * @example { em: 'em', vw: 'vw', custom: (n) => `${n * 10}px` }\n */\n units?: Record<string, string | UnitHandler>;\n /**\n * Custom functions for the style parser (merged with existing).\n * Functions process parsed style groups and return CSS values.\n * @example { myFunc: (groups) => groups.map(g => g.output).join(' ') }\n */\n funcs?: Record<string, (groups: StyleDetails[]) => string>;\n /**\n * Color space used for decomposed color token companion variables.\n * Controls the CSS function and suffix for alpha composition.\n *\n * - `'rgb'` — suffix `-rgb`, e.g. `rgb(var(--name-color-rgb) / .5)`\n * - `'hsl'` — suffix `-hsl`, e.g. `hsl(var(--name-color-hsl) / .5)`\n * - `'oklch'` — suffix `-oklch`, e.g. `oklch(var(--name-color-oklch) / .5)`\n *\n * @default 'oklch'\n */\n colorSpace?: ColorSpace;\n /**\n * Automatically infer and register CSS @property declarations\n * from custom property values found in styles, keyframes, and global config.\n * Covers all types: \\<color\\>, \\<number\\>, \\<length\\>, \\<angle\\>, \\<percentage\\>, \\<time\\>.\n * When false, only explicitly declared @properties are registered.\n * @default true\n */\n autoPropertyTypes?: boolean;\n /**\n * Plugins that extend tasty with custom functions, units, or states.\n * Plugins are processed in order, with later plugins overriding earlier ones.\n * @example\n * ```ts\n * import { okhslPlugin } from '@tenphi/tasty';\n *\n * configure({\n * plugins: [okhslPlugin()],\n * });\n * ```\n */\n plugins?: TastyPlugin[];\n /**\n * Global keyframes definitions that can be referenced by animation names in styles.\n * Keys are animation names, values are keyframes step definitions.\n * Keyframes are only injected when actually used in styles.\n * @example\n * ```ts\n * configure({\n * keyframes: {\n * fadeIn: { from: { opacity: 0 }, to: { opacity: 1 } },\n * pulse: { '0%, 100%': { transform: 'scale(1)' }, '50%': { transform: 'scale(1.05)' } },\n * },\n * });\n * ```\n */\n keyframes?: Record<string, KeyframesSteps>;\n /**\n * Global CSS @property definitions for custom properties.\n * Keys use tasty token syntax ($name for properties, #name for colors).\n * Properties are only injected when the component using them is rendered.\n *\n * For color tokens (#name), `syntax: '<color>'` is auto-set and\n * `initialValue` defaults to `'transparent'` if not specified.\n *\n * @example\n * ```ts\n * configure({\n * properties: {\n * '$rotation': { syntax: '<angle>', initialValue: '0deg' },\n * '$scale': { syntax: '<number>', inherits: false, initialValue: 1 },\n * '#accent': { initialValue: 'purple' }, // syntax: '<color>' auto-set\n * },\n * });\n *\n * // Now use in styles - properties are registered when component renders:\n * const Spinner = tasty({\n * styles: {\n * transform: 'rotate($rotation)',\n * transition: '$$rotation 0.3s', // outputs: --rotation 0.3s\n * },\n * });\n * ```\n */\n properties?: Record<string, PropertyDefinition>;\n /**\n * Custom style handlers that transform style properties into CSS declarations.\n * Handlers replace built-in handlers for the same style name.\n * @example\n * ```ts\n * import { styleHandlers } from '@tenphi/tasty';\n *\n * configure({\n * handlers: {\n * // Override fill with custom behavior\n * fill: ({ fill }) => {\n * if (fill?.startsWith('gradient:')) {\n * return { background: fill.slice(9) };\n * }\n * return styleHandlers.fill({ fill });\n * },\n * // Add new custom style\n * elevation: ({ elevation }) => {\n * const level = parseInt(elevation) || 1;\n * return {\n * 'box-shadow': `0 ${level * 2}px ${level * 4}px rgba(0,0,0,0.1)`,\n * 'z-index': String(level * 100),\n * };\n * },\n * },\n * });\n * ```\n */\n handlers?: Record<string, StyleHandlerDefinition>;\n /**\n * Design tokens injected as CSS custom properties on `:root`.\n * Values are parsed through the Tasty DSL. Supports state maps\n * for responsive/theme-aware tokens.\n *\n * - `$name` keys become `--name` CSS custom properties\n * - `#name` keys become `--name-color` and `--name-color-{colorSpace}` properties\n *\n * Tokens are injected once when the first style is rendered.\n *\n * @example\n * ```ts\n * configure({\n * tokens: {\n * '$gap': '4px',\n * '#primary': {\n * '': '#purple',\n * '@dark': '#light-purple',\n * },\n * },\n * });\n * ```\n */\n tokens?: ConfigTokens;\n /**\n * Predefined tokens that are replaced during style parsing (parse-time substitution).\n * Use `$name` for custom properties and `#name` for color tokens.\n * Values are substituted inline before CSS generation, unlike `tokens` which\n * inject CSS custom properties on `:root`.\n *\n * For color tokens (#name), boolean `true` is converted to `transparent`.\n *\n * @example\n * ```ts\n * configure({\n * replaceTokens: {\n * $spacing: '2x',\n * '#accent': '#purple',\n * '#overlay': true, // → transparent\n * },\n * });\n *\n * // Now use in styles - tokens are replaced at parse time:\n * const Card = tasty({\n * styles: {\n * padding: '$spacing', // → calc(2 * var(--gap))\n * fill: '#accent', // → var(--purple-color)\n * },\n * });\n * ```\n */\n replaceTokens?: Record<`$${string}`, string | number | boolean> &\n Record<`#${string}`, string | number | boolean>;\n /**\n * Predefined style recipes -- named style bundles that can be applied via `recipe` style property.\n * Recipe values are flat tasty styles (no sub-element keys). They may contain base styles,\n * tokens (`$name`/`#name` definitions), local states, `@keyframes`, and `@properties`.\n *\n * Components reference recipes via: `recipe: 'name1 name2'` in their styles.\n * Use `/` to separate base recipes from post recipes: `recipe: 'base1 base2 / post1'`.\n * Use `none` to skip base recipes: `recipe: 'none / post1'`.\n * Resolution order: `base_recipes → component styles → post_recipes`.\n *\n * Recipes cannot reference other recipes.\n *\n * @example\n * ```ts\n * configure({\n * recipes: {\n * card: { padding: '4x', fill: '#surface', radius: '1r', border: true },\n * elevated: { shadow: '2x 2x 4x #shadow' },\n * },\n * });\n *\n * // Usage in styles:\n * const Card = tasty({\n * styles: {\n * recipe: 'card elevated',\n * color: '#text', // Overrides recipe values\n * },\n * });\n * ```\n */\n recipes?: Record<string, RecipeStyles>;\n}\n\n// Warnings tracking to avoid duplicates\nconst emittedWarnings = new Set<string>();\n\nconst devMode = isDevEnv();\n\n/**\n * Emit a warning only once\n */\nfunction warnOnce(key: string, message: string): void {\n if (devMode && !emittedWarnings.has(key)) {\n emittedWarnings.add(key);\n console.warn(message);\n }\n}\n\n// ============================================================================\n// Configuration State\n// ============================================================================\n\n// Track whether styles have been generated (locks configuration)\nlet stylesGenerated = false;\n\n// Current configuration (null until first configure() or auto-configured on first use)\nlet currentConfig: TastyConfig | null = null;\n\n// Global keyframes storage (null = no keyframes configured, empty object checked via hasGlobalKeyframes)\nlet globalKeyframes: Record<string, KeyframesSteps> | null = null;\n\n// Global properties storage (null = no properties configured)\nlet globalProperties: Record<string, PropertyDefinition> | null = null;\n\n// Global recipes storage (null = no recipes configured)\nlet globalRecipes: Record<string, RecipeStyles> | null = null;\n\n// Global token styles storage (injected as :root CSS custom properties)\nlet globalConfigTokens: ConfigTokens | null = null;\n\n/**\n * Internal properties required by tasty core features.\n * These are always injected when styles are first generated.\n * Keys use tasty token syntax (#name for colors, $name for other properties).\n *\n * For properties with CSS @property-compatible types (length, time, number, color),\n * an `initialValue` is provided so the property works even without a project-level token.\n */\nexport const INTERNAL_PROPERTIES: Record<string, PropertyDefinition> = {\n // Used by dual-fill feature to enable CSS transitions on the second fill color\n '#tasty-second-fill': {\n inherits: false,\n initialValue: 'transparent',\n },\n // Current color context variable (set by the color style handler).\n '#current': {\n inherits: true,\n initialValue: 'transparent',\n },\n // White and black are fundamental colors that need explicit initial values.\n '#white': {\n inherits: true,\n initialValue: 'rgb(255 255 255)',\n },\n '#black': {\n inherits: true,\n initialValue: 'rgb(0 0 0)',\n },\n\n // ---- Core design tokens used by style handlers ----\n // These provide sensible defaults so tasty works standalone without a design system.\n // Consuming projects (e.g. uikit) override these by defining tokens on :root.\n\n $gap: {\n syntax: '<length>',\n inherits: true,\n initialValue: '4px',\n },\n $radius: {\n syntax: '<length>',\n inherits: true,\n initialValue: '6px',\n },\n '$border-width': {\n syntax: '<length>',\n inherits: true,\n initialValue: '1px',\n },\n '$outline-width': {\n syntax: '<length>',\n inherits: true,\n initialValue: '3px',\n },\n $transition: {\n syntax: '<time>',\n inherits: true,\n initialValue: '80ms',\n },\n // Used by radius.ts for `radius=\"leaf\"` modifier\n '$sharp-radius': {\n syntax: '<length>',\n inherits: true,\n initialValue: '0px',\n },\n // Used by preset.ts for `preset=\"... strong\"`\n '$bold-font-weight': {\n syntax: '<number>',\n inherits: true,\n initialValue: '700',\n },\n};\n\n/**\n * Internal token defaults that cannot be expressed as CSS @property initial values\n * (e.g. font stacks, keyword colors). These are injected as :root CSS variables.\n * Consuming projects override them by setting their own tokens on :root.\n *\n * Keys are raw CSS custom property names (--name).\n */\nexport const INTERNAL_TOKENS: Record<string, string> = {\n '--font':\n 'system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\", sans-serif',\n '--monospace-font':\n 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace',\n // Default border color to the element's current text color\n '--border-color': 'currentColor',\n};\n\n// Global injector instance key\nconst GLOBAL_INJECTOR_KEY = '__TASTY_GLOBAL_INJECTOR__';\n\ninterface TastyGlobalStorage {\n [GLOBAL_INJECTOR_KEY]?: StyleInjector;\n}\n\ndeclare global {\n interface Window {\n [GLOBAL_INJECTOR_KEY]?: StyleInjector;\n }\n\n var __TASTY_GLOBAL_INJECTOR__: StyleInjector | undefined;\n}\n\n/**\n * Detect if we're running in a test environment\n */\nexport function isTestEnvironment(): boolean {\n // Check Node.js environment\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'test') {\n return true;\n }\n\n // Check for test runner globals (safely)\n if (typeof global !== 'undefined') {\n const g = global as unknown as Record<string, unknown>;\n if (g.vi || g.jest || g.expect || g.describe || g.it) {\n return true;\n }\n }\n\n // Check for jsdom environment (common in tests)\n if (\n typeof window !== 'undefined' &&\n window.navigator?.userAgent?.includes('jsdom')\n ) {\n return true;\n }\n\n // Check for other test runners\n if (typeof globalThis !== 'undefined') {\n const gt = globalThis as unknown as Record<string, unknown>;\n if (gt.vitest || gt.mocha) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Create default configuration with optional test environment detection\n */\nfunction createDefaultConfig(isTest?: boolean): TastyConfig {\n return {\n maxRulesPerSheet: 8192,\n unusedStylesThreshold: 500,\n bulkCleanupDelay: 5000,\n idleCleanup: true,\n forceTextInjection: isTest ?? false,\n devMode: isDevEnv(),\n bulkCleanupBatchRatio: 0.5,\n unusedStylesMinAgeMs: 10000,\n };\n}\n\n// ============================================================================\n// stylesGenerated Flag Management\n// ============================================================================\n\n/**\n * Mark that styles have been generated (called by injector on first inject)\n * This locks the configuration - no further changes allowed.\n * Also injects internal and global properties.\n */\nexport function markStylesGenerated(): void {\n if (stylesGenerated) return; // Already marked, skip\n\n stylesGenerated = true;\n\n const injector = getGlobalInjector();\n\n // Inject internal properties required by tasty core features\n for (const [token, definition] of Object.entries(INTERNAL_PROPERTIES)) {\n injector.property(token, definition);\n }\n\n // Inject internal token defaults as :root CSS variables.\n // Use injectGlobal (not injectRawCSS) so the rule goes through the same\n // injection path as all other tasty styles (consistent in both DOM and text/test mode).\n const internalTokenEntries = Object.entries(INTERNAL_TOKENS);\n if (internalTokenEntries.length > 0) {\n const declarations = internalTokenEntries\n .map(([name, value]) => `${name}: ${value}`)\n .join('; ');\n injector.injectGlobal([{ selector: ':root', declarations }]);\n }\n\n // Inject global properties if any were configured\n // Properties are permanent and only need to be injected once\n if (globalProperties && Object.keys(globalProperties).length > 0) {\n for (const [token, definition] of Object.entries(globalProperties)) {\n injector.property(token, definition);\n }\n }\n\n // Inject configured tokens as :root CSS custom properties\n if (globalConfigTokens && Object.keys(globalConfigTokens).length > 0) {\n const tokenRules = renderStyles(\n globalConfigTokens,\n ':root',\n ) as StyleResult[];\n if (tokenRules.length > 0) {\n injector.injectGlobal(tokenRules);\n }\n }\n}\n\n/**\n * Check if styles have been generated (configuration is locked)\n */\nexport function hasStylesGenerated(): boolean {\n return stylesGenerated;\n}\n\n/**\n * Reset styles generated flag (for testing only)\n */\nexport function resetStylesGenerated(): void {\n stylesGenerated = false;\n emittedWarnings.clear();\n}\n\n// ============================================================================\n// Global Keyframes Management\n// ============================================================================\n\nlet _hasGlobalKeyframes = false;\n\n/**\n * Check if any global keyframes are configured.\n * Uses a pre-computed flag to avoid Object.keys() allocation on every call.\n */\nexport function hasGlobalKeyframes(): boolean {\n return _hasGlobalKeyframes;\n}\n\n/**\n * Get global keyframes configuration.\n * Returns null if no keyframes configured (fast path for zero-overhead).\n */\nexport function getGlobalKeyframes(): Record<string, KeyframesSteps> | null {\n return globalKeyframes;\n}\n\n/**\n * Set global keyframes (called from configure).\n * Internal use only.\n */\nfunction setGlobalKeyframes(keyframes: Record<string, KeyframesSteps>): void {\n if (stylesGenerated) {\n warnOnce(\n 'keyframes-after-styles',\n `[Tasty] Cannot update keyframes after styles have been generated.\\n` +\n `The new keyframes will be ignored.`,\n );\n return;\n }\n globalKeyframes = keyframes;\n _hasGlobalKeyframes = Object.keys(keyframes).length > 0;\n}\n\n// ============================================================================\n// Global Properties Management\n// ============================================================================\n\n/**\n * Check if any global properties are configured.\n * Fast path: returns false if no properties were ever set.\n */\nexport function hasGlobalProperties(): boolean {\n return globalProperties !== null && Object.keys(globalProperties).length > 0;\n}\n\n/**\n * Get global properties configuration.\n * Returns null if no properties configured (fast path for zero-overhead).\n */\nexport function getGlobalProperties(): Record<\n string,\n PropertyDefinition\n> | null {\n return globalProperties;\n}\n\n/**\n * Set global properties (called from configure).\n * Internal use only.\n */\nfunction setGlobalProperties(\n properties: Record<string, PropertyDefinition>,\n): void {\n if (stylesGenerated) {\n warnOnce(\n 'properties-after-styles',\n `[Tasty] Cannot update properties after styles have been generated.\\n` +\n `The new properties will be ignored.`,\n );\n return;\n }\n globalProperties = properties;\n}\n\n// ============================================================================\n// Global Recipes Management\n// ============================================================================\n\n/**\n * Check if any global recipes are configured.\n * Fast path: returns false if no recipes were ever set.\n */\nexport function hasGlobalRecipes(): boolean {\n return globalRecipes !== null && Object.keys(globalRecipes).length > 0;\n}\n\n/**\n * Get global recipes configuration.\n * Returns null if no recipes configured (fast path for zero-overhead).\n */\nexport function getGlobalRecipes(): Record<string, RecipeStyles> | null {\n return globalRecipes;\n}\n\n/**\n * Set global recipes (called from configure).\n * Internal use only.\n */\nfunction setGlobalRecipes(recipes: Record<string, RecipeStyles>): void {\n if (stylesGenerated) {\n warnOnce(\n 'recipes-after-styles',\n `[Tasty] Cannot update recipes after styles have been generated.\\n` +\n `The new recipes will be ignored.`,\n );\n return;\n }\n\n // Dev-mode validation\n if (devMode) {\n for (const [name, recipeStyles] of Object.entries(recipes)) {\n if (name === 'none') {\n warnOnce(\n 'recipe-reserved-none',\n `[Tasty] Recipe name \"none\" is reserved. ` +\n `It is used as a keyword meaning \"no base recipes\" ` +\n `(e.g. recipe: 'none / post-recipe'). ` +\n `Choose a different name for your recipe.`,\n );\n }\n\n for (const key of Object.keys(recipeStyles)) {\n if (isSelector(key)) {\n warnOnce(\n `recipe-selector-${name}-${key}`,\n `[Tasty] Recipe \"${name}\" contains sub-element key \"${key}\". ` +\n `Recipes must be flat styles without sub-element keys. ` +\n `Remove the sub-element key from the recipe definition.`,\n );\n }\n if (key === 'recipe') {\n warnOnce(\n `recipe-recursive-${name}`,\n `[Tasty] Recipe \"${name}\" contains a \"recipe\" key. ` +\n `Recipes cannot reference other recipes. ` +\n `Use space-separated names for composition: recipe: 'base elevated'.`,\n );\n }\n }\n }\n }\n\n globalRecipes = recipes;\n}\n\n// ============================================================================\n// Global Token Styles Management\n// ============================================================================\n\n/**\n * Get global token styles for :root injection.\n * Returns null if no tokens configured.\n */\nexport function getGlobalConfigTokens(): ConfigTokens | null {\n return globalConfigTokens;\n}\n\n/**\n * Set global token styles (called from configure).\n * Internal use only.\n */\nfunction setGlobalConfigTokens(styles: ConfigTokens): void {\n if (stylesGenerated) {\n warnOnce(\n 'tokens-after-styles',\n `[Tasty] Cannot update tokens after styles have been generated.\\n` +\n `The new tokens will be ignored.`,\n );\n return;\n }\n globalConfigTokens = globalConfigTokens\n ? { ...globalConfigTokens, ...styles }\n : styles;\n}\n\n/**\n * Check if configuration is locked (styles have been generated)\n */\nexport function isConfigLocked(): boolean {\n return stylesGenerated;\n}\n\n// ============================================================================\n// Configuration API\n// ============================================================================\n\n/**\n * Configure the Tasty style system.\n *\n * Must be called BEFORE any styles are generated (before first render that uses tasty).\n * After styles are generated, configuration is locked and calls to configure() will\n * emit a warning and be ignored.\n *\n * @example\n * ```ts\n * import { configure } from '@tenphi/tasty';\n *\n * // Configure before app renders\n * configure({\n * nonce: 'abc123',\n * states: {\n * '@mobile': '@media(w < 768px)',\n * '@dark': '@root(theme=dark)',\n * },\n * });\n * ```\n */\nexport function configure(config: Partial<TastyConfig> = {}): void {\n if (stylesGenerated) {\n warnOnce(\n 'configure-after-styles',\n `[Tasty] Cannot call configure() after styles have been generated.\\n` +\n `Configuration must be done before the first render. The configuration will be ignored.`,\n );\n return;\n }\n\n // Collect merged values from plugins first, then override with direct config\n let mergedStates: Record<string, string> = {};\n let mergedUnits: Record<string, string | UnitHandler> = {};\n let mergedFuncs: Record<string, (groups: StyleDetails[]) => string> = {};\n let mergedHandlers: Record<string, StyleHandlerDefinition> = {};\n let mergedReplaceTokens: Record<string, string | number | boolean> = {};\n let mergedConfigTokens: ConfigTokens = {} as ConfigTokens;\n let mergedRecipes: Record<string, RecipeStyles> = {};\n\n // Process plugins in order\n if (config.plugins) {\n for (const plugin of config.plugins) {\n if (plugin.states) {\n mergedStates = { ...mergedStates, ...plugin.states };\n }\n if (plugin.units) {\n mergedUnits = { ...mergedUnits, ...plugin.units };\n }\n if (plugin.funcs) {\n mergedFuncs = { ...mergedFuncs, ...plugin.funcs };\n }\n if (plugin.handlers) {\n mergedHandlers = { ...mergedHandlers, ...plugin.handlers };\n }\n if (plugin.replaceTokens) {\n mergedReplaceTokens = {\n ...mergedReplaceTokens,\n ...plugin.replaceTokens,\n };\n }\n if (plugin.tokens) {\n mergedConfigTokens = { ...mergedConfigTokens, ...plugin.tokens };\n }\n if (plugin.recipes) {\n mergedRecipes = { ...mergedRecipes, ...plugin.recipes };\n }\n }\n }\n\n // Direct config overrides plugins\n if (config.states) {\n mergedStates = { ...mergedStates, ...config.states };\n }\n if (config.units) {\n mergedUnits = { ...mergedUnits, ...config.units };\n }\n if (config.funcs) {\n mergedFuncs = { ...mergedFuncs, ...config.funcs };\n }\n if (config.handlers) {\n mergedHandlers = { ...mergedHandlers, ...config.handlers };\n }\n if (config.replaceTokens) {\n mergedReplaceTokens = { ...mergedReplaceTokens, ...config.replaceTokens };\n }\n if (config.tokens) {\n mergedConfigTokens = { ...mergedConfigTokens, ...config.tokens };\n }\n if (config.recipes) {\n mergedRecipes = { ...mergedRecipes, ...config.recipes };\n }\n\n // Warn on tokens/replaceTokens key conflicts\n if (devMode) {\n const tokenKeys = new Set(Object.keys(mergedConfigTokens));\n for (const key of Object.keys(mergedReplaceTokens)) {\n if (tokenKeys.has(key)) {\n warnOnce(\n `token-conflict-${key}`,\n `[Tasty] Token \"${key}\" is defined in both \\`tokens\\` and \\`replaceTokens\\`. ` +\n `\\`replaceTokens\\` performs parse-time substitution, so the \\`tokens\\` ` +\n `CSS custom property will be injected but never used by Tasty styles. ` +\n `Remove it from one of the two.`,\n );\n }\n }\n }\n\n // Handle color space (must be set before any token processing)\n if (config.colorSpace) {\n setColorSpace(config.colorSpace);\n // Color space affects parser output (e.g. #name.5 → oklch(...) vs rgb(...))\n getGlobalParser().clearCache();\n }\n\n // Handle predefined states\n if (Object.keys(mergedStates).length > 0) {\n setGlobalPredefinedStates(mergedStates);\n }\n\n // Handle parser configuration (merge semantics - extend, not replace)\n const parser = getGlobalParser();\n\n if (config.parserCacheSize !== undefined) {\n parser.updateOptions({ cacheSize: config.parserCacheSize });\n }\n\n if (Object.keys(mergedUnits).length > 0) {\n // Merge with existing units\n const currentUnits = parser.getUnits() ?? CUSTOM_UNITS;\n parser.setUnits({ ...currentUnits, ...mergedUnits });\n }\n\n if (Object.keys(mergedFuncs).length > 0) {\n // Merge with existing funcs\n const currentFuncs = getGlobalFuncs();\n const finalFuncs = { ...currentFuncs, ...mergedFuncs };\n parser.setFuncs(finalFuncs);\n // Also update the global registry so customFunc() continues to work\n Object.assign(currentFuncs, mergedFuncs);\n }\n\n // Handle keyframes\n if (config.keyframes) {\n setGlobalKeyframes(config.keyframes);\n }\n\n // Handle properties\n if (config.properties) {\n setGlobalProperties(config.properties);\n }\n\n // Handle custom handlers\n if (Object.keys(mergedHandlers).length > 0) {\n for (const [name, definition] of Object.entries(mergedHandlers)) {\n const handler = normalizeHandlerDefinition(name, definition);\n registerHandler(handler);\n }\n }\n\n // Handle replaceTokens (parse-time substitution)\n if (Object.keys(mergedReplaceTokens).length > 0) {\n const processedTokens: Record<string, string> = {};\n for (const [key, value] of Object.entries(mergedReplaceTokens)) {\n if (key.startsWith('#')) {\n const normalized = normalizeColorTokenValue(value);\n if (normalized === null) continue;\n processedTokens[key] = String(normalized);\n } else if (value === false) {\n continue;\n } else {\n processedTokens[key] = String(value);\n }\n }\n setGlobalPredefinedTokens(processedTokens);\n }\n\n // Handle tokens (CSS custom properties on :root)\n if (Object.keys(mergedConfigTokens).length > 0) {\n setGlobalConfigTokens(mergedConfigTokens);\n }\n\n // Handle recipes\n if (Object.keys(mergedRecipes).length > 0) {\n setGlobalRecipes(mergedRecipes);\n }\n\n const {\n states: _states,\n parserCacheSize: _parserCacheSize,\n units: _units,\n funcs: _funcs,\n plugins: _plugins,\n keyframes: _keyframes,\n properties: _properties,\n handlers: _handlers,\n tokens: _tokens,\n replaceTokens: _replaceTokens,\n recipes: _recipes,\n colorSpace: _colorSpace,\n ...injectorConfig\n } = config;\n\n const fullConfig: TastyConfig = {\n ...createDefaultConfig(),\n ...currentConfig,\n ...injectorConfig,\n };\n\n // Store the config\n currentConfig = fullConfig;\n\n // Create/replace the global injector\n const storage: TastyGlobalStorage =\n typeof window !== 'undefined' ? window : globalThis;\n storage[GLOBAL_INJECTOR_KEY] = new StyleInjector(fullConfig);\n}\n\n/**\n * Get the current configuration.\n * If not configured, returns default configuration.\n */\nexport function getConfig(): TastyConfig {\n if (!currentConfig) {\n currentConfig = createDefaultConfig(isTestEnvironment());\n }\n return currentConfig;\n}\n\n/**\n * Get the global injector instance.\n * Auto-configures with defaults if not already configured.\n */\nexport function getGlobalInjector(): StyleInjector {\n const storage: TastyGlobalStorage =\n typeof window !== 'undefined' ? window : globalThis;\n\n if (!storage[GLOBAL_INJECTOR_KEY]) {\n configure();\n }\n\n return storage[GLOBAL_INJECTOR_KEY]!;\n}\n\n/**\n * Reset configuration (for testing only).\n * Clears the global injector and allows reconfiguration.\n */\nexport function resetConfig(): void {\n stylesGenerated = false;\n currentConfig = null;\n globalKeyframes = null;\n _hasGlobalKeyframes = false;\n globalProperties = null;\n globalRecipes = null;\n globalConfigTokens = null;\n resetGlobalPredefinedTokens();\n resetHandlers();\n resetColorSpace();\n clearPipelineCache();\n emittedWarnings.clear();\n\n const storage: TastyGlobalStorage =\n typeof window !== 'undefined' ? window : globalThis;\n delete storage[GLOBAL_INJECTOR_KEY];\n}\n\n// Re-export TastyConfig as StyleInjectorConfig for backward compatibility\nexport type { TastyConfig as StyleInjectorConfig };\n"],"mappings":"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"}
|
package/dist/tasty.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { StyleValue, StyleValueStateMap } from "./utils/styles.js";
|
|
2
2
|
import { Styles, StylesInterface } from "./styles/types.js";
|
|
3
3
|
import { AllBaseProps, BaseProps, BaseStyleProps, ModValue, Mods, Props, Tokens } from "./types.js";
|
|
4
|
+
import * as react from "react";
|
|
4
5
|
import { AllHTMLAttributes, ComponentType, ForwardRefExoticComponent, JSX, PropsWithoutRef, RefAttributes } from "react";
|
|
5
6
|
|
|
6
7
|
//#region src/tasty.d.ts
|
|
@@ -66,7 +67,7 @@ type SubElementComponents<E extends ElementsDefinition> = { [K in keyof E]: Forw
|
|
|
66
67
|
* Base type containing common properties shared between TastyProps and TastyElementOptions.
|
|
67
68
|
* Separated to avoid code duplication while allowing different type constraints.
|
|
68
69
|
*/
|
|
69
|
-
type TastyBaseProps<K extends StyleList, V extends VariantMap, E extends ElementsDefinition = Record<string, never>, M extends ModPropsInput = readonly
|
|
70
|
+
type TastyBaseProps<K extends StyleList, V extends VariantMap, E extends ElementsDefinition = Record<string, never>, M extends ModPropsInput = readonly never[]> = {
|
|
70
71
|
/** Default styles of the element. */styles?: Styles; /** The list of styles that can be provided by props */
|
|
71
72
|
styleProps?: K; /** Modifier keys exposed as top-level component props (array or typed object form). */
|
|
72
73
|
modProps?: M;
|
|
@@ -75,7 +76,7 @@ type TastyBaseProps<K extends StyleList, V extends VariantMap, E extends Element
|
|
|
75
76
|
tokens?: Tokens; /** Sub-element definitions for compound components */
|
|
76
77
|
elements?: E;
|
|
77
78
|
} & Pick<BaseProps, 'qa' | 'qaVal'> & WithVariant<V>;
|
|
78
|
-
type TastyProps<K extends StyleList, V extends VariantMap, E extends ElementsDefinition = Record<string, never>, DefaultProps = Props, M extends ModPropsInput = readonly
|
|
79
|
+
type TastyProps<K extends StyleList, V extends VariantMap, E extends ElementsDefinition = Record<string, never>, DefaultProps = Props, M extends ModPropsInput = readonly never[]> = TastyBaseProps<K, V, E, M> & {
|
|
79
80
|
/** The tag name of the element or a React component. */as?: string | ComponentType<any>;
|
|
80
81
|
} & Partial<Omit<DefaultProps, 'as' | 'styles' | 'styleProps' | 'modProps' | 'tokens'>>;
|
|
81
82
|
/**
|
|
@@ -86,10 +87,10 @@ type TastyProps<K extends StyleList, V extends VariantMap, E extends ElementsDef
|
|
|
86
87
|
* Note: Uses a separate index signature with `unknown` instead of inheriting
|
|
87
88
|
* from Props (which has `any`) to ensure strict type checking for styles.
|
|
88
89
|
*/
|
|
89
|
-
type TastyElementOptions<K extends StyleList, V extends VariantMap, E extends ElementsDefinition = Record<string, never>, Tag extends keyof JSX.IntrinsicElements = 'div', M extends ModPropsInput = readonly
|
|
90
|
+
type TastyElementOptions<K extends StyleList, V extends VariantMap, E extends ElementsDefinition = Record<string, never>, Tag extends keyof JSX.IntrinsicElements = 'div', M extends ModPropsInput = readonly never[]> = TastyBaseProps<K, V, E, M> & {
|
|
90
91
|
/** The tag name of the element or a React component. */as?: Tag | ComponentType<any>;
|
|
91
92
|
} & Record<string, unknown>;
|
|
92
|
-
type AllBasePropsWithMods<K extends StyleList, M extends ModPropsInput = readonly
|
|
93
|
+
type AllBasePropsWithMods<K extends StyleList, M extends ModPropsInput = readonly never[]> = AllBaseProps & { [key in K[number]]?: StyleValue<StylesInterface[key]> | StyleValueStateMap<StylesInterface[key]> } & BaseStyleProps & ResolveModProps<M>;
|
|
93
94
|
/**
|
|
94
95
|
* Keys from BasePropsWithoutChildren that should be omitted from HTML attributes.
|
|
95
96
|
* This excludes event handlers so they can be properly typed from JSX.IntrinsicElements.
|
|
@@ -101,14 +102,18 @@ type TastySpecificKeys = 'as' | 'qa' | 'qaVal' | 'element' | 'styles' | 'breakpo
|
|
|
101
102
|
* - HTML attributes for flexibility (properly typed based on tag)
|
|
102
103
|
* - Variant support
|
|
103
104
|
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
105
|
+
* AllBasePropsWithMods carries generic AllHTMLAttributes which can conflict
|
|
106
|
+
* with tag-specific types from JSX.IntrinsicElements (e.g. `src` is `string`
|
|
107
|
+
* in AllHTMLAttributes but `string | Blob` in ImgHTMLAttributes). To avoid
|
|
108
|
+
* intersection-narrowing, we Omit tag-specific keys from AllBasePropsWithMods
|
|
109
|
+
* (keeping TastySpecificKeys and style props) and let JSX.IntrinsicElements
|
|
110
|
+
* supply the authoritative HTML attribute types.
|
|
106
111
|
*/
|
|
107
|
-
type TastyElementProps<K extends StyleList, V extends VariantMap, Tag extends keyof JSX.IntrinsicElements = 'div', M extends ModPropsInput = readonly
|
|
112
|
+
type TastyElementProps<K extends StyleList, V extends VariantMap, Tag extends keyof JSX.IntrinsicElements = 'div', M extends ModPropsInput = readonly never[]> = Omit<AllBasePropsWithMods<K, M>, Exclude<keyof JSX.IntrinsicElements[Tag], TastySpecificKeys | K[number]>> & WithVariant<V> & Omit<Omit<AllHTMLAttributes<HTMLElement>, keyof JSX.IntrinsicElements[Tag]> & JSX.IntrinsicElements[Tag], TastySpecificKeys | K[number]>;
|
|
108
113
|
type TastyComponentPropsWithDefaults<Props extends PropsWithStyles, DefaultProps extends Partial<Props>> = keyof DefaultProps extends never ? Props : { [key in Extract<keyof Props, keyof DefaultProps>]?: Props[key] } & { [key in keyof Omit<Props, keyof DefaultProps>]: Props[key] };
|
|
109
|
-
declare function tasty<K extends StyleList, V extends VariantMap, E extends ElementsDefinition = Record<string, never>, Tag extends keyof JSX.IntrinsicElements = 'div', M extends ModPropsInput = readonly
|
|
114
|
+
declare function tasty<K extends StyleList, V extends VariantMap, E extends ElementsDefinition = Record<string, never>, Tag extends keyof JSX.IntrinsicElements = 'div', M extends ModPropsInput = readonly never[]>(options: TastyElementOptions<K, V, E, Tag, M>, secondArg?: never): ForwardRefExoticComponent<PropsWithoutRef<TastyElementProps<K, V, Tag, M>> & RefAttributes<unknown>> & SubElementComponents<E>;
|
|
110
115
|
declare function tasty<Props extends PropsWithStyles, DefaultProps extends Partial<Props> = Partial<Props>>(Component: ComponentType<Props>, options?: TastyProps<never, never, Record<string, never>, Props>): ComponentType<TastyComponentPropsWithDefaults<Props, DefaultProps>>;
|
|
111
|
-
declare const Element: ForwardRefExoticComponent<Omit<TastyElementProps<StyleList, VariantMap, "div", readonly string[]>, "ref"> & RefAttributes<unknown>> & SubElementComponents<Record<string, never>>;
|
|
116
|
+
declare const Element: ForwardRefExoticComponent<Omit<AllBasePropsWithMods<StyleList, readonly never[]>, "slot" | "title" | "children" | "className" | "role" | "id" | "hidden" | "prefix" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "autoCapitalize" | "autoFocus" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "enterKeyHint" | "lang" | "nonce" | "spellCheck" | "tabIndex" | "radioGroup" | "about" | "datatype" | "inlist" | "property" | "rel" | "resource" | "rev" | "typeof" | "vocab" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "popover" | "popoverTargetAction" | "popoverTarget" | "inert" | "inputMode" | "is" | "exportparts" | "part" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerLeave" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onScrollEnd" | "onScrollEndCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onToggle" | "onBeforeToggle" | "onTransitionCancel" | "onTransitionCancelCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "onTransitionRun" | "onTransitionRunCapture" | "onTransitionStart" | "onTransitionStartCapture" | "key"> & WithVariant<VariantMap> & Omit<Omit<AllHTMLAttributes<HTMLElement>, keyof react.ClassAttributes<HTMLDivElement> | keyof react.HTMLAttributes<HTMLDivElement>> & react.ClassAttributes<HTMLDivElement> & react.HTMLAttributes<HTMLDivElement>, "style" | "clipPath" | "filter" | "image" | "marker" | "mask" | "fill" | "qa" | "qaVal" | "color" | "font" | "outline" | "gap" | "padding" | "margin" | "width" | "height" | "border" | "transition" | "placeContent" | "placeItems" | "accentColor" | "alignContent" | "alignItems" | "alignSelf" | "alignTracks" | "alignmentBaseline" | "anchorName" | "anchorScope" | "animationComposition" | "animationDelay" | "animationDirection" | "animationDuration" | "animationFillMode" | "animationIterationCount" | "animationName" | "animationPlayState" | "animationRangeEnd" | "animationRangeStart" | "animationTimeline" | "animationTimingFunction" | "appearance" | "aspectRatio" | "backdropFilter" | "backfaceVisibility" | "backgroundAttachment" | "backgroundBlendMode" | "backgroundClip" | "backgroundColor" | "backgroundImage" | "backgroundOrigin" | "backgroundPositionX" | "backgroundPositionY" | "backgroundRepeat" | "backgroundSize" | "baselineShift" | "blockSize" | "borderBlockEndColor" | "borderBlockEndStyle" | "borderBlockEndWidth" | "borderBlockStartColor" | "borderBlockStartStyle" | "borderBlockStartWidth" | "borderBottomColor" | "borderBottomLeftRadius" | "borderBottomRightRadius" | "borderBottomStyle" | "borderBottomWidth" | "borderCollapse" | "borderEndEndRadius" | "borderEndStartRadius" | "borderImageOutset" | "borderImageRepeat" | "borderImageSlice" | "borderImageSource" | "borderImageWidth" | "borderInlineEndColor" | "borderInlineEndStyle" | "borderInlineEndWidth" | "borderInlineStartColor" | "borderInlineStartStyle" | "borderInlineStartWidth" | "borderLeftColor" | "borderLeftStyle" | "borderLeftWidth" | "borderRightColor" | "borderRightStyle" | "borderRightWidth" | "borderSpacing" | "borderStartEndRadius" | "borderStartStartRadius" | "borderTopColor" | "borderTopLeftRadius" | "borderTopRightRadius" | "borderTopStyle" | "borderTopWidth" | "bottom" | "boxDecorationBreak" | "boxShadow" | "boxSizing" | "breakAfter" | "breakBefore" | "breakInside" | "captionSide" | "caretColor" | "caretShape" | "clear" | "clipRule" | "colorAdjust" | "colorInterpolationFilters" | "colorScheme" | "columnCount" | "columnFill" | "columnGap" | "columnRuleColor" | "columnRuleStyle" | "columnRuleWidth" | "columnSpan" | "columnWidth" | "contain" | "containIntrinsicBlockSize" | "containIntrinsicHeight" | "containIntrinsicInlineSize" | "containIntrinsicWidth" | "containerName" | "containerType" | "content" | "contentVisibility" | "counterIncrement" | "counterReset" | "counterSet" | "cursor" | "cx" | "cy" | "d" | "direction" | "display" | "dominantBaseline" | "emptyCells" | "fieldSizing" | "fillOpacity" | "fillRule" | "flexBasis" | "flexDirection" | "flexGrow" | "flexShrink" | "flexWrap" | "float" | "floodColor" | "floodOpacity" | "fontFamily" | "fontFeatureSettings" | "fontKerning" | "fontLanguageOverride" | "fontOpticalSizing" | "fontPalette" | "fontSize" | "fontSizeAdjust" | "fontSmooth" | "fontStyle" | "fontSynthesis" | "fontSynthesisPosition" | "fontSynthesisSmallCaps" | "fontSynthesisStyle" | "fontSynthesisWeight" | "fontVariant" | "fontVariantAlternates" | "fontVariantCaps" | "fontVariantEastAsian" | "fontVariantEmoji" | "fontVariantLigatures" | "fontVariantNumeric" | "fontVariantPosition" | "fontVariationSettings" | "fontWeight" | "fontWidth" | "forcedColorAdjust" | "gridAutoColumns" | "gridAutoFlow" | "gridAutoRows" | "gridColumnEnd" | "gridColumnStart" | "gridRowEnd" | "gridRowStart" | "gridTemplateAreas" | "gridTemplateColumns" | "gridTemplateRows" | "hangingPunctuation" | "hyphenateCharacter" | "hyphenateLimitChars" | "hyphens" | "imageOrientation" | "imageRendering" | "imageResolution" | "initialLetter" | "initialLetterAlign" | "inlineSize" | "insetBlockEnd" | "insetBlockStart" | "insetInlineEnd" | "insetInlineStart" | "interpolateSize" | "isolation" | "justifyContent" | "justifyItems" | "justifySelf" | "justifyTracks" | "left" | "letterSpacing" | "lightingColor" | "lineBreak" | "lineHeight" | "lineHeightStep" | "listStyleImage" | "listStylePosition" | "listStyleType" | "marginBlockEnd" | "marginBlockStart" | "marginBottom" | "marginInlineEnd" | "marginInlineStart" | "marginLeft" | "marginRight" | "marginTop" | "marginTrim" | "markerEnd" | "markerMid" | "markerStart" | "maskBorderMode" | "maskBorderOutset" | "maskBorderRepeat" | "maskBorderSlice" | "maskBorderSource" | "maskBorderWidth" | "maskClip" | "maskComposite" | "maskImage" | "maskMode" | "maskOrigin" | "maskPosition" | "maskRepeat" | "maskSize" | "maskType" | "masonryAutoFlow" | "mathDepth" | "mathShift" | "mathStyle" | "maxBlockSize" | "maxHeight" | "maxInlineSize" | "maxLines" | "maxWidth" | "minBlockSize" | "minHeight" | "minInlineSize" | "minWidth" | "mixBlendMode" | "motionDistance" | "motionPath" | "motionRotation" | "objectFit" | "objectPosition" | "objectViewBox" | "offsetAnchor" | "offsetDistance" | "offsetPath" | "offsetPosition" | "offsetRotate" | "offsetRotation" | "opacity" | "order" | "orphans" | "outlineColor" | "outlineOffset" | "outlineStyle" | "outlineWidth" | "overflowAnchor" | "overflowBlock" | "overflowClipBox" | "overflowClipMargin" | "overflowInline" | "overflowWrap" | "overflowX" | "overflowY" | "overlay" | "overscrollBehaviorBlock" | "overscrollBehaviorInline" | "overscrollBehaviorX" | "overscrollBehaviorY" | "paddingBlockEnd" | "paddingBlockStart" | "paddingBottom" | "paddingInlineEnd" | "paddingInlineStart" | "paddingLeft" | "paddingRight" | "paddingTop" | "page" | "paintOrder" | "perspective" | "perspectiveOrigin" | "pointerEvents" | "position" | "positionAnchor" | "positionArea" | "positionTryFallbacks" | "positionTryOrder" | "positionVisibility" | "printColorAdjust" | "quotes" | "r" | "resize" | "right" | "rotate" | "rowGap" | "rubyAlign" | "rubyMerge" | "rubyOverhang" | "rubyPosition" | "rx" | "ry" | "scale" | "scrollBehavior" | "scrollInitialTarget" | "scrollMarginBlockEnd" | "scrollMarginBlockStart" | "scrollMarginBottom" | "scrollMarginInlineEnd" | "scrollMarginInlineStart" | "scrollMarginLeft" | "scrollMarginRight" | "scrollMarginTop" | "scrollPaddingBlockEnd" | "scrollPaddingBlockStart" | "scrollPaddingBottom" | "scrollPaddingInlineEnd" | "scrollPaddingInlineStart" | "scrollPaddingLeft" | "scrollPaddingRight" | "scrollPaddingTop" | "scrollSnapAlign" | "scrollSnapMarginBottom" | "scrollSnapMarginLeft" | "scrollSnapMarginRight" | "scrollSnapMarginTop" | "scrollSnapStop" | "scrollSnapType" | "scrollTimelineAxis" | "scrollTimelineName" | "scrollbarColor" | "scrollbarGutter" | "scrollbarWidth" | "shapeImageThreshold" | "shapeMargin" | "shapeOutside" | "shapeRendering" | "speakAs" | "stopColor" | "stopOpacity" | "stroke" | "strokeColor" | "strokeDasharray" | "strokeDashoffset" | "strokeLinecap" | "strokeLinejoin" | "strokeMiterlimit" | "strokeOpacity" | "strokeWidth" | "tabSize" | "tableLayout" | "textAlign" | "textAlignLast" | "textAnchor" | "textAutospace" | "textBox" | "textBoxEdge" | "textBoxTrim" | "textCombineUpright" | "textDecorationColor" | "textDecorationLine" | "textDecorationSkip" | "textDecorationSkipInk" | "textDecorationStyle" | "textDecorationThickness" | "textEmphasisColor" | "textEmphasisPosition" | "textEmphasisStyle" | "textIndent" | "textJustify" | "textOrientation" | "textOverflow" | "textRendering" | "textShadow" | "textSizeAdjust" | "textSpacingTrim" | "textTransform" | "textUnderlineOffset" | "textUnderlinePosition" | "textWrapMode" | "textWrapStyle" | "timelineScope" | "top" | "touchAction" | "transform" | "transformBox" | "transformOrigin" | "transformStyle" | "transitionBehavior" | "transitionDelay" | "transitionDuration" | "transitionProperty" | "transitionTimingFunction" | "translate" | "unicodeBidi" | "userSelect" | "vectorEffect" | "verticalAlign" | "viewTimelineAxis" | "viewTimelineInset" | "viewTimelineName" | "viewTransitionClass" | "viewTransitionName" | "visibility" | "whiteSpace" | "whiteSpaceCollapse" | "widows" | "willChange" | "wordBreak" | "wordSpacing" | "wordWrap" | "writingMode" | "x" | "y" | "zIndex" | "zoom" | "all" | "animation" | "animationRange" | "background" | "backgroundPosition" | "borderBlock" | "borderBlockColor" | "borderBlockEnd" | "borderBlockStart" | "borderBlockStyle" | "borderBlockWidth" | "borderBottom" | "borderColor" | "borderImage" | "borderInline" | "borderInlineColor" | "borderInlineEnd" | "borderInlineStart" | "borderInlineStyle" | "borderInlineWidth" | "borderLeft" | "borderRadius" | "borderRight" | "borderStyle" | "borderTop" | "borderWidth" | "caret" | "columnRule" | "columns" | "containIntrinsicSize" | "container" | "flex" | "flexFlow" | "grid" | "gridArea" | "gridColumn" | "gridRow" | "gridTemplate" | "inset" | "insetBlock" | "insetInline" | "lineClamp" | "listStyle" | "marginBlock" | "marginInline" | "maskBorder" | "motion" | "offset" | "overflow" | "overscrollBehavior" | "paddingBlock" | "paddingInline" | "placeSelf" | "positionTry" | "scrollMargin" | "scrollMarginBlock" | "scrollMarginInline" | "scrollPadding" | "scrollPaddingBlock" | "scrollPaddingInline" | "scrollSnapMargin" | "scrollTimeline" | "textDecoration" | "textEmphasis" | "textWrap" | "viewTimeline" | "MozAnimationDelay" | "MozAnimationDirection" | "MozAnimationDuration" | "MozAnimationFillMode" | "MozAnimationIterationCount" | "MozAnimationName" | "MozAnimationPlayState" | "MozAnimationTimingFunction" | "MozAppearance" | "MozBackfaceVisibility" | "MozBinding" | "MozBorderBottomColors" | "MozBorderEndColor" | "MozBorderEndStyle" | "MozBorderEndWidth" | "MozBorderLeftColors" | "MozBorderRightColors" | "MozBorderStartColor" | "MozBorderStartStyle" | "MozBorderTopColors" | "MozBoxSizing" | "MozColumnRuleColor" | "MozColumnRuleStyle" | "MozColumnRuleWidth" | "MozColumnWidth" | "MozContextProperties" | "MozFontFeatureSettings" | "MozFontLanguageOverride" | "MozHyphens" | "MozMarginEnd" | "MozMarginStart" | "MozOrient" | "MozOsxFontSmoothing" | "MozOutlineRadiusBottomleft" | "MozOutlineRadiusBottomright" | "MozOutlineRadiusTopleft" | "MozOutlineRadiusTopright" | "MozPaddingEnd" | "MozPaddingStart" | "MozPerspective" | "MozPerspectiveOrigin" | "MozStackSizing" | "MozTabSize" | "MozTextBlink" | "MozTextSizeAdjust" | "MozTransform" | "MozTransformOrigin" | "MozTransformStyle" | "MozUserModify" | "MozUserSelect" | "MozWindowDragging" | "MozWindowShadow" | "msAccelerator" | "msBlockProgression" | "msContentZoomChaining" | "msContentZoomLimitMax" | "msContentZoomLimitMin" | "msContentZoomSnapPoints" | "msContentZoomSnapType" | "msContentZooming" | "msFilter" | "msFlexDirection" | "msFlexPositive" | "msFlowFrom" | "msFlowInto" | "msGridColumns" | "msGridRows" | "msHighContrastAdjust" | "msHyphenateLimitChars" | "msHyphenateLimitLines" | "msHyphenateLimitZone" | "msHyphens" | "msImeAlign" | "msLineBreak" | "msOrder" | "msOverflowStyle" | "msOverflowX" | "msOverflowY" | "msScrollChaining" | "msScrollLimitXMax" | "msScrollLimitXMin" | "msScrollLimitYMax" | "msScrollLimitYMin" | "msScrollRails" | "msScrollSnapPointsX" | "msScrollSnapPointsY" | "msScrollSnapType" | "msScrollTranslation" | "msScrollbar3dlightColor" | "msScrollbarArrowColor" | "msScrollbarBaseColor" | "msScrollbarDarkshadowColor" | "msScrollbarFaceColor" | "msScrollbarHighlightColor" | "msScrollbarShadowColor" | "msScrollbarTrackColor" | "msTextAutospace" | "msTextCombineHorizontal" | "msTextOverflow" | "msTouchAction" | "msTouchSelect" | "msTransform" | "msTransformOrigin" | "msTransitionDelay" | "msTransitionDuration" | "msTransitionProperty" | "msTransitionTimingFunction" | "msUserSelect" | "msWordBreak" | "msWrapFlow" | "msWrapMargin" | "msWrapThrough" | "msWritingMode" | "WebkitAlignContent" | "WebkitAlignItems" | "WebkitAlignSelf" | "WebkitAnimationDelay" | "WebkitAnimationDirection" | "WebkitAnimationDuration" | "WebkitAnimationFillMode" | "WebkitAnimationIterationCount" | "WebkitAnimationName" | "WebkitAnimationPlayState" | "WebkitAnimationTimingFunction" | "WebkitAppearance" | "WebkitBackdropFilter" | "WebkitBackfaceVisibility" | "WebkitBackgroundClip" | "WebkitBackgroundOrigin" | "WebkitBackgroundSize" | "WebkitBorderBeforeColor" | "WebkitBorderBeforeStyle" | "WebkitBorderBeforeWidth" | "WebkitBorderBottomLeftRadius" | "WebkitBorderBottomRightRadius" | "WebkitBorderImageSlice" | "WebkitBorderTopLeftRadius" | "WebkitBorderTopRightRadius" | "WebkitBoxDecorationBreak" | "WebkitBoxReflect" | "WebkitBoxShadow" | "WebkitBoxSizing" | "WebkitClipPath" | "WebkitColumnCount" | "WebkitColumnFill" | "WebkitColumnRuleColor" | "WebkitColumnRuleStyle" | "WebkitColumnRuleWidth" | "WebkitColumnSpan" | "WebkitColumnWidth" | "WebkitFilter" | "WebkitFlexBasis" | "WebkitFlexDirection" | "WebkitFlexGrow" | "WebkitFlexShrink" | "WebkitFlexWrap" | "WebkitFontFeatureSettings" | "WebkitFontKerning" | "WebkitFontSmoothing" | "WebkitFontVariantLigatures" | "WebkitHyphenateCharacter" | "WebkitHyphens" | "WebkitInitialLetter" | "WebkitJustifyContent" | "WebkitLineBreak" | "WebkitLineClamp" | "WebkitLogicalHeight" | "WebkitLogicalWidth" | "WebkitMarginEnd" | "WebkitMarginStart" | "WebkitMaskAttachment" | "WebkitMaskBoxImageOutset" | "WebkitMaskBoxImageRepeat" | "WebkitMaskBoxImageSlice" | "WebkitMaskBoxImageSource" | "WebkitMaskBoxImageWidth" | "WebkitMaskClip" | "WebkitMaskComposite" | "WebkitMaskImage" | "WebkitMaskOrigin" | "WebkitMaskPosition" | "WebkitMaskPositionX" | "WebkitMaskPositionY" | "WebkitMaskRepeat" | "WebkitMaskRepeatX" | "WebkitMaskRepeatY" | "WebkitMaskSize" | "WebkitMaxInlineSize" | "WebkitOrder" | "WebkitOverflowScrolling" | "WebkitPaddingEnd" | "WebkitPaddingStart" | "WebkitPerspective" | "WebkitPerspectiveOrigin" | "WebkitPrintColorAdjust" | "WebkitRubyPosition" | "WebkitScrollSnapType" | "WebkitShapeMargin" | "WebkitTapHighlightColor" | "WebkitTextCombine" | "WebkitTextDecorationColor" | "WebkitTextDecorationLine" | "WebkitTextDecorationSkip" | "WebkitTextDecorationStyle" | "WebkitTextEmphasisColor" | "WebkitTextEmphasisPosition" | "WebkitTextEmphasisStyle" | "WebkitTextFillColor" | "WebkitTextOrientation" | "WebkitTextSizeAdjust" | "WebkitTextStrokeColor" | "WebkitTextStrokeWidth" | "WebkitTextUnderlinePosition" | "WebkitTouchCallout" | "WebkitTransform" | "WebkitTransformOrigin" | "WebkitTransformStyle" | "WebkitTransitionDelay" | "WebkitTransitionDuration" | "WebkitTransitionProperty" | "WebkitTransitionTimingFunction" | "WebkitUserModify" | "WebkitUserSelect" | "WebkitWritingMode" | "MozAnimation" | "MozBorderImage" | "MozColumnRule" | "MozColumns" | "MozOutlineRadius" | "MozTransition" | "msContentZoomLimit" | "msContentZoomSnap" | "msFlex" | "msScrollLimit" | "msScrollSnapX" | "msScrollSnapY" | "msTransition" | "WebkitAnimation" | "WebkitBorderBefore" | "WebkitBorderImage" | "WebkitBorderRadius" | "WebkitColumnRule" | "WebkitColumns" | "WebkitFlex" | "WebkitFlexFlow" | "WebkitMask" | "WebkitMaskBoxImage" | "WebkitTextEmphasis" | "WebkitTextStroke" | "WebkitTransition" | "boxAlign" | "boxDirection" | "boxFlex" | "boxFlexGroup" | "boxLines" | "boxOrdinalGroup" | "boxOrient" | "boxPack" | "clip" | "fontStretch" | "gridColumnGap" | "gridGap" | "gridRowGap" | "imeMode" | "insetArea" | "offsetBlock" | "offsetBlockEnd" | "offsetBlockStart" | "offsetInline" | "offsetInlineEnd" | "offsetInlineStart" | "pageBreakAfter" | "pageBreakBefore" | "pageBreakInside" | "positionTryOptions" | "scrollSnapCoordinate" | "scrollSnapDestination" | "scrollSnapPointsX" | "scrollSnapPointsY" | "scrollSnapTypeX" | "scrollSnapTypeY" | "KhtmlBoxAlign" | "KhtmlBoxDirection" | "KhtmlBoxFlex" | "KhtmlBoxFlexGroup" | "KhtmlBoxLines" | "KhtmlBoxOrdinalGroup" | "KhtmlBoxOrient" | "KhtmlBoxPack" | "KhtmlLineBreak" | "KhtmlOpacity" | "KhtmlUserSelect" | "MozBackgroundClip" | "MozBackgroundOrigin" | "MozBackgroundSize" | "MozBorderRadius" | "MozBorderRadiusBottomleft" | "MozBorderRadiusBottomright" | "MozBorderRadiusTopleft" | "MozBorderRadiusTopright" | "MozBoxAlign" | "MozBoxDirection" | "MozBoxFlex" | "MozBoxOrdinalGroup" | "MozBoxOrient" | "MozBoxPack" | "MozBoxShadow" | "MozColumnCount" | "MozColumnFill" | "MozFloatEdge" | "MozForceBrokenImageIcon" | "MozOpacity" | "MozOutline" | "MozOutlineColor" | "MozOutlineStyle" | "MozOutlineWidth" | "MozTextAlignLast" | "MozTextDecorationColor" | "MozTextDecorationLine" | "MozTextDecorationStyle" | "MozTransitionDelay" | "MozTransitionDuration" | "MozTransitionProperty" | "MozTransitionTimingFunction" | "MozUserFocus" | "MozUserInput" | "msImeMode" | "OAnimation" | "OAnimationDelay" | "OAnimationDirection" | "OAnimationDuration" | "OAnimationFillMode" | "OAnimationIterationCount" | "OAnimationName" | "OAnimationPlayState" | "OAnimationTimingFunction" | "OBackgroundSize" | "OBorderImage" | "OObjectFit" | "OObjectPosition" | "OTabSize" | "OTextOverflow" | "OTransform" | "OTransformOrigin" | "OTransition" | "OTransitionDelay" | "OTransitionDuration" | "OTransitionProperty" | "OTransitionTimingFunction" | "WebkitBoxAlign" | "WebkitBoxDirection" | "WebkitBoxFlex" | "WebkitBoxFlexGroup" | "WebkitBoxLines" | "WebkitBoxOrdinalGroup" | "WebkitBoxOrient" | "WebkitBoxPack" | "colorInterpolation" | "colorRendering" | "glyphOrientationVertical" | "svgFill" | "fade" | "scrollbar" | "boldFontWeight" | "hide" | "shadow" | "radius" | "flow" | "gridAreas" | "gridColumns" | "gridRows" | "preset" | "align" | "justify" | "place" | "@keyframes" | "@properties" | "recipe" | "as" | "element" | "styles" | "breakpoints" | "block" | "inline" | "mods" | "isHidden" | "isDisabled" | "css" | "theme" | "tokens" | "ref"> & RefAttributes<unknown>> & SubElementComponents<Record<string, never>>;
|
|
112
117
|
//#endregion
|
|
113
118
|
export { AllBasePropsWithMods, Element, ElementsDefinition, ModPropDef, ModPropsInput, ResolveModPropDef, ResolveModProps, SubElementDefinition, SubElementProps, TastyElementOptions, TastyElementProps, TastyProps, VariantMap, WithVariant, tasty };
|
|
114
119
|
//# sourceMappingURL=tasty.d.ts.map
|
package/dist/tasty.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasty.js","names":["modAttrs"],"sources":["../src/tasty.tsx"],"sourcesContent":["import type {\n AllHTMLAttributes,\n ComponentType,\n ForwardRefExoticComponent,\n JSX,\n PropsWithoutRef,\n RefAttributes,\n} from 'react';\nimport { createElement, forwardRef, useMemo, useRef } from 'react';\nimport { useStyles } from './hooks/useStyles';\nimport { BASE_STYLES } from './styles/list';\nimport type { Styles, StylesInterface } from './styles/types';\nimport type {\n AllBaseProps,\n BaseProps,\n BaseStyleProps,\n ModValue,\n Mods,\n Props,\n Tokens,\n} from './types';\nimport { getDisplayName } from './utils/get-display-name';\nimport { isValidElementType } from './utils/is-valid-element-type';\nimport { mergeStyles } from './utils/merge-styles';\nimport { isSelector } from './pipeline';\nimport { hasKeys } from './utils/has-keys';\nimport { modAttrs } from './utils/mod-attrs';\nimport { processTokens, stringifyTokens } from './utils/process-tokens';\n\nimport type { StyleValue, StyleValueStateMap } from './utils/styles';\n\n/**\n * Mapping of is* properties to their corresponding HTML attributes\n */\nconst IS_PROPERTIES_MAP = {\n isDisabled: 'disabled',\n isHidden: 'hidden',\n isChecked: 'checked',\n} as const;\n\n/**\n * Precalculated entries for performance optimization\n */\nconst IS_PROPERTIES_ENTRIES = Object.entries(IS_PROPERTIES_MAP);\n\n/**\n * Helper function to handle is* properties consistently\n * Transforms is* props to HTML attributes and adds corresponding data-* attributes\n */\nfunction handleIsProperties(props: Record<string, unknown>) {\n for (const [isProperty, targetAttribute] of IS_PROPERTIES_ENTRIES) {\n if (isProperty in props) {\n props[targetAttribute] = props[isProperty];\n delete props[isProperty];\n }\n\n // Add data-* attribute if target attribute is truthy and doesn't already exist\n const dataAttribute = `data-${targetAttribute}`;\n if (!(dataAttribute in props) && props[targetAttribute]) {\n props[dataAttribute] = '';\n }\n }\n}\n\n/**\n * Creates a sub-element component for compound component patterns.\n * Sub-elements are lightweight components with data-element attribute for CSS targeting.\n */\nfunction createSubElement<Tag extends keyof JSX.IntrinsicElements>(\n elementName: string,\n definition: SubElementDefinition<Tag>,\n): ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<Tag>> & RefAttributes<unknown>\n> {\n // Normalize definition to object form\n const config =\n typeof definition === 'string'\n ? { as: definition as Tag }\n : (definition as { as?: Tag; qa?: string; qaVal?: string | number });\n\n const tag = config.as ?? ('div' as Tag);\n const defaultQa = config.qa;\n const defaultQaVal = config.qaVal;\n\n const SubElement = forwardRef<unknown, SubElementProps<Tag>>((props, ref) => {\n const {\n qa,\n qaVal,\n mods,\n tokens,\n isDisabled,\n isHidden,\n isChecked,\n className,\n style,\n ...htmlProps\n } = props as SubElementProps<Tag> & {\n className?: string;\n style?: Record<string, unknown>;\n };\n\n // Build mod attributes\n let modDataAttrs: Record<string, unknown> | undefined;\n if (mods) {\n modDataAttrs = modAttrs(mods as Mods) as Record<string, unknown>;\n }\n\n // Process tokens into inline style properties\n const tokenStyle = tokens\n ? (processTokens(tokens) as Record<string, unknown>)\n : undefined;\n\n // Merge token styles with explicit style prop (style has priority)\n let mergedStyle: Record<string, unknown> | undefined;\n if (tokenStyle || style) {\n mergedStyle =\n tokenStyle && style\n ? { ...tokenStyle, ...style }\n : ((tokenStyle ?? style) as Record<string, unknown>);\n }\n\n const elementProps = {\n 'data-element': elementName,\n 'data-qa': qa ?? defaultQa,\n 'data-qaval': qaVal ?? defaultQaVal,\n ...(modDataAttrs || {}),\n ...htmlProps,\n className,\n style: mergedStyle,\n isDisabled,\n isHidden,\n isChecked,\n ref,\n } as Record<string, unknown>;\n\n // Handle is* properties (isDisabled -> disabled + data-disabled, etc.)\n handleIsProperties(elementProps);\n\n // Clean up undefined data attributes\n if (elementProps['data-qa'] === undefined) delete elementProps['data-qa'];\n if (elementProps['data-qaval'] === undefined)\n delete elementProps['data-qaval'];\n\n return createElement(tag, elementProps);\n });\n\n SubElement.displayName = `SubElement(${elementName})`;\n\n return SubElement as ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<Tag>> & RefAttributes<unknown>\n >;\n}\n\ntype StyleList = readonly (keyof {\n [key in keyof StylesInterface]: StylesInterface[key];\n})[];\n\n// ============================================================================\n// Mod props types — expose modifier keys as top-level component props\n// ============================================================================\n\n/** Type descriptor for a single mod prop: a JS constructor or an enum array. */\nexport type ModPropDef =\n | BooleanConstructor\n | StringConstructor\n | NumberConstructor\n | readonly string[];\n\n/** Array form: list of mod key names (types default to ModValue). */\ntype ModPropsList = readonly string[];\n\n/** Object form: map of mod key names to type descriptors. */\ntype ModPropsMap = Readonly<Record<string, ModPropDef>>;\n\n/** Either array or object form accepted by `modProps` option. */\nexport type ModPropsInput = ModPropsList | ModPropsMap;\n\n/** Resolve a single ModPropDef to its TypeScript type. */\nexport type ResolveModPropDef<T> = T extends BooleanConstructor\n ? boolean\n : T extends StringConstructor\n ? string\n : T extends NumberConstructor\n ? number\n : T extends readonly (infer U)[]\n ? U\n : ModValue;\n\n/** Resolve an entire `modProps` definition to the component prop types it adds. */\nexport type ResolveModProps<M extends ModPropsInput> =\n M extends readonly (infer K)[]\n ? Partial<Record<K & string, ModValue>>\n : M extends Record<string, ModPropDef>\n ? { [key in keyof M & string]?: ResolveModPropDef<M[key]> }\n : // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n {};\n\nexport type PropsWithStyles = {\n styles?: Styles;\n} & Omit<Props, 'styles'>;\n\nexport type VariantMap = Record<string, Styles>;\n\nexport interface WithVariant<V extends VariantMap> {\n variant?: keyof V;\n}\n\n// ============================================================================\n// Sub-element types for compound components\n// ============================================================================\n\n/**\n * Definition for a sub-element. Can be either:\n * - A tag name string (e.g., 'div', 'span')\n * - An object with configuration options\n */\nexport type SubElementDefinition<\n Tag extends keyof JSX.IntrinsicElements = 'div',\n> =\n | Tag\n | {\n as?: Tag;\n qa?: string;\n qaVal?: string | number;\n };\n\n/**\n * Map of sub-element definitions.\n * Keys become the sub-component names (e.g., { Icon: 'span' } -> Component.Icon)\n */\nexport type ElementsDefinition = Record<\n string,\n SubElementDefinition<keyof JSX.IntrinsicElements>\n>;\n\n/**\n * Resolves the tag from a SubElementDefinition\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype ResolveElementTag<T extends SubElementDefinition<any>> = T extends string\n ? T\n : T extends { as?: infer Tag }\n ? Tag extends keyof JSX.IntrinsicElements\n ? Tag\n : 'div'\n : 'div';\n\n/**\n * Props for sub-element components.\n * Combines HTML attributes with tasty-specific props (qa, qaVal, mods, tokens, isDisabled, etc.)\n */\nexport type SubElementProps<Tag extends keyof JSX.IntrinsicElements = 'div'> =\n Omit<\n JSX.IntrinsicElements[Tag],\n 'ref' | 'color' | 'content' | 'translate'\n > & {\n qa?: string;\n qaVal?: string | number;\n mods?: Mods;\n tokens?: Tokens;\n isDisabled?: boolean;\n isHidden?: boolean;\n isChecked?: boolean;\n };\n\n/**\n * Generates the sub-element component types from an ElementsDefinition\n */\ntype SubElementComponents<E extends ElementsDefinition> = {\n [K in keyof E]: ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<ResolveElementTag<E[K]>>> &\n RefAttributes<\n ResolveElementTag<E[K]> extends keyof HTMLElementTagNameMap\n ? HTMLElementTagNameMap[ResolveElementTag<E[K]>]\n : Element\n >\n >;\n};\n\n/**\n * Base type containing common properties shared between TastyProps and TastyElementOptions.\n * Separated to avoid code duplication while allowing different type constraints.\n */\ntype TastyBaseProps<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n M extends ModPropsInput = readonly string[],\n> = {\n /** Default styles of the element. */\n styles?: Styles;\n /** The list of styles that can be provided by props */\n styleProps?: K;\n /** Modifier keys exposed as top-level component props (array or typed object form). */\n modProps?: M;\n element?: BaseProps['element'];\n variants?: V;\n /** Default tokens for inline CSS custom properties */\n tokens?: Tokens;\n /** Sub-element definitions for compound components */\n elements?: E;\n} & Pick<BaseProps, 'qa' | 'qaVal'> &\n WithVariant<V>;\n\nexport type TastyProps<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n DefaultProps = Props,\n M extends ModPropsInput = readonly string[],\n> = TastyBaseProps<K, V, E, M> & {\n /** The tag name of the element or a React component. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n as?: string | ComponentType<any>;\n} & Partial<\n Omit<DefaultProps, 'as' | 'styles' | 'styleProps' | 'modProps' | 'tokens'>\n >;\n\n/**\n * TastyElementOptions is used for the element-creation overload of tasty().\n * It includes a Tag generic that allows TypeScript to infer the correct\n * HTML element type from the `as` prop.\n *\n * Note: Uses a separate index signature with `unknown` instead of inheriting\n * from Props (which has `any`) to ensure strict type checking for styles.\n */\nexport type TastyElementOptions<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n M extends ModPropsInput = readonly string[],\n> = TastyBaseProps<K, V, E, M> & {\n /** The tag name of the element or a React component. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n as?: Tag | ComponentType<any>;\n} & Record<string, unknown>;\n\nexport type AllBasePropsWithMods<\n K extends StyleList,\n M extends ModPropsInput = readonly string[],\n> = AllBaseProps & {\n [key in K[number]]?:\n | StyleValue<StylesInterface[key]>\n | StyleValueStateMap<StylesInterface[key]>;\n} & BaseStyleProps &\n ResolveModProps<M>;\n\n/**\n * Keys from BasePropsWithoutChildren that should be omitted from HTML attributes.\n * This excludes event handlers so they can be properly typed from JSX.IntrinsicElements.\n */\ntype TastySpecificKeys =\n | 'as'\n | 'qa'\n | 'qaVal'\n | 'element'\n | 'styles'\n | 'breakpoints'\n | 'block'\n | 'inline'\n | 'mods'\n | 'isHidden'\n | 'isDisabled'\n | 'css'\n | 'style'\n | 'theme'\n | 'tokens'\n | 'ref'\n | 'color';\n\n/**\n * Props type for tasty elements that combines:\n * - AllBasePropsWithMods for style props with strict tokens type\n * - HTML attributes for flexibility (properly typed based on tag)\n * - Variant support\n *\n * Uses AllHTMLAttributes as base for common attributes (like disabled),\n * but overrides event handlers with tag-specific types from JSX.IntrinsicElements.\n */\nexport type TastyElementProps<\n K extends StyleList,\n V extends VariantMap,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n M extends ModPropsInput = readonly string[],\n> = AllBasePropsWithMods<K, M> &\n WithVariant<V> &\n Omit<\n Omit<AllHTMLAttributes<HTMLElement>, keyof JSX.IntrinsicElements[Tag]> &\n JSX.IntrinsicElements[Tag],\n TastySpecificKeys | K[number]\n >;\n\ntype TastyComponentPropsWithDefaults<\n Props extends PropsWithStyles,\n DefaultProps extends Partial<Props>,\n> = keyof DefaultProps extends never\n ? Props\n : {\n [key in Extract<keyof Props, keyof DefaultProps>]?: Props[key];\n } & {\n [key in keyof Omit<Props, keyof DefaultProps>]: Props[key];\n };\n\nexport function tasty<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n M extends ModPropsInput = readonly string[],\n>(\n options: TastyElementOptions<K, V, E, Tag, M>,\n secondArg?: never,\n): ForwardRefExoticComponent<\n PropsWithoutRef<TastyElementProps<K, V, Tag, M>> & RefAttributes<unknown>\n> &\n SubElementComponents<E>;\nexport function tasty<\n Props extends PropsWithStyles,\n DefaultProps extends Partial<Props> = Partial<Props>,\n>(\n Component: ComponentType<Props>,\n options?: TastyProps<never, never, Record<string, never>, Props>,\n): ComponentType<TastyComponentPropsWithDefaults<Props, DefaultProps>>;\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n// Implementation\nexport function tasty<\n K extends StyleList,\n V extends VariantMap,\n _C = Record<string, unknown>,\n>(Component: any, options?: any) {\n if (isValidElementType(Component)) {\n return tastyWrap(Component as ComponentType<any>, options);\n }\n\n return tastyElement(Component as TastyProps<K, V>);\n}\n\nfunction tastyWrap<\n P extends PropsWithStyles,\n DefaultProps extends Partial<P> = Partial<P>,\n>(\n Component: ComponentType<P>,\n options?: TastyProps<never, never, P>,\n): ComponentType<TastyComponentPropsWithDefaults<P, DefaultProps>> {\n const {\n as: extendTag,\n element: extendElement,\n ...defaultProps\n } = (options ?? {}) as TastyProps<never, never, P>;\n\n const propsWithStyles = ['styles'].concat(\n Object.keys(defaultProps).filter((prop) => prop.endsWith('Styles')),\n );\n\n const _WrappedComponent = forwardRef<any, any>((props, ref) => {\n const { as, element, ...restProps } = props as Record<string, unknown>;\n const propsWithStylesValues = propsWithStyles.map(\n (prop) => (props as any)[prop],\n );\n\n const mergedStylesMap: Styles | undefined = useMemo(() => {\n return propsWithStyles.reduce((map, prop) => {\n const restValue = (restProps as any)[prop];\n const defaultValue = (defaultProps as any)[prop];\n\n if (restValue != null && defaultValue != null) {\n (map as any)[prop] = mergeStyles(defaultValue, restValue);\n } else {\n (map as any)[prop] = restValue ?? defaultValue;\n }\n\n return map;\n }, {} as Styles);\n }, [propsWithStylesValues]);\n\n const elementProps = {\n ...(defaultProps as unknown as Record<string, unknown>),\n ...(restProps as unknown as Record<string, unknown>),\n ...(mergedStylesMap as unknown as Record<string, unknown>),\n as: (as as string | undefined) ?? extendTag,\n element: (element as string | undefined) || extendElement,\n ref,\n } as unknown as P;\n\n return createElement(Component as ComponentType<P>, elementProps);\n });\n\n _WrappedComponent.displayName = `TastyWrappedComponent(${getDisplayName(\n Component,\n (defaultProps as any).qa ?? (extendTag as any) ?? 'Anonymous',\n )})`;\n\n return _WrappedComponent as unknown as ComponentType<\n TastyComponentPropsWithDefaults<P, DefaultProps>\n >;\n}\n\nfunction tastyElement<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition,\n>(tastyOptions: TastyProps<K, V, E>) {\n const {\n as: originalAs = 'div',\n element: defaultElement,\n styles: defaultStyles,\n styleProps,\n modProps: modPropsDef,\n variants,\n tokens: defaultTokens,\n elements,\n ...defaultProps\n } = tastyOptions;\n\n // Pre-compute merged styles for each variant (if variants are defined)\n // This avoids creating separate component instances per variant\n let variantStylesMap: Record<string, Styles | undefined> | undefined;\n if (variants) {\n // Split defaultStyles: extend-mode state maps (no '' key, non-selector)\n // are pulled out and applied AFTER variant merge so they survive\n // replace-mode maps in variants.\n let baseStyles = defaultStyles;\n let extensionStyles: Styles | undefined;\n\n if (defaultStyles) {\n for (const key of Object.keys(defaultStyles)) {\n if (isSelector(key)) continue;\n\n const value = (defaultStyles as Record<string, unknown>)[key];\n\n if (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n !('' in value)\n ) {\n if (!extensionStyles) {\n baseStyles = { ...defaultStyles } as Styles;\n extensionStyles = {} as Styles;\n }\n (extensionStyles as Record<string, unknown>)[key] = value;\n delete (baseStyles as Record<string, unknown>)[key];\n }\n }\n }\n\n const variantEntries = Object.entries(variants) as [string, Styles][];\n variantStylesMap = variantEntries.reduce(\n (map, [variant, variantStyles]) => {\n map[variant] = extensionStyles\n ? mergeStyles(baseStyles, variantStyles, extensionStyles)\n : mergeStyles(baseStyles, variantStyles);\n return map;\n },\n {} as Record<string, Styles | undefined>,\n );\n // Ensure 'default' variant always exists\n if (!variantStylesMap['default']) {\n variantStylesMap['default'] = defaultStyles;\n }\n }\n\n const {\n qa: defaultQa,\n qaVal: defaultQaVal,\n ...otherDefaultProps\n } = defaultProps ?? {};\n\n const propsToCheck = styleProps\n ? (styleProps as StyleList).concat(BASE_STYLES)\n : BASE_STYLES;\n\n const modPropsKeys: string[] | undefined = modPropsDef\n ? ((Array.isArray(modPropsDef)\n ? modPropsDef\n : Object.keys(modPropsDef)) as string[])\n : undefined;\n\n const _TastyComponent = forwardRef<\n unknown,\n AllBasePropsWithMods<K> & WithVariant<V>\n >((allProps, ref) => {\n const {\n as,\n styles: rawStyles,\n variant,\n mods,\n element,\n qa,\n qaVal,\n className: userClassName,\n tokens,\n style,\n ...otherProps\n } = allProps as Record<string, unknown> as AllBasePropsWithMods<K> &\n WithVariant<V> & {\n className?: string;\n tokens?: Tokens;\n style?: Record<string, unknown>;\n };\n\n let styles = rawStyles;\n\n let propStyles: Styles | null = null;\n let propStylesKey = '';\n\n for (const prop of propsToCheck) {\n const key = prop as unknown as string;\n\n if (key in otherProps) {\n if (!propStyles) propStyles = {};\n const value = (otherProps as any)[key];\n (propStyles as any)[key] = value;\n delete (otherProps as any)[key];\n propStylesKey += key + '\\0' + value + '\\0';\n }\n }\n\n if (!styles || (styles && !hasKeys(styles as Record<string, unknown>))) {\n styles = undefined as unknown as Styles;\n }\n\n // Stabilize propStyles reference: only update when content actually changes\n const propStylesRef = useRef<{ key: string; styles: Styles | null }>({\n key: '',\n styles: null,\n });\n if (propStylesRef.current.key !== propStylesKey) {\n propStylesRef.current = { key: propStylesKey, styles: propStyles };\n }\n\n // Determine base styles: use variant styles if available, otherwise default styles\n const baseStyles = variantStylesMap\n ? (variantStylesMap[(variant as string) || 'default'] ??\n variantStylesMap['default'])\n : defaultStyles;\n\n // Merge base styles with instance styles and prop styles\n const allStyles = useMemo(() => {\n const currentPropStyles = propStylesRef.current.styles;\n const hasStyleProps =\n styles && hasKeys(styles as Record<string, unknown>);\n const hasPropStyles = currentPropStyles && hasKeys(currentPropStyles);\n\n if (!hasStyleProps && !hasPropStyles) {\n return baseStyles;\n }\n\n return mergeStyles(\n baseStyles,\n styles as Styles,\n currentPropStyles as Styles,\n );\n }, [baseStyles, styles, propStylesKey]);\n\n // Use the useStyles hook for style generation and injection\n const { className: stylesClassName } = useStyles(allStyles);\n\n // Merge default tokens with instance tokens (instance overrides defaults)\n const tokensKey = stringifyTokens(tokens as Tokens | undefined);\n const mergedTokens = useMemo(() => {\n if (!defaultTokens && !tokens) return undefined;\n if (!defaultTokens) return tokens as Tokens;\n if (!tokens) return defaultTokens;\n return { ...defaultTokens, ...tokens } as Tokens;\n }, [tokensKey]);\n\n // Process merged tokens into inline style properties\n const processedTokenStyle = useMemo(() => {\n return processTokens(mergedTokens);\n }, [mergedTokens]);\n\n // Merge processed tokens with explicit style prop (style has priority)\n const mergedStyle = useMemo(() => {\n if (!processedTokenStyle && !style) return undefined;\n if (!processedTokenStyle) return style;\n if (!style) return processedTokenStyle;\n return { ...processedTokenStyle, ...style };\n }, [processedTokenStyle, style]);\n\n let propMods: Record<string, ModValue> | undefined;\n if (modPropsKeys) {\n for (const key of modPropsKeys) {\n if (key in otherProps) {\n if (!propMods) propMods = {};\n propMods[key] = (otherProps as Record<string, unknown>)[\n key\n ] as ModValue;\n delete (otherProps as Record<string, unknown>)[key];\n }\n }\n }\n\n const mergedMods = propMods\n ? { ...(mods as Record<string, ModValue>), ...propMods }\n : (mods as Record<string, ModValue> | undefined);\n\n let modDataAttrs: Record<string, unknown> | undefined;\n if (mergedMods) {\n modDataAttrs = modAttrs(mergedMods as unknown as Mods) as Record<\n string,\n unknown\n >;\n }\n\n // Merge user className with generated className\n const finalClassName = [(userClassName as string) || '', stylesClassName]\n .filter(Boolean)\n .join(' ');\n\n const elementProps = {\n 'data-element': (element as string | undefined) || defaultElement,\n 'data-qa': (qa as string | undefined) || defaultQa,\n 'data-qaval': (qaVal as string | undefined) || defaultQaVal,\n ...(otherDefaultProps as unknown as Record<string, unknown>),\n ...(modDataAttrs || {}),\n ...(otherProps as unknown as Record<string, unknown>),\n className: finalClassName,\n style: mergedStyle,\n ref,\n } as Record<string, unknown>;\n\n // Apply the helper to handle is* properties\n handleIsProperties(elementProps);\n\n const renderedElement = createElement(\n (as as string | 'div') ?? originalAs,\n elementProps,\n );\n\n return renderedElement;\n });\n\n _TastyComponent.displayName = `TastyComponent(${\n (defaultProps as any).qa || originalAs\n })`;\n\n // Attach sub-element components if elements are defined\n if (elements) {\n const subElements = Object.entries(elements).reduce(\n (acc, [name, definition]) => {\n acc[name] = createSubElement(\n name,\n definition as SubElementDefinition<keyof JSX.IntrinsicElements>,\n );\n return acc;\n },\n {} as Record<string, ForwardRefExoticComponent<any>>,\n );\n\n return Object.assign(_TastyComponent, subElements);\n }\n\n return _TastyComponent;\n}\n\nexport const Element = tasty({});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tasty.js","names":["modAttrs"],"sources":["../src/tasty.tsx"],"sourcesContent":["import type {\n AllHTMLAttributes,\n ComponentType,\n ForwardRefExoticComponent,\n JSX,\n PropsWithoutRef,\n RefAttributes,\n} from 'react';\nimport { createElement, forwardRef, useMemo, useRef } from 'react';\nimport { useStyles } from './hooks/useStyles';\nimport { BASE_STYLES } from './styles/list';\nimport type { Styles, StylesInterface } from './styles/types';\nimport type {\n AllBaseProps,\n BaseProps,\n BaseStyleProps,\n ModValue,\n Mods,\n Props,\n Tokens,\n} from './types';\nimport { getDisplayName } from './utils/get-display-name';\nimport { isValidElementType } from './utils/is-valid-element-type';\nimport { mergeStyles } from './utils/merge-styles';\nimport { isSelector } from './pipeline';\nimport { hasKeys } from './utils/has-keys';\nimport { modAttrs } from './utils/mod-attrs';\nimport { processTokens, stringifyTokens } from './utils/process-tokens';\n\nimport type { StyleValue, StyleValueStateMap } from './utils/styles';\n\n/**\n * Mapping of is* properties to their corresponding HTML attributes\n */\nconst IS_PROPERTIES_MAP = {\n isDisabled: 'disabled',\n isHidden: 'hidden',\n isChecked: 'checked',\n} as const;\n\n/**\n * Precalculated entries for performance optimization\n */\nconst IS_PROPERTIES_ENTRIES = Object.entries(IS_PROPERTIES_MAP);\n\n/**\n * Helper function to handle is* properties consistently\n * Transforms is* props to HTML attributes and adds corresponding data-* attributes\n */\nfunction handleIsProperties(props: Record<string, unknown>) {\n for (const [isProperty, targetAttribute] of IS_PROPERTIES_ENTRIES) {\n if (isProperty in props) {\n props[targetAttribute] = props[isProperty];\n delete props[isProperty];\n }\n\n // Add data-* attribute if target attribute is truthy and doesn't already exist\n const dataAttribute = `data-${targetAttribute}`;\n if (!(dataAttribute in props) && props[targetAttribute]) {\n props[dataAttribute] = '';\n }\n }\n}\n\n/**\n * Creates a sub-element component for compound component patterns.\n * Sub-elements are lightweight components with data-element attribute for CSS targeting.\n */\nfunction createSubElement<Tag extends keyof JSX.IntrinsicElements>(\n elementName: string,\n definition: SubElementDefinition<Tag>,\n): ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<Tag>> & RefAttributes<unknown>\n> {\n // Normalize definition to object form\n const config =\n typeof definition === 'string'\n ? { as: definition as Tag }\n : (definition as { as?: Tag; qa?: string; qaVal?: string | number });\n\n const tag = config.as ?? ('div' as Tag);\n const defaultQa = config.qa;\n const defaultQaVal = config.qaVal;\n\n const SubElement = forwardRef<unknown, SubElementProps<Tag>>((props, ref) => {\n const {\n qa,\n qaVal,\n mods,\n tokens,\n isDisabled,\n isHidden,\n isChecked,\n className,\n style,\n ...htmlProps\n } = props as SubElementProps<Tag> & {\n className?: string;\n style?: Record<string, unknown>;\n };\n\n // Build mod attributes\n let modDataAttrs: Record<string, unknown> | undefined;\n if (mods) {\n modDataAttrs = modAttrs(mods as Mods) as Record<string, unknown>;\n }\n\n // Process tokens into inline style properties\n const tokenStyle = tokens\n ? (processTokens(tokens) as Record<string, unknown>)\n : undefined;\n\n // Merge token styles with explicit style prop (style has priority)\n let mergedStyle: Record<string, unknown> | undefined;\n if (tokenStyle || style) {\n mergedStyle =\n tokenStyle && style\n ? { ...tokenStyle, ...style }\n : ((tokenStyle ?? style) as Record<string, unknown>);\n }\n\n const elementProps = {\n 'data-element': elementName,\n 'data-qa': qa ?? defaultQa,\n 'data-qaval': qaVal ?? defaultQaVal,\n ...(modDataAttrs || {}),\n ...htmlProps,\n className,\n style: mergedStyle,\n isDisabled,\n isHidden,\n isChecked,\n ref,\n } as Record<string, unknown>;\n\n // Handle is* properties (isDisabled -> disabled + data-disabled, etc.)\n handleIsProperties(elementProps);\n\n // Clean up undefined data attributes\n if (elementProps['data-qa'] === undefined) delete elementProps['data-qa'];\n if (elementProps['data-qaval'] === undefined)\n delete elementProps['data-qaval'];\n\n return createElement(tag, elementProps);\n });\n\n SubElement.displayName = `SubElement(${elementName})`;\n\n return SubElement as ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<Tag>> & RefAttributes<unknown>\n >;\n}\n\ntype StyleList = readonly (keyof {\n [key in keyof StylesInterface]: StylesInterface[key];\n})[];\n\n// ============================================================================\n// Mod props types — expose modifier keys as top-level component props\n// ============================================================================\n\n/** Type descriptor for a single mod prop: a JS constructor or an enum array. */\nexport type ModPropDef =\n | BooleanConstructor\n | StringConstructor\n | NumberConstructor\n | readonly string[];\n\n/** Array form: list of mod key names (types default to ModValue). */\ntype ModPropsList = readonly string[];\n\n/** Object form: map of mod key names to type descriptors. */\ntype ModPropsMap = Readonly<Record<string, ModPropDef>>;\n\n/** Either array or object form accepted by `modProps` option. */\nexport type ModPropsInput = ModPropsList | ModPropsMap;\n\n/** Resolve a single ModPropDef to its TypeScript type. */\nexport type ResolveModPropDef<T> = T extends BooleanConstructor\n ? boolean\n : T extends StringConstructor\n ? string\n : T extends NumberConstructor\n ? number\n : T extends readonly (infer U)[]\n ? U\n : ModValue;\n\n/** Resolve an entire `modProps` definition to the component prop types it adds. */\nexport type ResolveModProps<M extends ModPropsInput> =\n M extends readonly (infer K)[]\n ? Partial<Record<K & string, ModValue>>\n : M extends Record<string, ModPropDef>\n ? { [key in keyof M & string]?: ResolveModPropDef<M[key]> }\n : // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n {};\n\nexport type PropsWithStyles = {\n styles?: Styles;\n} & Omit<Props, 'styles'>;\n\nexport type VariantMap = Record<string, Styles>;\n\nexport interface WithVariant<V extends VariantMap> {\n variant?: keyof V;\n}\n\n// ============================================================================\n// Sub-element types for compound components\n// ============================================================================\n\n/**\n * Definition for a sub-element. Can be either:\n * - A tag name string (e.g., 'div', 'span')\n * - An object with configuration options\n */\nexport type SubElementDefinition<\n Tag extends keyof JSX.IntrinsicElements = 'div',\n> =\n | Tag\n | {\n as?: Tag;\n qa?: string;\n qaVal?: string | number;\n };\n\n/**\n * Map of sub-element definitions.\n * Keys become the sub-component names (e.g., { Icon: 'span' } -> Component.Icon)\n */\nexport type ElementsDefinition = Record<\n string,\n SubElementDefinition<keyof JSX.IntrinsicElements>\n>;\n\n/**\n * Resolves the tag from a SubElementDefinition\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype ResolveElementTag<T extends SubElementDefinition<any>> = T extends string\n ? T\n : T extends { as?: infer Tag }\n ? Tag extends keyof JSX.IntrinsicElements\n ? Tag\n : 'div'\n : 'div';\n\n/**\n * Props for sub-element components.\n * Combines HTML attributes with tasty-specific props (qa, qaVal, mods, tokens, isDisabled, etc.)\n */\nexport type SubElementProps<Tag extends keyof JSX.IntrinsicElements = 'div'> =\n Omit<\n JSX.IntrinsicElements[Tag],\n 'ref' | 'color' | 'content' | 'translate'\n > & {\n qa?: string;\n qaVal?: string | number;\n mods?: Mods;\n tokens?: Tokens;\n isDisabled?: boolean;\n isHidden?: boolean;\n isChecked?: boolean;\n };\n\n/**\n * Generates the sub-element component types from an ElementsDefinition\n */\ntype SubElementComponents<E extends ElementsDefinition> = {\n [K in keyof E]: ForwardRefExoticComponent<\n PropsWithoutRef<SubElementProps<ResolveElementTag<E[K]>>> &\n RefAttributes<\n ResolveElementTag<E[K]> extends keyof HTMLElementTagNameMap\n ? HTMLElementTagNameMap[ResolveElementTag<E[K]>]\n : Element\n >\n >;\n};\n\n/**\n * Base type containing common properties shared between TastyProps and TastyElementOptions.\n * Separated to avoid code duplication while allowing different type constraints.\n */\ntype TastyBaseProps<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n M extends ModPropsInput = readonly never[],\n> = {\n /** Default styles of the element. */\n styles?: Styles;\n /** The list of styles that can be provided by props */\n styleProps?: K;\n /** Modifier keys exposed as top-level component props (array or typed object form). */\n modProps?: M;\n element?: BaseProps['element'];\n variants?: V;\n /** Default tokens for inline CSS custom properties */\n tokens?: Tokens;\n /** Sub-element definitions for compound components */\n elements?: E;\n} & Pick<BaseProps, 'qa' | 'qaVal'> &\n WithVariant<V>;\n\nexport type TastyProps<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n DefaultProps = Props,\n M extends ModPropsInput = readonly never[],\n> = TastyBaseProps<K, V, E, M> & {\n /** The tag name of the element or a React component. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n as?: string | ComponentType<any>;\n} & Partial<\n Omit<DefaultProps, 'as' | 'styles' | 'styleProps' | 'modProps' | 'tokens'>\n >;\n\n/**\n * TastyElementOptions is used for the element-creation overload of tasty().\n * It includes a Tag generic that allows TypeScript to infer the correct\n * HTML element type from the `as` prop.\n *\n * Note: Uses a separate index signature with `unknown` instead of inheriting\n * from Props (which has `any`) to ensure strict type checking for styles.\n */\nexport type TastyElementOptions<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n M extends ModPropsInput = readonly never[],\n> = TastyBaseProps<K, V, E, M> & {\n /** The tag name of the element or a React component. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n as?: Tag | ComponentType<any>;\n} & Record<string, unknown>;\n\nexport type AllBasePropsWithMods<\n K extends StyleList,\n M extends ModPropsInput = readonly never[],\n> = AllBaseProps & {\n [key in K[number]]?:\n | StyleValue<StylesInterface[key]>\n | StyleValueStateMap<StylesInterface[key]>;\n} & BaseStyleProps &\n ResolveModProps<M>;\n\n/**\n * Keys from BasePropsWithoutChildren that should be omitted from HTML attributes.\n * This excludes event handlers so they can be properly typed from JSX.IntrinsicElements.\n */\ntype TastySpecificKeys =\n | 'as'\n | 'qa'\n | 'qaVal'\n | 'element'\n | 'styles'\n | 'breakpoints'\n | 'block'\n | 'inline'\n | 'mods'\n | 'isHidden'\n | 'isDisabled'\n | 'css'\n | 'style'\n | 'theme'\n | 'tokens'\n | 'ref'\n | 'color';\n\n/**\n * Props type for tasty elements that combines:\n * - AllBasePropsWithMods for style props with strict tokens type\n * - HTML attributes for flexibility (properly typed based on tag)\n * - Variant support\n *\n * AllBasePropsWithMods carries generic AllHTMLAttributes which can conflict\n * with tag-specific types from JSX.IntrinsicElements (e.g. `src` is `string`\n * in AllHTMLAttributes but `string | Blob` in ImgHTMLAttributes). To avoid\n * intersection-narrowing, we Omit tag-specific keys from AllBasePropsWithMods\n * (keeping TastySpecificKeys and style props) and let JSX.IntrinsicElements\n * supply the authoritative HTML attribute types.\n */\nexport type TastyElementProps<\n K extends StyleList,\n V extends VariantMap,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n M extends ModPropsInput = readonly never[],\n> = Omit<\n AllBasePropsWithMods<K, M>,\n Exclude<keyof JSX.IntrinsicElements[Tag], TastySpecificKeys | K[number]>\n> &\n WithVariant<V> &\n Omit<\n Omit<AllHTMLAttributes<HTMLElement>, keyof JSX.IntrinsicElements[Tag]> &\n JSX.IntrinsicElements[Tag],\n TastySpecificKeys | K[number]\n >;\n\ntype TastyComponentPropsWithDefaults<\n Props extends PropsWithStyles,\n DefaultProps extends Partial<Props>,\n> = keyof DefaultProps extends never\n ? Props\n : {\n [key in Extract<keyof Props, keyof DefaultProps>]?: Props[key];\n } & {\n [key in keyof Omit<Props, keyof DefaultProps>]: Props[key];\n };\n\nexport function tasty<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition = Record<string, never>,\n Tag extends keyof JSX.IntrinsicElements = 'div',\n M extends ModPropsInput = readonly never[],\n>(\n options: TastyElementOptions<K, V, E, Tag, M>,\n secondArg?: never,\n): ForwardRefExoticComponent<\n PropsWithoutRef<TastyElementProps<K, V, Tag, M>> & RefAttributes<unknown>\n> &\n SubElementComponents<E>;\nexport function tasty<\n Props extends PropsWithStyles,\n DefaultProps extends Partial<Props> = Partial<Props>,\n>(\n Component: ComponentType<Props>,\n options?: TastyProps<never, never, Record<string, never>, Props>,\n): ComponentType<TastyComponentPropsWithDefaults<Props, DefaultProps>>;\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n// Implementation\nexport function tasty<\n K extends StyleList,\n V extends VariantMap,\n _C = Record<string, unknown>,\n>(Component: any, options?: any) {\n if (isValidElementType(Component)) {\n return tastyWrap(Component as ComponentType<any>, options);\n }\n\n return tastyElement(Component as TastyProps<K, V>);\n}\n\nfunction tastyWrap<\n P extends PropsWithStyles,\n DefaultProps extends Partial<P> = Partial<P>,\n>(\n Component: ComponentType<P>,\n options?: TastyProps<never, never, P>,\n): ComponentType<TastyComponentPropsWithDefaults<P, DefaultProps>> {\n const {\n as: extendTag,\n element: extendElement,\n ...defaultProps\n } = (options ?? {}) as TastyProps<never, never, P>;\n\n const propsWithStyles = ['styles'].concat(\n Object.keys(defaultProps).filter((prop) => prop.endsWith('Styles')),\n );\n\n const _WrappedComponent = forwardRef<any, any>((props, ref) => {\n const { as, element, ...restProps } = props as Record<string, unknown>;\n const propsWithStylesValues = propsWithStyles.map(\n (prop) => (props as any)[prop],\n );\n\n const mergedStylesMap: Styles | undefined = useMemo(() => {\n return propsWithStyles.reduce((map, prop) => {\n const restValue = (restProps as any)[prop];\n const defaultValue = (defaultProps as any)[prop];\n\n if (restValue != null && defaultValue != null) {\n (map as any)[prop] = mergeStyles(defaultValue, restValue);\n } else {\n (map as any)[prop] = restValue ?? defaultValue;\n }\n\n return map;\n }, {} as Styles);\n }, [propsWithStylesValues]);\n\n const elementProps = {\n ...(defaultProps as unknown as Record<string, unknown>),\n ...(restProps as unknown as Record<string, unknown>),\n ...(mergedStylesMap as unknown as Record<string, unknown>),\n as: (as as string | undefined) ?? extendTag,\n element: (element as string | undefined) || extendElement,\n ref,\n } as unknown as P;\n\n return createElement(Component as ComponentType<P>, elementProps);\n });\n\n _WrappedComponent.displayName = `TastyWrappedComponent(${getDisplayName(\n Component,\n (defaultProps as any).qa ?? (extendTag as any) ?? 'Anonymous',\n )})`;\n\n return _WrappedComponent as unknown as ComponentType<\n TastyComponentPropsWithDefaults<P, DefaultProps>\n >;\n}\n\nfunction tastyElement<\n K extends StyleList,\n V extends VariantMap,\n E extends ElementsDefinition,\n>(tastyOptions: TastyProps<K, V, E>) {\n const {\n as: originalAs = 'div',\n element: defaultElement,\n styles: defaultStyles,\n styleProps,\n modProps: modPropsDef,\n variants,\n tokens: defaultTokens,\n elements,\n ...defaultProps\n } = tastyOptions;\n\n // Pre-compute merged styles for each variant (if variants are defined)\n // This avoids creating separate component instances per variant\n let variantStylesMap: Record<string, Styles | undefined> | undefined;\n if (variants) {\n // Split defaultStyles: extend-mode state maps (no '' key, non-selector)\n // are pulled out and applied AFTER variant merge so they survive\n // replace-mode maps in variants.\n let baseStyles = defaultStyles;\n let extensionStyles: Styles | undefined;\n\n if (defaultStyles) {\n for (const key of Object.keys(defaultStyles)) {\n if (isSelector(key)) continue;\n\n const value = (defaultStyles as Record<string, unknown>)[key];\n\n if (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n !('' in value)\n ) {\n if (!extensionStyles) {\n baseStyles = { ...defaultStyles } as Styles;\n extensionStyles = {} as Styles;\n }\n (extensionStyles as Record<string, unknown>)[key] = value;\n delete (baseStyles as Record<string, unknown>)[key];\n }\n }\n }\n\n const variantEntries = Object.entries(variants) as [string, Styles][];\n variantStylesMap = variantEntries.reduce(\n (map, [variant, variantStyles]) => {\n map[variant] = extensionStyles\n ? mergeStyles(baseStyles, variantStyles, extensionStyles)\n : mergeStyles(baseStyles, variantStyles);\n return map;\n },\n {} as Record<string, Styles | undefined>,\n );\n // Ensure 'default' variant always exists\n if (!variantStylesMap['default']) {\n variantStylesMap['default'] = defaultStyles;\n }\n }\n\n const {\n qa: defaultQa,\n qaVal: defaultQaVal,\n ...otherDefaultProps\n } = defaultProps ?? {};\n\n const propsToCheck = styleProps\n ? (styleProps as StyleList).concat(BASE_STYLES)\n : BASE_STYLES;\n\n const modPropsKeys: string[] | undefined = modPropsDef\n ? ((Array.isArray(modPropsDef)\n ? modPropsDef\n : Object.keys(modPropsDef)) as string[])\n : undefined;\n\n const _TastyComponent = forwardRef<\n unknown,\n AllBasePropsWithMods<K> & WithVariant<V>\n >((allProps, ref) => {\n const {\n as,\n styles: rawStyles,\n variant,\n mods,\n element,\n qa,\n qaVal,\n className: userClassName,\n tokens,\n style,\n ...otherProps\n } = allProps as Record<string, unknown> as AllBasePropsWithMods<K> &\n WithVariant<V> & {\n className?: string;\n tokens?: Tokens;\n style?: Record<string, unknown>;\n };\n\n let styles = rawStyles;\n\n let propStyles: Styles | null = null;\n let propStylesKey = '';\n\n for (const prop of propsToCheck) {\n const key = prop as unknown as string;\n\n if (key in otherProps) {\n if (!propStyles) propStyles = {};\n const value = (otherProps as any)[key];\n (propStyles as any)[key] = value;\n delete (otherProps as any)[key];\n propStylesKey += key + '\\0' + value + '\\0';\n }\n }\n\n if (!styles || (styles && !hasKeys(styles as Record<string, unknown>))) {\n styles = undefined as unknown as Styles;\n }\n\n // Stabilize propStyles reference: only update when content actually changes\n const propStylesRef = useRef<{ key: string; styles: Styles | null }>({\n key: '',\n styles: null,\n });\n if (propStylesRef.current.key !== propStylesKey) {\n propStylesRef.current = { key: propStylesKey, styles: propStyles };\n }\n\n // Determine base styles: use variant styles if available, otherwise default styles\n const baseStyles = variantStylesMap\n ? (variantStylesMap[(variant as string) || 'default'] ??\n variantStylesMap['default'])\n : defaultStyles;\n\n // Merge base styles with instance styles and prop styles\n const allStyles = useMemo(() => {\n const currentPropStyles = propStylesRef.current.styles;\n const hasStyleProps =\n styles && hasKeys(styles as Record<string, unknown>);\n const hasPropStyles = currentPropStyles && hasKeys(currentPropStyles);\n\n if (!hasStyleProps && !hasPropStyles) {\n return baseStyles;\n }\n\n return mergeStyles(\n baseStyles,\n styles as Styles,\n currentPropStyles as Styles,\n );\n }, [baseStyles, styles, propStylesKey]);\n\n // Use the useStyles hook for style generation and injection\n const { className: stylesClassName } = useStyles(allStyles);\n\n // Merge default tokens with instance tokens (instance overrides defaults)\n const tokensKey = stringifyTokens(tokens as Tokens | undefined);\n const mergedTokens = useMemo(() => {\n if (!defaultTokens && !tokens) return undefined;\n if (!defaultTokens) return tokens as Tokens;\n if (!tokens) return defaultTokens;\n return { ...defaultTokens, ...tokens } as Tokens;\n }, [tokensKey]);\n\n // Process merged tokens into inline style properties\n const processedTokenStyle = useMemo(() => {\n return processTokens(mergedTokens);\n }, [mergedTokens]);\n\n // Merge processed tokens with explicit style prop (style has priority)\n const mergedStyle = useMemo(() => {\n if (!processedTokenStyle && !style) return undefined;\n if (!processedTokenStyle) return style;\n if (!style) return processedTokenStyle;\n return { ...processedTokenStyle, ...style };\n }, [processedTokenStyle, style]);\n\n let propMods: Record<string, ModValue> | undefined;\n if (modPropsKeys) {\n for (const key of modPropsKeys) {\n if (key in otherProps) {\n if (!propMods) propMods = {};\n propMods[key] = (otherProps as Record<string, unknown>)[\n key\n ] as ModValue;\n delete (otherProps as Record<string, unknown>)[key];\n }\n }\n }\n\n const mergedMods = propMods\n ? { ...(mods as Record<string, ModValue>), ...propMods }\n : (mods as Record<string, ModValue> | undefined);\n\n let modDataAttrs: Record<string, unknown> | undefined;\n if (mergedMods) {\n modDataAttrs = modAttrs(mergedMods as unknown as Mods) as Record<\n string,\n unknown\n >;\n }\n\n // Merge user className with generated className\n const finalClassName = [(userClassName as string) || '', stylesClassName]\n .filter(Boolean)\n .join(' ');\n\n const elementProps = {\n 'data-element': (element as string | undefined) || defaultElement,\n 'data-qa': (qa as string | undefined) || defaultQa,\n 'data-qaval': (qaVal as string | undefined) || defaultQaVal,\n ...(otherDefaultProps as unknown as Record<string, unknown>),\n ...(modDataAttrs || {}),\n ...(otherProps as unknown as Record<string, unknown>),\n className: finalClassName,\n style: mergedStyle,\n ref,\n } as Record<string, unknown>;\n\n // Apply the helper to handle is* properties\n handleIsProperties(elementProps);\n\n const renderedElement = createElement(\n (as as string | 'div') ?? originalAs,\n elementProps,\n );\n\n return renderedElement;\n });\n\n _TastyComponent.displayName = `TastyComponent(${\n (defaultProps as any).qa || originalAs\n })`;\n\n // Attach sub-element components if elements are defined\n if (elements) {\n const subElements = Object.entries(elements).reduce(\n (acc, [name, definition]) => {\n acc[name] = createSubElement(\n name,\n definition as SubElementDefinition<keyof JSX.IntrinsicElements>,\n );\n return acc;\n },\n {} as Record<string, ForwardRefExoticComponent<any>>,\n );\n\n return Object.assign(_TastyComponent, subElements);\n }\n\n return _TastyComponent;\n}\n\nexport const Element = tasty({});\n"],"mappings":"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"}
|
package/dist/zero/babel.js
CHANGED
|
@@ -107,6 +107,7 @@ var babel_default = declare((api, options) => {
|
|
|
107
107
|
name: "tasty-zero",
|
|
108
108
|
pre() {
|
|
109
109
|
this.staticStyleRegistry = {};
|
|
110
|
+
this._fileAddedCSS = false;
|
|
110
111
|
if (devMode && this.filename) this.sourceFile = this.filename.split("/").pop() || this.filename;
|
|
111
112
|
},
|
|
112
113
|
visitor: {
|
|
@@ -125,6 +126,7 @@ var babel_default = declare((api, options) => {
|
|
|
125
126
|
CallExpression(path, state) {
|
|
126
127
|
const callee = path.node.callee;
|
|
127
128
|
if (!t.isIdentifier(callee, { name: "tastyStatic" })) return;
|
|
129
|
+
state._fileAddedCSS = true;
|
|
128
130
|
const args = path.node.arguments;
|
|
129
131
|
if (args.length === 0) throw path.buildCodeFrameError("tastyStatic() requires at least one argument");
|
|
130
132
|
const firstArg = args[0];
|
|
@@ -154,7 +156,7 @@ var babel_default = declare((api, options) => {
|
|
|
154
156
|
}
|
|
155
157
|
},
|
|
156
158
|
post() {
|
|
157
|
-
if (cssWriter.size > 0) cssWriter.write();
|
|
159
|
+
if (this._fileAddedCSS && cssWriter.size > 0) cssWriter.write();
|
|
158
160
|
}
|
|
159
161
|
};
|
|
160
162
|
});
|
package/dist/zero/babel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"babel.js","names":[],"sources":["../../src/zero/babel.ts"],"sourcesContent":["/**\n * Babel plugin for zero-runtime tasty static site generation.\n *\n * Transforms:\n * - `tastyStatic(styles)` → StaticStyle object { className, styles, toString() }\n * - `tastyStatic(base, styles)` → StaticStyle object with merged styles\n * - `tastyStatic(selector, styles)` → removed entirely\n *\n * Usage:\n * ```javascript\n * // babel.config.js\n * module.exports = {\n * plugins: [\n * ['@tenphi/tasty/babel-plugin', { output: 'public/tasty.css' }]\n * ]\n * };\n * ```\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nimport { declare } from '@babel/helper-plugin-utils';\nimport * as t from '@babel/types';\nimport { createJiti } from 'jiti';\n\nimport { configure, getGlobalConfigTokens, resetConfig } from '../config';\nimport type { RecipeStyles, Styles, ConfigTokens } from '../styles/types';\nimport { mergeStyles } from '../utils/merge-styles';\nimport { resolveRecipes } from '../utils/resolve-recipes';\nimport type { StyleHandlerDefinition } from '../utils/styles';\n\nimport { CSSWriter } from './css-writer';\nimport {\n extractKeyframesFromStyles,\n extractPropertiesFromStyles,\n extractStylesForSelector,\n extractStylesWithChunks,\n} from './extractor';\n\nimport type { NodePath, PluginPass } from '@babel/core';\nimport type { KeyframesSteps } from '../injector/types';\nimport type { StyleDetails, UnitHandler } from '../parser/types';\nimport type { TastyPlugin } from '../plugins/types';\n\n/**\n * Build-time configuration for zero-runtime mode.\n * Subset of TastyConfig that applies at build time.\n */\nexport interface TastyZeroConfig {\n /**\n * Global predefined states for advanced state mapping.\n * Example: { '@mobile': '@media(w < 768px)', '@dark': '@root(theme=dark)' }\n */\n states?: Record<string, string>;\n /**\n * Enable development mode features: source comments in generated CSS.\n * Default: false\n */\n devMode?: boolean;\n /**\n * Parser LRU cache size (default: 1000).\n * Larger values improve performance for builds with many unique style values.\n */\n parserCacheSize?: number;\n /**\n * Custom units for the style parser (merged with built-in units).\n * Units transform numeric values like `2x` → `calc(2 * var(--gap))`.\n * @example { em: 'em', vw: 'vw', custom: (n) => `${n * 10}px` }\n */\n units?: Record<string, string | UnitHandler>;\n /**\n * Custom functions for the style parser (merged with existing).\n * Functions process parsed style groups and return CSS values.\n * @example { myFunc: (groups) => groups.map(g => g.output).join(' ') }\n */\n funcs?: Record<string, (groups: StyleDetails[]) => string>;\n /**\n * Plugins that extend tasty with custom functions, units, states, and handlers.\n * Plugins are processed in order, with later plugins overriding earlier ones.\n * @example\n * ```ts\n * import { okhslPlugin } from '@tenphi/tasty';\n *\n * // babel.config.js\n * module.exports = {\n * plugins: [\n * ['@tenphi/tasty/babel-plugin', {\n * config: { plugins: [okhslPlugin()] }\n * }]\n * ]\n * };\n * ```\n */\n plugins?: TastyPlugin[];\n /**\n * Global keyframes definitions for static extraction.\n * Keys are animation names, values are keyframes step definitions.\n * @example { fadeIn: { from: { opacity: 0 }, to: { opacity: 1 } } }\n */\n keyframes?: Record<string, KeyframesSteps>;\n /**\n * Custom style handlers that transform style properties into CSS declarations.\n * Handlers replace built-in handlers for the same style name.\n * @example\n * ```ts\n * handlers: {\n * fill: ({ fill }) => fill ? { 'background-color': fill } : undefined,\n * elevation: ({ elevation }) => ({\n * 'box-shadow': `0 ${elevation}px ${elevation * 2}px rgba(0,0,0,0.1)`,\n * }),\n * }\n * ```\n */\n handlers?: Record<string, StyleHandlerDefinition>;\n /**\n * Design tokens injected as CSS custom properties on `:root`.\n * Values are parsed through the Tasty DSL. Supports state maps.\n * @example { '$gap': '4px', '#primary': { '': '#purple', '@dark': '#light-purple' } }\n */\n tokens?: ConfigTokens;\n /**\n * Predefined tokens replaced during style parsing (parse-time substitution).\n * Use `$name` for custom properties and `#name` for color tokens.\n * @example { $spacing: '2x', '#accent': '#purple' }\n */\n replaceTokens?: Record<`$${string}` | `#${string}`, string | number>;\n /**\n * Predefined style recipes -- named style bundles that can be applied via `recipe` style property.\n * Recipe values are flat tasty styles (no sub-element keys).\n * @example\n * ```ts\n * recipes: {\n * card: { padding: '4x', fill: '#surface', radius: '1r', border: true },\n * elevated: { shadow: '2x 2x 4x #shadow' },\n * }\n * ```\n */\n recipes?: Record<string, RecipeStyles>;\n /**\n * Automatically infer and register CSS @property declarations from values.\n * @default true\n */\n autoPropertyTypes?: boolean;\n}\n\nexport interface TastyZeroBabelOptions {\n /** Output path for generated CSS (default: 'tasty.css') */\n output?: string;\n /**\n * Tasty configuration for build-time processing.\n * Can be a static object or a factory function that returns fresh config.\n * A factory is called on each plugin invocation, enabling hot reload\n * of config values that depend on external files (e.g. theme tokens).\n */\n config?: TastyZeroConfig | (() => TastyZeroConfig);\n /**\n * Absolute path to a TypeScript/JavaScript module that default-exports\n * a `TastyZeroConfig` object. The module is loaded via jiti on each\n * plugin invocation, enabling hot reload when the file changes.\n *\n * This option is JSON-serializable and is the primary way Turbopack\n * passes config to the Babel plugin (since Turbopack loader options\n * must be plain primitives/objects/arrays).\n *\n * When both `config` and `configFile` are set, `config` takes precedence.\n *\n * @example '/absolute/path/to/tasty-zero.config.ts'\n */\n configFile?: string;\n /**\n * Absolute file paths whose content affects the generated CSS.\n * When any of these files change, babel-loader invalidates its cache\n * and re-runs the plugin with fresh config values.\n *\n * Typically includes theme files that define Glaze palettes or token values.\n * Paths must be absolute (resolved by the Next.js wrapper).\n */\n configDeps?: string[];\n /**\n * Automatically replace `@tenphi/tasty/static` imports with an import\n * of the generated CSS file. This eliminates the need for users to\n * manually import the CSS in their app entry point.\n *\n * @default true\n */\n injectImport?: boolean;\n}\n\n/**\n * Registry to track StaticStyle objects by their variable names.\n * Used to resolve base styles when extending.\n */\ntype StaticStyleRegistry = Record<\n string,\n {\n styles: Styles;\n className: string;\n }\n>;\n\ninterface PluginState extends PluginPass {\n staticStyleRegistry: StaticStyleRegistry;\n /** Current source file path (for devMode source comments) */\n sourceFile?: string;\n}\n\nfunction mtime(filePath: string): number | null {\n try {\n return fs.statSync(filePath).mtimeMs;\n } catch {\n return null;\n }\n}\n\nfunction clearRequireCacheTree(filePath: string): void {\n let resolved: string;\n\n try {\n resolved = require.resolve(filePath);\n } catch {\n return;\n }\n\n const mod = require.cache[resolved];\n\n if (!mod) return;\n\n const dir = resolved.substring(0, resolved.lastIndexOf('/'));\n\n if (mod.children) {\n for (const child of mod.children) {\n if (child.id.startsWith(dir) && !child.id.includes('node_modules')) {\n clearRequireCacheTree(child.id);\n }\n }\n }\n\n delete require.cache[resolved];\n}\n\n// Shared CSSWriter cache keyed by resolved output path.\n// Persists across per-file Babel invocations (Turbopack model) so that\n// CSS from all files accumulates instead of being overwritten.\ninterface WriterCacheEntry {\n writer: CSSWriter;\n configKey: string;\n registry: StaticStyleRegistry;\n config: TastyZeroConfig;\n}\nconst writerCache = new Map<string, WriterCacheEntry>();\n\n/** Clear the shared CSSWriter cache. Exposed for testing. */\nexport function clearWriterCache(): void {\n writerCache.clear();\n}\n\n// @ts-expect-error PluginState vs PluginPass type mismatch in @babel/helper-plugin-utils\nexport default declare<TastyZeroBabelOptions>((api, options) => {\n api.assertVersion(7);\n\n const outputPath = options.output || 'tasty.css';\n const resolvedOutputPath = path.resolve(outputPath);\n const injectImport = options.injectImport ?? true;\n\n if (injectImport) {\n const dir = path.dirname(resolvedOutputPath);\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n if (!fs.existsSync(resolvedOutputPath)) {\n fs.writeFileSync(\n resolvedOutputPath,\n '/* Generated by @tenphi/tasty/zero - DO NOT EDIT */\\n',\n );\n }\n }\n\n const configDeps = [\n ...(options.configFile ? [options.configFile] : []),\n ...(options.configDeps || []),\n ];\n\n // Fingerprint for config deps — used to detect config changes\n // and invalidate the shared CSSWriter cache.\n const configKey =\n configDeps.length > 0 ? configDeps.map(mtime).join(',') : '';\n\n // Register external dependencies for babel-loader cache invalidation.\n // When any configDeps file changes, babel-loader discards the cached\n // transform result and re-runs the plugin, picking up fresh config.\n if (configDeps.length > 0) {\n api.cache.using(() => configKey);\n\n for (const dep of configDeps) {\n try {\n (\n api as unknown as { addExternalDependency(path: string): void }\n ).addExternalDependency(dep);\n } catch {\n // addExternalDependency may not be available in all environments\n }\n }\n } else {\n api.cache.forever();\n }\n\n // When configDeps are set, clear the require cache so we get fresh values.\n if (configDeps.length > 0) {\n for (const dep of configDeps) {\n clearRequireCacheTree(dep);\n }\n }\n\n // Look up or create the shared CSSWriter for this output path.\n // When config deps change (different configKey), discard the old writer\n // and reset pipeline state so configure() can run again.\n const cached = writerCache.get(resolvedOutputPath);\n const configChanged = !cached || cached.configKey !== configKey;\n\n if (configChanged) {\n const configOption = options.config;\n let resolvedConfig: TastyZeroConfig;\n\n if (configOption) {\n resolvedConfig =\n typeof configOption === 'function' ? configOption() : configOption;\n } else if (options.configFile) {\n const jiti = createJiti(path.dirname(options.configFile), {\n moduleCache: false,\n });\n\n resolvedConfig = jiti(options.configFile) as TastyZeroConfig;\n } else {\n resolvedConfig = {};\n }\n\n const devMode = resolvedConfig.devMode ?? false;\n\n if (cached) {\n resetConfig();\n }\n\n configure(resolvedConfig);\n\n const newWriter = new CSSWriter(outputPath, { devMode });\n\n // Emit configured tokens as :root CSS custom properties\n const tokenStyles = getGlobalConfigTokens();\n if (tokenStyles && Object.keys(tokenStyles).length > 0) {\n const result = extractStylesForSelector(':root', tokenStyles);\n if (result.css) {\n newWriter.add(':root:tokens', result.css);\n }\n }\n\n writerCache.set(resolvedOutputPath, {\n writer: newWriter,\n configKey,\n registry: {},\n config: resolvedConfig,\n });\n }\n\n const entry = writerCache.get(resolvedOutputPath)!;\n const cssWriter = entry.writer;\n const globalRegistry = entry.registry;\n const config = entry.config;\n const devMode = config.devMode ?? false;\n\n return {\n name: 'tasty-zero',\n\n pre(this: PluginState) {\n // Initialize per-file registry\n this.staticStyleRegistry = {};\n // Extract source filename for devMode comments\n if (devMode && this.filename) {\n // Get relative path or just filename\n this.sourceFile = this.filename.split('/').pop() || this.filename;\n }\n },\n\n visitor: {\n ImportDeclaration(\n nodePath: NodePath<t.ImportDeclaration>,\n state: PluginState,\n ) {\n const source = nodePath.node.source.value;\n\n if (\n source === '@tenphi/tasty/static' ||\n source.endsWith('/tasty/static')\n ) {\n if (injectImport) {\n let importPath = resolvedOutputPath;\n\n if (state.filename) {\n const sourceDir = path.dirname(state.filename);\n importPath = path.relative(sourceDir, resolvedOutputPath);\n\n if (!importPath.startsWith('.')) {\n importPath = './' + importPath;\n }\n }\n\n nodePath.replaceWith(\n t.importDeclaration([], t.stringLiteral(importPath)),\n );\n } else {\n nodePath.remove();\n }\n }\n },\n\n // Transform tastyStatic() calls\n CallExpression(path: NodePath<t.CallExpression>, state: PluginState) {\n const callee = path.node.callee;\n\n // Match tastyStatic(...) calls\n if (!t.isIdentifier(callee, { name: 'tastyStatic' })) {\n return;\n }\n\n const args = path.node.arguments;\n\n if (args.length === 0) {\n throw path.buildCodeFrameError(\n 'tastyStatic() requires at least one argument',\n );\n }\n\n const firstArg = args[0];\n\n if (t.isStringLiteral(firstArg)) {\n // Selector mode: tastyStatic(selector, styles)\n handleSelectorMode(\n path,\n args,\n cssWriter,\n state.sourceFile,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else if (t.isObjectExpression(firstArg)) {\n // Styles mode: tastyStatic(styles)\n handleStylesMode(\n path,\n args,\n cssWriter,\n state,\n globalRegistry,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else if (t.isIdentifier(firstArg)) {\n // Extension mode: tastyStatic(base, styles)\n handleExtensionMode(\n path,\n args,\n cssWriter,\n state,\n globalRegistry,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else {\n throw path.buildCodeFrameError(\n 'tastyStatic() first argument must be an object (styles), ' +\n 'identifier (base StaticStyle), or string (selector)',\n );\n }\n },\n\n // Track variable declarations to register StaticStyle objects\n VariableDeclarator(\n path: NodePath<t.VariableDeclarator>,\n state: PluginState,\n ) {\n const init = path.node.init;\n const id = path.node.id;\n\n // Check if this is a StaticStyle object (has className and styles properties)\n if (\n t.isIdentifier(id) &&\n t.isObjectExpression(init) &&\n isStaticStyleObject(init)\n ) {\n const variableName = id.name;\n const styles = extractStylesFromStaticStyleObject(init, path);\n const className = extractClassNameFromStaticStyleObject(init);\n\n if (styles && className) {\n state.staticStyleRegistry[variableName] = { styles, className };\n globalRegistry[variableName] = { styles, className };\n }\n }\n },\n },\n\n post() {\n // Write all collected CSS at the end of the build\n if (cssWriter.size > 0) {\n cssWriter.write();\n }\n },\n };\n});\n\n/**\n * Check if an object expression looks like a StaticStyle object\n */\nfunction isStaticStyleObject(node: t.ObjectExpression): boolean {\n const hasClassName = node.properties.some(\n (p) =>\n t.isObjectProperty(p) && t.isIdentifier(p.key, { name: 'className' }),\n );\n const hasStyles = node.properties.some(\n (p) => t.isObjectProperty(p) && t.isIdentifier(p.key, { name: 'styles' }),\n );\n return hasClassName && hasStyles;\n}\n\n/**\n * Extract styles object from a StaticStyle object expression\n */\nfunction extractStylesFromStaticStyleObject(\n node: t.ObjectExpression,\n path: NodePath,\n): Styles | null {\n for (const prop of node.properties) {\n if (\n t.isObjectProperty(prop) &&\n t.isIdentifier(prop.key, { name: 'styles' }) &&\n t.isObjectExpression(prop.value)\n ) {\n return evaluateObjectExpression(prop.value, path) as Styles;\n }\n }\n return null;\n}\n\n/**\n * Extract className from a StaticStyle object expression\n */\nfunction extractClassNameFromStaticStyleObject(\n node: t.ObjectExpression,\n): string | null {\n for (const prop of node.properties) {\n if (\n t.isObjectProperty(prop) &&\n t.isIdentifier(prop.key, { name: 'className' }) &&\n t.isStringLiteral(prop.value)\n ) {\n return prop.value.value;\n }\n }\n return null;\n}\n\n/**\n * Handle tastyStatic(styles) - returns StaticStyle object\n */\nfunction handleStylesMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n const stylesArg = args[0];\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(styles) argument must be a static object literal',\n );\n }\n\n // Evaluate styles object at build time\n const rawStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Resolve recipes before extraction\n const styles = resolveRecipes(rawStyles);\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n styles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, state.sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(styles, { autoPropertyTypes });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, state.sourceFile);\n }\n\n // Extract styles with chunking\n const chunks = extractStylesWithChunks(styles);\n\n // Add CSS to writer, replacing animation names if needed\n for (const chunk of chunks) {\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(chunk.css, nameMap)\n : chunk.css;\n cssWriter.add(chunk.className, css, state.sourceFile);\n }\n\n // Generate className\n const className =\n chunks.length > 0 ? chunks.map((c) => c.className).join(' ') : '';\n\n // Replace call with StaticStyle object\n const staticStyleObject = createStaticStyleAST(className, styles);\n path.replaceWith(staticStyleObject);\n\n // Register if this is being assigned to a variable\n registerIfVariableDeclaration(path, className, styles, state, globalRegistry);\n}\n\n/**\n * Handle tastyStatic(base, styles) - extends base with additional styles\n */\nfunction handleExtensionMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n if (args.length < 2) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) requires two arguments',\n );\n }\n\n const baseArg = args[0];\n const stylesArg = args[1];\n\n if (!t.isIdentifier(baseArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) first argument must be an identifier',\n );\n }\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) second argument must be a static object literal',\n );\n }\n\n const baseName = baseArg.name;\n\n // Look up base styles in registry\n const baseEntry =\n state.staticStyleRegistry[baseName] || globalRegistry[baseName];\n\n if (!baseEntry) {\n throw path.buildCodeFrameError(\n `Cannot find base StaticStyle '${baseName}'. ` +\n 'Make sure it is defined before being extended.',\n );\n }\n\n // Evaluate override styles\n const overrideStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Merge styles using mergeStyles, then resolve recipes\n const mergedStyles = resolveRecipes(\n mergeStyles(baseEntry.styles, overrideStyles),\n );\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n mergedStyles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, state.sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(mergedStyles, {\n autoPropertyTypes,\n });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, state.sourceFile);\n }\n\n // Extract styles with chunking\n const chunks = extractStylesWithChunks(mergedStyles);\n\n // Add CSS to writer, replacing animation names if needed\n for (const chunk of chunks) {\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(chunk.css, nameMap)\n : chunk.css;\n cssWriter.add(chunk.className, css, state.sourceFile);\n }\n\n // Generate className\n const className =\n chunks.length > 0 ? chunks.map((c) => c.className).join(' ') : '';\n\n // Replace call with StaticStyle object\n const staticStyleObject = createStaticStyleAST(className, mergedStyles);\n path.replaceWith(staticStyleObject);\n\n // Register if this is being assigned to a variable\n registerIfVariableDeclaration(\n path,\n className,\n mergedStyles,\n state,\n globalRegistry,\n );\n}\n\n/**\n * Handle tastyStatic(selector, styles) - removes the call entirely\n */\nfunction handleSelectorMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n sourceFile?: string,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n if (args.length < 2) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) requires two arguments',\n );\n }\n\n const selectorArg = args[0];\n const stylesArg = args[1];\n\n if (!t.isStringLiteral(selectorArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) first argument must be a string literal',\n );\n }\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) second argument must be a static object literal',\n );\n }\n\n const selector = selectorArg.value;\n const rawStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Resolve recipes before extraction\n const styles = resolveRecipes(rawStyles);\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n styles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(styles, { autoPropertyTypes });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, sourceFile);\n }\n\n // Extract styles for selector\n const result = extractStylesForSelector(selector, styles);\n\n // Replace animation names if needed and add CSS\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(result.css, nameMap)\n : result.css;\n cssWriter.add(selector, css, sourceFile);\n\n // Remove the entire statement\n const parent = path.parentPath;\n if (parent && t.isExpressionStatement(parent.node)) {\n parent.remove();\n } else {\n // If used in an expression context (which would be incorrect usage),\n // replace with undefined\n path.replaceWith(t.identifier('undefined'));\n }\n}\n\n/**\n * Create a StaticStyle object AST node\n */\nfunction createStaticStyleAST(\n className: string,\n styles: Styles,\n): t.ObjectExpression {\n return t.objectExpression([\n t.objectProperty(t.identifier('className'), t.stringLiteral(className)),\n t.objectProperty(t.identifier('styles'), valueToAST(styles)),\n t.objectMethod(\n 'method',\n t.identifier('toString'),\n [],\n t.blockStatement([\n t.returnStatement(\n t.memberExpression(t.thisExpression(), t.identifier('className')),\n ),\n ]),\n ),\n ]);\n}\n\n/**\n * Register a StaticStyle in the registry if it's being assigned to a variable\n */\nfunction registerIfVariableDeclaration(\n path: NodePath,\n className: string,\n styles: Styles,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n): void {\n const parent = path.parentPath;\n if (parent && t.isVariableDeclarator(parent.node)) {\n const id = parent.node.id;\n if (t.isIdentifier(id)) {\n const variableName = id.name;\n state.staticStyleRegistry[variableName] = { styles, className };\n globalRegistry[variableName] = { styles, className };\n }\n }\n}\n\n/**\n * Convert a JavaScript value to an AST node\n */\nfunction valueToAST(value: unknown): t.Expression {\n if (value === null) {\n return t.nullLiteral();\n }\n if (value === undefined) {\n return t.identifier('undefined');\n }\n if (typeof value === 'string') {\n return t.stringLiteral(value);\n }\n if (typeof value === 'number') {\n return t.numericLiteral(value);\n }\n if (typeof value === 'boolean') {\n return t.booleanLiteral(value);\n }\n if (Array.isArray(value)) {\n return t.arrayExpression(value.map(valueToAST));\n }\n if (typeof value === 'object') {\n const properties = Object.entries(value).map(([key, val]) =>\n t.objectProperty(\n /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)\n ? t.identifier(key)\n : t.stringLiteral(key),\n valueToAST(val),\n ),\n );\n return t.objectExpression(properties);\n }\n // Fallback for unsupported types\n return t.identifier('undefined');\n}\n\n/**\n * Evaluate an ObjectExpression to a plain JavaScript object.\n * Only supports static values that can be determined at build time.\n */\nfunction evaluateObjectExpression(\n node: t.ObjectExpression,\n path: NodePath,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const prop of node.properties) {\n if (t.isSpreadElement(prop)) {\n throw path.buildCodeFrameError(\n 'Spread elements are not supported in tastyStatic() - styles must be fully static',\n );\n }\n\n if (!t.isObjectProperty(prop)) {\n throw path.buildCodeFrameError(\n 'Only object properties are supported in tastyStatic()',\n );\n }\n\n // Get key\n let key: string;\n if (t.isIdentifier(prop.key)) {\n key = prop.key.name;\n } else if (t.isStringLiteral(prop.key)) {\n key = prop.key.value;\n } else {\n throw path.buildCodeFrameError(\n 'Dynamic property keys are not supported in tastyStatic()',\n );\n }\n\n // Get value\n const value = evaluateExpression(prop.value, path);\n result[key] = value;\n }\n\n return result;\n}\n\n/**\n * Evaluate an expression to a JavaScript value.\n */\nfunction evaluateExpression(node: t.Node, path: NodePath): unknown {\n if (t.isStringLiteral(node)) {\n return node.value;\n }\n\n if (t.isNumericLiteral(node)) {\n return node.value;\n }\n\n if (t.isBooleanLiteral(node)) {\n return node.value;\n }\n\n if (t.isNullLiteral(node)) {\n return null;\n }\n\n if (t.isIdentifier(node, { name: 'undefined' })) {\n return undefined;\n }\n\n if (t.isArrayExpression(node)) {\n return node.elements.map((el) => {\n if (el === null) return null;\n if (t.isSpreadElement(el)) {\n throw path.buildCodeFrameError(\n 'Spread elements are not supported in tastyStatic()',\n );\n }\n return evaluateExpression(el, path);\n });\n }\n\n if (t.isObjectExpression(node)) {\n return evaluateObjectExpression(node, path);\n }\n\n if (t.isTemplateLiteral(node)) {\n // Only support template literals without expressions\n if (node.expressions.length > 0) {\n throw path.buildCodeFrameError(\n 'Template literals with expressions are not supported in tastyStatic()',\n );\n }\n return node.quasis.map((q) => q.value.cooked).join('');\n }\n\n if (t.isUnaryExpression(node, { operator: '-' })) {\n const arg = evaluateExpression(node.argument, path);\n if (typeof arg === 'number') {\n return -arg;\n }\n }\n\n throw path.buildCodeFrameError(\n `Dynamic expressions are not supported in tastyStatic() - got ${node.type}. ` +\n 'All values must be static literals.',\n );\n}\n\n/**\n * Replace animation names in CSS string.\n * Wraps the keyframes replaceAnimationNames to work on full CSS blocks.\n */\nfunction replaceAnimationNamesInCSS(\n css: string,\n nameMap: Map<string, string>,\n): string {\n if (nameMap.size === 0) return css;\n\n // The CSS contains full rules like \".class { animation: name 1s; }\"\n // We need to replace animation names within declaration blocks\n return css.replace(\n /(animation(?:-name)?)\\s*:\\s*([^;}]+)/gi,\n (match, prop, value) => {\n let newValue = value;\n for (const [original, replacement] of nameMap) {\n // Word boundary replacement\n const pattern = new RegExp(`\\\\b${escapeRegex(original)}\\\\b`, 'g');\n newValue = newValue.replace(pattern, replacement);\n }\n return `${prop}: ${newValue}`;\n },\n );\n}\n\n/**\n * Escape special regex characters.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"babel.js","names":[],"sources":["../../src/zero/babel.ts"],"sourcesContent":["/**\n * Babel plugin for zero-runtime tasty static site generation.\n *\n * Transforms:\n * - `tastyStatic(styles)` → StaticStyle object { className, styles, toString() }\n * - `tastyStatic(base, styles)` → StaticStyle object with merged styles\n * - `tastyStatic(selector, styles)` → removed entirely\n *\n * Usage:\n * ```javascript\n * // babel.config.js\n * module.exports = {\n * plugins: [\n * ['@tenphi/tasty/babel-plugin', { output: 'public/tasty.css' }]\n * ]\n * };\n * ```\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nimport { declare } from '@babel/helper-plugin-utils';\nimport * as t from '@babel/types';\nimport { createJiti } from 'jiti';\n\nimport { configure, getGlobalConfigTokens, resetConfig } from '../config';\nimport type { RecipeStyles, Styles, ConfigTokens } from '../styles/types';\nimport { mergeStyles } from '../utils/merge-styles';\nimport { resolveRecipes } from '../utils/resolve-recipes';\nimport type { StyleHandlerDefinition } from '../utils/styles';\n\nimport { CSSWriter } from './css-writer';\nimport {\n extractKeyframesFromStyles,\n extractPropertiesFromStyles,\n extractStylesForSelector,\n extractStylesWithChunks,\n} from './extractor';\n\nimport type { NodePath, PluginPass } from '@babel/core';\nimport type { KeyframesSteps } from '../injector/types';\nimport type { StyleDetails, UnitHandler } from '../parser/types';\nimport type { TastyPlugin } from '../plugins/types';\n\n/**\n * Build-time configuration for zero-runtime mode.\n * Subset of TastyConfig that applies at build time.\n */\nexport interface TastyZeroConfig {\n /**\n * Global predefined states for advanced state mapping.\n * Example: { '@mobile': '@media(w < 768px)', '@dark': '@root(theme=dark)' }\n */\n states?: Record<string, string>;\n /**\n * Enable development mode features: source comments in generated CSS.\n * Default: false\n */\n devMode?: boolean;\n /**\n * Parser LRU cache size (default: 1000).\n * Larger values improve performance for builds with many unique style values.\n */\n parserCacheSize?: number;\n /**\n * Custom units for the style parser (merged with built-in units).\n * Units transform numeric values like `2x` → `calc(2 * var(--gap))`.\n * @example { em: 'em', vw: 'vw', custom: (n) => `${n * 10}px` }\n */\n units?: Record<string, string | UnitHandler>;\n /**\n * Custom functions for the style parser (merged with existing).\n * Functions process parsed style groups and return CSS values.\n * @example { myFunc: (groups) => groups.map(g => g.output).join(' ') }\n */\n funcs?: Record<string, (groups: StyleDetails[]) => string>;\n /**\n * Plugins that extend tasty with custom functions, units, states, and handlers.\n * Plugins are processed in order, with later plugins overriding earlier ones.\n * @example\n * ```ts\n * import { okhslPlugin } from '@tenphi/tasty';\n *\n * // babel.config.js\n * module.exports = {\n * plugins: [\n * ['@tenphi/tasty/babel-plugin', {\n * config: { plugins: [okhslPlugin()] }\n * }]\n * ]\n * };\n * ```\n */\n plugins?: TastyPlugin[];\n /**\n * Global keyframes definitions for static extraction.\n * Keys are animation names, values are keyframes step definitions.\n * @example { fadeIn: { from: { opacity: 0 }, to: { opacity: 1 } } }\n */\n keyframes?: Record<string, KeyframesSteps>;\n /**\n * Custom style handlers that transform style properties into CSS declarations.\n * Handlers replace built-in handlers for the same style name.\n * @example\n * ```ts\n * handlers: {\n * fill: ({ fill }) => fill ? { 'background-color': fill } : undefined,\n * elevation: ({ elevation }) => ({\n * 'box-shadow': `0 ${elevation}px ${elevation * 2}px rgba(0,0,0,0.1)`,\n * }),\n * }\n * ```\n */\n handlers?: Record<string, StyleHandlerDefinition>;\n /**\n * Design tokens injected as CSS custom properties on `:root`.\n * Values are parsed through the Tasty DSL. Supports state maps.\n * @example { '$gap': '4px', '#primary': { '': '#purple', '@dark': '#light-purple' } }\n */\n tokens?: ConfigTokens;\n /**\n * Predefined tokens replaced during style parsing (parse-time substitution).\n * Use `$name` for custom properties and `#name` for color tokens.\n * @example { $spacing: '2x', '#accent': '#purple' }\n */\n replaceTokens?: Record<`$${string}` | `#${string}`, string | number>;\n /**\n * Predefined style recipes -- named style bundles that can be applied via `recipe` style property.\n * Recipe values are flat tasty styles (no sub-element keys).\n * @example\n * ```ts\n * recipes: {\n * card: { padding: '4x', fill: '#surface', radius: '1r', border: true },\n * elevated: { shadow: '2x 2x 4x #shadow' },\n * }\n * ```\n */\n recipes?: Record<string, RecipeStyles>;\n /**\n * Automatically infer and register CSS @property declarations from values.\n * @default true\n */\n autoPropertyTypes?: boolean;\n}\n\nexport interface TastyZeroBabelOptions {\n /** Output path for generated CSS (default: 'tasty.css') */\n output?: string;\n /**\n * Tasty configuration for build-time processing.\n * Can be a static object or a factory function that returns fresh config.\n * A factory is called on each plugin invocation, enabling hot reload\n * of config values that depend on external files (e.g. theme tokens).\n */\n config?: TastyZeroConfig | (() => TastyZeroConfig);\n /**\n * Absolute path to a TypeScript/JavaScript module that default-exports\n * a `TastyZeroConfig` object. The module is loaded via jiti on each\n * plugin invocation, enabling hot reload when the file changes.\n *\n * This option is JSON-serializable and is the primary way Turbopack\n * passes config to the Babel plugin (since Turbopack loader options\n * must be plain primitives/objects/arrays).\n *\n * When both `config` and `configFile` are set, `config` takes precedence.\n *\n * @example '/absolute/path/to/tasty-zero.config.ts'\n */\n configFile?: string;\n /**\n * Absolute file paths whose content affects the generated CSS.\n * When any of these files change, babel-loader invalidates its cache\n * and re-runs the plugin with fresh config values.\n *\n * Typically includes theme files that define Glaze palettes or token values.\n * Paths must be absolute (resolved by the Next.js wrapper).\n */\n configDeps?: string[];\n /**\n * Automatically replace `@tenphi/tasty/static` imports with an import\n * of the generated CSS file. This eliminates the need for users to\n * manually import the CSS in their app entry point.\n *\n * @default true\n */\n injectImport?: boolean;\n}\n\n/**\n * Registry to track StaticStyle objects by their variable names.\n * Used to resolve base styles when extending.\n */\ntype StaticStyleRegistry = Record<\n string,\n {\n styles: Styles;\n className: string;\n }\n>;\n\ninterface PluginState extends PluginPass {\n staticStyleRegistry: StaticStyleRegistry;\n /** Current source file path (for devMode source comments) */\n sourceFile?: string;\n /** Whether this file added CSS blocks to the writer (via tastyStatic calls) */\n _fileAddedCSS?: boolean;\n}\n\nfunction mtime(filePath: string): number | null {\n try {\n return fs.statSync(filePath).mtimeMs;\n } catch {\n return null;\n }\n}\n\nfunction clearRequireCacheTree(filePath: string): void {\n let resolved: string;\n\n try {\n resolved = require.resolve(filePath);\n } catch {\n return;\n }\n\n const mod = require.cache[resolved];\n\n if (!mod) return;\n\n const dir = resolved.substring(0, resolved.lastIndexOf('/'));\n\n if (mod.children) {\n for (const child of mod.children) {\n if (child.id.startsWith(dir) && !child.id.includes('node_modules')) {\n clearRequireCacheTree(child.id);\n }\n }\n }\n\n delete require.cache[resolved];\n}\n\n// Shared CSSWriter cache keyed by resolved output path.\n// Persists across per-file Babel invocations (Turbopack model) so that\n// CSS from all files accumulates instead of being overwritten.\ninterface WriterCacheEntry {\n writer: CSSWriter;\n configKey: string;\n registry: StaticStyleRegistry;\n config: TastyZeroConfig;\n}\nconst writerCache = new Map<string, WriterCacheEntry>();\n\n/** Clear the shared CSSWriter cache. Exposed for testing. */\nexport function clearWriterCache(): void {\n writerCache.clear();\n}\n\n// @ts-expect-error PluginState vs PluginPass type mismatch in @babel/helper-plugin-utils\nexport default declare<TastyZeroBabelOptions>((api, options) => {\n api.assertVersion(7);\n\n const outputPath = options.output || 'tasty.css';\n const resolvedOutputPath = path.resolve(outputPath);\n const injectImport = options.injectImport ?? true;\n\n if (injectImport) {\n const dir = path.dirname(resolvedOutputPath);\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n if (!fs.existsSync(resolvedOutputPath)) {\n fs.writeFileSync(\n resolvedOutputPath,\n '/* Generated by @tenphi/tasty/zero - DO NOT EDIT */\\n',\n );\n }\n }\n\n const configDeps = [\n ...(options.configFile ? [options.configFile] : []),\n ...(options.configDeps || []),\n ];\n\n // Fingerprint for config deps — used to detect config changes\n // and invalidate the shared CSSWriter cache.\n const configKey =\n configDeps.length > 0 ? configDeps.map(mtime).join(',') : '';\n\n // Register external dependencies for babel-loader cache invalidation.\n // When any configDeps file changes, babel-loader discards the cached\n // transform result and re-runs the plugin, picking up fresh config.\n if (configDeps.length > 0) {\n api.cache.using(() => configKey);\n\n for (const dep of configDeps) {\n try {\n (\n api as unknown as { addExternalDependency(path: string): void }\n ).addExternalDependency(dep);\n } catch {\n // addExternalDependency may not be available in all environments\n }\n }\n } else {\n api.cache.forever();\n }\n\n // When configDeps are set, clear the require cache so we get fresh values.\n if (configDeps.length > 0) {\n for (const dep of configDeps) {\n clearRequireCacheTree(dep);\n }\n }\n\n // Look up or create the shared CSSWriter for this output path.\n // When config deps change (different configKey), discard the old writer\n // and reset pipeline state so configure() can run again.\n const cached = writerCache.get(resolvedOutputPath);\n const configChanged = !cached || cached.configKey !== configKey;\n\n if (configChanged) {\n const configOption = options.config;\n let resolvedConfig: TastyZeroConfig;\n\n if (configOption) {\n resolvedConfig =\n typeof configOption === 'function' ? configOption() : configOption;\n } else if (options.configFile) {\n const jiti = createJiti(path.dirname(options.configFile), {\n moduleCache: false,\n });\n\n resolvedConfig = jiti(options.configFile) as TastyZeroConfig;\n } else {\n resolvedConfig = {};\n }\n\n const devMode = resolvedConfig.devMode ?? false;\n\n if (cached) {\n resetConfig();\n }\n\n configure(resolvedConfig);\n\n const newWriter = new CSSWriter(outputPath, { devMode });\n\n // Emit configured tokens as :root CSS custom properties\n const tokenStyles = getGlobalConfigTokens();\n if (tokenStyles && Object.keys(tokenStyles).length > 0) {\n const result = extractStylesForSelector(':root', tokenStyles);\n if (result.css) {\n newWriter.add(':root:tokens', result.css);\n }\n }\n\n writerCache.set(resolvedOutputPath, {\n writer: newWriter,\n configKey,\n registry: {},\n config: resolvedConfig,\n });\n }\n\n const entry = writerCache.get(resolvedOutputPath)!;\n const cssWriter = entry.writer;\n const globalRegistry = entry.registry;\n const config = entry.config;\n const devMode = config.devMode ?? false;\n\n return {\n name: 'tasty-zero',\n\n pre(this: PluginState) {\n // Initialize per-file registry\n this.staticStyleRegistry = {};\n this._fileAddedCSS = false;\n // Extract source filename for devMode comments\n if (devMode && this.filename) {\n // Get relative path or just filename\n this.sourceFile = this.filename.split('/').pop() || this.filename;\n }\n },\n\n visitor: {\n ImportDeclaration(\n nodePath: NodePath<t.ImportDeclaration>,\n state: PluginState,\n ) {\n const source = nodePath.node.source.value;\n\n if (\n source === '@tenphi/tasty/static' ||\n source.endsWith('/tasty/static')\n ) {\n if (injectImport) {\n let importPath = resolvedOutputPath;\n\n if (state.filename) {\n const sourceDir = path.dirname(state.filename);\n importPath = path.relative(sourceDir, resolvedOutputPath);\n\n if (!importPath.startsWith('.')) {\n importPath = './' + importPath;\n }\n }\n\n nodePath.replaceWith(\n t.importDeclaration([], t.stringLiteral(importPath)),\n );\n } else {\n nodePath.remove();\n }\n }\n },\n\n // Transform tastyStatic() calls\n CallExpression(path: NodePath<t.CallExpression>, state: PluginState) {\n const callee = path.node.callee;\n\n // Match tastyStatic(...) calls\n if (!t.isIdentifier(callee, { name: 'tastyStatic' })) {\n return;\n }\n\n state._fileAddedCSS = true;\n\n const args = path.node.arguments;\n\n if (args.length === 0) {\n throw path.buildCodeFrameError(\n 'tastyStatic() requires at least one argument',\n );\n }\n\n const firstArg = args[0];\n\n if (t.isStringLiteral(firstArg)) {\n // Selector mode: tastyStatic(selector, styles)\n handleSelectorMode(\n path,\n args,\n cssWriter,\n state.sourceFile,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else if (t.isObjectExpression(firstArg)) {\n // Styles mode: tastyStatic(styles)\n handleStylesMode(\n path,\n args,\n cssWriter,\n state,\n globalRegistry,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else if (t.isIdentifier(firstArg)) {\n // Extension mode: tastyStatic(base, styles)\n handleExtensionMode(\n path,\n args,\n cssWriter,\n state,\n globalRegistry,\n config.keyframes,\n config.autoPropertyTypes,\n );\n } else {\n throw path.buildCodeFrameError(\n 'tastyStatic() first argument must be an object (styles), ' +\n 'identifier (base StaticStyle), or string (selector)',\n );\n }\n },\n\n // Track variable declarations to register StaticStyle objects\n VariableDeclarator(\n path: NodePath<t.VariableDeclarator>,\n state: PluginState,\n ) {\n const init = path.node.init;\n const id = path.node.id;\n\n // Check if this is a StaticStyle object (has className and styles properties)\n if (\n t.isIdentifier(id) &&\n t.isObjectExpression(init) &&\n isStaticStyleObject(init)\n ) {\n const variableName = id.name;\n const styles = extractStylesFromStaticStyleObject(init, path);\n const className = extractClassNameFromStaticStyleObject(init);\n\n if (styles && className) {\n state.staticStyleRegistry[variableName] = { styles, className };\n globalRegistry[variableName] = { styles, className };\n }\n }\n },\n },\n\n post(this: PluginState) {\n // Only write when this file contributed CSS (had tastyStatic calls).\n // In Turbopack, separate workers each have their own CSSWriter with\n // only token CSS. Letting those workers write would overwrite the\n // complete CSS produced by the worker that processed tastyStatic files.\n if (this._fileAddedCSS && cssWriter.size > 0) {\n cssWriter.write();\n }\n },\n };\n});\n\n/**\n * Check if an object expression looks like a StaticStyle object\n */\nfunction isStaticStyleObject(node: t.ObjectExpression): boolean {\n const hasClassName = node.properties.some(\n (p) =>\n t.isObjectProperty(p) && t.isIdentifier(p.key, { name: 'className' }),\n );\n const hasStyles = node.properties.some(\n (p) => t.isObjectProperty(p) && t.isIdentifier(p.key, { name: 'styles' }),\n );\n return hasClassName && hasStyles;\n}\n\n/**\n * Extract styles object from a StaticStyle object expression\n */\nfunction extractStylesFromStaticStyleObject(\n node: t.ObjectExpression,\n path: NodePath,\n): Styles | null {\n for (const prop of node.properties) {\n if (\n t.isObjectProperty(prop) &&\n t.isIdentifier(prop.key, { name: 'styles' }) &&\n t.isObjectExpression(prop.value)\n ) {\n return evaluateObjectExpression(prop.value, path) as Styles;\n }\n }\n return null;\n}\n\n/**\n * Extract className from a StaticStyle object expression\n */\nfunction extractClassNameFromStaticStyleObject(\n node: t.ObjectExpression,\n): string | null {\n for (const prop of node.properties) {\n if (\n t.isObjectProperty(prop) &&\n t.isIdentifier(prop.key, { name: 'className' }) &&\n t.isStringLiteral(prop.value)\n ) {\n return prop.value.value;\n }\n }\n return null;\n}\n\n/**\n * Handle tastyStatic(styles) - returns StaticStyle object\n */\nfunction handleStylesMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n const stylesArg = args[0];\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(styles) argument must be a static object literal',\n );\n }\n\n // Evaluate styles object at build time\n const rawStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Resolve recipes before extraction\n const styles = resolveRecipes(rawStyles);\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n styles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, state.sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(styles, { autoPropertyTypes });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, state.sourceFile);\n }\n\n // Extract styles with chunking\n const chunks = extractStylesWithChunks(styles);\n\n // Add CSS to writer, replacing animation names if needed\n for (const chunk of chunks) {\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(chunk.css, nameMap)\n : chunk.css;\n cssWriter.add(chunk.className, css, state.sourceFile);\n }\n\n // Generate className\n const className =\n chunks.length > 0 ? chunks.map((c) => c.className).join(' ') : '';\n\n // Replace call with StaticStyle object\n const staticStyleObject = createStaticStyleAST(className, styles);\n path.replaceWith(staticStyleObject);\n\n // Register if this is being assigned to a variable\n registerIfVariableDeclaration(path, className, styles, state, globalRegistry);\n}\n\n/**\n * Handle tastyStatic(base, styles) - extends base with additional styles\n */\nfunction handleExtensionMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n if (args.length < 2) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) requires two arguments',\n );\n }\n\n const baseArg = args[0];\n const stylesArg = args[1];\n\n if (!t.isIdentifier(baseArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) first argument must be an identifier',\n );\n }\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(base, styles) second argument must be a static object literal',\n );\n }\n\n const baseName = baseArg.name;\n\n // Look up base styles in registry\n const baseEntry =\n state.staticStyleRegistry[baseName] || globalRegistry[baseName];\n\n if (!baseEntry) {\n throw path.buildCodeFrameError(\n `Cannot find base StaticStyle '${baseName}'. ` +\n 'Make sure it is defined before being extended.',\n );\n }\n\n // Evaluate override styles\n const overrideStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Merge styles using mergeStyles, then resolve recipes\n const mergedStyles = resolveRecipes(\n mergeStyles(baseEntry.styles, overrideStyles),\n );\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n mergedStyles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, state.sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(mergedStyles, {\n autoPropertyTypes,\n });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, state.sourceFile);\n }\n\n // Extract styles with chunking\n const chunks = extractStylesWithChunks(mergedStyles);\n\n // Add CSS to writer, replacing animation names if needed\n for (const chunk of chunks) {\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(chunk.css, nameMap)\n : chunk.css;\n cssWriter.add(chunk.className, css, state.sourceFile);\n }\n\n // Generate className\n const className =\n chunks.length > 0 ? chunks.map((c) => c.className).join(' ') : '';\n\n // Replace call with StaticStyle object\n const staticStyleObject = createStaticStyleAST(className, mergedStyles);\n path.replaceWith(staticStyleObject);\n\n // Register if this is being assigned to a variable\n registerIfVariableDeclaration(\n path,\n className,\n mergedStyles,\n state,\n globalRegistry,\n );\n}\n\n/**\n * Handle tastyStatic(selector, styles) - removes the call entirely\n */\nfunction handleSelectorMode(\n path: NodePath<t.CallExpression>,\n args: t.CallExpression['arguments'],\n cssWriter: CSSWriter,\n sourceFile?: string,\n globalKeyframes?: Record<string, KeyframesSteps>,\n autoPropertyTypes?: boolean,\n): void {\n if (args.length < 2) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) requires two arguments',\n );\n }\n\n const selectorArg = args[0];\n const stylesArg = args[1];\n\n if (!t.isStringLiteral(selectorArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) first argument must be a string literal',\n );\n }\n\n if (!t.isObjectExpression(stylesArg)) {\n throw path.buildCodeFrameError(\n 'tastyStatic(selector, styles) second argument must be a static object literal',\n );\n }\n\n const selector = selectorArg.value;\n const rawStyles = evaluateObjectExpression(stylesArg, path) as Styles;\n\n // Resolve recipes before extraction\n const styles = resolveRecipes(rawStyles);\n\n // Extract keyframes (deduplicated by content)\n const { keyframes, nameMap } = extractKeyframesFromStyles(\n styles,\n globalKeyframes,\n );\n\n // Add keyframes CSS\n for (const kf of keyframes) {\n cssWriter.add(kf.css, kf.css, sourceFile);\n }\n\n // Extract and add auto-inferred @property rules\n const properties = extractPropertiesFromStyles(styles, { autoPropertyTypes });\n for (const prop of properties) {\n cssWriter.add(prop.css, prop.css, sourceFile);\n }\n\n // Extract styles for selector\n const result = extractStylesForSelector(selector, styles);\n\n // Replace animation names if needed and add CSS\n const css =\n nameMap.size > 0\n ? replaceAnimationNamesInCSS(result.css, nameMap)\n : result.css;\n cssWriter.add(selector, css, sourceFile);\n\n // Remove the entire statement\n const parent = path.parentPath;\n if (parent && t.isExpressionStatement(parent.node)) {\n parent.remove();\n } else {\n // If used in an expression context (which would be incorrect usage),\n // replace with undefined\n path.replaceWith(t.identifier('undefined'));\n }\n}\n\n/**\n * Create a StaticStyle object AST node\n */\nfunction createStaticStyleAST(\n className: string,\n styles: Styles,\n): t.ObjectExpression {\n return t.objectExpression([\n t.objectProperty(t.identifier('className'), t.stringLiteral(className)),\n t.objectProperty(t.identifier('styles'), valueToAST(styles)),\n t.objectMethod(\n 'method',\n t.identifier('toString'),\n [],\n t.blockStatement([\n t.returnStatement(\n t.memberExpression(t.thisExpression(), t.identifier('className')),\n ),\n ]),\n ),\n ]);\n}\n\n/**\n * Register a StaticStyle in the registry if it's being assigned to a variable\n */\nfunction registerIfVariableDeclaration(\n path: NodePath,\n className: string,\n styles: Styles,\n state: PluginState,\n globalRegistry: StaticStyleRegistry,\n): void {\n const parent = path.parentPath;\n if (parent && t.isVariableDeclarator(parent.node)) {\n const id = parent.node.id;\n if (t.isIdentifier(id)) {\n const variableName = id.name;\n state.staticStyleRegistry[variableName] = { styles, className };\n globalRegistry[variableName] = { styles, className };\n }\n }\n}\n\n/**\n * Convert a JavaScript value to an AST node\n */\nfunction valueToAST(value: unknown): t.Expression {\n if (value === null) {\n return t.nullLiteral();\n }\n if (value === undefined) {\n return t.identifier('undefined');\n }\n if (typeof value === 'string') {\n return t.stringLiteral(value);\n }\n if (typeof value === 'number') {\n return t.numericLiteral(value);\n }\n if (typeof value === 'boolean') {\n return t.booleanLiteral(value);\n }\n if (Array.isArray(value)) {\n return t.arrayExpression(value.map(valueToAST));\n }\n if (typeof value === 'object') {\n const properties = Object.entries(value).map(([key, val]) =>\n t.objectProperty(\n /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)\n ? t.identifier(key)\n : t.stringLiteral(key),\n valueToAST(val),\n ),\n );\n return t.objectExpression(properties);\n }\n // Fallback for unsupported types\n return t.identifier('undefined');\n}\n\n/**\n * Evaluate an ObjectExpression to a plain JavaScript object.\n * Only supports static values that can be determined at build time.\n */\nfunction evaluateObjectExpression(\n node: t.ObjectExpression,\n path: NodePath,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const prop of node.properties) {\n if (t.isSpreadElement(prop)) {\n throw path.buildCodeFrameError(\n 'Spread elements are not supported in tastyStatic() - styles must be fully static',\n );\n }\n\n if (!t.isObjectProperty(prop)) {\n throw path.buildCodeFrameError(\n 'Only object properties are supported in tastyStatic()',\n );\n }\n\n // Get key\n let key: string;\n if (t.isIdentifier(prop.key)) {\n key = prop.key.name;\n } else if (t.isStringLiteral(prop.key)) {\n key = prop.key.value;\n } else {\n throw path.buildCodeFrameError(\n 'Dynamic property keys are not supported in tastyStatic()',\n );\n }\n\n // Get value\n const value = evaluateExpression(prop.value, path);\n result[key] = value;\n }\n\n return result;\n}\n\n/**\n * Evaluate an expression to a JavaScript value.\n */\nfunction evaluateExpression(node: t.Node, path: NodePath): unknown {\n if (t.isStringLiteral(node)) {\n return node.value;\n }\n\n if (t.isNumericLiteral(node)) {\n return node.value;\n }\n\n if (t.isBooleanLiteral(node)) {\n return node.value;\n }\n\n if (t.isNullLiteral(node)) {\n return null;\n }\n\n if (t.isIdentifier(node, { name: 'undefined' })) {\n return undefined;\n }\n\n if (t.isArrayExpression(node)) {\n return node.elements.map((el) => {\n if (el === null) return null;\n if (t.isSpreadElement(el)) {\n throw path.buildCodeFrameError(\n 'Spread elements are not supported in tastyStatic()',\n );\n }\n return evaluateExpression(el, path);\n });\n }\n\n if (t.isObjectExpression(node)) {\n return evaluateObjectExpression(node, path);\n }\n\n if (t.isTemplateLiteral(node)) {\n // Only support template literals without expressions\n if (node.expressions.length > 0) {\n throw path.buildCodeFrameError(\n 'Template literals with expressions are not supported in tastyStatic()',\n );\n }\n return node.quasis.map((q) => q.value.cooked).join('');\n }\n\n if (t.isUnaryExpression(node, { operator: '-' })) {\n const arg = evaluateExpression(node.argument, path);\n if (typeof arg === 'number') {\n return -arg;\n }\n }\n\n throw path.buildCodeFrameError(\n `Dynamic expressions are not supported in tastyStatic() - got ${node.type}. ` +\n 'All values must be static literals.',\n );\n}\n\n/**\n * Replace animation names in CSS string.\n * Wraps the keyframes replaceAnimationNames to work on full CSS blocks.\n */\nfunction replaceAnimationNamesInCSS(\n css: string,\n nameMap: Map<string, string>,\n): string {\n if (nameMap.size === 0) return css;\n\n // The CSS contains full rules like \".class { animation: name 1s; }\"\n // We need to replace animation names within declaration blocks\n return css.replace(\n /(animation(?:-name)?)\\s*:\\s*([^;}]+)/gi,\n (match, prop, value) => {\n let newValue = value;\n for (const [original, replacement] of nameMap) {\n // Word boundary replacement\n const pattern = new RegExp(`\\\\b${escapeRegex(original)}\\\\b`, 'g');\n newValue = newValue.replace(pattern, replacement);\n }\n return `${prop}: ${newValue}`;\n },\n );\n}\n\n/**\n * Escape special regex characters.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"mappings":"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"}
|