@adea-ai/ui 0.102.0 → 0.103.1
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 +27 -11
- package/dist/components/composites/appearance-editor/appearance-choices.d.ts +7 -0
- package/dist/components/composites/appearance-editor/appearance-choices.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-choices.js +44 -3
- 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 +7 -3
- package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-types.d.ts +8 -0
- package/dist/components/composites/appearance-editor/appearance-types.d.ts.map +1 -1
- package/dist/components/composites/update-dialog/update-dialog.d.ts +15 -2
- package/dist/components/composites/update-dialog/update-dialog.d.ts.map +1 -1
- package/dist/components/composites/update-dialog/update-dialog.js +80 -16
- package/dist/components/composites/update-dialog/update-dialog.js.map +1 -1
- package/dist/components/theme/appearance-panel.d.ts +2 -1
- package/dist/components/theme/appearance-panel.d.ts.map +1 -1
- package/dist/components/theme/appearance-panel.js +62 -22
- package/dist/components/theme/appearance-panel.js.map +1 -1
- package/dist/components/theme/theme-provider.d.ts +13 -2
- package/dist/components/theme/theme-provider.d.ts.map +1 -1
- package/dist/components/theme/theme-provider.js +9 -5
- package/dist/components/theme/theme-provider.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/lib/theme-accents.d.ts +9 -0
- package/dist/lib/theme-accents.d.ts.map +1 -0
- package/dist/lib/theme-accents.js +41 -0
- package/dist/lib/theme-accents.js.map +1 -0
- package/dist/lib/themes.d.ts +69 -5
- package/dist/lib/themes.d.ts.map +1 -1
- package/dist/lib/themes.js +100 -7
- package/dist/lib/themes.js.map +1 -1
- package/dist/r/appearance-editor.json +1 -1
- package/dist/r/lib.json +6 -1
- package/dist/r/registry.json +8 -2
- package/dist/r/src/components/composites/appearance-editor/appearance-choices.tsx +41 -4
- package/dist/r/src/components/composites/appearance-editor/appearance-editor.tsx +12 -6
- package/dist/r/src/components/composites/appearance-editor/appearance-types.ts +8 -0
- package/dist/r/src/components/composites/update-dialog/update-dialog.tsx +90 -10
- package/dist/r/src/components/theme/appearance-panel.tsx +60 -29
- package/dist/r/src/components/theme/theme-provider.tsx +35 -7
- package/dist/r/src/lib/theme-accents.ts +44 -0
- package/dist/r/src/lib/themes.ts +116 -5
- package/dist/r/theming.json +1 -0
- package/package.json +2 -2
- package/registry.json +8 -2
- package/src/components/composites/appearance-editor/appearance-choices.tsx +41 -4
- package/src/components/composites/appearance-editor/appearance-editor.tsx +12 -6
- package/src/components/composites/appearance-editor/appearance-types.ts +8 -0
- package/src/components/composites/update-dialog/update-dialog.tsx +90 -10
- package/src/components/theme/appearance-panel.tsx +60 -29
- package/src/components/theme/theme-provider.tsx +35 -7
- package/src/index.ts +7 -0
- package/src/lib/theme-accents.ts +44 -0
- package/src/lib/themes.ts +116 -5
package/src/lib/themes.ts
CHANGED
|
@@ -35,9 +35,11 @@
|
|
|
35
35
|
|
|
36
36
|
import {
|
|
37
37
|
ACCENTS,
|
|
38
|
+
accentForeground,
|
|
38
39
|
accentRoles,
|
|
39
40
|
chartSeries,
|
|
40
41
|
getAccent,
|
|
42
|
+
getTheme,
|
|
41
43
|
hasTheme,
|
|
42
44
|
shadcnDestructiveProjection,
|
|
43
45
|
statusForeground,
|
|
@@ -47,10 +49,16 @@ import {
|
|
|
47
49
|
syntaxRoles,
|
|
48
50
|
themes as catalogue,
|
|
49
51
|
themesByAppearance,
|
|
52
|
+
themeAccentPresets,
|
|
50
53
|
validateCatalogue,
|
|
54
|
+
type AccentPreset,
|
|
55
|
+
type AdeaTheme,
|
|
51
56
|
type AdeaThemeRecord,
|
|
52
57
|
type ContrastFinding,
|
|
53
58
|
} from '@adea-ai/themes'
|
|
59
|
+
import { isThemeAccentId } from './theme-accents'
|
|
60
|
+
|
|
61
|
+
export { isThemeAccentId } from './theme-accents'
|
|
54
62
|
|
|
55
63
|
export type ThemeAppearance = 'light' | 'dark'
|
|
56
64
|
|
|
@@ -320,6 +328,100 @@ export function themeFamilies(): { family: string; label: string; themes: ThemeV
|
|
|
320
328
|
/** The accent presets, in the order a picker should show them. */
|
|
321
329
|
export const accents = ACCENTS
|
|
322
330
|
|
|
331
|
+
/**
|
|
332
|
+
* The canonical catalogue records, in catalogue order.
|
|
333
|
+
*
|
|
334
|
+
* {@link builtinThemes} is this system's projection of the catalogue onto the
|
|
335
|
+
* shadcn vocabulary, which is what a document is painted with. A *preview* of a
|
|
336
|
+
* theme — the miniatures `AppearanceEditor` and `ThemeMiniature` draw — reads the
|
|
337
|
+
* catalogue's own roles instead (`surfaceActive`, `borderMuted`, `textSubtle`…),
|
|
338
|
+
* several of which the projection folds together. These are those records, so a
|
|
339
|
+
* consumer hands the editor exactly what it takes rather than reconstructing it
|
|
340
|
+
* from the projection.
|
|
341
|
+
*/
|
|
342
|
+
export const themeRecords: readonly AdeaThemeRecord[] = catalogue
|
|
343
|
+
|
|
344
|
+
export function themeRecordById(id: string): AdeaThemeRecord | undefined {
|
|
345
|
+
return getTheme(id)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** A light/dark theme pair by id, with the defaults standing in for an unknown id. */
|
|
349
|
+
function recordPair(lightThemeId: string, darkThemeId: string) {
|
|
350
|
+
const light = getTheme(lightThemeId) ?? getTheme(defaultLightThemeId)!
|
|
351
|
+
const dark = getTheme(darkThemeId) ?? getTheme(defaultDarkThemeId)!
|
|
352
|
+
return { light, dark }
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* The accents the selected light/dark pair carries — offered beside the presets.
|
|
357
|
+
*
|
|
358
|
+
* Computed per pair rather than per theme because a theme accent is a *pair* of
|
|
359
|
+
* values, like a preset: a slot is offered only when both themes can offer it.
|
|
360
|
+
*/
|
|
361
|
+
export function themeAccentsFor(
|
|
362
|
+
lightThemeId: string,
|
|
363
|
+
darkThemeId: string
|
|
364
|
+
): readonly AccentPreset[] {
|
|
365
|
+
const { light, dark } = recordPair(lightThemeId, darkThemeId)
|
|
366
|
+
return themeAccentPresets(light, dark)
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* An accent id resolved against a theme pair: a preset, a theme accent the pair
|
|
371
|
+
* offers, or `undefined` for `theme`, an unknown id, or a slot this pair cannot
|
|
372
|
+
* offer — each of which means "use the theme's own primary".
|
|
373
|
+
*
|
|
374
|
+
* Theme accent ids are role-shaped (`ansi-blue`), so a stored one survives a theme
|
|
375
|
+
* switch and resolves to the new theme's blue; when the new pair cannot offer the
|
|
376
|
+
* slot it resolves to nothing, the same fallback a stale preset id gets.
|
|
377
|
+
*/
|
|
378
|
+
export function resolveAccentPreset(
|
|
379
|
+
accentId: string,
|
|
380
|
+
light: AdeaTheme,
|
|
381
|
+
dark: AdeaTheme
|
|
382
|
+
): AccentPreset | undefined {
|
|
383
|
+
if (accentId === 'theme') return undefined
|
|
384
|
+
const preset = getAccent(accentId)
|
|
385
|
+
if (preset) return preset
|
|
386
|
+
if (!isThemeAccentId(accentId)) return undefined
|
|
387
|
+
return themeAccentPresets(light, dark).find((option) => option.id === accentId)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* A theme with an accent laid over it, in the catalogue's own shape.
|
|
392
|
+
*
|
|
393
|
+
* The accent replaces `accent` and its measured label, which is all an accent
|
|
394
|
+
* changes about a theme; `undefined` returns the theme untouched. This is the
|
|
395
|
+
* overlay a host needs for `AppearanceEditor`'s `lightTheme`/`darkTheme`.
|
|
396
|
+
*/
|
|
397
|
+
export function withAccent<T extends AdeaTheme>(theme: T, accent: AccentPreset | undefined): T {
|
|
398
|
+
if (!accent) return theme
|
|
399
|
+
const value = theme.appearance === 'dark' ? accent.dark : accent.light
|
|
400
|
+
return {
|
|
401
|
+
...theme,
|
|
402
|
+
colors: { ...theme.colors, accent: value, accentForeground: accentForeground(value) },
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* The two preview themes an appearance selection resolves to, accent applied.
|
|
408
|
+
*
|
|
409
|
+
* The adapter between a stored selection and `AppearanceEditor`: it takes ids —
|
|
410
|
+
* what a preference holds — and returns the canonical records the editor's
|
|
411
|
+
* `lightTheme` and `darkTheme` props take, so a host does not map roles by hand.
|
|
412
|
+
* Unknown ids fall back to the defaults and an accent the pair cannot offer falls
|
|
413
|
+
* back to the theme's own, exactly as `ThemeProvider` resolves them.
|
|
414
|
+
*/
|
|
415
|
+
export function appearancePreviewThemes(selection: {
|
|
416
|
+
lightThemeId: string
|
|
417
|
+
darkThemeId: string
|
|
418
|
+
accent: string
|
|
419
|
+
}): { lightTheme: AdeaThemeRecord; darkTheme: AdeaThemeRecord } {
|
|
420
|
+
const { light, dark } = recordPair(selection.lightThemeId, selection.darkThemeId)
|
|
421
|
+
const accent = resolveAccentPreset(selection.accent, light, dark)
|
|
422
|
+
return { lightTheme: withAccent(light, accent), darkTheme: withAccent(dark, accent) }
|
|
423
|
+
}
|
|
424
|
+
|
|
323
425
|
/**
|
|
324
426
|
* The properties an accent selection overrides, as CSS custom properties.
|
|
325
427
|
*
|
|
@@ -339,16 +441,25 @@ export const accents = ACCENTS
|
|
|
339
441
|
* provider and the CSS generator call `accentRoles` out of `@adea-ai/themes`, and
|
|
340
442
|
* `tests/appearance-axes.test.ts` asserts the two agree value for value.
|
|
341
443
|
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
444
|
+
* A theme accent (`ansi-blue`) has no block: its value depends on the theme pair,
|
|
445
|
+
* so it is resolved against `pair` — the selection's light and dark theme ids —
|
|
446
|
+
* and only ever applied here. Without a pair it resolves against the defaults.
|
|
447
|
+
*
|
|
448
|
+
* Returns `undefined` for `theme` — the variant's own primary — for an id the
|
|
449
|
+
* catalogue does not have, and for a theme accent the pair does not offer, so a
|
|
450
|
+
* stale stored preference falls back to the theme rather than blanking the primary.
|
|
345
451
|
*/
|
|
346
452
|
export function accentVariables(
|
|
347
453
|
accentId: string,
|
|
348
|
-
appearance: ThemeAppearance
|
|
454
|
+
appearance: ThemeAppearance,
|
|
455
|
+
pair: { lightThemeId: string; darkThemeId: string } = {
|
|
456
|
+
lightThemeId: defaultLightThemeId,
|
|
457
|
+
darkThemeId: defaultDarkThemeId,
|
|
458
|
+
}
|
|
349
459
|
): Record<string, string> | undefined {
|
|
350
460
|
if (accentId === 'theme') return undefined
|
|
351
|
-
const
|
|
461
|
+
const { light, dark } = recordPair(pair.lightThemeId, pair.darkThemeId)
|
|
462
|
+
const preset = resolveAccentPreset(accentId, light, dark)
|
|
352
463
|
if (!preset) return undefined
|
|
353
464
|
|
|
354
465
|
const roles = accentRoles(preset, appearance)
|