@adea-ai/ui 0.69.1 → 0.70.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/README.md +14 -9
- package/dist/components/composites/appearance-editor/appearance-editor.d.ts +1 -1
- package/dist/components/composites/appearance-editor/appearance-editor.js +1 -1
- package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-rows.d.ts +7 -0
- package/dist/components/composites/appearance-editor/appearance-rows.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-rows.js +187 -41
- package/dist/components/composites/appearance-editor/appearance-rows.js.map +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts +6 -4
- package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.js +21 -15
- package/dist/components/ui/dropdown-menu/dropdown-menu.js.map +1 -1
- package/dist/r/appearance-editor.json +1 -1
- package/dist/r/registry.json +1 -1
- package/dist/r/src/components/composites/appearance-editor/appearance-editor.tsx +1 -1
- package/dist/r/src/components/composites/appearance-editor/appearance-rows.tsx +231 -34
- package/dist/r/src/components/ui/dropdown-menu/dropdown-menu.tsx +8 -6
- package/package.json +1 -1
- package/registry.json +1 -1
- package/src/components/composites/appearance-editor/appearance-editor.tsx +1 -1
- package/src/components/composites/appearance-editor/appearance-rows.tsx +231 -34
- package/src/components/ui/dropdown-menu/dropdown-menu.tsx +8 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-menu.js","names":["DropdownMenu","KobalteDropdownMenu","Check","ChevronRight","Circle","ComponentProps","splitProps","menuContentPadding","menuItem","menuLabel","menuSeparator","overlayMotion","overlaySurface","popoverArrow","cn","props","_$createComponent","DropdownMenuTrigger","Trigger","DropdownMenuPortal","Portal","DropdownMenuContentProps","Content","hideArrow","DropdownMenuContent","local","rest","children","_$mergeProps","class","_$memo","Arrow","DropdownMenuItem","Item","variant","shortcut","_el$","_tmpl$","_$insert","DropdownMenuShortcut","_el$2","_tmpl$2","_$spread","DropdownMenuCheckboxItem","CheckboxItem","ItemIndicator","DropdownMenuRadioGroup","RadioGroup","DropdownMenuRadioItem","RadioItem","DropdownMenuLabel","GroupLabel","DropdownMenuGroup","Group","DropdownMenuSeparator","Separator","DropdownMenuSub","Sub","DropdownMenuSubTrigger","SubTrigger","DropdownMenuSubContent","SubContent","DropdownMenu","_$createComponent","KobalteDropdownMenu","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/dropdown-menu/dropdown-menu.tsx"],"sourcesContent":["import { DropdownMenu as KobalteDropdownMenu } from '@kobalte/core/dropdown-menu'\nimport { Check, ChevronRight, Circle } from 'lucide-solid'\nimport type { ComponentProps } from 'solid-js'\nimport { splitProps } from 'solid-js'\nimport {\n menuContentPadding,\n menuItem,\n menuLabel,\n menuSeparator,\n overlayMotion,\n overlaySurface,\n popoverArrow,\n} from '#lib/overlay'\nimport { cn } from '#lib/utils'\n\n/**\n * DropdownMenu.\n *\n * A list of actions on a trigger. This is the right home for \"what can I do\n * with this thing\": rename, duplicate, export, delete. It is not a Select\n * (which holds a *value* the user is choosing) and not a Popover (which holds\n * arbitrary content).\n *\n * Kobalte supplies the full menu contract — arrow keys, typeahead, the roving\n * highlight, Escape to close and return focus — which is exactly what a\n * hand-rolled `div` with click handlers gets wrong.\n *\n * The `destructive` variant on an item is a *colour*, not a confirmation.\n * Pairing it with an AlertDialog is the caller's job.\n */\nexport function DropdownMenu(props: ComponentProps<typeof KobalteDropdownMenu>) {\n return <KobalteDropdownMenu {...props} />\n}\n\nexport function DropdownMenuTrigger(props: ComponentProps<typeof KobalteDropdownMenu.Trigger>) {\n return <KobalteDropdownMenu.Trigger {...props} />\n}\n\nexport function DropdownMenuPortal(props: ComponentProps<typeof KobalteDropdownMenu.Portal>) {\n return <KobalteDropdownMenu.Portal {...props} />\n}\n\nexport type DropdownMenuContentProps = ComponentProps<typeof KobalteDropdownMenu.Content> & {\n hideArrow?: boolean\n}\n\nexport function DropdownMenuContent(props: DropdownMenuContentProps) {\n const [local, rest] = splitProps(props, ['class', 'hideArrow', 'children'])\n\n return (\n <KobalteDropdownMenu.Portal>\n <KobalteDropdownMenu.Content\n class={cn(\n overlaySurface,\n overlayMotion,\n 'z-(--z-menu) min-w-[10rem] origin-(--kb-menu-content-transform-origin) overflow-hidden',\n menuContentPadding,\n local.class\n )}\n {...rest}\n >\n {!local.hideArrow && <KobalteDropdownMenu.Arrow aria-hidden=\"true\" class={popoverArrow} />}\n {local.children}\n </KobalteDropdownMenu.Content>\n </KobalteDropdownMenu.Portal>\n )\n}\n\nexport function DropdownMenuItem(\n props: ComponentProps<typeof KobalteDropdownMenu.Item> & {\n /** Colour the row as a destructive action. Confirm it separately. */\n variant?: 'default' | 'destructive'\n /** Draw a shortcut hint at the trailing edge of the row. */\n shortcut?: string\n }\n) {\n const [local, rest] = splitProps(props, ['class', 'variant', 'shortcut', 'children'])\n\n return (\n <KobalteDropdownMenu.Item\n class={cn(\n menuItem,\n {\n 'text-destructive data-[highlighted]:bg-destructive-subtle data-[highlighted]:text-destructive':\n local.variant === 'destructive',\n },\n local.class\n )}\n {...rest}\n >\n {local.children}\n {local.shortcut ? (\n <span class=\"text-muted-foreground ms-auto font-mono text-2xs tracking-widest\">\n {local.shortcut}\n </span>\n ) : null}\n </KobalteDropdownMenu.Item>\n )\n}\n\n/**\n * The chord drawn at a row's trailing edge.\n *\n * A component as well as the `shortcut` prop on an item, because a caller composing\n * a row by hand needs the same treatment — and because the alternative is every\n * caller inventing the same mono-and-dimmed span.\n */\nexport function DropdownMenuShortcut(props: ComponentProps<'span'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n class={cn('text-muted-foreground ms-auto font-mono text-2xs tracking-widest', local.class)}\n {...rest}\n />\n )\n}\n\nexport function DropdownMenuCheckboxItem(\n props: ComponentProps<typeof KobalteDropdownMenu.CheckboxItem>\n) {\n const [local, rest] = splitProps(props, ['class', 'children'])\n\n return (\n <KobalteDropdownMenu.CheckboxItem class={cn(menuItem, 'pe-8', local.class)} {...rest}>\n {local.children}\n <KobalteDropdownMenu.ItemIndicator class=\"absolute end-2 flex size-4 items-center justify-center\">\n <Check class=\"size-4\" />\n </KobalteDropdownMenu.ItemIndicator>\n </KobalteDropdownMenu.CheckboxItem>\n )\n}\n\nexport function DropdownMenuRadioGroup(\n props: ComponentProps<typeof KobalteDropdownMenu.RadioGroup>\n) {\n return <KobalteDropdownMenu.RadioGroup {...props} />\n}\n\nexport function DropdownMenuRadioItem(props: ComponentProps<typeof KobalteDropdownMenu.RadioItem>) {\n const [local, rest] = splitProps(props, ['class', 'children'])\n\n return (\n <KobalteDropdownMenu.RadioItem class={cn(menuItem, 'pe-8', local.class)} {...rest}>\n {local.children}\n <KobalteDropdownMenu.ItemIndicator class=\"absolute end-2 flex size-4 items-center justify-center\">\n <Circle class=\"size-2 fill-current\" />\n </KobalteDropdownMenu.ItemIndicator>\n </KobalteDropdownMenu.RadioItem>\n )\n}\n\nexport function DropdownMenuLabel(props: ComponentProps<typeof KobalteDropdownMenu.GroupLabel>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDropdownMenu.GroupLabel class={cn(menuLabel, local.class)} {...rest} />\n}\n\nexport function DropdownMenuGroup(props: ComponentProps<typeof KobalteDropdownMenu.Group>) {\n return <KobalteDropdownMenu.Group {...props} />\n}\n\nexport function DropdownMenuSeparator(props: ComponentProps<typeof KobalteDropdownMenu.Separator>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDropdownMenu.Separator class={cn(menuSeparator, local.class)} {...rest} />\n}\n\nexport function DropdownMenuSub(props: ComponentProps<typeof KobalteDropdownMenu.Sub>) {\n return <KobalteDropdownMenu.Sub {...props} />\n}\n\nexport function DropdownMenuSubTrigger(\n props: ComponentProps<typeof KobalteDropdownMenu.SubTrigger>\n) {\n const [local, rest] = splitProps(props, ['class', 'children'])\n\n return (\n <KobalteDropdownMenu.SubTrigger class={cn(menuItem, local.class)} {...rest}>\n {local.children}\n <ChevronRight class=\"ms-auto size-4\" />\n </KobalteDropdownMenu.SubTrigger>\n )\n}\n\nexport function DropdownMenuSubContent(\n props: ComponentProps<typeof KobalteDropdownMenu.SubContent>\n) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <KobalteDropdownMenu.Portal>\n <KobalteDropdownMenu.SubContent\n class={cn(\n overlaySurface,\n overlayMotion,\n 'z-(--z-menu) min-w-[8rem] origin-(--kb-menu-content-transform-origin) overflow-hidden',\n menuContentPadding,\n local.class\n )}\n {...rest}\n />\n </KobalteDropdownMenu.Portal>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dropdown-menu.js","names":["DropdownMenu","KobalteDropdownMenu","Check","ChevronRight","Circle","ComponentProps","splitProps","menuContentPadding","menuItem","menuLabel","menuSeparator","overlayMotion","overlaySurface","popoverArrow","cn","props","_$createComponent","DropdownMenuTrigger","Trigger","DropdownMenuPortal","Portal","DropdownMenuContentProps","Content","hideArrow","portalMount","HTMLElement","DropdownMenuContent","local","rest","mount","children","_$mergeProps","class","_$memo","Arrow","DropdownMenuItem","Item","variant","shortcut","_el$","_tmpl$","_$insert","DropdownMenuShortcut","_el$2","_tmpl$2","_$spread","DropdownMenuCheckboxItem","CheckboxItem","ItemIndicator","DropdownMenuRadioGroup","RadioGroup","DropdownMenuRadioItem","RadioItem","DropdownMenuLabel","GroupLabel","DropdownMenuGroup","Group","DropdownMenuSeparator","Separator","DropdownMenuSub","Sub","DropdownMenuSubTrigger","SubTrigger","DropdownMenuSubContent","SubContent","DropdownMenu","_$createComponent","KobalteDropdownMenu","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/dropdown-menu/dropdown-menu.tsx"],"sourcesContent":["import { DropdownMenu as KobalteDropdownMenu } from '@kobalte/core/dropdown-menu'\nimport { Check, ChevronRight, Circle } from 'lucide-solid'\nimport type { ComponentProps } from 'solid-js'\nimport { splitProps } from 'solid-js'\nimport {\n menuContentPadding,\n menuItem,\n menuLabel,\n menuSeparator,\n overlayMotion,\n overlaySurface,\n popoverArrow,\n} from '#lib/overlay'\nimport { cn } from '#lib/utils'\n\n/**\n * DropdownMenu.\n *\n * A list of actions on a trigger, with radio groups for persistent choices\n * that fit naturally in a compact menu. Use Select for form inputs whose\n * selected value needs the field-style control, and Popover for arbitrary\n * content.\n *\n * Kobalte supplies the full menu contract — arrow keys, typeahead, the roving\n * highlight, Escape to close and return focus — which is exactly what a\n * hand-rolled `div` with click handlers gets wrong.\n *\n * The `destructive` variant on an item is a *colour*, not a confirmation.\n * Pairing it with an AlertDialog is the caller's job.\n */\nexport function DropdownMenu(props: ComponentProps<typeof KobalteDropdownMenu>) {\n return <KobalteDropdownMenu {...props} />\n}\n\nexport function DropdownMenuTrigger(props: ComponentProps<typeof KobalteDropdownMenu.Trigger>) {\n return <KobalteDropdownMenu.Trigger {...props} />\n}\n\nexport function DropdownMenuPortal(props: ComponentProps<typeof KobalteDropdownMenu.Portal>) {\n return <KobalteDropdownMenu.Portal {...props} />\n}\n\nexport type DropdownMenuContentProps = ComponentProps<typeof KobalteDropdownMenu.Content> & {\n hideArrow?: boolean\n /** Mount under an owner element such as a modal, keeping the menu in its accessible subtree. */\n portalMount?: HTMLElement\n}\n\nexport function DropdownMenuContent(props: DropdownMenuContentProps) {\n const [local, rest] = splitProps(props, ['class', 'hideArrow', 'children', 'portalMount'])\n\n return (\n <KobalteDropdownMenu.Portal mount={local.portalMount}>\n <KobalteDropdownMenu.Content\n class={cn(\n overlaySurface,\n overlayMotion,\n 'z-(--z-menu) min-w-[10rem] origin-(--kb-menu-content-transform-origin) overflow-hidden',\n menuContentPadding,\n local.class\n )}\n {...rest}\n >\n {!local.hideArrow && <KobalteDropdownMenu.Arrow aria-hidden=\"true\" class={popoverArrow} />}\n {local.children}\n </KobalteDropdownMenu.Content>\n </KobalteDropdownMenu.Portal>\n )\n}\n\nexport function DropdownMenuItem(\n props: ComponentProps<typeof KobalteDropdownMenu.Item> & {\n /** Colour the row as a destructive action. Confirm it separately. */\n variant?: 'default' | 'destructive'\n /** Draw a shortcut hint at the trailing edge of the row. */\n shortcut?: string\n }\n) {\n const [local, rest] = splitProps(props, ['class', 'variant', 'shortcut', 'children'])\n\n return (\n <KobalteDropdownMenu.Item\n class={cn(\n menuItem,\n {\n 'text-destructive data-[highlighted]:bg-destructive-subtle data-[highlighted]:text-destructive':\n local.variant === 'destructive',\n },\n local.class\n )}\n {...rest}\n >\n {local.children}\n {local.shortcut ? (\n <span class=\"text-muted-foreground ms-auto font-mono text-2xs tracking-widest\">\n {local.shortcut}\n </span>\n ) : null}\n </KobalteDropdownMenu.Item>\n )\n}\n\n/**\n * The chord drawn at a row's trailing edge.\n *\n * A component as well as the `shortcut` prop on an item, because a caller composing\n * a row by hand needs the same treatment — and because the alternative is every\n * caller inventing the same mono-and-dimmed span.\n */\nexport function DropdownMenuShortcut(props: ComponentProps<'span'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n class={cn('text-muted-foreground ms-auto font-mono text-2xs tracking-widest', local.class)}\n {...rest}\n />\n )\n}\n\nexport function DropdownMenuCheckboxItem(\n props: ComponentProps<typeof KobalteDropdownMenu.CheckboxItem>\n) {\n const [local, rest] = splitProps(props, ['class', 'children'])\n\n return (\n <KobalteDropdownMenu.CheckboxItem class={cn(menuItem, 'pe-8', local.class)} {...rest}>\n {local.children}\n <KobalteDropdownMenu.ItemIndicator class=\"absolute end-2 flex size-4 items-center justify-center\">\n <Check class=\"size-4\" />\n </KobalteDropdownMenu.ItemIndicator>\n </KobalteDropdownMenu.CheckboxItem>\n )\n}\n\nexport function DropdownMenuRadioGroup(\n props: ComponentProps<typeof KobalteDropdownMenu.RadioGroup>\n) {\n return <KobalteDropdownMenu.RadioGroup {...props} />\n}\n\nexport function DropdownMenuRadioItem(props: ComponentProps<typeof KobalteDropdownMenu.RadioItem>) {\n const [local, rest] = splitProps(props, ['class', 'children'])\n\n return (\n <KobalteDropdownMenu.RadioItem class={cn(menuItem, 'pe-8', local.class)} {...rest}>\n {local.children}\n <KobalteDropdownMenu.ItemIndicator class=\"absolute end-2 flex size-4 items-center justify-center\">\n <Circle class=\"size-2 fill-current\" />\n </KobalteDropdownMenu.ItemIndicator>\n </KobalteDropdownMenu.RadioItem>\n )\n}\n\nexport function DropdownMenuLabel(props: ComponentProps<typeof KobalteDropdownMenu.GroupLabel>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDropdownMenu.GroupLabel class={cn(menuLabel, local.class)} {...rest} />\n}\n\nexport function DropdownMenuGroup(props: ComponentProps<typeof KobalteDropdownMenu.Group>) {\n return <KobalteDropdownMenu.Group {...props} />\n}\n\nexport function DropdownMenuSeparator(props: ComponentProps<typeof KobalteDropdownMenu.Separator>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteDropdownMenu.Separator class={cn(menuSeparator, local.class)} {...rest} />\n}\n\nexport function DropdownMenuSub(props: ComponentProps<typeof KobalteDropdownMenu.Sub>) {\n return <KobalteDropdownMenu.Sub {...props} />\n}\n\nexport function DropdownMenuSubTrigger(\n props: ComponentProps<typeof KobalteDropdownMenu.SubTrigger>\n) {\n const [local, rest] = splitProps(props, ['class', 'children'])\n\n return (\n <KobalteDropdownMenu.SubTrigger class={cn(menuItem, local.class)} {...rest}>\n {local.children}\n <ChevronRight class=\"ms-auto size-4\" />\n </KobalteDropdownMenu.SubTrigger>\n )\n}\n\nexport function DropdownMenuSubContent(\n props: ComponentProps<typeof KobalteDropdownMenu.SubContent>\n) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <KobalteDropdownMenu.Portal>\n <KobalteDropdownMenu.SubContent\n class={cn(\n overlaySurface,\n overlayMotion,\n 'z-(--z-menu) min-w-[8rem] origin-(--kb-menu-content-transform-origin) overflow-hidden',\n menuContentPadding,\n local.class\n )}\n {...rest}\n />\n </KobalteDropdownMenu.Portal>\n )\n}\n"],"mappings":"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"}
|
package/dist/r/registry.json
CHANGED
|
@@ -208,7 +208,7 @@ export function AppearanceEditor(props: AppearanceEditorProps) {
|
|
|
208
208
|
)
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
/** Modal anchoring/dismissal and nested-
|
|
211
|
+
/** Modal anchoring/dismissal and nested-menu behavior come from Kobalte.
|
|
212
212
|
* Its measured available height also bounds scrolling, keeping footer actions
|
|
213
213
|
* reachable when a narrow popup begins below its trigger. */
|
|
214
214
|
export function AppearancePopover(props: AppearancePopoverProps) {
|
|
@@ -24,18 +24,33 @@
|
|
|
24
24
|
// Retains the compact divided row and palette-preview selector from the pinned
|
|
25
25
|
// Zeron/Adea composition; Kobalte owns option navigation and nested dismissal.
|
|
26
26
|
import type { AdeaTheme, AdeaThemeRecord } from '@adea-ai/themes'
|
|
27
|
-
import { Show, createMemo, createSignal, type JSX } from 'solid-js'
|
|
28
|
-
import { Palette } from 'lucide-solid'
|
|
27
|
+
import { For, Show, createMemo, createSignal, onCleanup, type JSX } from 'solid-js'
|
|
28
|
+
import { ChevronDown, Palette } from 'lucide-solid'
|
|
29
29
|
import { cn } from '../../../lib/utils'
|
|
30
|
+
import { Button } from '../../ui/button/button'
|
|
30
31
|
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} from '../../ui/
|
|
32
|
+
DropdownMenu,
|
|
33
|
+
DropdownMenuContent,
|
|
34
|
+
DropdownMenuRadioGroup,
|
|
35
|
+
DropdownMenuRadioItem,
|
|
36
|
+
DropdownMenuTrigger,
|
|
37
|
+
} from '../../ui/dropdown-menu/dropdown-menu'
|
|
37
38
|
import { PalettePreview } from './theme-preview'
|
|
38
39
|
|
|
40
|
+
const POINTER_FOCUS_TARGET_SELECTOR =
|
|
41
|
+
'a[href], area[href], button, input, select, textarea, iframe, [tabindex], [contenteditable], details > summary:first-of-type'
|
|
42
|
+
|
|
43
|
+
function isTabStop(element: HTMLElement) {
|
|
44
|
+
return (
|
|
45
|
+
(element.tabIndex >= 0 ||
|
|
46
|
+
(element.matches('details > summary:first-of-type') && !element.hasAttribute('tabindex'))) &&
|
|
47
|
+
!element.matches(':disabled') &&
|
|
48
|
+
element.getAttribute('aria-disabled') !== 'true' &&
|
|
49
|
+
element.closest('[hidden], [inert], [aria-hidden="true"]') === null &&
|
|
50
|
+
element.getClientRects().length > 0
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
39
54
|
export function SettingsRow(props: {
|
|
40
55
|
title: string
|
|
41
56
|
icon: JSX.Element
|
|
@@ -66,6 +81,13 @@ export function SettingsRow(props: {
|
|
|
66
81
|
)
|
|
67
82
|
}
|
|
68
83
|
|
|
84
|
+
/**
|
|
85
|
+
* A compact persistent theme choice. Kobalte handles menu navigation and
|
|
86
|
+
* dismissal; this row moves Tab to the adjacent browser-reported stop because
|
|
87
|
+
* menus consume Tab by default. Enumerating elements and checking their native
|
|
88
|
+
* tabIndex keeps details summaries in the order while preserving explicit
|
|
89
|
+
* tabindex overrides.
|
|
90
|
+
*/
|
|
69
91
|
export function ThemeRow(props: {
|
|
70
92
|
appearance: 'light' | 'dark'
|
|
71
93
|
selectedId: string
|
|
@@ -75,6 +97,15 @@ export function ThemeRow(props: {
|
|
|
75
97
|
onSelect: (id: string) => void
|
|
76
98
|
}) {
|
|
77
99
|
const [portalMount, setPortalMount] = createSignal<HTMLDivElement>()
|
|
100
|
+
const [triggerElement, setTriggerElement] = createSignal<HTMLButtonElement>()
|
|
101
|
+
const [menuOpen, setMenuOpen] = createSignal(false)
|
|
102
|
+
const [focusOutsideTarget, setFocusOutsideTarget] = createSignal<HTMLElement>()
|
|
103
|
+
const [restoreTriggerFocus, setRestoreTriggerFocus] = createSignal(false)
|
|
104
|
+
let focusTargetAfterTab: HTMLElement | undefined
|
|
105
|
+
let focusLifecycleVersion = 0
|
|
106
|
+
onCleanup(() => {
|
|
107
|
+
focusLifecycleVersion += 1
|
|
108
|
+
})
|
|
78
109
|
const options = createMemo(() =>
|
|
79
110
|
props.themes.filter((theme) => theme.appearance === props.appearance)
|
|
80
111
|
)
|
|
@@ -84,38 +115,204 @@ export function ThemeRow(props: {
|
|
|
84
115
|
options().find((theme) => theme.id === props.preview.id)
|
|
85
116
|
)
|
|
86
117
|
const label = () => (props.appearance === 'light' ? 'Light theme' : 'Dark theme')
|
|
118
|
+
const closeMenu = () => {
|
|
119
|
+
if (menuOpen()) focusLifecycleVersion += 1
|
|
120
|
+
setMenuOpen(false)
|
|
121
|
+
}
|
|
122
|
+
const moveFocusOnTab = (event: KeyboardEvent) => {
|
|
123
|
+
if (event.key !== 'Tab' || event.isComposing) return
|
|
124
|
+
|
|
125
|
+
const trigger = triggerElement()
|
|
126
|
+
if (!trigger) return
|
|
127
|
+
const parentDialog = portalMount()?.closest<HTMLElement>('[role="dialog"]')
|
|
128
|
+
const focusScope = parentDialog ?? portalMount()?.ownerDocument.body
|
|
129
|
+
if (!focusScope) return
|
|
130
|
+
|
|
131
|
+
const focusStops = Array.from(focusScope.querySelectorAll<HTMLElement>('*')).filter(
|
|
132
|
+
(element) =>
|
|
133
|
+
isTabStop(element) &&
|
|
134
|
+
element.closest('[role="menu"], [hidden], [inert], [aria-hidden="true"]') === null
|
|
135
|
+
)
|
|
136
|
+
const orderedFocusStops = [
|
|
137
|
+
...focusStops
|
|
138
|
+
.filter((element) => element.tabIndex > 0)
|
|
139
|
+
.toSorted((a, b) => a.tabIndex - b.tabIndex),
|
|
140
|
+
...focusStops.filter((element) => element.tabIndex <= 0),
|
|
141
|
+
]
|
|
142
|
+
const triggerIndex = orderedFocusStops.indexOf(trigger)
|
|
143
|
+
const direction = event.shiftKey ? -1 : 1
|
|
144
|
+
const adjacent =
|
|
145
|
+
orderedFocusStops[triggerIndex + direction] ??
|
|
146
|
+
(parentDialog ? (direction > 0 ? orderedFocusStops[0] : orderedFocusStops.at(-1)) : undefined)
|
|
147
|
+
|
|
148
|
+
event.stopPropagation()
|
|
149
|
+
setRestoreTriggerFocus(false)
|
|
150
|
+
if (adjacent) {
|
|
151
|
+
event.preventDefault()
|
|
152
|
+
focusTargetAfterTab = adjacent
|
|
153
|
+
setFocusOutsideTarget(adjacent)
|
|
154
|
+
closeMenu()
|
|
155
|
+
adjacent.focus({ preventScroll: true })
|
|
156
|
+
} else {
|
|
157
|
+
focusTargetAfterTab = undefined
|
|
158
|
+
setFocusOutsideTarget(undefined)
|
|
159
|
+
closeMenu()
|
|
160
|
+
}
|
|
161
|
+
}
|
|
87
162
|
return (
|
|
88
163
|
<SettingsRow title={label()} icon={<Palette />}>
|
|
89
164
|
<div ref={setPortalMount}>
|
|
90
|
-
<
|
|
165
|
+
<DropdownMenu
|
|
91
166
|
modal={false}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
167
|
+
open={menuOpen()}
|
|
168
|
+
onOpenChange={(open) => {
|
|
169
|
+
if (open !== menuOpen()) focusLifecycleVersion += 1
|
|
170
|
+
setMenuOpen(open)
|
|
171
|
+
if (open) {
|
|
172
|
+
focusTargetAfterTab = undefined
|
|
173
|
+
setFocusOutsideTarget(undefined)
|
|
174
|
+
setRestoreTriggerFocus(false)
|
|
175
|
+
}
|
|
99
176
|
}}
|
|
100
|
-
itemComponent={(item) => (
|
|
101
|
-
<SelectItem item={item.item}>
|
|
102
|
-
<PalettePreview theme={item.item.rawValue} />
|
|
103
|
-
{item.item.rawValue.name}
|
|
104
|
-
</SelectItem>
|
|
105
|
-
)}
|
|
106
177
|
>
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
178
|
+
<DropdownMenuTrigger
|
|
179
|
+
ref={setTriggerElement}
|
|
180
|
+
as={Button}
|
|
181
|
+
variant="outline"
|
|
182
|
+
size="sm"
|
|
183
|
+
aria-label={label()}
|
|
184
|
+
disabled={props.disabled || options().length === 0}
|
|
185
|
+
class="w-full justify-between sm:w-52"
|
|
186
|
+
>
|
|
187
|
+
<span class="flex min-w-0 flex-1 items-center gap-2">
|
|
188
|
+
<PalettePreview theme={props.preview} />
|
|
189
|
+
<span class="min-w-0 flex-1 truncate">{selected()?.name ?? props.preview.name}</span>
|
|
190
|
+
</span>
|
|
191
|
+
<ChevronDown aria-hidden="true" class="shrink-0 text-muted-foreground" />
|
|
192
|
+
</DropdownMenuTrigger>
|
|
193
|
+
<DropdownMenuContent
|
|
194
|
+
portalMount={portalMount()}
|
|
195
|
+
class="max-h-(--kb-popper-content-available-height) w-(--kb-popper-anchor-width) min-w-32 overflow-x-hidden overflow-y-auto"
|
|
196
|
+
onInteractOutside={(event) => {
|
|
197
|
+
if (event.detail.originalEvent.type !== 'pointerdown') return
|
|
198
|
+
const parentDialog = portalMount()?.closest<HTMLElement>('[role="dialog"]')
|
|
199
|
+
const focusScope = parentDialog ?? portalMount()?.ownerDocument.body
|
|
200
|
+
const target = event.detail.originalEvent.target
|
|
201
|
+
if (!(target instanceof Element) || !focusScope?.contains(target)) return
|
|
202
|
+
|
|
203
|
+
const focusTarget = target.closest<HTMLElement>(POINTER_FOCUS_TARGET_SELECTOR)
|
|
204
|
+
if (focusTarget && isTabStop(focusTarget)) {
|
|
205
|
+
setRestoreTriggerFocus(false)
|
|
206
|
+
setFocusOutsideTarget(focusTarget)
|
|
207
|
+
} else {
|
|
208
|
+
setRestoreTriggerFocus(true)
|
|
209
|
+
}
|
|
210
|
+
}}
|
|
211
|
+
onFocusOutside={(event) => {
|
|
212
|
+
// The containing dialog or document body can briefly reclaim
|
|
213
|
+
// focus when the menu opens. Keep that handoff from dismissing
|
|
214
|
+
// it; focus moving to another descendant still closes the menu.
|
|
215
|
+
const parentDialog = portalMount()?.closest<HTMLElement>('[role="dialog"]')
|
|
216
|
+
const focusScope = parentDialog ?? portalMount()?.ownerDocument.body
|
|
217
|
+
const target = event.detail.originalEvent.target
|
|
218
|
+
if (target === focusScope) {
|
|
219
|
+
event.preventDefault()
|
|
220
|
+
} else if (target instanceof HTMLElement && focusScope?.contains(target)) {
|
|
221
|
+
setRestoreTriggerFocus(false)
|
|
222
|
+
setFocusOutsideTarget(target)
|
|
223
|
+
}
|
|
224
|
+
}}
|
|
225
|
+
onEscapeKeyDown={() => setRestoreTriggerFocus(true)}
|
|
226
|
+
onCloseAutoFocus={(event) => {
|
|
227
|
+
// A prior menu instance can finish its focus cleanup after this
|
|
228
|
+
// row has already reopened. Do not let that cleanup steal focus.
|
|
229
|
+
if (menuOpen()) {
|
|
230
|
+
event.preventDefault()
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const lifecycleVersion = focusLifecycleVersion
|
|
235
|
+
const shouldRestore = restoreTriggerFocus()
|
|
236
|
+
const focusTarget = focusTargetAfterTab ?? focusOutsideTarget()
|
|
237
|
+
focusTargetAfterTab = undefined
|
|
238
|
+
setFocusOutsideTarget(undefined)
|
|
239
|
+
setRestoreTriggerFocus(false)
|
|
240
|
+
if (shouldRestore) {
|
|
241
|
+
// The saved focus may be the containing dialog rather than
|
|
242
|
+
// the trigger when WebKit opens this menu from a pointer click.
|
|
243
|
+
event.preventDefault()
|
|
244
|
+
triggerElement()?.focus({ preventScroll: true })
|
|
245
|
+
return
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const parentDialog = portalMount()?.closest<HTMLElement>('[role="dialog"]')
|
|
249
|
+
const focusScope = parentDialog ?? portalMount()?.ownerDocument.body
|
|
250
|
+
if (focusTarget?.isConnected && focusScope?.contains(focusTarget)) {
|
|
251
|
+
// Preserve the intended in-scope destination across
|
|
252
|
+
// Kobalte's deferred stale-focus restore.
|
|
253
|
+
event.preventDefault()
|
|
254
|
+
queueMicrotask(() => {
|
|
255
|
+
if (lifecycleVersion !== focusLifecycleVersion || menuOpen()) return
|
|
256
|
+
|
|
257
|
+
const activeElement = document.activeElement
|
|
258
|
+
const isMenuFocus =
|
|
259
|
+
activeElement instanceof HTMLElement &&
|
|
260
|
+
activeElement.closest('[role="menu"]') !== null
|
|
261
|
+
const isTriggerFocus = activeElement === triggerElement()
|
|
262
|
+
if (
|
|
263
|
+
activeElement !== focusTarget &&
|
|
264
|
+
(activeElement === document.body ||
|
|
265
|
+
activeElement === focusScope ||
|
|
266
|
+
isMenuFocus ||
|
|
267
|
+
isTriggerFocus)
|
|
268
|
+
) {
|
|
269
|
+
focusTarget.focus({ preventScroll: true })
|
|
270
|
+
}
|
|
271
|
+
})
|
|
272
|
+
return
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const activeElement = document.activeElement
|
|
276
|
+
if (
|
|
277
|
+
focusScope &&
|
|
278
|
+
activeElement instanceof HTMLElement &&
|
|
279
|
+
activeElement !== focusScope &&
|
|
280
|
+
focusScope.contains(activeElement) &&
|
|
281
|
+
activeElement.closest('[role="menu"]') === null
|
|
282
|
+
) {
|
|
283
|
+
// Preserve a real focus target in this scope instead of
|
|
284
|
+
// restoring the stale element captured when the menu mounted. A
|
|
285
|
+
// focused menu item is about to unmount, so Kobalte must restore
|
|
286
|
+
// focus to the trigger instead.
|
|
287
|
+
event.preventDefault()
|
|
288
|
+
}
|
|
289
|
+
}}
|
|
290
|
+
>
|
|
291
|
+
<DropdownMenuRadioGroup
|
|
292
|
+
value={selected()?.id ?? ''}
|
|
293
|
+
aria-label={`${label()} options`}
|
|
294
|
+
on:keydown={moveFocusOnTab}
|
|
295
|
+
onChange={(id) => {
|
|
296
|
+
if (!props.disabled && typeof id === 'string') props.onSelect(id)
|
|
297
|
+
}}
|
|
298
|
+
>
|
|
299
|
+
<For each={options()}>
|
|
300
|
+
{(theme) => (
|
|
301
|
+
<DropdownMenuRadioItem
|
|
302
|
+
value={theme.id}
|
|
303
|
+
textValue={theme.name}
|
|
304
|
+
closeOnSelect={true}
|
|
305
|
+
disabled={props.disabled}
|
|
306
|
+
onSelect={() => setRestoreTriggerFocus(true)}
|
|
307
|
+
>
|
|
308
|
+
<PalettePreview theme={theme} />
|
|
309
|
+
<span class="min-w-0 flex-1 truncate">{theme.name}</span>
|
|
310
|
+
</DropdownMenuRadioItem>
|
|
311
|
+
)}
|
|
312
|
+
</For>
|
|
313
|
+
</DropdownMenuRadioGroup>
|
|
314
|
+
</DropdownMenuContent>
|
|
315
|
+
</DropdownMenu>
|
|
119
316
|
</div>
|
|
120
317
|
</SettingsRow>
|
|
121
318
|
)
|
|
@@ -16,10 +16,10 @@ import { cn } from '../../../lib/utils'
|
|
|
16
16
|
/**
|
|
17
17
|
* DropdownMenu.
|
|
18
18
|
*
|
|
19
|
-
* A list of actions on a trigger
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* A list of actions on a trigger, with radio groups for persistent choices
|
|
20
|
+
* that fit naturally in a compact menu. Use Select for form inputs whose
|
|
21
|
+
* selected value needs the field-style control, and Popover for arbitrary
|
|
22
|
+
* content.
|
|
23
23
|
*
|
|
24
24
|
* Kobalte supplies the full menu contract — arrow keys, typeahead, the roving
|
|
25
25
|
* highlight, Escape to close and return focus — which is exactly what a
|
|
@@ -42,13 +42,15 @@ export function DropdownMenuPortal(props: ComponentProps<typeof KobalteDropdownM
|
|
|
42
42
|
|
|
43
43
|
export type DropdownMenuContentProps = ComponentProps<typeof KobalteDropdownMenu.Content> & {
|
|
44
44
|
hideArrow?: boolean
|
|
45
|
+
/** Mount under an owner element such as a modal, keeping the menu in its accessible subtree. */
|
|
46
|
+
portalMount?: HTMLElement
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
export function DropdownMenuContent(props: DropdownMenuContentProps) {
|
|
48
|
-
const [local, rest] = splitProps(props, ['class', 'hideArrow', 'children'])
|
|
50
|
+
const [local, rest] = splitProps(props, ['class', 'hideArrow', 'children', 'portalMount'])
|
|
49
51
|
|
|
50
52
|
return (
|
|
51
|
-
<KobalteDropdownMenu.Portal>
|
|
53
|
+
<KobalteDropdownMenu.Portal mount={local.portalMount}>
|
|
52
54
|
<KobalteDropdownMenu.Content
|
|
53
55
|
class={cn(
|
|
54
56
|
overlaySurface,
|
package/package.json
CHANGED
package/registry.json
CHANGED
|
@@ -208,7 +208,7 @@ export function AppearanceEditor(props: AppearanceEditorProps) {
|
|
|
208
208
|
)
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
/** Modal anchoring/dismissal and nested-
|
|
211
|
+
/** Modal anchoring/dismissal and nested-menu behavior come from Kobalte.
|
|
212
212
|
* Its measured available height also bounds scrolling, keeping footer actions
|
|
213
213
|
* reachable when a narrow popup begins below its trigger. */
|
|
214
214
|
export function AppearancePopover(props: AppearancePopoverProps) {
|