Skip to content

Commit 344011a

Browse files
committed
fix: handle drop events on empty tree
1 parent e7975ea commit 344011a

File tree

11 files changed

+63
-8
lines changed

11 files changed

+63
-8
lines changed

.changeset/metal-ears-design.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@headless-tree/core": patch
3+
---
4+
5+
fixed an issue where dropping items on an empty tree didn't trigger any events

examples/basic/src/style.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ body {
77

88
.tree {
99
max-width: 300px;
10+
min-height: 100px;
1011
}
1112

1213
.tree button[role="treeitem"] {

examples/comprehensive/src/style.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ body {
77

88
.tree {
99
max-width: 300px;
10+
min-height: 100px;
1011
}
1112

1213
.tree button[role="treeitem"] {

examples/nextjs/src/style.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ body {
77

88
.tree {
99
max-width: 300px;
10+
min-height: 100px;
1011
}
1112

1213
.tree button[role="treeitem"] {

examples/react-compiler/src/style.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ body {
77

88
.tree {
99
max-width: 300px;
10+
min-height: 100px;
1011
}
1112

1213
.tree button[role="treeitem"] {

packages/core/src/features/drag-and-drop/feature.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FeatureImplementation } from "../../types/core";
2-
import { DndDataRef, DragLineData } from "./types";
2+
import { DndDataRef, DragLineData, DragTarget } from "./types";
33
import {
44
canDrop,
55
getDragCode,
@@ -83,10 +83,38 @@ export const dragAndDropFeature: FeatureImplementation = {
8383
: { display: "none" };
8484
},
8585

86-
getContainerProps: ({ prev }, treeLabel) => {
86+
getContainerProps: ({ prev, tree }, treeLabel) => {
8787
const prevProps = prev?.(treeLabel);
8888
return {
8989
...prevProps,
90+
91+
onDragOver: (e: DragEvent) => {
92+
e.preventDefault();
93+
},
94+
95+
onDrop: async (e: DragEvent) => {
96+
// TODO merge implementation with itemInstance.onDrop
97+
const dataRef = tree.getDataRef<DndDataRef>();
98+
const target: DragTarget<any> = { item: tree.getRootItem() };
99+
100+
if (!canDrop(e.dataTransfer, target, tree)) {
101+
return;
102+
}
103+
104+
e.preventDefault();
105+
const config = tree.getConfig();
106+
const draggedItems = tree.getState().dnd?.draggedItems;
107+
108+
dataRef.current.lastDragCode = undefined;
109+
tree.applySubStateUpdate("dnd", null);
110+
111+
if (draggedItems) {
112+
await config.onDrop?.(draggedItems, target);
113+
} else if (e.dataTransfer) {
114+
await config.onDropForeignDragObject?.(e.dataTransfer, target);
115+
}
116+
},
117+
90118
style: {
91119
...prevProps?.style,
92120
position: "relative",
@@ -193,6 +221,7 @@ export const dragAndDropFeature: FeatureImplementation = {
193221
},
194222

195223
onDrop: async (e: DragEvent) => {
224+
e.stopPropagation();
196225
const dataRef = tree.getDataRef<DndDataRef>();
197226
const target = getDragTarget(e, item, tree);
198227

packages/core/src/features/tree/feature.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ export const treeFeature: FeatureImplementation<any> = {
8282
);
8383
},
8484

85+
getRootItem: ({ tree }) => {
86+
const { rootItemId } = tree.getConfig();
87+
return tree.getItemInstance(rootItemId);
88+
},
89+
8590
focusNextItem: ({ tree }) => {
8691
const focused = tree.getFocusedItem().getItemMeta();
8792
if (!focused) return;

packages/core/src/features/tree/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ export type TreeFeatureDef<T> = {
3333
/** @internal */
3434
getItemsMeta: () => ItemMeta[];
3535

36-
getFocusedItem: () => ItemInstance<any>;
36+
getFocusedItem: () => ItemInstance<T>;
37+
getRootItem: () => ItemInstance<T>;
3738
focusNextItem: () => void;
3839
focusPreviousItem: () => void;
3940
updateDomFocus: () => void;

packages/docs/docs/2-features/10-checkboxes.mdx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,18 @@ import { FeaturePageHeader } from "../../src/components/docs-page/feature-page-h
1414
feature="checkboxes"
1515
/>
1616

17-
<DemoBox tags={["feature/checkbox"]} initialStory="react-checkboxes-general--general" />
18-
19-
:::warning
17+
:::danger
2018

21-
The checkboxes feature was not released on the `latest` channel yet. You can try it out in a snapshot
22-
version with `npm i @headless-tree/core@snapshot` or `npm i @headless-tree/react@snapshot`.
19+
The checkboxes feature is still in development and considered Alpha. Its interface may change with breaking
20+
changes between patch version releases without additional notices. You can get notified of the proper
21+
release of the checkboxes feature on [Bluesky](https://bsky.app/profile/lukasbach.bsky.social) or
22+
[Discord](https://discord.gg/KuZ6EezzVw).
2323

2424
:::
2525

26+
<DemoBox tags={["feature/checkbox"]} initialStory="react-checkboxes-general--general" />
27+
28+
2629
The checkboxes feature allows users to multi-select items in a more permanent way than the normal
2730
selection feature, and visualize that state with checkboxes.
2831

packages/docs/docs/3-dnd/1-overview.mdx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ const tree = useTree<Item>({
7070
});
7171
```
7272

73+
:::tip
74+
75+
Add a minimum height to your tree container (the component receiving `tree.getProps()`) to make sure
76+
that users can drop items there even if the tree is empty.
77+
78+
:::
79+
7380
## The Drop Event
7481

7582
When the user drops tree items onto a target within the tree, the [`onDrop`](/api/core/interface/DragAndDropFeatureConfig#onDrop) event is called

0 commit comments

Comments
 (0)