@adea-ai/ui 0.113.0 → 0.114.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.
@@ -42,7 +42,16 @@ export type DialogContentProps = ComponentProps<typeof KobalteDialogContent> & {
42
42
  positioner?: 'default' | 'inset';
43
43
  };
44
44
  export declare function DialogContent(props: DialogContentProps): JSX.Element;
45
- export declare function DialogHeader(props: ComponentProps<'div'>): JSX.Element;
45
+ /**
46
+ * The dialog's title block. `band` steps it onto the elevation ladder's
47
+ * subtle-fill rung (`--muted`), the same treatment as the sheet parts' band —
48
+ * for the dialog family whose panel anatomy matches a sheet's (a title band
49
+ * over a full-bleed shell, such as a settings dialog) rather than the centred
50
+ * modal's documented flat surface. See `SheetFooter` for the rung's rationale.
51
+ */
52
+ export declare function DialogHeader(props: ComponentProps<'div'> & {
53
+ band?: boolean;
54
+ }): JSX.Element;
46
55
  export declare function DialogFooter(props: ComponentProps<'div'>): JSX.Element;
47
56
  export declare function DialogTitle(props: ComponentProps<typeof KobalteDialog.Title>): JSX.Element;
48
57
  export declare function DialogDescription(props: ComponentProps<typeof KobalteDialog.Description>): JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/dialog/dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,IAAI,aAAa,EACvB,OAAO,IAAI,oBAAoB,EAC/B,OAAO,IAAI,oBAAoB,EAChC,MAAM,sBAAsB,CAAA;AAG7B,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AA+C7D,KAAK,6BAA6B,GAAG;IACnC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;IACvB,eAAe,CAAC,EAAE,QAAQ,CAAC,WAAW,GAAG,SAAS,CAAC,CAAA;IACnD,eAAe,CAAC,EAAE,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC,iBAAiB,CAAC,CAAA;IAChF,gBAAgB,CAAC,EAAE,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC,kBAAkB,CAAC,CAAA;CACnF,CAAA;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,IAAI,EACJ,eAAe,EACf,eAAe,EAAE,qBAAqB,EACtC,gBAAgB,EAAE,sBAAsB,GACzC,EAAE,6BAA6B;6BA6DE,KAAK;8BA8CJ,KAAK;EA8CvC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,eAEjE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,OAAO,CAAC,eAEhF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,MAAM,CAAC,eAE9E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,oBAAoB,CAAC,eAY/E;AAED,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,GAAG;IAC7E;;;;OAIG;IACH,WAAW,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,KAAK,CAAA;IACjC,qFAAqF;IACrF,UAAU,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;CACjC,CAAA;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,eAuCtD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eASxD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eASxD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,KAAK,CAAC,eAG5E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,WAAW,CAAC,eAKxF;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,WAAW,CAAC,eAGxF;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,WAAW,CAAC,eAGlF"}
1
+ {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/dialog/dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,IAAI,aAAa,EACvB,OAAO,IAAI,oBAAoB,EAC/B,OAAO,IAAI,oBAAoB,EAChC,MAAM,sBAAsB,CAAA;AAG7B,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AA+C7D,KAAK,6BAA6B,GAAG;IACnC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;IACvB,eAAe,CAAC,EAAE,QAAQ,CAAC,WAAW,GAAG,SAAS,CAAC,CAAA;IACnD,eAAe,CAAC,EAAE,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC,iBAAiB,CAAC,CAAA;IAChF,gBAAgB,CAAC,EAAE,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC,kBAAkB,CAAC,CAAA;CACnF,CAAA;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,IAAI,EACJ,eAAe,EACf,eAAe,EAAE,qBAAqB,EACtC,gBAAgB,EAAE,sBAAsB,GACzC,EAAE,6BAA6B;6BA6DE,KAAK;8BA8CJ,KAAK;EA8CvC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,eAEjE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,OAAO,CAAC,eAEhF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,MAAM,CAAC,eAE9E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,oBAAoB,CAAC,eAY/E;AAED,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,GAAG;IAC7E;;;;OAIG;IACH,WAAW,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,KAAK,CAAA;IACjC,qFAAqF;IACrF,UAAU,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;CACjC,CAAA;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,eAuCtD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,eAS7E;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eASxD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,KAAK,CAAC,eAG5E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,WAAW,CAAC,eAKxF;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,WAAW,CAAC,eAGxF;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,WAAW,CAAC,eAGlF"}
@@ -198,12 +198,19 @@ function DialogContent(props) {
198
198
  })()];
199
199
  } });
200
200
  }
201
+ /**
202
+ * The dialog's title block. `band` steps it onto the elevation ladder's
203
+ * subtle-fill rung (`--muted`), the same treatment as the sheet parts' band —
204
+ * for the dialog family whose panel anatomy matches a sheet's (a title band
205
+ * over a full-bleed shell, such as a settings dialog) rather than the centred
206
+ * modal's documented flat surface. See `SheetFooter` for the rung's rationale.
207
+ */
201
208
  function DialogHeader(props) {
202
- const [local, rest] = splitProps(props, ["class"]);
209
+ const [local, rest] = splitProps(props, ["class", "band"]);
203
210
  return (() => {
204
211
  var _el$2 = _tmpl$2();
205
212
  spread(_el$2, mergeProps({ get ["class"]() {
206
- return cn("flex flex-col gap-1.5 pe-6 text-start", local.class);
213
+ return cn("flex flex-col gap-1.5 pe-6 text-start", { "bg-muted": local.band }, local.class);
207
214
  } }, rest), false, false);
208
215
  return _el$2;
209
216
  })();
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.js","names":["Dialog","KobalteDialog","Content","KobalteDialogContent","Overlay","KobalteDialogOverlay","X","Accessor","ComponentProps","JSX","createRenderEffect","onCleanup","Show","splitProps","dialogSurface","overlayMotion","overlayPositioner","overlayScrim","overlayTitle","cn","Tooltip","TooltipContent","TooltipTrigger","FocusCycle","content","HTMLElement","opener","openerEligible","closed","focusMovedOutside","closeAutoFocusScheduled","frame","fallbackTimer","observer","MutationObserver","onFocusIn","event","FocusEvent","canRestoreFocus","target","isConnected","document","body","documentElement","closest","matches","getClientRects","length","hasOtherOverlay","querySelectorAll","some","overlay","contains","DialogFocusRestorationOptions","open","restoreFocusRef","onOpenAutoFocus","onCloseAutoFocus","createDialogFocusRestoration","callerOnOpenAutoFocus","callerOnCloseAutoFocus","focusCycles","WeakMap","activeFocusCycle","pendingOpener","pendingOpenerEligible","active","activeElement","finishFocusCycle","cycle","undefined","window","cancelAnimationFrame","clearTimeout","disconnect","removeEventListener","scheduleFocusRestore","requestAnimationFrame","focusIsAvailable","Node","focus","preventScroll","Event","element","currentTarget","openerWasCaptured","focusEvent","set","addEventListener","get","defaultPrevented","observe","attributes","attributeFilter","childList","subtree","queueMicrotask","setTimeout","props","_$createComponent","DialogTrigger","Trigger","DialogPortal","Portal","DialogOverlay","local","rest","_$mergeProps","class","DialogContentProps","closeButton","Element","positioner","DialogContent","children","_el$","_tmpl$","_$insert","_$memo","when","as","CloseButton","_$effect","_$className","DialogHeader","_el$2","_tmpl$2","_$spread","DialogFooter","_el$3","_tmpl$3","DialogTitle","Title","DialogDescription","Description","DialogCloseButton","DialogClose","Dialog","_$createComponent","KobalteDialog","KobalteDialogOverlay","_$mergeProps","KobalteDialogContent","_$memo","_$className"],"sources":["../../../../src/components/ui/dialog/dialog.tsx"],"sourcesContent":["import {\n Dialog as KobalteDialog,\n Content as KobalteDialogContent,\n Overlay as KobalteDialogOverlay,\n} from '@kobalte/core/dialog'\n// AlertDialog assigns to the shared DialogRoot.Content object, so these named exports stay role-stable.\nimport { X } from 'lucide-solid'\nimport type { Accessor, ComponentProps, JSX } from 'solid-js'\nimport { createRenderEffect, onCleanup, Show, splitProps } from 'solid-js'\nimport {\n dialogSurface,\n overlayMotion,\n overlayPositioner,\n overlayScrim,\n overlayTitle,\n} from '#lib/overlay'\nimport { cn } from '#lib/utils'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip'\n\ntype FocusCycle = {\n content: HTMLElement\n opener: HTMLElement | null\n openerEligible: boolean\n closed: boolean\n focusMovedOutside: boolean\n closeAutoFocusScheduled: boolean\n frame?: number\n fallbackTimer?: number\n observer?: MutationObserver\n onFocusIn: (event: FocusEvent) => void\n}\n\nfunction canRestoreFocus(target: HTMLElement): boolean {\n return (\n target.isConnected &&\n target !== document.body &&\n target !== document.documentElement &&\n !target.closest('[inert], [aria-hidden=\"true\"]') &&\n !target.matches(':disabled') &&\n target.getClientRects().length > 0\n )\n}\n\nfunction hasOtherOverlay(content: HTMLElement, opener: HTMLElement): boolean {\n return [...document.querySelectorAll<HTMLElement>('[role=\"dialog\"], [role=\"alertdialog\"]')].some(\n (overlay) =>\n overlay !== content &&\n !content.contains(overlay) &&\n !overlay.contains(opener) &&\n !overlay.closest('[aria-hidden=\"true\"], [inert]') &&\n overlay.getClientRects().length > 0\n )\n}\n\ntype DialogFocusRestorationOptions = {\n open: Accessor<boolean>\n restoreFocusRef?: Accessor<HTMLElement | undefined>\n onOpenAutoFocus?: ComponentProps<typeof KobalteDialogContent>['onOpenAutoFocus']\n onCloseAutoFocus?: ComponentProps<typeof KobalteDialogContent>['onCloseAutoFocus']\n}\n\n/**\n * Adds guarded opener capture and restoration to a Kobalte dialog content.\n * Composed surfaces use this internal helper; it is omitted from the public\n * dialog barrel so the restoration policy stays with the dialog components.\n */\nexport function createDialogFocusRestoration({\n open,\n restoreFocusRef,\n onOpenAutoFocus: callerOnOpenAutoFocus,\n onCloseAutoFocus: callerOnCloseAutoFocus,\n}: DialogFocusRestorationOptions) {\n const focusCycles = new WeakMap<HTMLElement, FocusCycle>()\n let activeFocusCycle: FocusCycle | undefined\n let pendingOpener: HTMLElement | null = null\n let pendingOpenerEligible = false\n\n createRenderEffect(() => {\n if (!open() || typeof document === 'undefined') {\n pendingOpener = null\n pendingOpenerEligible = false\n return\n }\n const active = restoreFocusRef?.() ?? document.activeElement\n pendingOpener = active instanceof HTMLElement ? active : null\n pendingOpenerEligible = active instanceof HTMLElement && canRestoreFocus(active)\n })\n\n const finishFocusCycle = (cycle: FocusCycle) => {\n if (cycle.frame !== undefined) window.cancelAnimationFrame(cycle.frame)\n if (cycle.fallbackTimer !== undefined) window.clearTimeout(cycle.fallbackTimer)\n cycle.observer?.disconnect()\n document.removeEventListener('focusin', cycle.onFocusIn)\n if (activeFocusCycle === cycle) activeFocusCycle = undefined\n }\n\n const scheduleFocusRestore = (cycle: FocusCycle) => {\n if (cycle.frame !== undefined) return\n cycle.frame = window.requestAnimationFrame(() => {\n cycle.frame = undefined\n const opener = cycle.opener\n const active = document.activeElement\n const focusIsAvailable =\n active === document.body ||\n active === document.documentElement ||\n active === cycle.content ||\n (active instanceof Node && cycle.content.contains(active))\n if (\n activeFocusCycle !== cycle ||\n !cycle.closed ||\n cycle.focusMovedOutside ||\n !opener ||\n !opener.isConnected ||\n opener.matches(':disabled') ||\n opener.getClientRects().length === 0 ||\n !focusIsAvailable ||\n hasOtherOverlay(cycle.content, opener)\n ) {\n finishFocusCycle(cycle)\n return\n }\n\n // Inert and aria-hidden are removed by the dialog's containment cleanup.\n // Wait for that cleanup before returning focus to the original control.\n if (opener.closest('[inert], [aria-hidden=\"true\"]')) return\n if (cycle.openerEligible && canRestoreFocus(opener)) {\n opener.focus({ preventScroll: true })\n }\n finishFocusCycle(cycle)\n })\n }\n\n const onOpenAutoFocus = (event: Event) => {\n const element = event.currentTarget\n if (element instanceof HTMLElement) {\n if (activeFocusCycle) finishFocusCycle(activeFocusCycle)\n\n const openerWasCaptured = pendingOpener !== null\n const opener = pendingOpener ?? document.activeElement\n const openerEligible = openerWasCaptured\n ? pendingOpenerEligible\n : opener instanceof HTMLElement && canRestoreFocus(opener)\n pendingOpener = null\n pendingOpenerEligible = false\n const cycle: FocusCycle = {\n content: element,\n opener: opener instanceof HTMLElement ? opener : null,\n openerEligible,\n closed: false,\n focusMovedOutside: false,\n closeAutoFocusScheduled: false,\n onFocusIn: (focusEvent) => {\n const target = focusEvent.target\n if (\n !(target instanceof HTMLElement) ||\n target === document.body ||\n target === document.documentElement\n ) {\n return\n }\n if (\n target === element ||\n element.contains(target) ||\n target === (opener instanceof HTMLElement ? opener : null)\n ) {\n if (!cycle.closed) cycle.focusMovedOutside = false\n return\n }\n cycle.focusMovedOutside = true\n },\n }\n focusCycles.set(element, cycle)\n activeFocusCycle = cycle\n document.addEventListener('focusin', cycle.onFocusIn)\n }\n callerOnOpenAutoFocus?.(event)\n }\n\n const onCloseAutoFocus = (event: Event) => {\n const element = event.currentTarget\n const cycle = element instanceof HTMLElement ? focusCycles.get(element) : undefined\n callerOnCloseAutoFocus?.(event)\n\n if (!cycle) return\n cycle.closed = true\n\n // A caller that prevents Kobalte's close autofocus owns the focus decision.\n if (event.defaultPrevented) {\n finishFocusCycle(cycle)\n return\n }\n\n if (cycle.fallbackTimer !== undefined) {\n window.clearTimeout(cycle.fallbackTimer)\n cycle.fallbackTimer = undefined\n }\n cycle.closeAutoFocusScheduled = true\n cycle.observer = new MutationObserver(() => scheduleFocusRestore(cycle))\n cycle.observer.observe(document.body, {\n attributes: true,\n attributeFilter: ['aria-hidden', 'inert'],\n childList: true,\n subtree: true,\n })\n scheduleFocusRestore(cycle)\n }\n\n onCleanup(() => {\n const cycle = activeFocusCycle\n if (!cycle) return\n cycle.closed = true\n\n // Kobalte dispatches unmount autofocus from a timer. This fallback only\n // releases the scoped focus listener if the content did not dispatch it.\n queueMicrotask(() => {\n if (cycle.closeAutoFocusScheduled) return\n cycle.fallbackTimer = window.setTimeout(() => {\n cycle.fallbackTimer = undefined\n if (!cycle.closeAutoFocusScheduled) finishFocusCycle(cycle)\n }, 0)\n })\n })\n\n return { onOpenAutoFocus, onCloseAutoFocus }\n}\n\n/**\n * Dialog.\n *\n * A modal surface for a decision or a short task. `Dialog.Portal` keeps the\n * panel out of the app's stacking and overflow contexts, `Dialog.Overlay`\n * dims what is behind it, and Kobalte handles the focus trap, the escape key,\n * scroll locking and returning focus to the trigger on close.\n *\n * The close button is part of the content rather than optional, because every\n * modal needs a way out that is not the keyboard. A dialog whose only exit is\n * Escape is a trap for anyone using a pointer.\n */\nexport function Dialog(props: ComponentProps<typeof KobalteDialog>) {\n return <KobalteDialog {...props} />\n}\n\nexport function DialogTrigger(props: ComponentProps<typeof KobalteDialog.Trigger>) {\n return <KobalteDialog.Trigger {...props} />\n}\n\nexport function DialogPortal(props: ComponentProps<typeof KobalteDialog.Portal>) {\n return <KobalteDialog.Portal {...props} />\n}\n\nexport function DialogOverlay(props: ComponentProps<typeof KobalteDialogOverlay>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteDialogOverlay\n class={cn(\n overlayScrim,\n 'data-expanded:animate-in data-expanded:fade-in-0 data-closed:animate-out data-closed:fade-out-0',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport type DialogContentProps = ComponentProps<typeof KobalteDialogContent> & {\n /**\n * Replaces the default close button. Pass `false` to remove it — only for a\n * dialog that cannot be dismissed (an update that must finish); anything the\n * user can escape from needs the button.\n */\n closeButton?: JSX.Element | false\n /** Use a 1rem inset as the positioner bounds for tall, viewport-filling surfaces. */\n positioner?: 'default' | 'inset'\n}\n\nexport function DialogContent(props: DialogContentProps) {\n const [local, rest] = splitProps(props, ['class', 'children', 'closeButton', 'positioner'])\n\n return (\n <KobalteDialog.Portal>\n <DialogOverlay />\n <div class={cn(overlayPositioner, local.positioner === 'inset' && 'inset-4 grid-rows-1 p-0')}>\n <KobalteDialogContent\n class={cn(\n dialogSurface,\n overlayMotion,\n 'relative grid w-full max-w-lg gap-4 p-5',\n local.class\n )}\n {...rest}\n >\n {local.children}\n <Show when={local.closeButton !== false}>\n {/* The corner close is icon-only, so it carries the shared tooltip\n treatment while its accessible name stays \"Close\". */}\n <Tooltip>\n <TooltipTrigger\n as={KobalteDialog.CloseButton}\n aria-label=\"Close\"\n class={cn(\n 'absolute top-3.5 end-3.5 rounded-md p-1 text-muted-foreground',\n 'transition-colors ease-out hover:bg-surface-hover hover:text-foreground',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle outline-none'\n )}\n >\n {local.closeButton ?? <X class=\"size-4\" />}\n </TooltipTrigger>\n <TooltipContent>Close dialog.</TooltipContent>\n </Tooltip>\n </Show>\n </KobalteDialogContent>\n </div>\n </KobalteDialog.Portal>\n )\n}\n\nexport function DialogHeader(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"dialog-header\"\n class={cn('flex flex-col gap-1.5 pe-6 text-start', local.class)}\n {...rest}\n />\n )\n}\n\nexport function DialogFooter(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"dialog-footer\"\n class={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', local.class)}\n {...rest}\n />\n )\n}\n\nexport function DialogTitle(props: ComponentProps<typeof KobalteDialog.Title>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDialog.Title class={cn(overlayTitle, local.class)} {...rest} />\n}\n\nexport function DialogDescription(props: ComponentProps<typeof KobalteDialog.Description>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteDialog.Description class={cn('text-muted-foreground text-sm', local.class)} {...rest} />\n )\n}\n\nexport function DialogCloseButton(props: ComponentProps<typeof KobalteDialog.CloseButton>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDialog.CloseButton class={cn('focus-ring', local.class)} {...rest} />\n}\n\n/**\n * The close control, unstyled and polymorphic — for a footer's text \"Cancel\" or\n * \"Close\", which is a different control from the corner icon `DialogCloseButton`\n * draws. Take it as `as={Button}` so it carries the button's variants rather than\n * a copied class string.\n */\nexport function DialogClose(props: ComponentProps<typeof KobalteDialog.CloseButton>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDialog.CloseButton class={cn('focus-ring', local.class)} {...rest} />\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"dialog.js","names":["Dialog","KobalteDialog","Content","KobalteDialogContent","Overlay","KobalteDialogOverlay","X","Accessor","ComponentProps","JSX","createRenderEffect","onCleanup","Show","splitProps","dialogSurface","overlayMotion","overlayPositioner","overlayScrim","overlayTitle","cn","Tooltip","TooltipContent","TooltipTrigger","FocusCycle","content","HTMLElement","opener","openerEligible","closed","focusMovedOutside","closeAutoFocusScheduled","frame","fallbackTimer","observer","MutationObserver","onFocusIn","event","FocusEvent","canRestoreFocus","target","isConnected","document","body","documentElement","closest","matches","getClientRects","length","hasOtherOverlay","querySelectorAll","some","overlay","contains","DialogFocusRestorationOptions","open","restoreFocusRef","onOpenAutoFocus","onCloseAutoFocus","createDialogFocusRestoration","callerOnOpenAutoFocus","callerOnCloseAutoFocus","focusCycles","WeakMap","activeFocusCycle","pendingOpener","pendingOpenerEligible","active","activeElement","finishFocusCycle","cycle","undefined","window","cancelAnimationFrame","clearTimeout","disconnect","removeEventListener","scheduleFocusRestore","requestAnimationFrame","focusIsAvailable","Node","focus","preventScroll","Event","element","currentTarget","openerWasCaptured","focusEvent","set","addEventListener","get","defaultPrevented","observe","attributes","attributeFilter","childList","subtree","queueMicrotask","setTimeout","props","_$createComponent","DialogTrigger","Trigger","DialogPortal","Portal","DialogOverlay","local","rest","_$mergeProps","class","DialogContentProps","closeButton","Element","positioner","DialogContent","children","_el$","_tmpl$","_$insert","_$memo","when","as","CloseButton","_$effect","_$className","DialogHeader","band","_el$2","_tmpl$2","_$spread","DialogFooter","_el$3","_tmpl$3","DialogTitle","Title","DialogDescription","Description","DialogCloseButton","DialogClose","Dialog","_$createComponent","KobalteDialog","KobalteDialogOverlay","_$mergeProps","KobalteDialogContent","_$memo","_$className"],"sources":["../../../../src/components/ui/dialog/dialog.tsx"],"sourcesContent":["import {\n Dialog as KobalteDialog,\n Content as KobalteDialogContent,\n Overlay as KobalteDialogOverlay,\n} from '@kobalte/core/dialog'\n// AlertDialog assigns to the shared DialogRoot.Content object, so these named exports stay role-stable.\nimport { X } from 'lucide-solid'\nimport type { Accessor, ComponentProps, JSX } from 'solid-js'\nimport { createRenderEffect, onCleanup, Show, splitProps } from 'solid-js'\nimport {\n dialogSurface,\n overlayMotion,\n overlayPositioner,\n overlayScrim,\n overlayTitle,\n} from '#lib/overlay'\nimport { cn } from '#lib/utils'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip'\n\ntype FocusCycle = {\n content: HTMLElement\n opener: HTMLElement | null\n openerEligible: boolean\n closed: boolean\n focusMovedOutside: boolean\n closeAutoFocusScheduled: boolean\n frame?: number\n fallbackTimer?: number\n observer?: MutationObserver\n onFocusIn: (event: FocusEvent) => void\n}\n\nfunction canRestoreFocus(target: HTMLElement): boolean {\n return (\n target.isConnected &&\n target !== document.body &&\n target !== document.documentElement &&\n !target.closest('[inert], [aria-hidden=\"true\"]') &&\n !target.matches(':disabled') &&\n target.getClientRects().length > 0\n )\n}\n\nfunction hasOtherOverlay(content: HTMLElement, opener: HTMLElement): boolean {\n return [...document.querySelectorAll<HTMLElement>('[role=\"dialog\"], [role=\"alertdialog\"]')].some(\n (overlay) =>\n overlay !== content &&\n !content.contains(overlay) &&\n !overlay.contains(opener) &&\n !overlay.closest('[aria-hidden=\"true\"], [inert]') &&\n overlay.getClientRects().length > 0\n )\n}\n\ntype DialogFocusRestorationOptions = {\n open: Accessor<boolean>\n restoreFocusRef?: Accessor<HTMLElement | undefined>\n onOpenAutoFocus?: ComponentProps<typeof KobalteDialogContent>['onOpenAutoFocus']\n onCloseAutoFocus?: ComponentProps<typeof KobalteDialogContent>['onCloseAutoFocus']\n}\n\n/**\n * Adds guarded opener capture and restoration to a Kobalte dialog content.\n * Composed surfaces use this internal helper; it is omitted from the public\n * dialog barrel so the restoration policy stays with the dialog components.\n */\nexport function createDialogFocusRestoration({\n open,\n restoreFocusRef,\n onOpenAutoFocus: callerOnOpenAutoFocus,\n onCloseAutoFocus: callerOnCloseAutoFocus,\n}: DialogFocusRestorationOptions) {\n const focusCycles = new WeakMap<HTMLElement, FocusCycle>()\n let activeFocusCycle: FocusCycle | undefined\n let pendingOpener: HTMLElement | null = null\n let pendingOpenerEligible = false\n\n createRenderEffect(() => {\n if (!open() || typeof document === 'undefined') {\n pendingOpener = null\n pendingOpenerEligible = false\n return\n }\n const active = restoreFocusRef?.() ?? document.activeElement\n pendingOpener = active instanceof HTMLElement ? active : null\n pendingOpenerEligible = active instanceof HTMLElement && canRestoreFocus(active)\n })\n\n const finishFocusCycle = (cycle: FocusCycle) => {\n if (cycle.frame !== undefined) window.cancelAnimationFrame(cycle.frame)\n if (cycle.fallbackTimer !== undefined) window.clearTimeout(cycle.fallbackTimer)\n cycle.observer?.disconnect()\n document.removeEventListener('focusin', cycle.onFocusIn)\n if (activeFocusCycle === cycle) activeFocusCycle = undefined\n }\n\n const scheduleFocusRestore = (cycle: FocusCycle) => {\n if (cycle.frame !== undefined) return\n cycle.frame = window.requestAnimationFrame(() => {\n cycle.frame = undefined\n const opener = cycle.opener\n const active = document.activeElement\n const focusIsAvailable =\n active === document.body ||\n active === document.documentElement ||\n active === cycle.content ||\n (active instanceof Node && cycle.content.contains(active))\n if (\n activeFocusCycle !== cycle ||\n !cycle.closed ||\n cycle.focusMovedOutside ||\n !opener ||\n !opener.isConnected ||\n opener.matches(':disabled') ||\n opener.getClientRects().length === 0 ||\n !focusIsAvailable ||\n hasOtherOverlay(cycle.content, opener)\n ) {\n finishFocusCycle(cycle)\n return\n }\n\n // Inert and aria-hidden are removed by the dialog's containment cleanup.\n // Wait for that cleanup before returning focus to the original control.\n if (opener.closest('[inert], [aria-hidden=\"true\"]')) return\n if (cycle.openerEligible && canRestoreFocus(opener)) {\n opener.focus({ preventScroll: true })\n }\n finishFocusCycle(cycle)\n })\n }\n\n const onOpenAutoFocus = (event: Event) => {\n const element = event.currentTarget\n if (element instanceof HTMLElement) {\n if (activeFocusCycle) finishFocusCycle(activeFocusCycle)\n\n const openerWasCaptured = pendingOpener !== null\n const opener = pendingOpener ?? document.activeElement\n const openerEligible = openerWasCaptured\n ? pendingOpenerEligible\n : opener instanceof HTMLElement && canRestoreFocus(opener)\n pendingOpener = null\n pendingOpenerEligible = false\n const cycle: FocusCycle = {\n content: element,\n opener: opener instanceof HTMLElement ? opener : null,\n openerEligible,\n closed: false,\n focusMovedOutside: false,\n closeAutoFocusScheduled: false,\n onFocusIn: (focusEvent) => {\n const target = focusEvent.target\n if (\n !(target instanceof HTMLElement) ||\n target === document.body ||\n target === document.documentElement\n ) {\n return\n }\n if (\n target === element ||\n element.contains(target) ||\n target === (opener instanceof HTMLElement ? opener : null)\n ) {\n if (!cycle.closed) cycle.focusMovedOutside = false\n return\n }\n cycle.focusMovedOutside = true\n },\n }\n focusCycles.set(element, cycle)\n activeFocusCycle = cycle\n document.addEventListener('focusin', cycle.onFocusIn)\n }\n callerOnOpenAutoFocus?.(event)\n }\n\n const onCloseAutoFocus = (event: Event) => {\n const element = event.currentTarget\n const cycle = element instanceof HTMLElement ? focusCycles.get(element) : undefined\n callerOnCloseAutoFocus?.(event)\n\n if (!cycle) return\n cycle.closed = true\n\n // A caller that prevents Kobalte's close autofocus owns the focus decision.\n if (event.defaultPrevented) {\n finishFocusCycle(cycle)\n return\n }\n\n if (cycle.fallbackTimer !== undefined) {\n window.clearTimeout(cycle.fallbackTimer)\n cycle.fallbackTimer = undefined\n }\n cycle.closeAutoFocusScheduled = true\n cycle.observer = new MutationObserver(() => scheduleFocusRestore(cycle))\n cycle.observer.observe(document.body, {\n attributes: true,\n attributeFilter: ['aria-hidden', 'inert'],\n childList: true,\n subtree: true,\n })\n scheduleFocusRestore(cycle)\n }\n\n onCleanup(() => {\n const cycle = activeFocusCycle\n if (!cycle) return\n cycle.closed = true\n\n // Kobalte dispatches unmount autofocus from a timer. This fallback only\n // releases the scoped focus listener if the content did not dispatch it.\n queueMicrotask(() => {\n if (cycle.closeAutoFocusScheduled) return\n cycle.fallbackTimer = window.setTimeout(() => {\n cycle.fallbackTimer = undefined\n if (!cycle.closeAutoFocusScheduled) finishFocusCycle(cycle)\n }, 0)\n })\n })\n\n return { onOpenAutoFocus, onCloseAutoFocus }\n}\n\n/**\n * Dialog.\n *\n * A modal surface for a decision or a short task. `Dialog.Portal` keeps the\n * panel out of the app's stacking and overflow contexts, `Dialog.Overlay`\n * dims what is behind it, and Kobalte handles the focus trap, the escape key,\n * scroll locking and returning focus to the trigger on close.\n *\n * The close button is part of the content rather than optional, because every\n * modal needs a way out that is not the keyboard. A dialog whose only exit is\n * Escape is a trap for anyone using a pointer.\n */\nexport function Dialog(props: ComponentProps<typeof KobalteDialog>) {\n return <KobalteDialog {...props} />\n}\n\nexport function DialogTrigger(props: ComponentProps<typeof KobalteDialog.Trigger>) {\n return <KobalteDialog.Trigger {...props} />\n}\n\nexport function DialogPortal(props: ComponentProps<typeof KobalteDialog.Portal>) {\n return <KobalteDialog.Portal {...props} />\n}\n\nexport function DialogOverlay(props: ComponentProps<typeof KobalteDialogOverlay>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteDialogOverlay\n class={cn(\n overlayScrim,\n 'data-expanded:animate-in data-expanded:fade-in-0 data-closed:animate-out data-closed:fade-out-0',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport type DialogContentProps = ComponentProps<typeof KobalteDialogContent> & {\n /**\n * Replaces the default close button. Pass `false` to remove it — only for a\n * dialog that cannot be dismissed (an update that must finish); anything the\n * user can escape from needs the button.\n */\n closeButton?: JSX.Element | false\n /** Use a 1rem inset as the positioner bounds for tall, viewport-filling surfaces. */\n positioner?: 'default' | 'inset'\n}\n\nexport function DialogContent(props: DialogContentProps) {\n const [local, rest] = splitProps(props, ['class', 'children', 'closeButton', 'positioner'])\n\n return (\n <KobalteDialog.Portal>\n <DialogOverlay />\n <div class={cn(overlayPositioner, local.positioner === 'inset' && 'inset-4 grid-rows-1 p-0')}>\n <KobalteDialogContent\n class={cn(\n dialogSurface,\n overlayMotion,\n 'relative grid w-full max-w-lg gap-4 p-5',\n local.class\n )}\n {...rest}\n >\n {local.children}\n <Show when={local.closeButton !== false}>\n {/* The corner close is icon-only, so it carries the shared tooltip\n treatment while its accessible name stays \"Close\". */}\n <Tooltip>\n <TooltipTrigger\n as={KobalteDialog.CloseButton}\n aria-label=\"Close\"\n class={cn(\n 'absolute top-3.5 end-3.5 rounded-md p-1 text-muted-foreground',\n 'transition-colors ease-out hover:bg-surface-hover hover:text-foreground',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle outline-none'\n )}\n >\n {local.closeButton ?? <X class=\"size-4\" />}\n </TooltipTrigger>\n <TooltipContent>Close dialog.</TooltipContent>\n </Tooltip>\n </Show>\n </KobalteDialogContent>\n </div>\n </KobalteDialog.Portal>\n )\n}\n\n/**\n * The dialog's title block. `band` steps it onto the elevation ladder's\n * subtle-fill rung (`--muted`), the same treatment as the sheet parts' band —\n * for the dialog family whose panel anatomy matches a sheet's (a title band\n * over a full-bleed shell, such as a settings dialog) rather than the centred\n * modal's documented flat surface. See `SheetFooter` for the rung's rationale.\n */\nexport function DialogHeader(props: ComponentProps<'div'> & { band?: boolean }) {\n const [local, rest] = splitProps(props, ['class', 'band'])\n return (\n <div\n data-slot=\"dialog-header\"\n class={cn('flex flex-col gap-1.5 pe-6 text-start', { 'bg-muted': local.band }, local.class)}\n {...rest}\n />\n )\n}\n\nexport function DialogFooter(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"dialog-footer\"\n class={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', local.class)}\n {...rest}\n />\n )\n}\n\nexport function DialogTitle(props: ComponentProps<typeof KobalteDialog.Title>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDialog.Title class={cn(overlayTitle, local.class)} {...rest} />\n}\n\nexport function DialogDescription(props: ComponentProps<typeof KobalteDialog.Description>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteDialog.Description class={cn('text-muted-foreground text-sm', local.class)} {...rest} />\n )\n}\n\nexport function DialogCloseButton(props: ComponentProps<typeof KobalteDialog.CloseButton>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDialog.CloseButton class={cn('focus-ring', local.class)} {...rest} />\n}\n\n/**\n * The close control, unstyled and polymorphic — for a footer's text \"Cancel\" or\n * \"Close\", which is a different control from the corner icon `DialogCloseButton`\n * draws. Take it as `as={Button}` so it carries the button's variants rather than\n * a copied class string.\n */\nexport function DialogClose(props: ComponentProps<typeof KobalteDialog.CloseButton>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDialog.CloseButton class={cn('focus-ring', local.class)} {...rest} />\n}\n"],"mappings":"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"}
@@ -23,8 +23,9 @@ import { type VariantProps } from '#lib/variants';
23
23
  *
24
24
  * Its parts read alike everywhere: `SheetHeader` holds a heading, a description
25
25
  * and a full-width rule beneath, with the close button in the corner;
26
- * `SheetBody` scrolls on its own; `SheetFooter` is a full-width tinted band that
27
- * holds the decision.
26
+ * `SheetBody` scrolls on its own; `SheetFooter` is a full-width band that holds
27
+ * the decision. Pass `band` to the header, the footer, or both to step those
28
+ * parts onto the ladder's subtle-fill rung (see `SheetFooter`).
28
29
  *
29
30
  * Controlled sheets opened from outside a `SheetTrigger` restore focus to the
30
31
  * element focused before opening. Pass `restoreFocusRef` when a stable external
@@ -46,9 +47,32 @@ export declare function SheetContent(props: SheetContentProps): JSX.Element;
46
47
  export declare function Sheet(props: ComponentProps<typeof KobalteDialog>): JSX.Element;
47
48
  export declare function SheetTrigger(props: ComponentProps<typeof KobalteDialog.Trigger>): JSX.Element;
48
49
  export declare function SheetCloseButton(props: ComponentProps<typeof KobalteDialog.CloseButton>): JSX.Element;
49
- export declare function SheetHeader(props: ComponentProps<'div'>): JSX.Element;
50
+ /**
51
+ * The sheet's title band: a heading, a description and the full-width rule
52
+ * beneath, with the close button in the corner. `band` steps the band onto the
53
+ * subtle-fill rung (see `SheetFooter`) — the two-toned anatomy of a sheet that
54
+ * reads as a panel beside the work rather than one flat canvas.
55
+ */
56
+ export declare function SheetHeader(props: ComponentProps<'div'> & {
57
+ band?: boolean;
58
+ }): JSX.Element;
50
59
  export declare function SheetBody(props: ComponentProps<'div'>): JSX.Element;
51
- export declare function SheetFooter(props: ComponentProps<'div'>): JSX.Element;
60
+ /**
61
+ * The sheet's decision band: a full-width, hairline-ruled strip that holds the
62
+ * actions. `band` paints it with `--muted` — the elevation ladder's
63
+ * subtle-fill rung, one step up from the panel's `--background` — so the sheet
64
+ * reads two-toned: title band and decision band on the raised rung, scrolling
65
+ * body on the panel surface. The rung already exists for cards, sidebars and
66
+ * input fills; this is the panel-shaped overlay family claiming it. Opt-in
67
+ * because the flat panel is the documented default: the centred modal
68
+ * separates with veil, hairline and shadow instead (the elevated overlay rung
69
+ * amplifies the canvas chroma, which reads as a cast across a large panel),
70
+ * and a host opts a whole sheet family in by passing the prop where it composes
71
+ * the parts — not by restyling them from the outside.
72
+ */
73
+ export declare function SheetFooter(props: ComponentProps<'div'> & {
74
+ band?: boolean;
75
+ }): JSX.Element;
52
76
  export declare function SheetTitle(props: ComponentProps<typeof KobalteDialog.Title>): JSX.Element;
53
77
  export declare function SheetDescription(props: ComponentProps<typeof KobalteDialog.Description>): JSX.Element;
54
78
  export { sheetVariants };
@@ -1 +1 @@
1
- {"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/sheet/sheet.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,IAAI,aAAa,EACvB,OAAO,IAAI,oBAAoB,EAEhC,MAAM,sBAAsB,CAAA;AAG7B,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAE7D,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAKtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,QAAA,MAAM,aAAa;;;8EAuClB,CAAA;AAQD,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,GACzE,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IACnC,WAAW,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,KAAK,CAAA;IACjC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sFAAsF;IACtF,eAAe,CAAC,EAAE,QAAQ,CAAC,WAAW,GAAG,SAAS,CAAC,CAAA;CACpD,CAAA;AAEH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,eA0DpD;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,eAEhE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,OAAO,CAAC,eAE/E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,WAAW,CAAC,eAGvF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eAYvD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eASrD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eAYvD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,KAAK,CAAC,eAG3E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,WAAW,CAAC,eAKvF;AAED,OAAO,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/sheet/sheet.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,IAAI,aAAa,EACvB,OAAO,IAAI,oBAAoB,EAEhC,MAAM,sBAAsB,CAAA;AAG7B,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAE7D,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAKtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,QAAA,MAAM,aAAa;;;8EAuClB,CAAA;AAQD,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,GACzE,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IACnC,WAAW,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,KAAK,CAAA;IACjC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sFAAsF;IACtF,eAAe,CAAC,EAAE,QAAQ,CAAC,WAAW,GAAG,SAAS,CAAC,CAAA;CACpD,CAAA;AAEH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,eA0DpD;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,eAEhE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,OAAO,CAAC,eAE/E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,WAAW,CAAC,eAGvF;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,eAa5E;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eASrD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,eAa5E;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,KAAK,CAAC,eAG3E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,aAAa,CAAC,WAAW,CAAC,eAKvF;AAED,OAAO,EAAE,aAAa,EAAE,CAAA"}
@@ -32,8 +32,9 @@ var _tmpl$3 = /*#__PURE__*/ template(`<div data-slot=sheet-footer>`);
32
32
  *
33
33
  * Its parts read alike everywhere: `SheetHeader` holds a heading, a description
34
34
  * and a full-width rule beneath, with the close button in the corner;
35
- * `SheetBody` scrolls on its own; `SheetFooter` is a full-width tinted band that
36
- * holds the decision.
35
+ * `SheetBody` scrolls on its own; `SheetFooter` is a full-width band that holds
36
+ * the decision. Pass `band` to the header, the footer, or both to step those
37
+ * parts onto the ladder's subtle-fill rung (see `SheetFooter`).
37
38
  *
38
39
  * Controlled sheets opened from outside a `SheetTrigger` restore focus to the
39
40
  * element focused before opening. Pass `restoreFocusRef` when a stable external
@@ -161,12 +162,18 @@ function SheetCloseButton(props) {
161
162
  return cn(local.class);
162
163
  } }, rest));
163
164
  }
165
+ /**
166
+ * The sheet's title band: a heading, a description and the full-width rule
167
+ * beneath, with the close button in the corner. `band` steps the band onto the
168
+ * subtle-fill rung (see `SheetFooter`) — the two-toned anatomy of a sheet that
169
+ * reads as a panel beside the work rather than one flat canvas.
170
+ */
164
171
  function SheetHeader(props) {
165
- const [local, rest] = splitProps(props, ["class"]);
172
+ const [local, rest] = splitProps(props, ["class", "band"]);
166
173
  return (() => {
167
174
  var _el$ = _tmpl$();
168
175
  spread(_el$, mergeProps({ get ["class"]() {
169
- return cn("flex shrink-0 flex-col gap-1.5 border-b border-border p-4 pe-12 text-start", local.class);
176
+ return cn("flex shrink-0 flex-col gap-1.5 border-b border-border p-4 pe-12 text-start", { "bg-muted": local.band }, local.class);
170
177
  } }, rest), false, false);
171
178
  return _el$;
172
179
  })();
@@ -181,12 +188,25 @@ function SheetBody(props) {
181
188
  return _el$2;
182
189
  })();
183
190
  }
191
+ /**
192
+ * The sheet's decision band: a full-width, hairline-ruled strip that holds the
193
+ * actions. `band` paints it with `--muted` — the elevation ladder's
194
+ * subtle-fill rung, one step up from the panel's `--background` — so the sheet
195
+ * reads two-toned: title band and decision band on the raised rung, scrolling
196
+ * body on the panel surface. The rung already exists for cards, sidebars and
197
+ * input fills; this is the panel-shaped overlay family claiming it. Opt-in
198
+ * because the flat panel is the documented default: the centred modal
199
+ * separates with veil, hairline and shadow instead (the elevated overlay rung
200
+ * amplifies the canvas chroma, which reads as a cast across a large panel),
201
+ * and a host opts a whole sheet family in by passing the prop where it composes
202
+ * the parts — not by restyling them from the outside.
203
+ */
184
204
  function SheetFooter(props) {
185
- const [local, rest] = splitProps(props, ["class"]);
205
+ const [local, rest] = splitProps(props, ["class", "band"]);
186
206
  return (() => {
187
207
  var _el$3 = _tmpl$3();
188
208
  spread(_el$3, mergeProps({ get ["class"]() {
189
- return cn("flex shrink-0 flex-wrap items-center justify-end gap-2 border-t border-border bg-background px-4 py-3", local.class);
209
+ return cn("flex shrink-0 flex-wrap items-center justify-end gap-2 border-t border-border bg-background px-4 py-3", { "bg-muted": local.band }, local.class);
190
210
  } }, rest), false, false);
191
211
  return _el$3;
192
212
  })();
@@ -1 +1 @@
1
- {"version":3,"file":"sheet.js","names":["Dialog","KobalteDialog","Content","KobalteDialogContent","useDialogContext","X","Accessor","ComponentProps","JSX","Show","splitProps","cva","VariantProps","overlayTitle","cn","createDialogFocusRestoration","DialogOverlay","sheetVariants","variants","side","top","bottom","start","end","variant","edge","inset","compoundVariants","class","defaultVariants","sheetVariantFor","SheetContentProps","closeButton","Element","closeLabel","restoreFocusRef","HTMLElement","SheetContent","props","local","rest","dialog","focusRestoration","open","isOpen","onOpenAutoFocus","onCloseAutoFocus","_$createComponent","Portal","children","when","_$mergeProps","data-variant","_$memo","CloseButton","aria-label","tabindex","Sheet","SheetTrigger","Trigger","SheetCloseButton","SheetHeader","_el$","_tmpl$","_$spread","SheetBody","_el$2","_tmpl$2","SheetFooter","_el$3","_tmpl$3","SheetTitle","Title","SheetDescription","Description","_$createComponent","KobalteDialog","KobalteDialogContent","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/sheet/sheet.tsx"],"sourcesContent":["import {\n Dialog as KobalteDialog,\n Content as KobalteDialogContent,\n useDialogContext,\n} from '@kobalte/core/dialog'\n// AlertDialog shares DialogRoot.Content; Sheet uses the stable named primitive.\nimport { X } from 'lucide-solid'\nimport type { Accessor, ComponentProps, JSX } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { cva, type VariantProps } from '#lib/variants'\nimport { overlayTitle } from '#lib/overlay'\nimport { cn } from '#lib/utils'\nimport { createDialogFocusRestoration, DialogOverlay } from '../dialog/dialog'\n\n/**\n * Sheet.\n *\n * A dialog anchored to an edge of the window rather than centred. Use it when\n * the content is a *panel beside* the work — a details inspector, a filter rail,\n * a settings flyout — so the user keeps the context it belongs to in view.\n * A centred dialog interrupts; a sheet is inspected.\n *\n * `side` decides which edge; the panel is a full-height column for `start` and\n * `end`, and a full-width row for `top` and `bottom`. The slide-in direction\n * follows from the side, so a caller never pairs them by hand.\n *\n * `variant` decides how it meets that edge. `inset` — the default for `end` —\n * docks the panel inside the main view: below the top bar, one equal gap from\n * the top bar, the end edge and the bottom, with no scrim, so the work it edits\n * stays visible and the top bar stays reachable. It is the shape for editing one\n * thing beside its context (appearance settings, a task, a record). `edge` runs\n * edge to edge over a scrim — the shape of a navigation drawer, and the default\n * for every other side.\n *\n * Its parts read alike everywhere: `SheetHeader` holds a heading, a description\n * and a full-width rule beneath, with the close button in the corner;\n * `SheetBody` scrolls on its own; `SheetFooter` is a full-width tinted band that\n * holds the decision.\n *\n * Controlled sheets opened from outside a `SheetTrigger` restore focus to the\n * element focused before opening. Pass `restoreFocusRef` when a stable external\n * opener must be used instead, such as when another layer closes before the\n * sheet opens.\n */\n// `overflow-clip`, not `overflow-hidden`: a hidden overflow can still be\n// scrolled programmatically (focus, scrollIntoView, scrollTop), which slid the\n// pinned footer out of view. Only SheetBody scrolls.\nconst sheetVariants = cva(\n 'bg-background text-foreground fixed z-(--z-dialog) flex flex-col overflow-clip border-border shadow-lg',\n {\n variants: {\n side: {\n top: 'data-expanded:slide-in-from-top data-closed:slide-out-to-top',\n bottom: 'data-expanded:slide-in-from-bottom data-closed:slide-out-to-bottom',\n start: 'data-expanded:slide-in-from-left data-closed:slide-out-to-left',\n end: 'data-expanded:slide-in-from-right data-closed:slide-out-to-right',\n },\n variant: {\n edge: '',\n inset: 'panel-dialog-inset w-lg rounded-xl border',\n },\n },\n compoundVariants: [\n {\n side: 'top',\n variant: 'edge',\n class: 'inset-x-0 top-0 h-auto max-h-[85vh] rounded-b-xl border-b',\n },\n {\n side: 'bottom',\n variant: 'edge',\n class: 'inset-x-0 bottom-0 h-auto max-h-[85vh] rounded-t-xl border-t',\n },\n {\n side: 'start',\n variant: 'edge',\n class: 'inset-y-0 start-0 h-full w-80 max-w-[85vw] rounded-e-xl border-e',\n },\n {\n side: 'end',\n variant: 'edge',\n class: 'inset-y-0 end-0 h-full w-80 max-w-[85vw] rounded-s-xl border-s',\n },\n ],\n defaultVariants: { side: 'end', variant: 'edge' },\n }\n)\n\n/** `inset` for the end edge, `edge` for every other side, unless the caller says. */\nconst sheetVariantFor = (\n side: SheetContentProps['side'],\n variant: SheetContentProps['variant']\n): 'edge' | 'inset' => variant ?? ((side ?? 'end') === 'end' ? 'inset' : 'edge')\n\nexport type SheetContentProps = ComponentProps<typeof KobalteDialogContent> &\n VariantProps<typeof sheetVariants> & {\n closeButton?: JSX.Element | false\n /** The close button's accessible name. Defaults to \"Close\". */\n closeLabel?: string\n /** Supplies the stable external element to focus when the controlled sheet closes. */\n restoreFocusRef?: Accessor<HTMLElement | undefined>\n }\n\nexport function SheetContent(props: SheetContentProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'side',\n 'variant',\n 'children',\n 'closeButton',\n 'closeLabel',\n 'restoreFocusRef',\n 'onOpenAutoFocus',\n 'onCloseAutoFocus',\n ])\n const dialog = useDialogContext()\n const focusRestoration = createDialogFocusRestoration({\n open: dialog.isOpen,\n restoreFocusRef: local.restoreFocusRef,\n onOpenAutoFocus: local.onOpenAutoFocus,\n onCloseAutoFocus: local.onCloseAutoFocus,\n })\n\n const variant = () => sheetVariantFor(local.side, local.variant)\n\n return (\n <KobalteDialog.Portal>\n {/* An inset panel is beside the work, so the work stays in view: no scrim.\n It is still modal — focus stays inside and an outside click dismisses. */}\n <Show when={variant() === 'edge'}>\n <DialogOverlay />\n </Show>\n <KobalteDialogContent\n data-variant={variant()}\n class={cn(\n sheetVariants({ side: local.side, variant: variant() }),\n 'data-expanded:animate-in data-expanded:fade-in-0 data-expanded:duration-200',\n 'data-closed:animate-out data-closed:fade-out-0 data-closed:duration-150',\n local.class\n )}\n {...rest}\n onOpenAutoFocus={focusRestoration.onOpenAutoFocus}\n onCloseAutoFocus={focusRestoration.onCloseAutoFocus}\n >\n {local.children}\n <Show when={local.closeButton !== false}>\n {/* The close action opts into the tab order explicitly. Engines that\n derive tabbability from the DOM instead of the host (Playwright's\n WebKit walks only explicit tabindex and form controls) would skip\n an implicitly-tabbable button and jump past the sheet's end. */}\n <KobalteDialog.CloseButton\n aria-label={local.closeLabel ?? 'Close'}\n tabindex=\"0\"\n class=\"absolute top-3.5 end-3.5 rounded-md p-1 text-muted-foreground transition-colors ease-out outline-none hover:bg-surface-hover hover:text-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle\"\n >\n {local.closeButton ?? <X class=\"size-4\" />}\n </KobalteDialog.CloseButton>\n </Show>\n </KobalteDialogContent>\n </KobalteDialog.Portal>\n )\n}\n\nexport function Sheet(props: ComponentProps<typeof KobalteDialog>) {\n return <KobalteDialog {...props} />\n}\n\nexport function SheetTrigger(props: ComponentProps<typeof KobalteDialog.Trigger>) {\n return <KobalteDialog.Trigger {...props} />\n}\n\nexport function SheetCloseButton(props: ComponentProps<typeof KobalteDialog.CloseButton>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDialog.CloseButton class={cn(local.class)} {...rest} />\n}\n\nexport function SheetHeader(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"sheet-header\"\n class={cn(\n 'flex shrink-0 flex-col gap-1.5 border-b border-border p-4 pe-12 text-start',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function SheetBody(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"sheet-body\"\n class={cn('min-h-0 flex-1 overflow-y-auto p-4', local.class)}\n {...rest}\n />\n )\n}\n\nexport function SheetFooter(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"sheet-footer\"\n class={cn(\n 'flex shrink-0 flex-wrap items-center justify-end gap-2 border-t border-border bg-background px-4 py-3',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function SheetTitle(props: ComponentProps<typeof KobalteDialog.Title>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDialog.Title class={cn(overlayTitle, local.class)} {...rest} />\n}\n\nexport function SheetDescription(props: ComponentProps<typeof KobalteDialog.Description>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteDialog.Description class={cn('text-muted-foreground text-sm', local.class)} {...rest} />\n )\n}\n\nexport { sheetVariants }\n"],"mappings":"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"}
1
+ {"version":3,"file":"sheet.js","names":["Dialog","KobalteDialog","Content","KobalteDialogContent","useDialogContext","X","Accessor","ComponentProps","JSX","Show","splitProps","cva","VariantProps","overlayTitle","cn","createDialogFocusRestoration","DialogOverlay","sheetVariants","variants","side","top","bottom","start","end","variant","edge","inset","compoundVariants","class","defaultVariants","sheetVariantFor","SheetContentProps","closeButton","Element","closeLabel","restoreFocusRef","HTMLElement","SheetContent","props","local","rest","dialog","focusRestoration","open","isOpen","onOpenAutoFocus","onCloseAutoFocus","_$createComponent","Portal","children","when","_$mergeProps","data-variant","_$memo","CloseButton","aria-label","tabindex","Sheet","SheetTrigger","Trigger","SheetCloseButton","SheetHeader","band","_el$","_tmpl$","_$spread","SheetBody","_el$2","_tmpl$2","SheetFooter","_el$3","_tmpl$3","SheetTitle","Title","SheetDescription","Description","_$createComponent","KobalteDialog","KobalteDialogContent","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/sheet/sheet.tsx"],"sourcesContent":["import {\n Dialog as KobalteDialog,\n Content as KobalteDialogContent,\n useDialogContext,\n} from '@kobalte/core/dialog'\n// AlertDialog shares DialogRoot.Content; Sheet uses the stable named primitive.\nimport { X } from 'lucide-solid'\nimport type { Accessor, ComponentProps, JSX } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { cva, type VariantProps } from '#lib/variants'\nimport { overlayTitle } from '#lib/overlay'\nimport { cn } from '#lib/utils'\nimport { createDialogFocusRestoration, DialogOverlay } from '../dialog/dialog'\n\n/**\n * Sheet.\n *\n * A dialog anchored to an edge of the window rather than centred. Use it when\n * the content is a *panel beside* the work — a details inspector, a filter rail,\n * a settings flyout — so the user keeps the context it belongs to in view.\n * A centred dialog interrupts; a sheet is inspected.\n *\n * `side` decides which edge; the panel is a full-height column for `start` and\n * `end`, and a full-width row for `top` and `bottom`. The slide-in direction\n * follows from the side, so a caller never pairs them by hand.\n *\n * `variant` decides how it meets that edge. `inset` — the default for `end` —\n * docks the panel inside the main view: below the top bar, one equal gap from\n * the top bar, the end edge and the bottom, with no scrim, so the work it edits\n * stays visible and the top bar stays reachable. It is the shape for editing one\n * thing beside its context (appearance settings, a task, a record). `edge` runs\n * edge to edge over a scrim — the shape of a navigation drawer, and the default\n * for every other side.\n *\n * Its parts read alike everywhere: `SheetHeader` holds a heading, a description\n * and a full-width rule beneath, with the close button in the corner;\n * `SheetBody` scrolls on its own; `SheetFooter` is a full-width band that holds\n * the decision. Pass `band` to the header, the footer, or both to step those\n * parts onto the ladder's subtle-fill rung (see `SheetFooter`).\n *\n * Controlled sheets opened from outside a `SheetTrigger` restore focus to the\n * element focused before opening. Pass `restoreFocusRef` when a stable external\n * opener must be used instead, such as when another layer closes before the\n * sheet opens.\n */\n// `overflow-clip`, not `overflow-hidden`: a hidden overflow can still be\n// scrolled programmatically (focus, scrollIntoView, scrollTop), which slid the\n// pinned footer out of view. Only SheetBody scrolls.\nconst sheetVariants = cva(\n 'bg-background text-foreground fixed z-(--z-dialog) flex flex-col overflow-clip border-border shadow-lg',\n {\n variants: {\n side: {\n top: 'data-expanded:slide-in-from-top data-closed:slide-out-to-top',\n bottom: 'data-expanded:slide-in-from-bottom data-closed:slide-out-to-bottom',\n start: 'data-expanded:slide-in-from-left data-closed:slide-out-to-left',\n end: 'data-expanded:slide-in-from-right data-closed:slide-out-to-right',\n },\n variant: {\n edge: '',\n inset: 'panel-dialog-inset w-lg rounded-xl border',\n },\n },\n compoundVariants: [\n {\n side: 'top',\n variant: 'edge',\n class: 'inset-x-0 top-0 h-auto max-h-[85vh] rounded-b-xl border-b',\n },\n {\n side: 'bottom',\n variant: 'edge',\n class: 'inset-x-0 bottom-0 h-auto max-h-[85vh] rounded-t-xl border-t',\n },\n {\n side: 'start',\n variant: 'edge',\n class: 'inset-y-0 start-0 h-full w-80 max-w-[85vw] rounded-e-xl border-e',\n },\n {\n side: 'end',\n variant: 'edge',\n class: 'inset-y-0 end-0 h-full w-80 max-w-[85vw] rounded-s-xl border-s',\n },\n ],\n defaultVariants: { side: 'end', variant: 'edge' },\n }\n)\n\n/** `inset` for the end edge, `edge` for every other side, unless the caller says. */\nconst sheetVariantFor = (\n side: SheetContentProps['side'],\n variant: SheetContentProps['variant']\n): 'edge' | 'inset' => variant ?? ((side ?? 'end') === 'end' ? 'inset' : 'edge')\n\nexport type SheetContentProps = ComponentProps<typeof KobalteDialogContent> &\n VariantProps<typeof sheetVariants> & {\n closeButton?: JSX.Element | false\n /** The close button's accessible name. Defaults to \"Close\". */\n closeLabel?: string\n /** Supplies the stable external element to focus when the controlled sheet closes. */\n restoreFocusRef?: Accessor<HTMLElement | undefined>\n }\n\nexport function SheetContent(props: SheetContentProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'side',\n 'variant',\n 'children',\n 'closeButton',\n 'closeLabel',\n 'restoreFocusRef',\n 'onOpenAutoFocus',\n 'onCloseAutoFocus',\n ])\n const dialog = useDialogContext()\n const focusRestoration = createDialogFocusRestoration({\n open: dialog.isOpen,\n restoreFocusRef: local.restoreFocusRef,\n onOpenAutoFocus: local.onOpenAutoFocus,\n onCloseAutoFocus: local.onCloseAutoFocus,\n })\n\n const variant = () => sheetVariantFor(local.side, local.variant)\n\n return (\n <KobalteDialog.Portal>\n {/* An inset panel is beside the work, so the work stays in view: no scrim.\n It is still modal — focus stays inside and an outside click dismisses. */}\n <Show when={variant() === 'edge'}>\n <DialogOverlay />\n </Show>\n <KobalteDialogContent\n data-variant={variant()}\n class={cn(\n sheetVariants({ side: local.side, variant: variant() }),\n 'data-expanded:animate-in data-expanded:fade-in-0 data-expanded:duration-200',\n 'data-closed:animate-out data-closed:fade-out-0 data-closed:duration-150',\n local.class\n )}\n {...rest}\n onOpenAutoFocus={focusRestoration.onOpenAutoFocus}\n onCloseAutoFocus={focusRestoration.onCloseAutoFocus}\n >\n {local.children}\n <Show when={local.closeButton !== false}>\n {/* The close action opts into the tab order explicitly. Engines that\n derive tabbability from the DOM instead of the host (Playwright's\n WebKit walks only explicit tabindex and form controls) would skip\n an implicitly-tabbable button and jump past the sheet's end. */}\n <KobalteDialog.CloseButton\n aria-label={local.closeLabel ?? 'Close'}\n tabindex=\"0\"\n class=\"absolute top-3.5 end-3.5 rounded-md p-1 text-muted-foreground transition-colors ease-out outline-none hover:bg-surface-hover hover:text-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle\"\n >\n {local.closeButton ?? <X class=\"size-4\" />}\n </KobalteDialog.CloseButton>\n </Show>\n </KobalteDialogContent>\n </KobalteDialog.Portal>\n )\n}\n\nexport function Sheet(props: ComponentProps<typeof KobalteDialog>) {\n return <KobalteDialog {...props} />\n}\n\nexport function SheetTrigger(props: ComponentProps<typeof KobalteDialog.Trigger>) {\n return <KobalteDialog.Trigger {...props} />\n}\n\nexport function SheetCloseButton(props: ComponentProps<typeof KobalteDialog.CloseButton>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDialog.CloseButton class={cn(local.class)} {...rest} />\n}\n\n/**\n * The sheet's title band: a heading, a description and the full-width rule\n * beneath, with the close button in the corner. `band` steps the band onto the\n * subtle-fill rung (see `SheetFooter`) — the two-toned anatomy of a sheet that\n * reads as a panel beside the work rather than one flat canvas.\n */\nexport function SheetHeader(props: ComponentProps<'div'> & { band?: boolean }) {\n const [local, rest] = splitProps(props, ['class', 'band'])\n return (\n <div\n data-slot=\"sheet-header\"\n class={cn(\n 'flex shrink-0 flex-col gap-1.5 border-b border-border p-4 pe-12 text-start',\n { 'bg-muted': local.band },\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function SheetBody(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"sheet-body\"\n class={cn('min-h-0 flex-1 overflow-y-auto p-4', local.class)}\n {...rest}\n />\n )\n}\n\n/**\n * The sheet's decision band: a full-width, hairline-ruled strip that holds the\n * actions. `band` paints it with `--muted` — the elevation ladder's\n * subtle-fill rung, one step up from the panel's `--background` — so the sheet\n * reads two-toned: title band and decision band on the raised rung, scrolling\n * body on the panel surface. The rung already exists for cards, sidebars and\n * input fills; this is the panel-shaped overlay family claiming it. Opt-in\n * because the flat panel is the documented default: the centred modal\n * separates with veil, hairline and shadow instead (the elevated overlay rung\n * amplifies the canvas chroma, which reads as a cast across a large panel),\n * and a host opts a whole sheet family in by passing the prop where it composes\n * the parts — not by restyling them from the outside.\n */\nexport function SheetFooter(props: ComponentProps<'div'> & { band?: boolean }) {\n const [local, rest] = splitProps(props, ['class', 'band'])\n return (\n <div\n data-slot=\"sheet-footer\"\n class={cn(\n 'flex shrink-0 flex-wrap items-center justify-end gap-2 border-t border-border bg-background px-4 py-3',\n { 'bg-muted': local.band },\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function SheetTitle(props: ComponentProps<typeof KobalteDialog.Title>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDialog.Title class={cn(overlayTitle, local.class)} {...rest} />\n}\n\nexport function SheetDescription(props: ComponentProps<typeof KobalteDialog.Description>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteDialog.Description class={cn('text-muted-foreground text-sm', local.class)} {...rest} />\n )\n}\n\nexport { sheetVariants }\n"],"mappings":"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"}
@@ -34,6 +34,12 @@ export type ToastOptions = {
34
34
  /** Which Toaster region to render into. */
35
35
  region?: string;
36
36
  };
37
+ /**
38
+ * The error contract, resolved: destructive tone, persistent unless the caller
39
+ * says otherwise. Exported because this decision is the part a caller depends
40
+ * on and the part testable without a browser — the card render itself needs one.
41
+ */
42
+ export declare function errorToastOptions(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): ToastOptions;
37
43
  /**
38
44
  * The toast API. `show` is the general form; the tone helpers are shorthand for
39
45
  * the four cases that come up constantly.
@@ -41,6 +47,13 @@ export type ToastOptions = {
41
47
  export declare const toast: {
42
48
  show(options: ToastOptions): number;
43
49
  success(title: string, options?: Omit<ToastOptions, "title" | "tone">): number;
50
+ /**
51
+ * A failure the user caused. Persistent by default — an error that times out
52
+ * while its reader is mid-sentence has not been reported — but `persistent`
53
+ * stays caller-owned: a failure inside a retry loop (a failed "check again",
54
+ * a background poll) passes `persistent: false` and a `duration`, because a
55
+ * dismiss-only toast there is one more thing to close by hand.
56
+ */
44
57
  error(title: string, options?: Omit<ToastOptions, "title" | "tone">): number;
45
58
  warning(title: string, options?: Omit<ToastOptions, "title" | "tone">): number;
46
59
  info(title: string, options?: Omit<ToastOptions, "title" | "tone">): number;
@@ -1 +1 @@
1
- {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/toast/toast.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,YAAY,EAA4B,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAE9F,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAInD;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,KAAK,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,CAAA;AAgB3E,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACpB,iFAAiF;IACjF,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAoDD;;;GAGG;AACH,eAAO,MAAM,KAAK;kBACF,YAAY,GAAG,MAAM;mBAKpB,MAAM,YAAY,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG,MAAM;iBAGjE,MAAM,YAAY,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG,MAAM;mBAG7D,MAAM,YAAY,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG,MAAM;gBAGlE,MAAM,YAAY,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG,MAAM;IAG3E;;;;OAIG;YACK,CAAC,WACE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,YAC9B;QACR,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC,CAAA;QACvC,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC,CAAA;KAC7C,GACA,OAAO,CAAC,CAAC,CAAC;;;CAgCd,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,YAAY,CAAC,MAAM,CAAC,GAAG;IACtE,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,CAAA;IACpE,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAyBD,iFAAiF;AACjF,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,eA4B1C;AAED,OAAO,EAAE,OAAO,EAAE,CAAA"}
1
+ {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/toast/toast.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,YAAY,EAA4B,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAE9F,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAInD;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,KAAK,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,CAAA;AAgB3E,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACpB,iFAAiF;IACjF,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAoDD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,GAC7C,YAAY,CAEd;AAED;;;GAGG;AACH,eAAO,MAAM,KAAK;kBACF,YAAY,GAAG,MAAM;mBAKpB,MAAM,YAAY,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG,MAAM;IAG9E;;;;;;OAMG;iBACU,MAAM,YAAY,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG,MAAM;mBAG7D,MAAM,YAAY,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG,MAAM;gBAGlE,MAAM,YAAY,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG,MAAM;IAG3E;;;;OAIG;YACK,CAAC,WACE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,YAC9B;QACR,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC,CAAA;QACvC,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC,CAAA;KAC7C,GACA,OAAO,CAAC,CAAC,CAAC;;;CAgCd,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,YAAY,CAAC,MAAM,CAAC,GAAG;IACtE,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,CAAA;IACpE,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAyBD,iFAAiF;AACjF,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,eA4B1C;AAED,OAAO,EAAE,OAAO,EAAE,CAAA"}
@@ -89,6 +89,19 @@ function ToastCard(props) {
89
89
  });
90
90
  }
91
91
  /**
92
+ * The error contract, resolved: destructive tone, persistent unless the caller
93
+ * says otherwise. Exported because this decision is the part a caller depends
94
+ * on and the part testable without a browser — the card render itself needs one.
95
+ */
96
+ function errorToastOptions(title, options) {
97
+ return {
98
+ ...options,
99
+ title,
100
+ tone: "destructive",
101
+ persistent: options?.persistent ?? true
102
+ };
103
+ }
104
+ /**
92
105
  * The toast API. `show` is the general form; the tone helpers are shorthand for
93
106
  * the four cases that come up constantly.
94
107
  */
@@ -103,13 +116,15 @@ var toast = {
103
116
  tone: "success"
104
117
  });
105
118
  },
119
+ /**
120
+ * A failure the user caused. Persistent by default — an error that times out
121
+ * while its reader is mid-sentence has not been reported — but `persistent`
122
+ * stays caller-owned: a failure inside a retry loop (a failed "check again",
123
+ * a background poll) passes `persistent: false` and a `duration`, because a
124
+ * dismiss-only toast there is one more thing to close by hand.
125
+ */
106
126
  error(title, options) {
107
- return toast.show({
108
- ...options,
109
- title,
110
- tone: "destructive",
111
- persistent: true
112
- });
127
+ return toast.show(errorToastOptions(title, options));
113
128
  },
114
129
  warning(title, options) {
115
130
  return toast.show({
@@ -198,6 +213,6 @@ function Toaster(props) {
198
213
  } }));
199
214
  }
200
215
  //#endregion
201
- export { Toaster, toast, toaster };
216
+ export { Toaster, errorToastOptions, toast, toaster };
202
217
 
203
218
  //# sourceMappingURL=toast.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toast.js","names":["Toast","KobalteToast","ToastComponentProps","toaster","X","ComponentProps","JSX","Show","splitProps","cn","ToastTone","toastTones","Record","default","success","warning","destructive","info","ToastOptions","title","description","tone","action","Element","persistent","duration","region","ToastCard","props","_$createComponent","toastId","priority","class","style","children","_tmpl$","_el$2","_tmpl$3","_$insert","Title","when","Description","_el$3","_tmpl$2","CloseButton","toast","show","options","_$mergeProps","Omit","error","promise","Promise","T","messages","pending","data","resolved","state","dismiss","clear","ToasterProps","Region","position","toasterPosition","toasterAlignment","Toaster","local","rest","regionId","limit","swipeDirection","pauseOnInteraction","pauseOnPageIdle","List","_$createComponent","KobalteToast","_$mergeProps"],"sources":["../../../../src/components/ui/toast/toast.tsx"],"sourcesContent":["import { Toast as KobalteToast, type ToastComponentProps, toaster } from '@kobalte/core/toast'\nimport { X } from 'lucide-solid'\nimport type { ComponentProps, JSX } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\n\n/**\n * Toast.\n *\n * A short, self-dismissing message about something that already happened.\n *\n * The rules that make toasts helpful rather than hostile are built into this\n * API rather than left to callers:\n *\n * - A toast never carries the only route to an action. Anything important\n * enough to need doing belongs in the interface, not in a message that\n * disappears. `action` exists, but it is a convenience, not a flow.\n * - Errors from user-initiated work get `priority=\"high\"` so a screen reader\n * interrupts to announce them; background progress uses the default low\n * priority so it is not read over whatever the user is doing.\n * - A toast with a way to undo is preferred to a confirmation dialog for a\n * reversible action. Undo after the fact costs the user nothing; a modal\n * before it costs everyone a click.\n *\n * `Toaster` is mounted once, near the root of the app.\n */\n\ntype ToastTone = 'default' | 'success' | 'warning' | 'destructive' | 'info'\n\n/**\n * The tone dot's colour. A custom property rather than five colour utilities\n * because the value is applied inline (the tone is data, not markup) and a\n * Tailwind colour class cannot be built from a runtime value without becoming\n * invisible to the linter.\n */\nconst toastTones: Record<ToastTone, string> = {\n default: 'var(--foreground)',\n success: 'var(--success)',\n warning: 'var(--warning)',\n destructive: 'var(--destructive)',\n info: 'var(--info)',\n}\n\nexport type ToastOptions = {\n title: string\n description?: string\n tone?: ToastTone\n /** A control rendered inside the toast, usually an Undo. */\n action?: JSX.Element\n /** Keep the toast until it is dismissed. Use for a failure the user must see. */\n persistent?: boolean\n /** Milliseconds before auto-dismiss. Overrides the region's setting. */\n duration?: number\n /** Which Toaster region to render into. */\n region?: string\n}\n\nfunction ToastCard(props: ToastComponentProps & ToastOptions) {\n const tone = () => props.tone ?? 'default'\n\n return (\n <KobalteToast\n toastId={props.toastId}\n /**\n * A user-initiated outcome is announced; a background one waits its turn.\n * A failure the user caused is worth interrupting for; a sync finishing\n * quietly is not.\n */\n priority={tone() === 'destructive' ? 'high' : 'low'}\n duration={props.duration}\n persistent={props.persistent}\n class={cn(\n 'pointer-events-auto flex w-full items-start gap-3 rounded-xl border border-border bg-popover p-3 shadow-lg',\n 'data-[opened]:animate-in data-[opened]:slide-in-from-right-full data-[opened]:fade-in-0',\n 'data-[closed]:animate-out data-[closed]:slide-out-to-right-full data-[closed]:fade-out-0',\n 'data-[swipe=move]:translate-x-(--kb-toast-swipe-move-x) data-[swipe=move]:transition-none',\n 'data-[swipe=cancel]:translate-x-0 data-[swipe=cancel]:transition-transform',\n 'data-[swipe=end]:animate-out data-[swipe=end]:slide-out-to-right-full'\n )}\n style={{ '--toast-tone': toastTones[tone()] }}\n >\n <span\n aria-hidden=\"true\"\n class=\"mt-1.5 size-1.5 shrink-0 rounded-full\"\n style={{ 'background-color': 'var(--toast-tone)' }}\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <KobalteToast.Title class=\"text-sm font-medium\">{props.title}</KobalteToast.Title>\n <Show when={props.description}>\n <KobalteToast.Description class=\"text-sm text-muted-foreground\">\n {props.description}\n </KobalteToast.Description>\n </Show>\n <Show when={props.action}>\n <div class=\"mt-1.5 flex items-center gap-2\">{props.action}</div>\n </Show>\n </div>\n <KobalteToast.CloseButton\n aria-label=\"Dismiss notification\"\n class=\"text-muted-foreground shrink-0 rounded-sm p-0.5 transition-colors ease-out outline-none hover:text-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle\"\n >\n <X class=\"size-3.5\" />\n </KobalteToast.CloseButton>\n </KobalteToast>\n )\n}\n\n/**\n * The toast API. `show` is the general form; the tone helpers are shorthand for\n * the four cases that come up constantly.\n */\nexport const toast = {\n show(options: ToastOptions): number {\n return toaster.show((props) => <ToastCard {...props} {...options} />, {\n region: options.region,\n })\n },\n success(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {\n return toast.show({ ...options, title, tone: 'success' })\n },\n error(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {\n return toast.show({ ...options, title, tone: 'destructive', persistent: true })\n },\n warning(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {\n return toast.show({ ...options, title, tone: 'warning' })\n },\n info(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {\n return toast.show({ ...options, title, tone: 'info' })\n },\n /**\n * A toast that resolves with a promise: pending, then success or failure.\n * The right shape for an operation with a visible duration, because the user\n * gets one message instead of three.\n */\n promise<T>(\n promise: Promise<T> | (() => Promise<T>),\n messages: {\n pending: string\n success: string | ((data: T) => string)\n error: string | ((error: unknown) => string)\n }\n ): Promise<T> {\n const resolved = typeof promise === 'function' ? promise() : promise\n toaster.promise(resolved, (props) => {\n const tone: ToastTone =\n props.state === 'fulfilled'\n ? 'success'\n : props.state === 'rejected'\n ? 'destructive'\n : 'default'\n const title =\n props.state === 'pending'\n ? messages.pending\n : props.state === 'fulfilled'\n ? typeof messages.success === 'function'\n ? messages.success(props.data as T)\n : messages.success\n : typeof messages.error === 'function'\n ? messages.error(props.error)\n : messages.error\n return (\n <ToastCard\n toastId={props.toastId}\n title={title}\n tone={tone}\n persistent={props.state === 'rejected'}\n />\n )\n })\n return resolved\n },\n dismiss: toaster.dismiss,\n clear: toaster.clear,\n}\n\nexport type ToasterProps = ComponentProps<typeof KobalteToast.Region> & {\n /** Where the stack sits. Defaults to the bottom-right, clear of the shell. */\n position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'\n region?: string\n}\n\n/**\n * `class` lands on the region too: the props describe the region, and the\n * region is the element a caller lays out (an inset clear of a status bar, a\n * narrower stack). The list inside it is an implementation detail.\n *\n * The corner is set on the region, not the list. The region is the `fixed`\n * element: an inset on the list inside it positions nothing, and the region falls\n * back to wherever it happens to sit in the document flow.\n */\nconst toasterPosition = {\n 'top-left': 'top-0 left-0',\n 'top-right': 'top-0 right-0',\n 'bottom-left': 'bottom-0 left-0',\n 'bottom-right': 'bottom-0 right-0',\n}\n\nconst toasterAlignment = {\n 'top-left': 'items-start',\n 'top-right': 'items-end',\n 'bottom-left': 'items-start',\n 'bottom-right': 'items-end',\n}\n\n/** Mount once, near the root. Renders the stack and owns its timing defaults. */\nexport function Toaster(props: ToasterProps) {\n const [local, rest] = splitProps(props, ['position', 'region', 'class'])\n\n return (\n <KobalteToast.Region\n regionId={local.region}\n duration={5000}\n limit={3}\n swipeDirection=\"right\"\n pauseOnInteraction\n pauseOnPageIdle\n /**\n * The toast region is a top layer: opening a dialog must not hide an\n * in-flight notification, and clicking a toast must not dismiss the\n * dialog behind it.\n */\n class={cn(\n 'pointer-events-none fixed z-(--z-toast) flex max-h-screen w-full flex-col gap-2 p-4 sm:max-w-sm',\n toasterPosition[local.position ?? 'bottom-right'],\n local.class\n )}\n {...rest}\n >\n <KobalteToast.List\n class={cn('flex flex-col gap-2', toasterAlignment[local.position ?? 'bottom-right'])}\n />\n </KobalteToast.Region>\n )\n}\n\nexport { toaster }\n"],"mappings":"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"}
1
+ {"version":3,"file":"toast.js","names":["Toast","KobalteToast","ToastComponentProps","toaster","X","ComponentProps","JSX","Show","splitProps","cn","ToastTone","toastTones","Record","default","success","warning","destructive","info","ToastOptions","title","description","tone","action","Element","persistent","duration","region","ToastCard","props","_$createComponent","toastId","priority","class","style","children","_tmpl$","_el$2","_tmpl$3","_$insert","Title","when","Description","_el$3","_tmpl$2","CloseButton","errorToastOptions","options","Omit","toast","show","_$mergeProps","error","promise","Promise","T","messages","pending","data","resolved","state","dismiss","clear","ToasterProps","Region","position","toasterPosition","toasterAlignment","Toaster","local","rest","regionId","limit","swipeDirection","pauseOnInteraction","pauseOnPageIdle","List","_$createComponent","KobalteToast","_$mergeProps"],"sources":["../../../../src/components/ui/toast/toast.tsx"],"sourcesContent":["import { Toast as KobalteToast, type ToastComponentProps, toaster } from '@kobalte/core/toast'\nimport { X } from 'lucide-solid'\nimport type { ComponentProps, JSX } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\n\n/**\n * Toast.\n *\n * A short, self-dismissing message about something that already happened.\n *\n * The rules that make toasts helpful rather than hostile are built into this\n * API rather than left to callers:\n *\n * - A toast never carries the only route to an action. Anything important\n * enough to need doing belongs in the interface, not in a message that\n * disappears. `action` exists, but it is a convenience, not a flow.\n * - Errors from user-initiated work get `priority=\"high\"` so a screen reader\n * interrupts to announce them; background progress uses the default low\n * priority so it is not read over whatever the user is doing.\n * - A toast with a way to undo is preferred to a confirmation dialog for a\n * reversible action. Undo after the fact costs the user nothing; a modal\n * before it costs everyone a click.\n *\n * `Toaster` is mounted once, near the root of the app.\n */\n\ntype ToastTone = 'default' | 'success' | 'warning' | 'destructive' | 'info'\n\n/**\n * The tone dot's colour. A custom property rather than five colour utilities\n * because the value is applied inline (the tone is data, not markup) and a\n * Tailwind colour class cannot be built from a runtime value without becoming\n * invisible to the linter.\n */\nconst toastTones: Record<ToastTone, string> = {\n default: 'var(--foreground)',\n success: 'var(--success)',\n warning: 'var(--warning)',\n destructive: 'var(--destructive)',\n info: 'var(--info)',\n}\n\nexport type ToastOptions = {\n title: string\n description?: string\n tone?: ToastTone\n /** A control rendered inside the toast, usually an Undo. */\n action?: JSX.Element\n /** Keep the toast until it is dismissed. Use for a failure the user must see. */\n persistent?: boolean\n /** Milliseconds before auto-dismiss. Overrides the region's setting. */\n duration?: number\n /** Which Toaster region to render into. */\n region?: string\n}\n\nfunction ToastCard(props: ToastComponentProps & ToastOptions) {\n const tone = () => props.tone ?? 'default'\n\n return (\n <KobalteToast\n toastId={props.toastId}\n /**\n * A user-initiated outcome is announced; a background one waits its turn.\n * A failure the user caused is worth interrupting for; a sync finishing\n * quietly is not.\n */\n priority={tone() === 'destructive' ? 'high' : 'low'}\n duration={props.duration}\n persistent={props.persistent}\n class={cn(\n 'pointer-events-auto flex w-full items-start gap-3 rounded-xl border border-border bg-popover p-3 shadow-lg',\n 'data-[opened]:animate-in data-[opened]:slide-in-from-right-full data-[opened]:fade-in-0',\n 'data-[closed]:animate-out data-[closed]:slide-out-to-right-full data-[closed]:fade-out-0',\n 'data-[swipe=move]:translate-x-(--kb-toast-swipe-move-x) data-[swipe=move]:transition-none',\n 'data-[swipe=cancel]:translate-x-0 data-[swipe=cancel]:transition-transform',\n 'data-[swipe=end]:animate-out data-[swipe=end]:slide-out-to-right-full'\n )}\n style={{ '--toast-tone': toastTones[tone()] }}\n >\n <span\n aria-hidden=\"true\"\n class=\"mt-1.5 size-1.5 shrink-0 rounded-full\"\n style={{ 'background-color': 'var(--toast-tone)' }}\n />\n <div class=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <KobalteToast.Title class=\"text-sm font-medium\">{props.title}</KobalteToast.Title>\n <Show when={props.description}>\n <KobalteToast.Description class=\"text-sm text-muted-foreground\">\n {props.description}\n </KobalteToast.Description>\n </Show>\n <Show when={props.action}>\n <div class=\"mt-1.5 flex items-center gap-2\">{props.action}</div>\n </Show>\n </div>\n <KobalteToast.CloseButton\n aria-label=\"Dismiss notification\"\n class=\"text-muted-foreground shrink-0 rounded-sm p-0.5 transition-colors ease-out outline-none hover:text-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle\"\n >\n <X class=\"size-3.5\" />\n </KobalteToast.CloseButton>\n </KobalteToast>\n )\n}\n\n/**\n * The error contract, resolved: destructive tone, persistent unless the caller\n * says otherwise. Exported because this decision is the part a caller depends\n * on and the part testable without a browser — the card render itself needs one.\n */\nexport function errorToastOptions(\n title: string,\n options?: Omit<ToastOptions, 'title' | 'tone'>\n): ToastOptions {\n return { ...options, title, tone: 'destructive', persistent: options?.persistent ?? true }\n}\n\n/**\n * The toast API. `show` is the general form; the tone helpers are shorthand for\n * the four cases that come up constantly.\n */\nexport const toast = {\n show(options: ToastOptions): number {\n return toaster.show((props) => <ToastCard {...props} {...options} />, {\n region: options.region,\n })\n },\n success(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {\n return toast.show({ ...options, title, tone: 'success' })\n },\n /**\n * A failure the user caused. Persistent by default — an error that times out\n * while its reader is mid-sentence has not been reported — but `persistent`\n * stays caller-owned: a failure inside a retry loop (a failed \"check again\",\n * a background poll) passes `persistent: false` and a `duration`, because a\n * dismiss-only toast there is one more thing to close by hand.\n */\n error(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {\n return toast.show(errorToastOptions(title, options))\n },\n warning(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {\n return toast.show({ ...options, title, tone: 'warning' })\n },\n info(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {\n return toast.show({ ...options, title, tone: 'info' })\n },\n /**\n * A toast that resolves with a promise: pending, then success or failure.\n * The right shape for an operation with a visible duration, because the user\n * gets one message instead of three.\n */\n promise<T>(\n promise: Promise<T> | (() => Promise<T>),\n messages: {\n pending: string\n success: string | ((data: T) => string)\n error: string | ((error: unknown) => string)\n }\n ): Promise<T> {\n const resolved = typeof promise === 'function' ? promise() : promise\n toaster.promise(resolved, (props) => {\n const tone: ToastTone =\n props.state === 'fulfilled'\n ? 'success'\n : props.state === 'rejected'\n ? 'destructive'\n : 'default'\n const title =\n props.state === 'pending'\n ? messages.pending\n : props.state === 'fulfilled'\n ? typeof messages.success === 'function'\n ? messages.success(props.data as T)\n : messages.success\n : typeof messages.error === 'function'\n ? messages.error(props.error)\n : messages.error\n return (\n <ToastCard\n toastId={props.toastId}\n title={title}\n tone={tone}\n persistent={props.state === 'rejected'}\n />\n )\n })\n return resolved\n },\n dismiss: toaster.dismiss,\n clear: toaster.clear,\n}\n\nexport type ToasterProps = ComponentProps<typeof KobalteToast.Region> & {\n /** Where the stack sits. Defaults to the bottom-right, clear of the shell. */\n position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'\n region?: string\n}\n\n/**\n * `class` lands on the region too: the props describe the region, and the\n * region is the element a caller lays out (an inset clear of a status bar, a\n * narrower stack). The list inside it is an implementation detail.\n *\n * The corner is set on the region, not the list. The region is the `fixed`\n * element: an inset on the list inside it positions nothing, and the region falls\n * back to wherever it happens to sit in the document flow.\n */\nconst toasterPosition = {\n 'top-left': 'top-0 left-0',\n 'top-right': 'top-0 right-0',\n 'bottom-left': 'bottom-0 left-0',\n 'bottom-right': 'bottom-0 right-0',\n}\n\nconst toasterAlignment = {\n 'top-left': 'items-start',\n 'top-right': 'items-end',\n 'bottom-left': 'items-start',\n 'bottom-right': 'items-end',\n}\n\n/** Mount once, near the root. Renders the stack and owns its timing defaults. */\nexport function Toaster(props: ToasterProps) {\n const [local, rest] = splitProps(props, ['position', 'region', 'class'])\n\n return (\n <KobalteToast.Region\n regionId={local.region}\n duration={5000}\n limit={3}\n swipeDirection=\"right\"\n pauseOnInteraction\n pauseOnPageIdle\n /**\n * The toast region is a top layer: opening a dialog must not hide an\n * in-flight notification, and clicking a toast must not dismiss the\n * dialog behind it.\n */\n class={cn(\n 'pointer-events-none fixed z-(--z-toast) flex max-h-screen w-full flex-col gap-2 p-4 sm:max-w-sm',\n toasterPosition[local.position ?? 'bottom-right'],\n local.class\n )}\n {...rest}\n >\n <KobalteToast.List\n class={cn('flex flex-col gap-2', toasterAlignment[local.position ?? 'bottom-right'])}\n />\n </KobalteToast.Region>\n )\n}\n\nexport { toaster }\n"],"mappings":"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"}
@@ -314,12 +314,19 @@ export function DialogContent(props: DialogContentProps) {
314
314
  )
315
315
  }
316
316
 
317
- export function DialogHeader(props: ComponentProps<'div'>) {
318
- const [local, rest] = splitProps(props, ['class'])
317
+ /**
318
+ * The dialog's title block. `band` steps it onto the elevation ladder's
319
+ * subtle-fill rung (`--muted`), the same treatment as the sheet parts' band —
320
+ * for the dialog family whose panel anatomy matches a sheet's (a title band
321
+ * over a full-bleed shell, such as a settings dialog) rather than the centred
322
+ * modal's documented flat surface. See `SheetFooter` for the rung's rationale.
323
+ */
324
+ export function DialogHeader(props: ComponentProps<'div'> & { band?: boolean }) {
325
+ const [local, rest] = splitProps(props, ['class', 'band'])
319
326
  return (
320
327
  <div
321
328
  data-slot="dialog-header"
322
- class={cn('flex flex-col gap-1.5 pe-6 text-start', local.class)}
329
+ class={cn('flex flex-col gap-1.5 pe-6 text-start', { 'bg-muted': local.band }, local.class)}
323
330
  {...rest}
324
331
  />
325
332
  )
@@ -34,8 +34,9 @@ import { createDialogFocusRestoration, DialogOverlay } from '../dialog/dialog'
34
34
  *
35
35
  * Its parts read alike everywhere: `SheetHeader` holds a heading, a description
36
36
  * and a full-width rule beneath, with the close button in the corner;
37
- * `SheetBody` scrolls on its own; `SheetFooter` is a full-width tinted band that
38
- * holds the decision.
37
+ * `SheetBody` scrolls on its own; `SheetFooter` is a full-width band that holds
38
+ * the decision. Pass `band` to the header, the footer, or both to step those
39
+ * parts onto the ladder's subtle-fill rung (see `SheetFooter`).
39
40
  *
40
41
  * Controlled sheets opened from outside a `SheetTrigger` restore focus to the
41
42
  * element focused before opening. Pass `restoreFocusRef` when a stable external
@@ -174,13 +175,20 @@ export function SheetCloseButton(props: ComponentProps<typeof KobalteDialog.Clos
174
175
  return <KobalteDialog.CloseButton class={cn(local.class)} {...rest} />
175
176
  }
176
177
 
177
- export function SheetHeader(props: ComponentProps<'div'>) {
178
- const [local, rest] = splitProps(props, ['class'])
178
+ /**
179
+ * The sheet's title band: a heading, a description and the full-width rule
180
+ * beneath, with the close button in the corner. `band` steps the band onto the
181
+ * subtle-fill rung (see `SheetFooter`) — the two-toned anatomy of a sheet that
182
+ * reads as a panel beside the work rather than one flat canvas.
183
+ */
184
+ export function SheetHeader(props: ComponentProps<'div'> & { band?: boolean }) {
185
+ const [local, rest] = splitProps(props, ['class', 'band'])
179
186
  return (
180
187
  <div
181
188
  data-slot="sheet-header"
182
189
  class={cn(
183
190
  'flex shrink-0 flex-col gap-1.5 border-b border-border p-4 pe-12 text-start',
191
+ { 'bg-muted': local.band },
184
192
  local.class
185
193
  )}
186
194
  {...rest}
@@ -199,13 +207,27 @@ export function SheetBody(props: ComponentProps<'div'>) {
199
207
  )
200
208
  }
201
209
 
202
- export function SheetFooter(props: ComponentProps<'div'>) {
203
- const [local, rest] = splitProps(props, ['class'])
210
+ /**
211
+ * The sheet's decision band: a full-width, hairline-ruled strip that holds the
212
+ * actions. `band` paints it with `--muted` — the elevation ladder's
213
+ * subtle-fill rung, one step up from the panel's `--background` — so the sheet
214
+ * reads two-toned: title band and decision band on the raised rung, scrolling
215
+ * body on the panel surface. The rung already exists for cards, sidebars and
216
+ * input fills; this is the panel-shaped overlay family claiming it. Opt-in
217
+ * because the flat panel is the documented default: the centred modal
218
+ * separates with veil, hairline and shadow instead (the elevated overlay rung
219
+ * amplifies the canvas chroma, which reads as a cast across a large panel),
220
+ * and a host opts a whole sheet family in by passing the prop where it composes
221
+ * the parts — not by restyling them from the outside.
222
+ */
223
+ export function SheetFooter(props: ComponentProps<'div'> & { band?: boolean }) {
224
+ const [local, rest] = splitProps(props, ['class', 'band'])
204
225
  return (
205
226
  <div
206
227
  data-slot="sheet-footer"
207
228
  class={cn(
208
229
  'flex shrink-0 flex-wrap items-center justify-end gap-2 border-t border-border bg-background px-4 py-3',
230
+ { 'bg-muted': local.band },
209
231
  local.class
210
232
  )}
211
233
  {...rest}
@@ -105,6 +105,18 @@ function ToastCard(props: ToastComponentProps & ToastOptions) {
105
105
  )
106
106
  }
107
107
 
108
+ /**
109
+ * The error contract, resolved: destructive tone, persistent unless the caller
110
+ * says otherwise. Exported because this decision is the part a caller depends
111
+ * on and the part testable without a browser — the card render itself needs one.
112
+ */
113
+ export function errorToastOptions(
114
+ title: string,
115
+ options?: Omit<ToastOptions, 'title' | 'tone'>
116
+ ): ToastOptions {
117
+ return { ...options, title, tone: 'destructive', persistent: options?.persistent ?? true }
118
+ }
119
+
108
120
  /**
109
121
  * The toast API. `show` is the general form; the tone helpers are shorthand for
110
122
  * the four cases that come up constantly.
@@ -118,8 +130,15 @@ export const toast = {
118
130
  success(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {
119
131
  return toast.show({ ...options, title, tone: 'success' })
120
132
  },
133
+ /**
134
+ * A failure the user caused. Persistent by default — an error that times out
135
+ * while its reader is mid-sentence has not been reported — but `persistent`
136
+ * stays caller-owned: a failure inside a retry loop (a failed "check again",
137
+ * a background poll) passes `persistent: false` and a `duration`, because a
138
+ * dismiss-only toast there is one more thing to close by hand.
139
+ */
121
140
  error(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {
122
- return toast.show({ ...options, title, tone: 'destructive', persistent: true })
141
+ return toast.show(errorToastOptions(title, options))
123
142
  },
124
143
  warning(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {
125
144
  return toast.show({ ...options, title, tone: 'warning' })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.113.0",
3
+ "version": "0.114.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",
@@ -314,12 +314,19 @@ export function DialogContent(props: DialogContentProps) {
314
314
  )
315
315
  }
316
316
 
317
- export function DialogHeader(props: ComponentProps<'div'>) {
318
- const [local, rest] = splitProps(props, ['class'])
317
+ /**
318
+ * The dialog's title block. `band` steps it onto the elevation ladder's
319
+ * subtle-fill rung (`--muted`), the same treatment as the sheet parts' band —
320
+ * for the dialog family whose panel anatomy matches a sheet's (a title band
321
+ * over a full-bleed shell, such as a settings dialog) rather than the centred
322
+ * modal's documented flat surface. See `SheetFooter` for the rung's rationale.
323
+ */
324
+ export function DialogHeader(props: ComponentProps<'div'> & { band?: boolean }) {
325
+ const [local, rest] = splitProps(props, ['class', 'band'])
319
326
  return (
320
327
  <div
321
328
  data-slot="dialog-header"
322
- class={cn('flex flex-col gap-1.5 pe-6 text-start', local.class)}
329
+ class={cn('flex flex-col gap-1.5 pe-6 text-start', { 'bg-muted': local.band }, local.class)}
323
330
  {...rest}
324
331
  />
325
332
  )
@@ -34,8 +34,9 @@ import { createDialogFocusRestoration, DialogOverlay } from '../dialog/dialog'
34
34
  *
35
35
  * Its parts read alike everywhere: `SheetHeader` holds a heading, a description
36
36
  * and a full-width rule beneath, with the close button in the corner;
37
- * `SheetBody` scrolls on its own; `SheetFooter` is a full-width tinted band that
38
- * holds the decision.
37
+ * `SheetBody` scrolls on its own; `SheetFooter` is a full-width band that holds
38
+ * the decision. Pass `band` to the header, the footer, or both to step those
39
+ * parts onto the ladder's subtle-fill rung (see `SheetFooter`).
39
40
  *
40
41
  * Controlled sheets opened from outside a `SheetTrigger` restore focus to the
41
42
  * element focused before opening. Pass `restoreFocusRef` when a stable external
@@ -174,13 +175,20 @@ export function SheetCloseButton(props: ComponentProps<typeof KobalteDialog.Clos
174
175
  return <KobalteDialog.CloseButton class={cn(local.class)} {...rest} />
175
176
  }
176
177
 
177
- export function SheetHeader(props: ComponentProps<'div'>) {
178
- const [local, rest] = splitProps(props, ['class'])
178
+ /**
179
+ * The sheet's title band: a heading, a description and the full-width rule
180
+ * beneath, with the close button in the corner. `band` steps the band onto the
181
+ * subtle-fill rung (see `SheetFooter`) — the two-toned anatomy of a sheet that
182
+ * reads as a panel beside the work rather than one flat canvas.
183
+ */
184
+ export function SheetHeader(props: ComponentProps<'div'> & { band?: boolean }) {
185
+ const [local, rest] = splitProps(props, ['class', 'band'])
179
186
  return (
180
187
  <div
181
188
  data-slot="sheet-header"
182
189
  class={cn(
183
190
  'flex shrink-0 flex-col gap-1.5 border-b border-border p-4 pe-12 text-start',
191
+ { 'bg-muted': local.band },
184
192
  local.class
185
193
  )}
186
194
  {...rest}
@@ -199,13 +207,27 @@ export function SheetBody(props: ComponentProps<'div'>) {
199
207
  )
200
208
  }
201
209
 
202
- export function SheetFooter(props: ComponentProps<'div'>) {
203
- const [local, rest] = splitProps(props, ['class'])
210
+ /**
211
+ * The sheet's decision band: a full-width, hairline-ruled strip that holds the
212
+ * actions. `band` paints it with `--muted` — the elevation ladder's
213
+ * subtle-fill rung, one step up from the panel's `--background` — so the sheet
214
+ * reads two-toned: title band and decision band on the raised rung, scrolling
215
+ * body on the panel surface. The rung already exists for cards, sidebars and
216
+ * input fills; this is the panel-shaped overlay family claiming it. Opt-in
217
+ * because the flat panel is the documented default: the centred modal
218
+ * separates with veil, hairline and shadow instead (the elevated overlay rung
219
+ * amplifies the canvas chroma, which reads as a cast across a large panel),
220
+ * and a host opts a whole sheet family in by passing the prop where it composes
221
+ * the parts — not by restyling them from the outside.
222
+ */
223
+ export function SheetFooter(props: ComponentProps<'div'> & { band?: boolean }) {
224
+ const [local, rest] = splitProps(props, ['class', 'band'])
204
225
  return (
205
226
  <div
206
227
  data-slot="sheet-footer"
207
228
  class={cn(
208
229
  'flex shrink-0 flex-wrap items-center justify-end gap-2 border-t border-border bg-background px-4 py-3',
230
+ { 'bg-muted': local.band },
209
231
  local.class
210
232
  )}
211
233
  {...rest}
@@ -105,6 +105,18 @@ function ToastCard(props: ToastComponentProps & ToastOptions) {
105
105
  )
106
106
  }
107
107
 
108
+ /**
109
+ * The error contract, resolved: destructive tone, persistent unless the caller
110
+ * says otherwise. Exported because this decision is the part a caller depends
111
+ * on and the part testable without a browser — the card render itself needs one.
112
+ */
113
+ export function errorToastOptions(
114
+ title: string,
115
+ options?: Omit<ToastOptions, 'title' | 'tone'>
116
+ ): ToastOptions {
117
+ return { ...options, title, tone: 'destructive', persistent: options?.persistent ?? true }
118
+ }
119
+
108
120
  /**
109
121
  * The toast API. `show` is the general form; the tone helpers are shorthand for
110
122
  * the four cases that come up constantly.
@@ -118,8 +130,15 @@ export const toast = {
118
130
  success(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {
119
131
  return toast.show({ ...options, title, tone: 'success' })
120
132
  },
133
+ /**
134
+ * A failure the user caused. Persistent by default — an error that times out
135
+ * while its reader is mid-sentence has not been reported — but `persistent`
136
+ * stays caller-owned: a failure inside a retry loop (a failed "check again",
137
+ * a background poll) passes `persistent: false` and a `duration`, because a
138
+ * dismiss-only toast there is one more thing to close by hand.
139
+ */
121
140
  error(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {
122
- return toast.show({ ...options, title, tone: 'destructive', persistent: true })
141
+ return toast.show(errorToastOptions(title, options))
123
142
  },
124
143
  warning(title: string, options?: Omit<ToastOptions, 'title' | 'tone'>): number {
125
144
  return toast.show({ ...options, title, tone: 'warning' })