@wix/web5-core 1.63.42 → 1.63.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/client/applyThemeOverrides.js +41 -9
- package/dist/cjs/client/applyThemeOverrides.js.map +1 -1
- package/dist/cjs/client/themeDebug.js +15 -6
- package/dist/cjs/client/themeDebug.js.map +1 -1
- package/dist/cjs/components/ui/AiDisclosure.js +17 -19
- package/dist/cjs/components/ui/AiDisclosure.js.map +1 -1
- package/dist/cjs/components/ui/SearchSection.js +44 -36
- package/dist/cjs/components/ui/SearchSection.js.map +1 -1
- package/dist/cjs/index.js +21 -5
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/assistant.js +58 -0
- package/dist/cjs/lib/assistant.js.map +1 -0
- package/dist/cjs/theme/themeScheme.js +375 -0
- package/dist/cjs/theme/themeScheme.js.map +1 -0
- package/dist/cjs/theme/tokenContract.js +8 -1
- package/dist/cjs/theme/tokenContract.js.map +1 -1
- package/dist/esm/client/applyThemeOverrides.js +42 -10
- package/dist/esm/client/applyThemeOverrides.js.map +1 -1
- package/dist/esm/client/themeDebug.js +15 -6
- package/dist/esm/client/themeDebug.js.map +1 -1
- package/dist/esm/components/ui/AiDisclosure.js +7 -8
- package/dist/esm/components/ui/AiDisclosure.js.map +1 -1
- package/dist/esm/components/ui/SearchSection.js +10 -1
- package/dist/esm/components/ui/SearchSection.js.map +1 -1
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/assistant.js +52 -0
- package/dist/esm/lib/assistant.js.map +1 -0
- package/dist/esm/theme/themeScheme.js +372 -0
- package/dist/esm/theme/themeScheme.js.map +1 -0
- package/dist/esm/theme/tokenContract.js +7 -0
- package/dist/esm/theme/tokenContract.js.map +1 -1
- package/dist/types/client/applyThemeOverrides.d.ts +1 -1
- package/dist/types/client/applyThemeOverrides.d.ts.map +1 -1
- package/dist/types/client/themeDebug.d.ts +2 -2
- package/dist/types/client/themeDebug.d.ts.map +1 -1
- package/dist/types/components/ui/AiDisclosure.d.ts +7 -5
- package/dist/types/components/ui/AiDisclosure.d.ts.map +1 -1
- package/dist/types/components/ui/SearchSection.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/assistant.d.ts +39 -0
- package/dist/types/lib/assistant.d.ts.map +1 -0
- package/dist/types/theme/themeScheme.d.ts +79 -0
- package/dist/types/theme/themeScheme.d.ts.map +1 -0
- package/dist/types/theme/tokenContract.d.ts +6 -0
- package/dist/types/theme/tokenContract.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["WEB5_SCOPE","traceThemeOverrides","THEME_TOKEN_CONTRACT","bucketOf","hostAliasFor","THEME_OVERRIDE_TOKENS","Set","Object","keys","KEY_PATTERN","MARKER_ATTR","wellFormedEntries","overrides","entries","filter","_ref","key","wellFormed","test","console","warn","applyThemeOverrides","userOverrides","document","existing","head","querySelector","userEntries","length","remove","style","createElement","setAttribute","appendChild","sheet","insertRule","rule","cssRules","applied","write","value","target","source","setProperty","push","token","writtenAs"],"sources":["../../../src/client/applyThemeOverrides.ts"],"sourcesContent":["/**\n * Runtime theme token injection (DL #131).\n *\n * `Configuration.themeOverrides` carries per-store CSS custom-property\n * overrides (`--primary`, `--radius`, `--heading`, ...) computed from the\n * store's own theme (e.g. the Shopify `settings_data.json` extractor). This\n * applies them to the page so they win over the bundle's baked `theme.css`:\n *\n * - **Scoped, not `:root`**: the rule targets `WEB5_SCOPE`, the same\n * `:is(#root, .w5-root, [data-web5-placement], .debug-view)` selector every\n * compiled bundle stylesheet uses — host-page styling is never touched, and\n * equal specificity + later document order makes the override win. Callers\n * must therefore apply AFTER the client bundle's CSS is in the document.\n * - **Bucketed, since DL #193**: a `brand` token (colour roles, font families)\n * is written as itself, so the store's identity beats the template's. Every\n * other key — `host` tokens and anything the contract has never heard of —\n * is written as its `--web5-host-*` alias, which core's stylesheets consume\n * as a `var()` fallback. A template stating the real token therefore wins on\n * shape, and an unknown key is inert rather than dangerous: a custom property\n * nothing references renders nothing, so an adapter that learns to read a new\n * token cannot silently override a template.\n * - **The token set stays open, but the destination changed.** Before DL #193\n * an unrecognised key was applied verbatim, so a template could consume\n * `var(--foo)` and grow a token with no release. It now arrives as\n * `--web5-host-foo`, so the template consumes `var(--web5-host-foo, <default>)`\n * instead. One line different, and the provenance is explicit — the wiring\n * line is what activates a host token, not the contract entry.\n * - The mandatory `--` prefix means an override can only define custom\n * properties — it can never set a real CSS property inside the scope. The\n * server enforces the same shape (plus value sanitation) at write time.\n * - **Values are inert**: entries are written with\n * `CSSStyleDeclaration.setProperty`, never string-concatenated into CSS, so\n * a hostile value cannot terminate the declaration or open a new rule.\n * - **The shop owner is the last word (DL #193)**: `userOverrides` carries the\n * choices a human made in the owner panel, and every one of them is written\n * as the real token whatever its bucket. Bucketing exists to arbitrate a\n * disagreement between a store and a template; an owner who opened a panel\n * and set a value has already settled that argument, so aliasing theirs would\n * let the template overrule the person who chose. They are written last, so a\n * token both maps carry resolves to the owner's value.\n * - **Idempotent**: one marker element per document, replaced wholesale on\n * re-apply; empty/absent input removes it.\n */\nimport { WEB5_SCOPE } from '../hostScope';\nimport {\n traceThemeOverrides,\n type AppliedToken,\n type ThemeOverrideSource,\n} from './themeDebug';\nimport {\n THEME_TOKEN_CONTRACT,\n bucketOf,\n hostAliasFor,\n} from '../theme/tokenContract';\n\n/** A themeOverrides key: always a CSS custom property. */\nexport type ThemeOverrideKey = `--${string}`;\n\n/**\n * Writer-side shape for a theme override map. The catalog below documents\n * the tokens the seed consumes today; the type stays open so new tokens\n * flow end-to-end with no release anywhere but the seed.\n */\nexport type ThemeOverrides = Record<ThemeOverrideKey, string>;\n\n/**\n * The known token catalog. GUIDANCE, NOT A GATE — `applyThemeOverrides` still\n * applies any well-formed custom property, so the vocabulary can grow without a\n * release here.\n *\n * Derived from `@wix/web5-token-contract` rather than restated, because two\n * hand-maintained copies of one list is how they drift. The contract also\n * carries what this Set cannot: which bucket each token is in, and therefore\n * who wins when a store and a template disagree.\n */\nexport const THEME_OVERRIDE_TOKENS: ReadonlySet<string> = new Set(\n Object.keys(THEME_TOKEN_CONTRACT),\n);\n\n/** Mirrors the server's Consts.ThemeOverrideKeyPattern. */\nconst KEY_PATTERN = /^--[a-z][a-z0-9-]{0,62}$/;\n\nconst MARKER_ATTR = 'data-web5-theme-overrides';\n\n/** Drops keys that are not well-formed custom properties, warning about each. */\nfunction wellFormedEntries(\n overrides?: Record<string, string> | null,\n): [string, string][] {\n return Object.entries(overrides ?? {}).filter(([key]) => {\n const wellFormed = KEY_PATTERN.test(key);\n if (!wellFormed) {\n console.warn(\n `[web5-theme] Skipping malformed theme override key: ${key}`,\n );\n }\n return wellFormed;\n });\n}\n\nexport function applyThemeOverrides(\n overrides?: Record<string, string> | null,\n userOverrides?: Record<string, string> | null,\n): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n const existing = document.head.querySelector(`style[${MARKER_ATTR}]`);\n const entries = wellFormedEntries(overrides);\n const userEntries = wellFormedEntries(userOverrides);\n\n if (entries.length === 0 && userEntries.length === 0) {\n existing?.remove();\n // Nothing to apply is itself a traceable answer: it means every token on\n // the page is the template's, which is otherwise indistinguishable from\n // tracing having failed.\n traceThemeOverrides([]);\n return;\n }\n\n const style = document.createElement('style');\n style.setAttribute(MARKER_ATTR, '');\n document.head.appendChild(style);\n const sheet = style.sheet;\n if (!sheet) {\n style.remove();\n return;\n }\n sheet.insertRule(`${WEB5_SCOPE} {}`, 0);\n const rule = sheet.cssRules[0] as CSSStyleRule;\n const applied: AppliedToken[] = [];\n const write = (\n key: string,\n value: string,\n target: string,\n source: ThemeOverrideSource,\n ): void => {\n try {\n rule.style.setProperty(target, value);\n applied.push({ token: key, value, writtenAs: target, source });\n } catch {\n // An engine that rejects the value leaves the token at its baked\n // default — degraded theming, never broken CSS.\n }\n };\n\n for (const [key, value] of entries) {\n // Brand wins over the template, so it is written as the token the\n // stylesheets actually read. Everything else lands in the host namespace,\n // where core consumes it only as a fallback the template can beat.\n write(\n key,\n value,\n bucketOf(key) === 'brand' ? key : hostAliasFor(key),\n 'store',\n );\n }\n // Owner choices last and never aliased: within one declaration block the last\n // write of a property wins, so a token both maps carry ends up the owner's.\n for (const [key, value] of userEntries) {\n write(key, value, key, 'user');\n }\n // Replace-on-reapply: the fresh element is appended (so it stays last in\n // document order) before the stale one is dropped.\n existing?.remove();\n // AFTER the stale element is gone, so the resolved values traced below are\n // the ones the page will actually render. Off unless explicitly enabled.\n traceThemeOverrides(applied);\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["WEB5_SCOPE","traceThemeOverrides","THEME_OVERRIDE_KEY_PATTERN","THEME_TOKEN_CONTRACT","bucketOf","hostAliasFor","THEME_OVERRIDE_TOKENS","Set","Object","keys","MARKER_ATTR","wellFormedEntries","overrides","entries","filter","_ref","key","wellFormed","test","console","warn","bucketed","applyThemeOverrides","userOverrides","schemeTokens","document","existing","head","querySelector","userEntries","activeSchemeEntries","length","remove","style","createElement","setAttribute","appendChild","sheet","insertRule","rule","cssRules","applied","write","value","target","source","setProperty","push","token","writtenAs"],"sources":["../../../src/client/applyThemeOverrides.ts"],"sourcesContent":["/**\n * Runtime theme token injection (DL #131).\n *\n * `Configuration.themeOverrides` carries per-store CSS custom-property\n * overrides (`--primary`, `--radius`, `--heading`, ...) computed from the\n * store's own theme (e.g. the Shopify `settings_data.json` extractor). This\n * applies them to the page so they win over the bundle's baked `theme.css`:\n *\n * - **Scoped, not `:root`**: the rule targets `WEB5_SCOPE`, the same\n * `:is(#root, .w5-root, [data-web5-placement], .debug-view)` selector every\n * compiled bundle stylesheet uses — host-page styling is never touched, and\n * equal specificity + later document order makes the override win. Callers\n * must therefore apply AFTER the client bundle's CSS is in the document.\n * - **Bucketed, since DL #193**: a `brand` token (colour roles, font families)\n * is written as itself, so the store's identity beats the template's. Every\n * other key — `host` tokens and anything the contract has never heard of —\n * is written as its `--web5-host-*` alias, which core's stylesheets consume\n * as a `var()` fallback. A template stating the real token therefore wins on\n * shape, and an unknown key is inert rather than dangerous: a custom property\n * nothing references renders nothing, so an adapter that learns to read a new\n * token cannot silently override a template.\n * - **The token set stays open, but the destination changed.** Before DL #193\n * an unrecognised key was applied verbatim, so a template could consume\n * `var(--foo)` and grow a token with no release. It now arrives as\n * `--web5-host-foo`, so the template consumes `var(--web5-host-foo, <default>)`\n * instead. One line different, and the provenance is explicit — the wiring\n * line is what activates a host token, not the contract entry.\n * - The mandatory `--` prefix means an override can only define custom\n * properties — it can never set a real CSS property inside the scope. The\n * server enforces the same shape (plus value sanitation) at write time.\n * - **Values are inert**: entries are written with\n * `CSSStyleDeclaration.setProperty`, never string-concatenated into CSS, so\n * a hostile value cannot terminate the declaration or open a new rule.\n * - **The shop owner is the last word (DL #193)**: `userOverrides` carries the\n * choices a human made in the owner panel, and every one of them is written\n * as the real token whatever its bucket. Bucketing exists to arbitrate a\n * disagreement between a store and a template; an owner who opened a panel\n * and set a value has already settled that argument, so aliasing theirs would\n * let the template overrule the person who chose. They are written last, so a\n * token both maps carry resolves to the owner's value.\n * - **The active theme scheme sits between the two**: `schemeTokens` is the\n * resolved entry of `Configuration.themeSchemes` (see `theme/themeScheme`).\n * It is written after the store map and before the owner's overrides, under\n * the SAME bucket rule as the store map: a `brand` token (colours, fonts) as\n * the real token, anything else — `--radius`, a key the contract has never\n * heard of — as its `--web5-host-*` alias. Being the later write of either\n * property, the chosen palette beats the flat store map on colours and on\n * radius alike — yet a template that states `--radius` still wins on shape,\n * exactly as it does over an imported radius. A scheme is written like the\n * store map it stands in for, not like an owner override, so it gets no\n * exemption from aliasing; the owner's layer still wins over it. Its entries\n * are filtered exactly like the store map's too: the same key check, the same\n * warning, and no per-type value check — `setProperty` keeps any value inert,\n * and the typed grammar (`isSchemeTokenEntry`) is the panel's to enforce\n * before a write. So the scheme token set is as open as `themeOverrides`: a\n * new scheme token needs no release here. Absent → exactly the pre-scheme\n * behaviour.\n * - **Idempotent**: one marker element per document, replaced wholesale on\n * re-apply; empty/absent input (all three layers) removes it.\n */\nimport { WEB5_SCOPE } from '../hostScope';\nimport {\n traceThemeOverrides,\n type AppliedToken,\n type ThemeOverrideSource,\n} from './themeDebug';\nimport {\n THEME_OVERRIDE_KEY_PATTERN,\n THEME_TOKEN_CONTRACT,\n bucketOf,\n hostAliasFor,\n} from '../theme/tokenContract';\n\n/** A themeOverrides key: always a CSS custom property. */\nexport type ThemeOverrideKey = `--${string}`;\n\n/**\n * Writer-side shape for a theme override map. The catalog below documents\n * the tokens the seed consumes today; the type stays open so new tokens\n * flow end-to-end with no release anywhere but the seed.\n */\nexport type ThemeOverrides = Record<ThemeOverrideKey, string>;\n\n/**\n * The known token catalog. GUIDANCE, NOT A GATE — `applyThemeOverrides` still\n * applies any well-formed custom property, so the vocabulary can grow without a\n * release here.\n *\n * Derived from `@wix/web5-token-contract` rather than restated, because two\n * hand-maintained copies of one list is how they drift. The contract also\n * carries what this Set cannot: which bucket each token is in, and therefore\n * who wins when a store and a template disagree.\n */\nexport const THEME_OVERRIDE_TOKENS: ReadonlySet<string> = new Set(\n Object.keys(THEME_TOKEN_CONTRACT),\n);\n\nconst MARKER_ATTR = 'data-web5-theme-overrides';\n\n/**\n * Drops keys that are not well-formed custom properties, warning about each.\n * Used for all three layers — store, scheme and owner.\n */\nfunction wellFormedEntries(\n overrides?: Record<string, string> | null,\n): [string, string][] {\n return Object.entries(overrides ?? {}).filter(([key]) => {\n const wellFormed = THEME_OVERRIDE_KEY_PATTERN.test(key);\n if (!wellFormed) {\n console.warn(\n `[web5-theme] Skipping malformed theme override key: ${key}`,\n );\n }\n return wellFormed;\n });\n}\n\n/**\n * Where a store-side token lands: a `brand` token as itself, so the store's\n * identity beats the template's; everything else as its `--web5-host-*` alias,\n * which core consumes only as a fallback the template can beat.\n */\nconst bucketed = (key: string): string =>\n bucketOf(key) === 'brand' ? key : hostAliasFor(key);\n\nexport function applyThemeOverrides(\n overrides?: Record<string, string> | null,\n userOverrides?: Record<string, string> | null,\n schemeTokens?: Record<string, string> | null,\n): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n const existing = document.head.querySelector(`style[${MARKER_ATTR}]`);\n const entries = wellFormedEntries(overrides);\n const userEntries = wellFormedEntries(userOverrides);\n const activeSchemeEntries = wellFormedEntries(schemeTokens);\n\n if (\n entries.length === 0 &&\n activeSchemeEntries.length === 0 &&\n userEntries.length === 0\n ) {\n existing?.remove();\n // Nothing to apply is itself a traceable answer: it means every token on\n // the page is the template's, which is otherwise indistinguishable from\n // tracing having failed.\n traceThemeOverrides([]);\n return;\n }\n\n const style = document.createElement('style');\n style.setAttribute(MARKER_ATTR, '');\n document.head.appendChild(style);\n const sheet = style.sheet;\n if (!sheet) {\n style.remove();\n return;\n }\n sheet.insertRule(`${WEB5_SCOPE} {}`, 0);\n const rule = sheet.cssRules[0] as CSSStyleRule;\n const applied: AppliedToken[] = [];\n const write = (\n key: string,\n value: string,\n target: string,\n source: ThemeOverrideSource,\n ): void => {\n try {\n rule.style.setProperty(target, value);\n applied.push({ token: key, value, writtenAs: target, source });\n } catch {\n // An engine that rejects the value leaves the token at its baked\n // default — degraded theming, never broken CSS.\n }\n };\n\n for (const [key, value] of entries) {\n // Brand wins over the template, so it is written as the token the\n // stylesheets actually read. Everything else lands in the host namespace,\n // where core consumes it only as a fallback the template can beat.\n write(key, value, bucketed(key), 'store');\n }\n // The active scheme over the store map, bucketed the same way: a brand token\n // as itself, `--radius` and unknown keys as their alias. Either way this is\n // the later write of that property, so it beats the store's — and a\n // template's `--radius` still beats the alias.\n for (const [key, value] of activeSchemeEntries) {\n write(key, value, bucketed(key), 'scheme');\n }\n // Owner choices last and never aliased: within one declaration block the last\n // write of a property wins, so a token both maps carry ends up the owner's.\n for (const [key, value] of userEntries) {\n write(key, value, key, 'user');\n }\n // Replace-on-reapply: the fresh element is appended (so it stays last in\n // document order) before the stale one is dropped.\n existing?.remove();\n // AFTER the stale element is gone, so the resolved values traced below are\n // the ones the page will actually render. Off unless explicitly enabled.\n traceThemeOverrides(applied);\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,SAASA,UAAU,QAAQ,cAAc;AACzC,SACEC,mBAAmB,QAGd,cAAc;AACrB,SACEC,0BAA0B,EAC1BC,oBAAoB,EACpBC,QAAQ,EACRC,YAAY,QACP,wBAAwB;;AAE/B;;AAGA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,qBAA0C,GAAG,IAAIC,GAAG,CAC/DC,MAAM,CAACC,IAAI,CAACN,oBAAoB,CAClC,CAAC;AAED,MAAMO,WAAW,GAAG,2BAA2B;;AAE/C;AACA;AACA;AACA;AACA,SAASC,iBAAiBA,CACxBC,SAAyC,EACrB;EACpB,OAAOJ,MAAM,CAACK,OAAO,CAACD,SAAS,IAAI,CAAC,CAAC,CAAC,CAACE,MAAM,CAACC,IAAA,IAAW;IAAA,IAAV,CAACC,GAAG,CAAC,GAAAD,IAAA;IAClD,MAAME,UAAU,GAAGf,0BAA0B,CAACgB,IAAI,CAACF,GAAG,CAAC;IACvD,IAAI,CAACC,UAAU,EAAE;MACfE,OAAO,CAACC,IAAI,CACV,uDAAuDJ,GAAG,EAC5D,CAAC;IACH;IACA,OAAOC,UAAU;EACnB,CAAC,CAAC;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAMI,QAAQ,GAAIL,GAAW,IAC3BZ,QAAQ,CAACY,GAAG,CAAC,KAAK,OAAO,GAAGA,GAAG,GAAGX,YAAY,CAACW,GAAG,CAAC;AAErD,OAAO,SAASM,mBAAmBA,CACjCV,SAAyC,EACzCW,aAA6C,EAC7CC,YAA4C,EACtC;EACN,IAAI,OAAOC,QAAQ,KAAK,WAAW,EAAE;IACnC;EACF;EAEA,MAAMC,QAAQ,GAAGD,QAAQ,CAACE,IAAI,CAACC,aAAa,CAAC,SAASlB,WAAW,GAAG,CAAC;EACrE,MAAMG,OAAO,GAAGF,iBAAiB,CAACC,SAAS,CAAC;EAC5C,MAAMiB,WAAW,GAAGlB,iBAAiB,CAACY,aAAa,CAAC;EACpD,MAAMO,mBAAmB,GAAGnB,iBAAiB,CAACa,YAAY,CAAC;EAE3D,IACEX,OAAO,CAACkB,MAAM,KAAK,CAAC,IACpBD,mBAAmB,CAACC,MAAM,KAAK,CAAC,IAChCF,WAAW,CAACE,MAAM,KAAK,CAAC,EACxB;IACAL,QAAQ,YAARA,QAAQ,CAAEM,MAAM,CAAC,CAAC;IAClB;IACA;IACA;IACA/B,mBAAmB,CAAC,EAAE,CAAC;IACvB;EACF;EAEA,MAAMgC,KAAK,GAAGR,QAAQ,CAACS,aAAa,CAAC,OAAO,CAAC;EAC7CD,KAAK,CAACE,YAAY,CAACzB,WAAW,EAAE,EAAE,CAAC;EACnCe,QAAQ,CAACE,IAAI,CAACS,WAAW,CAACH,KAAK,CAAC;EAChC,MAAMI,KAAK,GAAGJ,KAAK,CAACI,KAAK;EACzB,IAAI,CAACA,KAAK,EAAE;IACVJ,KAAK,CAACD,MAAM,CAAC,CAAC;IACd;EACF;EACAK,KAAK,CAACC,UAAU,CAAC,GAAGtC,UAAU,KAAK,EAAE,CAAC,CAAC;EACvC,MAAMuC,IAAI,GAAGF,KAAK,CAACG,QAAQ,CAAC,CAAC,CAAiB;EAC9C,MAAMC,OAAuB,GAAG,EAAE;EAClC,MAAMC,KAAK,GAAGA,CACZ1B,GAAW,EACX2B,KAAa,EACbC,MAAc,EACdC,MAA2B,KAClB;IACT,IAAI;MACFN,IAAI,CAACN,KAAK,CAACa,WAAW,CAACF,MAAM,EAAED,KAAK,CAAC;MACrCF,OAAO,CAACM,IAAI,CAAC;QAAEC,KAAK,EAAEhC,GAAG;QAAE2B,KAAK;QAAEM,SAAS,EAAEL,MAAM;QAAEC;MAAO,CAAC,CAAC;IAChE,CAAC,CAAC,MAAM;MACN;MACA;IAAA;EAEJ,CAAC;EAED,KAAK,MAAM,CAAC7B,GAAG,EAAE2B,KAAK,CAAC,IAAI9B,OAAO,EAAE;IAClC;IACA;IACA;IACA6B,KAAK,CAAC1B,GAAG,EAAE2B,KAAK,EAAEtB,QAAQ,CAACL,GAAG,CAAC,EAAE,OAAO,CAAC;EAC3C;EACA;EACA;EACA;EACA;EACA,KAAK,MAAM,CAACA,GAAG,EAAE2B,KAAK,CAAC,IAAIb,mBAAmB,EAAE;IAC9CY,KAAK,CAAC1B,GAAG,EAAE2B,KAAK,EAAEtB,QAAQ,CAACL,GAAG,CAAC,EAAE,QAAQ,CAAC;EAC5C;EACA;EACA;EACA,KAAK,MAAM,CAACA,GAAG,EAAE2B,KAAK,CAAC,IAAId,WAAW,EAAE;IACtCa,KAAK,CAAC1B,GAAG,EAAE2B,KAAK,EAAE3B,GAAG,EAAE,MAAM,CAAC;EAChC;EACA;EACA;EACAU,QAAQ,YAARA,QAAQ,CAAEM,MAAM,CAAC,CAAC;EAClB;EACA;EACA/B,mBAAmB,CAACwC,OAAO,CAAC;AAC9B","ignoreList":[]}
|
|
@@ -20,8 +20,12 @@
|
|
|
20
20
|
*
|
|
21
21
|
* [web5:theme] --radius host wrote --web5-host-radius=0rem → 1.25rem TEMPLATE
|
|
22
22
|
* [web5:theme] --primary brand wrote --primary=0 0% 9% → 0 0% 9% STORE
|
|
23
|
+
* [web5:theme] --radius scheme wrote --web5-host-radius=1rem → 1rem SCHEME
|
|
23
24
|
* [web5:theme] --radius owner wrote --radius=2rem → 2rem OWNER
|
|
24
25
|
*
|
|
26
|
+
* A scheme is bucketed like the store map, so its `--radius` is written as the
|
|
27
|
+
* alias too — and can lose to a template the same way.
|
|
28
|
+
*
|
|
25
29
|
* Off by default. Enable with `?web5DebugTheme=1` (one-shot, wins over storage)
|
|
26
30
|
* or `localStorage["web5_debug_theme"] = "1"` (sticky) — the same shape as
|
|
27
31
|
* `matchDebug`, so there is one convention to learn rather than two.
|
|
@@ -67,7 +71,7 @@ export const resetThemeDebugCache = () => {
|
|
|
67
71
|
cached = null;
|
|
68
72
|
};
|
|
69
73
|
|
|
70
|
-
/** Which layer asked for a value: the platform import, or a human. */
|
|
74
|
+
/** Which layer asked for a value: the platform import, the active theme scheme, or a human. */
|
|
71
75
|
|
|
72
76
|
/** One token as it was actually written to the mount rule. */
|
|
73
77
|
|
|
@@ -106,13 +110,18 @@ export function traceThemeOverrides(applied) {
|
|
|
106
110
|
// One computed-style read for the whole batch: the expensive part is the style
|
|
107
111
|
// recalculation it forces, not the per-property lookups off the result.
|
|
108
112
|
const computed = getComputedStyle(mount);
|
|
109
|
-
//
|
|
110
|
-
//
|
|
113
|
+
// Layers are written store → scheme → owner, and the last write of a token is
|
|
114
|
+
// the one that resolves — so the latest layer is credited, or a store value
|
|
111
115
|
// that happens to match would be credited with a win it did not have.
|
|
116
|
+
const rank = {
|
|
117
|
+
store: 0,
|
|
118
|
+
scheme: 1,
|
|
119
|
+
user: 2
|
|
120
|
+
};
|
|
112
121
|
const byToken = new Map();
|
|
113
122
|
for (const entry of applied) {
|
|
114
123
|
const held = byToken.get(entry.token);
|
|
115
|
-
if (!held || entry.source
|
|
124
|
+
if (!held || rank[entry.source] >= rank[held.source]) {
|
|
116
125
|
byToken.set(entry.token, entry);
|
|
117
126
|
}
|
|
118
127
|
}
|
|
@@ -127,11 +136,11 @@ export function traceThemeOverrides(applied) {
|
|
|
127
136
|
const wanted = value.trim();
|
|
128
137
|
return {
|
|
129
138
|
token,
|
|
130
|
-
bucket: source === 'user' ? 'owner' : bucketOf(token),
|
|
139
|
+
bucket: source === 'user' ? 'owner' : source === 'scheme' ? 'scheme' : bucketOf(token),
|
|
131
140
|
'written as': writtenAs,
|
|
132
141
|
'asked for': wanted,
|
|
133
142
|
'resolves to': resolved || '(nothing reads it)',
|
|
134
|
-
winner: !resolved ? 'NOBODY — no stylesheet consumes this token' : resolved !== wanted ? 'TEMPLATE' : source === 'user' ? 'OWNER' : 'STORE'
|
|
143
|
+
winner: !resolved ? 'NOBODY — no stylesheet consumes this token' : resolved !== wanted ? 'TEMPLATE' : source === 'user' ? 'OWNER' : source === 'scheme' ? 'SCHEME' : 'STORE'
|
|
135
144
|
};
|
|
136
145
|
});
|
|
137
146
|
const overridden = rows.filter(r => r.winner === 'TEMPLATE').length;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["WEB5_SCOPES","bucketOf","THEME_DEBUG_KEY","THEME_DEBUG_QUERY_PARAM","LOG_PREFIX","isTruthy","value","cached","isThemeDebugEnabled","URLSearchParams","window","location","search","get","localStorage","getItem","resetThemeDebugCache","traceThemeOverrides","applied","length","console","info","mount","document","querySelector","join","warn","computed","getComputedStyle","byToken","Map","entry","held","token","source","set","rows","values","map","writtenAs","resolved","getPropertyValue","trim","wanted","bucket","winner","overridden","filter","r","inert","startsWith","groupCollapsed","table","groupEnd"],"sources":["../../../src/client/themeDebug.ts"],"sourcesContent":["/**\n * Theme-override tracing (debug-only).\n *\n * Answers the one question the token pipeline cannot otherwise be asked:\n * **which layer actually won?**\n *\n * Since DL #193 a `brand` token is written as itself and everything else as its\n * `--web5-host-*` alias, which core's stylesheets consume as a `var()` fallback\n * a template can beat. That makes the outcome a cascade decision, and a cascade\n * decision is invisible — there is no callback, no return value, and nothing in\n * the DOM to read. Worse, `applyThemeOverrides` writes through the CSSOM\n * (`insertRule` + `setProperty`, never `textContent`) so that a hostile value\n * can never terminate a declaration, which means DevTools renders the marker as\n * `<style data-web5-theme-overrides=\"\">` — an empty tag, with the rules real but\n * nowhere in the DOM tree. Every part of that is deliberate and every part of it\n * looks broken.\n *\n * So this reads the resolved value back off the mount **after** the rule is in,\n * and reports what the browser actually decided:\n *\n * [web5:theme] --radius host wrote --web5-host-radius=0rem → 1.25rem TEMPLATE\n * [web5:theme] --primary brand wrote --primary=0 0% 9% → 0 0% 9% STORE\n * [web5:theme] --radius owner wrote --radius=2rem → 2rem OWNER\n *\n * Off by default. Enable with `?web5DebugTheme=1` (one-shot, wins over storage)\n * or `localStorage[\"web5_debug_theme\"] = \"1\"` (sticky) — the same shape as\n * `matchDebug`, so there is one convention to learn rather than two.\n *\n * It is gated rather than always-on because reading a computed value forces a\n * style recalculation, and this runs during page setup. One read is taken for\n * the whole batch, not one per token.\n */\nimport { WEB5_SCOPES } from '../hostScope';\nimport { bucketOf } from '../theme/tokenContract';\n\nexport const THEME_DEBUG_KEY = 'web5_debug_theme';\n\n/** Query param that forces theme tracing on, overriding localStorage. */\nexport const THEME_DEBUG_QUERY_PARAM = 'web5DebugTheme';\n\nconst LOG_PREFIX = '[web5:theme]';\n\nconst isTruthy = (value: unknown): boolean => value === '1' || value === 'true';\n\nlet cached: boolean | null = null;\n\n/** Whether theme tracing is enabled. Memoized — resolved once per page load. */\nexport const isThemeDebugEnabled = (): boolean => {\n if (cached !== null) {\n return cached;\n }\n cached = false;\n try {\n if (\n isTruthy(\n new URLSearchParams(window.location.search).get(\n THEME_DEBUG_QUERY_PARAM,\n ),\n )\n ) {\n cached = true;\n return cached;\n }\n } catch {\n // window / URLSearchParams unavailable (SSR, non-DOM environments).\n }\n try {\n cached = isTruthy(localStorage.getItem(THEME_DEBUG_KEY));\n } catch {\n // localStorage can throw in privacy mode / non-DOM environments.\n }\n return cached;\n};\n\n/** Test seam — the flag is memoized for the page, so tests must be able to clear it. */\nexport const resetThemeDebugCache = (): void => {\n cached = null;\n};\n\n/** Which layer asked for a value: the platform import, or a human. */\nexport type ThemeOverrideSource = 'store' | 'user';\n\n/** One token as it was actually written to the mount rule. */\nexport interface AppliedToken {\n token: string;\n value: string;\n writtenAs: string;\n source: ThemeOverrideSource;\n}\n\ninterface TraceRow {\n token: string;\n bucket: string;\n 'written as': string;\n 'asked for': string;\n 'resolves to': string;\n winner: string;\n}\n\n/**\n * Report what each override did, after the rule is live.\n *\n * `applied` is what `applyThemeOverrides` actually wrote — already filtered for\n * key shape, so anything malformed has been dropped and warned about before\n * reaching here.\n */\nexport function traceThemeOverrides(applied: AppliedToken[]): void {\n if (!isThemeDebugEnabled()) {\n return;\n }\n if (applied.length === 0) {\n // Silence here would be indistinguishable from tracing being broken, and\n // \"no overrides reached the page\" is itself the answer often enough — a\n // store with nothing imported means every token is the template's.\n // eslint-disable-next-line no-console\n console.info(\n `${LOG_PREFIX} no overrides applied — nothing usable arrived for this store, so every token is whatever the template and core defaults say`,\n );\n return;\n }\n let mount: Element | null = null;\n try {\n mount = document.querySelector(WEB5_SCOPES.join(','));\n } catch {\n // Malformed selector cannot happen with the constant, but querySelector is\n // the one call here that can throw, and a debug aid must never be the thing\n // that breaks a page.\n }\n if (!mount) {\n console.warn(\n `${LOG_PREFIX} no mount found (${WEB5_SCOPES.join(\n ', ',\n )}) — tokens were written, but their resolved values cannot be read`,\n );\n return;\n }\n\n // One computed-style read for the whole batch: the expensive part is the style\n // recalculation it forces, not the per-property lookups off the result.\n const computed = getComputedStyle(mount);\n // An owner's write is the last one into the rule, so when both layers name a\n // token the resolved value is theirs — check the owner first or a store value\n // that happens to match would be credited with a win it did not have.\n const byToken = new Map<string, AppliedToken>();\n for (const entry of applied) {\n const held = byToken.get(entry.token);\n if (!held || entry.source === 'user') {\n byToken.set(entry.token, entry);\n }\n }\n const rows: TraceRow[] = [...byToken.values()].map((entry) => {\n const { token, value, writtenAs, source } = entry;\n const resolved = computed.getPropertyValue(token).trim();\n const wanted = value.trim();\n return {\n token,\n bucket: source === 'user' ? 'owner' : bucketOf(token),\n 'written as': writtenAs,\n 'asked for': wanted,\n 'resolves to': resolved || '(nothing reads it)',\n winner: !resolved\n ? 'NOBODY — no stylesheet consumes this token'\n : resolved !== wanted\n ? 'TEMPLATE'\n : source === 'user'\n ? 'OWNER'\n : 'STORE',\n };\n });\n\n const overridden = rows.filter((r) => r.winner === 'TEMPLATE').length;\n const inert = rows.filter((r) => r.winner.startsWith('NOBODY')).length;\n\n /* eslint-disable no-console */\n console.groupCollapsed(\n `${LOG_PREFIX} ${rows.length} override(s) applied · ${overridden} kept by the template · ${inert} inert`,\n );\n console.table(rows);\n if (inert > 0) {\n console.info(\n `${LOG_PREFIX} \"inert\" means the value was written but no stylesheet reads that token — ` +\n `for a host token that means core has no \\`var(--web5-host-…)\\` wiring for it yet.`,\n );\n }\n console.info(\n `${LOG_PREFIX} the marker <style data-web5-theme-overrides> looks empty in DevTools on purpose: ` +\n `rules are inserted through the CSSOM, never as text. Read them with ` +\n `document.querySelector('style[data-web5-theme-overrides]').sheet.cssRules[0].cssText`,\n );\n console.groupEnd();\n /* eslint-enable no-console */\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["WEB5_SCOPES","bucketOf","THEME_DEBUG_KEY","THEME_DEBUG_QUERY_PARAM","LOG_PREFIX","isTruthy","value","cached","isThemeDebugEnabled","URLSearchParams","window","location","search","get","localStorage","getItem","resetThemeDebugCache","traceThemeOverrides","applied","length","console","info","mount","document","querySelector","join","warn","computed","getComputedStyle","rank","store","scheme","user","byToken","Map","entry","held","token","source","set","rows","values","map","writtenAs","resolved","getPropertyValue","trim","wanted","bucket","winner","overridden","filter","r","inert","startsWith","groupCollapsed","table","groupEnd"],"sources":["../../../src/client/themeDebug.ts"],"sourcesContent":["/**\n * Theme-override tracing (debug-only).\n *\n * Answers the one question the token pipeline cannot otherwise be asked:\n * **which layer actually won?**\n *\n * Since DL #193 a `brand` token is written as itself and everything else as its\n * `--web5-host-*` alias, which core's stylesheets consume as a `var()` fallback\n * a template can beat. That makes the outcome a cascade decision, and a cascade\n * decision is invisible — there is no callback, no return value, and nothing in\n * the DOM to read. Worse, `applyThemeOverrides` writes through the CSSOM\n * (`insertRule` + `setProperty`, never `textContent`) so that a hostile value\n * can never terminate a declaration, which means DevTools renders the marker as\n * `<style data-web5-theme-overrides=\"\">` — an empty tag, with the rules real but\n * nowhere in the DOM tree. Every part of that is deliberate and every part of it\n * looks broken.\n *\n * So this reads the resolved value back off the mount **after** the rule is in,\n * and reports what the browser actually decided:\n *\n * [web5:theme] --radius host wrote --web5-host-radius=0rem → 1.25rem TEMPLATE\n * [web5:theme] --primary brand wrote --primary=0 0% 9% → 0 0% 9% STORE\n * [web5:theme] --radius scheme wrote --web5-host-radius=1rem → 1rem SCHEME\n * [web5:theme] --radius owner wrote --radius=2rem → 2rem OWNER\n *\n * A scheme is bucketed like the store map, so its `--radius` is written as the\n * alias too — and can lose to a template the same way.\n *\n * Off by default. Enable with `?web5DebugTheme=1` (one-shot, wins over storage)\n * or `localStorage[\"web5_debug_theme\"] = \"1\"` (sticky) — the same shape as\n * `matchDebug`, so there is one convention to learn rather than two.\n *\n * It is gated rather than always-on because reading a computed value forces a\n * style recalculation, and this runs during page setup. One read is taken for\n * the whole batch, not one per token.\n */\nimport { WEB5_SCOPES } from '../hostScope';\nimport { bucketOf } from '../theme/tokenContract';\n\nexport const THEME_DEBUG_KEY = 'web5_debug_theme';\n\n/** Query param that forces theme tracing on, overriding localStorage. */\nexport const THEME_DEBUG_QUERY_PARAM = 'web5DebugTheme';\n\nconst LOG_PREFIX = '[web5:theme]';\n\nconst isTruthy = (value: unknown): boolean => value === '1' || value === 'true';\n\nlet cached: boolean | null = null;\n\n/** Whether theme tracing is enabled. Memoized — resolved once per page load. */\nexport const isThemeDebugEnabled = (): boolean => {\n if (cached !== null) {\n return cached;\n }\n cached = false;\n try {\n if (\n isTruthy(\n new URLSearchParams(window.location.search).get(\n THEME_DEBUG_QUERY_PARAM,\n ),\n )\n ) {\n cached = true;\n return cached;\n }\n } catch {\n // window / URLSearchParams unavailable (SSR, non-DOM environments).\n }\n try {\n cached = isTruthy(localStorage.getItem(THEME_DEBUG_KEY));\n } catch {\n // localStorage can throw in privacy mode / non-DOM environments.\n }\n return cached;\n};\n\n/** Test seam — the flag is memoized for the page, so tests must be able to clear it. */\nexport const resetThemeDebugCache = (): void => {\n cached = null;\n};\n\n/** Which layer asked for a value: the platform import, the active theme scheme, or a human. */\nexport type ThemeOverrideSource = 'store' | 'scheme' | 'user';\n\n/** One token as it was actually written to the mount rule. */\nexport interface AppliedToken {\n token: string;\n value: string;\n writtenAs: string;\n source: ThemeOverrideSource;\n}\n\ninterface TraceRow {\n token: string;\n bucket: string;\n 'written as': string;\n 'asked for': string;\n 'resolves to': string;\n winner: string;\n}\n\n/**\n * Report what each override did, after the rule is live.\n *\n * `applied` is what `applyThemeOverrides` actually wrote — already filtered for\n * key shape, so anything malformed has been dropped and warned about before\n * reaching here.\n */\nexport function traceThemeOverrides(applied: AppliedToken[]): void {\n if (!isThemeDebugEnabled()) {\n return;\n }\n if (applied.length === 0) {\n // Silence here would be indistinguishable from tracing being broken, and\n // \"no overrides reached the page\" is itself the answer often enough — a\n // store with nothing imported means every token is the template's.\n // eslint-disable-next-line no-console\n console.info(\n `${LOG_PREFIX} no overrides applied — nothing usable arrived for this store, so every token is whatever the template and core defaults say`,\n );\n return;\n }\n let mount: Element | null = null;\n try {\n mount = document.querySelector(WEB5_SCOPES.join(','));\n } catch {\n // Malformed selector cannot happen with the constant, but querySelector is\n // the one call here that can throw, and a debug aid must never be the thing\n // that breaks a page.\n }\n if (!mount) {\n console.warn(\n `${LOG_PREFIX} no mount found (${WEB5_SCOPES.join(\n ', ',\n )}) — tokens were written, but their resolved values cannot be read`,\n );\n return;\n }\n\n // One computed-style read for the whole batch: the expensive part is the style\n // recalculation it forces, not the per-property lookups off the result.\n const computed = getComputedStyle(mount);\n // Layers are written store → scheme → owner, and the last write of a token is\n // the one that resolves — so the latest layer is credited, or a store value\n // that happens to match would be credited with a win it did not have.\n const rank: Record<ThemeOverrideSource, number> = {\n store: 0,\n scheme: 1,\n user: 2,\n };\n const byToken = new Map<string, AppliedToken>();\n for (const entry of applied) {\n const held = byToken.get(entry.token);\n if (!held || rank[entry.source] >= rank[held.source]) {\n byToken.set(entry.token, entry);\n }\n }\n const rows: TraceRow[] = [...byToken.values()].map((entry) => {\n const { token, value, writtenAs, source } = entry;\n const resolved = computed.getPropertyValue(token).trim();\n const wanted = value.trim();\n return {\n token,\n bucket:\n source === 'user'\n ? 'owner'\n : source === 'scheme'\n ? 'scheme'\n : bucketOf(token),\n 'written as': writtenAs,\n 'asked for': wanted,\n 'resolves to': resolved || '(nothing reads it)',\n winner: !resolved\n ? 'NOBODY — no stylesheet consumes this token'\n : resolved !== wanted\n ? 'TEMPLATE'\n : source === 'user'\n ? 'OWNER'\n : source === 'scheme'\n ? 'SCHEME'\n : 'STORE',\n };\n });\n\n const overridden = rows.filter((r) => r.winner === 'TEMPLATE').length;\n const inert = rows.filter((r) => r.winner.startsWith('NOBODY')).length;\n\n /* eslint-disable no-console */\n console.groupCollapsed(\n `${LOG_PREFIX} ${rows.length} override(s) applied · ${overridden} kept by the template · ${inert} inert`,\n );\n console.table(rows);\n if (inert > 0) {\n console.info(\n `${LOG_PREFIX} \"inert\" means the value was written but no stylesheet reads that token — ` +\n `for a host token that means core has no \\`var(--web5-host-…)\\` wiring for it yet.`,\n );\n }\n console.info(\n `${LOG_PREFIX} the marker <style data-web5-theme-overrides> looks empty in DevTools on purpose: ` +\n `rules are inserted through the CSSOM, never as text. Read them with ` +\n `document.querySelector('style[data-web5-theme-overrides]').sheet.cssRules[0].cssText`,\n );\n console.groupEnd();\n /* eslint-enable no-console */\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import React, { Fragment } from 'react';
|
|
2
2
|
import { cn } from '../../lib/utils.js';
|
|
3
|
+
import { ASSISTANT_TOKEN, UNBRANDED_ASSISTANT_NAME } from '../../lib/assistant.js';
|
|
3
4
|
import { AiIcon } from './icons/AiIcon.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
+
* Re-exported for the callers that already import the token from here.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
* ("Ask {assistant}…"), so a store rename
|
|
10
|
-
* translator can put the name wherever the target
|
|
9
|
+
* It lives in `lib/assistant` alongside the name it stands for: the same token
|
|
10
|
+
* the prompt-input placeholder uses ("Ask {assistant}…"), so a store rename
|
|
11
|
+
* moves both together and a translator can put the name wherever the target
|
|
12
|
+
* language needs it.
|
|
11
13
|
*/
|
|
12
|
-
export
|
|
14
|
+
export { ASSISTANT_TOKEN };
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
17
|
* The disclosure a shopper must see. Wording is fixed here rather than in each
|
|
@@ -17,9 +19,6 @@ export const ASSISTANT_TOKEN = '{assistant}';
|
|
|
17
19
|
* text, so it should not be forkable per store by accident.
|
|
18
20
|
*/
|
|
19
21
|
export const DEFAULT_AI_DISCLOSURE_TEXT = `Generated by ${ASSISTANT_TOKEN} · Double-check anything important`;
|
|
20
|
-
|
|
21
|
-
/** Used when the host publishes no store name — still reads correctly. */
|
|
22
|
-
const UNBRANDED_ASSISTANT_NAME = 'AI';
|
|
23
22
|
/**
|
|
24
23
|
* "Generated by <Store> AI · Double-check anything important" — the AI
|
|
25
24
|
* disclosure shown at the top of a generated answer (EU AI Act, B2B-4488).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","Fragment","cn","
|
|
1
|
+
{"version":3,"names":["React","Fragment","cn","ASSISTANT_TOKEN","UNBRANDED_ASSISTANT_NAME","AiIcon","DEFAULT_AI_DISCLOSURE_TEXT","AiDisclosure","_ref","assistantName","text","icon","align","className","name","trim","segments","split","createElement","role","undefined","map","segment","index","key","length"],"sources":["../../../../src/components/ui/AiDisclosure.tsx"],"sourcesContent":["import React, { FC, Fragment, ReactNode } from 'react';\nimport { cn } from '../../lib/utils';\nimport { ASSISTANT_TOKEN, UNBRANDED_ASSISTANT_NAME } from '../../lib/assistant';\nimport { AiIcon } from './icons/AiIcon';\n\n/**\n * Re-exported for the callers that already import the token from here.\n *\n * It lives in `lib/assistant` alongside the name it stands for: the same token\n * the prompt-input placeholder uses (\"Ask {assistant}…\"), so a store rename\n * moves both together and a translator can put the name wherever the target\n * language needs it.\n */\nexport { ASSISTANT_TOKEN };\n\n/**\n * The disclosure a shopper must see. Wording is fixed here rather than in each\n * client bundle: it is what tells the shopper they are reading machine-written\n * text, so it should not be forkable per store by accident.\n */\nexport const DEFAULT_AI_DISCLOSURE_TEXT = `Generated by ${ASSISTANT_TOKEN} · Double-check anything important`;\n\nexport interface AiDisclosureProps {\n /**\n * What the assistant is called — the store's name plus \"AI\", e.g.\n * \"Smallflower AI\". Rendered in the display face so the store's brand is the\n * emphasized word in the line. Blank/omitted falls back to \"AI\".\n */\n assistantName?: string;\n /**\n * The full sentence, with `{assistant}` marking where the name goes.\n * Defaults to {@link DEFAULT_AI_DISCLOSURE_TEXT}. A string without the token\n * renders verbatim, with no emphasized name.\n */\n text?: string;\n /**\n * Replace the leading icon. `null` drops it — the text alone still carries\n * the disclosure, so removing the icon is a visual choice, not a\n * compliance one.\n */\n icon?: ReactNode;\n /** Row alignment. `'center'` (default) matches the hero; `'start'` for left-aligned surfaces. */\n align?: 'start' | 'center';\n className?: string;\n}\n\n/**\n * \"Generated by <Store> AI · Double-check anything important\" — the AI\n * disclosure shown at the top of a generated answer (EU AI Act, B2B-4488).\n *\n * Replaces the old \"AI can make mistakes.\" response footer: one notice, above\n * the content rather than below it, so a shopper reads it before the answer\n * instead of after.\n *\n * Presentational only. Hosts decide where it mounts and pass the store's\n * assistant name; every color, size and face resolves from web5 tokens, so a\n * client re-skins it by re-skinning the theme.\n */\nexport const AiDisclosure: FC<AiDisclosureProps> = ({\n assistantName,\n text = DEFAULT_AI_DISCLOSURE_TEXT,\n icon,\n align = 'center',\n className,\n}) => {\n const name = (assistantName ?? '').trim() || UNBRANDED_ASSISTANT_NAME;\n const segments = text.split(ASSISTANT_TOKEN);\n\n return (\n <p\n className={cn(\n 'web5-ai-disclosure',\n align === 'start' && 'web5-ai-disclosure--start',\n className,\n )}\n role=\"note\"\n >\n {icon === undefined ? (\n <AiIcon className=\"web5-ai-disclosure__icon\" />\n ) : (\n icon\n )}\n <span className=\"web5-ai-disclosure__text\">\n {segments.map((segment, index) => (\n <Fragment key={index}>\n {segment}\n {index < segments.length - 1 && (\n <span className=\"web5-ai-disclosure__assistant\">{name}</span>\n )}\n </Fragment>\n ))}\n </span>\n </p>\n );\n};\n"],"mappings":"AAAA,OAAOA,KAAK,IAAQC,QAAQ,QAAmB,OAAO;AACtD,SAASC,EAAE,QAAQ,iBAAiB;AACpC,SAASC,eAAe,EAAEC,wBAAwB,QAAQ,qBAAqB;AAC/E,SAASC,MAAM,QAAQ,gBAAgB;;AAEvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASF,eAAe;;AAExB;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMG,0BAA0B,GAAG,gBAAgBH,eAAe,oCAAoC;AA0B7G;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMI,YAAmC,GAAGC,IAAA,IAM7C;EAAA,IAN8C;IAClDC,aAAa;IACbC,IAAI,GAAGJ,0BAA0B;IACjCK,IAAI;IACJC,KAAK,GAAG,QAAQ;IAChBC;EACF,CAAC,GAAAL,IAAA;EACC,MAAMM,IAAI,GAAG,CAACL,aAAa,IAAI,EAAE,EAAEM,IAAI,CAAC,CAAC,IAAIX,wBAAwB;EACrE,MAAMY,QAAQ,GAAGN,IAAI,CAACO,KAAK,CAACd,eAAe,CAAC;EAE5C,oBACEH,KAAA,CAAAkB,aAAA;IACEL,SAAS,EAAEX,EAAE,CACX,oBAAoB,EACpBU,KAAK,KAAK,OAAO,IAAI,2BAA2B,EAChDC,SACF,CAAE;IACFM,IAAI,EAAC;EAAM,GAEVR,IAAI,KAAKS,SAAS,gBACjBpB,KAAA,CAAAkB,aAAA,CAACb,MAAM;IAACQ,SAAS,EAAC;EAA0B,CAAE,CAAC,GAE/CF,IACD,eACDX,KAAA,CAAAkB,aAAA;IAAML,SAAS,EAAC;EAA0B,GACvCG,QAAQ,CAACK,GAAG,CAAC,CAACC,OAAO,EAAEC,KAAK,kBAC3BvB,KAAA,CAAAkB,aAAA,CAACjB,QAAQ;IAACuB,GAAG,EAAED;EAAM,GAClBD,OAAO,EACPC,KAAK,GAAGP,QAAQ,CAACS,MAAM,GAAG,CAAC,iBAC1BzB,KAAA,CAAAkB,aAAA;IAAML,SAAS,EAAC;EAA+B,GAAEC,IAAW,CAEtD,CACX,CACG,CACL,CAAC;AAER,CAAC","ignoreList":[]}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
import React, { forwardRef, useEffect, useImperativeHandle, useState, useRef, useCallback, useLayoutEffect } from 'react';
|
|
3
3
|
import { cn } from '../../lib/utils.js';
|
|
4
|
+
import { DEFAULT_PROMPT_PLACEHOLDER, resolveAssistantPlaceholder } from '../../lib/assistant.js';
|
|
4
5
|
import { isWeb5Url } from '../../types/link-types.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Fallback for a bare `<SearchSection />` — the product default with no store
|
|
9
|
+
* name to resolve against, so "Ask AI...". Hosts that know the store (the
|
|
10
|
+
* full-page app, the embed widget) resolve the token themselves and pass the
|
|
11
|
+
* branded string in; this only covers the component used on its own.
|
|
12
|
+
*/
|
|
13
|
+
const UNBRANDED_PLACEHOLDER = resolveAssistantPlaceholder(DEFAULT_PROMPT_PLACEHOLDER);
|
|
5
14
|
const ArrowDownIcon = () => /*#__PURE__*/React.createElement("svg", {
|
|
6
15
|
xmlns: "http://www.w3.org/2000/svg",
|
|
7
16
|
width: "24",
|
|
@@ -65,7 +74,7 @@ const PromptSendIcon = props => /*#__PURE__*/React.createElement("svg", _extends
|
|
|
65
74
|
export const SearchSection = /*#__PURE__*/forwardRef(function SearchSection(_ref, ref) {
|
|
66
75
|
let {
|
|
67
76
|
onSubmit,
|
|
68
|
-
placeholder =
|
|
77
|
+
placeholder = UNBRANDED_PLACEHOLDER,
|
|
69
78
|
submitLabel,
|
|
70
79
|
collapsedLabel,
|
|
71
80
|
onCollapsedChange,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","forwardRef","useEffect","useImperativeHandle","useState","useRef","useCallback","useLayoutEffect","cn","isWeb5Url","ArrowDownIcon","createElement","xmlns","width","height","viewBox","fill","stroke","strokeWidth","strokeLinecap","strokeLinejoin","d","MicrophoneIcon","props","_extends","ArrowRightIcon","PromptSendIcon","SearchSection","_ref","ref","onSubmit","placeholder","submitLabel","collapsedLabel","onCollapsedChange","chips","chipDisplayMode","chipPosition","onVoiceInput","progressMessage","className","contextBanner","hasContext","canSubmitEmpty","hasContent","isBottomZoneVisible","onChipClick","onFocusChange","inputValue","setInputValue","isFocused","setIsFocused","hasFocusInside","setHasFocusInside","isMultiline","setIsMultiline","isCollapsed","setIsCollapsed","inputRef","hasExpandedWhileZoneVisibleRef","previouslyFocusedElementRef","showChips","length","effectiveCollapsedLabel","replace","handleSubmit","trimmedValue","trim","element","current","computedStyles","window","getComputedStyle","lineHeight","Number","parseFloat","hasValue","style","nextHeight","Math","min","max","scrollHeight","hasFocusInsideRef","onFocusChangeRef","focusInput","active","document","activeElement","HTMLElement","body","requestAnimationFrame","_inputRef$current","focus","_inputRef$current2","blurInput","_inputRef$current3","blur","handleKeyDown","e","key","_inputRef$current4","preventDefault","prev","shiftKey","handleInputChange","target","value","handleInputFocus","relatedTarget","handleContentFocus","handleContentBlur","next","currentTarget","contains","role","canSubmit","chipsMarkup","map","chip","label","href","onMouseDown","onClick","_inputRef$current5","tabIndex","handleExpandClick","type","onFocus","onBlur","rows","onChange","onKeyDown","undefined","disabled","Fragment"],"sources":["../../../../src/components/ui/SearchSection.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useState,\n useRef,\n useCallback,\n useLayoutEffect,\n} from 'react';\nimport { cn } from '../../lib/utils';\nimport { isWeb5Url } from '../../types/link-types';\n\nexport interface ScrollChip {\n label: string;\n href: string;\n iconHint?: string;\n}\n\nexport interface SearchSectionProps {\n onSubmit?: (value: string) => void;\n placeholder?: string;\n /**\n * When set, the submit control renders as a labeled CTA button (text +\n * right arrow) instead of the icon-only send button. Used by the empty\n * state (e.g. \"Find Your Pair\").\n */\n submitLabel?: string;\n collapsedLabel?: string;\n onCollapsedChange?: (isCollapsed: boolean) => void;\n chips?: ScrollChip[];\n chipDisplayMode?: 'focus' | 'always';\n chipPosition?: 'top' | 'bottom';\n onVoiceInput?: () => void;\n progressMessage?: string;\n className?: string;\n contextBanner?: React.ReactNode;\n hasContext?: boolean;\n canSubmitEmpty?: boolean;\n hasContent?: boolean;\n isBottomZoneVisible?: boolean;\n onChipClick?: (e: React.MouseEvent<HTMLAnchorElement>, href: string) => void;\n onFocusChange?: (focused: boolean) => void;\n}\n\nexport interface SearchSectionHandle {\n focusInput: () => void;\n blurInput: () => void;\n}\n\nconst ArrowDownIcon: React.FC = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 5v14\" />\n <path d=\"m19 12-7 7-7-7\" />\n </svg>\n);\n\nconst MicrophoneIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n stroke=\"none\"\n aria-hidden=\"true\"\n {...props}\n >\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path\n d=\"M19 10v2a7 7 0 0 1-14 0v-2M12 19v3\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n fill=\"none\"\n />\n </svg>\n);\n\nconst ArrowRightIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n {...props}\n >\n <path d=\"M5 12h14\" />\n <path d=\"m12 5 7 7-7 7\" />\n </svg>\n);\n\nconst PromptSendIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n aria-hidden=\"true\"\n {...props}\n >\n <path\n d=\"M13.0306 7.53114C12.9609 7.60106 12.8781 7.65654 12.787 7.69439C12.6958 7.73224 12.5981 7.75173 12.4993 7.75173C12.4006 7.75173 12.3029 7.73224 12.2117 7.69439C12.1206 7.65654 12.0378 7.60106 11.9681 7.53114L8.74997 4.31301V13.5005C8.74997 13.6994 8.67095 13.8902 8.5303 14.0308C8.38965 14.1715 8.19888 14.2505 7.99997 14.2505C7.80106 14.2505 7.61029 14.1715 7.46964 14.0308C7.32899 13.8902 7.24997 13.6994 7.24997 13.5005V4.31301L4.0306 7.53114C3.8897 7.67203 3.69861 7.75119 3.49935 7.75119C3.30009 7.75119 3.10899 7.67203 2.9681 7.53114C2.8272 7.39024 2.74805 7.19915 2.74805 6.99989C2.74805 6.80063 2.8272 6.60953 2.9681 6.46864L7.4681 1.96864C7.53778 1.89872 7.62057 1.84324 7.71173 1.80539C7.8029 1.76753 7.90064 1.74805 7.99935 1.74805C8.09806 1.74805 8.1958 1.76753 8.28696 1.80539C8.37813 1.84324 8.46092 1.89872 8.5306 1.96864L13.0306 6.46864C13.1005 6.53832 13.156 6.62111 13.1938 6.71227C13.2317 6.80344 13.2512 6.90118 13.2512 6.99989C13.2512 7.0986 13.2317 7.19634 13.1938 7.2875C13.156 7.37867 13.1005 7.46146 13.0306 7.53114Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\nexport const SearchSection = forwardRef<\n SearchSectionHandle,\n SearchSectionProps\n>(function SearchSection(\n {\n onSubmit,\n placeholder = 'Talk to us',\n submitLabel,\n collapsedLabel,\n onCollapsedChange,\n chips = [],\n chipDisplayMode = 'focus',\n chipPosition = 'top',\n onVoiceInput,\n progressMessage,\n className = '',\n contextBanner,\n hasContext,\n canSubmitEmpty = false,\n hasContent = false,\n isBottomZoneVisible = false,\n onChipClick,\n onFocusChange,\n },\n ref,\n) {\n const [inputValue, setInputValue] = useState('');\n const [isFocused, setIsFocused] = useState(false);\n const [hasFocusInside, setHasFocusInside] = useState(false);\n const [isMultiline, setIsMultiline] = useState(false);\n const [isCollapsed, setIsCollapsed] = useState(false);\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const hasExpandedWhileZoneVisibleRef = useRef(false);\n const previouslyFocusedElementRef = useRef<HTMLElement | null>(null);\n const showChips =\n chips.length > 0 &&\n !hasContext &&\n (chipDisplayMode === 'always' || hasFocusInside);\n const effectiveCollapsedLabel =\n collapsedLabel ?? placeholder.replace(/\\.\\.\\.$/, '');\n\n const handleSubmit = useCallback(() => {\n const trimmedValue = inputValue.trim();\n if (trimmedValue || canSubmitEmpty) {\n onSubmit?.(trimmedValue);\n setInputValue('');\n }\n }, [canSubmitEmpty, inputValue, onSubmit]);\n\n useLayoutEffect(() => {\n const element = inputRef.current;\n if (!element) {\n return;\n }\n\n const computedStyles = window.getComputedStyle(element);\n const lineHeight = Number.parseFloat(computedStyles.lineHeight) || 32;\n\n const hasValue = inputValue.trim().length > 0;\n element.style.height = 'auto';\n const nextHeight = hasValue\n ? Math.min(Math.max(element.scrollHeight, lineHeight), 175)\n : lineHeight;\n element.style.height = `${nextHeight}px`;\n setIsMultiline(hasValue && nextHeight > lineHeight);\n }, [inputValue]);\n\n useEffect(() => {\n if (progressMessage || !hasContent) {\n setIsCollapsed(false);\n hasExpandedWhileZoneVisibleRef.current = false;\n return;\n }\n\n if (!isBottomZoneVisible) {\n hasExpandedWhileZoneVisibleRef.current = false;\n setIsCollapsed(false);\n return;\n }\n\n if (!hasExpandedWhileZoneVisibleRef.current) {\n setIsCollapsed(true);\n }\n }, [hasContent, isBottomZoneVisible, progressMessage]);\n\n useEffect(() => {\n onCollapsedChange?.(isCollapsed);\n }, [isCollapsed, onCollapsedChange]);\n\n const hasFocusInsideRef = useRef(hasFocusInside);\n hasFocusInsideRef.current = hasFocusInside;\n const onFocusChangeRef = useRef(onFocusChange);\n onFocusChangeRef.current = onFocusChange;\n\n useEffect(() => {\n onFocusChange?.(hasFocusInside);\n }, [hasFocusInside, onFocusChange]);\n\n useEffect(() => {\n return () => {\n if (hasFocusInsideRef.current) {\n onFocusChangeRef.current?.(false);\n }\n };\n }, []);\n\n const focusInput = useCallback(() => {\n const active = document.activeElement;\n if (\n active instanceof HTMLElement &&\n active !== inputRef.current &&\n active !== document.body\n ) {\n previouslyFocusedElementRef.current = active;\n }\n if (isCollapsed) {\n hasExpandedWhileZoneVisibleRef.current = true;\n setIsCollapsed(false);\n window.requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n } else {\n inputRef.current?.focus();\n }\n }, [isCollapsed]);\n\n const blurInput = useCallback(() => {\n inputRef.current?.blur();\n }, []);\n\n useImperativeHandle(ref, () => ({ focusInput, blurInput }), [\n focusInput,\n blurInput,\n ]);\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n const prev = previouslyFocusedElementRef.current;\n previouslyFocusedElementRef.current = null;\n inputRef.current?.blur();\n prev?.focus?.();\n return;\n }\n if (\n e.key === 'Enter' &&\n !e.shiftKey &&\n (inputValue.trim() || canSubmitEmpty)\n ) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setInputValue(e.target.value);\n };\n\n const handleInputFocus = (e: React.FocusEvent<HTMLTextAreaElement>) => {\n setIsFocused(true);\n if (\n e.relatedTarget instanceof HTMLElement &&\n e.relatedTarget !== inputRef.current\n ) {\n previouslyFocusedElementRef.current = e.relatedTarget;\n }\n };\n\n const handleContentFocus = () => {\n setHasFocusInside(true);\n };\n\n const handleContentBlur = (e: React.FocusEvent<HTMLDivElement>) => {\n const next = e.relatedTarget as Node | null;\n if (!next || !e.currentTarget.contains(next)) {\n setHasFocusInside(false);\n }\n };\n\n if (progressMessage) {\n return (\n <div\n className={cn('web5-prompt-progress', className)}\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n >\n <div className=\"web5-prompt-progress__indicator\" aria-hidden=\"true\">\n <ArrowDownIcon />\n </div>\n <div className=\"web5-prompt-progress__message\">{progressMessage}</div>\n </div>\n );\n }\n\n const canSubmit = inputValue.trim().length > 0 || canSubmitEmpty;\n const chipsMarkup =\n chips.length > 0 ? (\n <div\n className={cn(\n 'web5-prompt-shell__chips',\n chipPosition === 'bottom'\n ? 'web5-prompt-shell__chips--bottom'\n : 'web5-prompt-shell__chips--top',\n showChips\n ? 'web5-prompt-shell__chips--visible'\n : 'web5-prompt-shell__chips--hidden',\n )}\n aria-hidden={isCollapsed || !showChips}\n >\n {chips.map((chip) => (\n <a\n key={chip.label}\n href={isWeb5Url(chip.href) ? '#' : chip.href}\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => {\n e.preventDefault();\n onChipClick?.(e, chip.href);\n setInputValue('');\n inputRef.current?.blur();\n }}\n tabIndex={!isCollapsed && showChips ? 0 : -1}\n // `has-custom-focus` opts out of Wix Thunderbolt's global keyboard focus ring\n // so our inset :focus-visible ring isn't overwritten when embedded in a Wix site.\n className=\"web5-prompt-chip has-custom-focus\"\n >\n {chip.label}\n <PromptSendIcon\n aria-hidden=\"true\"\n className=\"web5-prompt-send-icon\"\n />\n </a>\n ))}\n </div>\n ) : null;\n\n const handleExpandClick = () => {\n focusInput();\n };\n\n\n return (\n <div\n className={cn(\n 'web5-prompt-shell',\n isCollapsed && 'web5-prompt-shell--collapsed',\n // Widens the pill while the field or a chip holds focus. Driven by\n // `hasFocusInside` rather than `isFocused` so clicking a chip (which\n // preventDefaults its mousedown) doesn't collapse the width mid-click.\n hasFocusInside && !isCollapsed && 'web5-prompt-shell--focused',\n className,\n )}\n >\n <div className=\"web5-prompt-shell__stage\">\n <button\n type=\"button\"\n className=\"web5-prompt-shell__collapsed-button has-custom-focus\"\n onClick={handleExpandClick}\n aria-label={effectiveCollapsedLabel}\n aria-hidden={!isCollapsed}\n tabIndex={isCollapsed ? 0 : -1}\n >\n {effectiveCollapsedLabel}\n </button>\n\n <div\n className=\"web5-prompt-shell__content\"\n aria-hidden={isCollapsed}\n onFocus={handleContentFocus}\n onBlur={handleContentBlur}\n >\n {contextBanner}\n <div className=\"web5-prompt-shell__panel\">\n <div\n className={cn(\n 'web5-prompt-shell__stack',\n chipPosition === 'top' && 'web5-prompt-shell__stack--chips-top',\n )}\n >\n <div className=\"web5-prompt-search\" role=\"search\">\n <div className=\"web5-prompt-search__inner\">\n <div\n className={cn(\n 'web5-prompt-field',\n isFocused && 'web5-prompt-field--focused',\n isMultiline && 'web5-prompt-field--multiline',\n )}\n >\n <textarea\n ref={inputRef}\n rows={1}\n value={inputValue}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={handleInputFocus}\n onBlur={() => setIsFocused(false)}\n placeholder={placeholder}\n aria-label=\"Search or ask a question\"\n aria-keyshortcuts=\"/ Control+K\"\n className=\"web5-prompt-input has-custom-focus placeholder:text-search-input-hint\"\n tabIndex={isCollapsed ? -1 : undefined}\n />\n\n <div className=\"web5-prompt-actions\">\n {onVoiceInput && (\n <button\n type=\"button\"\n onClick={onVoiceInput}\n className=\"web5-prompt-voice\"\n aria-label=\"Voice input\"\n tabIndex={isCollapsed ? -1 : undefined}\n >\n <MicrophoneIcon />\n </button>\n )}\n <button\n type=\"button\"\n onClick={handleSubmit}\n className={cn(\n 'web5-prompt-submit',\n submitLabel && 'web5-prompt-submit--labeled',\n canSubmit && 'web5-prompt-submit--active',\n )}\n aria-label={submitLabel ?? 'Submit'}\n disabled={!canSubmit || isCollapsed}\n tabIndex={isCollapsed ? -1 : undefined}\n >\n {submitLabel ? (\n <>\n <span className=\"web5-prompt-submit__label\">\n {submitLabel}\n </span>\n <ArrowRightIcon\n aria-hidden=\"true\"\n className=\"web5-prompt-send-icon\"\n />\n </>\n ) : (\n <PromptSendIcon\n aria-hidden=\"true\"\n className=\"web5-prompt-send-icon\"\n />\n )}\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {chipsMarkup}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n});\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["React","forwardRef","useEffect","useImperativeHandle","useState","useRef","useCallback","useLayoutEffect","cn","DEFAULT_PROMPT_PLACEHOLDER","resolveAssistantPlaceholder","isWeb5Url","UNBRANDED_PLACEHOLDER","ArrowDownIcon","createElement","xmlns","width","height","viewBox","fill","stroke","strokeWidth","strokeLinecap","strokeLinejoin","d","MicrophoneIcon","props","_extends","ArrowRightIcon","PromptSendIcon","SearchSection","_ref","ref","onSubmit","placeholder","submitLabel","collapsedLabel","onCollapsedChange","chips","chipDisplayMode","chipPosition","onVoiceInput","progressMessage","className","contextBanner","hasContext","canSubmitEmpty","hasContent","isBottomZoneVisible","onChipClick","onFocusChange","inputValue","setInputValue","isFocused","setIsFocused","hasFocusInside","setHasFocusInside","isMultiline","setIsMultiline","isCollapsed","setIsCollapsed","inputRef","hasExpandedWhileZoneVisibleRef","previouslyFocusedElementRef","showChips","length","effectiveCollapsedLabel","replace","handleSubmit","trimmedValue","trim","element","current","computedStyles","window","getComputedStyle","lineHeight","Number","parseFloat","hasValue","style","nextHeight","Math","min","max","scrollHeight","hasFocusInsideRef","onFocusChangeRef","focusInput","active","document","activeElement","HTMLElement","body","requestAnimationFrame","_inputRef$current","focus","_inputRef$current2","blurInput","_inputRef$current3","blur","handleKeyDown","e","key","_inputRef$current4","preventDefault","prev","shiftKey","handleInputChange","target","value","handleInputFocus","relatedTarget","handleContentFocus","handleContentBlur","next","currentTarget","contains","role","canSubmit","chipsMarkup","map","chip","label","href","onMouseDown","onClick","_inputRef$current5","tabIndex","handleExpandClick","type","onFocus","onBlur","rows","onChange","onKeyDown","undefined","disabled","Fragment"],"sources":["../../../../src/components/ui/SearchSection.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useState,\n useRef,\n useCallback,\n useLayoutEffect,\n} from 'react';\nimport { cn } from '../../lib/utils';\nimport {\n DEFAULT_PROMPT_PLACEHOLDER,\n resolveAssistantPlaceholder,\n} from '../../lib/assistant';\nimport { isWeb5Url } from '../../types/link-types';\n\n/**\n * Fallback for a bare `<SearchSection />` — the product default with no store\n * name to resolve against, so \"Ask AI...\". Hosts that know the store (the\n * full-page app, the embed widget) resolve the token themselves and pass the\n * branded string in; this only covers the component used on its own.\n */\nconst UNBRANDED_PLACEHOLDER = resolveAssistantPlaceholder(\n DEFAULT_PROMPT_PLACEHOLDER,\n);\n\nexport interface ScrollChip {\n label: string;\n href: string;\n iconHint?: string;\n}\n\nexport interface SearchSectionProps {\n onSubmit?: (value: string) => void;\n placeholder?: string;\n /**\n * When set, the submit control renders as a labeled CTA button (text +\n * right arrow) instead of the icon-only send button. Used by the empty\n * state (e.g. \"Find Your Pair\").\n */\n submitLabel?: string;\n collapsedLabel?: string;\n onCollapsedChange?: (isCollapsed: boolean) => void;\n chips?: ScrollChip[];\n chipDisplayMode?: 'focus' | 'always';\n chipPosition?: 'top' | 'bottom';\n onVoiceInput?: () => void;\n progressMessage?: string;\n className?: string;\n contextBanner?: React.ReactNode;\n hasContext?: boolean;\n canSubmitEmpty?: boolean;\n hasContent?: boolean;\n isBottomZoneVisible?: boolean;\n onChipClick?: (e: React.MouseEvent<HTMLAnchorElement>, href: string) => void;\n onFocusChange?: (focused: boolean) => void;\n}\n\nexport interface SearchSectionHandle {\n focusInput: () => void;\n blurInput: () => void;\n}\n\nconst ArrowDownIcon: React.FC = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 5v14\" />\n <path d=\"m19 12-7 7-7-7\" />\n </svg>\n);\n\nconst MicrophoneIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n stroke=\"none\"\n aria-hidden=\"true\"\n {...props}\n >\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path\n d=\"M19 10v2a7 7 0 0 1-14 0v-2M12 19v3\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n fill=\"none\"\n />\n </svg>\n);\n\nconst ArrowRightIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n {...props}\n >\n <path d=\"M5 12h14\" />\n <path d=\"m12 5 7 7-7 7\" />\n </svg>\n);\n\nconst PromptSendIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n aria-hidden=\"true\"\n {...props}\n >\n <path\n d=\"M13.0306 7.53114C12.9609 7.60106 12.8781 7.65654 12.787 7.69439C12.6958 7.73224 12.5981 7.75173 12.4993 7.75173C12.4006 7.75173 12.3029 7.73224 12.2117 7.69439C12.1206 7.65654 12.0378 7.60106 11.9681 7.53114L8.74997 4.31301V13.5005C8.74997 13.6994 8.67095 13.8902 8.5303 14.0308C8.38965 14.1715 8.19888 14.2505 7.99997 14.2505C7.80106 14.2505 7.61029 14.1715 7.46964 14.0308C7.32899 13.8902 7.24997 13.6994 7.24997 13.5005V4.31301L4.0306 7.53114C3.8897 7.67203 3.69861 7.75119 3.49935 7.75119C3.30009 7.75119 3.10899 7.67203 2.9681 7.53114C2.8272 7.39024 2.74805 7.19915 2.74805 6.99989C2.74805 6.80063 2.8272 6.60953 2.9681 6.46864L7.4681 1.96864C7.53778 1.89872 7.62057 1.84324 7.71173 1.80539C7.8029 1.76753 7.90064 1.74805 7.99935 1.74805C8.09806 1.74805 8.1958 1.76753 8.28696 1.80539C8.37813 1.84324 8.46092 1.89872 8.5306 1.96864L13.0306 6.46864C13.1005 6.53832 13.156 6.62111 13.1938 6.71227C13.2317 6.80344 13.2512 6.90118 13.2512 6.99989C13.2512 7.0986 13.2317 7.19634 13.1938 7.2875C13.156 7.37867 13.1005 7.46146 13.0306 7.53114Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\nexport const SearchSection = forwardRef<\n SearchSectionHandle,\n SearchSectionProps\n>(function SearchSection(\n {\n onSubmit,\n placeholder = UNBRANDED_PLACEHOLDER,\n submitLabel,\n collapsedLabel,\n onCollapsedChange,\n chips = [],\n chipDisplayMode = 'focus',\n chipPosition = 'top',\n onVoiceInput,\n progressMessage,\n className = '',\n contextBanner,\n hasContext,\n canSubmitEmpty = false,\n hasContent = false,\n isBottomZoneVisible = false,\n onChipClick,\n onFocusChange,\n },\n ref,\n) {\n const [inputValue, setInputValue] = useState('');\n const [isFocused, setIsFocused] = useState(false);\n const [hasFocusInside, setHasFocusInside] = useState(false);\n const [isMultiline, setIsMultiline] = useState(false);\n const [isCollapsed, setIsCollapsed] = useState(false);\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const hasExpandedWhileZoneVisibleRef = useRef(false);\n const previouslyFocusedElementRef = useRef<HTMLElement | null>(null);\n const showChips =\n chips.length > 0 &&\n !hasContext &&\n (chipDisplayMode === 'always' || hasFocusInside);\n const effectiveCollapsedLabel =\n collapsedLabel ?? placeholder.replace(/\\.\\.\\.$/, '');\n\n const handleSubmit = useCallback(() => {\n const trimmedValue = inputValue.trim();\n if (trimmedValue || canSubmitEmpty) {\n onSubmit?.(trimmedValue);\n setInputValue('');\n }\n }, [canSubmitEmpty, inputValue, onSubmit]);\n\n useLayoutEffect(() => {\n const element = inputRef.current;\n if (!element) {\n return;\n }\n\n const computedStyles = window.getComputedStyle(element);\n const lineHeight = Number.parseFloat(computedStyles.lineHeight) || 32;\n\n const hasValue = inputValue.trim().length > 0;\n element.style.height = 'auto';\n const nextHeight = hasValue\n ? Math.min(Math.max(element.scrollHeight, lineHeight), 175)\n : lineHeight;\n element.style.height = `${nextHeight}px`;\n setIsMultiline(hasValue && nextHeight > lineHeight);\n }, [inputValue]);\n\n useEffect(() => {\n if (progressMessage || !hasContent) {\n setIsCollapsed(false);\n hasExpandedWhileZoneVisibleRef.current = false;\n return;\n }\n\n if (!isBottomZoneVisible) {\n hasExpandedWhileZoneVisibleRef.current = false;\n setIsCollapsed(false);\n return;\n }\n\n if (!hasExpandedWhileZoneVisibleRef.current) {\n setIsCollapsed(true);\n }\n }, [hasContent, isBottomZoneVisible, progressMessage]);\n\n useEffect(() => {\n onCollapsedChange?.(isCollapsed);\n }, [isCollapsed, onCollapsedChange]);\n\n const hasFocusInsideRef = useRef(hasFocusInside);\n hasFocusInsideRef.current = hasFocusInside;\n const onFocusChangeRef = useRef(onFocusChange);\n onFocusChangeRef.current = onFocusChange;\n\n useEffect(() => {\n onFocusChange?.(hasFocusInside);\n }, [hasFocusInside, onFocusChange]);\n\n useEffect(() => {\n return () => {\n if (hasFocusInsideRef.current) {\n onFocusChangeRef.current?.(false);\n }\n };\n }, []);\n\n const focusInput = useCallback(() => {\n const active = document.activeElement;\n if (\n active instanceof HTMLElement &&\n active !== inputRef.current &&\n active !== document.body\n ) {\n previouslyFocusedElementRef.current = active;\n }\n if (isCollapsed) {\n hasExpandedWhileZoneVisibleRef.current = true;\n setIsCollapsed(false);\n window.requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n } else {\n inputRef.current?.focus();\n }\n }, [isCollapsed]);\n\n const blurInput = useCallback(() => {\n inputRef.current?.blur();\n }, []);\n\n useImperativeHandle(ref, () => ({ focusInput, blurInput }), [\n focusInput,\n blurInput,\n ]);\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n const prev = previouslyFocusedElementRef.current;\n previouslyFocusedElementRef.current = null;\n inputRef.current?.blur();\n prev?.focus?.();\n return;\n }\n if (\n e.key === 'Enter' &&\n !e.shiftKey &&\n (inputValue.trim() || canSubmitEmpty)\n ) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setInputValue(e.target.value);\n };\n\n const handleInputFocus = (e: React.FocusEvent<HTMLTextAreaElement>) => {\n setIsFocused(true);\n if (\n e.relatedTarget instanceof HTMLElement &&\n e.relatedTarget !== inputRef.current\n ) {\n previouslyFocusedElementRef.current = e.relatedTarget;\n }\n };\n\n const handleContentFocus = () => {\n setHasFocusInside(true);\n };\n\n const handleContentBlur = (e: React.FocusEvent<HTMLDivElement>) => {\n const next = e.relatedTarget as Node | null;\n if (!next || !e.currentTarget.contains(next)) {\n setHasFocusInside(false);\n }\n };\n\n if (progressMessage) {\n return (\n <div\n className={cn('web5-prompt-progress', className)}\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n >\n <div className=\"web5-prompt-progress__indicator\" aria-hidden=\"true\">\n <ArrowDownIcon />\n </div>\n <div className=\"web5-prompt-progress__message\">{progressMessage}</div>\n </div>\n );\n }\n\n const canSubmit = inputValue.trim().length > 0 || canSubmitEmpty;\n const chipsMarkup =\n chips.length > 0 ? (\n <div\n className={cn(\n 'web5-prompt-shell__chips',\n chipPosition === 'bottom'\n ? 'web5-prompt-shell__chips--bottom'\n : 'web5-prompt-shell__chips--top',\n showChips\n ? 'web5-prompt-shell__chips--visible'\n : 'web5-prompt-shell__chips--hidden',\n )}\n aria-hidden={isCollapsed || !showChips}\n >\n {chips.map((chip) => (\n <a\n key={chip.label}\n href={isWeb5Url(chip.href) ? '#' : chip.href}\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => {\n e.preventDefault();\n onChipClick?.(e, chip.href);\n setInputValue('');\n inputRef.current?.blur();\n }}\n tabIndex={!isCollapsed && showChips ? 0 : -1}\n // `has-custom-focus` opts out of Wix Thunderbolt's global keyboard focus ring\n // so our inset :focus-visible ring isn't overwritten when embedded in a Wix site.\n className=\"web5-prompt-chip has-custom-focus\"\n >\n {chip.label}\n <PromptSendIcon\n aria-hidden=\"true\"\n className=\"web5-prompt-send-icon\"\n />\n </a>\n ))}\n </div>\n ) : null;\n\n const handleExpandClick = () => {\n focusInput();\n };\n\n\n return (\n <div\n className={cn(\n 'web5-prompt-shell',\n isCollapsed && 'web5-prompt-shell--collapsed',\n // Widens the pill while the field or a chip holds focus. Driven by\n // `hasFocusInside` rather than `isFocused` so clicking a chip (which\n // preventDefaults its mousedown) doesn't collapse the width mid-click.\n hasFocusInside && !isCollapsed && 'web5-prompt-shell--focused',\n className,\n )}\n >\n <div className=\"web5-prompt-shell__stage\">\n <button\n type=\"button\"\n className=\"web5-prompt-shell__collapsed-button has-custom-focus\"\n onClick={handleExpandClick}\n aria-label={effectiveCollapsedLabel}\n aria-hidden={!isCollapsed}\n tabIndex={isCollapsed ? 0 : -1}\n >\n {effectiveCollapsedLabel}\n </button>\n\n <div\n className=\"web5-prompt-shell__content\"\n aria-hidden={isCollapsed}\n onFocus={handleContentFocus}\n onBlur={handleContentBlur}\n >\n {contextBanner}\n <div className=\"web5-prompt-shell__panel\">\n <div\n className={cn(\n 'web5-prompt-shell__stack',\n chipPosition === 'top' && 'web5-prompt-shell__stack--chips-top',\n )}\n >\n <div className=\"web5-prompt-search\" role=\"search\">\n <div className=\"web5-prompt-search__inner\">\n <div\n className={cn(\n 'web5-prompt-field',\n isFocused && 'web5-prompt-field--focused',\n isMultiline && 'web5-prompt-field--multiline',\n )}\n >\n <textarea\n ref={inputRef}\n rows={1}\n value={inputValue}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={handleInputFocus}\n onBlur={() => setIsFocused(false)}\n placeholder={placeholder}\n aria-label=\"Search or ask a question\"\n aria-keyshortcuts=\"/ Control+K\"\n className=\"web5-prompt-input has-custom-focus placeholder:text-search-input-hint\"\n tabIndex={isCollapsed ? -1 : undefined}\n />\n\n <div className=\"web5-prompt-actions\">\n {onVoiceInput && (\n <button\n type=\"button\"\n onClick={onVoiceInput}\n className=\"web5-prompt-voice\"\n aria-label=\"Voice input\"\n tabIndex={isCollapsed ? -1 : undefined}\n >\n <MicrophoneIcon />\n </button>\n )}\n <button\n type=\"button\"\n onClick={handleSubmit}\n className={cn(\n 'web5-prompt-submit',\n submitLabel && 'web5-prompt-submit--labeled',\n canSubmit && 'web5-prompt-submit--active',\n )}\n aria-label={submitLabel ?? 'Submit'}\n disabled={!canSubmit || isCollapsed}\n tabIndex={isCollapsed ? -1 : undefined}\n >\n {submitLabel ? (\n <>\n <span className=\"web5-prompt-submit__label\">\n {submitLabel}\n </span>\n <ArrowRightIcon\n aria-hidden=\"true\"\n className=\"web5-prompt-send-icon\"\n />\n </>\n ) : (\n <PromptSendIcon\n aria-hidden=\"true\"\n className=\"web5-prompt-send-icon\"\n />\n )}\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {chipsMarkup}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n});\n"],"mappings":"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","ignoreList":[]}
|
package/dist/esm/index.js
CHANGED
|
@@ -118,7 +118,8 @@ export { PRODUCT_BACK_SESSION_KEY, writeProductBackHandoff, readProductBackHando
|
|
|
118
118
|
export { PromptEntryEmptyState } from './components/ui/PromptEntryEmptyState.js';
|
|
119
119
|
export { SearchSection } from './components/ui/SearchSection.js';
|
|
120
120
|
export { FeedbackBar } from './components/ui/FeedbackBar.js';
|
|
121
|
-
export { AiDisclosure,
|
|
121
|
+
export { AiDisclosure, DEFAULT_AI_DISCLOSURE_TEXT } from './components/ui/AiDisclosure.js';
|
|
122
|
+
export { ASSISTANT_TOKEN, UNBRANDED_ASSISTANT_NAME, DEFAULT_PROMPT_PLACEHOLDER, assistantName, resolveAssistantPlaceholder } from './lib/assistant.js';
|
|
122
123
|
export { AiIcon } from './components/ui/icons/AiIcon.js';
|
|
123
124
|
export { PoweredByBadge, DEFAULT_POWERED_BY_HREF } from './components/ui/PoweredByBadge.js';
|
|
124
125
|
export { BottomContainer } from './components/ui/BottomContainer.js';
|
|
@@ -160,7 +161,8 @@ export { getClientBundleOverride, isTrustedBundleHost } from './client/clientBun
|
|
|
160
161
|
export { TEMPLATES_CDN_BASE, TEMPLATES_MANIFEST_URL, getTemplateOverride, isTemplatePickerRequested, isValidTemplateId, resolveClientBundleUrl } from './client/clientBundleUrl.js';
|
|
161
162
|
export { mergeClientConfig } from './client/mergeClientConfig.js';
|
|
162
163
|
export { applyThemeOverrides, THEME_OVERRIDE_TOKENS } from './client/applyThemeOverrides.js';
|
|
163
|
-
export { THEME_TOKEN_CONTRACT, BRAND_TOKENS, EDITABLE_TOKENS, TOKEN_NAME_PATTERN, bucketOf, hostAliasFor } from './theme/tokenContract.js';
|
|
164
|
+
export { THEME_TOKEN_CONTRACT, BRAND_TOKENS, EDITABLE_TOKENS, TOKEN_NAME_PATTERN, THEME_OVERRIDE_KEY_PATTERN, bucketOf, hostAliasFor } from './theme/tokenContract.js';
|
|
165
|
+
export { SCHEME_COLOR_TOKENS, MAX_THEME_SCHEMES, SCHEME_ANCHOR_TOKENS, completeScheme, isThemeScheme, isSchemeTokenEntry, nextOwnerSchemeId, resolveActiveScheme, schemeDisplayName } from './theme/themeScheme.js';
|
|
164
166
|
export { isThemeDebugEnabled, THEME_DEBUG_KEY, THEME_DEBUG_QUERY_PARAM } from './client/themeDebug.js';
|
|
165
167
|
export { hexToHslTriplet, hslTripletToHex, isHslTriplet } from './theme/colorFormat.js';
|
|
166
168
|
|