@adea-ai/ui 0.130.3 → 0.131.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/README.md +15 -0
- package/dist/components/composites/appearance-editor/accent-swatch-groups.d.ts +7 -0
- package/dist/components/composites/appearance-editor/accent-swatch-groups.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/accent-swatch-groups.js +39 -13
- package/dist/components/composites/appearance-editor/accent-swatch-groups.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-choices.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-choices.js +222 -116
- package/dist/components/composites/appearance-editor/appearance-choices.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-editor.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-editor.js +6 -1
- package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-types.d.ts +22 -3
- package/dist/components/composites/appearance-editor/appearance-types.d.ts.map +1 -1
- package/dist/lib/accent-presets.d.ts +7 -0
- package/dist/lib/accent-presets.d.ts.map +1 -1
- package/dist/lib/accent-presets.js +2 -2
- package/dist/lib/accent-presets.js.map +1 -1
- package/dist/lib/theme-projection.d.ts +23 -0
- package/dist/lib/theme-projection.d.ts.map +1 -0
- package/dist/lib/theme-projection.js +48 -0
- package/dist/lib/theme-projection.js.map +1 -0
- package/dist/lib/theme-records.d.ts +2 -0
- package/dist/lib/theme-records.d.ts.map +1 -1
- package/dist/lib/theme-records.js.map +1 -1
- package/dist/r/lib.json +5 -0
- package/dist/r/registry.json +5 -0
- package/dist/r/src/components/composites/appearance-editor/accent-swatch-groups.tsx +44 -10
- package/dist/r/src/components/composites/appearance-editor/appearance-choices.tsx +158 -80
- package/dist/r/src/components/composites/appearance-editor/appearance-editor.tsx +7 -2
- package/dist/r/src/components/composites/appearance-editor/appearance-types.ts +22 -3
- package/dist/r/src/lib/accent-presets.ts +8 -0
- package/dist/r/src/lib/theme-projection.ts +52 -0
- package/dist/r/src/lib/theme-records.ts +3 -0
- package/package.json +1 -1
- package/registry.json +5 -0
- package/src/components/composites/appearance-editor/accent-swatch-groups.tsx +44 -10
- package/src/components/composites/appearance-editor/appearance-choices.tsx +158 -80
- package/src/components/composites/appearance-editor/appearance-editor.tsx +7 -2
- package/src/components/composites/appearance-editor/appearance-types.ts +22 -3
- package/src/lib/accent-presets.ts +8 -0
- package/src/lib/theme-projection.ts +52 -0
- package/src/lib/theme-records.ts +3 -0
|
@@ -24,8 +24,11 @@
|
|
|
24
24
|
// Pinned mode-card, accent-swatch, and glass-chip composition. Kobalte replaces
|
|
25
25
|
// the app port's manual roving focus; it does not replace the donor hierarchy.
|
|
26
26
|
import { RadioGroup as Radio } from '@kobalte/core/radio-group'
|
|
27
|
+
import { Monitor, Moon, Sun } from 'lucide-solid'
|
|
27
28
|
import { For, Show } from 'solid-js'
|
|
28
29
|
import { isThemeAccentId } from '#lib/theme-accents'
|
|
30
|
+
import { Button } from '../../ui/button/button'
|
|
31
|
+
import { Input } from '../../ui/input/input'
|
|
29
32
|
import { AccentSwatchGroups } from './accent-swatch-groups'
|
|
30
33
|
import type { AppearanceEditorProps } from './appearance-types'
|
|
31
34
|
import { ThemeMiniature, ThemeMiniatureSplit } from './theme-preview'
|
|
@@ -40,6 +43,8 @@ const SURFACES = [
|
|
|
40
43
|
{ value: 'frosted', label: 'Frosted' },
|
|
41
44
|
{ value: 'opaque', label: 'Opaque' },
|
|
42
45
|
] as const
|
|
46
|
+
const MODE_ICONS = { system: Monitor, light: Sun, dark: Moon } as const
|
|
47
|
+
|
|
43
48
|
export function ModeChoices(props: AppearanceEditorProps) {
|
|
44
49
|
return (
|
|
45
50
|
<Radio
|
|
@@ -54,30 +59,40 @@ export function ModeChoices(props: AppearanceEditorProps) {
|
|
|
54
59
|
class="grid grid-cols-1 gap-3 px-4 py-4 sm:grid-cols-3"
|
|
55
60
|
>
|
|
56
61
|
<For each={MODES}>
|
|
57
|
-
{(option) =>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
62
|
+
{(option) => {
|
|
63
|
+
const Icon = MODE_ICONS[option.value]
|
|
64
|
+
return (
|
|
65
|
+
<Radio.Item
|
|
66
|
+
value={option.value}
|
|
67
|
+
data-mode={option.value}
|
|
68
|
+
class="min-w-0 rounded-lg focus-within:ring-3 focus-within:ring-ring/50"
|
|
69
|
+
>
|
|
70
|
+
<Radio.ItemInput />
|
|
71
|
+
<Radio.ItemLabel class="flex cursor-pointer flex-col gap-2 rounded-lg border p-2 text-center text-xs data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50">
|
|
72
|
+
<span class="block h-20 w-full">
|
|
73
|
+
<Show
|
|
74
|
+
when={option.value === 'system'}
|
|
75
|
+
fallback={
|
|
76
|
+
<ThemeMiniature
|
|
77
|
+
theme={option.value === 'light' ? props.lightTheme : props.darkTheme}
|
|
78
|
+
/>
|
|
79
|
+
}
|
|
80
|
+
>
|
|
81
|
+
<ThemeMiniatureSplit light={props.lightTheme} dark={props.darkTheme} />
|
|
82
|
+
</Show>
|
|
83
|
+
</span>
|
|
84
|
+
{/* The glyph names the axis beside the miniature, so the cards read
|
|
85
|
+
like ThemeModeToggle without losing the previews. */}
|
|
86
|
+
<Show when={props.showModeIcons} fallback={<span>{option.label}</span>}>
|
|
87
|
+
<span class="flex items-center justify-center gap-1.5">
|
|
88
|
+
<Icon aria-hidden="true" class="size-3.5" />
|
|
89
|
+
{option.label}
|
|
90
|
+
</span>
|
|
75
91
|
</Show>
|
|
76
|
-
</
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
)}
|
|
92
|
+
</Radio.ItemLabel>
|
|
93
|
+
</Radio.Item>
|
|
94
|
+
)
|
|
95
|
+
}}
|
|
81
96
|
</For>
|
|
82
97
|
</Radio>
|
|
83
98
|
)
|
|
@@ -106,75 +121,138 @@ export function AccentChoices(props: AppearanceEditorProps) {
|
|
|
106
121
|
props.draft.mode === 'system' ? props.resolvedAppearance : props.draft.mode
|
|
107
122
|
const accentSelection = () => (isCustomAccent(props) ? 'custom' : props.draft.accent)
|
|
108
123
|
const showThemeDefault = () => props.showThemeDefaultAccent ?? true
|
|
124
|
+
const entryStyle = () => props.accentEntryStyle ?? 'swatches'
|
|
125
|
+
const themeDefaultColor = () =>
|
|
126
|
+
resolvedAppearance() === 'light'
|
|
127
|
+
? props.lightTheme.colors.accent
|
|
128
|
+
: props.darkTheme.colors.accent
|
|
109
129
|
// The named-chip style feeds the same resolved preset list to both entries:
|
|
110
130
|
// "Theme default" leads only when the host has not folded it into a preset.
|
|
111
131
|
const labelEntries = () => {
|
|
112
132
|
const presets = props.accentOptions.filter((option) => option.id !== 'theme')
|
|
113
133
|
return showThemeDefault() ? [{ id: 'theme', label: 'Theme default' }, ...presets] : presets
|
|
114
134
|
}
|
|
135
|
+
// The `row` style's Custom entry is a button that opens the native colour
|
|
136
|
+
// selector, so the draft only changes once a colour is chosen there. The
|
|
137
|
+
// input stays in the tree for the selector to anchor to and for the value a
|
|
138
|
+
// saved hex restores.
|
|
139
|
+
let colorPicker: HTMLInputElement | undefined
|
|
140
|
+
const openCustomColor = () => {
|
|
141
|
+
if (!colorPicker || props.saving) return
|
|
142
|
+
if (typeof colorPicker.showPicker === 'function') colorPicker.showPicker()
|
|
143
|
+
else colorPicker.click()
|
|
144
|
+
}
|
|
115
145
|
return (
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
<Show
|
|
147
|
+
when={entryStyle() === 'row'}
|
|
148
|
+
fallback={
|
|
149
|
+
<Radio
|
|
150
|
+
value={accentSelection()}
|
|
151
|
+
disabled={props.saving}
|
|
152
|
+
orientation="horizontal"
|
|
153
|
+
aria-label="Accent"
|
|
154
|
+
class="flex flex-col items-start gap-3"
|
|
155
|
+
onChange={(accent) =>
|
|
156
|
+
props.onChange({
|
|
157
|
+
accent: accent === 'custom' ? (props.customAccentValue ?? '') : accent,
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
>
|
|
161
|
+
<Show
|
|
162
|
+
when={entryStyle() === 'labels'}
|
|
163
|
+
fallback={
|
|
164
|
+
<>
|
|
165
|
+
<AccentSwatchGroups
|
|
166
|
+
accentOptions={props.accentOptions}
|
|
167
|
+
resolvedAppearance={resolvedAppearance()}
|
|
168
|
+
showThemeDefault={showThemeDefault()}
|
|
169
|
+
themeDefaultColor={themeDefaultColor()}
|
|
170
|
+
/>
|
|
171
|
+
<div class="flex flex-col gap-1">
|
|
172
|
+
<Show when={props.showCustomAccentCaption ?? true}>
|
|
173
|
+
<span class="text-xs font-medium text-muted-foreground">Custom</span>
|
|
174
|
+
</Show>
|
|
175
|
+
<Radio.Item value="custom">
|
|
176
|
+
<Radio.ItemInput />
|
|
177
|
+
<Radio.ItemLabel class="flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs whitespace-nowrap data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary">
|
|
178
|
+
Custom
|
|
179
|
+
</Radio.ItemLabel>
|
|
180
|
+
</Radio.Item>
|
|
181
|
+
</div>
|
|
182
|
+
</>
|
|
183
|
+
}
|
|
184
|
+
>
|
|
185
|
+
{/* The named-chip style: one grid, every choice a labelled control,
|
|
186
|
+
including the custom colour — nothing to caption from above. */}
|
|
187
|
+
<div class="grid grid-cols-2 gap-2 sm:grid-cols-3" data-accent-grid>
|
|
188
|
+
<For each={labelEntries()}>
|
|
189
|
+
{(option) => (
|
|
190
|
+
<Radio.Item value={option.id} class="min-w-0" data-accent-option={option.id}>
|
|
191
|
+
<Radio.ItemInput />
|
|
192
|
+
<Radio.ItemLabel class="flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs whitespace-nowrap data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary">
|
|
193
|
+
{option.label}
|
|
194
|
+
</Radio.ItemLabel>
|
|
195
|
+
</Radio.Item>
|
|
196
|
+
)}
|
|
197
|
+
</For>
|
|
198
|
+
<Radio.Item value="custom" class="min-w-0">
|
|
147
199
|
<Radio.ItemInput />
|
|
148
200
|
<Radio.ItemLabel class="flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs whitespace-nowrap data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary">
|
|
149
201
|
Custom
|
|
150
202
|
</Radio.ItemLabel>
|
|
151
203
|
</Radio.Item>
|
|
152
204
|
</div>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
205
|
+
</Show>
|
|
206
|
+
</Radio>
|
|
207
|
+
}
|
|
208
|
+
>
|
|
209
|
+
<div class="flex w-full min-w-0 items-center gap-2" data-accent-choices>
|
|
210
|
+
<Radio
|
|
211
|
+
value={accentSelection()}
|
|
212
|
+
disabled={props.saving}
|
|
213
|
+
orientation="horizontal"
|
|
214
|
+
aria-label="Accent"
|
|
215
|
+
class="min-w-0 flex-1"
|
|
216
|
+
onChange={(accent) => props.onChange({ accent })}
|
|
217
|
+
>
|
|
218
|
+
<AccentSwatchGroups
|
|
219
|
+
accentOptions={props.accentOptions}
|
|
220
|
+
resolvedAppearance={resolvedAppearance()}
|
|
221
|
+
showThemeDefault={showThemeDefault()}
|
|
222
|
+
themeDefaultColor={themeDefaultColor()}
|
|
223
|
+
layout="row"
|
|
224
|
+
/>
|
|
225
|
+
</Radio>
|
|
226
|
+
<Button
|
|
227
|
+
type="button"
|
|
228
|
+
variant="outline"
|
|
229
|
+
size="sm"
|
|
230
|
+
disabled={props.saving}
|
|
231
|
+
aria-pressed={isCustomAccent(props)}
|
|
232
|
+
onClick={openCustomColor}
|
|
233
|
+
>
|
|
234
|
+
Custom
|
|
235
|
+
</Button>
|
|
236
|
+
<Input
|
|
237
|
+
ref={(element) => {
|
|
238
|
+
colorPicker = element
|
|
239
|
+
}}
|
|
240
|
+
type="color"
|
|
241
|
+
// `w-px` beats the Input's own `w-full`: an absolutely positioned
|
|
242
|
+
// full-width input sized the sheet's scroll width.
|
|
243
|
+
class="sr-only w-px"
|
|
244
|
+
tabIndex={-1}
|
|
245
|
+
aria-label="Custom accent color"
|
|
246
|
+
value={
|
|
247
|
+
/^#[0-9a-f]{6}$/i.test(props.draft.accent)
|
|
248
|
+
? props.draft.accent
|
|
249
|
+
: (props.customAccentValue ?? '#000000')
|
|
250
|
+
}
|
|
251
|
+
disabled={props.saving}
|
|
252
|
+
onChange={(event) => props.onChange({ accent: event.currentTarget.value })}
|
|
253
|
+
/>
|
|
254
|
+
</div>
|
|
255
|
+
</Show>
|
|
178
256
|
)
|
|
179
257
|
}
|
|
180
258
|
|
|
@@ -199,7 +277,7 @@ export function GlassChoices(props: AppearanceEditorProps) {
|
|
|
199
277
|
class="rounded-md focus-within:ring-3 focus-within:ring-ring/50"
|
|
200
278
|
>
|
|
201
279
|
<Radio.ItemInput />
|
|
202
|
-
<Radio.ItemLabel class="flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50">
|
|
280
|
+
<Radio.ItemLabel class="flex h-7 cursor-pointer items-center rounded-md border px-2 text-xs whitespace-nowrap data-[checked]:border-primary data-[checked]:ring-1 data-[checked]:ring-primary data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50">
|
|
203
281
|
{option.label}
|
|
204
282
|
</Radio.ItemLabel>
|
|
205
283
|
</Radio.Item>
|
|
@@ -278,12 +278,17 @@ export function AppearancePopover(props: AppearancePopoverProps) {
|
|
|
278
278
|
<Sheet open={props.open} onOpenChange={(open) => (open ? props.onOpen() : props.onDismiss())}>
|
|
279
279
|
{/* The trigger is an icon-only action, so it explains itself through the
|
|
280
280
|
shared ActionButton's tooltip (keyboard focus included) rather than a
|
|
281
|
-
bare aria-label.
|
|
281
|
+
bare aria-label. `toolbar` also holds the pressed rung while Kobalte
|
|
282
|
+
marks the trigger `data-expanded`, and repeats the glyph in the
|
|
283
|
+
tooltip like the other toolbar actions. */}
|
|
282
284
|
<SheetTrigger
|
|
283
285
|
as={ActionButton}
|
|
284
|
-
variant=
|
|
286
|
+
variant={props.triggerVariant === 'toolbar' ? 'toolbar' : 'ghost'}
|
|
285
287
|
size="icon-sm"
|
|
286
288
|
tooltip="Open appearance settings"
|
|
289
|
+
tooltipIcon={
|
|
290
|
+
props.triggerVariant === 'toolbar' ? <Palette aria-hidden="true" /> : undefined
|
|
291
|
+
}
|
|
287
292
|
aria-label="Appearance settings"
|
|
288
293
|
>
|
|
289
294
|
<Palette />
|
|
@@ -67,10 +67,16 @@ export type AppearanceEditorProps = {
|
|
|
67
67
|
fontSettingsPlacement?: 'inline' | 'end'
|
|
68
68
|
/**
|
|
69
69
|
* How the accent row renders its choices. `swatches` — the default — paints
|
|
70
|
-
* each choice as a colour circle
|
|
71
|
-
* chip
|
|
70
|
+
* each choice as a colour circle in a wrapping grid, with Custom as one more
|
|
71
|
+
* chip. `labels` renders every choice as a named chip, for hosts whose accent
|
|
72
|
+
* contract is textual rather than chromatic. `row` draws the circles in ONE
|
|
73
|
+
* equally spaced line, which holds at a narrow panel width where the grid
|
|
74
|
+
* would wrap, and turns Custom into a button that opens the native colour
|
|
75
|
+
* selector: choosing a colour there is the only thing that changes the draft,
|
|
76
|
+
* so dismissing the selector leaves the accent as it was. The caption flag
|
|
77
|
+
* has no effect on `row`, which has nothing to caption.
|
|
72
78
|
*/
|
|
73
|
-
accentEntryStyle?: 'swatches' | 'labels'
|
|
79
|
+
accentEntryStyle?: 'swatches' | 'labels' | 'row'
|
|
74
80
|
/**
|
|
75
81
|
* Whether the accent row leads with a "Theme default" swatch. Default on.
|
|
76
82
|
* Hosts whose default accent already is one of the catalogue presets pass
|
|
@@ -83,10 +89,23 @@ export type AppearanceEditorProps = {
|
|
|
83
89
|
* caption reads as a second "Custom" label on the control.
|
|
84
90
|
*/
|
|
85
91
|
showCustomAccentCaption?: boolean
|
|
92
|
+
/**
|
|
93
|
+
* Whether each mode card names its axis with a sun, moon or monitor glyph
|
|
94
|
+
* beside the label, as `ThemeModeToggle` does. Default off.
|
|
95
|
+
*/
|
|
96
|
+
showModeIcons?: boolean
|
|
86
97
|
}
|
|
87
98
|
|
|
88
99
|
export type AppearancePopoverProps = AppearanceEditorProps & {
|
|
89
100
|
open: boolean
|
|
90
101
|
onOpen: () => void
|
|
91
102
|
onDismiss: () => void
|
|
103
|
+
/**
|
|
104
|
+
* The trigger's treatment. `ghost` — the default — is a quiet icon action.
|
|
105
|
+
* `toolbar` is the variant for a control that opens a surface: it holds the
|
|
106
|
+
* pressed rung while the sheet is open, so the one control that owns the
|
|
107
|
+
* visible sheet never reads like its idle neighbours, and its tooltip repeats
|
|
108
|
+
* the palette glyph the other toolbar actions carry.
|
|
109
|
+
*/
|
|
110
|
+
triggerVariant?: 'ghost' | 'toolbar'
|
|
92
111
|
}
|
|
@@ -8,6 +8,14 @@ import { ACCENTS } from '@adea-ai/themes'
|
|
|
8
8
|
* `accents`, so every existing import keeps working.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* A preset by id (`blue`), or `undefined` for `theme`, a theme-carried accent or an
|
|
13
|
+
* unknown id. The catalogue's own lookup, re-exported rather than copied so a host's
|
|
14
|
+
* stored-preference reader resolves an id exactly as the catalogue does without
|
|
15
|
+
* importing `lib/themes`.
|
|
16
|
+
*/
|
|
17
|
+
export { getAccent } from '@adea-ai/themes'
|
|
18
|
+
|
|
11
19
|
/**
|
|
12
20
|
* The accent axis.
|
|
13
21
|
*
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a host needs to turn a canonical theme record into the values it stores.
|
|
3
|
+
*
|
|
4
|
+
* Adea imports user themes: a file is validated, repaired toward the readable floor,
|
|
5
|
+
* and projected onto the hex values the host persists. That projection is the
|
|
6
|
+
* catalogue's own (`shadcnVariables`, the xterm adapter, the editor roles), so it is
|
|
7
|
+
* re-exported here and the host depends on this package alone for it — the pin
|
|
8
|
+
* between this package and `@adea-ai/themes` cannot drift from the host's.
|
|
9
|
+
*
|
|
10
|
+
* Its own module, with no catalogue data and no definition of its own beyond the two
|
|
11
|
+
* default records, so that:
|
|
12
|
+
*
|
|
13
|
+
* - a host's start-up path never reaches it (it is for an importer loaded on demand);
|
|
14
|
+
* - `lib/themes.ts`, which holds the 34-theme table, is not the place a host has to
|
|
15
|
+
* import from to get a record-shaped helper.
|
|
16
|
+
*/
|
|
17
|
+
import adeaDark from '@adea-ai/themes/themes/adea-dark'
|
|
18
|
+
import adeaLight from '@adea-ai/themes/themes/adea-light'
|
|
19
|
+
import {
|
|
20
|
+
themeAccentPresets,
|
|
21
|
+
type AccentPreset,
|
|
22
|
+
type AdeaTheme,
|
|
23
|
+
type AdeaThemeRecord,
|
|
24
|
+
} from '@adea-ai/themes'
|
|
25
|
+
|
|
26
|
+
export { editorRolesHex, syntaxRolesHex } from '@adea-ai/themes'
|
|
27
|
+
export { oklchToHex, parseColor as parseOklchColor } from '@adea-ai/themes/oklch'
|
|
28
|
+
export { shadcnDestructiveProjection, shadcnVariables } from '@adea-ai/themes/adapters/shadcn'
|
|
29
|
+
export { toXtermTheme } from '@adea-ai/themes/adapters/xterm'
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The default theme of an appearance as a canonical record: the roles an imported
|
|
33
|
+
* theme falls back to for anything its file does not carry.
|
|
34
|
+
*
|
|
35
|
+
* `defaultVariantFor` is the same theme as a runtime variant; a record keeps the
|
|
36
|
+
* catalogue's own roles (`surfaceActive`, `textSubtle`, the ANSI ramp) that a variant
|
|
37
|
+
* folds together.
|
|
38
|
+
*/
|
|
39
|
+
export function defaultThemeRecord(appearance: 'light' | 'dark'): AdeaThemeRecord {
|
|
40
|
+
return appearance === 'dark' ? adeaDark : adeaLight
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The accents a light/dark pair of records carries itself, beside the presets.
|
|
45
|
+
*
|
|
46
|
+
* For a host whose pair is not in the catalogue — an imported theme — where
|
|
47
|
+
* `themeAccentsFor` (which looks the pair up by id) cannot answer. A slot is offered
|
|
48
|
+
* only when both themes clear the catalogue's accent floors.
|
|
49
|
+
*/
|
|
50
|
+
export function themeAccentsForRecords(light: AdeaTheme, dark: AdeaTheme): readonly AccentPreset[] {
|
|
51
|
+
return themeAccentPresets(light, dark)
|
|
52
|
+
}
|
package/src/lib/theme-records.ts
CHANGED
|
@@ -30,6 +30,9 @@ import type {
|
|
|
30
30
|
ThemeVariant,
|
|
31
31
|
} from './themes'
|
|
32
32
|
|
|
33
|
+
/** The catalogue's canonical theme shapes, for a host that holds records and no catalogue. */
|
|
34
|
+
export type { AdeaTheme, AdeaThemeRecord } from '@adea-ai/themes'
|
|
35
|
+
|
|
33
36
|
/**
|
|
34
37
|
* The shadcn-vocabulary roles of one catalogue entry.
|
|
35
38
|
*
|