@proyecto-viviana/solidaria-components 0.2.9 → 0.3.1
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 +39 -272
- package/dist/ActionBar.d.ts +21 -13
- package/dist/ActionBar.d.ts.map +1 -1
- package/dist/ActionGroup.d.ts +8 -8
- package/dist/ActionGroup.d.ts.map +1 -1
- package/dist/Alert.d.ts +5 -5
- package/dist/Alert.d.ts.map +1 -1
- package/dist/Autocomplete.d.ts +5 -5
- package/dist/Autocomplete.d.ts.map +1 -1
- package/dist/Breadcrumbs.d.ts +18 -7
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Button.d.ts +24 -5
- package/dist/Button.d.ts.map +1 -1
- package/dist/Calendar.d.ts +38 -7
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +32 -7
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Collection.d.ts +19 -14
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Color.d.ts +103 -14
- package/dist/Color.d.ts.map +1 -1
- package/dist/ColorEditor.d.ts +6 -6
- package/dist/ColorEditor.d.ts.map +1 -1
- package/dist/ComboBox.d.ts +85 -19
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ContextualHelpTrigger.d.ts +2 -2
- package/dist/ContextualHelpTrigger.d.ts.map +1 -1
- package/dist/DateField.d.ts +8 -6
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DatePicker.d.ts +53 -22
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/DateRangePickerContext.d.ts +30 -0
- package/dist/DateRangePickerContext.d.ts.map +1 -0
- package/dist/Dialog.d.ts +5 -5
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Disclosure.d.ts +23 -5
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/DragAndDrop.d.ts +6 -6
- package/dist/DragAndDrop.d.ts.map +1 -1
- package/dist/DragPreview.d.ts +2 -2
- package/dist/DragPreview.d.ts.map +1 -1
- package/dist/DropZone.d.ts +4 -4
- package/dist/DropZone.d.ts.map +1 -1
- package/dist/FieldError.d.ts +9 -5
- package/dist/FieldError.d.ts.map +1 -1
- package/dist/FileTrigger.d.ts +3 -3
- package/dist/FileTrigger.d.ts.map +1 -1
- package/dist/Focusable.d.ts +2 -2
- package/dist/Focusable.d.ts.map +1 -1
- package/dist/Form.d.ts +18 -4
- package/dist/Form.d.ts.map +1 -1
- package/dist/GridList.d.ts +32 -12
- package/dist/GridList.d.ts.map +1 -1
- package/dist/HiddenDateInput.d.ts +26 -0
- package/dist/HiddenDateInput.d.ts.map +1 -0
- package/dist/HiddenTimeInput.d.ts +25 -0
- package/dist/HiddenTimeInput.d.ts.map +1 -0
- package/dist/Icon.d.ts +5 -5
- package/dist/Icon.d.ts.map +1 -1
- package/dist/Keyboard.d.ts +1 -1
- package/dist/Landmark.d.ts +3 -3
- package/dist/Landmark.d.ts.map +1 -1
- package/dist/Link.d.ts +10 -4
- package/dist/Link.d.ts.map +1 -1
- package/dist/ListBox.d.ts +32 -12
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListDropTargetDelegate.d.ts +6 -6
- package/dist/ListDropTargetDelegate.d.ts.map +1 -1
- package/dist/Menu.d.ts +65 -14
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Meter.d.ts +3 -3
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Modal.d.ts +5 -5
- package/dist/Modal.d.ts.map +1 -1
- package/dist/NumberField.d.ts +8 -12
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/Popover.d.ts +28 -5
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Pressable.d.ts +2 -2
- package/dist/Pressable.d.ts.map +1 -1
- package/dist/ProgressBar.d.ts +5 -3
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/RadioGroup.d.ts +43 -9
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RangeCalendar.d.ts +34 -7
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RouterProvider.d.ts +2 -2
- package/dist/RouterProvider.d.ts.map +1 -1
- package/dist/SearchField.d.ts +23 -20
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/Select.d.ts +41 -11
- package/dist/Select.d.ts.map +1 -1
- package/dist/SelectionIndicator.d.ts +3 -3
- package/dist/SelectionIndicator.d.ts.map +1 -1
- package/dist/Separator.d.ts +9 -3
- package/dist/Separator.d.ts.map +1 -1
- package/dist/SharedElementTransition.d.ts +6 -4
- package/dist/SharedElementTransition.d.ts.map +1 -1
- package/dist/Slider.d.ts +12 -8
- package/dist/Slider.d.ts.map +1 -1
- package/dist/StepList.d.ts +90 -0
- package/dist/StepList.d.ts.map +1 -0
- package/dist/Switch.d.ts +11 -5
- package/dist/Switch.d.ts.map +1 -1
- package/dist/Table.d.ts +187 -23
- package/dist/Table.d.ts.map +1 -1
- package/dist/Tabs.d.ts +45 -9
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/TagGroup.d.ts +12 -10
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/Text.d.ts +2 -2
- package/dist/TextField.d.ts +15 -11
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TimeField.d.ts +6 -6
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/Toast.d.ts +29 -14
- package/dist/Toast.d.ts.map +1 -1
- package/dist/ToggleButton.d.ts +11 -5
- package/dist/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButtonGroup.d.ts +7 -7
- package/dist/ToggleButtonGroup.d.ts.map +1 -1
- package/dist/Toolbar.d.ts +7 -3
- package/dist/Toolbar.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +50 -8
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tree.d.ts +66 -17
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Virtualizer.d.ts +12 -12
- package/dist/Virtualizer.d.ts.map +1 -1
- package/dist/VirtualizerLayouts.d.ts +2 -2
- package/dist/VirtualizerLayouts.d.ts.map +1 -1
- package/dist/VisuallyHidden.d.ts +1 -1
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/contexts.d.ts +5 -1
- package/dist/contexts.d.ts.map +1 -1
- package/dist/index.d.ts +73 -71
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23253 -18564
- package/dist/index.js.map +1 -1
- package/dist/index.jsx +18116 -0
- package/dist/index.jsx.map +1 -0
- package/dist/useDragAndDrop.d.ts +13 -13
- package/dist/useDragAndDrop.d.ts.map +1 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/virtualizer/Layout.d.ts +1 -1
- package/dist/virtualizer/Layout.d.ts.map +1 -1
- package/package.json +31 -32
- package/src/ActionBar.tsx +75 -72
- package/src/ActionGroup.tsx +53 -61
- package/src/Alert.tsx +17 -42
- package/src/Autocomplete.tsx +39 -44
- package/src/Breadcrumbs.tsx +149 -80
- package/src/Button.tsx +267 -70
- package/src/Calendar.tsx +218 -138
- package/src/Checkbox.tsx +413 -121
- package/src/Collection.tsx +67 -58
- package/src/Color.tsx +803 -380
- package/src/ColorEditor.tsx +131 -149
- package/src/ComboBox.tsx +414 -249
- package/src/ContextualHelpTrigger.tsx +86 -74
- package/src/DateField.tsx +185 -91
- package/src/DatePicker.tsx +524 -213
- package/src/DateRangePickerContext.tsx +44 -0
- package/src/Dialog.tsx +156 -118
- package/src/Disclosure.tsx +127 -80
- package/src/DragAndDrop.tsx +60 -54
- package/src/DragPreview.tsx +13 -11
- package/src/DropZone.tsx +42 -22
- package/src/FieldError.tsx +45 -23
- package/src/FileTrigger.tsx +19 -19
- package/src/Focusable.tsx +21 -24
- package/src/Form.tsx +71 -16
- package/src/GridList.tsx +273 -197
- package/src/HiddenDateInput.tsx +153 -0
- package/src/HiddenTimeInput.tsx +133 -0
- package/src/Icon.tsx +22 -43
- package/src/Keyboard.tsx +3 -3
- package/src/Landmark.tsx +37 -63
- package/src/Link.tsx +125 -75
- package/src/ListBox.tsx +332 -233
- package/src/ListDropTargetDelegate.ts +81 -80
- package/src/Menu.tsx +1023 -274
- package/src/Meter.tsx +38 -56
- package/src/Modal.tsx +251 -176
- package/src/NumberField.tsx +139 -143
- package/src/Popover.tsx +396 -234
- package/src/Pressable.tsx +21 -21
- package/src/ProgressBar.tsx +48 -57
- package/src/RadioGroup.tsx +524 -122
- package/src/RangeCalendar.tsx +157 -90
- package/src/RouterProvider.tsx +30 -47
- package/src/SearchField.tsx +362 -143
- package/src/Select.tsx +656 -233
- package/src/SelectionIndicator.tsx +18 -15
- package/src/Separator.tsx +47 -49
- package/src/SharedElementTransition.tsx +103 -97
- package/src/Slider.tsx +138 -98
- package/src/StepList.tsx +272 -0
- package/src/Switch.tsx +93 -46
- package/src/Table.tsx +1308 -342
- package/src/Tabs.tsx +324 -103
- package/src/TagGroup.tsx +139 -126
- package/src/Text.tsx +3 -3
- package/src/TextField.tsx +389 -79
- package/src/TimeField.tsx +136 -76
- package/src/Toast.tsx +216 -158
- package/src/ToggleButton.tsx +47 -37
- package/src/ToggleButtonGroup.tsx +39 -34
- package/src/Toolbar.tsx +54 -69
- package/src/Tooltip.tsx +387 -119
- package/src/Tree.tsx +651 -368
- package/src/Virtualizer.tsx +208 -180
- package/src/VirtualizerLayouts.ts +45 -30
- package/src/VisuallyHidden.tsx +19 -19
- package/src/contexts.ts +29 -37
- package/src/index.ts +110 -195
- package/src/useDragAndDrop.ts +87 -71
- package/src/utils.tsx +49 -60
- package/src/virtualizer/Layout.ts +14 -22
- package/dist/index.ssr.js +0 -16996
- package/dist/index.ssr.js.map +0 -1
package/src/ListBox.tsx
CHANGED
|
@@ -16,22 +16,21 @@ import {
|
|
|
16
16
|
useContext,
|
|
17
17
|
For,
|
|
18
18
|
Show,
|
|
19
|
-
} from
|
|
19
|
+
} from "solid-js";
|
|
20
20
|
import {
|
|
21
21
|
createListBox,
|
|
22
22
|
createOption,
|
|
23
23
|
createFocusRing,
|
|
24
|
-
createHover,
|
|
25
24
|
mergeProps,
|
|
26
25
|
type AriaListBoxProps,
|
|
27
26
|
type AriaOptionProps,
|
|
28
|
-
} from
|
|
27
|
+
} from "@proyecto-viviana/solidaria";
|
|
29
28
|
import {
|
|
30
29
|
createListState,
|
|
31
30
|
type ListState,
|
|
32
31
|
type Key,
|
|
33
32
|
type DropTarget,
|
|
34
|
-
} from
|
|
33
|
+
} from "@proyecto-viviana/solid-stately";
|
|
35
34
|
import {
|
|
36
35
|
type RenderChildren,
|
|
37
36
|
type ClassNameOrFunction,
|
|
@@ -39,20 +38,20 @@ import {
|
|
|
39
38
|
type SlotProps,
|
|
40
39
|
useRenderProps,
|
|
41
40
|
filterDOMProps,
|
|
42
|
-
} from
|
|
43
|
-
import { SharedElementTransition } from
|
|
41
|
+
} from "./utils";
|
|
42
|
+
import { SharedElementTransition } from "./SharedElementTransition";
|
|
44
43
|
import {
|
|
45
44
|
SelectionIndicatorContext,
|
|
46
45
|
type SelectionIndicatorContextValue,
|
|
47
|
-
} from
|
|
48
|
-
import { useVirtualizerContext } from
|
|
49
|
-
import { type DragAndDropHooks } from
|
|
46
|
+
} from "./SelectionIndicator";
|
|
47
|
+
import { useVirtualizerContext } from "./Virtualizer";
|
|
48
|
+
import { type DragAndDropHooks } from "./useDragAndDrop";
|
|
50
49
|
import {
|
|
51
50
|
getNormalizedDropTargetKey,
|
|
52
51
|
mergePersistedKeysIntoVirtualRange,
|
|
53
52
|
useDndPersistedKeys,
|
|
54
53
|
useRenderDropIndicator,
|
|
55
|
-
} from
|
|
54
|
+
} from "./DragAndDrop";
|
|
56
55
|
import {
|
|
57
56
|
CollectionRendererContext,
|
|
58
57
|
Section,
|
|
@@ -64,11 +63,7 @@ import {
|
|
|
64
63
|
useCollectionRenderer,
|
|
65
64
|
isCollectionSection,
|
|
66
65
|
flattenCollectionEntries,
|
|
67
|
-
} from
|
|
68
|
-
|
|
69
|
-
// ============================================
|
|
70
|
-
// TYPES
|
|
71
|
-
// ============================================
|
|
66
|
+
} from "./Collection";
|
|
72
67
|
|
|
73
68
|
export interface ListBoxRenderProps {
|
|
74
69
|
/** Whether the listbox has focus. */
|
|
@@ -81,9 +76,15 @@ export interface ListBoxRenderProps {
|
|
|
81
76
|
isEmpty: boolean;
|
|
82
77
|
}
|
|
83
78
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
type RefLike<T> = ((el: T) => void) | { current?: T | null } | undefined;
|
|
80
|
+
|
|
81
|
+
function assignRef<T>(ref: RefLike<T>, el: T): void {
|
|
82
|
+
if (!ref) return;
|
|
83
|
+
if (typeof ref === "function") ref(el);
|
|
84
|
+
else ref.current = el;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface ListBoxProps<T> extends Omit<AriaListBoxProps, "children">, SlotProps {
|
|
87
88
|
/** The items to render in the listbox. */
|
|
88
89
|
items: CollectionEntry<T>[];
|
|
89
90
|
/** Function to get the key from an item. */
|
|
@@ -93,15 +94,19 @@ export interface ListBoxProps<T>
|
|
|
93
94
|
/** Function to check if an item is disabled. */
|
|
94
95
|
getDisabled?: (item: T) => boolean;
|
|
95
96
|
/** The selection mode. */
|
|
96
|
-
selectionMode?:
|
|
97
|
+
selectionMode?: "none" | "single" | "multiple";
|
|
98
|
+
/** The selection behavior (toggle vs replace). */
|
|
99
|
+
selectionBehavior?: "toggle" | "replace";
|
|
100
|
+
/** Whether disabled items can still receive focus. */
|
|
101
|
+
disabledBehavior?: "selection" | "all";
|
|
97
102
|
/** Keys of disabled items. */
|
|
98
103
|
disabledKeys?: Iterable<Key>;
|
|
99
104
|
/** Currently selected keys (controlled). */
|
|
100
|
-
selectedKeys?:
|
|
105
|
+
selectedKeys?: "all" | Iterable<Key>;
|
|
101
106
|
/** Default selected keys (uncontrolled). */
|
|
102
|
-
defaultSelectedKeys?:
|
|
107
|
+
defaultSelectedKeys?: "all" | Iterable<Key>;
|
|
103
108
|
/** Handler called when selection changes. */
|
|
104
|
-
onSelectionChange?: (keys:
|
|
109
|
+
onSelectionChange?: (keys: "all" | Set<Key>) => void;
|
|
105
110
|
/** The children of the component. A function may be provided to render each item. */
|
|
106
111
|
children: (item: T) => JSX.Element;
|
|
107
112
|
/** The CSS className for the element. */
|
|
@@ -116,8 +121,16 @@ export interface ListBoxProps<T>
|
|
|
116
121
|
isLoading?: boolean;
|
|
117
122
|
/** Called when the load more sentinel becomes visible. */
|
|
118
123
|
onLoadMore?: () => void | Promise<void>;
|
|
124
|
+
/** Ref for the listbox element. */
|
|
125
|
+
ref?: RefLike<HTMLUListElement>;
|
|
119
126
|
/** Drag and drop hooks from `useDragAndDrop`. */
|
|
120
127
|
dragAndDropHooks?: DragAndDropHooks<T>;
|
|
128
|
+
/** Layout hint for styling parity. */
|
|
129
|
+
layout?: "stack" | "grid";
|
|
130
|
+
/** Orientation hint for styling parity. */
|
|
131
|
+
orientation?: "vertical" | "horizontal";
|
|
132
|
+
/** Slot definitions provided through ListBoxContext. */
|
|
133
|
+
slots?: Record<string, Partial<ListBoxProps<T>>>;
|
|
121
134
|
}
|
|
122
135
|
|
|
123
136
|
export interface ListBoxOptionRenderProps {
|
|
@@ -136,8 +149,7 @@ export interface ListBoxOptionRenderProps {
|
|
|
136
149
|
}
|
|
137
150
|
|
|
138
151
|
export interface ListBoxOptionProps<T>
|
|
139
|
-
extends Omit<AriaOptionProps,
|
|
140
|
-
SlotProps {
|
|
152
|
+
extends Omit<AriaOptionProps, "children" | "key">, SlotProps {
|
|
141
153
|
/** The unique key for the option. */
|
|
142
154
|
id: Key;
|
|
143
155
|
/** The item value. */
|
|
@@ -150,6 +162,8 @@ export interface ListBoxOptionProps<T>
|
|
|
150
162
|
style?: StyleOrFunction<ListBoxOptionRenderProps>;
|
|
151
163
|
/** The text value of the option (for typeahead). */
|
|
152
164
|
textValue?: string;
|
|
165
|
+
/** Ref for the option element. */
|
|
166
|
+
ref?: RefLike<HTMLLIElement>;
|
|
153
167
|
}
|
|
154
168
|
|
|
155
169
|
export interface ListBoxLoadMoreItemProps extends SlotProps {
|
|
@@ -157,6 +171,8 @@ export interface ListBoxLoadMoreItemProps extends SlotProps {
|
|
|
157
171
|
onLoadMore: () => void | Promise<void>;
|
|
158
172
|
/** Whether additional items are currently loading. */
|
|
159
173
|
isLoading?: boolean;
|
|
174
|
+
/** Scroll offset multiplier for early loading trigger (default: 1 = 100% of viewport height). */
|
|
175
|
+
scrollOffset?: number;
|
|
160
176
|
/** Content for the load more row. */
|
|
161
177
|
children?: JSX.Element;
|
|
162
178
|
/** The CSS className for the element. */
|
|
@@ -167,34 +183,58 @@ export interface ListBoxLoadMoreItemProps extends SlotProps {
|
|
|
167
183
|
|
|
168
184
|
export interface ListBoxSectionProps extends SectionProps {}
|
|
169
185
|
|
|
170
|
-
// ============================================
|
|
171
|
-
// CONTEXT
|
|
172
|
-
// ============================================
|
|
173
|
-
|
|
174
186
|
interface ListBoxContextValue<T> {
|
|
175
187
|
state: ListState<T>;
|
|
176
188
|
isDisabled: () => boolean;
|
|
177
189
|
dragAndDropHooks?: DragAndDropHooks<unknown>;
|
|
178
190
|
dragState?: unknown;
|
|
179
191
|
dropState?: unknown;
|
|
192
|
+
slots?: Record<string, Partial<ListBoxProps<T>>>;
|
|
180
193
|
}
|
|
181
194
|
|
|
182
195
|
export const ListBoxContext = createContext<ListBoxContextValue<unknown> | null>(null);
|
|
183
196
|
export const ListBoxStateContext = createContext<ListState<unknown> | null>(null);
|
|
184
197
|
export const ListStateContext = ListBoxStateContext;
|
|
185
198
|
|
|
186
|
-
// ============================================
|
|
187
|
-
// COMPONENTS
|
|
188
|
-
// ============================================
|
|
189
|
-
|
|
190
199
|
/**
|
|
191
200
|
* A listbox displays a list of options and allows a user to select one or more of them.
|
|
192
201
|
*/
|
|
193
202
|
export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
203
|
+
const parentContext = useContext(ListBoxContext) as ListBoxContextValue<T> | null;
|
|
204
|
+
const contextSlotProps = parentContext?.slots?.[props.slot ?? "default"];
|
|
205
|
+
const mergedListBoxProps = contextSlotProps
|
|
206
|
+
? (mergeProps(contextSlotProps, props) as ListBoxProps<T>)
|
|
207
|
+
: props;
|
|
194
208
|
const [local, stateProps, ariaProps] = splitProps(
|
|
195
|
-
|
|
196
|
-
[
|
|
197
|
-
|
|
209
|
+
mergedListBoxProps,
|
|
210
|
+
[
|
|
211
|
+
"children",
|
|
212
|
+
"class",
|
|
213
|
+
"style",
|
|
214
|
+
"slot",
|
|
215
|
+
"renderEmptyState",
|
|
216
|
+
"hasMore",
|
|
217
|
+
"isLoading",
|
|
218
|
+
"onLoadMore",
|
|
219
|
+
"dragAndDropHooks",
|
|
220
|
+
"slots",
|
|
221
|
+
"ref",
|
|
222
|
+
],
|
|
223
|
+
[
|
|
224
|
+
"items",
|
|
225
|
+
"getKey",
|
|
226
|
+
"getTextValue",
|
|
227
|
+
"getDisabled",
|
|
228
|
+
"disabledKeys",
|
|
229
|
+
"disabledBehavior",
|
|
230
|
+
"selectionMode",
|
|
231
|
+
"selectionBehavior",
|
|
232
|
+
"selectedKeys",
|
|
233
|
+
"defaultSelectedKeys",
|
|
234
|
+
"onSelectionChange",
|
|
235
|
+
"layout",
|
|
236
|
+
"orientation",
|
|
237
|
+
],
|
|
198
238
|
);
|
|
199
239
|
|
|
200
240
|
const flatItems = createMemo<T[]>(() => {
|
|
@@ -203,7 +243,6 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
203
243
|
|
|
204
244
|
const hasSections = createMemo(() => stateProps.items.some((item) => isCollectionSection(item)));
|
|
205
245
|
|
|
206
|
-
// Create list state
|
|
207
246
|
const state = createListState<T>({
|
|
208
247
|
get items() {
|
|
209
248
|
return flatItems();
|
|
@@ -223,6 +262,12 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
223
262
|
get selectionMode() {
|
|
224
263
|
return stateProps.selectionMode;
|
|
225
264
|
},
|
|
265
|
+
get selectionBehavior() {
|
|
266
|
+
return stateProps.selectionBehavior;
|
|
267
|
+
},
|
|
268
|
+
get disabledBehavior() {
|
|
269
|
+
return stateProps.disabledBehavior;
|
|
270
|
+
},
|
|
226
271
|
get selectedKeys() {
|
|
227
272
|
return stateProps.selectedKeys;
|
|
228
273
|
},
|
|
@@ -234,16 +279,14 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
234
279
|
},
|
|
235
280
|
});
|
|
236
281
|
|
|
237
|
-
// Helper to resolve isDisabled
|
|
238
282
|
const resolveDisabled = (): boolean => {
|
|
239
283
|
const disabled = ariaProps.isDisabled;
|
|
240
|
-
if (typeof disabled ===
|
|
284
|
+
if (typeof disabled === "function") {
|
|
241
285
|
return (disabled as () => boolean)();
|
|
242
286
|
}
|
|
243
287
|
return !!disabled;
|
|
244
288
|
};
|
|
245
289
|
|
|
246
|
-
// Create listbox aria props
|
|
247
290
|
const listBoxAria = createListBox(
|
|
248
291
|
{
|
|
249
292
|
...ariaProps,
|
|
@@ -251,13 +294,11 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
251
294
|
return resolveDisabled();
|
|
252
295
|
},
|
|
253
296
|
},
|
|
254
|
-
state
|
|
297
|
+
state,
|
|
255
298
|
);
|
|
256
299
|
|
|
257
|
-
// Create focus ring
|
|
258
300
|
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
259
301
|
|
|
260
|
-
// Render props values
|
|
261
302
|
const renderValues = createMemo<ListBoxRenderProps>(() => ({
|
|
262
303
|
isFocused: state.isFocused() || isFocused(),
|
|
263
304
|
isFocusVisible: isFocusVisible(),
|
|
@@ -265,23 +306,20 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
265
306
|
isEmpty: state.collection().size === 0,
|
|
266
307
|
}));
|
|
267
308
|
|
|
268
|
-
// Resolve render props
|
|
269
309
|
const renderProps = useRenderProps(
|
|
270
310
|
{
|
|
271
311
|
class: local.class,
|
|
272
312
|
style: local.style,
|
|
273
|
-
defaultClassName:
|
|
313
|
+
defaultClassName: "solidaria-ListBox",
|
|
274
314
|
},
|
|
275
|
-
renderValues
|
|
315
|
+
renderValues,
|
|
276
316
|
);
|
|
277
317
|
|
|
278
|
-
// Filter DOM props
|
|
279
318
|
const domProps = createMemo(() => {
|
|
280
319
|
const filtered = filterDOMProps(ariaProps as Record<string, unknown>, { global: true });
|
|
281
320
|
return filtered;
|
|
282
321
|
});
|
|
283
322
|
|
|
284
|
-
// Remove ref from spread props
|
|
285
323
|
const cleanListBoxProps = () => {
|
|
286
324
|
const { ref: _ref1, ...rest } = listBoxAria.listBoxProps as Record<string, unknown>;
|
|
287
325
|
return rest;
|
|
@@ -298,18 +336,25 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
298
336
|
|
|
299
337
|
const isEmpty = () => stateProps.items.length === 0;
|
|
300
338
|
const parentCollectionRenderer = useCollectionRenderer<unknown>();
|
|
301
|
-
const getItemNodes = createMemo(() =>
|
|
302
|
-
|
|
339
|
+
const getItemNodes = createMemo(() =>
|
|
340
|
+
Array.from(state.collection()).filter((node) => node.type === "item"),
|
|
341
|
+
);
|
|
342
|
+
const getDropTargetByIndex = (
|
|
343
|
+
index: number,
|
|
344
|
+
position: "before" | "after" | "on",
|
|
345
|
+
): DropTarget | null => {
|
|
303
346
|
const node = getItemNodes()[index];
|
|
304
347
|
if (!node) return null;
|
|
305
|
-
return { type:
|
|
348
|
+
return { type: "item", key: node.key, dropPosition: position };
|
|
306
349
|
};
|
|
307
350
|
const hasDroppableDnd = createMemo(() => {
|
|
308
351
|
const hooks = local.dragAndDropHooks;
|
|
309
352
|
return Boolean(
|
|
310
353
|
hooks?.useDroppableCollectionState &&
|
|
311
354
|
hooks.useDroppableCollection &&
|
|
312
|
-
(hooks.dropTargetDelegate ||
|
|
355
|
+
(hooks.dropTargetDelegate ||
|
|
356
|
+
parentCollectionRenderer?.dropTargetDelegate ||
|
|
357
|
+
hooks.ListDropTargetDelegate),
|
|
313
358
|
);
|
|
314
359
|
});
|
|
315
360
|
const dropState = createMemo(() => {
|
|
@@ -338,22 +383,23 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
338
383
|
const hooks = local.dragAndDropHooks;
|
|
339
384
|
const activeDropState = dropState();
|
|
340
385
|
if (!hooks?.useDroppableCollection || !activeDropState) return undefined;
|
|
341
|
-
const resolveDirection = ():
|
|
386
|
+
const resolveDirection = (): "ltr" | "rtl" => {
|
|
342
387
|
const el = listRef();
|
|
343
|
-
if (el && typeof window !==
|
|
388
|
+
if (el && typeof window !== "undefined" && typeof window.getComputedStyle === "function") {
|
|
344
389
|
const dir = window.getComputedStyle(el).direction;
|
|
345
|
-
if (dir ===
|
|
390
|
+
if (dir === "rtl") return "rtl";
|
|
346
391
|
}
|
|
347
|
-
return typeof document !==
|
|
392
|
+
return typeof document !== "undefined" && document.dir === "rtl" ? "rtl" : "ltr";
|
|
348
393
|
};
|
|
349
|
-
const dropTargetDelegate =
|
|
350
|
-
??
|
|
351
|
-
??
|
|
394
|
+
const dropTargetDelegate =
|
|
395
|
+
hooks.dropTargetDelegate ??
|
|
396
|
+
parentCollectionRenderer?.dropTargetDelegate ??
|
|
397
|
+
(hooks.ListDropTargetDelegate
|
|
352
398
|
? new hooks.ListDropTargetDelegate(
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
399
|
+
() => state.collection(),
|
|
400
|
+
() => listRef(),
|
|
401
|
+
{ layout: "stack", orientation: "vertical", direction: resolveDirection() },
|
|
402
|
+
)
|
|
357
403
|
: undefined);
|
|
358
404
|
if (!dropTargetDelegate) return undefined;
|
|
359
405
|
return hooks.useDroppableCollection(
|
|
@@ -369,16 +415,18 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
369
415
|
},
|
|
370
416
|
},
|
|
371
417
|
activeDropState,
|
|
372
|
-
() => listRef()
|
|
418
|
+
() => listRef(),
|
|
373
419
|
);
|
|
374
420
|
});
|
|
375
421
|
const isRootDropTarget = createMemo(() => {
|
|
376
|
-
return Boolean(dropState()?.target?.type ===
|
|
422
|
+
return Boolean(dropState()?.target?.type === "root");
|
|
377
423
|
});
|
|
378
|
-
const dndRenderDropIndicator = createMemo(() =>
|
|
379
|
-
|
|
424
|
+
const dndRenderDropIndicator = createMemo(() =>
|
|
425
|
+
useRenderDropIndicator(local.dragAndDropHooks, dropState()),
|
|
426
|
+
);
|
|
427
|
+
const dndDropIndicator = (index: number, position: "before" | "after" | "on") => {
|
|
380
428
|
const target = getDropTargetByIndex(index, position);
|
|
381
|
-
if (!target || target.type !==
|
|
429
|
+
if (!target || target.type !== "item") return undefined;
|
|
382
430
|
return dndRenderDropIndicator()?.(target);
|
|
383
431
|
};
|
|
384
432
|
const virtualizer = useVirtualizerContext();
|
|
@@ -386,7 +434,7 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
386
434
|
{ focusedKey: state.focusedKey },
|
|
387
435
|
local.dragAndDropHooks,
|
|
388
436
|
dropState(),
|
|
389
|
-
state.collection()
|
|
437
|
+
state.collection(),
|
|
390
438
|
);
|
|
391
439
|
const virtualRange = createMemo(() => {
|
|
392
440
|
if (!virtualizer || !parentCollectionRenderer?.isVirtualized || hasSections()) return null;
|
|
@@ -398,20 +446,31 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
398
446
|
const dropTarget = dropState()?.target;
|
|
399
447
|
const normalizedDropKey = getNormalizedDropTargetKey(dropTarget, state.collection());
|
|
400
448
|
const focusedKey = state.focusedKey();
|
|
401
|
-
const focusedIndex =
|
|
449
|
+
const focusedIndex =
|
|
450
|
+
focusedKey != null ? itemNodes.findIndex((node) => node.key === focusedKey) : -1;
|
|
402
451
|
const forceIncludeIndexes = [
|
|
403
|
-
dropTarget?.type ===
|
|
404
|
-
normalizedDropKey != null
|
|
405
|
-
|
|
452
|
+
dropTarget?.type === "item" ? itemNodes.findIndex((node) => node.key === dropTarget.key) : -1,
|
|
453
|
+
normalizedDropKey != null
|
|
454
|
+
? itemNodes.findIndex((node) => node.key === normalizedDropKey)
|
|
455
|
+
: -1,
|
|
456
|
+
dropTarget?.type === "item" ? -1 : focusedIndex,
|
|
406
457
|
].filter((index) => index >= 0);
|
|
407
|
-
return mergePersistedKeysIntoVirtualRange(
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
458
|
+
return mergePersistedKeysIntoVirtualRange(
|
|
459
|
+
baseRange,
|
|
460
|
+
persistedIndexes,
|
|
461
|
+
stateProps.items.length,
|
|
462
|
+
virtualizer,
|
|
463
|
+
80,
|
|
464
|
+
{
|
|
465
|
+
forceIncludeIndexes,
|
|
466
|
+
forceIncludeMaxSpan: 320,
|
|
467
|
+
},
|
|
468
|
+
);
|
|
411
469
|
});
|
|
412
470
|
createEffect(() => {
|
|
413
471
|
if (!virtualizer || !parentCollectionRenderer?.isVirtualized) return;
|
|
414
|
-
const getItemNodes = () =>
|
|
472
|
+
const getItemNodes = () =>
|
|
473
|
+
Array.from(state.collection()).filter((node) => node.type === "item");
|
|
415
474
|
virtualizer.setDropTargetItemCountResolver(() => getItemNodes().length);
|
|
416
475
|
virtualizer.setDropTargetIndexResolver((key) => {
|
|
417
476
|
const index = getItemNodes().findIndex((node) => node.key === key);
|
|
@@ -422,7 +481,7 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
422
481
|
if (!node) return target;
|
|
423
482
|
return {
|
|
424
483
|
...target,
|
|
425
|
-
key: typeof node.key ===
|
|
484
|
+
key: typeof node.key === "string" || typeof node.key === "number" ? node.key : undefined,
|
|
426
485
|
};
|
|
427
486
|
});
|
|
428
487
|
onCleanup(() => {
|
|
@@ -445,7 +504,7 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
445
504
|
index: globalIndex++,
|
|
446
505
|
}));
|
|
447
506
|
return {
|
|
448
|
-
type:
|
|
507
|
+
type: "section" as const,
|
|
449
508
|
section: entry,
|
|
450
509
|
items: sectionItems,
|
|
451
510
|
};
|
|
@@ -455,27 +514,31 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
455
514
|
index: globalIndex++,
|
|
456
515
|
};
|
|
457
516
|
return {
|
|
458
|
-
type:
|
|
517
|
+
type: "item" as const,
|
|
459
518
|
item: indexedItem,
|
|
460
519
|
};
|
|
461
520
|
});
|
|
462
521
|
});
|
|
463
522
|
const collectionRenderer = createMemo<CollectionRendererContextValue<unknown>>(() => ({
|
|
464
523
|
...parentCollectionRenderer,
|
|
465
|
-
renderItem: (item) =>
|
|
524
|
+
renderItem: (item) => local.children(item as T),
|
|
466
525
|
renderDropIndicator: (index, position) =>
|
|
467
|
-
dndDropIndicator(index, position) ??
|
|
526
|
+
dndDropIndicator(index, position) ??
|
|
527
|
+
parentCollectionRenderer?.renderDropIndicator?.(index, position),
|
|
468
528
|
}));
|
|
469
529
|
|
|
470
530
|
return (
|
|
471
531
|
<ListBoxContext.Provider
|
|
472
|
-
value={
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
532
|
+
value={
|
|
533
|
+
{
|
|
534
|
+
state,
|
|
535
|
+
isDisabled: resolveDisabled,
|
|
536
|
+
dragAndDropHooks: local.dragAndDropHooks as DragAndDropHooks<unknown> | undefined,
|
|
537
|
+
dragState: dragState(),
|
|
538
|
+
dropState: dropState(),
|
|
539
|
+
slots: local.slots,
|
|
540
|
+
} as ListBoxContextValue<unknown>
|
|
541
|
+
}
|
|
479
542
|
>
|
|
480
543
|
<ListBoxStateContext.Provider value={state}>
|
|
481
544
|
<CollectionRendererContext.Provider value={collectionRenderer()}>
|
|
@@ -488,10 +551,12 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
488
551
|
domProps(),
|
|
489
552
|
cleanListBoxProps(),
|
|
490
553
|
cleanFocusProps(),
|
|
491
|
-
(droppableCollection()?.collectionProps as Record<string, unknown> | undefined) ??
|
|
554
|
+
(droppableCollection()?.collectionProps as Record<string, unknown> | undefined) ??
|
|
555
|
+
{},
|
|
492
556
|
)}
|
|
493
557
|
ref={(el) => {
|
|
494
558
|
setListRef(el);
|
|
559
|
+
assignRef(local.ref, el);
|
|
495
560
|
}}
|
|
496
561
|
class={renderProps.class()}
|
|
497
562
|
style={renderProps.style()}
|
|
@@ -499,83 +564,104 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
499
564
|
data-focus-visible={isFocusVisible() || undefined}
|
|
500
565
|
data-disabled={resolveDisabled() || undefined}
|
|
501
566
|
data-empty={isEmpty() || undefined}
|
|
567
|
+
data-layout={stateProps.layout}
|
|
568
|
+
data-orientation={stateProps.orientation}
|
|
502
569
|
data-drop-target={isRootDropTarget() || undefined}
|
|
570
|
+
slot={local.slot}
|
|
503
571
|
>
|
|
504
572
|
<SharedElementTransition>
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
573
|
+
{isEmpty() && local.renderEmptyState ? (
|
|
574
|
+
<li role="option" style={{ display: "contents" }} data-empty-state>
|
|
575
|
+
{local.renderEmptyState()}
|
|
576
|
+
</li>
|
|
577
|
+
) : hasSections() ? (
|
|
578
|
+
<For each={sectionedRenderEntries()}>
|
|
579
|
+
{(entry) =>
|
|
580
|
+
entry.type === "section" ? (
|
|
581
|
+
<li role="presentation" data-section-wrapper>
|
|
582
|
+
<Section class="solidaria-ListBox-section">
|
|
583
|
+
{entry.section.title != null && (
|
|
584
|
+
<Header class="solidaria-ListBox-sectionHeader">
|
|
585
|
+
{entry.section.title}
|
|
586
|
+
</Header>
|
|
587
|
+
)}
|
|
588
|
+
<Group class="solidaria-ListBox-sectionGroup">
|
|
589
|
+
<ul role="group" aria-label={entry.section["aria-label"]}>
|
|
590
|
+
<For each={entry.items}>
|
|
591
|
+
{(indexedItem) => (
|
|
592
|
+
<>
|
|
593
|
+
{collectionRenderer().renderDropIndicator?.(
|
|
594
|
+
indexedItem.index,
|
|
595
|
+
"before",
|
|
528
596
|
)}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
597
|
+
{collectionRenderer().renderDropIndicator?.(
|
|
598
|
+
indexedItem.index,
|
|
599
|
+
"on",
|
|
600
|
+
)}
|
|
601
|
+
{local.children(indexedItem.item)}
|
|
602
|
+
{collectionRenderer().renderDropIndicator?.(
|
|
603
|
+
indexedItem.index,
|
|
604
|
+
"after",
|
|
605
|
+
)}
|
|
606
|
+
</>
|
|
607
|
+
)}
|
|
608
|
+
</For>
|
|
609
|
+
</ul>
|
|
610
|
+
</Group>
|
|
611
|
+
</Section>
|
|
612
|
+
</li>
|
|
613
|
+
) : (
|
|
614
|
+
<>
|
|
615
|
+
{collectionRenderer().renderDropIndicator?.(entry.item.index, "before")}
|
|
616
|
+
{collectionRenderer().renderDropIndicator?.(entry.item.index, "on")}
|
|
617
|
+
{local.children(entry.item.item)}
|
|
618
|
+
{collectionRenderer().renderDropIndicator?.(entry.item.index, "after")}
|
|
619
|
+
</>
|
|
620
|
+
)
|
|
621
|
+
}
|
|
622
|
+
</For>
|
|
623
|
+
) : (
|
|
624
|
+
<>
|
|
625
|
+
{virtualRange()?.offsetTop ? (
|
|
626
|
+
<li
|
|
627
|
+
role="presentation"
|
|
628
|
+
aria-hidden="true"
|
|
629
|
+
style={{ height: `${virtualRange()!.offsetTop}px` }}
|
|
630
|
+
data-virtualizer-spacer="top"
|
|
631
|
+
/>
|
|
632
|
+
) : null}
|
|
633
|
+
<For each={visibleItems()}>
|
|
634
|
+
{(item, index) => {
|
|
635
|
+
const itemIndex = () => (virtualRange()?.start ?? 0) + index();
|
|
636
|
+
const beforeIndicator = () =>
|
|
637
|
+
collectionRenderer().renderDropIndicator?.(itemIndex(), "before");
|
|
638
|
+
const onIndicator = () =>
|
|
639
|
+
collectionRenderer().renderDropIndicator?.(itemIndex(), "on");
|
|
640
|
+
const afterIndicator = () =>
|
|
641
|
+
collectionRenderer().renderDropIndicator?.(itemIndex(), "after");
|
|
642
|
+
return (
|
|
643
|
+
<>
|
|
644
|
+
{beforeIndicator()}
|
|
645
|
+
{onIndicator()}
|
|
646
|
+
{local.children(item as T)}
|
|
647
|
+
{afterIndicator()}
|
|
648
|
+
</>
|
|
649
|
+
);
|
|
650
|
+
}}
|
|
544
651
|
</For>
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
const onIndicator = () => collectionRenderer().renderDropIndicator?.(itemIndex(), 'on');
|
|
556
|
-
const afterIndicator = () => collectionRenderer().renderDropIndicator?.(itemIndex(), 'after');
|
|
557
|
-
return (
|
|
558
|
-
<>
|
|
559
|
-
{beforeIndicator()}
|
|
560
|
-
{onIndicator()}
|
|
561
|
-
{props.children(item as T)}
|
|
562
|
-
{afterIndicator()}
|
|
563
|
-
</>
|
|
564
|
-
);
|
|
565
|
-
}}
|
|
566
|
-
</For>
|
|
567
|
-
{virtualRange()?.offsetBottom
|
|
568
|
-
? <li role="presentation" aria-hidden="true" style={{ height: `${virtualRange()!.offsetBottom}px` }} data-virtualizer-spacer="bottom" />
|
|
569
|
-
: null}
|
|
570
|
-
</>
|
|
571
|
-
)
|
|
572
|
-
}
|
|
652
|
+
{virtualRange()?.offsetBottom ? (
|
|
653
|
+
<li
|
|
654
|
+
role="presentation"
|
|
655
|
+
aria-hidden="true"
|
|
656
|
+
style={{ height: `${virtualRange()!.offsetBottom}px` }}
|
|
657
|
+
data-virtualizer-spacer="bottom"
|
|
658
|
+
/>
|
|
659
|
+
) : null}
|
|
660
|
+
</>
|
|
661
|
+
)}
|
|
573
662
|
</SharedElementTransition>
|
|
574
663
|
{local.hasMore && local.onLoadMore && (
|
|
575
|
-
<ListBoxLoadMoreItem
|
|
576
|
-
onLoadMore={local.onLoadMore}
|
|
577
|
-
isLoading={local.isLoading}
|
|
578
|
-
/>
|
|
664
|
+
<ListBoxLoadMoreItem onLoadMore={local.onLoadMore} isLoading={local.isLoading} />
|
|
579
665
|
)}
|
|
580
666
|
</ul>
|
|
581
667
|
</>
|
|
@@ -590,120 +676,123 @@ export function ListBox<T>(props: ListBoxProps<T>): JSX.Element {
|
|
|
590
676
|
*/
|
|
591
677
|
export function ListBoxOption<T>(props: ListBoxOptionProps<T>): JSX.Element {
|
|
592
678
|
const [local, ariaProps] = splitProps(props, [
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
679
|
+
"class",
|
|
680
|
+
"style",
|
|
681
|
+
"slot",
|
|
682
|
+
"id",
|
|
683
|
+
"item",
|
|
684
|
+
"textValue",
|
|
685
|
+
"ref",
|
|
599
686
|
]);
|
|
600
687
|
|
|
601
|
-
// Get state from context
|
|
602
688
|
const context = useContext(ListBoxStateContext);
|
|
603
689
|
if (!context) {
|
|
604
|
-
throw new Error(
|
|
690
|
+
throw new Error("ListBoxOption must be used within a ListBox");
|
|
605
691
|
}
|
|
606
692
|
const state = context as ListState<T>;
|
|
607
693
|
const listContext = useContext(ListBoxContext) as ListBoxContextValue<T> | null;
|
|
608
694
|
const [ref, setRef] = createSignal<HTMLLIElement | null>(null);
|
|
609
695
|
|
|
610
|
-
// Create option aria props
|
|
611
696
|
const optionAria = createOption<T>(
|
|
612
697
|
{
|
|
613
698
|
key: local.id,
|
|
614
699
|
get isDisabled() {
|
|
615
700
|
return Boolean(ariaProps.isDisabled || listContext?.isDisabled());
|
|
616
701
|
},
|
|
617
|
-
get
|
|
618
|
-
return ariaProps[
|
|
702
|
+
get "aria-label"() {
|
|
703
|
+
return ariaProps["aria-label"] ?? local.textValue;
|
|
619
704
|
},
|
|
620
705
|
get shouldSelectOnPressUp() {
|
|
621
706
|
return ariaProps.shouldSelectOnPressUp;
|
|
622
707
|
},
|
|
708
|
+
get shouldFocusOnHover() {
|
|
709
|
+
return ariaProps.shouldFocusOnHover;
|
|
710
|
+
},
|
|
711
|
+
get onHoverStart() {
|
|
712
|
+
return ariaProps.onHoverStart;
|
|
713
|
+
},
|
|
714
|
+
get onHoverEnd() {
|
|
715
|
+
return ariaProps.onHoverEnd;
|
|
716
|
+
},
|
|
717
|
+
get onHoverChange() {
|
|
718
|
+
return ariaProps.onHoverChange;
|
|
719
|
+
},
|
|
623
720
|
},
|
|
624
|
-
state
|
|
721
|
+
state,
|
|
625
722
|
);
|
|
626
723
|
|
|
627
|
-
// Create hover
|
|
628
|
-
const { isHovered, hoverProps } = createHover({
|
|
629
|
-
get isDisabled() {
|
|
630
|
-
return optionAria.isDisabled();
|
|
631
|
-
},
|
|
632
|
-
});
|
|
633
|
-
|
|
634
|
-
// Render props values
|
|
635
724
|
const renderValues = createMemo<ListBoxOptionRenderProps>(() => ({
|
|
636
725
|
isSelected: optionAria.isSelected(),
|
|
637
726
|
isFocused: optionAria.isFocused(),
|
|
638
727
|
isFocusVisible: optionAria.isFocusVisible(),
|
|
639
728
|
isPressed: optionAria.isPressed(),
|
|
640
|
-
isHovered: isHovered(),
|
|
729
|
+
isHovered: optionAria.isHovered(),
|
|
641
730
|
isDisabled: optionAria.isDisabled(),
|
|
642
731
|
}));
|
|
643
732
|
|
|
644
|
-
// Resolve render props
|
|
645
733
|
const renderProps = useRenderProps(
|
|
646
734
|
{
|
|
647
735
|
children: props.children,
|
|
648
736
|
class: local.class,
|
|
649
737
|
style: local.style,
|
|
650
|
-
defaultClassName:
|
|
738
|
+
defaultClassName: "solidaria-ListBox-option",
|
|
651
739
|
},
|
|
652
|
-
renderValues
|
|
740
|
+
renderValues,
|
|
653
741
|
);
|
|
654
742
|
const hasPrimitiveLabel = () => {
|
|
655
|
-
return typeof props.children ===
|
|
743
|
+
return typeof props.children === "string" || typeof props.children === "number";
|
|
656
744
|
};
|
|
657
745
|
|
|
658
746
|
const selectionIndicatorContext = createMemo<SelectionIndicatorContextValue>(() => ({
|
|
659
747
|
isSelected: optionAria.isSelected,
|
|
660
748
|
}));
|
|
661
749
|
const draggableItem = createMemo(() => {
|
|
662
|
-
if (!listContext?.dragAndDropHooks?.useDraggableItem || !listContext.dragState)
|
|
750
|
+
if (!listContext?.dragAndDropHooks?.useDraggableItem || !listContext.dragState)
|
|
751
|
+
return undefined;
|
|
663
752
|
return listContext.dragAndDropHooks.useDraggableItem(
|
|
664
753
|
{
|
|
665
754
|
key: local.id as string | number,
|
|
666
755
|
},
|
|
667
|
-
listContext.dragState as Parameters<NonNullable<DragAndDropHooks<T>[
|
|
756
|
+
listContext.dragState as Parameters<NonNullable<DragAndDropHooks<T>["useDraggableItem"]>>[1],
|
|
668
757
|
);
|
|
669
758
|
});
|
|
670
759
|
const droppableItem = createMemo(() => {
|
|
671
|
-
if (!listContext?.dragAndDropHooks?.useDroppableItem || !listContext.dropState)
|
|
760
|
+
if (!listContext?.dragAndDropHooks?.useDroppableItem || !listContext.dropState)
|
|
761
|
+
return undefined;
|
|
672
762
|
return listContext.dragAndDropHooks.useDroppableItem(
|
|
673
763
|
{
|
|
674
764
|
key: local.id as string | number,
|
|
675
765
|
},
|
|
676
|
-
listContext.dropState as Parameters<NonNullable<DragAndDropHooks<T>[
|
|
677
|
-
() => ref()
|
|
766
|
+
listContext.dropState as Parameters<NonNullable<DragAndDropHooks<T>["useDroppableItem"]>>[1],
|
|
767
|
+
() => ref(),
|
|
678
768
|
);
|
|
679
769
|
});
|
|
680
770
|
|
|
681
|
-
// Remove ref from spread props
|
|
682
771
|
const cleanOptionProps = () => {
|
|
683
772
|
const {
|
|
684
773
|
ref: _ref1,
|
|
685
|
-
|
|
774
|
+
"aria-describedby": _ariaDescribedby,
|
|
686
775
|
...rest
|
|
687
776
|
} = optionAria.optionProps as Record<string, unknown>;
|
|
688
|
-
if (!hasPrimitiveLabel() && rest[
|
|
689
|
-
delete rest[
|
|
777
|
+
if (!hasPrimitiveLabel() && rest["aria-label"] == null) {
|
|
778
|
+
delete rest["aria-labelledby"];
|
|
690
779
|
}
|
|
691
780
|
return rest;
|
|
692
781
|
};
|
|
693
|
-
const
|
|
694
|
-
const { ref: _ref2, ...rest } = hoverProps as Record<string, unknown>;
|
|
695
|
-
return rest;
|
|
696
|
-
};
|
|
782
|
+
const domProps = () => filterDOMProps(ariaProps as Record<string, unknown>, { global: true });
|
|
697
783
|
|
|
698
784
|
return (
|
|
699
785
|
<SelectionIndicatorContext.Provider value={selectionIndicatorContext()}>
|
|
700
786
|
<li
|
|
701
|
-
ref={
|
|
787
|
+
ref={(el) => {
|
|
788
|
+
setRef(el);
|
|
789
|
+
assignRef(local.ref, el);
|
|
790
|
+
}}
|
|
702
791
|
{...mergeProps(
|
|
792
|
+
domProps(),
|
|
703
793
|
cleanOptionProps(),
|
|
704
|
-
cleanHoverProps(),
|
|
705
794
|
(draggableItem()?.dragProps as Record<string, unknown> | undefined) ?? {},
|
|
706
|
-
(droppableItem()?.dropProps as Record<string, unknown> | undefined) ?? {}
|
|
795
|
+
(droppableItem()?.dropProps as Record<string, unknown> | undefined) ?? {},
|
|
707
796
|
)}
|
|
708
797
|
class={renderProps.class()}
|
|
709
798
|
style={renderProps.style()}
|
|
@@ -711,14 +800,17 @@ export function ListBoxOption<T>(props: ListBoxOptionProps<T>): JSX.Element {
|
|
|
711
800
|
data-focused={optionAria.isFocused() || undefined}
|
|
712
801
|
data-focus-visible={optionAria.isFocusVisible() || undefined}
|
|
713
802
|
data-pressed={optionAria.isPressed() || undefined}
|
|
714
|
-
data-hovered={isHovered() || undefined}
|
|
803
|
+
data-hovered={optionAria.isHovered() || undefined}
|
|
715
804
|
data-disabled={optionAria.isDisabled() || undefined}
|
|
716
805
|
data-dragging={draggableItem()?.isDragging || undefined}
|
|
717
806
|
data-drop-target={droppableItem()?.isDropTarget || undefined}
|
|
807
|
+
slot={local.slot}
|
|
718
808
|
>
|
|
719
|
-
{hasPrimitiveLabel()
|
|
720
|
-
|
|
721
|
-
|
|
809
|
+
{hasPrimitiveLabel() ? (
|
|
810
|
+
<span {...optionAria.labelProps}>{renderProps.renderChildren()}</span>
|
|
811
|
+
) : (
|
|
812
|
+
renderProps.renderChildren()
|
|
813
|
+
)}
|
|
722
814
|
</li>
|
|
723
815
|
</SelectionIndicatorContext.Provider>
|
|
724
816
|
);
|
|
@@ -728,7 +820,7 @@ export function ListBoxOption<T>(props: ListBoxOptionProps<T>): JSX.Element {
|
|
|
728
820
|
* Load more sentinel item for listbox collections.
|
|
729
821
|
*/
|
|
730
822
|
export function ListBoxLoadMoreItem(props: ListBoxLoadMoreItemProps): JSX.Element {
|
|
731
|
-
let
|
|
823
|
+
let sentinelRef: HTMLDivElement | undefined;
|
|
732
824
|
const [isPending, setIsPending] = createSignal(false);
|
|
733
825
|
|
|
734
826
|
const isLoading = () => !!props.isLoading || isPending();
|
|
@@ -744,44 +836,52 @@ export function ListBoxLoadMoreItem(props: ListBoxLoadMoreItemProps): JSX.Elemen
|
|
|
744
836
|
};
|
|
745
837
|
|
|
746
838
|
createEffect(() => {
|
|
747
|
-
if (!
|
|
748
|
-
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
839
|
+
if (!sentinelRef || typeof IntersectionObserver !== "function") return;
|
|
840
|
+
|
|
841
|
+
const offset = props.scrollOffset ?? 1;
|
|
842
|
+
const margin = `0px 0px ${100 * offset}% 0px`;
|
|
843
|
+
const observer = new IntersectionObserver(
|
|
844
|
+
(entries) => {
|
|
845
|
+
if (entries[0]?.isIntersecting) {
|
|
846
|
+
void triggerLoadMore();
|
|
847
|
+
}
|
|
848
|
+
},
|
|
849
|
+
{ rootMargin: margin },
|
|
850
|
+
);
|
|
755
851
|
|
|
756
|
-
observer.observe(
|
|
852
|
+
observer.observe(sentinelRef);
|
|
757
853
|
return () => observer.disconnect();
|
|
758
854
|
});
|
|
759
855
|
|
|
760
856
|
const renderProps = useRenderProps(
|
|
761
857
|
{
|
|
762
|
-
children: props.children ?? (() => (isLoading() ?
|
|
858
|
+
children: props.children ?? (() => (isLoading() ? "Loading more..." : "Load more")),
|
|
763
859
|
class: props.class,
|
|
764
860
|
style: props.style,
|
|
765
|
-
defaultClassName:
|
|
861
|
+
defaultClassName: "solidaria-ListBox-loadMore",
|
|
766
862
|
},
|
|
767
|
-
() => ({ isLoading: isLoading() })
|
|
863
|
+
() => ({ isLoading: isLoading() }),
|
|
768
864
|
);
|
|
769
865
|
|
|
770
866
|
return (
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
867
|
+
<>
|
|
868
|
+
<li style={{ position: "relative", width: 0, height: 0, overflow: "hidden" }} inert>
|
|
869
|
+
<div ref={sentinelRef} style={{ position: "absolute", height: "1px", width: "1px" }} />
|
|
870
|
+
</li>
|
|
871
|
+
<li
|
|
872
|
+
role="option"
|
|
873
|
+
aria-disabled={true}
|
|
874
|
+
tabIndex={0}
|
|
875
|
+
onFocus={() => {
|
|
876
|
+
void triggerLoadMore();
|
|
877
|
+
}}
|
|
878
|
+
class={renderProps.class()}
|
|
879
|
+
style={renderProps.style()}
|
|
880
|
+
data-loading={isLoading() || undefined}
|
|
881
|
+
>
|
|
882
|
+
{renderProps.renderChildren()}
|
|
883
|
+
</li>
|
|
884
|
+
</>
|
|
785
885
|
);
|
|
786
886
|
}
|
|
787
887
|
|
|
@@ -792,6 +892,5 @@ export function ListBoxSection(props: ListBoxSectionProps): JSX.Element {
|
|
|
792
892
|
return <Section {...props} />;
|
|
793
893
|
}
|
|
794
894
|
|
|
795
|
-
// Attach Option as a static property
|
|
796
895
|
ListBox.Option = ListBoxOption;
|
|
797
896
|
ListBox.LoadMoreItem = ListBoxLoadMoreItem;
|