@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.
- package/dist/components/theme/appearance-panel.js +1 -1
- package/dist/components/theme/index.js +1 -1
- package/dist/components/theme/lazy.d.ts +15 -0
- package/dist/components/theme/lazy.d.ts.map +1 -0
- package/dist/components/theme/lazy.js +9 -0
- package/dist/components/theme/theme-catalogue-source.d.ts +15 -0
- package/dist/components/theme/theme-catalogue-source.d.ts.map +1 -0
- package/dist/components/theme/theme-catalogue-source.js +51 -0
- package/dist/components/theme/theme-catalogue-source.js.map +1 -0
- package/dist/components/theme/theme-document-core.d.ts +123 -0
- package/dist/components/theme/theme-document-core.d.ts.map +1 -0
- package/dist/components/theme/{theme-document.js → theme-document-core.js} +12 -12
- package/dist/components/theme/theme-document-core.js.map +1 -0
- package/dist/components/theme/theme-document.d.ts +8 -107
- package/dist/components/theme/theme-document.d.ts.map +1 -1
- package/dist/components/theme/theme-persistence.d.ts +1 -1
- package/dist/components/theme/theme-persistence.d.ts.map +1 -1
- package/dist/components/theme/theme-persistence.js +9 -6
- package/dist/components/theme/theme-persistence.js.map +1 -1
- package/dist/components/theme/theme-provider-core.d.ts +19 -0
- package/dist/components/theme/theme-provider-core.d.ts.map +1 -0
- package/dist/components/theme/theme-provider-core.js +28 -0
- package/dist/components/theme/theme-provider-core.js.map +1 -0
- package/dist/components/theme/theme-provider-lazy.d.ts +28 -0
- package/dist/components/theme/theme-provider-lazy.d.ts.map +1 -0
- package/dist/components/theme/theme-provider-lazy.js +36 -0
- package/dist/components/theme/theme-provider-lazy.js.map +1 -0
- package/dist/components/theme/theme-provider-value.d.ts +175 -0
- package/dist/components/theme/theme-provider-value.d.ts.map +1 -0
- package/dist/components/theme/theme-provider-value.js +200 -0
- package/dist/components/theme/theme-provider-value.js.map +1 -0
- package/dist/components/theme/theme-provider.d.ts +11 -136
- package/dist/components/theme/theme-provider.d.ts.map +1 -1
- package/dist/components/theme/theme-provider.js +27 -149
- package/dist/components/theme/theme-provider.js.map +1 -1
- package/dist/components/theme/theme-script.js +4 -3
- package/dist/components/theme/theme-script.js.map +1 -1
- package/dist/components/theme/theme-state-core.d.ts +248 -0
- package/dist/components/theme/theme-state-core.d.ts.map +1 -0
- package/dist/components/theme/{theme-state.js → theme-state-core.js} +8 -7
- package/dist/components/theme/theme-state-core.js.map +1 -0
- package/dist/components/theme/theme-state.d.ts +8 -214
- package/dist/components/theme/theme-state.d.ts.map +1 -1
- package/dist/components/theme/theme-toggle.js.map +1 -1
- package/dist/index.js +7 -4
- package/dist/lib/accent-presets.d.ts +26 -0
- package/dist/lib/accent-presets.d.ts.map +1 -0
- package/dist/lib/accent-presets.js +11 -0
- package/dist/lib/accent-presets.js.map +1 -0
- package/dist/lib/accent-roles.js +94 -9
- package/dist/lib/accent-roles.js.map +1 -1
- package/dist/lib/font-zoom.js +4 -2
- package/dist/lib/font-zoom.js.map +1 -1
- package/dist/lib/overlay.js +3 -1
- package/dist/lib/overlay.js.map +1 -1
- package/dist/lib/theme-catalogue.d.ts +3 -0
- package/dist/lib/theme-catalogue.d.ts.map +1 -0
- package/dist/lib/theme-catalogue.js +22 -0
- package/dist/lib/theme-catalogue.js.map +1 -0
- package/dist/lib/theme-css.d.ts +43 -0
- package/dist/lib/theme-css.d.ts.map +1 -0
- package/dist/lib/theme-css.js +167 -0
- package/dist/lib/theme-css.js.map +1 -0
- package/dist/lib/theme-defaults.d.ts +46 -0
- package/dist/lib/theme-defaults.d.ts.map +1 -0
- package/dist/lib/theme-defaults.generated.d.ts +13 -0
- package/dist/lib/theme-defaults.generated.d.ts.map +1 -0
- package/dist/lib/theme-defaults.generated.js +318 -0
- package/dist/lib/theme-defaults.generated.js.map +1 -0
- package/dist/lib/theme-defaults.js +47 -0
- package/dist/lib/theme-defaults.js.map +1 -0
- package/dist/lib/theme-engine-light.d.ts +3 -0
- package/dist/lib/theme-engine-light.d.ts.map +1 -0
- package/dist/lib/theme-engine-light.js +75 -0
- package/dist/lib/theme-engine-light.js.map +1 -0
- package/dist/lib/theme-engine.d.ts +69 -0
- package/dist/lib/theme-engine.d.ts.map +1 -0
- package/dist/lib/theme-engine.js +33 -0
- package/dist/lib/theme-engine.js.map +1 -0
- package/dist/lib/themes.d.ts +14 -48
- package/dist/lib/themes.d.ts.map +1 -1
- package/dist/lib/themes.js +24 -164
- package/dist/lib/themes.js.map +1 -1
- package/dist/lib/tokens.d.ts +1 -25
- package/dist/lib/tokens.d.ts.map +1 -1
- package/dist/lib/tokens.js +1 -24
- package/dist/lib/tokens.js.map +1 -1
- package/dist/lib/tooltip-focus-gate.js +7 -1
- package/dist/lib/tooltip-focus-gate.js.map +1 -1
- package/dist/lib/variants.js +2 -2
- package/dist/r/lib.json +35 -0
- package/dist/r/registry.json +70 -0
- package/dist/r/src/components/theme/lazy.ts +35 -0
- package/dist/r/src/components/theme/theme-catalogue-source.ts +59 -0
- package/dist/r/src/components/theme/theme-document-core.ts +262 -0
- package/dist/r/src/components/theme/theme-document.ts +23 -240
- package/dist/r/src/components/theme/theme-persistence.ts +14 -6
- package/dist/r/src/components/theme/theme-provider-core.tsx +40 -0
- package/dist/r/src/components/theme/theme-provider-lazy.tsx +34 -0
- package/dist/r/src/components/theme/theme-provider-value.ts +445 -0
- package/dist/r/src/components/theme/theme-provider.tsx +23 -346
- package/dist/r/src/components/theme/theme-script.ts +3 -3
- package/dist/r/src/components/theme/theme-state-core.ts +364 -0
- package/dist/r/src/components/theme/theme-state.ts +10 -329
- package/dist/r/src/components/theme/theme-toggle.tsx +1 -1
- package/dist/r/src/lib/accent-presets.ts +43 -0
- package/dist/r/src/lib/theme-catalogue.ts +26 -0
- package/dist/r/src/lib/theme-css.ts +201 -0
- package/dist/r/src/lib/theme-defaults.generated.ts +319 -0
- package/dist/r/src/lib/theme-defaults.ts +79 -0
- package/dist/r/src/lib/theme-engine-light.ts +117 -0
- package/dist/r/src/lib/theme-engine.ts +111 -0
- package/dist/r/src/lib/themes.ts +27 -191
- package/dist/r/src/lib/tokens.ts +1 -35
- package/dist/r/theming.json +35 -0
- package/package.json +12 -3
- package/registry.json +70 -0
- package/src/components/theme/lazy.ts +35 -0
- package/src/components/theme/theme-catalogue-source.ts +59 -0
- package/src/components/theme/theme-document-core.ts +262 -0
- package/src/components/theme/theme-document.ts +23 -240
- package/src/components/theme/theme-persistence.ts +14 -6
- package/src/components/theme/theme-provider-core.tsx +40 -0
- package/src/components/theme/theme-provider-lazy.tsx +34 -0
- package/src/components/theme/theme-provider-value.ts +445 -0
- package/src/components/theme/theme-provider.tsx +23 -346
- package/src/components/theme/theme-script.ts +3 -3
- package/src/components/theme/theme-state-core.ts +364 -0
- package/src/components/theme/theme-state.ts +10 -329
- package/src/components/theme/theme-toggle.tsx +1 -1
- package/src/lib/accent-presets.ts +43 -0
- package/src/lib/theme-catalogue.ts +26 -0
- package/src/lib/theme-css.ts +201 -0
- package/src/lib/theme-defaults.generated.ts +319 -0
- package/src/lib/theme-defaults.ts +79 -0
- package/src/lib/theme-engine-light.ts +117 -0
- package/src/lib/theme-engine.ts +111 -0
- package/src/lib/themes.ts +27 -191
- package/src/lib/tokens.ts +1 -35
- package/dist/components/theme/theme-document.js.map +0 -1
- package/dist/components/theme/theme-state.js.map +0 -1
|
@@ -1,33 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { createEffect, createMemo, createSignal, onCleanup, splitProps, untrack } from 'solid-js'
|
|
3
|
-
import { fontZoomShortcut, type FontZoomIntent } from '../../lib/font-zoom'
|
|
4
|
-
import { REDUCED_TRANSPARENCY_QUERY, resolveSurfaceState } from '../../lib/theme-surface'
|
|
1
|
+
import { catalogueThemeEngine } from '../../lib/theme-catalogue'
|
|
5
2
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type
|
|
9
|
-
|
|
10
|
-
type ThemeVariant,
|
|
11
|
-
} from '../../lib/themes'
|
|
12
|
-
import { themeContext } from './theme-context'
|
|
13
|
-
import { applyThemeToRoot, applyWithoutTransitions } from './theme-document'
|
|
14
|
-
import {
|
|
15
|
-
localStoragePersistence,
|
|
16
|
-
readPersisted,
|
|
17
|
-
writePersisted,
|
|
18
|
-
type ThemePersistence,
|
|
19
|
-
} from './theme-persistence'
|
|
20
|
-
import {
|
|
21
|
-
accentRolesForState,
|
|
22
|
-
initialThemeSelection,
|
|
23
|
-
mergeRegistry,
|
|
24
|
-
mergeThemeSelection,
|
|
25
|
-
resolveTerminalVariant,
|
|
26
|
-
resolveThemeState,
|
|
27
|
-
zoomedFontSettings,
|
|
28
|
-
type ThemeContextValue,
|
|
29
|
-
type ThemeSelection,
|
|
30
|
-
} from './theme-state'
|
|
3
|
+
ThemeProviderCore,
|
|
4
|
+
type ThemeCatalogueSource,
|
|
5
|
+
type ThemeProviderProps,
|
|
6
|
+
} from './theme-provider-core'
|
|
31
7
|
|
|
32
8
|
export { useOptionalTheme, useTheme } from './theme-context'
|
|
33
9
|
export {
|
|
@@ -40,6 +16,7 @@ export {
|
|
|
40
16
|
} from './theme-persistence'
|
|
41
17
|
export type { ThemeSurface } from '../../lib/theme-surface'
|
|
42
18
|
export type { EditorRolesMode } from '../../lib/themes'
|
|
19
|
+
export type { ThemeProviderProps } from './theme-provider-core'
|
|
43
20
|
export { inlineScriptLiteral, themeScript, type ThemeScriptOptions } from './theme-script'
|
|
44
21
|
export {
|
|
45
22
|
defaultThemeSelection,
|
|
@@ -47,329 +24,29 @@ export {
|
|
|
47
24
|
type ThemeContextValue,
|
|
48
25
|
type ThemeDensity,
|
|
49
26
|
type ThemeSelection,
|
|
50
|
-
} from './theme-state'
|
|
27
|
+
} from './theme-state-core'
|
|
28
|
+
|
|
29
|
+
/** The whole catalogue, already imported: nothing to load, nothing to wait for. */
|
|
30
|
+
const eagerCatalogue: ThemeCatalogueSource = {
|
|
31
|
+
engine: () => catalogueThemeEngine,
|
|
32
|
+
loaded: () => true,
|
|
33
|
+
failed: () => false,
|
|
34
|
+
load: () => Promise.resolve(),
|
|
35
|
+
}
|
|
51
36
|
|
|
52
37
|
/**
|
|
53
38
|
* ThemeProvider.
|
|
54
39
|
*
|
|
55
40
|
* Owns the appearance preference and applies it to the document. One provider near
|
|
56
|
-
* the root; everything below reads it.
|
|
41
|
+
* the root; everything below reads it. See {@link ThemeProviderProps} for the
|
|
42
|
+
* options, and `ThemeProviderCore` for how a selection is resolved and applied.
|
|
57
43
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* someone to author that combination.
|
|
64
|
-
*
|
|
65
|
-
* ## Where the rules live
|
|
66
|
-
*
|
|
67
|
-
* This component is wiring. What a selection merges to and resolves to is
|
|
68
|
-
* `theme-state.ts`; what lands on `<html>` is `theme-document.ts`; where the
|
|
69
|
-
* preference is kept is `theme-persistence.ts`. Each is plain code a test can call,
|
|
70
|
-
* which is the reason none of it is inlined here.
|
|
71
|
-
*
|
|
72
|
-
* ## Why the variants are applied as inline properties
|
|
73
|
-
*
|
|
74
|
-
* The catalogue is data, and a theme is applied by writing its roles onto
|
|
75
|
-
* `<html>` as custom properties. That is what makes an imported palette work
|
|
76
|
-
* without a hand-written `[data-theme]` block per theme, and it is why a settings
|
|
77
|
-
* UI can show a preview by reading the same object rather than by loading a
|
|
78
|
-
* stylesheet. `theme.css` keeps the default theme's values so the first paint is
|
|
79
|
-
* correct before any script runs.
|
|
44
|
+
* This provider imports the whole theme catalogue (about 129 KB raw, 34 KB gzipped)
|
|
45
|
+
* so that `useTheme().themes` is a complete array on the first render. A host that
|
|
46
|
+
* paints its theme from a stylesheet (`palette="stylesheet"`), keeps the default
|
|
47
|
+
* pair, and wants the catalogue out of its start-up chunk imports the lazy provider
|
|
48
|
+
* from `@adea-ai/ui/components/theme/lazy` instead; the props are the same.
|
|
80
49
|
*/
|
|
81
|
-
export type ThemeProviderProps = {
|
|
82
|
-
children?: JSX.Element
|
|
83
|
-
/** Where the preference is persisted. Distinct per application. */
|
|
84
|
-
storageKey?: string
|
|
85
|
-
/** Start from this instead of the stored preference. */
|
|
86
|
-
initial?: Partial<ThemeSelection>
|
|
87
|
-
/**
|
|
88
|
-
* The selection, owned by the caller.
|
|
89
|
-
*
|
|
90
|
-
* For a consumer that keeps the state itself — a settings store, or a workshop
|
|
91
|
-
* whose selection lives in Storybook globals — rather than handing it to this
|
|
92
|
-
* provider's signal. Each change lands here and the document follows; nothing is
|
|
93
|
-
* written to the store, because the caller is the one who persists. A picker
|
|
94
|
-
* below the provider still works, and its change is the caller's to read back.
|
|
95
|
-
*
|
|
96
|
-
* Absent, the provider is the whole owner: it reads `storageKey` on mount,
|
|
97
|
-
* seeds from `initial`, and persists every `setSelection`.
|
|
98
|
-
*/
|
|
99
|
-
selection?: Partial<ThemeSelection>
|
|
100
|
-
/**
|
|
101
|
-
* Where the preference is kept, in place of `localStorage` under `storageKey`.
|
|
102
|
-
*
|
|
103
|
-
* Read once when the provider is created, so changing the prop later does not
|
|
104
|
-
* move the store. `storageKey` is ignored when this is given.
|
|
105
|
-
*/
|
|
106
|
-
persistence?: ThemePersistence
|
|
107
|
-
/**
|
|
108
|
-
* Variants the host adds to the built-in catalogue — themes a user imported.
|
|
109
|
-
*
|
|
110
|
-
* A function is read inside the provider's reactive scope, so one that reads a
|
|
111
|
-
* signal keeps the picker and the document current when the set changes. A
|
|
112
|
-
* stored id that names no variant, built in or added, paints the default of its
|
|
113
|
-
* appearance and stays in the selection untouched.
|
|
114
|
-
*/
|
|
115
|
-
themes?: readonly ThemeVariant[] | (() => readonly ThemeVariant[])
|
|
116
|
-
/**
|
|
117
|
-
* Rewrites the custom properties of each pass before they are written to
|
|
118
|
-
* `<html>`: the variant's roles with the accent over them. `tokensAsHex` from
|
|
119
|
-
* `lib/themes` is the one the system ships.
|
|
120
|
-
*/
|
|
121
|
-
transformTokens?: (tokens: Record<string, string>) => Record<string, string>
|
|
122
|
-
/**
|
|
123
|
-
* Switch CSS transitions off for the frame that carries a change, so a theme
|
|
124
|
-
* switch cannot animate the whole page. Off by default: it adds a `<style>`
|
|
125
|
-
* element to `<head>` for two frames on every change.
|
|
126
|
-
*/
|
|
127
|
-
disableTransitionOnChange?: boolean
|
|
128
|
-
/**
|
|
129
|
-
* The contrast ratio an accent is held to against the variant's background,
|
|
130
|
-
* repaired to the nearest passing colour when it falls short. Absent, presets
|
|
131
|
-
* are painted verbatim — the catalogue measured them for its own themes — and
|
|
132
|
-
* only a custom `#rrggbb` is held to 3:1. A host that adds themes the catalogue
|
|
133
|
-
* never measured passes 3 to hold the presets to it as well; for the catalogue's
|
|
134
|
-
* own themes the floor changes no preset.
|
|
135
|
-
*/
|
|
136
|
-
accentContrastFloor?: number
|
|
137
|
-
/**
|
|
138
|
-
* Turns the surface axis on: `selection.surface` and `selection.reduceTransparency`
|
|
139
|
-
* are resolved against the operating system's Reduce Transparency setting and the
|
|
140
|
-
* host's capability, and `data-surface`, `data-reduce-transparency` and
|
|
141
|
-
* `--surface-alpha` are written to `<html>` (the frost rule in `theme.css` reads
|
|
142
|
-
* them). Off by default: a provider that never opts in writes none of them, adds no
|
|
143
|
-
* media-query listener, and stores nothing new.
|
|
144
|
-
*
|
|
145
|
-
* An object also states the host's capability. `nativeTranslucency` is whether the
|
|
146
|
-
* window can render the OS's own translucency; without it a `translucent`
|
|
147
|
-
* preference paints the tokenized `frosted` surface instead of pretending to
|
|
148
|
-
* vibrancy. A function is read inside the provider's reactive scope, for a
|
|
149
|
-
* capability that is learned after mount.
|
|
150
|
-
*
|
|
151
|
-
* A selection that already carries a `surface` turns the axis on for itself, so a
|
|
152
|
-
* host that stores the field gets the same document without the prop.
|
|
153
|
-
*/
|
|
154
|
-
surface?: boolean | { nativeTranslucency?: boolean | (() => boolean) }
|
|
155
|
-
/**
|
|
156
|
-
* Where a catalogue variant's palette comes from. `inline` (the default) writes
|
|
157
|
-
* every role onto `<html>`. `stylesheet` leaves a catalogue variant to the host's
|
|
158
|
-
* `[data-theme]` stylesheet and writes inline only what no stylesheet can know: a
|
|
159
|
-
* host's own `themes`, the accent, the pinned terminal palette, the surface alpha
|
|
160
|
-
* and the fonts. Switching from a host variant back to a catalogue one removes the
|
|
161
|
-
* properties the host variant wrote.
|
|
162
|
-
*/
|
|
163
|
-
palette?: 'inline' | 'stylesheet'
|
|
164
|
-
/**
|
|
165
|
-
* The projection behind the `--editor-*` ramp. `syntax` (the default) is the
|
|
166
|
-
* catalogue's quiet syntax roles, a comment among them deliberately below
|
|
167
|
-
* body-text contrast. `floor` holds all sixteen roles to 4.5:1 on the canvas, as
|
|
168
|
-
* hex, for a host that renders code as content (a diff, a file view) rather than
|
|
169
|
-
* as decoration.
|
|
170
|
-
*
|
|
171
|
-
* Applies to catalogue variants; a host's own `themes` keep their `editor` and
|
|
172
|
-
* their `tokens`. With `palette="stylesheet"` it is the one palette property a
|
|
173
|
-
* catalogue variant still writes inline, because `theme-variants.css` is generated
|
|
174
|
-
* for `syntax`. Absent, nothing changes.
|
|
175
|
-
*/
|
|
176
|
-
editorRoles?: EditorRolesMode
|
|
177
|
-
/**
|
|
178
|
-
* Bind the platform zoom chords (Cmd or Ctrl with `=`, `+`, `-`, `0`) to the three
|
|
179
|
-
* text sizes instead of the browser's page zoom: stepping them together is zoom
|
|
180
|
-
* inside the persisted type system. Off by default: it adds a capturing `keydown`
|
|
181
|
-
* listener to `window`, and an event already handled elsewhere is left alone.
|
|
182
|
-
* `zoomFonts` on the context does the same from a menu or a host's own binding.
|
|
183
|
-
*/
|
|
184
|
-
fontZoom?: boolean
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/** The operating system's Reduce Transparency query, where there is a window to ask. */
|
|
188
|
-
function reducedTransparencyMedia(): MediaQueryList | undefined {
|
|
189
|
-
return typeof window !== 'undefined' && typeof window.matchMedia === 'function'
|
|
190
|
-
? window.matchMedia(REDUCED_TRANSPARENCY_QUERY)
|
|
191
|
-
: undefined
|
|
192
|
-
}
|
|
193
|
-
|
|
194
50
|
export function ThemeProvider(props: ThemeProviderProps) {
|
|
195
|
-
|
|
196
|
-
'children',
|
|
197
|
-
'storageKey',
|
|
198
|
-
'initial',
|
|
199
|
-
'selection',
|
|
200
|
-
'persistence',
|
|
201
|
-
'themes',
|
|
202
|
-
'transformTokens',
|
|
203
|
-
'disableTransitionOnChange',
|
|
204
|
-
'accentContrastFloor',
|
|
205
|
-
'surface',
|
|
206
|
-
'palette',
|
|
207
|
-
'editorRoles',
|
|
208
|
-
'fontZoom',
|
|
209
|
-
])
|
|
210
|
-
const storageKey = () => local.storageKey ?? 'adea-appearance'
|
|
211
|
-
const persistence = local.persistence ?? localStoragePersistence(storageKey)
|
|
212
|
-
|
|
213
|
-
// Read before the first resolution and before the store is, so a persistence whose
|
|
214
|
-
// answer depends on the extras (an id it only accepts if the theme exists) sees
|
|
215
|
-
// them.
|
|
216
|
-
const extraThemes = createMemo(() =>
|
|
217
|
-
typeof local.themes === 'function' ? local.themes() : (local.themes ?? [])
|
|
218
|
-
)
|
|
219
|
-
const registry = createMemo(() => mergeRegistry(builtinThemes, extraThemes()))
|
|
220
|
-
|
|
221
|
-
const [selection, setSelectionState] = createSignal<ThemeSelection>(
|
|
222
|
-
initialThemeSelection(readPersisted(persistence), local.initial)
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
// The controlled half of the contract. A patch from the owner replaces the
|
|
226
|
-
// matching axes; the stored preference is untouched, since the owner is the one
|
|
227
|
-
// that persists. Reading `local.selection` — a prop getter, not a destructured
|
|
228
|
-
// value — is what keeps this subscribed for the provider's lifetime.
|
|
229
|
-
createEffect(() => {
|
|
230
|
-
const incoming = local.selection
|
|
231
|
-
if (incoming) setSelectionState((current) => mergeThemeSelection(current, incoming))
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
const [systemAppearance, setSystemAppearance] = createSignal<ThemeAppearance>('light')
|
|
235
|
-
|
|
236
|
-
if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
|
|
237
|
-
const query = window.matchMedia('(prefers-color-scheme: dark)')
|
|
238
|
-
setSystemAppearance(query.matches ? 'dark' : 'light')
|
|
239
|
-
const onChange = (event: MediaQueryListEvent) =>
|
|
240
|
-
setSystemAppearance(event.matches ? 'dark' : 'light')
|
|
241
|
-
query.addEventListener('change', onChange)
|
|
242
|
-
onCleanup(() => query.removeEventListener('change', onChange))
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// What the stored preference resolves to. `selection()`, `variant()` and
|
|
246
|
-
// `resolvedAppearance()` answer from this and never from a preview, so a picker
|
|
247
|
-
// that previews a draft still reads back what is committed.
|
|
248
|
-
const committed = createMemo(() => resolveThemeState(selection(), systemAppearance(), registry()))
|
|
249
|
-
const resolvedAppearance = createMemo<ThemeAppearance>(() => committed().appearance)
|
|
250
|
-
const variant = createMemo<ThemeVariant>(() => committed().variant)
|
|
251
|
-
|
|
252
|
-
const [draft, setDraft] = createSignal<Partial<ThemeSelection> | undefined>()
|
|
253
|
-
const shownSelection = createMemo(() => {
|
|
254
|
-
const preview = draft()
|
|
255
|
-
return preview ? mergeThemeSelection(selection(), preview) : selection()
|
|
256
|
-
})
|
|
257
|
-
const shown = createMemo(() =>
|
|
258
|
-
draft() ? resolveThemeState(shownSelection(), systemAppearance(), registry()) : committed()
|
|
259
|
-
)
|
|
260
|
-
|
|
261
|
-
// The surface axis. Off, none of this reads the operating system: the media query
|
|
262
|
-
// is subscribed only while the axis is on, so a provider that never opts in adds no
|
|
263
|
-
// listener and no repaint.
|
|
264
|
-
const surfaceOn = (candidate: ThemeSelection) =>
|
|
265
|
-
local.surface === true || typeof local.surface === 'object' || candidate.surface !== undefined
|
|
266
|
-
const nativeTranslucency = () => {
|
|
267
|
-
const capability = typeof local.surface === 'object' ? local.surface.nativeTranslucency : false
|
|
268
|
-
return (typeof capability === 'function' ? capability() : capability) === true
|
|
269
|
-
}
|
|
270
|
-
const [osReducedTransparency, setOsReducedTransparency] = createSignal(
|
|
271
|
-
surfaceOn(untrack(shownSelection)) ? (reducedTransparencyMedia()?.matches ?? false) : false
|
|
272
|
-
)
|
|
273
|
-
const axisOn = createMemo(() => surfaceOn(shownSelection()))
|
|
274
|
-
createEffect(() => {
|
|
275
|
-
const query = axisOn() ? reducedTransparencyMedia() : undefined
|
|
276
|
-
setOsReducedTransparency(query?.matches ?? false)
|
|
277
|
-
if (!query) return
|
|
278
|
-
const onChange = (event: MediaQueryListEvent) => setOsReducedTransparency(event.matches)
|
|
279
|
-
query.addEventListener('change', onChange)
|
|
280
|
-
onCleanup(() => query.removeEventListener('change', onChange))
|
|
281
|
-
})
|
|
282
|
-
const surfaceStateOf = (candidate: ThemeSelection) =>
|
|
283
|
-
resolveSurfaceState(candidate.surface, {
|
|
284
|
-
osReducedTransparency: osReducedTransparency(),
|
|
285
|
-
userReducedTransparency: candidate.reduceTransparency === true,
|
|
286
|
-
nativeTranslucency: nativeTranslucency(),
|
|
287
|
-
})
|
|
288
|
-
const committedSurface = createMemo(() =>
|
|
289
|
-
surfaceOn(selection()) ? surfaceStateOf(selection()) : undefined
|
|
290
|
-
)
|
|
291
|
-
|
|
292
|
-
let written: ReadonlySet<string> | undefined
|
|
293
|
-
let restoreTransitions: (() => void) | undefined
|
|
294
|
-
createEffect(() => {
|
|
295
|
-
if (typeof document === 'undefined') return
|
|
296
|
-
const state = {
|
|
297
|
-
selection: shownSelection(),
|
|
298
|
-
appearance: shown().appearance,
|
|
299
|
-
variant: shown().variant,
|
|
300
|
-
terminalVariant: resolveTerminalVariant(shownSelection().terminalThemeId, registry()),
|
|
301
|
-
surface: axisOn() ? surfaceStateOf(shownSelection()) : undefined,
|
|
302
|
-
}
|
|
303
|
-
const options = {
|
|
304
|
-
transformTokens: local.transformTokens,
|
|
305
|
-
accentContrastFloor: local.accentContrastFloor,
|
|
306
|
-
palette: local.palette,
|
|
307
|
-
editorRoles: local.editorRoles,
|
|
308
|
-
}
|
|
309
|
-
const apply = () => {
|
|
310
|
-
written = applyThemeToRoot(document.documentElement, state, options, written)
|
|
311
|
-
}
|
|
312
|
-
if (local.disableTransitionOnChange) {
|
|
313
|
-
restoreTransitions?.()
|
|
314
|
-
restoreTransitions = applyWithoutTransitions(document, apply)
|
|
315
|
-
} else {
|
|
316
|
-
apply()
|
|
317
|
-
}
|
|
318
|
-
})
|
|
319
|
-
onCleanup(() => restoreTransitions?.())
|
|
320
|
-
|
|
321
|
-
const themeAccents = createMemo(() =>
|
|
322
|
-
themeAccentsFor(selection().lightThemeId, selection().darkThemeId)
|
|
323
|
-
)
|
|
324
|
-
|
|
325
|
-
const zoomFonts = (intent: FontZoomIntent) =>
|
|
326
|
-
value.setSelection({ fonts: zoomedFontSettings(selection(), intent) })
|
|
327
|
-
|
|
328
|
-
// The platform zoom chords drive the three text sizes, captured like the other
|
|
329
|
-
// global chords; an event something else already handled never double-steps.
|
|
330
|
-
const onKeyDown = (event: KeyboardEvent) => {
|
|
331
|
-
if (event.defaultPrevented) return
|
|
332
|
-
const intent = fontZoomShortcut(event)
|
|
333
|
-
if (!intent) return
|
|
334
|
-
event.preventDefault()
|
|
335
|
-
zoomFonts(intent)
|
|
336
|
-
}
|
|
337
|
-
createEffect(() => {
|
|
338
|
-
if (!local.fontZoom || typeof window === 'undefined') return
|
|
339
|
-
window.addEventListener('keydown', onKeyDown, { capture: true })
|
|
340
|
-
onCleanup(() => window.removeEventListener('keydown', onKeyDown, { capture: true }))
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
const value: ThemeContextValue = {
|
|
344
|
-
selection,
|
|
345
|
-
resolvedAppearance,
|
|
346
|
-
variant,
|
|
347
|
-
themes: builtinThemes,
|
|
348
|
-
themeAccents,
|
|
349
|
-
allThemes: registry,
|
|
350
|
-
preview(next) {
|
|
351
|
-
setDraft(next ? { ...next } : undefined)
|
|
352
|
-
},
|
|
353
|
-
previewing: () => draft() !== undefined,
|
|
354
|
-
accentRolesFor: (accent, variantId) =>
|
|
355
|
-
accentRolesForState(accent, variantId, {
|
|
356
|
-
selection: selection(),
|
|
357
|
-
variant: variant(),
|
|
358
|
-
registry: registry(),
|
|
359
|
-
accentContrastFloor: local.accentContrastFloor,
|
|
360
|
-
}),
|
|
361
|
-
effectiveSurface: () => committedSurface()?.surface ?? 'opaque',
|
|
362
|
-
reduceTransparencyActive: () => committedSurface()?.reduceTransparencyActive ?? false,
|
|
363
|
-
zoomFonts,
|
|
364
|
-
setSelection(patch) {
|
|
365
|
-
const next = mergeThemeSelection(selection(), patch)
|
|
366
|
-
setSelectionState(next)
|
|
367
|
-
// The committed selection is now what should be showing.
|
|
368
|
-
setDraft(undefined)
|
|
369
|
-
writePersisted(persistence, next)
|
|
370
|
-
},
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const Context = themeContext()
|
|
374
|
-
return <Context.Provider value={value}>{local.children}</Context.Provider>
|
|
51
|
+
return <ThemeProviderCore {...props} catalogue={eagerCatalogue} />
|
|
375
52
|
}
|
|
@@ -11,8 +11,8 @@ import { fontSettingsBootstrapScript } from '../../lib/appearance-font-settings'
|
|
|
11
11
|
import { isCustomAccent } from '../../lib/accent-roles'
|
|
12
12
|
import { safeScriptStringLiteral } from '../../lib/safe-script'
|
|
13
13
|
import { REDUCED_TRANSPARENCY_QUERY, surfaceAlpha } from '../../lib/theme-surface'
|
|
14
|
-
import { accentPresets } from '../../lib/
|
|
15
|
-
import {
|
|
14
|
+
import { accentPresets } from '../../lib/accent-presets'
|
|
15
|
+
import { THEME_INDEX, defaultDarkThemeId, defaultLightThemeId } from '../../lib/theme-defaults'
|
|
16
16
|
import type { ThemeStorageSchema } from './theme-persistence'
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -164,7 +164,7 @@ function optionsFormScript(options: ThemeScriptOptions): string {
|
|
|
164
164
|
`var fallback=dark?${literal(defaultDarkThemeId)}:${literal(defaultLightThemeId)};`,
|
|
165
165
|
`var want=doc?(dark?doc.darkThemeId:doc.lightThemeId):null;`,
|
|
166
166
|
`if(typeof want!=='string')want=fallback;`,
|
|
167
|
-
`var ids=[${
|
|
167
|
+
`var ids=[${THEME_INDEX.map(([id]) => literal(id)).join(',')}];`,
|
|
168
168
|
`var id=ids.indexOf(want)!==-1?want:null,tokens=null;`
|
|
169
169
|
)
|
|
170
170
|
if (options.libraryKey !== undefined) {
|