@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,188 +1,139 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import ElementOrComponent from "../utils/ElementOrComponent.svelte"
|
|
1
|
+
<script lang="ts" module>import { useId } from "../hooks/use-id.js";
|
|
2
|
+
import { getIdContext } from "../utils/id.js";
|
|
3
|
+
import { ListboxStates, useActions, useData } from "./Listbox.svelte";
|
|
4
|
+
import { attemptSubmit } from "../utils/form.js";
|
|
5
|
+
import { Focus } from "../utils/calculate-active-index.js";
|
|
6
|
+
import { useFocusRing } from "../hooks/use-focus-ring.svelte.js";
|
|
7
|
+
import { useActivePress } from "../hooks/use-active-press.svelte.js";
|
|
8
|
+
import { useResolveButtonType } from "../hooks/use-resolve-button-type.svelte.js";
|
|
9
|
+
import { useFloating } from "../internal/floating.svelte.js";
|
|
10
|
+
import { stateFromSlot } from "../utils/state.js";
|
|
11
|
+
import { useLabelledBy } from "../label/context.svelte.js";
|
|
12
|
+
import { useDescribedBy } from "../description/context.svelte.js";
|
|
13
|
+
import { useHover } from "../hooks/use-hover.svelte.js";
|
|
14
|
+
import { mergeProps } from "../utils/render.js";
|
|
15
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
16
|
+
const DEFAULT_BUTTON_TAG = "button";
|
|
17
|
+
</script>
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_BUTTON_TAG">const data = useData("ListboxButton");
|
|
20
|
+
const actions = useActions("ListboxButton");
|
|
21
|
+
const internalId = useId();
|
|
22
|
+
const providedId = getIdContext();
|
|
23
|
+
let {
|
|
24
|
+
as = DEFAULT_BUTTON_TAG,
|
|
25
|
+
ref = $bindable(),
|
|
26
|
+
id = providedId || `headlessui-listbox-button-${internalId}`,
|
|
27
|
+
disabled: ownDisabled = false,
|
|
28
|
+
autofocus = false,
|
|
29
|
+
...theirProps
|
|
30
|
+
} = $props();
|
|
31
|
+
const { setReference, getReferenceProps: getFloatingReferenceProps } = useFloating();
|
|
32
|
+
$effect(() => {
|
|
33
|
+
data.buttonRef.current = ref || null;
|
|
34
|
+
setReference(ref);
|
|
35
|
+
});
|
|
36
|
+
const disabled = $derived(data.disabled || ownDisabled);
|
|
37
|
+
const handleKeyDown = (event) => {
|
|
38
|
+
switch (event.key) {
|
|
39
|
+
case "Enter":
|
|
40
|
+
if (event.currentTarget) attemptSubmit(event.currentTarget);
|
|
41
|
+
break;
|
|
42
|
+
case " ":
|
|
43
|
+
case "ArrowDown":
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
actions.openListbox();
|
|
46
|
+
if (!data.value) actions.goToOption(Focus.First);
|
|
47
|
+
break;
|
|
48
|
+
case "ArrowUp":
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
actions.openListbox();
|
|
51
|
+
if (!data.value) actions.goToOption(Focus.Last);
|
|
52
|
+
break;
|
|
30
53
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
54
|
+
};
|
|
55
|
+
const handleKeyUp = (event) => {
|
|
56
|
+
switch (event.key) {
|
|
57
|
+
case " ":
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const handleClick = (event) => {
|
|
63
|
+
if (data.listboxState === ListboxStates.Open) {
|
|
64
|
+
actions.closeListbox();
|
|
65
|
+
data.buttonRef.current?.focus({ preventScroll: true });
|
|
66
|
+
} else {
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
actions.openListbox();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const handleKeyPress = (event) => event.preventDefault();
|
|
72
|
+
const labelledBy = useLabelledBy();
|
|
73
|
+
const describedBy = useDescribedBy();
|
|
74
|
+
const { isHovered: hover, hoverProps } = $derived(
|
|
75
|
+
useHover({
|
|
76
|
+
get disabled() {
|
|
77
|
+
return disabled;
|
|
41
78
|
}
|
|
42
|
-
>
|
|
43
|
-
|
|
44
|
-
export type ListboxButtonChildren = Snippet<[ButtonRenderPropArg]>
|
|
45
|
-
</script>
|
|
46
|
-
|
|
47
|
-
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_BUTTON_TAG">
|
|
48
|
-
const data = useData("ListboxButton")
|
|
49
|
-
const actions = useActions("ListboxButton")
|
|
50
|
-
|
|
51
|
-
const internalId = useId()
|
|
52
|
-
const providedId = getIdContext()
|
|
53
|
-
let {
|
|
54
|
-
as = DEFAULT_BUTTON_TAG as TTag,
|
|
55
|
-
ref = $bindable(),
|
|
56
|
-
id = providedId || `headlessui-listbox-button-${internalId}`,
|
|
57
|
-
disabled: ownDisabled = false,
|
|
58
|
-
autofocus = false,
|
|
59
|
-
...theirProps
|
|
60
|
-
}: { as?: TTag } & ListboxButtonProps<TTag> = $props()
|
|
61
|
-
const { setReference, getReferenceProps: getFloatingReferenceProps } = useFloating()
|
|
62
|
-
$effect(() => {
|
|
63
|
-
data.buttonRef.current = ref || null
|
|
64
|
-
setReference(ref)
|
|
65
79
|
})
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// Ref: https://www.w3.org/WAI/ARIA/apg/patterns/menubutton/#keyboard-interaction-13
|
|
72
|
-
|
|
73
|
-
case "Enter":
|
|
74
|
-
if (event.currentTarget) attemptSubmit(event.currentTarget as HTMLElement)
|
|
75
|
-
break
|
|
76
|
-
|
|
77
|
-
case " ":
|
|
78
|
-
case "ArrowDown":
|
|
79
|
-
event.preventDefault()
|
|
80
|
-
actions.openListbox()
|
|
81
|
-
if (!data.value) actions.goToOption(Focus.First)
|
|
82
|
-
break
|
|
83
|
-
|
|
84
|
-
case "ArrowUp":
|
|
85
|
-
event.preventDefault()
|
|
86
|
-
actions.openListbox()
|
|
87
|
-
if (!data.value) actions.goToOption(Focus.Last)
|
|
88
|
-
break
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const handleKeyUp = (event: KeyboardEvent) => {
|
|
93
|
-
switch (event.key) {
|
|
94
|
-
case " ":
|
|
95
|
-
// Required for firefox, event.preventDefault() in handleKeyDown for
|
|
96
|
-
// the Space key doesn't cancel the handleKeyUp, which in turn
|
|
97
|
-
// triggers a *click*.
|
|
98
|
-
event.preventDefault()
|
|
99
|
-
break
|
|
80
|
+
);
|
|
81
|
+
const { pressed: active, pressProps } = $derived(
|
|
82
|
+
useActivePress({
|
|
83
|
+
get disabled() {
|
|
84
|
+
return disabled;
|
|
100
85
|
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
data.buttonRef.current?.focus({ preventScroll: true })
|
|
108
|
-
} else {
|
|
109
|
-
event.preventDefault()
|
|
110
|
-
actions.openListbox()
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
const { isFocusVisible: focus, focusProps } = $derived(
|
|
89
|
+
useFocusRing({
|
|
90
|
+
get autofocus() {
|
|
91
|
+
return autofocus;
|
|
111
92
|
}
|
|
93
|
+
})
|
|
94
|
+
);
|
|
95
|
+
const slot = $derived({
|
|
96
|
+
open: data.listboxState === ListboxStates.Open,
|
|
97
|
+
active: active || data.listboxState === ListboxStates.Open,
|
|
98
|
+
disabled,
|
|
99
|
+
invalid: data.invalid,
|
|
100
|
+
value: data.value,
|
|
101
|
+
hover,
|
|
102
|
+
focus,
|
|
103
|
+
autofocus: autofocus ?? false
|
|
104
|
+
});
|
|
105
|
+
const buttonType = useResolveButtonType({
|
|
106
|
+
get props() {
|
|
107
|
+
return { type: theirProps.type, as };
|
|
108
|
+
},
|
|
109
|
+
get ref() {
|
|
110
|
+
return data.buttonRef;
|
|
112
111
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
},
|
|
132
|
-
})
|
|
133
|
-
)
|
|
134
|
-
const { isFocusVisible: focus, focusProps } = $derived(
|
|
135
|
-
useFocusRing({
|
|
136
|
-
get autofocus() {
|
|
137
|
-
return autofocus
|
|
138
|
-
},
|
|
139
|
-
})
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
const slot = $derived({
|
|
143
|
-
open: data.listboxState === ListboxStates.Open,
|
|
144
|
-
active: active || data.listboxState === ListboxStates.Open,
|
|
145
|
-
disabled,
|
|
146
|
-
invalid: data.invalid,
|
|
147
|
-
value: data.value,
|
|
148
|
-
hover,
|
|
149
|
-
focus,
|
|
150
|
-
autofocus: autofocus ?? false,
|
|
151
|
-
} satisfies ButtonRenderPropArg)
|
|
152
|
-
|
|
153
|
-
const buttonType = useResolveButtonType({
|
|
154
|
-
get props() {
|
|
155
|
-
return { type: theirProps.type, as }
|
|
156
|
-
},
|
|
157
|
-
get ref() {
|
|
158
|
-
return data.buttonRef
|
|
112
|
+
});
|
|
113
|
+
const ourProps = $derived(
|
|
114
|
+
mergeProps(
|
|
115
|
+
{
|
|
116
|
+
...getFloatingReferenceProps(),
|
|
117
|
+
id,
|
|
118
|
+
type: buttonType.type,
|
|
119
|
+
"aria-haspopup": "listbox",
|
|
120
|
+
"aria-controls": data.optionsRef.current?.id,
|
|
121
|
+
"aria-expanded": data.listboxState === ListboxStates.Open,
|
|
122
|
+
"aria-labelledby": labelledBy.value,
|
|
123
|
+
"aria-describedby": describedBy.value,
|
|
124
|
+
disabled: disabled || void 0,
|
|
125
|
+
autofocus,
|
|
126
|
+
onkeydown: handleKeyDown,
|
|
127
|
+
onkeyup: handleKeyUp,
|
|
128
|
+
onkeypress: handleKeyPress,
|
|
129
|
+
onclick: handleClick
|
|
159
130
|
},
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
{
|
|
165
|
-
...getFloatingReferenceProps(),
|
|
166
|
-
id,
|
|
167
|
-
type: buttonType.type,
|
|
168
|
-
"aria-haspopup": "listbox",
|
|
169
|
-
"aria-controls": data.optionsRef.current?.id,
|
|
170
|
-
"aria-expanded": data.listboxState === ListboxStates.Open,
|
|
171
|
-
"aria-labelledby": labelledBy.value,
|
|
172
|
-
"aria-describedby": describedBy.value,
|
|
173
|
-
disabled: disabled || undefined,
|
|
174
|
-
autofocus,
|
|
175
|
-
onkeydown: handleKeyDown,
|
|
176
|
-
onkeyup: handleKeyUp,
|
|
177
|
-
onkeypress: handleKeyPress,
|
|
178
|
-
onclick: handleClick,
|
|
179
|
-
},
|
|
180
|
-
focusProps,
|
|
181
|
-
hoverProps,
|
|
182
|
-
pressProps,
|
|
183
|
-
stateFromSlot(slot)
|
|
184
|
-
)
|
|
131
|
+
focusProps,
|
|
132
|
+
hoverProps,
|
|
133
|
+
pressProps,
|
|
134
|
+
stateFromSlot(slot)
|
|
185
135
|
)
|
|
136
|
+
);
|
|
186
137
|
</script>
|
|
187
138
|
|
|
188
139
|
<ElementOrComponent {ourProps} {theirProps} {slot} defaultTag={DEFAULT_BUTTON_TAG} name="ListboxButton" bind:ref />
|
|
@@ -1,175 +1,134 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
import type { ElementType, Props } from "../utils/types.js"
|
|
3
|
-
|
|
4
|
-
const DEFAULT_OPTION_TAG = "div" as const
|
|
5
|
-
type OptionRenderPropArg = {
|
|
6
|
-
/** @deprecated use `focus` instead */
|
|
7
|
-
active: boolean
|
|
8
|
-
focus: boolean
|
|
9
|
-
selected: boolean
|
|
10
|
-
disabled: boolean
|
|
11
|
-
|
|
12
|
-
selectedOption: boolean
|
|
13
|
-
}
|
|
14
|
-
type OptionPropsWeControl = "aria-disabled" | "aria-selected" | "role" | "tabIndex"
|
|
15
|
-
|
|
16
|
-
export type ListboxOptionProps<TTag extends ElementType = typeof DEFAULT_OPTION_TAG, TType = string> = Props<
|
|
17
|
-
TTag,
|
|
18
|
-
OptionRenderPropArg,
|
|
19
|
-
OptionPropsWeControl,
|
|
20
|
-
{
|
|
21
|
-
id?: string
|
|
22
|
-
disabled?: boolean
|
|
23
|
-
value: TType
|
|
24
|
-
}
|
|
25
|
-
>
|
|
26
|
-
|
|
27
|
-
export type ListboxOptionChildren = Snippet<[OptionRenderPropArg]>
|
|
1
|
+
<script lang="ts" module>const DEFAULT_OPTION_TAG = "div";
|
|
28
2
|
</script>
|
|
29
3
|
|
|
30
|
-
<script lang="ts" generics="TType, TTag extends ElementType = typeof DEFAULT_OPTION_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
|
-
const selected = $derived(data.isSelected(value))
|
|
64
|
-
const getTextValue = useTextValue({
|
|
65
|
-
get element() {
|
|
66
|
-
return ref as HTMLElement
|
|
67
|
-
},
|
|
68
|
-
})
|
|
69
|
-
const bag: ListboxOptionDataRef<TType>["current"] = $derived({
|
|
70
|
-
disabled,
|
|
71
|
-
value,
|
|
72
|
-
domRef: { current: ref || null },
|
|
73
|
-
get textValue() {
|
|
74
|
-
return getTextValue()
|
|
75
|
-
},
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
$effect(() => {
|
|
79
|
-
if (!ref) {
|
|
80
|
-
data.listRef.current.delete(id)
|
|
81
|
-
} else {
|
|
82
|
-
data.listRef.current.set(id, ref)
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
$effect(() => {
|
|
87
|
-
if (data.__demoMode) return
|
|
88
|
-
if (data.listboxState !== ListboxStates.Open) return
|
|
89
|
-
if (!active) return
|
|
90
|
-
if (data.activationTrigger === ActivationTrigger.Pointer) return
|
|
91
|
-
return disposables().requestAnimationFrame(() => {
|
|
92
|
-
;(ref as HTMLElement)?.scrollIntoView?.({ block: "nearest" })
|
|
93
|
-
})
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
onMount(() => {
|
|
97
|
-
if (usedInSelectedOption) return
|
|
98
|
-
return actions.registerOption(id, {
|
|
99
|
-
get current() {
|
|
100
|
-
return bag
|
|
101
|
-
},
|
|
102
|
-
})
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
const handleClick = (event: { preventDefault: Function }) => {
|
|
106
|
-
if (disabled) return event.preventDefault()
|
|
107
|
-
actions.onChange(value)
|
|
108
|
-
if (data.mode === ValueMode.Single) {
|
|
109
|
-
actions.closeListbox()
|
|
110
|
-
data.buttonRef.current?.focus({ preventScroll: true })
|
|
111
|
-
}
|
|
4
|
+
<script lang="ts" generics="TType, TTag extends ElementType = typeof DEFAULT_OPTION_TAG">import { useId } from "../hooks/use-id.js";
|
|
5
|
+
import {
|
|
6
|
+
ActivationTrigger,
|
|
7
|
+
ListboxStates,
|
|
8
|
+
useActions,
|
|
9
|
+
useData,
|
|
10
|
+
ValueMode
|
|
11
|
+
} from "./Listbox.svelte";
|
|
12
|
+
import { disposables } from "../utils/disposables.js";
|
|
13
|
+
import { Focus } from "../utils/calculate-active-index.js";
|
|
14
|
+
import { getContext, onMount } from "svelte";
|
|
15
|
+
import { useTextValue } from "../hooks/use-text-value.svelte.js";
|
|
16
|
+
import { useTrackedPointer } from "../hooks/use-tracked-pointer.js";
|
|
17
|
+
import { stateFromSlot } from "../utils/state.js";
|
|
18
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
19
|
+
const internalId = useId();
|
|
20
|
+
let {
|
|
21
|
+
as = DEFAULT_OPTION_TAG,
|
|
22
|
+
ref = $bindable(),
|
|
23
|
+
id = `headlessui-listbox-option-${internalId}`,
|
|
24
|
+
disabled = false,
|
|
25
|
+
value,
|
|
26
|
+
...theirProps
|
|
27
|
+
} = $props();
|
|
28
|
+
const usedInSelectedOption = getContext("SelectedOptionContext") === true;
|
|
29
|
+
const data = useData("ListboxOption");
|
|
30
|
+
const actions = useActions("ListboxOption");
|
|
31
|
+
const active = $derived(data.activeOptionIndex !== null ? data.options[data.activeOptionIndex].id === id : false);
|
|
32
|
+
const selected = $derived(data.isSelected(value));
|
|
33
|
+
const getTextValue = useTextValue({
|
|
34
|
+
get element() {
|
|
35
|
+
return ref;
|
|
112
36
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
37
|
+
});
|
|
38
|
+
const bag = $derived({
|
|
39
|
+
disabled,
|
|
40
|
+
value,
|
|
41
|
+
domRef: { current: ref || null },
|
|
42
|
+
get textValue() {
|
|
43
|
+
return getTextValue();
|
|
117
44
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (active) return
|
|
125
|
-
actions.goToOption(Focus.Specific, id, ActivationTrigger.Pointer)
|
|
45
|
+
});
|
|
46
|
+
$effect(() => {
|
|
47
|
+
if (!ref) {
|
|
48
|
+
data.listRef.current.delete(id);
|
|
49
|
+
} else {
|
|
50
|
+
data.listRef.current.set(id, ref);
|
|
126
51
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
52
|
+
});
|
|
53
|
+
$effect(() => {
|
|
54
|
+
if (data.__demoMode) return;
|
|
55
|
+
if (data.listboxState !== ListboxStates.Open) return;
|
|
56
|
+
if (!active) return;
|
|
57
|
+
if (data.activationTrigger === ActivationTrigger.Pointer) return;
|
|
58
|
+
return disposables().requestAnimationFrame(() => {
|
|
59
|
+
;
|
|
60
|
+
ref?.scrollIntoView?.({ block: "nearest" });
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
onMount(() => {
|
|
64
|
+
if (usedInSelectedOption) return;
|
|
65
|
+
return actions.registerOption(id, {
|
|
66
|
+
get current() {
|
|
67
|
+
return bag;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
const handleClick = (event) => {
|
|
72
|
+
if (disabled) return event.preventDefault();
|
|
73
|
+
actions.onChange(value);
|
|
74
|
+
if (data.mode === ValueMode.Single) {
|
|
75
|
+
actions.closeListbox();
|
|
76
|
+
data.buttonRef.current?.focus({ preventScroll: true });
|
|
140
77
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
78
|
+
};
|
|
79
|
+
const handleFocus = () => {
|
|
80
|
+
if (disabled) return actions.goToOption(Focus.Nothing);
|
|
81
|
+
actions.goToOption(Focus.Specific, id);
|
|
82
|
+
};
|
|
83
|
+
const pointer = useTrackedPointer();
|
|
84
|
+
const handleEnter = (evt) => {
|
|
85
|
+
pointer.update(evt);
|
|
86
|
+
if (disabled) return;
|
|
87
|
+
if (active) return;
|
|
88
|
+
actions.goToOption(Focus.Specific, id, ActivationTrigger.Pointer);
|
|
89
|
+
};
|
|
90
|
+
const handleMove = (evt) => {
|
|
91
|
+
if (!pointer.wasMoved(evt)) return;
|
|
92
|
+
if (disabled) return;
|
|
93
|
+
if (active) return;
|
|
94
|
+
actions.goToOption(Focus.Specific, id, ActivationTrigger.Pointer);
|
|
95
|
+
};
|
|
96
|
+
const handleLeave = (evt) => {
|
|
97
|
+
if (!pointer.wasMoved(evt)) return;
|
|
98
|
+
if (disabled) return;
|
|
99
|
+
if (!active) return;
|
|
100
|
+
actions.goToOption(Focus.Nothing);
|
|
101
|
+
};
|
|
102
|
+
const slot = $derived({
|
|
103
|
+
active,
|
|
104
|
+
focus: active,
|
|
105
|
+
selected,
|
|
106
|
+
disabled,
|
|
107
|
+
selectedOption: selected && usedInSelectedOption
|
|
108
|
+
});
|
|
109
|
+
const ourProps = $derived(
|
|
110
|
+
!usedInSelectedOption ? {
|
|
111
|
+
id,
|
|
112
|
+
role: "option",
|
|
113
|
+
tabIndex: disabled === true ? void 0 : -1,
|
|
114
|
+
"aria-disabled": disabled === true ? true : void 0,
|
|
115
|
+
// According to the WAI-ARIA best practices, we should use aria-checked for
|
|
116
|
+
// multi-select,but Voice-Over disagrees. So we use aria-checked instead for
|
|
117
|
+
// both single and multi-select.
|
|
118
|
+
"aria-selected": selected,
|
|
119
|
+
disabled: void 0,
|
|
120
|
+
// Never forward the `disabled` prop
|
|
121
|
+
onclick: handleClick,
|
|
122
|
+
onfocus: handleFocus,
|
|
123
|
+
onpointerenter: handleEnter,
|
|
124
|
+
onmouseenter: handleEnter,
|
|
125
|
+
onpointermove: handleMove,
|
|
126
|
+
onmousemove: handleMove,
|
|
127
|
+
onpointerleave: handleLeave,
|
|
128
|
+
onmouseleave: handleLeave,
|
|
129
|
+
...stateFromSlot(slot)
|
|
130
|
+
} : {}
|
|
131
|
+
);
|
|
173
132
|
</script>
|
|
174
133
|
|
|
175
134
|
{#if selected || !usedInSelectedOption}
|