@adea-ai/ui 0.108.0 → 0.109.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 (74) hide show
  1. package/dist/NOTICE +13 -0
  2. package/dist/components/composites/update-dialog/update-dialog.js +1 -1
  3. package/dist/components/layout/contextual-sidebar/contextual-sidebar.d.ts.map +1 -1
  4. package/dist/components/layout/contextual-sidebar/contextual-sidebar.js +45 -35
  5. package/dist/components/layout/contextual-sidebar/contextual-sidebar.js.map +1 -1
  6. package/dist/components/layout/contextual-sidebar/mobile-contextual-sidebar.d.ts +12 -0
  7. package/dist/components/layout/contextual-sidebar/mobile-contextual-sidebar.d.ts.map +1 -0
  8. package/dist/components/layout/contextual-sidebar/mobile-contextual-sidebar.js +36 -0
  9. package/dist/components/layout/contextual-sidebar/mobile-contextual-sidebar.js.map +1 -0
  10. package/dist/components/ui/alert-dialog/alert-dialog.d.ts.map +1 -1
  11. package/dist/components/ui/alert-dialog/alert-dialog.js +2 -6
  12. package/dist/components/ui/alert-dialog/alert-dialog.js.map +1 -1
  13. package/dist/components/ui/annotation-surface/annotation-surface.css +27 -0
  14. package/dist/components/ui/annotation-surface/annotation-surface.d.ts +66 -0
  15. package/dist/components/ui/annotation-surface/annotation-surface.d.ts.map +1 -0
  16. package/dist/components/ui/annotation-surface/annotation-surface.js +244 -0
  17. package/dist/components/ui/annotation-surface/annotation-surface.js.map +1 -0
  18. package/dist/components/ui/annotation-surface/geometry.d.ts +10 -0
  19. package/dist/components/ui/annotation-surface/geometry.d.ts.map +1 -0
  20. package/dist/components/ui/annotation-surface/geometry.js +19 -0
  21. package/dist/components/ui/annotation-surface/geometry.js.map +1 -0
  22. package/dist/components/ui/annotation-surface/index.d.ts +4 -0
  23. package/dist/components/ui/annotation-surface/index.d.ts.map +1 -0
  24. package/dist/components/ui/annotation-surface/index.js +2 -0
  25. package/dist/components/ui/board/board.js +1 -1
  26. package/dist/components/ui/dialog/dialog.d.ts.map +1 -1
  27. package/dist/components/ui/dialog/dialog.js +2 -6
  28. package/dist/components/ui/dialog/dialog.js.map +1 -1
  29. package/dist/components/ui/item/item.d.ts +1 -1
  30. package/dist/components/ui/sheet/sheet.d.ts +1 -1
  31. package/dist/components/ui/sheet/sheet.d.ts.map +1 -1
  32. package/dist/components/ui/sheet/sheet.js +2 -5
  33. package/dist/components/ui/sheet/sheet.js.map +1 -1
  34. package/dist/components/ui/typography/typography.d.ts.map +1 -1
  35. package/dist/components/ui/typography/typography.js +2 -2
  36. package/dist/components/ui/typography/typography.js.map +1 -1
  37. package/dist/index.d.ts +1 -0
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +3 -2
  40. package/dist/lib/overlay.d.ts +5 -0
  41. package/dist/lib/overlay.d.ts.map +1 -1
  42. package/dist/lib/overlay.js +6 -1
  43. package/dist/lib/overlay.js.map +1 -1
  44. package/dist/r/alert-dialog.json +0 -1
  45. package/dist/r/annotation-surface.json +32 -0
  46. package/dist/r/contextual-sidebar.json +5 -0
  47. package/dist/r/dialog.json +0 -1
  48. package/dist/r/registry.json +37 -3
  49. package/dist/r/sheet.json +0 -1
  50. package/dist/r/src/components/layout/contextual-sidebar/contextual-sidebar.tsx +41 -16
  51. package/dist/r/src/components/layout/contextual-sidebar/mobile-contextual-sidebar.tsx +28 -0
  52. package/dist/r/src/components/ui/alert-dialog/alert-dialog.tsx +8 -8
  53. package/dist/r/src/components/ui/annotation-surface/annotation-surface.css +27 -0
  54. package/dist/r/src/components/ui/annotation-surface/annotation-surface.tsx +316 -0
  55. package/dist/r/src/components/ui/annotation-surface/geometry.ts +31 -0
  56. package/dist/r/src/components/ui/annotation-surface/index.ts +13 -0
  57. package/dist/r/src/components/ui/dialog/dialog.tsx +8 -8
  58. package/dist/r/src/components/ui/sheet/sheet.tsx +2 -7
  59. package/dist/r/src/components/ui/typography/typography.tsx +3 -2
  60. package/dist/r/src/lib/overlay.ts +6 -0
  61. package/package.json +3 -2
  62. package/registry.json +37 -3
  63. package/src/components/layout/contextual-sidebar/contextual-sidebar.tsx +41 -16
  64. package/src/components/layout/contextual-sidebar/mobile-contextual-sidebar.tsx +28 -0
  65. package/src/components/ui/alert-dialog/alert-dialog.tsx +8 -8
  66. package/src/components/ui/annotation-surface/annotation-surface.css +27 -0
  67. package/src/components/ui/annotation-surface/annotation-surface.tsx +316 -0
  68. package/src/components/ui/annotation-surface/geometry.ts +31 -0
  69. package/src/components/ui/annotation-surface/index.ts +13 -0
  70. package/src/components/ui/dialog/dialog.tsx +8 -8
  71. package/src/components/ui/sheet/sheet.tsx +2 -7
  72. package/src/components/ui/typography/typography.tsx +3 -2
  73. package/src/index.ts +1 -0
  74. package/src/lib/overlay.ts +6 -0
@@ -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 { overlayMotion, overlayPositioner, overlayScrim, overlaySurface } from '#lib/overlay'
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(
@@ -0,0 +1,27 @@
1
+ .dev-annotation-surface {
2
+ touch-action: none;
3
+ cursor: crosshair;
4
+ background-image: repeating-linear-gradient(
5
+ 45deg,
6
+ color-mix(in oklch, var(--muted) 55%, transparent) 0 calc(var(--spacing) * 2),
7
+ transparent calc(var(--spacing) * 2) calc(var(--spacing) * 4)
8
+ );
9
+ }
10
+
11
+ .dev-annotation-surface[data-tool='point'] {
12
+ cursor: cell;
13
+ }
14
+
15
+ .dev-annotation-surface[data-dragging='true'] {
16
+ cursor: grabbing;
17
+ }
18
+
19
+ .dev-annotation-surface[aria-disabled='true'] {
20
+ touch-action: auto;
21
+ cursor: default;
22
+ }
23
+
24
+ .dev-annotation-surface__region,
25
+ .dev-annotation-surface__hint {
26
+ pointer-events: none;
27
+ }
@@ -0,0 +1,316 @@
1
+ import {
2
+ createEffect,
3
+ createSignal,
4
+ createUniqueId,
5
+ onCleanup,
6
+ Show,
7
+ splitProps,
8
+ type JSX,
9
+ } from 'solid-js'
10
+ import { cn } from '#lib/utils'
11
+ import './annotation-surface.css'
12
+ import {
13
+ clampSurfaceFraction,
14
+ normalizedSurfacePoint,
15
+ type AnnotationSurfacePoint,
16
+ } from './geometry'
17
+
18
+ export type AnnotationSurfaceRegion = Readonly<{
19
+ x: number
20
+ y: number
21
+ width: number
22
+ height: number
23
+ }>
24
+
25
+ export type AnnotationSurfaceDrag = Readonly<{
26
+ start: AnnotationSurfacePoint
27
+ current: AnnotationSurfacePoint
28
+ }>
29
+
30
+ export type AnnotationSurfaceTool = 'region' | 'point'
31
+ export type AnnotationSurfaceDragPhase = 'start' | 'move' | 'end' | 'cancel' | 'keyboard'
32
+ export type AnnotationSurfacePointerEvent = PointerEvent & { currentTarget: HTMLDivElement }
33
+ export type AnnotationSurfaceKeyboardEvent = KeyboardEvent & { currentTarget: HTMLDivElement }
34
+ export type AnnotationSurfaceInputEvent =
35
+ | AnnotationSurfacePointerEvent
36
+ | AnnotationSurfaceKeyboardEvent
37
+
38
+ type SurfaceElementProps = Pick<JSX.HTMLAttributes<HTMLDivElement>, 'id' | 'aria-describedby'>
39
+
40
+ export type AnnotationSurfaceProps = SurfaceElementProps & {
41
+ /** Accessible instructions for the keyboard-operated surface. */
42
+ label: string
43
+ /** Region draws a captured drag; point reports a single placement point. */
44
+ tool: AnnotationSurfaceTool
45
+ /** Normalized 0..1 geometry supplied by the host; absent means no region. */
46
+ region?: AnnotationSurfaceRegion
47
+ /** Visible idle guidance. It is hidden while a region is present. */
48
+ hint?: JSX.Element
49
+ /** Disable new drawing while the host is busy. Defaults to true. */
50
+ interactive?: boolean
51
+ /** Changing this value cancels an in-flight drag owned by the host context. */
52
+ resetKey?: string | number
53
+ /** Receives one normalized point in point mode. */
54
+ onPoint?: (point: AnnotationSurfacePoint, event: AnnotationSurfaceInputEvent) => void
55
+ /** Receives drag phases; cancel has no drag and fires at most once per capture. */
56
+ onDragChange?: (
57
+ drag: AnnotationSurfaceDrag | undefined,
58
+ phase: AnnotationSurfaceDragPhase,
59
+ event?: AnnotationSurfaceInputEvent
60
+ ) => void
61
+ /** Domain keyboard policy stays with the host and receives the native event. */
62
+ onKeyDown?: (event: AnnotationSurfaceKeyboardEvent) => void
63
+ /** Ref to the actual focusable and pointer-capturing HTMLDivElement. */
64
+ ref?: (element: HTMLDivElement) => void
65
+ /** Layout only; appearance remains owned by the shared component. */
66
+ class?: string
67
+ }
68
+
69
+ type ActiveDrag = AnnotationSurfaceDrag & {
70
+ pointerId: number
71
+ target: HTMLDivElement
72
+ }
73
+
74
+ function pointFrom(event: PointerEvent, target: HTMLDivElement): AnnotationSurfacePoint {
75
+ const bounds = target.getBoundingClientRect()
76
+ return normalizedSurfacePoint(event.clientX, event.clientY, bounds)
77
+ }
78
+
79
+ /**
80
+ * AnnotationSurface.
81
+ *
82
+ * A keyboard-focusable, viewport-shaped drawing surface for hosts that own an
83
+ * annotation domain. It renders normalized region geometry and idle guidance,
84
+ * captures region drags, and reports normalized points without reading or
85
+ * rendering screenshot pixels. The host keeps tool policy, domain geometry,
86
+ * persistence and capture commands.
87
+ *
88
+ * This bespoke application widget is necessary because a generic button or
89
+ * slider cannot represent a two-dimensional drawing viewport. Its keyboard
90
+ * behavior is supplied by the host and forwarded as a native key event. Space
91
+ * creates a centered region or places a point at the center; Escape is left to
92
+ * the host first, which can prevent the default gesture cancellation while it
93
+ * applies its own draft and mode rules.
94
+ */
95
+ export function AnnotationSurface(props: AnnotationSurfaceProps) {
96
+ const [local] = splitProps(props, [
97
+ 'id',
98
+ 'aria-describedby',
99
+ 'label',
100
+ 'tool',
101
+ 'region',
102
+ 'hint',
103
+ 'interactive',
104
+ 'resetKey',
105
+ 'onPoint',
106
+ 'onDragChange',
107
+ 'onKeyDown',
108
+ 'ref',
109
+ 'class',
110
+ ])
111
+
112
+ const [dragging, setDragging] = createSignal(false)
113
+ const hintId = createUniqueId()
114
+ let activeDrag: ActiveDrag | undefined
115
+ let previousResetKey = local.resetKey
116
+ let previousTool = local.tool
117
+
118
+ const isInteractive = () => local.interactive ?? true
119
+
120
+ function releaseCapture(drag: ActiveDrag): void {
121
+ try {
122
+ if (drag.target.hasPointerCapture(drag.pointerId))
123
+ drag.target.releasePointerCapture(drag.pointerId)
124
+ } catch {
125
+ // The browser may release capture while a host reset or unmount is running.
126
+ }
127
+ }
128
+
129
+ function cancelDrag(event?: AnnotationSurfaceInputEvent, release = true): void {
130
+ const drag = activeDrag
131
+ if (!drag) return
132
+
133
+ activeDrag = undefined
134
+ setDragging(false)
135
+ if (release) releaseCapture(drag)
136
+ local.onDragChange?.(undefined, 'cancel', event)
137
+ }
138
+
139
+ createEffect(() => {
140
+ const resetKey = local.resetKey
141
+ const tool = local.tool
142
+ const interactive = isInteractive()
143
+ if (activeDrag && (resetKey !== previousResetKey || tool !== previousTool || !interactive)) {
144
+ cancelDrag()
145
+ }
146
+ previousResetKey = resetKey
147
+ previousTool = tool
148
+ })
149
+
150
+ onCleanup(() => cancelDrag())
151
+
152
+ function handlePointerDown(event: AnnotationSurfacePointerEvent): void {
153
+ if (!isInteractive() || !event.isPrimary || event.button !== 0) return
154
+ event.preventDefault()
155
+ event.currentTarget.focus({ preventScroll: true })
156
+ const point = pointFrom(event, event.currentTarget)
157
+ if (activeDrag) return
158
+
159
+ if (local.tool === 'point') {
160
+ local.onPoint?.(point, event)
161
+ return
162
+ }
163
+
164
+ try {
165
+ event.currentTarget.setPointerCapture(event.pointerId)
166
+ } catch {
167
+ // A drag without real pointer capture can lose its final coordinates.
168
+ return
169
+ }
170
+
171
+ const drag: ActiveDrag = {
172
+ pointerId: event.pointerId,
173
+ target: event.currentTarget,
174
+ start: point,
175
+ current: point,
176
+ }
177
+ activeDrag = drag
178
+ setDragging(true)
179
+ local.onDragChange?.({ start: point, current: point }, 'start', event)
180
+ }
181
+
182
+ function handlePointerMove(event: AnnotationSurfacePointerEvent): void {
183
+ const drag = activeDrag
184
+ if (!drag || drag.pointerId !== event.pointerId) return
185
+
186
+ const current = pointFrom(event, event.currentTarget)
187
+ activeDrag = { ...drag, current }
188
+ local.onDragChange?.({ start: drag.start, current }, 'move', event)
189
+ }
190
+
191
+ function handlePointerUp(event: AnnotationSurfacePointerEvent): void {
192
+ const drag = activeDrag
193
+ if (!drag || drag.pointerId !== event.pointerId) return
194
+
195
+ const current = pointFrom(event, event.currentTarget)
196
+ activeDrag = undefined
197
+ setDragging(false)
198
+ releaseCapture(drag)
199
+ local.onDragChange?.({ start: drag.start, current }, 'end', event)
200
+ }
201
+
202
+ function handlePointerCancel(event: AnnotationSurfacePointerEvent): void {
203
+ if (activeDrag?.pointerId === event.pointerId) cancelDrag(event)
204
+ }
205
+
206
+ function handleLostPointerCapture(event: AnnotationSurfacePointerEvent): void {
207
+ if (activeDrag?.pointerId === event.pointerId) cancelDrag(event, false)
208
+ }
209
+
210
+ function handleKeyDown(event: AnnotationSurfaceKeyboardEvent): void {
211
+ local.onKeyDown?.(event)
212
+ if (event.key === 'Escape') {
213
+ if (!event.defaultPrevented) cancelDrag()
214
+ return
215
+ }
216
+ if (
217
+ event.defaultPrevented ||
218
+ !isInteractive() ||
219
+ event.key !== ' ' ||
220
+ event.repeat ||
221
+ event.isComposing ||
222
+ event.altKey ||
223
+ event.ctrlKey ||
224
+ event.metaKey ||
225
+ activeDrag
226
+ )
227
+ return
228
+
229
+ event.preventDefault()
230
+ if (local.tool === 'point') {
231
+ local.onPoint?.({ x: 0.5, y: 0.5 }, event)
232
+ return
233
+ }
234
+
235
+ local.onDragChange?.(
236
+ {
237
+ start: { x: 0.25, y: 0.25 },
238
+ current: { x: 0.75, y: 0.75 },
239
+ },
240
+ 'keyboard',
241
+ event
242
+ )
243
+ }
244
+
245
+ const visibleRegion = (): AnnotationSurfaceRegion | undefined => {
246
+ const region = local.region
247
+ if (!region) return undefined
248
+ const x = clampSurfaceFraction(region.x)
249
+ const y = clampSurfaceFraction(region.y)
250
+ return {
251
+ x,
252
+ y,
253
+ width: Math.min(clampSurfaceFraction(region.width), 1 - x),
254
+ height: Math.min(clampSurfaceFraction(region.height), 1 - y),
255
+ }
256
+ }
257
+
258
+ const describedBy = () =>
259
+ [local['aria-describedby'], local.hint && !visibleRegion() ? hintId : undefined]
260
+ .filter(Boolean)
261
+ .join(' ') || undefined
262
+
263
+ return (
264
+ <div
265
+ id={local.id}
266
+ aria-describedby={describedBy()}
267
+ role="application"
268
+ aria-roledescription="annotation surface"
269
+ aria-label={local.label}
270
+ aria-disabled={isInteractive() ? undefined : 'true'}
271
+ tabIndex={0}
272
+ data-tool={local.tool}
273
+ data-dragging={dragging() ? 'true' : 'false'}
274
+ class={cn(
275
+ 'dev-annotation-surface relative isolate block w-full aspect-video select-none overflow-hidden rounded-md border border-border bg-muted/20 text-muted-foreground outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',
276
+ local.class
277
+ )}
278
+ ref={(element) => local.ref?.(element)}
279
+ onPointerDown={handlePointerDown}
280
+ onPointerMove={handlePointerMove}
281
+ onPointerUp={handlePointerUp}
282
+ onPointerCancel={handlePointerCancel}
283
+ onLostPointerCapture={handleLostPointerCapture}
284
+ onKeyDown={handleKeyDown}
285
+ >
286
+ <Show when={visibleRegion()}>
287
+ {(region) => (
288
+ <svg
289
+ class="dev-annotation-surface__region pointer-events-none absolute inset-0 size-full"
290
+ viewBox="0 0 10000 10000"
291
+ preserveAspectRatio="none"
292
+ aria-hidden="true"
293
+ >
294
+ <rect
295
+ class="fill-primary-subtle stroke-primary"
296
+ x={region().x * 10_000}
297
+ y={region().y * 10_000}
298
+ width={region().width * 10_000}
299
+ height={region().height * 10_000}
300
+ stroke-width="1.5"
301
+ vector-effect="non-scaling-stroke"
302
+ />
303
+ </svg>
304
+ )}
305
+ </Show>
306
+ <Show when={local.hint && !visibleRegion()}>
307
+ <span
308
+ id={hintId}
309
+ class="dev-annotation-surface__hint pointer-events-none absolute inset-0 grid place-items-center p-4 text-center text-xs text-muted-foreground"
310
+ >
311
+ {local.hint}
312
+ </span>
313
+ </Show>
314
+ </div>
315
+ )
316
+ }
@@ -0,0 +1,31 @@
1
+ export type AnnotationSurfacePoint = Readonly<{ x: number; y: number }>
2
+
3
+ type SurfaceBounds = Readonly<Pick<DOMRectReadOnly, 'left' | 'top' | 'width' | 'height'>>
4
+
5
+ function fraction(client: number, start: number, length: number): number {
6
+ if (
7
+ !Number.isFinite(client) ||
8
+ !Number.isFinite(start) ||
9
+ !Number.isFinite(length) ||
10
+ length <= 0
11
+ )
12
+ return 0
13
+
14
+ return Math.min(1, Math.max(0, (client - start) / length))
15
+ }
16
+
17
+ /** Pointer coordinates normalized to the surface; degenerate bounds resolve to the origin. */
18
+ export function normalizedSurfacePoint(
19
+ clientX: number,
20
+ clientY: number,
21
+ bounds: SurfaceBounds
22
+ ): AnnotationSurfacePoint {
23
+ return {
24
+ x: fraction(clientX, bounds.left, bounds.width),
25
+ y: fraction(clientY, bounds.top, bounds.height),
26
+ }
27
+ }
28
+
29
+ export function clampSurfaceFraction(value: number): number {
30
+ return Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : 0
31
+ }
@@ -0,0 +1,13 @@
1
+ /** Keyboard-operable normalized drawing surface; hosts retain domain geometry and actions. */
2
+ export {
3
+ AnnotationSurface,
4
+ type AnnotationSurfaceDrag,
5
+ type AnnotationSurfaceDragPhase,
6
+ type AnnotationSurfaceInputEvent,
7
+ type AnnotationSurfaceKeyboardEvent,
8
+ type AnnotationSurfacePointerEvent,
9
+ type AnnotationSurfaceProps,
10
+ type AnnotationSurfaceRegion,
11
+ type AnnotationSurfaceTool,
12
+ } from './annotation-surface'
13
+ export type { AnnotationSurfacePoint } from './geometry'
@@ -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 { overlayMotion, overlayPositioner, overlayScrim, overlaySurface } from '#lib/overlay'
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
- export const headingVariants = cva('font-semibold', {
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/index.ts CHANGED
@@ -18,6 +18,7 @@
18
18
  export * from './components/ui/accordion'
19
19
  export * from './components/ui/alert'
20
20
  export * from './components/ui/alert-dialog'
21
+ export * from './components/ui/annotation-surface'
21
22
  export * from './components/ui/aspect-ratio'
22
23
  export * from './components/ui/avatar'
23
24
  export * from './components/ui/board'
@@ -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