@proyecto-viviana/solidaria-components 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ActionBar.js +184 -0
- package/dist/ActionBar.js.map +1 -0
- package/dist/ActionBar.jsx +128 -0
- package/dist/ActionBar.jsx.map +1 -0
- package/dist/ActionGroup.js +179 -0
- package/dist/ActionGroup.js.map +1 -0
- package/dist/ActionGroup.jsx +129 -0
- package/dist/ActionGroup.jsx.map +1 -0
- package/dist/Alert.js +111 -0
- package/dist/Alert.js.map +1 -0
- package/dist/Alert.jsx +82 -0
- package/dist/Alert.jsx.map +1 -0
- package/dist/Autocomplete.js +130 -0
- package/dist/Autocomplete.js.map +1 -0
- package/dist/Autocomplete.jsx +116 -0
- package/dist/Autocomplete.jsx.map +1 -0
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Breadcrumbs.js +334 -0
- package/dist/Breadcrumbs.js.map +1 -0
- package/dist/Breadcrumbs.jsx +266 -0
- package/dist/Breadcrumbs.jsx.map +1 -0
- package/dist/Button.d.ts.map +1 -1
- package/dist/Button.js +348 -0
- package/dist/Button.js.map +1 -0
- package/dist/Button.jsx +314 -0
- package/dist/Button.jsx.map +1 -0
- package/dist/Calendar.d.ts +4 -4
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Calendar.js +538 -0
- package/dist/Calendar.js.map +1 -0
- package/dist/Calendar.jsx +333 -0
- package/dist/Calendar.jsx.map +1 -0
- package/dist/CalendarPicker.d.ts +33 -0
- package/dist/CalendarPicker.d.ts.map +1 -0
- package/dist/CalendarPicker.js +44 -0
- package/dist/CalendarPicker.js.map +1 -0
- package/dist/CalendarPicker.jsx +44 -0
- package/dist/CalendarPicker.jsx.map +1 -0
- package/dist/Checkbox.d.ts +83 -4
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Checkbox.js +923 -0
- package/dist/Checkbox.js.map +1 -0
- package/dist/Checkbox.jsx +707 -0
- package/dist/Checkbox.jsx.map +1 -0
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +202 -0
- package/dist/Collection.js.map +1 -0
- package/dist/Collection.jsx +152 -0
- package/dist/Collection.jsx.map +1 -0
- package/dist/Color.d.ts.map +1 -1
- package/dist/Color.js +1720 -0
- package/dist/Color.js.map +1 -0
- package/dist/Color.jsx +1344 -0
- package/dist/Color.jsx.map +1 -0
- package/dist/ColorEditor.js +208 -0
- package/dist/ColorEditor.js.map +1 -0
- package/dist/ColorEditor.jsx +120 -0
- package/dist/ColorEditor.jsx.map +1 -0
- package/dist/ComboBox.d.ts +8 -5
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ComboBox.js +992 -0
- package/dist/ComboBox.js.map +1 -0
- package/dist/ComboBox.jsx +714 -0
- package/dist/ComboBox.jsx.map +1 -0
- package/dist/ContextualHelpTrigger.js +146 -0
- package/dist/ContextualHelpTrigger.js.map +1 -0
- package/dist/ContextualHelpTrigger.jsx +109 -0
- package/dist/ContextualHelpTrigger.jsx.map +1 -0
- package/dist/DateField.d.ts +3 -3
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DateField.js +4 -0
- package/dist/DateField.jsx +4 -0
- package/dist/DateField2.js +499 -0
- package/dist/DateField2.js.map +1 -0
- package/dist/DateField2.jsx +317 -0
- package/dist/DateField2.jsx.map +1 -0
- package/dist/DatePicker.d.ts +4 -4
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/DatePicker.js +991 -0
- package/dist/DatePicker.js.map +1 -0
- package/dist/DatePicker.jsx +682 -0
- package/dist/DatePicker.jsx.map +1 -0
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Dialog.js +337 -0
- package/dist/Dialog.js.map +1 -0
- package/dist/Dialog.jsx +192 -0
- package/dist/Dialog.jsx.map +1 -0
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/Disclosure.js +328 -0
- package/dist/Disclosure.js.map +1 -0
- package/dist/Disclosure.jsx +230 -0
- package/dist/Disclosure.jsx.map +1 -0
- package/dist/DragAndDrop.d.ts.map +1 -1
- package/dist/DragAndDrop.js +176 -0
- package/dist/DragAndDrop.js.map +1 -0
- package/dist/DragAndDrop.jsx +160 -0
- package/dist/DragAndDrop.jsx.map +1 -0
- package/dist/DropZone.d.ts.map +1 -1
- package/dist/DropZone.js +189 -0
- package/dist/DropZone.js.map +1 -0
- package/dist/DropZone.jsx +144 -0
- package/dist/DropZone.jsx.map +1 -0
- package/dist/FieldError.js +66 -0
- package/dist/FieldError.js.map +1 -0
- package/dist/FieldError.jsx +47 -0
- package/dist/FieldError.jsx.map +1 -0
- package/dist/FileTrigger.js +79 -0
- package/dist/FileTrigger.js.map +1 -0
- package/dist/FileTrigger.jsx +49 -0
- package/dist/FileTrigger.jsx.map +1 -0
- package/dist/Focusable.js +70 -0
- package/dist/Focusable.js.map +1 -0
- package/dist/Focusable.jsx +69 -0
- package/dist/Focusable.jsx.map +1 -0
- package/dist/Form.js +99 -0
- package/dist/Form.js.map +1 -0
- package/dist/Form.jsx +73 -0
- package/dist/Form.jsx.map +1 -0
- package/dist/GridList.d.ts +34 -2
- package/dist/GridList.d.ts.map +1 -1
- package/dist/GridList.js +723 -0
- package/dist/GridList.js.map +1 -0
- package/dist/GridList.jsx +552 -0
- package/dist/GridList.jsx.map +1 -0
- package/dist/HiddenTimeInput.js +104 -0
- package/dist/HiddenTimeInput.js.map +1 -0
- package/dist/HiddenTimeInput.jsx +69 -0
- package/dist/HiddenTimeInput.jsx.map +1 -0
- package/dist/Icon.d.ts.map +1 -1
- package/dist/Icon.js +127 -0
- package/dist/Icon.js.map +1 -0
- package/dist/Icon.jsx +72 -0
- package/dist/Icon.jsx.map +1 -0
- package/dist/Keyboard.js +30 -0
- package/dist/Keyboard.js.map +1 -0
- package/dist/Keyboard.jsx +24 -0
- package/dist/Keyboard.jsx.map +1 -0
- package/dist/Landmark.js +134 -0
- package/dist/Landmark.js.map +1 -0
- package/dist/Landmark.jsx +118 -0
- package/dist/Landmark.jsx.map +1 -0
- package/dist/Link.d.ts.map +1 -1
- package/dist/Link.js +219 -0
- package/dist/Link.js.map +1 -0
- package/dist/Link.jsx +189 -0
- package/dist/Link.jsx.map +1 -0
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListBox.js +670 -0
- package/dist/ListBox.js.map +1 -0
- package/dist/ListBox.jsx +508 -0
- package/dist/ListBox.jsx.map +1 -0
- package/dist/Menu.d.ts +27 -9
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Menu.js +1254 -0
- package/dist/Menu.js.map +1 -0
- package/dist/Menu.jsx +1042 -0
- package/dist/Menu.jsx.map +1 -0
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Meter.js +123 -0
- package/dist/Meter.js.map +1 -0
- package/dist/Meter.jsx +107 -0
- package/dist/Meter.jsx.map +1 -0
- package/dist/Modal.d.ts.map +1 -1
- package/dist/Modal.js +380 -0
- package/dist/Modal.js.map +1 -0
- package/dist/Modal.jsx +314 -0
- package/dist/Modal.jsx.map +1 -0
- package/dist/NumberField.d.ts +3 -3
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/NumberField.js +573 -0
- package/dist/NumberField.js.map +1 -0
- package/dist/NumberField.jsx +443 -0
- package/dist/NumberField.jsx.map +1 -0
- package/dist/Popover.d.ts +10 -2
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Popover.js +464 -0
- package/dist/Popover.js.map +1 -0
- package/dist/Popover.jsx +333 -0
- package/dist/Popover.jsx.map +1 -0
- package/dist/Pressable.js +69 -0
- package/dist/Pressable.js.map +1 -0
- package/dist/Pressable.jsx +68 -0
- package/dist/Pressable.jsx.map +1 -0
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar.js +130 -0
- package/dist/ProgressBar.js.map +1 -0
- package/dist/ProgressBar.jsx +114 -0
- package/dist/ProgressBar.jsx.map +1 -0
- package/dist/RadioGroup.d.ts +82 -4
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RadioGroup.js +931 -0
- package/dist/RadioGroup.js.map +1 -0
- package/dist/RadioGroup.jsx +681 -0
- package/dist/RadioGroup.jsx.map +1 -0
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RangeCalendar.js +410 -0
- package/dist/RangeCalendar.js.map +1 -0
- package/dist/RangeCalendar.jsx +253 -0
- package/dist/RangeCalendar.jsx.map +1 -0
- package/dist/RouterProvider.js +118 -0
- package/dist/RouterProvider.js.map +1 -0
- package/dist/RouterProvider.jsx +112 -0
- package/dist/RouterProvider.jsx.map +1 -0
- package/dist/SearchField.d.ts +2 -2
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/SearchField.js +643 -0
- package/dist/SearchField.js.map +1 -0
- package/dist/SearchField.jsx +526 -0
- package/dist/SearchField.jsx.map +1 -0
- package/dist/Select.d.ts.map +1 -1
- package/dist/Select.js +1031 -0
- package/dist/Select.js.map +1 -0
- package/dist/Select.jsx +744 -0
- package/dist/Select.jsx.map +1 -0
- package/dist/SelectionIndicator.d.ts.map +1 -1
- package/dist/SelectionIndicator.js +86 -0
- package/dist/SelectionIndicator.js.map +1 -0
- package/dist/SelectionIndicator.jsx +50 -0
- package/dist/SelectionIndicator.jsx.map +1 -0
- package/dist/Separator.js +97 -0
- package/dist/Separator.js.map +1 -0
- package/dist/Separator.jsx +85 -0
- package/dist/Separator.jsx.map +1 -0
- package/dist/SharedElementTransition.d.ts.map +1 -1
- package/dist/SharedElementTransition.js +165 -0
- package/dist/SharedElementTransition.js.map +1 -0
- package/dist/SharedElementTransition.jsx +138 -0
- package/dist/SharedElementTransition.jsx.map +1 -0
- package/dist/Slider.d.ts +33 -1
- package/dist/Slider.d.ts.map +1 -1
- package/dist/Slider.js +515 -0
- package/dist/Slider.js.map +1 -0
- package/dist/Slider.jsx +403 -0
- package/dist/Slider.jsx.map +1 -0
- package/dist/StepList.js +198 -0
- package/dist/StepList.js.map +1 -0
- package/dist/StepList.jsx +141 -0
- package/dist/StepList.jsx.map +1 -0
- package/dist/Switch.d.ts +65 -2
- package/dist/Switch.d.ts.map +1 -1
- package/dist/Switch.js +534 -0
- package/dist/Switch.js.map +1 -0
- package/dist/Switch.jsx +393 -0
- package/dist/Switch.jsx.map +1 -0
- package/dist/Table.d.ts +48 -0
- package/dist/Table.d.ts.map +1 -1
- package/dist/Table.js +1759 -0
- package/dist/Table.js.map +1 -0
- package/dist/Table.jsx +1348 -0
- package/dist/Table.jsx.map +1 -0
- package/dist/Tabs.d.ts +0 -4
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/Tabs.js +595 -0
- package/dist/Tabs.js.map +1 -0
- package/dist/Tabs.jsx +367 -0
- package/dist/Tabs.jsx.map +1 -0
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/TagGroup.js +378 -0
- package/dist/TagGroup.js.map +1 -0
- package/dist/TagGroup.jsx +270 -0
- package/dist/TagGroup.jsx.map +1 -0
- package/dist/Text.d.ts +18 -6
- package/dist/Text.d.ts.map +1 -1
- package/dist/Text.js +42 -0
- package/dist/Text.js.map +1 -0
- package/dist/Text.jsx +35 -0
- package/dist/Text.jsx.map +1 -0
- package/dist/TextField.d.ts +7 -6
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TextField.js +436 -0
- package/dist/TextField.js.map +1 -0
- package/dist/TextField.jsx +403 -0
- package/dist/TextField.jsx.map +1 -0
- package/dist/TimeField.d.ts +3 -3
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/TimeField.js +372 -0
- package/dist/TimeField.js.map +1 -0
- package/dist/TimeField.jsx +224 -0
- package/dist/TimeField.jsx.map +1 -0
- package/dist/Toast.d.ts +14 -0
- package/dist/Toast.d.ts.map +1 -1
- package/dist/Toast.js +551 -0
- package/dist/Toast.js.map +1 -0
- package/dist/Toast.jsx +361 -0
- package/dist/Toast.jsx.map +1 -0
- package/dist/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton.js +123 -0
- package/dist/ToggleButton.js.map +1 -0
- package/dist/ToggleButton.jsx +88 -0
- package/dist/ToggleButton.jsx.map +1 -0
- package/dist/ToggleButtonGroup.d.ts.map +1 -1
- package/dist/ToggleButtonGroup.js +114 -0
- package/dist/ToggleButtonGroup.js.map +1 -0
- package/dist/ToggleButtonGroup.jsx +85 -0
- package/dist/ToggleButtonGroup.jsx.map +1 -0
- package/dist/Toolbar.js +112 -0
- package/dist/Toolbar.js.map +1 -0
- package/dist/Toolbar.jsx +92 -0
- package/dist/Toolbar.jsx.map +1 -0
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip.js +539 -0
- package/dist/Tooltip.js.map +1 -0
- package/dist/Tooltip.jsx +465 -0
- package/dist/Tooltip.jsx.map +1 -0
- package/dist/Tree.d.ts +14 -2
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Tree.js +1424 -0
- package/dist/Tree.js.map +1 -0
- package/dist/Tree.jsx +1172 -0
- package/dist/Tree.jsx.map +1 -0
- package/dist/Virtualizer.d.ts +16 -2
- package/dist/Virtualizer.d.ts.map +1 -1
- package/dist/Virtualizer.js +2 -0
- package/dist/Virtualizer.jsx +2 -0
- package/dist/Virtualizer2.js +751 -0
- package/dist/Virtualizer2.js.map +1 -0
- package/dist/Virtualizer2.jsx +730 -0
- package/dist/Virtualizer2.jsx.map +1 -0
- package/dist/VirtualizerLayouts.d.ts +18 -0
- package/dist/VirtualizerLayouts.d.ts.map +1 -1
- package/dist/VisuallyHidden.js +42 -0
- package/dist/VisuallyHidden.js.map +1 -0
- package/dist/VisuallyHidden.jsx +35 -0
- package/dist/VisuallyHidden.jsx.map +1 -0
- package/dist/contexts.js +33 -0
- package/dist/contexts.js.map +1 -0
- package/dist/contexts.jsx +33 -0
- package/dist/contexts.jsx.map +1 -0
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +70 -23711
- package/dist/index.jsx +70 -18116
- package/dist/useDragAndDrop.js +2 -0
- package/dist/useDragAndDrop.jsx +2 -0
- package/dist/useDragAndDrop2.js +395 -0
- package/dist/useDragAndDrop2.js.map +1 -0
- package/dist/useDragAndDrop2.jsx +395 -0
- package/dist/useDragAndDrop2.jsx.map +1 -0
- package/dist/utils.d.ts +83 -11
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +285 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.jsx +277 -0
- package/dist/utils.jsx.map +1 -0
- package/dist/virtualizer/Layout.js +144 -0
- package/dist/virtualizer/Layout.js.map +1 -0
- package/dist/virtualizer/Layout.jsx +144 -0
- package/dist/virtualizer/Layout.jsx.map +1 -0
- package/package.json +401 -4
- package/src/Breadcrumbs.tsx +3 -1
- package/src/Button.tsx +90 -23
- package/src/Calendar.tsx +27 -10
- package/src/CalendarPicker.tsx +73 -0
- package/src/Checkbox.tsx +539 -3
- package/src/Collection.tsx +9 -3
- package/src/Color.tsx +42 -14
- package/src/ComboBox.tsx +126 -14
- package/src/DateField.tsx +20 -2
- package/src/DatePicker.tsx +117 -10
- package/src/Dialog.tsx +13 -5
- package/src/Disclosure.tsx +3 -1
- package/src/DragAndDrop.tsx +3 -1
- package/src/DropZone.tsx +3 -1
- package/src/GridList.tsx +125 -24
- package/src/Icon.tsx +3 -1
- package/src/Link.tsx +3 -1
- package/src/ListBox.tsx +31 -4
- package/src/Menu.tsx +298 -131
- package/src/Meter.tsx +3 -1
- package/src/Modal.tsx +100 -52
- package/src/NumberField.tsx +73 -10
- package/src/Popover.tsx +49 -11
- package/src/ProgressBar.tsx +3 -1
- package/src/RadioGroup.tsx +468 -4
- package/src/RangeCalendar.tsx +3 -1
- package/src/SearchField.tsx +27 -3
- package/src/Select.tsx +22 -7
- package/src/SelectionIndicator.tsx +3 -1
- package/src/SharedElementTransition.tsx +3 -1
- package/src/Slider.tsx +159 -13
- package/src/Switch.tsx +395 -2
- package/src/Table.tsx +409 -95
- package/src/Tabs.tsx +16 -45
- package/src/TagGroup.tsx +4 -1
- package/src/Text.tsx +31 -10
- package/src/TextField.tsx +73 -10
- package/src/TimeField.tsx +20 -2
- package/src/Toast.tsx +79 -14
- package/src/ToggleButton.tsx +3 -1
- package/src/ToggleButtonGroup.tsx +3 -1
- package/src/Tooltip.tsx +55 -8
- package/src/Tree.tsx +77 -9
- package/src/Virtualizer.tsx +180 -31
- package/src/VirtualizerLayouts.ts +45 -10
- package/src/index.ts +50 -0
- package/src/utils.tsx +243 -27
- package/dist/index.js.map +0 -1
- package/dist/index.jsx.map +0 -1
package/src/Tooltip.tsx
CHANGED
|
@@ -226,6 +226,40 @@ const TriggerWrapper: ParentComponent<{
|
|
|
226
226
|
}> = (props) => {
|
|
227
227
|
const child = () => props.children as JSX.Element;
|
|
228
228
|
const [triggerElement, setTriggerElement] = createSignal<HTMLElement | null>(null);
|
|
229
|
+
const [wrapperElement, setWrapperElement] = createSignal<HTMLSpanElement | null>(null);
|
|
230
|
+
const getWrapperEventProps = () => {
|
|
231
|
+
const triggerProps = props.triggerProps as Record<string, unknown>;
|
|
232
|
+
const wrapperProps: Record<string, unknown> = {};
|
|
233
|
+
const eventPropNames = [
|
|
234
|
+
"onFocus",
|
|
235
|
+
"onBlur",
|
|
236
|
+
"onPointerEnter",
|
|
237
|
+
"onPointerLeave",
|
|
238
|
+
"onPointerOver",
|
|
239
|
+
"onPointerOut",
|
|
240
|
+
"onMouseEnter",
|
|
241
|
+
"onMouseLeave",
|
|
242
|
+
"onTouchStart",
|
|
243
|
+
"onPointerDown",
|
|
244
|
+
"onKeyDown",
|
|
245
|
+
];
|
|
246
|
+
|
|
247
|
+
for (const propName of eventPropNames) {
|
|
248
|
+
const handler = triggerProps[propName];
|
|
249
|
+
if (typeof handler === "function") {
|
|
250
|
+
wrapperProps[propName] = handler;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (!wrapperProps.onPointerEnter && typeof triggerProps.onMouseEnter === "function") {
|
|
255
|
+
wrapperProps.onPointerEnter = triggerProps.onMouseEnter;
|
|
256
|
+
}
|
|
257
|
+
if (!wrapperProps.onPointerLeave && typeof triggerProps.onMouseLeave === "function") {
|
|
258
|
+
wrapperProps.onPointerLeave = triggerProps.onMouseLeave;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return wrapperProps as JSX.HTMLAttributes<HTMLSpanElement>;
|
|
262
|
+
};
|
|
229
263
|
|
|
230
264
|
createEffect(() => {
|
|
231
265
|
const element = triggerElement();
|
|
@@ -241,7 +275,9 @@ const TriggerWrapper: ParentComponent<{
|
|
|
241
275
|
element.removeAttribute("aria-describedby");
|
|
242
276
|
}
|
|
243
277
|
|
|
244
|
-
const
|
|
278
|
+
const wrapper = wrapperElement();
|
|
279
|
+
const targets = Array.from(new Set([element, wrapper].filter(Boolean))) as HTMLElement[];
|
|
280
|
+
const listeners: Array<[HTMLElement, string, EventListener]> = [];
|
|
245
281
|
const eventProps = [
|
|
246
282
|
["onFocus", "focus"],
|
|
247
283
|
["onBlur", "blur"],
|
|
@@ -257,17 +293,24 @@ const TriggerWrapper: ParentComponent<{
|
|
|
257
293
|
] as const;
|
|
258
294
|
|
|
259
295
|
for (const [propName, eventName] of eventProps) {
|
|
260
|
-
|
|
296
|
+
let handler = triggerProps[propName];
|
|
297
|
+
if (!handler && propName === "onPointerEnter") {
|
|
298
|
+
handler = triggerProps.onMouseEnter;
|
|
299
|
+
} else if (!handler && propName === "onPointerLeave") {
|
|
300
|
+
handler = triggerProps.onMouseLeave;
|
|
301
|
+
}
|
|
261
302
|
if (typeof handler === "function") {
|
|
262
303
|
const listener = handler as EventListener;
|
|
263
|
-
|
|
264
|
-
|
|
304
|
+
for (const target of targets) {
|
|
305
|
+
target.addEventListener(eventName, listener);
|
|
306
|
+
listeners.push([target, eventName, listener]);
|
|
307
|
+
}
|
|
265
308
|
}
|
|
266
309
|
}
|
|
267
310
|
|
|
268
311
|
onCleanup(() => {
|
|
269
|
-
for (const [eventName, listener] of listeners) {
|
|
270
|
-
|
|
312
|
+
for (const [target, eventName, listener] of listeners) {
|
|
313
|
+
target.removeEventListener(eventName, listener);
|
|
271
314
|
}
|
|
272
315
|
if (describedBy && element.getAttribute("aria-describedby") === describedBy) {
|
|
273
316
|
element.removeAttribute("aria-describedby");
|
|
@@ -279,6 +322,8 @@ const TriggerWrapper: ParentComponent<{
|
|
|
279
322
|
// However, display:contents makes getBoundingClientRect return zeros,
|
|
280
323
|
// so we pass a ref callback that finds the first actual element child.
|
|
281
324
|
const handleRef = (span: HTMLSpanElement) => {
|
|
325
|
+
setWrapperElement(span);
|
|
326
|
+
|
|
282
327
|
const findElementChild = (el: Element): HTMLElement | null => {
|
|
283
328
|
for (const child of el.children) {
|
|
284
329
|
if (child instanceof HTMLElement) {
|
|
@@ -329,7 +374,7 @@ const TriggerWrapper: ParentComponent<{
|
|
|
329
374
|
};
|
|
330
375
|
|
|
331
376
|
return (
|
|
332
|
-
<span ref={handleRef} style={{ display: "contents" }}>
|
|
377
|
+
<span {...getWrapperEventProps()} ref={handleRef} style={{ display: "contents" }}>
|
|
333
378
|
{child()}
|
|
334
379
|
</span>
|
|
335
380
|
);
|
|
@@ -529,7 +574,9 @@ function TooltipContent(
|
|
|
529
574
|
{
|
|
530
575
|
class: props.class,
|
|
531
576
|
style: props.style,
|
|
532
|
-
children
|
|
577
|
+
get children() {
|
|
578
|
+
return props.children;
|
|
579
|
+
},
|
|
533
580
|
defaultClassName: "solidaria-Tooltip",
|
|
534
581
|
},
|
|
535
582
|
values,
|
package/src/Tree.tsx
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
createTree,
|
|
25
25
|
createTreeItem,
|
|
26
26
|
createTreeSelectionCheckbox,
|
|
27
|
+
createGridListSection,
|
|
27
28
|
createFocusRing,
|
|
28
29
|
createHover,
|
|
29
30
|
mergeProps,
|
|
@@ -60,14 +61,17 @@ import {
|
|
|
60
61
|
CollectionRendererContext,
|
|
61
62
|
flattenCollectionEntries,
|
|
62
63
|
isCollectionSection,
|
|
63
|
-
Section,
|
|
64
|
-
Header,
|
|
65
64
|
type CollectionEntry,
|
|
66
65
|
type CollectionRendererContextValue,
|
|
67
66
|
type SectionProps,
|
|
68
|
-
type HeaderProps,
|
|
69
67
|
useCollectionRenderer,
|
|
70
68
|
} from "./Collection";
|
|
69
|
+
import {
|
|
70
|
+
GridListHeader,
|
|
71
|
+
GridListHeaderContext,
|
|
72
|
+
GridListHeaderInnerContext,
|
|
73
|
+
type GridListHeaderProps,
|
|
74
|
+
} from "./GridList";
|
|
71
75
|
import { useVirtualizerContext } from "./Virtualizer";
|
|
72
76
|
import {
|
|
73
77
|
handleLinkClick,
|
|
@@ -242,7 +246,7 @@ export interface TreeLoadMoreItemProps extends SlotProps {
|
|
|
242
246
|
}
|
|
243
247
|
|
|
244
248
|
export interface TreeSectionProps extends SectionProps {}
|
|
245
|
-
export interface TreeHeaderProps extends
|
|
249
|
+
export interface TreeHeaderProps extends GridListHeaderProps {}
|
|
246
250
|
|
|
247
251
|
interface TreeContextValue<T extends object> {
|
|
248
252
|
state: TreeState<T, TreeCollection<T>>;
|
|
@@ -891,6 +895,7 @@ export function Tree<T extends object>(props: TreeProps<T>): JSX.Element {
|
|
|
891
895
|
isVirtualized: ariaProps.isVirtualized,
|
|
892
896
|
onAction: ariaProps.onAction,
|
|
893
897
|
isDisabled: ariaProps.isDisabled,
|
|
898
|
+
keyboardNavigationBehavior: ariaProps.keyboardNavigationBehavior,
|
|
894
899
|
direction: treeDirection(),
|
|
895
900
|
}),
|
|
896
901
|
() => state,
|
|
@@ -1565,7 +1570,9 @@ export function TreeItem<T extends object>(props: TreeItemProps<T>): JSX.Element
|
|
|
1565
1570
|
|
|
1566
1571
|
const renderProps = useRenderProps(
|
|
1567
1572
|
{
|
|
1568
|
-
children
|
|
1573
|
+
get children() {
|
|
1574
|
+
return props.children;
|
|
1575
|
+
},
|
|
1569
1576
|
class: local.class,
|
|
1570
1577
|
style: local.style,
|
|
1571
1578
|
defaultClassName: "solidaria-Tree-item",
|
|
@@ -1805,7 +1812,9 @@ export function TreeLoadMoreItem(props: TreeLoadMoreItemProps): JSX.Element {
|
|
|
1805
1812
|
|
|
1806
1813
|
const renderProps = useRenderProps(
|
|
1807
1814
|
{
|
|
1808
|
-
|
|
1815
|
+
get children() {
|
|
1816
|
+
return props.children ?? (() => (isLoading() ? "Loading more..." : "Load more"));
|
|
1817
|
+
},
|
|
1809
1818
|
class: props.class,
|
|
1810
1819
|
style: props.style,
|
|
1811
1820
|
defaultClassName: "solidaria-Tree-loadMore",
|
|
@@ -1858,7 +1867,9 @@ export function TreeItemContent(props: TreeItemContentProps): JSX.Element {
|
|
|
1858
1867
|
|
|
1859
1868
|
const renderProps = useRenderProps(
|
|
1860
1869
|
{
|
|
1861
|
-
children
|
|
1870
|
+
get children() {
|
|
1871
|
+
return props.children;
|
|
1872
|
+
},
|
|
1862
1873
|
},
|
|
1863
1874
|
() => context,
|
|
1864
1875
|
);
|
|
@@ -1866,12 +1877,69 @@ export function TreeItemContent(props: TreeItemContentProps): JSX.Element {
|
|
|
1866
1877
|
return <>{renderProps.renderChildren()}</>;
|
|
1867
1878
|
}
|
|
1868
1879
|
|
|
1880
|
+
/**
|
|
1881
|
+
* A section within a Tree. Renders as `role="rowgroup"` and supplies its
|
|
1882
|
+
* optional {@link TreeHeader} with the row/rowheader props that wire up the
|
|
1883
|
+
* section's `aria-labelledby` (mirrors upstream `TreeSection`, which reuses
|
|
1884
|
+
* `useGridListSection`).
|
|
1885
|
+
*/
|
|
1869
1886
|
export function TreeSection(props: TreeSectionProps): JSX.Element {
|
|
1870
|
-
|
|
1887
|
+
const [local, domProps] = splitProps(props, ["children", "class", "style", "slot", "ref"]);
|
|
1888
|
+
|
|
1889
|
+
const section = createGridListSection({
|
|
1890
|
+
get "aria-label"() {
|
|
1891
|
+
return (domProps as { "aria-label"?: string })["aria-label"];
|
|
1892
|
+
},
|
|
1893
|
+
});
|
|
1894
|
+
|
|
1895
|
+
// Mirror upstream: resolve class/style via renderProps but keep children out
|
|
1896
|
+
// of it. The real children must only be evaluated inside the header providers
|
|
1897
|
+
// below, otherwise a child <TreeHeader> would be instantiated in this
|
|
1898
|
+
// component's owner and read the header contexts as null. The values callback
|
|
1899
|
+
// runs during setup, so it must not read `local.children` either; mirror
|
|
1900
|
+
// upstream's `values: undefined` with a constant.
|
|
1901
|
+
const renderProps = useRenderProps(
|
|
1902
|
+
{
|
|
1903
|
+
children: undefined,
|
|
1904
|
+
class: local.class,
|
|
1905
|
+
style: local.style,
|
|
1906
|
+
defaultClassName: "solidaria-TreeSection",
|
|
1907
|
+
},
|
|
1908
|
+
() => ({ hasChildren: true }),
|
|
1909
|
+
);
|
|
1910
|
+
|
|
1911
|
+
const filteredDomProps = createMemo(() => filterDOMProps(domProps, { global: true }));
|
|
1912
|
+
|
|
1913
|
+
return (
|
|
1914
|
+
<div
|
|
1915
|
+
ref={(el) => assignRef(local.ref, el)}
|
|
1916
|
+
{...filteredDomProps()}
|
|
1917
|
+
{...section.rowGroupProps}
|
|
1918
|
+
class={renderProps.class()}
|
|
1919
|
+
style={renderProps.style()}
|
|
1920
|
+
slot={local.slot}
|
|
1921
|
+
data-section
|
|
1922
|
+
>
|
|
1923
|
+
<GridListHeaderContext.Provider value={section.rowProps}>
|
|
1924
|
+
<GridListHeaderInnerContext.Provider value={section.rowHeaderProps}>
|
|
1925
|
+
{local.children}
|
|
1926
|
+
</GridListHeaderInnerContext.Provider>
|
|
1927
|
+
</GridListHeaderContext.Provider>
|
|
1928
|
+
</div>
|
|
1929
|
+
);
|
|
1871
1930
|
}
|
|
1872
1931
|
|
|
1932
|
+
/**
|
|
1933
|
+
* The header of a {@link TreeSection}. Mirrors upstream `TreeHeader`, which is a
|
|
1934
|
+
* thin wrapper over `GridListHeader` with a Tree-specific class. The row and
|
|
1935
|
+
* rowheader semantics come from the enclosing section through context.
|
|
1936
|
+
*/
|
|
1873
1937
|
export function TreeHeader(props: TreeHeaderProps): JSX.Element {
|
|
1874
|
-
return
|
|
1938
|
+
return (
|
|
1939
|
+
<GridListHeader class="solidaria-TreeHeader" {...props}>
|
|
1940
|
+
{props.children}
|
|
1941
|
+
</GridListHeader>
|
|
1942
|
+
);
|
|
1875
1943
|
}
|
|
1876
1944
|
|
|
1877
1945
|
Tree.Item = TreeItem;
|
package/src/Virtualizer.tsx
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
type DefaultVirtualizerLayoutOptions,
|
|
33
33
|
type GridLayoutOptions,
|
|
34
34
|
type LayoutInfo,
|
|
35
|
+
type Orientation,
|
|
35
36
|
type Point,
|
|
36
37
|
type Rect,
|
|
37
38
|
type Size,
|
|
@@ -70,6 +71,13 @@ export interface VirtualizerContextValue<O = unknown> {
|
|
|
70
71
|
layout: VirtualizerLayout<O>;
|
|
71
72
|
layoutOptions?: O;
|
|
72
73
|
isVirtualized: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* The resolved primary orientation of the layout. Consumers render their
|
|
76
|
+
* windowing spacers along this axis (`width` when `horizontal`, `height`
|
|
77
|
+
* when `vertical`) so the spacer size matches the offsets `getVisibleRange`
|
|
78
|
+
* produced.
|
|
79
|
+
*/
|
|
80
|
+
orientation: Orientation;
|
|
73
81
|
getVisibleRange: (itemCount: number) => VirtualizerVisibleRange;
|
|
74
82
|
getLayoutInfo: (index: number) => LayoutInfo;
|
|
75
83
|
getDropTargetFromPoint: (point: Point, itemCount: number) => VirtualizerDropTarget | null;
|
|
@@ -117,6 +125,13 @@ export interface VirtualizerProps<O> extends Omit<
|
|
|
117
125
|
) => JSX.Element | undefined;
|
|
118
126
|
/** Optional operation resolver for collection drop target operations. */
|
|
119
127
|
getDropOperation?: VirtualizerDropOperationResolver;
|
|
128
|
+
/**
|
|
129
|
+
* Whether the collection may scroll with the page rather than only within its
|
|
130
|
+
* own scroll container. When enabled (the default, matching react-aria-components),
|
|
131
|
+
* the visible rect is the intersection of the window viewport with the scroll view,
|
|
132
|
+
* so a virtualizer with unbounded height still virtualizes as the page scrolls.
|
|
133
|
+
*/
|
|
134
|
+
allowsWindowScrolling?: boolean;
|
|
120
135
|
class?: string;
|
|
121
136
|
style?: string | JSX.CSSProperties;
|
|
122
137
|
}
|
|
@@ -159,12 +174,29 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
159
174
|
"layoutOptions",
|
|
160
175
|
"renderDropIndicator",
|
|
161
176
|
"getDropOperation",
|
|
177
|
+
"allowsWindowScrolling",
|
|
162
178
|
"class",
|
|
163
179
|
"style",
|
|
164
180
|
]);
|
|
181
|
+
// The scroll view's own scroll position (its scrollTop).
|
|
165
182
|
const [scrollOffset, setScrollOffset] = createSignal(0);
|
|
183
|
+
// The scroll view's horizontal scroll position (its scrollLeft), used as the
|
|
184
|
+
// primary scroll axis when the layout's orientation is horizontal.
|
|
185
|
+
const [scrollOffsetX, setScrollOffsetX] = createSignal(0);
|
|
186
|
+
// How far the scroll view's top edge is above the window viewport, due to the
|
|
187
|
+
// page (or an ancestor) being scrolled. Mirrors upstream ScrollView.viewportOffset.
|
|
188
|
+
const [viewportOffset, setViewportOffset] = createSignal(0);
|
|
189
|
+
// The window viewport height, used as the visible height cap when window scrolling.
|
|
190
|
+
const [windowViewportSize, setWindowViewportSize] = createSignal(0);
|
|
191
|
+
// The scroll view's own measured size (clientHeight/clientWidth).
|
|
166
192
|
const [measuredViewportSize, setMeasuredViewportSize] = createSignal(0);
|
|
167
193
|
const [measuredViewportWidth, setMeasuredViewportWidth] = createSignal(0);
|
|
194
|
+
const allowsWindowScrolling = createMemo(() => local.allowsWindowScrolling ?? true);
|
|
195
|
+
// Whether the scroll view is actively scrolling. Mirrors upstream ScrollView's
|
|
196
|
+
// `isScrolling`: while scrolling, the content gets `pointer-events: none` so pointer
|
|
197
|
+
// events don't hit rows recycling under a stationary cursor (avoiding hover-state
|
|
198
|
+
// flicker and needless hit-testing). It flips back 300ms after the last scroll.
|
|
199
|
+
const [isScrolling, setIsScrolling] = createSignal(false);
|
|
168
200
|
const [dropTargetResolver, setDropTargetResolver] = createSignal<
|
|
169
201
|
VirtualizerDropTargetResolver | undefined
|
|
170
202
|
>(undefined);
|
|
@@ -218,15 +250,44 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
218
250
|
});
|
|
219
251
|
const itemSize = createMemo(() => getObjectValue(virtualOptions(), "itemSize") ?? 40);
|
|
220
252
|
const overscan = createMemo(() => getObjectValue(virtualOptions(), "overscan") ?? 2);
|
|
221
|
-
const
|
|
222
|
-
() => getObjectValue(virtualOptions(), "
|
|
253
|
+
const orientation = createMemo<Orientation>(
|
|
254
|
+
() => getObjectValue(virtualOptions(), "orientation") ?? "vertical",
|
|
223
255
|
);
|
|
256
|
+
// The effective visible height. When window scrolling, this is the scroll view's
|
|
257
|
+
// size intersected with the window viewport (capped to what is actually on screen),
|
|
258
|
+
// mirroring upstream ScrollView.updateVisibleRect. Otherwise it is the scroll view's
|
|
259
|
+
// own clientHeight. An explicit `viewportSize` layout option still takes precedence.
|
|
260
|
+
const viewportSize = createMemo(() => {
|
|
261
|
+
const explicit = getObjectValue(virtualOptions(), "viewportSize");
|
|
262
|
+
if (explicit != null) return explicit;
|
|
263
|
+
const elementSize = measuredViewportSize() ?? 0;
|
|
264
|
+
if (allowsWindowScrolling()) {
|
|
265
|
+
return Math.max(0, Math.min(elementSize - viewportOffset(), windowViewportSize()));
|
|
266
|
+
}
|
|
267
|
+
return elementSize;
|
|
268
|
+
});
|
|
269
|
+
// The top of the visible rect in content coordinates: the scroll view's own scroll
|
|
270
|
+
// position plus how far it has been pushed above the window viewport by page scroll.
|
|
271
|
+
const effectiveScrollOffset = createMemo(() =>
|
|
272
|
+
allowsWindowScrolling() ? scrollOffset() + viewportOffset() : scrollOffset(),
|
|
273
|
+
);
|
|
274
|
+
// The primary-axis scroll offset and viewport size, selected by orientation.
|
|
275
|
+
// A horizontal layout scrolls along x (scrollLeft / client width); the vertical
|
|
276
|
+
// default scrolls along y (with the window-scrolling adjustments above).
|
|
277
|
+
const mainScrollOffset = createMemo(() =>
|
|
278
|
+
orientation() === "horizontal" ? scrollOffsetX() : effectiveScrollOffset(),
|
|
279
|
+
);
|
|
280
|
+
const mainViewportSize = createMemo(() => {
|
|
281
|
+
if (orientation() !== "horizontal") return viewportSize();
|
|
282
|
+
const explicit = getObjectValue(virtualOptions(), "viewportSize");
|
|
283
|
+
return explicit != null ? explicit : measuredViewportWidth();
|
|
284
|
+
});
|
|
224
285
|
|
|
225
286
|
const getVisibleRange = (itemCount: number): VirtualizerVisibleRange => {
|
|
226
287
|
const ctx: VirtualizerRangeContext = {
|
|
227
288
|
itemCount,
|
|
228
|
-
scrollOffset:
|
|
229
|
-
viewportSize:
|
|
289
|
+
scrollOffset: mainScrollOffset(),
|
|
290
|
+
viewportSize: mainViewportSize(),
|
|
230
291
|
overscan: overscan(),
|
|
231
292
|
viewportWidth: measuredViewportWidth(),
|
|
232
293
|
};
|
|
@@ -250,18 +311,32 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
250
311
|
const getLayoutInfo = (index: number): LayoutInfo => {
|
|
251
312
|
const ctx: VirtualizerLayoutInfoContext = {
|
|
252
313
|
viewportWidth: measuredViewportWidth(),
|
|
314
|
+
viewportHeight: measuredViewportSize(),
|
|
253
315
|
};
|
|
254
316
|
const layoutResult = resolvedLayout().getLayoutInfo?.(index, ctx, layoutOptionsWithViewport());
|
|
255
|
-
const nextInfo =
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
317
|
+
const nextInfo =
|
|
318
|
+
layoutResult ??
|
|
319
|
+
(orientation() === "horizontal"
|
|
320
|
+
? {
|
|
321
|
+
key: String(index),
|
|
322
|
+
index,
|
|
323
|
+
rect: {
|
|
324
|
+
x: index * itemSize(),
|
|
325
|
+
y: 0,
|
|
326
|
+
width: itemSize(),
|
|
327
|
+
height: Math.max(0, measuredViewportSize()),
|
|
328
|
+
},
|
|
329
|
+
}
|
|
330
|
+
: {
|
|
331
|
+
key: String(index),
|
|
332
|
+
index,
|
|
333
|
+
rect: {
|
|
334
|
+
x: 0,
|
|
335
|
+
y: index * itemSize(),
|
|
336
|
+
width: Math.max(0, measuredViewportWidth()),
|
|
337
|
+
height: itemSize(),
|
|
338
|
+
},
|
|
339
|
+
});
|
|
265
340
|
const cachedInfo = layoutInfoCache.get(index);
|
|
266
341
|
if (cachedInfo && isSameLayoutInfo(cachedInfo, nextInfo)) {
|
|
267
342
|
return cachedInfo;
|
|
@@ -566,7 +641,7 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
566
641
|
: direction === "next"
|
|
567
642
|
? -1
|
|
568
643
|
: itemCount;
|
|
569
|
-
const pageSize = Math.max(1, Math.floor(
|
|
644
|
+
const pageSize = Math.max(1, Math.floor(mainViewportSize() / Math.max(1, itemSize())));
|
|
570
645
|
const delta = direction === "next" ? 1 : -1;
|
|
571
646
|
const nextStart = currentIndex + delta * pageSize;
|
|
572
647
|
const clampedStart = Math.max(0, Math.min(itemCount - 1, nextStart));
|
|
@@ -633,6 +708,7 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
633
708
|
layout: resolvedLayout(),
|
|
634
709
|
layoutOptions: resolvedLayoutOptions(),
|
|
635
710
|
isVirtualized: true,
|
|
711
|
+
orientation: orientation(),
|
|
636
712
|
getVisibleRange,
|
|
637
713
|
getLayoutInfo,
|
|
638
714
|
getDropTargetFromPoint,
|
|
@@ -666,26 +742,96 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
666
742
|
if (nextWidth !== measuredViewportWidth()) setMeasuredViewportWidth(nextWidth);
|
|
667
743
|
};
|
|
668
744
|
|
|
745
|
+
const updateWindowViewport = () => {
|
|
746
|
+
if (typeof window === "undefined") return;
|
|
747
|
+
const next = window.innerHeight;
|
|
748
|
+
if (next !== windowViewportSize()) setWindowViewportSize(next);
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
// Recompute how far the scroll view's top edge sits above the window viewport.
|
|
752
|
+
// A negative bounding-rect top means the scroll view has been pushed up by page
|
|
753
|
+
// (or ancestor) scrolling; the offset is the amount scrolled past its top.
|
|
754
|
+
const updateViewportOffset = () => {
|
|
755
|
+
if (!containerRef || !allowsWindowScrolling()) return;
|
|
756
|
+
const rect = containerRef.getBoundingClientRect();
|
|
757
|
+
const next = rect.y < 0 ? -rect.y : 0;
|
|
758
|
+
if (next !== viewportOffset()) setViewportOffset(next);
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
let scrollFrame: number | undefined;
|
|
762
|
+
// Debounce handle that resets `isScrolling` after scrolling stops.
|
|
763
|
+
let scrollEndTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
764
|
+
onCleanup(() => {
|
|
765
|
+
if (scrollFrame != null) cancelAnimationFrame(scrollFrame);
|
|
766
|
+
if (scrollEndTimeout != null) clearTimeout(scrollEndTimeout);
|
|
767
|
+
});
|
|
768
|
+
|
|
669
769
|
onMount(() => {
|
|
670
770
|
updateViewportSize();
|
|
671
|
-
|
|
771
|
+
updateWindowViewport();
|
|
772
|
+
updateViewportOffset();
|
|
773
|
+
|
|
774
|
+
const handleResize = () => {
|
|
775
|
+
updateViewportSize();
|
|
776
|
+
updateWindowViewport();
|
|
777
|
+
updateViewportOffset();
|
|
778
|
+
};
|
|
672
779
|
window.addEventListener("resize", handleResize);
|
|
780
|
+
|
|
673
781
|
const resizeObserver =
|
|
674
782
|
typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => updateViewportSize()) : null;
|
|
675
783
|
if (containerRef && resizeObserver) {
|
|
676
784
|
resizeObserver.observe(containerRef);
|
|
677
785
|
}
|
|
786
|
+
|
|
787
|
+
// A capturing listener on the document sees scroll events on the scroll view
|
|
788
|
+
// itself as well as on any ancestor (including the page), so a single handler
|
|
789
|
+
// can update the local scroll position or the window offset as appropriate.
|
|
790
|
+
const handleDocumentScroll = (e: Event) => {
|
|
791
|
+
if (!containerRef) return;
|
|
792
|
+
const target = e.target as Node | null;
|
|
793
|
+
const isContainer = target === containerRef;
|
|
794
|
+
const isAncestor =
|
|
795
|
+
target === document ||
|
|
796
|
+
target === (window as unknown as Node) ||
|
|
797
|
+
(target instanceof Node && target.contains(containerRef));
|
|
798
|
+
if (!isContainer && !isAncestor) return;
|
|
799
|
+
// An ancestor/page scroll only matters when the collection scrolls with the page.
|
|
800
|
+
if (!isContainer && !allowsWindowScrolling()) return;
|
|
801
|
+
|
|
802
|
+
// Flag active scrolling and (re)arm the reset for 300ms after the last scroll.
|
|
803
|
+
// Our handler is already rAF-throttled, so a plain clear/reset debounce matches
|
|
804
|
+
// upstream's scrollEndTime bookkeeping without the extra accounting.
|
|
805
|
+
if (!isScrolling()) setIsScrolling(true);
|
|
806
|
+
if (scrollEndTimeout != null) clearTimeout(scrollEndTimeout);
|
|
807
|
+
scrollEndTimeout = setTimeout(() => {
|
|
808
|
+
scrollEndTimeout = undefined;
|
|
809
|
+
setIsScrolling(false);
|
|
810
|
+
}, 300);
|
|
811
|
+
|
|
812
|
+
if (scrollFrame != null) cancelAnimationFrame(scrollFrame);
|
|
813
|
+
scrollFrame = requestAnimationFrame(() => {
|
|
814
|
+
scrollFrame = undefined;
|
|
815
|
+
if (isContainer) {
|
|
816
|
+
const next = Math.max(0, containerRef!.scrollTop);
|
|
817
|
+
if (next !== scrollOffset()) setScrollOffset(next);
|
|
818
|
+
const nextX = Math.max(0, containerRef!.scrollLeft);
|
|
819
|
+
if (nextX !== scrollOffsetX()) setScrollOffsetX(nextX);
|
|
820
|
+
} else {
|
|
821
|
+
updateViewportOffset();
|
|
822
|
+
}
|
|
823
|
+
updateViewportSize();
|
|
824
|
+
});
|
|
825
|
+
};
|
|
826
|
+
document.addEventListener("scroll", handleDocumentScroll, true);
|
|
827
|
+
|
|
678
828
|
onCleanup(() => {
|
|
679
829
|
window.removeEventListener("resize", handleResize);
|
|
680
830
|
resizeObserver?.disconnect();
|
|
831
|
+
document.removeEventListener("scroll", handleDocumentScroll, true);
|
|
681
832
|
});
|
|
682
833
|
});
|
|
683
834
|
|
|
684
|
-
let scrollFrame: number | undefined;
|
|
685
|
-
onCleanup(() => {
|
|
686
|
-
if (scrollFrame != null) cancelAnimationFrame(scrollFrame);
|
|
687
|
-
});
|
|
688
|
-
|
|
689
835
|
return (
|
|
690
836
|
<CollectionRendererContext.Provider value={collectionRenderer()}>
|
|
691
837
|
<VirtualizerContext.Provider value={contextValue()}>
|
|
@@ -697,17 +843,19 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
|
697
843
|
class={local.class}
|
|
698
844
|
style={local.style}
|
|
699
845
|
data-virtualizer
|
|
700
|
-
onScroll={(e) => {
|
|
701
|
-
const target = e.currentTarget as HTMLDivElement;
|
|
702
|
-
if (scrollFrame != null) cancelAnimationFrame(scrollFrame);
|
|
703
|
-
scrollFrame = requestAnimationFrame(() => {
|
|
704
|
-
scrollFrame = undefined;
|
|
705
|
-
if (target.scrollTop !== scrollOffset()) setScrollOffset(target.scrollTop);
|
|
706
|
-
updateViewportSize();
|
|
707
|
-
});
|
|
708
|
-
}}
|
|
709
846
|
>
|
|
710
|
-
{
|
|
847
|
+
{/*
|
|
848
|
+
Content wrapper mirroring upstream ScrollView's inner content div. It
|
|
849
|
+
carries the `pointer-events: none` while-scrolling optimization and is
|
|
850
|
+
otherwise a layout-transparent passthrough (the outer div remains the
|
|
851
|
+
scroll container we measure and read scroll offsets from).
|
|
852
|
+
*/}
|
|
853
|
+
<div
|
|
854
|
+
data-virtualizer-content
|
|
855
|
+
style={{ "pointer-events": isScrolling() ? "none" : undefined }}
|
|
856
|
+
>
|
|
857
|
+
{local.children}
|
|
858
|
+
</div>
|
|
711
859
|
</div>
|
|
712
860
|
</VirtualizerContext.Provider>
|
|
713
861
|
</CollectionRendererContext.Provider>
|
|
@@ -724,6 +872,7 @@ export type {
|
|
|
724
872
|
WaterfallLayoutOptions,
|
|
725
873
|
VirtualizerDropTarget,
|
|
726
874
|
LayoutInfo,
|
|
875
|
+
Orientation,
|
|
727
876
|
Rect,
|
|
728
877
|
Size,
|
|
729
878
|
Point,
|
|
@@ -21,6 +21,13 @@ export interface Size {
|
|
|
21
21
|
height: number;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* The primary orientation of a linear layout — the axis items stack along, which
|
|
26
|
+
* is usually the direction the collection scrolls. Mirrors React Spectrum's
|
|
27
|
+
* `Orientation` and `ListLayout`'s `orientation` option.
|
|
28
|
+
*/
|
|
29
|
+
export type Orientation = "horizontal" | "vertical";
|
|
30
|
+
|
|
24
31
|
export interface LayoutInfo {
|
|
25
32
|
key: string | number;
|
|
26
33
|
index: number;
|
|
@@ -46,6 +53,13 @@ export interface DefaultVirtualizerLayoutOptions {
|
|
|
46
53
|
itemSize?: number;
|
|
47
54
|
overscan?: number;
|
|
48
55
|
viewportSize?: number;
|
|
56
|
+
/**
|
|
57
|
+
* The primary orientation of the items. Items offset along `x`/`width` when
|
|
58
|
+
* `horizontal`, and along `y`/`height` when `vertical`.
|
|
59
|
+
*
|
|
60
|
+
* @default 'vertical'
|
|
61
|
+
*/
|
|
62
|
+
orientation?: Orientation;
|
|
49
63
|
}
|
|
50
64
|
|
|
51
65
|
export interface GridLayoutOptions extends DefaultVirtualizerLayoutOptions {
|
|
@@ -62,6 +76,11 @@ export interface WaterfallLayoutOptions extends GridLayoutOptions {
|
|
|
62
76
|
|
|
63
77
|
export interface VirtualizerLayoutInfoContext {
|
|
64
78
|
viewportWidth: number;
|
|
79
|
+
/**
|
|
80
|
+
* The viewport height, used as the cross-axis size for a `horizontal` layout
|
|
81
|
+
* (the analogue of `viewportWidth` for the `vertical` default).
|
|
82
|
+
*/
|
|
83
|
+
viewportHeight?: number;
|
|
65
84
|
}
|
|
66
85
|
|
|
67
86
|
export interface VirtualizerDropTarget {
|
|
@@ -124,15 +143,29 @@ export class ListLayout {
|
|
|
124
143
|
context: VirtualizerLayoutInfoContext,
|
|
125
144
|
options?: DefaultVirtualizerLayoutOptions,
|
|
126
145
|
): LayoutInfo {
|
|
127
|
-
const
|
|
146
|
+
const itemSize = Math.max(1, options?.itemSize ?? 40);
|
|
147
|
+
if ((options?.orientation ?? "vertical") === "horizontal") {
|
|
148
|
+
// Items stack along the x axis; the cross axis (height) fills the viewport.
|
|
149
|
+
return {
|
|
150
|
+
key: String(index),
|
|
151
|
+
index,
|
|
152
|
+
rect: {
|
|
153
|
+
x: index * itemSize,
|
|
154
|
+
y: 0,
|
|
155
|
+
width: itemSize,
|
|
156
|
+
height: Math.max(0, context.viewportHeight ?? 0),
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// Items stack along the y axis; the cross axis (width) fills the viewport.
|
|
128
161
|
return {
|
|
129
162
|
key: String(index),
|
|
130
163
|
index,
|
|
131
164
|
rect: {
|
|
132
165
|
x: 0,
|
|
133
|
-
y: index *
|
|
166
|
+
y: index * itemSize,
|
|
134
167
|
width: Math.max(0, context.viewportWidth),
|
|
135
|
-
height:
|
|
168
|
+
height: itemSize,
|
|
136
169
|
},
|
|
137
170
|
};
|
|
138
171
|
}
|
|
@@ -143,18 +176,20 @@ export class ListLayout {
|
|
|
143
176
|
options?: DefaultVirtualizerLayoutOptions,
|
|
144
177
|
): VirtualizerDropTarget | null {
|
|
145
178
|
if (itemCount <= 0) return { type: "root", index: -1, position: "on" };
|
|
146
|
-
const
|
|
147
|
-
|
|
179
|
+
const itemSize = Math.max(1, options?.itemSize ?? 40);
|
|
180
|
+
// Measure the drop point along the primary (scroll) axis.
|
|
181
|
+
const offset = (options?.orientation ?? "vertical") === "horizontal" ? point.x : point.y;
|
|
182
|
+
if (offset < 0) {
|
|
148
183
|
return { type: "item", index: 0, position: "before" };
|
|
149
184
|
}
|
|
150
|
-
const
|
|
151
|
-
if (
|
|
185
|
+
const totalSize = itemCount * itemSize;
|
|
186
|
+
if (offset >= totalSize) {
|
|
152
187
|
return { type: "item", index: itemCount - 1, position: "after" };
|
|
153
188
|
}
|
|
154
|
-
const rawIndex = Math.floor(
|
|
189
|
+
const rawIndex = Math.floor(offset / itemSize);
|
|
155
190
|
const index = Math.max(0, Math.min(rawIndex, itemCount - 1));
|
|
156
|
-
const offsetWithinItem = Math.max(0,
|
|
157
|
-
const threshold =
|
|
191
|
+
const offsetWithinItem = Math.max(0, offset - index * itemSize);
|
|
192
|
+
const threshold = itemSize / 3;
|
|
158
193
|
const position: VirtualizerDropTarget["position"] =
|
|
159
194
|
offsetWithinItem < threshold ? "before" : offsetWithinItem > threshold * 2 ? "after" : "on";
|
|
160
195
|
return { type: "item", index, position };
|