@adea-ai/ui 0.83.1 → 0.85.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.
Files changed (54) hide show
  1. package/README.md +79 -0
  2. package/dist/NOTICE +26 -0
  3. package/dist/components/composites/catalog-browser/catalog-browser-group.d.ts +20 -0
  4. package/dist/components/composites/catalog-browser/catalog-browser-group.d.ts.map +1 -0
  5. package/dist/components/composites/catalog-browser/catalog-browser-group.js +195 -0
  6. package/dist/components/composites/catalog-browser/catalog-browser-group.js.map +1 -0
  7. package/dist/components/composites/catalog-browser/catalog-browser.d.ts +3 -0
  8. package/dist/components/composites/catalog-browser/catalog-browser.d.ts.map +1 -0
  9. package/dist/components/composites/catalog-browser/catalog-browser.js +378 -0
  10. package/dist/components/composites/catalog-browser/catalog-browser.js.map +1 -0
  11. package/dist/components/composites/catalog-browser/catalog-detail.d.ts +21 -0
  12. package/dist/components/composites/catalog-browser/catalog-detail.d.ts.map +1 -0
  13. package/dist/components/composites/catalog-browser/catalog-detail.js +92 -0
  14. package/dist/components/composites/catalog-browser/catalog-detail.js.map +1 -0
  15. package/dist/components/composites/catalog-browser/catalog-types.d.ts +78 -0
  16. package/dist/components/composites/catalog-browser/catalog-types.d.ts.map +1 -0
  17. package/dist/components/composites/catalog-browser/index.d.ts +4 -0
  18. package/dist/components/composites/catalog-browser/index.d.ts.map +1 -0
  19. package/dist/components/composites/catalog-browser/index.js +3 -0
  20. package/dist/components/layout/sidebar-nav/index.d.ts +1 -0
  21. package/dist/components/layout/sidebar-nav/index.d.ts.map +1 -1
  22. package/dist/components/layout/sidebar-nav/index.js +2 -1
  23. package/dist/components/layout/sidebar-nav/sidebar-nav-resize-handle.d.ts +21 -0
  24. package/dist/components/layout/sidebar-nav/sidebar-nav-resize-handle.d.ts.map +1 -0
  25. package/dist/components/layout/sidebar-nav/sidebar-nav-resize-handle.js +84 -0
  26. package/dist/components/layout/sidebar-nav/sidebar-nav-resize-handle.js.map +1 -0
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +5 -2
  30. package/dist/lint/index.d.ts +1 -0
  31. package/dist/lint/index.d.ts.map +1 -1
  32. package/dist/lint.js +171 -59
  33. package/dist/lint.js.map +1 -1
  34. package/dist/r/catalog-browser.json +47 -0
  35. package/dist/r/registry.json +53 -0
  36. package/dist/r/sidebar-nav.json +6 -0
  37. package/dist/r/src/components/composites/catalog-browser/catalog-browser-group.tsx +148 -0
  38. package/dist/r/src/components/composites/catalog-browser/catalog-browser.tsx +258 -0
  39. package/dist/r/src/components/composites/catalog-browser/catalog-detail.tsx +64 -0
  40. package/dist/r/src/components/composites/catalog-browser/catalog-types.ts +83 -0
  41. package/dist/r/src/components/composites/catalog-browser/index.ts +10 -0
  42. package/dist/r/src/components/layout/sidebar-nav/index.ts +4 -0
  43. package/dist/r/src/components/layout/sidebar-nav/sidebar-nav-resize-handle.tsx +59 -0
  44. package/package.json +1 -1
  45. package/registry.json +53 -0
  46. package/src/components/composites/catalog-browser/catalog-browser-group.tsx +148 -0
  47. package/src/components/composites/catalog-browser/catalog-browser.tsx +258 -0
  48. package/src/components/composites/catalog-browser/catalog-detail.tsx +64 -0
  49. package/src/components/composites/catalog-browser/catalog-types.ts +83 -0
  50. package/src/components/composites/catalog-browser/index.ts +10 -0
  51. package/src/components/layout/sidebar-nav/index.ts +4 -0
  52. package/src/components/layout/sidebar-nav/sidebar-nav-resize-handle.tsx +59 -0
  53. package/src/index.ts +1 -0
  54. package/src/lint/index.ts +168 -19
@@ -0,0 +1,258 @@
1
+ import { createEffect, createMemo, createSignal, For, onCleanup, Show } from 'solid-js'
2
+ import { ArrowLeft, Blocks, Search } from 'lucide-solid'
3
+ import { keyedRows } from '../../../lib/keyed-rows'
4
+ import { Button } from '../../ui/button'
5
+ import {
6
+ Empty,
7
+ EmptyContent,
8
+ EmptyDescription,
9
+ EmptyHeader,
10
+ EmptyMedia,
11
+ EmptyTitle,
12
+ } from '../../ui/empty'
13
+ import { InputGroup, InputGroupAddon, InputGroupInput } from '../../ui/input-group'
14
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../ui/tabs'
15
+ import { ScrollArea } from '../../ui/scroll-area'
16
+ import { cn } from '../../../lib/utils'
17
+ import { CatalogBrowserGroup, CatalogLoadingState } from './catalog-browser-group'
18
+ import type { CatalogBrowserProps } from './catalog-types'
19
+
20
+ export function CatalogBrowser<Value>(props: CatalogBrowserProps<Value>) {
21
+ const [expandedGroups, setExpandedGroups] = createSignal<ReadonlySet<string>>(new Set())
22
+ const [returnKey, setReturnKey] = createSignal<string>()
23
+ const [lastSelectedId, setLastSelectedId] = createSignal<string>()
24
+ const rowRefs = new Map<string, HTMLButtonElement>()
25
+ let searchInput: HTMLInputElement | undefined
26
+ let backButton: HTMLButtonElement | undefined
27
+
28
+ const selectedTab = createMemo(() => props.tabs.find((tab) => tab.id === props.tab))
29
+ const supplemental = () => selectedTab()?.kind === 'supplemental'
30
+ const selected = createMemo(() => {
31
+ const id = props.selectedId
32
+ return id && !supplemental() ? props.entries.find((entry) => entry.id === id) : undefined
33
+ })
34
+ const groupRows = keyedRows(
35
+ () => props.groups,
36
+ (group) => group.id
37
+ )
38
+ const [wide, setWide] = createSignal(
39
+ typeof window === 'undefined' || window.matchMedia('(min-width: 48rem)').matches
40
+ )
41
+ const updateWide = (event: MediaQueryListEvent) => setWide(event.matches)
42
+
43
+ createEffect(() => {
44
+ if (typeof window === 'undefined') return
45
+ const query = window.matchMedia('(min-width: 48rem)')
46
+ query.addEventListener('change', updateWide)
47
+ onCleanup(() => query.removeEventListener('change', updateWide))
48
+ })
49
+
50
+ createEffect(() => {
51
+ const open = props.open
52
+ const selectedId = props.selectedId
53
+ const selectedEntry = selected()
54
+ if (!open) {
55
+ setExpandedGroups(new Set<string>())
56
+ setLastSelectedId(undefined)
57
+ setReturnKey(undefined)
58
+ return
59
+ }
60
+ if (selectedId && selectedEntry) {
61
+ const previous = lastSelectedId()
62
+ setLastSelectedId(selectedId)
63
+ if (selectedId !== previous) {
64
+ window.requestAnimationFrame(() => {
65
+ if (props.open && props.selectedId === selectedId) backButton?.focus()
66
+ })
67
+ }
68
+ return
69
+ }
70
+ const previous = lastSelectedId()
71
+ if (!previous) return
72
+ const key = returnKey()
73
+ setLastSelectedId(undefined)
74
+ setReturnKey(undefined)
75
+ window.requestAnimationFrame(() => {
76
+ if (!props.open || props.selectedId) return
77
+ const row = key ? rowRefs.get(key) : undefined
78
+ if (row?.isConnected) row.focus()
79
+ else searchInput?.focus()
80
+ })
81
+ })
82
+
83
+ const registerRow = (key: string, element: HTMLButtonElement | undefined) => {
84
+ if (element) rowRefs.set(key, element)
85
+ else rowRefs.delete(key)
86
+ }
87
+ const selectEntry = (key: string, value: Value) => {
88
+ setReturnKey(key)
89
+ props.onSelect(value)
90
+ }
91
+ const toggleGroup = (id: string) => {
92
+ setExpandedGroups((current) => {
93
+ const next = new Set(current)
94
+ if (next.has(id)) next.delete(id)
95
+ else next.add(id)
96
+ return next
97
+ })
98
+ }
99
+ const previewCount = () => (wide() ? 6 : 3)
100
+ const countLabel = () =>
101
+ props.status === 'loading' ? props.loadingLabel : props.resultLabel(props.resultCount)
102
+ const supplementalContent = () => props.renderSupplementalView?.(props.tab)
103
+
104
+ return (
105
+ <div class={cn('flex min-h-0 min-w-0 flex-1 flex-col', props.class)}>
106
+ <Show
107
+ when={selected()}
108
+ fallback={
109
+ <Tabs
110
+ class="flex min-h-0 min-w-0 flex-1 flex-col gap-0"
111
+ value={props.tab}
112
+ onChange={(value) => value && props.onTabChange(value)}
113
+ >
114
+ <TabsList aria-label={props.tabsLabel} class="ms-auto max-w-full flex-wrap px-4 pt-2">
115
+ <For each={props.tabs}>
116
+ {(tab) => <TabsTrigger value={tab.id}>{tab.label}</TabsTrigger>}
117
+ </For>
118
+ </TabsList>
119
+ <TabsContent value={props.tab} class="flex min-h-0 min-w-0 flex-1 flex-col gap-3">
120
+ <Show
121
+ when={supplemental()}
122
+ fallback={
123
+ <>
124
+ <Show when={props.installError}>
125
+ {(message) => (
126
+ <p class="text-destructive px-4 pt-2 text-sm" role="alert">
127
+ {message()}
128
+ </p>
129
+ )}
130
+ </Show>
131
+ <div class="flex min-w-0 shrink-0 flex-wrap items-center gap-2 px-4 pt-2">
132
+ {props.filterControl}
133
+ <InputGroup class="min-w-0 flex-1 sm:max-w-md">
134
+ <InputGroupAddon>
135
+ <Search aria-hidden="true" />
136
+ </InputGroupAddon>
137
+ <InputGroupInput
138
+ ref={(element) => (searchInput = element)}
139
+ type="search"
140
+ aria-label={props.searchLabel}
141
+ placeholder={props.searchPlaceholder}
142
+ value={props.query}
143
+ onInput={(event) => props.onQueryChange(event.currentTarget.value)}
144
+ />
145
+ </InputGroup>
146
+ <span class="text-muted-foreground ms-auto text-sm" role="status">
147
+ {countLabel()}
148
+ </span>
149
+ </div>
150
+ <ScrollArea
151
+ role="region"
152
+ aria-label={props.resultsRegionLabel}
153
+ orientation="vertical"
154
+ class="flex min-h-0 min-w-0 flex-1 flex-col gap-5 px-4 pb-4"
155
+ >
156
+ <Show when={props.status === 'error'}>
157
+ <Empty
158
+ class="min-h-0 min-w-0 flex-1"
159
+ role={props.catalogError.role ?? 'alert'}
160
+ >
161
+ <EmptyHeader>
162
+ <EmptyMedia variant="icon">
163
+ <Blocks aria-hidden="true" />
164
+ </EmptyMedia>
165
+ <EmptyTitle>{props.catalogError.title}</EmptyTitle>
166
+ <EmptyDescription>{props.catalogError.description}</EmptyDescription>
167
+ </EmptyHeader>
168
+ <Show when={props.catalogErrorAction}>
169
+ <EmptyContent>{props.catalogErrorAction}</EmptyContent>
170
+ </Show>
171
+ </Empty>
172
+ </Show>
173
+ <Show when={props.status === 'loading'}>
174
+ <CatalogLoadingState label={props.loadingLabel} />
175
+ </Show>
176
+ <Show when={props.status === 'ready'}>
177
+ <Show
178
+ when={props.resultCount > 0}
179
+ fallback={
180
+ <Empty class="min-h-0 min-w-0 flex-1" role="status">
181
+ <EmptyHeader>
182
+ <EmptyMedia variant="icon">
183
+ <Blocks aria-hidden="true" />
184
+ </EmptyMedia>
185
+ <EmptyTitle>{props.emptyState.title}</EmptyTitle>
186
+ <EmptyDescription>{props.emptyState.description}</EmptyDescription>
187
+ </EmptyHeader>
188
+ <Show when={props.emptyStateAction}>
189
+ <EmptyContent>{props.emptyStateAction}</EmptyContent>
190
+ </Show>
191
+ </Empty>
192
+ }
193
+ >
194
+ <div class="grid min-w-0 gap-5">
195
+ <For each={groupRows()}>
196
+ {(row) => (
197
+ <CatalogBrowserGroup
198
+ group={row.item()}
199
+ expanded={expandedGroups().has(row.item().id)}
200
+ previewCount={previewCount()}
201
+ disabled={props.interactionDisabled ?? false}
202
+ installedLabel={props.installedLabel}
203
+ publishedByLabel={props.publishedByLabel}
204
+ showMoreLabel={props.showMoreLabel}
205
+ showLessLabel={props.showLessLabel}
206
+ renderIcon={props.renderIcon}
207
+ onSelect={(entry, key) => selectEntry(key, entry.value)}
208
+ onRef={registerRow}
209
+ onToggle={toggleGroup}
210
+ />
211
+ )}
212
+ </For>
213
+ </div>
214
+ </Show>
215
+ </Show>
216
+ <For each={props.notices ?? []}>
217
+ {(notice) => (
218
+ <p class="text-muted-foreground text-sm" role={notice.role}>
219
+ {notice.message}
220
+ </p>
221
+ )}
222
+ </For>
223
+ </ScrollArea>
224
+ </>
225
+ }
226
+ >
227
+ {supplementalContent()}
228
+ </Show>
229
+ </TabsContent>
230
+ </Tabs>
231
+ }
232
+ >
233
+ {(entry) => (
234
+ <div class="flex min-h-0 min-w-0 flex-1 flex-col gap-3" data-catalog-browser-detail>
235
+ <Button
236
+ ref={(element) => (backButton = element)}
237
+ variant="ghost"
238
+ size="sm"
239
+ onClick={() => props.onBack()}
240
+ class="mx-4 mt-2 self-start"
241
+ >
242
+ <ArrowLeft data-icon="inline-start" aria-hidden="true" />
243
+ {props.backLabel}
244
+ </Button>
245
+ <ScrollArea
246
+ role="region"
247
+ aria-label={props.detailRegionLabel}
248
+ orientation="vertical"
249
+ class="min-h-0 min-w-0 flex-1 px-4 pb-4"
250
+ >
251
+ {props.renderDetail(entry().value)}
252
+ </ScrollArea>
253
+ </div>
254
+ )}
255
+ </Show>
256
+ </div>
257
+ )
258
+ }
@@ -0,0 +1,64 @@
1
+ import { createUniqueId, Show, type JSX } from 'solid-js'
2
+ import { Badge } from '../../ui/badge'
3
+ import { Card, CardContent, CardFooter, CardHeader } from '../../ui/card'
4
+
5
+ /** Shared item summary and action frame for catalog-owned detail content. */
6
+ export function CatalogDetail(props: {
7
+ title: string
8
+ description: string
9
+ category: string
10
+ publisher: string
11
+ publishedByLabel: (publisher: string) => string
12
+ leading?: JSX.Element
13
+ eyebrow?: string
14
+ badges?: JSX.Element
15
+ action?: JSX.Element
16
+ status?: JSX.Element
17
+ children?: JSX.Element
18
+ }) {
19
+ return (
20
+ <article class="grid min-w-0 gap-4" data-catalog-detail>
21
+ <Card>
22
+ <CardHeader class="flex-row items-start gap-3">
23
+ <Show when={props.leading}>
24
+ <span class="shrink-0">{props.leading}</span>
25
+ </Show>
26
+ <div class="grid min-w-0 gap-1.5">
27
+ <div class="flex min-w-0 flex-wrap items-center gap-1.5">
28
+ <Show when={props.eyebrow}>
29
+ <Badge variant="outline">{props.eyebrow}</Badge>
30
+ </Show>
31
+ <Badge variant="secondary">{props.category}</Badge>
32
+ {props.badges}
33
+ </div>
34
+ <h2 class="text-base leading-tight font-semibold tracking-tight">{props.title}</h2>
35
+ <p class="text-muted-foreground text-sm">{props.description}</p>
36
+ <p class="text-muted-foreground text-xs">{props.publishedByLabel(props.publisher)}</p>
37
+ </div>
38
+ </CardHeader>
39
+ <CardFooter class="flex-wrap justify-between gap-3">
40
+ {props.action}
41
+ {props.status}
42
+ </CardFooter>
43
+ </Card>
44
+ <div class="grid min-w-0 gap-3">{props.children}</div>
45
+ </article>
46
+ )
47
+ }
48
+
49
+ /** A shared surface and heading for host-specific fields, permissions, and copy. */
50
+ export function CatalogDetailSection(props: { title: string; children?: JSX.Element }) {
51
+ const headingId = `catalog-detail-section-${createUniqueId()}`
52
+ return (
53
+ <section class="min-w-0" aria-labelledby={headingId}>
54
+ <Card>
55
+ <CardHeader>
56
+ <h3 id={headingId} class="text-sm font-semibold tracking-tight">
57
+ {props.title}
58
+ </h3>
59
+ </CardHeader>
60
+ <CardContent class="grid min-w-0 gap-3">{props.children}</CardContent>
61
+ </Card>
62
+ </section>
63
+ )
64
+ }
@@ -0,0 +1,83 @@
1
+ import type { JSX } from 'solid-js'
2
+
3
+ /** A host-owned catalog record reduced to the fields needed by the browser. */
4
+ export type CatalogBrowserEntry<Value> = Readonly<{
5
+ id: string
6
+ value: Value
7
+ name: string
8
+ description: string
9
+ category: string
10
+ publisher: string
11
+ installed: boolean
12
+ }>
13
+
14
+ /** One stable, host-ordered category in the browser. */
15
+ export type CatalogBrowserGroup<Value> = Readonly<{
16
+ id: string
17
+ label: string
18
+ entries: readonly CatalogBrowserEntry<Value>[]
19
+ }>
20
+
21
+ export type CatalogBrowserTab = Readonly<{
22
+ id: string
23
+ label: string
24
+ /** A host-rendered view, such as navigation settings, outside the catalog. */
25
+ kind?: 'catalog' | 'supplemental'
26
+ }>
27
+
28
+ export type CatalogBrowserNotice = Readonly<{
29
+ id: string
30
+ role: 'alert' | 'status'
31
+ message: string
32
+ }>
33
+
34
+ export type CatalogBrowserMessage = Readonly<{
35
+ title: string
36
+ description: string
37
+ role?: 'alert' | 'status'
38
+ }>
39
+
40
+ export type CatalogBrowserProps<Value> = Readonly<{
41
+ /** Optional layout hook for the host's containing surface. */
42
+ class?: string
43
+ /** Whether the containing host surface is open; closing it clears view-only state. */
44
+ open: boolean
45
+ tabs: readonly CatalogBrowserTab[]
46
+ tab: string
47
+ tabsLabel: string
48
+ onTabChange: (tab: string) => void
49
+ /** A host-owned view is rendered in the same tab frame without catalog assumptions. */
50
+ renderSupplementalView?: (tab: string) => JSX.Element | undefined
51
+ query: string
52
+ onQueryChange: (query: string) => void
53
+ searchLabel: string
54
+ searchPlaceholder: string
55
+ resultsRegionLabel: string
56
+ filterControl?: JSX.Element
57
+ resultCount: number
58
+ resultLabel: (count: number) => string
59
+ loadingLabel: string
60
+ status: 'loading' | 'ready' | 'error'
61
+ catalogError: CatalogBrowserMessage
62
+ catalogErrorAction?: JSX.Element
63
+ installError?: string
64
+ notices?: readonly CatalogBrowserNotice[]
65
+ emptyState: CatalogBrowserMessage
66
+ emptyStateAction?: JSX.Element
67
+ groups: readonly CatalogBrowserGroup<Value>[]
68
+ /** All selectable records, including records omitted by the current filter. */
69
+ entries: readonly CatalogBrowserEntry<Value>[]
70
+ selectedId: string | null
71
+ onSelect: (value: Value) => void
72
+ onBack: () => void
73
+ backLabel: string
74
+ detailRegionLabel: string
75
+ installedLabel: string
76
+ publishedByLabel: (publisher: string) => string
77
+ showMoreLabel: (entries: readonly CatalogBrowserEntry<Value>[], remainingCount: number) => string
78
+ showLessLabel: string
79
+ /** Temporarily disables catalog controls while a host menu owns interaction. */
80
+ interactionDisabled?: boolean
81
+ renderIcon: (value: Value) => JSX.Element
82
+ renderDetail: (value: Value) => JSX.Element
83
+ }>
@@ -0,0 +1,10 @@
1
+ export { CatalogBrowser } from './catalog-browser'
2
+ export { CatalogDetail, CatalogDetailSection } from './catalog-detail'
3
+ export type {
4
+ CatalogBrowserEntry,
5
+ CatalogBrowserGroup,
6
+ CatalogBrowserMessage,
7
+ CatalogBrowserNotice,
8
+ CatalogBrowserProps,
9
+ CatalogBrowserTab,
10
+ } from './catalog-types'
@@ -13,3 +13,7 @@ export {
13
13
  type SidebarNavProps,
14
14
  type SidebarNavTitleProps,
15
15
  } from './sidebar-nav'
16
+ export {
17
+ SidebarNavResizeHandle,
18
+ type SidebarNavResizeHandleProps,
19
+ } from './sidebar-nav-resize-handle'
@@ -0,0 +1,59 @@
1
+ import Resizable from '@corvu/resizable'
2
+ import { cn } from '../../../lib/utils'
3
+
4
+ export type SidebarNavResizeHandleProps = {
5
+ value: number
6
+ minimum: number
7
+ maximum: number
8
+ step?: number
9
+ label?: string
10
+ controls?: string
11
+ class?: string
12
+ onChange(value: number): void
13
+ onCommit?(value: number): void
14
+ }
15
+
16
+ /**
17
+ * Resize a contextual sidebar without making its host recreate a separator
18
+ * widget. Corvu owns pointer capture, cancellation, constraints, keyboard
19
+ * movement and cleanup. Its two invisible panels provide a bounded pixel
20
+ * ruler; the host retains the real pane layout and preference persistence.
21
+ * Place this inside the positioned sidebar. The ruler can extend over the
22
+ * adjacent content, but only its handle participates in pointer hit testing.
23
+ */
24
+ export function SidebarNavResizeHandle(props: SidebarNavResizeHandleProps) {
25
+ const maximum = () => Math.max(1, props.maximum)
26
+ const minimum = () => Math.min(maximum(), Math.max(0, props.minimum))
27
+ const value = () => Math.min(maximum(), Math.max(minimum(), props.value))
28
+ const commit = () => props.onCommit?.(value())
29
+
30
+ return (
31
+ <Resizable
32
+ orientation="horizontal"
33
+ sizes={[value() / maximum(), 1 - value() / maximum()]}
34
+ keyboardDelta={`${props.step ?? 16}px`}
35
+ style={{ width: `${maximum()}px` }}
36
+ class={cn('pointer-events-none absolute inset-y-0 start-0 flex', props.class)}
37
+ onSizesChange={(sizes) => {
38
+ const next = Math.round((sizes[0] ?? 0) * maximum())
39
+ if (next !== value()) props.onChange(Math.min(maximum(), Math.max(minimum(), next)))
40
+ }}
41
+ >
42
+ <Resizable.Panel minSize={minimum() / maximum()} maxSize={1} aria-hidden="true" />
43
+ <Resizable.Handle
44
+ aria-label={props.label ?? 'Resize navigation'}
45
+ aria-controls={props.controls}
46
+ aria-orientation="vertical"
47
+ aria-valuemin={minimum()}
48
+ aria-valuemax={maximum()}
49
+ aria-valuenow={value()}
50
+ onHandleDragEnd={commit}
51
+ onKeyUp={(event) => {
52
+ if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) commit()
53
+ }}
54
+ class="pointer-events-auto relative z-(--z-docked) w-px -translate-x-full shrink-0 bg-transparent after:absolute after:inset-y-0 after:-inset-x-1 after:w-3 hover:bg-primary focus-visible:bg-primary focus-visible:ring-3 focus-visible:ring-primary-subtle focus-visible:outline-none"
55
+ />
56
+ <Resizable.Panel minSize={0} aria-hidden="true" />
57
+ </Resizable>
58
+ )
59
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.83.1",
3
+ "version": "0.85.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",
package/registry.json CHANGED
@@ -1558,6 +1558,7 @@
1558
1558
  "title": "Sidebar Nav",
1559
1559
  "description": "",
1560
1560
  "dependencies": [
1561
+ "@corvu/resizable@^0.2.5",
1561
1562
  "@kobalte/core@^0.13.14",
1562
1563
  "lucide-solid@^1.48.0"
1563
1564
  ],
@@ -1570,6 +1571,11 @@
1570
1571
  "type": "registry:ui",
1571
1572
  "target": "components/layout/sidebar-nav/index.ts"
1572
1573
  },
1574
+ {
1575
+ "path": "src/components/layout/sidebar-nav/sidebar-nav-resize-handle.tsx",
1576
+ "type": "registry:ui",
1577
+ "target": "components/layout/sidebar-nav/sidebar-nav-resize-handle.tsx"
1578
+ },
1573
1579
  {
1574
1580
  "path": "src/components/layout/sidebar-nav/sidebar-nav.tsx",
1575
1581
  "type": "registry:ui",
@@ -1786,6 +1792,53 @@
1786
1792
  }
1787
1793
  ]
1788
1794
  },
1795
+ {
1796
+ "name": "catalog-browser",
1797
+ "type": "registry:ui",
1798
+ "title": "Catalog Browser",
1799
+ "description": "",
1800
+ "dependencies": [
1801
+ "lucide-solid@^1.48.0"
1802
+ ],
1803
+ "registryDependencies": [
1804
+ "@adea-ai/ui/badge",
1805
+ "@adea-ai/ui/button",
1806
+ "@adea-ai/ui/card",
1807
+ "@adea-ai/ui/empty",
1808
+ "@adea-ai/ui/input-group",
1809
+ "@adea-ai/ui/scroll-area",
1810
+ "@adea-ai/ui/skeleton",
1811
+ "@adea-ai/ui/tabs",
1812
+ "lib"
1813
+ ],
1814
+ "files": [
1815
+ {
1816
+ "path": "src/components/composites/catalog-browser/catalog-browser-group.tsx",
1817
+ "type": "registry:ui",
1818
+ "target": "components/composites/catalog-browser/catalog-browser-group.tsx"
1819
+ },
1820
+ {
1821
+ "path": "src/components/composites/catalog-browser/catalog-browser.tsx",
1822
+ "type": "registry:ui",
1823
+ "target": "components/composites/catalog-browser/catalog-browser.tsx"
1824
+ },
1825
+ {
1826
+ "path": "src/components/composites/catalog-browser/catalog-detail.tsx",
1827
+ "type": "registry:ui",
1828
+ "target": "components/composites/catalog-browser/catalog-detail.tsx"
1829
+ },
1830
+ {
1831
+ "path": "src/components/composites/catalog-browser/catalog-types.ts",
1832
+ "type": "registry:ui",
1833
+ "target": "components/composites/catalog-browser/catalog-types.ts"
1834
+ },
1835
+ {
1836
+ "path": "src/components/composites/catalog-browser/index.ts",
1837
+ "type": "registry:ui",
1838
+ "target": "components/composites/catalog-browser/index.ts"
1839
+ }
1840
+ ]
1841
+ },
1789
1842
  {
1790
1843
  "name": "list-row",
1791
1844
  "type": "registry:ui",