@adea-ai/ui 0.115.1 → 0.116.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/composites/appearance-editor/accent-swatch-groups.d.ts +6 -0
- package/dist/components/composites/appearance-editor/accent-swatch-groups.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/accent-swatch-groups.js +13 -6
- package/dist/components/composites/appearance-editor/accent-swatch-groups.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-choices.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-choices.js +85 -22
- package/dist/components/composites/appearance-editor/appearance-choices.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-editor.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-editor.js +39 -12
- package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-types.d.ts +26 -0
- package/dist/components/composites/appearance-editor/appearance-types.d.ts.map +1 -1
- package/dist/components/ui/command/command.d.ts.map +1 -1
- package/dist/components/ui/command/command.js +1 -1
- package/dist/components/ui/command/command.js.map +1 -1
- package/dist/components/ui/tabs/tabs.js +1 -1
- package/dist/components/ui/tabs/tabs.js.map +1 -1
- package/dist/components/ui/toggle/toggle.d.ts +4 -1
- package/dist/components/ui/toggle/toggle.d.ts.map +1 -1
- package/dist/components/ui/toggle/toggle.js +5 -2
- package/dist/components/ui/toggle/toggle.js.map +1 -1
- package/dist/components/ui/tooltip/tooltip.d.ts.map +1 -1
- package/dist/components/ui/tooltip/tooltip.js +5 -0
- package/dist/components/ui/tooltip/tooltip.js.map +1 -1
- package/dist/lib/tooltip-focus-gate.d.ts +29 -0
- package/dist/lib/tooltip-focus-gate.d.ts.map +1 -0
- package/dist/lib/tooltip-focus-gate.js +134 -0
- package/dist/lib/tooltip-focus-gate.js.map +1 -0
- package/dist/r/appearance-editor.json +1 -0
- package/dist/r/lib.json +5 -0
- package/dist/r/registry.json +6 -0
- package/dist/r/src/components/composites/appearance-editor/accent-swatch-groups.tsx +10 -2
- package/dist/r/src/components/composites/appearance-editor/appearance-choices.tsx +55 -17
- package/dist/r/src/components/composites/appearance-editor/appearance-editor.tsx +25 -8
- package/dist/r/src/components/composites/appearance-editor/appearance-types.ts +26 -0
- package/dist/r/src/components/ui/command/command.tsx +5 -1
- package/dist/r/src/components/ui/tabs/tabs.tsx +1 -1
- package/dist/r/src/components/ui/toggle/toggle.tsx +5 -2
- package/dist/r/src/components/ui/tooltip/tooltip.tsx +10 -0
- package/dist/r/src/lib/tooltip-focus-gate.ts +218 -0
- package/package.json +1 -1
- package/registry.json +6 -0
- package/src/components/composites/appearance-editor/accent-swatch-groups.tsx +10 -2
- package/src/components/composites/appearance-editor/appearance-choices.tsx +55 -17
- package/src/components/composites/appearance-editor/appearance-editor.tsx +25 -8
- package/src/components/composites/appearance-editor/appearance-types.ts +26 -0
- package/src/components/ui/command/command.tsx +5 -1
- package/src/components/ui/tabs/tabs.tsx +1 -1
- package/src/components/ui/toggle/toggle.tsx +5 -2
- package/src/components/ui/tooltip/tooltip.tsx +10 -0
- package/src/lib/tooltip-focus-gate.ts +218 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.js","names":["CommandDialog","CmdkDialog","CommandEmpty","CmdkEmpty","CommandGroup","CmdkGroup","CommandInput","CmdkInput","CommandItem","CmdkItem","CommandList","CmdkList","CommandLoading","CmdkLoading","CommandRoot","CmdkRoot","CommandSeparator","CmdkSeparator","useCommandState","Dialog","KobalteDialog","Search","ComponentProps","createEffect","createSignal","splitProps","createDialogFocusRestoration","menuItem","cn","commandItem","replace","Command","props","local","rest","_$createComponent","_$mergeProps","class","CommandDialogProps","Pick","Content","dialogProps","commandProps","isOpen","setIsOpen","open","defaultOpen","undefined","focus","onCloseAutoFocus","onOpenAutoFocus","onOpenChange","children","Portal","mount","container","Overlay","overlayClassName","aria-label","label","role","contentClassName","_el$","_tmpl$","_$insert","wrapper","setWrapper","HTMLDivElement","resultCount","state","filtered","count","root","selector","querySelector","setAttribute","_el$2","_tmpl$2","_$use","CommandShortcut","_el$3","_tmpl$3","_$effect","_$className","_$createComponent","CmdkRoot","_$mergeProps","KobalteDialog","CommandInput","CmdkInput","CommandList","CmdkList","CommandEmpty","CmdkEmpty","CommandGroup","CmdkGroup","CommandItem","CmdkItem","CommandSeparator","CmdkSeparator","CommandLoading","CmdkLoading","_$className"],"sources":["../../../../src/components/ui/command/command.tsx"],"sourcesContent":["import {\n CommandDialog as CmdkDialog,\n CommandEmpty as CmdkEmpty,\n CommandGroup as CmdkGroup,\n CommandInput as CmdkInput,\n CommandItem as CmdkItem,\n CommandList as CmdkList,\n CommandLoading as CmdkLoading,\n CommandRoot as CmdkRoot,\n CommandSeparator as CmdkSeparator,\n useCommandState,\n} from 'cmdk-solid'\nimport { Dialog as KobalteDialog } from '@kobalte/core/dialog'\nimport { Search } from 'lucide-solid'\nimport type { ComponentProps } from 'solid-js'\nimport { createEffect, createSignal, splitProps } from 'solid-js'\nimport { createDialogFocusRestoration } from '../dialog/dialog'\nimport { menuItem } from '#lib/overlay'\nimport { cn } from '#lib/utils'\n\n// cmdk emits data-disabled=\"false\" on enabled items, unlike the presence-only\n// attributes Kobalte menu rows use. Apply those shared disabled styles only when\n// cmdk's value is true.\nconst commandItem = menuItem\n .replace('data-[disabled]:pointer-events-none', '')\n .replace('data-[disabled]:text-muted-foreground', '')\n\n/**\n * Command.\n *\n * The command palette: a filtered list of everything the user can do, ranked\n * by fuzzy match. It is the one place in an app where a keyboard-first surface\n * is the *primary* one, so it carries rules the rest of the system does not:\n *\n * - Every item must be reachable by typing its name. If a user has to\n * remember which group it lives in, the palette has failed at its job.\n * - Groups exist for reading, not for navigation. The ranking crosses them.\n * - The empty state is not an apology — it should offer the closest thing\n * the app could guess, or say plainly that nothing matched.\n *\n * cmdk-solid supplies the filter, the scoring, the `aria-activedescendant`\n * wiring and the arrow-key navigation.\n */\nexport function Command(props: ComponentProps<typeof CmdkRoot>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <CmdkRoot\n class={cn(\n 'bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-xl',\n local.class\n )}\n {...rest}\n />\n )\n}\n\ntype CommandDialogProps = ComponentProps<typeof CmdkDialog> &\n Pick<ComponentProps<typeof KobalteDialog.Content>, 'onCloseAutoFocus' | 'onOpenAutoFocus'>\n\nexport function CommandDialog(props: CommandDialogProps) {\n // cmdk-solid's Dialog does not forward Content autofocus props: unknown\n // props fall through to its Command root. Compose Kobalte's dialog surface\n // here so Escape and other close paths can restore focus to the real opener.\n // Preserve the shared wrapper's `class` contract on the dialog surface;\n // `contentClassName` adds to it, while the nested Command keeps its own API.\n const [local, dialogProps, commandProps] = splitProps(\n props,\n [\n 'class',\n 'contentClassName',\n 'overlayClassName',\n 'container',\n 'onCloseAutoFocus',\n 'onOpenAutoFocus',\n ],\n [\n 'open',\n 'defaultOpen',\n 'onOpenChange',\n 'id',\n 'modal',\n 'preventScroll',\n 'forceMount',\n 'translations',\n ]\n )\n const [isOpen, setIsOpen] = createSignal(dialogProps.open ?? dialogProps.defaultOpen ?? false)\n\n createEffect(() => {\n if (dialogProps.open !== undefined) setIsOpen(dialogProps.open)\n })\n\n const focus = createDialogFocusRestoration({\n open: isOpen,\n onCloseAutoFocus: local.onCloseAutoFocus,\n onOpenAutoFocus: local.onOpenAutoFocus,\n })\n\n return (\n <KobalteDialog\n {...dialogProps}\n onOpenChange={(open) => {\n setIsOpen(open)\n dialogProps.onOpenChange?.(open)\n }}\n >\n <KobalteDialog.Portal mount={local.container}>\n <KobalteDialog.Overlay cmdk-overlay=\"\" class={local.overlayClassName} />\n <KobalteDialog.Content\n aria-label={commandProps.label}\n cmdk-dialog=\"\"\n role=\"dialog\"\n class={cn(\n 'bg-popover text-popover-foreground fixed top-1/3 left-1/2 z-(--z-dialog) w-full max-w-lg -translate-x-1/2 -translate-y-1/2',\n 'overflow-hidden rounded-xl border border-border shadow-xl',\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 local.class,\n local.contentClassName\n )}\n onOpenAutoFocus={focus.onOpenAutoFocus}\n onCloseAutoFocus={focus.onCloseAutoFocus}\n >\n <Command {...commandProps} />\n </KobalteDialog.Content>\n </KobalteDialog.Portal>\n </KobalteDialog>\n )\n}\n\nexport function CommandInput(props: ComponentProps<typeof CmdkInput>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <div\n data-slot=\"command-input-wrapper\"\n class=\"flex h-11 items-center gap-2 border-b border-border px-3\"\n >\n <Search class=\"size-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <CmdkInput\n class={cn(\n 'h-full w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n local.class\n )}\n {...rest}\n />\n </div>\n )\n}\n\n/**\n * The scrolling list.\n *\n * Two DOM corrections, and both are deliberate. cmdk builds a `role=\"listbox\"`\n * whose children include two elements ARIA does not allow there:\n *\n * - a bare `<div cmdk-list-sizer>` with no role, wrapped around every group;\n * - a `<div cmdk-separator role=\"separator\">`, and `separator` is a menu and\n * toolbar role — inside a listbox the only owned elements may be `option`\n * and `group`.\n *\n * Both are pure presentation: the sizer is layout, and the separator is a\n * hairline between groups that the groups already structure. `role=\"presentation\"`\n * is their accurate role rather than a workaround — each is flattened out of the\n * accessibility tree, and the options inside are reached exactly as before.\n *\n * Written onto the mounted nodes rather than through props, because cmdk owns\n * this markup and does not forward a `ref`; in an effect rather than `onMount`,\n * because cmdk renders the sizer with the first item, after the list itself.\n */\nexport function CommandList(props: ComponentProps<typeof CmdkList>) {\n const [local, rest] = splitProps(props, ['class'])\n const [wrapper, setWrapper] = createSignal<HTMLDivElement>()\n const resultCount = useCommandState((state) => state.filtered.count)\n\n createEffect(() => {\n const root = wrapper()\n if (!root) return\n for (const selector of ['[cmdk-list-sizer]', '[cmdk-separator]']) {\n root.querySelector(selector)?.setAttribute('role', 'presentation')\n }\n\n /*\n * A `listbox` must own at least one `option`, so a listbox with nothing in it\n * is invalid ARIA — which is what a search with no matches produces. When\n * there are no results the list is inert, so it becomes presentational and\n * the empty message carries the information instead. It keeps its `id`, so\n * the input's `aria-controls` still resolves.\n */\n root\n .querySelector('[cmdk-list]')\n ?.setAttribute('role', resultCount() > 0 ? 'listbox' : 'presentation')\n })\n\n return (\n <div ref={setWrapper} class=\"contents\">\n <CmdkList\n class={cn('max-h-80 scroll-py-1 overflow-y-auto overflow-x-hidden p-1', local.class)}\n {...rest}\n />\n </div>\n )\n}\n\nexport function CommandEmpty(props: ComponentProps<typeof CmdkEmpty>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <CmdkEmpty\n /*\n * A status rather than plain text: when the list is presentational, this is\n * the only thing that tells a screen reader the search matched nothing.\n */\n role=\"status\"\n class={cn('text-muted-foreground py-8 text-center text-sm', local.class)}\n {...rest}\n />\n )\n}\n\nexport function CommandGroup(props: ComponentProps<typeof CmdkGroup>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <CmdkGroup\n class={cn(\n 'text-foreground overflow-hidden p-1',\n '[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-2xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:tracking-wide [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:uppercase',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function CommandItem(props: ComponentProps<typeof CmdkItem>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <CmdkItem\n class={cn(\n commandItem,\n 'data-[disabled=true]:pointer-events-none data-[disabled=true]:text-muted-foreground',\n 'group/command-item text-popover-foreground data-[selected=true]:bg-card data-[selected=true]:text-popover-foreground',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function CommandSeparator(props: ComponentProps<typeof CmdkSeparator>) {\n const [local, rest] = splitProps(props, ['class'])\n return <CmdkSeparator class={cn('bg-border -mx-1 my-1 h-px', local.class)} {...rest} />\n}\n\nexport function CommandLoading(props: ComponentProps<typeof CmdkLoading>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <CmdkLoading\n class={cn('text-muted-foreground py-6 text-center text-sm', local.class)}\n {...rest}\n />\n )\n}\n\n/** The keyboard hint a palette item usually carries. */\nexport function CommandShortcut(props: {\n class?: string\n children?: ComponentProps<'span'>['children']\n}) {\n return (\n <span\n class={cn(\n 'text-muted-foreground ms-auto font-code text-code tracking-widest group-data-[selected=true]/command-item:text-foreground',\n props.class\n )}\n >\n {props.children}\n </span>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"command.js","names":["CommandDialog","CmdkDialog","CommandEmpty","CmdkEmpty","CommandGroup","CmdkGroup","CommandInput","CmdkInput","CommandItem","CmdkItem","CommandList","CmdkList","CommandLoading","CmdkLoading","CommandRoot","CmdkRoot","CommandSeparator","CmdkSeparator","useCommandState","Dialog","KobalteDialog","Search","ComponentProps","createEffect","createSignal","splitProps","createDialogFocusRestoration","menuItem","cn","commandItem","replace","Command","props","local","rest","_$createComponent","_$mergeProps","class","CommandDialogProps","Pick","Content","dialogProps","commandProps","isOpen","setIsOpen","open","defaultOpen","undefined","focus","onCloseAutoFocus","onOpenAutoFocus","onOpenChange","children","Portal","mount","container","Overlay","overlayClassName","aria-label","label","role","contentClassName","_el$","_tmpl$","_$insert","wrapper","setWrapper","HTMLDivElement","resultCount","state","filtered","count","root","selector","querySelector","setAttribute","_el$2","_tmpl$2","_$use","CommandShortcut","_el$3","_tmpl$3","_$effect","_$className","_$createComponent","CmdkRoot","_$mergeProps","KobalteDialog","CommandInput","CmdkInput","CommandList","CmdkList","CommandEmpty","CmdkEmpty","CommandGroup","CmdkGroup","CommandItem","CmdkItem","CommandSeparator","CmdkSeparator","CommandLoading","CmdkLoading","_$className"],"sources":["../../../../src/components/ui/command/command.tsx"],"sourcesContent":["import {\n CommandDialog as CmdkDialog,\n CommandEmpty as CmdkEmpty,\n CommandGroup as CmdkGroup,\n CommandInput as CmdkInput,\n CommandItem as CmdkItem,\n CommandList as CmdkList,\n CommandLoading as CmdkLoading,\n CommandRoot as CmdkRoot,\n CommandSeparator as CmdkSeparator,\n useCommandState,\n} from 'cmdk-solid'\nimport { Dialog as KobalteDialog } from '@kobalte/core/dialog'\nimport { Search } from 'lucide-solid'\nimport type { ComponentProps } from 'solid-js'\nimport { createEffect, createSignal, splitProps } from 'solid-js'\nimport { createDialogFocusRestoration } from '../dialog/dialog'\nimport { menuItem } from '#lib/overlay'\nimport { cn } from '#lib/utils'\n\n// cmdk emits data-disabled=\"false\" on enabled items, unlike the presence-only\n// attributes Kobalte menu rows use. Apply those shared disabled styles only when\n// cmdk's value is true.\nconst commandItem = menuItem\n .replace('data-[disabled]:pointer-events-none', '')\n .replace('data-[disabled]:text-muted-foreground', '')\n\n/**\n * Command.\n *\n * The command palette: a filtered list of everything the user can do, ranked\n * by fuzzy match. It is the one place in an app where a keyboard-first surface\n * is the *primary* one, so it carries rules the rest of the system does not:\n *\n * - Every item must be reachable by typing its name. If a user has to\n * remember which group it lives in, the palette has failed at its job.\n * - Groups exist for reading, not for navigation. The ranking crosses them.\n * - The empty state is not an apology — it should offer the closest thing\n * the app could guess, or say plainly that nothing matched.\n *\n * cmdk-solid supplies the filter, the scoring, the `aria-activedescendant`\n * wiring and the arrow-key navigation.\n */\nexport function Command(props: ComponentProps<typeof CmdkRoot>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <CmdkRoot\n class={cn(\n 'bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-xl',\n local.class\n )}\n {...rest}\n />\n )\n}\n\ntype CommandDialogProps = ComponentProps<typeof CmdkDialog> &\n Pick<ComponentProps<typeof KobalteDialog.Content>, 'onCloseAutoFocus' | 'onOpenAutoFocus'>\n\nexport function CommandDialog(props: CommandDialogProps) {\n // cmdk-solid's Dialog does not forward Content autofocus props: unknown\n // props fall through to its Command root. Compose Kobalte's dialog surface\n // here so Escape and other close paths can restore focus to the real opener.\n // Preserve the shared wrapper's `class` contract on the dialog surface;\n // `contentClassName` adds to it, while the nested Command keeps its own API.\n const [local, dialogProps, commandProps] = splitProps(\n props,\n [\n 'class',\n 'contentClassName',\n 'overlayClassName',\n 'container',\n 'onCloseAutoFocus',\n 'onOpenAutoFocus',\n ],\n [\n 'open',\n 'defaultOpen',\n 'onOpenChange',\n 'id',\n 'modal',\n 'preventScroll',\n 'forceMount',\n 'translations',\n ]\n )\n const [isOpen, setIsOpen] = createSignal(dialogProps.open ?? dialogProps.defaultOpen ?? false)\n\n createEffect(() => {\n if (dialogProps.open !== undefined) setIsOpen(dialogProps.open)\n })\n\n const focus = createDialogFocusRestoration({\n open: isOpen,\n onCloseAutoFocus: local.onCloseAutoFocus,\n onOpenAutoFocus: local.onOpenAutoFocus,\n })\n\n return (\n <KobalteDialog\n {...dialogProps}\n onOpenChange={(open) => {\n setIsOpen(open)\n dialogProps.onOpenChange?.(open)\n }}\n >\n <KobalteDialog.Portal mount={local.container}>\n <KobalteDialog.Overlay cmdk-overlay=\"\" class={local.overlayClassName} />\n <KobalteDialog.Content\n aria-label={commandProps.label}\n cmdk-dialog=\"\"\n role=\"dialog\"\n class={cn(\n 'bg-popover text-popover-foreground fixed top-1/3 left-1/2 z-(--z-dialog) w-full max-w-lg -translate-x-1/2 -translate-y-1/2',\n 'overflow-hidden rounded-xl border border-border shadow-xl',\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 local.class,\n local.contentClassName\n )}\n onOpenAutoFocus={focus.onOpenAutoFocus}\n onCloseAutoFocus={focus.onCloseAutoFocus}\n >\n <Command {...commandProps} />\n </KobalteDialog.Content>\n </KobalteDialog.Portal>\n </KobalteDialog>\n )\n}\n\nexport function CommandInput(props: ComponentProps<typeof CmdkInput>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <div\n data-slot=\"command-input-wrapper\"\n class=\"flex h-11 items-center gap-2 border-b border-border px-3\"\n >\n <Search class=\"size-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <CmdkInput\n class={cn(\n 'h-full w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n local.class\n )}\n {...rest}\n />\n </div>\n )\n}\n\n/**\n * The scrolling list.\n *\n * Two DOM corrections, and both are deliberate. cmdk builds a `role=\"listbox\"`\n * whose children include two elements ARIA does not allow there:\n *\n * - a bare `<div cmdk-list-sizer>` with no role, wrapped around every group;\n * - a `<div cmdk-separator role=\"separator\">`, and `separator` is a menu and\n * toolbar role — inside a listbox the only owned elements may be `option`\n * and `group`.\n *\n * Both are pure presentation: the sizer is layout, and the separator is a\n * hairline between groups that the groups already structure. `role=\"presentation\"`\n * is their accurate role rather than a workaround — each is flattened out of the\n * accessibility tree, and the options inside are reached exactly as before.\n *\n * Written onto the mounted nodes rather than through props, because cmdk owns\n * this markup and does not forward a `ref`; in an effect rather than `onMount`,\n * because cmdk renders the sizer with the first item, after the list itself.\n */\nexport function CommandList(props: ComponentProps<typeof CmdkList>) {\n const [local, rest] = splitProps(props, ['class'])\n const [wrapper, setWrapper] = createSignal<HTMLDivElement>()\n const resultCount = useCommandState((state) => state.filtered.count)\n\n createEffect(() => {\n const root = wrapper()\n if (!root) return\n for (const selector of ['[cmdk-list-sizer]', '[cmdk-separator]']) {\n root.querySelector(selector)?.setAttribute('role', 'presentation')\n }\n\n /*\n * A `listbox` must own at least one `option`, so a listbox with nothing in it\n * is invalid ARIA — which is what a search with no matches produces. When\n * there are no results the list is inert, so it becomes presentational and\n * the empty message carries the information instead. It keeps its `id`, so\n * the input's `aria-controls` still resolves.\n */\n root\n .querySelector('[cmdk-list]')\n ?.setAttribute('role', resultCount() > 0 ? 'listbox' : 'presentation')\n })\n\n return (\n <div ref={setWrapper} class=\"contents\">\n <CmdkList\n class={cn('max-h-80 scroll-py-1 overflow-y-auto overflow-x-hidden p-1', local.class)}\n {...rest}\n />\n </div>\n )\n}\n\nexport function CommandEmpty(props: ComponentProps<typeof CmdkEmpty>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <CmdkEmpty\n /*\n * A status rather than plain text: when the list is presentational, this is\n * the only thing that tells a screen reader the search matched nothing.\n */\n role=\"status\"\n class={cn('text-muted-foreground py-8 text-center text-sm', local.class)}\n {...rest}\n />\n )\n}\n\nexport function CommandGroup(props: ComponentProps<typeof CmdkGroup>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <CmdkGroup\n class={cn(\n 'text-foreground overflow-hidden p-1',\n '[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-2xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:tracking-wide [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:uppercase',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function CommandItem(props: ComponentProps<typeof CmdkItem>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <CmdkItem\n class={cn(\n commandItem,\n 'data-[disabled=true]:pointer-events-none data-[disabled=true]:text-muted-foreground',\n // The selected row sits on the accent rung — the same primary-subtle\n // fill the settings navigation's selected row owns — instead of the\n // popover rung, so what is chosen keeps the accent the checked menus\n // already carry in their indicators.\n 'group/command-item text-popover-foreground data-[selected=true]:bg-primary-subtle data-[selected=true]:text-foreground',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function CommandSeparator(props: ComponentProps<typeof CmdkSeparator>) {\n const [local, rest] = splitProps(props, ['class'])\n return <CmdkSeparator class={cn('bg-border -mx-1 my-1 h-px', local.class)} {...rest} />\n}\n\nexport function CommandLoading(props: ComponentProps<typeof CmdkLoading>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <CmdkLoading\n class={cn('text-muted-foreground py-6 text-center text-sm', local.class)}\n {...rest}\n />\n )\n}\n\n/** The keyboard hint a palette item usually carries. */\nexport function CommandShortcut(props: {\n class?: string\n children?: ComponentProps<'span'>['children']\n}) {\n return (\n <span\n class={cn(\n 'text-muted-foreground ms-auto font-code text-code tracking-widest group-data-[selected=true]/command-item:text-foreground',\n props.class\n )}\n >\n {props.children}\n </span>\n )\n}\n"],"mappings":"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"}
|
|
@@ -98,7 +98,7 @@ function TabsTrigger(props) {
|
|
|
98
98
|
return triggerId();
|
|
99
99
|
},
|
|
100
100
|
get ["class"]() {
|
|
101
|
-
return cn("inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap text-sm font-medium", "transition-colors ease-out outline-none select-none", "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle", "disabled:pointer-events-none disabled:opacity-50", "text-foreground", "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4", local.appearance === "segmented" ? "h-control-sm rounded-md px-control-sm data-[selected]:bg-
|
|
101
|
+
return cn("inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap text-sm font-medium", "transition-colors ease-out outline-none select-none", "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle", "disabled:pointer-events-none disabled:opacity-50", "text-foreground", "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4", local.appearance === "segmented" ? "h-control-sm rounded-md px-control-sm data-[selected]:bg-primary-subtle data-[selected]:text-foreground" : tabs.orientation() === "vertical" ? "h-control-md justify-start rounded-none border-s-2 border-transparent ps-3 pe-2 data-[selected]:border-primary" : "h-control-md -mb-px rounded-none border-b-2 border-transparent px-2 pb-2 data-[selected]:border-primary", local.class);
|
|
102
102
|
}
|
|
103
103
|
}, rest));
|
|
104
104
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.js","names":["Tabs","KobalteTabs","Accessor","ComponentProps","createContext","createRenderEffect","createSignal","createUniqueId","onCleanup","splitProps","useContext","cn","TabsIdContextValue","id","orientation","triggerIds","ReadonlyMap","registerTriggerId","value","unregisterTriggerId","TabsIdContext","useTabsId","tabs","Error","props","local","rest","generatedId","setTriggerIds","Map","triggerId","current","set","get","next","delete","_$createComponent","Provider","children","_$mergeProps","class","TabsListProps","List","appearance","TabsList","TabsTriggerProps","Trigger","TabsTrigger","TabsContent","Content","aria-labelledby","Tabs","_$createComponent","KobalteTabs","_$mergeProps"],"sources":["../../../../src/components/ui/tabs/tabs.tsx"],"sourcesContent":["import { Tabs as KobalteTabs } from '@kobalte/core/tabs'\nimport type { Accessor, ComponentProps } from 'solid-js'\nimport {\n createContext,\n createRenderEffect,\n createSignal,\n createUniqueId,\n onCleanup,\n splitProps,\n useContext,\n} from 'solid-js'\nimport { cn } from '#lib/utils'\n\ntype TabsIdContextValue = {\n id: Accessor<string>\n orientation: Accessor<'horizontal' | 'vertical'>\n triggerIds: Accessor<ReadonlyMap<string, string>>\n registerTriggerId: (value: string, id: string) => void\n unregisterTriggerId: (value: string, id: string) => void\n}\n\nconst TabsIdContext = createContext<TabsIdContextValue>()\n\nfunction useTabsId() {\n const tabs = useContext(TabsIdContext)\n if (!tabs) throw new Error('[adea-ui]: Tabs parts must be used within Tabs.')\n return tabs\n}\n\n/**\n * Tabs.\n *\n * For switching between sibling views of the *same* subject — a file's code,\n * diff and history. Not for moving between pages: a tab is expected to keep\n * its panel and its scroll position, which a route does not.\n *\n * `appearance=\"segmented\"` gives the joined bar KiroCrew uses inside a pane\n * where a full-width underline would collide with the panel's own header rule.\n */\nexport function Tabs(props: ComponentProps<typeof KobalteTabs>) {\n const [local, rest] = splitProps(props, ['class', 'id'])\n const generatedId = `tabs-${createUniqueId()}`\n const id = () => local.id ?? generatedId\n const [triggerIds, setTriggerIds] = createSignal<ReadonlyMap<string, string>>(new Map())\n const tabs: TabsIdContextValue = {\n id,\n orientation: () => rest.orientation ?? 'horizontal',\n triggerIds,\n registerTriggerId: (value, triggerId) => {\n setTriggerIds((current) => new Map(current).set(value, triggerId))\n },\n unregisterTriggerId: (value, triggerId) => {\n setTriggerIds((current) => {\n if (current.get(value) !== triggerId) return current\n const next = new Map(current)\n next.delete(value)\n return next\n })\n },\n }\n\n return (\n <TabsIdContext.Provider value={tabs}>\n <KobalteTabs\n id={id()}\n class={cn(\n 'flex min-h-0 min-w-0 flex-col gap-2 data-[orientation=vertical]:flex-row',\n local.class\n )}\n {...rest}\n />\n </TabsIdContext.Provider>\n )\n}\n\nexport type TabsListProps = ComponentProps<typeof KobalteTabs.List> & {\n appearance?: 'underline' | 'segmented'\n}\n\n/**\n * The underline appearance's rule is the baseline a horizontal row of tabs sits\n * on. A vertical list has no baseline — its triggers stack — so the rule is\n * dropped there; otherwise it draws as a stray line under the last trigger,\n * spanning only the list's width (the SettingsLayout rail showed exactly that).\n */\nexport function TabsList(props: TabsListProps) {\n const [local, rest] = splitProps(props, ['class', 'appearance'])\n\n return (\n <KobalteTabs.List\n class={cn(\n 'inline-flex w-fit shrink-0 items-center justify-center',\n local.appearance === 'segmented'\n ? 'gap-0.5 rounded-lg bg-surface-hover p-0.5'\n : 'gap-1 rounded-none border-b border-border data-[orientation=vertical]:border-b-0',\n 'data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport type TabsTriggerProps = ComponentProps<typeof KobalteTabs.Trigger> & {\n appearance?: 'underline' | 'segmented'\n}\n\n/**\n * The underline appearance marks the selected trigger on the edge it shares\n * with the list's axis. A horizontal row reads left to right along a baseline,\n * so the mark is a bottom bar sitting on the list's rule. A vertical list stacks\n * its triggers, and a bottom bar there underlines one row of a column — it reads\n * as a divider, not a selection — so the mark moves to the inline-start edge,\n * the leading bar a side navigation uses, and the label aligns to that edge.\n *\n * The orientation is read from the root rather than from a `data-orientation`\n * selector so the vertical classes are unprefixed: a composite that replaces the\n * mark (SettingsNavigation's filled row passes `border-0`) then overrides it\n * through the ordinary class merge instead of fighting a variant-scoped border.\n */\nexport function TabsTrigger(props: TabsTriggerProps) {\n const [local, rest] = splitProps(props, ['class', 'appearance', 'id'])\n const tabs = useTabsId()\n const triggerId = () => local.id ?? `${tabs.id()}-trigger-${rest.value}`\n\n // Register before panels render, including SSR where createEffect is skipped.\n createRenderEffect(() => {\n const value = rest.value\n const id = triggerId()\n tabs.registerTriggerId(value, id)\n onCleanup(() => tabs.unregisterTriggerId(value, id))\n })\n\n return (\n <KobalteTabs.Trigger\n id={triggerId()}\n class={cn(\n 'inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap text-sm font-medium',\n 'transition-colors ease-out outline-none select-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'disabled:pointer-events-none disabled:opacity-50',\n 'text-foreground',\n '[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4',\n local.appearance === 'segmented'\n ? 'h-control-sm rounded-md px-control-sm data-[selected]:bg-
|
|
1
|
+
{"version":3,"file":"tabs.js","names":["Tabs","KobalteTabs","Accessor","ComponentProps","createContext","createRenderEffect","createSignal","createUniqueId","onCleanup","splitProps","useContext","cn","TabsIdContextValue","id","orientation","triggerIds","ReadonlyMap","registerTriggerId","value","unregisterTriggerId","TabsIdContext","useTabsId","tabs","Error","props","local","rest","generatedId","setTriggerIds","Map","triggerId","current","set","get","next","delete","_$createComponent","Provider","children","_$mergeProps","class","TabsListProps","List","appearance","TabsList","TabsTriggerProps","Trigger","TabsTrigger","TabsContent","Content","aria-labelledby","Tabs","_$createComponent","KobalteTabs","_$mergeProps"],"sources":["../../../../src/components/ui/tabs/tabs.tsx"],"sourcesContent":["import { Tabs as KobalteTabs } from '@kobalte/core/tabs'\nimport type { Accessor, ComponentProps } from 'solid-js'\nimport {\n createContext,\n createRenderEffect,\n createSignal,\n createUniqueId,\n onCleanup,\n splitProps,\n useContext,\n} from 'solid-js'\nimport { cn } from '#lib/utils'\n\ntype TabsIdContextValue = {\n id: Accessor<string>\n orientation: Accessor<'horizontal' | 'vertical'>\n triggerIds: Accessor<ReadonlyMap<string, string>>\n registerTriggerId: (value: string, id: string) => void\n unregisterTriggerId: (value: string, id: string) => void\n}\n\nconst TabsIdContext = createContext<TabsIdContextValue>()\n\nfunction useTabsId() {\n const tabs = useContext(TabsIdContext)\n if (!tabs) throw new Error('[adea-ui]: Tabs parts must be used within Tabs.')\n return tabs\n}\n\n/**\n * Tabs.\n *\n * For switching between sibling views of the *same* subject — a file's code,\n * diff and history. Not for moving between pages: a tab is expected to keep\n * its panel and its scroll position, which a route does not.\n *\n * `appearance=\"segmented\"` gives the joined bar KiroCrew uses inside a pane\n * where a full-width underline would collide with the panel's own header rule.\n */\nexport function Tabs(props: ComponentProps<typeof KobalteTabs>) {\n const [local, rest] = splitProps(props, ['class', 'id'])\n const generatedId = `tabs-${createUniqueId()}`\n const id = () => local.id ?? generatedId\n const [triggerIds, setTriggerIds] = createSignal<ReadonlyMap<string, string>>(new Map())\n const tabs: TabsIdContextValue = {\n id,\n orientation: () => rest.orientation ?? 'horizontal',\n triggerIds,\n registerTriggerId: (value, triggerId) => {\n setTriggerIds((current) => new Map(current).set(value, triggerId))\n },\n unregisterTriggerId: (value, triggerId) => {\n setTriggerIds((current) => {\n if (current.get(value) !== triggerId) return current\n const next = new Map(current)\n next.delete(value)\n return next\n })\n },\n }\n\n return (\n <TabsIdContext.Provider value={tabs}>\n <KobalteTabs\n id={id()}\n class={cn(\n 'flex min-h-0 min-w-0 flex-col gap-2 data-[orientation=vertical]:flex-row',\n local.class\n )}\n {...rest}\n />\n </TabsIdContext.Provider>\n )\n}\n\nexport type TabsListProps = ComponentProps<typeof KobalteTabs.List> & {\n appearance?: 'underline' | 'segmented'\n}\n\n/**\n * The underline appearance's rule is the baseline a horizontal row of tabs sits\n * on. A vertical list has no baseline — its triggers stack — so the rule is\n * dropped there; otherwise it draws as a stray line under the last trigger,\n * spanning only the list's width (the SettingsLayout rail showed exactly that).\n */\nexport function TabsList(props: TabsListProps) {\n const [local, rest] = splitProps(props, ['class', 'appearance'])\n\n return (\n <KobalteTabs.List\n class={cn(\n 'inline-flex w-fit shrink-0 items-center justify-center',\n local.appearance === 'segmented'\n ? 'gap-0.5 rounded-lg bg-surface-hover p-0.5'\n : 'gap-1 rounded-none border-b border-border data-[orientation=vertical]:border-b-0',\n 'data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport type TabsTriggerProps = ComponentProps<typeof KobalteTabs.Trigger> & {\n appearance?: 'underline' | 'segmented'\n}\n\n/**\n * The underline appearance marks the selected trigger on the edge it shares\n * with the list's axis. A horizontal row reads left to right along a baseline,\n * so the mark is a bottom bar sitting on the list's rule. A vertical list stacks\n * its triggers, and a bottom bar there underlines one row of a column — it reads\n * as a divider, not a selection — so the mark moves to the inline-start edge,\n * the leading bar a side navigation uses, and the label aligns to that edge.\n *\n * The orientation is read from the root rather than from a `data-orientation`\n * selector so the vertical classes are unprefixed: a composite that replaces the\n * mark (SettingsNavigation's filled row passes `border-0`) then overrides it\n * through the ordinary class merge instead of fighting a variant-scoped border.\n */\nexport function TabsTrigger(props: TabsTriggerProps) {\n const [local, rest] = splitProps(props, ['class', 'appearance', 'id'])\n const tabs = useTabsId()\n const triggerId = () => local.id ?? `${tabs.id()}-trigger-${rest.value}`\n\n // Register before panels render, including SSR where createEffect is skipped.\n createRenderEffect(() => {\n const value = rest.value\n const id = triggerId()\n tabs.registerTriggerId(value, id)\n onCleanup(() => tabs.unregisterTriggerId(value, id))\n })\n\n return (\n <KobalteTabs.Trigger\n id={triggerId()}\n class={cn(\n 'inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap text-sm font-medium',\n 'transition-colors ease-out outline-none select-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'disabled:pointer-events-none disabled:opacity-50',\n 'text-foreground',\n '[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4',\n local.appearance === 'segmented'\n ? 'h-control-sm rounded-md px-control-sm data-[selected]:bg-primary-subtle data-[selected]:text-foreground'\n : tabs.orientation() === 'vertical'\n ? 'h-control-md justify-start rounded-none border-s-2 border-transparent ps-3 pe-2 data-[selected]:border-primary'\n : 'h-control-md -mb-px rounded-none border-b-2 border-transparent px-2 pb-2 data-[selected]:border-primary',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function TabsContent(props: ComponentProps<typeof KobalteTabs.Content>) {\n const [local, rest] = splitProps(props, ['class', 'aria-labelledby'])\n const tabs = useTabsId()\n return (\n <KobalteTabs.Content\n aria-labelledby={\n local['aria-labelledby'] ??\n tabs.triggerIds().get(rest.value) ??\n `${tabs.id()}-trigger-${rest.value}`\n }\n class={cn('min-h-0 min-w-0 flex-1 outline-none', local.class)}\n {...rest}\n />\n )\n}\n"],"mappings":"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"}
|
|
@@ -11,7 +11,10 @@ import { type VariantProps } from '#lib/variants';
|
|
|
11
11
|
*
|
|
12
12
|
* Kobalte supplies the pressed state and the keyboard behaviour; the styling
|
|
13
13
|
* adds the one thing a headless primitive cannot know — that a pressed toggle
|
|
14
|
-
* in a toolbar should read as *filled*, not merely outlined.
|
|
14
|
+
* in a toolbar should read as *filled*, not merely outlined. Pressed reads on
|
|
15
|
+
* the accent rung (`primary-subtle` with the accent glyph): pressed is the
|
|
16
|
+
* control's on state, the same family the checked checkbox and switch own, so
|
|
17
|
+
* it keeps a touch of the user's accent instead of a neutral fill.
|
|
15
18
|
*/
|
|
16
19
|
export declare const toggleVariants: (props?: ({
|
|
17
20
|
variant?: "default" | "outline" | "subtle" | null | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toggle.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/toggle/toggle.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE9C,OAAO,EAAwC,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAGvF
|
|
1
|
+
{"version":3,"file":"toggle.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/toggle/toggle.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE9C,OAAO,EAAwC,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAGvF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc;;;8EA8B1B,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,YAAY,CAAC,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,CAAA;AAEnG,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,kCASxC"}
|
|
@@ -14,9 +14,12 @@ import { ToggleButton } from "@kobalte/core/toggle-button";
|
|
|
14
14
|
*
|
|
15
15
|
* Kobalte supplies the pressed state and the keyboard behaviour; the styling
|
|
16
16
|
* adds the one thing a headless primitive cannot know — that a pressed toggle
|
|
17
|
-
* in a toolbar should read as *filled*, not merely outlined.
|
|
17
|
+
* in a toolbar should read as *filled*, not merely outlined. Pressed reads on
|
|
18
|
+
* the accent rung (`primary-subtle` with the accent glyph): pressed is the
|
|
19
|
+
* control's on state, the same family the checked checkbox and switch own, so
|
|
20
|
+
* it keeps a touch of the user's accent instead of a neutral fill.
|
|
18
21
|
*/
|
|
19
|
-
var toggleVariants = cva(`${controlInteractive} inline-flex items-center justify-center rounded-md font-medium whitespace-nowrap select-none hover:bg-surface-hover hover:text-foreground data-[pressed]:bg-
|
|
22
|
+
var toggleVariants = cva(`${controlInteractive} inline-flex items-center justify-center rounded-md font-medium whitespace-nowrap select-none hover:bg-surface-hover hover:text-foreground data-[pressed]:bg-primary-subtle data-[pressed]:text-primary disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0`, {
|
|
20
23
|
variants: {
|
|
21
24
|
variant: {
|
|
22
25
|
default: "bg-transparent",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toggle.js","names":["ToggleButton","ComponentProps","splitProps","cva","controlInteractive","controlSize","VariantProps","cn","toggleVariants","variants","variant","default","outline","subtle","size","xs","sm","md","lg","xl","defaultVariants","ToggleProps","Toggle","props","local","rest","_$createComponent","_$mergeProps","class","_$createComponent","_$mergeProps"],"sources":["../../../../src/components/ui/toggle/toggle.tsx"],"sourcesContent":["import { ToggleButton } from '@kobalte/core/toggle-button'\nimport type { ComponentProps } from 'solid-js'\nimport { splitProps } from 'solid-js'\nimport { cva, controlInteractive, controlSize, type VariantProps } from '#lib/variants'\nimport { cn } from '#lib/utils'\n\n/**\n * Toggle.\n *\n * A button that stays pressed. The difference from Button is state, not looks:\n * a Toggle reports `aria-pressed` and holds its pressed appearance until\n * released, which is what makes it right for a formatting control and wrong\n * for a command.\n *\n * Kobalte supplies the pressed state and the keyboard behaviour; the styling\n * adds the one thing a headless primitive cannot know — that a pressed toggle\n * in a toolbar should read as *filled*, not merely outlined.\n */\nexport const toggleVariants = cva(\n `${controlInteractive} inline-flex items-center justify-center rounded-md font-medium whitespace-nowrap select-none hover:bg-surface-hover hover:text-foreground data-[pressed]:bg-
|
|
1
|
+
{"version":3,"file":"toggle.js","names":["ToggleButton","ComponentProps","splitProps","cva","controlInteractive","controlSize","VariantProps","cn","toggleVariants","variants","variant","default","outline","subtle","size","xs","sm","md","lg","xl","defaultVariants","ToggleProps","Toggle","props","local","rest","_$createComponent","_$mergeProps","class","_$createComponent","_$mergeProps"],"sources":["../../../../src/components/ui/toggle/toggle.tsx"],"sourcesContent":["import { ToggleButton } from '@kobalte/core/toggle-button'\nimport type { ComponentProps } from 'solid-js'\nimport { splitProps } from 'solid-js'\nimport { cva, controlInteractive, controlSize, type VariantProps } from '#lib/variants'\nimport { cn } from '#lib/utils'\n\n/**\n * Toggle.\n *\n * A button that stays pressed. The difference from Button is state, not looks:\n * a Toggle reports `aria-pressed` and holds its pressed appearance until\n * released, which is what makes it right for a formatting control and wrong\n * for a command.\n *\n * Kobalte supplies the pressed state and the keyboard behaviour; the styling\n * adds the one thing a headless primitive cannot know — that a pressed toggle\n * in a toolbar should read as *filled*, not merely outlined. Pressed reads on\n * the accent rung (`primary-subtle` with the accent glyph): pressed is the\n * control's on state, the same family the checked checkbox and switch own, so\n * it keeps a touch of the user's accent instead of a neutral fill.\n */\nexport const toggleVariants = cva(\n `${controlInteractive} inline-flex items-center justify-center rounded-md font-medium whitespace-nowrap select-none hover:bg-surface-hover hover:text-foreground data-[pressed]:bg-primary-subtle data-[pressed]:text-primary disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0`,\n {\n variants: {\n variant: {\n default: 'bg-transparent',\n /** Sits inside a field or toolbar that already has a fill. */\n outline: 'border border-border bg-transparent',\n /** Filled even when unpressed, for a segmented control's idle item. */\n subtle: 'bg-surface-hover',\n },\n size: {\n '2xs': `${controlSize['2xs']} [&_svg]:size-3`,\n xs: `${controlSize.xs} [&_svg]:size-3.5`,\n sm: `${controlSize.sm} [&_svg]:size-3.5`,\n md: `${controlSize.md} [&_svg]:size-4`,\n lg: `${controlSize.lg} [&_svg]:size-4`,\n xl: `${controlSize.xl} [&_svg]:size-5`,\n '2xl': `${controlSize['2xl']} [&_svg]:size-6`,\n 'icon-2xs': 'size-control-2xs p-0 [&_svg]:size-3',\n 'icon-xs': 'size-control-xs p-0 [&_svg]:size-3.5',\n 'icon-sm': 'size-control-sm p-0 [&_svg]:size-3.5',\n 'icon-md': 'size-control-md p-0 [&_svg]:size-4',\n 'icon-lg': 'size-control-lg p-0 [&_svg]:size-4',\n 'icon-xl': 'size-control-xl p-0 [&_svg]:size-5',\n 'icon-2xl': 'size-control-2xl p-0 [&_svg]:size-6',\n },\n },\n defaultVariants: { variant: 'default', size: 'md' },\n }\n)\n\nexport type ToggleProps = ComponentProps<typeof ToggleButton> & VariantProps<typeof toggleVariants>\n\nexport function Toggle(props: ToggleProps) {\n const [local, rest] = splitProps(props, ['variant', 'size', 'class'])\n\n return (\n <ToggleButton\n class={cn(toggleVariants({ variant: local.variant, size: local.size }), local.class)}\n {...rest}\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,IAAaQ,iBAAiBL,IAC5B,GAAGC,mBAAkB,wSACrB;CACEK,UAAU;EACRC,SAAS;GACPC,SAAS;;GAETC,SAAS;;GAETC,QAAQ;EACV;EACAC,MAAM;GACJ,OAAO,GAAGT,YAAY,OAAM;GAC5BU,IAAI,GAAGV,YAAYU,GAAE;GACrBC,IAAI,GAAGX,YAAYW,GAAE;GACrBC,IAAI,GAAGZ,YAAYY,GAAE;GACrBC,IAAI,GAAGb,YAAYa,GAAE;GACrBC,IAAI,GAAGd,YAAYc,GAAE;GACrB,OAAO,GAAGd,YAAY,OAAM;GAC5B,YAAY;GACZ,WAAW;GACX,WAAW;GACX,WAAW;GACX,WAAW;GACX,WAAW;GACX,YAAY;EACd;CACF;CACAe,iBAAiB;EAAEV,SAAS;EAAWI,MAAM;CAAK;AACpD,CACF;AAIA,SAAgBQ,OAAOC,OAAoB;CACzC,MAAM,CAACC,OAAOC,QAAQvB,WAAWqB,OAAO;EAAC;EAAW;EAAQ;CAAO,CAAC;CAEpE,OAAAG,gBACG1B,cAAY2B,WAAA,EAAA,KAAA,WAAA;EAAA,OACJpB,GAAGC,eAAe;GAAEE,SAASc,MAAMd;GAASI,MAAMU,MAAMV;EAAK,CAAC,GAAGU,MAAMI,KAAK;CAAC,EAAA,GAChFH,IAAI,CAAA;AAGd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/tooltip/tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAqB,MAAM,uBAAuB,CAAA;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/tooltip/tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAqB,MAAM,uBAAuB,CAAA;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AA2InD,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAA;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,eAY1D;AAED,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,cAAc,CAAC,CAAA;AAEpE,wBAAgB,OAAO,CAAC,KAAK,EAAE,gBAAgB,eAyJ9C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,eA0ClF;AAED,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,GAAG;IAChF;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CACnB,CAAA;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,eAwExD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { cn } from "../../../lib/utils.js";
|
|
2
2
|
import { tooltipTip, topLayerProps } from "../../../lib/overlay.js";
|
|
3
|
+
import { acquireTooltipFocusGate, releaseTooltipFocusGate } from "../../../lib/tooltip-focus-gate.js";
|
|
3
4
|
import { createComponent, insert, isServer, memo, mergeProps, template } from "solid-js/web";
|
|
4
5
|
import { Show, createContext, createEffect, createSignal, createUniqueId, onCleanup, splitProps, useContext } from "solid-js";
|
|
5
6
|
import { Tooltip, useTooltipContext } from "@kobalte/core/tooltip";
|
|
@@ -88,6 +89,10 @@ function TooltipProvider(props) {
|
|
|
88
89
|
});
|
|
89
90
|
}
|
|
90
91
|
function Tooltip$1(props) {
|
|
92
|
+
if (!isServer) {
|
|
93
|
+
acquireTooltipFocusGate();
|
|
94
|
+
onCleanup(releaseTooltipFocusGate);
|
|
95
|
+
}
|
|
91
96
|
const timing = useContext(TooltipTimingContext);
|
|
92
97
|
const [local, rest] = splitProps(props, [
|
|
93
98
|
"open",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tooltip.js","names":["Tooltip","KobalteTooltip","useTooltipContext","ComponentProps","JSX","createContext","createEffect","createSignal","createUniqueId","onCleanup","Show","splitProps","useContext","isServer","tooltipTip","topLayerProps","cn","TooltipTiming","openDelay","closeDelay","skipDelayDuration","tooltipDefaults","TooltipTimingContext","TooltipInteraction","id","trigger","HTMLElement","setTrigger","element","isOpen","isDisabled","isTriggerFocused","markOpenIntent","clearOpenIntent","requestCloseFromAnotherTooltip","markPointerCloseIntent","clearPointerCloseIntent","markCloseIntent","TooltipInteractionContext","openTooltipInteractions","Set","pendingTooltipOpenId","tooltipScrollListenerAttached","clearPendingTooltipOpen","undefined","tooltipScrollContainsTrigger","event","Event","target","window","Node","contains","handleTooltipScroll","interaction","handleTooltipPointerMove","PointerEvent","setTooltipInteractionOpen","open","has","add","addEventListener","document","delete","size","removeEventListener","registerTooltipInteraction","invokeEventHandler","handler","Array","isArray","callback","data","TooltipProviderProps","children","TooltipProvider","props","_$createComponent","Provider","value","TooltipRootProps","timing","local","rest","controlled","uncontrolledOpen","setUncontrolledOpen","defaultOpen","closeIntent","ignoreDuplicateClose","onOpenChange","next","source","pointerCloseIntentUntil","pointerCloseIntentTimeout","ReturnType","setTimeout","clearTimeout","Date","now","queueMicrotask","disabled","Boolean","activeElement","openInteraction","focusedTrigger","anotherTooltipOpening","pointerClosePending","handleKeyDown","KeyboardEvent","key","_$mergeProps","TooltipTrigger","Trigger","ref","onFocus","defaultPrevented","onBlur","onPointerEnter","onPointerLeave","onClick","TooltipContentProps","Content","icon","Element","TooltipContent","context","Portal","class","style","aria-hidden","_$memo","onEscapeKeyDown","onPointerDownOutside","when","_el$","_tmpl$","_$insert","_$createComponent","Tooltip","KobalteTooltip","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/tooltip/tooltip.tsx"],"sourcesContent":["import { Tooltip as KobalteTooltip, useTooltipContext } from '@kobalte/core/tooltip'\nimport type { ComponentProps, JSX } from 'solid-js'\nimport {\n createContext,\n createEffect,\n createSignal,\n createUniqueId,\n onCleanup,\n Show,\n splitProps,\n useContext,\n} from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport { tooltipTip, topLayerProps } from '#lib/overlay'\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\ntype TooltipInteraction = {\n id: string\n trigger: () => HTMLElement | undefined\n setTrigger: (element: HTMLElement) => void\n isOpen: () => boolean\n isDisabled: () => boolean\n isTriggerFocused: () => boolean\n markOpenIntent: () => void\n clearOpenIntent: () => void\n requestCloseFromAnotherTooltip: () => void\n markPointerCloseIntent: () => void\n clearPointerCloseIntent: () => void\n markCloseIntent: () => void\n}\n\nconst TooltipInteractionContext = createContext<TooltipInteraction>()\nconst openTooltipInteractions = new Set<TooltipInteraction>()\nlet pendingTooltipOpenId: string | undefined\nlet tooltipScrollListenerAttached = false\n\nfunction clearPendingTooltipOpen(id: string) {\n if (pendingTooltipOpenId === id) pendingTooltipOpenId = undefined\n}\n\nfunction tooltipScrollContainsTrigger(event: Event, trigger: HTMLElement) {\n const target = event.target\n return target === window || (target instanceof Node && target.contains(trigger))\n}\n\nfunction handleTooltipScroll(event: Event) {\n for (const interaction of openTooltipInteractions) {\n const trigger = interaction.trigger()\n if (interaction.isOpen() && trigger && tooltipScrollContainsTrigger(event, trigger)) {\n interaction.markCloseIntent()\n }\n }\n}\n\nfunction handleTooltipPointerMove(event: PointerEvent) {\n for (const interaction of openTooltipInteractions) {\n const trigger = interaction.trigger()\n const target = event.target\n if (\n interaction.isOpen() &&\n interaction.isTriggerFocused() &&\n trigger &&\n !(target instanceof Node && trigger.contains(target))\n ) {\n interaction.markPointerCloseIntent()\n }\n }\n}\n\nfunction setTooltipInteractionOpen(interaction: TooltipInteraction, open: boolean) {\n if (isServer) return\n\n if (open) {\n if (openTooltipInteractions.has(interaction)) return\n openTooltipInteractions.add(interaction)\n if (!tooltipScrollListenerAttached) {\n tooltipScrollListenerAttached = true\n // Register before Kobalte's global listeners so intentional scroll\n // dismissal can be distinguished from its delayed pointer dismissal.\n window.addEventListener('scroll', handleTooltipScroll, true)\n document.addEventListener('pointermove', handleTooltipPointerMove, true)\n }\n } else {\n openTooltipInteractions.delete(interaction)\n if (openTooltipInteractions.size === 0 && tooltipScrollListenerAttached) {\n tooltipScrollListenerAttached = false\n window.removeEventListener('scroll', handleTooltipScroll, true)\n document.removeEventListener('pointermove', handleTooltipPointerMove, true)\n }\n }\n}\n\nfunction registerTooltipInteraction(interaction: TooltipInteraction) {\n onCleanup(() => {\n setTooltipInteractionOpen(interaction, false)\n clearPendingTooltipOpen(interaction.id)\n })\n}\n\nfunction invokeEventHandler(handler: unknown, event: Event) {\n if (Array.isArray(handler)) {\n const [callback, data] = handler as [(data: unknown, event: Event) => void, unknown]\n callback(data, event)\n } else if (typeof handler === 'function') {\n const callback = handler as (event: Event) => void\n callback(event)\n }\n}\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 const [local, rest] = splitProps(props, ['open', 'defaultOpen', 'onOpenChange', 'disabled'])\n const id = createUniqueId()\n const controlled = () => local.open !== undefined\n const [uncontrolledOpen, setUncontrolledOpen] = createSignal(local.defaultOpen ?? false)\n const isOpen = () => (controlled() ? (local.open ?? false) : uncontrolledOpen())\n const [trigger, setTrigger] = createSignal<HTMLElement>()\n let closeIntent = false\n let ignoreDuplicateClose = false\n let onOpenChange: (next: boolean, source?: 'handoff') => void\n let pointerCloseIntentUntil = 0\n let pointerCloseIntentTimeout: ReturnType<typeof setTimeout> | undefined\n const clearPointerCloseIntent = () => {\n pointerCloseIntentUntil = 0\n if (pointerCloseIntentTimeout) clearTimeout(pointerCloseIntentTimeout)\n pointerCloseIntentTimeout = undefined\n }\n const markPointerCloseIntent = () => {\n if (!isOpen()) return\n clearPointerCloseIntent()\n const closeDelay = props.closeDelay ?? timing.closeDelay\n pointerCloseIntentUntil = Date.now() + closeDelay + 50\n pointerCloseIntentTimeout = setTimeout(clearPointerCloseIntent, closeDelay + 50)\n }\n const markCloseIntent = () => {\n closeIntent = true\n clearPointerCloseIntent()\n queueMicrotask(() => {\n closeIntent = false\n })\n }\n const requestCloseFromAnotherTooltip = () => {\n if (!isOpen()) return\n\n // Another trigger is an explicit handoff, even when a focused tooltip has\n // a pending pointer-close intent that would otherwise suppress Kobalte's\n // close callback. Route the request through the same controlled/uncontrolled\n // state contract as Kobalte and ignore its duplicate callback for this turn.\n ignoreDuplicateClose = true\n queueMicrotask(() => {\n ignoreDuplicateClose = false\n })\n onOpenChange(false, 'handoff')\n }\n const interaction: TooltipInteraction = {\n id,\n trigger,\n setTrigger,\n isOpen,\n isDisabled: () => local.disabled ?? false,\n isTriggerFocused: () =>\n Boolean(trigger() && typeof document !== 'undefined' && trigger() === document.activeElement),\n markOpenIntent: () => {\n clearPointerCloseIntent()\n pendingTooltipOpenId = id\n // A focused tooltip ignores ordinary pointer movement, but entering or\n // focusing another tooltip is an explicit transfer.\n for (const openInteraction of openTooltipInteractions) {\n if (openInteraction.id !== id) openInteraction.requestCloseFromAnotherTooltip()\n }\n },\n clearOpenIntent: () => clearPendingTooltipOpen(id),\n requestCloseFromAnotherTooltip,\n markPointerCloseIntent,\n clearPointerCloseIntent,\n markCloseIntent,\n }\n registerTooltipInteraction(interaction)\n onCleanup(() => {\n clearPointerCloseIntent()\n ignoreDuplicateClose = false\n })\n if (isOpen()) setTooltipInteractionOpen(interaction, true)\n createEffect(() => setTooltipInteractionOpen(interaction, isOpen()))\n onOpenChange = (next: boolean, source) => {\n if (!next && source !== 'handoff' && ignoreDuplicateClose) return\n\n if (next) {\n clearPendingTooltipOpen(id)\n clearPointerCloseIntent()\n // Install this capture listener before Kobalte's open-state effect adds\n // its scroll listener later in the same update.\n setTooltipInteractionOpen(interaction, true)\n } else {\n const focusedTrigger = interaction.isTriggerFocused()\n const anotherTooltipOpening =\n pendingTooltipOpenId !== undefined && pendingTooltipOpenId !== id\n const pointerClosePending = Date.now() <= pointerCloseIntentUntil\n if (\n source !== 'handoff' &&\n focusedTrigger &&\n pointerClosePending &&\n !closeIntent &&\n !anotherTooltipOpening\n ) {\n clearPointerCloseIntent()\n return\n }\n closeIntent = false\n clearPointerCloseIntent()\n clearPendingTooltipOpen(id)\n }\n\n if (!controlled()) setUncontrolledOpen(next)\n local.onOpenChange?.(next)\n if (next) {\n // A controlled parent can reject the open request without changing its\n // signal, so the effect above would not rerun to release this listener.\n queueMicrotask(() => {\n if (!isOpen()) setTooltipInteractionOpen(interaction, false)\n })\n }\n }\n\n // Kobalte dismisses on Escape only when its content owns the top-most\n // layer, and a handoff keeps the previous tooltip's content mounted while\n // it exits — swallowing the key for the tooltip that just took over.\n // Listening on document (capture) closes this tooltip first; the layer's\n // own handler still runs for anything stacked above it.\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return\n markCloseIntent()\n onOpenChange(false)\n }\n createEffect(() => {\n if (isServer || !isOpen()) return\n document.addEventListener('keydown', handleKeyDown, true)\n onCleanup(() => document.removeEventListener('keydown', handleKeyDown, true))\n })\n\n return (\n <TooltipInteractionContext.Provider value={interaction}>\n <KobalteTooltip\n open={isOpen()}\n onOpenChange={onOpenChange}\n disabled={local.disabled}\n openDelay={props.openDelay ?? timing.openDelay}\n closeDelay={props.closeDelay ?? timing.closeDelay}\n skipDelayDuration={props.skipDelayDuration ?? timing.skipDelayDuration}\n {...rest}\n />\n </TooltipInteractionContext.Provider>\n )\n}\n\nexport function TooltipTrigger(props: ComponentProps<typeof KobalteTooltip.Trigger>) {\n const interaction = useContext(TooltipInteractionContext)\n const [local, rest] = splitProps(props, [\n 'ref',\n 'onFocus',\n 'onBlur',\n 'onPointerEnter',\n 'onPointerLeave',\n 'onClick',\n ])\n\n return (\n <KobalteTooltip.Trigger\n {...rest}\n ref={(element) => {\n interaction?.setTrigger(element)\n if (typeof local.ref === 'function') local.ref(element)\n }}\n onFocus={(event) => {\n invokeEventHandler(local.onFocus, event)\n if (!event.defaultPrevented && !interaction?.isDisabled()) interaction?.markOpenIntent()\n }}\n onBlur={(event) => {\n invokeEventHandler(local.onBlur, event)\n interaction?.clearOpenIntent()\n interaction?.markCloseIntent()\n }}\n onPointerEnter={(event) => {\n invokeEventHandler(local.onPointerEnter, event)\n if (!event.defaultPrevented && !interaction?.isDisabled()) interaction?.markOpenIntent()\n }}\n onPointerLeave={(event) => {\n invokeEventHandler(local.onPointerLeave, event)\n interaction?.clearOpenIntent()\n interaction?.markPointerCloseIntent()\n }}\n onClick={(event) => {\n invokeEventHandler(local.onClick, event)\n interaction?.markCloseIntent()\n }}\n />\n )\n}\n\nexport type TooltipContentProps = ComponentProps<typeof KobalteTooltip.Content> & {\n /**\n * A leading icon, repeating the trigger's glyph inside the tip — the side\n * rail's icon+label treatment, offered so a toolbar or rail tooltip does not\n * have to hand-roll it. Decorative by contract: the tip is `aria-hidden`\n * while closed and never the accessible name, so the icon must not be the\n * only carrier of meaning. Size it by leaving the svg bare; the slot fixes\n * it to the system's control size.\n */\n icon?: JSX.Element\n}\n\nexport function TooltipContent(props: TooltipContentProps) {\n const interaction = useContext(TooltipInteractionContext)\n const [local, rest] = splitProps(props, [\n 'class',\n 'children',\n 'icon',\n 'aria-hidden',\n 'onEscapeKeyDown',\n 'onPointerDownOutside',\n ])\n const context = useTooltipContext()\n\n // Kobalte keeps force-mounted and exiting content present after close. Hide\n // that retained tooltip from assistive technology until it opens again.\n return (\n <KobalteTooltip.Portal>\n <KobalteTooltip.Content\n /* The slot is what base.css's pointer-transparency rule keys on; every\n tip carries it, so no consumer has to remember to pass it. */\n data-slot=\"tooltip-content\"\n class={cn(\n tooltipTip,\n // The max width is a token, not a fixed measure: it has to fall\n // behind the viewport at large root font sizes or the tip — which\n // Kobalte can shift but never shrink — forces a horizontal scroll.\n 'z-(--z-tooltip) w-fit max-w-(--tooltip-max-width) px-2 py-1',\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 // An icon+label tip is one row that reads as a unit, so the label\n // never wraps under the glyph.\n { 'flex items-center gap-2 whitespace-nowrap': !!local.icon },\n local.class\n )}\n // A tooltip is never interactive: the content is plain text, and the\n // placement draws the tip below its action — where a hit-testing tip\n // would hold the next control hostage, open or departing. Kobalte\n // inlines pointer-events auto, so this is forced after its merge; the\n // pointer belongs to the control underneath.\n style={{ 'pointer-events': 'none' }}\n aria-hidden={context.isOpen() ? local['aria-hidden'] : true}\n onEscapeKeyDown={(event) => {\n invokeEventHandler(local.onEscapeKeyDown, event)\n if (!event.defaultPrevented) interaction?.markCloseIntent()\n }}\n onPointerDownOutside={(event) => {\n invokeEventHandler(local.onPointerDownOutside, event)\n if (!event.defaultPrevented) interaction?.markCloseIntent()\n }}\n // A tooltip opened from inside a modal dialog is part of that dialog's\n // surface, so it carries the same top-layer exemption as a menu or a\n // popover — without it the dialog's hide-outside observer aria-hides\n // the tip while it is on screen.\n {...topLayerProps}\n {...rest}\n >\n <Show when={local.icon}>\n {(icon) => (\n <span\n data-slot=\"tooltip-icon\"\n aria-hidden=\"true\"\n class=\"flex size-4 shrink-0 items-center justify-center [&_svg]:size-4\"\n >\n {icon()}\n </span>\n )}\n </Show>\n {local.children}\n </KobalteTooltip.Content>\n </KobalteTooltip.Portal>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tooltip.js","names":["Tooltip","KobalteTooltip","useTooltipContext","ComponentProps","JSX","createContext","createEffect","createSignal","createUniqueId","onCleanup","Show","splitProps","useContext","isServer","tooltipTip","topLayerProps","acquireTooltipFocusGate","releaseTooltipFocusGate","cn","TooltipTiming","openDelay","closeDelay","skipDelayDuration","tooltipDefaults","TooltipTimingContext","TooltipInteraction","id","trigger","HTMLElement","setTrigger","element","isOpen","isDisabled","isTriggerFocused","markOpenIntent","clearOpenIntent","requestCloseFromAnotherTooltip","markPointerCloseIntent","clearPointerCloseIntent","markCloseIntent","TooltipInteractionContext","openTooltipInteractions","Set","pendingTooltipOpenId","tooltipScrollListenerAttached","clearPendingTooltipOpen","undefined","tooltipScrollContainsTrigger","event","Event","target","window","Node","contains","handleTooltipScroll","interaction","handleTooltipPointerMove","PointerEvent","setTooltipInteractionOpen","open","has","add","addEventListener","document","delete","size","removeEventListener","registerTooltipInteraction","invokeEventHandler","handler","Array","isArray","callback","data","TooltipProviderProps","children","TooltipProvider","props","_$createComponent","Provider","value","TooltipRootProps","timing","local","rest","controlled","uncontrolledOpen","setUncontrolledOpen","defaultOpen","closeIntent","ignoreDuplicateClose","onOpenChange","next","source","pointerCloseIntentUntil","pointerCloseIntentTimeout","ReturnType","setTimeout","clearTimeout","Date","now","queueMicrotask","disabled","Boolean","activeElement","openInteraction","focusedTrigger","anotherTooltipOpening","pointerClosePending","handleKeyDown","KeyboardEvent","key","_$mergeProps","TooltipTrigger","Trigger","ref","onFocus","defaultPrevented","onBlur","onPointerEnter","onPointerLeave","onClick","TooltipContentProps","Content","icon","Element","TooltipContent","context","Portal","class","style","aria-hidden","_$memo","onEscapeKeyDown","onPointerDownOutside","when","_el$","_tmpl$","_$insert","_$createComponent","Tooltip","KobalteTooltip","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/tooltip/tooltip.tsx"],"sourcesContent":["import { Tooltip as KobalteTooltip, useTooltipContext } from '@kobalte/core/tooltip'\nimport type { ComponentProps, JSX } from 'solid-js'\nimport {\n createContext,\n createEffect,\n createSignal,\n createUniqueId,\n onCleanup,\n Show,\n splitProps,\n useContext,\n} from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport { tooltipTip, topLayerProps } from '#lib/overlay'\nimport { acquireTooltipFocusGate, releaseTooltipFocusGate } from '#lib/tooltip-focus-gate'\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\ntype TooltipInteraction = {\n id: string\n trigger: () => HTMLElement | undefined\n setTrigger: (element: HTMLElement) => void\n isOpen: () => boolean\n isDisabled: () => boolean\n isTriggerFocused: () => boolean\n markOpenIntent: () => void\n clearOpenIntent: () => void\n requestCloseFromAnotherTooltip: () => void\n markPointerCloseIntent: () => void\n clearPointerCloseIntent: () => void\n markCloseIntent: () => void\n}\n\nconst TooltipInteractionContext = createContext<TooltipInteraction>()\nconst openTooltipInteractions = new Set<TooltipInteraction>()\nlet pendingTooltipOpenId: string | undefined\nlet tooltipScrollListenerAttached = false\n\nfunction clearPendingTooltipOpen(id: string) {\n if (pendingTooltipOpenId === id) pendingTooltipOpenId = undefined\n}\n\nfunction tooltipScrollContainsTrigger(event: Event, trigger: HTMLElement) {\n const target = event.target\n return target === window || (target instanceof Node && target.contains(trigger))\n}\n\nfunction handleTooltipScroll(event: Event) {\n for (const interaction of openTooltipInteractions) {\n const trigger = interaction.trigger()\n if (interaction.isOpen() && trigger && tooltipScrollContainsTrigger(event, trigger)) {\n interaction.markCloseIntent()\n }\n }\n}\n\nfunction handleTooltipPointerMove(event: PointerEvent) {\n for (const interaction of openTooltipInteractions) {\n const trigger = interaction.trigger()\n const target = event.target\n if (\n interaction.isOpen() &&\n interaction.isTriggerFocused() &&\n trigger &&\n !(target instanceof Node && trigger.contains(target))\n ) {\n interaction.markPointerCloseIntent()\n }\n }\n}\n\nfunction setTooltipInteractionOpen(interaction: TooltipInteraction, open: boolean) {\n if (isServer) return\n\n if (open) {\n if (openTooltipInteractions.has(interaction)) return\n openTooltipInteractions.add(interaction)\n if (!tooltipScrollListenerAttached) {\n tooltipScrollListenerAttached = true\n // Register before Kobalte's global listeners so intentional scroll\n // dismissal can be distinguished from its delayed pointer dismissal.\n window.addEventListener('scroll', handleTooltipScroll, true)\n document.addEventListener('pointermove', handleTooltipPointerMove, true)\n }\n } else {\n openTooltipInteractions.delete(interaction)\n if (openTooltipInteractions.size === 0 && tooltipScrollListenerAttached) {\n tooltipScrollListenerAttached = false\n window.removeEventListener('scroll', handleTooltipScroll, true)\n document.removeEventListener('pointermove', handleTooltipPointerMove, true)\n }\n }\n}\n\nfunction registerTooltipInteraction(interaction: TooltipInteraction) {\n onCleanup(() => {\n setTooltipInteractionOpen(interaction, false)\n clearPendingTooltipOpen(interaction.id)\n })\n}\n\nfunction invokeEventHandler(handler: unknown, event: Event) {\n if (Array.isArray(handler)) {\n const [callback, data] = handler as [(data: unknown, event: Event) => void, unknown]\n callback(data, event)\n } else if (typeof handler === 'function') {\n const callback = handler as (event: Event) => void\n callback(event)\n }\n}\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 // One document-level focus gate for every tooltip in the document: the first\n // tooltip acquires it, the last to unmount releases it. This is what keeps a\n // dialog's autofocus and an overlay's focus restoration from opening a tip —\n // see #lib/tooltip-focus-gate for the contract and the two over-reach traps\n // (pointer gestures and separator resize grips) it must not swallow.\n if (!isServer) {\n acquireTooltipFocusGate()\n onCleanup(releaseTooltipFocusGate)\n }\n const timing = useContext(TooltipTimingContext)\n const [local, rest] = splitProps(props, ['open', 'defaultOpen', 'onOpenChange', 'disabled'])\n const id = createUniqueId()\n const controlled = () => local.open !== undefined\n const [uncontrolledOpen, setUncontrolledOpen] = createSignal(local.defaultOpen ?? false)\n const isOpen = () => (controlled() ? (local.open ?? false) : uncontrolledOpen())\n const [trigger, setTrigger] = createSignal<HTMLElement>()\n let closeIntent = false\n let ignoreDuplicateClose = false\n let onOpenChange: (next: boolean, source?: 'handoff') => void\n let pointerCloseIntentUntil = 0\n let pointerCloseIntentTimeout: ReturnType<typeof setTimeout> | undefined\n const clearPointerCloseIntent = () => {\n pointerCloseIntentUntil = 0\n if (pointerCloseIntentTimeout) clearTimeout(pointerCloseIntentTimeout)\n pointerCloseIntentTimeout = undefined\n }\n const markPointerCloseIntent = () => {\n if (!isOpen()) return\n clearPointerCloseIntent()\n const closeDelay = props.closeDelay ?? timing.closeDelay\n pointerCloseIntentUntil = Date.now() + closeDelay + 50\n pointerCloseIntentTimeout = setTimeout(clearPointerCloseIntent, closeDelay + 50)\n }\n const markCloseIntent = () => {\n closeIntent = true\n clearPointerCloseIntent()\n queueMicrotask(() => {\n closeIntent = false\n })\n }\n const requestCloseFromAnotherTooltip = () => {\n if (!isOpen()) return\n\n // Another trigger is an explicit handoff, even when a focused tooltip has\n // a pending pointer-close intent that would otherwise suppress Kobalte's\n // close callback. Route the request through the same controlled/uncontrolled\n // state contract as Kobalte and ignore its duplicate callback for this turn.\n ignoreDuplicateClose = true\n queueMicrotask(() => {\n ignoreDuplicateClose = false\n })\n onOpenChange(false, 'handoff')\n }\n const interaction: TooltipInteraction = {\n id,\n trigger,\n setTrigger,\n isOpen,\n isDisabled: () => local.disabled ?? false,\n isTriggerFocused: () =>\n Boolean(trigger() && typeof document !== 'undefined' && trigger() === document.activeElement),\n markOpenIntent: () => {\n clearPointerCloseIntent()\n pendingTooltipOpenId = id\n // A focused tooltip ignores ordinary pointer movement, but entering or\n // focusing another tooltip is an explicit transfer.\n for (const openInteraction of openTooltipInteractions) {\n if (openInteraction.id !== id) openInteraction.requestCloseFromAnotherTooltip()\n }\n },\n clearOpenIntent: () => clearPendingTooltipOpen(id),\n requestCloseFromAnotherTooltip,\n markPointerCloseIntent,\n clearPointerCloseIntent,\n markCloseIntent,\n }\n registerTooltipInteraction(interaction)\n onCleanup(() => {\n clearPointerCloseIntent()\n ignoreDuplicateClose = false\n })\n if (isOpen()) setTooltipInteractionOpen(interaction, true)\n createEffect(() => setTooltipInteractionOpen(interaction, isOpen()))\n onOpenChange = (next: boolean, source) => {\n if (!next && source !== 'handoff' && ignoreDuplicateClose) return\n\n if (next) {\n clearPendingTooltipOpen(id)\n clearPointerCloseIntent()\n // Install this capture listener before Kobalte's open-state effect adds\n // its scroll listener later in the same update.\n setTooltipInteractionOpen(interaction, true)\n } else {\n const focusedTrigger = interaction.isTriggerFocused()\n const anotherTooltipOpening =\n pendingTooltipOpenId !== undefined && pendingTooltipOpenId !== id\n const pointerClosePending = Date.now() <= pointerCloseIntentUntil\n if (\n source !== 'handoff' &&\n focusedTrigger &&\n pointerClosePending &&\n !closeIntent &&\n !anotherTooltipOpening\n ) {\n clearPointerCloseIntent()\n return\n }\n closeIntent = false\n clearPointerCloseIntent()\n clearPendingTooltipOpen(id)\n }\n\n if (!controlled()) setUncontrolledOpen(next)\n local.onOpenChange?.(next)\n if (next) {\n // A controlled parent can reject the open request without changing its\n // signal, so the effect above would not rerun to release this listener.\n queueMicrotask(() => {\n if (!isOpen()) setTooltipInteractionOpen(interaction, false)\n })\n }\n }\n\n // Kobalte dismisses on Escape only when its content owns the top-most\n // layer, and a handoff keeps the previous tooltip's content mounted while\n // it exits — swallowing the key for the tooltip that just took over.\n // Listening on document (capture) closes this tooltip first; the layer's\n // own handler still runs for anything stacked above it.\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return\n markCloseIntent()\n onOpenChange(false)\n }\n createEffect(() => {\n if (isServer || !isOpen()) return\n document.addEventListener('keydown', handleKeyDown, true)\n onCleanup(() => document.removeEventListener('keydown', handleKeyDown, true))\n })\n\n return (\n <TooltipInteractionContext.Provider value={interaction}>\n <KobalteTooltip\n open={isOpen()}\n onOpenChange={onOpenChange}\n disabled={local.disabled}\n openDelay={props.openDelay ?? timing.openDelay}\n closeDelay={props.closeDelay ?? timing.closeDelay}\n skipDelayDuration={props.skipDelayDuration ?? timing.skipDelayDuration}\n {...rest}\n />\n </TooltipInteractionContext.Provider>\n )\n}\n\nexport function TooltipTrigger(props: ComponentProps<typeof KobalteTooltip.Trigger>) {\n const interaction = useContext(TooltipInteractionContext)\n const [local, rest] = splitProps(props, [\n 'ref',\n 'onFocus',\n 'onBlur',\n 'onPointerEnter',\n 'onPointerLeave',\n 'onClick',\n ])\n\n return (\n <KobalteTooltip.Trigger\n {...rest}\n ref={(element) => {\n interaction?.setTrigger(element)\n if (typeof local.ref === 'function') local.ref(element)\n }}\n onFocus={(event) => {\n invokeEventHandler(local.onFocus, event)\n if (!event.defaultPrevented && !interaction?.isDisabled()) interaction?.markOpenIntent()\n }}\n onBlur={(event) => {\n invokeEventHandler(local.onBlur, event)\n interaction?.clearOpenIntent()\n interaction?.markCloseIntent()\n }}\n onPointerEnter={(event) => {\n invokeEventHandler(local.onPointerEnter, event)\n if (!event.defaultPrevented && !interaction?.isDisabled()) interaction?.markOpenIntent()\n }}\n onPointerLeave={(event) => {\n invokeEventHandler(local.onPointerLeave, event)\n interaction?.clearOpenIntent()\n interaction?.markPointerCloseIntent()\n }}\n onClick={(event) => {\n invokeEventHandler(local.onClick, event)\n interaction?.markCloseIntent()\n }}\n />\n )\n}\n\nexport type TooltipContentProps = ComponentProps<typeof KobalteTooltip.Content> & {\n /**\n * A leading icon, repeating the trigger's glyph inside the tip — the side\n * rail's icon+label treatment, offered so a toolbar or rail tooltip does not\n * have to hand-roll it. Decorative by contract: the tip is `aria-hidden`\n * while closed and never the accessible name, so the icon must not be the\n * only carrier of meaning. Size it by leaving the svg bare; the slot fixes\n * it to the system's control size.\n */\n icon?: JSX.Element\n}\n\nexport function TooltipContent(props: TooltipContentProps) {\n const interaction = useContext(TooltipInteractionContext)\n const [local, rest] = splitProps(props, [\n 'class',\n 'children',\n 'icon',\n 'aria-hidden',\n 'onEscapeKeyDown',\n 'onPointerDownOutside',\n ])\n const context = useTooltipContext()\n\n // Kobalte keeps force-mounted and exiting content present after close. Hide\n // that retained tooltip from assistive technology until it opens again.\n return (\n <KobalteTooltip.Portal>\n <KobalteTooltip.Content\n /* The slot is what base.css's pointer-transparency rule keys on; every\n tip carries it, so no consumer has to remember to pass it. */\n data-slot=\"tooltip-content\"\n class={cn(\n tooltipTip,\n // The max width is a token, not a fixed measure: it has to fall\n // behind the viewport at large root font sizes or the tip — which\n // Kobalte can shift but never shrink — forces a horizontal scroll.\n 'z-(--z-tooltip) w-fit max-w-(--tooltip-max-width) px-2 py-1',\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 // An icon+label tip is one row that reads as a unit, so the label\n // never wraps under the glyph.\n { 'flex items-center gap-2 whitespace-nowrap': !!local.icon },\n local.class\n )}\n // A tooltip is never interactive: the content is plain text, and the\n // placement draws the tip below its action — where a hit-testing tip\n // would hold the next control hostage, open or departing. Kobalte\n // inlines pointer-events auto, so this is forced after its merge; the\n // pointer belongs to the control underneath.\n style={{ 'pointer-events': 'none' }}\n aria-hidden={context.isOpen() ? local['aria-hidden'] : true}\n onEscapeKeyDown={(event) => {\n invokeEventHandler(local.onEscapeKeyDown, event)\n if (!event.defaultPrevented) interaction?.markCloseIntent()\n }}\n onPointerDownOutside={(event) => {\n invokeEventHandler(local.onPointerDownOutside, event)\n if (!event.defaultPrevented) interaction?.markCloseIntent()\n }}\n // A tooltip opened from inside a modal dialog is part of that dialog's\n // surface, so it carries the same top-layer exemption as a menu or a\n // popover — without it the dialog's hide-outside observer aria-hides\n // the tip while it is on screen.\n {...topLayerProps}\n {...rest}\n >\n <Show when={local.icon}>\n {(icon) => (\n <span\n data-slot=\"tooltip-icon\"\n aria-hidden=\"true\"\n class=\"flex size-4 shrink-0 items-center justify-center [&_svg]:size-4\"\n >\n {icon()}\n </span>\n )}\n </Show>\n {local.children}\n </KobalteTooltip.Content>\n </KobalteTooltip.Portal>\n )\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** How long after a Tab key press a resulting focus event still counts as
|
|
2
|
+
* keyboard navigation. The native focus move follows the key press
|
|
3
|
+
* immediately; the window only has to bridge that dispatch, not a later
|
|
4
|
+
* script-driven focus. */
|
|
5
|
+
export declare const TOOLTIP_FOCUS_INTENT_WINDOW_MS = 250;
|
|
6
|
+
/**
|
|
7
|
+
* Whether a focus event landing on this target could open a tooltip on a
|
|
8
|
+
* button-like control. Accepts any Element (an SVG glyph inside a control,
|
|
9
|
+
* for instance) and duck-types so the decision is testable without a DOM.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isButtonLikeFocusTarget(target: unknown): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* The suppression decision: a button-like focus target hides a tooltip only
|
|
14
|
+
* when no keyboard navigation is in flight. Anything else — a Tab-driven
|
|
15
|
+
* focus, or focus on a non-button element — passes through untouched.
|
|
16
|
+
*/
|
|
17
|
+
export declare function shouldSuppressTooltipFocus(input: {
|
|
18
|
+
isButtonLike: boolean;
|
|
19
|
+
keyboardIntentActive: boolean;
|
|
20
|
+
}): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Install the gate on a document. Idempotent per document; returns a disposer
|
|
23
|
+
* that removes the listeners (used by tests and by the tooltip root, which
|
|
24
|
+
* releases the gate when its document's last tooltip unmounts).
|
|
25
|
+
*/
|
|
26
|
+
export declare function installTooltipFocusGate(doc?: Document): () => void;
|
|
27
|
+
export declare function acquireTooltipFocusGate(targetDoc?: Document): void;
|
|
28
|
+
export declare function releaseTooltipFocusGate(targetDoc?: Document): void;
|
|
29
|
+
//# sourceMappingURL=tooltip-focus-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tooltip-focus-gate.d.ts","sourceRoot":"","sources":["../../src/lib/tooltip-focus-gate.ts"],"names":[],"mappings":"AAmEA;;;2BAG2B;AAC3B,eAAO,MAAM,8BAA8B,MAAM,CAAA;AAMjD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAShE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,YAAY,EAAE,OAAO,CAAA;IACrB,oBAAoB,EAAE,OAAO,CAAA;CAC9B,GAAG,OAAO,CAEV;AAID;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,QAAmB,GAAG,MAAM,IAAI,CA0E5E;AAWD,wBAAgB,uBAAuB,CAAC,SAAS,CAAC,EAAE,QAAQ,GAAG,IAAI,CAMlE;AAED,wBAAgB,uBAAuB,CAAC,SAAS,CAAC,EAAE,QAAQ,GAAG,IAAI,CAYlE"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/** Elements a tooltip-bearing control is rendered as. Everything else keeps
|
|
2
|
+
* its native focus behaviour, and so do resize grips (see below). */
|
|
3
|
+
var BUTTON_LIKE_SELECTOR = "button, a[href], [role=\"button\"], [role=\"link\"]";
|
|
4
|
+
/**
|
|
5
|
+
* Whether a focus event landing on this target could open a tooltip on a
|
|
6
|
+
* button-like control. Accepts any Element (an SVG glyph inside a control,
|
|
7
|
+
* for instance) and duck-types so the decision is testable without a DOM.
|
|
8
|
+
*/
|
|
9
|
+
function isButtonLikeFocusTarget(target) {
|
|
10
|
+
const element = target;
|
|
11
|
+
if (typeof element?.closest !== "function") return false;
|
|
12
|
+
const control = element.closest(BUTTON_LIKE_SELECTOR);
|
|
13
|
+
if (control === null) return false;
|
|
14
|
+
return control.getAttribute?.("role") !== "separator";
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The suppression decision: a button-like focus target hides a tooltip only
|
|
18
|
+
* when no keyboard navigation is in flight. Anything else — a Tab-driven
|
|
19
|
+
* focus, or focus on a non-button element — passes through untouched.
|
|
20
|
+
*/
|
|
21
|
+
function shouldSuppressTooltipFocus(input) {
|
|
22
|
+
return input.isButtonLike && !input.keyboardIntentActive;
|
|
23
|
+
}
|
|
24
|
+
var installedDocuments = /* @__PURE__ */ new WeakSet();
|
|
25
|
+
/**
|
|
26
|
+
* Install the gate on a document. Idempotent per document; returns a disposer
|
|
27
|
+
* that removes the listeners (used by tests and by the tooltip root, which
|
|
28
|
+
* releases the gate when its document's last tooltip unmounts).
|
|
29
|
+
*/
|
|
30
|
+
function installTooltipFocusGate(doc = document) {
|
|
31
|
+
if (installedDocuments.has(doc)) return () => {};
|
|
32
|
+
let lastTabKeyDownAt = 0;
|
|
33
|
+
/** True between a pointerdown and its pointerup/pointercancel: focus events
|
|
34
|
+
* inside that window belong to a pointer gesture (drag bootstrap, press)
|
|
35
|
+
* and must reach their element untouched. */
|
|
36
|
+
let pointerGestureActive = false;
|
|
37
|
+
/** The element holding a suppressed programmatic focus, if it still holds
|
|
38
|
+
* `activeElement`. One slot: a newer suppressed focus replaces an older
|
|
39
|
+
* one, and anything that already lost focus needs no release. */
|
|
40
|
+
let phantomFocusTarget;
|
|
41
|
+
/** The phantom-release `pointermove` listener exists only while a phantom
|
|
42
|
+
* does: a gate that parks a permanent pointer listener on every document
|
|
43
|
+
* with a tooltip in it costs every page a standing listener for a state
|
|
44
|
+
* that is live for a few hundred milliseconds at most. */
|
|
45
|
+
let phantomReleaseAttached = false;
|
|
46
|
+
const onKeyDown = (event) => {
|
|
47
|
+
if (event.key === "Tab") lastTabKeyDownAt = Date.now();
|
|
48
|
+
};
|
|
49
|
+
const onPointerDown = () => {
|
|
50
|
+
pointerGestureActive = true;
|
|
51
|
+
releasePhantomFocus();
|
|
52
|
+
};
|
|
53
|
+
const onPointerGestureEnd = () => {
|
|
54
|
+
pointerGestureActive = false;
|
|
55
|
+
};
|
|
56
|
+
const dropPhantom = () => {
|
|
57
|
+
phantomFocusTarget = void 0;
|
|
58
|
+
if (phantomReleaseAttached) {
|
|
59
|
+
phantomReleaseAttached = false;
|
|
60
|
+
doc.removeEventListener("pointermove", onPointerMove, true);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const onFocus = (event) => {
|
|
64
|
+
if (phantomFocusTarget && event.target !== phantomFocusTarget) dropPhantom();
|
|
65
|
+
if (pointerGestureActive) return;
|
|
66
|
+
if (!isButtonLikeFocusTarget(event.target)) return;
|
|
67
|
+
if (!shouldSuppressTooltipFocus({
|
|
68
|
+
isButtonLike: true,
|
|
69
|
+
keyboardIntentActive: Date.now() - lastTabKeyDownAt <= 250
|
|
70
|
+
})) return;
|
|
71
|
+
event.stopPropagation();
|
|
72
|
+
phantomFocusTarget = event.target;
|
|
73
|
+
if (!phantomReleaseAttached) {
|
|
74
|
+
phantomReleaseAttached = true;
|
|
75
|
+
doc.addEventListener("pointermove", onPointerMove, true);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const releasePhantomFocus = () => {
|
|
79
|
+
if (pointerGestureActive) return;
|
|
80
|
+
if (!phantomFocusTarget) return;
|
|
81
|
+
const phantom = phantomFocusTarget;
|
|
82
|
+
dropPhantom();
|
|
83
|
+
if (doc.activeElement !== phantom) return;
|
|
84
|
+
if (typeof phantom.blur === "function") phantom.blur();
|
|
85
|
+
};
|
|
86
|
+
const onPointerMove = () => releasePhantomFocus();
|
|
87
|
+
doc.addEventListener("keydown", onKeyDown, true);
|
|
88
|
+
doc.addEventListener("focus", onFocus, true);
|
|
89
|
+
doc.addEventListener("pointerdown", onPointerDown, true);
|
|
90
|
+
doc.addEventListener("pointerup", onPointerGestureEnd, true);
|
|
91
|
+
doc.addEventListener("pointercancel", onPointerGestureEnd, true);
|
|
92
|
+
installedDocuments.add(doc);
|
|
93
|
+
return () => {
|
|
94
|
+
doc.removeEventListener("keydown", onKeyDown, true);
|
|
95
|
+
doc.removeEventListener("focus", onFocus, true);
|
|
96
|
+
doc.removeEventListener("pointerdown", onPointerDown, true);
|
|
97
|
+
doc.removeEventListener("pointerup", onPointerGestureEnd, true);
|
|
98
|
+
doc.removeEventListener("pointercancel", onPointerGestureEnd, true);
|
|
99
|
+
doc.removeEventListener("pointermove", onPointerMove, true);
|
|
100
|
+
installedDocuments.delete(doc);
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Reference-counted install for the tooltip root: the first tooltip in a
|
|
105
|
+
* document acquires the gate, the last one to unmount releases it. The document
|
|
106
|
+
* parameter exists so tests can drive the counter without a global DOM; the
|
|
107
|
+
* production call site guards on the server render before calling.
|
|
108
|
+
*/
|
|
109
|
+
var gateHolders = /* @__PURE__ */ new WeakMap();
|
|
110
|
+
var gateDisposers = /* @__PURE__ */ new WeakMap();
|
|
111
|
+
function acquireTooltipFocusGate(targetDoc) {
|
|
112
|
+
if (typeof document === "undefined" && !targetDoc) return;
|
|
113
|
+
const doc = targetDoc ?? document;
|
|
114
|
+
const holders = gateHolders.get(doc) ?? 0;
|
|
115
|
+
gateHolders.set(doc, holders + 1);
|
|
116
|
+
if (holders === 0) gateDisposers.set(doc, installTooltipFocusGate(doc));
|
|
117
|
+
}
|
|
118
|
+
function releaseTooltipFocusGate(targetDoc) {
|
|
119
|
+
if (typeof document === "undefined" && !targetDoc) return;
|
|
120
|
+
const doc = targetDoc ?? document;
|
|
121
|
+
const holders = gateHolders.get(doc) ?? 0;
|
|
122
|
+
if (holders === 0) return;
|
|
123
|
+
if (holders === 1) {
|
|
124
|
+
gateHolders.delete(doc);
|
|
125
|
+
gateDisposers.get(doc)?.();
|
|
126
|
+
gateDisposers.delete(doc);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
gateHolders.set(doc, holders - 1);
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
export { acquireTooltipFocusGate, installTooltipFocusGate, isButtonLikeFocusTarget, releaseTooltipFocusGate, shouldSuppressTooltipFocus };
|
|
133
|
+
|
|
134
|
+
//# sourceMappingURL=tooltip-focus-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tooltip-focus-gate.js","names":[],"sources":["../../src/lib/tooltip-focus-gate.ts"],"sourcesContent":["/*\n * Tooltips open on active hover over the control, or on keyboard focus that\n * follows a Tab key press. They must never open from programmatic focus: the\n * autofocus a dialog or sheet gives its first control, and the focus a closing\n * overlay restores to its opener, both land on buttons that carry tooltips —\n * and the tooltip primitive opens immediately on focus and pins the tooltip\n * until blur. That is the \"tooltip auto-displays when a sheet opens\" report,\n * and the pinned tooltip is the \"tooltip gets stuck and never disappears\"\n * report: the pointer is nowhere near the control, so no pointer leave ever\n * closes it.\n *\n * The trigger listens for the native `focus` event on the trigger element, and\n * composites build tooltips internally (ActionButton renders one from its\n * `tooltip` prop), so the single interception point that covers every tooltip\n * is a capture-phase `focus` listener on `document`. When focus lands without a\n * keyboard-intent signal on a button-like element, the event is stopped before\n * any element listener runs: the tooltip never learns about the focus. Hover\n * opens are untouched (they ride pointer events), and the separate `focusin`\n * event still flows, so dialog focus-cycle tracking, `:focus-visible` styling,\n * and focus restoration all keep working. Focus still lands — only the event\n * is stopped — so `document.activeElement` and scripted `.blur()` behave.\n *\n * The keyboard-intent signal is a Tab key press immediately before the focus —\n * the only key that moves focus natively. Enter and Space open overlays too,\n * so any \"recent key\" window wide enough for those would let an overlay's own\n * autofocus back through; Tab-only keeps autofocus suppressed no matter how\n * the overlay was opened, while normal Tab navigation still announces each\n * control's tooltip (hover descriptions stay reachable from the keyboard).\n *\n * Suppression is scoped to button-like targets (`button`, `a[href]`,\n * `[role=\"button\"]`, `[role=\"link\"]`). Composite widgets that move focus\n * programmatically — menu items, listbox options, grid cells — are other\n * element types whose roving-focus highlighting must keep receiving focus\n * events, and text controls keep their own focus behaviour (select on focus,\n * caret placement).\n *\n * Suppressed focus is real as far as the DOM is concerned (`activeElement`\n * moves; only the event was stopped), and the tooltip interaction model treats\n * a trigger that is `activeElement` as keyboard-held: while a tooltip on it is\n * open, pointer movement away only *requests* a close and the request is\n * refused for as long as the pointer keeps moving. Left alone, a later real\n * hover on that control would open the tip and never let it leave — the\n * residual \"stuck\" case. The gate therefore treats a suppressed focus as a\n * phantom and releases it: the first pointer activity after the focus (a\n * pointer session taking over from a script) blurs the element. Keyboard\n * sessions never release it and never need to — keyboard focus moves by Tab,\n * which is never suppressed, so nothing pins; and the release only runs for\n * elements still holding `activeElement`, so a Tab already taken from the\n * phantom is left alone.\n *\n * Focus that arrives while a pointer button is held belongs to a pointer\n * gesture, not to a tooltip: the pixel resize handle focuses its handle when a\n * drag starts and cancels the drag on blur, so a gesture focus must pass\n * through untouched (no suppression, no phantom, no release). A gesture's own\n * click behaviour already keeps tooltips closed, and the autofocus cases this\n * gate exists for all happen with the pointer up.\n *\n * Independently of the gesture window, resize grips render as\n * `<button role=\"separator\">` and carry no tooltip, so they are excluded from\n * the button-like scope entirely (see `isButtonLikeFocusTarget`).\n *\n * The gate is installed by the `Tooltip` root for the lifetime of the first\n * tooltip in a document and removed when the last one unmounts, so every\n * consumer of the primitive — including composites that build their own\n * tooltips — inherits the contract without wiring of its own.\n */\n\n/** How long after a Tab key press a resulting focus event still counts as\n * keyboard navigation. The native focus move follows the key press\n * immediately; the window only has to bridge that dispatch, not a later\n * script-driven focus. */\nexport const TOOLTIP_FOCUS_INTENT_WINDOW_MS = 250\n\n/** Elements a tooltip-bearing control is rendered as. Everything else keeps\n * its native focus behaviour, and so do resize grips (see below). */\nconst BUTTON_LIKE_SELECTOR = 'button, a[href], [role=\"button\"], [role=\"link\"]'\n\n/**\n * Whether a focus event landing on this target could open a tooltip on a\n * button-like control. Accepts any Element (an SVG glyph inside a control,\n * for instance) and duck-types so the decision is testable without a DOM.\n */\nexport function isButtonLikeFocusTarget(target: unknown): boolean {\n const element = target as Element | null | undefined\n if (typeof element?.closest !== 'function') return false\n const control = element.closest(BUTTON_LIKE_SELECTOR)\n if (control === null) return false\n // Resize grips render as `<button role=\"separator\">` and focus themselves\n // when a pointer drag starts. They carry no tooltip, and the blur that\n // releases a suppressed focus would end the drag on its first move.\n return control.getAttribute?.('role') !== 'separator'\n}\n\n/**\n * The suppression decision: a button-like focus target hides a tooltip only\n * when no keyboard navigation is in flight. Anything else — a Tab-driven\n * focus, or focus on a non-button element — passes through untouched.\n */\nexport function shouldSuppressTooltipFocus(input: {\n isButtonLike: boolean\n keyboardIntentActive: boolean\n}): boolean {\n return input.isButtonLike && !input.keyboardIntentActive\n}\n\nconst installedDocuments = new WeakSet<Document>()\n\n/**\n * Install the gate on a document. Idempotent per document; returns a disposer\n * that removes the listeners (used by tests and by the tooltip root, which\n * releases the gate when its document's last tooltip unmounts).\n */\nexport function installTooltipFocusGate(doc: Document = document): () => void {\n if (installedDocuments.has(doc)) return () => {}\n\n let lastTabKeyDownAt = 0\n /** True between a pointerdown and its pointerup/pointercancel: focus events\n * inside that window belong to a pointer gesture (drag bootstrap, press)\n * and must reach their element untouched. */\n let pointerGestureActive = false\n /** The element holding a suppressed programmatic focus, if it still holds\n * `activeElement`. One slot: a newer suppressed focus replaces an older\n * one, and anything that already lost focus needs no release. */\n let phantomFocusTarget: Element | undefined\n /** The phantom-release `pointermove` listener exists only while a phantom\n * does: a gate that parks a permanent pointer listener on every document\n * with a tooltip in it costs every page a standing listener for a state\n * that is live for a few hundred milliseconds at most. */\n let phantomReleaseAttached = false\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Tab') lastTabKeyDownAt = Date.now()\n }\n const onPointerDown = () => {\n pointerGestureActive = true\n releasePhantomFocus()\n }\n const onPointerGestureEnd = () => {\n pointerGestureActive = false\n }\n const dropPhantom = () => {\n phantomFocusTarget = undefined\n if (phantomReleaseAttached) {\n phantomReleaseAttached = false\n doc.removeEventListener('pointermove', onPointerMove, true)\n }\n }\n const onFocus = (event: FocusEvent) => {\n // Focus that moves on retires the phantom: there is nothing left to\n // release, so the parked pointer listener goes with it.\n if (phantomFocusTarget && event.target !== phantomFocusTarget) dropPhantom()\n if (pointerGestureActive) return\n if (!isButtonLikeFocusTarget(event.target)) return\n const keyboardIntentActive = Date.now() - lastTabKeyDownAt <= TOOLTIP_FOCUS_INTENT_WINDOW_MS\n if (!shouldSuppressTooltipFocus({ isButtonLike: true, keyboardIntentActive })) return\n event.stopPropagation()\n phantomFocusTarget = event.target as Element\n if (!phantomReleaseAttached) {\n phantomReleaseAttached = true\n doc.addEventListener('pointermove', onPointerMove, true)\n }\n }\n const releasePhantomFocus = () => {\n if (pointerGestureActive) return\n if (!phantomFocusTarget) return\n const phantom = phantomFocusTarget\n dropPhantom()\n if ((doc as Document).activeElement !== phantom) return\n if (typeof (phantom as HTMLElement).blur === 'function') (phantom as HTMLElement).blur()\n }\n const onPointerMove = () => releasePhantomFocus()\n\n doc.addEventListener('keydown', onKeyDown, true)\n doc.addEventListener('focus', onFocus, true)\n doc.addEventListener('pointerdown', onPointerDown, true)\n doc.addEventListener('pointerup', onPointerGestureEnd, true)\n doc.addEventListener('pointercancel', onPointerGestureEnd, true)\n installedDocuments.add(doc)\n return () => {\n doc.removeEventListener('keydown', onKeyDown, true)\n doc.removeEventListener('focus', onFocus, true)\n doc.removeEventListener('pointerdown', onPointerDown, true)\n doc.removeEventListener('pointerup', onPointerGestureEnd, true)\n doc.removeEventListener('pointercancel', onPointerGestureEnd, true)\n doc.removeEventListener('pointermove', onPointerMove, true)\n installedDocuments.delete(doc)\n }\n}\n\n/**\n * Reference-counted install for the tooltip root: the first tooltip in a\n * document acquires the gate, the last one to unmount releases it. The document\n * parameter exists so tests can drive the counter without a global DOM; the\n * production call site guards on the server render before calling.\n */\nconst gateHolders = new WeakMap<Document, number>()\nconst gateDisposers = new WeakMap<Document, () => void>()\n\nexport function acquireTooltipFocusGate(targetDoc?: Document): void {\n if (typeof document === 'undefined' && !targetDoc) return\n const doc = targetDoc ?? document\n const holders = gateHolders.get(doc) ?? 0\n gateHolders.set(doc, holders + 1)\n if (holders === 0) gateDisposers.set(doc, installTooltipFocusGate(doc))\n}\n\nexport function releaseTooltipFocusGate(targetDoc?: Document): void {\n if (typeof document === 'undefined' && !targetDoc) return\n const doc = targetDoc ?? document\n const holders = gateHolders.get(doc) ?? 0\n if (holders === 0) return\n if (holders === 1) {\n gateHolders.delete(doc)\n gateDisposers.get(doc)?.()\n gateDisposers.delete(doc)\n return\n }\n gateHolders.set(doc, holders - 1)\n}\n"],"mappings":"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"}
|
package/dist/r/lib.json
CHANGED