@wix/web5-core 1.63.44 → 1.63.46

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.
Files changed (49) hide show
  1. package/dist/cjs/client/applyThemeOverrides.js +47 -30
  2. package/dist/cjs/client/applyThemeOverrides.js.map +1 -1
  3. package/dist/cjs/index.js +12 -13
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/privacy/consentGate.js +32 -178
  6. package/dist/cjs/privacy/consentGate.js.map +1 -1
  7. package/dist/cjs/privacy/index.js +2 -9
  8. package/dist/cjs/privacy/index.js.map +1 -1
  9. package/dist/cjs/styles/base-tokens.css +19 -0
  10. package/dist/cjs/styles/tailwind-theme.css +12 -0
  11. package/dist/cjs/theme/chromeTokens.js +60 -0
  12. package/dist/cjs/theme/chromeTokens.js.map +1 -0
  13. package/dist/cjs/theme/themeScheme.js +64 -50
  14. package/dist/cjs/theme/themeScheme.js.map +1 -1
  15. package/dist/cjs/utils/analyticsEvents.js +16 -37
  16. package/dist/cjs/utils/analyticsEvents.js.map +1 -1
  17. package/dist/esm/client/applyThemeOverrides.js +55 -30
  18. package/dist/esm/client/applyThemeOverrides.js.map +1 -1
  19. package/dist/esm/index.js +5 -4
  20. package/dist/esm/index.js.map +1 -1
  21. package/dist/esm/privacy/consentGate.js +30 -173
  22. package/dist/esm/privacy/consentGate.js.map +1 -1
  23. package/dist/esm/privacy/index.js +1 -1
  24. package/dist/esm/privacy/index.js.map +1 -1
  25. package/dist/esm/styles/base-tokens.css +19 -0
  26. package/dist/esm/styles/tailwind-theme.css +12 -0
  27. package/dist/esm/theme/chromeTokens.js +53 -0
  28. package/dist/esm/theme/chromeTokens.js.map +1 -0
  29. package/dist/esm/theme/themeScheme.js +70 -51
  30. package/dist/esm/theme/themeScheme.js.map +1 -1
  31. package/dist/esm/utils/analyticsEvents.js +16 -36
  32. package/dist/esm/utils/analyticsEvents.js.map +1 -1
  33. package/dist/types/client/applyThemeOverrides.d.ts +11 -0
  34. package/dist/types/client/applyThemeOverrides.d.ts.map +1 -1
  35. package/dist/types/index.d.ts +6 -5
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/dist/types/privacy/consentGate.d.ts +28 -61
  38. package/dist/types/privacy/consentGate.d.ts.map +1 -1
  39. package/dist/types/privacy/index.d.ts +1 -1
  40. package/dist/types/privacy/index.d.ts.map +1 -1
  41. package/dist/types/theme/chromeTokens.d.ts +46 -0
  42. package/dist/types/theme/chromeTokens.d.ts.map +1 -0
  43. package/dist/types/theme/themeScheme.d.ts +30 -12
  44. package/dist/types/theme/themeScheme.d.ts.map +1 -1
  45. package/dist/types/utils/analyticsEvents.d.ts +0 -10
  46. package/dist/types/utils/analyticsEvents.d.ts.map +1 -1
  47. package/package.json +2 -2
  48. package/src/styles/base-tokens.css +19 -0
  49. package/src/styles/tailwind-theme.css +12 -0
@@ -1 +1 @@
1
- {"version":3,"names":["UNKNOWN_CONSENT","DEFAULT_BUFFER_LIMIT","LOG_PREFIX","log","_len","arguments","length","args","Array","_key","console","debug","describe","s","analytics","performance","marketing","snapshot","engaged","provider","unsubscribeProvider","buffer","bufferLimit","droppedFromOverflow","listeners","Set","view","Object","freeze","consent","rebuildView","notify","listener","mayTransmit","purpose","state","settleBuffer","stillHeld","releasing","held","push","dropped","label","send","transmit","unlockOnUserAction","isUserEngaged","mayPersistIdentity","getConsentSnapshot","getGateView","subscribeToConsent","add","delete","applySnapshot","next","installConsentProvider","initial","read","name","subscribe","getInstalledProviderName","_provider","setConsentBufferLimit","limit","Math","max","getConsentGateStats","resetConsentGateForTests","clear"],"sources":["../../../src/privacy/consentGate.ts"],"sourcesContent":["/**\n * The consent gate — DL #218.\n *\n * Every BI, telemetry and analytics emitter in web5 goes through `transmit()`\n * instead of calling its transport directly. The gate exists because the\n * consent signal resolves *after* the events that need it: Shopify's consent\n * API is not on the page by default and has to be requested, and the fedops\n * app-load pair fires inside that window. A boolean checked at each call site\n * can only ever drop an event that is already in flight; the gate can hold it.\n *\n * Two independent unlocks, and they do not compose as a plain \"either/or\":\n *\n * | consent | engaged | result |\n * |-----------|---------|---------------------------------|\n * | granted | either | transmit |\n * | unknown | no | hold in the buffer |\n * | unknown | yes | transmit, and flush what's held |\n * | denied | yes | still nothing |\n *\n * Denied outranks engaged. A visitor who refused analytics in the banner does\n * not re-enable tracking by typing a question.\n */\n\nimport {\n UNKNOWN_CONSENT,\n type ConsentProvider,\n type ConsentPurpose,\n type ConsentSnapshot,\n type GatedPurpose,\n} from './types';\n\n/** Held events are dropped past this many — a runaway emitter must not become a leak. */\nconst DEFAULT_BUFFER_LIMIT = 50;\n\n/**\n * One prefix for the whole consent trail, so `[w5-consent]` in the console\n * filter shows the full story: which CMP was found, what it answered, and for\n * every event whether it was sent, held, dropped or replayed.\n */\nconst LOG_PREFIX = '[w5-consent]';\n\nconst log = (...args: unknown[]): void => {\n try {\n console.debug(LOG_PREFIX, ...args);\n } catch {\n // A console that throws must never break a send.\n }\n};\n\nconst describe = (s: ConsentSnapshot): string =>\n `analytics=${s.analytics} performance=${s.performance} marketing=${s.marketing}`;\n\ninterface HeldEvent {\n purpose: GatedPurpose;\n send: () => void;\n label: string;\n}\n\nexport interface GateView {\n consent: ConsentSnapshot;\n engaged: boolean;\n}\n\ntype Listener = () => void;\n\nlet snapshot: ConsentSnapshot = UNKNOWN_CONSENT;\nlet engaged = false;\nlet provider: ConsentProvider | null = null;\nlet unsubscribeProvider: (() => void) | null = null;\nlet buffer: HeldEvent[] = [];\nlet bufferLimit = DEFAULT_BUFFER_LIMIT;\nlet droppedFromOverflow = 0;\n\nconst listeners = new Set<Listener>();\n\n/**\n * Cached so `getGateView` is referentially stable between changes —\n * `useSyncExternalStore` re-renders forever if the snapshot is a fresh object\n * on every read.\n */\nlet view: GateView = Object.freeze({\n consent: UNKNOWN_CONSENT,\n engaged: false,\n});\n\nconst rebuildView = (): void => {\n view = Object.freeze({ consent: snapshot, engaged });\n};\n\nconst notify = (): void => {\n for (const listener of listeners) {\n try {\n listener();\n } catch {\n // A subscriber that throws must not stop the others, or stop a flush.\n }\n }\n};\n\n/**\n * Whether an event for `purpose` may go on the wire right now.\n *\n * `necessary` is always allowed. For everything else: explicit consent wins in\n * both directions, and engagement resolves only the `unknown` case.\n */\nexport const mayTransmit = (purpose: ConsentPurpose): boolean => {\n if (purpose === 'necessary') {\n return true;\n }\n const state = snapshot[purpose];\n if (state === 'denied') {\n return false;\n }\n if (state === 'granted') {\n return true;\n }\n return engaged;\n};\n\n/**\n * Release everything the gate is holding that is now allowed, and drop\n * everything that is now refused. Anything still `unknown` stays held.\n *\n * Order is preserved among released events, but a flush necessarily emits them\n * later than they were raised — a held app-load event reaches the wire after\n * the prompt that unlocked it. Anything reading these as a timeline has to\n * know that.\n */\nconst settleBuffer = (): void => {\n if (buffer.length === 0) {\n return;\n }\n const stillHeld: HeldEvent[] = [];\n const releasing: HeldEvent[] = [];\n\n for (const held of buffer) {\n if (mayTransmit(held.purpose)) {\n releasing.push(held);\n } else if (snapshot[held.purpose] === 'denied') {\n // dropped on the floor, deliberately and permanently\n } else {\n stillHeld.push(held);\n }\n }\n\n const dropped = buffer.length - stillHeld.length - releasing.length;\n buffer = stillHeld;\n\n if (releasing.length || dropped) {\n log(\n `settle — releasing ${releasing.length}` +\n (dropped ? `, dropping ${dropped} (refused)` : '') +\n (stillHeld.length ? `, still holding ${stillHeld.length}` : ''),\n );\n }\n\n for (const held of releasing) {\n try {\n log(` ↳ REPLAY ${held.label} (${held.purpose})`);\n held.send();\n } catch {\n // A failed send must not strand the rest of the flush.\n }\n }\n};\n\n/**\n * The single entry point for anything that would put a request on the wire.\n *\n * Allowed → sent now. Refused → dropped. Not yet known → held until an unlock\n * settles it, or discarded with the page.\n */\nexport const transmit = (\n purpose: ConsentPurpose,\n send: () => void,\n label = 'event',\n): void => {\n if (mayTransmit(purpose)) {\n log(`SEND ${label} (${purpose}) — allowed`);\n send();\n return;\n }\n if (purpose !== 'necessary' && snapshot[purpose] === 'denied') {\n log(`DROP ${label} (${purpose}) — visitor refused`);\n return;\n }\n if (buffer.length >= bufferLimit) {\n droppedFromOverflow += 1;\n log(\n `DROP ${label} (${purpose}) — buffer full at ${bufferLimit}, ${droppedFromOverflow} lost`,\n );\n return;\n }\n buffer.push({ purpose: purpose as GatedPurpose, send, label });\n log(`HOLD ${label} (${purpose}) — no answer yet, ${buffer.length} held`);\n};\n\n/**\n * The visitor did something deliberate — submitted a prompt — so the session\n * may be measured even though no CMP has answered.\n *\n * This is the unlock that keeps web5 measurable at all: on a Shopify store\n * with no privacy configuration the consent API never loads, consent stays\n * `unknown` forever, and without this every store would report nothing.\n *\n * It unlocks **transmission only**. Persistent identity stays gated on real\n * consent (see `mayPersistIdentity`) — typing a question is a reason to\n * measure the session, not a reason to persist an identifier across visits.\n * It also cannot override a `denied`.\n */\nexport const unlockOnUserAction = (): void => {\n if (engaged) {\n return;\n }\n engaged = true;\n log(\n `UNLOCK — visitor submitted a prompt; ${buffer.length} held event(s) to settle`,\n );\n rebuildView();\n settleBuffer();\n notify();\n};\n\n/** Whether the visitor has taken the deliberate action that unlocks the session. */\nexport const isUserEngaged = (): boolean => engaged;\n\n/**\n * Persistent, cross-visit storage of a visitor identifier requires real\n * consent — engagement is deliberately not enough.\n */\nexport const mayPersistIdentity = (): boolean =>\n snapshot.analytics === 'granted';\n\nexport const getConsentSnapshot = (): ConsentSnapshot => snapshot;\n\n/** Referentially stable between changes, for `useSyncExternalStore`. */\nexport const getGateView = (): GateView => view;\n\nexport const subscribeToConsent = (listener: Listener): (() => void) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n};\n\nconst applySnapshot = (next: ConsentSnapshot): void => {\n if (\n next.analytics === snapshot.analytics &&\n next.marketing === snapshot.marketing &&\n next.performance === snapshot.performance\n ) {\n return;\n }\n log(`ANSWER — ${describe(snapshot)} → ${describe(next)}`);\n snapshot = Object.freeze({ ...next });\n rebuildView();\n settleBuffer();\n notify();\n};\n\n/**\n * Install the host's provider. Reads its current state immediately, *then*\n * subscribes — DL #217: a listener registered into an already-rendered page is\n * bound to an event that may have fired long before the bundle executed, so\n * subscribing alone would leave the gate permanently at `unknown`.\n */\nexport const installConsentProvider = (next: ConsentProvider): void => {\n unsubscribeProvider?.();\n provider = next;\n const initial = next.read();\n log(`provider installed: ${next.name} — reads ${describe(initial)}`);\n applySnapshot(initial);\n unsubscribeProvider = next.subscribe(applySnapshot);\n};\n\nexport const getInstalledProviderName = (): string | null =>\n provider?.name ?? null;\n\nexport const setConsentBufferLimit = (limit: number): void => {\n bufferLimit = Math.max(0, limit);\n};\n\n/** Diagnostics only — how much the gate is holding, and what it had to drop. */\nexport const getConsentGateStats = (): {\n held: number;\n droppedFromOverflow: number;\n} => ({ held: buffer.length, droppedFromOverflow });\n\nexport const resetConsentGateForTests = (): void => {\n unsubscribeProvider?.();\n unsubscribeProvider = null;\n provider = null;\n snapshot = UNKNOWN_CONSENT;\n engaged = false;\n buffer = [];\n bufferLimit = DEFAULT_BUFFER_LIMIT;\n droppedFromOverflow = 0;\n listeners.clear();\n rebuildView();\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["UNKNOWN_CONSENT","LOG_PREFIX","log","_len","arguments","length","args","Array","_key","console","debug","describe","s","analytics","performance","marketing","snapshot","engaged","unsubscribeProvider","listeners","Set","notify","listener","mayPersistToken","state","unlockOnUserAction","getConsentSnapshot","subscribeToConsent","add","delete","applySnapshot","next","Object","freeze","installConsentProvider","initial","read","name","subscribe","resetConsentGateForTests","clear"],"sources":["../../../src/privacy/consentGate.ts"],"sourcesContent":["/**\n * The consent gate — DL #218 (revised).\n *\n * Legal cleared analytics/BI transmission to need no consent gate, so the old\n * `transmit()` + buffer machinery is gone. What analytics emitters used to route\n * through the gate now goes straight to the wire.\n *\n * Analytics AND performance telemetry both go straight to the wire now, so there\n * is nothing left to \"transmit\"-gate. What remains is the consent SIGNAL —\n * snapshot, engagement, provider — behind a single predicate:\n *\n * - `mayPersistToken()` — whether the visitor's OAuth token may be written to\n * localStorage. Persisting the token persists a cross-visit visitor identity\n * (its refresh token), which is the one thing consent still governs. Truth\n * table: granted → yes; denied → never; unknown → only once the visitor\n * engaged.\n *\n * Engagement (`unlockOnUserAction`, fired when the visitor submits a prompt)\n * resolves the `unknown` case — typing a question is a reason to remember this\n * visitor for the session — but it never overrides a `denied`.\n */\n\nimport {\n UNKNOWN_CONSENT,\n type ConsentProvider,\n type ConsentSnapshot,\n} from './types';\n\nconst LOG_PREFIX = '[w5-consent]';\n\nconst log = (...args: unknown[]): void => {\n try {\n console.debug(LOG_PREFIX, ...args);\n } catch {\n // A console that throws must never break anything.\n }\n};\n\nconst describe = (s: ConsentSnapshot): string =>\n `analytics=${s.analytics} performance=${s.performance} marketing=${s.marketing}`;\n\ntype Listener = () => void;\n\nlet snapshot: ConsentSnapshot = UNKNOWN_CONSENT;\nlet engaged = false;\nlet unsubscribeProvider: (() => void) | null = null;\n\nconst listeners = new Set<Listener>();\n\nconst notify = (): void => {\n for (const listener of listeners) {\n try {\n listener();\n } catch {\n // A subscriber that throws must not stop the others.\n }\n }\n};\n\n/**\n * Whether the visitor's OAuth token may be persisted to `localStorage`.\n *\n * Persisting the token persists a cross-visit visitor identity (the refresh\n * token re-identifies the visitor on their next visit), so it answers to\n * consent — the one thing that still does. Explicit consent wins in both\n * directions; engagement resolves only the `unknown` case. The token still\n * lives in memory for the session regardless — only the write to storage is\n * gated.\n */\nexport const mayPersistToken = (): boolean => {\n const state = snapshot.analytics;\n if (state === 'denied') {\n return false;\n }\n if (state === 'granted') {\n return true;\n }\n return engaged;\n};\n\n/**\n * The visitor did something deliberate — submitted a prompt — so we may remember\n * them for the session even though no CMP has answered. Unlocks the `unknown`\n * case only; it cannot override a `denied`.\n */\nexport const unlockOnUserAction = (): void => {\n if (engaged) {\n return;\n }\n engaged = true;\n log('UNLOCK — visitor submitted a prompt');\n notify();\n};\n\nexport const getConsentSnapshot = (): ConsentSnapshot => snapshot;\n\nexport const subscribeToConsent = (listener: Listener): (() => void) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n};\n\nconst applySnapshot = (next: ConsentSnapshot): void => {\n if (\n next.analytics === snapshot.analytics &&\n next.marketing === snapshot.marketing &&\n next.performance === snapshot.performance\n ) {\n return;\n }\n log(`ANSWER — ${describe(snapshot)} → ${describe(next)}`);\n snapshot = Object.freeze({ ...next });\n notify();\n};\n\n/**\n * Install the host's provider. Reads its current state immediately, *then*\n * subscribes — DL #217: a listener registered into an already-rendered page is\n * bound to an event that may have fired long before the bundle executed, so\n * subscribing alone would leave the gate permanently at `unknown`.\n */\nexport const installConsentProvider = (next: ConsentProvider): void => {\n unsubscribeProvider?.();\n const initial = next.read();\n log(`provider installed: ${next.name} — reads ${describe(initial)}`);\n applySnapshot(initial);\n unsubscribeProvider = next.subscribe(applySnapshot);\n};\n\nexport const resetConsentGateForTests = (): void => {\n unsubscribeProvider?.();\n unsubscribeProvider = null;\n snapshot = UNKNOWN_CONSENT;\n engaged = false;\n listeners.clear();\n};\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SACEA,eAAe,QAGV,SAAS;AAEhB,MAAMC,UAAU,GAAG,cAAc;AAEjC,MAAMC,GAAG,GAAG,SAAAA,CAAA,EAA8B;EACxC,IAAI;IAAA,SAAAC,IAAA,GAAAC,SAAA,CAAAC,MAAA,EADUC,IAAI,OAAAC,KAAA,CAAAJ,IAAA,GAAAK,IAAA,MAAAA,IAAA,GAAAL,IAAA,EAAAK,IAAA;MAAJF,IAAI,CAAAE,IAAA,IAAAJ,SAAA,CAAAI,IAAA;IAAA;IAEhBC,OAAO,CAACC,KAAK,CAACT,UAAU,EAAE,GAAGK,IAAI,CAAC;EACpC,CAAC,CAAC,MAAM;IACN;EAAA;AAEJ,CAAC;AAED,MAAMK,QAAQ,GAAIC,CAAkB,IAClC,aAAaA,CAAC,CAACC,SAAS,gBAAgBD,CAAC,CAACE,WAAW,cAAcF,CAAC,CAACG,SAAS,EAAE;AAIlF,IAAIC,QAAyB,GAAGhB,eAAe;AAC/C,IAAIiB,OAAO,GAAG,KAAK;AACnB,IAAIC,mBAAwC,GAAG,IAAI;AAEnD,MAAMC,SAAS,GAAG,IAAIC,GAAG,CAAW,CAAC;AAErC,MAAMC,MAAM,GAAGA,CAAA,KAAY;EACzB,KAAK,MAAMC,QAAQ,IAAIH,SAAS,EAAE;IAChC,IAAI;MACFG,QAAQ,CAAC,CAAC;IACZ,CAAC,CAAC,MAAM;MACN;IAAA;EAEJ;AACF,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,eAAe,GAAGA,CAAA,KAAe;EAC5C,MAAMC,KAAK,GAAGR,QAAQ,CAACH,SAAS;EAChC,IAAIW,KAAK,KAAK,QAAQ,EAAE;IACtB,OAAO,KAAK;EACd;EACA,IAAIA,KAAK,KAAK,SAAS,EAAE;IACvB,OAAO,IAAI;EACb;EACA,OAAOP,OAAO;AAChB,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMQ,kBAAkB,GAAGA,CAAA,KAAY;EAC5C,IAAIR,OAAO,EAAE;IACX;EACF;EACAA,OAAO,GAAG,IAAI;EACdf,GAAG,CAAC,qCAAqC,CAAC;EAC1CmB,MAAM,CAAC,CAAC;AACV,CAAC;AAED,OAAO,MAAMK,kBAAkB,GAAGA,CAAA,KAAuBV,QAAQ;AAEjE,OAAO,MAAMW,kBAAkB,GAAIL,QAAkB,IAAmB;EACtEH,SAAS,CAACS,GAAG,CAACN,QAAQ,CAAC;EACvB,OAAO,MAAM;IACXH,SAAS,CAACU,MAAM,CAACP,QAAQ,CAAC;EAC5B,CAAC;AACH,CAAC;AAED,MAAMQ,aAAa,GAAIC,IAAqB,IAAW;EACrD,IACEA,IAAI,CAAClB,SAAS,KAAKG,QAAQ,CAACH,SAAS,IACrCkB,IAAI,CAAChB,SAAS,KAAKC,QAAQ,CAACD,SAAS,IACrCgB,IAAI,CAACjB,WAAW,KAAKE,QAAQ,CAACF,WAAW,EACzC;IACA;EACF;EACAZ,GAAG,CAAC,YAAYS,QAAQ,CAACK,QAAQ,CAAC,QAAQL,QAAQ,CAACoB,IAAI,CAAC,EAAE,CAAC;EAC3Df,QAAQ,GAAGgB,MAAM,CAACC,MAAM,CAAC;IAAE,GAAGF;EAAK,CAAC,CAAC;EACrCV,MAAM,CAAC,CAAC;AACV,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMa,sBAAsB,GAAIH,IAAqB,IAAW;EACrEb,mBAAmB,YAAnBA,mBAAmB,CAAG,CAAC;EACvB,MAAMiB,OAAO,GAAGJ,IAAI,CAACK,IAAI,CAAC,CAAC;EAC3BlC,GAAG,CAAC,uBAAuB6B,IAAI,CAACM,IAAI,YAAY1B,QAAQ,CAACwB,OAAO,CAAC,EAAE,CAAC;EACpEL,aAAa,CAACK,OAAO,CAAC;EACtBjB,mBAAmB,GAAGa,IAAI,CAACO,SAAS,CAACR,aAAa,CAAC;AACrD,CAAC;AAED,OAAO,MAAMS,wBAAwB,GAAGA,CAAA,KAAY;EAClDrB,mBAAmB,YAAnBA,mBAAmB,CAAG,CAAC;EACvBA,mBAAmB,GAAG,IAAI;EAC1BF,QAAQ,GAAGhB,eAAe;EAC1BiB,OAAO,GAAG,KAAK;EACfE,SAAS,CAACqB,KAAK,CAAC,CAAC;AACnB,CAAC","ignoreList":[]}
@@ -1,5 +1,5 @@
1
1
  export { UNKNOWN_CONSENT } from './types.js';
2
- export { transmit, mayTransmit, unlockOnUserAction, isUserEngaged, mayPersistIdentity, getConsentSnapshot, getGateView, subscribeToConsent, installConsentProvider, getInstalledProviderName, setConsentBufferLimit, getConsentGateStats, resetConsentGateForTests } from './consentGate.js';
2
+ export { unlockOnUserAction, mayPersistToken, getConsentSnapshot, subscribeToConsent, installConsentProvider, resetConsentGateForTests } from './consentGate.js';
3
3
  export { detectConsentProvider, initConsentGate } from './detectProvider.js';
4
4
  export { CONSENT_OVERRIDE_KEY, CONSENT_OVERRIDE_QUERY_PARAM, getConsentOverride, setConsentOverride } from './consentOverride.js';
5
5
  export { createShopifyConsentProvider, isShopifyHost } from './providers/shopifyProvider.js';
@@ -1 +1 @@
1
- {"version":3,"names":["UNKNOWN_CONSENT","transmit","mayTransmit","unlockOnUserAction","isUserEngaged","mayPersistIdentity","getConsentSnapshot","getGateView","subscribeToConsent","installConsentProvider","getInstalledProviderName","setConsentBufferLimit","getConsentGateStats","resetConsentGateForTests","detectConsentProvider","initConsentGate","CONSENT_OVERRIDE_KEY","CONSENT_OVERRIDE_QUERY_PARAM","getConsentOverride","setConsentOverride","createShopifyConsentProvider","isShopifyHost","createOneTrustConsentProvider","isOneTrustHost","HOST_CONSENT_GLOBAL","createHostSuppliedConsentProvider","hasHostSuppliedConsent","publishHostConsent"],"sources":["../../../src/privacy/index.ts"],"sourcesContent":["export {\n type ConsentState,\n type ConsentPurpose,\n type GatedPurpose,\n type ConsentSnapshot,\n type ConsentProvider,\n UNKNOWN_CONSENT,\n} from './types';\n\nexport {\n type GateView,\n transmit,\n mayTransmit,\n unlockOnUserAction,\n isUserEngaged,\n mayPersistIdentity,\n getConsentSnapshot,\n getGateView,\n subscribeToConsent,\n installConsentProvider,\n getInstalledProviderName,\n setConsentBufferLimit,\n getConsentGateStats,\n resetConsentGateForTests,\n} from './consentGate';\n\nexport { detectConsentProvider, initConsentGate } from './detectProvider';\n\nexport {\n CONSENT_OVERRIDE_KEY,\n CONSENT_OVERRIDE_QUERY_PARAM,\n getConsentOverride,\n setConsentOverride,\n} from './consentOverride';\n\nexport {\n createShopifyConsentProvider,\n isShopifyHost,\n} from './providers/shopifyProvider';\nexport {\n createOneTrustConsentProvider,\n isOneTrustHost,\n} from './providers/oneTrustProvider';\nexport {\n type HostConsentInput,\n HOST_CONSENT_GLOBAL,\n createHostSuppliedConsentProvider,\n hasHostSuppliedConsent,\n publishHostConsent,\n} from './providers/hostSuppliedProvider';\n"],"mappings":"AAAA,SAMEA,eAAe,QACV,SAAS;AAEhB,SAEEC,QAAQ,EACRC,WAAW,EACXC,kBAAkB,EAClBC,aAAa,EACbC,kBAAkB,EAClBC,kBAAkB,EAClBC,WAAW,EACXC,kBAAkB,EAClBC,sBAAsB,EACtBC,wBAAwB,EACxBC,qBAAqB,EACrBC,mBAAmB,EACnBC,wBAAwB,QACnB,eAAe;AAEtB,SAASC,qBAAqB,EAAEC,eAAe,QAAQ,kBAAkB;AAEzE,SACEC,oBAAoB,EACpBC,4BAA4B,EAC5BC,kBAAkB,EAClBC,kBAAkB,QACb,mBAAmB;AAE1B,SACEC,4BAA4B,EAC5BC,aAAa,QACR,6BAA6B;AACpC,SACEC,6BAA6B,EAC7BC,cAAc,QACT,8BAA8B;AACrC,SAEEC,mBAAmB,EACnBC,iCAAiC,EACjCC,sBAAsB,EACtBC,kBAAkB,QACb,kCAAkC","ignoreList":[]}
1
+ {"version":3,"names":["UNKNOWN_CONSENT","unlockOnUserAction","mayPersistToken","getConsentSnapshot","subscribeToConsent","installConsentProvider","resetConsentGateForTests","detectConsentProvider","initConsentGate","CONSENT_OVERRIDE_KEY","CONSENT_OVERRIDE_QUERY_PARAM","getConsentOverride","setConsentOverride","createShopifyConsentProvider","isShopifyHost","createOneTrustConsentProvider","isOneTrustHost","HOST_CONSENT_GLOBAL","createHostSuppliedConsentProvider","hasHostSuppliedConsent","publishHostConsent"],"sources":["../../../src/privacy/index.ts"],"sourcesContent":["export {\n type ConsentState,\n type ConsentPurpose,\n type GatedPurpose,\n type ConsentSnapshot,\n type ConsentProvider,\n UNKNOWN_CONSENT,\n} from './types';\n\nexport {\n unlockOnUserAction,\n mayPersistToken,\n getConsentSnapshot,\n subscribeToConsent,\n installConsentProvider,\n resetConsentGateForTests,\n} from './consentGate';\n\nexport { detectConsentProvider, initConsentGate } from './detectProvider';\n\nexport {\n CONSENT_OVERRIDE_KEY,\n CONSENT_OVERRIDE_QUERY_PARAM,\n getConsentOverride,\n setConsentOverride,\n} from './consentOverride';\n\nexport {\n createShopifyConsentProvider,\n isShopifyHost,\n} from './providers/shopifyProvider';\nexport {\n createOneTrustConsentProvider,\n isOneTrustHost,\n} from './providers/oneTrustProvider';\nexport {\n type HostConsentInput,\n HOST_CONSENT_GLOBAL,\n createHostSuppliedConsentProvider,\n hasHostSuppliedConsent,\n publishHostConsent,\n} from './providers/hostSuppliedProvider';\n"],"mappings":"AAAA,SAMEA,eAAe,QACV,SAAS;AAEhB,SACEC,kBAAkB,EAClBC,eAAe,EACfC,kBAAkB,EAClBC,kBAAkB,EAClBC,sBAAsB,EACtBC,wBAAwB,QACnB,eAAe;AAEtB,SAASC,qBAAqB,EAAEC,eAAe,QAAQ,kBAAkB;AAEzE,SACEC,oBAAoB,EACpBC,4BAA4B,EAC5BC,kBAAkB,EAClBC,kBAAkB,QACb,mBAAmB;AAE1B,SACEC,4BAA4B,EAC5BC,aAAa,QACR,6BAA6B;AACpC,SACEC,6BAA6B,EAC7BC,cAAc,QACT,8BAA8B;AACrC,SAEEC,mBAAmB,EACnBC,iCAAiC,EACjCC,sBAAsB,EACtBC,kBAAkB,QACb,kCAAkC","ignoreList":[]}
@@ -31,6 +31,25 @@
31
31
  --input: 0 0% 89.8%;
32
32
  --ring: 0 0% 3.9%;
33
33
 
34
+ /* Owner chrome tokens — HSL triplets. The Customize panel's own greys (ADR
35
+ * 0243), held apart from the store's palette ON PURPOSE: the panel edits and
36
+ * previews `--background`, `--card` and the rest, so chrome painted with them
37
+ * repaints itself — a dark scheme turned the panel black and its labels
38
+ * unreadable. Nothing writes these: they are not in THEME_TOKEN_CONTRACT, no
39
+ * store import, scheme or owner override carries them, and an unknown key
40
+ * from a flat map lands on its `--web5-host-*` alias, never here. Light only
41
+ * (no `.dark` twin) — admin chrome, not themed. */
42
+ --web5-chrome-surface: 0 0% 100%;
43
+ --web5-chrome-foreground: 0 0% 18.8%;
44
+ --web5-chrome-muted-foreground: 0 0% 38%;
45
+ --web5-chrome-subtle-foreground: 210 4.5% 56.9%;
46
+ --web5-chrome-border: 0 0% 89%;
47
+ --web5-chrome-border-strong: 0 0% 71%;
48
+ --web5-chrome-tint: 0 0% 98%;
49
+ --web5-chrome-accent: 0 0% 18.8%;
50
+ --web5-chrome-accent-foreground: 0 0% 100%;
51
+ --web5-chrome-destructive: 9 72.2% 44.9%;
52
+
34
53
  /* Typography tokens */
35
54
  --font-sans: ui-sans-serif, system-ui, sans-serif;
36
55
  --font-serif: serif;
@@ -47,6 +47,18 @@
47
47
  --color-text-accent-hover: var(--text-accent-hover);
48
48
  --color-accent-border: var(--accent-border);
49
49
 
50
+ /* Owner chrome — the Customize panel's store-independent greys */
51
+ --color-web5-chrome-surface: hsl(var(--web5-chrome-surface));
52
+ --color-web5-chrome-foreground: hsl(var(--web5-chrome-foreground));
53
+ --color-web5-chrome-muted-foreground: hsl(var(--web5-chrome-muted-foreground));
54
+ --color-web5-chrome-subtle-foreground: hsl(var(--web5-chrome-subtle-foreground));
55
+ --color-web5-chrome-border: hsl(var(--web5-chrome-border));
56
+ --color-web5-chrome-border-strong: hsl(var(--web5-chrome-border-strong));
57
+ --color-web5-chrome-tint: hsl(var(--web5-chrome-tint));
58
+ --color-web5-chrome-accent: hsl(var(--web5-chrome-accent));
59
+ --color-web5-chrome-accent-foreground: hsl(var(--web5-chrome-accent-foreground));
60
+ --color-web5-chrome-destructive: hsl(var(--web5-chrome-destructive));
61
+
50
62
  --radius-sm: calc(var(--radius) - 4px);
51
63
  --radius-md: calc(var(--radius) - 2px);
52
64
  --radius-lg: var(--radius);
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The owner panel's own chrome colours (`--web5-chrome-*`).
3
+ *
4
+ * The Customize panel edits and previews the store's colour tokens, so its
5
+ * chrome cannot be painted with them: a dark scheme would turn its labels
6
+ * dark-on-dark and a cream card colour would turn the whole panel cream. It
7
+ * takes these instead — light, neutral, and written by nothing the store or the
8
+ * merchant controls.
9
+ *
10
+ * WHY A CONSTANT AND NOT ONLY CSS. `base-tokens.css` declares the same values,
11
+ * but that stylesheet reaches a page through the CLIENT bundle, and every
12
+ * client bundle pins the core version it was built against. A storefront whose
13
+ * template predates these tokens would leave the panel's `hsl(var(...))`
14
+ * invalid — a transparent panel inheriting the scheme's text colour. The panel
15
+ * lives in web50-server-ui, which bundles its own core, so it writes each value
16
+ * as the `var()` fallback (`hsl(var(--web5-chrome-surface, 0 0% 100%))`, see
17
+ * `chrome()` in the TemplatePicker) and never depends on the client's CSS.
18
+ * `chromeTokens.spec.ts` keeps this map and `base-tokens.css` equal.
19
+ *
20
+ * Bare HSL triplets, like every colour token: callers wrap them in `hsl()`.
21
+ * A leaf module (no CSS imports), for the reason `tokenContract.ts` gives.
22
+ */
23
+
24
+ /** Token name (without the `--web5-chrome-` prefix) → bare HSL triplet. */
25
+ export const WEB5_CHROME_TOKENS = Object.freeze({
26
+ surface: '0 0% 100%',
27
+ foreground: '0 0% 18.8%',
28
+ 'muted-foreground': '0 0% 38%',
29
+ 'subtle-foreground': '210 4.5% 56.9%',
30
+ border: '0 0% 89%',
31
+ 'border-strong': '0 0% 71%',
32
+ tint: '0 0% 98%',
33
+ accent: '0 0% 18.8%',
34
+ 'accent-foreground': '0 0% 100%',
35
+ destructive: '9 72.2% 44.9%'
36
+ });
37
+ /** `surface` → `--web5-chrome-surface`. */
38
+ export const web5ChromeProperty = token => `--web5-chrome-${token}`;
39
+
40
+ /**
41
+ * Every chrome token as custom properties, ready to spread into an element's
42
+ * inline style (`style={{ ...web5ChromeProperties(), ... }}`), so the element
43
+ * and everything inside it resolve `var(--web5-chrome-*)` without any
44
+ * stylesheet.
45
+ */
46
+ export function web5ChromeProperties() {
47
+ const out = {};
48
+ for (const [token, value] of Object.entries(WEB5_CHROME_TOKENS)) {
49
+ out[web5ChromeProperty(token)] = value;
50
+ }
51
+ return out;
52
+ }
53
+ //# sourceMappingURL=chromeTokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["WEB5_CHROME_TOKENS","Object","freeze","surface","foreground","border","tint","accent","destructive","web5ChromeProperty","token","web5ChromeProperties","out","value","entries"],"sources":["../../../src/theme/chromeTokens.ts"],"sourcesContent":["/**\n * The owner panel's own chrome colours (`--web5-chrome-*`).\n *\n * The Customize panel edits and previews the store's colour tokens, so its\n * chrome cannot be painted with them: a dark scheme would turn its labels\n * dark-on-dark and a cream card colour would turn the whole panel cream. It\n * takes these instead — light, neutral, and written by nothing the store or the\n * merchant controls.\n *\n * WHY A CONSTANT AND NOT ONLY CSS. `base-tokens.css` declares the same values,\n * but that stylesheet reaches a page through the CLIENT bundle, and every\n * client bundle pins the core version it was built against. A storefront whose\n * template predates these tokens would leave the panel's `hsl(var(...))`\n * invalid — a transparent panel inheriting the scheme's text colour. The panel\n * lives in web50-server-ui, which bundles its own core, so it writes each value\n * as the `var()` fallback (`hsl(var(--web5-chrome-surface, 0 0% 100%))`, see\n * `chrome()` in the TemplatePicker) and never depends on the client's CSS.\n * `chromeTokens.spec.ts` keeps this map and `base-tokens.css` equal.\n *\n * Bare HSL triplets, like every colour token: callers wrap them in `hsl()`.\n * A leaf module (no CSS imports), for the reason `tokenContract.ts` gives.\n */\n\n/** Token name (without the `--web5-chrome-` prefix) → bare HSL triplet. */\nexport const WEB5_CHROME_TOKENS = Object.freeze({\n surface: '0 0% 100%',\n foreground: '0 0% 18.8%',\n 'muted-foreground': '0 0% 38%',\n 'subtle-foreground': '210 4.5% 56.9%',\n border: '0 0% 89%',\n 'border-strong': '0 0% 71%',\n tint: '0 0% 98%',\n accent: '0 0% 18.8%',\n 'accent-foreground': '0 0% 100%',\n destructive: '9 72.2% 44.9%',\n} as const);\n\nexport type Web5ChromeToken = keyof typeof WEB5_CHROME_TOKENS;\n\n/** `surface` → `--web5-chrome-surface`. */\nexport const web5ChromeProperty = (token: Web5ChromeToken): `--web5-chrome-${string}` =>\n `--web5-chrome-${token}`;\n\n/**\n * Every chrome token as custom properties, ready to spread into an element's\n * inline style (`style={{ ...web5ChromeProperties(), ... }}`), so the element\n * and everything inside it resolve `var(--web5-chrome-*)` without any\n * stylesheet.\n */\nexport function web5ChromeProperties(): Record<`--web5-chrome-${string}`, string> {\n const out = {} as Record<`--web5-chrome-${string}`, string>;\n for (const [token, value] of Object.entries(WEB5_CHROME_TOKENS)) {\n out[web5ChromeProperty(token as Web5ChromeToken)] = value;\n }\n return out;\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,OAAO,MAAMA,kBAAkB,GAAGC,MAAM,CAACC,MAAM,CAAC;EAC9CC,OAAO,EAAE,WAAW;EACpBC,UAAU,EAAE,YAAY;EACxB,kBAAkB,EAAE,UAAU;EAC9B,mBAAmB,EAAE,gBAAgB;EACrCC,MAAM,EAAE,UAAU;EAClB,eAAe,EAAE,UAAU;EAC3BC,IAAI,EAAE,UAAU;EAChBC,MAAM,EAAE,YAAY;EACpB,mBAAmB,EAAE,WAAW;EAChCC,WAAW,EAAE;AACf,CAAU,CAAC;AAIX;AACA,OAAO,MAAMC,kBAAkB,GAAIC,KAAsB,IACvD,iBAAiBA,KAAK,EAAE;;AAE1B;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,oBAAoBA,CAAA,EAA8C;EAChF,MAAMC,GAAG,GAAG,CAAC,CAA8C;EAC3D,KAAK,MAAM,CAACF,KAAK,EAAEG,KAAK,CAAC,IAAIZ,MAAM,CAACa,OAAO,CAACd,kBAAkB,CAAC,EAAE;IAC/DY,GAAG,CAACH,kBAAkB,CAACC,KAAwB,CAAC,CAAC,GAAGG,KAAK;EAC3D;EACA,OAAOD,GAAG;AACZ","ignoreList":[]}
@@ -29,9 +29,22 @@
29
29
  * but a deep import of a zero-CSS leaf works. It imports only its siblings
30
30
  * `./tokenContract` and `./colorFormat`, both leaves themselves.
31
31
  *
32
+ * ## What a scheme carries (ADR 0243)
33
+ *
34
+ * A theme scheme is a background and its text, plus the colours mechanically
35
+ * derived from those two: `SCHEME_TOKENS`. Card colours, button colours,
36
+ * radius and fonts are the store's global set (`themeOverrides`) and the
37
+ * owner's global edits (`userThemeOverrides`), applied under and over the
38
+ * scheme respectively — so they survive every scheme switch. Rows written
39
+ * before 0243 may still carry more; readers apply whatever a row holds, and
40
+ * the owner panel writes only `SCHEME_TOKENS` into the rows it creates.
41
+ *
42
+ * An edited THEME scheme is an OWNER row that names it in `baseSchemeId`, so
43
+ * the panel can show the edit on that scheme's tile and revert only that one.
44
+ *
32
45
  * ## `completeScheme` — what the owner panel recomputes
33
46
  *
34
- * The owner edits the four anchors. The rest of the palette has to move with
47
+ * The owner edits the two anchors. The rest of the scheme has to move with
35
48
  * them the way `web50-shopify-adapter/src/theme-tokens.ts` would have moved it
36
49
  * had the theme stated those anchors, so the arithmetic below is a COPY of the
37
50
  * adapter's (`composite`/`mix`/`toTriplet` and the token assignments at the end
@@ -42,30 +55,22 @@
42
55
  * | ------------------------ | ------------------------------------------------------ |
43
56
  * | `--background` | anchor (else inherited from base) |
44
57
  * | `--foreground` | anchor (else inherited from base) |
45
- * | `--card` | anchor; when not given, derived: foreground 4% over background |
46
- * | `--card-foreground` | anchor; when not given, derived: = foreground |
47
58
  * | `--popover` | derived: = background |
48
59
  * | `--popover-foreground` | derived: = foreground |
49
60
  * | `--muted` | derived: foreground 4% over background |
50
61
  * | `--muted-foreground` | derived: foreground 60% over background |
51
62
  * | `--secondary` | derived: primary 10% over background |
52
63
  * | `--accent` | derived: primary 10% over background |
53
- * | `--primary` | inherited from base (the theme's button colour) |
54
- * | `--primary-foreground` | inherited from base (the theme's button label) |
55
- * | `--secondary-foreground` | inherited from base (the theme's outline-button label) |
56
- * | `--accent-foreground` | inherited from base; fallback = primary |
57
- * | `--ring` | inherited from base; fallback = primary |
58
64
  * | `--border` | inherited from base (no fallback — see below) |
59
65
  * | `--input` | inherited from base (no fallback — see below) |
60
- * | `--heading` | inherited from base (no adapter fills it) |
61
- * | any non-colour key | `--radius`, fonts, unknown: copied from base when valid |
62
66
  *
63
- * "Inherited" tokens are ones the adapter reads straight off the theme, which
64
- * no arithmetic over the anchors can recover. Where base lacks one, the
65
- * adapter's own fallback applies: `--ring` and `--accent-foreground` are the
66
- * primary colour. `--border`/`--input` have none the adapter reconstructs a
67
- * missing border from the theme's `*_border_opacity` setting, which a token map
68
- * does not carry so they are omitted, as the adapter omits them.
67
+ * Primary is not a scheme token it is the store's button colour — so the
68
+ * caller passes it as `context.primary`; without one, base's own `--primary`
69
+ * (a pre-0243 row) is used. `--border`/`--input` are read straight off the
70
+ * theme by the adapter, which reconstructs a missing border from the theme's
71
+ * `*_border_opacity` setting a token map does not carry — so they are
72
+ * inherited from base, and omitted when base lacks them, as the adapter omits
73
+ * them.
69
74
  *
70
75
  * ## Rounding: why an unchanged input keeps base's value
71
76
  *
@@ -124,8 +129,24 @@ const SCHEME_RADIUS_VALUE = /^\d{1,4}(?:\.\d+)?(?:px|rem|em)$/;
124
129
  const SCHEME_LOOSE_VALUE = /^[^;{}\p{Cc}]+$/u;
125
130
  const MAX_SCHEME_VALUE_LENGTH = 256;
126
131
 
127
- /** The four the owner edits, in panel order. Equal to the contract's editable colour tokens. */
128
- export const SCHEME_ANCHOR_TOKENS = ['--background', '--foreground', '--card', '--card-foreground'];
132
+ /**
133
+ * What a scheme is (ADR 0243): its background and text, and the colours
134
+ * derived from those two. The panel writes exactly these into the OWNER rows
135
+ * it creates, and mirrors exactly these of the active row into `themeOverrides`.
136
+ */
137
+ export const SCHEME_TOKENS = ['--background', '--foreground', '--popover', '--popover-foreground', '--muted', '--muted-foreground', '--border', '--input', '--secondary', '--accent'];
138
+ const SCHEME_TOKEN_SET = new Set(SCHEME_TOKENS);
139
+
140
+ /** Only the `SCHEME_TOKENS` entries of `map`. */
141
+ export function schemeTokensOf(map) {
142
+ return Object.fromEntries(Object.entries(map ?? {}).filter(_ref3 => {
143
+ let [token] = _ref3;
144
+ return SCHEME_TOKEN_SET.has(token);
145
+ }));
146
+ }
147
+
148
+ /** The two the owner edits on a scheme, in panel order. */
149
+ export const SCHEME_ANCHOR_TOKENS = ['--background', '--foreground'];
129
150
  /** Upper bound on schemes per configuration. */
130
151
  export const MAX_THEME_SCHEMES = 16;
131
152
  const SCHEME_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,31}$/;
@@ -148,11 +169,15 @@ export function isThemeScheme(value) {
148
169
  id,
149
170
  name,
150
171
  origin,
172
+ baseSchemeId,
151
173
  tokens
152
174
  } = value;
153
175
  if (typeof id !== 'string' || !SCHEME_ID_PATTERN.test(id)) {
154
176
  return false;
155
177
  }
178
+ if (baseSchemeId !== undefined && typeof baseSchemeId !== 'string') {
179
+ return false;
180
+ }
156
181
  if (name !== undefined && (typeof name !== 'string' || name.length > MAX_SCHEME_NAME_LENGTH)) {
157
182
  return false;
158
183
  }
@@ -217,12 +242,12 @@ function mix(fg, ratio, bg) {
217
242
  }
218
243
 
219
244
  /** Adapter `toTriplet`: `"H S% L%"`, integer-rounded. */
220
- function toTriplet(_ref3) {
245
+ function toTriplet(_ref4) {
221
246
  let {
222
247
  r,
223
248
  g,
224
249
  b
225
- } = _ref3;
250
+ } = _ref4;
226
251
  const rn = r / 255;
227
252
  const gn = g / 255;
228
253
  const bn = b / 255;
@@ -246,25 +271,25 @@ function toTriplet(_ref3) {
246
271
  return `${Math.round(h)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`;
247
272
  }
248
273
 
249
- /** Tokens the adapter reads off the theme rather than computing from the anchors. */
250
- const INHERITED_TOKENS = ['--primary', '--primary-foreground', '--secondary-foreground', '--accent-foreground', '--ring', '--border', '--input', '--heading'];
274
+ /** What `completeScheme` needs from outside the scheme. */
251
275
 
252
276
  /**
253
- * A full colour-token map for a palette whose anchors the owner just edited.
277
+ * The `SCHEME_TOKENS` of a scheme whose anchors the owner just edited.
254
278
  *
255
279
  * `anchors` win; everything the adapter derives from them is recomputed when
256
280
  * one of its inputs changed (and kept from `base` when none did — see "Rounding"
257
- * in the module header); everything it reads directly is taken from `base`.
258
- * Invalid triplets in either input are ignored, and a derived token whose
259
- * inputs are unavailable keeps `base`'s value, if any.
281
+ * in the module header); `--border`/`--input` are taken from `base`. Invalid
282
+ * triplets in any input are ignored, and a derived token whose inputs are
283
+ * unavailable keeps `base`'s value, if any.
260
284
  *
261
- * Returns the whole scheme map, not only its colours: every non-colour entry of
262
- * `base` that passes `isSchemeTokenEntry` `--radius`, a font stack, a token
263
- * this module does not know — is copied as is, so customizing a palette keeps
264
- * everything it states beyond colour. Every output entry passes
265
- * `isSchemeTokenEntry`.
285
+ * Returns ONLY `SCHEME_TOKENS`: whatever else `base` carries (a pre-0243 row's
286
+ * card or button colours, its radius) is the store's global set now, not the
287
+ * scheme's, and is dropped. Every output entry passes `isSchemeTokenEntry`.
266
288
  */
267
- export function completeScheme(base, anchors) {
289
+ export function completeScheme(base, anchors, context) {
290
+ if (context === void 0) {
291
+ context = {};
292
+ }
268
293
  // Both checks: `isHslTriplet` is what the arithmetic can convert, and the
269
294
  // scheme grammar is what a write accepts — failing either would poison a
270
295
  // derivation or get the whole save refused.
@@ -292,30 +317,24 @@ export function completeScheme(base, anchors) {
292
317
  const mixOver = (over, ratio) => () => over !== null && bg !== null ? toTriplet(mix(over, ratio, bg)) : undefined;
293
318
  put('--background', background);
294
319
  put('--foreground', foreground);
295
- put('--card', fromAnchor('--card') ?? derive('--card', bgChanged || fgChanged, mixOver(fg, 0.04)));
296
- put('--card-foreground', fromAnchor('--card-foreground') ?? derive('--card-foreground', fgChanged, () => foreground));
297
320
  put('--popover', derive('--popover', bgChanged, () => background));
298
321
  put('--popover-foreground', derive('--popover-foreground', fgChanged, () => foreground));
299
322
  put('--muted', derive('--muted', bgChanged || fgChanged, mixOver(fg, 0.04)));
300
323
  put('--muted-foreground', derive('--muted-foreground', bgChanged || fgChanged, mixOver(fg, 0.6)));
301
- for (const token of INHERITED_TOKENS) {
302
- put(token, fromBase(token));
303
- }
304
- // Primary is inherited, so of the button family's inputs only the page can change.
305
- const primaryTriplet = out['--primary'];
306
- const primary = primaryTriplet === undefined ? null : tripletToRgb(primaryTriplet);
307
- put('--ring', out['--ring'] ?? primaryTriplet);
308
- put('--accent-foreground', out['--accent-foreground'] ?? primaryTriplet);
309
- put('--secondary', derive('--secondary', bgChanged, mixOver(primary, 0.1)));
310
- put('--accent', derive('--accent', bgChanged, mixOver(primary, 0.1)));
324
+ put('--border', fromBase('--border'));
325
+ put('--input', fromBase('--input'));
311
326
 
312
- // Not colours, so no arithmetic touches them: the palette keeps its shape,
313
- // its type, and any token a writer added that this module has never heard of.
314
- for (const [token, value] of Object.entries(base)) {
315
- if (!SCHEME_COLOR_TOKENS.has(token) && isSchemeTokenEntry(token, value)) {
316
- out[token] = value;
317
- }
318
- }
327
+ // Primary is the store's, not the scheme's. It counts as a changed input only
328
+ // when base states the primary its tints were computed from and the context
329
+ // names a different one; a base without one keeps its tints until the page
330
+ // itself moves.
331
+ const basePrimary = fromBase('--primary');
332
+ const primaryTriplet = valid(context.primary) ?? basePrimary;
333
+ const primaryChanged = basePrimary !== undefined && primaryTriplet !== undefined && primaryTriplet !== basePrimary;
334
+ const primary = primaryTriplet === undefined ? null : tripletToRgb(primaryTriplet);
335
+ const tintChanged = bgChanged || primaryChanged;
336
+ put('--secondary', derive('--secondary', tintChanged, mixOver(primary, 0.1)));
337
+ put('--accent', derive('--accent', tintChanged, mixOver(primary, 0.1)));
319
338
  return out;
320
339
  }
321
340
 
@@ -1 +1 @@
1
- {"version":3,"names":["isHslTriplet","THEME_OVERRIDE_KEY_PATTERN","THEME_TOKEN_CONTRACT","SCHEME_COLOR_TOKENS","Object","freeze","Set","entries","filter","_ref","entry","type","map","_ref2","token","SCHEME_COLOR_VALUE","SCHEME_RADIUS_VALUE","SCHEME_LOOSE_VALUE","MAX_SCHEME_VALUE_LENGTH","SCHEME_ANCHOR_TOKENS","MAX_THEME_SCHEMES","SCHEME_ID_PATTERN","MAX_SCHEME_NAME_LENGTH","isPlainObject","value","Array","isArray","isThemeScheme","id","name","origin","tokens","test","undefined","length","values","every","v","resolveActiveScheme","cfg","themeSchemes","schemes","activeId","activeThemeSchemeId","active","find","scheme","TRIPLET","tripletToRgb","triplet","parts","exec","trim","h","Number","s","l","c","Math","abs","x","m","r","g","b","mix","fg","ratio","bg","round","toTriplet","_ref3","rn","gn","bn","max","min","delta","INHERITED_TOKENS","completeScheme","base","anchors","valid","isSchemeColorValue","fromBase","fromAnchor","out","put","background","foreground","bgChanged","fgChanged","derive","inputsChanged","compute","kept","mixOver","over","primaryTriplet","primary","has","isSchemeTokenEntry","schemeDisplayName","index","nextOwnerSchemeId","taken","n","key","_THEME_TOKEN_CONTRACT"],"sources":["../../../src/theme/themeScheme.ts"],"sourcesContent":["/**\n * Named theme schemes on a site configuration, and the one that is active.\n *\n * A store's theme states a SET of palettes rather than one — Dawn and Horizon\n * ship `scheme-1`..`scheme-5` for the page, the cards, the hero band, the\n * footer. The configuration therefore carries a list of schemes plus the id of\n * the active one, beside the flat `themeOverrides` map it has always had:\n *\n * themeSchemes?: [{ id, name?, origin?, tokens: { '--background': '0 0% 100%', … } }]\n * activeThemeSchemeId?: 'scheme-1'\n *\n * A scheme's `tokens` are finished CSS tokens, spelled exactly as\n * `themeOverrides` spells them — and, like `themeOverrides`, the key set is\n * OPEN. Today's writers put the 18 colour roles (`SCHEME_COLOR_TOKENS`) there,\n * sometimes `--radius`; that a palette may carry shape as well as colour is why\n * this is a THEME scheme and not a colour scheme. A new token (a font stack,\n * something the contract has not catalogued yet) needs no release anywhere but\n * its writer. The server checks only the loose shape `themeOverrides` gets (key\n * `THEME_OVERRIDE_KEY_PATTERN`, a value free of `;`, `{`, `}` and control\n * characters, ≤ 256, at most 24 entries); the typed per-token grammar is the\n * CLIENT's contract, enforced by `isSchemeTokenEntry` before the panel writes.\n * Nothing is expanded at apply time: the reader resolves the active entry and\n * hands its map to `applyThemeOverrides`, which layers it between the store map\n * and the owner's overrides, filtered and bucketed exactly like the store map.\n * A configuration with no schemes renders exactly as it did before they existed.\n *\n * A leaf module beside `tokenContract.ts`, and for the same reason that file\n * documents: requiring core's ENTRY from plain Node fails on its CSS import,\n * but a deep import of a zero-CSS leaf works. It imports only its siblings\n * `./tokenContract` and `./colorFormat`, both leaves themselves.\n *\n * ## `completeScheme` — what the owner panel recomputes\n *\n * The owner edits the four anchors. The rest of the palette has to move with\n * them the way `web50-shopify-adapter/src/theme-tokens.ts` would have moved it\n * had the theme stated those anchors, so the arithmetic below is a COPY of the\n * adapter's (`composite`/`mix`/`toTriplet` and the token assignments at the end\n * of `extractThemeOverrides`), integer rounding included. It is copied rather\n * than shared on purpose: the adapter must not import core.\n *\n * | token | role |\n * | ------------------------ | ------------------------------------------------------ |\n * | `--background` | anchor (else inherited from base) |\n * | `--foreground` | anchor (else inherited from base) |\n * | `--card` | anchor; when not given, derived: foreground 4% over background |\n * | `--card-foreground` | anchor; when not given, derived: = foreground |\n * | `--popover` | derived: = background |\n * | `--popover-foreground` | derived: = foreground |\n * | `--muted` | derived: foreground 4% over background |\n * | `--muted-foreground` | derived: foreground 60% over background |\n * | `--secondary` | derived: primary 10% over background |\n * | `--accent` | derived: primary 10% over background |\n * | `--primary` | inherited from base (the theme's button colour) |\n * | `--primary-foreground` | inherited from base (the theme's button label) |\n * | `--secondary-foreground` | inherited from base (the theme's outline-button label) |\n * | `--accent-foreground` | inherited from base; fallback = primary |\n * | `--ring` | inherited from base; fallback = primary |\n * | `--border` | inherited from base (no fallback — see below) |\n * | `--input` | inherited from base (no fallback — see below) |\n * | `--heading` | inherited from base (no adapter fills it) |\n * | any non-colour key | `--radius`, fonts, unknown: copied from base when valid |\n *\n * \"Inherited\" tokens are ones the adapter reads straight off the theme, which\n * no arithmetic over the anchors can recover. Where base lacks one, the\n * adapter's own fallback applies: `--ring` and `--accent-foreground` are the\n * primary colour. `--border`/`--input` have none — the adapter reconstructs a\n * missing border from the theme's `*_border_opacity` setting, which a token map\n * does not carry — so they are omitted, as the adapter omits them.\n *\n * ## Rounding: why an unchanged input keeps base's value\n *\n * The adapter mixes 8-bit channels parsed from the theme's hex; a scheme only\n * has the integer-rounded triplet, and the hex cannot be recovered from it.\n * Re-deriving from triplets therefore lands a point off now and then — Horizon\n * `color_palette`'s `--muted-foreground` comes back `359 83% 68%` against the\n * adapter's `359 84% 68%`. So a derived token is recomputed only when one of\n * its INPUTS differs from base; otherwise base's value stands. A merchant who\n * edits nothing gets the adapter's map back exactly, and one who edits the\n * background gets the family recomputed.\n *\n * When it is recomputed, triplets convert back to RGB WITHOUT rounding to\n * 8-bit first — that would be a second quantisation the adapter never\n * performs, and enough to move smallflower's `--secondary` from `230 38% 94%`\n * to `230 42% 94%`. The mix result is rounded exactly where the adapter\n * rounds it.\n */\nimport { isHslTriplet } from './colorFormat';\nimport {\n THEME_OVERRIDE_KEY_PATTERN,\n THEME_TOKEN_CONTRACT,\n} from './tokenContract';\n\n/** Where a scheme came from. Any other value on the wire reads as unknown. */\nexport type SchemeOrigin = 'UNKNOWN_SCHEME_ORIGIN' | 'THEME' | 'OWNER';\n\n/** One named palette as the configuration carries it. */\nexport interface ThemeScheme {\n /** `^[a-z0-9][a-z0-9-]{0,31}$`, unique within the list. */\n id: string;\n /** Shown in the owner panel; at most 48 characters. */\n name?: string;\n origin?: SchemeOrigin | string;\n /**\n * Token → value, keys as open as `themeOverrides`': colours as bare HSL\n * triplets (`0 0% 100%`), `--radius` as a length (`0.5rem`), anything else\n * in the loose value shape. See `isSchemeTokenEntry`.\n */\n tokens: Record<string, string>;\n}\n\n/** Every colour role in the contract (`type: 'color-hsl'`, `--heading` included). */\nexport const SCHEME_COLOR_TOKENS: ReadonlySet<string> = Object.freeze(\n new Set(\n Object.entries(THEME_TOKEN_CONTRACT)\n .filter(([, entry]) => entry.type === 'color-hsl')\n .map(([token]) => token),\n ),\n) as ReadonlySet<string>;\n\n/**\n * A scheme colour (`type: 'color-hsl'`): `H S% L%`, single-spaced, no `hsl()`\n * wrapper. Saturation and lightness are additionally capped at 100\n * (`isSchemeColorValue`); hue is bounded only by its three digits.\n */\nconst SCHEME_COLOR_VALUE =\n /^(\\d{1,3}(?:\\.\\d+)?) (\\d{1,3}(?:\\.\\d+)?)% (\\d{1,3}(?:\\.\\d+)?)%$/;\n\n/**\n * A scheme length (`type: 'length'`, i.e. `--radius`): px/rem/em, unit REQUIRED\n * (`0px`, not `0`). A bare `0` would turn `calc(var(--radius) - 4px)` into\n * invalid CSS — see the `length` note in `tokenContract.ts`.\n */\nconst SCHEME_RADIUS_VALUE = /^\\d{1,4}(?:\\.\\d+)?(?:px|rem|em)$/;\n\n/**\n * Any other scheme value — a font stack, a key the contract has not catalogued:\n * no `;`, `{`, `}` or control character. The server's `themeOverrides` value\n * shape (`^[^;{}\\p{Cntrl}]{1,256}$`); the length is checked separately in\n * UTF-16 units, as the server counts, since a `u`-flag quantifier counts code\n * points.\n */\nconst SCHEME_LOOSE_VALUE = /^[^;{}\\p{Cc}]+$/u;\nconst MAX_SCHEME_VALUE_LENGTH = 256;\n\n/** The four the owner edits, in panel order. Equal to the contract's editable colour tokens. */\nexport const SCHEME_ANCHOR_TOKENS = [\n '--background',\n '--foreground',\n '--card',\n '--card-foreground',\n] as const;\n\nexport type SchemeAnchorToken = (typeof SCHEME_ANCHOR_TOKENS)[number];\n\n/** Upper bound on schemes per configuration. */\nexport const MAX_THEME_SCHEMES = 16;\n\nconst SCHEME_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,31}$/;\nconst MAX_SCHEME_NAME_LENGTH = 48;\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * Whether an untrusted value has a scheme's SHAPE.\n *\n * Token content is deliberately not judged here: `applyThemeOverrides` drops a\n * malformed key one entry at a time, exactly as it does for the flat store map\n * (and says so), so one bad token costs that token rather than the whole\n * palette. The typed value grammar is `isSchemeTokenEntry`, checked by writers.\n */\nexport function isThemeScheme(value: unknown): value is ThemeScheme {\n if (!isPlainObject(value)) {\n return false;\n }\n const { id, name, origin, tokens } = value;\n if (typeof id !== 'string' || !SCHEME_ID_PATTERN.test(id)) {\n return false;\n }\n if (\n name !== undefined &&\n (typeof name !== 'string' || name.length > MAX_SCHEME_NAME_LENGTH)\n ) {\n return false;\n }\n if (origin !== undefined && typeof origin !== 'string') {\n return false;\n }\n return (\n isPlainObject(tokens) &&\n Object.values(tokens).every((v) => typeof v === 'string')\n );\n}\n\n/**\n * The active scheme: the entry whose id is `activeThemeSchemeId`, else the\n * first entry, else null. Entries failing `isThemeScheme` are skipped first, so\n * a dangling id or a malformed entry falls through to the first usable one.\n */\nexport function resolveActiveScheme(\n cfg:\n | { themeSchemes?: unknown; activeThemeSchemeId?: string | null }\n | null\n | undefined,\n): ThemeScheme | null {\n if (!cfg || !Array.isArray(cfg.themeSchemes)) {\n return null;\n }\n const schemes = cfg.themeSchemes.filter(isThemeScheme);\n if (schemes.length === 0) {\n return null;\n }\n const activeId = cfg.activeThemeSchemeId;\n const active =\n typeof activeId === 'string'\n ? schemes.find((scheme) => scheme.id === activeId)\n : undefined;\n return active ?? schemes[0];\n}\n\n// ── Arithmetic copied from web50-shopify-adapter/src/theme-tokens.ts ────────\n\ninterface Rgb {\n r: number;\n g: number;\n b: number;\n}\n\nconst TRIPLET = /^(\\d{1,3}(?:\\.\\d+)?)\\s+(\\d{1,3}(?:\\.\\d+)?)%\\s+(\\d{1,3}(?:\\.\\d+)?)%$/;\n\n/**\n * A triplet as RGB in 0–255, NOT rounded to 8-bit — see the module header for\n * why. Same conversion as `colorFormat.hslTripletToHex`, minus its rounding.\n */\nfunction tripletToRgb(triplet: string): Rgb | null {\n const parts = TRIPLET.exec(triplet.trim());\n if (!parts || !isHslTriplet(triplet)) {\n return null;\n }\n const h = Number(parts[1]);\n const s = Number(parts[2]) / 100;\n const l = Number(parts[3]) / 100;\n\n const c = (1 - Math.abs(2 * l - 1)) * s;\n const x = c * (1 - Math.abs(((h / 60) % 2) - 1));\n const m = l - c / 2;\n const [r, g, b] =\n h < 60\n ? [c, x, 0]\n : h < 120\n ? [x, c, 0]\n : h < 180\n ? [0, c, x]\n : h < 240\n ? [0, x, c]\n : h < 300\n ? [x, 0, c]\n : [c, 0, x];\n return { r: (r + m) * 255, g: (g + m) * 255, b: (b + m) * 255 };\n}\n\n/** Adapter `composite` for an opaque-over-opaque mix, via its `mix`: channels rounded to 8-bit. */\nfunction mix(fg: Rgb, ratio: number, bg: Rgb): Rgb {\n return {\n r: Math.round(fg.r * ratio + bg.r * (1 - ratio)),\n g: Math.round(fg.g * ratio + bg.g * (1 - ratio)),\n b: Math.round(fg.b * ratio + bg.b * (1 - ratio)),\n };\n}\n\n/** Adapter `toTriplet`: `\"H S% L%\"`, integer-rounded. */\nfunction toTriplet({ r, g, b }: Rgb): string {\n const rn = r / 255;\n const gn = g / 255;\n const bn = b / 255;\n const max = Math.max(rn, gn, bn);\n const min = Math.min(rn, gn, bn);\n const l = (max + min) / 2;\n const delta = max - min;\n\n let h = 0;\n let s = 0;\n if (delta !== 0) {\n s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min);\n if (max === rn) {\n h = (gn - bn) / delta + (gn < bn ? 6 : 0);\n } else if (max === gn) {\n h = (bn - rn) / delta + 2;\n } else {\n h = (rn - gn) / delta + 4;\n }\n h *= 60;\n }\n return `${Math.round(h)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`;\n}\n\n/** Tokens the adapter reads off the theme rather than computing from the anchors. */\nconst INHERITED_TOKENS = [\n '--primary',\n '--primary-foreground',\n '--secondary-foreground',\n '--accent-foreground',\n '--ring',\n '--border',\n '--input',\n '--heading',\n] as const;\n\n/**\n * A full colour-token map for a palette whose anchors the owner just edited.\n *\n * `anchors` win; everything the adapter derives from them is recomputed when\n * one of its inputs changed (and kept from `base` when none did — see \"Rounding\"\n * in the module header); everything it reads directly is taken from `base`.\n * Invalid triplets in either input are ignored, and a derived token whose\n * inputs are unavailable keeps `base`'s value, if any.\n *\n * Returns the whole scheme map, not only its colours: every non-colour entry of\n * `base` that passes `isSchemeTokenEntry` — `--radius`, a font stack, a token\n * this module does not know — is copied as is, so customizing a palette keeps\n * everything it states beyond colour. Every output entry passes\n * `isSchemeTokenEntry`.\n */\nexport function completeScheme(\n base: Record<string, string>,\n anchors: Partial<Record<SchemeAnchorToken, string>>,\n): Record<string, string> {\n // Both checks: `isHslTriplet` is what the arithmetic can convert, and the\n // scheme grammar is what a write accepts — failing either would poison a\n // derivation or get the whole save refused.\n const valid = (value: unknown): string | undefined =>\n typeof value === 'string' &&\n isHslTriplet(value) &&\n isSchemeColorValue(value.trim())\n ? value.trim()\n : undefined;\n const fromBase = (token: string): string | undefined => valid(base[token]);\n const fromAnchor = (token: SchemeAnchorToken): string | undefined =>\n valid(anchors[token]);\n\n const out: Record<string, string> = {};\n const put = (token: string, value: string | undefined): void => {\n if (value !== undefined) {\n out[token] = value;\n }\n };\n\n const background = fromAnchor('--background') ?? fromBase('--background');\n const foreground = fromAnchor('--foreground') ?? fromBase('--foreground');\n const bgChanged = background !== fromBase('--background');\n const fgChanged = foreground !== fromBase('--foreground');\n const bg = background === undefined ? null : tripletToRgb(background);\n const fg = foreground === undefined ? null : tripletToRgb(foreground);\n\n /** base's value while the inputs are unchanged, else the recomputation (else base's). */\n const derive = (\n token: string,\n inputsChanged: boolean,\n compute: () => string | undefined,\n ): string | undefined => {\n const kept = fromBase(token);\n return !inputsChanged && kept !== undefined ? kept : compute() ?? kept;\n };\n const mixOver = (over: Rgb | null, ratio: number) => (): string | undefined =>\n over !== null && bg !== null ? toTriplet(mix(over, ratio, bg)) : undefined;\n\n put('--background', background);\n put('--foreground', foreground);\n put(\n '--card',\n fromAnchor('--card') ??\n derive('--card', bgChanged || fgChanged, mixOver(fg, 0.04)),\n );\n put(\n '--card-foreground',\n fromAnchor('--card-foreground') ??\n derive('--card-foreground', fgChanged, () => foreground),\n );\n put('--popover', derive('--popover', bgChanged, () => background));\n put(\n '--popover-foreground',\n derive('--popover-foreground', fgChanged, () => foreground),\n );\n put('--muted', derive('--muted', bgChanged || fgChanged, mixOver(fg, 0.04)));\n put(\n '--muted-foreground',\n derive('--muted-foreground', bgChanged || fgChanged, mixOver(fg, 0.6)),\n );\n\n for (const token of INHERITED_TOKENS) {\n put(token, fromBase(token));\n }\n // Primary is inherited, so of the button family's inputs only the page can change.\n const primaryTriplet = out['--primary'];\n const primary =\n primaryTriplet === undefined ? null : tripletToRgb(primaryTriplet);\n put('--ring', out['--ring'] ?? primaryTriplet);\n put('--accent-foreground', out['--accent-foreground'] ?? primaryTriplet);\n put('--secondary', derive('--secondary', bgChanged, mixOver(primary, 0.1)));\n put('--accent', derive('--accent', bgChanged, mixOver(primary, 0.1)));\n\n // Not colours, so no arithmetic touches them: the palette keeps its shape,\n // its type, and any token a writer added that this module has never heard of.\n for (const [token, value] of Object.entries(base)) {\n if (!SCHEME_COLOR_TOKENS.has(token) && isSchemeTokenEntry(token, value)) {\n out[token] = value;\n }\n }\n\n return out;\n}\n\n/** The label the panel shows: the trimmed name, else `Palette N` (1-based). */\nexport function schemeDisplayName(scheme: ThemeScheme, index: number): string {\n const name = typeof scheme.name === 'string' ? scheme.name.trim() : '';\n return name !== '' ? name : `Palette ${index + 1}`;\n}\n\n/** `owner-N` with the smallest N ≥ 1 not already taken. */\nexport function nextOwnerSchemeId(schemes: readonly { id: string }[]): string {\n const taken = new Set(schemes.map((scheme) => scheme.id));\n let n = 1;\n while (taken.has(`owner-${n}`)) {\n n += 1;\n }\n return `owner-${n}`;\n}\n\n/** A colour value a scheme may hold: `SCHEME_COLOR_VALUE`, with S and L ≤ 100. */\nfunction isSchemeColorValue(value: string): boolean {\n const parts = SCHEME_COLOR_VALUE.exec(value);\n return parts !== null && Number(parts[2]) <= 100 && Number(parts[3]) <= 100;\n}\n\n/**\n * Whether a key/value pair may be written as a scheme token — the CLIENT's\n * contract, checked before the panel writes and by `completeScheme`.\n *\n * There is no allow-list: any key of the `themeOverrides` shape\n * (`THEME_OVERRIDE_KEY_PATTERN`) is a candidate. The value grammar follows the\n * key's contract type: `color-hsl` → an HSL triplet with S and L ≤ 100;\n * `length` → a px/rem/em length with its unit; anything else (font stacks,\n * keys the contract does not know) → the loose `themeOverrides` value shape.\n *\n * The server enforces only that loose shape for every key, so a `0 101% 50%`\n * colour or a unitless radius would be ACCEPTED there — and render wrong. That\n * is why the panel refuses them here. The renderer does not re-check values.\n */\nexport function isSchemeTokenEntry(key: string, value: unknown): boolean {\n if (typeof value !== 'string' || !THEME_OVERRIDE_KEY_PATTERN.test(key)) {\n return false;\n }\n switch (THEME_TOKEN_CONTRACT[key]?.type) {\n case 'color-hsl':\n return isSchemeColorValue(value);\n case 'length':\n return SCHEME_RADIUS_VALUE.test(value);\n default:\n return (\n value.length <= MAX_SCHEME_VALUE_LENGTH &&\n SCHEME_LOOSE_VALUE.test(value)\n );\n }\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,YAAY,QAAQ,eAAe;AAC5C,SACEC,0BAA0B,EAC1BC,oBAAoB,QACf,iBAAiB;;AAExB;;AAGA;;AAeA;AACA,OAAO,MAAMC,mBAAwC,GAAGC,MAAM,CAACC,MAAM,CACnE,IAAIC,GAAG,CACLF,MAAM,CAACG,OAAO,CAACL,oBAAoB,CAAC,CACjCM,MAAM,CAACC,IAAA;EAAA,IAAC,GAAGC,KAAK,CAAC,GAAAD,IAAA;EAAA,OAAKC,KAAK,CAACC,IAAI,KAAK,WAAW;AAAA,EAAC,CACjDC,GAAG,CAACC,KAAA;EAAA,IAAC,CAACC,KAAK,CAAC,GAAAD,KAAA;EAAA,OAAKC,KAAK;AAAA,EAC3B,CACF,CAAwB;;AAExB;AACA;AACA;AACA;AACA;AACA,MAAMC,kBAAkB,GACtB,iEAAiE;;AAEnE;AACA;AACA;AACA;AACA;AACA,MAAMC,mBAAmB,GAAG,kCAAkC;;AAE9D;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,kBAAkB,GAAG,kBAAkB;AAC7C,MAAMC,uBAAuB,GAAG,GAAG;;AAEnC;AACA,OAAO,MAAMC,oBAAoB,GAAG,CAClC,cAAc,EACd,cAAc,EACd,QAAQ,EACR,mBAAmB,CACX;AAIV;AACA,OAAO,MAAMC,iBAAiB,GAAG,EAAE;AAEnC,MAAMC,iBAAiB,GAAG,2BAA2B;AACrD,MAAMC,sBAAsB,GAAG,EAAE;AAEjC,MAAMC,aAAa,GAAIC,KAAc,IACnC,OAAOA,KAAK,KAAK,QAAQ,IAAIA,KAAK,KAAK,IAAI,IAAI,CAACC,KAAK,CAACC,OAAO,CAACF,KAAK,CAAC;;AAEtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASG,aAAaA,CAACH,KAAc,EAAwB;EAClE,IAAI,CAACD,aAAa,CAACC,KAAK,CAAC,EAAE;IACzB,OAAO,KAAK;EACd;EACA,MAAM;IAAEI,EAAE;IAAEC,IAAI;IAAEC,MAAM;IAAEC;EAAO,CAAC,GAAGP,KAAK;EAC1C,IAAI,OAAOI,EAAE,KAAK,QAAQ,IAAI,CAACP,iBAAiB,CAACW,IAAI,CAACJ,EAAE,CAAC,EAAE;IACzD,OAAO,KAAK;EACd;EACA,IACEC,IAAI,KAAKI,SAAS,KACjB,OAAOJ,IAAI,KAAK,QAAQ,IAAIA,IAAI,CAACK,MAAM,GAAGZ,sBAAsB,CAAC,EAClE;IACA,OAAO,KAAK;EACd;EACA,IAAIQ,MAAM,KAAKG,SAAS,IAAI,OAAOH,MAAM,KAAK,QAAQ,EAAE;IACtD,OAAO,KAAK;EACd;EACA,OACEP,aAAa,CAACQ,MAAM,CAAC,IACrB3B,MAAM,CAAC+B,MAAM,CAACJ,MAAM,CAAC,CAACK,KAAK,CAAEC,CAAC,IAAK,OAAOA,CAAC,KAAK,QAAQ,CAAC;AAE7D;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CACjCC,GAGa,EACO;EACpB,IAAI,CAACA,GAAG,IAAI,CAACd,KAAK,CAACC,OAAO,CAACa,GAAG,CAACC,YAAY,CAAC,EAAE;IAC5C,OAAO,IAAI;EACb;EACA,MAAMC,OAAO,GAAGF,GAAG,CAACC,YAAY,CAAChC,MAAM,CAACmB,aAAa,CAAC;EACtD,IAAIc,OAAO,CAACP,MAAM,KAAK,CAAC,EAAE;IACxB,OAAO,IAAI;EACb;EACA,MAAMQ,QAAQ,GAAGH,GAAG,CAACI,mBAAmB;EACxC,MAAMC,MAAM,GACV,OAAOF,QAAQ,KAAK,QAAQ,GACxBD,OAAO,CAACI,IAAI,CAAEC,MAAM,IAAKA,MAAM,CAAClB,EAAE,KAAKc,QAAQ,CAAC,GAChDT,SAAS;EACf,OAAOW,MAAM,IAAIH,OAAO,CAAC,CAAC,CAAC;AAC7B;;AAEA;;AAQA,MAAMM,OAAO,GAAG,qEAAqE;;AAErF;AACA;AACA;AACA;AACA,SAASC,YAAYA,CAACC,OAAe,EAAc;EACjD,MAAMC,KAAK,GAAGH,OAAO,CAACI,IAAI,CAACF,OAAO,CAACG,IAAI,CAAC,CAAC,CAAC;EAC1C,IAAI,CAACF,KAAK,IAAI,CAAClD,YAAY,CAACiD,OAAO,CAAC,EAAE;IACpC,OAAO,IAAI;EACb;EACA,MAAMI,CAAC,GAAGC,MAAM,CAACJ,KAAK,CAAC,CAAC,CAAC,CAAC;EAC1B,MAAMK,CAAC,GAAGD,MAAM,CAACJ,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;EAChC,MAAMM,CAAC,GAAGF,MAAM,CAACJ,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;EAEhC,MAAMO,CAAC,GAAG,CAAC,CAAC,GAAGC,IAAI,CAACC,GAAG,CAAC,CAAC,GAAGH,CAAC,GAAG,CAAC,CAAC,IAAID,CAAC;EACvC,MAAMK,CAAC,GAAGH,CAAC,IAAI,CAAC,GAAGC,IAAI,CAACC,GAAG,CAAGN,CAAC,GAAG,EAAE,GAAI,CAAC,GAAI,CAAC,CAAC,CAAC;EAChD,MAAMQ,CAAC,GAAGL,CAAC,GAAGC,CAAC,GAAG,CAAC;EACnB,MAAM,CAACK,CAAC,EAAEC,CAAC,EAAEC,CAAC,CAAC,GACbX,CAAC,GAAG,EAAE,GACF,CAACI,CAAC,EAAEG,CAAC,EAAE,CAAC,CAAC,GACTP,CAAC,GAAG,GAAG,GACP,CAACO,CAAC,EAAEH,CAAC,EAAE,CAAC,CAAC,GACTJ,CAAC,GAAG,GAAG,GACP,CAAC,CAAC,EAAEI,CAAC,EAAEG,CAAC,CAAC,GACTP,CAAC,GAAG,GAAG,GACP,CAAC,CAAC,EAAEO,CAAC,EAAEH,CAAC,CAAC,GACTJ,CAAC,GAAG,GAAG,GACP,CAACO,CAAC,EAAE,CAAC,EAAEH,CAAC,CAAC,GACT,CAACA,CAAC,EAAE,CAAC,EAAEG,CAAC,CAAC;EACf,OAAO;IAAEE,CAAC,EAAE,CAACA,CAAC,GAAGD,CAAC,IAAI,GAAG;IAAEE,CAAC,EAAE,CAACA,CAAC,GAAGF,CAAC,IAAI,GAAG;IAAEG,CAAC,EAAE,CAACA,CAAC,GAAGH,CAAC,IAAI;EAAI,CAAC;AACjE;;AAEA;AACA,SAASI,GAAGA,CAACC,EAAO,EAAEC,KAAa,EAAEC,EAAO,EAAO;EACjD,OAAO;IACLN,CAAC,EAAEJ,IAAI,CAACW,KAAK,CAACH,EAAE,CAACJ,CAAC,GAAGK,KAAK,GAAGC,EAAE,CAACN,CAAC,IAAI,CAAC,GAAGK,KAAK,CAAC,CAAC;IAChDJ,CAAC,EAAEL,IAAI,CAACW,KAAK,CAACH,EAAE,CAACH,CAAC,GAAGI,KAAK,GAAGC,EAAE,CAACL,CAAC,IAAI,CAAC,GAAGI,KAAK,CAAC,CAAC;IAChDH,CAAC,EAAEN,IAAI,CAACW,KAAK,CAACH,EAAE,CAACF,CAAC,GAAGG,KAAK,GAAGC,EAAE,CAACJ,CAAC,IAAI,CAAC,GAAGG,KAAK,CAAC;EACjD,CAAC;AACH;;AAEA;AACA,SAASG,SAASA,CAAAC,KAAA,EAA2B;EAAA,IAA1B;IAAET,CAAC;IAAEC,CAAC;IAAEC;EAAO,CAAC,GAAAO,KAAA;EACjC,MAAMC,EAAE,GAAGV,CAAC,GAAG,GAAG;EAClB,MAAMW,EAAE,GAAGV,CAAC,GAAG,GAAG;EAClB,MAAMW,EAAE,GAAGV,CAAC,GAAG,GAAG;EAClB,MAAMW,GAAG,GAAGjB,IAAI,CAACiB,GAAG,CAACH,EAAE,EAAEC,EAAE,EAAEC,EAAE,CAAC;EAChC,MAAME,GAAG,GAAGlB,IAAI,CAACkB,GAAG,CAACJ,EAAE,EAAEC,EAAE,EAAEC,EAAE,CAAC;EAChC,MAAMlB,CAAC,GAAG,CAACmB,GAAG,GAAGC,GAAG,IAAI,CAAC;EACzB,MAAMC,KAAK,GAAGF,GAAG,GAAGC,GAAG;EAEvB,IAAIvB,CAAC,GAAG,CAAC;EACT,IAAIE,CAAC,GAAG,CAAC;EACT,IAAIsB,KAAK,KAAK,CAAC,EAAE;IACftB,CAAC,GAAGC,CAAC,GAAG,GAAG,GAAGqB,KAAK,IAAI,CAAC,GAAGF,GAAG,GAAGC,GAAG,CAAC,GAAGC,KAAK,IAAIF,GAAG,GAAGC,GAAG,CAAC;IAC3D,IAAID,GAAG,KAAKH,EAAE,EAAE;MACdnB,CAAC,GAAG,CAACoB,EAAE,GAAGC,EAAE,IAAIG,KAAK,IAAIJ,EAAE,GAAGC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC,MAAM,IAAIC,GAAG,KAAKF,EAAE,EAAE;MACrBpB,CAAC,GAAG,CAACqB,EAAE,GAAGF,EAAE,IAAIK,KAAK,GAAG,CAAC;IAC3B,CAAC,MAAM;MACLxB,CAAC,GAAG,CAACmB,EAAE,GAAGC,EAAE,IAAII,KAAK,GAAG,CAAC;IAC3B;IACAxB,CAAC,IAAI,EAAE;EACT;EACA,OAAO,GAAGK,IAAI,CAACW,KAAK,CAAChB,CAAC,CAAC,IAAIK,IAAI,CAACW,KAAK,CAACd,CAAC,GAAG,GAAG,CAAC,KAAKG,IAAI,CAACW,KAAK,CAACb,CAAC,GAAG,GAAG,CAAC,GAAG;AAC3E;;AAEA;AACA,MAAMsB,gBAAgB,GAAG,CACvB,WAAW,EACX,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,QAAQ,EACR,UAAU,EACV,SAAS,EACT,WAAW,CACH;;AAEV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,cAAcA,CAC5BC,IAA4B,EAC5BC,OAAmD,EAC3B;EACxB;EACA;EACA;EACA,MAAMC,KAAK,GAAI1D,KAAc,IAC3B,OAAOA,KAAK,KAAK,QAAQ,IACzBxB,YAAY,CAACwB,KAAK,CAAC,IACnB2D,kBAAkB,CAAC3D,KAAK,CAAC4B,IAAI,CAAC,CAAC,CAAC,GAC5B5B,KAAK,CAAC4B,IAAI,CAAC,CAAC,GACZnB,SAAS;EACf,MAAMmD,QAAQ,GAAItE,KAAa,IAAyBoE,KAAK,CAACF,IAAI,CAAClE,KAAK,CAAC,CAAC;EAC1E,MAAMuE,UAAU,GAAIvE,KAAwB,IAC1CoE,KAAK,CAACD,OAAO,CAACnE,KAAK,CAAC,CAAC;EAEvB,MAAMwE,GAA2B,GAAG,CAAC,CAAC;EACtC,MAAMC,GAAG,GAAGA,CAACzE,KAAa,EAAEU,KAAyB,KAAW;IAC9D,IAAIA,KAAK,KAAKS,SAAS,EAAE;MACvBqD,GAAG,CAACxE,KAAK,CAAC,GAAGU,KAAK;IACpB;EACF,CAAC;EAED,MAAMgE,UAAU,GAAGH,UAAU,CAAC,cAAc,CAAC,IAAID,QAAQ,CAAC,cAAc,CAAC;EACzE,MAAMK,UAAU,GAAGJ,UAAU,CAAC,cAAc,CAAC,IAAID,QAAQ,CAAC,cAAc,CAAC;EACzE,MAAMM,SAAS,GAAGF,UAAU,KAAKJ,QAAQ,CAAC,cAAc,CAAC;EACzD,MAAMO,SAAS,GAAGF,UAAU,KAAKL,QAAQ,CAAC,cAAc,CAAC;EACzD,MAAMhB,EAAE,GAAGoB,UAAU,KAAKvD,SAAS,GAAG,IAAI,GAAGe,YAAY,CAACwC,UAAU,CAAC;EACrE,MAAMtB,EAAE,GAAGuB,UAAU,KAAKxD,SAAS,GAAG,IAAI,GAAGe,YAAY,CAACyC,UAAU,CAAC;;EAErE;EACA,MAAMG,MAAM,GAAGA,CACb9E,KAAa,EACb+E,aAAsB,EACtBC,OAAiC,KACV;IACvB,MAAMC,IAAI,GAAGX,QAAQ,CAACtE,KAAK,CAAC;IAC5B,OAAO,CAAC+E,aAAa,IAAIE,IAAI,KAAK9D,SAAS,GAAG8D,IAAI,GAAGD,OAAO,CAAC,CAAC,IAAIC,IAAI;EACxE,CAAC;EACD,MAAMC,OAAO,GAAGA,CAACC,IAAgB,EAAE9B,KAAa,KAAK,MACnD8B,IAAI,KAAK,IAAI,IAAI7B,EAAE,KAAK,IAAI,GAAGE,SAAS,CAACL,GAAG,CAACgC,IAAI,EAAE9B,KAAK,EAAEC,EAAE,CAAC,CAAC,GAAGnC,SAAS;EAE5EsD,GAAG,CAAC,cAAc,EAAEC,UAAU,CAAC;EAC/BD,GAAG,CAAC,cAAc,EAAEE,UAAU,CAAC;EAC/BF,GAAG,CACD,QAAQ,EACRF,UAAU,CAAC,QAAQ,CAAC,IAClBO,MAAM,CAAC,QAAQ,EAAEF,SAAS,IAAIC,SAAS,EAAEK,OAAO,CAAC9B,EAAE,EAAE,IAAI,CAAC,CAC9D,CAAC;EACDqB,GAAG,CACD,mBAAmB,EACnBF,UAAU,CAAC,mBAAmB,CAAC,IAC7BO,MAAM,CAAC,mBAAmB,EAAED,SAAS,EAAE,MAAMF,UAAU,CAC3D,CAAC;EACDF,GAAG,CAAC,WAAW,EAAEK,MAAM,CAAC,WAAW,EAAEF,SAAS,EAAE,MAAMF,UAAU,CAAC,CAAC;EAClED,GAAG,CACD,sBAAsB,EACtBK,MAAM,CAAC,sBAAsB,EAAED,SAAS,EAAE,MAAMF,UAAU,CAC5D,CAAC;EACDF,GAAG,CAAC,SAAS,EAAEK,MAAM,CAAC,SAAS,EAAEF,SAAS,IAAIC,SAAS,EAAEK,OAAO,CAAC9B,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;EAC5EqB,GAAG,CACD,oBAAoB,EACpBK,MAAM,CAAC,oBAAoB,EAAEF,SAAS,IAAIC,SAAS,EAAEK,OAAO,CAAC9B,EAAE,EAAE,GAAG,CAAC,CACvE,CAAC;EAED,KAAK,MAAMpD,KAAK,IAAIgE,gBAAgB,EAAE;IACpCS,GAAG,CAACzE,KAAK,EAAEsE,QAAQ,CAACtE,KAAK,CAAC,CAAC;EAC7B;EACA;EACA,MAAMoF,cAAc,GAAGZ,GAAG,CAAC,WAAW,CAAC;EACvC,MAAMa,OAAO,GACXD,cAAc,KAAKjE,SAAS,GAAG,IAAI,GAAGe,YAAY,CAACkD,cAAc,CAAC;EACpEX,GAAG,CAAC,QAAQ,EAAED,GAAG,CAAC,QAAQ,CAAC,IAAIY,cAAc,CAAC;EAC9CX,GAAG,CAAC,qBAAqB,EAAED,GAAG,CAAC,qBAAqB,CAAC,IAAIY,cAAc,CAAC;EACxEX,GAAG,CAAC,aAAa,EAAEK,MAAM,CAAC,aAAa,EAAEF,SAAS,EAAEM,OAAO,CAACG,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;EAC3EZ,GAAG,CAAC,UAAU,EAAEK,MAAM,CAAC,UAAU,EAAEF,SAAS,EAAEM,OAAO,CAACG,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;;EAErE;EACA;EACA,KAAK,MAAM,CAACrF,KAAK,EAAEU,KAAK,CAAC,IAAIpB,MAAM,CAACG,OAAO,CAACyE,IAAI,CAAC,EAAE;IACjD,IAAI,CAAC7E,mBAAmB,CAACiG,GAAG,CAACtF,KAAK,CAAC,IAAIuF,kBAAkB,CAACvF,KAAK,EAAEU,KAAK,CAAC,EAAE;MACvE8D,GAAG,CAACxE,KAAK,CAAC,GAAGU,KAAK;IACpB;EACF;EAEA,OAAO8D,GAAG;AACZ;;AAEA;AACA,OAAO,SAASgB,iBAAiBA,CAACxD,MAAmB,EAAEyD,KAAa,EAAU;EAC5E,MAAM1E,IAAI,GAAG,OAAOiB,MAAM,CAACjB,IAAI,KAAK,QAAQ,GAAGiB,MAAM,CAACjB,IAAI,CAACuB,IAAI,CAAC,CAAC,GAAG,EAAE;EACtE,OAAOvB,IAAI,KAAK,EAAE,GAAGA,IAAI,GAAG,WAAW0E,KAAK,GAAG,CAAC,EAAE;AACpD;;AAEA;AACA,OAAO,SAASC,iBAAiBA,CAAC/D,OAAkC,EAAU;EAC5E,MAAMgE,KAAK,GAAG,IAAInG,GAAG,CAACmC,OAAO,CAAC7B,GAAG,CAAEkC,MAAM,IAAKA,MAAM,CAAClB,EAAE,CAAC,CAAC;EACzD,IAAI8E,CAAC,GAAG,CAAC;EACT,OAAOD,KAAK,CAACL,GAAG,CAAC,SAASM,CAAC,EAAE,CAAC,EAAE;IAC9BA,CAAC,IAAI,CAAC;EACR;EACA,OAAO,SAASA,CAAC,EAAE;AACrB;;AAEA;AACA,SAASvB,kBAAkBA,CAAC3D,KAAa,EAAW;EAClD,MAAM0B,KAAK,GAAGnC,kBAAkB,CAACoC,IAAI,CAAC3B,KAAK,CAAC;EAC5C,OAAO0B,KAAK,KAAK,IAAI,IAAII,MAAM,CAACJ,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAII,MAAM,CAACJ,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG;AAC7E;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASmD,kBAAkBA,CAACM,GAAW,EAAEnF,KAAc,EAAW;EAAA,IAAAoF,qBAAA;EACvE,IAAI,OAAOpF,KAAK,KAAK,QAAQ,IAAI,CAACvB,0BAA0B,CAAC+B,IAAI,CAAC2E,GAAG,CAAC,EAAE;IACtE,OAAO,KAAK;EACd;EACA,SAAAC,qBAAA,GAAQ1G,oBAAoB,CAACyG,GAAG,CAAC,qBAAzBC,qBAAA,CAA2BjG,IAAI;IACrC,KAAK,WAAW;MACd,OAAOwE,kBAAkB,CAAC3D,KAAK,CAAC;IAClC,KAAK,QAAQ;MACX,OAAOR,mBAAmB,CAACgB,IAAI,CAACR,KAAK,CAAC;IACxC;MACE,OACEA,KAAK,CAACU,MAAM,IAAIhB,uBAAuB,IACvCD,kBAAkB,CAACe,IAAI,CAACR,KAAK,CAAC;EAEpC;AACF","ignoreList":[]}
1
+ {"version":3,"names":["isHslTriplet","THEME_OVERRIDE_KEY_PATTERN","THEME_TOKEN_CONTRACT","SCHEME_COLOR_TOKENS","Object","freeze","Set","entries","filter","_ref","entry","type","map","_ref2","token","SCHEME_COLOR_VALUE","SCHEME_RADIUS_VALUE","SCHEME_LOOSE_VALUE","MAX_SCHEME_VALUE_LENGTH","SCHEME_TOKENS","SCHEME_TOKEN_SET","schemeTokensOf","fromEntries","_ref3","has","SCHEME_ANCHOR_TOKENS","MAX_THEME_SCHEMES","SCHEME_ID_PATTERN","MAX_SCHEME_NAME_LENGTH","isPlainObject","value","Array","isArray","isThemeScheme","id","name","origin","baseSchemeId","tokens","test","undefined","length","values","every","v","resolveActiveScheme","cfg","themeSchemes","schemes","activeId","activeThemeSchemeId","active","find","scheme","TRIPLET","tripletToRgb","triplet","parts","exec","trim","h","Number","s","l","c","Math","abs","x","m","r","g","b","mix","fg","ratio","bg","round","toTriplet","_ref4","rn","gn","bn","max","min","delta","completeScheme","base","anchors","context","valid","isSchemeColorValue","fromBase","fromAnchor","out","put","background","foreground","bgChanged","fgChanged","derive","inputsChanged","compute","kept","mixOver","over","basePrimary","primaryTriplet","primary","primaryChanged","tintChanged","schemeDisplayName","index","nextOwnerSchemeId","taken","n","isSchemeTokenEntry","key","_THEME_TOKEN_CONTRACT"],"sources":["../../../src/theme/themeScheme.ts"],"sourcesContent":["/**\n * Named theme schemes on a site configuration, and the one that is active.\n *\n * A store's theme states a SET of palettes rather than one — Dawn and Horizon\n * ship `scheme-1`..`scheme-5` for the page, the cards, the hero band, the\n * footer. The configuration therefore carries a list of schemes plus the id of\n * the active one, beside the flat `themeOverrides` map it has always had:\n *\n * themeSchemes?: [{ id, name?, origin?, tokens: { '--background': '0 0% 100%', … } }]\n * activeThemeSchemeId?: 'scheme-1'\n *\n * A scheme's `tokens` are finished CSS tokens, spelled exactly as\n * `themeOverrides` spells them — and, like `themeOverrides`, the key set is\n * OPEN. Today's writers put the 18 colour roles (`SCHEME_COLOR_TOKENS`) there,\n * sometimes `--radius`; that a palette may carry shape as well as colour is why\n * this is a THEME scheme and not a colour scheme. A new token (a font stack,\n * something the contract has not catalogued yet) needs no release anywhere but\n * its writer. The server checks only the loose shape `themeOverrides` gets (key\n * `THEME_OVERRIDE_KEY_PATTERN`, a value free of `;`, `{`, `}` and control\n * characters, ≤ 256, at most 24 entries); the typed per-token grammar is the\n * CLIENT's contract, enforced by `isSchemeTokenEntry` before the panel writes.\n * Nothing is expanded at apply time: the reader resolves the active entry and\n * hands its map to `applyThemeOverrides`, which layers it between the store map\n * and the owner's overrides, filtered and bucketed exactly like the store map.\n * A configuration with no schemes renders exactly as it did before they existed.\n *\n * A leaf module beside `tokenContract.ts`, and for the same reason that file\n * documents: requiring core's ENTRY from plain Node fails on its CSS import,\n * but a deep import of a zero-CSS leaf works. It imports only its siblings\n * `./tokenContract` and `./colorFormat`, both leaves themselves.\n *\n * ## What a scheme carries (ADR 0243)\n *\n * A theme scheme is a background and its text, plus the colours mechanically\n * derived from those two: `SCHEME_TOKENS`. Card colours, button colours,\n * radius and fonts are the store's global set (`themeOverrides`) and the\n * owner's global edits (`userThemeOverrides`), applied under and over the\n * scheme respectively — so they survive every scheme switch. Rows written\n * before 0243 may still carry more; readers apply whatever a row holds, and\n * the owner panel writes only `SCHEME_TOKENS` into the rows it creates.\n *\n * An edited THEME scheme is an OWNER row that names it in `baseSchemeId`, so\n * the panel can show the edit on that scheme's tile and revert only that one.\n *\n * ## `completeScheme` — what the owner panel recomputes\n *\n * The owner edits the two anchors. The rest of the scheme has to move with\n * them the way `web50-shopify-adapter/src/theme-tokens.ts` would have moved it\n * had the theme stated those anchors, so the arithmetic below is a COPY of the\n * adapter's (`composite`/`mix`/`toTriplet` and the token assignments at the end\n * of `extractThemeOverrides`), integer rounding included. It is copied rather\n * than shared on purpose: the adapter must not import core.\n *\n * | token | role |\n * | ------------------------ | ------------------------------------------------------ |\n * | `--background` | anchor (else inherited from base) |\n * | `--foreground` | anchor (else inherited from base) |\n * | `--popover` | derived: = background |\n * | `--popover-foreground` | derived: = foreground |\n * | `--muted` | derived: foreground 4% over background |\n * | `--muted-foreground` | derived: foreground 60% over background |\n * | `--secondary` | derived: primary 10% over background |\n * | `--accent` | derived: primary 10% over background |\n * | `--border` | inherited from base (no fallback — see below) |\n * | `--input` | inherited from base (no fallback — see below) |\n *\n * Primary is not a scheme token — it is the store's button colour — so the\n * caller passes it as `context.primary`; without one, base's own `--primary`\n * (a pre-0243 row) is used. `--border`/`--input` are read straight off the\n * theme by the adapter, which reconstructs a missing border from the theme's\n * `*_border_opacity` setting a token map does not carry — so they are\n * inherited from base, and omitted when base lacks them, as the adapter omits\n * them.\n *\n * ## Rounding: why an unchanged input keeps base's value\n *\n * The adapter mixes 8-bit channels parsed from the theme's hex; a scheme only\n * has the integer-rounded triplet, and the hex cannot be recovered from it.\n * Re-deriving from triplets therefore lands a point off now and then — Horizon\n * `color_palette`'s `--muted-foreground` comes back `359 83% 68%` against the\n * adapter's `359 84% 68%`. So a derived token is recomputed only when one of\n * its INPUTS differs from base; otherwise base's value stands. A merchant who\n * edits nothing gets the adapter's map back exactly, and one who edits the\n * background gets the family recomputed.\n *\n * When it is recomputed, triplets convert back to RGB WITHOUT rounding to\n * 8-bit first — that would be a second quantisation the adapter never\n * performs, and enough to move smallflower's `--secondary` from `230 38% 94%`\n * to `230 42% 94%`. The mix result is rounded exactly where the adapter\n * rounds it.\n */\nimport { isHslTriplet } from './colorFormat';\nimport {\n THEME_OVERRIDE_KEY_PATTERN,\n THEME_TOKEN_CONTRACT,\n} from './tokenContract';\n\n/** Where a scheme came from. Any other value on the wire reads as unknown. */\nexport type SchemeOrigin = 'UNKNOWN_SCHEME_ORIGIN' | 'THEME' | 'OWNER';\n\n/** One named palette as the configuration carries it. */\nexport interface ThemeScheme {\n /** `^[a-z0-9][a-z0-9-]{0,31}$`, unique within the list. */\n id: string;\n /** Shown in the owner panel; at most 48 characters. */\n name?: string;\n origin?: SchemeOrigin | string;\n /**\n * On an OWNER row: the id of the THEME scheme it is an edit of. Not the\n * row's own id, unique across rows (at most one edit per scheme), and it may\n * dangle — a theme publish can remove the base, and the edit survives it.\n */\n baseSchemeId?: string;\n /**\n * Token → value, keys as open as `themeOverrides`': colours as bare HSL\n * triplets (`0 0% 100%`), `--radius` as a length (`0.5rem`), anything else\n * in the loose value shape. See `isSchemeTokenEntry`.\n */\n tokens: Record<string, string>;\n}\n\n/** Every colour role in the contract (`type: 'color-hsl'`, `--heading` included). */\nexport const SCHEME_COLOR_TOKENS: ReadonlySet<string> = Object.freeze(\n new Set(\n Object.entries(THEME_TOKEN_CONTRACT)\n .filter(([, entry]) => entry.type === 'color-hsl')\n .map(([token]) => token),\n ),\n) as ReadonlySet<string>;\n\n/**\n * A scheme colour (`type: 'color-hsl'`): `H S% L%`, single-spaced, no `hsl()`\n * wrapper. Saturation and lightness are additionally capped at 100\n * (`isSchemeColorValue`); hue is bounded only by its three digits.\n */\nconst SCHEME_COLOR_VALUE =\n /^(\\d{1,3}(?:\\.\\d+)?) (\\d{1,3}(?:\\.\\d+)?)% (\\d{1,3}(?:\\.\\d+)?)%$/;\n\n/**\n * A scheme length (`type: 'length'`, i.e. `--radius`): px/rem/em, unit REQUIRED\n * (`0px`, not `0`). A bare `0` would turn `calc(var(--radius) - 4px)` into\n * invalid CSS — see the `length` note in `tokenContract.ts`.\n */\nconst SCHEME_RADIUS_VALUE = /^\\d{1,4}(?:\\.\\d+)?(?:px|rem|em)$/;\n\n/**\n * Any other scheme value — a font stack, a key the contract has not catalogued:\n * no `;`, `{`, `}` or control character. The server's `themeOverrides` value\n * shape (`^[^;{}\\p{Cntrl}]{1,256}$`); the length is checked separately in\n * UTF-16 units, as the server counts, since a `u`-flag quantifier counts code\n * points.\n */\nconst SCHEME_LOOSE_VALUE = /^[^;{}\\p{Cc}]+$/u;\nconst MAX_SCHEME_VALUE_LENGTH = 256;\n\n/**\n * What a scheme is (ADR 0243): its background and text, and the colours\n * derived from those two. The panel writes exactly these into the OWNER rows\n * it creates, and mirrors exactly these of the active row into `themeOverrides`.\n */\nexport const SCHEME_TOKENS = [\n '--background',\n '--foreground',\n '--popover',\n '--popover-foreground',\n '--muted',\n '--muted-foreground',\n '--border',\n '--input',\n '--secondary',\n '--accent',\n] as const;\n\nexport type SchemeToken = (typeof SCHEME_TOKENS)[number];\n\nconst SCHEME_TOKEN_SET: ReadonlySet<string> = new Set(SCHEME_TOKENS);\n\n/** Only the `SCHEME_TOKENS` entries of `map`. */\nexport function schemeTokensOf(\n map: Record<string, string> | null | undefined,\n): Record<string, string> {\n return Object.fromEntries(\n Object.entries(map ?? {}).filter(([token]) => SCHEME_TOKEN_SET.has(token)),\n );\n}\n\n/** The two the owner edits on a scheme, in panel order. */\nexport const SCHEME_ANCHOR_TOKENS = ['--background', '--foreground'] as const;\n\nexport type SchemeAnchorToken = (typeof SCHEME_ANCHOR_TOKENS)[number];\n\n/** Upper bound on schemes per configuration. */\nexport const MAX_THEME_SCHEMES = 16;\n\nconst SCHEME_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,31}$/;\nconst MAX_SCHEME_NAME_LENGTH = 48;\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * Whether an untrusted value has a scheme's SHAPE.\n *\n * Token content is deliberately not judged here: `applyThemeOverrides` drops a\n * malformed key one entry at a time, exactly as it does for the flat store map\n * (and says so), so one bad token costs that token rather than the whole\n * palette. The typed value grammar is `isSchemeTokenEntry`, checked by writers.\n */\nexport function isThemeScheme(value: unknown): value is ThemeScheme {\n if (!isPlainObject(value)) {\n return false;\n }\n const { id, name, origin, baseSchemeId, tokens } = value;\n if (typeof id !== 'string' || !SCHEME_ID_PATTERN.test(id)) {\n return false;\n }\n if (baseSchemeId !== undefined && typeof baseSchemeId !== 'string') {\n return false;\n }\n if (\n name !== undefined &&\n (typeof name !== 'string' || name.length > MAX_SCHEME_NAME_LENGTH)\n ) {\n return false;\n }\n if (origin !== undefined && typeof origin !== 'string') {\n return false;\n }\n return (\n isPlainObject(tokens) &&\n Object.values(tokens).every((v) => typeof v === 'string')\n );\n}\n\n/**\n * The active scheme: the entry whose id is `activeThemeSchemeId`, else the\n * first entry, else null. Entries failing `isThemeScheme` are skipped first, so\n * a dangling id or a malformed entry falls through to the first usable one.\n */\nexport function resolveActiveScheme(\n cfg:\n | { themeSchemes?: unknown; activeThemeSchemeId?: string | null }\n | null\n | undefined,\n): ThemeScheme | null {\n if (!cfg || !Array.isArray(cfg.themeSchemes)) {\n return null;\n }\n const schemes = cfg.themeSchemes.filter(isThemeScheme);\n if (schemes.length === 0) {\n return null;\n }\n const activeId = cfg.activeThemeSchemeId;\n const active =\n typeof activeId === 'string'\n ? schemes.find((scheme) => scheme.id === activeId)\n : undefined;\n return active ?? schemes[0];\n}\n\n// ── Arithmetic copied from web50-shopify-adapter/src/theme-tokens.ts ────────\n\ninterface Rgb {\n r: number;\n g: number;\n b: number;\n}\n\nconst TRIPLET =\n /^(\\d{1,3}(?:\\.\\d+)?)\\s+(\\d{1,3}(?:\\.\\d+)?)%\\s+(\\d{1,3}(?:\\.\\d+)?)%$/;\n\n/**\n * A triplet as RGB in 0–255, NOT rounded to 8-bit — see the module header for\n * why. Same conversion as `colorFormat.hslTripletToHex`, minus its rounding.\n */\nfunction tripletToRgb(triplet: string): Rgb | null {\n const parts = TRIPLET.exec(triplet.trim());\n if (!parts || !isHslTriplet(triplet)) {\n return null;\n }\n const h = Number(parts[1]);\n const s = Number(parts[2]) / 100;\n const l = Number(parts[3]) / 100;\n\n const c = (1 - Math.abs(2 * l - 1)) * s;\n const x = c * (1 - Math.abs(((h / 60) % 2) - 1));\n const m = l - c / 2;\n const [r, g, b] =\n h < 60\n ? [c, x, 0]\n : h < 120\n ? [x, c, 0]\n : h < 180\n ? [0, c, x]\n : h < 240\n ? [0, x, c]\n : h < 300\n ? [x, 0, c]\n : [c, 0, x];\n return { r: (r + m) * 255, g: (g + m) * 255, b: (b + m) * 255 };\n}\n\n/** Adapter `composite` for an opaque-over-opaque mix, via its `mix`: channels rounded to 8-bit. */\nfunction mix(fg: Rgb, ratio: number, bg: Rgb): Rgb {\n return {\n r: Math.round(fg.r * ratio + bg.r * (1 - ratio)),\n g: Math.round(fg.g * ratio + bg.g * (1 - ratio)),\n b: Math.round(fg.b * ratio + bg.b * (1 - ratio)),\n };\n}\n\n/** Adapter `toTriplet`: `\"H S% L%\"`, integer-rounded. */\nfunction toTriplet({ r, g, b }: Rgb): string {\n const rn = r / 255;\n const gn = g / 255;\n const bn = b / 255;\n const max = Math.max(rn, gn, bn);\n const min = Math.min(rn, gn, bn);\n const l = (max + min) / 2;\n const delta = max - min;\n\n let h = 0;\n let s = 0;\n if (delta !== 0) {\n s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min);\n if (max === rn) {\n h = (gn - bn) / delta + (gn < bn ? 6 : 0);\n } else if (max === gn) {\n h = (bn - rn) / delta + 2;\n } else {\n h = (rn - gn) / delta + 4;\n }\n h *= 60;\n }\n return `${Math.round(h)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`;\n}\n\n/** What `completeScheme` needs from outside the scheme. */\nexport interface SchemeContext {\n /** The store's button colour, which tints `--secondary`/`--accent`. */\n primary?: string;\n}\n\n/**\n * The `SCHEME_TOKENS` of a scheme whose anchors the owner just edited.\n *\n * `anchors` win; everything the adapter derives from them is recomputed when\n * one of its inputs changed (and kept from `base` when none did — see \"Rounding\"\n * in the module header); `--border`/`--input` are taken from `base`. Invalid\n * triplets in any input are ignored, and a derived token whose inputs are\n * unavailable keeps `base`'s value, if any.\n *\n * Returns ONLY `SCHEME_TOKENS`: whatever else `base` carries (a pre-0243 row's\n * card or button colours, its radius) is the store's global set now, not the\n * scheme's, and is dropped. Every output entry passes `isSchemeTokenEntry`.\n */\nexport function completeScheme(\n base: Record<string, string>,\n anchors: Partial<Record<SchemeAnchorToken, string>>,\n context: SchemeContext = {},\n): Record<string, string> {\n // Both checks: `isHslTriplet` is what the arithmetic can convert, and the\n // scheme grammar is what a write accepts — failing either would poison a\n // derivation or get the whole save refused.\n const valid = (value: unknown): string | undefined =>\n typeof value === 'string' &&\n isHslTriplet(value) &&\n isSchemeColorValue(value.trim())\n ? value.trim()\n : undefined;\n const fromBase = (token: string): string | undefined => valid(base[token]);\n const fromAnchor = (token: SchemeAnchorToken): string | undefined =>\n valid(anchors[token]);\n\n const out: Record<string, string> = {};\n const put = (token: string, value: string | undefined): void => {\n if (value !== undefined) {\n out[token] = value;\n }\n };\n\n const background = fromAnchor('--background') ?? fromBase('--background');\n const foreground = fromAnchor('--foreground') ?? fromBase('--foreground');\n const bgChanged = background !== fromBase('--background');\n const fgChanged = foreground !== fromBase('--foreground');\n const bg = background === undefined ? null : tripletToRgb(background);\n const fg = foreground === undefined ? null : tripletToRgb(foreground);\n\n /** base's value while the inputs are unchanged, else the recomputation (else base's). */\n const derive = (\n token: string,\n inputsChanged: boolean,\n compute: () => string | undefined,\n ): string | undefined => {\n const kept = fromBase(token);\n return !inputsChanged && kept !== undefined ? kept : compute() ?? kept;\n };\n const mixOver = (over: Rgb | null, ratio: number) => (): string | undefined =>\n over !== null && bg !== null ? toTriplet(mix(over, ratio, bg)) : undefined;\n\n put('--background', background);\n put('--foreground', foreground);\n put(\n '--popover',\n derive('--popover', bgChanged, () => background),\n );\n put(\n '--popover-foreground',\n derive('--popover-foreground', fgChanged, () => foreground),\n );\n put('--muted', derive('--muted', bgChanged || fgChanged, mixOver(fg, 0.04)));\n put(\n '--muted-foreground',\n derive('--muted-foreground', bgChanged || fgChanged, mixOver(fg, 0.6)),\n );\n\n put('--border', fromBase('--border'));\n put('--input', fromBase('--input'));\n\n // Primary is the store's, not the scheme's. It counts as a changed input only\n // when base states the primary its tints were computed from and the context\n // names a different one; a base without one keeps its tints until the page\n // itself moves.\n const basePrimary = fromBase('--primary');\n const primaryTriplet = valid(context.primary) ?? basePrimary;\n const primaryChanged =\n basePrimary !== undefined &&\n primaryTriplet !== undefined &&\n primaryTriplet !== basePrimary;\n const primary =\n primaryTriplet === undefined ? null : tripletToRgb(primaryTriplet);\n const tintChanged = bgChanged || primaryChanged;\n put('--secondary', derive('--secondary', tintChanged, mixOver(primary, 0.1)));\n put('--accent', derive('--accent', tintChanged, mixOver(primary, 0.1)));\n\n return out;\n}\n\n/** The label the panel shows: the trimmed name, else `Palette N` (1-based). */\nexport function schemeDisplayName(scheme: ThemeScheme, index: number): string {\n const name = typeof scheme.name === 'string' ? scheme.name.trim() : '';\n return name !== '' ? name : `Palette ${index + 1}`;\n}\n\n/** `owner-N` with the smallest N ≥ 1 not already taken. */\nexport function nextOwnerSchemeId(schemes: readonly { id: string }[]): string {\n const taken = new Set(schemes.map((scheme) => scheme.id));\n let n = 1;\n while (taken.has(`owner-${n}`)) {\n n += 1;\n }\n return `owner-${n}`;\n}\n\n/** A colour value a scheme may hold: `SCHEME_COLOR_VALUE`, with S and L ≤ 100. */\nfunction isSchemeColorValue(value: string): boolean {\n const parts = SCHEME_COLOR_VALUE.exec(value);\n return parts !== null && Number(parts[2]) <= 100 && Number(parts[3]) <= 100;\n}\n\n/**\n * Whether a key/value pair may be written as a scheme token — the CLIENT's\n * contract, checked before the panel writes and by `completeScheme`.\n *\n * There is no allow-list: any key of the `themeOverrides` shape\n * (`THEME_OVERRIDE_KEY_PATTERN`) is a candidate. The value grammar follows the\n * key's contract type: `color-hsl` → an HSL triplet with S and L ≤ 100;\n * `length` → a px/rem/em length with its unit; anything else (font stacks,\n * keys the contract does not know) → the loose `themeOverrides` value shape.\n *\n * The server enforces only that loose shape for every key, so a `0 101% 50%`\n * colour or a unitless radius would be ACCEPTED there — and render wrong. That\n * is why the panel refuses them here. The renderer does not re-check values.\n */\nexport function isSchemeTokenEntry(key: string, value: unknown): boolean {\n if (typeof value !== 'string' || !THEME_OVERRIDE_KEY_PATTERN.test(key)) {\n return false;\n }\n switch (THEME_TOKEN_CONTRACT[key]?.type) {\n case 'color-hsl':\n return isSchemeColorValue(value);\n case 'length':\n return SCHEME_RADIUS_VALUE.test(value);\n default:\n return (\n value.length <= MAX_SCHEME_VALUE_LENGTH &&\n SCHEME_LOOSE_VALUE.test(value)\n );\n }\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,YAAY,QAAQ,eAAe;AAC5C,SACEC,0BAA0B,EAC1BC,oBAAoB,QACf,iBAAiB;;AAExB;;AAGA;;AAqBA;AACA,OAAO,MAAMC,mBAAwC,GAAGC,MAAM,CAACC,MAAM,CACnE,IAAIC,GAAG,CACLF,MAAM,CAACG,OAAO,CAACL,oBAAoB,CAAC,CACjCM,MAAM,CAACC,IAAA;EAAA,IAAC,GAAGC,KAAK,CAAC,GAAAD,IAAA;EAAA,OAAKC,KAAK,CAACC,IAAI,KAAK,WAAW;AAAA,EAAC,CACjDC,GAAG,CAACC,KAAA;EAAA,IAAC,CAACC,KAAK,CAAC,GAAAD,KAAA;EAAA,OAAKC,KAAK;AAAA,EAC3B,CACF,CAAwB;;AAExB;AACA;AACA;AACA;AACA;AACA,MAAMC,kBAAkB,GACtB,iEAAiE;;AAEnE;AACA;AACA;AACA;AACA;AACA,MAAMC,mBAAmB,GAAG,kCAAkC;;AAE9D;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,kBAAkB,GAAG,kBAAkB;AAC7C,MAAMC,uBAAuB,GAAG,GAAG;;AAEnC;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,aAAa,GAAG,CAC3B,cAAc,EACd,cAAc,EACd,WAAW,EACX,sBAAsB,EACtB,SAAS,EACT,oBAAoB,EACpB,UAAU,EACV,SAAS,EACT,aAAa,EACb,UAAU,CACF;AAIV,MAAMC,gBAAqC,GAAG,IAAId,GAAG,CAACa,aAAa,CAAC;;AAEpE;AACA,OAAO,SAASE,cAAcA,CAC5BT,GAA8C,EACtB;EACxB,OAAOR,MAAM,CAACkB,WAAW,CACvBlB,MAAM,CAACG,OAAO,CAACK,GAAG,IAAI,CAAC,CAAC,CAAC,CAACJ,MAAM,CAACe,KAAA;IAAA,IAAC,CAACT,KAAK,CAAC,GAAAS,KAAA;IAAA,OAAKH,gBAAgB,CAACI,GAAG,CAACV,KAAK,CAAC;EAAA,EAC3E,CAAC;AACH;;AAEA;AACA,OAAO,MAAMW,oBAAoB,GAAG,CAAC,cAAc,EAAE,cAAc,CAAU;AAI7E;AACA,OAAO,MAAMC,iBAAiB,GAAG,EAAE;AAEnC,MAAMC,iBAAiB,GAAG,2BAA2B;AACrD,MAAMC,sBAAsB,GAAG,EAAE;AAEjC,MAAMC,aAAa,GAAIC,KAAc,IACnC,OAAOA,KAAK,KAAK,QAAQ,IAAIA,KAAK,KAAK,IAAI,IAAI,CAACC,KAAK,CAACC,OAAO,CAACF,KAAK,CAAC;;AAEtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASG,aAAaA,CAACH,KAAc,EAAwB;EAClE,IAAI,CAACD,aAAa,CAACC,KAAK,CAAC,EAAE;IACzB,OAAO,KAAK;EACd;EACA,MAAM;IAAEI,EAAE;IAAEC,IAAI;IAAEC,MAAM;IAAEC,YAAY;IAAEC;EAAO,CAAC,GAAGR,KAAK;EACxD,IAAI,OAAOI,EAAE,KAAK,QAAQ,IAAI,CAACP,iBAAiB,CAACY,IAAI,CAACL,EAAE,CAAC,EAAE;IACzD,OAAO,KAAK;EACd;EACA,IAAIG,YAAY,KAAKG,SAAS,IAAI,OAAOH,YAAY,KAAK,QAAQ,EAAE;IAClE,OAAO,KAAK;EACd;EACA,IACEF,IAAI,KAAKK,SAAS,KACjB,OAAOL,IAAI,KAAK,QAAQ,IAAIA,IAAI,CAACM,MAAM,GAAGb,sBAAsB,CAAC,EAClE;IACA,OAAO,KAAK;EACd;EACA,IAAIQ,MAAM,KAAKI,SAAS,IAAI,OAAOJ,MAAM,KAAK,QAAQ,EAAE;IACtD,OAAO,KAAK;EACd;EACA,OACEP,aAAa,CAACS,MAAM,CAAC,IACrBlC,MAAM,CAACsC,MAAM,CAACJ,MAAM,CAAC,CAACK,KAAK,CAAEC,CAAC,IAAK,OAAOA,CAAC,KAAK,QAAQ,CAAC;AAE7D;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CACjCC,GAGa,EACO;EACpB,IAAI,CAACA,GAAG,IAAI,CAACf,KAAK,CAACC,OAAO,CAACc,GAAG,CAACC,YAAY,CAAC,EAAE;IAC5C,OAAO,IAAI;EACb;EACA,MAAMC,OAAO,GAAGF,GAAG,CAACC,YAAY,CAACvC,MAAM,CAACyB,aAAa,CAAC;EACtD,IAAIe,OAAO,CAACP,MAAM,KAAK,CAAC,EAAE;IACxB,OAAO,IAAI;EACb;EACA,MAAMQ,QAAQ,GAAGH,GAAG,CAACI,mBAAmB;EACxC,MAAMC,MAAM,GACV,OAAOF,QAAQ,KAAK,QAAQ,GACxBD,OAAO,CAACI,IAAI,CAAEC,MAAM,IAAKA,MAAM,CAACnB,EAAE,KAAKe,QAAQ,CAAC,GAChDT,SAAS;EACf,OAAOW,MAAM,IAAIH,OAAO,CAAC,CAAC,CAAC;AAC7B;;AAEA;;AAQA,MAAMM,OAAO,GACX,qEAAqE;;AAEvE;AACA;AACA;AACA;AACA,SAASC,YAAYA,CAACC,OAAe,EAAc;EACjD,MAAMC,KAAK,GAAGH,OAAO,CAACI,IAAI,CAACF,OAAO,CAACG,IAAI,CAAC,CAAC,CAAC;EAC1C,IAAI,CAACF,KAAK,IAAI,CAACzD,YAAY,CAACwD,OAAO,CAAC,EAAE;IACpC,OAAO,IAAI;EACb;EACA,MAAMI,CAAC,GAAGC,MAAM,CAACJ,KAAK,CAAC,CAAC,CAAC,CAAC;EAC1B,MAAMK,CAAC,GAAGD,MAAM,CAACJ,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;EAChC,MAAMM,CAAC,GAAGF,MAAM,CAACJ,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;EAEhC,MAAMO,CAAC,GAAG,CAAC,CAAC,GAAGC,IAAI,CAACC,GAAG,CAAC,CAAC,GAAGH,CAAC,GAAG,CAAC,CAAC,IAAID,CAAC;EACvC,MAAMK,CAAC,GAAGH,CAAC,IAAI,CAAC,GAAGC,IAAI,CAACC,GAAG,CAAGN,CAAC,GAAG,EAAE,GAAI,CAAC,GAAI,CAAC,CAAC,CAAC;EAChD,MAAMQ,CAAC,GAAGL,CAAC,GAAGC,CAAC,GAAG,CAAC;EACnB,MAAM,CAACK,CAAC,EAAEC,CAAC,EAAEC,CAAC,CAAC,GACbX,CAAC,GAAG,EAAE,GACF,CAACI,CAAC,EAAEG,CAAC,EAAE,CAAC,CAAC,GACTP,CAAC,GAAG,GAAG,GACP,CAACO,CAAC,EAAEH,CAAC,EAAE,CAAC,CAAC,GACTJ,CAAC,GAAG,GAAG,GACP,CAAC,CAAC,EAAEI,CAAC,EAAEG,CAAC,CAAC,GACTP,CAAC,GAAG,GAAG,GACP,CAAC,CAAC,EAAEO,CAAC,EAAEH,CAAC,CAAC,GACTJ,CAAC,GAAG,GAAG,GACP,CAACO,CAAC,EAAE,CAAC,EAAEH,CAAC,CAAC,GACT,CAACA,CAAC,EAAE,CAAC,EAAEG,CAAC,CAAC;EACf,OAAO;IAAEE,CAAC,EAAE,CAACA,CAAC,GAAGD,CAAC,IAAI,GAAG;IAAEE,CAAC,EAAE,CAACA,CAAC,GAAGF,CAAC,IAAI,GAAG;IAAEG,CAAC,EAAE,CAACA,CAAC,GAAGH,CAAC,IAAI;EAAI,CAAC;AACjE;;AAEA;AACA,SAASI,GAAGA,CAACC,EAAO,EAAEC,KAAa,EAAEC,EAAO,EAAO;EACjD,OAAO;IACLN,CAAC,EAAEJ,IAAI,CAACW,KAAK,CAACH,EAAE,CAACJ,CAAC,GAAGK,KAAK,GAAGC,EAAE,CAACN,CAAC,IAAI,CAAC,GAAGK,KAAK,CAAC,CAAC;IAChDJ,CAAC,EAAEL,IAAI,CAACW,KAAK,CAACH,EAAE,CAACH,CAAC,GAAGI,KAAK,GAAGC,EAAE,CAACL,CAAC,IAAI,CAAC,GAAGI,KAAK,CAAC,CAAC;IAChDH,CAAC,EAAEN,IAAI,CAACW,KAAK,CAACH,EAAE,CAACF,CAAC,GAAGG,KAAK,GAAGC,EAAE,CAACJ,CAAC,IAAI,CAAC,GAAGG,KAAK,CAAC;EACjD,CAAC;AACH;;AAEA;AACA,SAASG,SAASA,CAAAC,KAAA,EAA2B;EAAA,IAA1B;IAAET,CAAC;IAAEC,CAAC;IAAEC;EAAO,CAAC,GAAAO,KAAA;EACjC,MAAMC,EAAE,GAAGV,CAAC,GAAG,GAAG;EAClB,MAAMW,EAAE,GAAGV,CAAC,GAAG,GAAG;EAClB,MAAMW,EAAE,GAAGV,CAAC,GAAG,GAAG;EAClB,MAAMW,GAAG,GAAGjB,IAAI,CAACiB,GAAG,CAACH,EAAE,EAAEC,EAAE,EAAEC,EAAE,CAAC;EAChC,MAAME,GAAG,GAAGlB,IAAI,CAACkB,GAAG,CAACJ,EAAE,EAAEC,EAAE,EAAEC,EAAE,CAAC;EAChC,MAAMlB,CAAC,GAAG,CAACmB,GAAG,GAAGC,GAAG,IAAI,CAAC;EACzB,MAAMC,KAAK,GAAGF,GAAG,GAAGC,GAAG;EAEvB,IAAIvB,CAAC,GAAG,CAAC;EACT,IAAIE,CAAC,GAAG,CAAC;EACT,IAAIsB,KAAK,KAAK,CAAC,EAAE;IACftB,CAAC,GAAGC,CAAC,GAAG,GAAG,GAAGqB,KAAK,IAAI,CAAC,GAAGF,GAAG,GAAGC,GAAG,CAAC,GAAGC,KAAK,IAAIF,GAAG,GAAGC,GAAG,CAAC;IAC3D,IAAID,GAAG,KAAKH,EAAE,EAAE;MACdnB,CAAC,GAAG,CAACoB,EAAE,GAAGC,EAAE,IAAIG,KAAK,IAAIJ,EAAE,GAAGC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC,MAAM,IAAIC,GAAG,KAAKF,EAAE,EAAE;MACrBpB,CAAC,GAAG,CAACqB,EAAE,GAAGF,EAAE,IAAIK,KAAK,GAAG,CAAC;IAC3B,CAAC,MAAM;MACLxB,CAAC,GAAG,CAACmB,EAAE,GAAGC,EAAE,IAAII,KAAK,GAAG,CAAC;IAC3B;IACAxB,CAAC,IAAI,EAAE;EACT;EACA,OAAO,GAAGK,IAAI,CAACW,KAAK,CAAChB,CAAC,CAAC,IAAIK,IAAI,CAACW,KAAK,CAACd,CAAC,GAAG,GAAG,CAAC,KAAKG,IAAI,CAACW,KAAK,CAACb,CAAC,GAAG,GAAG,CAAC,GAAG;AAC3E;;AAEA;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASsB,cAAcA,CAC5BC,IAA4B,EAC5BC,OAAmD,EACnDC,OAAsB,EACE;EAAA,IADxBA,OAAsB;IAAtBA,OAAsB,GAAG,CAAC,CAAC;EAAA;EAE3B;EACA;EACA;EACA,MAAMC,KAAK,GAAI3D,KAAc,IAC3B,OAAOA,KAAK,KAAK,QAAQ,IACzB9B,YAAY,CAAC8B,KAAK,CAAC,IACnB4D,kBAAkB,CAAC5D,KAAK,CAAC6B,IAAI,CAAC,CAAC,CAAC,GAC5B7B,KAAK,CAAC6B,IAAI,CAAC,CAAC,GACZnB,SAAS;EACf,MAAMmD,QAAQ,GAAI7E,KAAa,IAAyB2E,KAAK,CAACH,IAAI,CAACxE,KAAK,CAAC,CAAC;EAC1E,MAAM8E,UAAU,GAAI9E,KAAwB,IAC1C2E,KAAK,CAACF,OAAO,CAACzE,KAAK,CAAC,CAAC;EAEvB,MAAM+E,GAA2B,GAAG,CAAC,CAAC;EACtC,MAAMC,GAAG,GAAGA,CAAChF,KAAa,EAAEgB,KAAyB,KAAW;IAC9D,IAAIA,KAAK,KAAKU,SAAS,EAAE;MACvBqD,GAAG,CAAC/E,KAAK,CAAC,GAAGgB,KAAK;IACpB;EACF,CAAC;EAED,MAAMiE,UAAU,GAAGH,UAAU,CAAC,cAAc,CAAC,IAAID,QAAQ,CAAC,cAAc,CAAC;EACzE,MAAMK,UAAU,GAAGJ,UAAU,CAAC,cAAc,CAAC,IAAID,QAAQ,CAAC,cAAc,CAAC;EACzE,MAAMM,SAAS,GAAGF,UAAU,KAAKJ,QAAQ,CAAC,cAAc,CAAC;EACzD,MAAMO,SAAS,GAAGF,UAAU,KAAKL,QAAQ,CAAC,cAAc,CAAC;EACzD,MAAMhB,EAAE,GAAGoB,UAAU,KAAKvD,SAAS,GAAG,IAAI,GAAGe,YAAY,CAACwC,UAAU,CAAC;EACrE,MAAMtB,EAAE,GAAGuB,UAAU,KAAKxD,SAAS,GAAG,IAAI,GAAGe,YAAY,CAACyC,UAAU,CAAC;;EAErE;EACA,MAAMG,MAAM,GAAGA,CACbrF,KAAa,EACbsF,aAAsB,EACtBC,OAAiC,KACV;IACvB,MAAMC,IAAI,GAAGX,QAAQ,CAAC7E,KAAK,CAAC;IAC5B,OAAO,CAACsF,aAAa,IAAIE,IAAI,KAAK9D,SAAS,GAAG8D,IAAI,GAAGD,OAAO,CAAC,CAAC,IAAIC,IAAI;EACxE,CAAC;EACD,MAAMC,OAAO,GAAGA,CAACC,IAAgB,EAAE9B,KAAa,KAAK,MACnD8B,IAAI,KAAK,IAAI,IAAI7B,EAAE,KAAK,IAAI,GAAGE,SAAS,CAACL,GAAG,CAACgC,IAAI,EAAE9B,KAAK,EAAEC,EAAE,CAAC,CAAC,GAAGnC,SAAS;EAE5EsD,GAAG,CAAC,cAAc,EAAEC,UAAU,CAAC;EAC/BD,GAAG,CAAC,cAAc,EAAEE,UAAU,CAAC;EAC/BF,GAAG,CACD,WAAW,EACXK,MAAM,CAAC,WAAW,EAAEF,SAAS,EAAE,MAAMF,UAAU,CACjD,CAAC;EACDD,GAAG,CACD,sBAAsB,EACtBK,MAAM,CAAC,sBAAsB,EAAED,SAAS,EAAE,MAAMF,UAAU,CAC5D,CAAC;EACDF,GAAG,CAAC,SAAS,EAAEK,MAAM,CAAC,SAAS,EAAEF,SAAS,IAAIC,SAAS,EAAEK,OAAO,CAAC9B,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;EAC5EqB,GAAG,CACD,oBAAoB,EACpBK,MAAM,CAAC,oBAAoB,EAAEF,SAAS,IAAIC,SAAS,EAAEK,OAAO,CAAC9B,EAAE,EAAE,GAAG,CAAC,CACvE,CAAC;EAEDqB,GAAG,CAAC,UAAU,EAAEH,QAAQ,CAAC,UAAU,CAAC,CAAC;EACrCG,GAAG,CAAC,SAAS,EAAEH,QAAQ,CAAC,SAAS,CAAC,CAAC;;EAEnC;EACA;EACA;EACA;EACA,MAAMc,WAAW,GAAGd,QAAQ,CAAC,WAAW,CAAC;EACzC,MAAMe,cAAc,GAAGjB,KAAK,CAACD,OAAO,CAACmB,OAAO,CAAC,IAAIF,WAAW;EAC5D,MAAMG,cAAc,GAClBH,WAAW,KAAKjE,SAAS,IACzBkE,cAAc,KAAKlE,SAAS,IAC5BkE,cAAc,KAAKD,WAAW;EAChC,MAAME,OAAO,GACXD,cAAc,KAAKlE,SAAS,GAAG,IAAI,GAAGe,YAAY,CAACmD,cAAc,CAAC;EACpE,MAAMG,WAAW,GAAGZ,SAAS,IAAIW,cAAc;EAC/Cd,GAAG,CAAC,aAAa,EAAEK,MAAM,CAAC,aAAa,EAAEU,WAAW,EAAEN,OAAO,CAACI,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;EAC7Eb,GAAG,CAAC,UAAU,EAAEK,MAAM,CAAC,UAAU,EAAEU,WAAW,EAAEN,OAAO,CAACI,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;EAEvE,OAAOd,GAAG;AACZ;;AAEA;AACA,OAAO,SAASiB,iBAAiBA,CAACzD,MAAmB,EAAE0D,KAAa,EAAU;EAC5E,MAAM5E,IAAI,GAAG,OAAOkB,MAAM,CAAClB,IAAI,KAAK,QAAQ,GAAGkB,MAAM,CAAClB,IAAI,CAACwB,IAAI,CAAC,CAAC,GAAG,EAAE;EACtE,OAAOxB,IAAI,KAAK,EAAE,GAAGA,IAAI,GAAG,WAAW4E,KAAK,GAAG,CAAC,EAAE;AACpD;;AAEA;AACA,OAAO,SAASC,iBAAiBA,CAAChE,OAAkC,EAAU;EAC5E,MAAMiE,KAAK,GAAG,IAAI3G,GAAG,CAAC0C,OAAO,CAACpC,GAAG,CAAEyC,MAAM,IAAKA,MAAM,CAACnB,EAAE,CAAC,CAAC;EACzD,IAAIgF,CAAC,GAAG,CAAC;EACT,OAAOD,KAAK,CAACzF,GAAG,CAAC,SAAS0F,CAAC,EAAE,CAAC,EAAE;IAC9BA,CAAC,IAAI,CAAC;EACR;EACA,OAAO,SAASA,CAAC,EAAE;AACrB;;AAEA;AACA,SAASxB,kBAAkBA,CAAC5D,KAAa,EAAW;EAClD,MAAM2B,KAAK,GAAG1C,kBAAkB,CAAC2C,IAAI,CAAC5B,KAAK,CAAC;EAC5C,OAAO2B,KAAK,KAAK,IAAI,IAAII,MAAM,CAACJ,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAII,MAAM,CAACJ,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG;AAC7E;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAAS0D,kBAAkBA,CAACC,GAAW,EAAEtF,KAAc,EAAW;EAAA,IAAAuF,qBAAA;EACvE,IAAI,OAAOvF,KAAK,KAAK,QAAQ,IAAI,CAAC7B,0BAA0B,CAACsC,IAAI,CAAC6E,GAAG,CAAC,EAAE;IACtE,OAAO,KAAK;EACd;EACA,SAAAC,qBAAA,GAAQnH,oBAAoB,CAACkH,GAAG,CAAC,qBAAzBC,qBAAA,CAA2B1G,IAAI;IACrC,KAAK,WAAW;MACd,OAAO+E,kBAAkB,CAAC5D,KAAK,CAAC;IAClC,KAAK,QAAQ;MACX,OAAOd,mBAAmB,CAACuB,IAAI,CAACT,KAAK,CAAC;IACxC;MACE,OACEA,KAAK,CAACW,MAAM,IAAIvB,uBAAuB,IACvCD,kBAAkB,CAACsB,IAAI,CAACT,KAAK,CAAC;EAEpC;AACF","ignoreList":[]}