@adea-ai/ui 0.70.0 → 0.70.2

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.
@@ -14,21 +14,30 @@ import { DialogContent } from '../dialog/dialog';
14
14
  * tab order and the accessibility tree without depending on that bookkeeping, and
15
15
  * it restores exactly the elements that did not already have it — so a nested
16
16
  * dialog does not un-inert its parent.
17
- * 3. **It labels itself explicitly.** The title registers its id for
18
- * `aria-labelledby` in a mount effect; if that registration is ever lost, the
19
- * dialog renders with a heading and no name. Passing the label as well costs
20
- * nothing and removes the race.
17
+ * 3. **It sets an explicit accessible name.** The content receives `aria-label`
18
+ * from `title`, so its name does not depend on the title id registration effect.
19
+ * Pass `aria-label` to use a different name while keeping the visible title;
20
+ * pass `aria-labelledby` when another visible label should take precedence.
21
21
  *
22
22
  * Use `Dialog` directly when you need its composition; use this when you want a
23
23
  * dialog that is correct by default.
24
24
  */
25
- export type ModalDialogProps = Omit<ComponentProps<typeof DialogContent>, 'children'> & {
25
+ export type ModalDialogProps = Omit<ComponentProps<typeof DialogContent>, 'children' | 'aria-label' | 'aria-labelledby'> & {
26
26
  open: boolean;
27
27
  onClose: () => void;
28
28
  title: string;
29
+ /**
30
+ * Controls Kobalte's focus, scroll and accessibility modality. Defaults to `true`;
31
+ * background body children remain inert in either mode.
32
+ */
33
+ modal?: boolean;
29
34
  description?: string;
30
35
  /** A mark or icon drawn before the title. */
31
36
  headerLeading?: JSX.Element;
37
+ /** Replaces `title` as the accessible name while keeping the visible title. */
38
+ 'aria-label'?: string;
39
+ /** Names the dialog from a visible element; ARIA gives it precedence over `aria-label`. */
40
+ 'aria-labelledby'?: string;
32
41
  children?: JSX.Element;
33
42
  };
34
43
  export declare function ModalDialog(props: ModalDialogProps): JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"modal-dialog.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/modal-dialog/modal-dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAGnD,OAAO,EAEL,aAAa,EAId,MAAM,kBAAkB,CAAA;AAEzB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,aAAa,CAAC,EAAE,UAAU,CAAC,GAAG;IACtF,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IAC3B,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CACvB,CAAA;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,eAmDlD"}
1
+ {"version":3,"file":"modal-dialog.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/modal-dialog/modal-dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAGnD,OAAO,EAEL,aAAa,EAId,MAAM,kBAAkB,CAAA;AAEzB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,cAAc,CAAC,OAAO,aAAa,CAAC,EACpC,UAAU,GAAG,YAAY,GAAG,iBAAiB,CAC9C,GAAG;IACF,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,2FAA2F;IAC3F,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CACvB,CAAA;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,eA8DlD"}
@@ -8,10 +8,13 @@ function ModalDialog(props) {
8
8
  "open",
9
9
  "onClose",
10
10
  "title",
11
+ "modal",
11
12
  "description",
12
13
  "headerLeading",
13
14
  "class",
14
- "children"
15
+ "children",
16
+ "aria-label",
17
+ "aria-labelledby"
15
18
  ]);
16
19
  const [content, setContent] = createSignal();
17
20
  createEffect(() => {
@@ -34,12 +37,21 @@ function ModalDialog(props) {
34
37
  get children() {
35
38
  return createComponent(Dialog, {
36
39
  open: true,
40
+ get modal() {
41
+ return local.modal ?? true;
42
+ },
37
43
  onOpenChange: (next) => !next && local.onClose(),
38
44
  get children() {
39
45
  return createComponent(DialogContent, mergeProps({
40
46
  ref: setContent,
41
47
  get ["class"]() {
42
48
  return cn("gap-4", local.class);
49
+ },
50
+ get ["aria-label"]() {
51
+ return local["aria-label"] ?? local.title;
52
+ },
53
+ get ["aria-labelledby"]() {
54
+ return local["aria-labelledby"] ?? (local["aria-label"] !== void 0 ? "" : void 0);
43
55
  }
44
56
  }, rest, { get children() {
45
57
  return [createComponent(DialogHeader, { get children() {
@@ -1 +1 @@
1
- {"version":3,"file":"modal-dialog.js","names":["ComponentProps","JSX","Show","createEffect","createSignal","onCleanup","splitProps","cn","Dialog","DialogContent","DialogDescription","DialogHeader","DialogTitle","ModalDialogProps","Omit","open","onClose","title","description","headerLeading","Element","children","ModalDialog","props","local","rest","content","setContent","HTMLElement","element","background","document","body","filter","child","contains","wasInert","map","node","hasAttribute","setAttribute","forEach","index","removeAttribute","_$createComponent","when","onOpenChange","next","_$mergeProps","ref","class","_$memo","_$createComponent","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/modal-dialog/modal-dialog.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'solid-js'\nimport { Show, createEffect, createSignal, onCleanup, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '../dialog/dialog'\n\n/**\n * ModalDialog.\n *\n * A dialog that owns three things `Dialog` leaves to its caller, each of which is a\n * real defect when it is missed:\n *\n * 1. **It unmounts while closed.** An always-mounted dialog that closes as a side\n * effect of an async action can leave Kobalte's `aria-hidden` bookkeeping behind,\n * which hides the rest of the application from assistive technology. Unmounting\n * the whole owner makes cleanup the only way the layer can end.\n * 2. **It marks the background `inert`.** `inert` keeps the background out of the\n * tab order and the accessibility tree without depending on that bookkeeping, and\n * it restores exactly the elements that did not already have it — so a nested\n * dialog does not un-inert its parent.\n * 3. **It labels itself explicitly.** The title registers its id for\n * `aria-labelledby` in a mount effect; if that registration is ever lost, the\n * dialog renders with a heading and no name. Passing the label as well costs\n * nothing and removes the race.\n *\n * Use `Dialog` directly when you need its composition; use this when you want a\n * dialog that is correct by default.\n */\nexport type ModalDialogProps = Omit<ComponentProps<typeof DialogContent>, 'children'> & {\n open: boolean\n onClose: () => void\n title: string\n description?: string\n /** A mark or icon drawn before the title. */\n headerLeading?: JSX.Element\n children?: JSX.Element\n}\n\nexport function ModalDialog(props: ModalDialogProps) {\n const [local, rest] = splitProps(props, [\n 'open',\n 'onClose',\n 'title',\n 'description',\n 'headerLeading',\n 'class',\n 'children',\n ])\n\n const [content, setContent] = createSignal<HTMLElement>()\n\n createEffect(() => {\n if (!local.open) return\n const element = content()\n if (!element) return\n\n const background = [...document.body.children].filter(\n (child): child is HTMLElement => child instanceof HTMLElement && !child.contains(element)\n )\n const wasInert = background.map((node) => node.hasAttribute('inert'))\n for (const node of background) node.setAttribute('inert', '')\n\n onCleanup(() => {\n background.forEach((node, index) => {\n // Only the elements that were not already inert are restored, so a nested\n // dialog closing does not undo its parent's containment.\n if (!wasInert[index]) node.removeAttribute('inert')\n })\n })\n })\n\n return (\n <Show when={local.open}>\n <Dialog open onOpenChange={(next) => !next && local.onClose()}>\n <DialogContent ref={setContent} class={cn('gap-4', local.class)} {...rest}>\n <DialogHeader>\n <DialogTitle class=\"flex items-center gap-2\">\n <Show when={local.headerLeading}>{local.headerLeading}</Show>\n {local.title}\n </DialogTitle>\n <Show when={local.description}>\n <DialogDescription>{local.description}</DialogDescription>\n </Show>\n </DialogHeader>\n {local.children}\n </DialogContent>\n </Dialog>\n </Show>\n )\n}\n"],"mappings":";;;;;AA2CA,SAAgBsB,YAAYC,OAAyB;CACnD,MAAM,CAACC,OAAOC,QAAQnB,WAAWiB,OAAO;EACtC;EACA;EACA;EACA;EACA;EACA;EACA;CAAU,CACX;CAED,MAAM,CAACG,SAASC,cAAcvB,aAA0B;CAExDD,mBAAmB;EACjB,IAAI,CAACqB,MAAMT,MAAM;EACjB,MAAMc,UAAUH,QAAQ;EACxB,IAAI,CAACG,SAAS;EAEd,MAAMC,aAAa,CAAC,GAAGC,SAASC,KAAKX,QAAQ,CAAC,CAACY,QAC5CC,UAAgCA,iBAAiBN,eAAe,CAACM,MAAMC,SAASN,OAAO,CAC1F;EACA,MAAMO,WAAWN,WAAWO,KAAKC,SAASA,KAAKC,aAAa,OAAO,CAAC;EACpE,KAAK,MAAMD,QAAQR,YAAYQ,KAAKE,aAAa,SAAS,EAAE;EAE5DnC,gBAAgB;GACdyB,WAAWW,SAASH,MAAMI,UAAU;IAGlC,IAAI,CAACN,SAASM,QAAQJ,KAAKK,gBAAgB,OAAO;GACpD,CAAC;EACH,CAAC;CACH,CAAC;CAED,OAAAC,gBACG1C,MAAI;EAAA,IAAC2C,OAAI;GAAA,OAAErB,MAAMT;EAAI;EAAA,IAAAM,WAAA;GAAA,OAAAuB,gBACnBpC,QAAM;IAACO,MAAI;IAAC+B,eAAeC,SAAS,CAACA,QAAQvB,MAAMR,QAAQ;IAAC,IAAAK,WAAA;KAAA,OAAAuB,gBAC1DnC,eAAauC,WAAA;MAAAC,KAAMtB;MAAU,KAAA,WAAA;OAAA,OAASpB,GAAG,SAASiB,MAAM0B,KAAK;MAAC;KAAA,GAAMzB,MAAI,EAAA,IAAAJ,WAAA;MAAA,OAAA,CAAAuB,gBACtEjC,cAAY,EAAA,IAAAU,WAAA;OAAA,OAAA,CAAAuB,gBACVhC,aAAW;QAAA,SAAA;QAAA,IAAAS,WAAA;SAAA,OAAA,CAAAuB,gBACT1C,MAAI;UAAA,IAAC2C,OAAI;WAAA,OAAErB,MAAML;UAAa;UAAA,IAAAE,WAAA;WAAA,OAAGG,MAAML;UAAa;SAAA,CAAA,GAAAgC,WACpD3B,MAAMP,KAAK,CAAA;QAAA;OAAA,CAAA,GAAA2B,gBAEb1C,MAAI;QAAA,IAAC2C,OAAI;SAAA,OAAErB,MAAMN;QAAW;QAAA,IAAAG,WAAA;SAAA,OAAAuB,gBAC1BlC,mBAAiB,EAAA,IAAAW,WAAA;UAAA,OAAEG,MAAMN;SAAW,EAAA,CAAA;QAAA;OAAA,CAAA,CAAA;MAAA,EAAA,CAAA,GAAAiC,WAGxC3B,MAAMH,QAAQ,CAAA;KAAA,EAAA,CAAA,CAAA;IAAA;GAAA,CAAA;EAAA;CAAA,CAAA;AAKzB"}
1
+ {"version":3,"file":"modal-dialog.js","names":["ComponentProps","JSX","Show","createEffect","createSignal","onCleanup","splitProps","cn","Dialog","DialogContent","DialogDescription","DialogHeader","DialogTitle","ModalDialogProps","Omit","open","onClose","title","modal","description","headerLeading","Element","children","ModalDialog","props","local","rest","content","setContent","HTMLElement","element","background","document","body","filter","child","contains","wasInert","map","node","hasAttribute","setAttribute","forEach","index","removeAttribute","_$createComponent","when","onOpenChange","next","_$mergeProps","ref","class","aria-label","aria-labelledby","undefined","_$memo","_$createComponent","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/modal-dialog/modal-dialog.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'solid-js'\nimport { Show, createEffect, createSignal, onCleanup, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '../dialog/dialog'\n\n/**\n * ModalDialog.\n *\n * A dialog that owns three things `Dialog` leaves to its caller, each of which is a\n * real defect when it is missed:\n *\n * 1. **It unmounts while closed.** An always-mounted dialog that closes as a side\n * effect of an async action can leave Kobalte's `aria-hidden` bookkeeping behind,\n * which hides the rest of the application from assistive technology. Unmounting\n * the whole owner makes cleanup the only way the layer can end.\n * 2. **It marks the background `inert`.** `inert` keeps the background out of the\n * tab order and the accessibility tree without depending on that bookkeeping, and\n * it restores exactly the elements that did not already have it — so a nested\n * dialog does not un-inert its parent.\n * 3. **It sets an explicit accessible name.** The content receives `aria-label`\n * from `title`, so its name does not depend on the title id registration effect.\n * Pass `aria-label` to use a different name while keeping the visible title;\n * pass `aria-labelledby` when another visible label should take precedence.\n *\n * Use `Dialog` directly when you need its composition; use this when you want a\n * dialog that is correct by default.\n */\nexport type ModalDialogProps = Omit<\n ComponentProps<typeof DialogContent>,\n 'children' | 'aria-label' | 'aria-labelledby'\n> & {\n open: boolean\n onClose: () => void\n title: string\n /**\n * Controls Kobalte's focus, scroll and accessibility modality. Defaults to `true`;\n * background body children remain inert in either mode.\n */\n modal?: boolean\n description?: string\n /** A mark or icon drawn before the title. */\n headerLeading?: JSX.Element\n /** Replaces `title` as the accessible name while keeping the visible title. */\n 'aria-label'?: string\n /** Names the dialog from a visible element; ARIA gives it precedence over `aria-label`. */\n 'aria-labelledby'?: string\n children?: JSX.Element\n}\n\nexport function ModalDialog(props: ModalDialogProps) {\n const [local, rest] = splitProps(props, [\n 'open',\n 'onClose',\n 'title',\n 'modal',\n 'description',\n 'headerLeading',\n 'class',\n 'children',\n 'aria-label',\n 'aria-labelledby',\n ])\n\n const [content, setContent] = createSignal<HTMLElement>()\n\n createEffect(() => {\n if (!local.open) return\n const element = content()\n if (!element) return\n\n const background = [...document.body.children].filter(\n (child): child is HTMLElement => child instanceof HTMLElement && !child.contains(element)\n )\n const wasInert = background.map((node) => node.hasAttribute('inert'))\n for (const node of background) node.setAttribute('inert', '')\n\n onCleanup(() => {\n background.forEach((node, index) => {\n // Only the elements that were not already inert are restored, so a nested\n // dialog closing does not undo its parent's containment.\n if (!wasInert[index]) node.removeAttribute('inert')\n })\n })\n })\n\n return (\n <Show when={local.open}>\n <Dialog open modal={local.modal ?? true} onOpenChange={(next) => !next && local.onClose()}>\n <DialogContent\n ref={setContent}\n class={cn('gap-4', local.class)}\n aria-label={local['aria-label'] ?? local.title}\n aria-labelledby={\n local['aria-labelledby'] ?? (local['aria-label'] !== undefined ? '' : undefined)\n }\n {...rest}\n >\n <DialogHeader>\n <DialogTitle class=\"flex items-center gap-2\">\n <Show when={local.headerLeading}>{local.headerLeading}</Show>\n {local.title}\n </DialogTitle>\n <Show when={local.description}>\n <DialogDescription>{local.description}</DialogDescription>\n </Show>\n </DialogHeader>\n {local.children}\n </DialogContent>\n </Dialog>\n </Show>\n )\n}\n"],"mappings":";;;;;AAuDA,SAAgBuB,YAAYC,OAAyB;CACnD,MAAM,CAACC,OAAOC,QAAQpB,WAAWkB,OAAO;EACtC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAAiB,CAClB;CAED,MAAM,CAACG,SAASC,cAAcxB,aAA0B;CAExDD,mBAAmB;EACjB,IAAI,CAACsB,MAAMV,MAAM;EACjB,MAAMe,UAAUH,QAAQ;EACxB,IAAI,CAACG,SAAS;EAEd,MAAMC,aAAa,CAAC,GAAGC,SAASC,KAAKX,QAAQ,CAAC,CAACY,QAC5CC,UAAgCA,iBAAiBN,eAAe,CAACM,MAAMC,SAASN,OAAO,CAC1F;EACA,MAAMO,WAAWN,WAAWO,KAAKC,SAASA,KAAKC,aAAa,OAAO,CAAC;EACpE,KAAK,MAAMD,QAAQR,YAAYQ,KAAKE,aAAa,SAAS,EAAE;EAE5DpC,gBAAgB;GACd0B,WAAWW,SAASH,MAAMI,UAAU;IAGlC,IAAI,CAACN,SAASM,QAAQJ,KAAKK,gBAAgB,OAAO;GACpD,CAAC;EACH,CAAC;CACH,CAAC;CAED,OAAAC,gBACG3C,MAAI;EAAA,IAAC4C,OAAI;GAAA,OAAErB,MAAMV;EAAI;EAAA,IAAAO,WAAA;GAAA,OAAAuB,gBACnBrC,QAAM;IAACO,MAAI;IAAA,IAACG,QAAK;KAAA,OAAEO,MAAMP,SAAS;IAAI;IAAE6B,eAAeC,SAAS,CAACA,QAAQvB,MAAMT,QAAQ;IAAC,IAAAM,WAAA;KAAA,OAAAuB,gBACtFpC,eAAawC,WAAA;MAAAC,KACPtB;MAAU,KAAA,WAAA;OAAA,OACRrB,GAAG,SAASkB,MAAM0B,KAAK;MAAC;MAAA,KAAA,gBAAA;OAAA,OACnB1B,MAAM,iBAAiBA,MAAMR;MAAK;MAAA,KAAA,qBAAA;OAAA,OAE5CQ,MAAM,uBAAuBA,MAAM,kBAAkB6B,KAAAA,IAAY,KAAKA,KAAAA;MAAU;KAAA,GAE9E5B,MAAI,EAAA,IAAAJ,WAAA;MAAA,OAAA,CAAAuB,gBAEPlC,cAAY,EAAA,IAAAW,WAAA;OAAA,OAAA,CAAAuB,gBACVjC,aAAW;QAAA,SAAA;QAAA,IAAAU,WAAA;SAAA,OAAA,CAAAuB,gBACT3C,MAAI;UAAA,IAAC4C,OAAI;WAAA,OAAErB,MAAML;UAAa;UAAA,IAAAE,WAAA;WAAA,OAAGG,MAAML;UAAa;SAAA,CAAA,GAAAmC,WACpD9B,MAAMR,KAAK,CAAA;QAAA;OAAA,CAAA,GAAA4B,gBAEb3C,MAAI;QAAA,IAAC4C,OAAI;SAAA,OAAErB,MAAMN;QAAW;QAAA,IAAAG,WAAA;SAAA,OAAAuB,gBAC1BnC,mBAAiB,EAAA,IAAAY,WAAA;UAAA,OAAEG,MAAMN;SAAW,EAAA,CAAA;QAAA;OAAA,CAAA,CAAA;MAAA,EAAA,CAAA,GAAAoC,WAGxC9B,MAAMH,QAAQ,CAAA;KAAA,EAAA,CAAA,CAAA;IAAA;GAAA,CAAA;EAAA;CAAA,CAAA;AAKzB"}
@@ -57,7 +57,7 @@ function TooltipContent(props) {
57
57
  return createComponent(Tooltip.Content, mergeProps({ get ["class"]() {
58
58
  return cn("bg-scrim text-scrim-foreground z-(--z-tooltip) w-fit max-w-64 rounded-md px-2 py-1 text-xs", "origin-(--kb-tooltip-content-transform-origin) text-balance", "data-expanded:animate-in data-expanded:fade-in-0 data-expanded:zoom-in-95", "data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", "data-expanded:duration-150 data-closed:duration-100", local.class);
59
59
  } }, rest, { get children() {
60
- return [memo(() => local.children), createComponent(Tooltip.Arrow, { "aria-hidden": "true" })];
60
+ return [memo(() => local.children), memo(() => memo(() => !!!local.hideArrow)() && createComponent(Tooltip.Arrow, { "aria-hidden": "true" }))];
61
61
  } }));
62
62
  } });
63
63
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.js","names":["Tooltip","KobalteTooltip","ComponentProps","createContext","splitProps","useContext","cn","TooltipTiming","openDelay","closeDelay","skipDelayDuration","tooltipDefaults","TooltipTimingContext","TooltipProviderProps","children","TooltipProvider","props","_$createComponent","Provider","value","TooltipRootProps","timing","_$mergeProps","TooltipTrigger","Trigger","TooltipContentProps","Content","hideArrow","TooltipContent","local","rest","Portal","class","_$memo","Arrow","_$createComponent","Tooltip","KobalteTooltip","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/tooltip/tooltip.tsx"],"sourcesContent":["import { Tooltip as KobalteTooltip } from '@kobalte/core/tooltip'\nimport type { ComponentProps } from 'solid-js'\nimport { createContext, splitProps, useContext } from 'solid-js'\nimport { cn } from '#lib/utils'\n\n/**\n * The provider sets the *timing* defaults for every tooltip below it.\n *\n * Timing is the part of a tooltip that has to agree across an app: one that\n * opens in 200ms in a toolbar and 700ms in a sidebar reads as a bug. The\n * provider is where that agreement lives. It is optional — a tooltip outside a\n * provider falls back to the same defaults — so a consumer can drop it in\n * without restructuring anything.\n */\ntype TooltipTiming = {\n openDelay: number\n closeDelay: number\n skipDelayDuration: number\n}\n\nconst tooltipDefaults: TooltipTiming = {\n /** Long enough that a pointer crossing a toolbar does not strobe tooltips. */\n openDelay: 400,\n /** Short, because the pointer has already left the control. */\n closeDelay: 80,\n /**\n * After a tooltip has been seen, the next one opens immediately for this\n * long. This is what makes moving along a row of icons feel like one\n * gesture instead of four separate waits.\n */\n skipDelayDuration: 500,\n}\n\nconst TooltipTimingContext = createContext<TooltipTiming>(tooltipDefaults)\n\nexport type TooltipProviderProps = {\n children?: ComponentProps<'div'>['children']\n openDelay?: number\n closeDelay?: number\n skipDelayDuration?: number\n}\n\nexport function TooltipProvider(props: TooltipProviderProps) {\n return (\n <TooltipTimingContext.Provider\n value={{\n openDelay: props.openDelay ?? tooltipDefaults.openDelay,\n closeDelay: props.closeDelay ?? tooltipDefaults.closeDelay,\n skipDelayDuration: props.skipDelayDuration ?? tooltipDefaults.skipDelayDuration,\n }}\n >\n {props.children}\n </TooltipTimingContext.Provider>\n )\n}\n\nexport type TooltipRootProps = ComponentProps<typeof KobalteTooltip>\n\nexport function Tooltip(props: TooltipRootProps) {\n const timing = useContext(TooltipTimingContext)\n\n return (\n <KobalteTooltip\n openDelay={props.openDelay ?? timing.openDelay}\n closeDelay={props.closeDelay ?? timing.closeDelay}\n skipDelayDuration={props.skipDelayDuration ?? timing.skipDelayDuration}\n {...props}\n />\n )\n}\n\nexport function TooltipTrigger(props: ComponentProps<typeof KobalteTooltip.Trigger>) {\n return <KobalteTooltip.Trigger {...props} />\n}\n\nexport type TooltipContentProps = ComponentProps<typeof KobalteTooltip.Content> & {\n /** Hide the caret pointing at the trigger. */\n hideArrow?: boolean\n}\n\nexport function TooltipContent(props: TooltipContentProps) {\n const [local, rest] = splitProps(props, ['class', 'hideArrow', 'children'])\n\n return (\n <KobalteTooltip.Portal>\n <KobalteTooltip.Content\n class={cn(\n 'bg-scrim text-scrim-foreground z-(--z-tooltip) w-fit max-w-64 rounded-md px-2 py-1 text-xs',\n 'origin-(--kb-tooltip-content-transform-origin) text-balance',\n 'data-expanded:animate-in data-expanded:fade-in-0 data-expanded:zoom-in-95',\n 'data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',\n 'data-expanded:duration-150 data-closed:duration-100',\n local.class\n )}\n {...rest}\n >\n {local.children}\n <KobalteTooltip.Arrow aria-hidden=\"true\" />\n </KobalteTooltip.Content>\n </KobalteTooltip.Portal>\n )\n}\n"],"mappings":";;;;;AAoBA,IAAMW,kBAAiC;;CAErCH,WAAW;;CAEXC,YAAY;;;;;;CAMZC,mBAAmB;AACrB;AAEA,IAAME,uBAAuBT,cAA6BQ,eAAe;AASzE,SAAgBI,gBAAgBC,OAA6B;CAC3D,OAAAC,gBACGL,qBAAqBM,UAAQ;EAAA,IAC5BC,QAAK;GAAA,OAAE;IACLX,WAAWQ,MAAMR,aAAaG,gBAAgBH;IAC9CC,YAAYO,MAAMP,cAAcE,gBAAgBF;IAChDC,mBAAmBM,MAAMN,qBAAqBC,gBAAgBD;GAChE;EAAC;EAAA,IAAAI,WAAA;GAAA,OAEAE,MAAMF;EAAQ;CAAA,CAAA;AAGrB;AAIA,SAAgBd,UAAQgB,OAAyB;CAC/C,MAAMK,SAAShB,WAAWO,oBAAoB;CAE9C,OAAAK,gBACGhB,SAAcqB,WAAA;EAAA,IACbd,YAAS;GAAA,OAAEQ,MAAMR,aAAaa,OAAOb;EAAS;EAAA,IAC9CC,aAAU;GAAA,OAAEO,MAAMP,cAAcY,OAAOZ;EAAU;EAAA,IACjDC,oBAAiB;GAAA,OAAEM,MAAMN,qBAAqBW,OAAOX;EAAiB;CAAA,GAClEM,KAAK,CAAA;AAGf;AAEA,SAAgBO,eAAeP,OAAsD;CACnF,OAAAC,gBAAQhB,QAAeuB,SAAYR,KAAK;AAC1C;AAOA,SAAgBY,eAAeZ,OAA4B;CACzD,MAAM,CAACa,OAAOC,QAAQ1B,WAAWY,OAAO;EAAC;EAAS;EAAa;CAAU,CAAC;CAE1E,OAAAC,gBACGhB,QAAe8B,QAAM,EAAA,IAAAjB,WAAA;EAAA,OAAAG,gBACnBhB,QAAeyB,SAAOJ,WAAA,EAAA,KAAA,WAAA;GAAA,OACdhB,GACL,8FACA,+DACA,6EACA,0EACA,uDACAuB,MAAMG,KACR;EAAC,EAAA,GACGF,MAAI,EAAA,IAAAhB,WAAA;GAAA,OAAA,CAAAmB,WAEPJ,MAAMf,QAAQ,GAAAG,gBACdhB,QAAeiC,OAAK,EAAA,eAAA,OAAA,CAAA,CAAA;EAAA,EAAA,CAAA,CAAA;CAAA,EAAA,CAAA;AAI7B"}
1
+ {"version":3,"file":"tooltip.js","names":["Tooltip","KobalteTooltip","ComponentProps","createContext","splitProps","useContext","cn","TooltipTiming","openDelay","closeDelay","skipDelayDuration","tooltipDefaults","TooltipTimingContext","TooltipProviderProps","children","TooltipProvider","props","_$createComponent","Provider","value","TooltipRootProps","timing","_$mergeProps","TooltipTrigger","Trigger","TooltipContentProps","Content","hideArrow","TooltipContent","local","rest","Portal","class","_$memo","Arrow","_$createComponent","Tooltip","KobalteTooltip","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/tooltip/tooltip.tsx"],"sourcesContent":["import { Tooltip as KobalteTooltip } from '@kobalte/core/tooltip'\nimport type { ComponentProps } from 'solid-js'\nimport { createContext, splitProps, useContext } from 'solid-js'\nimport { cn } from '#lib/utils'\n\n/**\n * The provider sets the *timing* defaults for every tooltip below it.\n *\n * Timing is the part of a tooltip that has to agree across an app: one that\n * opens in 200ms in a toolbar and 700ms in a sidebar reads as a bug. The\n * provider is where that agreement lives. It is optional — a tooltip outside a\n * provider falls back to the same defaults — so a consumer can drop it in\n * without restructuring anything.\n */\ntype TooltipTiming = {\n openDelay: number\n closeDelay: number\n skipDelayDuration: number\n}\n\nconst tooltipDefaults: TooltipTiming = {\n /** Long enough that a pointer crossing a toolbar does not strobe tooltips. */\n openDelay: 400,\n /** Short, because the pointer has already left the control. */\n closeDelay: 80,\n /**\n * After a tooltip has been seen, the next one opens immediately for this\n * long. This is what makes moving along a row of icons feel like one\n * gesture instead of four separate waits.\n */\n skipDelayDuration: 500,\n}\n\nconst TooltipTimingContext = createContext<TooltipTiming>(tooltipDefaults)\n\nexport type TooltipProviderProps = {\n children?: ComponentProps<'div'>['children']\n openDelay?: number\n closeDelay?: number\n skipDelayDuration?: number\n}\n\nexport function TooltipProvider(props: TooltipProviderProps) {\n return (\n <TooltipTimingContext.Provider\n value={{\n openDelay: props.openDelay ?? tooltipDefaults.openDelay,\n closeDelay: props.closeDelay ?? tooltipDefaults.closeDelay,\n skipDelayDuration: props.skipDelayDuration ?? tooltipDefaults.skipDelayDuration,\n }}\n >\n {props.children}\n </TooltipTimingContext.Provider>\n )\n}\n\nexport type TooltipRootProps = ComponentProps<typeof KobalteTooltip>\n\nexport function Tooltip(props: TooltipRootProps) {\n const timing = useContext(TooltipTimingContext)\n\n return (\n <KobalteTooltip\n openDelay={props.openDelay ?? timing.openDelay}\n closeDelay={props.closeDelay ?? timing.closeDelay}\n skipDelayDuration={props.skipDelayDuration ?? timing.skipDelayDuration}\n {...props}\n />\n )\n}\n\nexport function TooltipTrigger(props: ComponentProps<typeof KobalteTooltip.Trigger>) {\n return <KobalteTooltip.Trigger {...props} />\n}\n\nexport type TooltipContentProps = ComponentProps<typeof KobalteTooltip.Content> & {\n /** Hide the caret pointing at the trigger. */\n hideArrow?: boolean\n}\n\nexport function TooltipContent(props: TooltipContentProps) {\n const [local, rest] = splitProps(props, ['class', 'hideArrow', 'children'])\n\n return (\n <KobalteTooltip.Portal>\n <KobalteTooltip.Content\n class={cn(\n 'bg-scrim text-scrim-foreground z-(--z-tooltip) w-fit max-w-64 rounded-md px-2 py-1 text-xs',\n 'origin-(--kb-tooltip-content-transform-origin) text-balance',\n 'data-expanded:animate-in data-expanded:fade-in-0 data-expanded:zoom-in-95',\n 'data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',\n 'data-expanded:duration-150 data-closed:duration-100',\n local.class\n )}\n {...rest}\n >\n {local.children}\n {!local.hideArrow && <KobalteTooltip.Arrow aria-hidden=\"true\" />}\n </KobalteTooltip.Content>\n </KobalteTooltip.Portal>\n )\n}\n"],"mappings":";;;;;AAoBA,IAAMW,kBAAiC;;CAErCH,WAAW;;CAEXC,YAAY;;;;;;CAMZC,mBAAmB;AACrB;AAEA,IAAME,uBAAuBT,cAA6BQ,eAAe;AASzE,SAAgBI,gBAAgBC,OAA6B;CAC3D,OAAAC,gBACGL,qBAAqBM,UAAQ;EAAA,IAC5BC,QAAK;GAAA,OAAE;IACLX,WAAWQ,MAAMR,aAAaG,gBAAgBH;IAC9CC,YAAYO,MAAMP,cAAcE,gBAAgBF;IAChDC,mBAAmBM,MAAMN,qBAAqBC,gBAAgBD;GAChE;EAAC;EAAA,IAAAI,WAAA;GAAA,OAEAE,MAAMF;EAAQ;CAAA,CAAA;AAGrB;AAIA,SAAgBd,UAAQgB,OAAyB;CAC/C,MAAMK,SAAShB,WAAWO,oBAAoB;CAE9C,OAAAK,gBACGhB,SAAcqB,WAAA;EAAA,IACbd,YAAS;GAAA,OAAEQ,MAAMR,aAAaa,OAAOb;EAAS;EAAA,IAC9CC,aAAU;GAAA,OAAEO,MAAMP,cAAcY,OAAOZ;EAAU;EAAA,IACjDC,oBAAiB;GAAA,OAAEM,MAAMN,qBAAqBW,OAAOX;EAAiB;CAAA,GAClEM,KAAK,CAAA;AAGf;AAEA,SAAgBO,eAAeP,OAAsD;CACnF,OAAAC,gBAAQhB,QAAeuB,SAAYR,KAAK;AAC1C;AAOA,SAAgBY,eAAeZ,OAA4B;CACzD,MAAM,CAACa,OAAOC,QAAQ1B,WAAWY,OAAO;EAAC;EAAS;EAAa;CAAU,CAAC;CAE1E,OAAAC,gBACGhB,QAAe8B,QAAM,EAAA,IAAAjB,WAAA;EAAA,OAAAG,gBACnBhB,QAAeyB,SAAOJ,WAAA,EAAA,KAAA,WAAA;GAAA,OACdhB,GACL,8FACA,+DACA,6EACA,0EACA,uDACAuB,MAAMG,KACR;EAAC,EAAA,GACGF,MAAI,EAAA,IAAAhB,WAAA;GAAA,OAAA,CAAAmB,WAEPJ,MAAMf,QAAQ,GAAAmB,WACdA,WAAA,CAAA,CAAA,CAACJ,MAAMF,SAAS,CAAA,CAAA,KAAAV,gBAAKhB,QAAeiC,OAAK,EAAA,eAAA,OAAA,CAAA,CAAsB,CAAA;EAAA,EAAA,CAAA,CAAA;CAAA,EAAA,CAAA;AAIxE"}
@@ -23,21 +23,33 @@ import {
23
23
  * tab order and the accessibility tree without depending on that bookkeeping, and
24
24
  * it restores exactly the elements that did not already have it — so a nested
25
25
  * dialog does not un-inert its parent.
26
- * 3. **It labels itself explicitly.** The title registers its id for
27
- * `aria-labelledby` in a mount effect; if that registration is ever lost, the
28
- * dialog renders with a heading and no name. Passing the label as well costs
29
- * nothing and removes the race.
26
+ * 3. **It sets an explicit accessible name.** The content receives `aria-label`
27
+ * from `title`, so its name does not depend on the title id registration effect.
28
+ * Pass `aria-label` to use a different name while keeping the visible title;
29
+ * pass `aria-labelledby` when another visible label should take precedence.
30
30
  *
31
31
  * Use `Dialog` directly when you need its composition; use this when you want a
32
32
  * dialog that is correct by default.
33
33
  */
34
- export type ModalDialogProps = Omit<ComponentProps<typeof DialogContent>, 'children'> & {
34
+ export type ModalDialogProps = Omit<
35
+ ComponentProps<typeof DialogContent>,
36
+ 'children' | 'aria-label' | 'aria-labelledby'
37
+ > & {
35
38
  open: boolean
36
39
  onClose: () => void
37
40
  title: string
41
+ /**
42
+ * Controls Kobalte's focus, scroll and accessibility modality. Defaults to `true`;
43
+ * background body children remain inert in either mode.
44
+ */
45
+ modal?: boolean
38
46
  description?: string
39
47
  /** A mark or icon drawn before the title. */
40
48
  headerLeading?: JSX.Element
49
+ /** Replaces `title` as the accessible name while keeping the visible title. */
50
+ 'aria-label'?: string
51
+ /** Names the dialog from a visible element; ARIA gives it precedence over `aria-label`. */
52
+ 'aria-labelledby'?: string
41
53
  children?: JSX.Element
42
54
  }
43
55
 
@@ -46,10 +58,13 @@ export function ModalDialog(props: ModalDialogProps) {
46
58
  'open',
47
59
  'onClose',
48
60
  'title',
61
+ 'modal',
49
62
  'description',
50
63
  'headerLeading',
51
64
  'class',
52
65
  'children',
66
+ 'aria-label',
67
+ 'aria-labelledby',
53
68
  ])
54
69
 
55
70
  const [content, setContent] = createSignal<HTMLElement>()
@@ -76,8 +91,16 @@ export function ModalDialog(props: ModalDialogProps) {
76
91
 
77
92
  return (
78
93
  <Show when={local.open}>
79
- <Dialog open onOpenChange={(next) => !next && local.onClose()}>
80
- <DialogContent ref={setContent} class={cn('gap-4', local.class)} {...rest}>
94
+ <Dialog open modal={local.modal ?? true} onOpenChange={(next) => !next && local.onClose()}>
95
+ <DialogContent
96
+ ref={setContent}
97
+ class={cn('gap-4', local.class)}
98
+ aria-label={local['aria-label'] ?? local.title}
99
+ aria-labelledby={
100
+ local['aria-labelledby'] ?? (local['aria-label'] !== undefined ? '' : undefined)
101
+ }
102
+ {...rest}
103
+ >
81
104
  <DialogHeader>
82
105
  <DialogTitle class="flex items-center gap-2">
83
106
  <Show when={local.headerLeading}>{local.headerLeading}</Show>
@@ -95,7 +95,7 @@ export function TooltipContent(props: TooltipContentProps) {
95
95
  {...rest}
96
96
  >
97
97
  {local.children}
98
- <KobalteTooltip.Arrow aria-hidden="true" />
98
+ {!local.hideArrow && <KobalteTooltip.Arrow aria-hidden="true" />}
99
99
  </KobalteTooltip.Content>
100
100
  </KobalteTooltip.Portal>
101
101
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.70.0",
3
+ "version": "0.70.2",
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",
@@ -23,21 +23,33 @@ import {
23
23
  * tab order and the accessibility tree without depending on that bookkeeping, and
24
24
  * it restores exactly the elements that did not already have it — so a nested
25
25
  * dialog does not un-inert its parent.
26
- * 3. **It labels itself explicitly.** The title registers its id for
27
- * `aria-labelledby` in a mount effect; if that registration is ever lost, the
28
- * dialog renders with a heading and no name. Passing the label as well costs
29
- * nothing and removes the race.
26
+ * 3. **It sets an explicit accessible name.** The content receives `aria-label`
27
+ * from `title`, so its name does not depend on the title id registration effect.
28
+ * Pass `aria-label` to use a different name while keeping the visible title;
29
+ * pass `aria-labelledby` when another visible label should take precedence.
30
30
  *
31
31
  * Use `Dialog` directly when you need its composition; use this when you want a
32
32
  * dialog that is correct by default.
33
33
  */
34
- export type ModalDialogProps = Omit<ComponentProps<typeof DialogContent>, 'children'> & {
34
+ export type ModalDialogProps = Omit<
35
+ ComponentProps<typeof DialogContent>,
36
+ 'children' | 'aria-label' | 'aria-labelledby'
37
+ > & {
35
38
  open: boolean
36
39
  onClose: () => void
37
40
  title: string
41
+ /**
42
+ * Controls Kobalte's focus, scroll and accessibility modality. Defaults to `true`;
43
+ * background body children remain inert in either mode.
44
+ */
45
+ modal?: boolean
38
46
  description?: string
39
47
  /** A mark or icon drawn before the title. */
40
48
  headerLeading?: JSX.Element
49
+ /** Replaces `title` as the accessible name while keeping the visible title. */
50
+ 'aria-label'?: string
51
+ /** Names the dialog from a visible element; ARIA gives it precedence over `aria-label`. */
52
+ 'aria-labelledby'?: string
41
53
  children?: JSX.Element
42
54
  }
43
55
 
@@ -46,10 +58,13 @@ export function ModalDialog(props: ModalDialogProps) {
46
58
  'open',
47
59
  'onClose',
48
60
  'title',
61
+ 'modal',
49
62
  'description',
50
63
  'headerLeading',
51
64
  'class',
52
65
  'children',
66
+ 'aria-label',
67
+ 'aria-labelledby',
53
68
  ])
54
69
 
55
70
  const [content, setContent] = createSignal<HTMLElement>()
@@ -76,8 +91,16 @@ export function ModalDialog(props: ModalDialogProps) {
76
91
 
77
92
  return (
78
93
  <Show when={local.open}>
79
- <Dialog open onOpenChange={(next) => !next && local.onClose()}>
80
- <DialogContent ref={setContent} class={cn('gap-4', local.class)} {...rest}>
94
+ <Dialog open modal={local.modal ?? true} onOpenChange={(next) => !next && local.onClose()}>
95
+ <DialogContent
96
+ ref={setContent}
97
+ class={cn('gap-4', local.class)}
98
+ aria-label={local['aria-label'] ?? local.title}
99
+ aria-labelledby={
100
+ local['aria-labelledby'] ?? (local['aria-label'] !== undefined ? '' : undefined)
101
+ }
102
+ {...rest}
103
+ >
81
104
  <DialogHeader>
82
105
  <DialogTitle class="flex items-center gap-2">
83
106
  <Show when={local.headerLeading}>{local.headerLeading}</Show>
@@ -95,7 +95,7 @@ export function TooltipContent(props: TooltipContentProps) {
95
95
  {...rest}
96
96
  >
97
97
  {local.children}
98
- <KobalteTooltip.Arrow aria-hidden="true" />
98
+ {!local.hideArrow && <KobalteTooltip.Arrow aria-hidden="true" />}
99
99
  </KobalteTooltip.Content>
100
100
  </KobalteTooltip.Portal>
101
101
  )