{"version":3,"file":"themes.mjs","names":[],"sources":["../src/themes.ts"],"sourcesContent":["/**\n * Browser-safe theme-enumeration + naming helpers. Exported through the\n * `@unpunnyfuns/swatchbook-core/themes` subpath so the addon's preset\n * codegen, the addon's preview decorator, the MCP server's tuple lookup,\n * and the blocks-side display name share one implementation. Same set\n * of \"themes a project surfaces\" (default + per-axis singletons +\n * presets) consumers iterate over; same `tupleToName` join everyone\n * uses for the `data-<prefix>-theme` attribute.\n *\n * Pure functions over structural input types — no `Project` import, no\n * Terrazzo parser, no Node deps.\n */\n\n/** One named theme produced by enumeration — the canonical name + the tuple it resolves to. */\nexport interface ThemeEntry {\n  readonly name: string;\n  readonly tuple: Readonly<Record<string, string>>;\n}\n\n/** Minimal axis shape `enumerateThemes` and `tupleToName` need. */\nexport interface ThemeEnumAxis {\n  readonly name: string;\n  readonly default: string;\n  readonly contexts: readonly string[];\n}\n\n/** Minimal preset shape `enumerateThemes` needs. */\nexport interface ThemeEnumPreset {\n  readonly name: string;\n  readonly axes: Partial<Record<string, string>>;\n}\n\n/**\n * Synthesize the canonical theme name from a tuple — axis values joined\n * by ` · ` in axis declaration order. Same form the\n * `data-<prefix>-theme` attribute holds. Falls back to each axis's\n * `default` when the tuple omits it.\n *\n * Not interchangeable with `permutationID` (types.ts): this is the\n * axis-order display name that fills omitted axes from defaults, whereas\n * `permutationID` is the insertion-order internal wire key with no default\n * fallback.\n */\nexport function tupleToName(\n  axes: readonly { readonly name: string; readonly default: string }[],\n  tuple: Readonly<Record<string, string>>,\n): string {\n  return axes.map((a) => tuple[a.name] ?? a.default).join(' · ');\n}\n\n/**\n * Enumerate every theme a project surfaces:\n *\n *   1. The default tuple (axes at their defaults), always first.\n *   2. Per-axis non-default singletons (`{...defaults, [axis]: ctx}`)\n *      for each `(axis, non-default-context)` pair.\n *   3. Presets — fill omitted axes from defaults.\n *\n * Deduped by name (presets pointing at a singleton or the default tuple\n * collapse into the singleton entry). Order matches the loader's own\n * singleton enumeration: default → per-axis singletons → presets.\n */\nexport function enumerateThemes(input: {\n  readonly axes: readonly ThemeEnumAxis[];\n  readonly presets: readonly ThemeEnumPreset[];\n  readonly defaultTuple: Readonly<Record<string, string>>;\n}): ThemeEntry[] {\n  const out: ThemeEntry[] = [];\n  const seen = new Set<string>();\n\n  const push = (tuple: Record<string, string>): void => {\n    const name = tupleToName(input.axes, tuple);\n    if (seen.has(name)) return;\n    seen.add(name);\n    out.push({ name, tuple });\n  };\n\n  push({ ...input.defaultTuple });\n  for (const axis of input.axes) {\n    for (const ctx of axis.contexts) {\n      if (ctx === axis.default) continue;\n      push({ ...input.defaultTuple, [axis.name]: ctx });\n    }\n  }\n  for (const preset of input.presets) {\n    const tuple: Record<string, string> = { ...input.defaultTuple };\n    for (const [a, c] of Object.entries(preset.axes)) {\n      if (c !== undefined) tuple[a] = c;\n    }\n    push(tuple);\n  }\n\n  return out;\n}\n"],"mappings":";;;;;;;;;;;;AA2CA,SAAgB,YACd,MACA,OACQ;AACR,QAAO,KAAK,KAAK,MAAM,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,KAAK,MAAM;;;;;;;;;;;;;;AAehE,SAAgB,gBAAgB,OAIf;CACf,MAAM,MAAoB,EAAE;CAC5B,MAAM,uBAAO,IAAI,KAAa;CAE9B,MAAM,QAAQ,UAAwC;EACpD,MAAM,OAAO,YAAY,MAAM,MAAM,MAAM;AAC3C,MAAI,KAAK,IAAI,KAAK,CAAE;AACpB,OAAK,IAAI,KAAK;AACd,MAAI,KAAK;GAAE;GAAM;GAAO,CAAC;;AAG3B,MAAK,EAAE,GAAG,MAAM,cAAc,CAAC;AAC/B,MAAK,MAAM,QAAQ,MAAM,KACvB,MAAK,MAAM,OAAO,KAAK,UAAU;AAC/B,MAAI,QAAQ,KAAK,QAAS;AAC1B,OAAK;GAAE,GAAG,MAAM;IAAe,KAAK,OAAO;GAAK,CAAC;;AAGrD,MAAK,MAAM,UAAU,MAAM,SAAS;EAClC,MAAM,QAAgC,EAAE,GAAG,MAAM,cAAc;AAC/D,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,OAAO,KAAK,CAC9C,KAAI,MAAM,KAAA,EAAW,OAAM,KAAK;AAElC,OAAK,MAAM;;AAGb,QAAO"}