@pyreon/styler 0.12.10 → 0.12.11

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/lib/index.d.ts CHANGED
@@ -24,10 +24,19 @@ declare function ThemeProvider({
24
24
  }): VNode | null;
25
25
  //#endregion
26
26
  //#region src/resolve.d.ts
27
- type Interpolation = string | number | boolean | null | undefined | CSSResult | Interpolation[] | ((props: {
28
- theme?: DefaultTheme & Record<string, any>;
29
- [key: string]: any;
30
- }) => Interpolation);
27
+ /**
28
+ * Props passed to interpolation functions inside tagged templates.
29
+ * Generic `P` allows consumers to type their custom props (e.g. transient $-prefixed):
30
+ *
31
+ * @example
32
+ * styled('div')<{ $color: string }>`
33
+ * background: ${(props) => props.$color}; // props.$color is typed!
34
+ * `
35
+ */
36
+ type StyledProps<P extends object = Record<string, unknown>> = P & {
37
+ theme?: DefaultTheme & Record<string, unknown>;
38
+ };
39
+ type Interpolation<P extends object = Record<string, unknown>> = string | number | boolean | null | undefined | CSSResult | Interpolation<P>[] | ((props: StyledProps<P>) => Interpolation<P>);
31
40
  /**
32
41
  * Lazy representation of a `css` tagged template. Stores the raw template
33
42
  * strings and interpolation values without resolving them. Resolution is
@@ -211,7 +220,19 @@ interface StyledOptions {
211
220
  */
212
221
  layer?: string;
213
222
  }
214
- type TagTemplateFn = (strings: TemplateStringsArray, ...values: Interpolation[]) => ComponentFn;
223
+ /**
224
+ * Generic tagged template function returned by `styled(tag)` and `styled.tag`.
225
+ *
226
+ * Accepts an optional type parameter `<P>` for consumer-defined props
227
+ * (typically transient $-prefixed props that aren't forwarded to the DOM).
228
+ *
229
+ * @example
230
+ * const Box = styled('div')<{ $color: string }>`
231
+ * background: ${(props) => props.$color};
232
+ * `
233
+ * <Box $color="red" /> // $color is required and typed
234
+ */
235
+ type TagTemplateFn = <P extends object = Record<string, unknown>>(strings: TemplateStringsArray, ...values: Interpolation<P>[]) => ComponentFn<P & Record<string, unknown>>;
215
236
  type HtmlTags = 'a' | 'abbr' | 'address' | 'article' | 'aside' | 'audio' | 'b' | 'blockquote' | 'body' | 'br' | 'button' | 'canvas' | 'caption' | 'code' | 'col' | 'colgroup' | 'dd' | 'details' | 'div' | 'dl' | 'dt' | 'em' | 'fieldset' | 'figcaption' | 'figure' | 'footer' | 'form' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'head' | 'header' | 'hr' | 'html' | 'i' | 'iframe' | 'img' | 'input' | 'label' | 'legend' | 'li' | 'link' | 'main' | 'mark' | 'menu' | 'meta' | 'nav' | 'ol' | 'optgroup' | 'option' | 'output' | 'p' | 'picture' | 'pre' | 'progress' | 'q' | 'section' | 'select' | 'small' | 'source' | 'span' | 'strong' | 'style' | 'sub' | 'summary' | 'sup' | 'svg' | 'table' | 'tbody' | 'td' | 'template' | 'textarea' | 'tfoot' | 'th' | 'thead' | 'time' | 'tr' | 'u' | 'ul' | 'video';
216
237
  type StyledFunction = ((tag: Tag, options?: StyledOptions) => TagTemplateFn) & { [K in HtmlTags]: TagTemplateFn };
217
238
  declare const styled: StyledFunction;
@@ -1 +1 @@
1
- {"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/ThemeProvider.ts","../../src/resolve.ts","../../src/css.ts","../../src/forward.ts","../../src/globalStyle.ts","../../src/hash.ts","../../src/keyframes.ts","../../src/shared.ts","../../src/sheet.ts","../../src/styled.tsx","../../src/useCSS.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/ThemeProvider.ts","../../src/resolve.ts","../../src/css.ts","../../src/forward.ts","../../src/globalStyle.ts","../../src/hash.ts","../../src/keyframes.ts","../../src/shared.ts","../../src/sheet.ts","../../src/styled.tsx","../../src/useCSS.ts"],"mappings":"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"}
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/resolve.ts","../src/css.ts","../src/forward.ts","../src/shared.ts","../src/hash.ts","../src/sheet.ts","../src/ThemeProvider.ts","../src/globalStyle.ts","../src/keyframes.ts","../src/styled.tsx","../src/useCSS.ts"],"sourcesContent":["/**\n * Interpolation resolver: converts tagged template strings + values into a\n * final CSS string. Handles nested CSSResults, arrays, functions, and\n * primitive values.\n */\n\nimport type { DefaultTheme } from './ThemeProvider'\n\nexport type Interpolation =\n | string\n | number\n | boolean\n | null\n | undefined\n | CSSResult\n | Interpolation[]\n | ((props: { theme?: DefaultTheme & Record<string, any>; [key: string]: any }) => Interpolation)\n\n/**\n * Lazy representation of a `css` tagged template. Stores the raw template\n * strings and interpolation values without resolving them. Resolution is\n * deferred until a styled component renders (or until explicitly resolved).\n */\nexport class CSSResult {\n constructor(\n readonly strings: TemplateStringsArray,\n readonly values: Interpolation[],\n ) {}\n\n /** Resolve with empty props — useful for static templates, testing, and debugging. */\n toString(): string {\n return resolve(this.strings, this.values, {})\n }\n}\n\n/** Resolve a tagged template's strings + values into a final CSS string. */\nexport const resolve = (\n strings: TemplateStringsArray,\n values: Interpolation[],\n props: Record<string, any>,\n): string => {\n // Tagged templates guarantee strings.length === values.length + 1,\n // so strings[0] and strings[i+1] are always defined — no ?? needed.\n let result = strings[0] as string\n for (let i = 0; i < values.length; i++) {\n const v = values[i]\n const s = strings[i + 1] as string\n // Inline the most common value types to avoid function call overhead.\n if (typeof v === 'function') {\n const r = v(props)\n result +=\n (typeof r === 'string'\n ? r\n : r == null || r === false || r === true\n ? ''\n : resolveValue(r as Interpolation, props)) + s\n } else if (v == null || v === false || v === true) {\n result += s\n } else if (typeof v === 'string') {\n result += v + s\n } else if (typeof v === 'number') {\n result += v + s\n } else {\n result += resolveValue(v, props) + s\n }\n }\n return result\n}\n\n/**\n * Normalize resolved CSS text for strict `insertRule` compatibility.\n *\n * Single-pass scanner that handles all cleanup in one traversal:\n * - Strips block comments and line comments (preserves :// in URLs)\n * - Collapses whitespace to single spaces\n * - Removes redundant semicolons\n * - Trims leading/trailing whitespace\n */\nconst normCache = new Map<string, string>()\n/** Clear the normalizeCSS cache (called during HMR cleanup). */\nexport const clearNormCache = () => normCache.clear()\n\nexport const normalizeCSS = (css: string): string => {\n const cached = normCache.get(css)\n if (cached !== undefined) return cached\n\n const len = css.length\n let out = ''\n let space = false // pending space to emit before next non-whitespace char\n let last = 0 // charCode of last char written to output (0 = nothing yet)\n\n for (let i = 0; i < len; i++) {\n const c = css.charCodeAt(i)\n\n // /* block comment */\n if (c === 47 /* / */ && css.charCodeAt(i + 1) === 42 /* * */) {\n const end = css.indexOf('*/', i + 2)\n i = end === -1 ? len : end + 1\n space = true\n continue\n }\n\n // // line comment (but not :// in URLs)\n if (c === 47 /* / */ && css.charCodeAt(i + 1) === 47 /* / */ && last !== 58 /* : */) {\n const nl = css.indexOf('\\n', i + 2)\n i = nl === -1 ? len : nl\n space = true\n continue\n }\n\n // Whitespace → collapse\n if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {\n space = true\n continue\n }\n\n // Semicolon → skip if redundant (after start, {, }, or another ;)\n if (c === 59 /* ; */) {\n if (last === 0 || last === 123 /* { */ || last === 125 /* } */ || last === 59 /* ; */) {\n continue\n }\n space = false\n out += ';'\n last = 59\n continue\n }\n\n // Regular char — emit pending space (but not at start of output)\n if (space && last !== 0) out += ' '\n space = false\n\n out += css[i]\n last = c\n }\n\n // Evict oldest ~10% to prevent memory leaks without cliff-edge drop\n if (normCache.size > 2000) {\n let count = 0\n for (const key of normCache.keys()) {\n if (count >= 200) break\n normCache.delete(key)\n count++\n }\n }\n normCache.set(css, out)\n\n return out\n}\n\nexport const resolveValue = (value: Interpolation, props: Record<string, any>): string => {\n // null, undefined, false, true → empty (enables conditional: ${cond && css`...`})\n if (value == null || value === false || value === true) return ''\n\n // function interpolation → call with props/theme context, resolve result\n if (typeof value === 'function') return resolveValue(value(props) as Interpolation, props)\n\n // nested CSSResult → recursively resolve\n if (value instanceof CSSResult) return resolve(value.strings, value.values, props)\n\n // array of results (e.g. from makeItResponsive's breakpoints.map())\n if (Array.isArray(value)) {\n let arrayResult = ''\n for (let i = 0; i < value.length; i++) {\n arrayResult += resolveValue(value[i], props)\n }\n return arrayResult\n }\n\n return String(value)\n}\n","import { CSSResult, type Interpolation } from './resolve'\n\n/**\n * Tagged template function for CSS. Captures the template strings and\n * interpolation values as a lazy CSSResult — resolution is deferred\n * until a styled component renders.\n *\n * Works as both a tagged template (`css\\`...\\``) and a regular function\n * call (`css(...args)`) since tagged templates are syntactic sugar for\n * function calls with (TemplateStringsArray, ...values).\n */\nexport const css = (strings: TemplateStringsArray, ...values: Interpolation[]): CSSResult =>\n new CSSResult(strings, values)\n","/**\n * HTML prop filtering. Prevents unknown props from being forwarded to DOM\n * elements (which causes warnings). Props starting with `$` are\n * transient (styling-only) and are always filtered out.\n */\n\n// Common HTML attributes, event handlers, and ARIA/data attributes\nconst HTML_PROPS = new Set([\n // Core props\n 'className',\n 'class',\n 'dangerouslySetInnerHTML',\n 'htmlFor',\n 'id',\n 'key',\n 'ref',\n 'style',\n 'tabIndex',\n 'role',\n // Event handlers\n 'onAbort',\n 'onAnimationEnd',\n 'onAnimationIteration',\n 'onAnimationStart',\n 'onBlur',\n 'onChange',\n 'onClick',\n 'onCompositionEnd',\n 'onCompositionStart',\n 'onCompositionUpdate',\n 'onContextMenu',\n 'onCopy',\n 'onCut',\n 'onDoubleClick',\n 'onDrag',\n 'onDragEnd',\n 'onDragEnter',\n 'onDragLeave',\n 'onDragOver',\n 'onDragStart',\n 'onDrop',\n 'onError',\n 'onFocus',\n 'onInput',\n 'onKeyDown',\n 'onKeyPress',\n 'onKeyUp',\n 'onLoad',\n 'onMouseDown',\n 'onMouseEnter',\n 'onMouseLeave',\n 'onMouseMove',\n 'onMouseOut',\n 'onMouseOver',\n 'onMouseUp',\n 'onPaste',\n 'onPointerCancel',\n 'onPointerDown',\n 'onPointerEnter',\n 'onPointerLeave',\n 'onPointerMove',\n 'onPointerOut',\n 'onPointerOver',\n 'onPointerUp',\n 'onScroll',\n 'onSelect',\n 'onSubmit',\n 'onTouchCancel',\n 'onTouchEnd',\n 'onTouchMove',\n 'onTouchStart',\n 'onTransitionEnd',\n 'onWheel',\n // HTML attributes\n 'accept',\n 'acceptCharset',\n 'accessKey',\n 'action',\n 'allow',\n 'allowFullScreen',\n 'alt',\n 'as',\n 'async',\n 'autoCapitalize',\n 'autoComplete',\n 'autoCorrect',\n 'autoFocus',\n 'autoPlay',\n 'capture',\n 'cellPadding',\n 'cellSpacing',\n 'charSet',\n 'checked',\n 'cite',\n 'cols',\n 'colSpan',\n 'content',\n 'contentEditable',\n 'controls',\n 'controlsList',\n 'coords',\n 'crossOrigin',\n 'dateTime',\n 'decoding',\n 'default',\n 'defaultChecked',\n 'defaultValue',\n 'defer',\n 'dir',\n 'disabled',\n 'disablePictureInPicture',\n 'disableRemotePlayback',\n 'download',\n 'draggable',\n 'encType',\n 'enterKeyHint',\n 'fetchPriority',\n 'form',\n 'formAction',\n 'formEncType',\n 'formMethod',\n 'formNoValidate',\n 'formTarget',\n 'frameBorder',\n 'headers',\n 'height',\n 'hidden',\n 'high',\n 'href',\n 'hrefLang',\n 'httpEquiv',\n 'inputMode',\n 'integrity',\n 'is',\n 'label',\n 'lang',\n 'list',\n 'loading',\n 'loop',\n 'low',\n 'max',\n 'maxLength',\n 'media',\n 'method',\n 'min',\n 'minLength',\n 'multiple',\n 'muted',\n 'name',\n 'noModule',\n 'noValidate',\n 'nonce',\n 'open',\n 'optimum',\n 'pattern',\n 'placeholder',\n 'playsInline',\n 'poster',\n 'preload',\n 'readOnly',\n 'referrerPolicy',\n 'rel',\n 'required',\n 'reversed',\n 'rows',\n 'rowSpan',\n 'sandbox',\n 'scope',\n 'scoped',\n 'scrolling',\n 'selected',\n 'shape',\n 'size',\n 'sizes',\n 'slot',\n 'span',\n 'spellCheck',\n 'src',\n 'srcDoc',\n 'srcLang',\n 'srcSet',\n 'start',\n 'step',\n 'summary',\n 'target',\n 'title',\n 'translate',\n 'type',\n 'useMap',\n 'value',\n 'width',\n 'wrap',\n])\n\n/**\n * Filters props for HTML elements. Keeps valid HTML attrs, data-*, aria-*.\n * Rejects unknown props and $-prefixed transient props.\n */\nexport const filterProps = (props: Record<string, unknown>): Record<string, unknown> => {\n const filtered: Record<string, unknown> = {}\n\n for (const key in props) {\n // Skip transient props ($-prefixed) — used for styling-only props\n if (key.charCodeAt(0) === 36) continue // '$'\n\n // Skip `as` prop — handled separately by styled\n if (key === 'as') continue\n\n // Keep data-* and aria-* attributes\n if (key.startsWith('data-') || key.startsWith('aria-')) {\n filtered[key] = props[key]\n continue\n }\n\n // Keep known HTML props\n if (HTML_PROPS.has(key)) {\n filtered[key] = props[key]\n }\n }\n\n return filtered\n}\n\n/**\n * Build final props for a styled component in a single pass.\n * Combines className merging, ref injection, and prop filtering into one\n * allocation and one iteration.\n */\nexport const buildProps = (\n rawProps: Record<string, any>,\n generatedCls: string,\n isDOM: boolean,\n customFilter?: (prop: string) => boolean,\n): Record<string, any> => {\n const result: Record<string, any> = {}\n\n // Merge generated + user className\n const userCls = rawProps.class || rawProps.className\n if (generatedCls) {\n result.class = userCls ? `${generatedCls} ${userCls}` : generatedCls\n } else if (userCls) {\n result.class = userCls\n }\n\n // Component target — forward all props except as/className/class and $-prefixed\n if (!isDOM) {\n for (const key in rawProps) {\n if (key === 'as' || key === 'className' || key === 'class') continue\n if (key.charCodeAt(0) === 36) continue // $-prefixed transient\n result[key] = rawProps[key]\n }\n return result\n }\n\n // DOM element with custom shouldForwardProp\n if (customFilter) {\n for (const key in rawProps) {\n if (key === 'as' || key === 'className' || key === 'class') continue\n if (customFilter(key)) result[key] = rawProps[key]\n }\n return result\n }\n\n // DOM element with default filtering\n for (const key in rawProps) {\n if (key === 'as' || key === 'className' || key === 'class') continue\n if (key.charCodeAt(0) === 36) continue // $-prefixed transient\n if (key.startsWith('data-') || key.startsWith('aria-')) {\n result[key] = rawProps[key]\n continue\n }\n if (HTML_PROPS.has(key)) result[key] = rawProps[key]\n }\n return result\n}\n","/**\n * Shared utilities used across multiple modules.\n */\nimport { CSSResult, type Interpolation } from './resolve'\n\n/** Check if an interpolation value is dynamic (contains functions or nested dynamic CSSResults). */\nexport const isDynamic = (v: Interpolation): boolean => {\n if (typeof v === 'function') return true\n if (Array.isArray(v)) return v.some(isDynamic)\n if (v instanceof CSSResult) return v.values.some(isDynamic)\n return false\n}\n","/**\n * Fast FNV-1a non-cryptographic hash. Returns base-36 string for compact class names.\n *\n * 32-bit hash space → ~4.3 billion unique values. Collision probability is\n * negligible for typical applications (< 10,000 unique CSS rules).\n */\n\n/** FNV-1a offset basis — starting state for streaming hash. */\nexport const HASH_INIT = 2166136261\n\nconst FNV_PRIME = 16777619\n\n/**\n * Feed a string segment into the running hash state.\n * Streaming: hashUpdate(hashUpdate(HASH_INIT, 'ab'), 'cd') === hash('abcd').\n */\nexport const hashUpdate = (init: number, str: string): number => {\n let h = init\n for (let i = 0; i < str.length; i++) {\n h ^= str.charCodeAt(i)\n h = Math.imul(h, FNV_PRIME)\n }\n return h\n}\n\n/** Finalize a hash state into a base-36 class name suffix. */\nexport const hashFinalize = (h: number): string => (h >>> 0).toString(36)\n\n/** Hash a complete string in one shot. Returns base-36 string. */\nexport const hash = (str: string): string => hashFinalize(hashUpdate(HASH_INIT, str))\n","/**\n * StyleSheet manager. Handles CSS rule injection, hash-based deduplication,\n * SSR buffering, client-side hydration, bounded cache, and @layer support.\n *\n * Media queries (@media), @supports, and @container blocks nested inside\n * component CSS are automatically extracted into separate top-level rules.\n */\nimport { hash } from './hash'\nimport { clearNormCache } from './resolve'\n\nconst PREFIX = 'pyr'\nconst ATTR = 'data-pyreon-styler'\nconst DEFAULT_MAX_CACHE_SIZE = 10000\n\nexport interface StyleSheetOptions {\n /** Maximum number of cached rules before eviction (default: 10000). */\n maxCacheSize?: number\n /** CSS @layer name to wrap scoped rules in. */\n layer?: string\n}\n\nexport class StyleSheet {\n private cache = new Map<string, string>()\n private insertCache = new Map<string, string>()\n private sheet: CSSStyleSheet | null = null\n private ssrBuffer: string[] = []\n private isSSR: boolean\n private maxCacheSize: number\n private layer: string | undefined\n private supportsLayer = false\n\n constructor(options: StyleSheetOptions = {}) {\n this.maxCacheSize = options.maxCacheSize ?? DEFAULT_MAX_CACHE_SIZE\n this.layer = options.layer\n this.isSSR = typeof document === 'undefined'\n if (!this.isSSR) this.mount()\n }\n\n private mount() {\n // Reuse existing <style> tag from SSR hydration\n const existing = document.querySelector(`style[${ATTR}]`) as HTMLStyleElement | null\n\n if (existing) {\n this.sheet = existing.sheet ?? null\n this.hydrateFromTag(existing)\n } else {\n const el = document.createElement('style')\n el.setAttribute(ATTR, '')\n document.head.appendChild(el)\n this.sheet = el.sheet ?? null\n }\n\n // Inject single @layer for all framework CSS.\n // Using one shared layer ensures rocketstyle overrides base via source\n // order (rocketstyle rules inserted after base), while media queries\n // from base components still work correctly within the same layer.\n // A two-layer approach (base < rocketstyle) breaks responsive styles\n // because higher layers always win regardless of @media conditions.\n if (this.sheet) {\n try {\n this.sheet.insertRule('@layer pyreon;', 0)\n this.supportsLayer = true\n } catch {\n // @layer not supported — falls back to source order\n }\n }\n }\n\n /** Extract className from a selector like \".pyr-abc\" or \".pyr-abc.pyr-abc\" → \"pyr-abc\" */\n private extractClassName(selectorText: string): string | null {\n if (selectorText[0] !== '.') return null\n const dotIdx = selectorText.indexOf('.', 1)\n return dotIdx > 0 ? selectorText.slice(1, dotIdx) : selectorText.slice(1)\n }\n\n /** Parse existing rules from SSR-rendered <style> tag into cache. */\n private hydrateFromTag(el: HTMLStyleElement) {\n const sheet = el.sheet\n if (!sheet) return\n\n for (let i = 0; i < sheet.cssRules.length; i++) {\n const rule = sheet.cssRules[i]\n\n if (rule instanceof CSSStyleRule) {\n const className = this.extractClassName(rule.selectorText)\n if (className) this.cache.set(className, className)\n }\n\n // Handle split @media rules that wrap our selectors\n if (typeof CSSMediaRule !== 'undefined' && rule instanceof CSSMediaRule) {\n for (let j = 0; j < rule.cssRules.length; j++) {\n const inner = rule.cssRules[j]\n if (inner instanceof CSSStyleRule) {\n const className = this.extractClassName(inner.selectorText)\n if (className) this.cache.set(className, className)\n }\n }\n }\n }\n }\n\n /** Evict oldest entries when cache exceeds max size. */\n private evictIfNeeded() {\n if (this.cache.size <= this.maxCacheSize) return\n\n // Map iteration order is insertion order — delete oldest 10%\n const toDelete = Math.floor(this.maxCacheSize * 0.1)\n let count = 0\n for (const key of this.cache.keys()) {\n if (count >= toDelete) break\n this.cache.delete(key)\n count++\n }\n }\n\n /**\n * Extract nested at-rules (@media, @supports, @container) from CSS text\n * and wrap their content in the given selector as separate top-level rules.\n */\n private splitAtRules(cssText: string, selector: string): { base: string; atRules: string[] } {\n // Fast path: no at-rules to split\n if (cssText.indexOf('@') === -1) return { base: cssText, atRules: [] }\n\n const atRules: string[] = []\n const baseParts: string[] = []\n let depth = 0\n let atStart = -1\n let lastBase = 0\n\n for (let i = 0; i < cssText.length; i++) {\n const ch = cssText[i]\n\n if (ch === '{') {\n depth++\n } else if (ch === '}') {\n depth--\n if (depth === 0 && atStart >= 0) {\n // End of a tracked at-rule block — extract and wrap with selector\n const openBrace = cssText.indexOf('{', atStart)\n const atPrefix = cssText.slice(atStart, openBrace).trim()\n const innerCSS = cssText.slice(openBrace + 1, i).trim()\n if (innerCSS) {\n atRules.push(`${atPrefix}{${selector}{${innerCSS}}}`)\n }\n atStart = -1\n lastBase = i + 1\n }\n } else if (depth === 0 && ch === '@' && atStart < 0) {\n // Check if this starts a splittable at-rule (not @keyframes, @font-face, etc.)\n const remaining = cssText.slice(i, i + 20)\n if (/^@(?:media|supports|container)\\b/.test(remaining)) {\n // Save any base CSS that precedes this at-rule\n const baseBefore = cssText.slice(lastBase, i).trim()\n if (baseBefore) baseParts.push(baseBefore)\n atStart = i\n }\n }\n }\n\n // Collect remaining base CSS after the last at-rule\n if (lastBase < cssText.length && atStart < 0) {\n const remaining = cssText.slice(lastBase).trim()\n if (remaining) baseParts.push(remaining)\n }\n\n // If no at-rules were found, return original unchanged\n if (atRules.length === 0) return { base: cssText, atRules: [] }\n\n return { base: baseParts.join(' '), atRules }\n }\n\n /**\n * Compute a className from CSS text without injecting (pure function).\n */\n getClassName(cssText: string): string {\n const cached = this.insertCache.get(cssText)\n if (cached) return cached\n const h = hash(cssText)\n return `${PREFIX}-${h}`\n }\n\n /**\n * Insert CSS rules for a component. Returns the class name (deterministic, hash-based).\n * Deduplicates: same CSS text always produces the same class name and\n * the rules are only injected once.\n *\n * @param cssText - CSS declarations to insert\n * @param _unused - Reserved for backward compatibility (was `boost`)\n * @param insertLayer - CSS @layer to wrap this rule in (e.g. 'rocketstyle').\n * Used by rocketstyle to ensure wrapper styles override inner component styles\n * via @layer order (base < rocketstyle) instead of specificity hacks.\n */\n insert(cssText: string, _unused = false, insertLayer?: string): string {\n // Fast path: skip hash computation on repeated insertions of same CSS text\n const icKey = insertLayer ? `${cssText}\\0L:${insertLayer}` : cssText\n const icHit = this.insertCache.get(icKey)\n if (icHit) return icHit\n\n const h = hash(cssText)\n const className = `${PREFIX}-${h}`\n\n if (this.cache.has(className)) {\n this.insertCache.set(icKey, className)\n return className\n }\n\n this.evictIfNeeded()\n this.cache.set(className, className)\n\n const selector = `.${className}`\n\n // Split nested at-rules into separate top-level rules\n const { base, atRules } = this.splitAtRules(cssText, selector)\n\n const rules: string[] = []\n if (base) rules.push(`${selector}{${base}}`)\n rules.push(...atRules)\n\n // Apply @layer wrapping — per-insert layer takes precedence over sheet-level layer.\n // In SSR, always apply layers (output goes to real browsers).\n // In client, skip if @layer isn't supported (e.g. happy-dom in tests).\n const layerName = (this.isSSR || this.supportsLayer) ? (insertLayer ?? this.layer) : undefined\n const finalRules = layerName ? rules.map((r) => `@layer ${layerName}{${r}}`) : rules\n\n if (this.isSSR) {\n for (const rule of finalRules) {\n this.ssrBuffer.push(rule)\n }\n } else if (this.sheet) {\n for (const rule of finalRules) {\n try {\n this.sheet.insertRule(rule, this.sheet.cssRules.length)\n } catch (_e) {\n if (process.env.NODE_ENV !== 'production') {\n // oxlint-disable-next-line no-console\n console.warn('[styler] Failed to insert CSS rule:', rule, _e)\n }\n }\n }\n }\n\n this.insertCache.set(icKey, className)\n return className\n }\n\n /** Insert a @keyframes rule. Deduplicates by animation name. */\n insertKeyframes(name: string, body: string): void {\n if (this.cache.has(name)) return\n\n this.evictIfNeeded()\n this.cache.set(name, name)\n\n const rule = `@keyframes ${name}{${body}}`\n\n if (this.isSSR) {\n this.ssrBuffer.push(rule)\n } else if (this.sheet) {\n try {\n this.sheet.insertRule(rule, this.sheet.cssRules.length)\n } catch (_e) {\n if (process.env.NODE_ENV !== 'production') {\n // silently ignore invalid CSS rules in production\n }\n }\n }\n }\n\n /**\n * Split CSS text into individual top-level rules.\n * CSSStyleSheet.insertRule() only accepts one rule at a time.\n */\n private splitRules(cssText: string): string[] {\n const rules: string[] = []\n let depth = 0\n let start = 0\n\n for (let i = 0; i < cssText.length; i++) {\n const ch = cssText[i]\n if (ch === '{') depth++\n else if (ch === '}') {\n depth--\n if (depth === 0) {\n const rule = cssText.slice(start, i + 1).trim()\n if (rule) rules.push(rule)\n start = i + 1\n }\n }\n }\n\n return rules\n }\n\n /** Insert global CSS rules (no wrapper selector). Deduplicates by hash. */\n insertGlobal(cssText: string): void {\n const h = hash(cssText)\n const key = `global-${h}`\n\n if (this.cache.has(key)) return\n\n this.evictIfNeeded()\n this.cache.set(key, key)\n\n if (this.isSSR) {\n this.ssrBuffer.push(cssText)\n } else if (this.sheet) {\n const rules = this.splitRules(cssText)\n for (const rule of rules) {\n try {\n this.sheet.insertRule(rule, this.sheet.cssRules.length)\n } catch (_e) {\n if (process.env.NODE_ENV !== 'production') {\n // oxlint-disable-next-line no-console\n console.warn('[styler] Failed to insert global CSS rule:', rule, _e)\n }\n }\n }\n }\n }\n\n /** Returns collected CSS for SSR as a complete `<style>` tag string. */\n getStyleTag(): string {\n if (this.ssrBuffer.length === 0) return `<style ${ATTR}=\"\"></style>`\n const layerDecl = this.layer ? `@layer ${this.layer};` : ''\n const css = (layerDecl + this.ssrBuffer.join('')).replace(/<\\/style/gi, '<\\\\/style')\n return `<style ${ATTR}=\"\">${css}</style>`\n }\n\n /** Returns collected CSS rules as a raw string (useful for streaming SSR). */\n getStyles(): string {\n if (this.ssrBuffer.length === 0) return ''\n const layerDecl = this.layer ? `@layer ${this.layer};` : ''\n return layerDecl + this.ssrBuffer.join('')\n }\n\n /** Reset SSR buffer and cache (call between server requests). */\n reset(): void {\n this.ssrBuffer = []\n this.cache.clear()\n this.insertCache.clear()\n }\n\n /** Clear the dedup cache. Useful for HMR / dev-time reloads. */\n clearCache(): void {\n this.cache.clear()\n this.insertCache.clear()\n clearNormCache()\n }\n\n /**\n * Full cleanup: clear cache and remove all CSS rules from the DOM.\n * Intended for HMR / dev-time reloads where stale styles must be purged.\n */\n clearAll(): void {\n this.cache.clear()\n this.insertCache.clear()\n clearNormCache()\n this.ssrBuffer = []\n if (this.sheet) {\n while (this.sheet.cssRules.length > 0) {\n this.sheet.deleteRule(0)\n }\n }\n }\n\n /**\n * Compute className and full CSS rule text without injecting.\n */\n prepare(cssText: string): { className: string; rules: string } {\n const h = hash(cssText)\n const className = `${PREFIX}-${h}`\n const selector = `.${className}`\n const { base, atRules } = this.splitAtRules(cssText, selector)\n\n const allRules: string[] = []\n if (base) allRules.push(`${selector}{${base}}`)\n allRules.push(...atRules)\n\n const finalRules = this.layer ? allRules.map((r) => `@layer ${this.layer}{${r}}`) : allRules\n\n return { className, rules: finalRules.join('') }\n }\n\n /** Check if a className is already in the cache. O(1) Map lookup. */\n has(className: string): boolean {\n return this.cache.has(className)\n }\n\n /** Current number of cached rules. */\n get cacheSize(): number {\n return this.cache.size\n }\n}\n\n/** Default singleton sheet for client-side use. */\nexport const sheet = new StyleSheet({ layer: 'pyreon' })\n\n/**\n * Factory for creating isolated StyleSheet instances.\n * Use in SSR to get per-request isolation.\n */\nexport const createSheet = (options?: StyleSheetOptions): StyleSheet => new StyleSheet(options)\n","/**\n * Theme context for styled components.\n *\n * Extensible theme interface. Consumers can augment this via module\n * declaration merging for full strict types:\n *\n * declare module '@pyreon/styler' {\n * interface DefaultTheme {\n * colors: { primary: string; secondary: string }\n * spacing: (n: number) => string\n * }\n * }\n */\nimport type { VNode, VNodeChild } from '@pyreon/core'\nimport { createContext, provide, useContext } from '@pyreon/core'\n\nexport interface DefaultTheme {}\n\ntype Theme = DefaultTheme & Record<string, unknown>\n\nexport const ThemeContext = createContext<Theme>({} as Theme)\n\n/** Hook to read the current theme from the nearest ThemeProvider. */\nexport const useTheme = <T extends object = Theme>(): T => useContext(ThemeContext) as T\n\n/**\n * @internal Low-level provider — use `PyreonUI` from `@pyreon/ui-core` instead.\n *\n * Provides a theme object to all nested styled components via Pyreon context.\n *\n * @deprecated Prefer `<PyreonUI theme={theme}>` which provides theme to\n * all three context layers (styler, core, mode) in one component.\n */\nexport function ThemeProvider({\n theme,\n children,\n}: {\n theme: Theme\n children?: VNodeChild\n}): VNode | null {\n provide(ThemeContext, theme)\n return (children ?? null) as VNode | null\n}\n","/**\n * createGlobalStyle() — tagged template function that injects global CSS\n * rules (not scoped to a class name). Returns a component function that\n * injects styles when called and supports dynamic interpolations via\n * props/theme.\n *\n * Usage:\n * const GlobalStyle = createGlobalStyle`\n * body { margin: 0; font-family: ${({ theme }) => theme.font}; }\n * *, *::before, *::after { box-sizing: border-box; }\n * `\n */\nimport type { ComponentFn } from '@pyreon/core'\nimport { type Interpolation, normalizeCSS, resolve } from './resolve'\nimport { isDynamic } from './shared'\nimport { sheet } from './sheet'\nimport { useTheme } from './ThemeProvider'\n\nexport const createGlobalStyle = (\n strings: TemplateStringsArray,\n ...values: Interpolation[]\n): ComponentFn => {\n const hasDynamicValues = values.some(isDynamic)\n\n // STATIC FAST PATH: compute once at creation time\n if (!hasDynamicValues) {\n const cssText = normalizeCSS(resolve(strings, values, {}))\n\n // Inject into sheet immediately\n if (cssText.trim()) sheet.insertGlobal(cssText)\n\n const StaticGlobal: ComponentFn = () => null\n return StaticGlobal\n }\n\n // DYNAMIC PATH: resolve on every render with theme/props\n const DynamicGlobal: ComponentFn = (props: Record<string, any>) => {\n const theme = useTheme()\n const allProps = { ...props, theme }\n const cssText = normalizeCSS(resolve(strings, values, allProps))\n\n if (cssText.trim()) sheet.insertGlobal(cssText)\n\n return null\n }\n\n return DynamicGlobal\n}\n","/**\n * keyframes() tagged template function. Creates a CSS @keyframes rule,\n * injects it into the stylesheet, and returns the generated animation name.\n *\n * Usage:\n * const fadeIn = keyframes`\n * from { opacity: 0; }\n * to { opacity: 1; }\n * `\n * // fadeIn === \"pyr-kf-abc123\" (deterministic, hash-based)\n */\nimport { hash } from './hash'\nimport { type Interpolation, normalizeCSS, resolve } from './resolve'\nimport { sheet } from './sheet'\n\nclass KeyframesResult {\n readonly name: string\n\n constructor(strings: TemplateStringsArray, values: Interpolation[]) {\n const body = normalizeCSS(resolve(strings, values, {}))\n const h = hash(body)\n this.name = `pyr-kf-${h}`\n\n sheet.insertKeyframes(this.name, body)\n }\n\n /** Returns the animation name when used in string context. */\n toString(): string {\n return this.name\n }\n}\n\nexport const keyframes = (\n strings: TemplateStringsArray,\n ...values: Interpolation[]\n): KeyframesResult => new KeyframesResult(strings, values)\n","/**\n * styled() component factory. Creates Pyreon components that inject CSS\n * class names from tagged template literals.\n *\n * Supports:\n * - styled('div')`...` and styled(Component)`...`\n * - styled.div`...` (via Proxy)\n * - `as` prop for polymorphic rendering\n * - $-prefixed transient props (not forwarded to DOM)\n * - Custom shouldForwardProp for per-component prop filtering\n * - Static path optimization (templates with no dynamic interpolations)\n * - Boost specificity via doubled selector\n *\n * CSS nesting (`&` selectors) works natively — the resolver passes CSS\n * through without transformation, so `&:hover`, `&::before`, etc. work\n * as-is in browsers supporting CSS Nesting (all modern browsers).\n */\nimport type { ComponentFn, VNode } from '@pyreon/core'\nimport { h } from '@pyreon/core'\nimport { effect, runUntracked } from '@pyreon/reactivity'\nimport { buildProps } from './forward'\nimport { type Interpolation, normalizeCSS, resolve } from './resolve'\nimport { isDynamic } from './shared'\nimport { sheet } from './sheet'\nimport { useTheme } from './ThemeProvider'\n\ntype Tag = string | ComponentFn<any>\n\nexport interface StyledOptions {\n /** Custom prop filter. Return true to forward the prop to the DOM element. */\n shouldForwardProp?: (prop: string) => boolean\n /**\n * CSS @layer name. Rules are wrapped in `@layer <name> { ... }`.\n * All framework CSS uses a single 'pyreon' layer. Source order within\n * the layer determines override precedence (rocketstyle inserts after base).\n */\n layer?: string\n}\n\nconst getDisplayName = (tag: Tag): string =>\n typeof tag === 'string'\n ? tag\n : (tag as ComponentFn<any> & { displayName?: string }).displayName || tag.name || 'Component'\n\n// Component cache: same template literal + tag + no options → same component.\n// WeakMap on `strings` (TemplateStringsArray is object-identity per source location).\nconst staticComponentCache = new WeakMap<TemplateStringsArray, Map<Tag, ComponentFn>>()\n\n// Single-entry hot cache — just 3 reference comparisons, no Map/WeakMap overhead.\nlet _hotStrings: TemplateStringsArray | null = null\nlet _hotTag: Tag | null = null\nlet _hotComponent: ComponentFn | null = null\n\nconst createStyledComponent = (\n tag: Tag,\n strings: TemplateStringsArray,\n values: Interpolation[],\n options?: StyledOptions,\n): ComponentFn => {\n // Ultra-fast hot cache: 3 reference comparisons → return immediately\n if (values.length === 0 && !options) {\n if (strings === _hotStrings && tag === _hotTag) return _hotComponent as ComponentFn\n\n // WeakMap fallback for alternating patterns\n const tagMap = staticComponentCache.get(strings)\n if (tagMap) {\n const cached = tagMap.get(tag)\n if (cached) {\n _hotStrings = strings\n _hotTag = tag\n _hotComponent = cached\n return cached\n }\n }\n }\n\n // Fast check: no values means no dynamic interpolations — avoids .some() scan\n const hasDynamicValues = values.length > 0 && values.some(isDynamic)\n const customFilter = options ? options.shouldForwardProp : undefined\n const insertLayer = options?.layer\n\n // STATIC FAST PATH: no function interpolations → compute class once at creation time\n if (!hasDynamicValues) {\n // Inline resolve for the common no-values case\n const raw = values.length === 0 ? (strings[0] as string) : resolve(strings, values, {})\n const cssText = normalizeCSS(raw)\n const hasCss = cssText.length > 0\n\n const staticClassName = hasCss ? sheet.insert(cssText, false, insertLayer) : ''\n\n const StaticStyled: ComponentFn = (rawProps: Record<string, any>): VNode | null => {\n const finalTag = rawProps.as || tag\n const isDOM = typeof finalTag === 'string'\n const finalProps = buildProps(rawProps, staticClassName, isDOM, customFilter)\n\n return h(\n finalTag as string,\n finalProps,\n ...(Array.isArray(rawProps.children)\n ? rawProps.children\n : rawProps.children != null\n ? [rawProps.children]\n : []),\n )\n }\n\n ;(StaticStyled as ComponentFn & { displayName?: string }).displayName =\n `styled(${getDisplayName(tag)})`\n\n // Store in component cache + hot cache for future reuse\n if (!options && values.length === 0) {\n let tagMap = staticComponentCache.get(strings)\n if (!tagMap) {\n tagMap = new Map()\n staticComponentCache.set(strings, tagMap)\n }\n tagMap.set(tag, StaticStyled)\n _hotStrings = strings\n _hotTag = tag\n _hotComponent = StaticStyled\n }\n\n return StaticStyled\n }\n\n // DYNAMIC PATH: resolve CSS on every render with theme/props.\n // When $rocketstyle is a function accessor (from rocketstyle's\n // EnhancedComponent), we resolve it initially for the first class,\n // then set up an effect to reactively swap classes when mode changes.\n // This avoids VNode remounting — only classList updates on the DOM element.\n const DynamicStyled: ComponentFn = (rawProps: Record<string, any>): VNode | null => {\n const theme = useTheme()\n const $rs = rawProps.$rocketstyle\n const $rsState = rawProps.$rocketstate\n const isReactiveRS = typeof $rs === 'function'\n const isReactiveState = typeof $rsState === 'function'\n\n // Resolve initial accessor values — both $rocketstyle and $rocketstate\n // must be plain objects when passed to resolve(), because .styles()\n // interpolation functions destructure them directly:\n // const { hover, pressed } = $rocketstate.pseudo\n // const { hover: hoverStyles } = $rocketstyle\n const resolvedRS = isReactiveRS ? $rs() : $rs\n const resolvedState = isReactiveState ? $rsState() : $rsState\n const initialProps = {\n ...rawProps,\n ...(isReactiveRS ? { $rocketstyle: resolvedRS } : {}),\n ...(isReactiveState ? { $rocketstate: resolvedState } : {}),\n }\n const cssText = normalizeCSS(resolve(strings, values, { ...initialProps, theme }))\n const initialClassName = cssText.length > 0 ? sheet.insert(cssText, false, insertLayer) : ''\n\n const finalTag = rawProps.as || tag\n const isDOM = typeof finalTag === 'string'\n\n // Track mounted element for reactive class updates\n let el: Element | null = null\n let currentClassName = initialClassName\n\n const originalRef = rawProps.ref\n const refCallback = (node: Element | null) => {\n el = node\n if (originalRef) {\n if (typeof originalRef === 'function') originalRef(node)\n else if (originalRef && typeof originalRef === 'object') originalRef.current = node\n }\n }\n\n const finalProps = buildProps(\n { ...rawProps, ref: isReactiveRS ? refCallback : rawProps.ref },\n initialClassName,\n isDOM,\n customFilter,\n )\n\n // Set up reactive class swap when $rocketstyle is a function accessor.\n // CRITICAL: only $rs() is tracked. resolve() and DOM mutations run\n // inside runUntracked() to prevent subscribing to signals read by\n // interpolation functions (theme properties, context getters, etc.).\n // Without this, every styled component's effect subscribes to every\n // signal touched during CSS resolution — causing an exponential\n // cascade across 50+ components on any signal change.\n if (isReactiveRS) {\n effect(() => {\n const newRS = $rs() // TRACKED: subscribes to mode + dimension signals\n const newState = isReactiveState ? $rsState() : $rsState // TRACKED\n\n runUntracked(() => {\n // UNTRACKED: resolve + DOM mutation — no additional subscriptions\n const newResolvedProps = {\n ...rawProps,\n $rocketstyle: newRS,\n $rocketstate: newState,\n }\n const newCss = normalizeCSS(\n resolve(strings, values, { ...newResolvedProps, theme }),\n )\n const newClass = newCss.length > 0 ? sheet.insert(newCss, false, insertLayer) : ''\n\n if (el && newClass !== currentClassName) {\n if (currentClassName) el.classList.remove(currentClassName)\n if (newClass) el.classList.add(newClass)\n currentClassName = newClass\n }\n })\n })\n }\n\n // STATIC VNode — created once, never remounted on mode change\n return h(\n finalTag as string,\n finalProps,\n ...(Array.isArray(rawProps.children)\n ? rawProps.children\n : rawProps.children != null\n ? [rawProps.children]\n : []),\n )\n }\n\n ;(DynamicStyled as ComponentFn & { displayName?: string }).displayName =\n `styled(${getDisplayName(tag)})`\n return DynamicStyled\n}\n\n/** Factory function: styled(tag) returns a tagged template function. */\nconst styledFactory = (tag: Tag, options?: StyledOptions) => {\n const templateFn = (strings: TemplateStringsArray, ...values: Interpolation[]) =>\n createStyledComponent(tag, strings, values, options)\n\n return templateFn\n}\n\n/**\n * Main styled export. Supports both calling conventions:\n * - `styled('div')` or `styled(Component)` → returns tagged template function\n * - `styled('div', { shouldForwardProp })` → with custom prop filtering\n * - `styled.div` → shorthand via Proxy (no options)\n */\n// Cache template functions per tag to avoid closure allocation on every Proxy get\nconst proxyCache = new Map<string, (...args: any[]) => any>()\n\ntype TagTemplateFn = (strings: TemplateStringsArray, ...values: Interpolation[]) => ComponentFn\n\ntype HtmlTags =\n | 'a'\n | 'abbr'\n | 'address'\n | 'article'\n | 'aside'\n | 'audio'\n | 'b'\n | 'blockquote'\n | 'body'\n | 'br'\n | 'button'\n | 'canvas'\n | 'caption'\n | 'code'\n | 'col'\n | 'colgroup'\n | 'dd'\n | 'details'\n | 'div'\n | 'dl'\n | 'dt'\n | 'em'\n | 'fieldset'\n | 'figcaption'\n | 'figure'\n | 'footer'\n | 'form'\n | 'h1'\n | 'h2'\n | 'h3'\n | 'h4'\n | 'h5'\n | 'h6'\n | 'head'\n | 'header'\n | 'hr'\n | 'html'\n | 'i'\n | 'iframe'\n | 'img'\n | 'input'\n | 'label'\n | 'legend'\n | 'li'\n | 'link'\n | 'main'\n | 'mark'\n | 'menu'\n | 'meta'\n | 'nav'\n | 'ol'\n | 'optgroup'\n | 'option'\n | 'output'\n | 'p'\n | 'picture'\n | 'pre'\n | 'progress'\n | 'q'\n | 'section'\n | 'select'\n | 'small'\n | 'source'\n | 'span'\n | 'strong'\n | 'style'\n | 'sub'\n | 'summary'\n | 'sup'\n | 'svg'\n | 'table'\n | 'tbody'\n | 'td'\n | 'template'\n | 'textarea'\n | 'tfoot'\n | 'th'\n | 'thead'\n | 'time'\n | 'tr'\n | 'u'\n | 'ul'\n | 'video'\n\nexport type StyledFunction = ((tag: Tag, options?: StyledOptions) => TagTemplateFn) & {\n [K in HtmlTags]: TagTemplateFn\n}\n\n// Proxy is needed to support styled.div`...` syntax; the cast bridges\n// styledFactory's call signature to StyledFunction which adds HTML tag properties.\n// Proxy target uses `as any` because TS can't resolve Proxy<StyledFunction> with mapped types\nexport const styled: StyledFunction = new Proxy(styledFactory as any, {\n get(_target: unknown, prop: string) {\n if (prop === 'prototype' || prop === '$$typeof') return undefined\n // styled.div`...`, styled.span`...`, etc.\n let fn = proxyCache.get(prop)\n if (!fn) {\n fn = (strings: TemplateStringsArray, ...values: Interpolation[]) =>\n createStyledComponent(prop, strings, values)\n proxyCache.set(prop, fn)\n }\n return fn\n },\n})\n","/**\n * Hook that resolves a CSSResult template with props, injects CSS\n * into the shared stylesheet, and returns the className.\n *\n * Use this when you need computed CSS class names on plain elements\n * without the overhead of a styled component layer.\n */\nimport { type CSSResult, normalizeCSS, resolve } from './resolve'\nimport { sheet } from './sheet'\nimport { useTheme } from './ThemeProvider'\n\nexport function useCSS(template: CSSResult, props?: Record<string, any>, boost?: boolean): string {\n const theme = useTheme()\n const allProps = theme ? { ...props, theme } : (props ?? {})\n const cssText = normalizeCSS(resolve(template.strings, template.values, allProps))\n\n if (!cssText.trim()) return ''\n\n return sheet.insert(cssText, boost)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/resolve.ts","../src/css.ts","../src/forward.ts","../src/shared.ts","../src/hash.ts","../src/sheet.ts","../src/ThemeProvider.ts","../src/globalStyle.ts","../src/keyframes.ts","../src/styled.tsx","../src/useCSS.ts"],"sourcesContent":["/**\n * Interpolation resolver: converts tagged template strings + values into a\n * final CSS string. Handles nested CSSResults, arrays, functions, and\n * primitive values.\n */\n\nimport type { DefaultTheme } from './ThemeProvider'\n\n/**\n * Props passed to interpolation functions inside tagged templates.\n * Generic `P` allows consumers to type their custom props (e.g. transient $-prefixed):\n *\n * @example\n * styled('div')<{ $color: string }>`\n * background: ${(props) => props.$color}; // props.$color is typed!\n * `\n */\nexport type StyledProps<P extends object = Record<string, unknown>> = P & {\n theme?: DefaultTheme & Record<string, unknown>\n}\n\nexport type Interpolation<P extends object = Record<string, unknown>> =\n | string\n | number\n | boolean\n | null\n | undefined\n | CSSResult\n | Interpolation<P>[]\n | ((props: StyledProps<P>) => Interpolation<P>)\n\n/**\n * Lazy representation of a `css` tagged template. Stores the raw template\n * strings and interpolation values without resolving them. Resolution is\n * deferred until a styled component renders (or until explicitly resolved).\n */\nexport class CSSResult {\n constructor(\n readonly strings: TemplateStringsArray,\n readonly values: Interpolation[],\n ) {}\n\n /** Resolve with empty props — useful for static templates, testing, and debugging. */\n toString(): string {\n return resolve(this.strings, this.values, {})\n }\n}\n\n/** Resolve a tagged template's strings + values into a final CSS string. */\nexport const resolve = (\n strings: TemplateStringsArray,\n values: Interpolation[],\n props: Record<string, any>,\n): string => {\n // Tagged templates guarantee strings.length === values.length + 1,\n // so strings[0] and strings[i+1] are always defined — no ?? needed.\n let result = strings[0] as string\n for (let i = 0; i < values.length; i++) {\n const v = values[i]\n const s = strings[i + 1] as string\n // Inline the most common value types to avoid function call overhead.\n if (typeof v === 'function') {\n const r = v(props)\n result +=\n (typeof r === 'string'\n ? r\n : r == null || r === false || r === true\n ? ''\n : resolveValue(r as Interpolation, props)) + s\n } else if (v == null || v === false || v === true) {\n result += s\n } else if (typeof v === 'string') {\n result += v + s\n } else if (typeof v === 'number') {\n result += v + s\n } else {\n result += resolveValue(v, props) + s\n }\n }\n return result\n}\n\n/**\n * Normalize resolved CSS text for strict `insertRule` compatibility.\n *\n * Single-pass scanner that handles all cleanup in one traversal:\n * - Strips block comments and line comments (preserves :// in URLs)\n * - Collapses whitespace to single spaces\n * - Removes redundant semicolons\n * - Trims leading/trailing whitespace\n */\nconst normCache = new Map<string, string>()\n/** Clear the normalizeCSS cache (called during HMR cleanup). */\nexport const clearNormCache = () => normCache.clear()\n\nexport const normalizeCSS = (css: string): string => {\n const cached = normCache.get(css)\n if (cached !== undefined) return cached\n\n const len = css.length\n let out = ''\n let space = false // pending space to emit before next non-whitespace char\n let last = 0 // charCode of last char written to output (0 = nothing yet)\n\n for (let i = 0; i < len; i++) {\n const c = css.charCodeAt(i)\n\n // /* block comment */\n if (c === 47 /* / */ && css.charCodeAt(i + 1) === 42 /* * */) {\n const end = css.indexOf('*/', i + 2)\n i = end === -1 ? len : end + 1\n space = true\n continue\n }\n\n // // line comment (but not :// in URLs)\n if (c === 47 /* / */ && css.charCodeAt(i + 1) === 47 /* / */ && last !== 58 /* : */) {\n const nl = css.indexOf('\\n', i + 2)\n i = nl === -1 ? len : nl\n space = true\n continue\n }\n\n // Whitespace → collapse\n if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {\n space = true\n continue\n }\n\n // Semicolon → skip if redundant (after start, {, }, or another ;)\n if (c === 59 /* ; */) {\n if (last === 0 || last === 123 /* { */ || last === 125 /* } */ || last === 59 /* ; */) {\n continue\n }\n space = false\n out += ';'\n last = 59\n continue\n }\n\n // Regular char — emit pending space (but not at start of output)\n if (space && last !== 0) out += ' '\n space = false\n\n out += css[i]\n last = c\n }\n\n // Evict oldest ~10% to prevent memory leaks without cliff-edge drop\n if (normCache.size > 2000) {\n let count = 0\n for (const key of normCache.keys()) {\n if (count >= 200) break\n normCache.delete(key)\n count++\n }\n }\n normCache.set(css, out)\n\n return out\n}\n\nexport const resolveValue = (value: Interpolation, props: Record<string, any>): string => {\n // null, undefined, false, true → empty (enables conditional: ${cond && css`...`})\n if (value == null || value === false || value === true) return ''\n\n // function interpolation → call with props/theme context, resolve result\n if (typeof value === 'function') return resolveValue(value(props) as Interpolation, props)\n\n // nested CSSResult → recursively resolve\n if (value instanceof CSSResult) return resolve(value.strings, value.values, props)\n\n // array of results (e.g. from makeItResponsive's breakpoints.map())\n if (Array.isArray(value)) {\n let arrayResult = ''\n for (let i = 0; i < value.length; i++) {\n arrayResult += resolveValue(value[i], props)\n }\n return arrayResult\n }\n\n return String(value)\n}\n","import { CSSResult, type Interpolation } from './resolve'\n\n/**\n * Tagged template function for CSS. Captures the template strings and\n * interpolation values as a lazy CSSResult — resolution is deferred\n * until a styled component renders.\n *\n * Works as both a tagged template (`css\\`...\\``) and a regular function\n * call (`css(...args)`) since tagged templates are syntactic sugar for\n * function calls with (TemplateStringsArray, ...values).\n */\nexport const css = (strings: TemplateStringsArray, ...values: Interpolation[]): CSSResult =>\n new CSSResult(strings, values)\n","/**\n * HTML prop filtering. Prevents unknown props from being forwarded to DOM\n * elements (which causes warnings). Props starting with `$` are\n * transient (styling-only) and are always filtered out.\n */\n\n// Common HTML attributes, event handlers, and ARIA/data attributes\nconst HTML_PROPS = new Set([\n // Core props\n 'className',\n 'class',\n 'dangerouslySetInnerHTML',\n 'htmlFor',\n 'id',\n 'key',\n 'ref',\n 'style',\n 'tabIndex',\n 'role',\n // Event handlers\n 'onAbort',\n 'onAnimationEnd',\n 'onAnimationIteration',\n 'onAnimationStart',\n 'onBlur',\n 'onChange',\n 'onClick',\n 'onCompositionEnd',\n 'onCompositionStart',\n 'onCompositionUpdate',\n 'onContextMenu',\n 'onCopy',\n 'onCut',\n 'onDoubleClick',\n 'onDrag',\n 'onDragEnd',\n 'onDragEnter',\n 'onDragLeave',\n 'onDragOver',\n 'onDragStart',\n 'onDrop',\n 'onError',\n 'onFocus',\n 'onInput',\n 'onKeyDown',\n 'onKeyPress',\n 'onKeyUp',\n 'onLoad',\n 'onMouseDown',\n 'onMouseEnter',\n 'onMouseLeave',\n 'onMouseMove',\n 'onMouseOut',\n 'onMouseOver',\n 'onMouseUp',\n 'onPaste',\n 'onPointerCancel',\n 'onPointerDown',\n 'onPointerEnter',\n 'onPointerLeave',\n 'onPointerMove',\n 'onPointerOut',\n 'onPointerOver',\n 'onPointerUp',\n 'onScroll',\n 'onSelect',\n 'onSubmit',\n 'onTouchCancel',\n 'onTouchEnd',\n 'onTouchMove',\n 'onTouchStart',\n 'onTransitionEnd',\n 'onWheel',\n // HTML attributes\n 'accept',\n 'acceptCharset',\n 'accessKey',\n 'action',\n 'allow',\n 'allowFullScreen',\n 'alt',\n 'as',\n 'async',\n 'autoCapitalize',\n 'autoComplete',\n 'autoCorrect',\n 'autoFocus',\n 'autoPlay',\n 'capture',\n 'cellPadding',\n 'cellSpacing',\n 'charSet',\n 'checked',\n 'cite',\n 'cols',\n 'colSpan',\n 'content',\n 'contentEditable',\n 'controls',\n 'controlsList',\n 'coords',\n 'crossOrigin',\n 'dateTime',\n 'decoding',\n 'default',\n 'defaultChecked',\n 'defaultValue',\n 'defer',\n 'dir',\n 'disabled',\n 'disablePictureInPicture',\n 'disableRemotePlayback',\n 'download',\n 'draggable',\n 'encType',\n 'enterKeyHint',\n 'fetchPriority',\n 'form',\n 'formAction',\n 'formEncType',\n 'formMethod',\n 'formNoValidate',\n 'formTarget',\n 'frameBorder',\n 'headers',\n 'height',\n 'hidden',\n 'high',\n 'href',\n 'hrefLang',\n 'httpEquiv',\n 'inputMode',\n 'integrity',\n 'is',\n 'label',\n 'lang',\n 'list',\n 'loading',\n 'loop',\n 'low',\n 'max',\n 'maxLength',\n 'media',\n 'method',\n 'min',\n 'minLength',\n 'multiple',\n 'muted',\n 'name',\n 'noModule',\n 'noValidate',\n 'nonce',\n 'open',\n 'optimum',\n 'pattern',\n 'placeholder',\n 'playsInline',\n 'poster',\n 'preload',\n 'readOnly',\n 'referrerPolicy',\n 'rel',\n 'required',\n 'reversed',\n 'rows',\n 'rowSpan',\n 'sandbox',\n 'scope',\n 'scoped',\n 'scrolling',\n 'selected',\n 'shape',\n 'size',\n 'sizes',\n 'slot',\n 'span',\n 'spellCheck',\n 'src',\n 'srcDoc',\n 'srcLang',\n 'srcSet',\n 'start',\n 'step',\n 'summary',\n 'target',\n 'title',\n 'translate',\n 'type',\n 'useMap',\n 'value',\n 'width',\n 'wrap',\n])\n\n/**\n * Filters props for HTML elements. Keeps valid HTML attrs, data-*, aria-*.\n * Rejects unknown props and $-prefixed transient props.\n */\nexport const filterProps = (props: Record<string, unknown>): Record<string, unknown> => {\n const filtered: Record<string, unknown> = {}\n\n for (const key in props) {\n // Skip transient props ($-prefixed) — used for styling-only props\n if (key.charCodeAt(0) === 36) continue // '$'\n\n // Skip `as` prop — handled separately by styled\n if (key === 'as') continue\n\n // Keep data-* and aria-* attributes\n if (key.startsWith('data-') || key.startsWith('aria-')) {\n filtered[key] = props[key]\n continue\n }\n\n // Keep known HTML props\n if (HTML_PROPS.has(key)) {\n filtered[key] = props[key]\n }\n }\n\n return filtered\n}\n\n/**\n * Build final props for a styled component in a single pass.\n * Combines className merging, ref injection, and prop filtering into one\n * allocation and one iteration.\n */\nexport const buildProps = (\n rawProps: Record<string, any>,\n generatedCls: string,\n isDOM: boolean,\n customFilter?: (prop: string) => boolean,\n): Record<string, any> => {\n const result: Record<string, any> = {}\n\n // Merge generated + user className\n const userCls = rawProps.class || rawProps.className\n if (generatedCls) {\n result.class = userCls ? `${generatedCls} ${userCls}` : generatedCls\n } else if (userCls) {\n result.class = userCls\n }\n\n // Component target — forward all props except as/className/class and $-prefixed\n if (!isDOM) {\n for (const key in rawProps) {\n if (key === 'as' || key === 'className' || key === 'class') continue\n if (key.charCodeAt(0) === 36) continue // $-prefixed transient\n result[key] = rawProps[key]\n }\n return result\n }\n\n // DOM element with custom shouldForwardProp\n if (customFilter) {\n for (const key in rawProps) {\n if (key === 'as' || key === 'className' || key === 'class') continue\n if (customFilter(key)) result[key] = rawProps[key]\n }\n return result\n }\n\n // DOM element with default filtering\n for (const key in rawProps) {\n if (key === 'as' || key === 'className' || key === 'class') continue\n if (key.charCodeAt(0) === 36) continue // $-prefixed transient\n if (key.startsWith('data-') || key.startsWith('aria-')) {\n result[key] = rawProps[key]\n continue\n }\n if (HTML_PROPS.has(key)) result[key] = rawProps[key]\n }\n return result\n}\n","/**\n * Shared utilities used across multiple modules.\n */\nimport { CSSResult, type Interpolation } from './resolve'\n\n/** Check if an interpolation value is dynamic (contains functions or nested dynamic CSSResults). */\nexport const isDynamic = (v: Interpolation): boolean => {\n if (typeof v === 'function') return true\n if (Array.isArray(v)) return v.some(isDynamic)\n if (v instanceof CSSResult) return v.values.some(isDynamic)\n return false\n}\n","/**\n * Fast FNV-1a non-cryptographic hash. Returns base-36 string for compact class names.\n *\n * 32-bit hash space → ~4.3 billion unique values. Collision probability is\n * negligible for typical applications (< 10,000 unique CSS rules).\n */\n\n/** FNV-1a offset basis — starting state for streaming hash. */\nexport const HASH_INIT = 2166136261\n\nconst FNV_PRIME = 16777619\n\n/**\n * Feed a string segment into the running hash state.\n * Streaming: hashUpdate(hashUpdate(HASH_INIT, 'ab'), 'cd') === hash('abcd').\n */\nexport const hashUpdate = (init: number, str: string): number => {\n let h = init\n for (let i = 0; i < str.length; i++) {\n h ^= str.charCodeAt(i)\n h = Math.imul(h, FNV_PRIME)\n }\n return h\n}\n\n/** Finalize a hash state into a base-36 class name suffix. */\nexport const hashFinalize = (h: number): string => (h >>> 0).toString(36)\n\n/** Hash a complete string in one shot. Returns base-36 string. */\nexport const hash = (str: string): string => hashFinalize(hashUpdate(HASH_INIT, str))\n","/**\n * StyleSheet manager. Handles CSS rule injection, hash-based deduplication,\n * SSR buffering, client-side hydration, bounded cache, and @layer support.\n *\n * Media queries (@media), @supports, and @container blocks nested inside\n * component CSS are automatically extracted into separate top-level rules.\n */\nimport { hash } from './hash'\nimport { clearNormCache } from './resolve'\n\nconst PREFIX = 'pyr'\nconst ATTR = 'data-pyreon-styler'\nconst DEFAULT_MAX_CACHE_SIZE = 10000\n\nexport interface StyleSheetOptions {\n /** Maximum number of cached rules before eviction (default: 10000). */\n maxCacheSize?: number\n /** CSS @layer name to wrap scoped rules in. */\n layer?: string\n}\n\nexport class StyleSheet {\n private cache = new Map<string, string>()\n private insertCache = new Map<string, string>()\n private sheet: CSSStyleSheet | null = null\n private ssrBuffer: string[] = []\n private isSSR: boolean\n private maxCacheSize: number\n private layer: string | undefined\n private supportsLayer = false\n\n constructor(options: StyleSheetOptions = {}) {\n this.maxCacheSize = options.maxCacheSize ?? DEFAULT_MAX_CACHE_SIZE\n this.layer = options.layer\n this.isSSR = typeof document === 'undefined'\n if (!this.isSSR) this.mount()\n }\n\n private mount() {\n // Reuse existing <style> tag from SSR hydration\n const existing = document.querySelector(`style[${ATTR}]`) as HTMLStyleElement | null\n\n if (existing) {\n this.sheet = existing.sheet ?? null\n this.hydrateFromTag(existing)\n } else {\n const el = document.createElement('style')\n el.setAttribute(ATTR, '')\n document.head.appendChild(el)\n this.sheet = el.sheet ?? null\n }\n\n // Inject single @layer for all framework CSS.\n // Using one shared layer ensures rocketstyle overrides base via source\n // order (rocketstyle rules inserted after base), while media queries\n // from base components still work correctly within the same layer.\n // A two-layer approach (base < rocketstyle) breaks responsive styles\n // because higher layers always win regardless of @media conditions.\n if (this.sheet) {\n try {\n this.sheet.insertRule('@layer pyreon;', 0)\n this.supportsLayer = true\n } catch {\n // @layer not supported — falls back to source order\n }\n }\n }\n\n /** Extract className from a selector like \".pyr-abc\" or \".pyr-abc.pyr-abc\" → \"pyr-abc\" */\n private extractClassName(selectorText: string): string | null {\n if (selectorText[0] !== '.') return null\n const dotIdx = selectorText.indexOf('.', 1)\n return dotIdx > 0 ? selectorText.slice(1, dotIdx) : selectorText.slice(1)\n }\n\n /** Parse existing rules from SSR-rendered <style> tag into cache. */\n private hydrateFromTag(el: HTMLStyleElement) {\n const sheet = el.sheet\n if (!sheet) return\n\n for (let i = 0; i < sheet.cssRules.length; i++) {\n const rule = sheet.cssRules[i]\n\n if (rule instanceof CSSStyleRule) {\n const className = this.extractClassName(rule.selectorText)\n if (className) this.cache.set(className, className)\n }\n\n // Handle split @media rules that wrap our selectors\n if (typeof CSSMediaRule !== 'undefined' && rule instanceof CSSMediaRule) {\n for (let j = 0; j < rule.cssRules.length; j++) {\n const inner = rule.cssRules[j]\n if (inner instanceof CSSStyleRule) {\n const className = this.extractClassName(inner.selectorText)\n if (className) this.cache.set(className, className)\n }\n }\n }\n }\n }\n\n /** Evict oldest entries when cache exceeds max size. */\n private evictIfNeeded() {\n if (this.cache.size <= this.maxCacheSize) return\n\n // Map iteration order is insertion order — delete oldest 10%\n const toDelete = Math.floor(this.maxCacheSize * 0.1)\n let count = 0\n for (const key of this.cache.keys()) {\n if (count >= toDelete) break\n this.cache.delete(key)\n count++\n }\n }\n\n /**\n * Extract nested at-rules (@media, @supports, @container) from CSS text\n * and wrap their content in the given selector as separate top-level rules.\n */\n private splitAtRules(cssText: string, selector: string): { base: string; atRules: string[] } {\n // Fast path: no at-rules to split\n if (cssText.indexOf('@') === -1) return { base: cssText, atRules: [] }\n\n const atRules: string[] = []\n const baseParts: string[] = []\n let depth = 0\n let atStart = -1\n let lastBase = 0\n\n for (let i = 0; i < cssText.length; i++) {\n const ch = cssText[i]\n\n if (ch === '{') {\n depth++\n } else if (ch === '}') {\n depth--\n if (depth === 0 && atStart >= 0) {\n // End of a tracked at-rule block — extract and wrap with selector\n const openBrace = cssText.indexOf('{', atStart)\n const atPrefix = cssText.slice(atStart, openBrace).trim()\n const innerCSS = cssText.slice(openBrace + 1, i).trim()\n if (innerCSS) {\n atRules.push(`${atPrefix}{${selector}{${innerCSS}}}`)\n }\n atStart = -1\n lastBase = i + 1\n }\n } else if (depth === 0 && ch === '@' && atStart < 0) {\n // Check if this starts a splittable at-rule (not @keyframes, @font-face, etc.)\n const remaining = cssText.slice(i, i + 20)\n if (/^@(?:media|supports|container)\\b/.test(remaining)) {\n // Save any base CSS that precedes this at-rule\n const baseBefore = cssText.slice(lastBase, i).trim()\n if (baseBefore) baseParts.push(baseBefore)\n atStart = i\n }\n }\n }\n\n // Collect remaining base CSS after the last at-rule\n if (lastBase < cssText.length && atStart < 0) {\n const remaining = cssText.slice(lastBase).trim()\n if (remaining) baseParts.push(remaining)\n }\n\n // If no at-rules were found, return original unchanged\n if (atRules.length === 0) return { base: cssText, atRules: [] }\n\n return { base: baseParts.join(' '), atRules }\n }\n\n /**\n * Compute a className from CSS text without injecting (pure function).\n */\n getClassName(cssText: string): string {\n const cached = this.insertCache.get(cssText)\n if (cached) return cached\n const h = hash(cssText)\n return `${PREFIX}-${h}`\n }\n\n /**\n * Insert CSS rules for a component. Returns the class name (deterministic, hash-based).\n * Deduplicates: same CSS text always produces the same class name and\n * the rules are only injected once.\n *\n * @param cssText - CSS declarations to insert\n * @param _unused - Reserved for backward compatibility (was `boost`)\n * @param insertLayer - CSS @layer to wrap this rule in (e.g. 'rocketstyle').\n * Used by rocketstyle to ensure wrapper styles override inner component styles\n * via @layer order (base < rocketstyle) instead of specificity hacks.\n */\n insert(cssText: string, _unused = false, insertLayer?: string): string {\n // Fast path: skip hash computation on repeated insertions of same CSS text\n const icKey = insertLayer ? `${cssText}\\0L:${insertLayer}` : cssText\n const icHit = this.insertCache.get(icKey)\n if (icHit) return icHit\n\n const h = hash(cssText)\n const className = `${PREFIX}-${h}`\n\n if (this.cache.has(className)) {\n this.insertCache.set(icKey, className)\n return className\n }\n\n this.evictIfNeeded()\n this.cache.set(className, className)\n\n const selector = `.${className}`\n\n // Split nested at-rules into separate top-level rules\n const { base, atRules } = this.splitAtRules(cssText, selector)\n\n const rules: string[] = []\n if (base) rules.push(`${selector}{${base}}`)\n rules.push(...atRules)\n\n // Apply @layer wrapping — per-insert layer takes precedence over sheet-level layer.\n // In SSR, always apply layers (output goes to real browsers).\n // In client, skip if @layer isn't supported (e.g. happy-dom in tests).\n const layerName = (this.isSSR || this.supportsLayer) ? (insertLayer ?? this.layer) : undefined\n const finalRules = layerName ? rules.map((r) => `@layer ${layerName}{${r}}`) : rules\n\n if (this.isSSR) {\n for (const rule of finalRules) {\n this.ssrBuffer.push(rule)\n }\n } else if (this.sheet) {\n for (const rule of finalRules) {\n try {\n this.sheet.insertRule(rule, this.sheet.cssRules.length)\n } catch (_e) {\n if (process.env.NODE_ENV !== 'production') {\n // oxlint-disable-next-line no-console\n console.warn('[styler] Failed to insert CSS rule:', rule, _e)\n }\n }\n }\n }\n\n this.insertCache.set(icKey, className)\n return className\n }\n\n /** Insert a @keyframes rule. Deduplicates by animation name. */\n insertKeyframes(name: string, body: string): void {\n if (this.cache.has(name)) return\n\n this.evictIfNeeded()\n this.cache.set(name, name)\n\n const rule = `@keyframes ${name}{${body}}`\n\n if (this.isSSR) {\n this.ssrBuffer.push(rule)\n } else if (this.sheet) {\n try {\n this.sheet.insertRule(rule, this.sheet.cssRules.length)\n } catch (_e) {\n if (process.env.NODE_ENV !== 'production') {\n // silently ignore invalid CSS rules in production\n }\n }\n }\n }\n\n /**\n * Split CSS text into individual top-level rules.\n * CSSStyleSheet.insertRule() only accepts one rule at a time.\n */\n private splitRules(cssText: string): string[] {\n const rules: string[] = []\n let depth = 0\n let start = 0\n\n for (let i = 0; i < cssText.length; i++) {\n const ch = cssText[i]\n if (ch === '{') depth++\n else if (ch === '}') {\n depth--\n if (depth === 0) {\n const rule = cssText.slice(start, i + 1).trim()\n if (rule) rules.push(rule)\n start = i + 1\n }\n }\n }\n\n return rules\n }\n\n /** Insert global CSS rules (no wrapper selector). Deduplicates by hash. */\n insertGlobal(cssText: string): void {\n const h = hash(cssText)\n const key = `global-${h}`\n\n if (this.cache.has(key)) return\n\n this.evictIfNeeded()\n this.cache.set(key, key)\n\n if (this.isSSR) {\n this.ssrBuffer.push(cssText)\n } else if (this.sheet) {\n const rules = this.splitRules(cssText)\n for (const rule of rules) {\n try {\n this.sheet.insertRule(rule, this.sheet.cssRules.length)\n } catch (_e) {\n if (process.env.NODE_ENV !== 'production') {\n // oxlint-disable-next-line no-console\n console.warn('[styler] Failed to insert global CSS rule:', rule, _e)\n }\n }\n }\n }\n }\n\n /** Returns collected CSS for SSR as a complete `<style>` tag string. */\n getStyleTag(): string {\n if (this.ssrBuffer.length === 0) return `<style ${ATTR}=\"\"></style>`\n const layerDecl = this.layer ? `@layer ${this.layer};` : ''\n const css = (layerDecl + this.ssrBuffer.join('')).replace(/<\\/style/gi, '<\\\\/style')\n return `<style ${ATTR}=\"\">${css}</style>`\n }\n\n /** Returns collected CSS rules as a raw string (useful for streaming SSR). */\n getStyles(): string {\n if (this.ssrBuffer.length === 0) return ''\n const layerDecl = this.layer ? `@layer ${this.layer};` : ''\n return layerDecl + this.ssrBuffer.join('')\n }\n\n /** Reset SSR buffer and cache (call between server requests). */\n reset(): void {\n this.ssrBuffer = []\n this.cache.clear()\n this.insertCache.clear()\n }\n\n /** Clear the dedup cache. Useful for HMR / dev-time reloads. */\n clearCache(): void {\n this.cache.clear()\n this.insertCache.clear()\n clearNormCache()\n }\n\n /**\n * Full cleanup: clear cache and remove all CSS rules from the DOM.\n * Intended for HMR / dev-time reloads where stale styles must be purged.\n */\n clearAll(): void {\n this.cache.clear()\n this.insertCache.clear()\n clearNormCache()\n this.ssrBuffer = []\n if (this.sheet) {\n while (this.sheet.cssRules.length > 0) {\n this.sheet.deleteRule(0)\n }\n }\n }\n\n /**\n * Compute className and full CSS rule text without injecting.\n */\n prepare(cssText: string): { className: string; rules: string } {\n const h = hash(cssText)\n const className = `${PREFIX}-${h}`\n const selector = `.${className}`\n const { base, atRules } = this.splitAtRules(cssText, selector)\n\n const allRules: string[] = []\n if (base) allRules.push(`${selector}{${base}}`)\n allRules.push(...atRules)\n\n const finalRules = this.layer ? allRules.map((r) => `@layer ${this.layer}{${r}}`) : allRules\n\n return { className, rules: finalRules.join('') }\n }\n\n /** Check if a className is already in the cache. O(1) Map lookup. */\n has(className: string): boolean {\n return this.cache.has(className)\n }\n\n /** Current number of cached rules. */\n get cacheSize(): number {\n return this.cache.size\n }\n}\n\n/** Default singleton sheet for client-side use. */\nexport const sheet = new StyleSheet({ layer: 'pyreon' })\n\n/**\n * Factory for creating isolated StyleSheet instances.\n * Use in SSR to get per-request isolation.\n */\nexport const createSheet = (options?: StyleSheetOptions): StyleSheet => new StyleSheet(options)\n","/**\n * Theme context for styled components.\n *\n * Extensible theme interface. Consumers can augment this via module\n * declaration merging for full strict types:\n *\n * declare module '@pyreon/styler' {\n * interface DefaultTheme {\n * colors: { primary: string; secondary: string }\n * spacing: (n: number) => string\n * }\n * }\n */\nimport type { VNode, VNodeChild } from '@pyreon/core'\nimport { createContext, provide, useContext } from '@pyreon/core'\n\nexport interface DefaultTheme {}\n\ntype Theme = DefaultTheme & Record<string, unknown>\n\nexport const ThemeContext = createContext<Theme>({} as Theme)\n\n/** Hook to read the current theme from the nearest ThemeProvider. */\nexport const useTheme = <T extends object = Theme>(): T => useContext(ThemeContext) as T\n\n/**\n * @internal Low-level provider — use `PyreonUI` from `@pyreon/ui-core` instead.\n *\n * Provides a theme object to all nested styled components via Pyreon context.\n *\n * @deprecated Prefer `<PyreonUI theme={theme}>` which provides theme to\n * all three context layers (styler, core, mode) in one component.\n */\nexport function ThemeProvider({\n theme,\n children,\n}: {\n theme: Theme\n children?: VNodeChild\n}): VNode | null {\n provide(ThemeContext, theme)\n return (children ?? null) as VNode | null\n}\n","/**\n * createGlobalStyle() — tagged template function that injects global CSS\n * rules (not scoped to a class name). Returns a component function that\n * injects styles when called and supports dynamic interpolations via\n * props/theme.\n *\n * Usage:\n * const GlobalStyle = createGlobalStyle`\n * body { margin: 0; font-family: ${({ theme }) => theme.font}; }\n * *, *::before, *::after { box-sizing: border-box; }\n * `\n */\nimport type { ComponentFn } from '@pyreon/core'\nimport { type Interpolation, normalizeCSS, resolve } from './resolve'\nimport { isDynamic } from './shared'\nimport { sheet } from './sheet'\nimport { useTheme } from './ThemeProvider'\n\nexport const createGlobalStyle = (\n strings: TemplateStringsArray,\n ...values: Interpolation[]\n): ComponentFn => {\n const hasDynamicValues = values.some(isDynamic)\n\n // STATIC FAST PATH: compute once at creation time\n if (!hasDynamicValues) {\n const cssText = normalizeCSS(resolve(strings, values, {}))\n\n // Inject into sheet immediately\n if (cssText.trim()) sheet.insertGlobal(cssText)\n\n const StaticGlobal: ComponentFn = () => null\n return StaticGlobal\n }\n\n // DYNAMIC PATH: resolve on every render with theme/props\n const DynamicGlobal: ComponentFn = (props: Record<string, any>) => {\n const theme = useTheme()\n const allProps = { ...props, theme }\n const cssText = normalizeCSS(resolve(strings, values, allProps))\n\n if (cssText.trim()) sheet.insertGlobal(cssText)\n\n return null\n }\n\n return DynamicGlobal\n}\n","/**\n * keyframes() tagged template function. Creates a CSS @keyframes rule,\n * injects it into the stylesheet, and returns the generated animation name.\n *\n * Usage:\n * const fadeIn = keyframes`\n * from { opacity: 0; }\n * to { opacity: 1; }\n * `\n * // fadeIn === \"pyr-kf-abc123\" (deterministic, hash-based)\n */\nimport { hash } from './hash'\nimport { type Interpolation, normalizeCSS, resolve } from './resolve'\nimport { sheet } from './sheet'\n\nclass KeyframesResult {\n readonly name: string\n\n constructor(strings: TemplateStringsArray, values: Interpolation[]) {\n const body = normalizeCSS(resolve(strings, values, {}))\n const h = hash(body)\n this.name = `pyr-kf-${h}`\n\n sheet.insertKeyframes(this.name, body)\n }\n\n /** Returns the animation name when used in string context. */\n toString(): string {\n return this.name\n }\n}\n\nexport const keyframes = (\n strings: TemplateStringsArray,\n ...values: Interpolation[]\n): KeyframesResult => new KeyframesResult(strings, values)\n","/**\n * styled() component factory. Creates Pyreon components that inject CSS\n * class names from tagged template literals.\n *\n * Supports:\n * - styled('div')`...` and styled(Component)`...`\n * - styled.div`...` (via Proxy)\n * - `as` prop for polymorphic rendering\n * - $-prefixed transient props (not forwarded to DOM)\n * - Custom shouldForwardProp for per-component prop filtering\n * - Static path optimization (templates with no dynamic interpolations)\n * - Boost specificity via doubled selector\n *\n * CSS nesting (`&` selectors) works natively — the resolver passes CSS\n * through without transformation, so `&:hover`, `&::before`, etc. work\n * as-is in browsers supporting CSS Nesting (all modern browsers).\n */\nimport type { ComponentFn, VNode } from '@pyreon/core'\nimport { h } from '@pyreon/core'\nimport { effect, runUntracked } from '@pyreon/reactivity'\nimport { buildProps } from './forward'\nimport { type Interpolation, normalizeCSS, resolve } from './resolve'\nimport { isDynamic } from './shared'\nimport { sheet } from './sheet'\nimport { useTheme } from './ThemeProvider'\n\ntype Tag = string | ComponentFn<any>\n\nexport interface StyledOptions {\n /** Custom prop filter. Return true to forward the prop to the DOM element. */\n shouldForwardProp?: (prop: string) => boolean\n /**\n * CSS @layer name. Rules are wrapped in `@layer <name> { ... }`.\n * All framework CSS uses a single 'pyreon' layer. Source order within\n * the layer determines override precedence (rocketstyle inserts after base).\n */\n layer?: string\n}\n\nconst getDisplayName = (tag: Tag): string =>\n typeof tag === 'string'\n ? tag\n : (tag as ComponentFn<any> & { displayName?: string }).displayName || tag.name || 'Component'\n\n// Component cache: same template literal + tag + no options → same component.\n// WeakMap on `strings` (TemplateStringsArray is object-identity per source location).\nconst staticComponentCache = new WeakMap<TemplateStringsArray, Map<Tag, ComponentFn>>()\n\n// Single-entry hot cache — just 3 reference comparisons, no Map/WeakMap overhead.\nlet _hotStrings: TemplateStringsArray | null = null\nlet _hotTag: Tag | null = null\nlet _hotComponent: ComponentFn | null = null\n\nconst createStyledComponent = (\n tag: Tag,\n strings: TemplateStringsArray,\n values: Interpolation[],\n options?: StyledOptions,\n): ComponentFn => {\n // Ultra-fast hot cache: 3 reference comparisons → return immediately\n if (values.length === 0 && !options) {\n if (strings === _hotStrings && tag === _hotTag) return _hotComponent as ComponentFn\n\n // WeakMap fallback for alternating patterns\n const tagMap = staticComponentCache.get(strings)\n if (tagMap) {\n const cached = tagMap.get(tag)\n if (cached) {\n _hotStrings = strings\n _hotTag = tag\n _hotComponent = cached\n return cached\n }\n }\n }\n\n // Fast check: no values means no dynamic interpolations — avoids .some() scan\n const hasDynamicValues = values.length > 0 && values.some(isDynamic)\n const customFilter = options ? options.shouldForwardProp : undefined\n const insertLayer = options?.layer\n\n // STATIC FAST PATH: no function interpolations → compute class once at creation time\n if (!hasDynamicValues) {\n // Inline resolve for the common no-values case\n const raw = values.length === 0 ? (strings[0] as string) : resolve(strings, values, {})\n const cssText = normalizeCSS(raw)\n const hasCss = cssText.length > 0\n\n const staticClassName = hasCss ? sheet.insert(cssText, false, insertLayer) : ''\n\n const StaticStyled: ComponentFn = (rawProps: Record<string, any>): VNode | null => {\n const finalTag = rawProps.as || tag\n const isDOM = typeof finalTag === 'string'\n const finalProps = buildProps(rawProps, staticClassName, isDOM, customFilter)\n\n return h(\n finalTag as string,\n finalProps,\n ...(Array.isArray(rawProps.children)\n ? rawProps.children\n : rawProps.children != null\n ? [rawProps.children]\n : []),\n )\n }\n\n ;(StaticStyled as ComponentFn & { displayName?: string }).displayName =\n `styled(${getDisplayName(tag)})`\n\n // Store in component cache + hot cache for future reuse\n if (!options && values.length === 0) {\n let tagMap = staticComponentCache.get(strings)\n if (!tagMap) {\n tagMap = new Map()\n staticComponentCache.set(strings, tagMap)\n }\n tagMap.set(tag, StaticStyled)\n _hotStrings = strings\n _hotTag = tag\n _hotComponent = StaticStyled\n }\n\n return StaticStyled\n }\n\n // DYNAMIC PATH: resolve CSS on every render with theme/props.\n // When $rocketstyle is a function accessor (from rocketstyle's\n // EnhancedComponent), we resolve it initially for the first class,\n // then set up an effect to reactively swap classes when mode changes.\n // This avoids VNode remounting — only classList updates on the DOM element.\n const DynamicStyled: ComponentFn = (rawProps: Record<string, any>): VNode | null => {\n const theme = useTheme()\n const $rs = rawProps.$rocketstyle\n const $rsState = rawProps.$rocketstate\n const isReactiveRS = typeof $rs === 'function'\n const isReactiveState = typeof $rsState === 'function'\n\n // Resolve initial accessor values — both $rocketstyle and $rocketstate\n // must be plain objects when passed to resolve(), because .styles()\n // interpolation functions destructure them directly:\n // const { hover, pressed } = $rocketstate.pseudo\n // const { hover: hoverStyles } = $rocketstyle\n const resolvedRS = isReactiveRS ? $rs() : $rs\n const resolvedState = isReactiveState ? $rsState() : $rsState\n const initialProps = {\n ...rawProps,\n ...(isReactiveRS ? { $rocketstyle: resolvedRS } : {}),\n ...(isReactiveState ? { $rocketstate: resolvedState } : {}),\n }\n const cssText = normalizeCSS(resolve(strings, values, { ...initialProps, theme }))\n const initialClassName = cssText.length > 0 ? sheet.insert(cssText, false, insertLayer) : ''\n\n const finalTag = rawProps.as || tag\n const isDOM = typeof finalTag === 'string'\n\n // Track mounted element for reactive class updates\n let el: Element | null = null\n let currentClassName = initialClassName\n\n const originalRef = rawProps.ref\n const refCallback = (node: Element | null) => {\n el = node\n if (originalRef) {\n if (typeof originalRef === 'function') originalRef(node)\n else if (originalRef && typeof originalRef === 'object') originalRef.current = node\n }\n }\n\n const finalProps = buildProps(\n { ...rawProps, ref: isReactiveRS ? refCallback : rawProps.ref },\n initialClassName,\n isDOM,\n customFilter,\n )\n\n // Set up reactive class swap when $rocketstyle is a function accessor.\n // CRITICAL: only $rs() is tracked. resolve() and DOM mutations run\n // inside runUntracked() to prevent subscribing to signals read by\n // interpolation functions (theme properties, context getters, etc.).\n // Without this, every styled component's effect subscribes to every\n // signal touched during CSS resolution — causing an exponential\n // cascade across 50+ components on any signal change.\n if (isReactiveRS) {\n effect(() => {\n const newRS = $rs() // TRACKED: subscribes to mode + dimension signals\n const newState = isReactiveState ? $rsState() : $rsState // TRACKED\n\n runUntracked(() => {\n // UNTRACKED: resolve + DOM mutation — no additional subscriptions\n const newResolvedProps = {\n ...rawProps,\n $rocketstyle: newRS,\n $rocketstate: newState,\n }\n const newCss = normalizeCSS(\n resolve(strings, values, { ...newResolvedProps, theme }),\n )\n const newClass = newCss.length > 0 ? sheet.insert(newCss, false, insertLayer) : ''\n\n if (el && newClass !== currentClassName) {\n if (currentClassName) el.classList.remove(currentClassName)\n if (newClass) el.classList.add(newClass)\n currentClassName = newClass\n }\n })\n })\n }\n\n // STATIC VNode — created once, never remounted on mode change\n return h(\n finalTag as string,\n finalProps,\n ...(Array.isArray(rawProps.children)\n ? rawProps.children\n : rawProps.children != null\n ? [rawProps.children]\n : []),\n )\n }\n\n ;(DynamicStyled as ComponentFn & { displayName?: string }).displayName =\n `styled(${getDisplayName(tag)})`\n return DynamicStyled\n}\n\n/** Factory function: styled(tag) returns a tagged template function. */\nconst styledFactory = (tag: Tag, options?: StyledOptions) => {\n const templateFn = (strings: TemplateStringsArray, ...values: Interpolation[]) =>\n createStyledComponent(tag, strings, values, options)\n\n return templateFn\n}\n\n/**\n * Main styled export. Supports both calling conventions:\n * - `styled('div')` or `styled(Component)` → returns tagged template function\n * - `styled('div', { shouldForwardProp })` → with custom prop filtering\n * - `styled.div` → shorthand via Proxy (no options)\n */\n// Cache template functions per tag to avoid closure allocation on every Proxy get\nconst proxyCache = new Map<string, (...args: any[]) => any>()\n\n/**\n * Generic tagged template function returned by `styled(tag)` and `styled.tag`.\n *\n * Accepts an optional type parameter `<P>` for consumer-defined props\n * (typically transient $-prefixed props that aren't forwarded to the DOM).\n *\n * @example\n * const Box = styled('div')<{ $color: string }>`\n * background: ${(props) => props.$color};\n * `\n * <Box $color=\"red\" /> // $color is required and typed\n */\ntype TagTemplateFn = <P extends object = Record<string, unknown>>(\n strings: TemplateStringsArray,\n ...values: Interpolation<P>[]\n) => ComponentFn<P & Record<string, unknown>>\n\ntype HtmlTags =\n | 'a'\n | 'abbr'\n | 'address'\n | 'article'\n | 'aside'\n | 'audio'\n | 'b'\n | 'blockquote'\n | 'body'\n | 'br'\n | 'button'\n | 'canvas'\n | 'caption'\n | 'code'\n | 'col'\n | 'colgroup'\n | 'dd'\n | 'details'\n | 'div'\n | 'dl'\n | 'dt'\n | 'em'\n | 'fieldset'\n | 'figcaption'\n | 'figure'\n | 'footer'\n | 'form'\n | 'h1'\n | 'h2'\n | 'h3'\n | 'h4'\n | 'h5'\n | 'h6'\n | 'head'\n | 'header'\n | 'hr'\n | 'html'\n | 'i'\n | 'iframe'\n | 'img'\n | 'input'\n | 'label'\n | 'legend'\n | 'li'\n | 'link'\n | 'main'\n | 'mark'\n | 'menu'\n | 'meta'\n | 'nav'\n | 'ol'\n | 'optgroup'\n | 'option'\n | 'output'\n | 'p'\n | 'picture'\n | 'pre'\n | 'progress'\n | 'q'\n | 'section'\n | 'select'\n | 'small'\n | 'source'\n | 'span'\n | 'strong'\n | 'style'\n | 'sub'\n | 'summary'\n | 'sup'\n | 'svg'\n | 'table'\n | 'tbody'\n | 'td'\n | 'template'\n | 'textarea'\n | 'tfoot'\n | 'th'\n | 'thead'\n | 'time'\n | 'tr'\n | 'u'\n | 'ul'\n | 'video'\n\nexport type StyledFunction = ((tag: Tag, options?: StyledOptions) => TagTemplateFn) & {\n [K in HtmlTags]: TagTemplateFn\n}\n\n// Proxy is needed to support styled.div`...` syntax; the cast bridges\n// styledFactory's call signature to StyledFunction which adds HTML tag properties.\n// Proxy target uses `as any` because TS can't resolve Proxy<StyledFunction> with mapped types\nexport const styled: StyledFunction = new Proxy(styledFactory as any, {\n get(_target: unknown, prop: string) {\n if (prop === 'prototype' || prop === '$$typeof') return undefined\n // styled.div`...`, styled.span`...`, etc.\n let fn = proxyCache.get(prop)\n if (!fn) {\n fn = (strings: TemplateStringsArray, ...values: Interpolation[]) =>\n createStyledComponent(prop, strings, values)\n proxyCache.set(prop, fn)\n }\n return fn\n },\n})\n","/**\n * Hook that resolves a CSSResult template with props, injects CSS\n * into the shared stylesheet, and returns the className.\n *\n * Use this when you need computed CSS class names on plain elements\n * without the overhead of a styled component layer.\n */\nimport { type CSSResult, normalizeCSS, resolve } from './resolve'\nimport { sheet } from './sheet'\nimport { useTheme } from './ThemeProvider'\n\nexport function useCSS(template: CSSResult, props?: Record<string, any>, boost?: boolean): string {\n const theme = useTheme()\n const allProps = theme ? { ...props, theme } : (props ?? {})\n const cssText = normalizeCSS(resolve(template.strings, template.values, allProps))\n\n if (!cssText.trim()) return ''\n\n return sheet.insert(cssText, boost)\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/styler",
3
- "version": "0.12.10",
3
+ "version": "0.12.11",
4
4
  "description": "Lightweight CSS-in-JS engine for Pyreon",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -40,12 +40,12 @@
40
40
  "typecheck": "tsc --noEmit"
41
41
  },
42
42
  "devDependencies": {
43
- "@pyreon/typescript": "^0.12.10",
43
+ "@pyreon/typescript": "^0.12.11",
44
44
  "@vitus-labs/tools-rolldown": "^1.15.3"
45
45
  },
46
46
  "peerDependencies": {
47
- "@pyreon/core": "^0.12.10",
48
- "@pyreon/reactivity": "^0.12.10"
47
+ "@pyreon/core": "^0.12.11",
48
+ "@pyreon/reactivity": "^0.12.11"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">= 22"
@@ -104,6 +104,35 @@ describe('styled', () => {
104
104
  })
105
105
  })
106
106
 
107
+ describe('generic typed props', () => {
108
+ it('accepts a type parameter for typed interpolation props', () => {
109
+ // The generic provides type-safe access to consumer props inside interpolations
110
+ const Comp = styled('div')<{ $color: string; $size: number }>`
111
+ color: ${(props) => props.$color};
112
+ font-size: ${(props) => props.$size}px;
113
+ `
114
+ const vnode = Comp({ $color: 'red', $size: 14 }) as VNode
115
+ expect(vnode.props.class).toMatch(/^pyr-/)
116
+ })
117
+
118
+ it('different typed prop values produce different classes', () => {
119
+ const Comp = styled('div')<{ $variant: 'primary' | 'danger' }>`
120
+ background: ${(props) => (props.$variant === 'primary' ? 'blue' : 'red')};
121
+ `
122
+ const a = Comp({ $variant: 'primary' }) as VNode
123
+ const b = Comp({ $variant: 'danger' }) as VNode
124
+ expect(a.props.class).not.toBe(b.props.class)
125
+ })
126
+
127
+ it('default generic still allows untyped interpolations (back-compat)', () => {
128
+ const Comp = styled('div')`
129
+ color: ${(props: { color?: string }) => props.color || 'black'};
130
+ `
131
+ const vnode = Comp({ color: 'red' }) as VNode
132
+ expect(vnode.props.class).toMatch(/^pyr-/)
133
+ })
134
+ })
135
+
107
136
  describe('dynamic CSS (function interpolations)', () => {
108
137
  it('resolves function interpolations with props', () => {
109
138
  const Comp = styled('div')`
package/src/resolve.ts CHANGED
@@ -6,15 +6,28 @@
6
6
 
7
7
  import type { DefaultTheme } from './ThemeProvider'
8
8
 
9
- export type Interpolation =
9
+ /**
10
+ * Props passed to interpolation functions inside tagged templates.
11
+ * Generic `P` allows consumers to type their custom props (e.g. transient $-prefixed):
12
+ *
13
+ * @example
14
+ * styled('div')<{ $color: string }>`
15
+ * background: ${(props) => props.$color}; // props.$color is typed!
16
+ * `
17
+ */
18
+ export type StyledProps<P extends object = Record<string, unknown>> = P & {
19
+ theme?: DefaultTheme & Record<string, unknown>
20
+ }
21
+
22
+ export type Interpolation<P extends object = Record<string, unknown>> =
10
23
  | string
11
24
  | number
12
25
  | boolean
13
26
  | null
14
27
  | undefined
15
28
  | CSSResult
16
- | Interpolation[]
17
- | ((props: { theme?: DefaultTheme & Record<string, any>; [key: string]: any }) => Interpolation)
29
+ | Interpolation<P>[]
30
+ | ((props: StyledProps<P>) => Interpolation<P>)
18
31
 
19
32
  /**
20
33
  * Lazy representation of a `css` tagged template. Stores the raw template
package/src/styled.tsx CHANGED
@@ -240,7 +240,22 @@ const styledFactory = (tag: Tag, options?: StyledOptions) => {
240
240
  // Cache template functions per tag to avoid closure allocation on every Proxy get
241
241
  const proxyCache = new Map<string, (...args: any[]) => any>()
242
242
 
243
- type TagTemplateFn = (strings: TemplateStringsArray, ...values: Interpolation[]) => ComponentFn
243
+ /**
244
+ * Generic tagged template function returned by `styled(tag)` and `styled.tag`.
245
+ *
246
+ * Accepts an optional type parameter `<P>` for consumer-defined props
247
+ * (typically transient $-prefixed props that aren't forwarded to the DOM).
248
+ *
249
+ * @example
250
+ * const Box = styled('div')<{ $color: string }>`
251
+ * background: ${(props) => props.$color};
252
+ * `
253
+ * <Box $color="red" /> // $color is required and typed
254
+ */
255
+ type TagTemplateFn = <P extends object = Record<string, unknown>>(
256
+ strings: TemplateStringsArray,
257
+ ...values: Interpolation<P>[]
258
+ ) => ComponentFn<P & Record<string, unknown>>
244
259
 
245
260
  type HtmlTags =
246
261
  | 'a'