@adea-ai/ui 0.122.3 → 0.123.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.
Files changed (45) hide show
  1. package/dist/components/layout/split-layout/resize-controller-core-retry.d.ts +13 -0
  2. package/dist/components/layout/split-layout/resize-controller-core-retry.d.ts.map +1 -0
  3. package/dist/components/layout/split-layout/resize-controller-core-retry.js +63 -0
  4. package/dist/components/layout/split-layout/resize-controller-core-retry.js.map +1 -0
  5. package/dist/components/layout/split-layout/resize-controller-core.d.ts +13 -0
  6. package/dist/components/layout/split-layout/resize-controller-core.d.ts.map +1 -0
  7. package/dist/components/layout/split-layout/resize-controller-core.js +63 -0
  8. package/dist/components/layout/split-layout/resize-controller-core.js.map +1 -0
  9. package/dist/components/layout/split-layout/resize-controller-retry-2.d.ts +3 -0
  10. package/dist/components/layout/split-layout/resize-controller-retry-2.d.ts.map +1 -0
  11. package/dist/components/layout/split-layout/resize-controller-retry-2.js +2 -0
  12. package/dist/components/layout/split-layout/resize-controller-retry.d.ts +2 -0
  13. package/dist/components/layout/split-layout/resize-controller-retry.d.ts.map +1 -0
  14. package/dist/components/layout/split-layout/resize-controller-retry.js +2 -0
  15. package/dist/components/layout/split-layout/resize-controller.d.ts +2 -0
  16. package/dist/components/layout/split-layout/resize-controller.d.ts.map +1 -0
  17. package/dist/components/layout/split-layout/resize-controller.js +2 -0
  18. package/dist/components/layout/split-layout/split-layout.d.ts.map +1 -1
  19. package/dist/components/layout/split-layout/split-layout.js +171 -60
  20. package/dist/components/layout/split-layout/split-layout.js.map +1 -1
  21. package/dist/lib/themes.d.ts +8 -7
  22. package/dist/lib/themes.d.ts.map +1 -1
  23. package/dist/lib/themes.js +53 -55
  24. package/dist/lib/themes.js.map +1 -1
  25. package/dist/r/appearance-editor.json +1 -1
  26. package/dist/r/lib.json +1 -1
  27. package/dist/r/registry.json +29 -3
  28. package/dist/r/split-layout.json +26 -0
  29. package/dist/r/src/components/layout/split-layout/resize-controller-core-retry.tsx +66 -0
  30. package/dist/r/src/components/layout/split-layout/resize-controller-core.tsx +66 -0
  31. package/dist/r/src/components/layout/split-layout/resize-controller-retry-2.tsx +2 -0
  32. package/dist/r/src/components/layout/split-layout/resize-controller-retry.tsx +1 -0
  33. package/dist/r/src/components/layout/split-layout/resize-controller.tsx +1 -0
  34. package/dist/r/src/components/layout/split-layout/split-layout.tsx +197 -49
  35. package/dist/r/src/lib/themes.ts +56 -73
  36. package/dist/r/theming.json +1 -1
  37. package/package.json +2 -2
  38. package/registry.json +29 -3
  39. package/src/components/layout/split-layout/resize-controller-core-retry.tsx +66 -0
  40. package/src/components/layout/split-layout/resize-controller-core.tsx +66 -0
  41. package/src/components/layout/split-layout/resize-controller-retry-2.tsx +2 -0
  42. package/src/components/layout/split-layout/resize-controller-retry.tsx +1 -0
  43. package/src/components/layout/split-layout/resize-controller.tsx +1 -0
  44. package/src/components/layout/split-layout/split-layout.tsx +197 -49
  45. package/src/lib/themes.ts +56 -73
@@ -24,13 +24,13 @@
24
24
  *
25
25
  * ## The mapping, and the entry that is not a rename
26
26
  *
27
- * {@link ROLE_FOR} maps canonical roles onto this system's variable vocabulary. One
28
- * entry will trip a reader: the catalogue's `accent` becomes this system's
29
- * `primary`, because in the shadcn vocabulary `--primary` is the action colour — the
30
- * fill of a primary button, the thing a focus ring is drawn in — while `--accent` is
31
- * a low-contrast hover wash. The catalogue's `accent` is the former, so it goes to
32
- * `--primary`, and `--accent` is filled from `surfaceHover`, which is what shadcn
33
- * components actually use it for.
27
+ * The package-owned `shadcnVariables` adapter maps canonical roles onto this
28
+ * system's vocabulary. One entry will trip a reader: the catalogue's `accent`
29
+ * becomes this system's `primary`, because in the shadcn vocabulary `--primary` is
30
+ * the action colour — the fill of a primary button, the thing a focus ring is drawn
31
+ * in — while `--accent` is a low-contrast hover wash. The catalogue's `accent` is
32
+ * the former, so it goes to `--primary`, and `--accent` is filled from
33
+ * `surfaceHover`, which is what shadcn components actually use it for.
34
34
  */
35
35
 
36
36
  import {
@@ -56,6 +56,7 @@ import {
56
56
  type AdeaThemeRecord,
57
57
  type ContrastFinding,
58
58
  } from '@adea-ai/themes'
59
+ import { shadcnVariables } from '@adea-ai/themes/adapters/shadcn'
59
60
  import { isThemeAccentId } from './theme-accents'
60
61
 
61
62
  export { isThemeAccentId } from './theme-accents'
@@ -106,6 +107,7 @@ export type ThemeColors = {
106
107
  sidebarForeground: string
107
108
  sidebarAccent: string
108
109
  sidebarBorder: string
110
+ sidebarMutedForeground: string
109
111
  }
110
112
 
111
113
  /** The sixteen ANSI colours a terminal needs, plus its cursor and selection. */
@@ -179,75 +181,56 @@ export type ThemeVariant = {
179
181
  provenance: ThemeProvenance
180
182
  }
181
183
 
182
- /**
183
- * Canonical role → this system's `ThemeColors` key.
184
- *
185
- * Read by {@link toVariant}. The two derived destructive-action presentation values
186
- * are intentionally excluded; the shared Themes adapter owns their color math.
187
- */
188
- type ThemeRole = Exclude<keyof ThemeColors, 'destructiveAction' | 'destructiveActionForeground'>
189
-
190
- const ROLE_FOR: Readonly<Record<ThemeRole, keyof AdeaThemeRecord['colors']>> = {
191
- background: 'background',
192
- foreground: 'text',
193
- card: 'surface',
194
- cardForeground: 'text',
195
- popover: 'surfaceElevated',
196
- popoverForeground: 'text',
197
- // Not a rename — see this module's header.
198
- primary: 'accent',
199
- primaryForeground: 'accentForeground',
200
- // shadcn's `secondary` and `muted` are both the first surface rung used as a fill.
201
- secondary: 'surface',
202
- secondaryForeground: 'text',
203
- muted: 'surface',
204
- mutedForeground: 'textMuted',
205
- // shadcn's `accent` is a hover wash, which is exactly `surfaceHover`.
206
- accent: 'surfaceHover',
207
- accentForeground: 'text',
208
- destructive: 'error',
209
- // Overwritten below from the measured pairing; nominal here so the table is total.
210
- destructiveForeground: 'error',
211
- destructiveSubtle: 'error',
212
- success: 'success',
213
- successForeground: 'success',
214
- successSubtle: 'success',
215
- warning: 'warning',
216
- warningForeground: 'warning',
217
- warningSubtle: 'warning',
218
- info: 'info',
219
- infoForeground: 'info',
220
- infoSubtle: 'info',
221
- border: 'border',
222
- input: 'border',
223
- ring: 'accent',
224
- sidebar: 'surface',
225
- sidebarForeground: 'text',
226
- sidebarAccent: 'surfaceHover',
227
- sidebarBorder: 'border',
228
- }
229
-
230
184
  /** Builds the design system's view of one catalogue entry. */
231
185
  function toVariant(theme: AdeaThemeRecord): ThemeVariant {
232
- const colors = {} as ThemeColors
233
- for (const key of Object.keys(ROLE_FOR) as ThemeRole[]) {
234
- colors[key] = theme.colors[ROLE_FOR[key]]
186
+ const projected = shadcnVariables(theme)
187
+ const token = (name: string): string => {
188
+ const value = projected[`--${name}`]
189
+ if (!value) throw new Error(`${theme.id} has no shared shadcn projection for --${name}`)
190
+ return value
235
191
  }
236
- // Keep the semantic foreground paired with the canonical error role. Filled
237
- // destructive actions use the distinct projection below so their /90 hover state
238
- // remains readable without changing icons, borders, or tinted status surfaces.
239
- colors.destructiveForeground = statusForeground(theme, 'error')
240
- colors.destructiveSubtle = tint(theme.colors.error, theme.colors.background)
241
192
  const destructiveAction = shadcnDestructiveProjection(theme)
242
- colors.destructiveAction = destructiveAction.fill
243
- colors.destructiveActionForeground = destructiveAction.foreground
244
- colors.successForeground = statusForeground(theme, 'success')
245
- colors.successSubtle = tint(theme.colors.success, theme.colors.background)
246
- colors.warningForeground = statusForeground(theme, 'warning')
247
- colors.warningSubtle = tint(theme.colors.warning, theme.colors.background)
248
- colors.infoForeground = statusForeground(theme, 'info')
249
- colors.infoSubtle = tint(theme.colors.info, theme.colors.background)
250
-
193
+ const colors: ThemeColors = {
194
+ background: token('background'),
195
+ foreground: token('foreground'),
196
+ card: token('card'),
197
+ cardForeground: token('card-foreground'),
198
+ popover: token('popover'),
199
+ popoverForeground: token('popover-foreground'),
200
+ primary: token('primary'),
201
+ primaryForeground: token('primary-foreground'),
202
+ secondary: token('secondary'),
203
+ secondaryForeground: token('secondary-foreground'),
204
+ muted: token('muted'),
205
+ mutedForeground: token('muted-foreground'),
206
+ accent: token('accent'),
207
+ accentForeground: token('accent-foreground'),
208
+ // Preserve the UI's semantic error token. The Themes projection uses its
209
+ // contrast-safe solid-action fill for --destructive; UI keeps that fill in
210
+ // the separate destructiveAction pair below.
211
+ destructive: theme.colors.error,
212
+ destructiveForeground: statusForeground(theme, 'error'),
213
+ destructiveSubtle: tint(theme.colors.error, theme.colors.background),
214
+ destructiveAction: destructiveAction.fill,
215
+ destructiveActionForeground: destructiveAction.foreground,
216
+ success: token('success'),
217
+ successForeground: statusForeground(theme, 'success'),
218
+ successSubtle: tint(theme.colors.success, theme.colors.background),
219
+ warning: token('warning'),
220
+ warningForeground: statusForeground(theme, 'warning'),
221
+ warningSubtle: tint(theme.colors.warning, theme.colors.background),
222
+ info: token('info'),
223
+ infoForeground: statusForeground(theme, 'info'),
224
+ infoSubtle: tint(theme.colors.info, theme.colors.background),
225
+ border: token('border'),
226
+ input: token('input'),
227
+ ring: token('ring'),
228
+ sidebar: token('sidebar'),
229
+ sidebarForeground: token('sidebar-foreground'),
230
+ sidebarAccent: token('sidebar-accent'),
231
+ sidebarBorder: token('sidebar-border'),
232
+ sidebarMutedForeground: token('sidebar-muted-foreground'),
233
+ }
251
234
  const syntax = syntaxRoles(theme)
252
235
 
253
236
  return {
@@ -556,7 +539,7 @@ export function themeCssVariables(theme: ThemeVariant): Record<string, string> {
556
539
  '--sidebar-primary': c.primary,
557
540
  '--sidebar-primary-foreground': c.primaryForeground,
558
541
  '--sidebar-ring': c.ring,
559
- '--sidebar-muted-foreground': c.mutedForeground,
542
+ '--sidebar-muted-foreground': c.sidebarMutedForeground,
560
543
  '--surface-sunken': c.muted,
561
544
  '--surface-hover': c.accent,
562
545
  '--surface-active': c.border,
@@ -4,7 +4,7 @@
4
4
  "title": "Theming",
5
5
  "description": "",
6
6
  "dependencies": [
7
- "@adea-ai/themes@^0.9.10",
7
+ "@adea-ai/themes@^0.10.4",
8
8
  "@kobalte/core@^0.13.14",
9
9
  "lucide-solid@^1.51.0"
10
10
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.122.3",
3
+ "version": "0.123.1",
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",
@@ -129,7 +129,7 @@
129
129
  "check:packed-paste-model": "node scripts/check-packed-paste-model.mjs"
130
130
  },
131
131
  "dependencies": {
132
- "@adea-ai/themes": "^0.9.10",
132
+ "@adea-ai/themes": "^0.10.4",
133
133
  "@corvu/calendar": "^0.1.2",
134
134
  "@corvu/drawer": "^0.2.4",
135
135
  "@corvu/otp-field": "^0.1.4",
package/registry.json CHANGED
@@ -1811,6 +1811,7 @@
1811
1811
  ],
1812
1812
  "registryDependencies": [
1813
1813
  "@adea-ai/ui/action-button",
1814
+ "@adea-ai/ui/button",
1814
1815
  "lib"
1815
1816
  ],
1816
1817
  "files": [
@@ -1834,6 +1835,31 @@
1834
1835
  "type": "registry:ui",
1835
1836
  "target": "components/layout/split-layout/model.ts"
1836
1837
  },
1838
+ {
1839
+ "path": "src/components/layout/split-layout/resize-controller-core-retry.tsx",
1840
+ "type": "registry:ui",
1841
+ "target": "components/layout/split-layout/resize-controller-core-retry.tsx"
1842
+ },
1843
+ {
1844
+ "path": "src/components/layout/split-layout/resize-controller-core.tsx",
1845
+ "type": "registry:ui",
1846
+ "target": "components/layout/split-layout/resize-controller-core.tsx"
1847
+ },
1848
+ {
1849
+ "path": "src/components/layout/split-layout/resize-controller-retry-2.tsx",
1850
+ "type": "registry:ui",
1851
+ "target": "components/layout/split-layout/resize-controller-retry-2.tsx"
1852
+ },
1853
+ {
1854
+ "path": "src/components/layout/split-layout/resize-controller-retry.tsx",
1855
+ "type": "registry:ui",
1856
+ "target": "components/layout/split-layout/resize-controller-retry.tsx"
1857
+ },
1858
+ {
1859
+ "path": "src/components/layout/split-layout/resize-controller.tsx",
1860
+ "type": "registry:ui",
1861
+ "target": "components/layout/split-layout/resize-controller.tsx"
1862
+ },
1837
1863
  {
1838
1864
  "path": "src/components/layout/split-layout/split-layout.tsx",
1839
1865
  "type": "registry:ui",
@@ -1998,7 +2024,7 @@
1998
2024
  "title": "Appearance Editor",
1999
2025
  "description": "",
2000
2026
  "dependencies": [
2001
- "@adea-ai/themes@^0.9.10",
2027
+ "@adea-ai/themes@^0.10.4",
2002
2028
  "@kobalte/core@^0.13.14",
2003
2029
  "lucide-solid@^1.51.0"
2004
2030
  ],
@@ -2477,7 +2503,7 @@
2477
2503
  "title": "Theming",
2478
2504
  "description": "",
2479
2505
  "dependencies": [
2480
- "@adea-ai/themes@^0.9.10",
2506
+ "@adea-ai/themes@^0.10.4",
2481
2507
  "@kobalte/core@^0.13.14",
2482
2508
  "lucide-solid@^1.51.0"
2483
2509
  ],
@@ -2592,7 +2618,7 @@
2592
2618
  "title": "Class-name and token helpers",
2593
2619
  "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.",
2594
2620
  "dependencies": [
2595
- "@adea-ai/themes@^0.9.10",
2621
+ "@adea-ai/themes@^0.10.4",
2596
2622
  "class-variance-authority@^0.7.1",
2597
2623
  "cn@^0.4.0"
2598
2624
  ],
@@ -0,0 +1,66 @@
1
+ import Resizable from '@corvu/resizable'
2
+ import { type Accessor, type JSX } from 'solid-js'
3
+ import {
4
+ listLeaves,
5
+ MIN_SPLIT_RATIO,
6
+ MAX_SPLIT_RATIO,
7
+ type SplitLayoutBranch,
8
+ type SplitLayoutLeaf,
9
+ } from './model'
10
+
11
+ export type SplitLayoutResizeControllerProps<L extends SplitLayoutLeaf> = {
12
+ branch: Accessor<SplitLayoutBranch<L>>
13
+ rect: Accessor<JSX.CSSProperties>
14
+ domId: (id: string) => string
15
+ root: () => HTMLDivElement | undefined
16
+ labelForSeparator?: (branch: SplitLayoutBranch<L>) => string
17
+ onResize: (splitId: string, ratio: number) => void
18
+ }
19
+
20
+ /** Corvu stays behind the first real split while the pane owners remain mounted. */
21
+ export default function SplitLayoutResizeController<L extends SplitLayoutLeaf>(
22
+ props: SplitLayoutResizeControllerProps<L>
23
+ ) {
24
+ const id = () => props.branch().id
25
+ return (
26
+ <Resizable
27
+ orientation={props.branch().direction === 'row' ? 'horizontal' : 'vertical'}
28
+ sizes={[props.branch().ratio, 1 - props.branch().ratio]}
29
+ keyboardDelta={0.05}
30
+ onSizesChange={(sizes) => {
31
+ // Corvu also reports panel registration/unregistration while
32
+ // mounting or disposing a controller. Those incomplete or
33
+ // hidden-host sizes are not user resize intent.
34
+ const root = props.root()
35
+ if (!root?.isConnected || root.getClientRects().length === 0) return
36
+ if (
37
+ sizes.length !== 2 ||
38
+ sizes.some((size) => !Number.isFinite(size)) ||
39
+ Math.abs(sizes[0]! + sizes[1]! - 1) > 0.000001
40
+ )
41
+ return
42
+ if (sizes[0] !== undefined && Math.abs(sizes[0] - props.branch().ratio) > 0.000001)
43
+ props.onResize(id(), sizes[0])
44
+ }}
45
+ style={props.rect()}
46
+ class="pointer-events-none absolute flex min-h-0 min-w-0 data-[orientation=vertical]:flex-col"
47
+ >
48
+ <Resizable.Panel minSize={MIN_SPLIT_RATIO} maxSize={MAX_SPLIT_RATIO} aria-hidden="true" />
49
+ <Resizable.Handle
50
+ aria-label={
51
+ props.labelForSeparator?.(props.branch()) ??
52
+ (props.branch().direction === 'row' ? 'Resize pane columns' : 'Resize pane rows')
53
+ }
54
+ aria-orientation={props.branch().direction === 'row' ? 'vertical' : 'horizontal'}
55
+ aria-controls={listLeaves(props.branch())
56
+ .map((leaf) => props.domId(leaf.id))
57
+ .join(' ')}
58
+ aria-valuemin={10}
59
+ aria-valuemax={90}
60
+ aria-valuenow={Math.round(props.branch().ratio * 100)}
61
+ class="pointer-events-auto relative w-px shrink-0 bg-border after:absolute after:inset-y-0 after:-inset-x-1 after:w-3 focus-visible:bg-primary focus-visible:outline-none hover:bg-primary data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-1 data-[orientation=vertical]:after:h-3 data-[orientation=vertical]:after:w-full"
62
+ />
63
+ <Resizable.Panel minSize={MIN_SPLIT_RATIO} maxSize={MAX_SPLIT_RATIO} aria-hidden="true" />
64
+ </Resizable>
65
+ )
66
+ }
@@ -0,0 +1,66 @@
1
+ import Resizable from '@corvu/resizable'
2
+ import { type Accessor, type JSX } from 'solid-js'
3
+ import {
4
+ listLeaves,
5
+ MIN_SPLIT_RATIO,
6
+ MAX_SPLIT_RATIO,
7
+ type SplitLayoutBranch,
8
+ type SplitLayoutLeaf,
9
+ } from './model'
10
+
11
+ export type SplitLayoutResizeControllerProps<L extends SplitLayoutLeaf> = {
12
+ branch: Accessor<SplitLayoutBranch<L>>
13
+ rect: Accessor<JSX.CSSProperties>
14
+ domId: (id: string) => string
15
+ root: () => HTMLDivElement | undefined
16
+ labelForSeparator?: (branch: SplitLayoutBranch<L>) => string
17
+ onResize: (splitId: string, ratio: number) => void
18
+ }
19
+
20
+ /** Corvu stays behind the first real split while the pane owners remain mounted. */
21
+ export default function SplitLayoutResizeController<L extends SplitLayoutLeaf>(
22
+ props: SplitLayoutResizeControllerProps<L>
23
+ ) {
24
+ const id = () => props.branch().id
25
+ return (
26
+ <Resizable
27
+ orientation={props.branch().direction === 'row' ? 'horizontal' : 'vertical'}
28
+ sizes={[props.branch().ratio, 1 - props.branch().ratio]}
29
+ keyboardDelta={0.05}
30
+ onSizesChange={(sizes) => {
31
+ // Corvu also reports panel registration/unregistration while
32
+ // mounting or disposing a controller. Those incomplete or
33
+ // hidden-host sizes are not user resize intent.
34
+ const root = props.root()
35
+ if (!root?.isConnected || root.getClientRects().length === 0) return
36
+ if (
37
+ sizes.length !== 2 ||
38
+ sizes.some((size) => !Number.isFinite(size)) ||
39
+ Math.abs(sizes[0]! + sizes[1]! - 1) > 0.000001
40
+ )
41
+ return
42
+ if (sizes[0] !== undefined && Math.abs(sizes[0] - props.branch().ratio) > 0.000001)
43
+ props.onResize(id(), sizes[0])
44
+ }}
45
+ style={props.rect()}
46
+ class="pointer-events-none absolute flex min-h-0 min-w-0 data-[orientation=vertical]:flex-col"
47
+ >
48
+ <Resizable.Panel minSize={MIN_SPLIT_RATIO} maxSize={MAX_SPLIT_RATIO} aria-hidden="true" />
49
+ <Resizable.Handle
50
+ aria-label={
51
+ props.labelForSeparator?.(props.branch()) ??
52
+ (props.branch().direction === 'row' ? 'Resize pane columns' : 'Resize pane rows')
53
+ }
54
+ aria-orientation={props.branch().direction === 'row' ? 'vertical' : 'horizontal'}
55
+ aria-controls={listLeaves(props.branch())
56
+ .map((leaf) => props.domId(leaf.id))
57
+ .join(' ')}
58
+ aria-valuemin={10}
59
+ aria-valuemax={90}
60
+ aria-valuenow={Math.round(props.branch().ratio * 100)}
61
+ class="pointer-events-auto relative w-px shrink-0 bg-border after:absolute after:inset-y-0 after:-inset-x-1 after:w-3 focus-visible:bg-primary focus-visible:outline-none hover:bg-primary data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-1 data-[orientation=vertical]:after:h-3 data-[orientation=vertical]:after:w-full"
62
+ />
63
+ <Resizable.Panel minSize={MIN_SPLIT_RATIO} maxSize={MAX_SPLIT_RATIO} aria-hidden="true" />
64
+ </Resizable>
65
+ )
66
+ }
@@ -0,0 +1,2 @@
1
+ /** Independent module entrypoint to recover from a cached failed primary core import. */
2
+ export { default } from './resize-controller-core-retry'
@@ -0,0 +1 @@
1
+ export { default } from './resize-controller-core'
@@ -0,0 +1 @@
1
+ export { default } from './resize-controller-core'