@adea-ai/ui 0.128.3 → 0.129.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/components/theme/script.d.ts +12 -0
- package/dist/components/theme/script.d.ts.map +1 -0
- package/dist/components/theme/script.js +2 -0
- package/dist/index.js +2 -1
- package/dist/lib/accent-presets.d.ts +9 -0
- package/dist/lib/accent-presets.d.ts.map +1 -1
- package/dist/lib/accent-presets.js +10 -1
- package/dist/lib/accent-presets.js.map +1 -1
- package/dist/lib/theme-records.d.ts +39 -0
- package/dist/lib/theme-records.d.ts.map +1 -0
- package/dist/lib/theme-records.js +178 -0
- package/dist/lib/theme-records.js.map +1 -0
- package/dist/lib/themes.d.ts +2 -12
- package/dist/lib/themes.d.ts.map +1 -1
- package/dist/lib/themes.js +4 -161
- package/dist/lib/themes.js.map +1 -1
- package/dist/r/lib.json +5 -0
- package/dist/r/registry.json +10 -0
- package/dist/r/src/components/theme/script.ts +11 -0
- package/dist/r/src/lib/accent-presets.ts +12 -1
- package/dist/r/src/lib/theme-records.ts +205 -0
- package/dist/r/src/lib/themes.ts +4 -185
- package/dist/r/theming.json +5 -0
- package/package.json +7 -1
- package/registry.json +10 -0
- package/src/components/theme/script.ts +11 -0
- package/src/lib/accent-presets.ts +12 -1
- package/src/lib/theme-records.ts +205 -0
- package/src/lib/themes.ts +4 -185
package/dist/r/theming.json
CHANGED
|
@@ -33,6 +33,11 @@
|
|
|
33
33
|
"type": "registry:ui",
|
|
34
34
|
"target": "components/theming/lazy.ts"
|
|
35
35
|
},
|
|
36
|
+
{
|
|
37
|
+
"path": "src/components/theme/script.ts",
|
|
38
|
+
"type": "registry:ui",
|
|
39
|
+
"target": "components/theming/script.ts"
|
|
40
|
+
},
|
|
36
41
|
{
|
|
37
42
|
"path": "src/components/theme/theme-catalogue-source.ts",
|
|
38
43
|
"type": "registry:ui",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adea-ai/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.129.0",
|
|
4
4
|
"description": "The Adea design system: Kobalte-backed Solid components, semantic OKLCH tokens, and the app-shell layout primitives shared by Adea and Cortana.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adea",
|
|
@@ -74,6 +74,12 @@
|
|
|
74
74
|
"./fonts.css": "./src/styles/fonts.css",
|
|
75
75
|
"./registry.json": "./registry.json",
|
|
76
76
|
"./package.json": "./package.json",
|
|
77
|
+
"./components/theme/script": {
|
|
78
|
+
"types": "./dist/components/theme/script.d.ts",
|
|
79
|
+
"solid": "./src/components/theme/script.ts",
|
|
80
|
+
"development": "./src/components/theme/script.ts",
|
|
81
|
+
"import": "./dist/components/theme/script.js"
|
|
82
|
+
},
|
|
77
83
|
"./components/theme/lazy": {
|
|
78
84
|
"types": "./dist/components/theme/lazy.d.ts",
|
|
79
85
|
"solid": "./src/components/theme/lazy.ts",
|
package/registry.json
CHANGED
|
@@ -2532,6 +2532,11 @@
|
|
|
2532
2532
|
"type": "registry:ui",
|
|
2533
2533
|
"target": "components/theming/lazy.ts"
|
|
2534
2534
|
},
|
|
2535
|
+
{
|
|
2536
|
+
"path": "src/components/theme/script.ts",
|
|
2537
|
+
"type": "registry:ui",
|
|
2538
|
+
"target": "components/theming/script.ts"
|
|
2539
|
+
},
|
|
2535
2540
|
{
|
|
2536
2541
|
"path": "src/components/theme/theme-catalogue-source.ts",
|
|
2537
2542
|
"type": "registry:ui",
|
|
@@ -2789,6 +2794,11 @@
|
|
|
2789
2794
|
"type": "registry:lib",
|
|
2790
2795
|
"target": "lib/theme-engine.ts"
|
|
2791
2796
|
},
|
|
2797
|
+
{
|
|
2798
|
+
"path": "src/lib/theme-records.ts",
|
|
2799
|
+
"type": "registry:lib",
|
|
2800
|
+
"target": "lib/theme-records.ts"
|
|
2801
|
+
},
|
|
2792
2802
|
{
|
|
2793
2803
|
"path": "src/lib/theme-surface.ts",
|
|
2794
2804
|
"type": "registry:lib",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The no-flash boot script, importable where there is no UI runtime.
|
|
3
|
+
*
|
|
4
|
+
* `themeScript` writes the document attributes before first paint. A host that
|
|
5
|
+
* renders its HTML at build time (a Vite `index.html` served by a desktop shell
|
|
6
|
+
* whose CSP allows no inline script) needs the string in Node, and the provider
|
|
7
|
+
* entries cannot be imported there: they load Solid's client runtime. This entry
|
|
8
|
+
* holds only the script and the types it takes, so it loads anywhere.
|
|
9
|
+
*/
|
|
10
|
+
export { inlineScriptLiteral, themeScript, type ThemeScriptOptions } from './theme-script'
|
|
11
|
+
export type { ThemeStorageSchema } from './theme-persistence'
|
|
@@ -4,7 +4,8 @@ import { ACCENTS } from '@adea-ai/themes'
|
|
|
4
4
|
* Its own module so the theme provider's start-up path (the stored-preference reader
|
|
5
5
|
* and the boot script both need the preset ids) does not import the token manifest in
|
|
6
6
|
* `tokens.ts`, which is 20 KB of documentation data a provider never reads.
|
|
7
|
-
* `tokens.ts` re-exports
|
|
7
|
+
* `tokens.ts` re-exports `accentPresets` and `AccentPreset`, and `themes.ts` re-exports
|
|
8
|
+
* `accents`, so every existing import keeps working.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -41,3 +42,13 @@ export const accentPresets: readonly AccentPreset[] = Object.freeze([
|
|
|
41
42
|
},
|
|
42
43
|
...ACCENTS,
|
|
43
44
|
])
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The six brand accent presets, in the order a picker should show them: the list
|
|
48
|
+
* `accentPresets` carries after its own `theme` entry.
|
|
49
|
+
*
|
|
50
|
+
* Here and not beside the theme table in `lib/themes.ts` (which re-exports it, so
|
|
51
|
+
* `@adea-ai/ui/lib/themes` still has it) because a bundler places a module whole, and
|
|
52
|
+
* a host that wants only the list should not ship the 34-theme catalogue with it.
|
|
53
|
+
*/
|
|
54
|
+
export const accents = ACCENTS
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One catalogue record, as this system's {@link ThemeVariant}.
|
|
3
|
+
*
|
|
4
|
+
* `variantFromRecord` and the lazy form the catalogue is built with live here, and not
|
|
5
|
+
* beside the 34-theme table in `lib/themes.ts`, because a bundler places a module
|
|
6
|
+
* whole: a host that imports `variantFromRecord` from the same module as the table
|
|
7
|
+
* ships the table with it. This module reads a record it is handed and imports no
|
|
8
|
+
* catalogue, so a start-up path that only turns a stored record into a variant
|
|
9
|
+
* (an imported theme, a reconstruction) stays small. `lib/themes.ts` re-exports
|
|
10
|
+
* `variantFromRecord`, so `@adea-ai/ui/lib/themes` keeps working; the lazy start-up
|
|
11
|
+
* gate (`check:theme-startup`) holds the split in place.
|
|
12
|
+
*
|
|
13
|
+
* It does import `@adea-ai/themes` for the projection helpers (`chartSeries`,
|
|
14
|
+
* `tint`, `shadcnVariables`…), none of which reads the table of themes.
|
|
15
|
+
*/
|
|
16
|
+
import {
|
|
17
|
+
chartSeries,
|
|
18
|
+
shadcnDestructiveProjection,
|
|
19
|
+
statusForeground,
|
|
20
|
+
syntaxRoles,
|
|
21
|
+
tint,
|
|
22
|
+
type AdeaThemeRecord,
|
|
23
|
+
} from '@adea-ai/themes'
|
|
24
|
+
import { shadcnVariables } from '@adea-ai/themes/adapters/shadcn'
|
|
25
|
+
import type {
|
|
26
|
+
ThemeColors,
|
|
27
|
+
ThemeEditorPalette,
|
|
28
|
+
ThemeProvenance,
|
|
29
|
+
ThemeTerminalPalette,
|
|
30
|
+
ThemeVariant,
|
|
31
|
+
} from './themes'
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The shadcn-vocabulary roles of one catalogue entry.
|
|
35
|
+
*
|
|
36
|
+
* The expensive half of a variant: `shadcnVariables` projects the whole palette
|
|
37
|
+
* (about 4 ms a theme), which is why {@link lazyVariantFromRecord} defers it.
|
|
38
|
+
*/
|
|
39
|
+
function colorsOf(theme: AdeaThemeRecord): ThemeColors {
|
|
40
|
+
const projected = shadcnVariables(theme)
|
|
41
|
+
const token = (name: string): string => {
|
|
42
|
+
const value = projected[`--${name}`]
|
|
43
|
+
if (!value) throw new Error(`${theme.id} has no shared shadcn projection for --${name}`)
|
|
44
|
+
return value
|
|
45
|
+
}
|
|
46
|
+
const destructiveAction = shadcnDestructiveProjection(theme)
|
|
47
|
+
return {
|
|
48
|
+
background: token('background'),
|
|
49
|
+
foreground: token('foreground'),
|
|
50
|
+
card: token('card'),
|
|
51
|
+
cardForeground: token('card-foreground'),
|
|
52
|
+
popover: token('popover'),
|
|
53
|
+
popoverForeground: token('popover-foreground'),
|
|
54
|
+
primary: token('primary'),
|
|
55
|
+
primaryForeground: token('primary-foreground'),
|
|
56
|
+
secondary: token('secondary'),
|
|
57
|
+
secondaryForeground: token('secondary-foreground'),
|
|
58
|
+
muted: token('muted'),
|
|
59
|
+
mutedForeground: token('muted-foreground'),
|
|
60
|
+
accent: token('accent'),
|
|
61
|
+
accentForeground: token('accent-foreground'),
|
|
62
|
+
// Preserve the UI's semantic error token. The Themes projection uses its
|
|
63
|
+
// contrast-safe solid-action fill for --destructive; UI keeps that fill in
|
|
64
|
+
// the separate destructiveAction pair below.
|
|
65
|
+
destructive: theme.colors.error,
|
|
66
|
+
destructiveForeground: statusForeground(theme, 'error'),
|
|
67
|
+
destructiveSubtle: tint(theme.colors.error, theme.colors.background),
|
|
68
|
+
destructiveAction: destructiveAction.fill,
|
|
69
|
+
destructiveActionForeground: destructiveAction.foreground,
|
|
70
|
+
success: token('success'),
|
|
71
|
+
successForeground: statusForeground(theme, 'success'),
|
|
72
|
+
successSubtle: tint(theme.colors.success, theme.colors.background),
|
|
73
|
+
warning: token('warning'),
|
|
74
|
+
warningForeground: statusForeground(theme, 'warning'),
|
|
75
|
+
warningSubtle: tint(theme.colors.warning, theme.colors.background),
|
|
76
|
+
info: token('info'),
|
|
77
|
+
infoForeground: statusForeground(theme, 'info'),
|
|
78
|
+
infoSubtle: tint(theme.colors.info, theme.colors.background),
|
|
79
|
+
border: token('border'),
|
|
80
|
+
input: token('input'),
|
|
81
|
+
ring: token('ring'),
|
|
82
|
+
sidebar: token('sidebar'),
|
|
83
|
+
sidebarForeground: token('sidebar-foreground'),
|
|
84
|
+
sidebarAccent: token('sidebar-accent'),
|
|
85
|
+
sidebarBorder: token('sidebar-border'),
|
|
86
|
+
sidebarMutedForeground: token('sidebar-muted-foreground'),
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// The embedded terminal uses the theme's own canvas rather than a palette of its
|
|
91
|
+
// own. The ANSI colours came from the palette that produced the canvas, so they
|
|
92
|
+
// were chosen against it; a terminal on a different background would be the one
|
|
93
|
+
// surface in the application not lit by the active theme.
|
|
94
|
+
function terminalOf(theme: AdeaThemeRecord): ThemeTerminalPalette {
|
|
95
|
+
return {
|
|
96
|
+
background: theme.colors.background,
|
|
97
|
+
foreground: theme.colors.foreground,
|
|
98
|
+
cursor: theme.cursor,
|
|
99
|
+
selection: theme.selection,
|
|
100
|
+
...theme.ansi,
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function editorOf(theme: AdeaThemeRecord): ThemeEditorPalette {
|
|
105
|
+
const syntax = syntaxRoles(theme)
|
|
106
|
+
return {
|
|
107
|
+
keyword: syntax.keyword,
|
|
108
|
+
string: syntax.string,
|
|
109
|
+
number: syntax.number,
|
|
110
|
+
comment: syntax.comment,
|
|
111
|
+
function: syntax.function,
|
|
112
|
+
variable: syntax.variable,
|
|
113
|
+
type: syntax.type,
|
|
114
|
+
tag: syntax.tag,
|
|
115
|
+
attribute: syntax.attribute,
|
|
116
|
+
operator: syntax.operator,
|
|
117
|
+
heading: syntax.heading,
|
|
118
|
+
link: syntax.link,
|
|
119
|
+
diffAdd: syntax.diffAdd,
|
|
120
|
+
diffDelete: syntax.diffDelete,
|
|
121
|
+
diffHunk: syntax.diffHunk,
|
|
122
|
+
searchMatch: syntax.searchMatch,
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function provenanceOf(theme: AdeaThemeRecord): ThemeProvenance {
|
|
127
|
+
return {
|
|
128
|
+
source: theme.provenance.project,
|
|
129
|
+
url: theme.provenance.url,
|
|
130
|
+
license: theme.provenance.license,
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The design system's view of one catalogue record, built in full and at once.
|
|
136
|
+
*
|
|
137
|
+
* For a host that holds a record the catalogue does not — an imported theme, a
|
|
138
|
+
* reconstruction from stored data — and wants a variant it can hand to
|
|
139
|
+
* `ThemeProvider`'s `themes`. It throws for a record the shadcn projection cannot
|
|
140
|
+
* map, here and now, rather than on first paint. The catalogue itself goes through
|
|
141
|
+
* {@link lazyVariantFromRecord} instead.
|
|
142
|
+
*/
|
|
143
|
+
export function variantFromRecord(theme: AdeaThemeRecord): ThemeVariant {
|
|
144
|
+
return {
|
|
145
|
+
id: theme.id,
|
|
146
|
+
family: theme.family,
|
|
147
|
+
familyLabel: theme.familyLabel,
|
|
148
|
+
label: theme.label,
|
|
149
|
+
appearance: theme.appearance,
|
|
150
|
+
description: theme.description,
|
|
151
|
+
colors: colorsOf(theme),
|
|
152
|
+
terminal: terminalOf(theme),
|
|
153
|
+
editor: editorOf(theme),
|
|
154
|
+
chart: chartSeries(theme),
|
|
155
|
+
provenance: provenanceOf(theme),
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Runs `build` on first call and returns that value from then on. A throw is not cached. */
|
|
160
|
+
function once<T>(build: () => T): () => T {
|
|
161
|
+
let built = false
|
|
162
|
+
let value: T
|
|
163
|
+
return () => {
|
|
164
|
+
if (!built) {
|
|
165
|
+
value = build()
|
|
166
|
+
built = true
|
|
167
|
+
}
|
|
168
|
+
return value
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const lazy = <T>(build: () => T): PropertyDescriptor => ({
|
|
173
|
+
get: once(build),
|
|
174
|
+
enumerable: true,
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* {@link variantFromRecord} with the four derived palettes built on first read.
|
|
179
|
+
*
|
|
180
|
+
* Evaluating this module used to project all 34 catalogue themes up front, about
|
|
181
|
+
* 155 ms before a single one was needed, on the hydration path of every consumer.
|
|
182
|
+
* A page paints one variant, and a picker's labels and appearance are plain
|
|
183
|
+
* fields, so only a variant whose `colors`, `terminal`, `editor` or `chart` is read
|
|
184
|
+
* pays for them, once. The properties stay enumerable data-shaped accessors, so
|
|
185
|
+
* spreading, `Object.entries` and JSON see the same object they always did.
|
|
186
|
+
*/
|
|
187
|
+
export function lazyVariantFromRecord(theme: AdeaThemeRecord): ThemeVariant {
|
|
188
|
+
return Object.defineProperties(
|
|
189
|
+
{
|
|
190
|
+
id: theme.id,
|
|
191
|
+
family: theme.family,
|
|
192
|
+
familyLabel: theme.familyLabel,
|
|
193
|
+
label: theme.label,
|
|
194
|
+
appearance: theme.appearance,
|
|
195
|
+
description: theme.description,
|
|
196
|
+
provenance: provenanceOf(theme),
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
colors: lazy(() => colorsOf(theme)),
|
|
200
|
+
terminal: lazy(() => terminalOf(theme)),
|
|
201
|
+
editor: lazy(() => editorOf(theme)),
|
|
202
|
+
chart: lazy(() => chartSeries(theme)),
|
|
203
|
+
}
|
|
204
|
+
) as ThemeVariant
|
|
205
|
+
}
|
package/src/lib/themes.ts
CHANGED
|
@@ -34,18 +34,12 @@
|
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
36
|
import {
|
|
37
|
-
ACCENTS,
|
|
38
37
|
accentForeground,
|
|
39
|
-
chartSeries,
|
|
40
38
|
editorRolesHex,
|
|
41
39
|
getAccent,
|
|
42
40
|
getTheme,
|
|
43
41
|
hasTheme,
|
|
44
|
-
shadcnDestructiveProjection,
|
|
45
|
-
statusForeground,
|
|
46
|
-
tint,
|
|
47
42
|
primarySubtleCss,
|
|
48
|
-
syntaxRoles,
|
|
49
43
|
themes as catalogue,
|
|
50
44
|
themesByAppearance,
|
|
51
45
|
themeAccentPresets,
|
|
@@ -55,15 +49,17 @@ import {
|
|
|
55
49
|
type AdeaThemeRecord,
|
|
56
50
|
type ContrastFinding,
|
|
57
51
|
} from '@adea-ai/themes'
|
|
58
|
-
import { shadcnVariables } from '@adea-ai/themes/adapters/shadcn'
|
|
59
52
|
import { accentOverrideVariables, resolveAccentRoles, type AccentRoles } from './accent-roles'
|
|
60
53
|
import { isThemeAccentId } from './theme-accents'
|
|
61
54
|
import { themeCssVariablesWith } from './theme-css'
|
|
62
55
|
import { defaultDarkThemeId, defaultLightThemeId } from './theme-defaults'
|
|
56
|
+
import { lazyVariantFromRecord } from './theme-records'
|
|
63
57
|
|
|
58
|
+
export { accents } from './accent-presets'
|
|
64
59
|
export { isThemeAccentId } from './theme-accents'
|
|
65
60
|
export { terminalCssVariables, tokensAsHex } from './theme-css'
|
|
66
61
|
export { defaultDarkThemeId, defaultLightThemeId, resolveVariant } from './theme-defaults'
|
|
62
|
+
export { variantFromRecord } from './theme-records'
|
|
67
63
|
|
|
68
64
|
export type ThemeAppearance = 'light' | 'dark'
|
|
69
65
|
|
|
@@ -194,180 +190,6 @@ export type ThemeVariant = {
|
|
|
194
190
|
tokens?: Readonly<Record<string, string>>
|
|
195
191
|
}
|
|
196
192
|
|
|
197
|
-
/**
|
|
198
|
-
* The shadcn-vocabulary roles of one catalogue entry.
|
|
199
|
-
*
|
|
200
|
-
* The expensive half of a variant: `shadcnVariables` projects the whole palette
|
|
201
|
-
* (about 4 ms a theme), which is why {@link lazyVariant} defers it.
|
|
202
|
-
*/
|
|
203
|
-
function colorsOf(theme: AdeaThemeRecord): ThemeColors {
|
|
204
|
-
const projected = shadcnVariables(theme)
|
|
205
|
-
const token = (name: string): string => {
|
|
206
|
-
const value = projected[`--${name}`]
|
|
207
|
-
if (!value) throw new Error(`${theme.id} has no shared shadcn projection for --${name}`)
|
|
208
|
-
return value
|
|
209
|
-
}
|
|
210
|
-
const destructiveAction = shadcnDestructiveProjection(theme)
|
|
211
|
-
return {
|
|
212
|
-
background: token('background'),
|
|
213
|
-
foreground: token('foreground'),
|
|
214
|
-
card: token('card'),
|
|
215
|
-
cardForeground: token('card-foreground'),
|
|
216
|
-
popover: token('popover'),
|
|
217
|
-
popoverForeground: token('popover-foreground'),
|
|
218
|
-
primary: token('primary'),
|
|
219
|
-
primaryForeground: token('primary-foreground'),
|
|
220
|
-
secondary: token('secondary'),
|
|
221
|
-
secondaryForeground: token('secondary-foreground'),
|
|
222
|
-
muted: token('muted'),
|
|
223
|
-
mutedForeground: token('muted-foreground'),
|
|
224
|
-
accent: token('accent'),
|
|
225
|
-
accentForeground: token('accent-foreground'),
|
|
226
|
-
// Preserve the UI's semantic error token. The Themes projection uses its
|
|
227
|
-
// contrast-safe solid-action fill for --destructive; UI keeps that fill in
|
|
228
|
-
// the separate destructiveAction pair below.
|
|
229
|
-
destructive: theme.colors.error,
|
|
230
|
-
destructiveForeground: statusForeground(theme, 'error'),
|
|
231
|
-
destructiveSubtle: tint(theme.colors.error, theme.colors.background),
|
|
232
|
-
destructiveAction: destructiveAction.fill,
|
|
233
|
-
destructiveActionForeground: destructiveAction.foreground,
|
|
234
|
-
success: token('success'),
|
|
235
|
-
successForeground: statusForeground(theme, 'success'),
|
|
236
|
-
successSubtle: tint(theme.colors.success, theme.colors.background),
|
|
237
|
-
warning: token('warning'),
|
|
238
|
-
warningForeground: statusForeground(theme, 'warning'),
|
|
239
|
-
warningSubtle: tint(theme.colors.warning, theme.colors.background),
|
|
240
|
-
info: token('info'),
|
|
241
|
-
infoForeground: statusForeground(theme, 'info'),
|
|
242
|
-
infoSubtle: tint(theme.colors.info, theme.colors.background),
|
|
243
|
-
border: token('border'),
|
|
244
|
-
input: token('input'),
|
|
245
|
-
ring: token('ring'),
|
|
246
|
-
sidebar: token('sidebar'),
|
|
247
|
-
sidebarForeground: token('sidebar-foreground'),
|
|
248
|
-
sidebarAccent: token('sidebar-accent'),
|
|
249
|
-
sidebarBorder: token('sidebar-border'),
|
|
250
|
-
sidebarMutedForeground: token('sidebar-muted-foreground'),
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// The embedded terminal uses the theme's own canvas rather than a palette of its
|
|
255
|
-
// own. The ANSI colours came from the palette that produced the canvas, so they
|
|
256
|
-
// were chosen against it; a terminal on a different background would be the one
|
|
257
|
-
// surface in the application not lit by the active theme.
|
|
258
|
-
function terminalOf(theme: AdeaThemeRecord): ThemeTerminalPalette {
|
|
259
|
-
return {
|
|
260
|
-
background: theme.colors.background,
|
|
261
|
-
foreground: theme.colors.foreground,
|
|
262
|
-
cursor: theme.cursor,
|
|
263
|
-
selection: theme.selection,
|
|
264
|
-
...theme.ansi,
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function editorOf(theme: AdeaThemeRecord): ThemeEditorPalette {
|
|
269
|
-
const syntax = syntaxRoles(theme)
|
|
270
|
-
return {
|
|
271
|
-
keyword: syntax.keyword,
|
|
272
|
-
string: syntax.string,
|
|
273
|
-
number: syntax.number,
|
|
274
|
-
comment: syntax.comment,
|
|
275
|
-
function: syntax.function,
|
|
276
|
-
variable: syntax.variable,
|
|
277
|
-
type: syntax.type,
|
|
278
|
-
tag: syntax.tag,
|
|
279
|
-
attribute: syntax.attribute,
|
|
280
|
-
operator: syntax.operator,
|
|
281
|
-
heading: syntax.heading,
|
|
282
|
-
link: syntax.link,
|
|
283
|
-
diffAdd: syntax.diffAdd,
|
|
284
|
-
diffDelete: syntax.diffDelete,
|
|
285
|
-
diffHunk: syntax.diffHunk,
|
|
286
|
-
searchMatch: syntax.searchMatch,
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function provenanceOf(theme: AdeaThemeRecord): ThemeProvenance {
|
|
291
|
-
return {
|
|
292
|
-
source: theme.provenance.project,
|
|
293
|
-
url: theme.provenance.url,
|
|
294
|
-
license: theme.provenance.license,
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* The design system's view of one catalogue record, built in full and at once.
|
|
300
|
-
*
|
|
301
|
-
* For a host that holds a record the catalogue does not — an imported theme, a
|
|
302
|
-
* reconstruction from stored data — and wants a variant it can hand to
|
|
303
|
-
* `ThemeProvider`'s `themes`. It throws for a record the shadcn projection cannot
|
|
304
|
-
* map, here and now, rather than on first paint. The catalogue itself goes through
|
|
305
|
-
* {@link lazyVariant} instead.
|
|
306
|
-
*/
|
|
307
|
-
export function variantFromRecord(theme: AdeaThemeRecord): ThemeVariant {
|
|
308
|
-
return {
|
|
309
|
-
id: theme.id,
|
|
310
|
-
family: theme.family,
|
|
311
|
-
familyLabel: theme.familyLabel,
|
|
312
|
-
label: theme.label,
|
|
313
|
-
appearance: theme.appearance,
|
|
314
|
-
description: theme.description,
|
|
315
|
-
colors: colorsOf(theme),
|
|
316
|
-
terminal: terminalOf(theme),
|
|
317
|
-
editor: editorOf(theme),
|
|
318
|
-
chart: chartSeries(theme),
|
|
319
|
-
provenance: provenanceOf(theme),
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/** Runs `build` on first call and returns that value from then on. A throw is not cached. */
|
|
324
|
-
function once<T>(build: () => T): () => T {
|
|
325
|
-
let built = false
|
|
326
|
-
let value: T
|
|
327
|
-
return () => {
|
|
328
|
-
if (!built) {
|
|
329
|
-
value = build()
|
|
330
|
-
built = true
|
|
331
|
-
}
|
|
332
|
-
return value
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const lazy = <T>(build: () => T): PropertyDescriptor => ({
|
|
337
|
-
get: once(build),
|
|
338
|
-
enumerable: true,
|
|
339
|
-
})
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* {@link variantFromRecord} with the four derived palettes built on first read.
|
|
343
|
-
*
|
|
344
|
-
* Evaluating this module used to project all 34 catalogue themes up front, about
|
|
345
|
-
* 155 ms before a single one was needed, on the hydration path of every consumer.
|
|
346
|
-
* A page paints one variant, and a picker's labels and appearance are plain
|
|
347
|
-
* fields, so only a variant whose `colors`, `terminal`, `editor` or `chart` is read
|
|
348
|
-
* pays for them, once. The properties stay enumerable data-shaped accessors, so
|
|
349
|
-
* spreading, `Object.entries` and JSON see the same object they always did.
|
|
350
|
-
*/
|
|
351
|
-
function lazyVariant(theme: AdeaThemeRecord): ThemeVariant {
|
|
352
|
-
return Object.defineProperties(
|
|
353
|
-
{
|
|
354
|
-
id: theme.id,
|
|
355
|
-
family: theme.family,
|
|
356
|
-
familyLabel: theme.familyLabel,
|
|
357
|
-
label: theme.label,
|
|
358
|
-
appearance: theme.appearance,
|
|
359
|
-
description: theme.description,
|
|
360
|
-
provenance: provenanceOf(theme),
|
|
361
|
-
},
|
|
362
|
-
{
|
|
363
|
-
colors: lazy(() => colorsOf(theme)),
|
|
364
|
-
terminal: lazy(() => terminalOf(theme)),
|
|
365
|
-
editor: lazy(() => editorOf(theme)),
|
|
366
|
-
chart: lazy(() => chartSeries(theme)),
|
|
367
|
-
}
|
|
368
|
-
) as ThemeVariant
|
|
369
|
-
}
|
|
370
|
-
|
|
371
193
|
/**
|
|
372
194
|
* A variant's `--primary-subtle`: the tint over `var(--primary)` at the strength its
|
|
373
195
|
* catalogue record measures (`primarySubtleAlpha`). A variant that is not in the
|
|
@@ -386,7 +208,7 @@ export function primarySubtleFor(theme: Pick<ThemeVariant, 'id' | 'appearance'>)
|
|
|
386
208
|
* (`tokensAsHex`, `isThemeAccentId`, `resolveVariant`…) and never reads it.
|
|
387
209
|
*/
|
|
388
210
|
export const builtinThemes: readonly ThemeVariant[] = /* @__PURE__ */ Object.freeze(
|
|
389
|
-
/* @__PURE__ */ catalogue.map(
|
|
211
|
+
/* @__PURE__ */ catalogue.map(lazyVariantFromRecord)
|
|
390
212
|
)
|
|
391
213
|
|
|
392
214
|
export function themeById(id: string): ThemeVariant | undefined {
|
|
@@ -415,9 +237,6 @@ export function themeFamilies(): { family: string; label: string; themes: ThemeV
|
|
|
415
237
|
return [...families.values()]
|
|
416
238
|
}
|
|
417
239
|
|
|
418
|
-
/** The accent presets, in the order a picker should show them. */
|
|
419
|
-
export const accents = ACCENTS
|
|
420
|
-
|
|
421
240
|
/**
|
|
422
241
|
* The canonical catalogue records, in catalogue order.
|
|
423
242
|
*
|