Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"test:vitest": "vitest run"
},
"dependencies": {
"@adea-ai/themes": "^0.9.5",
"@adea-ai/themes": "^0.10.4",
"@adea-ai/ui": "workspace:*",
"lucide-solid": "^1.48.0",
"solid-js": "^1.9.15"
Expand Down
8 changes: 4 additions & 4 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions docs/consumption.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,15 +200,15 @@ they were typed:
| `@adea-ai/ui` → `Board` | 22.3 kB | nothing |
| `@adea-ai/ui/components/composites/list-row` → `ListRowControl` | 21.7 kB | nothing — the row without its tooltip |
| `@adea-ai/ui` → `DiffBlock` | 22.9 kB | lucide icons |
| `@adea-ai/ui` → `CodeBlock` | 25.6 kB | lucide icons |
| `@adea-ai/ui` → `MessageRow` | 26.7 kB | nothing |
| `@adea-ai/ui` → `CodeBlock` | 25.9 kB | lucide icons |
| `@adea-ai/ui` → `MessageRow` | 26.8 kB | nothing |
| `@adea-ai/ui` → `CalendarSurface` | 29.6 kB | corvu calendar |
| `@adea-ai/ui` → `ModalDialog` | 49.6 kB | Kobalte dialog, the shared tooltip |
| `@adea-ai/ui` → `ModalDialog` | 50.3 kB | Kobalte dialog, the shared tooltip |
| `@adea-ai/ui/components/ui/carousel` → `Carousel` | 34.2 kB | embla |
| `@adea-ai/ui/components/composites/list-row` → `ListRow` | 41.2 kB | Kobalte tooltip |
| `@adea-ai/ui` → `NavigationMenu` | 56.5 kB | Kobalte navigation menu |
| `@adea-ai/ui/components/composites/list-row` → `ListRow` | 41.8 kB | Kobalte tooltip |
| `@adea-ai/ui` → `NavigationMenu` | 56.6 kB | Kobalte navigation menu |
| `@adea-ai/ui/components/ui/chart` → `LineChart` | 89.2 kB | chart.js, the line controller only |
| _root plus chart and carousel entries_ | _360.7 kB_ | — and `Button` is 6.1% of it |
| _root plus chart and carousel entries_ | _366.5 kB_ | — and `Button` is 6.0% of it |

The chart splits from itself, which is why chart.js was chosen: `LineChart` is
10.5 kB smaller than importing all seven chart types together (89.2 kB against 99.7 kB), because the
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
"check:packed-paste-model": "node scripts/check-packed-paste-model.mjs"
},
"dependencies": {
"@adea-ai/themes": "^0.9.10",
"@adea-ai/themes": "^0.10.4",
"@corvu/calendar": "^0.1.2",
"@corvu/drawer": "^0.2.4",
"@corvu/otp-field": "^0.1.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/public/r/appearance-editor.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"title": "Appearance Editor",
"description": "",
"dependencies": [
"@adea-ai/themes@^0.9.10",
"@adea-ai/themes@^0.10.4",
"@kobalte/core@^0.13.14",
"lucide-solid@^1.51.0"
],
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/public/r/lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"title": "Class-name and token helpers",
"description": "The private helpers the components import: the class-name merge, the variant recipes, the token manifest and the theme bridge. Installed automatically as a peer of any component that needs it.",
"dependencies": [
"@adea-ai/themes@^0.9.10",
"@adea-ai/themes@^0.10.4",
"class-variance-authority@^0.7.1",
"cn@^0.4.0"
],
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/public/r/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -1998,7 +1998,7 @@
"title": "Appearance Editor",
"description": "",
"dependencies": [
"@adea-ai/themes@^0.9.10",
"@adea-ai/themes@^0.10.4",
"@kobalte/core@^0.13.14",
"lucide-solid@^1.51.0"
],
Expand Down Expand Up @@ -2477,7 +2477,7 @@
"title": "Theming",
"description": "",
"dependencies": [
"@adea-ai/themes@^0.9.10",
"@adea-ai/themes@^0.10.4",
"@kobalte/core@^0.13.14",
"lucide-solid@^1.51.0"
],
Expand Down Expand Up @@ -2592,7 +2592,7 @@
"title": "Class-name and token helpers",
"description": "The private helpers the components import: the class-name merge, the variant recipes, the token manifest and the theme bridge. Installed automatically as a peer of any component that needs it.",
"dependencies": [
"@adea-ai/themes@^0.9.10",
"@adea-ai/themes@^0.10.4",
"class-variance-authority@^0.7.1",
"cn@^0.4.0"
],
Expand Down
129 changes: 56 additions & 73 deletions packages/ui/public/r/src/lib/themes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
*
* ## The mapping, and the entry that is not a rename
*
* {@link ROLE_FOR} maps canonical roles onto this system's variable vocabulary. One
* entry will trip a reader: the catalogue's `accent` becomes this system's
* `primary`, because in the shadcn vocabulary `--primary` is the action colour — the
* fill of a primary button, the thing a focus ring is drawn in — while `--accent` is
* a low-contrast hover wash. The catalogue's `accent` is the former, so it goes to
* `--primary`, and `--accent` is filled from `surfaceHover`, which is what shadcn
* components actually use it for.
* The package-owned `shadcnVariables` adapter maps canonical roles onto this
* system's vocabulary. One entry will trip a reader: the catalogue's `accent`
* becomes this system's `primary`, because in the shadcn vocabulary `--primary` is
* the action colour — the fill of a primary button, the thing a focus ring is drawn
* in — while `--accent` is a low-contrast hover wash. The catalogue's `accent` is
* the former, so it goes to `--primary`, and `--accent` is filled from
* `surfaceHover`, which is what shadcn components actually use it for.
*/

import {
Expand All @@ -56,6 +56,7 @@ import {
type AdeaThemeRecord,
type ContrastFinding,
} from '@adea-ai/themes'
import { shadcnVariables } from '@adea-ai/themes/adapters/shadcn'
import { isThemeAccentId } from './theme-accents'

export { isThemeAccentId } from './theme-accents'
Expand Down Expand Up @@ -106,6 +107,7 @@ export type ThemeColors = {
sidebarForeground: string
sidebarAccent: string
sidebarBorder: string
sidebarMutedForeground: string
}

/** The sixteen ANSI colours a terminal needs, plus its cursor and selection. */
Expand Down Expand Up @@ -179,75 +181,56 @@ export type ThemeVariant = {
provenance: ThemeProvenance
}

/**
* Canonical role → this system's `ThemeColors` key.
*
* Read by {@link toVariant}. The two derived destructive-action presentation values
* are intentionally excluded; the shared Themes adapter owns their color math.
*/
type ThemeRole = Exclude<keyof ThemeColors, 'destructiveAction' | 'destructiveActionForeground'>

const ROLE_FOR: Readonly<Record<ThemeRole, keyof AdeaThemeRecord['colors']>> = {
background: 'background',
foreground: 'text',
card: 'surface',
cardForeground: 'text',
popover: 'surfaceElevated',
popoverForeground: 'text',
// Not a rename — see this module's header.
primary: 'accent',
primaryForeground: 'accentForeground',
// shadcn's `secondary` and `muted` are both the first surface rung used as a fill.
secondary: 'surface',
secondaryForeground: 'text',
muted: 'surface',
mutedForeground: 'textMuted',
// shadcn's `accent` is a hover wash, which is exactly `surfaceHover`.
accent: 'surfaceHover',
accentForeground: 'text',
destructive: 'error',
// Overwritten below from the measured pairing; nominal here so the table is total.
destructiveForeground: 'error',
destructiveSubtle: 'error',
success: 'success',
successForeground: 'success',
successSubtle: 'success',
warning: 'warning',
warningForeground: 'warning',
warningSubtle: 'warning',
info: 'info',
infoForeground: 'info',
infoSubtle: 'info',
border: 'border',
input: 'border',
ring: 'accent',
sidebar: 'surface',
sidebarForeground: 'text',
sidebarAccent: 'surfaceHover',
sidebarBorder: 'border',
}

/** Builds the design system's view of one catalogue entry. */
function toVariant(theme: AdeaThemeRecord): ThemeVariant {
const colors = {} as ThemeColors
for (const key of Object.keys(ROLE_FOR) as ThemeRole[]) {
colors[key] = theme.colors[ROLE_FOR[key]]
const projected = shadcnVariables(theme)
const token = (name: string): string => {
const value = projected[`--${name}`]
if (!value) throw new Error(`${theme.id} has no shared shadcn projection for --${name}`)
return value
}
// Keep the semantic foreground paired with the canonical error role. Filled
// destructive actions use the distinct projection below so their /90 hover state
// remains readable without changing icons, borders, or tinted status surfaces.
colors.destructiveForeground = statusForeground(theme, 'error')
colors.destructiveSubtle = tint(theme.colors.error, theme.colors.background)
const destructiveAction = shadcnDestructiveProjection(theme)
colors.destructiveAction = destructiveAction.fill
colors.destructiveActionForeground = destructiveAction.foreground
colors.successForeground = statusForeground(theme, 'success')
colors.successSubtle = tint(theme.colors.success, theme.colors.background)
colors.warningForeground = statusForeground(theme, 'warning')
colors.warningSubtle = tint(theme.colors.warning, theme.colors.background)
colors.infoForeground = statusForeground(theme, 'info')
colors.infoSubtle = tint(theme.colors.info, theme.colors.background)

const colors: ThemeColors = {
background: token('background'),
foreground: token('foreground'),
card: token('card'),
cardForeground: token('card-foreground'),
popover: token('popover'),
popoverForeground: token('popover-foreground'),
primary: token('primary'),
primaryForeground: token('primary-foreground'),
secondary: token('secondary'),
secondaryForeground: token('secondary-foreground'),
muted: token('muted'),
mutedForeground: token('muted-foreground'),
accent: token('accent'),
accentForeground: token('accent-foreground'),
// Preserve the UI's semantic error token. The Themes projection uses its
// contrast-safe solid-action fill for --destructive; UI keeps that fill in
// the separate destructiveAction pair below.
destructive: theme.colors.error,
destructiveForeground: statusForeground(theme, 'error'),
destructiveSubtle: tint(theme.colors.error, theme.colors.background),
destructiveAction: destructiveAction.fill,
destructiveActionForeground: destructiveAction.foreground,
success: token('success'),
successForeground: statusForeground(theme, 'success'),
successSubtle: tint(theme.colors.success, theme.colors.background),
warning: token('warning'),
warningForeground: statusForeground(theme, 'warning'),
warningSubtle: tint(theme.colors.warning, theme.colors.background),
info: token('info'),
infoForeground: statusForeground(theme, 'info'),
infoSubtle: tint(theme.colors.info, theme.colors.background),
border: token('border'),
input: token('input'),
ring: token('ring'),
sidebar: token('sidebar'),
sidebarForeground: token('sidebar-foreground'),
sidebarAccent: token('sidebar-accent'),
sidebarBorder: token('sidebar-border'),
sidebarMutedForeground: token('sidebar-muted-foreground'),
}
const syntax = syntaxRoles(theme)

return {
Expand Down Expand Up @@ -556,7 +539,7 @@ export function themeCssVariables(theme: ThemeVariant): Record<string, string> {
'--sidebar-primary': c.primary,
'--sidebar-primary-foreground': c.primaryForeground,
'--sidebar-ring': c.ring,
'--sidebar-muted-foreground': c.mutedForeground,
'--sidebar-muted-foreground': c.sidebarMutedForeground,
'--surface-sunken': c.muted,
'--surface-hover': c.accent,
'--surface-active': c.border,
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/public/r/theming.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"title": "Theming",
"description": "",
"dependencies": [
"@adea-ai/themes@^0.9.10",
"@adea-ai/themes@^0.10.4",
"@kobalte/core@^0.13.14",
"lucide-solid@^1.51.0"
],
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -1998,7 +1998,7 @@
"title": "Appearance Editor",
"description": "",
"dependencies": [
"@adea-ai/themes@^0.9.10",
"@adea-ai/themes@^0.10.4",
"@kobalte/core@^0.13.14",
"lucide-solid@^1.51.0"
],
Expand Down Expand Up @@ -2477,7 +2477,7 @@
"title": "Theming",
"description": "",
"dependencies": [
"@adea-ai/themes@^0.9.10",
"@adea-ai/themes@^0.10.4",
"@kobalte/core@^0.13.14",
"lucide-solid@^1.51.0"
],
Expand Down Expand Up @@ -2592,7 +2592,7 @@
"title": "Class-name and token helpers",
"description": "The private helpers the components import: the class-name merge, the variant recipes, the token manifest and the theme bridge. Installed automatically as a peer of any component that needs it.",
"dependencies": [
"@adea-ai/themes@^0.9.10",
"@adea-ai/themes@^0.10.4",
"class-variance-authority@^0.7.1",
"cn@^0.4.0"
],
Expand Down
Loading
Loading