@pzerelles/headlessui-svelte 2.1.2-next.7 → 2.1.2-next.8
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/button/Button.svelte +54 -84
- package/dist/checkbox/Checkbox.svelte +120 -174
- package/dist/close-button/CloseButton.svelte +6 -12
- package/dist/combobox/Combobox.svelte +3 -50
- package/dist/data-interactive/DataInteractive.svelte +29 -57
- package/dist/description/Description.svelte +21 -32
- package/dist/dialog/Dialog.svelte +34 -69
- package/dist/dialog/DialogBackdrop.svelte +12 -29
- package/dist/dialog/DialogPanel.svelte +26 -49
- package/dist/dialog/DialogTitle.svelte +23 -38
- package/dist/dialog/InternalDialog.svelte +202 -263
- package/dist/field/Field.svelte +26 -49
- package/dist/fieldset/Fieldset.svelte +29 -50
- package/dist/focus-trap/FocusTrap.svelte +283 -419
- package/dist/input/Input.svelte +53 -84
- package/dist/internal/FocusSentinel.svelte +8 -16
- package/dist/internal/ForcePortalRoot.svelte +3 -7
- package/dist/internal/FormFields.svelte +20 -31
- package/dist/internal/FormResolver.svelte +15 -20
- package/dist/internal/Hidden.svelte +23 -44
- package/dist/internal/HoistFormFields.svelte +4 -7
- package/dist/internal/MainTreeProvider.svelte +36 -89
- package/dist/internal/Portal.svelte +14 -18
- package/dist/label/Label.svelte +57 -91
- package/dist/legend/Legend.svelte +3 -18
- package/dist/listbox/Listbox.svelte +396 -588
- package/dist/listbox/ListboxButton.svelte +127 -176
- package/dist/listbox/ListboxOption.svelte +125 -166
- package/dist/listbox/ListboxOptions.svelte +244 -340
- package/dist/listbox/ListboxSelectedOption.svelte +15 -38
- package/dist/menu/Menu.svelte +218 -307
- package/dist/menu/MenuButton.svelte +115 -157
- package/dist/menu/MenuHeading.svelte +14 -34
- package/dist/menu/MenuItem.svelte +107 -145
- package/dist/menu/MenuItems.svelte +224 -298
- package/dist/menu/MenuSection.svelte +9 -26
- package/dist/menu/MenuSeparator.svelte +4 -20
- package/dist/portal/InternalPortal.svelte +85 -141
- package/dist/portal/Portal.svelte +2 -5
- package/dist/portal/PortalGroup.svelte +9 -30
- package/dist/switch/Switch.svelte +132 -179
- package/dist/switch/SwitchGroup.svelte +31 -44
- package/dist/tabs/Tab.svelte +143 -195
- package/dist/tabs/TabGroup.svelte +205 -292
- package/dist/tabs/TabList.svelte +11 -31
- package/dist/tabs/TabPanel.svelte +43 -68
- package/dist/tabs/TabPanels.svelte +7 -18
- package/dist/textarea/Textarea.svelte +53 -84
- package/dist/transition/InternalTransitionChild.svelte +170 -259
- package/dist/transition/Transition.svelte +66 -96
- package/dist/transition/TransitionChild.svelte +11 -31
- package/dist/utils/ElementOrComponent.svelte +23 -44
- package/dist/utils/Generic.svelte +17 -29
- package/dist/utils/StableCollection.svelte +36 -54
- package/package.json +1 -1
|
@@ -1,169 +1,127 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<script lang="ts" module>import { tick } from "svelte";
|
|
2
|
+
const DEFAULT_BUTTON_TAG = "button";
|
|
3
|
+
</script>
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_BUTTON_TAG">import { useId } from "../hooks/use-id.js";
|
|
6
|
+
import { Focus } from "../utils/calculate-active-index.js";
|
|
7
|
+
import { useFocusRing } from "../hooks/use-focus-ring.svelte.js";
|
|
8
|
+
import { useActivePress } from "../hooks/use-active-press.svelte.js";
|
|
9
|
+
import { useResolveButtonType } from "../hooks/use-resolve-button-type.svelte.js";
|
|
10
|
+
import { useFloating } from "../internal/floating.svelte.js";
|
|
11
|
+
import { useHover } from "../hooks/use-hover.svelte.js";
|
|
12
|
+
import { mergeProps } from "../utils/render.js";
|
|
13
|
+
import { MenuStates, useMenuContext } from "./context.svelte.js";
|
|
14
|
+
import { untrack } from "svelte";
|
|
15
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
16
|
+
const internalId = useId();
|
|
17
|
+
let {
|
|
18
|
+
ref = $bindable(),
|
|
19
|
+
id = `headlessui-menu-button-${internalId}`,
|
|
20
|
+
disabled = false,
|
|
21
|
+
autofocus = false,
|
|
22
|
+
...theirProps
|
|
23
|
+
} = $props();
|
|
24
|
+
const _state = useMenuContext("MenuButton");
|
|
25
|
+
const { setReference, getReferenceProps: getFloatingReferenceProps } = useFloating();
|
|
26
|
+
$effect(() => {
|
|
27
|
+
untrack(() => _state.setButtonElement(ref ? ref : null));
|
|
28
|
+
setReference(ref);
|
|
29
|
+
});
|
|
30
|
+
const handleKeyDown = async (event) => {
|
|
31
|
+
switch (event.key) {
|
|
32
|
+
case " ":
|
|
33
|
+
case "Enter":
|
|
34
|
+
case "ArrowDown":
|
|
35
|
+
event.preventDefault();
|
|
36
|
+
event.stopPropagation();
|
|
37
|
+
_state.openMenu();
|
|
38
|
+
await tick();
|
|
39
|
+
_state.goToItem({ focus: Focus.First });
|
|
40
|
+
break;
|
|
41
|
+
case "ArrowUp":
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
event.stopPropagation();
|
|
44
|
+
_state.openMenu();
|
|
45
|
+
await tick();
|
|
46
|
+
_state.goToItem({ focus: Focus.Last });
|
|
47
|
+
break;
|
|
13
48
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
49
|
+
};
|
|
50
|
+
const handleKeyUp = (event) => {
|
|
51
|
+
switch (event.key) {
|
|
52
|
+
case " ":
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const handleClick = async (event) => {
|
|
58
|
+
if (disabled) return;
|
|
59
|
+
if (_state.menuState === MenuStates.Open) {
|
|
60
|
+
_state.closeMenu();
|
|
61
|
+
await tick();
|
|
62
|
+
_state.buttonElement?.focus({ preventScroll: true });
|
|
63
|
+
} else {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
_state.openMenu();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const { isFocusVisible: focus, focusProps } = $derived(
|
|
69
|
+
useFocusRing({
|
|
70
|
+
get autofocus() {
|
|
71
|
+
return autofocus;
|
|
25
72
|
}
|
|
26
|
-
>
|
|
27
|
-
|
|
28
|
-
export type MenuButtonChildren = Snippet<[ButtonRenderPropArg]>
|
|
29
|
-
</script>
|
|
30
|
-
|
|
31
|
-
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_BUTTON_TAG">
|
|
32
|
-
import { useId } from "../hooks/use-id.js"
|
|
33
|
-
import { Focus } from "../utils/calculate-active-index.js"
|
|
34
|
-
import { useFocusRing } from "../hooks/use-focus-ring.svelte.js"
|
|
35
|
-
import { useActivePress } from "../hooks/use-active-press.svelte.js"
|
|
36
|
-
import { useResolveButtonType } from "../hooks/use-resolve-button-type.svelte.js"
|
|
37
|
-
import { useFloating } from "../internal/floating.svelte.js"
|
|
38
|
-
import { useHover } from "../hooks/use-hover.svelte.js"
|
|
39
|
-
import { mergeProps } from "../utils/render.js"
|
|
40
|
-
import { MenuStates, useMenuContext } from "./context.svelte.js"
|
|
41
|
-
import { untrack } from "svelte"
|
|
42
|
-
import ElementOrComponent from "../utils/ElementOrComponent.svelte"
|
|
43
|
-
|
|
44
|
-
const internalId = useId()
|
|
45
|
-
let {
|
|
46
|
-
ref = $bindable(),
|
|
47
|
-
id = `headlessui-menu-button-${internalId}`,
|
|
48
|
-
disabled = false,
|
|
49
|
-
autofocus = false,
|
|
50
|
-
...theirProps
|
|
51
|
-
}: { as?: TTag } & MenuButtonProps<TTag> = $props()
|
|
52
|
-
const _state = useMenuContext("MenuButton")
|
|
53
|
-
const { setReference, getReferenceProps: getFloatingReferenceProps } = useFloating()
|
|
54
|
-
$effect(() => {
|
|
55
|
-
untrack(() => _state.setButtonElement(ref ? (ref as HTMLButtonElement) : null))
|
|
56
|
-
setReference(ref)
|
|
57
73
|
})
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
case " ":
|
|
64
|
-
case "Enter":
|
|
65
|
-
case "ArrowDown":
|
|
66
|
-
event.preventDefault()
|
|
67
|
-
event.stopPropagation()
|
|
68
|
-
_state.openMenu()
|
|
69
|
-
await tick()
|
|
70
|
-
_state.goToItem({ focus: Focus.First })
|
|
71
|
-
break
|
|
72
|
-
|
|
73
|
-
case "ArrowUp":
|
|
74
|
-
event.preventDefault()
|
|
75
|
-
event.stopPropagation()
|
|
76
|
-
_state.openMenu()
|
|
77
|
-
await tick()
|
|
78
|
-
_state.goToItem({ focus: Focus.Last })
|
|
79
|
-
break
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const handleKeyUp = (event: KeyboardEvent) => {
|
|
84
|
-
switch (event.key) {
|
|
85
|
-
case " ":
|
|
86
|
-
// Required for firefox, event.preventDefault() in handleKeyDown for
|
|
87
|
-
// the Space key doesn't cancel the handleKeyUp, which in turn
|
|
88
|
-
// triggers a *click*.
|
|
89
|
-
event.preventDefault()
|
|
90
|
-
break
|
|
74
|
+
);
|
|
75
|
+
const { isHovered: hover, hoverProps } = $derived(
|
|
76
|
+
useHover({
|
|
77
|
+
get disabled() {
|
|
78
|
+
return disabled;
|
|
91
79
|
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
_state.closeMenu()
|
|
99
|
-
await tick()
|
|
100
|
-
_state.buttonElement?.focus({ preventScroll: true })
|
|
101
|
-
} else {
|
|
102
|
-
event.preventDefault()
|
|
103
|
-
_state.openMenu()
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
const { pressed: active, pressProps } = $derived(
|
|
83
|
+
useActivePress({
|
|
84
|
+
get disabled() {
|
|
85
|
+
return disabled;
|
|
104
86
|
}
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
const slot = $derived({
|
|
90
|
+
open: _state.menuState === MenuStates.Open,
|
|
91
|
+
active: active || _state.menuState === MenuStates.Open,
|
|
92
|
+
disabled,
|
|
93
|
+
hover,
|
|
94
|
+
focus,
|
|
95
|
+
autofocus: autofocus ?? false
|
|
96
|
+
});
|
|
97
|
+
const buttonType = useResolveButtonType({
|
|
98
|
+
get props() {
|
|
99
|
+
return { type: theirProps.type, as: theirProps.as };
|
|
100
|
+
},
|
|
101
|
+
get ref() {
|
|
102
|
+
return { current: _state.buttonElement };
|
|
105
103
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const { pressed: active, pressProps } = $derived(
|
|
122
|
-
useActivePress({
|
|
123
|
-
get disabled() {
|
|
124
|
-
return disabled
|
|
125
|
-
},
|
|
126
|
-
})
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
const slot = $derived({
|
|
130
|
-
open: _state.menuState === MenuStates.Open,
|
|
131
|
-
active: active || _state.menuState === MenuStates.Open,
|
|
132
|
-
disabled,
|
|
133
|
-
hover,
|
|
134
|
-
focus,
|
|
135
|
-
autofocus: autofocus ?? false,
|
|
136
|
-
} satisfies ButtonRenderPropArg)
|
|
137
|
-
|
|
138
|
-
const buttonType = useResolveButtonType({
|
|
139
|
-
get props() {
|
|
140
|
-
return { type: theirProps.type, as: theirProps.as }
|
|
141
|
-
},
|
|
142
|
-
get ref() {
|
|
143
|
-
return { current: _state.buttonElement }
|
|
104
|
+
});
|
|
105
|
+
const ourProps = $derived(
|
|
106
|
+
mergeProps(
|
|
107
|
+
{
|
|
108
|
+
...getFloatingReferenceProps(),
|
|
109
|
+
id,
|
|
110
|
+
type: buttonType.type,
|
|
111
|
+
"aria-haspopup": "menu",
|
|
112
|
+
"aria-controls": _state.itemsElement?.id,
|
|
113
|
+
"aria-expanded": _state.menuState === MenuStates.Open,
|
|
114
|
+
disabled: disabled || void 0,
|
|
115
|
+
autofocus,
|
|
116
|
+
onkeydown: handleKeyDown,
|
|
117
|
+
onkeyup: handleKeyUp,
|
|
118
|
+
onclick: handleClick
|
|
144
119
|
},
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
mergeProps(
|
|
149
|
-
{
|
|
150
|
-
...getFloatingReferenceProps(),
|
|
151
|
-
id,
|
|
152
|
-
type: buttonType.type,
|
|
153
|
-
"aria-haspopup": "menu",
|
|
154
|
-
"aria-controls": _state.itemsElement?.id,
|
|
155
|
-
"aria-expanded": _state.menuState === MenuStates.Open,
|
|
156
|
-
disabled: disabled || undefined,
|
|
157
|
-
autofocus,
|
|
158
|
-
onkeydown: handleKeyDown,
|
|
159
|
-
onkeyup: handleKeyUp,
|
|
160
|
-
onclick: handleClick,
|
|
161
|
-
},
|
|
162
|
-
focusProps,
|
|
163
|
-
hoverProps,
|
|
164
|
-
pressProps
|
|
165
|
-
)
|
|
120
|
+
focusProps,
|
|
121
|
+
hoverProps,
|
|
122
|
+
pressProps
|
|
166
123
|
)
|
|
124
|
+
);
|
|
167
125
|
</script>
|
|
168
126
|
|
|
169
127
|
<ElementOrComponent {ourProps} {theirProps} {slot} defaultTag={DEFAULT_BUTTON_TAG} name="MenuButton" bind:ref />
|
|
@@ -1,39 +1,19 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
|
|
3
|
-
import type { ElementType, Props } from "../utils/types.js"
|
|
4
|
-
|
|
5
|
-
const DEFAULT_HEADING_TAG = "header" as const
|
|
6
|
-
type HeadingRenderPropArg = {}
|
|
7
|
-
type HeadingPropsWeControl = "role"
|
|
8
|
-
|
|
9
|
-
export type MenuHeadingProps<TTag extends ElementType = typeof DEFAULT_HEADING_TAG> = Props<
|
|
10
|
-
TTag,
|
|
11
|
-
HeadingRenderPropArg,
|
|
12
|
-
HeadingPropsWeControl,
|
|
13
|
-
{
|
|
14
|
-
id?: string
|
|
15
|
-
}
|
|
16
|
-
>
|
|
17
|
-
|
|
18
|
-
export type MenuHeadingChildren = Snippet<[HeadingRenderPropArg]>
|
|
1
|
+
<script lang="ts" module>import { onMount } from "svelte";
|
|
2
|
+
const DEFAULT_HEADING_TAG = "header";
|
|
19
3
|
</script>
|
|
20
4
|
|
|
21
|
-
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_HEADING_TAG">
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const context = useLabelContext()
|
|
34
|
-
onMount(() => context.register(id))
|
|
35
|
-
|
|
36
|
-
const ourProps = $derived({ id, role: "presentation", ...context.props })
|
|
5
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_HEADING_TAG">import { useId } from "../hooks/use-id.js";
|
|
6
|
+
import { useLabelContext } from "../label/context.svelte.js";
|
|
7
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
8
|
+
const internalId = useId();
|
|
9
|
+
let {
|
|
10
|
+
ref = $bindable(),
|
|
11
|
+
id = `headlessui-menu-heading-${internalId}`,
|
|
12
|
+
...theirProps
|
|
13
|
+
} = $props();
|
|
14
|
+
const context = useLabelContext();
|
|
15
|
+
onMount(() => context.register(id));
|
|
16
|
+
const ourProps = $derived({ id, role: "presentation", ...context.props });
|
|
37
17
|
</script>
|
|
38
18
|
|
|
39
19
|
<ElementOrComponent {ourProps} {theirProps} defaultTag={DEFAULT_HEADING_TAG} name="MenuItem" bind:ref />
|
|
@@ -1,152 +1,114 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
|
|
3
|
-
import { onMount, type Snippet } from "svelte"
|
|
4
|
-
|
|
5
|
-
const DEFAULT_ITEM_TAG = "svelte:fragment" as const
|
|
6
|
-
type ItemRenderPropArg = {
|
|
7
|
-
/** @deprecated use `focus` instead */
|
|
8
|
-
active: boolean
|
|
9
|
-
focus: boolean
|
|
10
|
-
disabled: boolean
|
|
11
|
-
close: () => void
|
|
12
|
-
props?: Record<string, any>
|
|
13
|
-
}
|
|
14
|
-
type ItemPropsWeControl = "aria-describedby" | "aria-disabled" | "aria-labelledby" | "role" | "tabIndex"
|
|
15
|
-
|
|
16
|
-
export type MenuItemProps<TTag extends ElementType = typeof DEFAULT_ITEM_TAG> = Props<
|
|
17
|
-
TTag,
|
|
18
|
-
ItemRenderPropArg,
|
|
19
|
-
ItemPropsWeControl | "children",
|
|
20
|
-
{
|
|
21
|
-
id?: string
|
|
22
|
-
disabled?: boolean
|
|
23
|
-
children: Children<ItemRenderPropArg>
|
|
24
|
-
}
|
|
25
|
-
>
|
|
26
|
-
|
|
27
|
-
export type MenuItemChildren = Children<ItemRenderPropArg>
|
|
1
|
+
<script lang="ts" module>import { onMount } from "svelte";
|
|
2
|
+
const DEFAULT_ITEM_TAG = "svelte:fragment";
|
|
28
3
|
</script>
|
|
29
4
|
|
|
30
|
-
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_ITEM_TAG">
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const getTextValue = useTextValue({
|
|
66
|
-
get element() {
|
|
67
|
-
return ref || null
|
|
68
|
-
},
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
const bag: MenuItemDataRef["current"] = $derived({
|
|
72
|
-
disabled,
|
|
73
|
-
domRef: { current: ref || null },
|
|
74
|
-
get textValue() {
|
|
75
|
-
return getTextValue()
|
|
76
|
-
},
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
onMount(() => {
|
|
80
|
-
_state.registerItem(id, {
|
|
81
|
-
get current() {
|
|
82
|
-
return bag
|
|
83
|
-
},
|
|
84
|
-
})
|
|
85
|
-
return () => _state.unregisterItem(id)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
const handleClick = (event: MouseEvent) => {
|
|
89
|
-
if (disabled) return event.preventDefault()
|
|
90
|
-
_state.closeMenu()
|
|
91
|
-
restoreFocusIfNecessary(_state.buttonElement)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const handleFocus = () => {
|
|
95
|
-
if (disabled) return _state.goToItem({ focus: Focus.Nothing })
|
|
96
|
-
_state.goToItem({ focus: Focus.Specific, id })
|
|
5
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_ITEM_TAG">import { useId } from "../hooks/use-id.js";
|
|
6
|
+
import { ActivationTrigger, MenuStates, useMenuContext } from "./context.svelte.js";
|
|
7
|
+
import { disposables } from "../utils/disposables.js";
|
|
8
|
+
import { useTextValue } from "../hooks/use-text-value.svelte.js";
|
|
9
|
+
import { restoreFocusIfNecessary } from "../utils/focus-management.js";
|
|
10
|
+
import { Focus } from "../utils/calculate-active-index.js";
|
|
11
|
+
import { useTrackedPointer } from "../hooks/use-tracked-pointer.js";
|
|
12
|
+
import { useLabels } from "../label/context.svelte.js";
|
|
13
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
14
|
+
import { mergeProps } from "../utils/render.js";
|
|
15
|
+
import { useDescriptions } from "../description/context.svelte.js";
|
|
16
|
+
const internalId = useId();
|
|
17
|
+
let {
|
|
18
|
+
ref = $bindable(),
|
|
19
|
+
id = `headlessui-menu-item-${internalId}`,
|
|
20
|
+
disabled = false,
|
|
21
|
+
...theirProps
|
|
22
|
+
} = $props();
|
|
23
|
+
const _state = useMenuContext("MenuItem");
|
|
24
|
+
const active = $derived(_state.activeItemIndex !== null ? _state.items[_state.activeItemIndex].id === id : false);
|
|
25
|
+
$effect(() => {
|
|
26
|
+
_state.activeItemIndex;
|
|
27
|
+
if (_state.__demoMode) return;
|
|
28
|
+
if (_state.menuState !== MenuStates.Open) return;
|
|
29
|
+
if (!active) return;
|
|
30
|
+
if (_state.activationTrigger === ActivationTrigger.Pointer) return;
|
|
31
|
+
return disposables().requestAnimationFrame(() => {
|
|
32
|
+
;
|
|
33
|
+
ref?.scrollIntoView?.({ block: "nearest" });
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
const getTextValue = useTextValue({
|
|
37
|
+
get element() {
|
|
38
|
+
return ref || null;
|
|
97
39
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (active) return
|
|
105
|
-
_state.goToItem({ focus: Focus.Specific, id, trigger: ActivationTrigger.Pointer })
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const handleMove = (evt: PointerEvent) => {
|
|
109
|
-
if (!pointer.wasMoved(evt)) return
|
|
110
|
-
if (disabled) return
|
|
111
|
-
if (active) return
|
|
112
|
-
_state.goToItem({ focus: Focus.Specific, id, trigger: ActivationTrigger.Pointer })
|
|
40
|
+
});
|
|
41
|
+
const bag = $derived({
|
|
42
|
+
disabled,
|
|
43
|
+
domRef: { current: ref || null },
|
|
44
|
+
get textValue() {
|
|
45
|
+
return getTextValue();
|
|
113
46
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
)
|
|
47
|
+
});
|
|
48
|
+
onMount(() => {
|
|
49
|
+
_state.registerItem(id, {
|
|
50
|
+
get current() {
|
|
51
|
+
return bag;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return () => _state.unregisterItem(id);
|
|
55
|
+
});
|
|
56
|
+
const handleClick = (event) => {
|
|
57
|
+
if (disabled) return event.preventDefault();
|
|
58
|
+
_state.closeMenu();
|
|
59
|
+
restoreFocusIfNecessary(_state.buttonElement);
|
|
60
|
+
};
|
|
61
|
+
const handleFocus = () => {
|
|
62
|
+
if (disabled) return _state.goToItem({ focus: Focus.Nothing });
|
|
63
|
+
_state.goToItem({ focus: Focus.Specific, id });
|
|
64
|
+
};
|
|
65
|
+
const pointer = useTrackedPointer();
|
|
66
|
+
const handleEnter = (evt) => {
|
|
67
|
+
pointer.update(evt);
|
|
68
|
+
if (disabled) return;
|
|
69
|
+
if (active) return;
|
|
70
|
+
_state.goToItem({ focus: Focus.Specific, id, trigger: ActivationTrigger.Pointer });
|
|
71
|
+
};
|
|
72
|
+
const handleMove = (evt) => {
|
|
73
|
+
if (!pointer.wasMoved(evt)) return;
|
|
74
|
+
if (disabled) return;
|
|
75
|
+
if (active) return;
|
|
76
|
+
_state.goToItem({ focus: Focus.Specific, id, trigger: ActivationTrigger.Pointer });
|
|
77
|
+
};
|
|
78
|
+
const handleLeave = (evt) => {
|
|
79
|
+
if (!pointer.wasMoved(evt)) return;
|
|
80
|
+
if (disabled) return;
|
|
81
|
+
if (!active) return;
|
|
82
|
+
_state.goToItem({ focus: Focus.Nothing });
|
|
83
|
+
};
|
|
84
|
+
const labelledby = useLabels();
|
|
85
|
+
const describedby = useDescriptions();
|
|
86
|
+
const slot = $derived({
|
|
87
|
+
active,
|
|
88
|
+
focus: active,
|
|
89
|
+
disabled,
|
|
90
|
+
close: _state.closeMenu
|
|
91
|
+
});
|
|
92
|
+
const ourProps = $derived(
|
|
93
|
+
mergeProps({
|
|
94
|
+
id,
|
|
95
|
+
role: "menuitem",
|
|
96
|
+
tabindex: disabled === true ? void 0 : -1,
|
|
97
|
+
"aria-disabled": disabled === true ? true : void 0,
|
|
98
|
+
"aria-labelledby": labelledby.value,
|
|
99
|
+
"aria-describedby": describedby.value,
|
|
100
|
+
disabled: void 0,
|
|
101
|
+
// Never forward the `disabled` prop
|
|
102
|
+
onclick: handleClick,
|
|
103
|
+
onfocus: handleFocus,
|
|
104
|
+
onpointerenter: handleEnter,
|
|
105
|
+
onmouseenter: handleEnter,
|
|
106
|
+
onpointermove: handleMove,
|
|
107
|
+
onmousemove: handleMove,
|
|
108
|
+
onpointerleave: handleLeave,
|
|
109
|
+
onmouseleave: handleLeave
|
|
110
|
+
})
|
|
111
|
+
);
|
|
150
112
|
</script>
|
|
151
113
|
|
|
152
114
|
<ElementOrComponent {ourProps} {theirProps} {slot} defaultTag={DEFAULT_ITEM_TAG} name="MenuItem" bind:ref />
|