@adea-ai/ui 0.109.0 → 0.110.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 +14 -0
- package/dist/components/composites/update-dialog/update-dialog.js +1 -1
- package/dist/components/layout/contextual-sidebar/contextual-sidebar.d.ts.map +1 -1
- package/dist/components/layout/contextual-sidebar/contextual-sidebar.js +45 -35
- package/dist/components/layout/contextual-sidebar/contextual-sidebar.js.map +1 -1
- package/dist/components/layout/contextual-sidebar/mobile-contextual-sidebar.d.ts +12 -0
- package/dist/components/layout/contextual-sidebar/mobile-contextual-sidebar.d.ts.map +1 -0
- package/dist/components/layout/contextual-sidebar/mobile-contextual-sidebar.js +36 -0
- package/dist/components/layout/contextual-sidebar/mobile-contextual-sidebar.js.map +1 -0
- package/dist/components/layout/split-layout/index.js +2 -2
- package/dist/components/layout/split-layout/model.d.ts +13 -0
- package/dist/components/layout/split-layout/model.d.ts.map +1 -1
- package/dist/components/layout/split-layout/model.js +55 -18
- package/dist/components/layout/split-layout/model.js.map +1 -1
- package/dist/components/ui/alert-dialog/alert-dialog.d.ts.map +1 -1
- package/dist/components/ui/alert-dialog/alert-dialog.js +2 -6
- package/dist/components/ui/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/components/ui/board/board.js +1 -1
- package/dist/components/ui/dialog/dialog.d.ts.map +1 -1
- package/dist/components/ui/dialog/dialog.js +2 -6
- package/dist/components/ui/dialog/dialog.js.map +1 -1
- package/dist/components/ui/item/item.d.ts +1 -1
- package/dist/components/ui/sheet/sheet.d.ts.map +1 -1
- package/dist/components/ui/sheet/sheet.js +2 -5
- package/dist/components/ui/sheet/sheet.js.map +1 -1
- package/dist/components/ui/typography/typography.d.ts.map +1 -1
- package/dist/components/ui/typography/typography.js +2 -2
- package/dist/components/ui/typography/typography.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/lib/overlay.d.ts +5 -0
- package/dist/lib/overlay.d.ts.map +1 -1
- package/dist/lib/overlay.js +6 -1
- package/dist/lib/overlay.js.map +1 -1
- package/dist/r/alert-dialog.json +0 -1
- package/dist/r/contextual-sidebar.json +5 -0
- package/dist/r/dialog.json +0 -1
- package/dist/r/registry.json +5 -3
- package/dist/r/sheet.json +0 -1
- package/dist/r/src/components/layout/contextual-sidebar/contextual-sidebar.tsx +41 -16
- package/dist/r/src/components/layout/contextual-sidebar/mobile-contextual-sidebar.tsx +28 -0
- package/dist/r/src/components/layout/split-layout/model.ts +62 -10
- package/dist/r/src/components/ui/alert-dialog/alert-dialog.tsx +8 -8
- package/dist/r/src/components/ui/dialog/dialog.tsx +8 -8
- package/dist/r/src/components/ui/sheet/sheet.tsx +2 -7
- package/dist/r/src/components/ui/typography/typography.tsx +3 -2
- package/dist/r/src/lib/overlay.ts +6 -0
- package/package.json +1 -1
- package/registry.json +5 -3
- package/src/components/layout/contextual-sidebar/contextual-sidebar.tsx +41 -16
- package/src/components/layout/contextual-sidebar/mobile-contextual-sidebar.tsx +28 -0
- package/src/components/layout/split-layout/model.ts +62 -10
- package/src/components/ui/alert-dialog/alert-dialog.tsx +8 -8
- package/src/components/ui/dialog/dialog.tsx +8 -8
- package/src/components/ui/sheet/sheet.tsx +2 -7
- package/src/components/ui/typography/typography.tsx +3 -2
- package/src/lib/overlay.ts +6 -0
|
@@ -41,6 +41,10 @@ export type SplitPaneInput<L extends SplitLayoutLeaf = SplitLayoutLeaf> = Readon
|
|
|
41
41
|
splitId: string
|
|
42
42
|
}>
|
|
43
43
|
|
|
44
|
+
export type BalancedSplitPaneInput<L extends SplitLayoutLeaf = SplitLayoutLeaf> = Readonly<
|
|
45
|
+
Pick<SplitPaneInput<L>, 'placement' | 'leaf' | 'splitId'>
|
|
46
|
+
>
|
|
47
|
+
|
|
44
48
|
function replaceLeaf<L extends SplitLayoutLeaf>(
|
|
45
49
|
node: SplitLayoutNode<L>,
|
|
46
50
|
leafId: string,
|
|
@@ -86,14 +90,19 @@ function assertUniqueInput<L extends SplitLayoutLeaf>(
|
|
|
86
90
|
if (typeof splitId !== 'string' || splitId.length === 0)
|
|
87
91
|
throw new Error('invalid_state: split identity must be nonempty')
|
|
88
92
|
const ids = new Set<string>()
|
|
93
|
+
const splitIds: string[] = []
|
|
89
94
|
const visit = (node: SplitLayoutNode<L>) => {
|
|
90
95
|
if (ids.has(node.id)) throw new Error('invalid_state: duplicate pane id')
|
|
91
96
|
ids.add(node.id)
|
|
92
|
-
if (node.kind === 'split')
|
|
97
|
+
if (node.kind === 'split') {
|
|
98
|
+
splitIds.push(node.id)
|
|
99
|
+
node.children.forEach(visit)
|
|
100
|
+
}
|
|
93
101
|
}
|
|
94
102
|
visit(state.center)
|
|
95
103
|
if (ids.has(leaf.id) || ids.has(splitId) || leaf.id === splitId)
|
|
96
104
|
throw new Error('invalid_state: duplicate pane id')
|
|
105
|
+
return splitIds
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
/** Visual-tree validation only; applications still decode and scope persisted preferences. */
|
|
@@ -163,6 +172,51 @@ export function splitPane<L extends SplitLayoutLeaf>(
|
|
|
163
172
|
return { ...state, center, focusedLeafId: input.leaf.id, closed: [] }
|
|
164
173
|
}
|
|
165
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Add a pane beside the selected leaf and reflow the visual tree into a
|
|
177
|
+
* balanced row-major grid. One or two leaves share one row; from three leaves
|
|
178
|
+
* onward, leaves fill a first row and then a second row, with no more than four
|
|
179
|
+
* columns in either. Each row gives its leaves equal width and the two rows
|
|
180
|
+
* equal height. Existing opaque leaf objects are preserved. Split IDs are
|
|
181
|
+
* recycled across rebuilt branches, whose axis and descendants can change;
|
|
182
|
+
* resize actions must resolve against the current tree. Ratios are recomputed.
|
|
183
|
+
* This is opt-in: callers
|
|
184
|
+
* that need an explicit axis and ratio should keep using `splitPane`.
|
|
185
|
+
*/
|
|
186
|
+
export function splitPaneBalanced<L extends SplitLayoutLeaf>(
|
|
187
|
+
state: SplitLayoutState<L>,
|
|
188
|
+
targetLeafId: string,
|
|
189
|
+
input: BalancedSplitPaneInput<L>
|
|
190
|
+
): SplitLayoutState<L> {
|
|
191
|
+
const leaves = [...listLeaves(state.center)]
|
|
192
|
+
const targetIndex = leaves.findIndex((leaf) => leaf.id === targetLeafId)
|
|
193
|
+
if (targetIndex < 0) return state
|
|
194
|
+
if (leaves.length >= MAX_LAYOUT_LEAVES)
|
|
195
|
+
throw new Error('limit_exceeded: center layout has eight leaves')
|
|
196
|
+
const splitIds = assertUniqueInput(state, input.leaf, input.splitId)
|
|
197
|
+
|
|
198
|
+
const insertionIndex = targetIndex + (input.placement === 'before' ? 0 : 1)
|
|
199
|
+
leaves.splice(insertionIndex, 0, input.leaf)
|
|
200
|
+
|
|
201
|
+
const build = (start: number, end: number, vertical = false): SplitLayoutNode<L> => {
|
|
202
|
+
if (end - start === 1) return leaves[start]!
|
|
203
|
+
const middle = start + Math.ceil((end - start) / 2)
|
|
204
|
+
// The new identity belongs to the lowest branch separating the selected
|
|
205
|
+
// pane from its new neighbour. Other branches reuse the existing ID pool.
|
|
206
|
+
const id = middle === targetIndex + 1 ? input.splitId : splitIds.shift()!
|
|
207
|
+
return {
|
|
208
|
+
kind: 'split',
|
|
209
|
+
id,
|
|
210
|
+
direction: vertical ? 'column' : 'row',
|
|
211
|
+
ratio: vertical ? 0.5 : (middle - start) / (end - start),
|
|
212
|
+
children: [build(start, middle), build(middle, end)],
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const center = build(0, leaves.length, leaves.length > 2)
|
|
216
|
+
assertLayoutTree(center)
|
|
217
|
+
return { ...state, center, focusedLeafId: input.leaf.id, closed: [] }
|
|
218
|
+
}
|
|
219
|
+
|
|
166
220
|
export function closePane<L extends SplitLayoutLeaf>(
|
|
167
221
|
state: SplitLayoutState<L>,
|
|
168
222
|
leafId: string,
|
|
@@ -287,21 +341,19 @@ export function resizeSplit<L extends SplitLayoutLeaf>(
|
|
|
287
341
|
export function normalizeLayout<L extends SplitLayoutLeaf>(
|
|
288
342
|
state: SplitLayoutState<L>
|
|
289
343
|
): SplitLayoutState<L> {
|
|
290
|
-
const visit = (node: SplitLayoutNode<L>):
|
|
291
|
-
if (node.kind === 'leaf') return
|
|
344
|
+
const visit = (node: SplitLayoutNode<L>): SplitLayoutNode<L> => {
|
|
345
|
+
if (node.kind === 'leaf') return node
|
|
292
346
|
const first = visit(node.children[0])
|
|
293
347
|
const second = visit(node.children[1])
|
|
294
348
|
const ratio = Number.isFinite(node.ratio)
|
|
295
349
|
? Math.min(MAX_SPLIT_RATIO, Math.max(MIN_SPLIT_RATIO, node.ratio))
|
|
296
350
|
: (MIN_SPLIT_RATIO + MAX_SPLIT_RATIO) / 2
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
changed,
|
|
301
|
-
}
|
|
351
|
+
return first === node.children[0] && second === node.children[1] && ratio === node.ratio
|
|
352
|
+
? node
|
|
353
|
+
: { ...node, ratio, children: [first, second] }
|
|
302
354
|
}
|
|
303
|
-
const
|
|
304
|
-
return
|
|
355
|
+
const center = visit(state.center)
|
|
356
|
+
return center === state.center ? state : { ...state, center }
|
|
305
357
|
}
|
|
306
358
|
|
|
307
359
|
/** The leaf immediately after (`1`) or before (`-1`) the given leaf in reading order. */
|
|
@@ -5,9 +5,14 @@ import {
|
|
|
5
5
|
// Use the alert-specific export rather than DialogRoot.Content, which other imports can replace.
|
|
6
6
|
import type { ComponentProps } from 'solid-js'
|
|
7
7
|
import { createEffect, createSignal, splitProps } from 'solid-js'
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
overlayMotion,
|
|
10
|
+
overlayPositioner,
|
|
11
|
+
overlayScrim,
|
|
12
|
+
overlaySurface,
|
|
13
|
+
overlayTitle,
|
|
14
|
+
} from '#lib/overlay'
|
|
9
15
|
import { cn } from '#lib/utils'
|
|
10
|
-
import { headingVariants } from '../typography'
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* AlertDialog.
|
|
@@ -116,12 +121,7 @@ export function AlertDialogFooter(props: ComponentProps<'div'>) {
|
|
|
116
121
|
|
|
117
122
|
export function AlertDialogTitle(props: ComponentProps<typeof KobalteAlertDialog.Title>) {
|
|
118
123
|
const [local, rest] = splitProps(props, ['class'])
|
|
119
|
-
return (
|
|
120
|
-
<KobalteAlertDialog.Title
|
|
121
|
-
class={cn(headingVariants({ size: 'card', leading: 'none' }), local.class)}
|
|
122
|
-
{...rest}
|
|
123
|
-
/>
|
|
124
|
-
)
|
|
124
|
+
return <KobalteAlertDialog.Title class={cn(overlayTitle, local.class)} {...rest} />
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
export function AlertDialogDescription(
|
|
@@ -7,9 +7,14 @@ import {
|
|
|
7
7
|
import { X } from 'lucide-solid'
|
|
8
8
|
import type { Accessor, ComponentProps, JSX } from 'solid-js'
|
|
9
9
|
import { createRenderEffect, onCleanup, Show, splitProps } from 'solid-js'
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
overlayMotion,
|
|
12
|
+
overlayPositioner,
|
|
13
|
+
overlayScrim,
|
|
14
|
+
overlaySurface,
|
|
15
|
+
overlayTitle,
|
|
16
|
+
} from '#lib/overlay'
|
|
11
17
|
import { cn } from '#lib/utils'
|
|
12
|
-
import { headingVariants } from '../typography'
|
|
13
18
|
|
|
14
19
|
type FocusCycle = {
|
|
15
20
|
content: HTMLElement
|
|
@@ -326,12 +331,7 @@ export function DialogFooter(props: ComponentProps<'div'>) {
|
|
|
326
331
|
|
|
327
332
|
export function DialogTitle(props: ComponentProps<typeof KobalteDialog.Title>) {
|
|
328
333
|
const [local, rest] = splitProps(props, ['class'])
|
|
329
|
-
return (
|
|
330
|
-
<KobalteDialog.Title
|
|
331
|
-
class={cn(headingVariants({ size: 'card', leading: 'none' }), local.class)}
|
|
332
|
-
{...rest}
|
|
333
|
-
/>
|
|
334
|
-
)
|
|
334
|
+
return <KobalteDialog.Title class={cn(overlayTitle, local.class)} {...rest} />
|
|
335
335
|
}
|
|
336
336
|
|
|
337
337
|
export function DialogDescription(props: ComponentProps<typeof KobalteDialog.Description>) {
|
|
@@ -8,9 +8,9 @@ import { X } from 'lucide-solid'
|
|
|
8
8
|
import type { Accessor, ComponentProps, JSX } from 'solid-js'
|
|
9
9
|
import { Show, splitProps } from 'solid-js'
|
|
10
10
|
import { cva, type VariantProps } from '#lib/variants'
|
|
11
|
+
import { overlayTitle } from '#lib/overlay'
|
|
11
12
|
import { cn } from '#lib/utils'
|
|
12
13
|
import { createDialogFocusRestoration, DialogOverlay } from '../dialog/dialog'
|
|
13
|
-
import { headingVariants } from '../typography'
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Sheet.
|
|
@@ -215,12 +215,7 @@ export function SheetFooter(props: ComponentProps<'div'>) {
|
|
|
215
215
|
|
|
216
216
|
export function SheetTitle(props: ComponentProps<typeof KobalteDialog.Title>) {
|
|
217
217
|
const [local, rest] = splitProps(props, ['class'])
|
|
218
|
-
return (
|
|
219
|
-
<KobalteDialog.Title
|
|
220
|
-
class={cn(headingVariants({ size: 'card', leading: 'none' }), local.class)}
|
|
221
|
-
{...rest}
|
|
222
|
-
/>
|
|
223
|
-
)
|
|
218
|
+
return <KobalteDialog.Title class={cn(overlayTitle, local.class)} {...rest} />
|
|
224
219
|
}
|
|
225
220
|
|
|
226
221
|
export function SheetDescription(props: ComponentProps<typeof KobalteDialog.Description>) {
|
|
@@ -25,7 +25,8 @@ import { cn } from '#lib/utils'
|
|
|
25
25
|
* stack already sets the rhythm (a card or dialog header), and is the only other
|
|
26
26
|
* option.
|
|
27
27
|
*/
|
|
28
|
-
|
|
28
|
+
// cva only returns a closure. A heading-only consumer must discard Text's recipe.
|
|
29
|
+
export const headingVariants = /* @__PURE__ */ cva('font-semibold', {
|
|
29
30
|
variants: {
|
|
30
31
|
size: {
|
|
31
32
|
/** 30px. An app-level headline — a first-run or empty-app screen. Once per app. */
|
|
@@ -130,7 +131,7 @@ export function Heading<T extends ValidComponent = 'h2'>(props: HeadingProps<T>)
|
|
|
130
131
|
*
|
|
131
132
|
* Defaults: `body` renders a `p`, `code` a `code`, every other variant a `span`.
|
|
132
133
|
*/
|
|
133
|
-
export const textVariants = cva('', {
|
|
134
|
+
export const textVariants = /* @__PURE__ */ cva('', {
|
|
134
135
|
variants: {
|
|
135
136
|
variant: {
|
|
136
137
|
/** 14px / 400. Body copy and descriptions. */
|
package/src/lib/overlay.ts
CHANGED
|
@@ -14,6 +14,12 @@
|
|
|
14
14
|
export const overlaySurface =
|
|
15
15
|
'bg-popover text-popover-foreground rounded-xl border border-border shadow-lg'
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Overlay titles have one fixed typography role. Keep this small recipe shared
|
|
19
|
+
* without loading the configurable Heading component into every dialog.
|
|
20
|
+
*/
|
|
21
|
+
export const overlayTitle = 'font-semibold text-base tracking-tight leading-none'
|
|
22
|
+
|
|
17
23
|
/** The span of the portal wrapper that centres a dialog-like overlay. */
|
|
18
24
|
export const overlayPositioner = 'fixed inset-0 z-(--z-dialog) grid place-items-center p-4'
|
|
19
25
|
|