@adea-ai/ui 0.124.0 → 0.125.0
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/NOTICE +18 -0
- package/dist/components/theme/theme-document.d.ts +6 -0
- package/dist/components/theme/theme-document.d.ts.map +1 -1
- package/dist/components/theme/theme-document.js +7 -2
- package/dist/components/theme/theme-document.js.map +1 -1
- package/dist/components/theme/theme-persistence.d.ts.map +1 -1
- package/dist/components/theme/theme-persistence.js +2 -1
- package/dist/components/theme/theme-persistence.js.map +1 -1
- package/dist/components/theme/theme-provider.d.ts +9 -0
- package/dist/components/theme/theme-provider.d.ts.map +1 -1
- package/dist/components/theme/theme-provider.js +13 -3
- package/dist/components/theme/theme-provider.js.map +1 -1
- package/dist/components/theme/theme-state.d.ts +27 -2
- package/dist/components/theme/theme-state.d.ts.map +1 -1
- package/dist/components/theme/theme-state.js +20 -2
- package/dist/components/theme/theme-state.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/lib/accent-roles.d.ts +124 -0
- package/dist/lib/accent-roles.d.ts.map +1 -0
- package/dist/lib/accent-roles.js +163 -0
- package/dist/lib/accent-roles.js.map +1 -0
- package/dist/lib/themes.d.ts +23 -1
- package/dist/lib/themes.d.ts.map +1 -1
- package/dist/lib/themes.js +23 -13
- package/dist/lib/themes.js.map +1 -1
- package/dist/r/lib.json +5 -0
- package/dist/r/registry.json +5 -0
- package/dist/r/src/components/theme/theme-document.ts +18 -2
- package/dist/r/src/components/theme/theme-persistence.ts +5 -2
- package/dist/r/src/components/theme/theme-provider.tsx +22 -1
- package/dist/r/src/components/theme/theme-state.ts +52 -3
- package/dist/r/src/lib/accent-roles.ts +338 -0
- package/dist/r/src/lib/themes.ts +44 -19
- package/package.json +1 -1
- package/registry.json +5 -0
- package/src/components/theme/theme-document.ts +18 -2
- package/src/components/theme/theme-persistence.ts +5 -2
- package/src/components/theme/theme-provider.tsx +22 -1
- package/src/components/theme/theme-state.ts +52 -3
- package/src/index.ts +8 -0
- package/src/lib/accent-roles.ts +338 -0
- package/src/lib/themes.ts +44 -19
package/dist/NOTICE
CHANGED
|
@@ -318,6 +318,24 @@ Zeron" above, applies to the translated portion. The ThemeProvider's preview,
|
|
|
318
318
|
persistence and document-application seams are written against Adea's provider
|
|
319
319
|
contract and introduce no further upstream source.
|
|
320
320
|
|
|
321
|
+
## Accent roles and colour helpers translated from Zeron
|
|
322
|
+
|
|
323
|
+
`packages/ui/src/lib/accent-roles.ts` translates Zeron's `Color` helpers and
|
|
324
|
+
`AccentRoles` derivation (https://github.com/zeronsh/zeron), as Adea's accepted
|
|
325
|
+
port of them in `packages/ui/src/components/appearance.ts` expresses it: the hex
|
|
326
|
+
parser and serialiser, the alpha-compositing contrast measure, the contrast
|
|
327
|
+
repair that raises a colour to a floor, the 3:1 interaction
|
|
328
|
+
gate applied to a custom accent, and the per-element paint of an accent's roles.
|
|
329
|
+
The colour engine, the preset values and the role derivation they feed remain
|
|
330
|
+
`@adea-ai/themes`'; the `#rrggbb` selection grammar and the use of the gate in the
|
|
331
|
+
provider are Adea behaviour that port retains.
|
|
332
|
+
|
|
333
|
+
Copyright (c) 2026 Wing
|
|
334
|
+
Licensed under the MIT License.
|
|
335
|
+
|
|
336
|
+
Zeron's MIT notice, reproduced in full under "Appearance editor translated from
|
|
337
|
+
Zeron" above, applies to the translated portion.
|
|
338
|
+
|
|
321
339
|
## Strict binary layout extracted from the accepted Adea donor port
|
|
322
340
|
|
|
323
341
|
`packages/ui/src/components/layout/split-layout/model.ts` is extracted from
|
|
@@ -20,6 +20,12 @@ export type ThemeDocumentOptions = {
|
|
|
20
20
|
* must return the full map; a name it drops is not written.
|
|
21
21
|
*/
|
|
22
22
|
transformTokens?: (tokens: Record<string, string>) => Record<string, string>;
|
|
23
|
+
/**
|
|
24
|
+
* The contrast an accent is held to against the variant's background. Absent, a
|
|
25
|
+
* preset is painted verbatim (the catalogue measured it for its own themes) and
|
|
26
|
+
* only a custom `#rrggbb` is held to the default floor of 3:1.
|
|
27
|
+
*/
|
|
28
|
+
accentContrastFloor?: number;
|
|
23
29
|
};
|
|
24
30
|
/**
|
|
25
31
|
* The custom properties a state paints: the variant's roles, with the accent
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-document.d.ts","sourceRoot":"","sources":["../../../src/components/theme/theme-document.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"theme-document.d.ts","sourceRoot":"","sources":["../../../src/components/theme/theme-document.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AAEpE;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,IAAI,CAC1B,WAAW,EACX,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,iBAAiB,GAAG,cAAc,CACvE,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,mFAAmF;IACnF,SAAS,EAAE,cAAc,CAAA;IACzB,UAAU,EAAE,eAAe,CAAA;IAC3B,OAAO,EAAE,YAAY,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5E;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,kBAAkB,EACzB,OAAO,GAAE,oBAAyB,GACjC;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAYvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,kBAAkB,EACzB,OAAO,GAAE,oBAAyB,EAClC,QAAQ,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAC7B,WAAW,CAAC,MAAM,CAAC,CAsCrB;AAED,gEAAgE;AAChE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE;QAAE,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;KAAE,CAAA;IAC7C,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG;QAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;QAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,MAAM,IAAI,IAAI,CAAA;KACf,CAAA;CACF,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,kBAAkB,EACvB,KAAK,EAAE,MAAM,IAAI,EACjB,QAAQ,GAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAsB,GACzD,MAAM,IAAI,CAqBZ"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isCustomAccent } from "../../lib/accent-roles.js";
|
|
1
2
|
import { accentVariables, themeCssVariables } from "../../lib/themes.js";
|
|
2
3
|
import { applyAppearanceFontSettings, normalizeAppearanceEditorFontSettings } from "../../lib/appearance-font-settings.js";
|
|
3
4
|
import { resolvedDensity } from "./theme-state.js";
|
|
@@ -15,7 +16,11 @@ import { resolvedDensity } from "./theme-state.js";
|
|
|
15
16
|
*/
|
|
16
17
|
function themeDocumentTokens(state, options = {}) {
|
|
17
18
|
const properties = { ...themeCssVariables(state.variant) };
|
|
18
|
-
const accent = accentVariables(state.selection.accent, state.appearance, state.selection
|
|
19
|
+
const accent = accentVariables(state.selection.accent, state.appearance, state.selection, {
|
|
20
|
+
background: state.variant.colors.background,
|
|
21
|
+
floor: options.accentContrastFloor,
|
|
22
|
+
variantId: state.variant.id
|
|
23
|
+
});
|
|
19
24
|
if (accent) Object.assign(properties, accent);
|
|
20
25
|
return {
|
|
21
26
|
tokens: options.transformTokens ? options.transformTokens(properties) : properties,
|
|
@@ -42,7 +47,7 @@ function applyThemeToRoot(root, state, options = {}, previous) {
|
|
|
42
47
|
root.dataset["appearance"] = state.appearance;
|
|
43
48
|
root.style.colorScheme = state.appearance;
|
|
44
49
|
if (!accented) root.removeAttribute("data-accent");
|
|
45
|
-
else root.dataset["accent"] = state.selection.accent;
|
|
50
|
+
else root.dataset["accent"] = isCustomAccent(state.selection.accent) ? "custom" : state.selection.accent;
|
|
46
51
|
applyAppearanceFontSettings(root, normalizeAppearanceEditorFontSettings(state.selection.fonts, state.selection.font).settings);
|
|
47
52
|
if (resolvedDensity(state.selection) === "comfortable") root.removeAttribute("data-density");
|
|
48
53
|
else root.dataset["density"] = resolvedDensity(state.selection);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-document.js","names":[],"sources":["../../../src/components/theme/theme-document.ts"],"sourcesContent":["import {\n applyAppearanceFontSettings,\n normalizeAppearanceEditorFontSettings,\n} from '#lib/appearance-font-settings'\nimport {\n accentVariables,\n themeCssVariables,\n type ThemeAppearance,\n type ThemeVariant,\n} from '#lib/themes'\nimport { resolvedDensity, type ThemeSelection } from './theme-state'\n\n/**\n * The document half of the theme provider: the single writer of `<html>`.\n *\n * Written against the few members of an element it uses, so the rules can be tested\n * on a stand-in and the provider's effect stays a one-line call.\n */\nexport type ThemeRoot = Pick<\n HTMLElement,\n 'classList' | 'dataset' | 'style' | 'removeAttribute' | 'setAttribute'\n>\n\nexport type ThemeDocumentState = {\n /** What the document shows: the committed selection, or a preview laid over it. */\n selection: ThemeSelection\n appearance: ThemeAppearance\n variant: ThemeVariant\n}\n\nexport type ThemeDocumentOptions = {\n /**\n * Rewrites the custom properties just before they are written: the variant's\n * roles with the accent laid over them. It sees every property of the pass and\n * must return the full map; a name it drops is not written.\n */\n transformTokens?: (tokens: Record<string, string>) => Record<string, string>\n}\n\n/**\n * The custom properties a state paints: the variant's roles, with the accent\n * selection laid over them, then `transformTokens`.\n *\n * The accent is applied *here* rather than left to the `[data-accent]` blocks in\n * `theme.css`, because the properties are written inline and an inline declaration\n * outranks every stylesheet selector however specific it is. The blocks still exist\n * and are still correct — they are what styles the window before this runs — but\n * they cannot win from here, so leaving the accent to them meant the attribute was\n * set, the rules were present, and nothing changed on screen.\n */\nexport function themeDocumentTokens(\n state: ThemeDocumentState,\n options: ThemeDocumentOptions = {}\n): { tokens: Record<string, string>; accented: boolean } {\n const properties = { ...themeCssVariables(state.variant) }\n const accent = accentVariables(state.selection.accent, state.appearance, state.selection)\n if (accent) Object.assign(properties, accent)\n return {\n tokens: options.transformTokens ? options.transformTokens(properties) : properties,\n accented: accent !== undefined,\n }\n}\n\n/**\n * Write a state onto a root and report which custom properties it owns.\n *\n * Pass the previous call's return as `previous` and any palette property that pass\n * wrote and this one does not is removed. For the catalogue the two sets are the\n * same, so nothing is ever removed; it matters for a host variant that carries\n * `tokens` the catalogue does not, which would otherwise stay inline, beating the\n * stylesheet, after the user switched away from it.\n */\nexport function applyThemeToRoot(\n root: ThemeRoot,\n state: ThemeDocumentState,\n options: ThemeDocumentOptions = {},\n previous?: ReadonlySet<string>\n): ReadonlySet<string> {\n const { tokens, accented } = themeDocumentTokens(state, options)\n\n for (const [name, value] of Object.entries(tokens)) {\n root.style.setProperty(name, value)\n }\n if (previous) {\n for (const name of previous) {\n if (!(name in tokens)) root.style.removeProperty(name)\n }\n }\n\n root.classList.toggle('dark', state.appearance === 'dark')\n root.dataset['theme'] = state.variant.id\n root.dataset['appearance'] = state.appearance\n root.style.colorScheme = state.appearance\n\n if (!accented) root.removeAttribute('data-accent')\n else
|
|
1
|
+
{"version":3,"file":"theme-document.js","names":[],"sources":["../../../src/components/theme/theme-document.ts"],"sourcesContent":["import {\n applyAppearanceFontSettings,\n normalizeAppearanceEditorFontSettings,\n} from '#lib/appearance-font-settings'\nimport {\n accentVariables,\n themeCssVariables,\n type ThemeAppearance,\n type ThemeVariant,\n} from '#lib/themes'\nimport { isCustomAccent } from '#lib/accent-roles'\nimport { resolvedDensity, type ThemeSelection } from './theme-state'\n\n/**\n * The document half of the theme provider: the single writer of `<html>`.\n *\n * Written against the few members of an element it uses, so the rules can be tested\n * on a stand-in and the provider's effect stays a one-line call.\n */\nexport type ThemeRoot = Pick<\n HTMLElement,\n 'classList' | 'dataset' | 'style' | 'removeAttribute' | 'setAttribute'\n>\n\nexport type ThemeDocumentState = {\n /** What the document shows: the committed selection, or a preview laid over it. */\n selection: ThemeSelection\n appearance: ThemeAppearance\n variant: ThemeVariant\n}\n\nexport type ThemeDocumentOptions = {\n /**\n * Rewrites the custom properties just before they are written: the variant's\n * roles with the accent laid over them. It sees every property of the pass and\n * must return the full map; a name it drops is not written.\n */\n transformTokens?: (tokens: Record<string, string>) => Record<string, string>\n /**\n * The contrast an accent is held to against the variant's background. Absent, a\n * preset is painted verbatim (the catalogue measured it for its own themes) and\n * only a custom `#rrggbb` is held to the default floor of 3:1.\n */\n accentContrastFloor?: number\n}\n\n/**\n * The custom properties a state paints: the variant's roles, with the accent\n * selection laid over them, then `transformTokens`.\n *\n * The accent is applied *here* rather than left to the `[data-accent]` blocks in\n * `theme.css`, because the properties are written inline and an inline declaration\n * outranks every stylesheet selector however specific it is. The blocks still exist\n * and are still correct — they are what styles the window before this runs — but\n * they cannot win from here, so leaving the accent to them meant the attribute was\n * set, the rules were present, and nothing changed on screen.\n */\nexport function themeDocumentTokens(\n state: ThemeDocumentState,\n options: ThemeDocumentOptions = {}\n): { tokens: Record<string, string>; accented: boolean } {\n const properties = { ...themeCssVariables(state.variant) }\n const accent = accentVariables(state.selection.accent, state.appearance, state.selection, {\n background: state.variant.colors.background,\n floor: options.accentContrastFloor,\n variantId: state.variant.id,\n })\n if (accent) Object.assign(properties, accent)\n return {\n tokens: options.transformTokens ? options.transformTokens(properties) : properties,\n accented: accent !== undefined,\n }\n}\n\n/**\n * Write a state onto a root and report which custom properties it owns.\n *\n * Pass the previous call's return as `previous` and any palette property that pass\n * wrote and this one does not is removed. For the catalogue the two sets are the\n * same, so nothing is ever removed; it matters for a host variant that carries\n * `tokens` the catalogue does not, which would otherwise stay inline, beating the\n * stylesheet, after the user switched away from it.\n */\nexport function applyThemeToRoot(\n root: ThemeRoot,\n state: ThemeDocumentState,\n options: ThemeDocumentOptions = {},\n previous?: ReadonlySet<string>\n): ReadonlySet<string> {\n const { tokens, accented } = themeDocumentTokens(state, options)\n\n for (const [name, value] of Object.entries(tokens)) {\n root.style.setProperty(name, value)\n }\n if (previous) {\n for (const name of previous) {\n if (!(name in tokens)) root.style.removeProperty(name)\n }\n }\n\n root.classList.toggle('dark', state.appearance === 'dark')\n root.dataset['theme'] = state.variant.id\n root.dataset['appearance'] = state.appearance\n root.style.colorScheme = state.appearance\n\n // A custom colour has no stylesheet block to select, and its value is the\n // attribute's worst possible content, so it is reported as `custom`.\n if (!accented) root.removeAttribute('data-accent')\n else\n root.dataset['accent'] = isCustomAccent(state.selection.accent)\n ? 'custom'\n : state.selection.accent\n\n applyAppearanceFontSettings(\n root,\n normalizeAppearanceEditorFontSettings(state.selection.fonts, state.selection.font).settings\n )\n\n // Density is a pure token shift, so unlike the colour axes there is nothing to\n // compute: the attribute selects a block in `theme.css`. It is applied here for\n // the same reason as the others — this is the one place that knows what the\n // current selection is, and it is the only writer of these attributes.\n if (resolvedDensity(state.selection) === 'comfortable') root.removeAttribute('data-density')\n else root.dataset['density'] = resolvedDensity(state.selection)\n\n return new Set(Object.keys(tokens))\n}\n\n/** What {@link applyWithoutTransitions} needs of a document. */\nexport type TransitionDocument = {\n head: { appendChild(node: unknown): unknown }\n createElement(tag: 'style'): {\n textContent: string | null\n offsetHeight?: number\n remove(): void\n }\n}\n\n/**\n * Run `apply` with every CSS transition switched off for the frame that carries\n * it, so a theme switch cannot animate page-wide.\n *\n * Without this, flipping the custom properties on `<html>` starts a transition on\n * every element that declares one, and each fades from the old palette to the new\n * over its own duration: a theme change that looks like a rendering fault. The\n * rule is removed two frames later, after the browser has committed the new styles\n * with transitions off, and `restore` runs it early (the provider calls it when it\n * is disposed mid-switch).\n *\n * `schedule` is the frame source; it defaults to `requestAnimationFrame` and falls\n * back to running at once where there is none, which leaves transitions on rather\n * than off.\n */\nexport function applyWithoutTransitions(\n doc: TransitionDocument,\n apply: () => void,\n schedule: (callback: () => void) => void = defaultSchedule\n): () => void {\n const style = doc.createElement('style')\n style.textContent = '*{transition:none !important}'\n doc.head.appendChild(style)\n // Reading a layout property forces the browser to commit the rule before the\n // properties change; without it the two can be batched into one style recalc.\n void style.offsetHeight\n let removed = false\n const restore = () => {\n if (removed) return\n removed = true\n style.remove()\n }\n try {\n apply()\n } catch (error) {\n restore()\n throw error\n }\n schedule(() => schedule(restore))\n return restore\n}\n\nfunction defaultSchedule(callback: () => void): void {\n if (typeof requestAnimationFrame === 'function') requestAnimationFrame(callback)\n else callback()\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyDA,SAAgB,oBACd,OACA,UAAgC,CAAC,GACsB;CACvD,MAAM,aAAa,EAAE,GAAG,kBAAkB,MAAM,OAAO,EAAE;CACzD,MAAM,SAAS,gBAAgB,MAAM,UAAU,QAAQ,MAAM,YAAY,MAAM,WAAW;EACxF,YAAY,MAAM,QAAQ,OAAO;EACjC,OAAO,QAAQ;EACf,WAAW,MAAM,QAAQ;CAC3B,CAAC;CACD,IAAI,QAAQ,OAAO,OAAO,YAAY,MAAM;CAC5C,OAAO;EACL,QAAQ,QAAQ,kBAAkB,QAAQ,gBAAgB,UAAU,IAAI;EACxE,UAAU,WAAW,KAAA;CACvB;AACF;;;;;;;;;;AAWA,SAAgB,iBACd,MACA,OACA,UAAgC,CAAC,GACjC,UACqB;CACrB,MAAM,EAAE,QAAQ,aAAa,oBAAoB,OAAO,OAAO;CAE/D,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,GAC/C,KAAK,MAAM,YAAY,MAAM,KAAK;CAEpC,IAAI,UACG;OAAA,MAAM,QAAQ,UACjB,IAAI,EAAE,QAAQ,SAAS,KAAK,MAAM,eAAe,IAAI;CAAA;CAIzD,KAAK,UAAU,OAAO,QAAQ,MAAM,eAAe,MAAM;CACzD,KAAK,QAAQ,WAAW,MAAM,QAAQ;CACtC,KAAK,QAAQ,gBAAgB,MAAM;CACnC,KAAK,MAAM,cAAc,MAAM;CAI/B,IAAI,CAAC,UAAU,KAAK,gBAAgB,aAAa;MAE/C,KAAK,QAAQ,YAAY,eAAe,MAAM,UAAU,MAAM,IAC1D,WACA,MAAM,UAAU;CAEtB,4BACE,MACA,sCAAsC,MAAM,UAAU,OAAO,MAAM,UAAU,IAAI,CAAC,CAAC,QACrF;CAMA,IAAI,gBAAgB,MAAM,SAAS,MAAM,eAAe,KAAK,gBAAgB,cAAc;MACtF,KAAK,QAAQ,aAAa,gBAAgB,MAAM,SAAS;CAE9D,OAAO,IAAI,IAAI,OAAO,KAAK,MAAM,CAAC;AACpC;;;;;;;;;;;;;;;;AA2BA,SAAgB,wBACd,KACA,OACA,WAA2C,iBAC/B;CACZ,MAAM,QAAQ,IAAI,cAAc,OAAO;CACvC,MAAM,cAAc;CACpB,IAAI,KAAK,YAAY,KAAK;CAG1B,MAAW;CACX,IAAI,UAAU;CACd,MAAM,gBAAgB;EACpB,IAAI,SAAS;EACb,UAAU;EACV,MAAM,OAAO;CACf;CACA,IAAI;EACF,MAAM;CACR,SAAS,OAAO;EACd,QAAQ;EACR,MAAM;CACR;CACA,eAAe,SAAS,OAAO,CAAC;CAChC,OAAO;AACT;AAEA,SAAS,gBAAgB,UAA4B;CACnD,IAAI,OAAO,0BAA0B,YAAY,sBAAsB,QAAQ;MAC1E,SAAS;AAChB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-persistence.d.ts","sourceRoot":"","sources":["../../../src/components/theme/theme-persistence.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"theme-persistence.d.ts","sourceRoot":"","sources":["../../../src/components/theme/theme-persistence.ts"],"names":[],"mappings":"AAIA,OAAO,EAA0C,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AAE3F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,IAAI,OAAO,CAAC,cAAc,CAAC,GAAG,SAAS,CAAA;IAC3C,KAAK,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAAA;CAClC,CAAA;AA8DD;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,gBAAgB,CAatF;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,SAAS,CAMhG;AAED,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,WAAW,EAAE,gBAAgB,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAOxF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { accentPresets } from "../../lib/tokens.js";
|
|
2
|
+
import { normalizeCustomAccent } from "../../lib/accent-roles.js";
|
|
2
3
|
import { isThemeAccentId } from "../../lib/theme-accents.js";
|
|
3
4
|
import { defaultDarkThemeId, defaultLightThemeId, themeById } from "../../lib/themes.js";
|
|
4
5
|
import { normalizeAppearanceEditorFontSettings } from "../../lib/appearance-font-settings.js";
|
|
@@ -27,7 +28,7 @@ function readSelection(storageKey) {
|
|
|
27
28
|
appearance: parsed.appearance === "light" || parsed.appearance === "dark" || parsed.appearance === "system" ? parsed.appearance : defaultThemeSelection.appearance,
|
|
28
29
|
lightThemeId: themeById(parsed.lightThemeId ?? "")?.appearance === "light" ? parsed.lightThemeId : defaultLightThemeId,
|
|
29
30
|
darkThemeId: themeById(parsed.darkThemeId ?? "")?.appearance === "dark" ? parsed.darkThemeId : defaultDarkThemeId,
|
|
30
|
-
accent: typeof parsed.accent === "string" && (accentPresets.some((preset) => preset.id === parsed.accent) || isThemeAccentId(parsed.accent)) ? parsed.accent : defaultThemeSelection.accent,
|
|
31
|
+
accent: typeof parsed.accent === "string" && (accentPresets.some((preset) => preset.id === parsed.accent) || isThemeAccentId(parsed.accent)) ? parsed.accent : normalizeCustomAccent(parsed.accent) ?? defaultThemeSelection.accent,
|
|
31
32
|
font: fonts.ui.family,
|
|
32
33
|
fonts,
|
|
33
34
|
density: resolvedDensity(parsed)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-persistence.js","names":[],"sources":["../../../src/components/theme/theme-persistence.ts"],"sourcesContent":["import { accentPresets } from '#lib/tokens'\nimport { normalizeAppearanceEditorFontSettings } from '#lib/appearance-font-settings'\nimport { defaultDarkThemeId, defaultLightThemeId, isThemeAccentId, themeById } from '#lib/themes'\nimport { defaultThemeSelection, resolvedDensity, type ThemeSelection } from './theme-state'\n\n/**\n * Where a selection is kept between sessions.\n *\n * The provider never touches storage itself; it asks a `ThemePersistence`. The\n * default is {@link localStoragePersistence}, which is what the provider always did.\n * A host that stores the preference in a different shape, under a versioned\n * envelope, or somewhere that is not `localStorage` supplies its own and the\n * resolution and application rules stay the shared ones.\n *\n * The contract is deliberately narrow, so that an implementation cannot make the\n * provider less safe than it was:\n *\n * - `read` is synchronous and runs once, when the provider is created. It may\n * repair or quarantine what it finds, and it must not throw: the provider\n * treats a throw as \"nothing stored\" and starts from the defaults.\n * - `write` runs only from `setSelection`. Never on mount, never from `preview`,\n * never as a side effect of reading, so the first write to a store is always a\n * user's decision. A throw is swallowed, because a full or blocked store must\n * not break the switch.\n */\nexport type ThemePersistence = {\n read(): Partial<ThemeSelection> | undefined\n write(next: ThemeSelection): void\n}\n\n/**\n * The preference store, or nothing.\n *\n * Only ever called inside a `try`: where storage is blocked — a sandboxed iframe, a\n * privacy mode, a denied site-data permission — merely *reading* the `localStorage`\n * global throws (\"Access is denied\", `SecurityError`), so even the `typeof` guard\n * has to sit inside the `try` rather than in front of it. Without a store the\n * preference lives only in the provider's signal for the session.\n */\nfunction preferenceStore(): Storage | undefined {\n return typeof localStorage === 'undefined' ? undefined : localStorage\n}\n\n/** The stored preference, validated against the catalogue. */\nfunction readSelection(storageKey: string): ThemeSelection {\n try {\n const raw = preferenceStore()?.getItem(storageKey)\n if (!raw) return defaultThemeSelection\n const parsed = JSON.parse(raw) as Partial<ThemeSelection>\n const fonts = normalizeAppearanceEditorFontSettings(parsed.fonts, parsed.font).settings\n return {\n appearance:\n parsed.appearance === 'light' ||\n parsed.appearance === 'dark' ||\n parsed.appearance === 'system'\n ? parsed.appearance\n : defaultThemeSelection.appearance,\n // An unknown id would leave the document with no theme at all, so a stale\n // preference from an older catalogue falls back rather than applying nothing.\n lightThemeId:\n themeById(parsed.lightThemeId ?? '')?.appearance === 'light'\n ? (parsed.lightThemeId as string)\n : defaultLightThemeId,\n darkThemeId:\n themeById(parsed.darkThemeId ?? '')?.appearance === 'dark'\n ? (parsed.darkThemeId as string)\n : defaultDarkThemeId,\n // A theme accent is kept whenever it names a slot, even one the stored pair\n // cannot offer: the id is role-shaped so it survives a theme switch, and an\n // unoffered slot already resolves to the theme's own primary when applied.\n accent:\n typeof parsed.accent === 'string' &&\n (accentPresets.some((preset) => preset.id === parsed.accent) ||\n isThemeAccentId(parsed.accent))\n ? parsed.accent\n : defaultThemeSelection.accent,\n font: fonts.ui.family,\n fonts,\n // Every axis has to be read back here, or it is lost twice: the provider's\n // document effect removes the `data-density` that `themeScript` set for the first paint, and\n // the next `setSelection` rewrites the store without it.\n density: resolvedDensity(parsed as ThemeSelection),\n }\n } catch {\n return defaultThemeSelection\n }\n}\n\n/**\n * The default persistence: one JSON document in `localStorage` under `key`.\n *\n * `read` is the provider's original `readSelection`, moved here unchanged — every\n * stored id is validated against the catalogue, so a stale preference falls back to\n * a default rather than reaching the document. `key` may be a function so a\n * provider whose `storageKey` prop changes writes to the key it is now given.\n *\n * Blocked, full or absent storage is survivable in both directions: a read answers\n * with the defaults and a write is dropped, so the preference simply lasts the\n * session.\n */\nexport function localStoragePersistence(key: string | (() => string)): ThemePersistence {\n const keyOf = () => (typeof key === 'function' ? key() : key)\n return {\n read: () => readSelection(keyOf()),\n write(next) {\n try {\n preferenceStore()?.setItem(keyOf(), JSON.stringify(next))\n } catch {\n // A full, blocked or unavailable store must not break the switch: the\n // preference simply does not survive the reload.\n }\n },\n }\n}\n\n/**\n * What a persistence knows, or nothing.\n *\n * The seam's `read` must not throw, and the provider does not rely on that: a host\n * persistence is code the design system has not seen, and a theme provider that\n * fails to mount because a store misbehaved has turned a lost preference into a\n * blank application.\n */\nexport function readPersisted(persistence: ThemePersistence): Partial<ThemeSelection> | undefined {\n try {\n return persistence.read()\n } catch {\n return undefined\n }\n}\n\n/** Hand a selection to the store; a store that throws loses the preference, not the switch. */\nexport function writePersisted(persistence: ThemePersistence, next: ThemeSelection): void {\n try {\n persistence.write(next)\n } catch {\n // Same contract as a full or blocked `localStorage`: the choice holds for the\n // session and does not survive the reload.\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"theme-persistence.js","names":[],"sources":["../../../src/components/theme/theme-persistence.ts"],"sourcesContent":["import { normalizeCustomAccent } from '#lib/accent-roles'\nimport { accentPresets } from '#lib/tokens'\nimport { normalizeAppearanceEditorFontSettings } from '#lib/appearance-font-settings'\nimport { defaultDarkThemeId, defaultLightThemeId, isThemeAccentId, themeById } from '#lib/themes'\nimport { defaultThemeSelection, resolvedDensity, type ThemeSelection } from './theme-state'\n\n/**\n * Where a selection is kept between sessions.\n *\n * The provider never touches storage itself; it asks a `ThemePersistence`. The\n * default is {@link localStoragePersistence}, which is what the provider always did.\n * A host that stores the preference in a different shape, under a versioned\n * envelope, or somewhere that is not `localStorage` supplies its own and the\n * resolution and application rules stay the shared ones.\n *\n * The contract is deliberately narrow, so that an implementation cannot make the\n * provider less safe than it was:\n *\n * - `read` is synchronous and runs once, when the provider is created. It may\n * repair or quarantine what it finds, and it must not throw: the provider\n * treats a throw as \"nothing stored\" and starts from the defaults.\n * - `write` runs only from `setSelection`. Never on mount, never from `preview`,\n * never as a side effect of reading, so the first write to a store is always a\n * user's decision. A throw is swallowed, because a full or blocked store must\n * not break the switch.\n */\nexport type ThemePersistence = {\n read(): Partial<ThemeSelection> | undefined\n write(next: ThemeSelection): void\n}\n\n/**\n * The preference store, or nothing.\n *\n * Only ever called inside a `try`: where storage is blocked — a sandboxed iframe, a\n * privacy mode, a denied site-data permission — merely *reading* the `localStorage`\n * global throws (\"Access is denied\", `SecurityError`), so even the `typeof` guard\n * has to sit inside the `try` rather than in front of it. Without a store the\n * preference lives only in the provider's signal for the session.\n */\nfunction preferenceStore(): Storage | undefined {\n return typeof localStorage === 'undefined' ? undefined : localStorage\n}\n\n/** The stored preference, validated against the catalogue. */\nfunction readSelection(storageKey: string): ThemeSelection {\n try {\n const raw = preferenceStore()?.getItem(storageKey)\n if (!raw) return defaultThemeSelection\n const parsed = JSON.parse(raw) as Partial<ThemeSelection>\n const fonts = normalizeAppearanceEditorFontSettings(parsed.fonts, parsed.font).settings\n return {\n appearance:\n parsed.appearance === 'light' ||\n parsed.appearance === 'dark' ||\n parsed.appearance === 'system'\n ? parsed.appearance\n : defaultThemeSelection.appearance,\n // An unknown id would leave the document with no theme at all, so a stale\n // preference from an older catalogue falls back rather than applying nothing.\n lightThemeId:\n themeById(parsed.lightThemeId ?? '')?.appearance === 'light'\n ? (parsed.lightThemeId as string)\n : defaultLightThemeId,\n darkThemeId:\n themeById(parsed.darkThemeId ?? '')?.appearance === 'dark'\n ? (parsed.darkThemeId as string)\n : defaultDarkThemeId,\n // A theme accent is kept whenever it names a slot, even one the stored pair\n // cannot offer: the id is role-shaped so it survives a theme switch, and an\n // unoffered slot already resolves to the theme's own primary when applied. A\n // custom `#rrggbb` is kept in its one stored spelling; its readability is\n // settled when it is painted, not when it is read.\n accent:\n typeof parsed.accent === 'string' &&\n (accentPresets.some((preset) => preset.id === parsed.accent) ||\n isThemeAccentId(parsed.accent))\n ? parsed.accent\n : (normalizeCustomAccent(parsed.accent) ?? defaultThemeSelection.accent),\n font: fonts.ui.family,\n fonts,\n // Every axis has to be read back here, or it is lost twice: the provider's\n // document effect removes the `data-density` that `themeScript` set for the first paint, and\n // the next `setSelection` rewrites the store without it.\n density: resolvedDensity(parsed as ThemeSelection),\n }\n } catch {\n return defaultThemeSelection\n }\n}\n\n/**\n * The default persistence: one JSON document in `localStorage` under `key`.\n *\n * `read` is the provider's original `readSelection`, moved here unchanged — every\n * stored id is validated against the catalogue, so a stale preference falls back to\n * a default rather than reaching the document. `key` may be a function so a\n * provider whose `storageKey` prop changes writes to the key it is now given.\n *\n * Blocked, full or absent storage is survivable in both directions: a read answers\n * with the defaults and a write is dropped, so the preference simply lasts the\n * session.\n */\nexport function localStoragePersistence(key: string | (() => string)): ThemePersistence {\n const keyOf = () => (typeof key === 'function' ? key() : key)\n return {\n read: () => readSelection(keyOf()),\n write(next) {\n try {\n preferenceStore()?.setItem(keyOf(), JSON.stringify(next))\n } catch {\n // A full, blocked or unavailable store must not break the switch: the\n // preference simply does not survive the reload.\n }\n },\n }\n}\n\n/**\n * What a persistence knows, or nothing.\n *\n * The seam's `read` must not throw, and the provider does not rely on that: a host\n * persistence is code the design system has not seen, and a theme provider that\n * fails to mount because a store misbehaved has turned a lost preference into a\n * blank application.\n */\nexport function readPersisted(persistence: ThemePersistence): Partial<ThemeSelection> | undefined {\n try {\n return persistence.read()\n } catch {\n return undefined\n }\n}\n\n/** Hand a selection to the store; a store that throws loses the preference, not the switch. */\nexport function writePersisted(persistence: ThemePersistence, next: ThemeSelection): void {\n try {\n persistence.write(next)\n } catch {\n // Same contract as a full or blocked `localStorage`: the choice holds for the\n // session and does not survive the reload.\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAwCA,SAAS,kBAAuC;CAC9C,OAAO,OAAO,iBAAiB,cAAc,KAAA,IAAY;AAC3D;;AAGA,SAAS,cAAc,YAAoC;CACzD,IAAI;EACF,MAAM,MAAM,gBAAgB,CAAC,EAAE,QAAQ,UAAU;EACjD,IAAI,CAAC,KAAK,OAAO;EACjB,MAAM,SAAS,KAAK,MAAM,GAAG;EAC7B,MAAM,QAAQ,sCAAsC,OAAO,OAAO,OAAO,IAAI,CAAC,CAAC;EAC/E,OAAO;GACL,YACE,OAAO,eAAe,WACtB,OAAO,eAAe,UACtB,OAAO,eAAe,WAClB,OAAO,aACP,sBAAsB;GAG5B,cACE,UAAU,OAAO,gBAAgB,EAAE,CAAC,EAAE,eAAe,UAChD,OAAO,eACR;GACN,aACE,UAAU,OAAO,eAAe,EAAE,CAAC,EAAE,eAAe,SAC/C,OAAO,cACR;GAMN,QACE,OAAO,OAAO,WAAW,aACxB,cAAc,MAAM,WAAW,OAAO,OAAO,OAAO,MAAM,KACzD,gBAAgB,OAAO,MAAM,KAC3B,OAAO,SACN,sBAAsB,OAAO,MAAM,KAAK,sBAAsB;GACrE,MAAM,MAAM,GAAG;GACf;GAIA,SAAS,gBAAgB,MAAwB;EACnD;CACF,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;;;;;;AAcA,SAAgB,wBAAwB,KAAgD;CACtF,MAAM,cAAe,OAAO,QAAQ,aAAa,IAAI,IAAI;CACzD,OAAO;EACL,YAAY,cAAc,MAAM,CAAC;EACjC,MAAM,MAAM;GACV,IAAI;IACF,gBAAgB,CAAC,EAAE,QAAQ,MAAM,GAAG,KAAK,UAAU,IAAI,CAAC;GAC1D,QAAQ,CAGR;EACF;CACF;AACF;;;;;;;;;AAUA,SAAgB,cAAc,aAAoE;CAChG,IAAI;EACF,OAAO,YAAY,KAAK;CAC1B,QAAQ;EACN;CACF;AACF;;AAGA,SAAgB,eAAe,aAA+B,MAA4B;CACxF,IAAI;EACF,YAAY,MAAM,IAAI;CACxB,QAAQ,CAGR;AACF"}
|
|
@@ -81,6 +81,15 @@ export type ThemeProviderProps = {
|
|
|
81
81
|
* element to `<head>` for two frames on every change.
|
|
82
82
|
*/
|
|
83
83
|
disableTransitionOnChange?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* The contrast ratio an accent is held to against the variant's background,
|
|
86
|
+
* repaired to the nearest passing colour when it falls short. Absent, presets
|
|
87
|
+
* are painted verbatim — the catalogue measured them for its own themes — and
|
|
88
|
+
* only a custom `#rrggbb` is held to 3:1. A host that adds themes the catalogue
|
|
89
|
+
* never measured passes 3 to hold the presets to it as well; for the catalogue's
|
|
90
|
+
* own themes the floor changes no preset.
|
|
91
|
+
*/
|
|
92
|
+
accentContrastFloor?: number;
|
|
84
93
|
};
|
|
85
94
|
export declare function ThemeProvider(props: ThemeProviderProps): JSX.Element;
|
|
86
95
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-provider.d.ts","sourceRoot":"","sources":["../../../src/components/theme/theme-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAInC,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,aAAa,CAAA;AAGpB,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,
|
|
1
|
+
{"version":3,"file":"theme-provider.d.ts","sourceRoot":"","sources":["../../../src/components/theme/theme-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAInC,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,aAAa,CAAA;AAGpB,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EAAE,uBAAuB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACpF,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,cAAc,GACpB,MAAM,eAAe,CAAA;AAEtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACtB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,wDAAwD;IACxD,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IACjC;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IACnC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAA;IAC9B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,CAAC,MAAM,SAAS,YAAY,EAAE,CAAC,CAAA;IAClE;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5E;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAA;IACnC;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,eAyHtD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CAAC,UAAU,SAAoB,GAAG,MAAM,CAGlE"}
|
|
@@ -2,7 +2,7 @@ import { builtinThemes, themeAccentsFor } from "../../lib/themes.js";
|
|
|
2
2
|
import { safeScriptStringLiteral } from "../../lib/safe-script.js";
|
|
3
3
|
import { fontSettingsBootstrapScript } from "../../lib/appearance-font-settings.js";
|
|
4
4
|
import { themeContext, useOptionalTheme, useTheme } from "./theme-context.js";
|
|
5
|
-
import { defaultThemeSelection, initialThemeSelection, mergeRegistry, mergeThemeSelection, resolveThemeState, resolvedDensity } from "./theme-state.js";
|
|
5
|
+
import { accentRolesForState, defaultThemeSelection, initialThemeSelection, mergeRegistry, mergeThemeSelection, resolveThemeState, resolvedDensity } from "./theme-state.js";
|
|
6
6
|
import { applyThemeToRoot, applyWithoutTransitions } from "./theme-document.js";
|
|
7
7
|
import { localStoragePersistence, readPersisted, writePersisted } from "./theme-persistence.js";
|
|
8
8
|
import { createComponent } from "solid-js/web";
|
|
@@ -17,7 +17,8 @@ function ThemeProvider(props) {
|
|
|
17
17
|
"persistence",
|
|
18
18
|
"themes",
|
|
19
19
|
"transformTokens",
|
|
20
|
-
"disableTransitionOnChange"
|
|
20
|
+
"disableTransitionOnChange",
|
|
21
|
+
"accentContrastFloor"
|
|
21
22
|
]);
|
|
22
23
|
const storageKey = () => local.storageKey ?? "adea-appearance";
|
|
23
24
|
const persistence = local.persistence ?? localStoragePersistence(storageKey);
|
|
@@ -54,7 +55,10 @@ function ThemeProvider(props) {
|
|
|
54
55
|
appearance: shown().appearance,
|
|
55
56
|
variant: shown().variant
|
|
56
57
|
};
|
|
57
|
-
const options = {
|
|
58
|
+
const options = {
|
|
59
|
+
transformTokens: local.transformTokens,
|
|
60
|
+
accentContrastFloor: local.accentContrastFloor
|
|
61
|
+
};
|
|
58
62
|
const apply = () => {
|
|
59
63
|
written = applyThemeToRoot(document.documentElement, state, options, written);
|
|
60
64
|
};
|
|
@@ -76,6 +80,12 @@ function ThemeProvider(props) {
|
|
|
76
80
|
setDraft(next ? { ...next } : void 0);
|
|
77
81
|
},
|
|
78
82
|
previewing: () => draft() !== void 0,
|
|
83
|
+
accentRolesFor: (accent, variantId) => accentRolesForState(accent, variantId, {
|
|
84
|
+
selection: selection(),
|
|
85
|
+
variant: variant(),
|
|
86
|
+
registry: registry(),
|
|
87
|
+
accentContrastFloor: local.accentContrastFloor
|
|
88
|
+
}),
|
|
79
89
|
setSelection(patch) {
|
|
80
90
|
const next = mergeThemeSelection(selection(), patch);
|
|
81
91
|
setSelectionState(next);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-provider.js","names":["JSX","createEffect","createMemo","createSignal","onCleanup","splitProps","safeScriptStringLiteral","fontSettingsBootstrapScript","builtinThemes","themeAccentsFor","ThemeAppearance","ThemeVariant","themeContext","applyThemeToRoot","applyWithoutTransitions","localStoragePersistence","readPersisted","writePersisted","ThemePersistence","initialThemeSelection","mergeRegistry","mergeThemeSelection","resolveThemeState","ThemeContextValue","ThemeSelection","useOptionalTheme","useTheme","defaultThemeSelection","resolvedDensity","ThemeDensity","ThemeProviderProps","children","Element","storageKey","initial","Partial","selection","persistence","themes","transformTokens","tokens","Record","disableTransitionOnChange","ThemeProvider","props","local","extraThemes","registry","setSelectionState","incoming","current","systemAppearance","setSystemAppearance","window","matchMedia","query","matches","onChange","event","MediaQueryListEvent","addEventListener","removeEventListener","committed","resolvedAppearance","appearance","variant","draft","setDraft","shownSelection","preview","shown","written","ReadonlySet","restoreTransitions","document","state","options","apply","documentElement","themeAccents","lightThemeId","darkThemeId","value","allThemes","next","undefined","previewing","setSelection","patch","Context","_$createComponent","Provider","inlineScriptLiteral","themeScript","script","_$createComponent"],"sources":["../../../src/components/theme/theme-provider.tsx"],"sourcesContent":["import type { JSX } from 'solid-js'\nimport { createEffect, createMemo, createSignal, onCleanup, splitProps } from 'solid-js'\nimport { safeScriptStringLiteral } from '#lib/safe-script'\nimport { fontSettingsBootstrapScript } from '#lib/appearance-font-settings'\nimport {\n builtinThemes,\n themeAccentsFor,\n type ThemeAppearance,\n type ThemeVariant,\n} from '#lib/themes'\nimport { themeContext } from './theme-context'\nimport { applyThemeToRoot, applyWithoutTransitions } from './theme-document'\nimport {\n localStoragePersistence,\n readPersisted,\n writePersisted,\n type ThemePersistence,\n} from './theme-persistence'\nimport {\n initialThemeSelection,\n mergeRegistry,\n mergeThemeSelection,\n resolveThemeState,\n type ThemeContextValue,\n type ThemeSelection,\n} from './theme-state'\n\nexport { useOptionalTheme, useTheme } from './theme-context'\nexport { localStoragePersistence, type ThemePersistence } from './theme-persistence'\nexport {\n defaultThemeSelection,\n resolvedDensity,\n type ThemeContextValue,\n type ThemeDensity,\n type ThemeSelection,\n} from './theme-state'\n\n/**\n * ThemeProvider.\n *\n * Owns the appearance preference and applies it to the document. One provider near\n * the root; everything below reads it.\n *\n * ## What a preference is\n *\n * Four independent choices (`ThemeSelection`), and keeping them independent is the\n * point: appearance, a theme per appearance, an accent and fonts. They compose: a\n * user who wants Nord with a violet accent and the system font should not need\n * someone to author that combination.\n *\n * ## Where the rules live\n *\n * This component is wiring. What a selection merges to and resolves to is\n * `theme-state.ts`; what lands on `<html>` is `theme-document.ts`; where the\n * preference is kept is `theme-persistence.ts`. Each is plain code a test can call,\n * which is the reason none of it is inlined here.\n *\n * ## Why the variants are applied as inline properties\n *\n * The catalogue is data, and a theme is applied by writing its roles onto\n * `<html>` as custom properties. That is what makes an imported palette work\n * without a hand-written `[data-theme]` block per theme, and it is why a settings\n * UI can show a preview by reading the same object rather than by loading a\n * stylesheet. `theme.css` keeps the default theme's values so the first paint is\n * correct before any script runs.\n */\nexport type ThemeProviderProps = {\n children?: JSX.Element\n /** Where the preference is persisted. Distinct per application. */\n storageKey?: string\n /** Start from this instead of the stored preference. */\n initial?: Partial<ThemeSelection>\n /**\n * The selection, owned by the caller.\n *\n * For a consumer that keeps the state itself — a settings store, or a workshop\n * whose selection lives in Storybook globals — rather than handing it to this\n * provider's signal. Each change lands here and the document follows; nothing is\n * written to the store, because the caller is the one who persists. A picker\n * below the provider still works, and its change is the caller's to read back.\n *\n * Absent, the provider is the whole owner: it reads `storageKey` on mount,\n * seeds from `initial`, and persists every `setSelection`.\n */\n selection?: Partial<ThemeSelection>\n /**\n * Where the preference is kept, in place of `localStorage` under `storageKey`.\n *\n * Read once when the provider is created, so changing the prop later does not\n * move the store. `storageKey` is ignored when this is given.\n */\n persistence?: ThemePersistence\n /**\n * Variants the host adds to the built-in catalogue — themes a user imported.\n *\n * A function is read inside the provider's reactive scope, so one that reads a\n * signal keeps the picker and the document current when the set changes. A\n * stored id that names no variant, built in or added, paints the default of its\n * appearance and stays in the selection untouched.\n */\n themes?: readonly ThemeVariant[] | (() => readonly ThemeVariant[])\n /**\n * Rewrites the custom properties of each pass before they are written to\n * `<html>`: the variant's roles with the accent over them. `tokensAsHex` from\n * `lib/themes` is the one the system ships.\n */\n transformTokens?: (tokens: Record<string, string>) => Record<string, string>\n /**\n * Switch CSS transitions off for the frame that carries a change, so a theme\n * switch cannot animate the whole page. Off by default: it adds a `<style>`\n * element to `<head>` for two frames on every change.\n */\n disableTransitionOnChange?: boolean\n}\n\nexport function ThemeProvider(props: ThemeProviderProps) {\n const [local] = splitProps(props, [\n 'children',\n 'storageKey',\n 'initial',\n 'selection',\n 'persistence',\n 'themes',\n 'transformTokens',\n 'disableTransitionOnChange',\n ])\n const storageKey = () => local.storageKey ?? 'adea-appearance'\n const persistence = local.persistence ?? localStoragePersistence(storageKey)\n\n // Read before the first resolution and before the store is, so a persistence whose\n // answer depends on the extras (an id it only accepts if the theme exists) sees\n // them.\n const extraThemes = createMemo(() =>\n typeof local.themes === 'function' ? local.themes() : (local.themes ?? [])\n )\n const registry = createMemo(() => mergeRegistry(builtinThemes, extraThemes()))\n\n const [selection, setSelectionState] = createSignal<ThemeSelection>(\n initialThemeSelection(readPersisted(persistence), local.initial)\n )\n\n // The controlled half of the contract. A patch from the owner replaces the\n // matching axes; the stored preference is untouched, since the owner is the one\n // that persists. Reading `local.selection` — a prop getter, not a destructured\n // value — is what keeps this subscribed for the provider's lifetime.\n createEffect(() => {\n const incoming = local.selection\n if (incoming) setSelectionState((current) => mergeThemeSelection(current, incoming))\n })\n\n const [systemAppearance, setSystemAppearance] = createSignal<ThemeAppearance>('light')\n\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n const query = window.matchMedia('(prefers-color-scheme: dark)')\n setSystemAppearance(query.matches ? 'dark' : 'light')\n const onChange = (event: MediaQueryListEvent) =>\n setSystemAppearance(event.matches ? 'dark' : 'light')\n query.addEventListener('change', onChange)\n onCleanup(() => query.removeEventListener('change', onChange))\n }\n\n // What the stored preference resolves to. `selection()`, `variant()` and\n // `resolvedAppearance()` answer from this and never from a preview, so a picker\n // that previews a draft still reads back what is committed.\n const committed = createMemo(() => resolveThemeState(selection(), systemAppearance(), registry()))\n const resolvedAppearance = createMemo<ThemeAppearance>(() => committed().appearance)\n const variant = createMemo<ThemeVariant>(() => committed().variant)\n\n const [draft, setDraft] = createSignal<Partial<ThemeSelection> | undefined>()\n const shownSelection = createMemo(() => {\n const preview = draft()\n return preview ? mergeThemeSelection(selection(), preview) : selection()\n })\n const shown = createMemo(() =>\n draft() ? resolveThemeState(shownSelection(), systemAppearance(), registry()) : committed()\n )\n\n let written: ReadonlySet<string> | undefined\n let restoreTransitions: (() => void) | undefined\n createEffect(() => {\n if (typeof document === 'undefined') return\n const state = {\n selection: shownSelection(),\n appearance: shown().appearance,\n variant: shown().variant,\n }\n const options = { transformTokens: local.transformTokens }\n const apply = () => {\n written = applyThemeToRoot(document.documentElement, state, options, written)\n }\n if (local.disableTransitionOnChange) {\n restoreTransitions?.()\n restoreTransitions = applyWithoutTransitions(document, apply)\n } else {\n apply()\n }\n })\n onCleanup(() => restoreTransitions?.())\n\n const themeAccents = createMemo(() =>\n themeAccentsFor(selection().lightThemeId, selection().darkThemeId)\n )\n\n const value: ThemeContextValue = {\n selection,\n resolvedAppearance,\n variant,\n themes: builtinThemes,\n themeAccents,\n allThemes: registry,\n preview(next) {\n setDraft(next ? { ...next } : undefined)\n },\n previewing: () => draft() !== undefined,\n setSelection(patch) {\n const next = mergeThemeSelection(selection(), patch)\n setSelectionState(next)\n // The committed selection is now what should be showing.\n setDraft(undefined)\n writePersisted(persistence, next)\n },\n }\n\n const Context = themeContext()\n return <Context.Provider value={value}>{local.children}</Context.Provider>\n}\n\n/**\n * A string as a JavaScript literal that is also safe inside an inline `<script>`.\n *\n * `JSON.stringify` produces a correct JavaScript literal, and it is **not** safe\n * here: it leaves `<` and `>` alone, so a value containing `</script>` ends the tag\n * early and everything after it is parsed as HTML. That is the classic inline-script\n * injection, and it is a real one even though the value is a developer-supplied prop\n * rather than user input — a prop can come from configuration, and a key that happens\n * to contain a closing tag should not be able to execute.\n *\n * The escape is also correct JavaScript: `\\u003c` is `<` to the parser, so the value\n * is byte-identical at runtime and inert to the HTML tokenizer. `\\u2028` and `\\u2029`\n * are escaped for the neighbouring reason — they are legal inside a JSON string and\n * were, before ES2019, line terminators to a JavaScript parser.\n *\n * CodeQL flags the unescaped form as `js/bad-code-sanitization`, which is how this\n * was found; `tests/theme-script.test.ts` pins it so it cannot come back.\n */\nexport function inlineScriptLiteral(value: string): string {\n return safeScriptStringLiteral(value)\n}\n\n/**\n * The no-flash script.\n *\n * Rendered inline in `<head>` before any stylesheet that matters. Without it a dark\n * preference paints the light theme first and then swaps, which is the flash every\n * themed application has to solve and the one thing a provider cannot do from\n * inside the body.\n *\n * Deliberately tiny and dependency-free: it reads the stored preference, resolves\n * `system`, and sets the class. It does not apply the variant's roles — the default\n * theme in `theme.css` covers the first paint, and the provider writes the rest on\n * mount.\n *\n * The script reads two values out of `localStorage` and writes them to `dataset`,\n * which is a *property* assignment rather than code: a stored accent or font id can\n * set an attribute and cannot execute. The one value that reaches the source as text\n * is `storageKey`, and it goes through {@link inlineScriptLiteral} for the reason\n * documented there.\n */\nexport function themeScript(storageKey = 'adea-appearance'): string {\n const script = `(function(){try{var s=localStorage.getItem(${inlineScriptLiteral(storageKey)});var p=s?JSON.parse(s):{};var a=p.appearance||'system';var d=a==='dark'||(a==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);var r=document.documentElement;if(d)r.classList.add('dark');r.style.colorScheme=d?'dark':'light';if(p.accent&&p.accent!=='theme')r.dataset.accent=p.accent;if(p.density==='compact')r.dataset.density='compact';}catch(e){}})();`\n return `${script}${fontSettingsBootstrapScript(storageKey)}`\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"theme-provider.js","names":["JSX","createEffect","createMemo","createSignal","onCleanup","splitProps","safeScriptStringLiteral","fontSettingsBootstrapScript","builtinThemes","themeAccentsFor","ThemeAppearance","ThemeVariant","themeContext","applyThemeToRoot","applyWithoutTransitions","localStoragePersistence","readPersisted","writePersisted","ThemePersistence","accentRolesForState","initialThemeSelection","mergeRegistry","mergeThemeSelection","resolveThemeState","ThemeContextValue","ThemeSelection","useOptionalTheme","useTheme","defaultThemeSelection","resolvedDensity","ThemeDensity","ThemeProviderProps","children","Element","storageKey","initial","Partial","selection","persistence","themes","transformTokens","tokens","Record","disableTransitionOnChange","accentContrastFloor","ThemeProvider","props","local","extraThemes","registry","setSelectionState","incoming","current","systemAppearance","setSystemAppearance","window","matchMedia","query","matches","onChange","event","MediaQueryListEvent","addEventListener","removeEventListener","committed","resolvedAppearance","appearance","variant","draft","setDraft","shownSelection","preview","shown","written","ReadonlySet","restoreTransitions","document","state","options","apply","documentElement","themeAccents","lightThemeId","darkThemeId","value","allThemes","next","undefined","previewing","accentRolesFor","accent","variantId","setSelection","patch","Context","_$createComponent","Provider","inlineScriptLiteral","themeScript","script","_$createComponent"],"sources":["../../../src/components/theme/theme-provider.tsx"],"sourcesContent":["import type { JSX } from 'solid-js'\nimport { createEffect, createMemo, createSignal, onCleanup, splitProps } from 'solid-js'\nimport { safeScriptStringLiteral } from '#lib/safe-script'\nimport { fontSettingsBootstrapScript } from '#lib/appearance-font-settings'\nimport {\n builtinThemes,\n themeAccentsFor,\n type ThemeAppearance,\n type ThemeVariant,\n} from '#lib/themes'\nimport { themeContext } from './theme-context'\nimport { applyThemeToRoot, applyWithoutTransitions } from './theme-document'\nimport {\n localStoragePersistence,\n readPersisted,\n writePersisted,\n type ThemePersistence,\n} from './theme-persistence'\nimport {\n accentRolesForState,\n initialThemeSelection,\n mergeRegistry,\n mergeThemeSelection,\n resolveThemeState,\n type ThemeContextValue,\n type ThemeSelection,\n} from './theme-state'\n\nexport { useOptionalTheme, useTheme } from './theme-context'\nexport { localStoragePersistence, type ThemePersistence } from './theme-persistence'\nexport {\n defaultThemeSelection,\n resolvedDensity,\n type ThemeContextValue,\n type ThemeDensity,\n type ThemeSelection,\n} from './theme-state'\n\n/**\n * ThemeProvider.\n *\n * Owns the appearance preference and applies it to the document. One provider near\n * the root; everything below reads it.\n *\n * ## What a preference is\n *\n * Four independent choices (`ThemeSelection`), and keeping them independent is the\n * point: appearance, a theme per appearance, an accent and fonts. They compose: a\n * user who wants Nord with a violet accent and the system font should not need\n * someone to author that combination.\n *\n * ## Where the rules live\n *\n * This component is wiring. What a selection merges to and resolves to is\n * `theme-state.ts`; what lands on `<html>` is `theme-document.ts`; where the\n * preference is kept is `theme-persistence.ts`. Each is plain code a test can call,\n * which is the reason none of it is inlined here.\n *\n * ## Why the variants are applied as inline properties\n *\n * The catalogue is data, and a theme is applied by writing its roles onto\n * `<html>` as custom properties. That is what makes an imported palette work\n * without a hand-written `[data-theme]` block per theme, and it is why a settings\n * UI can show a preview by reading the same object rather than by loading a\n * stylesheet. `theme.css` keeps the default theme's values so the first paint is\n * correct before any script runs.\n */\nexport type ThemeProviderProps = {\n children?: JSX.Element\n /** Where the preference is persisted. Distinct per application. */\n storageKey?: string\n /** Start from this instead of the stored preference. */\n initial?: Partial<ThemeSelection>\n /**\n * The selection, owned by the caller.\n *\n * For a consumer that keeps the state itself — a settings store, or a workshop\n * whose selection lives in Storybook globals — rather than handing it to this\n * provider's signal. Each change lands here and the document follows; nothing is\n * written to the store, because the caller is the one who persists. A picker\n * below the provider still works, and its change is the caller's to read back.\n *\n * Absent, the provider is the whole owner: it reads `storageKey` on mount,\n * seeds from `initial`, and persists every `setSelection`.\n */\n selection?: Partial<ThemeSelection>\n /**\n * Where the preference is kept, in place of `localStorage` under `storageKey`.\n *\n * Read once when the provider is created, so changing the prop later does not\n * move the store. `storageKey` is ignored when this is given.\n */\n persistence?: ThemePersistence\n /**\n * Variants the host adds to the built-in catalogue — themes a user imported.\n *\n * A function is read inside the provider's reactive scope, so one that reads a\n * signal keeps the picker and the document current when the set changes. A\n * stored id that names no variant, built in or added, paints the default of its\n * appearance and stays in the selection untouched.\n */\n themes?: readonly ThemeVariant[] | (() => readonly ThemeVariant[])\n /**\n * Rewrites the custom properties of each pass before they are written to\n * `<html>`: the variant's roles with the accent over them. `tokensAsHex` from\n * `lib/themes` is the one the system ships.\n */\n transformTokens?: (tokens: Record<string, string>) => Record<string, string>\n /**\n * Switch CSS transitions off for the frame that carries a change, so a theme\n * switch cannot animate the whole page. Off by default: it adds a `<style>`\n * element to `<head>` for two frames on every change.\n */\n disableTransitionOnChange?: boolean\n /**\n * The contrast ratio an accent is held to against the variant's background,\n * repaired to the nearest passing colour when it falls short. Absent, presets\n * are painted verbatim — the catalogue measured them for its own themes — and\n * only a custom `#rrggbb` is held to 3:1. A host that adds themes the catalogue\n * never measured passes 3 to hold the presets to it as well; for the catalogue's\n * own themes the floor changes no preset.\n */\n accentContrastFloor?: number\n}\n\nexport function ThemeProvider(props: ThemeProviderProps) {\n const [local] = splitProps(props, [\n 'children',\n 'storageKey',\n 'initial',\n 'selection',\n 'persistence',\n 'themes',\n 'transformTokens',\n 'disableTransitionOnChange',\n 'accentContrastFloor',\n ])\n const storageKey = () => local.storageKey ?? 'adea-appearance'\n const persistence = local.persistence ?? localStoragePersistence(storageKey)\n\n // Read before the first resolution and before the store is, so a persistence whose\n // answer depends on the extras (an id it only accepts if the theme exists) sees\n // them.\n const extraThemes = createMemo(() =>\n typeof local.themes === 'function' ? local.themes() : (local.themes ?? [])\n )\n const registry = createMemo(() => mergeRegistry(builtinThemes, extraThemes()))\n\n const [selection, setSelectionState] = createSignal<ThemeSelection>(\n initialThemeSelection(readPersisted(persistence), local.initial)\n )\n\n // The controlled half of the contract. A patch from the owner replaces the\n // matching axes; the stored preference is untouched, since the owner is the one\n // that persists. Reading `local.selection` — a prop getter, not a destructured\n // value — is what keeps this subscribed for the provider's lifetime.\n createEffect(() => {\n const incoming = local.selection\n if (incoming) setSelectionState((current) => mergeThemeSelection(current, incoming))\n })\n\n const [systemAppearance, setSystemAppearance] = createSignal<ThemeAppearance>('light')\n\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n const query = window.matchMedia('(prefers-color-scheme: dark)')\n setSystemAppearance(query.matches ? 'dark' : 'light')\n const onChange = (event: MediaQueryListEvent) =>\n setSystemAppearance(event.matches ? 'dark' : 'light')\n query.addEventListener('change', onChange)\n onCleanup(() => query.removeEventListener('change', onChange))\n }\n\n // What the stored preference resolves to. `selection()`, `variant()` and\n // `resolvedAppearance()` answer from this and never from a preview, so a picker\n // that previews a draft still reads back what is committed.\n const committed = createMemo(() => resolveThemeState(selection(), systemAppearance(), registry()))\n const resolvedAppearance = createMemo<ThemeAppearance>(() => committed().appearance)\n const variant = createMemo<ThemeVariant>(() => committed().variant)\n\n const [draft, setDraft] = createSignal<Partial<ThemeSelection> | undefined>()\n const shownSelection = createMemo(() => {\n const preview = draft()\n return preview ? mergeThemeSelection(selection(), preview) : selection()\n })\n const shown = createMemo(() =>\n draft() ? resolveThemeState(shownSelection(), systemAppearance(), registry()) : committed()\n )\n\n let written: ReadonlySet<string> | undefined\n let restoreTransitions: (() => void) | undefined\n createEffect(() => {\n if (typeof document === 'undefined') return\n const state = {\n selection: shownSelection(),\n appearance: shown().appearance,\n variant: shown().variant,\n }\n const options = {\n transformTokens: local.transformTokens,\n accentContrastFloor: local.accentContrastFloor,\n }\n const apply = () => {\n written = applyThemeToRoot(document.documentElement, state, options, written)\n }\n if (local.disableTransitionOnChange) {\n restoreTransitions?.()\n restoreTransitions = applyWithoutTransitions(document, apply)\n } else {\n apply()\n }\n })\n onCleanup(() => restoreTransitions?.())\n\n const themeAccents = createMemo(() =>\n themeAccentsFor(selection().lightThemeId, selection().darkThemeId)\n )\n\n const value: ThemeContextValue = {\n selection,\n resolvedAppearance,\n variant,\n themes: builtinThemes,\n themeAccents,\n allThemes: registry,\n preview(next) {\n setDraft(next ? { ...next } : undefined)\n },\n previewing: () => draft() !== undefined,\n accentRolesFor: (accent, variantId) =>\n accentRolesForState(accent, variantId, {\n selection: selection(),\n variant: variant(),\n registry: registry(),\n accentContrastFloor: local.accentContrastFloor,\n }),\n setSelection(patch) {\n const next = mergeThemeSelection(selection(), patch)\n setSelectionState(next)\n // The committed selection is now what should be showing.\n setDraft(undefined)\n writePersisted(persistence, next)\n },\n }\n\n const Context = themeContext()\n return <Context.Provider value={value}>{local.children}</Context.Provider>\n}\n\n/**\n * A string as a JavaScript literal that is also safe inside an inline `<script>`.\n *\n * `JSON.stringify` produces a correct JavaScript literal, and it is **not** safe\n * here: it leaves `<` and `>` alone, so a value containing `</script>` ends the tag\n * early and everything after it is parsed as HTML. That is the classic inline-script\n * injection, and it is a real one even though the value is a developer-supplied prop\n * rather than user input — a prop can come from configuration, and a key that happens\n * to contain a closing tag should not be able to execute.\n *\n * The escape is also correct JavaScript: `\\u003c` is `<` to the parser, so the value\n * is byte-identical at runtime and inert to the HTML tokenizer. `\\u2028` and `\\u2029`\n * are escaped for the neighbouring reason — they are legal inside a JSON string and\n * were, before ES2019, line terminators to a JavaScript parser.\n *\n * CodeQL flags the unescaped form as `js/bad-code-sanitization`, which is how this\n * was found; `tests/theme-script.test.ts` pins it so it cannot come back.\n */\nexport function inlineScriptLiteral(value: string): string {\n return safeScriptStringLiteral(value)\n}\n\n/**\n * The no-flash script.\n *\n * Rendered inline in `<head>` before any stylesheet that matters. Without it a dark\n * preference paints the light theme first and then swaps, which is the flash every\n * themed application has to solve and the one thing a provider cannot do from\n * inside the body.\n *\n * Deliberately tiny and dependency-free: it reads the stored preference, resolves\n * `system`, and sets the class. It does not apply the variant's roles — the default\n * theme in `theme.css` covers the first paint, and the provider writes the rest on\n * mount.\n *\n * The script reads two values out of `localStorage` and writes them to `dataset`,\n * which is a *property* assignment rather than code: a stored accent or font id can\n * set an attribute and cannot execute. The one value that reaches the source as text\n * is `storageKey`, and it goes through {@link inlineScriptLiteral} for the reason\n * documented there.\n */\nexport function themeScript(storageKey = 'adea-appearance'): string {\n const script = `(function(){try{var s=localStorage.getItem(${inlineScriptLiteral(storageKey)});var p=s?JSON.parse(s):{};var a=p.appearance||'system';var d=a==='dark'||(a==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);var r=document.documentElement;if(d)r.classList.add('dark');r.style.colorScheme=d?'dark':'light';if(p.accent&&p.accent!=='theme')r.dataset.accent=p.accent;if(p.density==='compact')r.dataset.density='compact';}catch(e){}})();`\n return `${script}${fontSettingsBootstrapScript(storageKey)}`\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type AppearanceEditorFontSettings } from '#lib/appearance-font-settings';
|
|
2
2
|
import type { AccentPreset } from '@adea-ai/themes';
|
|
3
|
+
import { type AccentRoles } from '#lib/accent-roles';
|
|
3
4
|
import { type ThemeAppearance, type ThemeVariant } from '#lib/themes';
|
|
4
5
|
/**
|
|
5
6
|
* The pure half of the theme provider: what a selection is, how two selections
|
|
@@ -29,8 +30,12 @@ export type ThemeSelection = {
|
|
|
29
30
|
darkThemeId: string;
|
|
30
31
|
/**
|
|
31
32
|
* An `accentPresets` id, a theme accent id from `themeAccents()` (`ansi-blue`…),
|
|
32
|
-
*
|
|
33
|
-
* not offer falls back to the variant's own primary.
|
|
33
|
+
* `theme` for the variant's own primary, or a custom colour as `#rrggbb`. A theme
|
|
34
|
+
* accent the current pair does not offer falls back to the variant's own primary.
|
|
35
|
+
*
|
|
36
|
+
* A custom colour is stored lower case and is raised to the contrast floor when it
|
|
37
|
+
* is painted, never when it is stored: the selection keeps what the user chose.
|
|
38
|
+
* Anything else that is not an id is dropped at paint, not rejected here.
|
|
34
39
|
*/
|
|
35
40
|
accent: string;
|
|
36
41
|
/** UI-family alias for consumers of the original single-font preference. */
|
|
@@ -103,6 +108,14 @@ export type ThemeContextValue = {
|
|
|
103
108
|
preview: (draft: Partial<ThemeSelection> | undefined) => void;
|
|
104
109
|
/** True while a {@link ThemeContextValue.preview} draft is on the document. */
|
|
105
110
|
previewing: () => boolean;
|
|
111
|
+
/**
|
|
112
|
+
* The roles `accent` paints over `variantId` (default: the variant in use), held
|
|
113
|
+
* to the provider's `accentContrastFloor`, for an element-scoped override with
|
|
114
|
+
* `paintAccentRoles` — a workspace that carries its own colour. `undefined` for
|
|
115
|
+
* `null`, for `theme`, for an id that resolves to nothing, and for a variant the
|
|
116
|
+
* registry does not hold: each means "keep the inherited accent".
|
|
117
|
+
*/
|
|
118
|
+
accentRolesFor: (accent: string | null, variantId?: string) => AccentRoles | undefined;
|
|
106
119
|
};
|
|
107
120
|
/** Keep the deprecated single-font view synchronized with the UI axis. */
|
|
108
121
|
export declare function mergeThemeSelection(base: ThemeSelection, patch: Partial<ThemeSelection>): ThemeSelection;
|
|
@@ -139,4 +152,16 @@ export declare function resolveThemeState(selection: ThemeSelection, system: The
|
|
|
139
152
|
* takes the first match: a host's variant can add a theme but cannot shadow one.
|
|
140
153
|
*/
|
|
141
154
|
export declare function mergeRegistry(builtin: readonly ThemeVariant[], extra: readonly ThemeVariant[] | undefined): readonly ThemeVariant[];
|
|
155
|
+
/**
|
|
156
|
+
* The roles an accent paints over a variant, for {@link ThemeContextValue.accentRolesFor}.
|
|
157
|
+
*
|
|
158
|
+
* Resolved against the committed selection's theme pair, so an `ansi-*` accent means
|
|
159
|
+
* the same colour here as it does on `<html>`.
|
|
160
|
+
*/
|
|
161
|
+
export declare function accentRolesForState(accent: string | null, variantId: string | undefined, state: {
|
|
162
|
+
selection: ThemeSelection;
|
|
163
|
+
variant: ThemeVariant;
|
|
164
|
+
registry: readonly ThemeVariant[];
|
|
165
|
+
accentContrastFloor?: number;
|
|
166
|
+
}): AccentRoles | undefined;
|
|
142
167
|
//# sourceMappingURL=theme-state.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-state.d.ts","sourceRoot":"","sources":["../../../src/components/theme/theme-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,4BAA4B,EAClC,MAAM,+BAA+B,CAAA;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,
|
|
1
|
+
{"version":3,"file":"theme-state.d.ts","sourceRoot":"","sources":["../../../src/components/theme/theme-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeCustomAccent } from "../../lib/accent-roles.js";
|
|
2
|
+
import { accentRolesForSelection, defaultDarkThemeId, defaultLightThemeId, resolveVariant } from "../../lib/themes.js";
|
|
2
3
|
import { DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS, normalizeAppearanceEditorFontSettings } from "../../lib/appearance-font-settings.js";
|
|
3
4
|
//#region src/components/theme/theme-state.ts
|
|
4
5
|
/**
|
|
@@ -50,6 +51,7 @@ function mergeThemeSelection(base, patch) {
|
|
|
50
51
|
} else fonts = normalizeAppearanceEditorFontSettings(merged.fonts, merged.font).settings;
|
|
51
52
|
return {
|
|
52
53
|
...merged,
|
|
54
|
+
accent: normalizeCustomAccent(merged.accent) ?? merged.accent,
|
|
53
55
|
fonts,
|
|
54
56
|
font: fonts.ui.family
|
|
55
57
|
};
|
|
@@ -98,7 +100,23 @@ function resolveThemeState(selection, system, registry) {
|
|
|
98
100
|
function mergeRegistry(builtin, extra) {
|
|
99
101
|
return extra && extra.length > 0 ? [...builtin, ...extra] : builtin;
|
|
100
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* The roles an accent paints over a variant, for {@link ThemeContextValue.accentRolesFor}.
|
|
105
|
+
*
|
|
106
|
+
* Resolved against the committed selection's theme pair, so an `ansi-*` accent means
|
|
107
|
+
* the same colour here as it does on `<html>`.
|
|
108
|
+
*/
|
|
109
|
+
function accentRolesForState(accent, variantId, state) {
|
|
110
|
+
if (accent === null) return void 0;
|
|
111
|
+
const variant = variantId === void 0 ? state.variant : state.registry.find((candidate) => candidate.id === variantId);
|
|
112
|
+
if (!variant) return void 0;
|
|
113
|
+
return accentRolesForSelection(accent, variant.appearance, state.selection, {
|
|
114
|
+
background: variant.colors.background,
|
|
115
|
+
floor: state.accentContrastFloor,
|
|
116
|
+
variantId: variant.id
|
|
117
|
+
});
|
|
118
|
+
}
|
|
101
119
|
//#endregion
|
|
102
|
-
export { defaultThemeSelection, initialThemeSelection, mergeRegistry, mergeThemeSelection, resolveAppearance, resolveThemeState, resolvedDensity, selectedThemeId };
|
|
120
|
+
export { accentRolesForState, defaultThemeSelection, initialThemeSelection, mergeRegistry, mergeThemeSelection, resolveAppearance, resolveThemeState, resolvedDensity, selectedThemeId };
|
|
103
121
|
|
|
104
122
|
//# sourceMappingURL=theme-state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-state.js","names":[],"sources":["../../../src/components/theme/theme-state.ts"],"sourcesContent":["import {\n DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS,\n normalizeAppearanceEditorFontSettings,\n type AppearanceEditorFontSettings,\n} from '#lib/appearance-font-settings'\nimport type { AccentPreset } from '@adea-ai/themes'\nimport {\n defaultDarkThemeId,\n defaultLightThemeId,\n resolveVariant,\n type ThemeAppearance,\n type ThemeVariant,\n} from '#lib/themes'\n\n/**\n * The pure half of the theme provider: what a selection is, how two selections\n * merge, and what a selection resolves to.\n *\n * Nothing here touches the document, storage or a signal, so each rule can be\n * tested by calling it. `ThemeProvider` owns the reactivity and wires these to it;\n * `theme-document.ts` owns the writes; `theme-persistence.ts` owns the store.\n */\n\n/**\n * Four independent choices, and keeping them independent is the point:\n *\n * - **appearance** — light, dark, or follow the system.\n * - **a theme per appearance** — so a user can run Catppuccin Mocha by night and\n * Solarized Light by day without re-choosing when the system flips.\n * - **an accent** — adea's six presets, or one of the accents the selected theme\n * pair carries itself (`ansi-blue`…), which re-colour the interactive roles on\n * top of whichever theme is active.\n * - **fonts** — separate family and size choices for UI, content and code.\n */\nexport type ThemeSelection = {\n /** `system` follows `prefers-color-scheme` and updates when it changes. */\n appearance: ThemeAppearance | 'system'\n /** The variant to use when the resolved appearance is light. */\n lightThemeId: string\n /** The variant to use when the resolved appearance is dark. */\n darkThemeId: string\n /**\n * An `accentPresets` id, a theme accent id from `themeAccents()` (`ansi-blue`…),\n * or `theme` for the variant's own primary. A theme accent the current pair does\n * not offer falls back to the variant's own primary.\n */\n accent: string\n /** UI-family alias for consumers of the original single-font preference. */\n font: string\n /** UI, content and code font settings. Omitted legacy records are migrated from `font`. */\n fonts?: AppearanceEditorFontSettings\n /**\n * `comfortable` is the system's default geometry; `compact` moves the control\n * ladder down one rung.\n *\n * Optional, and defaulted on read, so a preference stored before density existed\n * keeps working and `ThemeSelection` stays assignable without it.\n */\n density?: ThemeDensity\n}\n\n/**\n * The two density rungs.\n *\n * `comfortable` is the geometry in `theme.css`, so it is the absence of an\n * attribute rather than a value: a document that ships no `data-density` at all\n * renders correctly, which is what keeps this additive.\n */\nexport type ThemeDensity = 'comfortable' | 'compact'\n\n/**\n * Deliberately lists only the fields every consumer has always had. A field added\n * to {@link ThemeSelection} later gets no default here: `JSON.stringify` drops an\n * `undefined`, so a store written by a consumer that never sets the field stays\n * byte-identical to what it was before the field existed.\n */\nexport const defaultThemeSelection: ThemeSelection = {\n appearance: 'system',\n lightThemeId: defaultLightThemeId,\n darkThemeId: defaultDarkThemeId,\n accent: 'theme',\n font: 'system',\n fonts: DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS,\n density: 'comfortable',\n}\n\n/**\n * A stored selection's density, defaulted.\n *\n * The stored value is read through here rather than trusted, because a preference\n * written before density existed has no `density` key and a hand-edited store may\n * hold anything.\n */\nexport function resolvedDensity(selection: ThemeSelection): ThemeDensity {\n return selection.density === 'compact' ? 'compact' : 'comfortable'\n}\n\nexport type ThemeContextValue = {\n /** The preference as stored. A {@link ThemeContextValue.preview} does not change it. */\n selection: () => ThemeSelection\n /** What the preference resolves to right now, after `system`. */\n resolvedAppearance: () => ThemeAppearance\n /** The variant in use. */\n variant: () => ThemeVariant\n /** Update part of the preference. */\n setSelection: (patch: Partial<ThemeSelection>) => void\n /**\n * The built-in catalogue, so a picker does not import it separately. A plain\n * array: {@link ThemeContextValue.allThemes} is the one that follows a host's\n * extra themes.\n */\n themes: readonly ThemeVariant[]\n /**\n * The accents the selected light/dark pair carries, offered beside the presets.\n * Follows the selection: a different theme pair may offer different slots.\n */\n themeAccents: () => readonly AccentPreset[]\n /**\n * The built-in catalogue followed by the provider's `themes` prop. Reactive when\n * that prop is a function that reads signals.\n */\n allThemes: () => readonly ThemeVariant[]\n /**\n * Paint the document from `draft` laid over the stored selection, without\n * persisting it or changing what {@link ThemeContextValue.selection} returns.\n * `undefined` ends the preview. A {@link ThemeContextValue.setSelection} ends it\n * too, because the committed selection is then what should be showing.\n */\n preview: (draft: Partial<ThemeSelection> | undefined) => void\n /** True while a {@link ThemeContextValue.preview} draft is on the document. */\n previewing: () => boolean\n}\n\n/** A selection with the `undefined` keys of a patch left out. */\nfunction definedOnly<T extends object>(value: T): Partial<T> {\n return Object.fromEntries(\n Object.entries(value).filter(([, entry]) => entry !== undefined)\n ) as Partial<T>\n}\n\n/** Keep the deprecated single-font view synchronized with the UI axis. */\nexport function mergeThemeSelection(\n base: ThemeSelection,\n patch: Partial<ThemeSelection>\n): ThemeSelection {\n const merged = { ...base, ...patch }\n let fonts: AppearanceEditorFontSettings\n\n if (patch.fonts !== undefined) {\n fonts = normalizeAppearanceEditorFontSettings(patch.fonts).settings\n } else if (patch.font !== undefined) {\n const currentFonts = normalizeAppearanceEditorFontSettings(base.fonts, base.font).settings\n fonts = normalizeAppearanceEditorFontSettings({\n ...currentFonts,\n ui: { ...currentFonts.ui, family: patch.font },\n }).settings\n } else {\n fonts = normalizeAppearanceEditorFontSettings(merged.fonts, merged.font).settings\n }\n\n return { ...merged, fonts, font: fonts.ui.family }\n}\n\n/**\n * The selection a provider starts from: the defaults, then whatever the store\n * returned, then `initial`.\n *\n * `initial` wins over the store on every mount. That precedence is part of the\n * contract Cortana relies on (its `initial` pins `appearance` and `font`), and it\n * is why the store's answer is only the middle layer. A store that returned\n * nothing, or threw, or answered with explicit `undefined`s, leaves the defaults\n * standing for those fields.\n */\nexport function initialThemeSelection(\n stored: Partial<ThemeSelection> | undefined,\n initial: Partial<ThemeSelection> | undefined\n): ThemeSelection {\n const base = mergeThemeSelection(defaultThemeSelection, definedOnly(stored ?? {}))\n return mergeThemeSelection(base, initial ?? {})\n}\n\n/** `system` resolved against what the operating system reports. */\nexport function resolveAppearance(\n preference: ThemeSelection['appearance'],\n system: ThemeAppearance\n): ThemeAppearance {\n return preference === 'system' ? system : preference\n}\n\n/** The theme id the selection names for a resolved appearance. */\nexport function selectedThemeId(selection: ThemeSelection, appearance: ThemeAppearance): string {\n return appearance === 'dark' ? selection.darkThemeId : selection.lightThemeId\n}\n\n/**\n * What a selection paints: the resolved appearance and the variant for it.\n *\n * An id the registry does not hold resolves to the appearance's default rather than\n * being rewritten (see `resolveVariant`), so the selection a host stores is never\n * changed by being unresolvable.\n */\nexport function resolveThemeState(\n selection: ThemeSelection,\n system: ThemeAppearance,\n registry: readonly ThemeVariant[]\n): { appearance: ThemeAppearance; variant: ThemeVariant } {\n const appearance = resolveAppearance(selection.appearance, system)\n return {\n appearance,\n variant: resolveVariant(registry, selectedThemeId(selection, appearance), appearance),\n }\n}\n\n/**\n * The registry a provider resolves against: the catalogue, then the host's extras.\n *\n * The catalogue wins an id collision, because it is listed first and `resolveVariant`\n * takes the first match: a host's variant can add a theme but cannot shadow one.\n */\nexport function mergeRegistry(\n builtin: readonly ThemeVariant[],\n extra: readonly ThemeVariant[] | undefined\n): readonly ThemeVariant[] {\n return extra && extra.length > 0 ? [...builtin, ...extra] : builtin\n}\n"],"mappings":";;;;;;;;;AA4EA,IAAa,wBAAwC;CACnD,YAAY;CACZ,cAAc;CACd,aAAa;CACb,QAAQ;CACR,MAAM;CACN,OAAO;CACP,SAAS;AACX;;;;;;;;AASA,SAAgB,gBAAgB,WAAyC;CACvE,OAAO,UAAU,YAAY,YAAY,YAAY;AACvD;;AAuCA,SAAS,YAA8B,OAAsB;CAC3D,OAAO,OAAO,YACZ,OAAO,QAAQ,KAAK,CAAC,CAAC,QAAQ,GAAG,WAAW,UAAU,KAAA,CAAS,CACjE;AACF;;AAGA,SAAgB,oBACd,MACA,OACgB;CAChB,MAAM,SAAS;EAAE,GAAG;EAAM,GAAG;CAAM;CACnC,IAAI;CAEJ,IAAI,MAAM,UAAU,KAAA,GAClB,QAAQ,sCAAsC,MAAM,KAAK,CAAC,CAAC;MACtD,IAAI,MAAM,SAAS,KAAA,GAAW;EACnC,MAAM,eAAe,sCAAsC,KAAK,OAAO,KAAK,IAAI,CAAC,CAAC;EAClF,QAAQ,sCAAsC;GAC5C,GAAG;GACH,IAAI;IAAE,GAAG,aAAa;IAAI,QAAQ,MAAM;GAAK;EAC/C,CAAC,CAAC,CAAC;CACL,OACE,QAAQ,sCAAsC,OAAO,OAAO,OAAO,IAAI,CAAC,CAAC;CAG3E,OAAO;EAAE,GAAG;EAAQ;EAAO,MAAM,MAAM,GAAG;CAAO;AACnD;;;;;;;;;;;AAYA,SAAgB,sBACd,QACA,SACgB;CAEhB,OAAO,oBADM,oBAAoB,uBAAuB,YAAY,UAAU,CAAC,CAAC,CACrD,GAAM,WAAW,CAAC,CAAC;AAChD;;AAGA,SAAgB,kBACd,YACA,QACiB;CACjB,OAAO,eAAe,WAAW,SAAS;AAC5C;;AAGA,SAAgB,gBAAgB,WAA2B,YAAqC;CAC9F,OAAO,eAAe,SAAS,UAAU,cAAc,UAAU;AACnE;;;;;;;;AASA,SAAgB,kBACd,WACA,QACA,UACwD;CACxD,MAAM,aAAa,kBAAkB,UAAU,YAAY,MAAM;CACjE,OAAO;EACL;EACA,SAAS,eAAe,UAAU,gBAAgB,WAAW,UAAU,GAAG,UAAU;CACtF;AACF;;;;;;;AAQA,SAAgB,cACd,SACA,OACyB;CACzB,OAAO,SAAS,MAAM,SAAS,IAAI,CAAC,GAAG,SAAS,GAAG,KAAK,IAAI;AAC9D"}
|
|
1
|
+
{"version":3,"file":"theme-state.js","names":[],"sources":["../../../src/components/theme/theme-state.ts"],"sourcesContent":["import {\n DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS,\n normalizeAppearanceEditorFontSettings,\n type AppearanceEditorFontSettings,\n} from '#lib/appearance-font-settings'\nimport type { AccentPreset } from '@adea-ai/themes'\nimport { normalizeCustomAccent, type AccentRoles } from '#lib/accent-roles'\nimport {\n accentRolesForSelection,\n defaultDarkThemeId,\n defaultLightThemeId,\n resolveVariant,\n type ThemeAppearance,\n type ThemeVariant,\n} from '#lib/themes'\n\n/**\n * The pure half of the theme provider: what a selection is, how two selections\n * merge, and what a selection resolves to.\n *\n * Nothing here touches the document, storage or a signal, so each rule can be\n * tested by calling it. `ThemeProvider` owns the reactivity and wires these to it;\n * `theme-document.ts` owns the writes; `theme-persistence.ts` owns the store.\n */\n\n/**\n * Four independent choices, and keeping them independent is the point:\n *\n * - **appearance** — light, dark, or follow the system.\n * - **a theme per appearance** — so a user can run Catppuccin Mocha by night and\n * Solarized Light by day without re-choosing when the system flips.\n * - **an accent** — adea's six presets, or one of the accents the selected theme\n * pair carries itself (`ansi-blue`…), which re-colour the interactive roles on\n * top of whichever theme is active.\n * - **fonts** — separate family and size choices for UI, content and code.\n */\nexport type ThemeSelection = {\n /** `system` follows `prefers-color-scheme` and updates when it changes. */\n appearance: ThemeAppearance | 'system'\n /** The variant to use when the resolved appearance is light. */\n lightThemeId: string\n /** The variant to use when the resolved appearance is dark. */\n darkThemeId: string\n /**\n * An `accentPresets` id, a theme accent id from `themeAccents()` (`ansi-blue`…),\n * `theme` for the variant's own primary, or a custom colour as `#rrggbb`. A theme\n * accent the current pair does not offer falls back to the variant's own primary.\n *\n * A custom colour is stored lower case and is raised to the contrast floor when it\n * is painted, never when it is stored: the selection keeps what the user chose.\n * Anything else that is not an id is dropped at paint, not rejected here.\n */\n accent: string\n /** UI-family alias for consumers of the original single-font preference. */\n font: string\n /** UI, content and code font settings. Omitted legacy records are migrated from `font`. */\n fonts?: AppearanceEditorFontSettings\n /**\n * `comfortable` is the system's default geometry; `compact` moves the control\n * ladder down one rung.\n *\n * Optional, and defaulted on read, so a preference stored before density existed\n * keeps working and `ThemeSelection` stays assignable without it.\n */\n density?: ThemeDensity\n}\n\n/**\n * The two density rungs.\n *\n * `comfortable` is the geometry in `theme.css`, so it is the absence of an\n * attribute rather than a value: a document that ships no `data-density` at all\n * renders correctly, which is what keeps this additive.\n */\nexport type ThemeDensity = 'comfortable' | 'compact'\n\n/**\n * Deliberately lists only the fields every consumer has always had. A field added\n * to {@link ThemeSelection} later gets no default here: `JSON.stringify` drops an\n * `undefined`, so a store written by a consumer that never sets the field stays\n * byte-identical to what it was before the field existed.\n */\nexport const defaultThemeSelection: ThemeSelection = {\n appearance: 'system',\n lightThemeId: defaultLightThemeId,\n darkThemeId: defaultDarkThemeId,\n accent: 'theme',\n font: 'system',\n fonts: DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS,\n density: 'comfortable',\n}\n\n/**\n * A stored selection's density, defaulted.\n *\n * The stored value is read through here rather than trusted, because a preference\n * written before density existed has no `density` key and a hand-edited store may\n * hold anything.\n */\nexport function resolvedDensity(selection: ThemeSelection): ThemeDensity {\n return selection.density === 'compact' ? 'compact' : 'comfortable'\n}\n\nexport type ThemeContextValue = {\n /** The preference as stored. A {@link ThemeContextValue.preview} does not change it. */\n selection: () => ThemeSelection\n /** What the preference resolves to right now, after `system`. */\n resolvedAppearance: () => ThemeAppearance\n /** The variant in use. */\n variant: () => ThemeVariant\n /** Update part of the preference. */\n setSelection: (patch: Partial<ThemeSelection>) => void\n /**\n * The built-in catalogue, so a picker does not import it separately. A plain\n * array: {@link ThemeContextValue.allThemes} is the one that follows a host's\n * extra themes.\n */\n themes: readonly ThemeVariant[]\n /**\n * The accents the selected light/dark pair carries, offered beside the presets.\n * Follows the selection: a different theme pair may offer different slots.\n */\n themeAccents: () => readonly AccentPreset[]\n /**\n * The built-in catalogue followed by the provider's `themes` prop. Reactive when\n * that prop is a function that reads signals.\n */\n allThemes: () => readonly ThemeVariant[]\n /**\n * Paint the document from `draft` laid over the stored selection, without\n * persisting it or changing what {@link ThemeContextValue.selection} returns.\n * `undefined` ends the preview. A {@link ThemeContextValue.setSelection} ends it\n * too, because the committed selection is then what should be showing.\n */\n preview: (draft: Partial<ThemeSelection> | undefined) => void\n /** True while a {@link ThemeContextValue.preview} draft is on the document. */\n previewing: () => boolean\n /**\n * The roles `accent` paints over `variantId` (default: the variant in use), held\n * to the provider's `accentContrastFloor`, for an element-scoped override with\n * `paintAccentRoles` — a workspace that carries its own colour. `undefined` for\n * `null`, for `theme`, for an id that resolves to nothing, and for a variant the\n * registry does not hold: each means \"keep the inherited accent\".\n */\n accentRolesFor: (accent: string | null, variantId?: string) => AccentRoles | undefined\n}\n\n/** A selection with the `undefined` keys of a patch left out. */\nfunction definedOnly<T extends object>(value: T): Partial<T> {\n return Object.fromEntries(\n Object.entries(value).filter(([, entry]) => entry !== undefined)\n ) as Partial<T>\n}\n\n/** Keep the deprecated single-font view synchronized with the UI axis. */\nexport function mergeThemeSelection(\n base: ThemeSelection,\n patch: Partial<ThemeSelection>\n): ThemeSelection {\n const merged = { ...base, ...patch }\n let fonts: AppearanceEditorFontSettings\n\n if (patch.fonts !== undefined) {\n fonts = normalizeAppearanceEditorFontSettings(patch.fonts).settings\n } else if (patch.font !== undefined) {\n const currentFonts = normalizeAppearanceEditorFontSettings(base.fonts, base.font).settings\n fonts = normalizeAppearanceEditorFontSettings({\n ...currentFonts,\n ui: { ...currentFonts.ui, family: patch.font },\n }).settings\n } else {\n fonts = normalizeAppearanceEditorFontSettings(merged.fonts, merged.font).settings\n }\n\n return {\n ...merged,\n // One spelling for a custom colour, so equal choices compare and store equal.\n accent: normalizeCustomAccent(merged.accent) ?? merged.accent,\n fonts,\n font: fonts.ui.family,\n }\n}\n\n/**\n * The selection a provider starts from: the defaults, then whatever the store\n * returned, then `initial`.\n *\n * `initial` wins over the store on every mount. That precedence is part of the\n * contract Cortana relies on (its `initial` pins `appearance` and `font`), and it\n * is why the store's answer is only the middle layer. A store that returned\n * nothing, or threw, or answered with explicit `undefined`s, leaves the defaults\n * standing for those fields.\n */\nexport function initialThemeSelection(\n stored: Partial<ThemeSelection> | undefined,\n initial: Partial<ThemeSelection> | undefined\n): ThemeSelection {\n const base = mergeThemeSelection(defaultThemeSelection, definedOnly(stored ?? {}))\n return mergeThemeSelection(base, initial ?? {})\n}\n\n/** `system` resolved against what the operating system reports. */\nexport function resolveAppearance(\n preference: ThemeSelection['appearance'],\n system: ThemeAppearance\n): ThemeAppearance {\n return preference === 'system' ? system : preference\n}\n\n/** The theme id the selection names for a resolved appearance. */\nexport function selectedThemeId(selection: ThemeSelection, appearance: ThemeAppearance): string {\n return appearance === 'dark' ? selection.darkThemeId : selection.lightThemeId\n}\n\n/**\n * What a selection paints: the resolved appearance and the variant for it.\n *\n * An id the registry does not hold resolves to the appearance's default rather than\n * being rewritten (see `resolveVariant`), so the selection a host stores is never\n * changed by being unresolvable.\n */\nexport function resolveThemeState(\n selection: ThemeSelection,\n system: ThemeAppearance,\n registry: readonly ThemeVariant[]\n): { appearance: ThemeAppearance; variant: ThemeVariant } {\n const appearance = resolveAppearance(selection.appearance, system)\n return {\n appearance,\n variant: resolveVariant(registry, selectedThemeId(selection, appearance), appearance),\n }\n}\n\n/**\n * The registry a provider resolves against: the catalogue, then the host's extras.\n *\n * The catalogue wins an id collision, because it is listed first and `resolveVariant`\n * takes the first match: a host's variant can add a theme but cannot shadow one.\n */\nexport function mergeRegistry(\n builtin: readonly ThemeVariant[],\n extra: readonly ThemeVariant[] | undefined\n): readonly ThemeVariant[] {\n return extra && extra.length > 0 ? [...builtin, ...extra] : builtin\n}\n\n/**\n * The roles an accent paints over a variant, for {@link ThemeContextValue.accentRolesFor}.\n *\n * Resolved against the committed selection's theme pair, so an `ansi-*` accent means\n * the same colour here as it does on `<html>`.\n */\nexport function accentRolesForState(\n accent: string | null,\n variantId: string | undefined,\n state: {\n selection: ThemeSelection\n variant: ThemeVariant\n registry: readonly ThemeVariant[]\n accentContrastFloor?: number\n }\n): AccentRoles | undefined {\n if (accent === null) return undefined\n const variant =\n variantId === undefined\n ? state.variant\n : state.registry.find((candidate) => candidate.id === variantId)\n if (!variant) return undefined\n return accentRolesForSelection(accent, variant.appearance, state.selection, {\n background: variant.colors.background,\n floor: state.accentContrastFloor,\n variantId: variant.id,\n })\n}\n"],"mappings":";;;;;;;;;;AAkFA,IAAa,wBAAwC;CACnD,YAAY;CACZ,cAAc;CACd,aAAa;CACb,QAAQ;CACR,MAAM;CACN,OAAO;CACP,SAAS;AACX;;;;;;;;AASA,SAAgB,gBAAgB,WAAyC;CACvE,OAAO,UAAU,YAAY,YAAY,YAAY;AACvD;;AA+CA,SAAS,YAA8B,OAAsB;CAC3D,OAAO,OAAO,YACZ,OAAO,QAAQ,KAAK,CAAC,CAAC,QAAQ,GAAG,WAAW,UAAU,KAAA,CAAS,CACjE;AACF;;AAGA,SAAgB,oBACd,MACA,OACgB;CAChB,MAAM,SAAS;EAAE,GAAG;EAAM,GAAG;CAAM;CACnC,IAAI;CAEJ,IAAI,MAAM,UAAU,KAAA,GAClB,QAAQ,sCAAsC,MAAM,KAAK,CAAC,CAAC;MACtD,IAAI,MAAM,SAAS,KAAA,GAAW;EACnC,MAAM,eAAe,sCAAsC,KAAK,OAAO,KAAK,IAAI,CAAC,CAAC;EAClF,QAAQ,sCAAsC;GAC5C,GAAG;GACH,IAAI;IAAE,GAAG,aAAa;IAAI,QAAQ,MAAM;GAAK;EAC/C,CAAC,CAAC,CAAC;CACL,OACE,QAAQ,sCAAsC,OAAO,OAAO,OAAO,IAAI,CAAC,CAAC;CAG3E,OAAO;EACL,GAAG;EAEH,QAAQ,sBAAsB,OAAO,MAAM,KAAK,OAAO;EACvD;EACA,MAAM,MAAM,GAAG;CACjB;AACF;;;;;;;;;;;AAYA,SAAgB,sBACd,QACA,SACgB;CAEhB,OAAO,oBADM,oBAAoB,uBAAuB,YAAY,UAAU,CAAC,CAAC,CACrD,GAAM,WAAW,CAAC,CAAC;AAChD;;AAGA,SAAgB,kBACd,YACA,QACiB;CACjB,OAAO,eAAe,WAAW,SAAS;AAC5C;;AAGA,SAAgB,gBAAgB,WAA2B,YAAqC;CAC9F,OAAO,eAAe,SAAS,UAAU,cAAc,UAAU;AACnE;;;;;;;;AASA,SAAgB,kBACd,WACA,QACA,UACwD;CACxD,MAAM,aAAa,kBAAkB,UAAU,YAAY,MAAM;CACjE,OAAO;EACL;EACA,SAAS,eAAe,UAAU,gBAAgB,WAAW,UAAU,GAAG,UAAU;CACtF;AACF;;;;;;;AAQA,SAAgB,cACd,SACA,OACyB;CACzB,OAAO,SAAS,MAAM,SAAS,IAAI,CAAC,GAAG,SAAS,GAAG,KAAK,IAAI;AAC9D;;;;;;;AAQA,SAAgB,oBACd,QACA,WACA,OAMyB;CACzB,IAAI,WAAW,MAAM,OAAO,KAAA;CAC5B,MAAM,UACJ,cAAc,KAAA,IACV,MAAM,UACN,MAAM,SAAS,MAAM,cAAc,UAAU,OAAO,SAAS;CACnE,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,OAAO,wBAAwB,QAAQ,QAAQ,YAAY,MAAM,WAAW;EAC1E,YAAY,QAAQ,OAAO;EAC3B,OAAO,MAAM;EACb,WAAW,QAAQ;CACrB,CAAC;AACH"}
|
package/dist/index.d.ts
CHANGED
|
@@ -103,6 +103,7 @@ export * from './components/composites/about-dialog';
|
|
|
103
103
|
export * from './components/composites/help-center';
|
|
104
104
|
export * from './components/composites/workspace-mark';
|
|
105
105
|
export { cn } from './lib/utils';
|
|
106
|
+
export { isCustomAccent, normalizeCustomAccent, paintAccentRoles, resolveAccentRoles, type AccentRoles, type AccentTarget, } from './lib/accent-roles';
|
|
106
107
|
export { controlInteractive, controlSize, controlSizeIcon, controlSizes, cva, surfaceInteractive, type ControlSize, type VariantProps, } from './lib/variants';
|
|
107
108
|
export { appearancePreviewThemes, builtinThemes, contrastRatio, defaultDarkThemeId, defaultLightThemeId, isThemeAccentId, resolveAccentPreset, resolveVariant, themeAccentsFor, themeById, themeCssVariables, themeFamilies, themeRecordById, themeRecords, themesForAppearance, tokensAsHex, validateTheme, validateThemeRegistry, variantFromRecord, withAccent, type ThemeAppearance, type ThemeColors, type ThemeEditorPalette, type ThemeFinding, type ThemeProvenance, type ThemeTerminalPalette, type ThemeVariant, } from './lib/themes';
|
|
108
109
|
export { keyedRows, type KeyedRow } from './lib/keyed-rows';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -103,6 +103,7 @@ import { AttachmentCard, ThreadPanel } from "./components/conversation/thread-pa
|
|
|
103
103
|
import { PASTE_THRESHOLD_CHARS, PASTE_THRESHOLD_LINES, PASTE_TOKEN_REGEX, countLines, expandAll, findTokenRanges, formatToken, isPasteBlock, nextSeq, pruneBlocks, recollapsePastes, remapCarriedBlocks, shouldCollapse, stripTrailingBlankLines, tokenRangeAt } from "./components/conversation/paste-tokens.js";
|
|
104
104
|
import { fontOptions } from "./lib/font-catalog.js";
|
|
105
105
|
import { accentPresets, allTokens, colorTokens, densityTokens, designTokens, elevationTokens, motionTokens, radiusTokens, typographyTokens, undocumentedTokenAliases, zIndexTokens } from "./lib/tokens.js";
|
|
106
|
+
import { isCustomAccent, normalizeCustomAccent, paintAccentRoles, resolveAccentRoles } from "./lib/accent-roles.js";
|
|
106
107
|
import { isThemeAccentId } from "./lib/theme-accents.js";
|
|
107
108
|
import { appearancePreviewThemes, builtinThemes, contrastRatio, defaultDarkThemeId, defaultLightThemeId, resolveAccentPreset, resolveVariant, themeAccentsFor, themeById, themeCssVariables, themeFamilies, themeRecordById, themeRecords, themesForAppearance, tokensAsHex, validateTheme, validateThemeRegistry, variantFromRecord, withAccent } from "./lib/themes.js";
|
|
108
109
|
import { APPEARANCE_EDITOR_FONT_AXES, APPEARANCE_EDITOR_FONT_SIZE_MAX, APPEARANCE_EDITOR_FONT_SIZE_MIN, DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS, applyAppearanceFontSettings, fontSettingsBootstrapScript, normalizeAppearanceEditorFontSettings, normalizeAppearanceEditorFontSize } from "./lib/appearance-font-settings.js";
|
|
@@ -136,4 +137,4 @@ import { AboutDialog } from "./components/composites/about-dialog/about-dialog.j
|
|
|
136
137
|
import { HelpCenter } from "./components/composites/help-center/help-center.js";
|
|
137
138
|
import { WorkspaceMark } from "./components/composites/workspace-mark/workspace-mark.js";
|
|
138
139
|
import { writeClipboardText } from "./lib/clipboard.js";
|
|
139
|
-
export { APPEARANCE_EDITOR_FONT_AXES, APPEARANCE_EDITOR_FONT_SIZE_MAX, APPEARANCE_EDITOR_FONT_SIZE_MIN, AboutDialog, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AccountMenu, ActionButton, Alert, AlertAction, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnnotationSurface, AppShell, AppShellBody, AppShellContent, AppShellMain, AppearanceEditor, AppearanceEditorActions, AppearanceFontSettingsGroup, AppearancePanel, AppearancePopover, AspectRatio, AttachmentCard, Avatar, AvatarFallback, AvatarImage, Badge, Board, BoardCardBody, BoardCardTitle, BoardCardTrigger, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, BusySendButton, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CalendarSurface, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CatalogBrowser, CatalogDetail, CatalogDetailSection, ChatComposer, Checkbox, CheckboxDescription, CheckboxLabel, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxClear, ComboboxContent, ComboboxControl, ComboboxInput, ComboboxItem, ComboboxSection, ComboboxTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandHint, CommandInput, CommandItem, CommandList, CommandLoading, CommandSeparator, CommandShortcut, CommandStatus, ComposerAttachmentButton, ComposerHint, ComposerMenu, ComposerMenuItem, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, ContextualSidebar, ConversationAvatar, ConversationPane, ConversationSurface, DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS, DatePicker, DetailPanel, DetailPanelBody, DetailPanelField, DetailPanelHeader, DetailPanelSection, Dialog, DialogClose, DialogCloseButton, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffBlock, DiffSummary, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, EntityIcon, FLOATING_PREVIEW_CORNER_RADIUS, FLOATING_PREVIEW_EDGE_GAP, Field, FieldDescription, FieldError, FieldGroup, FieldInput, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTextArea, FloatingPreview, FormField, Heading, HelpCenter, HoverCard, HoverCardContent, HoverCardTrigger, InlineCode, Input, InputControl, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputOtp, InputOtpCaret, Item, ItemDescription, ItemEmpty, ItemGroup, ItemGroupEntry, ItemTitle, Kbd, KbdChord, KbdGroup, Label, ListGroup, ListRow, ListRowControl, MAX_LAYOUT_DEPTH, MAX_LAYOUT_LEAVES, MAX_SPLIT_RATIO, MIN_SPLIT_RATIO, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MessageBody, MessageComposer, MessageDayDivider, MessageGroup, MessageRow, ModalDialog, Motion, NO_FLOATING_PREVIEW_OBSTACLES, NO_PREVIEW_MINI_PLAYER_OBSTACLES, NativeSelect, NavigationMenu, NavigationMenuContent, NavigationMenuGroup, NavigationMenuGroupLabel, NavigationMenuItem, NavigationMenuMenu, NavigationMenuSeparator, NavigationMenuTrigger, NavigationMenuViewport, NumberField, OrbitItem, OrbitLayout, PASTE_THRESHOLD_CHARS, PASTE_THRESHOLD_LINES, PASTE_TOKEN_REGEX, PREVIEW_MINI_PLAYER_CORNER_RADIUS, PREVIEW_MINI_PLAYER_EDGE_GAP, Page, PageHeader, PageHeaderActions, PageHeaderContent, PageHeaderDescription, PageHeaderTitle, PageSection, Pagination, PaginationEllipsis, PaginationItem, PaginationNext, PaginationPrevious, PalettePreview, Panel, PanelActions, PanelBody, PanelCard, PanelDescription, PanelFooter, PanelHeader, PanelPlaceholder, PanelTitle, PanelToolbar, PixelResizeHandle, Popover, PopoverAnchor, PopoverCloseButton, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger, Presence, Progress, PropertyList, PropertyRow, PropertyTerm, PropertyValue, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, SceneControls, ScrollArea, SecretInputGroup, Select, SelectChevronsUpDown, SelectContent, SelectItem, SelectLabel, SelectSection, SelectTrigger, SelectValue, Separator, SettingsField, SettingsLayout, SettingsNavigation, SettingsPage, SettingsRow, SettingsSection, Sheet, SheetBody, SheetCloseButton, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, SideRail, SideRailButton, SideRailContent, SideRailFooter, SideRailHeader, SideRailItem, SideRailSection, SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavLabel, SidebarNavResizeHandle, SidebarNavRow, SidebarNavSection, SidebarNavTitle, Skeleton, SkipLink, Slider, Spinner, SplitLayout, Stat, StatGroup, StatusBar, StatusBarItem, StatusBarSpacer, StatusChip, StatusList, Switch, SwitchDescription, SwitchLabel, TALL_CODE_BLOCK_PX, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableNumericCell, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Text, TextLink, Textarea, ThemeMiniature, ThemeMiniatureSplit, ThemeModeToggle, ThemePicker, ThemePreview, ThemeProvider, ThemeSwatch, ThemeToggle, ThreadPanel, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TopBar, TopBarBreadcrumb, TopBarPill, TopBarSearch, TopBarSection, TopBarTitle, TranscriptComposition, Tree, TreeRow, TreeRowActions, UpdateChannelControl, UpdateDialog, ValueCombobox, VirtualWindow, WorkspaceMark, accentPresets, alertVariants, allTokens, appearancePreviewThemes, applyAppearanceFontSettings, badgeVariants, boardCardTitleVariants, builtinThemes, buttonVariants, cardVariants, clampFloatingPreviewPosition, clampPreviewMiniPlayerPosition, closePane, cn, colorTokens, computeLayoutFrames, contrastRatio, controlInteractive, controlSize, controlSizeIcon, controlSizes, countLeaves, countLines, createAppMenuItems, createLayoutState, cva, defaultDarkThemeId, defaultLightThemeId, defaultThemeSelection, densityTokens, designTokens, diffLineVariants, diffStats, diffTargetPath, elevationTokens, entityIconVariants, expandAll, findTokenRanges, focusPane, fontOptions, fontSettingsBootstrapScript, formatBytes, formatReleaseDate, formatToken, headingElement, headingVariants, initialsFrom, inlineScriptLiteral, isPasteBlock, isThemeAccentId, itemVariants, kbdChordKeys, kbdGroupVariants, kbdVariants, keyedRows, layoutDepth, listLeaves, localStoragePersistence, monogram, motionTokens, movePane, neighborLeaf, nextSeq, normalizeAppearanceEditorFontSettings, normalizeAppearanceEditorFontSize, normalizeLayout, parseDiff, plainTextFromMarkdown, platformModifierKey, pruneBlocks, radiusTokens, recollapsePastes, remapCarriedBlocks, resizeFloatingPreview, resizePreviewMiniPlayer, resizeSplit, resolveAccentPreset, resolveFloatingPreviewFrame, resolvePreviewMiniPlayerFrame, resolveVariant, resolvedDensity, searchShortcutKeyshortcuts, searchShortcutLabel, sheetVariants, shouldCollapse, sidebarNavItemClass, sidebarNavItemStateClass, splitPane, splitPaneBalanced, statusDotVariants, stripTrailingBlankLines, surfaceInteractive, swapPanes, textElement, textVariants, textareaVariants, themeAccentsFor, themeById, themeCssVariables, themeFamilies, themeRecordById, themeRecords, themeScript, themesForAppearance, toast, toaster, toggleVariants, tokenRangeAt, tokensAsHex, transcriptDisclosureKey, typographyTokens, undoClosePane, undocumentedTokenAliases, useOptionalTheme, useSideRail, useTheme, validateTheme, validateThemeRegistry, variantFromRecord, withAccent, writeClipboardText, zIndexTokens };
|
|
140
|
+
export { APPEARANCE_EDITOR_FONT_AXES, APPEARANCE_EDITOR_FONT_SIZE_MAX, APPEARANCE_EDITOR_FONT_SIZE_MIN, AboutDialog, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AccountMenu, ActionButton, Alert, AlertAction, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnnotationSurface, AppShell, AppShellBody, AppShellContent, AppShellMain, AppearanceEditor, AppearanceEditorActions, AppearanceFontSettingsGroup, AppearancePanel, AppearancePopover, AspectRatio, AttachmentCard, Avatar, AvatarFallback, AvatarImage, Badge, Board, BoardCardBody, BoardCardTitle, BoardCardTrigger, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, BusySendButton, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CalendarSurface, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CatalogBrowser, CatalogDetail, CatalogDetailSection, ChatComposer, Checkbox, CheckboxDescription, CheckboxLabel, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxClear, ComboboxContent, ComboboxControl, ComboboxInput, ComboboxItem, ComboboxSection, ComboboxTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandHint, CommandInput, CommandItem, CommandList, CommandLoading, CommandSeparator, CommandShortcut, CommandStatus, ComposerAttachmentButton, ComposerHint, ComposerMenu, ComposerMenuItem, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, ContextualSidebar, ConversationAvatar, ConversationPane, ConversationSurface, DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS, DatePicker, DetailPanel, DetailPanelBody, DetailPanelField, DetailPanelHeader, DetailPanelSection, Dialog, DialogClose, DialogCloseButton, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffBlock, DiffSummary, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyState, EmptyTitle, EntityIcon, FLOATING_PREVIEW_CORNER_RADIUS, FLOATING_PREVIEW_EDGE_GAP, Field, FieldDescription, FieldError, FieldGroup, FieldInput, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTextArea, FloatingPreview, FormField, Heading, HelpCenter, HoverCard, HoverCardContent, HoverCardTrigger, InlineCode, Input, InputControl, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputOtp, InputOtpCaret, Item, ItemDescription, ItemEmpty, ItemGroup, ItemGroupEntry, ItemTitle, Kbd, KbdChord, KbdGroup, Label, ListGroup, ListRow, ListRowControl, MAX_LAYOUT_DEPTH, MAX_LAYOUT_LEAVES, MAX_SPLIT_RATIO, MIN_SPLIT_RATIO, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MessageBody, MessageComposer, MessageDayDivider, MessageGroup, MessageRow, ModalDialog, Motion, NO_FLOATING_PREVIEW_OBSTACLES, NO_PREVIEW_MINI_PLAYER_OBSTACLES, NativeSelect, NavigationMenu, NavigationMenuContent, NavigationMenuGroup, NavigationMenuGroupLabel, NavigationMenuItem, NavigationMenuMenu, NavigationMenuSeparator, NavigationMenuTrigger, NavigationMenuViewport, NumberField, OrbitItem, OrbitLayout, PASTE_THRESHOLD_CHARS, PASTE_THRESHOLD_LINES, PASTE_TOKEN_REGEX, PREVIEW_MINI_PLAYER_CORNER_RADIUS, PREVIEW_MINI_PLAYER_EDGE_GAP, Page, PageHeader, PageHeaderActions, PageHeaderContent, PageHeaderDescription, PageHeaderTitle, PageSection, Pagination, PaginationEllipsis, PaginationItem, PaginationNext, PaginationPrevious, PalettePreview, Panel, PanelActions, PanelBody, PanelCard, PanelDescription, PanelFooter, PanelHeader, PanelPlaceholder, PanelTitle, PanelToolbar, PixelResizeHandle, Popover, PopoverAnchor, PopoverCloseButton, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger, Presence, Progress, PropertyList, PropertyRow, PropertyTerm, PropertyValue, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, SceneControls, ScrollArea, SecretInputGroup, Select, SelectChevronsUpDown, SelectContent, SelectItem, SelectLabel, SelectSection, SelectTrigger, SelectValue, Separator, SettingsField, SettingsLayout, SettingsNavigation, SettingsPage, SettingsRow, SettingsSection, Sheet, SheetBody, SheetCloseButton, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, SideRail, SideRailButton, SideRailContent, SideRailFooter, SideRailHeader, SideRailItem, SideRailSection, SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavLabel, SidebarNavResizeHandle, SidebarNavRow, SidebarNavSection, SidebarNavTitle, Skeleton, SkipLink, Slider, Spinner, SplitLayout, Stat, StatGroup, StatusBar, StatusBarItem, StatusBarSpacer, StatusChip, StatusList, Switch, SwitchDescription, SwitchLabel, TALL_CODE_BLOCK_PX, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableNumericCell, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Text, TextLink, Textarea, ThemeMiniature, ThemeMiniatureSplit, ThemeModeToggle, ThemePicker, ThemePreview, ThemeProvider, ThemeSwatch, ThemeToggle, ThreadPanel, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TopBar, TopBarBreadcrumb, TopBarPill, TopBarSearch, TopBarSection, TopBarTitle, TranscriptComposition, Tree, TreeRow, TreeRowActions, UpdateChannelControl, UpdateDialog, ValueCombobox, VirtualWindow, WorkspaceMark, accentPresets, alertVariants, allTokens, appearancePreviewThemes, applyAppearanceFontSettings, badgeVariants, boardCardTitleVariants, builtinThemes, buttonVariants, cardVariants, clampFloatingPreviewPosition, clampPreviewMiniPlayerPosition, closePane, cn, colorTokens, computeLayoutFrames, contrastRatio, controlInteractive, controlSize, controlSizeIcon, controlSizes, countLeaves, countLines, createAppMenuItems, createLayoutState, cva, defaultDarkThemeId, defaultLightThemeId, defaultThemeSelection, densityTokens, designTokens, diffLineVariants, diffStats, diffTargetPath, elevationTokens, entityIconVariants, expandAll, findTokenRanges, focusPane, fontOptions, fontSettingsBootstrapScript, formatBytes, formatReleaseDate, formatToken, headingElement, headingVariants, initialsFrom, inlineScriptLiteral, isCustomAccent, isPasteBlock, isThemeAccentId, itemVariants, kbdChordKeys, kbdGroupVariants, kbdVariants, keyedRows, layoutDepth, listLeaves, localStoragePersistence, monogram, motionTokens, movePane, neighborLeaf, nextSeq, normalizeAppearanceEditorFontSettings, normalizeAppearanceEditorFontSize, normalizeCustomAccent, normalizeLayout, paintAccentRoles, parseDiff, plainTextFromMarkdown, platformModifierKey, pruneBlocks, radiusTokens, recollapsePastes, remapCarriedBlocks, resizeFloatingPreview, resizePreviewMiniPlayer, resizeSplit, resolveAccentPreset, resolveAccentRoles, resolveFloatingPreviewFrame, resolvePreviewMiniPlayerFrame, resolveVariant, resolvedDensity, searchShortcutKeyshortcuts, searchShortcutLabel, sheetVariants, shouldCollapse, sidebarNavItemClass, sidebarNavItemStateClass, splitPane, splitPaneBalanced, statusDotVariants, stripTrailingBlankLines, surfaceInteractive, swapPanes, textElement, textVariants, textareaVariants, themeAccentsFor, themeById, themeCssVariables, themeFamilies, themeRecordById, themeRecords, themeScript, themesForAppearance, toast, toaster, toggleVariants, tokenRangeAt, tokensAsHex, transcriptDisclosureKey, typographyTokens, undoClosePane, undocumentedTokenAliases, useOptionalTheme, useSideRail, useTheme, validateTheme, validateThemeRegistry, variantFromRecord, withAccent, writeClipboardText, zIndexTokens };
|