torch-glare 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/apps/lib/components/ActionButton.tsx +7 -12
- package/apps/lib/components/ActionsGroup.tsx +4 -15
- package/apps/lib/components/AlertDialog.tsx +173 -191
- package/apps/lib/components/Avatar.tsx +13 -16
- package/apps/lib/components/Badge.tsx +7 -3
- package/apps/lib/components/BadgeField.tsx +76 -71
- package/apps/lib/components/Breadcrumb.tsx +49 -85
- package/apps/lib/components/Button.tsx +20 -19
- package/apps/lib/components/ButtonGroup.tsx +31 -41
- package/apps/lib/components/Calendar.tsx +51 -29
- package/apps/lib/components/Card.tsx +2 -13
- package/apps/lib/components/ChartBlockTool.ts +17 -52
- package/apps/lib/components/Checkbox.tsx +9 -16
- package/apps/lib/components/ContextMenu.tsx +110 -106
- package/apps/lib/components/CountBadge.tsx +4 -6
- package/apps/lib/components/DataTable.tsx +196 -216
- package/apps/lib/components/DataViews/DataViewRadio.tsx +10 -8
- package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +21 -55
- package/apps/lib/components/DataViews/DataViewsHeader.tsx +1 -3
- package/apps/lib/components/DataViews/DataViewsLayout.tsx +5 -12
- package/apps/lib/components/DataViews/FilterPanel.tsx +173 -150
- package/apps/lib/components/DataViews/HeaderSearch.tsx +1 -5
- package/apps/lib/components/DataViews/InboxView.tsx +22 -68
- package/apps/lib/components/DataViews/InboxViewCard.tsx +68 -77
- package/apps/lib/components/DataViews/KanbanView.tsx +8 -25
- package/apps/lib/components/DataViews/PanelControls.tsx +3 -13
- package/apps/lib/components/DataViews/SettingsPanel.tsx +83 -89
- package/apps/lib/components/DataViews/TableView.tsx +8 -28
- package/apps/lib/components/DataViews/TreeView.tsx +12 -40
- package/apps/lib/components/DataViews/badgeAdapter.ts +32 -28
- package/apps/lib/components/DataViews/fieldRenderers.tsx +106 -141
- package/apps/lib/components/DataViews/filters/DatePickerRangeFilter.tsx +87 -0
- package/apps/lib/components/DataViews/filters/DateRangePopover.tsx +39 -32
- package/apps/lib/components/DataViews/filters/PresetChips.tsx +15 -15
- package/apps/lib/components/DataViews/filters/RangeSliderWithInputs.tsx +69 -58
- package/apps/lib/components/DataViews/index.ts +26 -26
- package/apps/lib/components/DataViews/tree/TreeDrawer.tsx +12 -16
- package/apps/lib/components/DataViews/tree/TreeSidebar.tsx +28 -31
- package/apps/lib/components/DataViews/types.ts +111 -114
- package/apps/lib/components/DatePicker.tsx +198 -191
- package/apps/lib/components/Dialog.tsx +92 -105
- package/apps/lib/components/Divider.tsx +21 -24
- package/apps/lib/components/Drawer.tsx +79 -139
- package/apps/lib/components/DropdownMenu.tsx +144 -181
- package/apps/lib/components/FieldHint.tsx +4 -11
- package/apps/lib/components/Form.tsx +146 -155
- package/apps/lib/components/FormStepper.tsx +9 -39
- package/apps/lib/components/HeaderBar.tsx +119 -0
- package/apps/lib/components/ImageAttachment.tsx +111 -73
- package/apps/lib/components/InnerLabelField.tsx +20 -16
- package/apps/lib/components/Input.tsx +171 -172
- package/apps/lib/components/InputField.tsx +44 -45
- package/apps/lib/components/InputOTP.tsx +68 -69
- package/apps/lib/components/Label.tsx +31 -35
- package/apps/lib/components/LabelField.tsx +4 -5
- package/apps/lib/components/LabeledCheckBox.tsx +8 -12
- package/apps/lib/components/LabeledRadio.tsx +7 -5
- package/apps/lib/components/LinkButton.tsx +2 -9
- package/apps/lib/components/LoginButton.tsx +4 -9
- package/apps/lib/components/PasswordLevel.tsx +5 -5
- package/apps/lib/components/Popover.tsx +15 -33
- package/apps/lib/components/ProfileMenu.tsx +67 -72
- package/apps/lib/components/Radio.tsx +1 -5
- package/apps/lib/components/RadioCard.tsx +9 -28
- package/apps/lib/components/ScrollArea.tsx +45 -43
- package/apps/lib/components/SearchField.tsx +49 -39
- package/apps/lib/components/SearchableSelect.tsx +46 -52
- package/apps/lib/components/SearchableTable.tsx +199 -219
- package/apps/lib/components/SearchableTree.tsx +469 -0
- package/apps/lib/components/SearchableTreeDialog.tsx +493 -0
- package/apps/lib/components/SectionBlock.tsx +4 -16
- package/apps/lib/components/Select.tsx +53 -80
- package/apps/lib/components/SimpleSelect.tsx +196 -187
- package/apps/lib/components/Skeleton.tsx +9 -12
- package/apps/lib/components/SlideDatePicker.tsx +215 -166
- package/apps/lib/components/SpinLoading.tsx +33 -49
- package/apps/lib/components/Stepper.tsx +13 -56
- package/apps/lib/components/Switch.tsx +8 -10
- package/apps/lib/components/TabFormItem.tsx +3 -12
- package/apps/lib/components/TabSwitch.tsx +7 -34
- package/apps/lib/components/Table.tsx +60 -75
- package/apps/lib/components/TableDnDWrapper.ts +15 -48
- package/apps/lib/components/TextEditor.tsx +93 -104
- package/apps/lib/components/Textarea.tsx +8 -12
- package/apps/lib/components/Timeline.tsx +21 -41
- package/apps/lib/components/Toast.tsx +83 -83
- package/apps/lib/components/Toggle.tsx +112 -114
- package/apps/lib/components/ToggleButton.tsx +1 -1
- package/apps/lib/components/Tooltip.tsx +24 -19
- package/apps/lib/components/TransparentLabel.tsx +61 -62
- package/apps/lib/components/TreeDropDown.tsx +86 -52
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +15 -48
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +16 -21
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +9 -20
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +3 -3
- package/apps/lib/components/TreeFolder/icons.tsx +14 -17
- package/apps/lib/components/TreeFolder/index.ts +15 -8
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +47 -52
- package/apps/lib/components/TreeFolder/types.ts +32 -32
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +117 -123
- package/apps/lib/hooks/useActiveTreeItem.ts +52 -55
- package/apps/lib/hooks/useClickOutside.ts +21 -20
- package/apps/lib/hooks/useDataViewsState.ts +86 -80
- package/apps/lib/hooks/useIsMobile.ts +12 -12
- package/apps/lib/hooks/useResize.ts +54 -65
- package/apps/lib/hooks/useTagSelection.ts +201 -201
- package/apps/lib/layouts/CNLayout.tsx +181 -140
- package/apps/lib/layouts/DataViewCard.tsx +4 -18
- package/apps/lib/layouts/FieldSection.tsx +2 -6
- package/apps/lib/layouts/TreeSubLayout.tsx +24 -38
- package/apps/lib/providers/ThemeProvider.tsx +8 -23
- package/apps/lib/registry.json +1004 -0
- package/apps/lib/tsconfig.json +9 -0
- package/apps/lib/utils/cn.ts +1 -1
- package/apps/lib/utils/dataViews/columnUtils.ts +46 -44
- package/apps/lib/utils/dataViews/fieldUtils.ts +70 -71
- package/apps/lib/utils/dataViews/nestedDataUtils.tsx +129 -122
- package/apps/lib/utils/dataViews/pathUtils.ts +74 -67
- package/apps/lib/utils/dataViews/rangeUtils.ts +121 -112
- package/apps/lib/utils/dataViews/treeUtils.ts +204 -211
- package/apps/lib/utils/dateFormat.ts +64 -54
- package/apps/lib/utils/markdownParser.ts +2 -7
- package/apps/lib/utils/resize.ts +21 -25
- package/apps/lib/utils/types.ts +13 -13
- package/dist/bin/index.js +8 -2
- package/dist/bin/index.js.map +1 -1
- package/dist/src/shared/getAvailableFiles.d.ts.map +1 -1
- package/dist/src/shared/getAvailableFiles.js +6 -1
- package/dist/src/shared/getAvailableFiles.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +7 -0
- package/dist/src/shared/loadRegistry.d.ts.map +1 -0
- package/dist/src/shared/loadRegistry.js +31 -0
- package/dist/src/shared/loadRegistry.js.map +1 -0
- package/dist/src/shared/resolveInstallPlan.d.ts +12 -0
- package/dist/src/shared/resolveInstallPlan.d.ts.map +1 -0
- package/dist/src/shared/resolveInstallPlan.js +39 -0
- package/dist/src/shared/resolveInstallPlan.js.map +1 -0
- package/dist/src/types/main.d.ts +24 -0
- package/dist/src/types/main.d.ts.map +1 -1
- package/docs/README.md +10 -2
- package/docs/components/action-button.md +30 -24
- package/docs/components/actions-group.md +26 -20
- package/docs/components/alert-dialog.md +45 -45
- package/docs/components/avatar.md +6 -2
- package/docs/components/badge-field.md +6 -2
- package/docs/components/badge.md +7 -1
- package/docs/components/breadcrumb.md +15 -40
- package/docs/components/button-group.md +13 -10
- package/docs/components/button.md +58 -33
- package/docs/components/calendar.md +26 -19
- package/docs/components/card.md +19 -16
- package/docs/components/chart-block-tool.md +128 -0
- package/docs/components/checkbox.md +16 -8
- package/docs/components/cn-layout.md +7 -1
- package/docs/components/context-menu.md +47 -24
- package/docs/components/count-badge.md +7 -1
- package/docs/components/data-table.md +45 -33
- package/docs/components/data-views-config-panel.md +18 -14
- package/docs/components/data-views-layout.md +20 -17
- package/docs/components/date-picker.md +30 -23
- package/docs/components/dialog.md +43 -42
- package/docs/components/divider.md +10 -4
- package/docs/components/drawer.md +8 -33
- package/docs/components/dropdown-menu.md +51 -32
- package/docs/components/field-hint.md +37 -25
- package/docs/components/field-section.md +9 -3
- package/docs/components/form-stepper.md +6 -0
- package/docs/components/form.md +17 -20
- package/docs/components/header-bar.md +187 -0
- package/docs/components/image-attachment.md +33 -41
- package/docs/components/inbox-view.md +16 -5
- package/docs/components/inner-label-field.md +34 -24
- package/docs/components/input-field.md +18 -10
- package/docs/components/input-otp.md +14 -11
- package/docs/components/input.md +22 -16
- package/docs/components/kanban-view.md +15 -5
- package/docs/components/label-field.md +32 -22
- package/docs/components/label.md +43 -32
- package/docs/components/labeled-check-box.md +16 -8
- package/docs/components/labeled-radio.md +18 -11
- package/docs/components/link-button.md +7 -1
- package/docs/components/login-button.md +8 -2
- package/docs/components/password-level.md +37 -24
- package/docs/components/popover.md +26 -23
- package/docs/components/profile-menu.md +38 -27
- package/docs/components/radio-card.md +16 -9
- package/docs/components/radio.md +16 -8
- package/docs/components/scroll-area.md +6 -2
- package/docs/components/search-field.md +14 -6
- package/docs/components/searchable-select.md +19 -14
- package/docs/components/searchable-table.md +60 -41
- package/docs/components/searchable-tree-dialog.md +190 -0
- package/docs/components/searchable-tree.md +200 -0
- package/docs/components/section-block.md +130 -4
- package/docs/components/select.md +23 -18
- package/docs/components/simple-select.md +14 -10
- package/docs/components/skeleton.md +43 -33
- package/docs/components/slide-date-picker.md +37 -29
- package/docs/components/spin-loading.md +32 -23
- package/docs/components/stepper.md +6 -0
- package/docs/components/switch.md +14 -6
- package/docs/components/tab-form-item.md +7 -1
- package/docs/components/tab-switch.md +13 -6
- package/docs/components/table-dnd-wrapper.md +105 -0
- package/docs/components/table-view.md +15 -5
- package/docs/components/table.md +28 -28
- package/docs/components/text-editor.md +19 -13
- package/docs/components/textarea.md +15 -7
- package/docs/components/timeline.md +6 -0
- package/docs/components/toast.md +35 -26
- package/docs/components/toggle-button.md +24 -21
- package/docs/components/toggle.md +23 -15
- package/docs/components/tooltip.md +42 -30
- package/docs/components/transparent-label.md +29 -20
- package/docs/components/tree-drop-down.md +31 -23
- package/docs/components/tree-sub-layout.md +6 -2
- package/docs/components/tree-view.md +16 -5
- package/docs/explanation/architecture.md +54 -0
- package/docs/explanation/design-system.md +52 -0
- package/docs/how-to/data-views-from-backend-response.md +7 -4
- package/docs/how-to/guides.md +24 -18
- package/docs/migration/changelog.md +38 -0
- package/docs/reference/cli.md +87 -0
- package/docs/reference/components.md +11 -12
- package/docs/reference/hooks.md +8 -8
- package/docs/reference/providers.md +22 -22
- package/docs/reference/tailwind-plugins.md +2 -2
- package/docs/reference/theme.md +85 -0
- package/docs/reference/types.md +4 -4
- package/docs/reference/utilities.md +19 -26
- package/docs/tutorials/building-first-form.md +20 -13
- package/docs/tutorials/component-composition.md +34 -50
- package/docs/tutorials/getting-started.md +2 -2
- package/docs/tutorials/theming-basics.md +13 -10
- package/package.json +31 -3
- package/dist/src/commands/block.d.ts +0 -5
- package/dist/src/commands/block.d.ts.map +0 -1
- package/dist/src/commands/block.js +0 -255
- package/dist/src/commands/block.js.map +0 -1
- package/dist/src/shared/configureFonts.d.ts +0 -6
- package/dist/src/shared/configureFonts.d.ts.map +0 -1
- package/dist/src/shared/configureFonts.js +0 -106
- package/dist/src/shared/configureFonts.js.map +0 -1
- package/dist/src/shared/configureGlobalCss.d.ts +0 -6
- package/dist/src/shared/configureGlobalCss.d.ts.map +0 -1
- package/dist/src/shared/configureGlobalCss.js +0 -154
- package/dist/src/shared/configureGlobalCss.js.map +0 -1
- package/dist/src/shared/configureTailwind.d.ts +0 -7
- package/dist/src/shared/configureTailwind.d.ts.map +0 -1
- package/dist/src/shared/configureTailwind.js +0 -163
- package/dist/src/shared/configureTailwind.js.map +0 -1
- package/dist/src/shared/detectFramework.d.ts +0 -23
- package/dist/src/shared/detectFramework.d.ts.map +0 -1
- package/dist/src/shared/detectFramework.js +0 -119
- package/dist/src/shared/detectFramework.js.map +0 -1
- package/dist/src/shared/installBaseUtils.d.ts +0 -5
- package/dist/src/shared/installBaseUtils.d.ts.map +0 -1
- package/dist/src/shared/installBaseUtils.js +0 -79
- package/dist/src/shared/installBaseUtils.js.map +0 -1
- package/dist/src/shared/resolveAliases.d.ts +0 -24
- package/dist/src/shared/resolveAliases.d.ts.map +0 -1
- package/dist/src/shared/resolveAliases.js +0 -98
- package/dist/src/shared/resolveAliases.js.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { TreeFolderBreadcrumb, TreeFolderMoveArgs, TreeFolderNode } from "./types"
|
|
1
|
+
import type { TreeFolderBreadcrumb, TreeFolderMoveArgs, TreeFolderNode } from "./types";
|
|
2
2
|
|
|
3
3
|
export function findPath(roots: TreeFolderNode[], id: string): TreeFolderNode[] | null {
|
|
4
4
|
for (const root of roots) {
|
|
5
|
-
const trail = walkPath(root, id, [])
|
|
6
|
-
if (trail) return trail
|
|
5
|
+
const trail = walkPath(root, id, []);
|
|
6
|
+
if (trail) return trail;
|
|
7
7
|
}
|
|
8
|
-
return null
|
|
8
|
+
return null;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
function walkPath(
|
|
@@ -13,102 +13,97 @@ function walkPath(
|
|
|
13
13
|
id: string,
|
|
14
14
|
trail: TreeFolderNode[],
|
|
15
15
|
): TreeFolderNode[] | null {
|
|
16
|
-
const next = [...trail, node]
|
|
17
|
-
if (node.id === id) return next
|
|
16
|
+
const next = [...trail, node];
|
|
17
|
+
if (node.id === id) return next;
|
|
18
18
|
if (node.children) {
|
|
19
19
|
for (const c of node.children) {
|
|
20
|
-
const found = walkPath(c, id, next)
|
|
21
|
-
if (found) return found
|
|
20
|
+
const found = walkPath(c, id, next);
|
|
21
|
+
if (found) return found;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
return null
|
|
24
|
+
return null;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function toBreadcrumb(path: TreeFolderNode[]): TreeFolderBreadcrumb {
|
|
28
|
-
return path.map((n) => ({ id: n.id, name: n.name }))
|
|
28
|
+
return path.map((n) => ({ id: n.id, name: n.name }));
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export function findNode(roots: TreeFolderNode[], id: string): TreeFolderNode | null {
|
|
32
32
|
for (const root of roots) {
|
|
33
|
-
if (root.id === id) return root
|
|
33
|
+
if (root.id === id) return root;
|
|
34
34
|
if (root.children) {
|
|
35
|
-
const inChild = findNode(root.children, id)
|
|
36
|
-
if (inChild) return inChild
|
|
35
|
+
const inChild = findNode(root.children, id);
|
|
36
|
+
if (inChild) return inChild;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
return null
|
|
39
|
+
return null;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export function isAncestor(parent: TreeFolderNode, id: string): boolean {
|
|
43
|
-
if (parent.id === id) return true
|
|
44
|
-
if (!parent.children) return false
|
|
43
|
+
if (parent.id === id) return true;
|
|
44
|
+
if (!parent.children) return false;
|
|
45
45
|
for (const c of parent.children) {
|
|
46
|
-
if (isAncestor(c, id)) return true
|
|
46
|
+
if (isAncestor(c, id)) return true;
|
|
47
47
|
}
|
|
48
|
-
return false
|
|
48
|
+
return false;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export function descendantIds(node: TreeFolderNode, includeSelf = false): Set<string> {
|
|
52
|
-
const out = new Set<string>()
|
|
53
|
-
if (includeSelf) out.add(node.id)
|
|
52
|
+
const out = new Set<string>();
|
|
53
|
+
if (includeSelf) out.add(node.id);
|
|
54
54
|
const walk = (n: TreeFolderNode) => {
|
|
55
|
-
if (!n.children) return
|
|
55
|
+
if (!n.children) return;
|
|
56
56
|
for (const c of n.children) {
|
|
57
|
-
out.add(c.id)
|
|
58
|
-
walk(c)
|
|
57
|
+
out.add(c.id);
|
|
58
|
+
walk(c);
|
|
59
59
|
}
|
|
60
|
-
}
|
|
61
|
-
walk(node)
|
|
62
|
-
return out
|
|
60
|
+
};
|
|
61
|
+
walk(node);
|
|
62
|
+
return out;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
export function applyMove(
|
|
66
|
-
|
|
67
|
-
args: TreeFolderMoveArgs,
|
|
68
|
-
): TreeFolderNode[] {
|
|
69
|
-
const dragSet = new Set(args.dragIds)
|
|
65
|
+
export function applyMove(roots: TreeFolderNode[], args: TreeFolderMoveArgs): TreeFolderNode[] {
|
|
66
|
+
const dragSet = new Set(args.dragIds);
|
|
70
67
|
|
|
71
68
|
if (args.parentId) {
|
|
72
69
|
for (const id of args.dragIds) {
|
|
73
|
-
const node = findNode(roots, id)
|
|
74
|
-
if (node && isAncestor(node, args.parentId)) return roots
|
|
70
|
+
const node = findNode(roots, id);
|
|
71
|
+
if (node && isAncestor(node, args.parentId)) return roots;
|
|
75
72
|
}
|
|
76
73
|
}
|
|
77
74
|
|
|
78
|
-
const extracted: TreeFolderNode[] = []
|
|
75
|
+
const extracted: TreeFolderNode[] = [];
|
|
79
76
|
|
|
80
77
|
const extract = (records: TreeFolderNode[]): TreeFolderNode[] =>
|
|
81
78
|
records
|
|
82
79
|
.map((n) => {
|
|
83
|
-
const next: TreeFolderNode = n.children
|
|
84
|
-
? { ...n, children: extract(n.children) }
|
|
85
|
-
: n
|
|
80
|
+
const next: TreeFolderNode = n.children ? { ...n, children: extract(n.children) } : n;
|
|
86
81
|
if (dragSet.has(n.id)) {
|
|
87
|
-
extracted.push(next)
|
|
88
|
-
return null
|
|
82
|
+
extracted.push(next);
|
|
83
|
+
return null;
|
|
89
84
|
}
|
|
90
|
-
return next
|
|
85
|
+
return next;
|
|
91
86
|
})
|
|
92
|
-
.filter((n): n is TreeFolderNode => n !== null)
|
|
87
|
+
.filter((n): n is TreeFolderNode => n !== null);
|
|
93
88
|
|
|
94
|
-
const pruned = extract(roots)
|
|
89
|
+
const pruned = extract(roots);
|
|
95
90
|
|
|
96
91
|
if (args.parentId == null) {
|
|
97
|
-
const at = Math.max(0, Math.min(args.index, pruned.length))
|
|
98
|
-
return [...pruned.slice(0, at), ...extracted, ...pruned.slice(at)]
|
|
92
|
+
const at = Math.max(0, Math.min(args.index, pruned.length));
|
|
93
|
+
return [...pruned.slice(0, at), ...extracted, ...pruned.slice(at)];
|
|
99
94
|
}
|
|
100
95
|
|
|
101
96
|
const insert = (records: TreeFolderNode[]): TreeFolderNode[] =>
|
|
102
97
|
records.map((n) => {
|
|
103
98
|
if (n.id === args.parentId) {
|
|
104
|
-
const kids = n.children ? [...n.children] : []
|
|
105
|
-
const at = Math.max(0, Math.min(args.index, kids.length))
|
|
106
|
-
kids.splice(at, 0, ...extracted)
|
|
107
|
-
return { ...n, children: kids }
|
|
99
|
+
const kids = n.children ? [...n.children] : [];
|
|
100
|
+
const at = Math.max(0, Math.min(args.index, kids.length));
|
|
101
|
+
kids.splice(at, 0, ...extracted);
|
|
102
|
+
return { ...n, children: kids };
|
|
108
103
|
}
|
|
109
|
-
if (n.children) return { ...n, children: insert(n.children) }
|
|
110
|
-
return n
|
|
111
|
-
})
|
|
104
|
+
if (n.children) return { ...n, children: insert(n.children) };
|
|
105
|
+
return n;
|
|
106
|
+
});
|
|
112
107
|
|
|
113
|
-
return insert(pruned)
|
|
108
|
+
return insert(pruned);
|
|
114
109
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactNode } from "react"
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
3
|
export type TreeFolderNodeType =
|
|
4
4
|
| "folder"
|
|
@@ -13,49 +13,49 @@ export type TreeFolderNodeType =
|
|
|
13
13
|
| "link"
|
|
14
14
|
| "section"
|
|
15
15
|
| "container"
|
|
16
|
-
| (string &
|
|
16
|
+
| (string & Record<never, never>);
|
|
17
17
|
|
|
18
18
|
export type TreeFolderNode = {
|
|
19
|
-
id: string
|
|
20
|
-
name: string
|
|
21
|
-
type?: TreeFolderNodeType
|
|
22
|
-
icon?: ReactNode
|
|
23
|
-
meta?: ReactNode
|
|
24
|
-
disabled?: boolean
|
|
25
|
-
draggable?: boolean
|
|
26
|
-
droppable?: boolean
|
|
27
|
-
data?: unknown
|
|
28
|
-
children?: TreeFolderNode[]
|
|
29
|
-
}
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
type?: TreeFolderNodeType;
|
|
22
|
+
icon?: ReactNode;
|
|
23
|
+
meta?: ReactNode;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
draggable?: boolean;
|
|
26
|
+
droppable?: boolean;
|
|
27
|
+
data?: unknown;
|
|
28
|
+
children?: TreeFolderNode[];
|
|
29
|
+
};
|
|
30
30
|
|
|
31
31
|
export type TreeFolderMoveArgs = {
|
|
32
|
-
dragIds: string[]
|
|
33
|
-
parentId: string | null
|
|
34
|
-
index: number
|
|
35
|
-
}
|
|
32
|
+
dragIds: string[];
|
|
33
|
+
parentId: string | null;
|
|
34
|
+
index: number;
|
|
35
|
+
};
|
|
36
36
|
|
|
37
37
|
export type TreeFolderIconResolver = (
|
|
38
38
|
node: TreeFolderNode,
|
|
39
39
|
state: { isOpen: boolean; isInternal: boolean; isSelected: boolean },
|
|
40
|
-
) => ReactNode
|
|
40
|
+
) => ReactNode;
|
|
41
41
|
|
|
42
|
-
export type TreeFolderBreadcrumb = Array<{ id: string; name: string }
|
|
42
|
+
export type TreeFolderBreadcrumb = Array<{ id: string; name: string }>;
|
|
43
43
|
|
|
44
44
|
// ---------------------------------------------------------------------------
|
|
45
45
|
// Visible-row + DnD primitives.
|
|
46
46
|
// ---------------------------------------------------------------------------
|
|
47
47
|
|
|
48
48
|
export type TreeFolderVisibleRow = {
|
|
49
|
-
node: TreeFolderNode
|
|
50
|
-
level: number
|
|
49
|
+
node: TreeFolderNode;
|
|
50
|
+
level: number;
|
|
51
51
|
/** Resolved parent id (null for roots). */
|
|
52
|
-
parentId: string | null
|
|
52
|
+
parentId: string | null;
|
|
53
53
|
/** Position of this node among its siblings in the source tree (0-based). */
|
|
54
|
-
childIndex: number
|
|
54
|
+
childIndex: number;
|
|
55
55
|
/** True when the node is internal AND open. */
|
|
56
|
-
isOpen: boolean
|
|
56
|
+
isOpen: boolean;
|
|
57
57
|
/** True for internal nodes (any node with non-empty children). */
|
|
58
|
-
isInternal: boolean
|
|
58
|
+
isInternal: boolean;
|
|
59
59
|
/**
|
|
60
60
|
* Connector-line geometry. `isLastChild` toggles the row's own bend between L
|
|
61
61
|
* (last) and T (non-last). `ancestorHasMoreSiblings[d]` is true when the
|
|
@@ -63,15 +63,15 @@ export type TreeFolderVisibleRow = {
|
|
|
63
63
|
* controls whether the vertical guide renders in that ancestor's gutter.
|
|
64
64
|
* Length === `level`.
|
|
65
65
|
*/
|
|
66
|
-
isLastChild: boolean
|
|
67
|
-
ancestorHasMoreSiblings: boolean[]
|
|
68
|
-
}
|
|
66
|
+
isLastChild: boolean;
|
|
67
|
+
ancestorHasMoreSiblings: boolean[];
|
|
68
|
+
};
|
|
69
69
|
|
|
70
70
|
/** Where the pointer is dropping relative to the hovered row. */
|
|
71
|
-
export type TreeFolderDropPosition = "before" | "after" | "inside"
|
|
71
|
+
export type TreeFolderDropPosition = "before" | "after" | "inside";
|
|
72
72
|
|
|
73
73
|
export type TreeFolderDropTarget = {
|
|
74
74
|
/** The id whose `parentId` the drop will resolve to. */
|
|
75
|
-
rowId: string
|
|
76
|
-
position: TreeFolderDropPosition
|
|
77
|
-
}
|
|
75
|
+
rowId: string;
|
|
76
|
+
position: TreeFolderDropPosition;
|
|
77
|
+
};
|
|
@@ -1,50 +1,46 @@
|
|
|
1
|
-
"use client"
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import { useCallback, useEffect, useRef, useState } from "react"
|
|
4
|
-
import { isAncestor } from "./treeFolderUtils"
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { isAncestor } from "./treeFolderUtils";
|
|
5
5
|
import type {
|
|
6
6
|
TreeFolderDropPosition,
|
|
7
7
|
TreeFolderDropTarget,
|
|
8
8
|
TreeFolderMoveArgs,
|
|
9
9
|
TreeFolderNode,
|
|
10
10
|
TreeFolderVisibleRow,
|
|
11
|
-
} from "./types"
|
|
11
|
+
} from "./types";
|
|
12
12
|
|
|
13
|
-
type RowLookup = Map<string, TreeFolderVisibleRow
|
|
13
|
+
type RowLookup = Map<string, TreeFolderVisibleRow>;
|
|
14
14
|
|
|
15
|
-
const SCROLL_EDGE_PX = 32
|
|
16
|
-
const SCROLL_SPEED_PX_PER_FRAME = 8
|
|
17
|
-
const DRAG_DATA_MIME = "application/x-treefolder-ids"
|
|
15
|
+
const SCROLL_EDGE_PX = 32;
|
|
16
|
+
const SCROLL_SPEED_PX_PER_FRAME = 8;
|
|
17
|
+
const DRAG_DATA_MIME = "application/x-treefolder-ids";
|
|
18
18
|
|
|
19
19
|
export type UseTreeFolderDnDOptions = {
|
|
20
|
-
data: TreeFolderNode[]
|
|
21
|
-
rowsById: RowLookup
|
|
22
|
-
scrollContainerRef: React.RefObject<HTMLDivElement | null
|
|
23
|
-
enabled: boolean
|
|
24
|
-
onMove?: (args: TreeFolderMoveArgs) => void
|
|
20
|
+
data: TreeFolderNode[];
|
|
21
|
+
rowsById: RowLookup;
|
|
22
|
+
scrollContainerRef: React.RefObject<HTMLDivElement | null>;
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
onMove?: (args: TreeFolderMoveArgs) => void;
|
|
25
25
|
/**
|
|
26
26
|
* Predicate. Return false to forbid the drop. Defaults to allow except for
|
|
27
27
|
* dropping a node into itself or a descendant.
|
|
28
28
|
*/
|
|
29
|
-
canDrop?: (args: {
|
|
30
|
-
|
|
31
|
-
parentId: string | null
|
|
32
|
-
index: number
|
|
33
|
-
}) => boolean
|
|
34
|
-
}
|
|
29
|
+
canDrop?: (args: { dragIds: string[]; parentId: string | null; index: number }) => boolean;
|
|
30
|
+
};
|
|
35
31
|
|
|
36
32
|
export type UseTreeFolderDnDResult = {
|
|
37
|
-
dragIds: string[]
|
|
38
|
-
dropTarget: TreeFolderDropTarget | null
|
|
33
|
+
dragIds: string[];
|
|
34
|
+
dropTarget: TreeFolderDropTarget | null;
|
|
39
35
|
getRowDragHandlers: (rowId: string) => {
|
|
40
|
-
draggable: boolean
|
|
41
|
-
onDragStart: (e: React.DragEvent<HTMLElement>) => void
|
|
42
|
-
onDragEnd: (e: React.DragEvent<HTMLElement>) => void
|
|
43
|
-
onDragOver: (e: React.DragEvent<HTMLElement>) => void
|
|
44
|
-
onDragLeave: (e: React.DragEvent<HTMLElement>) => void
|
|
45
|
-
onDrop: (e: React.DragEvent<HTMLElement>) => void
|
|
46
|
-
}
|
|
47
|
-
}
|
|
36
|
+
draggable: boolean;
|
|
37
|
+
onDragStart: (e: React.DragEvent<HTMLElement>) => void;
|
|
38
|
+
onDragEnd: (e: React.DragEvent<HTMLElement>) => void;
|
|
39
|
+
onDragOver: (e: React.DragEvent<HTMLElement>) => void;
|
|
40
|
+
onDragLeave: (e: React.DragEvent<HTMLElement>) => void;
|
|
41
|
+
onDrop: (e: React.DragEvent<HTMLElement>) => void;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
48
44
|
|
|
49
45
|
export function useTreeFolderDnD({
|
|
50
46
|
data,
|
|
@@ -54,108 +50,108 @@ export function useTreeFolderDnD({
|
|
|
54
50
|
onMove,
|
|
55
51
|
canDrop,
|
|
56
52
|
}: UseTreeFolderDnDOptions): UseTreeFolderDnDResult {
|
|
57
|
-
const [dragIds, setDragIds] = useState<string[]>([])
|
|
58
|
-
const [dropTarget, setDropTarget] = useState<TreeFolderDropTarget | null>(null)
|
|
53
|
+
const [dragIds, setDragIds] = useState<string[]>([]);
|
|
54
|
+
const [dropTarget, setDropTarget] = useState<TreeFolderDropTarget | null>(null);
|
|
59
55
|
|
|
60
56
|
// Auto-scroll loop while the user is dragging near a container edge.
|
|
61
|
-
const autoScrollDeltaRef = useRef(0)
|
|
62
|
-
const autoScrollRafRef = useRef<number | null>(null)
|
|
57
|
+
const autoScrollDeltaRef = useRef(0);
|
|
58
|
+
const autoScrollRafRef = useRef<number | null>(null);
|
|
63
59
|
|
|
64
60
|
const stopAutoScroll = useCallback(() => {
|
|
65
|
-
autoScrollDeltaRef.current = 0
|
|
61
|
+
autoScrollDeltaRef.current = 0;
|
|
66
62
|
if (autoScrollRafRef.current != null) {
|
|
67
|
-
cancelAnimationFrame(autoScrollRafRef.current)
|
|
68
|
-
autoScrollRafRef.current = null
|
|
63
|
+
cancelAnimationFrame(autoScrollRafRef.current);
|
|
64
|
+
autoScrollRafRef.current = null;
|
|
69
65
|
}
|
|
70
|
-
}, [])
|
|
66
|
+
}, []);
|
|
71
67
|
|
|
72
68
|
const tickAutoScroll = useCallback(() => {
|
|
73
|
-
const el = scrollContainerRef.current
|
|
74
|
-
const delta = autoScrollDeltaRef.current
|
|
69
|
+
const el = scrollContainerRef.current;
|
|
70
|
+
const delta = autoScrollDeltaRef.current;
|
|
75
71
|
if (!el || delta === 0) {
|
|
76
|
-
autoScrollRafRef.current = null
|
|
77
|
-
return
|
|
72
|
+
autoScrollRafRef.current = null;
|
|
73
|
+
return;
|
|
78
74
|
}
|
|
79
|
-
el.scrollTop += delta
|
|
80
|
-
autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll)
|
|
81
|
-
}, [scrollContainerRef])
|
|
75
|
+
el.scrollTop += delta;
|
|
76
|
+
autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
|
|
77
|
+
}, [scrollContainerRef]);
|
|
82
78
|
|
|
83
79
|
const maybeAutoScroll = useCallback(
|
|
84
80
|
(clientY: number) => {
|
|
85
|
-
const el = scrollContainerRef.current
|
|
86
|
-
if (!el) return
|
|
87
|
-
const rect = el.getBoundingClientRect()
|
|
88
|
-
let delta = 0
|
|
89
|
-
if (clientY - rect.top < SCROLL_EDGE_PX) delta = -SCROLL_SPEED_PX_PER_FRAME
|
|
90
|
-
else if (rect.bottom - clientY < SCROLL_EDGE_PX) delta = SCROLL_SPEED_PX_PER_FRAME
|
|
91
|
-
autoScrollDeltaRef.current = delta
|
|
81
|
+
const el = scrollContainerRef.current;
|
|
82
|
+
if (!el) return;
|
|
83
|
+
const rect = el.getBoundingClientRect();
|
|
84
|
+
let delta = 0;
|
|
85
|
+
if (clientY - rect.top < SCROLL_EDGE_PX) delta = -SCROLL_SPEED_PX_PER_FRAME;
|
|
86
|
+
else if (rect.bottom - clientY < SCROLL_EDGE_PX) delta = SCROLL_SPEED_PX_PER_FRAME;
|
|
87
|
+
autoScrollDeltaRef.current = delta;
|
|
92
88
|
if (delta !== 0 && autoScrollRafRef.current == null) {
|
|
93
|
-
autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll)
|
|
89
|
+
autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
|
|
94
90
|
} else if (delta === 0) {
|
|
95
|
-
stopAutoScroll()
|
|
91
|
+
stopAutoScroll();
|
|
96
92
|
}
|
|
97
93
|
},
|
|
98
94
|
[scrollContainerRef, stopAutoScroll, tickAutoScroll],
|
|
99
|
-
)
|
|
95
|
+
);
|
|
100
96
|
|
|
101
|
-
useEffect(() => stopAutoScroll, [stopAutoScroll])
|
|
97
|
+
useEffect(() => stopAutoScroll, [stopAutoScroll]);
|
|
102
98
|
|
|
103
99
|
const computePosition = useCallback(
|
|
104
100
|
(target: HTMLElement, clientY: number, isInternal: boolean): TreeFolderDropPosition => {
|
|
105
|
-
const rect = target.getBoundingClientRect()
|
|
106
|
-
const offset = clientY - rect.top
|
|
107
|
-
const ratio = offset / rect.height
|
|
101
|
+
const rect = target.getBoundingClientRect();
|
|
102
|
+
const offset = clientY - rect.top;
|
|
103
|
+
const ratio = offset / rect.height;
|
|
108
104
|
// Leaves can't accept "inside" drops — squash that zone into before/after.
|
|
109
|
-
if (!isInternal) return ratio < 0.5 ? "before" : "after"
|
|
110
|
-
if (ratio < 0.25) return "before"
|
|
111
|
-
if (ratio > 0.75) return "after"
|
|
112
|
-
return "inside"
|
|
105
|
+
if (!isInternal) return ratio < 0.5 ? "before" : "after";
|
|
106
|
+
if (ratio < 0.25) return "before";
|
|
107
|
+
if (ratio > 0.75) return "after";
|
|
108
|
+
return "inside";
|
|
113
109
|
},
|
|
114
110
|
[],
|
|
115
|
-
)
|
|
111
|
+
);
|
|
116
112
|
|
|
117
113
|
const resolveMoveArgs = useCallback(
|
|
118
114
|
(drag: string[], drop: TreeFolderDropTarget): TreeFolderMoveArgs | null => {
|
|
119
|
-
const targetRow = rowsById.get(drop.rowId)
|
|
120
|
-
if (!targetRow) return null
|
|
115
|
+
const targetRow = rowsById.get(drop.rowId);
|
|
116
|
+
if (!targetRow) return null;
|
|
121
117
|
|
|
122
|
-
let parentId: string | null
|
|
123
|
-
let index: number
|
|
118
|
+
let parentId: string | null;
|
|
119
|
+
let index: number;
|
|
124
120
|
|
|
125
121
|
if (drop.position === "inside") {
|
|
126
|
-
parentId = targetRow.node.id
|
|
122
|
+
parentId = targetRow.node.id;
|
|
127
123
|
// Drop at the end of the target's children.
|
|
128
|
-
index = targetRow.node.children?.length ?? 0
|
|
124
|
+
index = targetRow.node.children?.length ?? 0;
|
|
129
125
|
} else {
|
|
130
|
-
parentId = targetRow.parentId
|
|
131
|
-
index = drop.position === "before" ? targetRow.childIndex : targetRow.childIndex + 1
|
|
126
|
+
parentId = targetRow.parentId;
|
|
127
|
+
index = drop.position === "before" ? targetRow.childIndex : targetRow.childIndex + 1;
|
|
132
128
|
}
|
|
133
129
|
|
|
134
130
|
// Reject: dropping into self or any descendant.
|
|
135
131
|
for (const id of drag) {
|
|
136
|
-
const node = rowsById.get(id)?.node
|
|
137
|
-
if (!node) continue
|
|
138
|
-
if (parentId && (node.id === parentId || isAncestor(node, parentId))) return null
|
|
132
|
+
const node = rowsById.get(id)?.node;
|
|
133
|
+
if (!node) continue;
|
|
134
|
+
if (parentId && (node.id === parentId || isAncestor(node, parentId))) return null;
|
|
139
135
|
}
|
|
140
136
|
|
|
141
|
-
if (canDrop && !canDrop({ dragIds: drag, parentId, index })) return null
|
|
137
|
+
if (canDrop && !canDrop({ dragIds: drag, parentId, index })) return null;
|
|
142
138
|
|
|
143
139
|
// No-op safety: skipping the equivalent of "drop where you already are".
|
|
144
140
|
if (drag.length === 1) {
|
|
145
|
-
const onlyDrag = rowsById.get(drag[0])
|
|
141
|
+
const onlyDrag = rowsById.get(drag[0]);
|
|
146
142
|
if (
|
|
147
143
|
onlyDrag &&
|
|
148
144
|
onlyDrag.parentId === parentId &&
|
|
149
145
|
(onlyDrag.childIndex === index || onlyDrag.childIndex + 1 === index)
|
|
150
146
|
) {
|
|
151
|
-
return null
|
|
147
|
+
return null;
|
|
152
148
|
}
|
|
153
149
|
}
|
|
154
150
|
|
|
155
|
-
return { dragIds: drag, parentId, index }
|
|
151
|
+
return { dragIds: drag, parentId, index };
|
|
156
152
|
},
|
|
157
153
|
[rowsById, canDrop],
|
|
158
|
-
)
|
|
154
|
+
);
|
|
159
155
|
|
|
160
156
|
const getRowDragHandlers = useCallback(
|
|
161
157
|
(rowId: string) => {
|
|
@@ -167,77 +163,75 @@ export function useTreeFolderDnD({
|
|
|
167
163
|
onDragOver: () => {},
|
|
168
164
|
onDragLeave: () => {},
|
|
169
165
|
onDrop: () => {},
|
|
170
|
-
}
|
|
166
|
+
};
|
|
171
167
|
}
|
|
172
168
|
return {
|
|
173
169
|
draggable: true,
|
|
174
170
|
onDragStart: (e: React.DragEvent<HTMLElement>) => {
|
|
175
|
-
const ids = [rowId]
|
|
176
|
-
setDragIds(ids)
|
|
177
|
-
e.dataTransfer.effectAllowed = "move"
|
|
171
|
+
const ids = [rowId];
|
|
172
|
+
setDragIds(ids);
|
|
173
|
+
e.dataTransfer.effectAllowed = "move";
|
|
178
174
|
try {
|
|
179
|
-
e.dataTransfer.setData(DRAG_DATA_MIME, ids.join(","))
|
|
175
|
+
e.dataTransfer.setData(DRAG_DATA_MIME, ids.join(","));
|
|
180
176
|
// Required for Firefox to initiate the drag at all.
|
|
181
|
-
e.dataTransfer.setData("text/plain", ids.join(","))
|
|
177
|
+
e.dataTransfer.setData("text/plain", ids.join(","));
|
|
182
178
|
} catch {
|
|
183
179
|
// setData can throw in some sandboxed contexts; ignore.
|
|
184
180
|
}
|
|
185
181
|
},
|
|
186
182
|
onDragEnd: () => {
|
|
187
|
-
setDragIds([])
|
|
188
|
-
setDropTarget(null)
|
|
189
|
-
stopAutoScroll()
|
|
183
|
+
setDragIds([]);
|
|
184
|
+
setDropTarget(null);
|
|
185
|
+
stopAutoScroll();
|
|
190
186
|
},
|
|
191
187
|
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
|
192
|
-
if (dragIds.length === 0) return
|
|
188
|
+
if (dragIds.length === 0) return;
|
|
193
189
|
// Reject self-drops upfront so the cursor reflects "no drop" outside the tree.
|
|
194
190
|
if (dragIds.includes(rowId)) {
|
|
195
|
-
e.dataTransfer.dropEffect = "none"
|
|
196
|
-
return
|
|
191
|
+
e.dataTransfer.dropEffect = "none";
|
|
192
|
+
return;
|
|
197
193
|
}
|
|
198
|
-
const row = rowsById.get(rowId)
|
|
199
|
-
if (!row) return
|
|
194
|
+
const row = rowsById.get(rowId);
|
|
195
|
+
if (!row) return;
|
|
200
196
|
// Reject dropping onto a descendant of any dragged node.
|
|
201
197
|
for (const dragId of dragIds) {
|
|
202
|
-
const dragNode = rowsById.get(dragId)?.node
|
|
198
|
+
const dragNode = rowsById.get(dragId)?.node;
|
|
203
199
|
if (dragNode && isAncestor(dragNode, rowId)) {
|
|
204
|
-
e.dataTransfer.dropEffect = "none"
|
|
205
|
-
return
|
|
200
|
+
e.dataTransfer.dropEffect = "none";
|
|
201
|
+
return;
|
|
206
202
|
}
|
|
207
203
|
}
|
|
208
|
-
e.preventDefault()
|
|
209
|
-
e.dataTransfer.dropEffect = "move"
|
|
210
|
-
const position = computePosition(e.currentTarget, e.clientY, row.isInternal)
|
|
204
|
+
e.preventDefault();
|
|
205
|
+
e.dataTransfer.dropEffect = "move";
|
|
206
|
+
const position = computePosition(e.currentTarget, e.clientY, row.isInternal);
|
|
211
207
|
// Only setState when something actually changed (avoids re-render storms).
|
|
212
208
|
setDropTarget((prev) =>
|
|
213
|
-
prev && prev.rowId === rowId && prev.position === position
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
)
|
|
217
|
-
maybeAutoScroll(e.clientY)
|
|
209
|
+
prev && prev.rowId === rowId && prev.position === position ? prev : { rowId, position },
|
|
210
|
+
);
|
|
211
|
+
maybeAutoScroll(e.clientY);
|
|
218
212
|
},
|
|
219
213
|
onDragLeave: () => {
|
|
220
214
|
// No-op: onDragOver on the next row will overwrite dropTarget. Clearing
|
|
221
215
|
// here would flicker the indicator during normal row-to-row hovering.
|
|
222
216
|
},
|
|
223
217
|
onDrop: (e: React.DragEvent<HTMLElement>) => {
|
|
224
|
-
if (dragIds.length === 0) return
|
|
225
|
-
e.preventDefault()
|
|
226
|
-
const row = rowsById.get(rowId)
|
|
218
|
+
if (dragIds.length === 0) return;
|
|
219
|
+
e.preventDefault();
|
|
220
|
+
const row = rowsById.get(rowId);
|
|
227
221
|
if (!row) {
|
|
228
|
-
setDragIds([])
|
|
229
|
-
setDropTarget(null)
|
|
230
|
-
stopAutoScroll()
|
|
231
|
-
return
|
|
222
|
+
setDragIds([]);
|
|
223
|
+
setDropTarget(null);
|
|
224
|
+
stopAutoScroll();
|
|
225
|
+
return;
|
|
232
226
|
}
|
|
233
|
-
const position = computePosition(e.currentTarget, e.clientY, row.isInternal)
|
|
234
|
-
const moveArgs = resolveMoveArgs(dragIds, { rowId, position })
|
|
235
|
-
if (moveArgs) onMove?.(moveArgs)
|
|
236
|
-
setDragIds([])
|
|
237
|
-
setDropTarget(null)
|
|
238
|
-
stopAutoScroll()
|
|
227
|
+
const position = computePosition(e.currentTarget, e.clientY, row.isInternal);
|
|
228
|
+
const moveArgs = resolveMoveArgs(dragIds, { rowId, position });
|
|
229
|
+
if (moveArgs) onMove?.(moveArgs);
|
|
230
|
+
setDragIds([]);
|
|
231
|
+
setDropTarget(null);
|
|
232
|
+
stopAutoScroll();
|
|
239
233
|
},
|
|
240
|
-
}
|
|
234
|
+
};
|
|
241
235
|
},
|
|
242
236
|
[
|
|
243
237
|
enabled,
|
|
@@ -249,13 +243,13 @@ export function useTreeFolderDnD({
|
|
|
249
243
|
maybeAutoScroll,
|
|
250
244
|
stopAutoScroll,
|
|
251
245
|
],
|
|
252
|
-
)
|
|
246
|
+
);
|
|
253
247
|
|
|
254
248
|
// If the data tree changes mid-drag, clear stale targets.
|
|
255
249
|
useEffect(() => {
|
|
256
|
-
if (dragIds.length === 0) return
|
|
257
|
-
setDropTarget((prev) => (prev && rowsById.has(prev.rowId) ? prev : null))
|
|
258
|
-
}, [data, rowsById, dragIds.length])
|
|
250
|
+
if (dragIds.length === 0) return;
|
|
251
|
+
setDropTarget((prev) => (prev && rowsById.has(prev.rowId) ? prev : null));
|
|
252
|
+
}, [data, rowsById, dragIds.length]);
|
|
259
253
|
|
|
260
|
-
return { dragIds, dropTarget, getRowDragHandlers }
|
|
254
|
+
return { dragIds, dropTarget, getRowDragHandlers };
|
|
261
255
|
}
|