{"version":3,"sources":["../src/registry.ts","../src/sheet.ts"],"names":[],"mappings":"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","file":"hmr.cjs","sourcesContent":["/**\n * Shared registry for detecting duplicate namespace registrations.\n */\nexport const registeredNamespaces = new Set<string>();\n\nconst COLON = ':';\n\n/**\n * Drop reserved `scopeId:namespace` keys so a module can re-register after HMR.\n * `namespace` is the first argument to `styles.component()` / `styles.class()` (not the scope).\n */\nexport function releaseReservedNamespacesForComponentOrClassNames(\n  namespaces: readonly string[],\n): void {\n  if (namespaces.length === 0) return;\n  const wanted = new Set(namespaces);\n  const toRemove: string[] = [];\n  for (const key of registeredNamespaces) {\n    const i = key.indexOf(COLON);\n    if (i === -1) continue;\n    if (wanted.has(key.slice(i + 1))) {\n      toRemove.push(key);\n    }\n  }\n  for (const key of toRemove) {\n    registeredNamespaces.delete(key);\n  }\n}\n\n/** Vite plugin passes `.${namespace}-` prefixes for `styles.component()` invalidation. */\nexport function namespacesFromTypestylesHmrPrefixes(prefixes: readonly string[]): string[] {\n  const out: string[] = [];\n  for (const p of prefixes) {\n    if (p.length >= 2 && p.startsWith('.') && p.endsWith('-')) {\n      out.push(p.slice(1, -1));\n    }\n  }\n  return out;\n}\n","import {\n  namespacesFromTypestylesHmrPrefixes,\n  releaseReservedNamespacesForComponentOrClassNames,\n} from './registry';\n\nconst STYLE_ELEMENT_ID = 'typestyles';\n\n/**\n * Tracks which CSS rules have been inserted to avoid duplicates.\n */\nconst insertedRules = new Set<string>();\n\n/**\n * Last emitted CSS per dedupe key (see {@link warnIfDuplicateRuleKeyConflict}).\n * Cleared with {@link reset} and kept in sync when keys are invalidated.\n */\nconst ruleCssByKey = new Map<string, string>();\n\nfunction duplicateRuleKeyConflictWarningsEnabled(): boolean {\n  if (typeof process === 'undefined') return true;\n  return process.env.NODE_ENV !== 'production';\n}\n\n/**\n * When the same key is registered again with different CSS, the second rule is skipped\n * (idempotency / HMR). In non-production builds, surface that so overlapping globals\n * (e.g. reset `body` + app `body` in the same scope) are not silent failures.\n */\nfunction warnIfDuplicateRuleKeyConflict(\n  key: string,\n  previousCss: string,\n  ignoredCss: string,\n): void {\n  if (!duplicateRuleKeyConflictWarningsEnabled()) return;\n  const prevShort = previousCss.length > 220 ? `${previousCss.slice(0, 220)}…` : previousCss;\n  const nextShort = ignoredCss.length > 220 ? `${ignoredCss.slice(0, 220)}…` : ignoredCss;\n  console.warn(\n    `[typestyles] Skipped a rule: dedupe key \"${key}\" already exists with different CSS. ` +\n      `Only the first registration is kept. For globals, merge into one \\`global.style\\`, ` +\n      `or use a distinct selector (e.g. \\`html body\\` after reset’s \\`body\\`).\\n` +\n      `  Existing: ${prevShort}\\n` +\n      `  Skipped:  ${nextShort}`,\n  );\n}\n\n/**\n * Whether runtime DOM insertion is disabled (for build-time/zero-runtime mode).\n * The Vite plugin (mode: 'build') defines __TYPESTYLES_RUNTIME_DISABLED__ as the\n * string \"true\" at build time, so this is true in production and no <style> is created.\n *\n * `@typestyles/next/build` `withTypestylesExtract` sets `NEXT_PUBLIC_TYPESTYLES_RUNTIME_DISABLED`\n * via `next.config` `env` so Turbopack and webpack both inline the flag (DefinePlugin\n * alone does not run under Turbopack).\n */\ndeclare const __TYPESTYLES_RUNTIME_DISABLED__: string | undefined;\nfunction readNextPublicRuntimeDisabled(): boolean {\n  if (typeof process === 'undefined' || !process.env) return false;\n  return process.env.NEXT_PUBLIC_TYPESTYLES_RUNTIME_DISABLED === 'true';\n}\nconst RUNTIME_DISABLED =\n  (typeof __TYPESTYLES_RUNTIME_DISABLED__ !== 'undefined' &&\n    __TYPESTYLES_RUNTIME_DISABLED__ === 'true') ||\n  readNextPublicRuntimeDisabled();\n\n/**\n * Buffer of CSS rules waiting to be flushed.\n */\nlet pendingRules: string[] = [];\n\n/**\n * All CSS rules ever registered (for SSR extraction).\n * Unlike pendingRules (which is cleared on flush), this retains every rule\n * so getRegisteredCss() can return the full stylesheet at any point.\n */\nconst allRules: string[] = [];\n\n/**\n * Whether a flush is scheduled.\n */\nlet flushScheduled = false;\n\n/**\n * The managed <style> element, lazily created.\n */\nlet styleElement: HTMLStyleElement | null = null;\n\n/**\n * When in SSR collection mode, CSS is captured here instead of injected.\n */\nlet ssrBuffer: string[] | null = null;\n\n/**\n * Whether we're running in a browser environment.\n */\nconst isBrowser = typeof document !== 'undefined' && typeof window !== 'undefined';\n\n/**\n * Re-insert every registered rule into a (usually fresh) <style> element.\n * Used when the live element was detached (e.g. Astro view transitions replacing <head>).\n */\nfunction writeAllRulesToStyleElement(el: HTMLStyleElement): void {\n  if (RUNTIME_DISABLED || allRules.length === 0) return;\n  const sheet = el.sheet;\n  if (sheet) {\n    for (const css of allRules) {\n      try {\n        sheet.insertRule(css, sheet.cssRules.length);\n      } catch {\n        el.appendChild(document.createTextNode(css));\n      }\n    }\n  } else {\n    el.appendChild(document.createTextNode(allRules.join('\\n')));\n  }\n}\n\nfunction getStyleElement(): HTMLStyleElement {\n  let reconnectAfterDetach = false;\n  if (styleElement && !styleElement.isConnected) {\n    reconnectAfterDetach = true;\n    styleElement = null;\n  }\n  if (styleElement) return styleElement;\n\n  // Prefer an element actually in the document (SSR or another copy on the page).\n  const existing = document.getElementById(STYLE_ELEMENT_ID) as HTMLStyleElement | null;\n  if (existing?.isConnected) {\n    styleElement = existing;\n    return styleElement;\n  }\n\n  styleElement = document.createElement('style');\n  styleElement.id = STYLE_ELEMENT_ID;\n  document.head.appendChild(styleElement);\n\n  // After a doc swap, we have a new empty sheet but insertRule() won't re-queue (deduped keys).\n  if (reconnectAfterDetach && allRules.length > 0) {\n    writeAllRulesToStyleElement(styleElement);\n  }\n\n  return styleElement;\n}\n\n/**\n * Ensure the managed <style id=\"typestyles\"> is attached to the current document and populated.\n * Call after SPA-style navigation (e.g. Astro `astro:after-swap`) when runtime injection is enabled.\n */\nexport function ensureDocumentStylesAttached(): void {\n  if (!isBrowser || RUNTIME_DISABLED) return;\n  getStyleElement();\n}\n\nfunction flush(): void {\n  flushScheduled = false;\n  if (pendingRules.length === 0) return;\n\n  const rules = pendingRules;\n  pendingRules = [];\n\n  if (ssrBuffer) {\n    ssrBuffer.push(...rules);\n    return;\n  }\n\n  if (!isBrowser || RUNTIME_DISABLED) return;\n\n  const el = getStyleElement();\n  const sheet = el.sheet;\n\n  if (sheet) {\n    for (const rule of rules) {\n      try {\n        sheet.insertRule(rule, sheet.cssRules.length);\n      } catch {\n        // Fallback: append as text (handles edge cases with certain selectors)\n        el.appendChild(document.createTextNode(rule));\n      }\n    }\n  } else {\n    // Sheet not available yet, append as text\n    el.appendChild(document.createTextNode(rules.join('\\n')));\n  }\n}\n\nfunction scheduleFlush(): void {\n  if (flushScheduled) return;\n  flushScheduled = true;\n\n  if (ssrBuffer) {\n    // In SSR mode, flush synchronously\n    flush();\n    return;\n  }\n\n  if (isBrowser && !RUNTIME_DISABLED) {\n    // Use microtask for fast, batched insertion\n    queueMicrotask(flush);\n  }\n}\n\n/**\n * Register a single `@layer a, b, c;` preamble so layer **order** is defined before any\n * `@layer name { … }` blocks. Inserts at the front of the virtual sheet and at CSSOM index 0\n * when injecting into the document.\n */\nexport function registerCascadeLayerOrder(preambleKey: string, css: string): void {\n  const key = `typestyles:@layer-order:${preambleKey}`;\n  if (insertedRules.has(key)) return;\n  insertedRules.add(key);\n\n  allRules.unshift(css);\n\n  if (ssrBuffer) {\n    ssrBuffer.unshift(css);\n    return;\n  }\n\n  if (RUNTIME_DISABLED) return;\n\n  if (!isBrowser) return;\n\n  const el = getStyleElement();\n  const sheet = el.sheet;\n  if (sheet) {\n    try {\n      sheet.insertRule(css, 0);\n    } catch {\n      el.insertBefore(document.createTextNode(`${css}\\n`), el.firstChild);\n    }\n  } else {\n    el.insertBefore(document.createTextNode(`${css}\\n`), el.firstChild);\n  }\n}\n\n/**\n * Insert a CSS rule. Deduplicates by rule key.\n */\nexport function insertRule(key: string, css: string): void {\n  if (insertedRules.has(key)) {\n    const prev = ruleCssByKey.get(key);\n    if (prev != null && prev !== css) {\n      warnIfDuplicateRuleKeyConflict(key, prev, css);\n    }\n    return;\n  }\n  insertedRules.add(key);\n  ruleCssByKey.set(key, css);\n  allRules.push(css);\n  if (RUNTIME_DISABLED && !ssrBuffer) return;\n  pendingRules.push(css);\n  scheduleFlush();\n}\n\n/**\n * Insert multiple CSS rules at once.\n */\nexport function insertRules(rules: Array<{ key: string; css: string }>): void {\n  let added = false;\n  for (const { key, css } of rules) {\n    if (insertedRules.has(key)) {\n      const prev = ruleCssByKey.get(key);\n      if (prev != null && prev !== css) {\n        warnIfDuplicateRuleKeyConflict(key, prev, css);\n      }\n      continue;\n    }\n    insertedRules.add(key);\n    ruleCssByKey.set(key, css);\n    allRules.push(css);\n    if (!RUNTIME_DISABLED || ssrBuffer) {\n      pendingRules.push(css);\n      added = true;\n    }\n  }\n  if (added) scheduleFlush();\n}\n\n/**\n * Replace a CSS rule (used for HMR). Removes the old rule and inserts the new one.\n */\nexport function replaceRule(key: string, css: string): void {\n  if (!isBrowser || RUNTIME_DISABLED) return;\n\n  insertedRules.delete(key);\n  ruleCssByKey.delete(key);\n\n  // Remove existing rule from the sheet if possible\n  const el = getStyleElement();\n  const sheet = el.sheet;\n  if (sheet) {\n    for (let i = sheet.cssRules.length - 1; i >= 0; i--) {\n      // We can't reliably match by key in CSSOM, so for HMR we fall back to\n      // clearing and re-inserting. This is fine since HMR is dev-only.\n    }\n  }\n\n  insertRule(key, css);\n}\n\n/**\n * Start collecting CSS for SSR. Returns a function to stop collection and get the CSS.\n */\nexport function startCollection(): () => string {\n  ssrBuffer = [];\n  return () => {\n    const css = ssrBuffer ? ssrBuffer.join('\\n') : '';\n    ssrBuffer = null;\n    return css;\n  };\n}\n\n/**\n * Return all registered CSS as a string.\n *\n * Unlike `collectStyles`, this doesn't require wrapping a render function.\n * It simply returns every CSS rule that has been registered via\n * `styles.component`, `styles.class`, `tokens.create`, `keyframes.create`, etc.\n *\n * Ideal for SSR frameworks that need the CSS separately from the render\n * pass (e.g. TanStack Start's `head()`, Next.js metadata, Remix links).\n *\n * @example\n * ```ts\n * import { getRegisteredCss } from 'typestyles/server';\n *\n * // In a route's head/meta function:\n * export const head = () => ({\n *   styles: [{ id: 'typestyles', children: getRegisteredCss() }],\n * });\n * ```\n */\nexport function getRegisteredCss(): string {\n  return allRules.join('\\n');\n}\n\n/**\n * Reset all state (useful for testing).\n */\nexport function reset(): void {\n  insertedRules.clear();\n  ruleCssByKey.clear();\n  pendingRules = [];\n  allRules.length = 0;\n  flushScheduled = false;\n  ssrBuffer = null;\n  if (isBrowser && styleElement) {\n    styleElement.remove();\n    styleElement = null;\n  }\n}\n\n/**\n * Flush all pending rules synchronously. Used for SSR and testing.\n */\nexport function flushSync(): void {\n  flush();\n}\n\n/**\n * Invalidate all dedup keys that start with the given prefix.\n * Also removes matching rules from the live stylesheet.\n * Used for HMR — allows modules to re-register their styles after editing.\n */\nexport function invalidatePrefix(prefix: string): void {\n  for (const key of insertedRules) {\n    if (key.startsWith(prefix)) {\n      insertedRules.delete(key);\n      ruleCssByKey.delete(key);\n    }\n  }\n\n  releaseReservedNamespacesForComponentOrClassNames(namespacesFromTypestylesHmrPrefixes([prefix]));\n\n  if (!isBrowser) return;\n\n  const el = styleElement;\n  if (!el) return;\n  const sheet = el.sheet;\n  if (!sheet) return;\n\n  for (let i = sheet.cssRules.length - 1; i >= 0; i--) {\n    const rule = sheet.cssRules[i];\n    if (ruleMatchesPrefix(rule, prefix)) {\n      sheet.deleteRule(i);\n    }\n  }\n}\n\n/**\n * Invalidate a list of exact keys or prefixes.\n * Each entry in `keys` is treated as an exact key match.\n * Each entry in `prefixes` is treated as a prefix match.\n * Used for HMR to invalidate all styles from a module at once.\n */\nexport function invalidateKeys(keys: string[], prefixes: string[]): void {\n  for (const key of keys) {\n    insertedRules.delete(key);\n    ruleCssByKey.delete(key);\n  }\n  for (const prefix of prefixes) {\n    for (const key of insertedRules) {\n      if (key.startsWith(prefix)) {\n        insertedRules.delete(key);\n        ruleCssByKey.delete(key);\n      }\n    }\n  }\n\n  releaseReservedNamespacesForComponentOrClassNames(namespacesFromTypestylesHmrPrefixes(prefixes));\n\n  if (!isBrowser) return;\n\n  const el = styleElement;\n  if (!el) return;\n  const sheet = el.sheet;\n  if (!sheet) return;\n\n  const keySet = new Set(keys);\n  for (let i = sheet.cssRules.length - 1; i >= 0; i--) {\n    const rule = sheet.cssRules[i];\n    let shouldRemove = false;\n\n    for (const prefix of prefixes) {\n      if (ruleMatchesPrefix(rule, prefix)) {\n        shouldRemove = true;\n        break;\n      }\n    }\n\n    if (!shouldRemove) {\n      // Check exact key matches — for tokens/themes/keyframes,\n      // we match based on rule content patterns\n      const ruleText = rule.cssText;\n      for (const key of keySet) {\n        if (ruleMatchesKey(ruleText, key)) {\n          shouldRemove = true;\n          break;\n        }\n      }\n    }\n\n    if (shouldRemove) {\n      sheet.deleteRule(i);\n    }\n  }\n}\n\n/**\n * Drop every rule key tied to a `styles.component('namespace', …)` registration, including\n * `@layer`-wrapped keys (`layer:….:.namespace-…`), and release reserved namespace entries.\n * Used for Vite HMR and for dev recovery when a module re-runs before `hot.dispose`.\n */\nexport function invalidateComponentNamespaceForDev(namespace: string): void {\n  const selectorInfix = `.${namespace}-`;\n  const keysToDrop: string[] = [];\n  for (const k of insertedRules) {\n    if (k.includes(selectorInfix)) {\n      keysToDrop.push(k);\n    }\n  }\n  invalidateKeys(keysToDrop, [selectorInfix]);\n}\n\nfunction ruleMatchesPrefix(rule: CSSRule, prefix: string): boolean {\n  if (prefix.startsWith('font-face:')) {\n    const family = prefix.slice('font-face:'.length).split(':')[0];\n    // CSSFontFaceRule has type 5 and cssText contains @font-face\n    if (rule.cssText.includes('@font-face')) {\n      return rule.cssText.includes(`\"${family}\"`) || rule.cssText.includes(`'${family}'`);\n    }\n    return false;\n  }\n  if ('selectorText' in rule) {\n    return (rule as CSSStyleRule).selectorText.startsWith(prefix);\n  }\n  if ('name' in rule && prefix.startsWith('keyframes:')) {\n    return (rule as CSSKeyframesRule).name === prefix.slice('keyframes:'.length);\n  }\n  // For at-rules wrapping style rules, check inner rules\n  if ('cssRules' in rule) {\n    const innerRules = (rule as CSSGroupingRule).cssRules;\n    for (let i = 0; i < innerRules.length; i++) {\n      if (ruleMatchesPrefix(innerRules[i], prefix)) return true;\n    }\n  }\n  return false;\n}\n\nfunction ruleMatchesKey(cssText: string, key: string): boolean {\n  if (key.startsWith('tokens:')) {\n    // tokens:color or tokens:color@layerName -> :root rule with --color- custom properties\n    const rest = key.slice('tokens:'.length);\n    const at = rest.lastIndexOf('@');\n    const namespace = at === -1 ? rest : rest.slice(0, at);\n    return cssText.includes(`:root`) && cssText.includes(`--${namespace}-`);\n  }\n  if (key.startsWith('theme:')) {\n    // theme:dark -> .theme-dark selector\n    const name = key.slice('theme:'.length);\n    return cssText.includes(`.theme-${name}`);\n  }\n  if (key.startsWith('keyframes:')) {\n    const name = key.slice('keyframes:'.length);\n    return cssText.includes(`@keyframes ${name}`);\n  }\n  return false;\n}\n"]}