@proyecto-viviana/solidaria-components 0.3.2 → 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 +4 -4
- 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 +6 -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 -23932
- package/dist/index.jsx +70 -18337
- 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 +22 -2
- 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 +50 -6
- package/src/DateField.tsx +20 -2
- package/src/DatePicker.tsx +57 -5
- 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 +252 -128
- package/src/Meter.tsx +3 -1
- package/src/Modal.tsx +100 -52
- package/src/NumberField.tsx +51 -8
- package/src/Popover.tsx +40 -10
- 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 +3 -1
- package/src/Text.tsx +31 -10
- package/src/TextField.tsx +43 -5
- 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 +3 -1
- 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/dist/Tree.jsx
ADDED
|
@@ -0,0 +1,1172 @@
|
|
|
1
|
+
import { filterDOMProps, useRenderProps } from "./utils.jsx";
|
|
2
|
+
import { SharedElementTransition } from "./SharedElementTransition.jsx";
|
|
3
|
+
import { handleLinkClick, useLinkProps, useRouter } from "./RouterProvider.jsx";
|
|
4
|
+
import { CollectionRendererContext, flattenCollectionEntries, isCollectionSection, useCollectionRenderer } from "./Collection.jsx";
|
|
5
|
+
import { r as useVirtualizerContext } from "./Virtualizer2.jsx";
|
|
6
|
+
import { getNormalizedDropTargetKey, mergePersistedKeysIntoVirtualRange, useDndPersistedKeys, useRenderDropIndicator } from "./DragAndDrop.jsx";
|
|
7
|
+
import { GridListHeader, GridListHeaderContext, GridListHeaderInnerContext } from "./GridList.jsx";
|
|
8
|
+
import { For, Show, createContext, createEffect, createMemo, createSignal, onCleanup, splitProps, useContext } from "solid-js";
|
|
9
|
+
import { createFocusRing, createGridListSection, createHover, createTree, createTreeItem, createTreeSelectionCheckbox, mergeProps as mergeProps$1 } from "@proyecto-viviana/solidaria";
|
|
10
|
+
import { createTreeCollection, createTreeState } from "@proyecto-viviana/solid-stately";
|
|
11
|
+
//#region src/Tree.tsx
|
|
12
|
+
/**
|
|
13
|
+
* Tree component for solidaria-components
|
|
14
|
+
*
|
|
15
|
+
* A pre-wired headless tree that combines state + aria hooks.
|
|
16
|
+
* Based on react-aria-components/src/Tree.tsx
|
|
17
|
+
*
|
|
18
|
+
* Tree displays hierarchical data with expandable/collapsible nodes,
|
|
19
|
+
* supporting keyboard navigation and selection.
|
|
20
|
+
*/
|
|
21
|
+
function assignRef(ref, el) {
|
|
22
|
+
if (!ref) return;
|
|
23
|
+
if (typeof ref === "function") ref(el);
|
|
24
|
+
else ref.current = el;
|
|
25
|
+
}
|
|
26
|
+
const X_SWITCH_THRESHOLD = 10;
|
|
27
|
+
const Y_SWITCH_THRESHOLD = 5;
|
|
28
|
+
const EXPANSION_KEYS = {
|
|
29
|
+
expand: {
|
|
30
|
+
ltr: "ArrowRight",
|
|
31
|
+
rtl: "ArrowLeft"
|
|
32
|
+
},
|
|
33
|
+
collapse: {
|
|
34
|
+
ltr: "ArrowLeft",
|
|
35
|
+
rtl: "ArrowRight"
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
function resolveTreeDirection(element) {
|
|
39
|
+
if (element) {
|
|
40
|
+
const dir = element.closest("[dir]")?.getAttribute("dir");
|
|
41
|
+
if (dir === "rtl") return "rtl";
|
|
42
|
+
if (dir === "ltr") return "ltr";
|
|
43
|
+
if (typeof window !== "undefined" && typeof window.getComputedStyle === "function") {
|
|
44
|
+
const computedDirection = window.getComputedStyle(element).direction;
|
|
45
|
+
if (computedDirection === "rtl") return "rtl";
|
|
46
|
+
if (computedDirection === "ltr") return "ltr";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (typeof document !== "undefined") return document.dir === "rtl" ? "rtl" : "ltr";
|
|
50
|
+
return "ltr";
|
|
51
|
+
}
|
|
52
|
+
function createTreeDropTargetDelegate(delegate, state, direction, baseKeyboardNav) {
|
|
53
|
+
const pointerTracking = {
|
|
54
|
+
lastY: 0,
|
|
55
|
+
lastX: 0,
|
|
56
|
+
yDirection: null,
|
|
57
|
+
xDirection: null,
|
|
58
|
+
boundaryContext: null
|
|
59
|
+
};
|
|
60
|
+
const getPotentialTargets = (originalTarget, isValidDropTarget) => {
|
|
61
|
+
if (originalTarget.dropPosition === "on") return [originalTarget];
|
|
62
|
+
const collection = state.collection;
|
|
63
|
+
const getNodeNextKey = (node) => {
|
|
64
|
+
if (!node) return null;
|
|
65
|
+
return node.nextKey ?? null;
|
|
66
|
+
};
|
|
67
|
+
const target = { ...originalTarget };
|
|
68
|
+
let currentItem = collection.getItem(target.key);
|
|
69
|
+
while (currentItem && currentItem.type !== "item") {
|
|
70
|
+
const nextKey = getNodeNextKey(currentItem);
|
|
71
|
+
if (nextKey == null) break;
|
|
72
|
+
target.key = nextKey;
|
|
73
|
+
currentItem = collection.getItem(nextKey);
|
|
74
|
+
}
|
|
75
|
+
const potentialTargets = [target];
|
|
76
|
+
if (currentItem && currentItem.hasChildNodes && state.expandedKeys.has(currentItem.key) && target.dropPosition === "after") {
|
|
77
|
+
let firstChildItemNode = null;
|
|
78
|
+
for (const child of collection.getChildren(currentItem.key)) if (child.type === "item") {
|
|
79
|
+
firstChildItemNode = child;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
if (firstChildItemNode) {
|
|
83
|
+
const beforeFirstChildTarget = {
|
|
84
|
+
type: "item",
|
|
85
|
+
key: firstChildItemNode.key,
|
|
86
|
+
dropPosition: "before"
|
|
87
|
+
};
|
|
88
|
+
if (isValidDropTarget(beforeFirstChildTarget)) return [beforeFirstChildTarget];
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (getNodeNextKey(currentItem) != null) return [originalTarget];
|
|
93
|
+
let parentKey = currentItem?.parentKey ?? null;
|
|
94
|
+
const ancestorTargets = [];
|
|
95
|
+
while (parentKey != null) {
|
|
96
|
+
const parentItem = collection.getItem(parentKey);
|
|
97
|
+
const nextKey = getNodeNextKey(parentItem);
|
|
98
|
+
const nextItem = nextKey != null ? collection.getItem(nextKey) : null;
|
|
99
|
+
if (!nextItem || nextItem.parentKey !== parentKey) {
|
|
100
|
+
const afterParentTarget = {
|
|
101
|
+
type: "item",
|
|
102
|
+
key: parentKey,
|
|
103
|
+
dropPosition: "after"
|
|
104
|
+
};
|
|
105
|
+
if (isValidDropTarget(afterParentTarget)) ancestorTargets.push(afterParentTarget);
|
|
106
|
+
if (nextItem) break;
|
|
107
|
+
}
|
|
108
|
+
parentKey = parentItem?.parentKey ?? null;
|
|
109
|
+
}
|
|
110
|
+
if (ancestorTargets.length > 0) potentialTargets.push(...ancestorTargets);
|
|
111
|
+
if (potentialTargets.length === 1) {
|
|
112
|
+
const nextKey = collection.getKeyAfter(target.key);
|
|
113
|
+
const nextNode = nextKey != null ? collection.getItem(nextKey) : null;
|
|
114
|
+
if (nextKey != null && nextNode && currentItem && nextNode.level != null && currentItem.level != null && nextNode.level > currentItem.level) {
|
|
115
|
+
const beforeTarget = {
|
|
116
|
+
type: "item",
|
|
117
|
+
key: nextKey,
|
|
118
|
+
dropPosition: "before"
|
|
119
|
+
};
|
|
120
|
+
if (isValidDropTarget(beforeTarget)) return [beforeTarget];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return potentialTargets.filter((candidate) => isValidDropTarget(candidate));
|
|
124
|
+
};
|
|
125
|
+
const selectTarget = (potentialTargets, originalTarget, x, y, currentYMovement, currentXMovement) => {
|
|
126
|
+
if (potentialTargets.length < 2) return potentialTargets[0];
|
|
127
|
+
const parentKey = state.collection.getItem(originalTarget.key)?.parentKey;
|
|
128
|
+
if (parentKey == null) return potentialTargets[0];
|
|
129
|
+
if (!pointerTracking.boundaryContext || pointerTracking.boundaryContext.parentKey !== parentKey) pointerTracking.boundaryContext = {
|
|
130
|
+
parentKey,
|
|
131
|
+
preferredTargetIndex: pointerTracking.yDirection === "up" ? potentialTargets.length - 1 : 0,
|
|
132
|
+
lastSwitchY: y,
|
|
133
|
+
lastSwitchX: x
|
|
134
|
+
};
|
|
135
|
+
const boundaryContext = pointerTracking.boundaryContext;
|
|
136
|
+
const distanceFromLastXSwitch = Math.abs(x - boundaryContext.lastSwitchX);
|
|
137
|
+
if (Math.abs(y - boundaryContext.lastSwitchY) > Y_SWITCH_THRESHOLD && currentYMovement) {
|
|
138
|
+
const currentIndex = boundaryContext.preferredTargetIndex ?? 0;
|
|
139
|
+
if (currentYMovement === "down" && currentIndex === 0) boundaryContext.preferredTargetIndex = potentialTargets.length - 1;
|
|
140
|
+
else if (currentYMovement === "up" && currentIndex === potentialTargets.length - 1) boundaryContext.preferredTargetIndex = 0;
|
|
141
|
+
pointerTracking.xDirection = null;
|
|
142
|
+
}
|
|
143
|
+
if (distanceFromLastXSwitch > X_SWITCH_THRESHOLD && currentXMovement) {
|
|
144
|
+
const currentTargetIndex = boundaryContext.preferredTargetIndex ?? 0;
|
|
145
|
+
if (currentXMovement === "left") {
|
|
146
|
+
if (direction === "ltr") {
|
|
147
|
+
if (currentTargetIndex < potentialTargets.length - 1) {
|
|
148
|
+
boundaryContext.preferredTargetIndex = currentTargetIndex + 1;
|
|
149
|
+
boundaryContext.lastSwitchX = x;
|
|
150
|
+
}
|
|
151
|
+
} else if (currentTargetIndex > 0) {
|
|
152
|
+
boundaryContext.preferredTargetIndex = currentTargetIndex - 1;
|
|
153
|
+
boundaryContext.lastSwitchX = x;
|
|
154
|
+
}
|
|
155
|
+
} else if (currentXMovement === "right") {
|
|
156
|
+
if (direction === "ltr") {
|
|
157
|
+
if (currentTargetIndex > 0) {
|
|
158
|
+
boundaryContext.preferredTargetIndex = currentTargetIndex - 1;
|
|
159
|
+
boundaryContext.lastSwitchX = x;
|
|
160
|
+
}
|
|
161
|
+
} else if (currentTargetIndex < potentialTargets.length - 1) {
|
|
162
|
+
boundaryContext.preferredTargetIndex = currentTargetIndex + 1;
|
|
163
|
+
boundaryContext.lastSwitchX = x;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
pointerTracking.yDirection = null;
|
|
167
|
+
}
|
|
168
|
+
return potentialTargets[Math.max(0, Math.min(boundaryContext.preferredTargetIndex ?? 0, potentialTargets.length - 1))];
|
|
169
|
+
};
|
|
170
|
+
const getKeyboardNavigationTarget = (target, dir, isValidDropTarget) => {
|
|
171
|
+
const collection = state.collection;
|
|
172
|
+
if (target && target.type === "item") {
|
|
173
|
+
const node = collection.getItem(target.key);
|
|
174
|
+
if (!(node != null && node.rowIndex != null)) return baseKeyboardNav?.(target, dir, isValidDropTarget) ?? null;
|
|
175
|
+
}
|
|
176
|
+
const tryValid = (t) => isValidDropTarget(t) ? t : null;
|
|
177
|
+
const getNodeNextKey = (node) => {
|
|
178
|
+
if (!node) return null;
|
|
179
|
+
return node.nextKey ?? null;
|
|
180
|
+
};
|
|
181
|
+
const isExpanded = (key) => {
|
|
182
|
+
const node = collection.getItem(key);
|
|
183
|
+
if (!node || !node.hasChildNodes) return false;
|
|
184
|
+
return state.expandedKeys.has(key);
|
|
185
|
+
};
|
|
186
|
+
const getFirstChildItemKey = (key) => {
|
|
187
|
+
for (const child of collection.getChildren(key)) if (child.type === "item") return child.key;
|
|
188
|
+
return null;
|
|
189
|
+
};
|
|
190
|
+
const getLastChildItemKey = (key) => {
|
|
191
|
+
let lastKey = null;
|
|
192
|
+
for (const child of collection.getChildren(key)) if (child.type === "item") lastKey = child.key;
|
|
193
|
+
return lastKey;
|
|
194
|
+
};
|
|
195
|
+
const getDeepestLastChild = (key) => {
|
|
196
|
+
let current = key;
|
|
197
|
+
while (isExpanded(current)) {
|
|
198
|
+
const lastChild = getLastChildItemKey(current);
|
|
199
|
+
if (lastChild == null) break;
|
|
200
|
+
current = lastChild;
|
|
201
|
+
}
|
|
202
|
+
return current;
|
|
203
|
+
};
|
|
204
|
+
if (dir === "next") {
|
|
205
|
+
if (!target) return tryValid({ type: "root" });
|
|
206
|
+
if (target.type === "root") {
|
|
207
|
+
const firstKey = collection.getFirstKey();
|
|
208
|
+
if (firstKey != null) return tryValid({
|
|
209
|
+
type: "item",
|
|
210
|
+
key: firstKey,
|
|
211
|
+
dropPosition: "before"
|
|
212
|
+
});
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
if (target.type === "item") switch (target.dropPosition) {
|
|
216
|
+
case "before": return tryValid({
|
|
217
|
+
type: "item",
|
|
218
|
+
key: target.key,
|
|
219
|
+
dropPosition: "on"
|
|
220
|
+
}) ?? tryValid({
|
|
221
|
+
type: "item",
|
|
222
|
+
key: target.key,
|
|
223
|
+
dropPosition: "after"
|
|
224
|
+
});
|
|
225
|
+
case "on": {
|
|
226
|
+
if (isExpanded(target.key)) {
|
|
227
|
+
const firstChild = getFirstChildItemKey(target.key);
|
|
228
|
+
if (firstChild != null) return tryValid({
|
|
229
|
+
type: "item",
|
|
230
|
+
key: firstChild,
|
|
231
|
+
dropPosition: "before"
|
|
232
|
+
}) ?? tryValid({
|
|
233
|
+
type: "item",
|
|
234
|
+
key: firstChild,
|
|
235
|
+
dropPosition: "on"
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
const nextKey = collection.getKeyAfter(target.key);
|
|
239
|
+
const targetNode = collection.getItem(target.key);
|
|
240
|
+
const nextNode = nextKey != null ? collection.getItem(nextKey) : null;
|
|
241
|
+
if (targetNode && nextNode && nextNode.level != null && targetNode.level != null && nextNode.level >= targetNode.level) return tryValid({
|
|
242
|
+
type: "item",
|
|
243
|
+
key: nextNode.key,
|
|
244
|
+
dropPosition: "before"
|
|
245
|
+
}) ?? tryValid({
|
|
246
|
+
type: "item",
|
|
247
|
+
key: target.key,
|
|
248
|
+
dropPosition: "after"
|
|
249
|
+
});
|
|
250
|
+
return tryValid({
|
|
251
|
+
type: "item",
|
|
252
|
+
key: target.key,
|
|
253
|
+
dropPosition: "after"
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
case "after": {
|
|
257
|
+
if (isExpanded(target.key)) {
|
|
258
|
+
const firstChild = getFirstChildItemKey(target.key);
|
|
259
|
+
if (firstChild != null) return tryValid({
|
|
260
|
+
type: "item",
|
|
261
|
+
key: firstChild,
|
|
262
|
+
dropPosition: "before"
|
|
263
|
+
}) ?? tryValid({
|
|
264
|
+
type: "item",
|
|
265
|
+
key: firstChild,
|
|
266
|
+
dropPosition: "on"
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const targetNode = collection.getItem(target.key);
|
|
270
|
+
const nextSiblingKey = getNodeNextKey(targetNode);
|
|
271
|
+
if (nextSiblingKey != null) {
|
|
272
|
+
const nextSibling = collection.getItem(nextSiblingKey);
|
|
273
|
+
if (nextSibling?.type === "item") return tryValid({
|
|
274
|
+
type: "item",
|
|
275
|
+
key: nextSibling.key,
|
|
276
|
+
dropPosition: "before"
|
|
277
|
+
}) ?? tryValid({
|
|
278
|
+
type: "item",
|
|
279
|
+
key: nextSibling.key,
|
|
280
|
+
dropPosition: "on"
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
if (targetNode?.parentKey != null) {
|
|
284
|
+
const parentNode = collection.getItem(targetNode.parentKey);
|
|
285
|
+
const parentNextKey = getNodeNextKey(parentNode);
|
|
286
|
+
const parentNextNode = parentNextKey != null ? collection.getItem(parentNextKey) : null;
|
|
287
|
+
if (parentNextNode?.type === "item") return tryValid({
|
|
288
|
+
type: "item",
|
|
289
|
+
key: parentNextNode.key,
|
|
290
|
+
dropPosition: "before"
|
|
291
|
+
});
|
|
292
|
+
if (parentNode?.type === "item") return tryValid({
|
|
293
|
+
type: "item",
|
|
294
|
+
key: parentNode.key,
|
|
295
|
+
dropPosition: "after"
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
const nextKey = collection.getKeyAfter(target.key);
|
|
299
|
+
if (nextKey != null) return tryValid({
|
|
300
|
+
type: "item",
|
|
301
|
+
key: nextKey,
|
|
302
|
+
dropPosition: "before"
|
|
303
|
+
}) ?? tryValid({
|
|
304
|
+
type: "item",
|
|
305
|
+
key: nextKey,
|
|
306
|
+
dropPosition: "on"
|
|
307
|
+
});
|
|
308
|
+
return tryValid({ type: "root" });
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
if (!target || target.type === "root") {
|
|
314
|
+
const lastKey = collection.getLastKey();
|
|
315
|
+
if (lastKey != null) {
|
|
316
|
+
let rootKey = lastKey;
|
|
317
|
+
let node = collection.getItem(lastKey);
|
|
318
|
+
while (node?.parentKey != null) {
|
|
319
|
+
rootKey = node.parentKey;
|
|
320
|
+
node = collection.getItem(rootKey);
|
|
321
|
+
}
|
|
322
|
+
return tryValid({
|
|
323
|
+
type: "item",
|
|
324
|
+
key: rootKey,
|
|
325
|
+
dropPosition: "after"
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
if (target.type === "item") switch (target.dropPosition) {
|
|
331
|
+
case "after": {
|
|
332
|
+
const deepest = getDeepestLastChild(target.key);
|
|
333
|
+
if (deepest !== target.key) return tryValid({
|
|
334
|
+
type: "item",
|
|
335
|
+
key: deepest,
|
|
336
|
+
dropPosition: "after"
|
|
337
|
+
}) ?? tryValid({
|
|
338
|
+
type: "item",
|
|
339
|
+
key: target.key,
|
|
340
|
+
dropPosition: "on"
|
|
341
|
+
});
|
|
342
|
+
return tryValid({
|
|
343
|
+
type: "item",
|
|
344
|
+
key: target.key,
|
|
345
|
+
dropPosition: "on"
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
case "on": return tryValid({
|
|
349
|
+
type: "item",
|
|
350
|
+
key: target.key,
|
|
351
|
+
dropPosition: "before"
|
|
352
|
+
});
|
|
353
|
+
case "before": {
|
|
354
|
+
const prevKey = collection.getKeyBefore(target.key);
|
|
355
|
+
if (prevKey != null) return tryValid({
|
|
356
|
+
type: "item",
|
|
357
|
+
key: getDeepestLastChild(prevKey),
|
|
358
|
+
dropPosition: "after"
|
|
359
|
+
}) ?? tryValid({
|
|
360
|
+
type: "item",
|
|
361
|
+
key: prevKey,
|
|
362
|
+
dropPosition: "on"
|
|
363
|
+
});
|
|
364
|
+
return tryValid({ type: "root" });
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return null;
|
|
368
|
+
};
|
|
369
|
+
return {
|
|
370
|
+
getDropTargetFromPoint(x, y, isValidDropTarget) {
|
|
371
|
+
const baseTarget = delegate.getDropTargetFromPoint(x, y, isValidDropTarget);
|
|
372
|
+
if (!baseTarget || baseTarget.type === "root") return baseTarget;
|
|
373
|
+
const deltaY = y - pointerTracking.lastY;
|
|
374
|
+
const deltaX = x - pointerTracking.lastX;
|
|
375
|
+
let currentYMovement = pointerTracking.yDirection;
|
|
376
|
+
let currentXMovement = pointerTracking.xDirection;
|
|
377
|
+
if (Math.abs(deltaY) > Y_SWITCH_THRESHOLD) {
|
|
378
|
+
currentYMovement = deltaY > 0 ? "down" : "up";
|
|
379
|
+
pointerTracking.yDirection = currentYMovement;
|
|
380
|
+
pointerTracking.lastY = y;
|
|
381
|
+
}
|
|
382
|
+
if (Math.abs(deltaX) > X_SWITCH_THRESHOLD) {
|
|
383
|
+
currentXMovement = deltaX > 0 ? "right" : "left";
|
|
384
|
+
pointerTracking.xDirection = currentXMovement;
|
|
385
|
+
pointerTracking.lastX = x;
|
|
386
|
+
}
|
|
387
|
+
let target = baseTarget;
|
|
388
|
+
if (target.dropPosition === "before") {
|
|
389
|
+
const keyBefore = state.collection.getKeyBefore(target.key);
|
|
390
|
+
if (keyBefore != null) {
|
|
391
|
+
const normalized = {
|
|
392
|
+
type: "item",
|
|
393
|
+
key: keyBefore,
|
|
394
|
+
dropPosition: "after"
|
|
395
|
+
};
|
|
396
|
+
if (isValidDropTarget(normalized)) target = normalized;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
const potentialTargets = getPotentialTargets(target, isValidDropTarget);
|
|
400
|
+
if (potentialTargets.length === 0) return { type: "root" };
|
|
401
|
+
if (potentialTargets.length > 1) return selectTarget(potentialTargets, target, x, y, currentYMovement, currentXMovement);
|
|
402
|
+
pointerTracking.boundaryContext = null;
|
|
403
|
+
return potentialTargets[0];
|
|
404
|
+
},
|
|
405
|
+
getKeyboardNavigationTarget,
|
|
406
|
+
getKeyboardPageNavigationTarget: delegate.getKeyboardPageNavigationTarget?.bind(delegate)
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
const TreeContext = createContext(null);
|
|
410
|
+
const TreeStateContext = createContext(null);
|
|
411
|
+
const TreeItemContext = createContext(null);
|
|
412
|
+
const TreeItemContentContext = createContext(null);
|
|
413
|
+
function isTreeItemRecord(value) {
|
|
414
|
+
return typeof value === "object" && value !== null;
|
|
415
|
+
}
|
|
416
|
+
function treeItemDataFromNode(node) {
|
|
417
|
+
const value = node.value;
|
|
418
|
+
const item = isTreeItemRecord(value) ? value : {};
|
|
419
|
+
return {
|
|
420
|
+
...item,
|
|
421
|
+
key: node.key,
|
|
422
|
+
id: item.id ?? node.key,
|
|
423
|
+
value: value ?? void 0,
|
|
424
|
+
textValue: node.textValue,
|
|
425
|
+
isDisabled: node.isDisabled,
|
|
426
|
+
hasChildItems: node.hasChildNodes,
|
|
427
|
+
children: node.childNodes.length > 0 ? node.childNodes.map((child) => treeItemDataFromNode(child)) : void 0
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* A tree displays hierarchical data with expandable/collapsible nodes,
|
|
432
|
+
* supporting keyboard navigation and selection.
|
|
433
|
+
*/
|
|
434
|
+
function Tree(props) {
|
|
435
|
+
const [local, stateProps, ariaProps] = splitProps(props, [
|
|
436
|
+
"class",
|
|
437
|
+
"style",
|
|
438
|
+
"slot",
|
|
439
|
+
"renderEmptyState",
|
|
440
|
+
"hasMore",
|
|
441
|
+
"isLoading",
|
|
442
|
+
"loadingState",
|
|
443
|
+
"onLoadMore",
|
|
444
|
+
"renderLoadMoreItem",
|
|
445
|
+
"loadMoreClass",
|
|
446
|
+
"loadMoreStyle",
|
|
447
|
+
"dragAndDropHooks",
|
|
448
|
+
"ref"
|
|
449
|
+
], [
|
|
450
|
+
"items",
|
|
451
|
+
"disabledKeys",
|
|
452
|
+
"disabledBehavior",
|
|
453
|
+
"selectionMode",
|
|
454
|
+
"selectionBehavior",
|
|
455
|
+
"selectedKeys",
|
|
456
|
+
"defaultSelectedKeys",
|
|
457
|
+
"onSelectionChange",
|
|
458
|
+
"expandedKeys",
|
|
459
|
+
"defaultExpandedKeys",
|
|
460
|
+
"onExpandedChange"
|
|
461
|
+
]);
|
|
462
|
+
const [ref, setRef] = createSignal(null);
|
|
463
|
+
const flatItems = createMemo(() => flattenCollectionEntries(stateProps.items ?? []));
|
|
464
|
+
const hasSections = createMemo(() => (stateProps.items ?? []).some((entry) => isCollectionSection(entry)));
|
|
465
|
+
const state = createTreeState(() => ({
|
|
466
|
+
collectionFactory: (expandedKeys) => createTreeCollection(flatItems(), expandedKeys),
|
|
467
|
+
disabledKeys: stateProps.disabledKeys,
|
|
468
|
+
disabledBehavior: stateProps.disabledBehavior,
|
|
469
|
+
selectionMode: stateProps.selectionMode,
|
|
470
|
+
selectionBehavior: stateProps.selectionBehavior,
|
|
471
|
+
selectedKeys: stateProps.selectedKeys,
|
|
472
|
+
defaultSelectedKeys: stateProps.defaultSelectedKeys,
|
|
473
|
+
onSelectionChange: stateProps.onSelectionChange,
|
|
474
|
+
expandedKeys: stateProps.expandedKeys,
|
|
475
|
+
defaultExpandedKeys: stateProps.defaultExpandedKeys,
|
|
476
|
+
onExpandedChange: stateProps.onExpandedChange
|
|
477
|
+
}));
|
|
478
|
+
const [lastExpandedKeys, setLastExpandedKeys] = createSignal(/* @__PURE__ */ new Set());
|
|
479
|
+
const [lastItemsLength, setLastItemsLength] = createSignal(flatItems().length);
|
|
480
|
+
const [collectionVersion, setCollectionVersion] = createSignal(0);
|
|
481
|
+
createEffect(() => {
|
|
482
|
+
const expanded = state.expandedKeys;
|
|
483
|
+
const items = flatItems();
|
|
484
|
+
if (!areSetsEqual(lastExpandedKeys(), expanded) || lastItemsLength() !== items.length) {
|
|
485
|
+
setLastExpandedKeys(new Set(expanded));
|
|
486
|
+
setLastItemsLength(items.length);
|
|
487
|
+
setCollectionVersion((v) => v + 1);
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
const treeDirection = createMemo(() => ariaProps.direction ?? resolveTreeDirection(ref()));
|
|
491
|
+
const { treeProps } = createTree(() => ({
|
|
492
|
+
id: ariaProps.id,
|
|
493
|
+
"aria-label": ariaProps["aria-label"],
|
|
494
|
+
"aria-labelledby": ariaProps["aria-labelledby"],
|
|
495
|
+
"aria-describedby": ariaProps["aria-describedby"],
|
|
496
|
+
isVirtualized: ariaProps.isVirtualized,
|
|
497
|
+
onAction: ariaProps.onAction,
|
|
498
|
+
isDisabled: ariaProps.isDisabled,
|
|
499
|
+
keyboardNavigationBehavior: ariaProps.keyboardNavigationBehavior,
|
|
500
|
+
direction: treeDirection()
|
|
501
|
+
}), () => state, ref);
|
|
502
|
+
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
503
|
+
const renderValues = createMemo(() => ({
|
|
504
|
+
isFocused: state.isFocused || isFocused(),
|
|
505
|
+
isFocusVisible: isFocusVisible(),
|
|
506
|
+
isDisabled: ariaProps.isDisabled ?? false,
|
|
507
|
+
isEmpty: flatItems().length === 0
|
|
508
|
+
}));
|
|
509
|
+
const renderProps = useRenderProps({
|
|
510
|
+
class: local.class,
|
|
511
|
+
style: local.style,
|
|
512
|
+
defaultClassName: "solidaria-Tree"
|
|
513
|
+
}, renderValues);
|
|
514
|
+
const domProps = createMemo(() => {
|
|
515
|
+
return filterDOMProps(ariaProps, { global: true });
|
|
516
|
+
});
|
|
517
|
+
const cleanTreeProps = () => {
|
|
518
|
+
const { ref: _ref1, ...rest } = treeProps;
|
|
519
|
+
return rest;
|
|
520
|
+
};
|
|
521
|
+
const cleanFocusProps = () => {
|
|
522
|
+
const { ref: _ref2, ...rest } = focusProps;
|
|
523
|
+
return rest;
|
|
524
|
+
};
|
|
525
|
+
const isEmpty = () => flatItems().length === 0;
|
|
526
|
+
const visibleRows = createMemo(() => {
|
|
527
|
+
collectionVersion();
|
|
528
|
+
return state.collection.rows;
|
|
529
|
+
});
|
|
530
|
+
const virtualizer = useVirtualizerContext();
|
|
531
|
+
const parentCollectionRenderer = useCollectionRenderer();
|
|
532
|
+
const getDropTargetByIndex = (index, position) => {
|
|
533
|
+
const node = visibleRows()[index];
|
|
534
|
+
if (!node) return null;
|
|
535
|
+
return {
|
|
536
|
+
type: "item",
|
|
537
|
+
key: node.key,
|
|
538
|
+
dropPosition: position
|
|
539
|
+
};
|
|
540
|
+
};
|
|
541
|
+
const hasDroppableDnd = createMemo(() => {
|
|
542
|
+
const hooks = local.dragAndDropHooks;
|
|
543
|
+
return Boolean(hooks?.useDroppableCollectionState && hooks.useDroppableCollection && (hooks.dropTargetDelegate || parentCollectionRenderer?.dropTargetDelegate || hooks.ListDropTargetDelegate));
|
|
544
|
+
});
|
|
545
|
+
const hasDraggableDnd = createMemo(() => {
|
|
546
|
+
const hooks = local.dragAndDropHooks;
|
|
547
|
+
return Boolean(hooks?.useDraggableCollectionState && hooks.useDraggableCollection);
|
|
548
|
+
});
|
|
549
|
+
const dragState = createMemo(() => {
|
|
550
|
+
if (!hasDraggableDnd()) return void 0;
|
|
551
|
+
return local.dragAndDropHooks?.useDraggableCollectionState?.({ items: visibleRows().map((node) => node.value) });
|
|
552
|
+
});
|
|
553
|
+
const dropState = createMemo(() => {
|
|
554
|
+
if (!hasDroppableDnd()) return void 0;
|
|
555
|
+
return local.dragAndDropHooks?.useDroppableCollectionState?.({});
|
|
556
|
+
});
|
|
557
|
+
createEffect(() => {
|
|
558
|
+
const activeDropState = dropState();
|
|
559
|
+
if (!activeDropState) return;
|
|
560
|
+
const originalGetDropOperation = activeDropState.getDropOperation.bind(activeDropState);
|
|
561
|
+
activeDropState.getDropOperation = (target, types, allowedOperations) => {
|
|
562
|
+
const currentDraggingKeys = dragState()?.draggingKeys ?? /* @__PURE__ */ new Set();
|
|
563
|
+
if (target.type === "item" && currentDraggingKeys.size > 0) {
|
|
564
|
+
if (currentDraggingKeys.has(target.key) && target.dropPosition === "on") return "cancel";
|
|
565
|
+
let currentKey = target.key;
|
|
566
|
+
while (currentKey != null) {
|
|
567
|
+
const parentKey = state.collection.getItem(currentKey)?.parentKey;
|
|
568
|
+
if (parentKey != null && currentDraggingKeys.has(parentKey)) return "cancel";
|
|
569
|
+
currentKey = parentKey ?? null;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return originalGetDropOperation(target, types, allowedOperations);
|
|
573
|
+
};
|
|
574
|
+
onCleanup(() => {
|
|
575
|
+
activeDropState.getDropOperation = originalGetDropOperation;
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
createEffect(() => {
|
|
579
|
+
if (!hasDraggableDnd()) return;
|
|
580
|
+
const hooks = local.dragAndDropHooks;
|
|
581
|
+
const activeDragState = dragState();
|
|
582
|
+
if (!hooks?.useDraggableCollection || !activeDragState) return;
|
|
583
|
+
hooks.useDraggableCollection({}, activeDragState, () => ref());
|
|
584
|
+
});
|
|
585
|
+
const contextValue = createMemo(() => ({
|
|
586
|
+
state,
|
|
587
|
+
collection: state.collection,
|
|
588
|
+
isDisabled: ariaProps.isDisabled ?? false,
|
|
589
|
+
renderItem: props.children,
|
|
590
|
+
dragAndDropHooks: local.dragAndDropHooks,
|
|
591
|
+
dragState: dragState(),
|
|
592
|
+
dropState: dropState()
|
|
593
|
+
}));
|
|
594
|
+
const droppableCollection = createMemo(() => {
|
|
595
|
+
if (!hasDroppableDnd()) return void 0;
|
|
596
|
+
const hooks = local.dragAndDropHooks;
|
|
597
|
+
const activeDropState = dropState();
|
|
598
|
+
if (!hooks?.useDroppableCollection || !activeDropState) return void 0;
|
|
599
|
+
const direction = resolveTreeDirection(ref());
|
|
600
|
+
const baseDropTargetDelegate = hooks.dropTargetDelegate ?? parentCollectionRenderer?.dropTargetDelegate ?? (hooks.ListDropTargetDelegate ? new hooks.ListDropTargetDelegate(() => state.collection, () => ref(), {
|
|
601
|
+
layout: "stack",
|
|
602
|
+
orientation: "vertical",
|
|
603
|
+
direction
|
|
604
|
+
}) : void 0);
|
|
605
|
+
if (!baseDropTargetDelegate) return void 0;
|
|
606
|
+
const dropTargetDelegate = createTreeDropTargetDelegate(baseDropTargetDelegate, state, direction, virtualizer?.getBaseKeyboardNavigationTarget);
|
|
607
|
+
return hooks.useDroppableCollection({
|
|
608
|
+
dropTargetDelegate,
|
|
609
|
+
keyboardDelegate: {
|
|
610
|
+
getFirstKey: () => state.collection.getFirstKey(),
|
|
611
|
+
getLastKey: () => state.collection.getLastKey(),
|
|
612
|
+
getKeyBelow: (key) => state.collection.getKeyAfter(key),
|
|
613
|
+
getKeyAbove: (key) => state.collection.getKeyBefore(key),
|
|
614
|
+
getKeyPageBelow: (key) => state.collection.getKeyAfter(key),
|
|
615
|
+
getKeyPageAbove: (key) => state.collection.getKeyBefore(key)
|
|
616
|
+
},
|
|
617
|
+
get collection() {
|
|
618
|
+
return state.collection;
|
|
619
|
+
},
|
|
620
|
+
get selectedKeys() {
|
|
621
|
+
return state.selectedKeys;
|
|
622
|
+
},
|
|
623
|
+
setSelectedKeys: (keys) => {
|
|
624
|
+
if (state.selectionMode === "none") return;
|
|
625
|
+
state.clearSelection();
|
|
626
|
+
for (const key of keys) state.toggleSelection(key);
|
|
627
|
+
},
|
|
628
|
+
setFocusedKey: (key) => state.setFocusedKey(key),
|
|
629
|
+
onDropActivate: (event) => {
|
|
630
|
+
if (event.target.type !== "item") return;
|
|
631
|
+
const key = event.target.key;
|
|
632
|
+
const item = state.collection.getItem(key);
|
|
633
|
+
const isExpanded = state.isExpanded(key);
|
|
634
|
+
if (item?.hasChildNodes && (!isExpanded || hooks.isVirtualDragging?.())) state.toggleKey(key);
|
|
635
|
+
},
|
|
636
|
+
onKeyDown: (event) => {
|
|
637
|
+
const target = activeDropState.target;
|
|
638
|
+
if (!target || target.type !== "item" || target.dropPosition !== "on") return;
|
|
639
|
+
if (!state.collection.getItem(target.key)?.hasChildNodes) return;
|
|
640
|
+
const currentDirection = ariaProps.direction ?? resolveTreeDirection(ref());
|
|
641
|
+
const expandKey = EXPANSION_KEYS.expand[currentDirection];
|
|
642
|
+
const collapseKey = EXPANSION_KEYS.collapse[currentDirection];
|
|
643
|
+
if (event.key === expandKey && !state.isExpanded(target.key)) state.toggleKey(target.key);
|
|
644
|
+
else if (event.key === collapseKey && state.isExpanded(target.key)) state.toggleKey(target.key);
|
|
645
|
+
}
|
|
646
|
+
}, activeDropState, () => ref());
|
|
647
|
+
});
|
|
648
|
+
const isRootDropTarget = createMemo(() => {
|
|
649
|
+
return Boolean(dropState()?.target?.type === "root");
|
|
650
|
+
});
|
|
651
|
+
const dndRenderDropIndicator = createMemo(() => useRenderDropIndicator(local.dragAndDropHooks, dropState()));
|
|
652
|
+
const dndDropIndicator = (index, position) => {
|
|
653
|
+
const target = getDropTargetByIndex(index, position);
|
|
654
|
+
if (!target || target.type !== "item") return void 0;
|
|
655
|
+
return dndRenderDropIndicator()?.(target);
|
|
656
|
+
};
|
|
657
|
+
const persistedKeys = useDndPersistedKeys({ focusedKey: () => state.focusedKey }, local.dragAndDropHooks, dropState(), state.collection);
|
|
658
|
+
const virtualRange = createMemo(() => {
|
|
659
|
+
if (!virtualizer || !parentCollectionRenderer?.isVirtualized) return null;
|
|
660
|
+
const rows = visibleRows();
|
|
661
|
+
const baseRange = virtualizer.getVisibleRange(rows.length);
|
|
662
|
+
const persistedIndexes = Array.from(persistedKeys()).map((key) => rows.findIndex((node) => node.key === key)).filter((index) => index >= 0);
|
|
663
|
+
const dropTarget = dropState()?.target;
|
|
664
|
+
const normalizedDropKey = getNormalizedDropTargetKey(dropTarget, state.collection);
|
|
665
|
+
const focusedKey = state.focusedKey;
|
|
666
|
+
const focusedIndex = focusedKey != null ? rows.findIndex((node) => node.key === focusedKey) : -1;
|
|
667
|
+
const forceIncludeIndexes = [
|
|
668
|
+
dropTarget?.type === "item" ? rows.findIndex((node) => node.key === dropTarget.key) : -1,
|
|
669
|
+
normalizedDropKey != null ? rows.findIndex((node) => node.key === normalizedDropKey) : -1,
|
|
670
|
+
dropTarget?.type === "item" ? -1 : focusedIndex
|
|
671
|
+
].filter((index) => index >= 0);
|
|
672
|
+
return mergePersistedKeysIntoVirtualRange(baseRange, persistedIndexes, rows.length, virtualizer, 80, {
|
|
673
|
+
forceIncludeIndexes,
|
|
674
|
+
forceIncludeMaxSpan: 320
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
const virtualizedVisibleRows = createMemo(() => {
|
|
678
|
+
const range = virtualRange();
|
|
679
|
+
if (!range) return visibleRows();
|
|
680
|
+
return visibleRows().slice(range.start, range.end);
|
|
681
|
+
});
|
|
682
|
+
createEffect(() => {
|
|
683
|
+
if (!virtualizer || !parentCollectionRenderer?.isVirtualized) return;
|
|
684
|
+
virtualizer.setDropTargetItemCountResolver(() => visibleRows().length);
|
|
685
|
+
virtualizer.setDropTargetIndexResolver((key) => {
|
|
686
|
+
const index = visibleRows().findIndex((node) => node.key === key);
|
|
687
|
+
return index >= 0 ? index : null;
|
|
688
|
+
});
|
|
689
|
+
virtualizer.setDropTargetResolver((target) => {
|
|
690
|
+
const node = visibleRows()[target.index];
|
|
691
|
+
if (!node) return target;
|
|
692
|
+
return {
|
|
693
|
+
...target,
|
|
694
|
+
key: typeof node.key === "string" || typeof node.key === "number" ? node.key : void 0,
|
|
695
|
+
parentKey: typeof node.parentKey === "string" || typeof node.parentKey === "number" ? node.parentKey : node.parentKey == null ? null : void 0,
|
|
696
|
+
level: typeof node.level === "number" ? node.level : void 0
|
|
697
|
+
};
|
|
698
|
+
});
|
|
699
|
+
onCleanup(() => {
|
|
700
|
+
virtualizer.setDropTargetIndexResolver(void 0);
|
|
701
|
+
virtualizer.setDropTargetItemCountResolver(void 0);
|
|
702
|
+
virtualizer.setDropTargetResolver(void 0);
|
|
703
|
+
});
|
|
704
|
+
});
|
|
705
|
+
const rowIndexByKey = createMemo(() => {
|
|
706
|
+
const map = /* @__PURE__ */ new Map();
|
|
707
|
+
const rows = visibleRows();
|
|
708
|
+
for (let i = 0; i < rows.length; i += 1) map.set(rows[i].key, i);
|
|
709
|
+
return map;
|
|
710
|
+
});
|
|
711
|
+
const getAfterIndicatorIndexes = (absoluteIndex, renderRange) => {
|
|
712
|
+
const rows = visibleRows();
|
|
713
|
+
const current = rows[absoluteIndex];
|
|
714
|
+
if (!current) return [];
|
|
715
|
+
const next = rows[absoluteIndex + 1];
|
|
716
|
+
if (next && next.level >= current.level) return [];
|
|
717
|
+
const result = [];
|
|
718
|
+
let cursorIndex = absoluteIndex;
|
|
719
|
+
while (cursorIndex != null) {
|
|
720
|
+
const cursor = rows[cursorIndex];
|
|
721
|
+
if (!cursor) break;
|
|
722
|
+
if (!(!next || cursor.parentKey !== next.parentKey && next.level < cursor.level)) break;
|
|
723
|
+
result.push(cursorIndex);
|
|
724
|
+
if (cursor.parentKey == null) break;
|
|
725
|
+
cursorIndex = rowIndexByKey().get(cursor.parentKey) ?? null;
|
|
726
|
+
}
|
|
727
|
+
if (!renderRange) return result;
|
|
728
|
+
return result.filter((index) => index >= renderRange.start && index < renderRange.end);
|
|
729
|
+
};
|
|
730
|
+
createEffect(() => {
|
|
731
|
+
if (!virtualizer) return;
|
|
732
|
+
const direction = resolveTreeDirection(ref());
|
|
733
|
+
const treeDelegate = createTreeDropTargetDelegate({
|
|
734
|
+
getDropTargetFromPoint: parentCollectionRenderer?.dropTargetDelegate?.getDropTargetFromPoint ?? ((_x, _y, _v) => null),
|
|
735
|
+
getKeyboardNavigationTarget: parentCollectionRenderer?.dropTargetDelegate?.getKeyboardNavigationTarget,
|
|
736
|
+
getKeyboardPageNavigationTarget: parentCollectionRenderer?.dropTargetDelegate?.getKeyboardPageNavigationTarget
|
|
737
|
+
}, state, direction, virtualizer.getBaseKeyboardNavigationTarget);
|
|
738
|
+
virtualizer.setKeyboardNavigationOverride(treeDelegate.getKeyboardNavigationTarget ? (target, dir, isValid) => treeDelegate.getKeyboardNavigationTarget(target, dir, isValid) : void 0);
|
|
739
|
+
onCleanup(() => {
|
|
740
|
+
virtualizer.setKeyboardNavigationOverride(void 0);
|
|
741
|
+
});
|
|
742
|
+
});
|
|
743
|
+
const collectionRenderer = createMemo(() => ({
|
|
744
|
+
...parentCollectionRenderer,
|
|
745
|
+
renderItem: (item) => item,
|
|
746
|
+
renderDropIndicator: (index, position) => dndDropIndicator(index, position) ?? parentCollectionRenderer?.renderDropIndicator?.(index, position)
|
|
747
|
+
}));
|
|
748
|
+
const rootKeyByNodeKey = createMemo(() => {
|
|
749
|
+
const rootMap = /* @__PURE__ */ new Map();
|
|
750
|
+
for (const row of visibleRows()) {
|
|
751
|
+
let rootKey = row.key;
|
|
752
|
+
let parentKey = row.parentKey;
|
|
753
|
+
while (parentKey != null) {
|
|
754
|
+
rootKey = parentKey;
|
|
755
|
+
parentKey = state.collection.getParentKey(parentKey);
|
|
756
|
+
}
|
|
757
|
+
rootMap.set(row.key, rootKey);
|
|
758
|
+
}
|
|
759
|
+
return rootMap;
|
|
760
|
+
});
|
|
761
|
+
const renderRange = createMemo(() => {
|
|
762
|
+
const range = virtualRange();
|
|
763
|
+
if (!range) return null;
|
|
764
|
+
return {
|
|
765
|
+
start: range.start,
|
|
766
|
+
end: range.end
|
|
767
|
+
};
|
|
768
|
+
});
|
|
769
|
+
const renderableRows = createMemo(() => {
|
|
770
|
+
const offset = renderRange()?.start ?? 0;
|
|
771
|
+
return virtualizedVisibleRows().map((node, index) => ({
|
|
772
|
+
node,
|
|
773
|
+
globalIndex: offset + index
|
|
774
|
+
}));
|
|
775
|
+
});
|
|
776
|
+
const sectionedRenderableRows = createMemo(() => {
|
|
777
|
+
if (!hasSections()) return null;
|
|
778
|
+
const rootMap = rootKeyByNodeKey();
|
|
779
|
+
const rows = renderableRows();
|
|
780
|
+
return (stateProps.items ?? []).map((entry) => {
|
|
781
|
+
if (!isCollectionSection(entry)) return {
|
|
782
|
+
type: "single",
|
|
783
|
+
item: entry,
|
|
784
|
+
rows: rows.filter((row) => rootMap.get(row.node.key) === entry.key)
|
|
785
|
+
};
|
|
786
|
+
const sectionRootKeys = new Set(entry.items.map((item) => item.key));
|
|
787
|
+
return {
|
|
788
|
+
type: "section",
|
|
789
|
+
section: entry,
|
|
790
|
+
rows: rows.filter((row) => {
|
|
791
|
+
const rootKey = rootMap.get(row.node.key);
|
|
792
|
+
return rootKey != null && sectionRootKeys.has(rootKey);
|
|
793
|
+
})
|
|
794
|
+
};
|
|
795
|
+
});
|
|
796
|
+
});
|
|
797
|
+
const renderTreeRow = (node, itemIndex) => {
|
|
798
|
+
const beforeIndicator = () => collectionRenderer().renderDropIndicator?.(itemIndex, "before");
|
|
799
|
+
const onIndicator = () => collectionRenderer().renderDropIndicator?.(itemIndex, "on");
|
|
800
|
+
const afterIndicatorIndexes = () => getAfterIndicatorIndexes(itemIndex, renderRange());
|
|
801
|
+
const itemData = treeItemDataFromNode(node);
|
|
802
|
+
const itemState = {
|
|
803
|
+
isExpanded: node.isExpanded ?? false,
|
|
804
|
+
isExpandable: node.isExpandable ?? false,
|
|
805
|
+
level: node.level
|
|
806
|
+
};
|
|
807
|
+
return <>
|
|
808
|
+
{beforeIndicator()}
|
|
809
|
+
{onIndicator()}
|
|
810
|
+
{props.children(itemData, itemState)}
|
|
811
|
+
<For each={afterIndicatorIndexes()}>
|
|
812
|
+
{(afterIndex) => collectionRenderer().renderDropIndicator?.(afterIndex, "after")}
|
|
813
|
+
</For>
|
|
814
|
+
</>;
|
|
815
|
+
};
|
|
816
|
+
return <TreeContext.Provider value={contextValue()}>
|
|
817
|
+
<TreeStateContext.Provider value={state}>
|
|
818
|
+
<CollectionRendererContext.Provider value={collectionRenderer()}>
|
|
819
|
+
<div ref={(element) => {
|
|
820
|
+
setRef(element);
|
|
821
|
+
assignRef(local.ref, element);
|
|
822
|
+
}} {...mergeProps$1(domProps(), cleanTreeProps(), cleanFocusProps(), droppableCollection()?.collectionProps ?? {})} class={renderProps.class()} style={renderProps.style()} data-focused={state.isFocused || void 0} data-focus-visible={isFocusVisible() || void 0} data-disabled={ariaProps.isDisabled || void 0} data-empty={isEmpty() || void 0} data-drop-target={isRootDropTarget() || void 0} data-selection-mode={stateProps.selectionMode !== "none" ? stateProps.selectionMode : void 0} data-allows-dragging={hasDraggableDnd() || void 0}>
|
|
823
|
+
<SharedElementTransition>
|
|
824
|
+
{isEmpty() && local.renderEmptyState ? <div role="row" aria-level={1} style={{ display: "contents" }}>
|
|
825
|
+
<div role="gridcell" style={{ display: "contents" }}>
|
|
826
|
+
{local.renderEmptyState()}
|
|
827
|
+
</div>
|
|
828
|
+
</div> : <>
|
|
829
|
+
{virtualRange()?.offsetTop ? <div role="presentation" aria-hidden="true" style={{ height: `${virtualRange().offsetTop}px` }} data-virtualizer-spacer="top" /> : null}
|
|
830
|
+
<Show when={hasSections()} fallback={<For each={renderableRows()}>
|
|
831
|
+
{(row) => renderTreeRow(row.node, row.globalIndex)}
|
|
832
|
+
</For>}>
|
|
833
|
+
<For each={sectionedRenderableRows() ?? []}>
|
|
834
|
+
{(entry) => <Show when={entry.rows.length > 0}>
|
|
835
|
+
<Show when={entry.type === "section"} fallback={<For each={entry.rows}>
|
|
836
|
+
{(row) => renderTreeRow(row.node, row.globalIndex)}
|
|
837
|
+
</For>}>
|
|
838
|
+
<TreeSection>
|
|
839
|
+
{entry.type === "section" && entry.section.title ? <TreeHeader>{entry.section.title}</TreeHeader> : null}
|
|
840
|
+
<For each={entry.rows}>
|
|
841
|
+
{(row) => renderTreeRow(row.node, row.globalIndex)}
|
|
842
|
+
</For>
|
|
843
|
+
</TreeSection>
|
|
844
|
+
</Show>
|
|
845
|
+
</Show>}
|
|
846
|
+
</For>
|
|
847
|
+
</Show>
|
|
848
|
+
{virtualRange()?.offsetBottom ? <div role="presentation" aria-hidden="true" style={{ height: `${virtualRange().offsetBottom}px` }} data-virtualizer-spacer="bottom" /> : null}
|
|
849
|
+
</>}
|
|
850
|
+
</SharedElementTransition>
|
|
851
|
+
{local.hasMore && local.onLoadMore && <TreeLoadMoreItem onLoadMore={local.onLoadMore} isLoading={local.isLoading} loadingState={local.loadingState} class={local.loadMoreClass} style={local.loadMoreStyle}>
|
|
852
|
+
{local.renderLoadMoreItem?.({ isLoading: !!local.isLoading || local.loadingState === "loading" || local.loadingState === "loadingMore" })}
|
|
853
|
+
</TreeLoadMoreItem>}
|
|
854
|
+
</div>
|
|
855
|
+
</CollectionRendererContext.Provider>
|
|
856
|
+
</TreeStateContext.Provider>
|
|
857
|
+
</TreeContext.Provider>;
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* An item in a tree.
|
|
861
|
+
*/
|
|
862
|
+
function TreeItem(props) {
|
|
863
|
+
const [local, domProps] = splitProps(props, [
|
|
864
|
+
"class",
|
|
865
|
+
"style",
|
|
866
|
+
"slot",
|
|
867
|
+
"id",
|
|
868
|
+
"item",
|
|
869
|
+
"textValue",
|
|
870
|
+
"onAction",
|
|
871
|
+
"hasChildItems",
|
|
872
|
+
"isDisabled",
|
|
873
|
+
"href",
|
|
874
|
+
"target",
|
|
875
|
+
"download",
|
|
876
|
+
"rel",
|
|
877
|
+
"hrefLang",
|
|
878
|
+
"ping",
|
|
879
|
+
"referrerPolicy",
|
|
880
|
+
"routerOptions",
|
|
881
|
+
"ref",
|
|
882
|
+
"children"
|
|
883
|
+
]);
|
|
884
|
+
const context = useContext(TreeStateContext);
|
|
885
|
+
if (!context) throw new Error("TreeItem must be used within a Tree");
|
|
886
|
+
const state = context;
|
|
887
|
+
const treeContext = useContext(TreeContext);
|
|
888
|
+
const router = useRouter();
|
|
889
|
+
const linkProps = createMemo(() => useLinkProps({
|
|
890
|
+
href: local.href,
|
|
891
|
+
target: local.target,
|
|
892
|
+
rel: local.rel,
|
|
893
|
+
download: local.download,
|
|
894
|
+
ping: local.ping,
|
|
895
|
+
referrerPolicy: local.referrerPolicy
|
|
896
|
+
}));
|
|
897
|
+
const [ref, setRef] = createSignal(null);
|
|
898
|
+
const setItemRef = (element) => {
|
|
899
|
+
setRef(element);
|
|
900
|
+
assignRef(local.ref, element);
|
|
901
|
+
};
|
|
902
|
+
const itemNode = createMemo(() => {
|
|
903
|
+
const node = state.collection.getItem(local.id);
|
|
904
|
+
if (!node) return {
|
|
905
|
+
type: "item",
|
|
906
|
+
key: local.id,
|
|
907
|
+
value: local.item?.value ?? null,
|
|
908
|
+
textValue: local.textValue ?? String(local.id),
|
|
909
|
+
level: 0,
|
|
910
|
+
index: 0,
|
|
911
|
+
hasChildNodes: !!local.hasChildItems,
|
|
912
|
+
childNodes: [],
|
|
913
|
+
isDisabled: local.isDisabled,
|
|
914
|
+
isExpandable: !!local.hasChildItems,
|
|
915
|
+
isExpanded: false
|
|
916
|
+
};
|
|
917
|
+
return node;
|
|
918
|
+
});
|
|
919
|
+
const treeItemAria = createTreeItem(() => ({
|
|
920
|
+
node: itemNode(),
|
|
921
|
+
selectionBehavior: state.selectionBehavior,
|
|
922
|
+
onAction: local.onAction,
|
|
923
|
+
isDisabled: local.isDisabled,
|
|
924
|
+
textValue: local.textValue
|
|
925
|
+
}), () => state, ref);
|
|
926
|
+
const isSelected = () => treeItemAria.isSelected;
|
|
927
|
+
const isDisabled = () => treeItemAria.isDisabled;
|
|
928
|
+
const isPressed = () => treeItemAria.isPressed;
|
|
929
|
+
const isExpanded = () => treeItemAria.isExpanded;
|
|
930
|
+
const isExpandable = () => treeItemAria.isExpandable;
|
|
931
|
+
const level = () => treeItemAria.level;
|
|
932
|
+
const { isHovered, hoverProps } = createHover({ get isDisabled() {
|
|
933
|
+
return isDisabled();
|
|
934
|
+
} });
|
|
935
|
+
const { isFocusVisible, focusProps } = createFocusRing();
|
|
936
|
+
const isFocused = createMemo(() => state.focusedKey === local.id);
|
|
937
|
+
const draggableItem = createMemo(() => {
|
|
938
|
+
if (!treeContext?.dragAndDropHooks?.useDraggableItem || !treeContext.dragState) return void 0;
|
|
939
|
+
return treeContext.dragAndDropHooks.useDraggableItem({ key: local.id }, treeContext.dragState);
|
|
940
|
+
});
|
|
941
|
+
const droppableItem = createMemo(() => {
|
|
942
|
+
if (!treeContext?.dragAndDropHooks?.useDroppableItem || !treeContext.dropState) return void 0;
|
|
943
|
+
return treeContext.dragAndDropHooks.useDroppableItem({ key: local.id }, treeContext.dropState, () => ref());
|
|
944
|
+
});
|
|
945
|
+
const renderValues = createMemo(() => ({
|
|
946
|
+
isSelected: isSelected(),
|
|
947
|
+
isFocused: isFocused(),
|
|
948
|
+
isFocusVisible: isFocusVisible() && isFocused(),
|
|
949
|
+
isPressed: isPressed(),
|
|
950
|
+
isHovered: isHovered(),
|
|
951
|
+
isDisabled: isDisabled(),
|
|
952
|
+
isExpanded: isExpanded(),
|
|
953
|
+
isExpandable: isExpandable(),
|
|
954
|
+
level: level(),
|
|
955
|
+
selectionMode: state.selectionMode,
|
|
956
|
+
selectionBehavior: state.selectionBehavior
|
|
957
|
+
}));
|
|
958
|
+
const renderProps = useRenderProps({
|
|
959
|
+
get children() {
|
|
960
|
+
return props.children;
|
|
961
|
+
},
|
|
962
|
+
class: local.class,
|
|
963
|
+
style: local.style,
|
|
964
|
+
defaultClassName: "solidaria-Tree-item"
|
|
965
|
+
}, renderValues);
|
|
966
|
+
const cleanRowProps = () => {
|
|
967
|
+
const { ref: _ref1, ...rest } = treeItemAria.rowProps;
|
|
968
|
+
return rest;
|
|
969
|
+
};
|
|
970
|
+
const cleanHoverProps = () => {
|
|
971
|
+
const { ref: _ref2, ...rest } = hoverProps;
|
|
972
|
+
return rest;
|
|
973
|
+
};
|
|
974
|
+
const cleanFocusProps = () => {
|
|
975
|
+
const { ref: _ref3, ...rest } = focusProps;
|
|
976
|
+
return rest;
|
|
977
|
+
};
|
|
978
|
+
const itemContextValue = createMemo(() => ({
|
|
979
|
+
node: itemNode(),
|
|
980
|
+
isExpanded: isExpanded(),
|
|
981
|
+
isExpandable: isExpandable(),
|
|
982
|
+
level: level()
|
|
983
|
+
}));
|
|
984
|
+
const rowStyle = () => ({
|
|
985
|
+
"--tree-item-level": String(level()),
|
|
986
|
+
...typeof renderProps.style() === "object" ? renderProps.style() : {}
|
|
987
|
+
});
|
|
988
|
+
const rowContent = () => <TreeItemContentContext.Provider value={renderValues()}>
|
|
989
|
+
<div {...treeItemAria.gridCellProps} class="solidaria-Tree-item-content">
|
|
990
|
+
{renderProps.renderChildren()}
|
|
991
|
+
</div>
|
|
992
|
+
</TreeItemContentContext.Provider>;
|
|
993
|
+
const mergedRowProps = () => mergeProps$1(cleanRowProps(), cleanHoverProps(), cleanFocusProps(), draggableItem()?.dragProps ?? {}, droppableItem()?.dropProps ?? {});
|
|
994
|
+
const onLinkedRowClick = (event) => {
|
|
995
|
+
const onClick = mergedRowProps().onClick;
|
|
996
|
+
onClick?.(event);
|
|
997
|
+
handleLinkClick(event, router, local.href, local.routerOptions);
|
|
998
|
+
};
|
|
999
|
+
const downloadAttr = () => {
|
|
1000
|
+
const download = linkProps().download;
|
|
1001
|
+
return typeof download === "boolean" ? download ? "" : void 0 : download;
|
|
1002
|
+
};
|
|
1003
|
+
const referrerPolicyAttr = () => linkProps().referrerPolicy || void 0;
|
|
1004
|
+
const linkedRowDomProps = () => local.href ? {
|
|
1005
|
+
onClick: onLinkedRowClick,
|
|
1006
|
+
"data-href": linkProps().href,
|
|
1007
|
+
"data-target": linkProps().target,
|
|
1008
|
+
"data-download": downloadAttr(),
|
|
1009
|
+
"data-rel": linkProps().rel,
|
|
1010
|
+
"data-hreflang": local.hrefLang,
|
|
1011
|
+
"data-ping": linkProps().ping,
|
|
1012
|
+
"data-referrer-policy": referrerPolicyAttr()
|
|
1013
|
+
} : {};
|
|
1014
|
+
return <TreeItemContext.Provider value={itemContextValue()}>
|
|
1015
|
+
<div ref={setItemRef} {...domProps} {...mergedRowProps()} {...linkedRowDomProps()} class={renderProps.class()} style={rowStyle()} data-selected={isSelected() || void 0} data-focused={isFocused() || void 0} data-focus-visible={isFocusVisible() && isFocused() || void 0} data-pressed={isPressed() || void 0} data-hovered={isHovered() || void 0} data-disabled={isDisabled() || void 0} data-expanded={isExpanded() || void 0} data-expandable={isExpandable() || void 0} data-has-child-items={isExpandable() || void 0} data-level={level()} data-selection-mode={treeContext?.state.selectionMode !== "none" ? treeContext?.state.selectionMode : void 0} data-dragging={draggableItem()?.isDragging || void 0} data-drop-target={droppableItem()?.isDropTarget || void 0}>
|
|
1016
|
+
{rowContent()}
|
|
1017
|
+
</div>
|
|
1018
|
+
</TreeItemContext.Provider>;
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* A button to expand/collapse a tree item.
|
|
1022
|
+
*/
|
|
1023
|
+
function TreeExpandButton(props) {
|
|
1024
|
+
const itemContext = useContext(TreeItemContext);
|
|
1025
|
+
if (!itemContext) throw new Error("TreeExpandButton must be used within a Tree");
|
|
1026
|
+
const stateContext = useContext(TreeStateContext);
|
|
1027
|
+
if (!stateContext) throw new Error("TreeExpandButton must be used within a Tree");
|
|
1028
|
+
const state = stateContext;
|
|
1029
|
+
const treeItemAria = createTreeItem(() => ({ node: itemContext.node }), () => state, () => null);
|
|
1030
|
+
const cleanExpandProps = () => {
|
|
1031
|
+
const { ref: _ref, ...rest } = treeItemAria.expandButtonProps;
|
|
1032
|
+
return rest;
|
|
1033
|
+
};
|
|
1034
|
+
const dataProps = () => {
|
|
1035
|
+
const result = {};
|
|
1036
|
+
for (const key in props) if (key.startsWith("data-")) result[key] = props[key];
|
|
1037
|
+
return result;
|
|
1038
|
+
};
|
|
1039
|
+
const isExpanded = createMemo(() => state.isExpanded(itemContext.node.key));
|
|
1040
|
+
const renderChildren = () => {
|
|
1041
|
+
if (typeof props.children === "function") return props.children({ isExpanded: isExpanded() });
|
|
1042
|
+
return props.children;
|
|
1043
|
+
};
|
|
1044
|
+
return <Show when={itemContext.isExpandable}>
|
|
1045
|
+
<button {...cleanExpandProps()} {...dataProps()} class={props.class ?? "solidaria-Tree-expand-button"} style={props.style} data-expanded={isExpanded() || void 0}>
|
|
1046
|
+
{renderChildren()}
|
|
1047
|
+
</button>
|
|
1048
|
+
</Show>;
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* A checkbox for item selection in a tree.
|
|
1052
|
+
*/
|
|
1053
|
+
function TreeSelectionCheckbox(props) {
|
|
1054
|
+
const context = useContext(TreeStateContext);
|
|
1055
|
+
if (!context) throw new Error("TreeSelectionCheckbox must be used within a Tree");
|
|
1056
|
+
const state = context;
|
|
1057
|
+
const treeSelectionCheckboxAria = createTreeSelectionCheckbox(() => ({ key: props.itemKey }), () => state);
|
|
1058
|
+
return <input {...treeSelectionCheckboxAria.checkboxProps} class={props.class ?? "solidaria-Tree-checkbox"} style={props.style} tabIndex={props.excludeFromTabOrder ? -1 : void 0} aria-label={props["aria-label"] ?? treeSelectionCheckboxAria.checkboxProps["aria-label"]} />;
|
|
1059
|
+
}
|
|
1060
|
+
function TreeLoadMoreItem(props) {
|
|
1061
|
+
let sentinelRef;
|
|
1062
|
+
const [isPending, setIsPending] = createSignal(false);
|
|
1063
|
+
const isLoading = () => !!props.isLoading || props.loadingState === "loading" || props.loadingState === "loadingMore" || isPending();
|
|
1064
|
+
const triggerLoadMore = async () => {
|
|
1065
|
+
if (isLoading()) return;
|
|
1066
|
+
setIsPending(true);
|
|
1067
|
+
try {
|
|
1068
|
+
await props.onLoadMore();
|
|
1069
|
+
} finally {
|
|
1070
|
+
setIsPending(false);
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
createEffect(() => {});
|
|
1074
|
+
const renderProps = useRenderProps({
|
|
1075
|
+
get children() {
|
|
1076
|
+
return props.children ?? (() => isLoading() ? "Loading more..." : "Load more");
|
|
1077
|
+
},
|
|
1078
|
+
class: props.class,
|
|
1079
|
+
style: props.style,
|
|
1080
|
+
defaultClassName: "solidaria-Tree-loadMore"
|
|
1081
|
+
}, () => ({ isLoading: isLoading() }));
|
|
1082
|
+
return <>
|
|
1083
|
+
<div style={{
|
|
1084
|
+
position: "relative",
|
|
1085
|
+
width: 0,
|
|
1086
|
+
height: 0,
|
|
1087
|
+
overflow: "hidden"
|
|
1088
|
+
}} inert>
|
|
1089
|
+
<div ref={sentinelRef} style={{
|
|
1090
|
+
position: "absolute",
|
|
1091
|
+
height: "1px",
|
|
1092
|
+
width: "1px"
|
|
1093
|
+
}} />
|
|
1094
|
+
</div>
|
|
1095
|
+
<div role="row" aria-level={props.level ?? 1} onFocus={() => {
|
|
1096
|
+
triggerLoadMore();
|
|
1097
|
+
}} onFocusIn={() => {
|
|
1098
|
+
triggerLoadMore();
|
|
1099
|
+
}} class={renderProps.class()} style={renderProps.style()} data-loading={isLoading() || void 0} data-level={props.level ?? 1}>
|
|
1100
|
+
<div role="gridcell" onFocus={() => {
|
|
1101
|
+
triggerLoadMore();
|
|
1102
|
+
}}>
|
|
1103
|
+
{renderProps.renderChildren()}
|
|
1104
|
+
</div>
|
|
1105
|
+
</div>
|
|
1106
|
+
</>;
|
|
1107
|
+
}
|
|
1108
|
+
function TreeItemContent(props) {
|
|
1109
|
+
const context = useContext(TreeItemContentContext);
|
|
1110
|
+
if (!context) throw new Error("TreeItemContent must be used within a TreeItem");
|
|
1111
|
+
const renderProps = useRenderProps({ get children() {
|
|
1112
|
+
return props.children;
|
|
1113
|
+
} }, () => context);
|
|
1114
|
+
return <>{renderProps.renderChildren()}</>;
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* A section within a Tree. Renders as `role="rowgroup"` and supplies its
|
|
1118
|
+
* optional {@link TreeHeader} with the row/rowheader props that wire up the
|
|
1119
|
+
* section's `aria-labelledby` (mirrors upstream `TreeSection`, which reuses
|
|
1120
|
+
* `useGridListSection`).
|
|
1121
|
+
*/
|
|
1122
|
+
function TreeSection(props) {
|
|
1123
|
+
const [local, domProps] = splitProps(props, [
|
|
1124
|
+
"children",
|
|
1125
|
+
"class",
|
|
1126
|
+
"style",
|
|
1127
|
+
"slot",
|
|
1128
|
+
"ref"
|
|
1129
|
+
]);
|
|
1130
|
+
const section = createGridListSection({ get "aria-label"() {
|
|
1131
|
+
return domProps["aria-label"];
|
|
1132
|
+
} });
|
|
1133
|
+
const renderProps = useRenderProps({
|
|
1134
|
+
children: void 0,
|
|
1135
|
+
class: local.class,
|
|
1136
|
+
style: local.style,
|
|
1137
|
+
defaultClassName: "solidaria-TreeSection"
|
|
1138
|
+
}, () => ({ hasChildren: true }));
|
|
1139
|
+
const filteredDomProps = createMemo(() => filterDOMProps(domProps, { global: true }));
|
|
1140
|
+
return <div ref={(el) => assignRef(local.ref, el)} {...filteredDomProps()} {...section.rowGroupProps} class={renderProps.class()} style={renderProps.style()} slot={local.slot} data-section>
|
|
1141
|
+
<GridListHeaderContext.Provider value={section.rowProps}>
|
|
1142
|
+
<GridListHeaderInnerContext.Provider value={section.rowHeaderProps}>
|
|
1143
|
+
{local.children}
|
|
1144
|
+
</GridListHeaderInnerContext.Provider>
|
|
1145
|
+
</GridListHeaderContext.Provider>
|
|
1146
|
+
</div>;
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* The header of a {@link TreeSection}. Mirrors upstream `TreeHeader`, which is a
|
|
1150
|
+
* thin wrapper over `GridListHeader` with a Tree-specific class. The row and
|
|
1151
|
+
* rowheader semantics come from the enclosing section through context.
|
|
1152
|
+
*/
|
|
1153
|
+
function TreeHeader(props) {
|
|
1154
|
+
return <GridListHeader class="solidaria-TreeHeader" {...props}>
|
|
1155
|
+
{props.children}
|
|
1156
|
+
</GridListHeader>;
|
|
1157
|
+
}
|
|
1158
|
+
Tree.Item = TreeItem;
|
|
1159
|
+
Tree.ExpandButton = TreeExpandButton;
|
|
1160
|
+
Tree.SelectionCheckbox = TreeSelectionCheckbox;
|
|
1161
|
+
Tree.LoadMoreItem = TreeLoadMoreItem;
|
|
1162
|
+
Tree.Section = TreeSection;
|
|
1163
|
+
Tree.Header = TreeHeader;
|
|
1164
|
+
function areSetsEqual(a, b) {
|
|
1165
|
+
if (a.size !== b.size) return false;
|
|
1166
|
+
for (const entry of a) if (!b.has(entry)) return false;
|
|
1167
|
+
return true;
|
|
1168
|
+
}
|
|
1169
|
+
//#endregion
|
|
1170
|
+
export { Tree, TreeContext, TreeExpandButton, TreeHeader, TreeItem, TreeItemContent, TreeItemContext, TreeLoadMoreItem, TreeSection, TreeSelectionCheckbox, TreeStateContext };
|
|
1171
|
+
|
|
1172
|
+
//# sourceMappingURL=Tree.jsx.map
|