@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.
- package/dist/components/ui/modal-dialog/modal-dialog.d.ts +14 -5
- package/dist/components/ui/modal-dialog/modal-dialog.d.ts.map +1 -1
- package/dist/components/ui/modal-dialog/modal-dialog.js +13 -1
- package/dist/components/ui/modal-dialog/modal-dialog.js.map +1 -1
- package/dist/components/ui/tooltip/tooltip.js +1 -1
- package/dist/components/ui/tooltip/tooltip.js.map +1 -1
- package/dist/r/src/components/ui/modal-dialog/modal-dialog.tsx +30 -7
- package/dist/r/src/components/ui/tooltip/tooltip.tsx +1 -1
- package/package.json +1 -1
- package/src/components/ui/modal-dialog/modal-dialog.tsx +30 -7
- package/src/components/ui/tooltip/tooltip.tsx +1 -1
|
@@ -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
|
|
18
|
-
* `
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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,
|
|
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
|
|
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\"
|
|
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
|
|
27
|
-
* `
|
|
28
|
-
*
|
|
29
|
-
*
|
|
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<
|
|
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
|
|
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
|
@@ -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
|
|
27
|
-
* `
|
|
28
|
-
*
|
|
29
|
-
*
|
|
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<
|
|
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
|
|
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
|
)
|