@tenphi/tasty 0.0.0-snapshot.cfcf770 → 0.0.0-snapshot.d2dcdeb
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -19
- package/dist/compute-styles.js +6 -28
- package/dist/compute-styles.js.map +1 -1
- package/dist/config.d.ts +41 -1
- package/dist/config.js +92 -7
- package/dist/config.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +1 -1
- package/dist/debug.js +4 -4
- package/dist/debug.js.map +1 -1
- package/dist/hooks/useCounterStyle.d.ts +3 -17
- package/dist/hooks/useCounterStyle.js +55 -35
- package/dist/hooks/useCounterStyle.js.map +1 -1
- package/dist/hooks/useFontFace.d.ts +3 -1
- package/dist/hooks/useFontFace.js +21 -24
- package/dist/hooks/useFontFace.js.map +1 -1
- package/dist/hooks/useGlobalStyles.d.ts +18 -2
- package/dist/hooks/useGlobalStyles.js +51 -40
- package/dist/hooks/useGlobalStyles.js.map +1 -1
- package/dist/hooks/useKeyframes.d.ts +4 -2
- package/dist/hooks/useKeyframes.js +42 -50
- package/dist/hooks/useKeyframes.js.map +1 -1
- package/dist/hooks/useProperty.d.ts +4 -2
- package/dist/hooks/useProperty.js +29 -41
- package/dist/hooks/useProperty.js.map +1 -1
- package/dist/hooks/useRawCSS.d.ts +13 -44
- package/dist/hooks/useRawCSS.js +90 -21
- package/dist/hooks/useRawCSS.js.map +1 -1
- package/dist/hooks/useStyles.d.ts +4 -4
- package/dist/hooks/useStyles.js +7 -5
- package/dist/hooks/useStyles.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/injector/index.js +1 -1
- package/dist/injector/index.js.map +1 -1
- package/dist/injector/injector.d.ts +9 -7
- package/dist/injector/injector.js +126 -38
- package/dist/injector/injector.js.map +1 -1
- package/dist/injector/sheet-manager.js +4 -2
- package/dist/injector/sheet-manager.js.map +1 -1
- package/dist/injector/types.d.ts +11 -2
- package/dist/pipeline/parseStateKey.js +4 -4
- package/dist/pipeline/parseStateKey.js.map +1 -1
- package/dist/plugins/types.d.ts +12 -1
- package/dist/rsc-cache.js +79 -0
- package/dist/rsc-cache.js.map +1 -0
- package/dist/ssr/astro-client.d.ts +1 -0
- package/dist/ssr/astro-client.js +19 -0
- package/dist/ssr/astro-client.js.map +1 -0
- package/dist/ssr/astro-middleware.d.ts +15 -0
- package/dist/ssr/astro-middleware.js +19 -0
- package/dist/ssr/astro-middleware.js.map +1 -0
- package/dist/ssr/astro.d.ts +89 -10
- package/dist/ssr/astro.js +112 -27
- package/dist/ssr/astro.js.map +1 -1
- package/dist/ssr/async-storage.js +14 -4
- package/dist/ssr/async-storage.js.map +1 -1
- package/dist/ssr/collect-auto-properties.js +28 -9
- package/dist/ssr/collect-auto-properties.js.map +1 -1
- package/dist/ssr/collector.d.ts +5 -13
- package/dist/ssr/collector.js +27 -15
- package/dist/ssr/collector.js.map +1 -1
- package/dist/ssr/context.js +16 -0
- package/dist/ssr/context.js.map +1 -0
- package/dist/ssr/hydrate.d.ts +20 -13
- package/dist/ssr/hydrate.js +24 -28
- package/dist/ssr/hydrate.js.map +1 -1
- package/dist/ssr/index.d.ts +3 -3
- package/dist/ssr/index.js +4 -4
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/next.d.ts +7 -4
- package/dist/ssr/next.js +7 -6
- package/dist/ssr/next.js.map +1 -1
- package/dist/ssr/ssr-collector-ref.js +19 -2
- package/dist/ssr/ssr-collector-ref.js.map +1 -1
- package/dist/tasty.d.ts +1 -1
- package/dist/tasty.js +9 -4
- package/dist/tasty.js.map +1 -1
- package/dist/utils/deps-equal.js +15 -0
- package/dist/utils/deps-equal.js.map +1 -0
- package/dist/utils/hash.js +14 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/typography.d.ts +21 -10
- package/dist/utils/typography.js +1 -1
- package/dist/utils/typography.js.map +1 -1
- package/dist/zero/babel.d.ts +7 -108
- package/dist/zero/babel.js +36 -12
- package/dist/zero/babel.js.map +1 -1
- package/docs/README.md +2 -2
- package/docs/adoption.md +5 -3
- package/docs/comparison.md +24 -25
- package/docs/configuration.md +69 -1
- package/docs/design-system.md +22 -10
- package/docs/dsl.md +3 -3
- package/docs/getting-started.md +10 -10
- package/docs/injector.md +9 -7
- package/docs/methodology.md +2 -2
- package/docs/{runtime.md → react-api.md} +17 -32
- package/docs/ssr.md +125 -39
- package/docs/tasty-static.md +14 -2
- package/package.json +9 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sheet-manager.js","names":[],"sources":["../../src/injector/sheet-manager.ts"],"sourcesContent":["import { PropertyTypeResolver } from '../properties/property-type-resolver';\nimport { createStyle, STYLE_HANDLER_MAP } from '../styles';\n\nimport type {\n CacheMetrics,\n KeyframesInfo,\n KeyframesSteps,\n RawCSSInfo,\n RawCSSResult,\n RootRegistry,\n RuleInfo,\n SheetInfo,\n StyleInjectorConfig,\n StyleRule,\n} from './types';\n\nimport type { CSSMap, StyleHandler, StyleValueStateMap } from '../utils/styles';\n\nexport class SheetManager {\n private rootRegistries = new WeakMap<Document | ShadowRoot, RootRegistry>();\n /** Strong set of active roots so background GC can iterate them all */\n private activeRoots = new Set<Document | ShadowRoot>();\n private config: StyleInjectorConfig;\n /** Dedicated style elements for raw CSS per root */\n private rawStyleElements = new WeakMap<\n Document | ShadowRoot,\n HTMLStyleElement\n >();\n /** Tracking for raw CSS blocks per root */\n private rawCSSBlocks = new WeakMap<\n Document | ShadowRoot,\n Map<string, RawCSSInfo>\n >();\n /** Counter for generating unique raw CSS IDs */\n private rawCSSCounter = 0;\n\n constructor(config: StyleInjectorConfig) {\n this.config = config;\n }\n\n /**\n * Get or create registry for a root (Document or ShadowRoot)\n */\n getRegistry(root: Document | ShadowRoot): RootRegistry {\n let registry = this.rootRegistries.get(root);\n\n if (!registry) {\n const metrics: CacheMetrics | undefined = this.config.devMode\n ? {\n hits: 0,\n misses: 0,\n bulkCleanups: 0,\n totalInsertions: 0,\n totalUnused: 0,\n stylesCleanedUp: 0,\n cleanupHistory: [],\n startTime: Date.now(),\n }\n : undefined;\n\n registry = {\n sheets: [],\n refCounts: new Map(),\n rules: new Map(),\n cacheKeyToClassName: new Map(),\n ruleTextSet: new Set<string>(),\n metrics,\n classCounter: 0,\n keyframesCache: new Map(),\n keyframesNameToContent: new Map(),\n keyframesCounter: 0,\n injectedProperties: new Map<string, string>(),\n injectedFontFaces: new Set<string>(),\n injectedCounterStyles: new Set<string>(),\n globalRules: new Map(),\n propertyTypeResolver: new PropertyTypeResolver(),\n usageMap: new Map(),\n } as unknown as RootRegistry;\n\n this.rootRegistries.set(root, registry);\n this.activeRoots.add(root);\n }\n\n return registry;\n }\n\n /** Return all roots with active registries (for background GC sweep). */\n getActiveRoots(): Iterable<Document | ShadowRoot> {\n return this.activeRoots;\n }\n\n /** Check whether any roots have active registries. */\n hasActiveRoots(): boolean {\n return this.activeRoots.size > 0;\n }\n\n /** Remove registries for ShadowRoots whose host has been detached from the DOM. */\n pruneDisconnectedRoots(): void {\n const toPrune: (Document | ShadowRoot)[] = [];\n for (const root of this.activeRoots) {\n if (root !== document && !(root as ShadowRoot).host?.isConnected) {\n toPrune.push(root);\n }\n }\n for (const root of toPrune) {\n this.cleanup(root);\n }\n }\n\n /**\n * Create a new stylesheet for the registry\n */\n createSheet(registry: RootRegistry, root: Document | ShadowRoot): SheetInfo {\n const sheet = this.createStyleElement(root);\n\n const sheetInfo: SheetInfo = {\n sheet,\n ruleCount: 0,\n holes: [],\n };\n\n registry.sheets.push(sheetInfo);\n return sheetInfo;\n }\n\n /**\n * Create a style element and append to document\n */\n private createStyleElement(root: Document | ShadowRoot): HTMLStyleElement {\n const style =\n (root as Document).createElement?.('style') ||\n document.createElement('style');\n\n if (this.config.nonce) {\n style.nonce = this.config.nonce;\n }\n\n style.setAttribute('data-tasty', '');\n\n // Append to head or shadow root\n if ('head' in root && root.head) {\n root.head.appendChild(style);\n } else if ('appendChild' in root) {\n root.appendChild(style);\n } else {\n document.head.appendChild(style);\n }\n\n // Verify it was actually added - log only if there's a problem and we're not using forceTextInjection\n if (!style.isConnected && !this.config.forceTextInjection) {\n console.error('SheetManager: Style element failed to connect to DOM!', {\n parentNode: style.parentNode?.nodeName,\n isConnected: style.isConnected,\n });\n }\n\n return style;\n }\n\n /**\n * Insert CSS rules as a single block\n */\n insertRule(\n registry: RootRegistry,\n flattenedRules: StyleRule[],\n className: string,\n root: Document | ShadowRoot,\n ): RuleInfo | null {\n // Find or create a sheet with available space\n let targetSheet = this.findAvailableSheet(registry, root);\n\n if (!targetSheet) {\n targetSheet = this.createSheet(registry, root);\n }\n\n const sheetIndex = registry.sheets.indexOf(targetSheet);\n\n try {\n // Group rules by selector, at-rules, and startingStyle to combine declarations\n const groupedRules: StyleRule[] = [];\n const groupMap = new Map<\n string,\n {\n idx: number;\n selector: string;\n atRules?: string[];\n startingStyle?: boolean;\n declarations: string;\n }\n >();\n\n const atKey = (at?: string[]) => (at && at.length ? at.join('|') : '');\n\n flattenedRules.forEach((r) => {\n const key = `${atKey(r.atRules)}||${r.selector}||${r.startingStyle ? '1' : '0'}`;\n const existing = groupMap.get(key);\n if (existing) {\n // Append declarations, preserving order\n existing.declarations = existing.declarations\n ? `${existing.declarations} ${r.declarations}`\n : r.declarations;\n } else {\n groupMap.set(key, {\n idx: groupedRules.length,\n selector: r.selector,\n atRules: r.atRules,\n startingStyle: r.startingStyle,\n declarations: r.declarations,\n });\n groupedRules.push({ ...r });\n }\n });\n\n // Normalize groupedRules from map (with merged declarations)\n groupMap.forEach((val) => {\n groupedRules[val.idx] = {\n selector: val.selector,\n atRules: val.atRules,\n startingStyle: val.startingStyle,\n declarations: val.declarations,\n } as StyleRule;\n });\n\n // Insert grouped rules\n const insertedRuleTexts: string[] = [];\n const insertedIndices: number[] = []; // Track exact indices\n // Calculate rule index atomically right before insertion to prevent race conditions\n let currentRuleIndex = this.findAvailableRuleIndex(targetSheet);\n let firstInsertedIndex: number | null = null;\n let lastInsertedIndex: number | null = null;\n\n for (const rule of groupedRules) {\n const declarations = rule.declarations;\n const innerContent = rule.startingStyle\n ? `@starting-style { ${declarations} }`\n : declarations;\n const baseRule = `${rule.selector} { ${innerContent} }`;\n\n // Wrap with at-rules if present\n let fullRule = baseRule;\n if (rule.atRules && rule.atRules.length > 0) {\n fullRule = rule.atRules.reduce(\n (css, atRule) => `${atRule} { ${css} }`,\n baseRule,\n );\n }\n\n // Insert individual rule into style element\n const styleElement = targetSheet.sheet;\n const styleSheet = styleElement.sheet;\n\n if (styleSheet && !this.config.forceTextInjection) {\n // Calculate index atomically for each rule to prevent concurrent insertion races\n const maxIndex = styleSheet.cssRules.length;\n const atomicRuleIndex = this.findAvailableRuleIndex(targetSheet);\n const safeIndex = Math.min(Math.max(0, atomicRuleIndex), maxIndex);\n\n // Helper: split comma-separated selectors safely (ignores commas inside [] () \" ')\n const splitSelectorsSafely = (selectorList: string): string[] => {\n const parts: string[] = [];\n let buf = '';\n let depthSq = 0; // [] depth\n let depthPar = 0; // () depth\n let inStr: '\"' | \"'\" | '' = '';\n for (let i = 0; i < selectorList.length; i++) {\n const ch = selectorList[i];\n if (inStr) {\n if (ch === inStr && selectorList[i - 1] !== '\\\\') {\n inStr = '';\n }\n buf += ch;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n inStr = ch as '\"' | \"'\";\n buf += ch;\n continue;\n }\n if (ch === '[') depthSq++;\n else if (ch === ']') depthSq = Math.max(0, depthSq - 1);\n else if (ch === '(') depthPar++;\n else if (ch === ')') depthPar = Math.max(0, depthPar - 1);\n\n if (ch === ',' && depthSq === 0 && depthPar === 0) {\n const part = buf.trim();\n if (part) parts.push(part);\n buf = '';\n } else {\n buf += ch;\n }\n }\n const tail = buf.trim();\n if (tail) parts.push(tail);\n return parts;\n };\n\n try {\n styleSheet.insertRule(fullRule, safeIndex);\n // Update sheet ruleCount immediately to prevent concurrent race conditions\n targetSheet.ruleCount++;\n insertedIndices.push(safeIndex); // Track this index\n if (firstInsertedIndex == null) firstInsertedIndex = safeIndex;\n lastInsertedIndex = safeIndex;\n currentRuleIndex = safeIndex + 1;\n } catch (e) {\n // If the browser rejects the combined selector (e.g., vendor pseudo-elements),\n // try to split and insert each selector independently. Skip unsupported ones.\n const selectors = splitSelectorsSafely(rule.selector);\n if (selectors.length > 1) {\n let anyInserted = false;\n for (const sel of selectors) {\n const singleBase = `${sel} { ${declarations} }`;\n let singleRule = singleBase;\n if (rule.atRules && rule.atRules.length > 0) {\n singleRule = rule.atRules.reduce(\n (css, atRule) => `${atRule} { ${css} }`,\n singleBase,\n );\n }\n\n try {\n // Calculate index atomically for each individual selector insertion\n const maxIdx = styleSheet.cssRules.length;\n const atomicIdx = this.findAvailableRuleIndex(targetSheet);\n const idx = Math.min(Math.max(0, atomicIdx), maxIdx);\n styleSheet.insertRule(singleRule, idx);\n // Update sheet ruleCount immediately\n targetSheet.ruleCount++;\n insertedIndices.push(idx); // Track this index\n if (firstInsertedIndex == null) firstInsertedIndex = idx;\n lastInsertedIndex = idx;\n currentRuleIndex = idx + 1;\n anyInserted = true;\n } catch (singleErr) {\n // Skip unsupported selector in this engine (e.g., ::-moz-selection in Blink)\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[tasty] Browser rejected CSS rule:',\n singleRule,\n singleErr,\n );\n }\n }\n }\n // If none inserted, continue without throwing to avoid aborting the whole batch\n if (!anyInserted) {\n // noop: all selectors invalid here; safe to skip\n }\n } else {\n // Single selector failed — skip it silently (likely unsupported in this engine)\n if (process.env.NODE_ENV !== 'production') {\n console.warn('[tasty] Browser rejected CSS rule:', fullRule, e);\n }\n }\n }\n } else {\n // Use textContent (either as fallback or when forceTextInjection is enabled)\n // Calculate index atomically for textContent insertion too\n const atomicRuleIndex = this.findAvailableRuleIndex(targetSheet);\n styleElement.textContent =\n (styleElement.textContent || '') + '\\n' + fullRule;\n // Update sheet ruleCount immediately\n targetSheet.ruleCount++;\n insertedIndices.push(atomicRuleIndex); // Track this index\n if (firstInsertedIndex == null) firstInsertedIndex = atomicRuleIndex;\n lastInsertedIndex = atomicRuleIndex;\n currentRuleIndex = atomicRuleIndex + 1;\n }\n\n // CRITICAL DEBUG: Verify the style element is in DOM only if there are issues and we're not using forceTextInjection\n if (!styleElement.parentNode && !this.config.forceTextInjection) {\n console.error(\n 'SheetManager: Style element is NOT in DOM! This is the problem!',\n {\n className,\n ruleIndex: currentRuleIndex,\n },\n );\n }\n\n // Dev-only: store cssText for debugging tools\n if (this.config.devMode) {\n insertedRuleTexts.push(fullRule);\n try {\n registry.ruleTextSet.add(fullRule);\n } catch {\n // noop: defensive in case ruleTextSet is unavailable\n }\n }\n // currentRuleIndex already adjusted above\n }\n\n // Sheet ruleCount is now updated immediately after each insertion\n // No need for deferred update logic\n\n if (insertedIndices.length === 0) {\n return null;\n }\n\n return {\n className,\n ruleIndex: firstInsertedIndex ?? 0,\n sheetIndex,\n cssText: this.config.devMode ? insertedRuleTexts : undefined,\n endRuleIndex: lastInsertedIndex ?? firstInsertedIndex ?? 0,\n indices: insertedIndices,\n };\n } catch (error) {\n console.warn('Failed to insert CSS rules:', error, {\n flattenedRules,\n className,\n });\n return null;\n }\n }\n\n /**\n * Insert global CSS rules\n */\n insertGlobalRule(\n registry: RootRegistry,\n flattenedRules: StyleRule[],\n globalKey: string,\n root: Document | ShadowRoot,\n ): RuleInfo | null {\n // Insert the rule using the same mechanism as regular rules\n const ruleInfo = this.insertRule(registry, flattenedRules, globalKey, root);\n\n // Track global rules for index adjustment\n if (ruleInfo) {\n registry.globalRules.set(globalKey, ruleInfo);\n }\n\n return ruleInfo;\n }\n\n /**\n * Delete a global CSS rule by key\n */\n public deleteGlobalRule(registry: RootRegistry, globalKey: string): void {\n const ruleInfo = registry.globalRules.get(globalKey);\n if (!ruleInfo) {\n return;\n }\n\n // Delete the rule using the standard deletion mechanism\n this.deleteRule(registry, ruleInfo);\n\n // Remove from global rules tracking\n registry.globalRules.delete(globalKey);\n }\n\n /**\n * Adjust rule indices after deletion to account for shifting\n */\n private adjustIndicesAfterDeletion(\n registry: RootRegistry,\n sheetIndex: number,\n startIdx: number,\n endIdx: number,\n deleteCount: number,\n deletedRuleInfo: RuleInfo,\n deletedIndices?: number[],\n ): void {\n try {\n const sortedDeleted =\n deletedIndices && deletedIndices.length > 0\n ? [...deletedIndices].sort((a, b) => a - b)\n : null;\n const countDeletedBefore = (sorted: number[], idx: number): number => {\n let shift = 0;\n for (const delIdx of sorted) {\n if (delIdx < idx) shift++;\n else break;\n }\n return shift;\n };\n // Helper function to adjust a single RuleInfo\n const adjustRuleInfo = (info: RuleInfo): void => {\n if (info === deletedRuleInfo) return; // Skip the deleted rule\n if (info.sheetIndex !== sheetIndex) return; // Different sheet\n\n if (!info.indices || info.indices.length === 0) {\n return;\n }\n\n if (sortedDeleted) {\n // Adjust each index based on how many deleted indices are before it\n info.indices = info.indices.map((idx) => {\n return idx - countDeletedBefore(sortedDeleted, idx);\n });\n } else {\n // Contiguous deletion: shift indices after the deleted range\n info.indices = info.indices.map((idx) =>\n idx > endIdx ? Math.max(0, idx - deleteCount) : idx,\n );\n }\n\n // Update ruleIndex and endRuleIndex to match adjusted indices\n if (info.indices.length > 0) {\n info.ruleIndex = Math.min(...info.indices);\n info.endRuleIndex = Math.max(...info.indices);\n }\n };\n\n // Adjust active rules\n for (const info of registry.rules.values()) {\n adjustRuleInfo(info);\n }\n\n // Adjust global rules\n for (const info of registry.globalRules.values()) {\n adjustRuleInfo(info);\n }\n\n // No need to separately adjust unused rules since they're part of the rules Map\n\n // Adjust keyframes indices stored in cache\n for (const entry of registry.keyframesCache.values()) {\n const ki = entry.info as KeyframesInfo;\n if (ki.sheetIndex !== sheetIndex) continue;\n if (sortedDeleted) {\n const shift = countDeletedBefore(sortedDeleted, ki.ruleIndex);\n if (shift > 0) {\n ki.ruleIndex = Math.max(0, ki.ruleIndex - shift);\n }\n } else if (ki.ruleIndex > endIdx) {\n ki.ruleIndex = Math.max(0, ki.ruleIndex - deleteCount);\n }\n }\n } catch {\n // Defensive: do not let index adjustments crash cleanup\n }\n }\n\n /**\n * Delete a CSS rule from the sheet\n */\n deleteRule(registry: RootRegistry, ruleInfo: RuleInfo): void {\n const sheet = registry.sheets[ruleInfo.sheetIndex];\n\n if (!sheet) {\n return;\n }\n\n try {\n const texts: string[] =\n this.config.devMode && Array.isArray(ruleInfo.cssText)\n ? ruleInfo.cssText.slice()\n : [];\n\n const styleElement = sheet.sheet;\n const styleSheet = styleElement.sheet;\n\n if (styleSheet) {\n const rules = styleSheet.cssRules;\n\n // Use exact indices if available, otherwise fall back to range\n if (ruleInfo.indices && ruleInfo.indices.length > 0) {\n // NEW: Delete using exact tracked indices\n const sortedIndices = [...ruleInfo.indices].sort((a, b) => b - a); // Sort descending\n const deletedIndices: number[] = [];\n\n for (const idx of sortedIndices) {\n if (idx >= 0 && idx < styleSheet.cssRules.length) {\n try {\n styleSheet.deleteRule(idx);\n deletedIndices.push(idx);\n } catch (e) {\n console.warn(`Failed to delete rule at index ${idx}:`, e);\n }\n }\n }\n\n sheet.ruleCount = Math.max(\n 0,\n sheet.ruleCount - deletedIndices.length,\n );\n\n // Adjust indices for all other rules\n if (deletedIndices.length > 0) {\n this.adjustIndicesAfterDeletion(\n registry,\n ruleInfo.sheetIndex,\n Math.min(...deletedIndices),\n Math.max(...deletedIndices),\n deletedIndices.length,\n ruleInfo,\n deletedIndices,\n );\n }\n } else {\n // FALLBACK: Use old range-based deletion for backwards compatibility\n const startIdx = Math.max(0, ruleInfo.ruleIndex);\n const endIdx = Math.min(\n rules.length - 1,\n Number.isFinite(ruleInfo.endRuleIndex as number)\n ? (ruleInfo.endRuleIndex as number)\n : startIdx,\n );\n\n if (Number.isFinite(startIdx) && endIdx >= startIdx) {\n const deleteCount = endIdx - startIdx + 1;\n for (let idx = endIdx; idx >= startIdx; idx--) {\n if (idx < 0 || idx >= styleSheet.cssRules.length) continue;\n styleSheet.deleteRule(idx);\n }\n sheet.ruleCount = Math.max(0, sheet.ruleCount - deleteCount);\n\n // After deletion, all subsequent rule indices shift left by deleteCount.\n // We must adjust stored indices for all other RuleInfo within the same sheet.\n this.adjustIndicesAfterDeletion(\n registry,\n ruleInfo.sheetIndex,\n startIdx,\n endIdx,\n deleteCount,\n ruleInfo,\n );\n }\n }\n }\n\n // Dev-only: remove cssText entries from validation set\n if (this.config.devMode && texts.length) {\n try {\n for (const text of texts) {\n registry.ruleTextSet.delete(text);\n }\n } catch {\n // noop\n }\n }\n } catch (error) {\n console.warn('Failed to delete CSS rule:', error);\n }\n }\n\n /**\n * Find a sheet with available space or return null\n */\n private findAvailableSheet(\n registry: RootRegistry,\n _root: Document | ShadowRoot,\n ): SheetInfo | null {\n const maxRules = this.config.maxRulesPerSheet;\n\n if (!maxRules) {\n // No limit, use the last sheet if it exists\n const lastSheet = registry.sheets[registry.sheets.length - 1];\n return lastSheet || null;\n }\n\n // Find sheet with space\n for (const sheet of registry.sheets) {\n if (sheet.ruleCount < maxRules) {\n return sheet;\n }\n }\n\n return null; // No available sheet found\n }\n\n /**\n * Find an available rule index in the sheet\n */\n findAvailableRuleIndex(sheet: SheetInfo): number {\n // Always append to the end - CSS doesn't have holes\n return sheet.ruleCount;\n }\n\n /**\n * Force cleanup of unused styles\n */\n public forceCleanup(registry: RootRegistry): void {\n this.performBulkCleanup(registry);\n }\n\n /**\n * Perform bulk cleanup of all unused styles (refCount = 0).\n */\n private performBulkCleanup(registry: RootRegistry): void {\n const cleanupStartTime = Date.now();\n\n // Calculate unused rules dynamically: rules that have refCount = 0\n // and are not tracked in usageMap (GC-kept styles must survive)\n const unusedClassNames = Array.from(registry.refCounts.entries())\n .filter(\n ([className, refCount]) =>\n refCount === 0 && !registry.usageMap.has(className),\n )\n .map(([className]) => className);\n\n if (unusedClassNames.length === 0) return;\n\n const selected = unusedClassNames\n .map((className) => {\n const ruleInfo = registry.rules.get(className);\n return ruleInfo ? { className, ruleInfo } : null;\n })\n .filter((entry): entry is NonNullable<typeof entry> => entry != null);\n\n let cleanedUpCount = 0;\n let totalCssSize = 0;\n let totalRulesDeleted = 0;\n\n // Group by sheet for efficient deletion\n const rulesBySheet = new Map<\n number,\n { className: string; ruleInfo: RuleInfo }[]\n >();\n\n // Calculate CSS size before deletion and group rules\n for (const { className, ruleInfo } of selected) {\n const sheetIndex = ruleInfo.sheetIndex;\n\n // Dev-only metrics: estimate CSS size and rule count if available\n if (this.config.devMode && Array.isArray(ruleInfo.cssText)) {\n const cssSize = ruleInfo.cssText.reduce(\n (total, css) => total + css.length,\n 0,\n );\n totalCssSize += cssSize;\n totalRulesDeleted += ruleInfo.cssText.length;\n }\n\n if (!rulesBySheet.has(sheetIndex)) {\n rulesBySheet.set(sheetIndex, []);\n }\n rulesBySheet.get(sheetIndex)!.push({ className, ruleInfo });\n }\n\n // Delete rules from each sheet (in reverse order to preserve indices)\n for (const [_sheetIndex, rulesInSheet] of rulesBySheet) {\n // Sort by rule index in descending order for safe deletion\n rulesInSheet.sort((a, b) => b.ruleInfo.ruleIndex - a.ruleInfo.ruleIndex);\n\n for (const { className, ruleInfo } of rulesInSheet) {\n // SAFETY 1: Double-check refCount is still 0\n const currentRefCount = registry.refCounts.get(className) || 0;\n if (currentRefCount > 0) {\n // Class became active again; do not delete\n continue;\n }\n\n // SAFETY 2: Ensure rule wasn't replaced\n // Between scheduling and execution a class may have been replaced with a new RuleInfo\n const currentInfo = registry.rules.get(className);\n if (currentInfo !== ruleInfo) {\n // Rule was replaced; skip deletion of the old reference\n continue;\n }\n\n // SAFETY 3: Verify the sheet element is still valid and accessible\n const sheetInfo = registry.sheets[ruleInfo.sheetIndex];\n if (!sheetInfo || !sheetInfo.sheet) {\n // Sheet was removed or corrupted; skip this rule\n continue;\n }\n\n // SAFETY 4: Verify the stylesheet itself is accessible\n const styleSheet = sheetInfo.sheet.sheet;\n if (!styleSheet) {\n // Stylesheet not available; skip this rule\n continue;\n }\n\n // SAFETY 5: Verify rule index is still within valid range\n const maxRuleIndex = styleSheet.cssRules.length - 1;\n const startIdx = ruleInfo.ruleIndex;\n const endIdx = ruleInfo.endRuleIndex ?? ruleInfo.ruleIndex;\n\n if (startIdx < 0 || endIdx > maxRuleIndex || startIdx > endIdx) {\n // Rule indices are out of bounds; skip this rule\n continue;\n }\n\n // All safety checks passed - proceed with deletion\n this.deleteRule(registry, ruleInfo);\n registry.rules.delete(className);\n registry.refCounts.delete(className);\n\n // Clean up cache key mappings that point to this className\n const keysToDelete: string[] = [];\n for (const [\n key,\n mappedClassName,\n ] of registry.cacheKeyToClassName.entries()) {\n if (mappedClassName === className) {\n keysToDelete.push(key);\n }\n }\n for (const key of keysToDelete) {\n registry.cacheKeyToClassName.delete(key);\n }\n cleanedUpCount++;\n }\n }\n\n // Update metrics\n if (registry.metrics) {\n registry.metrics.bulkCleanups++;\n registry.metrics.stylesCleanedUp += cleanedUpCount;\n\n // Add detailed cleanup stats to history\n registry.metrics.cleanupHistory.push({\n timestamp: cleanupStartTime,\n classesDeleted: cleanedUpCount,\n cssSize: totalCssSize,\n rulesDeleted: totalRulesDeleted,\n });\n }\n }\n\n /**\n * Get total number of rules across all sheets\n */\n getTotalRuleCount(registry: RootRegistry): number {\n return registry.sheets.reduce(\n (total, sheet) => total + sheet.ruleCount - sheet.holes.length,\n 0,\n );\n }\n\n /**\n * Get CSS text from all sheets (for SSR)\n */\n getCssText(registry: RootRegistry): string {\n const cssChunks: string[] = [];\n\n for (const sheet of registry.sheets) {\n try {\n const styleElement = sheet.sheet;\n if (styleElement.textContent) {\n cssChunks.push(styleElement.textContent);\n } else if (styleElement.sheet) {\n const rules = Array.from(styleElement.sheet.cssRules);\n cssChunks.push(rules.map((rule) => rule.cssText).join('\\n'));\n }\n } catch (error) {\n console.warn('Failed to read CSS from sheet:', error);\n }\n }\n\n return cssChunks.join('\\n');\n }\n\n /**\n * Get cache performance metrics\n */\n getMetrics(registry: RootRegistry): CacheMetrics | null {\n if (!registry.metrics) return null;\n\n // Calculate unusedHits on demand - only count CSS rules since keyframes are disposed immediately\n const unusedRulesCount = Array.from(registry.refCounts.values()).filter(\n (count) => count === 0,\n ).length;\n\n return {\n ...registry.metrics,\n unusedHits: unusedRulesCount,\n };\n }\n\n /**\n * Reset cache performance metrics\n */\n resetMetrics(registry: RootRegistry): void {\n if (registry.metrics) {\n registry.metrics = {\n hits: 0,\n misses: 0,\n bulkCleanups: 0,\n totalInsertions: 0,\n totalUnused: 0,\n stylesCleanedUp: 0,\n cleanupHistory: [],\n startTime: Date.now(),\n };\n }\n }\n\n /**\n * Convert keyframes steps to CSS string.\n * Public so the SSR collector can format keyframes without DOM access.\n * Returns both the CSS text and a combined declarations string for property type scanning.\n */\n stepsToCSS(steps: KeyframesSteps): {\n css: string;\n declarations: string;\n } {\n const rules: string[] = [];\n const allDeclarations: string[] = [];\n\n for (const [key, value] of Object.entries(steps)) {\n // Support raw CSS strings for backwards compatibility\n if (typeof value === 'string') {\n rules.push(`${key} { ${value.trim()} }`);\n allDeclarations.push(value.trim());\n continue;\n }\n\n // Treat value as a style map and process via tasty style handlers\n const styleMap = (value || {}) as StyleValueStateMap;\n\n // Build a deterministic handler queue based on present style keys\n const styleNames = Object.keys(styleMap).sort();\n const handlerQueue: StyleHandler[] = [];\n const seenHandlers = new Set<StyleHandler>();\n\n styleNames.forEach((styleName) => {\n let handlers = STYLE_HANDLER_MAP[styleName];\n if (!handlers) {\n // Create a default handler for unknown styles (maps to kebab-case CSS or custom props)\n handlers = STYLE_HANDLER_MAP[styleName] = [createStyle(styleName)];\n }\n\n handlers.forEach((handler) => {\n if (!seenHandlers.has(handler)) {\n seenHandlers.add(handler);\n handlerQueue.push(handler);\n }\n });\n });\n\n // Accumulate declarations (ordered). We intentionally ignore `$` selector fan-out\n // and any responsive/state bindings for keyframes.\n const declarationPairs: { prop: string; value: string }[] = [];\n\n handlerQueue.forEach((handler) => {\n const lookup = handler.__lookupStyles;\n const filteredMap = lookup.reduce<StyleValueStateMap>((acc, name) => {\n const v = styleMap[name];\n if (v !== undefined) acc[name] = v;\n return acc;\n }, {});\n\n const result = handler(filteredMap);\n if (!result) return;\n\n const results = Array.isArray(result) ? result : [result];\n results.forEach((cssMap) => {\n if (!cssMap || typeof cssMap !== 'object') return;\n const { $: _$, ...props } = cssMap as CSSMap;\n\n Object.entries(props).forEach(([prop, val]) => {\n if (val == null || val === '') return;\n\n if (Array.isArray(val)) {\n // Multiple values for the same property -> emit in order\n val.forEach((v) => {\n if (v != null && v !== '') {\n declarationPairs.push({ prop, value: String(v) });\n }\n });\n } else {\n declarationPairs.push({ prop, value: String(val) });\n }\n });\n });\n });\n\n // Fallback: if nothing produced (e.g., empty object), generate empty block\n const declarations = declarationPairs\n .map((d) => `${d.prop}: ${d.value}`)\n .join('; ');\n\n rules.push(`${key} { ${declarations.trim()} }`);\n allDeclarations.push(declarations);\n }\n\n return { css: rules.join(' '), declarations: allDeclarations.join('; ') };\n }\n\n /**\n * Insert keyframes rule.\n * Returns the KeyframesInfo and the raw declarations string for property type scanning.\n */\n insertKeyframes(\n registry: RootRegistry,\n steps: KeyframesSteps,\n name: string,\n root: Document | ShadowRoot,\n ): { info: KeyframesInfo; declarations: string } | null {\n let targetSheet = this.findAvailableSheet(registry, root);\n if (!targetSheet) {\n targetSheet = this.createSheet(registry, root);\n }\n\n const ruleIndex = this.findAvailableRuleIndex(targetSheet);\n const sheetIndex = registry.sheets.indexOf(targetSheet);\n\n try {\n const { css: cssSteps, declarations } = this.stepsToCSS(steps);\n const fullRule = `@keyframes ${name} { ${cssSteps} }`;\n\n const styleElement = targetSheet.sheet;\n const styleSheet = styleElement.sheet;\n\n if (styleSheet && !this.config.forceTextInjection) {\n const safeIndex = Math.min(\n Math.max(0, ruleIndex),\n styleSheet.cssRules.length,\n );\n styleSheet.insertRule(fullRule, safeIndex);\n } else {\n styleElement.textContent =\n (styleElement.textContent || '') + '\\n' + fullRule;\n }\n\n targetSheet.ruleCount++;\n\n return {\n info: {\n name,\n ruleIndex,\n sheetIndex,\n cssText: this.config.devMode ? fullRule : undefined,\n },\n declarations,\n };\n } catch (error) {\n console.warn('Failed to insert keyframes:', error);\n return null;\n }\n }\n\n /**\n * Delete keyframes rule\n */\n deleteKeyframes(registry: RootRegistry, info: KeyframesInfo): void {\n const sheet = registry.sheets[info.sheetIndex];\n if (!sheet) return;\n\n try {\n const styleElement = sheet.sheet;\n const styleSheet = styleElement.sheet;\n\n if (styleSheet) {\n if (\n info.ruleIndex >= 0 &&\n info.ruleIndex < styleSheet.cssRules.length\n ) {\n styleSheet.deleteRule(info.ruleIndex);\n sheet.ruleCount = Math.max(0, sheet.ruleCount - 1);\n\n // Adjust indices for all other rules in the same sheet\n // This is critical - when a keyframe rule is deleted, all rules\n // with higher indices shift down by 1\n this.adjustIndicesAfterDeletion(\n registry,\n info.sheetIndex,\n info.ruleIndex,\n info.ruleIndex,\n 1,\n // Create a dummy RuleInfo to satisfy the function signature\n {\n className: '',\n ruleIndex: info.ruleIndex,\n sheetIndex: info.sheetIndex,\n } as RuleInfo,\n [info.ruleIndex],\n );\n }\n }\n } catch (error) {\n console.warn('Failed to delete keyframes:', error);\n }\n }\n\n /**\n * Clean up resources for a root\n */\n cleanup(root: Document | ShadowRoot): void {\n const registry = this.rootRegistries.get(root);\n\n if (!registry) {\n return;\n }\n\n // Remove all sheets\n for (const sheet of registry.sheets) {\n try {\n // Remove style element\n const styleElement = sheet.sheet;\n if (styleElement.parentNode) {\n styleElement.parentNode.removeChild(styleElement);\n }\n } catch (error) {\n console.warn('Failed to cleanup sheet:', error);\n }\n }\n\n // Clear registry\n this.rootRegistries.delete(root);\n this.activeRoots.delete(root);\n\n // Clean up raw CSS style element\n const rawStyleElement = this.rawStyleElements.get(root);\n if (rawStyleElement?.parentNode) {\n rawStyleElement.parentNode.removeChild(rawStyleElement);\n }\n this.rawStyleElements.delete(root);\n this.rawCSSBlocks.delete(root);\n }\n\n /**\n * Get or create a dedicated style element for raw CSS\n * Raw CSS is kept separate from tasty-managed sheets to avoid index conflicts\n */\n private getOrCreateRawStyleElement(\n root: Document | ShadowRoot,\n ): HTMLStyleElement {\n let styleElement = this.rawStyleElements.get(root);\n\n if (!styleElement) {\n styleElement =\n (root as Document).createElement?.('style') ||\n document.createElement('style');\n\n if (this.config.nonce) {\n styleElement.nonce = this.config.nonce;\n }\n\n styleElement.setAttribute('data-tasty-raw', '');\n\n // Append to head or shadow root\n if ('head' in root && root.head) {\n root.head.appendChild(styleElement);\n } else if ('appendChild' in root) {\n root.appendChild(styleElement);\n } else {\n document.head.appendChild(styleElement);\n }\n\n this.rawStyleElements.set(root, styleElement);\n this.rawCSSBlocks.set(root, new Map());\n }\n\n return styleElement;\n }\n\n /**\n * Inject raw CSS text directly without parsing\n * Returns a dispose function to remove the injected CSS\n */\n injectRawCSS(css: string, root: Document | ShadowRoot): RawCSSResult {\n if (!css.trim()) {\n return {\n dispose: () => {\n /* noop */\n },\n };\n }\n\n const styleElement = this.getOrCreateRawStyleElement(root);\n const blocksMap = this.rawCSSBlocks.get(root)!;\n\n // Generate unique ID for this block\n const id = `raw_${this.rawCSSCounter++}`;\n\n // Calculate offsets\n const currentContent = styleElement.textContent || '';\n const startOffset = currentContent.length;\n const cssWithNewline = (currentContent ? '\\n' : '') + css;\n const endOffset = startOffset + cssWithNewline.length;\n\n // Append CSS\n styleElement.textContent = currentContent + cssWithNewline;\n\n // Track the block\n const info: RawCSSInfo = {\n id,\n css,\n startOffset,\n endOffset,\n };\n blocksMap.set(id, info);\n\n return {\n dispose: () => {\n this.disposeRawCSS(id, root);\n },\n };\n }\n\n /**\n * Remove a raw CSS block by ID\n */\n private disposeRawCSS(id: string, root: Document | ShadowRoot): void {\n const styleElement = this.rawStyleElements.get(root);\n const blocksMap = this.rawCSSBlocks.get(root);\n\n if (!styleElement || !blocksMap) {\n return;\n }\n\n const info = blocksMap.get(id);\n if (!info) {\n return;\n }\n\n // Remove from tracking\n blocksMap.delete(id);\n\n // Rebuild the CSS content from remaining blocks\n // This is simpler and more reliable than trying to splice strings\n const remainingBlocks = Array.from(blocksMap.values());\n\n if (remainingBlocks.length === 0) {\n styleElement.textContent = '';\n } else {\n // Rebuild with remaining CSS blocks in order of their original insertion\n // Sort by original startOffset to maintain order\n remainingBlocks.sort((a, b) => a.startOffset - b.startOffset);\n const newContent = remainingBlocks.map((block) => block.css).join('\\n');\n styleElement.textContent = newContent;\n\n // Update offsets for remaining blocks\n let offset = 0;\n for (const block of remainingBlocks) {\n block.startOffset = offset;\n block.endOffset = offset + block.css.length;\n offset = block.endOffset + 1; // +1 for newline\n }\n }\n }\n\n /**\n * Get the raw CSS content for SSR\n */\n getRawCSSText(root: Document | ShadowRoot): string {\n const styleElement = this.rawStyleElements.get(root);\n return styleElement?.textContent || '';\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sheet-manager.js","names":[],"sources":["../../src/injector/sheet-manager.ts"],"sourcesContent":["import { PropertyTypeResolver } from '../properties/property-type-resolver';\nimport { createStyle, STYLE_HANDLER_MAP } from '../styles';\n\nimport type {\n CacheMetrics,\n KeyframesInfo,\n KeyframesSteps,\n RawCSSInfo,\n RawCSSResult,\n RootRegistry,\n RuleInfo,\n SheetInfo,\n StyleInjectorConfig,\n StyleRule,\n} from './types';\n\nimport type { CSSMap, StyleHandler, StyleValueStateMap } from '../utils/styles';\n\nexport class SheetManager {\n private rootRegistries = new WeakMap<Document | ShadowRoot, RootRegistry>();\n /** Strong set of active roots so background GC can iterate them all */\n private activeRoots = new Set<Document | ShadowRoot>();\n private config: StyleInjectorConfig;\n /** Dedicated style elements for raw CSS per root */\n private rawStyleElements = new WeakMap<\n Document | ShadowRoot,\n HTMLStyleElement\n >();\n /** Tracking for raw CSS blocks per root */\n private rawCSSBlocks = new WeakMap<\n Document | ShadowRoot,\n Map<string, RawCSSInfo>\n >();\n /** Counter for generating unique raw CSS IDs */\n private rawCSSCounter = 0;\n\n constructor(config: StyleInjectorConfig) {\n this.config = config;\n }\n\n /**\n * Get or create registry for a root (Document or ShadowRoot)\n */\n getRegistry(root: Document | ShadowRoot): RootRegistry {\n let registry = this.rootRegistries.get(root);\n\n if (!registry) {\n const metrics: CacheMetrics | undefined = this.config.devMode\n ? {\n hits: 0,\n misses: 0,\n bulkCleanups: 0,\n totalInsertions: 0,\n totalUnused: 0,\n stylesCleanedUp: 0,\n cleanupHistory: [],\n startTime: Date.now(),\n }\n : undefined;\n\n registry = {\n sheets: [],\n refCounts: new Map(),\n rules: new Map(),\n cacheKeyToClassName: new Map(),\n ruleTextSet: new Set<string>(),\n metrics,\n keyframesCache: new Map(),\n keyframesNameToContent: new Map(),\n keyframesCounter: 0,\n injectedProperties: new Map<string, string>(),\n injectedFontFaces: new Set<string>(),\n injectedCounterStyles: new Set<string>(),\n globalRules: new Map(),\n propertyTypeResolver: new PropertyTypeResolver(),\n usageMap: new Map(),\n touchCount: 0,\n serverClassSyncIndex: 0,\n rscStylesScanned: false,\n } as unknown as RootRegistry;\n\n this.rootRegistries.set(root, registry);\n this.activeRoots.add(root);\n }\n\n return registry;\n }\n\n /** Return all roots with active registries (for background GC sweep). */\n getActiveRoots(): Iterable<Document | ShadowRoot> {\n return this.activeRoots;\n }\n\n /** Check whether any roots have active registries. */\n hasActiveRoots(): boolean {\n return this.activeRoots.size > 0;\n }\n\n /** Remove registries for ShadowRoots whose host has been detached from the DOM. */\n pruneDisconnectedRoots(): void {\n const toPrune: (Document | ShadowRoot)[] = [];\n for (const root of this.activeRoots) {\n if (root !== document && !(root as ShadowRoot).host?.isConnected) {\n toPrune.push(root);\n }\n }\n for (const root of toPrune) {\n this.cleanup(root);\n }\n }\n\n /**\n * Create a new stylesheet for the registry\n */\n createSheet(registry: RootRegistry, root: Document | ShadowRoot): SheetInfo {\n const sheet = this.createStyleElement(root);\n\n const sheetInfo: SheetInfo = {\n sheet,\n ruleCount: 0,\n holes: [],\n };\n\n registry.sheets.push(sheetInfo);\n return sheetInfo;\n }\n\n /**\n * Create a style element and append to document\n */\n private createStyleElement(root: Document | ShadowRoot): HTMLStyleElement {\n const style =\n (root as Document).createElement?.('style') ||\n document.createElement('style');\n\n if (this.config.nonce) {\n style.nonce = this.config.nonce;\n }\n\n style.setAttribute('data-tasty', '');\n\n // Append to head or shadow root\n if ('head' in root && root.head) {\n root.head.appendChild(style);\n } else if ('appendChild' in root) {\n root.appendChild(style);\n } else {\n document.head.appendChild(style);\n }\n\n // Verify it was actually added - log only if there's a problem and we're not using forceTextInjection\n if (!style.isConnected && !this.config.forceTextInjection) {\n console.error('SheetManager: Style element failed to connect to DOM!', {\n parentNode: style.parentNode?.nodeName,\n isConnected: style.isConnected,\n });\n }\n\n return style;\n }\n\n /**\n * Insert CSS rules as a single block\n */\n insertRule(\n registry: RootRegistry,\n flattenedRules: StyleRule[],\n className: string,\n root: Document | ShadowRoot,\n ): RuleInfo | null {\n // Find or create a sheet with available space\n let targetSheet = this.findAvailableSheet(registry, root);\n\n if (!targetSheet) {\n targetSheet = this.createSheet(registry, root);\n }\n\n const sheetIndex = registry.sheets.indexOf(targetSheet);\n\n try {\n // Group rules by selector, at-rules, and startingStyle to combine declarations\n const groupedRules: StyleRule[] = [];\n const groupMap = new Map<\n string,\n {\n idx: number;\n selector: string;\n atRules?: string[];\n startingStyle?: boolean;\n declarations: string;\n }\n >();\n\n const atKey = (at?: string[]) => (at && at.length ? at.join('|') : '');\n\n flattenedRules.forEach((r) => {\n const key = `${atKey(r.atRules)}||${r.selector}||${r.startingStyle ? '1' : '0'}`;\n const existing = groupMap.get(key);\n if (existing) {\n // Append declarations, preserving order\n existing.declarations = existing.declarations\n ? `${existing.declarations} ${r.declarations}`\n : r.declarations;\n } else {\n groupMap.set(key, {\n idx: groupedRules.length,\n selector: r.selector,\n atRules: r.atRules,\n startingStyle: r.startingStyle,\n declarations: r.declarations,\n });\n groupedRules.push({ ...r });\n }\n });\n\n // Normalize groupedRules from map (with merged declarations)\n groupMap.forEach((val) => {\n groupedRules[val.idx] = {\n selector: val.selector,\n atRules: val.atRules,\n startingStyle: val.startingStyle,\n declarations: val.declarations,\n } as StyleRule;\n });\n\n // Insert grouped rules\n const insertedRuleTexts: string[] = [];\n const insertedIndices: number[] = []; // Track exact indices\n // Calculate rule index atomically right before insertion to prevent race conditions\n let currentRuleIndex = this.findAvailableRuleIndex(targetSheet);\n let firstInsertedIndex: number | null = null;\n let lastInsertedIndex: number | null = null;\n\n for (const rule of groupedRules) {\n const declarations = rule.declarations;\n const innerContent = rule.startingStyle\n ? `@starting-style { ${declarations} }`\n : declarations;\n const baseRule = `${rule.selector} { ${innerContent} }`;\n\n // Wrap with at-rules if present\n let fullRule = baseRule;\n if (rule.atRules && rule.atRules.length > 0) {\n fullRule = rule.atRules.reduce(\n (css, atRule) => `${atRule} { ${css} }`,\n baseRule,\n );\n }\n\n // Insert individual rule into style element\n const styleElement = targetSheet.sheet;\n const styleSheet = styleElement.sheet;\n\n if (styleSheet && !this.config.forceTextInjection) {\n // Calculate index atomically for each rule to prevent concurrent insertion races\n const maxIndex = styleSheet.cssRules.length;\n const atomicRuleIndex = this.findAvailableRuleIndex(targetSheet);\n const safeIndex = Math.min(Math.max(0, atomicRuleIndex), maxIndex);\n\n // Helper: split comma-separated selectors safely (ignores commas inside [] () \" ')\n const splitSelectorsSafely = (selectorList: string): string[] => {\n const parts: string[] = [];\n let buf = '';\n let depthSq = 0; // [] depth\n let depthPar = 0; // () depth\n let inStr: '\"' | \"'\" | '' = '';\n for (let i = 0; i < selectorList.length; i++) {\n const ch = selectorList[i];\n if (inStr) {\n if (ch === inStr && selectorList[i - 1] !== '\\\\') {\n inStr = '';\n }\n buf += ch;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n inStr = ch as '\"' | \"'\";\n buf += ch;\n continue;\n }\n if (ch === '[') depthSq++;\n else if (ch === ']') depthSq = Math.max(0, depthSq - 1);\n else if (ch === '(') depthPar++;\n else if (ch === ')') depthPar = Math.max(0, depthPar - 1);\n\n if (ch === ',' && depthSq === 0 && depthPar === 0) {\n const part = buf.trim();\n if (part) parts.push(part);\n buf = '';\n } else {\n buf += ch;\n }\n }\n const tail = buf.trim();\n if (tail) parts.push(tail);\n return parts;\n };\n\n try {\n styleSheet.insertRule(fullRule, safeIndex);\n // Update sheet ruleCount immediately to prevent concurrent race conditions\n targetSheet.ruleCount++;\n insertedIndices.push(safeIndex); // Track this index\n if (firstInsertedIndex == null) firstInsertedIndex = safeIndex;\n lastInsertedIndex = safeIndex;\n currentRuleIndex = safeIndex + 1;\n } catch (e) {\n // If the browser rejects the combined selector (e.g., vendor pseudo-elements),\n // try to split and insert each selector independently. Skip unsupported ones.\n const selectors = splitSelectorsSafely(rule.selector);\n if (selectors.length > 1) {\n let anyInserted = false;\n for (const sel of selectors) {\n const singleBase = `${sel} { ${declarations} }`;\n let singleRule = singleBase;\n if (rule.atRules && rule.atRules.length > 0) {\n singleRule = rule.atRules.reduce(\n (css, atRule) => `${atRule} { ${css} }`,\n singleBase,\n );\n }\n\n try {\n // Calculate index atomically for each individual selector insertion\n const maxIdx = styleSheet.cssRules.length;\n const atomicIdx = this.findAvailableRuleIndex(targetSheet);\n const idx = Math.min(Math.max(0, atomicIdx), maxIdx);\n styleSheet.insertRule(singleRule, idx);\n // Update sheet ruleCount immediately\n targetSheet.ruleCount++;\n insertedIndices.push(idx); // Track this index\n if (firstInsertedIndex == null) firstInsertedIndex = idx;\n lastInsertedIndex = idx;\n currentRuleIndex = idx + 1;\n anyInserted = true;\n } catch (singleErr) {\n // Skip unsupported selector in this engine (e.g., ::-moz-selection in Blink)\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[tasty] Browser rejected CSS rule:',\n singleRule,\n singleErr,\n );\n }\n }\n }\n // If none inserted, continue without throwing to avoid aborting the whole batch\n if (!anyInserted) {\n // noop: all selectors invalid here; safe to skip\n }\n } else {\n // Single selector failed — skip it silently (likely unsupported in this engine)\n if (process.env.NODE_ENV !== 'production') {\n console.warn('[tasty] Browser rejected CSS rule:', fullRule, e);\n }\n }\n }\n } else {\n // Use textContent (either as fallback or when forceTextInjection is enabled)\n // Calculate index atomically for textContent insertion too\n const atomicRuleIndex = this.findAvailableRuleIndex(targetSheet);\n styleElement.textContent =\n (styleElement.textContent || '') + '\\n' + fullRule;\n // Update sheet ruleCount immediately\n targetSheet.ruleCount++;\n insertedIndices.push(atomicRuleIndex); // Track this index\n if (firstInsertedIndex == null) firstInsertedIndex = atomicRuleIndex;\n lastInsertedIndex = atomicRuleIndex;\n currentRuleIndex = atomicRuleIndex + 1;\n }\n\n // CRITICAL DEBUG: Verify the style element is in DOM only if there are issues and we're not using forceTextInjection\n if (!styleElement.parentNode && !this.config.forceTextInjection) {\n console.error(\n 'SheetManager: Style element is NOT in DOM! This is the problem!',\n {\n className,\n ruleIndex: currentRuleIndex,\n },\n );\n }\n\n // Dev-only: store cssText for debugging tools\n if (this.config.devMode) {\n insertedRuleTexts.push(fullRule);\n try {\n registry.ruleTextSet.add(fullRule);\n } catch {\n // noop: defensive in case ruleTextSet is unavailable\n }\n }\n // currentRuleIndex already adjusted above\n }\n\n // Sheet ruleCount is now updated immediately after each insertion\n // No need for deferred update logic\n\n if (insertedIndices.length === 0) {\n return null;\n }\n\n return {\n className,\n ruleIndex: firstInsertedIndex ?? 0,\n sheetIndex,\n cssText: this.config.devMode ? insertedRuleTexts : undefined,\n endRuleIndex: lastInsertedIndex ?? firstInsertedIndex ?? 0,\n indices: insertedIndices,\n };\n } catch (error) {\n console.warn('Failed to insert CSS rules:', error, {\n flattenedRules,\n className,\n });\n return null;\n }\n }\n\n /**\n * Insert global CSS rules\n */\n insertGlobalRule(\n registry: RootRegistry,\n flattenedRules: StyleRule[],\n globalKey: string,\n root: Document | ShadowRoot,\n ): RuleInfo | null {\n // Insert the rule using the same mechanism as regular rules\n const ruleInfo = this.insertRule(registry, flattenedRules, globalKey, root);\n\n // Track global rules for index adjustment\n if (ruleInfo) {\n registry.globalRules.set(globalKey, ruleInfo);\n }\n\n return ruleInfo;\n }\n\n /**\n * Delete a global CSS rule by key\n */\n public deleteGlobalRule(registry: RootRegistry, globalKey: string): void {\n const ruleInfo = registry.globalRules.get(globalKey);\n if (!ruleInfo) {\n return;\n }\n\n // Delete the rule using the standard deletion mechanism\n this.deleteRule(registry, ruleInfo);\n\n // Remove from global rules tracking\n registry.globalRules.delete(globalKey);\n }\n\n /**\n * Adjust rule indices after deletion to account for shifting\n */\n private adjustIndicesAfterDeletion(\n registry: RootRegistry,\n sheetIndex: number,\n startIdx: number,\n endIdx: number,\n deleteCount: number,\n deletedRuleInfo: RuleInfo,\n deletedIndices?: number[],\n ): void {\n try {\n const sortedDeleted =\n deletedIndices && deletedIndices.length > 0\n ? [...deletedIndices].sort((a, b) => a - b)\n : null;\n const countDeletedBefore = (sorted: number[], idx: number): number => {\n let shift = 0;\n for (const delIdx of sorted) {\n if (delIdx < idx) shift++;\n else break;\n }\n return shift;\n };\n // Helper function to adjust a single RuleInfo\n const adjustRuleInfo = (info: RuleInfo): void => {\n if (info === deletedRuleInfo) return; // Skip the deleted rule\n if (info.sheetIndex !== sheetIndex) return; // Different sheet\n\n if (!info.indices || info.indices.length === 0) {\n return;\n }\n\n if (sortedDeleted) {\n // Adjust each index based on how many deleted indices are before it\n info.indices = info.indices.map((idx) => {\n return idx - countDeletedBefore(sortedDeleted, idx);\n });\n } else {\n // Contiguous deletion: shift indices after the deleted range\n info.indices = info.indices.map((idx) =>\n idx > endIdx ? Math.max(0, idx - deleteCount) : idx,\n );\n }\n\n // Update ruleIndex and endRuleIndex to match adjusted indices\n if (info.indices.length > 0) {\n info.ruleIndex = Math.min(...info.indices);\n info.endRuleIndex = Math.max(...info.indices);\n }\n };\n\n // Adjust active rules\n for (const info of registry.rules.values()) {\n adjustRuleInfo(info);\n }\n\n // Adjust global rules\n for (const info of registry.globalRules.values()) {\n adjustRuleInfo(info);\n }\n\n // No need to separately adjust unused rules since they're part of the rules Map\n\n // Adjust keyframes indices stored in cache\n for (const entry of registry.keyframesCache.values()) {\n const ki = entry.info as KeyframesInfo;\n if (ki.sheetIndex !== sheetIndex) continue;\n if (sortedDeleted) {\n const shift = countDeletedBefore(sortedDeleted, ki.ruleIndex);\n if (shift > 0) {\n ki.ruleIndex = Math.max(0, ki.ruleIndex - shift);\n }\n } else if (ki.ruleIndex > endIdx) {\n ki.ruleIndex = Math.max(0, ki.ruleIndex - deleteCount);\n }\n }\n } catch {\n // Defensive: do not let index adjustments crash cleanup\n }\n }\n\n /**\n * Delete a CSS rule from the sheet\n */\n deleteRule(registry: RootRegistry, ruleInfo: RuleInfo): void {\n const sheet = registry.sheets[ruleInfo.sheetIndex];\n\n if (!sheet) {\n return;\n }\n\n try {\n const texts: string[] =\n this.config.devMode && Array.isArray(ruleInfo.cssText)\n ? ruleInfo.cssText.slice()\n : [];\n\n const styleElement = sheet.sheet;\n const styleSheet = styleElement.sheet;\n\n if (styleSheet) {\n const rules = styleSheet.cssRules;\n\n // Use exact indices if available, otherwise fall back to range\n if (ruleInfo.indices && ruleInfo.indices.length > 0) {\n // NEW: Delete using exact tracked indices\n const sortedIndices = [...ruleInfo.indices].sort((a, b) => b - a); // Sort descending\n const deletedIndices: number[] = [];\n\n for (const idx of sortedIndices) {\n if (idx >= 0 && idx < styleSheet.cssRules.length) {\n try {\n styleSheet.deleteRule(idx);\n deletedIndices.push(idx);\n } catch (e) {\n console.warn(`Failed to delete rule at index ${idx}:`, e);\n }\n }\n }\n\n sheet.ruleCount = Math.max(\n 0,\n sheet.ruleCount - deletedIndices.length,\n );\n\n // Adjust indices for all other rules\n if (deletedIndices.length > 0) {\n this.adjustIndicesAfterDeletion(\n registry,\n ruleInfo.sheetIndex,\n Math.min(...deletedIndices),\n Math.max(...deletedIndices),\n deletedIndices.length,\n ruleInfo,\n deletedIndices,\n );\n }\n } else {\n // FALLBACK: Use old range-based deletion for backwards compatibility\n const startIdx = Math.max(0, ruleInfo.ruleIndex);\n const endIdx = Math.min(\n rules.length - 1,\n Number.isFinite(ruleInfo.endRuleIndex as number)\n ? (ruleInfo.endRuleIndex as number)\n : startIdx,\n );\n\n if (Number.isFinite(startIdx) && endIdx >= startIdx) {\n const deleteCount = endIdx - startIdx + 1;\n for (let idx = endIdx; idx >= startIdx; idx--) {\n if (idx < 0 || idx >= styleSheet.cssRules.length) continue;\n styleSheet.deleteRule(idx);\n }\n sheet.ruleCount = Math.max(0, sheet.ruleCount - deleteCount);\n\n // After deletion, all subsequent rule indices shift left by deleteCount.\n // We must adjust stored indices for all other RuleInfo within the same sheet.\n this.adjustIndicesAfterDeletion(\n registry,\n ruleInfo.sheetIndex,\n startIdx,\n endIdx,\n deleteCount,\n ruleInfo,\n );\n }\n }\n }\n\n // Dev-only: remove cssText entries from validation set\n if (this.config.devMode && texts.length) {\n try {\n for (const text of texts) {\n registry.ruleTextSet.delete(text);\n }\n } catch {\n // noop\n }\n }\n } catch (error) {\n console.warn('Failed to delete CSS rule:', error);\n }\n }\n\n /**\n * Find a sheet with available space or return null\n */\n private findAvailableSheet(\n registry: RootRegistry,\n _root: Document | ShadowRoot,\n ): SheetInfo | null {\n const maxRules = this.config.maxRulesPerSheet;\n\n if (!maxRules) {\n // No limit, use the last sheet if it exists\n const lastSheet = registry.sheets[registry.sheets.length - 1];\n return lastSheet || null;\n }\n\n // Find sheet with space\n for (const sheet of registry.sheets) {\n if (sheet.ruleCount < maxRules) {\n return sheet;\n }\n }\n\n return null; // No available sheet found\n }\n\n /**\n * Find an available rule index in the sheet\n */\n findAvailableRuleIndex(sheet: SheetInfo): number {\n // Always append to the end - CSS doesn't have holes\n return sheet.ruleCount;\n }\n\n /**\n * Force cleanup of unused styles\n */\n public forceCleanup(registry: RootRegistry): void {\n this.performBulkCleanup(registry);\n }\n\n /**\n * Perform bulk cleanup of all unused styles (refCount = 0).\n */\n private performBulkCleanup(registry: RootRegistry): void {\n const cleanupStartTime = Date.now();\n\n // Calculate unused rules dynamically: rules that have refCount = 0\n // and are not tracked in usageMap (GC-kept styles must survive)\n const unusedClassNames = Array.from(registry.refCounts.entries())\n .filter(\n ([className, refCount]) =>\n refCount === 0 && !registry.usageMap.has(className),\n )\n .map(([className]) => className);\n\n if (unusedClassNames.length === 0) return;\n\n const selected = unusedClassNames\n .map((className) => {\n const ruleInfo = registry.rules.get(className);\n return ruleInfo ? { className, ruleInfo } : null;\n })\n .filter((entry): entry is NonNullable<typeof entry> => entry != null);\n\n let cleanedUpCount = 0;\n let totalCssSize = 0;\n let totalRulesDeleted = 0;\n\n // Group by sheet for efficient deletion\n const rulesBySheet = new Map<\n number,\n { className: string; ruleInfo: RuleInfo }[]\n >();\n\n // Calculate CSS size before deletion and group rules\n for (const { className, ruleInfo } of selected) {\n const sheetIndex = ruleInfo.sheetIndex;\n\n // Dev-only metrics: estimate CSS size and rule count if available\n if (this.config.devMode && Array.isArray(ruleInfo.cssText)) {\n const cssSize = ruleInfo.cssText.reduce(\n (total, css) => total + css.length,\n 0,\n );\n totalCssSize += cssSize;\n totalRulesDeleted += ruleInfo.cssText.length;\n }\n\n if (!rulesBySheet.has(sheetIndex)) {\n rulesBySheet.set(sheetIndex, []);\n }\n rulesBySheet.get(sheetIndex)!.push({ className, ruleInfo });\n }\n\n // Delete rules from each sheet (in reverse order to preserve indices)\n for (const [_sheetIndex, rulesInSheet] of rulesBySheet) {\n // Sort by rule index in descending order for safe deletion\n rulesInSheet.sort((a, b) => b.ruleInfo.ruleIndex - a.ruleInfo.ruleIndex);\n\n for (const { className, ruleInfo } of rulesInSheet) {\n // SAFETY 1: Double-check refCount is still 0\n const currentRefCount = registry.refCounts.get(className) || 0;\n if (currentRefCount > 0) {\n // Class became active again; do not delete\n continue;\n }\n\n // SAFETY 2: Ensure rule wasn't replaced\n // Between scheduling and execution a class may have been replaced with a new RuleInfo\n const currentInfo = registry.rules.get(className);\n if (currentInfo !== ruleInfo) {\n // Rule was replaced; skip deletion of the old reference\n continue;\n }\n\n // SAFETY 3: Verify the sheet element is still valid and accessible\n const sheetInfo = registry.sheets[ruleInfo.sheetIndex];\n if (!sheetInfo || !sheetInfo.sheet) {\n // Sheet was removed or corrupted; skip this rule\n continue;\n }\n\n // SAFETY 4: Verify the stylesheet itself is accessible\n const styleSheet = sheetInfo.sheet.sheet;\n if (!styleSheet) {\n // Stylesheet not available; skip this rule\n continue;\n }\n\n // SAFETY 5: Verify rule index is still within valid range\n const maxRuleIndex = styleSheet.cssRules.length - 1;\n const startIdx = ruleInfo.ruleIndex;\n const endIdx = ruleInfo.endRuleIndex ?? ruleInfo.ruleIndex;\n\n if (startIdx < 0 || endIdx > maxRuleIndex || startIdx > endIdx) {\n // Rule indices are out of bounds; skip this rule\n continue;\n }\n\n // All safety checks passed - proceed with deletion\n this.deleteRule(registry, ruleInfo);\n registry.rules.delete(className);\n registry.refCounts.delete(className);\n\n // Clean up cache key mappings that point to this className\n const keysToDelete: string[] = [];\n for (const [\n key,\n mappedClassName,\n ] of registry.cacheKeyToClassName.entries()) {\n if (mappedClassName === className) {\n keysToDelete.push(key);\n }\n }\n for (const key of keysToDelete) {\n registry.cacheKeyToClassName.delete(key);\n }\n cleanedUpCount++;\n }\n }\n\n // Update metrics\n if (registry.metrics) {\n registry.metrics.bulkCleanups++;\n registry.metrics.stylesCleanedUp += cleanedUpCount;\n\n // Add detailed cleanup stats to history\n registry.metrics.cleanupHistory.push({\n timestamp: cleanupStartTime,\n classesDeleted: cleanedUpCount,\n cssSize: totalCssSize,\n rulesDeleted: totalRulesDeleted,\n });\n }\n }\n\n /**\n * Get total number of rules across all sheets\n */\n getTotalRuleCount(registry: RootRegistry): number {\n return registry.sheets.reduce(\n (total, sheet) => total + sheet.ruleCount - sheet.holes.length,\n 0,\n );\n }\n\n /**\n * Get CSS text from all sheets (for SSR)\n */\n getCssText(registry: RootRegistry): string {\n const cssChunks: string[] = [];\n\n for (const sheet of registry.sheets) {\n try {\n const styleElement = sheet.sheet;\n if (styleElement.textContent) {\n cssChunks.push(styleElement.textContent);\n } else if (styleElement.sheet) {\n const rules = Array.from(styleElement.sheet.cssRules);\n cssChunks.push(rules.map((rule) => rule.cssText).join('\\n'));\n }\n } catch (error) {\n console.warn('Failed to read CSS from sheet:', error);\n }\n }\n\n return cssChunks.join('\\n');\n }\n\n /**\n * Get cache performance metrics\n */\n getMetrics(registry: RootRegistry): CacheMetrics | null {\n if (!registry.metrics) return null;\n\n // Calculate unusedHits on demand - only count CSS rules since keyframes are disposed immediately\n const unusedRulesCount = Array.from(registry.refCounts.values()).filter(\n (count) => count === 0,\n ).length;\n\n return {\n ...registry.metrics,\n unusedHits: unusedRulesCount,\n };\n }\n\n /**\n * Reset cache performance metrics\n */\n resetMetrics(registry: RootRegistry): void {\n if (registry.metrics) {\n registry.metrics = {\n hits: 0,\n misses: 0,\n bulkCleanups: 0,\n totalInsertions: 0,\n totalUnused: 0,\n stylesCleanedUp: 0,\n cleanupHistory: [],\n startTime: Date.now(),\n };\n }\n }\n\n /**\n * Convert keyframes steps to CSS string.\n * Public so the SSR collector can format keyframes without DOM access.\n * Returns both the CSS text and a combined declarations string for property type scanning.\n */\n stepsToCSS(steps: KeyframesSteps): {\n css: string;\n declarations: string;\n } {\n const rules: string[] = [];\n const allDeclarations: string[] = [];\n\n for (const [key, value] of Object.entries(steps)) {\n // Support raw CSS strings for backwards compatibility\n if (typeof value === 'string') {\n rules.push(`${key} { ${value.trim()} }`);\n allDeclarations.push(value.trim());\n continue;\n }\n\n // Treat value as a style map and process via tasty style handlers\n const styleMap = (value || {}) as StyleValueStateMap;\n\n // Build a deterministic handler queue based on present style keys\n const styleNames = Object.keys(styleMap).sort();\n const handlerQueue: StyleHandler[] = [];\n const seenHandlers = new Set<StyleHandler>();\n\n styleNames.forEach((styleName) => {\n let handlers = STYLE_HANDLER_MAP[styleName];\n if (!handlers) {\n // Create a default handler for unknown styles (maps to kebab-case CSS or custom props)\n handlers = STYLE_HANDLER_MAP[styleName] = [createStyle(styleName)];\n }\n\n handlers.forEach((handler) => {\n if (!seenHandlers.has(handler)) {\n seenHandlers.add(handler);\n handlerQueue.push(handler);\n }\n });\n });\n\n // Accumulate declarations (ordered). We intentionally ignore `$` selector fan-out\n // and any responsive/state bindings for keyframes.\n const declarationPairs: { prop: string; value: string }[] = [];\n\n handlerQueue.forEach((handler) => {\n const lookup = handler.__lookupStyles;\n const filteredMap = lookup.reduce<StyleValueStateMap>((acc, name) => {\n const v = styleMap[name];\n if (v !== undefined) acc[name] = v;\n return acc;\n }, {});\n\n const result = handler(filteredMap);\n if (!result) return;\n\n const results = Array.isArray(result) ? result : [result];\n results.forEach((cssMap) => {\n if (!cssMap || typeof cssMap !== 'object') return;\n const { $: _$, ...props } = cssMap as CSSMap;\n\n Object.entries(props).forEach(([prop, val]) => {\n if (val == null || val === '') return;\n\n if (Array.isArray(val)) {\n // Multiple values for the same property -> emit in order\n val.forEach((v) => {\n if (v != null && v !== '') {\n declarationPairs.push({ prop, value: String(v) });\n }\n });\n } else {\n declarationPairs.push({ prop, value: String(val) });\n }\n });\n });\n });\n\n // Fallback: if nothing produced (e.g., empty object), generate empty block\n const declarations = declarationPairs\n .map((d) => `${d.prop}: ${d.value}`)\n .join('; ');\n\n rules.push(`${key} { ${declarations.trim()} }`);\n allDeclarations.push(declarations);\n }\n\n return { css: rules.join(' '), declarations: allDeclarations.join('; ') };\n }\n\n /**\n * Insert keyframes rule.\n * Returns the KeyframesInfo and the raw declarations string for property type scanning.\n */\n insertKeyframes(\n registry: RootRegistry,\n steps: KeyframesSteps,\n name: string,\n root: Document | ShadowRoot,\n ): { info: KeyframesInfo; declarations: string } | null {\n let targetSheet = this.findAvailableSheet(registry, root);\n if (!targetSheet) {\n targetSheet = this.createSheet(registry, root);\n }\n\n const ruleIndex = this.findAvailableRuleIndex(targetSheet);\n const sheetIndex = registry.sheets.indexOf(targetSheet);\n\n try {\n const { css: cssSteps, declarations } = this.stepsToCSS(steps);\n const fullRule = `@keyframes ${name} { ${cssSteps} }`;\n\n const styleElement = targetSheet.sheet;\n const styleSheet = styleElement.sheet;\n\n if (styleSheet && !this.config.forceTextInjection) {\n const safeIndex = Math.min(\n Math.max(0, ruleIndex),\n styleSheet.cssRules.length,\n );\n styleSheet.insertRule(fullRule, safeIndex);\n } else {\n styleElement.textContent =\n (styleElement.textContent || '') + '\\n' + fullRule;\n }\n\n targetSheet.ruleCount++;\n\n return {\n info: {\n name,\n ruleIndex,\n sheetIndex,\n cssText: this.config.devMode ? fullRule : undefined,\n },\n declarations,\n };\n } catch (error) {\n console.warn('Failed to insert keyframes:', error);\n return null;\n }\n }\n\n /**\n * Delete keyframes rule\n */\n deleteKeyframes(registry: RootRegistry, info: KeyframesInfo): void {\n const sheet = registry.sheets[info.sheetIndex];\n if (!sheet) return;\n\n try {\n const styleElement = sheet.sheet;\n const styleSheet = styleElement.sheet;\n\n if (styleSheet) {\n if (\n info.ruleIndex >= 0 &&\n info.ruleIndex < styleSheet.cssRules.length\n ) {\n styleSheet.deleteRule(info.ruleIndex);\n sheet.ruleCount = Math.max(0, sheet.ruleCount - 1);\n\n // Adjust indices for all other rules in the same sheet\n // This is critical - when a keyframe rule is deleted, all rules\n // with higher indices shift down by 1\n this.adjustIndicesAfterDeletion(\n registry,\n info.sheetIndex,\n info.ruleIndex,\n info.ruleIndex,\n 1,\n // Create a dummy RuleInfo to satisfy the function signature\n {\n className: '',\n ruleIndex: info.ruleIndex,\n sheetIndex: info.sheetIndex,\n } as RuleInfo,\n [info.ruleIndex],\n );\n }\n }\n } catch (error) {\n console.warn('Failed to delete keyframes:', error);\n }\n }\n\n /**\n * Clean up resources for a root\n */\n cleanup(root: Document | ShadowRoot): void {\n const registry = this.rootRegistries.get(root);\n\n if (!registry) {\n return;\n }\n\n // Remove all sheets\n for (const sheet of registry.sheets) {\n try {\n // Remove style element\n const styleElement = sheet.sheet;\n if (styleElement.parentNode) {\n styleElement.parentNode.removeChild(styleElement);\n }\n } catch (error) {\n console.warn('Failed to cleanup sheet:', error);\n }\n }\n\n // Clear registry\n this.rootRegistries.delete(root);\n this.activeRoots.delete(root);\n\n // Clean up raw CSS style element\n const rawStyleElement = this.rawStyleElements.get(root);\n if (rawStyleElement?.parentNode) {\n rawStyleElement.parentNode.removeChild(rawStyleElement);\n }\n this.rawStyleElements.delete(root);\n this.rawCSSBlocks.delete(root);\n }\n\n /**\n * Get or create a dedicated style element for raw CSS\n * Raw CSS is kept separate from tasty-managed sheets to avoid index conflicts\n */\n private getOrCreateRawStyleElement(\n root: Document | ShadowRoot,\n ): HTMLStyleElement {\n let styleElement = this.rawStyleElements.get(root);\n\n if (!styleElement) {\n styleElement =\n (root as Document).createElement?.('style') ||\n document.createElement('style');\n\n if (this.config.nonce) {\n styleElement.nonce = this.config.nonce;\n }\n\n styleElement.setAttribute('data-tasty-raw', '');\n\n // Append to head or shadow root\n if ('head' in root && root.head) {\n root.head.appendChild(styleElement);\n } else if ('appendChild' in root) {\n root.appendChild(styleElement);\n } else {\n document.head.appendChild(styleElement);\n }\n\n this.rawStyleElements.set(root, styleElement);\n this.rawCSSBlocks.set(root, new Map());\n }\n\n return styleElement;\n }\n\n /**\n * Inject raw CSS text directly without parsing\n * Returns a dispose function to remove the injected CSS\n */\n injectRawCSS(css: string, root: Document | ShadowRoot): RawCSSResult {\n if (!css.trim()) {\n return {\n dispose: () => {\n /* noop */\n },\n };\n }\n\n const styleElement = this.getOrCreateRawStyleElement(root);\n const blocksMap = this.rawCSSBlocks.get(root)!;\n\n // Generate unique ID for this block\n const id = `raw_${this.rawCSSCounter++}`;\n\n // Calculate offsets\n const currentContent = styleElement.textContent || '';\n const startOffset = currentContent.length;\n const cssWithNewline = (currentContent ? '\\n' : '') + css;\n const endOffset = startOffset + cssWithNewline.length;\n\n // Append CSS\n styleElement.textContent = currentContent + cssWithNewline;\n\n // Track the block\n const info: RawCSSInfo = {\n id,\n css,\n startOffset,\n endOffset,\n };\n blocksMap.set(id, info);\n\n return {\n dispose: () => {\n this.disposeRawCSS(id, root);\n },\n };\n }\n\n /**\n * Remove a raw CSS block by ID\n */\n private disposeRawCSS(id: string, root: Document | ShadowRoot): void {\n const styleElement = this.rawStyleElements.get(root);\n const blocksMap = this.rawCSSBlocks.get(root);\n\n if (!styleElement || !blocksMap) {\n return;\n }\n\n const info = blocksMap.get(id);\n if (!info) {\n return;\n }\n\n // Remove from tracking\n blocksMap.delete(id);\n\n // Rebuild the CSS content from remaining blocks\n // This is simpler and more reliable than trying to splice strings\n const remainingBlocks = Array.from(blocksMap.values());\n\n if (remainingBlocks.length === 0) {\n styleElement.textContent = '';\n } else {\n // Rebuild with remaining CSS blocks in order of their original insertion\n // Sort by original startOffset to maintain order\n remainingBlocks.sort((a, b) => a.startOffset - b.startOffset);\n const newContent = remainingBlocks.map((block) => block.css).join('\\n');\n styleElement.textContent = newContent;\n\n // Update offsets for remaining blocks\n let offset = 0;\n for (const block of remainingBlocks) {\n block.startOffset = offset;\n block.endOffset = offset + block.css.length;\n offset = block.endOffset + 1; // +1 for newline\n }\n }\n }\n\n /**\n * Get the raw CSS content for SSR\n */\n getRawCSSText(root: Document | ShadowRoot): string {\n const styleElement = this.rawStyleElements.get(root);\n return styleElement?.textContent || '';\n }\n}\n"],"mappings":"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"}
|
package/dist/injector/types.d.ts
CHANGED
|
@@ -2,6 +2,11 @@ import { PropertyTypeResolver } from "../properties/property-type-resolver.js";
|
|
|
2
2
|
import { StyleResult } from "../pipeline/index.js";
|
|
3
3
|
|
|
4
4
|
//#region src/injector/types.d.ts
|
|
5
|
+
declare global {
|
|
6
|
+
interface Window {
|
|
7
|
+
__TASTY__?: string[];
|
|
8
|
+
}
|
|
9
|
+
}
|
|
5
10
|
interface InjectResult {
|
|
6
11
|
className: string;
|
|
7
12
|
dispose: () => void;
|
|
@@ -110,8 +115,6 @@ interface RootRegistry {
|
|
|
110
115
|
ruleTextSet: Set<string>;
|
|
111
116
|
/** Performance metrics (optional) */
|
|
112
117
|
metrics?: CacheMetrics;
|
|
113
|
-
/** Counter for generating sequential class names like t0, t1, t2... */
|
|
114
|
-
classCounter: number;
|
|
115
118
|
/** Keyframes cache by content hash -> entry */
|
|
116
119
|
keyframesCache: Map<string, KeyframesCacheEntry>;
|
|
117
120
|
/** Keyframes name to content hash mapping for collision detection */
|
|
@@ -130,6 +133,12 @@ interface RootRegistry {
|
|
|
130
133
|
propertyTypeResolver: PropertyTypeResolver;
|
|
131
134
|
/** Per-className usage tracking for GC */
|
|
132
135
|
usageMap: Map<string, StyleUsage>;
|
|
136
|
+
/** Touch counter for scheduling GC (per-root) */
|
|
137
|
+
touchCount: number;
|
|
138
|
+
/** How many entries from `window.__TASTY__` have been synced into this registry */
|
|
139
|
+
serverClassSyncIndex: number;
|
|
140
|
+
/** Whether `<style data-tasty-rsc>` tags have been scanned for class names */
|
|
141
|
+
rscStylesScanned: boolean;
|
|
133
142
|
}
|
|
134
143
|
type StyleRule = StyleResult;
|
|
135
144
|
interface KeyframesInfo {
|
|
@@ -23,12 +23,12 @@ const parseCache = new Lru(5e3);
|
|
|
23
23
|
* Matches: operators, parentheses, @-prefixed states, value mods, boolean mods,
|
|
24
24
|
* pseudo-classes, class selectors, and attribute selectors.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* All @-prefixed state groups (@supports, @root, @parent, @own, @(...))
|
|
27
|
+
* and :is/:has/:not/:where pseudo-classes support up to 2 levels of
|
|
28
|
+
* nested parentheses via:
|
|
29
29
|
* [^()]*(?:\([^()]*(?:\([^)]*\))?[^)]*\))*[^)]*
|
|
30
30
|
*/
|
|
31
|
-
const STATE_TOKEN_PATTERN = /([&|!^])|([()])|(@media:[a-z]+)|(@media\([^)]+\))|(@supports\([^()]*(?:\([^)]*\))?[^)]*\))|(@root\([^)]
|
|
31
|
+
const STATE_TOKEN_PATTERN = /([&|!^])|([()])|(@media:[a-z]+)|(@media\([^)]+\))|(@supports\([^()]*(?:\([^()]*(?:\([^)]*\))?[^)]*\))*[^)]*\))|(@root\([^()]*(?:\([^()]*(?:\([^)]*\))?[^)]*\))*[^)]*\))|(@parent\([^()]*(?:\([^()]*(?:\([^)]*\))?[^)]*\))*[^)]*\))|(@own\([^()]*(?:\([^()]*(?:\([^)]*\))?[^)]*\))*[^)]*\))|(@\([^()]*(?:\([^()]*(?:\([^)]*\))?[^)]*\))*[^)]*\))|(@starting)|(@[A-Za-z][A-Za-z0-9-]*)|([a-z][a-z0-9-]*(?:\^=|\$=|\*=|=)(?:"[^"]*"|'[^']*'|[^\s&|!^()]+))|([a-z][a-z0-9-]+)|(:(?:is|has|not|where)\([^()]*(?:\([^()]*(?:\([^)]*\))?[^)]*\))*[^)]*\))|(:[-a-z][a-z0-9-]*(?:\([^)]+\))?)|(\.[a-z][a-z0-9-]+)|(\[[^\]]+\])/gi;
|
|
32
32
|
/**
|
|
33
33
|
* Tokenize a state notation string
|
|
34
34
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseStateKey.js","names":[],"sources":["../../src/pipeline/parseStateKey.ts"],"sourcesContent":["/**\n * State Key Parser\n *\n * Parses state notation strings (like 'hovered & !disabled', '@media(w < 768px)')\n * into ConditionNode trees for processing in the pipeline.\n */\n\nimport { Lru } from '../parser/lru';\nimport type { StateParserContext } from '../states';\nimport {\n expandDimensionShorthands,\n expandTastyUnits,\n findTopLevelComma,\n resolvePredefinedState,\n} from '../states';\nimport { camelToKebab } from '../utils/case-converter';\nimport { transformSelectorContent } from '../utils/selector-transform';\n\nimport type { ConditionNode, NumericBound } from './conditions';\nimport { emitWarning } from './warnings';\nimport {\n and,\n createContainerDimensionCondition,\n createContainerRawCondition,\n createContainerStyleCondition,\n createMediaDimensionCondition,\n createMediaFeatureCondition,\n createMediaTypeCondition,\n createModifierCondition,\n createOwnCondition,\n createParentCondition,\n createPseudoCondition,\n createRootCondition,\n createStartingCondition,\n createSupportsCondition,\n not,\n or,\n trueCondition,\n} from './conditions';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Maximum XOR operands before emitting a performance warning.\n * A ^ B ^ C ^ D = 8 OR branches (2^(n-1)), so chains above 4\n * risk exponential blowup in downstream processing.\n */\nconst MAX_XOR_CHAIN_LENGTH = 4;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ParseStateKeyOptions {\n context?: StateParserContext;\n isSubElement?: boolean;\n}\n\n// ============================================================================\n// Caching\n// ============================================================================\n\n// Cache for parsed state keys (key -> ConditionNode)\nconst parseCache = new Lru<string, ConditionNode>(5000);\n\n// ============================================================================\n// Tokenizer Patterns\n// ============================================================================\n\n/**\n * Pattern for tokenizing state notation.\n * Matches: operators, parentheses, @-prefixed states, value mods, boolean mods,\n * pseudo-classes, class selectors, and attribute selectors.\n *\n * Note: For @supports, @(...) container queries, and :is/:has/:not/:where\n * we need to handle nested parentheses.\n * We use a pattern that allows up to 2 levels of nesting:\n * [^()]*(?:\\([^()]*(?:\\([^)]*\\))?[^)]*\\))*[^)]*\n */\nconst STATE_TOKEN_PATTERN =\n /([&|!^])|([()])|(@media:[a-z]+)|(@media\\([^)]+\\))|(@supports\\([^()]*(?:\\([^)]*\\))?[^)]*\\))|(@root\\([^)]+\\))|(@parent\\([^)]+\\))|(@own\\([^)]+\\))|(@\\([^()]*(?:\\([^)]*\\))?[^)]*\\))|(@starting)|(@[A-Za-z][A-Za-z0-9-]*)|([a-z][a-z0-9-]*(?:\\^=|\\$=|\\*=|=)(?:\"[^\"]*\"|'[^']*'|[^\\s&|!^()]+))|([a-z][a-z0-9-]+)|(:(?:is|has|not|where)\\([^()]*(?:\\([^()]*(?:\\([^)]*\\))?[^)]*\\))*[^)]*\\))|(:[-a-z][a-z0-9-]*(?:\\([^)]+\\))?)|(\\.[a-z][a-z0-9-]+)|(\\[[^\\]]+\\])/gi;\n\n// ============================================================================\n// Token Types\n// ============================================================================\n\ntype TokenType = 'AND' | 'OR' | 'NOT' | 'XOR' | 'LPAREN' | 'RPAREN' | 'STATE';\n\ninterface Token {\n type: TokenType;\n value: string;\n raw: string;\n}\n\n// ============================================================================\n// Tokenizer\n// ============================================================================\n\n/**\n * Tokenize a state notation string\n */\nfunction tokenize(stateKey: string): Token[] {\n const tokens: Token[] = [];\n let match: RegExpExecArray | null;\n\n // Replace commas with | outside of parentheses (for compatibility)\n const normalized = replaceCommasOutsideParens(stateKey);\n\n STATE_TOKEN_PATTERN.lastIndex = 0;\n while ((match = STATE_TOKEN_PATTERN.exec(normalized)) !== null) {\n const fullMatch = match[0];\n\n if (match[1]) {\n // Operator: &, |, !, ^\n switch (fullMatch) {\n case '&':\n tokens.push({ type: 'AND', value: '&', raw: fullMatch });\n break;\n case '|':\n tokens.push({ type: 'OR', value: '|', raw: fullMatch });\n break;\n case '!':\n tokens.push({ type: 'NOT', value: '!', raw: fullMatch });\n break;\n case '^':\n tokens.push({ type: 'XOR', value: '^', raw: fullMatch });\n break;\n }\n } else if (match[2]) {\n // Parenthesis\n if (fullMatch === '(') {\n tokens.push({ type: 'LPAREN', value: '(', raw: fullMatch });\n } else {\n tokens.push({ type: 'RPAREN', value: ')', raw: fullMatch });\n }\n } else {\n // State token (all other capture groups)\n tokens.push({ type: 'STATE', value: fullMatch, raw: fullMatch });\n }\n }\n\n return tokens;\n}\n\n/**\n * Replace commas with | only outside of parentheses\n */\nfunction replaceCommasOutsideParens(str: string): string {\n let result = '';\n let depth = 0;\n\n for (const char of str) {\n if (char === '(') {\n depth++;\n result += char;\n } else if (char === ')') {\n depth--;\n result += char;\n } else if (char === ',' && depth === 0) {\n result += '|';\n } else {\n result += char;\n }\n }\n\n return result;\n}\n\n// ============================================================================\n// Recursive Descent Parser\n// ============================================================================\n\n/**\n * Parser state\n */\nclass Parser {\n private tokens: Token[];\n private pos = 0;\n private options: ParseStateKeyOptions;\n\n constructor(tokens: Token[], options: ParseStateKeyOptions) {\n this.tokens = tokens;\n this.options = options;\n }\n\n parse(): ConditionNode {\n if (this.tokens.length === 0) {\n return trueCondition();\n }\n const result = this.parseExpression();\n return result;\n }\n\n private current(): Token | undefined {\n return this.tokens[this.pos];\n }\n\n private advance(): Token | undefined {\n return this.tokens[this.pos++];\n }\n\n private match(type: TokenType): boolean {\n if (this.current()?.type === type) {\n this.advance();\n return true;\n }\n return false;\n }\n\n /**\n * Parse expression with operator precedence:\n * ! (NOT) > ^ (XOR) > | (OR) > & (AND)\n */\n private parseExpression(): ConditionNode {\n return this.parseAnd();\n }\n\n private parseAnd(): ConditionNode {\n let left = this.parseOr();\n\n while (this.current()?.type === 'AND') {\n this.advance();\n const right = this.parseOr();\n left = and(left, right);\n }\n\n return left;\n }\n\n private parseOr(): ConditionNode {\n let left = this.parseXor();\n\n while (this.current()?.type === 'OR') {\n this.advance();\n const right = this.parseXor();\n left = or(left, right);\n }\n\n return left;\n }\n\n private parseXor(): ConditionNode {\n let left = this.parseUnary();\n let operandCount = 1;\n\n while (this.current()?.type === 'XOR') {\n this.advance();\n const right = this.parseUnary();\n operandCount++;\n\n if (operandCount > MAX_XOR_CHAIN_LENGTH) {\n emitWarning(\n 'XOR_CHAIN_TOO_LONG',\n `XOR chain with ${operandCount} operands produces ${Math.pow(2, operandCount - 1)} OR branches. ` +\n `Consider breaking into smaller expressions to avoid exponential growth.`,\n );\n }\n\n // XOR: (A & !B) | (!A & B)\n left = or(and(left, not(right)), and(not(left), right));\n }\n\n return left;\n }\n\n private parseUnary(): ConditionNode {\n if (this.match('NOT')) {\n const operand = this.parseUnary();\n return not(operand);\n }\n return this.parsePrimary();\n }\n\n private parsePrimary(): ConditionNode {\n // Handle parentheses\n if (this.match('LPAREN')) {\n const expr = this.parseExpression();\n this.match('RPAREN'); // Consume closing paren (lenient if missing)\n return expr;\n }\n\n // Handle state tokens\n const token = this.current();\n if (token?.type === 'STATE') {\n this.advance();\n return this.parseStateToken(token.value);\n }\n\n // Fallback for empty/invalid - return TRUE\n return trueCondition();\n }\n\n /**\n * Parse a state token into a ConditionNode\n */\n private parseStateToken(value: string): ConditionNode {\n // @starting\n if (value === '@starting') {\n return createStartingCondition(false, value);\n }\n\n // @media:type (e.g., @media:print)\n if (value.startsWith('@media:')) {\n const mediaType = value.slice(7) as 'print' | 'screen' | 'all' | 'speech';\n return createMediaTypeCondition(mediaType, false, value);\n }\n\n // @media(...) - media query\n if (value.startsWith('@media(')) {\n return this.parseMediaQuery(value);\n }\n\n // @supports(...) - feature/selector support query\n if (value.startsWith('@supports(')) {\n return this.parseSupportsQuery(value);\n }\n\n // @root(...) - root state\n if (value.startsWith('@root(')) {\n return this.parseRootState(value);\n }\n\n // @parent(...) - parent element state\n if (value.startsWith('@parent(')) {\n return this.parseParentState(value);\n }\n\n // @own(...) - own state (sub-element)\n if (value.startsWith('@own(')) {\n return this.parseOwnState(value);\n }\n\n // @(...) - container query\n if (value.startsWith('@(')) {\n return this.parseContainerQuery(value);\n }\n\n // @name - predefined state\n if (value.startsWith('@') && /^@[A-Za-z][A-Za-z0-9-]*$/.test(value)) {\n return this.parsePredefinedState(value);\n }\n\n // Enhanced pseudo-classes: :is(), :has(), :not(), :where()\n // Transform capitalized words to [data-element=\"...\"] selectors,\n // auto-complete trailing combinators with *, and\n // normalize :not(X) → negated :is(X) for deduplication.\n if (value.startsWith(':')) {\n const enhancedMatch = /^:(is|has|not|where)\\(/.exec(value);\n if (enhancedMatch) {\n const fn = enhancedMatch[1];\n const prefix = enhancedMatch[0];\n let content = transformSelectorContent(value.slice(prefix.length, -1));\n\n // Auto-complete trailing combinator: :has(Icon >) → :has(... > *)\n content = content.replace(/([>+~])\\s*$/, '$1 *');\n\n if (fn === 'not') {\n return createPseudoCondition(`:is(${content})`, true, value);\n }\n\n return createPseudoCondition(`:${fn}(${content})`, false, value);\n }\n\n return createPseudoCondition(value, false, value);\n }\n\n // Class selector (e.g., .active)\n if (value.startsWith('.')) {\n return createPseudoCondition(value, false, value);\n }\n\n // Attribute selector (e.g., [disabled], [data-state=\"active\"])\n if (value.startsWith('[')) {\n return createPseudoCondition(value, false, value);\n }\n\n // Value modifier (e.g., theme=danger, size=large)\n if (value.includes('=')) {\n return this.parseValueModifier(value);\n }\n\n // Boolean modifier (e.g., hovered, disabled)\n return this.parseBooleanModifier(value);\n }\n\n /**\n * Parse @media(...) query\n */\n private parseMediaQuery(raw: string): ConditionNode {\n const content = raw.slice(7, -1); // Remove '@media(' and ')'\n if (!content.trim()) {\n return trueCondition();\n }\n\n // Expand shorthands and units\n let condition = expandDimensionShorthands(content);\n condition = expandTastyUnits(condition);\n\n // Check for feature queries (contains ':' but not dimension comparison)\n if (\n condition.includes(':') &&\n !condition.includes('<') &&\n !condition.includes('>') &&\n !condition.includes('=')\n ) {\n // Feature query: @media(prefers-contrast: high)\n const colonIdx = condition.indexOf(':');\n const feature = condition.slice(0, colonIdx).trim();\n const featureValue = condition.slice(colonIdx + 1).trim();\n return createMediaFeatureCondition(feature, featureValue, false, raw);\n }\n\n // Boolean feature query: @media(prefers-reduced-motion)\n if (\n !condition.includes('<') &&\n !condition.includes('>') &&\n !condition.includes('=')\n ) {\n return createMediaFeatureCondition(\n condition.trim(),\n undefined,\n false,\n raw,\n );\n }\n\n // Dimension query - parse bounds\n const { dimension, lowerBound, upperBound } =\n this.parseDimensionCondition(condition);\n\n if (!dimension) {\n // Fallback for unparseable - treat as pseudo\n return createPseudoCondition(raw, false, raw);\n }\n\n return createMediaDimensionCondition(\n dimension as 'width' | 'height',\n lowerBound,\n upperBound,\n false,\n raw,\n );\n }\n\n /**\n * Parse dimension condition string (e.g., \"width < 768px\", \"600px <= width < 1200px\")\n */\n private parseDimensionCondition(condition: string): {\n dimension?: string;\n lowerBound?: NumericBound;\n upperBound?: NumericBound;\n } {\n // Range syntax: \"600px <= width < 1200px\"\n const rangeMatch = condition.match(\n /^(.+?)\\s*(<=|<)\\s*(width|height|inline-size|block-size)\\s*(<=|<)\\s*(.+)$/,\n );\n if (rangeMatch) {\n const [, lowerValue, lowerOp, dimension, upperOp, upperValue] =\n rangeMatch;\n return {\n dimension,\n lowerBound: {\n value: lowerValue.trim(),\n valueNumeric: parseNumericValue(lowerValue.trim()),\n inclusive: lowerOp === '<=',\n },\n upperBound: {\n value: upperValue.trim(),\n valueNumeric: parseNumericValue(upperValue.trim()),\n inclusive: upperOp === '<=',\n },\n };\n }\n\n // Simple comparison: \"width < 768px\"\n const simpleMatch = condition.match(\n /^(width|height|inline-size|block-size)\\s*(<=|>=|<|>|=)\\s*(.+)$/,\n );\n if (simpleMatch) {\n const [, dimension, operator, value] = simpleMatch;\n const numeric = parseNumericValue(value.trim());\n\n if (operator === '<' || operator === '<=') {\n return {\n dimension,\n upperBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: operator === '<=',\n },\n };\n } else if (operator === '>' || operator === '>=') {\n return {\n dimension,\n lowerBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: operator === '>=',\n },\n };\n } else if (operator === '=') {\n // Exact match: both bounds are the same and inclusive\n return {\n dimension,\n lowerBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: true,\n },\n upperBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: true,\n },\n };\n }\n }\n\n // Reversed: \"768px > width\"\n const reversedMatch = condition.match(\n /^(.+?)\\s*(<=|>=|<|>|=)\\s*(width|height|inline-size|block-size)$/,\n );\n if (reversedMatch) {\n const [, value, operator, dimension] = reversedMatch;\n const numeric = parseNumericValue(value.trim());\n\n // Reverse the operator\n if (operator === '<' || operator === '<=') {\n return {\n dimension,\n lowerBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: operator === '<=',\n },\n };\n } else if (operator === '>' || operator === '>=') {\n return {\n dimension,\n upperBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: operator === '>=',\n },\n };\n }\n }\n\n return {};\n }\n\n /**\n * Parse @root(...) state\n */\n private parseInnerCondition(\n raw: string,\n prefixLen: number,\n wrap: (inner: ConditionNode) => ConditionNode,\n ): ConditionNode {\n const content = raw.slice(prefixLen, -1);\n if (!content.trim()) return trueCondition();\n return wrap(parseStateKey(content, this.options));\n }\n\n private parseRootState(raw: string): ConditionNode {\n return this.parseInnerCondition(raw, 6, (inner) =>\n createRootCondition(inner, false, raw),\n );\n }\n\n /**\n * Parse @parent(...) state\n *\n * Syntax:\n * @parent(hovered) → :is([data-hovered] *)\n * @parent(theme=dark) → :is([data-theme=\"dark\"] *)\n * @parent(hovered, >) → :is([data-hovered] > *) (direct parent)\n * @parent(.my-class) → :is(.my-class *)\n */\n private parseParentState(raw: string): ConditionNode {\n const content = raw.slice(8, -1);\n if (!content.trim()) {\n return trueCondition();\n }\n\n let condition = content.trim();\n let direct = false;\n\n const lastCommaIdx = condition.lastIndexOf(',');\n if (lastCommaIdx !== -1) {\n const afterComma = condition.slice(lastCommaIdx + 1).trim();\n if (afterComma === '>') {\n direct = true;\n condition = condition.slice(0, lastCommaIdx).trim();\n }\n }\n\n const innerCondition = parseStateKey(condition, this.options);\n return createParentCondition(innerCondition, direct, false, raw);\n }\n\n /**\n * Parse @supports(...) query\n *\n * Syntax:\n * @supports(display: grid) → @supports (display: grid)\n * @supports($, :has(*)) → @supports selector(:has(*))\n */\n private parseSupportsQuery(raw: string): ConditionNode {\n const content = raw.slice(10, -1); // Remove '@supports(' and ')'\n if (!content.trim()) {\n return trueCondition();\n }\n\n // Check for selector syntax: @supports($, :has(*))\n if (content.startsWith('$,')) {\n const selector = content.slice(2).trim(); // Remove '$,' prefix\n return createSupportsCondition('selector', selector, false, raw);\n }\n\n // Feature syntax: @supports(display: grid)\n return createSupportsCondition('feature', content, false, raw);\n }\n\n private parseOwnState(raw: string): ConditionNode {\n return this.parseInnerCondition(raw, 5, (inner) =>\n createOwnCondition(inner, false, raw),\n );\n }\n\n /**\n * Parse @(...) container query\n */\n private parseContainerQuery(raw: string): ConditionNode {\n const content = raw.slice(2, -1); // Remove '@(' and ')'\n if (!content.trim()) {\n return trueCondition();\n }\n\n // Check for named container: @(layout, w < 600px)\n // Use parentheses-aware comma search so inner commas (e.g., scroll-state(a, b)) are skipped\n const commaIdx = findTopLevelComma(content);\n let containerName: string | undefined;\n let condition: string;\n\n if (commaIdx !== -1) {\n containerName = content.slice(0, commaIdx).trim();\n condition = content.slice(commaIdx + 1).trim();\n } else {\n condition = content.trim();\n }\n\n // Check for style query shorthand: @($variant=primary)\n if (condition.startsWith('$')) {\n const styleQuery = condition.slice(1); // Remove '$'\n const eqIdx = styleQuery.indexOf('=');\n\n if (eqIdx === -1) {\n // Existence check: @($variant)\n return createContainerStyleCondition(\n styleQuery,\n undefined,\n containerName,\n false,\n raw,\n );\n }\n\n const property = styleQuery.slice(0, eqIdx).trim();\n let propertyValue = styleQuery.slice(eqIdx + 1).trim();\n\n // Remove quotes if present\n if (\n (propertyValue.startsWith('\"') && propertyValue.endsWith('\"')) ||\n (propertyValue.startsWith(\"'\") && propertyValue.endsWith(\"'\"))\n ) {\n propertyValue = propertyValue.slice(1, -1);\n }\n\n return createContainerStyleCondition(\n property,\n propertyValue,\n containerName,\n false,\n raw,\n );\n }\n\n // Check for function-like syntax: scroll-state(...), style(...), etc.\n // Passes the condition through to CSS verbatim.\n if (/^[a-zA-Z][\\w-]*\\s*\\(/.test(condition)) {\n return createContainerRawCondition(condition, containerName, false, raw);\n }\n\n // Dimension query\n let expandedCondition = expandDimensionShorthands(condition);\n expandedCondition = expandTastyUnits(expandedCondition);\n\n const { dimension, lowerBound, upperBound } =\n this.parseDimensionCondition(expandedCondition);\n\n if (!dimension) {\n // Fallback\n return createPseudoCondition(raw, false, raw);\n }\n\n return createContainerDimensionCondition(\n dimension as 'width' | 'height',\n lowerBound,\n upperBound,\n containerName,\n false,\n raw,\n );\n }\n\n /**\n * Parse predefined state (@mobile, @dark, etc.)\n */\n private parsePredefinedState(raw: string): ConditionNode {\n const ctx = this.options.context;\n if (!ctx) {\n // No context - can't resolve predefined states\n return createPseudoCondition(raw, false, raw);\n }\n\n const resolved = resolvePredefinedState(raw, ctx);\n if (!resolved) {\n // Undefined predefined state - treat as modifier\n return createModifierCondition(\n `data-${camelToKebab(raw.slice(1))}`,\n undefined,\n '=',\n false,\n raw,\n );\n }\n\n // Parse the resolved value recursively\n return parseStateKey(resolved, this.options);\n }\n\n /**\n * Parse value modifier (e.g., theme=danger, size^=sm)\n */\n private parseValueModifier(raw: string): ConditionNode {\n // Match operators: =, ^=, $=, *=\n const opMatch = raw.match(/^([a-z][a-z0-9-]*)(\\^=|\\$=|\\*=|=)(.+)$/i);\n if (!opMatch) {\n return createModifierCondition(\n `data-${camelToKebab(raw)}`,\n undefined,\n '=',\n false,\n raw,\n );\n }\n\n const [, key, operator, value] = opMatch;\n let cleanValue = value;\n\n // Remove quotes if present\n if (\n (cleanValue.startsWith('\"') && cleanValue.endsWith('\"')) ||\n (cleanValue.startsWith(\"'\") && cleanValue.endsWith(\"'\"))\n ) {\n cleanValue = cleanValue.slice(1, -1);\n }\n\n return createModifierCondition(\n `data-${camelToKebab(key)}`,\n cleanValue,\n operator as '=' | '^=' | '$=' | '*=',\n false,\n raw,\n );\n }\n\n /**\n * Parse boolean modifier (e.g., hovered, disabled)\n */\n private parseBooleanModifier(raw: string): ConditionNode {\n return createModifierCondition(\n `data-${camelToKebab(raw)}`,\n undefined,\n '=',\n false,\n raw,\n );\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Parse a numeric value from a CSS value string\n */\nfunction parseNumericValue(value: string): number | null {\n const match = value.match(/^(\\d+(?:\\.\\d+)?)(px|em|rem|vh|vw|%)?$/);\n if (match) {\n return parseFloat(match[1]);\n }\n return null;\n}\n\n// ============================================================================\n// Main Export\n// ============================================================================\n\n/**\n * Parse a state key string into a ConditionNode\n */\nexport function parseStateKey(\n stateKey: string,\n options: ParseStateKeyOptions = {},\n): ConditionNode {\n // Handle empty/default state\n if (!stateKey || !stateKey.trim()) {\n return trueCondition();\n }\n\n const trimmed = stateKey.trim();\n\n // Build cache key including local predefined states (they affect parsing)\n // Global predefined states are set once at initialization and don't change\n const ctx = options.context;\n const localStatesKey =\n ctx && Object.keys(ctx.localPredefinedStates).length > 0\n ? JSON.stringify(ctx.localPredefinedStates)\n : '';\n const cacheKey =\n trimmed + '\\0' + (options.isSubElement ? '1' : '0') + '\\0' + localStatesKey;\n\n // Check cache\n const cached = parseCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n\n // Tokenize and parse\n const tokens = tokenize(trimmed);\n const parser = new Parser(tokens, options);\n const result = parser.parse();\n\n // Cache result\n parseCache.set(cacheKey, result);\n\n return result;\n}\n\n/**\n * Clear the parse cache (for testing)\n */\nexport function clearParseCache(): void {\n parseCache.clear();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"parseStateKey.js","names":[],"sources":["../../src/pipeline/parseStateKey.ts"],"sourcesContent":["/**\n * State Key Parser\n *\n * Parses state notation strings (like 'hovered & !disabled', '@media(w < 768px)')\n * into ConditionNode trees for processing in the pipeline.\n */\n\nimport { Lru } from '../parser/lru';\nimport type { StateParserContext } from '../states';\nimport {\n expandDimensionShorthands,\n expandTastyUnits,\n findTopLevelComma,\n resolvePredefinedState,\n} from '../states';\nimport { camelToKebab } from '../utils/case-converter';\nimport { transformSelectorContent } from '../utils/selector-transform';\n\nimport type { ConditionNode, NumericBound } from './conditions';\nimport { emitWarning } from './warnings';\nimport {\n and,\n createContainerDimensionCondition,\n createContainerRawCondition,\n createContainerStyleCondition,\n createMediaDimensionCondition,\n createMediaFeatureCondition,\n createMediaTypeCondition,\n createModifierCondition,\n createOwnCondition,\n createParentCondition,\n createPseudoCondition,\n createRootCondition,\n createStartingCondition,\n createSupportsCondition,\n not,\n or,\n trueCondition,\n} from './conditions';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Maximum XOR operands before emitting a performance warning.\n * A ^ B ^ C ^ D = 8 OR branches (2^(n-1)), so chains above 4\n * risk exponential blowup in downstream processing.\n */\nconst MAX_XOR_CHAIN_LENGTH = 4;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ParseStateKeyOptions {\n context?: StateParserContext;\n isSubElement?: boolean;\n}\n\n// ============================================================================\n// Caching\n// ============================================================================\n\n// Cache for parsed state keys (key -> ConditionNode)\nconst parseCache = new Lru<string, ConditionNode>(5000);\n\n// ============================================================================\n// Tokenizer Patterns\n// ============================================================================\n\n/**\n * Pattern for tokenizing state notation.\n * Matches: operators, parentheses, @-prefixed states, value mods, boolean mods,\n * pseudo-classes, class selectors, and attribute selectors.\n *\n * All @-prefixed state groups (@supports, @root, @parent, @own, @(...))\n * and :is/:has/:not/:where pseudo-classes support up to 2 levels of\n * nested parentheses via:\n * [^()]*(?:\\([^()]*(?:\\([^)]*\\))?[^)]*\\))*[^)]*\n */\nconst STATE_TOKEN_PATTERN =\n /([&|!^])|([()])|(@media:[a-z]+)|(@media\\([^)]+\\))|(@supports\\([^()]*(?:\\([^()]*(?:\\([^)]*\\))?[^)]*\\))*[^)]*\\))|(@root\\([^()]*(?:\\([^()]*(?:\\([^)]*\\))?[^)]*\\))*[^)]*\\))|(@parent\\([^()]*(?:\\([^()]*(?:\\([^)]*\\))?[^)]*\\))*[^)]*\\))|(@own\\([^()]*(?:\\([^()]*(?:\\([^)]*\\))?[^)]*\\))*[^)]*\\))|(@\\([^()]*(?:\\([^()]*(?:\\([^)]*\\))?[^)]*\\))*[^)]*\\))|(@starting)|(@[A-Za-z][A-Za-z0-9-]*)|([a-z][a-z0-9-]*(?:\\^=|\\$=|\\*=|=)(?:\"[^\"]*\"|'[^']*'|[^\\s&|!^()]+))|([a-z][a-z0-9-]+)|(:(?:is|has|not|where)\\([^()]*(?:\\([^()]*(?:\\([^)]*\\))?[^)]*\\))*[^)]*\\))|(:[-a-z][a-z0-9-]*(?:\\([^)]+\\))?)|(\\.[a-z][a-z0-9-]+)|(\\[[^\\]]+\\])/gi;\n\n// ============================================================================\n// Token Types\n// ============================================================================\n\ntype TokenType = 'AND' | 'OR' | 'NOT' | 'XOR' | 'LPAREN' | 'RPAREN' | 'STATE';\n\ninterface Token {\n type: TokenType;\n value: string;\n raw: string;\n}\n\n// ============================================================================\n// Tokenizer\n// ============================================================================\n\n/**\n * Tokenize a state notation string\n */\nfunction tokenize(stateKey: string): Token[] {\n const tokens: Token[] = [];\n let match: RegExpExecArray | null;\n\n // Replace commas with | outside of parentheses (for compatibility)\n const normalized = replaceCommasOutsideParens(stateKey);\n\n STATE_TOKEN_PATTERN.lastIndex = 0;\n while ((match = STATE_TOKEN_PATTERN.exec(normalized)) !== null) {\n const fullMatch = match[0];\n\n if (match[1]) {\n // Operator: &, |, !, ^\n switch (fullMatch) {\n case '&':\n tokens.push({ type: 'AND', value: '&', raw: fullMatch });\n break;\n case '|':\n tokens.push({ type: 'OR', value: '|', raw: fullMatch });\n break;\n case '!':\n tokens.push({ type: 'NOT', value: '!', raw: fullMatch });\n break;\n case '^':\n tokens.push({ type: 'XOR', value: '^', raw: fullMatch });\n break;\n }\n } else if (match[2]) {\n // Parenthesis\n if (fullMatch === '(') {\n tokens.push({ type: 'LPAREN', value: '(', raw: fullMatch });\n } else {\n tokens.push({ type: 'RPAREN', value: ')', raw: fullMatch });\n }\n } else {\n // State token (all other capture groups)\n tokens.push({ type: 'STATE', value: fullMatch, raw: fullMatch });\n }\n }\n\n return tokens;\n}\n\n/**\n * Replace commas with | only outside of parentheses\n */\nfunction replaceCommasOutsideParens(str: string): string {\n let result = '';\n let depth = 0;\n\n for (const char of str) {\n if (char === '(') {\n depth++;\n result += char;\n } else if (char === ')') {\n depth--;\n result += char;\n } else if (char === ',' && depth === 0) {\n result += '|';\n } else {\n result += char;\n }\n }\n\n return result;\n}\n\n// ============================================================================\n// Recursive Descent Parser\n// ============================================================================\n\n/**\n * Parser state\n */\nclass Parser {\n private tokens: Token[];\n private pos = 0;\n private options: ParseStateKeyOptions;\n\n constructor(tokens: Token[], options: ParseStateKeyOptions) {\n this.tokens = tokens;\n this.options = options;\n }\n\n parse(): ConditionNode {\n if (this.tokens.length === 0) {\n return trueCondition();\n }\n const result = this.parseExpression();\n return result;\n }\n\n private current(): Token | undefined {\n return this.tokens[this.pos];\n }\n\n private advance(): Token | undefined {\n return this.tokens[this.pos++];\n }\n\n private match(type: TokenType): boolean {\n if (this.current()?.type === type) {\n this.advance();\n return true;\n }\n return false;\n }\n\n /**\n * Parse expression with operator precedence:\n * ! (NOT) > ^ (XOR) > | (OR) > & (AND)\n */\n private parseExpression(): ConditionNode {\n return this.parseAnd();\n }\n\n private parseAnd(): ConditionNode {\n let left = this.parseOr();\n\n while (this.current()?.type === 'AND') {\n this.advance();\n const right = this.parseOr();\n left = and(left, right);\n }\n\n return left;\n }\n\n private parseOr(): ConditionNode {\n let left = this.parseXor();\n\n while (this.current()?.type === 'OR') {\n this.advance();\n const right = this.parseXor();\n left = or(left, right);\n }\n\n return left;\n }\n\n private parseXor(): ConditionNode {\n let left = this.parseUnary();\n let operandCount = 1;\n\n while (this.current()?.type === 'XOR') {\n this.advance();\n const right = this.parseUnary();\n operandCount++;\n\n if (operandCount > MAX_XOR_CHAIN_LENGTH) {\n emitWarning(\n 'XOR_CHAIN_TOO_LONG',\n `XOR chain with ${operandCount} operands produces ${Math.pow(2, operandCount - 1)} OR branches. ` +\n `Consider breaking into smaller expressions to avoid exponential growth.`,\n );\n }\n\n // XOR: (A & !B) | (!A & B)\n left = or(and(left, not(right)), and(not(left), right));\n }\n\n return left;\n }\n\n private parseUnary(): ConditionNode {\n if (this.match('NOT')) {\n const operand = this.parseUnary();\n return not(operand);\n }\n return this.parsePrimary();\n }\n\n private parsePrimary(): ConditionNode {\n // Handle parentheses\n if (this.match('LPAREN')) {\n const expr = this.parseExpression();\n this.match('RPAREN'); // Consume closing paren (lenient if missing)\n return expr;\n }\n\n // Handle state tokens\n const token = this.current();\n if (token?.type === 'STATE') {\n this.advance();\n return this.parseStateToken(token.value);\n }\n\n // Fallback for empty/invalid - return TRUE\n return trueCondition();\n }\n\n /**\n * Parse a state token into a ConditionNode\n */\n private parseStateToken(value: string): ConditionNode {\n // @starting\n if (value === '@starting') {\n return createStartingCondition(false, value);\n }\n\n // @media:type (e.g., @media:print)\n if (value.startsWith('@media:')) {\n const mediaType = value.slice(7) as 'print' | 'screen' | 'all' | 'speech';\n return createMediaTypeCondition(mediaType, false, value);\n }\n\n // @media(...) - media query\n if (value.startsWith('@media(')) {\n return this.parseMediaQuery(value);\n }\n\n // @supports(...) - feature/selector support query\n if (value.startsWith('@supports(')) {\n return this.parseSupportsQuery(value);\n }\n\n // @root(...) - root state\n if (value.startsWith('@root(')) {\n return this.parseRootState(value);\n }\n\n // @parent(...) - parent element state\n if (value.startsWith('@parent(')) {\n return this.parseParentState(value);\n }\n\n // @own(...) - own state (sub-element)\n if (value.startsWith('@own(')) {\n return this.parseOwnState(value);\n }\n\n // @(...) - container query\n if (value.startsWith('@(')) {\n return this.parseContainerQuery(value);\n }\n\n // @name - predefined state\n if (value.startsWith('@') && /^@[A-Za-z][A-Za-z0-9-]*$/.test(value)) {\n return this.parsePredefinedState(value);\n }\n\n // Enhanced pseudo-classes: :is(), :has(), :not(), :where()\n // Transform capitalized words to [data-element=\"...\"] selectors,\n // auto-complete trailing combinators with *, and\n // normalize :not(X) → negated :is(X) for deduplication.\n if (value.startsWith(':')) {\n const enhancedMatch = /^:(is|has|not|where)\\(/.exec(value);\n if (enhancedMatch) {\n const fn = enhancedMatch[1];\n const prefix = enhancedMatch[0];\n let content = transformSelectorContent(value.slice(prefix.length, -1));\n\n // Auto-complete trailing combinator: :has(Icon >) → :has(... > *)\n content = content.replace(/([>+~])\\s*$/, '$1 *');\n\n if (fn === 'not') {\n return createPseudoCondition(`:is(${content})`, true, value);\n }\n\n return createPseudoCondition(`:${fn}(${content})`, false, value);\n }\n\n return createPseudoCondition(value, false, value);\n }\n\n // Class selector (e.g., .active)\n if (value.startsWith('.')) {\n return createPseudoCondition(value, false, value);\n }\n\n // Attribute selector (e.g., [disabled], [data-state=\"active\"])\n if (value.startsWith('[')) {\n return createPseudoCondition(value, false, value);\n }\n\n // Value modifier (e.g., theme=danger, size=large)\n if (value.includes('=')) {\n return this.parseValueModifier(value);\n }\n\n // Boolean modifier (e.g., hovered, disabled)\n return this.parseBooleanModifier(value);\n }\n\n /**\n * Parse @media(...) query\n */\n private parseMediaQuery(raw: string): ConditionNode {\n const content = raw.slice(7, -1); // Remove '@media(' and ')'\n if (!content.trim()) {\n return trueCondition();\n }\n\n // Expand shorthands and units\n let condition = expandDimensionShorthands(content);\n condition = expandTastyUnits(condition);\n\n // Check for feature queries (contains ':' but not dimension comparison)\n if (\n condition.includes(':') &&\n !condition.includes('<') &&\n !condition.includes('>') &&\n !condition.includes('=')\n ) {\n // Feature query: @media(prefers-contrast: high)\n const colonIdx = condition.indexOf(':');\n const feature = condition.slice(0, colonIdx).trim();\n const featureValue = condition.slice(colonIdx + 1).trim();\n return createMediaFeatureCondition(feature, featureValue, false, raw);\n }\n\n // Boolean feature query: @media(prefers-reduced-motion)\n if (\n !condition.includes('<') &&\n !condition.includes('>') &&\n !condition.includes('=')\n ) {\n return createMediaFeatureCondition(\n condition.trim(),\n undefined,\n false,\n raw,\n );\n }\n\n // Dimension query - parse bounds\n const { dimension, lowerBound, upperBound } =\n this.parseDimensionCondition(condition);\n\n if (!dimension) {\n // Fallback for unparseable - treat as pseudo\n return createPseudoCondition(raw, false, raw);\n }\n\n return createMediaDimensionCondition(\n dimension as 'width' | 'height',\n lowerBound,\n upperBound,\n false,\n raw,\n );\n }\n\n /**\n * Parse dimension condition string (e.g., \"width < 768px\", \"600px <= width < 1200px\")\n */\n private parseDimensionCondition(condition: string): {\n dimension?: string;\n lowerBound?: NumericBound;\n upperBound?: NumericBound;\n } {\n // Range syntax: \"600px <= width < 1200px\"\n const rangeMatch = condition.match(\n /^(.+?)\\s*(<=|<)\\s*(width|height|inline-size|block-size)\\s*(<=|<)\\s*(.+)$/,\n );\n if (rangeMatch) {\n const [, lowerValue, lowerOp, dimension, upperOp, upperValue] =\n rangeMatch;\n return {\n dimension,\n lowerBound: {\n value: lowerValue.trim(),\n valueNumeric: parseNumericValue(lowerValue.trim()),\n inclusive: lowerOp === '<=',\n },\n upperBound: {\n value: upperValue.trim(),\n valueNumeric: parseNumericValue(upperValue.trim()),\n inclusive: upperOp === '<=',\n },\n };\n }\n\n // Simple comparison: \"width < 768px\"\n const simpleMatch = condition.match(\n /^(width|height|inline-size|block-size)\\s*(<=|>=|<|>|=)\\s*(.+)$/,\n );\n if (simpleMatch) {\n const [, dimension, operator, value] = simpleMatch;\n const numeric = parseNumericValue(value.trim());\n\n if (operator === '<' || operator === '<=') {\n return {\n dimension,\n upperBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: operator === '<=',\n },\n };\n } else if (operator === '>' || operator === '>=') {\n return {\n dimension,\n lowerBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: operator === '>=',\n },\n };\n } else if (operator === '=') {\n // Exact match: both bounds are the same and inclusive\n return {\n dimension,\n lowerBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: true,\n },\n upperBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: true,\n },\n };\n }\n }\n\n // Reversed: \"768px > width\"\n const reversedMatch = condition.match(\n /^(.+?)\\s*(<=|>=|<|>|=)\\s*(width|height|inline-size|block-size)$/,\n );\n if (reversedMatch) {\n const [, value, operator, dimension] = reversedMatch;\n const numeric = parseNumericValue(value.trim());\n\n // Reverse the operator\n if (operator === '<' || operator === '<=') {\n return {\n dimension,\n lowerBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: operator === '<=',\n },\n };\n } else if (operator === '>' || operator === '>=') {\n return {\n dimension,\n upperBound: {\n value: value.trim(),\n valueNumeric: numeric,\n inclusive: operator === '>=',\n },\n };\n }\n }\n\n return {};\n }\n\n /**\n * Parse @root(...) state\n */\n private parseInnerCondition(\n raw: string,\n prefixLen: number,\n wrap: (inner: ConditionNode) => ConditionNode,\n ): ConditionNode {\n const content = raw.slice(prefixLen, -1);\n if (!content.trim()) return trueCondition();\n return wrap(parseStateKey(content, this.options));\n }\n\n private parseRootState(raw: string): ConditionNode {\n return this.parseInnerCondition(raw, 6, (inner) =>\n createRootCondition(inner, false, raw),\n );\n }\n\n /**\n * Parse @parent(...) state\n *\n * Syntax:\n * @parent(hovered) → :is([data-hovered] *)\n * @parent(theme=dark) → :is([data-theme=\"dark\"] *)\n * @parent(hovered, >) → :is([data-hovered] > *) (direct parent)\n * @parent(.my-class) → :is(.my-class *)\n */\n private parseParentState(raw: string): ConditionNode {\n const content = raw.slice(8, -1);\n if (!content.trim()) {\n return trueCondition();\n }\n\n let condition = content.trim();\n let direct = false;\n\n const lastCommaIdx = condition.lastIndexOf(',');\n if (lastCommaIdx !== -1) {\n const afterComma = condition.slice(lastCommaIdx + 1).trim();\n if (afterComma === '>') {\n direct = true;\n condition = condition.slice(0, lastCommaIdx).trim();\n }\n }\n\n const innerCondition = parseStateKey(condition, this.options);\n return createParentCondition(innerCondition, direct, false, raw);\n }\n\n /**\n * Parse @supports(...) query\n *\n * Syntax:\n * @supports(display: grid) → @supports (display: grid)\n * @supports($, :has(*)) → @supports selector(:has(*))\n */\n private parseSupportsQuery(raw: string): ConditionNode {\n const content = raw.slice(10, -1); // Remove '@supports(' and ')'\n if (!content.trim()) {\n return trueCondition();\n }\n\n // Check for selector syntax: @supports($, :has(*))\n if (content.startsWith('$,')) {\n const selector = content.slice(2).trim(); // Remove '$,' prefix\n return createSupportsCondition('selector', selector, false, raw);\n }\n\n // Feature syntax: @supports(display: grid)\n return createSupportsCondition('feature', content, false, raw);\n }\n\n private parseOwnState(raw: string): ConditionNode {\n return this.parseInnerCondition(raw, 5, (inner) =>\n createOwnCondition(inner, false, raw),\n );\n }\n\n /**\n * Parse @(...) container query\n */\n private parseContainerQuery(raw: string): ConditionNode {\n const content = raw.slice(2, -1); // Remove '@(' and ')'\n if (!content.trim()) {\n return trueCondition();\n }\n\n // Check for named container: @(layout, w < 600px)\n // Use parentheses-aware comma search so inner commas (e.g., scroll-state(a, b)) are skipped\n const commaIdx = findTopLevelComma(content);\n let containerName: string | undefined;\n let condition: string;\n\n if (commaIdx !== -1) {\n containerName = content.slice(0, commaIdx).trim();\n condition = content.slice(commaIdx + 1).trim();\n } else {\n condition = content.trim();\n }\n\n // Check for style query shorthand: @($variant=primary)\n if (condition.startsWith('$')) {\n const styleQuery = condition.slice(1); // Remove '$'\n const eqIdx = styleQuery.indexOf('=');\n\n if (eqIdx === -1) {\n // Existence check: @($variant)\n return createContainerStyleCondition(\n styleQuery,\n undefined,\n containerName,\n false,\n raw,\n );\n }\n\n const property = styleQuery.slice(0, eqIdx).trim();\n let propertyValue = styleQuery.slice(eqIdx + 1).trim();\n\n // Remove quotes if present\n if (\n (propertyValue.startsWith('\"') && propertyValue.endsWith('\"')) ||\n (propertyValue.startsWith(\"'\") && propertyValue.endsWith(\"'\"))\n ) {\n propertyValue = propertyValue.slice(1, -1);\n }\n\n return createContainerStyleCondition(\n property,\n propertyValue,\n containerName,\n false,\n raw,\n );\n }\n\n // Check for function-like syntax: scroll-state(...), style(...), etc.\n // Passes the condition through to CSS verbatim.\n if (/^[a-zA-Z][\\w-]*\\s*\\(/.test(condition)) {\n return createContainerRawCondition(condition, containerName, false, raw);\n }\n\n // Dimension query\n let expandedCondition = expandDimensionShorthands(condition);\n expandedCondition = expandTastyUnits(expandedCondition);\n\n const { dimension, lowerBound, upperBound } =\n this.parseDimensionCondition(expandedCondition);\n\n if (!dimension) {\n // Fallback\n return createPseudoCondition(raw, false, raw);\n }\n\n return createContainerDimensionCondition(\n dimension as 'width' | 'height',\n lowerBound,\n upperBound,\n containerName,\n false,\n raw,\n );\n }\n\n /**\n * Parse predefined state (@mobile, @dark, etc.)\n */\n private parsePredefinedState(raw: string): ConditionNode {\n const ctx = this.options.context;\n if (!ctx) {\n // No context - can't resolve predefined states\n return createPseudoCondition(raw, false, raw);\n }\n\n const resolved = resolvePredefinedState(raw, ctx);\n if (!resolved) {\n // Undefined predefined state - treat as modifier\n return createModifierCondition(\n `data-${camelToKebab(raw.slice(1))}`,\n undefined,\n '=',\n false,\n raw,\n );\n }\n\n // Parse the resolved value recursively\n return parseStateKey(resolved, this.options);\n }\n\n /**\n * Parse value modifier (e.g., theme=danger, size^=sm)\n */\n private parseValueModifier(raw: string): ConditionNode {\n // Match operators: =, ^=, $=, *=\n const opMatch = raw.match(/^([a-z][a-z0-9-]*)(\\^=|\\$=|\\*=|=)(.+)$/i);\n if (!opMatch) {\n return createModifierCondition(\n `data-${camelToKebab(raw)}`,\n undefined,\n '=',\n false,\n raw,\n );\n }\n\n const [, key, operator, value] = opMatch;\n let cleanValue = value;\n\n // Remove quotes if present\n if (\n (cleanValue.startsWith('\"') && cleanValue.endsWith('\"')) ||\n (cleanValue.startsWith(\"'\") && cleanValue.endsWith(\"'\"))\n ) {\n cleanValue = cleanValue.slice(1, -1);\n }\n\n return createModifierCondition(\n `data-${camelToKebab(key)}`,\n cleanValue,\n operator as '=' | '^=' | '$=' | '*=',\n false,\n raw,\n );\n }\n\n /**\n * Parse boolean modifier (e.g., hovered, disabled)\n */\n private parseBooleanModifier(raw: string): ConditionNode {\n return createModifierCondition(\n `data-${camelToKebab(raw)}`,\n undefined,\n '=',\n false,\n raw,\n );\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Parse a numeric value from a CSS value string\n */\nfunction parseNumericValue(value: string): number | null {\n const match = value.match(/^(\\d+(?:\\.\\d+)?)(px|em|rem|vh|vw|%)?$/);\n if (match) {\n return parseFloat(match[1]);\n }\n return null;\n}\n\n// ============================================================================\n// Main Export\n// ============================================================================\n\n/**\n * Parse a state key string into a ConditionNode\n */\nexport function parseStateKey(\n stateKey: string,\n options: ParseStateKeyOptions = {},\n): ConditionNode {\n // Handle empty/default state\n if (!stateKey || !stateKey.trim()) {\n return trueCondition();\n }\n\n const trimmed = stateKey.trim();\n\n // Build cache key including local predefined states (they affect parsing)\n // Global predefined states are set once at initialization and don't change\n const ctx = options.context;\n const localStatesKey =\n ctx && Object.keys(ctx.localPredefinedStates).length > 0\n ? JSON.stringify(ctx.localPredefinedStates)\n : '';\n const cacheKey =\n trimmed + '\\0' + (options.isSubElement ? '1' : '0') + '\\0' + localStatesKey;\n\n // Check cache\n const cached = parseCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n\n // Tokenize and parse\n const tokens = tokenize(trimmed);\n const parser = new Parser(tokens, options);\n const result = parser.parse();\n\n // Cache result\n parseCache.set(cacheKey, result);\n\n return result;\n}\n\n/**\n * Clear the parse cache (for testing)\n */\nexport function clearParseCache(): void {\n parseCache.clear();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiDA,MAAM,uBAAuB;AAgB7B,MAAM,aAAa,IAAI,IAA2B,IAAK;;;;;;;;;;;AAgBvD,MAAM,sBACJ;;;;AAqBF,SAAS,SAAS,UAA2B;CAC3C,MAAM,SAAkB,EAAE;CAC1B,IAAI;CAGJ,MAAM,aAAa,2BAA2B,SAAS;AAEvD,qBAAoB,YAAY;AAChC,SAAQ,QAAQ,oBAAoB,KAAK,WAAW,MAAM,MAAM;EAC9D,MAAM,YAAY,MAAM;AAExB,MAAI,MAAM,GAER,SAAQ,WAAR;GACE,KAAK;AACH,WAAO,KAAK;KAAE,MAAM;KAAO,OAAO;KAAK,KAAK;KAAW,CAAC;AACxD;GACF,KAAK;AACH,WAAO,KAAK;KAAE,MAAM;KAAM,OAAO;KAAK,KAAK;KAAW,CAAC;AACvD;GACF,KAAK;AACH,WAAO,KAAK;KAAE,MAAM;KAAO,OAAO;KAAK,KAAK;KAAW,CAAC;AACxD;GACF,KAAK;AACH,WAAO,KAAK;KAAE,MAAM;KAAO,OAAO;KAAK,KAAK;KAAW,CAAC;AACxD;;WAEK,MAAM,GAEf,KAAI,cAAc,IAChB,QAAO,KAAK;GAAE,MAAM;GAAU,OAAO;GAAK,KAAK;GAAW,CAAC;MAE3D,QAAO,KAAK;GAAE,MAAM;GAAU,OAAO;GAAK,KAAK;GAAW,CAAC;MAI7D,QAAO,KAAK;GAAE,MAAM;GAAS,OAAO;GAAW,KAAK;GAAW,CAAC;;AAIpE,QAAO;;;;;AAMT,SAAS,2BAA2B,KAAqB;CACvD,IAAI,SAAS;CACb,IAAI,QAAQ;AAEZ,MAAK,MAAM,QAAQ,IACjB,KAAI,SAAS,KAAK;AAChB;AACA,YAAU;YACD,SAAS,KAAK;AACvB;AACA,YAAU;YACD,SAAS,OAAO,UAAU,EACnC,WAAU;KAEV,WAAU;AAId,QAAO;;;;;AAUT,IAAM,SAAN,MAAa;CACX;CACA,MAAc;CACd;CAEA,YAAY,QAAiB,SAA+B;AAC1D,OAAK,SAAS;AACd,OAAK,UAAU;;CAGjB,QAAuB;AACrB,MAAI,KAAK,OAAO,WAAW,EACzB,QAAO,eAAe;AAGxB,SADe,KAAK,iBAAiB;;CAIvC,UAAqC;AACnC,SAAO,KAAK,OAAO,KAAK;;CAG1B,UAAqC;AACnC,SAAO,KAAK,OAAO,KAAK;;CAG1B,MAAc,MAA0B;AACtC,MAAI,KAAK,SAAS,EAAE,SAAS,MAAM;AACjC,QAAK,SAAS;AACd,UAAO;;AAET,SAAO;;;;;;CAOT,kBAAyC;AACvC,SAAO,KAAK,UAAU;;CAGxB,WAAkC;EAChC,IAAI,OAAO,KAAK,SAAS;AAEzB,SAAO,KAAK,SAAS,EAAE,SAAS,OAAO;AACrC,QAAK,SAAS;GACd,MAAM,QAAQ,KAAK,SAAS;AAC5B,UAAO,IAAI,MAAM,MAAM;;AAGzB,SAAO;;CAGT,UAAiC;EAC/B,IAAI,OAAO,KAAK,UAAU;AAE1B,SAAO,KAAK,SAAS,EAAE,SAAS,MAAM;AACpC,QAAK,SAAS;GACd,MAAM,QAAQ,KAAK,UAAU;AAC7B,UAAO,GAAG,MAAM,MAAM;;AAGxB,SAAO;;CAGT,WAAkC;EAChC,IAAI,OAAO,KAAK,YAAY;EAC5B,IAAI,eAAe;AAEnB,SAAO,KAAK,SAAS,EAAE,SAAS,OAAO;AACrC,QAAK,SAAS;GACd,MAAM,QAAQ,KAAK,YAAY;AAC/B;AAEA,OAAI,eAAe,qBACjB,aACE,sBACA,kBAAkB,aAAa,qBAAqB,KAAK,IAAI,GAAG,eAAe,EAAE,CAAC,uFAEnF;AAIH,UAAO,GAAG,IAAI,MAAM,IAAI,MAAM,CAAC,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,CAAC;;AAGzD,SAAO;;CAGT,aAAoC;AAClC,MAAI,KAAK,MAAM,MAAM,CAEnB,QAAO,IADS,KAAK,YAAY,CACd;AAErB,SAAO,KAAK,cAAc;;CAG5B,eAAsC;AAEpC,MAAI,KAAK,MAAM,SAAS,EAAE;GACxB,MAAM,OAAO,KAAK,iBAAiB;AACnC,QAAK,MAAM,SAAS;AACpB,UAAO;;EAIT,MAAM,QAAQ,KAAK,SAAS;AAC5B,MAAI,OAAO,SAAS,SAAS;AAC3B,QAAK,SAAS;AACd,UAAO,KAAK,gBAAgB,MAAM,MAAM;;AAI1C,SAAO,eAAe;;;;;CAMxB,gBAAwB,OAA8B;AAEpD,MAAI,UAAU,YACZ,QAAO,wBAAwB,OAAO,MAAM;AAI9C,MAAI,MAAM,WAAW,UAAU,CAE7B,QAAO,yBADW,MAAM,MAAM,EAAE,EACW,OAAO,MAAM;AAI1D,MAAI,MAAM,WAAW,UAAU,CAC7B,QAAO,KAAK,gBAAgB,MAAM;AAIpC,MAAI,MAAM,WAAW,aAAa,CAChC,QAAO,KAAK,mBAAmB,MAAM;AAIvC,MAAI,MAAM,WAAW,SAAS,CAC5B,QAAO,KAAK,eAAe,MAAM;AAInC,MAAI,MAAM,WAAW,WAAW,CAC9B,QAAO,KAAK,iBAAiB,MAAM;AAIrC,MAAI,MAAM,WAAW,QAAQ,CAC3B,QAAO,KAAK,cAAc,MAAM;AAIlC,MAAI,MAAM,WAAW,KAAK,CACxB,QAAO,KAAK,oBAAoB,MAAM;AAIxC,MAAI,MAAM,WAAW,IAAI,IAAI,2BAA2B,KAAK,MAAM,CACjE,QAAO,KAAK,qBAAqB,MAAM;AAOzC,MAAI,MAAM,WAAW,IAAI,EAAE;GACzB,MAAM,gBAAgB,yBAAyB,KAAK,MAAM;AAC1D,OAAI,eAAe;IACjB,MAAM,KAAK,cAAc;IACzB,MAAM,SAAS,cAAc;IAC7B,IAAI,UAAU,yBAAyB,MAAM,MAAM,OAAO,QAAQ,GAAG,CAAC;AAGtE,cAAU,QAAQ,QAAQ,eAAe,OAAO;AAEhD,QAAI,OAAO,MACT,QAAO,sBAAsB,OAAO,QAAQ,IAAI,MAAM,MAAM;AAG9D,WAAO,sBAAsB,IAAI,GAAG,GAAG,QAAQ,IAAI,OAAO,MAAM;;AAGlE,UAAO,sBAAsB,OAAO,OAAO,MAAM;;AAInD,MAAI,MAAM,WAAW,IAAI,CACvB,QAAO,sBAAsB,OAAO,OAAO,MAAM;AAInD,MAAI,MAAM,WAAW,IAAI,CACvB,QAAO,sBAAsB,OAAO,OAAO,MAAM;AAInD,MAAI,MAAM,SAAS,IAAI,CACrB,QAAO,KAAK,mBAAmB,MAAM;AAIvC,SAAO,KAAK,qBAAqB,MAAM;;;;;CAMzC,gBAAwB,KAA4B;EAClD,MAAM,UAAU,IAAI,MAAM,GAAG,GAAG;AAChC,MAAI,CAAC,QAAQ,MAAM,CACjB,QAAO,eAAe;EAIxB,IAAI,YAAY,0BAA0B,QAAQ;AAClD,cAAY,iBAAiB,UAAU;AAGvC,MACE,UAAU,SAAS,IAAI,IACvB,CAAC,UAAU,SAAS,IAAI,IACxB,CAAC,UAAU,SAAS,IAAI,IACxB,CAAC,UAAU,SAAS,IAAI,EACxB;GAEA,MAAM,WAAW,UAAU,QAAQ,IAAI;AAGvC,UAAO,4BAFS,UAAU,MAAM,GAAG,SAAS,CAAC,MAAM,EAC9B,UAAU,MAAM,WAAW,EAAE,CAAC,MAAM,EACC,OAAO,IAAI;;AAIvE,MACE,CAAC,UAAU,SAAS,IAAI,IACxB,CAAC,UAAU,SAAS,IAAI,IACxB,CAAC,UAAU,SAAS,IAAI,CAExB,QAAO,4BACL,UAAU,MAAM,EAChB,KAAA,GACA,OACA,IACD;EAIH,MAAM,EAAE,WAAW,YAAY,eAC7B,KAAK,wBAAwB,UAAU;AAEzC,MAAI,CAAC,UAEH,QAAO,sBAAsB,KAAK,OAAO,IAAI;AAG/C,SAAO,8BACL,WACA,YACA,YACA,OACA,IACD;;;;;CAMH,wBAAgC,WAI9B;EAEA,MAAM,aAAa,UAAU,MAC3B,2EACD;AACD,MAAI,YAAY;GACd,MAAM,GAAG,YAAY,SAAS,WAAW,SAAS,cAChD;AACF,UAAO;IACL;IACA,YAAY;KACV,OAAO,WAAW,MAAM;KACxB,cAAc,kBAAkB,WAAW,MAAM,CAAC;KAClD,WAAW,YAAY;KACxB;IACD,YAAY;KACV,OAAO,WAAW,MAAM;KACxB,cAAc,kBAAkB,WAAW,MAAM,CAAC;KAClD,WAAW,YAAY;KACxB;IACF;;EAIH,MAAM,cAAc,UAAU,MAC5B,iEACD;AACD,MAAI,aAAa;GACf,MAAM,GAAG,WAAW,UAAU,SAAS;GACvC,MAAM,UAAU,kBAAkB,MAAM,MAAM,CAAC;AAE/C,OAAI,aAAa,OAAO,aAAa,KACnC,QAAO;IACL;IACA,YAAY;KACV,OAAO,MAAM,MAAM;KACnB,cAAc;KACd,WAAW,aAAa;KACzB;IACF;YACQ,aAAa,OAAO,aAAa,KAC1C,QAAO;IACL;IACA,YAAY;KACV,OAAO,MAAM,MAAM;KACnB,cAAc;KACd,WAAW,aAAa;KACzB;IACF;YACQ,aAAa,IAEtB,QAAO;IACL;IACA,YAAY;KACV,OAAO,MAAM,MAAM;KACnB,cAAc;KACd,WAAW;KACZ;IACD,YAAY;KACV,OAAO,MAAM,MAAM;KACnB,cAAc;KACd,WAAW;KACZ;IACF;;EAKL,MAAM,gBAAgB,UAAU,MAC9B,kEACD;AACD,MAAI,eAAe;GACjB,MAAM,GAAG,OAAO,UAAU,aAAa;GACvC,MAAM,UAAU,kBAAkB,MAAM,MAAM,CAAC;AAG/C,OAAI,aAAa,OAAO,aAAa,KACnC,QAAO;IACL;IACA,YAAY;KACV,OAAO,MAAM,MAAM;KACnB,cAAc;KACd,WAAW,aAAa;KACzB;IACF;YACQ,aAAa,OAAO,aAAa,KAC1C,QAAO;IACL;IACA,YAAY;KACV,OAAO,MAAM,MAAM;KACnB,cAAc;KACd,WAAW,aAAa;KACzB;IACF;;AAIL,SAAO,EAAE;;;;;CAMX,oBACE,KACA,WACA,MACe;EACf,MAAM,UAAU,IAAI,MAAM,WAAW,GAAG;AACxC,MAAI,CAAC,QAAQ,MAAM,CAAE,QAAO,eAAe;AAC3C,SAAO,KAAK,cAAc,SAAS,KAAK,QAAQ,CAAC;;CAGnD,eAAuB,KAA4B;AACjD,SAAO,KAAK,oBAAoB,KAAK,IAAI,UACvC,oBAAoB,OAAO,OAAO,IAAI,CACvC;;;;;;;;;;;CAYH,iBAAyB,KAA4B;EACnD,MAAM,UAAU,IAAI,MAAM,GAAG,GAAG;AAChC,MAAI,CAAC,QAAQ,MAAM,CACjB,QAAO,eAAe;EAGxB,IAAI,YAAY,QAAQ,MAAM;EAC9B,IAAI,SAAS;EAEb,MAAM,eAAe,UAAU,YAAY,IAAI;AAC/C,MAAI,iBAAiB;OACA,UAAU,MAAM,eAAe,EAAE,CAAC,MAAM,KACxC,KAAK;AACtB,aAAS;AACT,gBAAY,UAAU,MAAM,GAAG,aAAa,CAAC,MAAM;;;AAKvD,SAAO,sBADgB,cAAc,WAAW,KAAK,QAAQ,EAChB,QAAQ,OAAO,IAAI;;;;;;;;;CAUlE,mBAA2B,KAA4B;EACrD,MAAM,UAAU,IAAI,MAAM,IAAI,GAAG;AACjC,MAAI,CAAC,QAAQ,MAAM,CACjB,QAAO,eAAe;AAIxB,MAAI,QAAQ,WAAW,KAAK,CAE1B,QAAO,wBAAwB,YADd,QAAQ,MAAM,EAAE,CAAC,MAAM,EACa,OAAO,IAAI;AAIlE,SAAO,wBAAwB,WAAW,SAAS,OAAO,IAAI;;CAGhE,cAAsB,KAA4B;AAChD,SAAO,KAAK,oBAAoB,KAAK,IAAI,UACvC,mBAAmB,OAAO,OAAO,IAAI,CACtC;;;;;CAMH,oBAA4B,KAA4B;EACtD,MAAM,UAAU,IAAI,MAAM,GAAG,GAAG;AAChC,MAAI,CAAC,QAAQ,MAAM,CACjB,QAAO,eAAe;EAKxB,MAAM,WAAW,kBAAkB,QAAQ;EAC3C,IAAI;EACJ,IAAI;AAEJ,MAAI,aAAa,IAAI;AACnB,mBAAgB,QAAQ,MAAM,GAAG,SAAS,CAAC,MAAM;AACjD,eAAY,QAAQ,MAAM,WAAW,EAAE,CAAC,MAAM;QAE9C,aAAY,QAAQ,MAAM;AAI5B,MAAI,UAAU,WAAW,IAAI,EAAE;GAC7B,MAAM,aAAa,UAAU,MAAM,EAAE;GACrC,MAAM,QAAQ,WAAW,QAAQ,IAAI;AAErC,OAAI,UAAU,GAEZ,QAAO,8BACL,YACA,KAAA,GACA,eACA,OACA,IACD;GAGH,MAAM,WAAW,WAAW,MAAM,GAAG,MAAM,CAAC,MAAM;GAClD,IAAI,gBAAgB,WAAW,MAAM,QAAQ,EAAE,CAAC,MAAM;AAGtD,OACG,cAAc,WAAW,KAAI,IAAI,cAAc,SAAS,KAAI,IAC5D,cAAc,WAAW,IAAI,IAAI,cAAc,SAAS,IAAI,CAE7D,iBAAgB,cAAc,MAAM,GAAG,GAAG;AAG5C,UAAO,8BACL,UACA,eACA,eACA,OACA,IACD;;AAKH,MAAI,uBAAuB,KAAK,UAAU,CACxC,QAAO,4BAA4B,WAAW,eAAe,OAAO,IAAI;EAI1E,IAAI,oBAAoB,0BAA0B,UAAU;AAC5D,sBAAoB,iBAAiB,kBAAkB;EAEvD,MAAM,EAAE,WAAW,YAAY,eAC7B,KAAK,wBAAwB,kBAAkB;AAEjD,MAAI,CAAC,UAEH,QAAO,sBAAsB,KAAK,OAAO,IAAI;AAG/C,SAAO,kCACL,WACA,YACA,YACA,eACA,OACA,IACD;;;;;CAMH,qBAA6B,KAA4B;EACvD,MAAM,MAAM,KAAK,QAAQ;AACzB,MAAI,CAAC,IAEH,QAAO,sBAAsB,KAAK,OAAO,IAAI;EAG/C,MAAM,WAAW,uBAAuB,KAAK,IAAI;AACjD,MAAI,CAAC,SAEH,QAAO,wBACL,QAAQ,aAAa,IAAI,MAAM,EAAE,CAAC,IAClC,KAAA,GACA,KACA,OACA,IACD;AAIH,SAAO,cAAc,UAAU,KAAK,QAAQ;;;;;CAM9C,mBAA2B,KAA4B;EAErD,MAAM,UAAU,IAAI,MAAM,0CAA0C;AACpE,MAAI,CAAC,QACH,QAAO,wBACL,QAAQ,aAAa,IAAI,IACzB,KAAA,GACA,KACA,OACA,IACD;EAGH,MAAM,GAAG,KAAK,UAAU,SAAS;EACjC,IAAI,aAAa;AAGjB,MACG,WAAW,WAAW,KAAI,IAAI,WAAW,SAAS,KAAI,IACtD,WAAW,WAAW,IAAI,IAAI,WAAW,SAAS,IAAI,CAEvD,cAAa,WAAW,MAAM,GAAG,GAAG;AAGtC,SAAO,wBACL,QAAQ,aAAa,IAAI,IACzB,YACA,UACA,OACA,IACD;;;;;CAMH,qBAA6B,KAA4B;AACvD,SAAO,wBACL,QAAQ,aAAa,IAAI,IACzB,KAAA,GACA,KACA,OACA,IACD;;;;;;AAWL,SAAS,kBAAkB,OAA8B;CACvD,MAAM,QAAQ,MAAM,MAAM,wCAAwC;AAClE,KAAI,MACF,QAAO,WAAW,MAAM,GAAG;AAE7B,QAAO;;;;;AAUT,SAAgB,cACd,UACA,UAAgC,EAAE,EACnB;AAEf,KAAI,CAAC,YAAY,CAAC,SAAS,MAAM,CAC/B,QAAO,eAAe;CAGxB,MAAM,UAAU,SAAS,MAAM;CAI/B,MAAM,MAAM,QAAQ;CACpB,MAAM,iBACJ,OAAO,OAAO,KAAK,IAAI,sBAAsB,CAAC,SAAS,IACnD,KAAK,UAAU,IAAI,sBAAsB,GACzC;CACN,MAAM,WACJ,UAAU,QAAQ,QAAQ,eAAe,MAAM,OAAO,OAAO;CAG/D,MAAM,SAAS,WAAW,IAAI,SAAS;AACvC,KAAI,OACF,QAAO;CAMT,MAAM,SADS,IAAI,OADJ,SAAS,QAAQ,EACE,QAAQ,CACpB,OAAO;AAG7B,YAAW,IAAI,UAAU,OAAO;AAEhC,QAAO"}
|
package/dist/plugins/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { StyleDetails, UnitHandler } from "../parser/types.js";
|
|
2
2
|
import { StyleHandlerDefinition } from "../utils/styles.js";
|
|
3
|
-
import { ConfigTokens, RecipeStyles } from "../styles/types.js";
|
|
3
|
+
import { ConfigTokens, RecipeStyles, Styles } from "../styles/types.js";
|
|
4
|
+
import { TypographyPreset } from "../utils/typography.js";
|
|
4
5
|
|
|
5
6
|
//#region src/plugins/types.d.ts
|
|
6
7
|
/**
|
|
@@ -50,6 +51,16 @@ interface TastyPlugin {
|
|
|
50
51
|
* ```
|
|
51
52
|
*/
|
|
52
53
|
recipes?: Record<string, RecipeStyles>;
|
|
54
|
+
/**
|
|
55
|
+
* Typography presets — shorthand for `generateTypographyTokens()`.
|
|
56
|
+
* Generated tokens are merged under explicit `tokens` (tokens win on conflict).
|
|
57
|
+
*/
|
|
58
|
+
presets?: Record<string, TypographyPreset>;
|
|
59
|
+
/**
|
|
60
|
+
* Global Tasty styles keyed by CSS selector.
|
|
61
|
+
* Supports the full Tasty style syntax.
|
|
62
|
+
*/
|
|
63
|
+
globalStyles?: Record<string, Styles>;
|
|
53
64
|
}
|
|
54
65
|
/**
|
|
55
66
|
* A factory function that creates a TastyPlugin.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { hashString } from "./utils/hash.js";
|
|
2
|
+
import { getRegisteredSSRCollector } from "./ssr/ssr-collector-ref.js";
|
|
3
|
+
import { cache } from "react";
|
|
4
|
+
//#region src/rsc-cache.ts
|
|
5
|
+
/**
|
|
6
|
+
* Shared RSC (React Server Components) inline style cache.
|
|
7
|
+
*
|
|
8
|
+
* Uses React.cache for per-request memoization in Server Components.
|
|
9
|
+
* Both computeStyles() and standalone style functions (useGlobalStyles,
|
|
10
|
+
* useRawCSS, useKeyframes, useProperty, useFontFace, useCounterStyle)
|
|
11
|
+
* share this cache so that CSS accumulated by standalone functions is
|
|
12
|
+
* flushed into inline <style> tags by the next tasty() component.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Per-request RSC style cache using React.cache.
|
|
16
|
+
* React.cache provides per-request memoization in Server Components,
|
|
17
|
+
* so each request gets its own isolated cache.
|
|
18
|
+
*/
|
|
19
|
+
const getRSCCache = cache(() => ({
|
|
20
|
+
cacheKeyToClassName: /* @__PURE__ */ new Map(),
|
|
21
|
+
emittedKeys: /* @__PURE__ */ new Set(),
|
|
22
|
+
internalsEmitted: false,
|
|
23
|
+
pendingCSS: [],
|
|
24
|
+
generatedNames: /* @__PURE__ */ new Map()
|
|
25
|
+
}));
|
|
26
|
+
function rscAllocateClassName(rscCache, cacheKey) {
|
|
27
|
+
const existing = rscCache.cacheKeyToClassName.get(cacheKey);
|
|
28
|
+
if (existing) return {
|
|
29
|
+
className: existing,
|
|
30
|
+
isNew: false
|
|
31
|
+
};
|
|
32
|
+
const className = `t${hashString(cacheKey)}`;
|
|
33
|
+
rscCache.cacheKeyToClassName.set(cacheKey, className);
|
|
34
|
+
return {
|
|
35
|
+
className,
|
|
36
|
+
isNew: true
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Flush any pending CSS accumulated by standalone functions.
|
|
41
|
+
* Returns the CSS string and clears the buffer.
|
|
42
|
+
*/
|
|
43
|
+
function flushPendingCSS(rscCache) {
|
|
44
|
+
if (rscCache.pendingCSS.length === 0) return "";
|
|
45
|
+
const css = rscCache.pendingCSS.join("\n");
|
|
46
|
+
rscCache.pendingCSS.length = 0;
|
|
47
|
+
return css;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Push CSS into the RSC pending buffer with dedup via emittedKeys.
|
|
51
|
+
* Returns true if the CSS was added, false if it was already emitted.
|
|
52
|
+
*/
|
|
53
|
+
function pushRSCCSS(rscCache, key, css) {
|
|
54
|
+
if (rscCache.emittedKeys.has(key)) return false;
|
|
55
|
+
rscCache.emittedKeys.add(key);
|
|
56
|
+
rscCache.pendingCSS.push(css);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Determine the current style injection target.
|
|
61
|
+
* Centralizes the three-way detection (SSR collector / RSC cache / client DOM)
|
|
62
|
+
* used by all style functions.
|
|
63
|
+
*/
|
|
64
|
+
function getStyleTarget() {
|
|
65
|
+
const collector = getRegisteredSSRCollector();
|
|
66
|
+
if (collector) return {
|
|
67
|
+
mode: "ssr",
|
|
68
|
+
collector
|
|
69
|
+
};
|
|
70
|
+
if (typeof document === "undefined") return {
|
|
71
|
+
mode: "rsc",
|
|
72
|
+
cache: getRSCCache()
|
|
73
|
+
};
|
|
74
|
+
return { mode: "client" };
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
export { flushPendingCSS, getRSCCache, getStyleTarget, pushRSCCSS, rscAllocateClassName };
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=rsc-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rsc-cache.js","names":[],"sources":["../src/rsc-cache.ts"],"sourcesContent":["/**\n * Shared RSC (React Server Components) inline style cache.\n *\n * Uses React.cache for per-request memoization in Server Components.\n * Both computeStyles() and standalone style functions (useGlobalStyles,\n * useRawCSS, useKeyframes, useProperty, useFontFace, useCounterStyle)\n * share this cache so that CSS accumulated by standalone functions is\n * flushed into inline <style> tags by the next tasty() component.\n */\n\nimport { cache } from 'react';\n\nimport type { ServerStyleCollector } from './ssr/collector';\nimport { getRegisteredSSRCollector } from './ssr/ssr-collector-ref';\nimport { hashString } from './utils/hash';\n\nexport interface RSCStyleCache {\n cacheKeyToClassName: Map<string, string>;\n emittedKeys: Set<string>;\n internalsEmitted: boolean;\n pendingCSS: string[];\n /** Maps dedup key -> generated name for keyframes and counter-styles in RSC mode. */\n generatedNames: Map<string, string>;\n}\n\n/**\n * Per-request RSC style cache using React.cache.\n * React.cache provides per-request memoization in Server Components,\n * so each request gets its own isolated cache.\n */\nexport const getRSCCache = cache(\n (): RSCStyleCache => ({\n cacheKeyToClassName: new Map(),\n emittedKeys: new Set(),\n internalsEmitted: false,\n pendingCSS: [],\n generatedNames: new Map(),\n }),\n);\n\nexport function rscAllocateClassName(\n rscCache: RSCStyleCache,\n cacheKey: string,\n): { className: string; isNew: boolean } {\n const existing = rscCache.cacheKeyToClassName.get(cacheKey);\n if (existing) return { className: existing, isNew: false };\n\n // Content-hash ensures stable names across all environments (RSC, SSR, client),\n // enabling cross-environment dedup and preventing class collisions.\n const className = `t${hashString(cacheKey)}`;\n rscCache.cacheKeyToClassName.set(cacheKey, className);\n return { className, isNew: true };\n}\n\n/**\n * Flush any pending CSS accumulated by standalone functions.\n * Returns the CSS string and clears the buffer.\n */\nexport function flushPendingCSS(rscCache: RSCStyleCache): string {\n if (rscCache.pendingCSS.length === 0) return '';\n const css = rscCache.pendingCSS.join('\\n');\n rscCache.pendingCSS.length = 0;\n return css;\n}\n\n/**\n * Push CSS into the RSC pending buffer with dedup via emittedKeys.\n * Returns true if the CSS was added, false if it was already emitted.\n */\nexport function pushRSCCSS(\n rscCache: RSCStyleCache,\n key: string,\n css: string,\n): boolean {\n if (rscCache.emittedKeys.has(key)) return false;\n rscCache.emittedKeys.add(key);\n rscCache.pendingCSS.push(css);\n return true;\n}\n\nexport type StyleTarget =\n | { mode: 'ssr'; collector: ServerStyleCollector }\n | { mode: 'rsc'; cache: RSCStyleCache }\n | { mode: 'client' };\n\n/**\n * Determine the current style injection target.\n * Centralizes the three-way detection (SSR collector / RSC cache / client DOM)\n * used by all style functions.\n */\nexport function getStyleTarget(): StyleTarget {\n const collector = getRegisteredSSRCollector();\n if (collector) return { mode: 'ssr', collector };\n if (typeof document === 'undefined')\n return { mode: 'rsc', cache: getRSCCache() };\n return { mode: 'client' };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA8BA,MAAa,cAAc,aACH;CACpB,qCAAqB,IAAI,KAAK;CAC9B,6BAAa,IAAI,KAAK;CACtB,kBAAkB;CAClB,YAAY,EAAE;CACd,gCAAgB,IAAI,KAAK;CAC1B,EACF;AAED,SAAgB,qBACd,UACA,UACuC;CACvC,MAAM,WAAW,SAAS,oBAAoB,IAAI,SAAS;AAC3D,KAAI,SAAU,QAAO;EAAE,WAAW;EAAU,OAAO;EAAO;CAI1D,MAAM,YAAY,IAAI,WAAW,SAAS;AAC1C,UAAS,oBAAoB,IAAI,UAAU,UAAU;AACrD,QAAO;EAAE;EAAW,OAAO;EAAM;;;;;;AAOnC,SAAgB,gBAAgB,UAAiC;AAC/D,KAAI,SAAS,WAAW,WAAW,EAAG,QAAO;CAC7C,MAAM,MAAM,SAAS,WAAW,KAAK,KAAK;AAC1C,UAAS,WAAW,SAAS;AAC7B,QAAO;;;;;;AAOT,SAAgB,WACd,UACA,KACA,KACS;AACT,KAAI,SAAS,YAAY,IAAI,IAAI,CAAE,QAAO;AAC1C,UAAS,YAAY,IAAI,IAAI;AAC7B,UAAS,WAAW,KAAK,IAAI;AAC7B,QAAO;;;;;;;AAaT,SAAgB,iBAA8B;CAC5C,MAAM,YAAY,2BAA2B;AAC7C,KAAI,UAAW,QAAO;EAAE,MAAM;EAAO;EAAW;AAChD,KAAI,OAAO,aAAa,YACtB,QAAO;EAAE,MAAM;EAAO,OAAO,aAAa;EAAE;AAC9C,QAAO,EAAE,MAAM,UAAU"}
|