@adea-ai/ui 0.128.1 → 0.128.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/dist/components/theme/appearance-panel.js +1 -1
  2. package/dist/components/theme/index.js +1 -1
  3. package/dist/components/theme/lazy.d.ts +15 -0
  4. package/dist/components/theme/lazy.d.ts.map +1 -0
  5. package/dist/components/theme/lazy.js +9 -0
  6. package/dist/components/theme/theme-catalogue-source.d.ts +15 -0
  7. package/dist/components/theme/theme-catalogue-source.d.ts.map +1 -0
  8. package/dist/components/theme/theme-catalogue-source.js +51 -0
  9. package/dist/components/theme/theme-catalogue-source.js.map +1 -0
  10. package/dist/components/theme/theme-document-core.d.ts +123 -0
  11. package/dist/components/theme/theme-document-core.d.ts.map +1 -0
  12. package/dist/components/theme/{theme-document.js → theme-document-core.js} +12 -12
  13. package/dist/components/theme/theme-document-core.js.map +1 -0
  14. package/dist/components/theme/theme-document.d.ts +8 -107
  15. package/dist/components/theme/theme-document.d.ts.map +1 -1
  16. package/dist/components/theme/theme-persistence.d.ts +1 -1
  17. package/dist/components/theme/theme-persistence.d.ts.map +1 -1
  18. package/dist/components/theme/theme-persistence.js +9 -6
  19. package/dist/components/theme/theme-persistence.js.map +1 -1
  20. package/dist/components/theme/theme-provider-core.d.ts +19 -0
  21. package/dist/components/theme/theme-provider-core.d.ts.map +1 -0
  22. package/dist/components/theme/theme-provider-core.js +28 -0
  23. package/dist/components/theme/theme-provider-core.js.map +1 -0
  24. package/dist/components/theme/theme-provider-lazy.d.ts +28 -0
  25. package/dist/components/theme/theme-provider-lazy.d.ts.map +1 -0
  26. package/dist/components/theme/theme-provider-lazy.js +36 -0
  27. package/dist/components/theme/theme-provider-lazy.js.map +1 -0
  28. package/dist/components/theme/theme-provider-value.d.ts +175 -0
  29. package/dist/components/theme/theme-provider-value.d.ts.map +1 -0
  30. package/dist/components/theme/theme-provider-value.js +200 -0
  31. package/dist/components/theme/theme-provider-value.js.map +1 -0
  32. package/dist/components/theme/theme-provider.d.ts +11 -136
  33. package/dist/components/theme/theme-provider.d.ts.map +1 -1
  34. package/dist/components/theme/theme-provider.js +27 -149
  35. package/dist/components/theme/theme-provider.js.map +1 -1
  36. package/dist/components/theme/theme-script.js +4 -3
  37. package/dist/components/theme/theme-script.js.map +1 -1
  38. package/dist/components/theme/theme-state-core.d.ts +248 -0
  39. package/dist/components/theme/theme-state-core.d.ts.map +1 -0
  40. package/dist/components/theme/{theme-state.js → theme-state-core.js} +8 -7
  41. package/dist/components/theme/theme-state-core.js.map +1 -0
  42. package/dist/components/theme/theme-state.d.ts +8 -214
  43. package/dist/components/theme/theme-state.d.ts.map +1 -1
  44. package/dist/components/theme/theme-toggle.js.map +1 -1
  45. package/dist/index.js +7 -4
  46. package/dist/lib/accent-presets.d.ts +26 -0
  47. package/dist/lib/accent-presets.d.ts.map +1 -0
  48. package/dist/lib/accent-presets.js +11 -0
  49. package/dist/lib/accent-presets.js.map +1 -0
  50. package/dist/lib/accent-roles.js +94 -9
  51. package/dist/lib/accent-roles.js.map +1 -1
  52. package/dist/lib/font-zoom.js +4 -2
  53. package/dist/lib/font-zoom.js.map +1 -1
  54. package/dist/lib/overlay.js +3 -1
  55. package/dist/lib/overlay.js.map +1 -1
  56. package/dist/lib/theme-catalogue.d.ts +3 -0
  57. package/dist/lib/theme-catalogue.d.ts.map +1 -0
  58. package/dist/lib/theme-catalogue.js +22 -0
  59. package/dist/lib/theme-catalogue.js.map +1 -0
  60. package/dist/lib/theme-css.d.ts +43 -0
  61. package/dist/lib/theme-css.d.ts.map +1 -0
  62. package/dist/lib/theme-css.js +167 -0
  63. package/dist/lib/theme-css.js.map +1 -0
  64. package/dist/lib/theme-defaults.d.ts +46 -0
  65. package/dist/lib/theme-defaults.d.ts.map +1 -0
  66. package/dist/lib/theme-defaults.generated.d.ts +13 -0
  67. package/dist/lib/theme-defaults.generated.d.ts.map +1 -0
  68. package/dist/lib/theme-defaults.generated.js +318 -0
  69. package/dist/lib/theme-defaults.generated.js.map +1 -0
  70. package/dist/lib/theme-defaults.js +47 -0
  71. package/dist/lib/theme-defaults.js.map +1 -0
  72. package/dist/lib/theme-engine-light.d.ts +3 -0
  73. package/dist/lib/theme-engine-light.d.ts.map +1 -0
  74. package/dist/lib/theme-engine-light.js +75 -0
  75. package/dist/lib/theme-engine-light.js.map +1 -0
  76. package/dist/lib/theme-engine.d.ts +69 -0
  77. package/dist/lib/theme-engine.d.ts.map +1 -0
  78. package/dist/lib/theme-engine.js +33 -0
  79. package/dist/lib/theme-engine.js.map +1 -0
  80. package/dist/lib/themes.d.ts +14 -48
  81. package/dist/lib/themes.d.ts.map +1 -1
  82. package/dist/lib/themes.js +24 -164
  83. package/dist/lib/themes.js.map +1 -1
  84. package/dist/lib/tokens.d.ts +1 -25
  85. package/dist/lib/tokens.d.ts.map +1 -1
  86. package/dist/lib/tokens.js +1 -24
  87. package/dist/lib/tokens.js.map +1 -1
  88. package/dist/lib/tooltip-focus-gate.js +7 -1
  89. package/dist/lib/tooltip-focus-gate.js.map +1 -1
  90. package/dist/lib/variants.js +2 -2
  91. package/dist/r/lib.json +35 -0
  92. package/dist/r/registry.json +70 -0
  93. package/dist/r/src/components/theme/lazy.ts +35 -0
  94. package/dist/r/src/components/theme/theme-catalogue-source.ts +59 -0
  95. package/dist/r/src/components/theme/theme-document-core.ts +262 -0
  96. package/dist/r/src/components/theme/theme-document.ts +23 -240
  97. package/dist/r/src/components/theme/theme-persistence.ts +14 -6
  98. package/dist/r/src/components/theme/theme-provider-core.tsx +40 -0
  99. package/dist/r/src/components/theme/theme-provider-lazy.tsx +34 -0
  100. package/dist/r/src/components/theme/theme-provider-value.ts +445 -0
  101. package/dist/r/src/components/theme/theme-provider.tsx +23 -346
  102. package/dist/r/src/components/theme/theme-script.ts +3 -3
  103. package/dist/r/src/components/theme/theme-state-core.ts +364 -0
  104. package/dist/r/src/components/theme/theme-state.ts +10 -329
  105. package/dist/r/src/components/theme/theme-toggle.tsx +1 -1
  106. package/dist/r/src/lib/accent-presets.ts +43 -0
  107. package/dist/r/src/lib/theme-catalogue.ts +26 -0
  108. package/dist/r/src/lib/theme-css.ts +201 -0
  109. package/dist/r/src/lib/theme-defaults.generated.ts +319 -0
  110. package/dist/r/src/lib/theme-defaults.ts +79 -0
  111. package/dist/r/src/lib/theme-engine-light.ts +117 -0
  112. package/dist/r/src/lib/theme-engine.ts +111 -0
  113. package/dist/r/src/lib/themes.ts +27 -191
  114. package/dist/r/src/lib/tokens.ts +1 -35
  115. package/dist/r/theming.json +35 -0
  116. package/package.json +12 -3
  117. package/registry.json +70 -0
  118. package/src/components/theme/lazy.ts +35 -0
  119. package/src/components/theme/theme-catalogue-source.ts +59 -0
  120. package/src/components/theme/theme-document-core.ts +262 -0
  121. package/src/components/theme/theme-document.ts +23 -240
  122. package/src/components/theme/theme-persistence.ts +14 -6
  123. package/src/components/theme/theme-provider-core.tsx +40 -0
  124. package/src/components/theme/theme-provider-lazy.tsx +34 -0
  125. package/src/components/theme/theme-provider-value.ts +445 -0
  126. package/src/components/theme/theme-provider.tsx +23 -346
  127. package/src/components/theme/theme-script.ts +3 -3
  128. package/src/components/theme/theme-state-core.ts +364 -0
  129. package/src/components/theme/theme-state.ts +10 -329
  130. package/src/components/theme/theme-toggle.tsx +1 -1
  131. package/src/lib/accent-presets.ts +43 -0
  132. package/src/lib/theme-catalogue.ts +26 -0
  133. package/src/lib/theme-css.ts +201 -0
  134. package/src/lib/theme-defaults.generated.ts +319 -0
  135. package/src/lib/theme-defaults.ts +79 -0
  136. package/src/lib/theme-engine-light.ts +117 -0
  137. package/src/lib/theme-engine.ts +111 -0
  138. package/src/lib/themes.ts +27 -191
  139. package/src/lib/tokens.ts +1 -35
  140. package/dist/components/theme/theme-document.js.map +0 -1
  141. package/dist/components/theme/theme-state.js.map +0 -1
@@ -1,149 +1,36 @@
1
+ import { catalogueThemeEngine } from '../../lib/theme-catalogue'
1
2
  import {
2
- applyAppearanceFontSettings,
3
- normalizeAppearanceEditorFontSettings,
4
- } from '../../lib/appearance-font-settings'
5
- import {
6
- accentVariables,
7
- isCatalogueVariant,
8
- terminalCssVariables,
9
- themeCssVariables,
10
- type EditorRolesMode,
11
- type ThemeAppearance,
12
- type ThemeVariant,
13
- } from '../../lib/themes'
14
- import { isCustomAccent } from '../../lib/accent-roles'
15
- import { surfaceAlpha, type SurfaceState } from '../../lib/theme-surface'
16
- import { resolvedDensity, type ThemeSelection } from './theme-state'
17
-
18
- /**
19
- * The document half of the theme provider: the single writer of `<html>`.
20
- *
21
- * Written against the few members of an element it uses, so the rules can be tested
22
- * on a stand-in and the provider's effect stays a one-line call.
23
- */
24
- export type ThemeRoot = Pick<
25
- HTMLElement,
26
- 'classList' | 'dataset' | 'style' | 'removeAttribute' | 'setAttribute'
27
- >
28
-
29
- export type ThemeDocumentState = {
30
- /** What the document shows: the committed selection, or a preview laid over it. */
31
- selection: ThemeSelection
32
- appearance: ThemeAppearance
33
- variant: ThemeVariant
34
- /**
35
- * The variant whose terminal palette is pinned over the interface variant's.
36
- * Absent, the terminal follows the interface theme.
37
- */
38
- terminalVariant?: ThemeVariant
39
- /**
40
- * The resolved surface axis. Absent, the axis is off: no attribute and no
41
- * `--surface-alpha` is written, and any this writer wrote before is removed.
42
- */
43
- surface?: SurfaceState
44
- }
45
-
46
- export type ThemeDocumentOptions = {
47
- /**
48
- * Rewrites the custom properties just before they are written: the variant's
49
- * roles with the accent laid over them. It sees every property of the pass and
50
- * must return the full map; a name it drops is not written.
51
- */
52
- transformTokens?: (tokens: Record<string, string>) => Record<string, string>
53
- /**
54
- * The contrast an accent is held to against the variant's background. Absent, a
55
- * preset is painted verbatim (the catalogue measured it for its own themes) and
56
- * only a custom `#rrggbb` is held to the default floor of 3:1.
57
- */
58
- accentContrastFloor?: number
59
- /**
60
- * Where a catalogue variant's palette comes from. `inline` (the default) writes
61
- * every role onto the root. `stylesheet` writes none for a catalogue variant,
62
- * because the host loads a stylesheet that carries a `[data-theme]` block for it;
63
- * a variant the catalogue does not hold (a host's imported theme) is still written
64
- * inline, since no stylesheet can know it. The accent, the terminal pin, the
65
- * surface alpha and the fonts are written the same in both.
66
- *
67
- * Switching from an imported variant back to a catalogue one removes what the
68
- * imported one wrote, so nothing inline outlives it to beat the stylesheet.
69
- */
70
- palette?: 'inline' | 'stylesheet'
71
- /**
72
- * The `--editor-*` projection. `syntax` (the default) is the catalogue's quiet
73
- * syntax roles, which is what `theme-variants.css` carries; `floor` holds every
74
- * editor role to 4.5:1 on the canvas, as hex.
75
- *
76
- * With `palette: 'stylesheet'`, `floor` is the one palette write a catalogue
77
- * variant still gets: the stylesheet is generated for the default projection, so
78
- * the sixteen `--editor-*` properties are written inline over it. The rest of the
79
- * palette stays in the stylesheet.
80
- */
81
- editorRoles?: EditorRolesMode
82
- }
3
+ applyThemeToRootWith,
4
+ themeDocumentTokensWith,
5
+ type ThemeDocumentOptions,
6
+ type ThemeDocumentState,
7
+ type ThemeRoot,
8
+ } from './theme-document-core'
9
+
10
+ export {
11
+ applyWithoutTransitions,
12
+ type ThemeDocumentOptions,
13
+ type ThemeDocumentState,
14
+ type ThemeRoot,
15
+ type TransitionDocument,
16
+ } from './theme-document-core'
83
17
 
84
18
  /**
85
- * What a catalogue variant still writes inline when its palette is the stylesheet's:
86
- * nothing, unless the editor projection is not the one the stylesheet was generated
87
- * for.
88
- */
89
- function stylesheetOverrides(
90
- variant: ThemeVariant,
91
- editorRoles: EditorRolesMode | undefined
92
- ): Record<string, string> {
93
- if (editorRoles !== 'floor') return {}
94
- return Object.fromEntries(
95
- Object.entries(themeCssVariables(variant, { editor: 'floor' })).filter(([name]) =>
96
- name.startsWith('--editor-')
97
- )
98
- )
99
- }
100
-
101
- /**
102
- * The custom properties a state paints: the variant's roles, with the accent
103
- * selection laid over them, the pinned terminal palette over that, the surface
104
- * alpha, then `transformTokens`.
105
- *
106
- * The accent is applied *here* rather than left to the `[data-accent]` blocks in
107
- * `theme.css`, because the properties are written inline and an inline declaration
108
- * outranks every stylesheet selector however specific it is. The blocks still exist
109
- * and are still correct — they are what styles the window before this runs — but
110
- * they cannot win from here, so leaving the accent to them meant the attribute was
111
- * set, the rules were present, and nothing changed on screen.
19
+ * The custom properties a state paints, resolved against the whole catalogue: the
20
+ * variant's roles, with the accent selection laid over them, the pinned terminal
21
+ * palette over that, the surface alpha, then `transformTokens`. See
22
+ * {@link themeDocumentTokensWith} for the rules.
112
23
  */
113
24
  export function themeDocumentTokens(
114
25
  state: ThemeDocumentState,
115
26
  options: ThemeDocumentOptions = {}
116
27
  ): { tokens: Record<string, string>; accented: boolean } {
117
- const fromStylesheet = options.palette === 'stylesheet' && isCatalogueVariant(state.variant)
118
- const properties = fromStylesheet
119
- ? stylesheetOverrides(state.variant, options.editorRoles)
120
- : { ...themeCssVariables(state.variant, { editor: options.editorRoles }) }
121
- const accent = accentVariables(state.selection.accent, state.appearance, state.selection, {
122
- background: state.variant.colors.background,
123
- floor: options.accentContrastFloor,
124
- variantId: state.variant.id,
125
- })
126
- if (accent) Object.assign(properties, accent)
127
- // Written after the variant and the accent, so it wins over the interface
128
- // variant's own terminal ramp (and over the stylesheet's, which it outranks as an
129
- // inline declaration). Dropping the pin needs no removal of its own: the ramp is
130
- // then rewritten by the variant, or swept back to the stylesheet.
131
- if (state.terminalVariant) Object.assign(properties, terminalCssVariables(state.terminalVariant))
132
- if (state.surface) properties['--surface-alpha'] = surfaceAlpha[state.surface.surface]
133
- return {
134
- tokens: options.transformTokens ? options.transformTokens(properties) : properties,
135
- accented: accent !== undefined,
136
- }
28
+ return themeDocumentTokensWith(catalogueThemeEngine, state, options)
137
29
  }
138
30
 
139
31
  /**
140
- * Write a state onto a root and report which custom properties it owns.
141
- *
142
- * Pass the previous call's return as `previous` and any palette property that pass
143
- * wrote and this one does not is removed. For the catalogue the two sets are the
144
- * same, so nothing is ever removed; it matters for a host variant that carries
145
- * `tokens` the catalogue does not, which would otherwise stay inline, beating the
146
- * stylesheet, after the user switched away from it.
32
+ * Write a state onto a root and report which custom properties it owns, resolved
33
+ * against the whole catalogue. See {@link applyThemeToRootWith} for the rules.
147
34
  */
148
35
  export function applyThemeToRoot(
149
36
  root: ThemeRoot,
@@ -151,109 +38,5 @@ export function applyThemeToRoot(
151
38
  options: ThemeDocumentOptions = {},
152
39
  previous?: ReadonlySet<string>
153
40
  ): ReadonlySet<string> {
154
- const { tokens, accented } = themeDocumentTokens(state, options)
155
-
156
- for (const [name, value] of Object.entries(tokens)) {
157
- root.style.setProperty(name, value)
158
- }
159
- if (previous) {
160
- for (const name of previous) {
161
- if (!(name in tokens)) root.style.removeProperty(name)
162
- }
163
- }
164
-
165
- root.classList.toggle('dark', state.appearance === 'dark')
166
- root.dataset['theme'] = state.variant.id
167
- root.dataset['appearance'] = state.appearance
168
- root.style.colorScheme = state.appearance
169
-
170
- // A custom colour has no stylesheet block to select, and its value is the
171
- // attribute's worst possible content, so it is reported as `custom`.
172
- if (!accented) root.removeAttribute('data-accent')
173
- else
174
- root.dataset['accent'] = isCustomAccent(state.selection.accent)
175
- ? 'custom'
176
- : state.selection.accent
177
-
178
- // The surface axis is opt-in, so its absence removes rather than defaults: a host
179
- // that never enables it keeps an `<html>` with neither attribute, and one that
180
- // turns it off leaves nothing behind. (`--surface-alpha` is swept with the tokens.)
181
- if (state.surface) {
182
- root.dataset['surface'] = state.surface.surface
183
- root.dataset['reduceTransparency'] = state.surface.reduceTransparencyActive ? 'true' : 'false'
184
- } else {
185
- root.removeAttribute('data-surface')
186
- root.removeAttribute('data-reduce-transparency')
187
- }
188
-
189
- applyAppearanceFontSettings(
190
- root,
191
- normalizeAppearanceEditorFontSettings(state.selection.fonts, state.selection.font).settings
192
- )
193
-
194
- // Density is a pure token shift, so unlike the colour axes there is nothing to
195
- // compute: the attribute selects a block in `theme.css`. It is applied here for
196
- // the same reason as the others — this is the one place that knows what the
197
- // current selection is, and it is the only writer of these attributes.
198
- if (resolvedDensity(state.selection) === 'comfortable') root.removeAttribute('data-density')
199
- else root.dataset['density'] = resolvedDensity(state.selection)
200
-
201
- return new Set(Object.keys(tokens))
202
- }
203
-
204
- /** What {@link applyWithoutTransitions} needs of a document. */
205
- export type TransitionDocument = {
206
- head: { appendChild(node: unknown): unknown }
207
- createElement(tag: 'style'): {
208
- textContent: string | null
209
- offsetHeight?: number
210
- remove(): void
211
- }
212
- }
213
-
214
- /**
215
- * Run `apply` with every CSS transition switched off for the frame that carries
216
- * it, so a theme switch cannot animate page-wide.
217
- *
218
- * Without this, flipping the custom properties on `<html>` starts a transition on
219
- * every element that declares one, and each fades from the old palette to the new
220
- * over its own duration: a theme change that looks like a rendering fault. The
221
- * rule is removed two frames later, after the browser has committed the new styles
222
- * with transitions off, and `restore` runs it early (the provider calls it when it
223
- * is disposed mid-switch).
224
- *
225
- * `schedule` is the frame source; it defaults to `requestAnimationFrame` and falls
226
- * back to running at once where there is none, which leaves transitions on rather
227
- * than off.
228
- */
229
- export function applyWithoutTransitions(
230
- doc: TransitionDocument,
231
- apply: () => void,
232
- schedule: (callback: () => void) => void = defaultSchedule
233
- ): () => void {
234
- const style = doc.createElement('style')
235
- style.textContent = '*{transition:none !important}'
236
- doc.head.appendChild(style)
237
- // Reading a layout property forces the browser to commit the rule before the
238
- // properties change; without it the two can be batched into one style recalc.
239
- void style.offsetHeight
240
- let removed = false
241
- const restore = () => {
242
- if (removed) return
243
- removed = true
244
- style.remove()
245
- }
246
- try {
247
- apply()
248
- } catch (error) {
249
- restore()
250
- throw error
251
- }
252
- schedule(() => schedule(restore))
253
- return restore
254
- }
255
-
256
- function defaultSchedule(callback: () => void): void {
257
- if (typeof requestAnimationFrame === 'function') requestAnimationFrame(callback)
258
- else callback()
41
+ return applyThemeToRootWith(catalogueThemeEngine, root, state, options, previous)
259
42
  }
@@ -1,7 +1,12 @@
1
1
  import { normalizeCustomAccent } from '../../lib/accent-roles'
2
- import { accentPresets } from '../../lib/tokens'
2
+ import { accentPresets } from '../../lib/accent-presets'
3
3
  import { normalizeAppearanceEditorFontSettings } from '../../lib/appearance-font-settings'
4
- import { defaultDarkThemeId, defaultLightThemeId, isThemeAccentId, themeById } from '../../lib/themes'
4
+ import { isThemeAccentId } from '../../lib/theme-accents'
5
+ import {
6
+ catalogueThemeAppearance,
7
+ defaultDarkThemeId,
8
+ defaultLightThemeId,
9
+ } from '../../lib/theme-defaults'
5
10
  import { normalizeSurface } from '../../lib/theme-surface'
6
11
  import {
7
12
  defaultPreferenceStorage,
@@ -11,7 +16,7 @@ import {
11
16
  writeVersionedRecord,
12
17
  type PreferenceStorage,
13
18
  } from '../../lib/preference-store'
14
- import { defaultThemeSelection, resolvedDensity, type ThemeSelection } from './theme-state'
19
+ import { defaultThemeSelection, resolvedDensity, type ThemeSelection } from './theme-state-core'
15
20
 
16
21
  /**
17
22
  * Where a selection is kept between sessions.
@@ -51,7 +56,10 @@ function preferenceStore(): Storage | undefined {
51
56
  return typeof localStorage === 'undefined' ? undefined : localStorage
52
57
  }
53
58
 
54
- /** The stored preference, validated against the catalogue. */
59
+ /**
60
+ * The stored preference, validated against the catalogue's ids (`theme-defaults`), so
61
+ * reading it never loads the catalogue.
62
+ */
55
63
  function readSelection(storageKey: string): ThemeSelection {
56
64
  try {
57
65
  const raw = preferenceStore()?.getItem(storageKey)
@@ -68,11 +76,11 @@ function readSelection(storageKey: string): ThemeSelection {
68
76
  // An unknown id would leave the document with no theme at all, so a stale
69
77
  // preference from an older catalogue falls back rather than applying nothing.
70
78
  lightThemeId:
71
- themeById(parsed.lightThemeId ?? '')?.appearance === 'light'
79
+ catalogueThemeAppearance(parsed.lightThemeId ?? '') === 'light'
72
80
  ? (parsed.lightThemeId as string)
73
81
  : defaultLightThemeId,
74
82
  darkThemeId:
75
- themeById(parsed.darkThemeId ?? '')?.appearance === 'dark'
83
+ catalogueThemeAppearance(parsed.darkThemeId ?? '') === 'dark'
76
84
  ? (parsed.darkThemeId as string)
77
85
  : defaultDarkThemeId,
78
86
  // A theme accent is kept whenever it names a slot, even one the stored pair
@@ -0,0 +1,40 @@
1
+ import { themeContext } from './theme-context'
2
+ import {
3
+ createThemeContextValue,
4
+ type ThemeCatalogueSource,
5
+ type ThemeProviderProps,
6
+ } from './theme-provider-value'
7
+
8
+ export type { ThemeCatalogueSource, ThemeProviderProps } from './theme-provider-value'
9
+ export {
10
+ createVersionedPersistence,
11
+ localStoragePersistence,
12
+ type ThemePersistence,
13
+ type ThemeStorageSchema,
14
+ type VersionedCodec,
15
+ type VersionedPersistenceOptions,
16
+ } from './theme-persistence'
17
+ export { useOptionalTheme, useTheme } from './theme-context'
18
+ export type { ThemeSurface } from '../../lib/theme-surface'
19
+ export type { EditorRolesMode } from '../../lib/themes'
20
+ export { inlineScriptLiteral, themeScript, type ThemeScriptOptions } from './theme-script'
21
+ export {
22
+ defaultThemeSelection,
23
+ resolvedDensity,
24
+ type ThemeContextValue,
25
+ type ThemeDensity,
26
+ type ThemeSelection,
27
+ } from './theme-state-core'
28
+
29
+ /**
30
+ * The provider, parameterised by where its catalogue comes from.
31
+ *
32
+ * `ThemeProvider` (`theme-provider.tsx`) and the lazy `ThemeProvider`
33
+ * (`theme-provider-lazy.tsx`) are this component with a source; the work is
34
+ * `createThemeContextValue`. It imports no catalogue code or data.
35
+ */
36
+ export function ThemeProviderCore(props: ThemeProviderProps & { catalogue: ThemeCatalogueSource }) {
37
+ const value = createThemeContextValue(props)
38
+ const Context = themeContext()
39
+ return <Context.Provider value={value}>{props.children}</Context.Provider>
40
+ }
@@ -0,0 +1,34 @@
1
+ import { createLazyCatalogue } from './theme-catalogue-source'
2
+ import { ThemeProviderCore, type ThemeProviderProps } from './theme-provider-core'
3
+
4
+ export { loadThemeCatalogue } from './theme-catalogue-source'
5
+
6
+ /**
7
+ * ThemeProvider, with the theme catalogue out of the start-up path.
8
+ *
9
+ * Same props, same context and same behaviour as `ThemeProvider` for everything the
10
+ * shipped default pair covers: the default light and dark themes, a host's own
11
+ * `themes`, every accent preset and custom colour, the surface axis, fonts and
12
+ * density. Only the 32 other catalogue themes are not in the start-up chunk. The first
13
+ * time the selection (or a preview) names one, or a theme-derived `ansi-*` accent over
14
+ * such a pair, this provider imports the catalogue in a chunk of its own:
15
+ *
16
+ * - until it arrives the document keeps what is on it (set before first paint by
17
+ * `themeScript`, painted by the stylesheet under `palette="stylesheet"`), and
18
+ * `variant()` is the default of the appearance;
19
+ * - when it arrives the provider re-resolves and paints the stored theme, and
20
+ * `useTheme().catalogueReady()` turns true;
21
+ * - a preview of a theme that has not loaded starts the load and shows when it ends.
22
+ *
23
+ * Pair it with `palette="stylesheet"` and `themeScript`: inline palettes of catalogue
24
+ * themes need the catalogue to compute, so under the default `inline` palette every
25
+ * stored theme but the defaults waits for the import.
26
+ *
27
+ * `useTheme().themes` and `allThemes()` list only the default pair until
28
+ * `catalogueReady()`; a picker calls `useTheme().loadCatalogue()` when it mounts.
29
+ */
30
+ export function ThemeProvider(props: ThemeProviderProps) {
31
+ // Hoisted: a JSX prop expression is re-evaluated on every read, and this source owns signals.
32
+ const catalogue = createLazyCatalogue()
33
+ return <ThemeProviderCore {...props} catalogue={catalogue} />
34
+ }