@octane-xplat/dnd-kit 0.0.1 → 0.10.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/LICENSE +21 -0
- package/README.md +306 -2
- package/dist/native/components.js +275 -0
- package/dist/native/controller.js +236 -0
- package/dist/native/geometry.js +18 -0
- package/dist/native/index.js +4 -0
- package/dist/native/octane-client-build.json +8 -0
- package/dist/native/sort.js +11 -0
- package/dist/web/components.js +215 -0
- package/dist/web/controller.js +236 -0
- package/dist/web/geometry.web.js +16 -0
- package/dist/web/index.js +4 -0
- package/dist/web/octane-client-build.json +8 -0
- package/dist/web/sort.js +11 -0
- package/examples/sortable.macos.tsx +128 -0
- package/examples/sortable.tsx +22 -0
- package/package.json +83 -3
- package/src/abort.macos.ts +7 -0
- package/src/components.tsx +262 -0
- package/src/components.web.test.tsx +118 -0
- package/src/controller.mobile.test.ts +176 -0
- package/src/controller.ts +301 -0
- package/src/geometry.macos.test.ts +34 -0
- package/src/geometry.macos.ts +32 -0
- package/src/geometry.ts +18 -0
- package/src/geometry.web.ts +14 -0
- package/src/index.macos.ts +23 -0
- package/src/index.ts +21 -0
- package/src/index.web.ts +21 -0
- package/src/props.ts +83 -0
- package/src/sort.ts +19 -0
- package/types/generated/.tsrx-typegen-manifest.json +11 -0
- package/types/generated/components.d.ts +13 -0
- package/types/generated/controller.d.ts +32 -0
- package/types/generated/geometry.web.d.ts +3 -0
- package/types/generated/index.d.ts +5 -0
- package/types/generated/props.d.ts +84 -0
- package/types/generated/sort.d.ts +2 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { measure } from "./geometry.web.js";
|
|
2
|
+
import { DragDropManager, Draggable, Droppable, Sensor } from "@dnd-kit/abstract";
|
|
3
|
+
import { defaultCollisionDetection } from "@dnd-kit/collision";
|
|
4
|
+
import { batch, effect, signal, untracked } from "@dnd-kit/state";
|
|
5
|
+
//#region src/controller.ts
|
|
6
|
+
var PanDraggable = class extends Draggable {
|
|
7
|
+
onPan;
|
|
8
|
+
};
|
|
9
|
+
/** Xplat View supplies normalized pan input; the abstract core owns the drag lifecycle. */
|
|
10
|
+
var PanSensor = class extends Sensor {
|
|
11
|
+
bind(input) {
|
|
12
|
+
const source = input;
|
|
13
|
+
let origin = null;
|
|
14
|
+
let bound = true;
|
|
15
|
+
let base = {
|
|
16
|
+
x: 0,
|
|
17
|
+
y: 0
|
|
18
|
+
};
|
|
19
|
+
let queue = Promise.resolve();
|
|
20
|
+
const handle = async (event) => {
|
|
21
|
+
const manager = this.manager;
|
|
22
|
+
if (!bound) return;
|
|
23
|
+
if (event.state === "began") {
|
|
24
|
+
if (source.disabled || !manager.dragOperation.status.idle) return;
|
|
25
|
+
origin = measure(manager.draggableNodes.get(source.id));
|
|
26
|
+
if (!origin) return;
|
|
27
|
+
base = {
|
|
28
|
+
x: event.dx,
|
|
29
|
+
y: event.dy
|
|
30
|
+
};
|
|
31
|
+
manager.scrollShift$.value = {
|
|
32
|
+
x: 0,
|
|
33
|
+
y: 0
|
|
34
|
+
};
|
|
35
|
+
manager.actions.start({
|
|
36
|
+
source,
|
|
37
|
+
coordinates: origin.center
|
|
38
|
+
});
|
|
39
|
+
manager.dragOperation.shape = origin;
|
|
40
|
+
manager.refresh();
|
|
41
|
+
await manager.renderer.rendering;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (!origin || manager.dragOperation.source?.id !== source.id || !manager.dragOperation.status.dragging) return;
|
|
45
|
+
const x = event.dx - base.x;
|
|
46
|
+
const y = event.dy - base.y;
|
|
47
|
+
manager.actions.move({ to: {
|
|
48
|
+
x: origin.center.x + x,
|
|
49
|
+
y: origin.center.y + y
|
|
50
|
+
} });
|
|
51
|
+
await Promise.resolve();
|
|
52
|
+
manager.dragOperation.shape = origin.translate(x, y);
|
|
53
|
+
manager.refresh();
|
|
54
|
+
if (event.state === "ended" || event.state === "cancelled") {
|
|
55
|
+
manager.actions.stop({ canceled: event.state === "cancelled" });
|
|
56
|
+
origin = null;
|
|
57
|
+
} else manager.startAutoScroll();
|
|
58
|
+
};
|
|
59
|
+
source.onPan = (event) => {
|
|
60
|
+
queue = queue.then(() => handle(event)).catch((error) => {
|
|
61
|
+
origin = null;
|
|
62
|
+
this.manager.cancel();
|
|
63
|
+
console.error("[dnd-kit] pan failed", error);
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
return () => {
|
|
67
|
+
bound = false;
|
|
68
|
+
source.onPan = void 0;
|
|
69
|
+
origin = null;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
/** One controller per DndContext; no global registry or cross-root context assumptions. */
|
|
74
|
+
var DndController = class extends DragDropManager {
|
|
75
|
+
options = {};
|
|
76
|
+
draggableNodes = /* @__PURE__ */ new Map();
|
|
77
|
+
droppableNodes = /* @__PURE__ */ new Map();
|
|
78
|
+
scrollShift$ = signal({
|
|
79
|
+
x: 0,
|
|
80
|
+
y: 0
|
|
81
|
+
});
|
|
82
|
+
listeners = /* @__PURE__ */ new Set();
|
|
83
|
+
snapshot = {
|
|
84
|
+
active: null,
|
|
85
|
+
over: null,
|
|
86
|
+
transform: {
|
|
87
|
+
x: 0,
|
|
88
|
+
y: 0
|
|
89
|
+
},
|
|
90
|
+
isDragging: false
|
|
91
|
+
};
|
|
92
|
+
dispose;
|
|
93
|
+
scrollTimer;
|
|
94
|
+
destroyed = false;
|
|
95
|
+
constructor() {
|
|
96
|
+
super({ sensors: [PanSensor] });
|
|
97
|
+
this.dispose = effect(() => {
|
|
98
|
+
const operation = this.dragOperation;
|
|
99
|
+
const active = operation.source;
|
|
100
|
+
const over = operation.target;
|
|
101
|
+
const transform = operation.transform;
|
|
102
|
+
const isDragging = operation.status.dragging;
|
|
103
|
+
this.snapshot = {
|
|
104
|
+
active: active && !operation.status.idle ? {
|
|
105
|
+
id: active.id,
|
|
106
|
+
data: active.data
|
|
107
|
+
} : null,
|
|
108
|
+
over: over && !operation.status.idle ? {
|
|
109
|
+
id: over.id,
|
|
110
|
+
data: over.data
|
|
111
|
+
} : null,
|
|
112
|
+
transform: {
|
|
113
|
+
x: operation.status.idle ? 0 : transform.x + this.scrollShift$.value.x,
|
|
114
|
+
y: operation.status.idle ? 0 : transform.y + this.scrollShift$.value.y
|
|
115
|
+
},
|
|
116
|
+
isDragging
|
|
117
|
+
};
|
|
118
|
+
untracked(() => {
|
|
119
|
+
for (const listener of this.listeners) listener();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
const event = (canceled = false) => {
|
|
123
|
+
const operation = this.dragOperation;
|
|
124
|
+
return {
|
|
125
|
+
active: operation.source ? {
|
|
126
|
+
id: operation.source.id,
|
|
127
|
+
data: operation.source.data
|
|
128
|
+
} : null,
|
|
129
|
+
over: operation.target ? {
|
|
130
|
+
id: operation.target.id,
|
|
131
|
+
data: operation.target.data
|
|
132
|
+
} : null,
|
|
133
|
+
transform: { ...operation.transform },
|
|
134
|
+
isDragging: operation.status.dragging,
|
|
135
|
+
canceled
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
this.monitor.addEventListener("dragstart", () => this.options.onDragStart?.(event()));
|
|
139
|
+
this.monitor.addEventListener("dragover", () => this.options.onDragOver?.(event()));
|
|
140
|
+
this.monitor.addEventListener("dragmove", () => queueMicrotask(() => queueMicrotask(() => {
|
|
141
|
+
if (!this.destroyed && this.dragOperation.status.dragging) this.options.onDragMove?.(event());
|
|
142
|
+
})));
|
|
143
|
+
this.monitor.addEventListener("dragend", ({ canceled }) => {
|
|
144
|
+
this.stopAutoScroll();
|
|
145
|
+
if (canceled) this.options.onDragCancel?.(event(true));
|
|
146
|
+
else this.options.onDragEnd?.(event());
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
getSnapshot = () => this.snapshot;
|
|
150
|
+
subscribe = (listener) => {
|
|
151
|
+
this.listeners.add(listener);
|
|
152
|
+
return () => {
|
|
153
|
+
this.listeners.delete(listener);
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
registerDraggable(options) {
|
|
157
|
+
if (this.registry.draggables.has(options.id)) throw new Error(`Duplicate draggable id: ${options.id}`);
|
|
158
|
+
const source = new PanDraggable({
|
|
159
|
+
...options,
|
|
160
|
+
register: false,
|
|
161
|
+
effects: () => [() => this.registry.sensors.get(PanSensor).bind(source)]
|
|
162
|
+
}, this);
|
|
163
|
+
source.register();
|
|
164
|
+
return source;
|
|
165
|
+
}
|
|
166
|
+
registerDroppable(options) {
|
|
167
|
+
if (this.registry.droppables.has(options.id)) throw new Error(`Duplicate droppable id: ${options.id}`);
|
|
168
|
+
const target = new Droppable({
|
|
169
|
+
...options,
|
|
170
|
+
register: false,
|
|
171
|
+
accept: options.accept ? (source) => options.accept({
|
|
172
|
+
id: source.id,
|
|
173
|
+
data: source.data
|
|
174
|
+
}) : void 0,
|
|
175
|
+
collisionDetector: (input) => input.dragOperation.source?.id === input.droppable.id ? null : (this.options.collisionDetection ?? defaultCollisionDetection)(input)
|
|
176
|
+
}, this);
|
|
177
|
+
target.register();
|
|
178
|
+
return target;
|
|
179
|
+
}
|
|
180
|
+
refresh() {
|
|
181
|
+
batch(() => {
|
|
182
|
+
for (const droppable of this.registry.droppables) droppable.shape = measure(this.droppableNodes.get(droppable.id)) ?? void 0;
|
|
183
|
+
});
|
|
184
|
+
this.collisionObserver.forceUpdate();
|
|
185
|
+
}
|
|
186
|
+
cancel() {
|
|
187
|
+
this.stopAutoScroll();
|
|
188
|
+
this.actions.stop({ canceled: true });
|
|
189
|
+
}
|
|
190
|
+
startAutoScroll() {
|
|
191
|
+
if (this.scrollTimer || !this.options.autoScroll) return;
|
|
192
|
+
this.scrollTimer = setInterval(() => {
|
|
193
|
+
const scroll = this.options.autoScroll;
|
|
194
|
+
if (!scroll || !this.dragOperation.status.dragging) {
|
|
195
|
+
this.stopAutoScroll();
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const bounds = scroll.bounds();
|
|
199
|
+
if (!bounds) return;
|
|
200
|
+
const horizontal = scroll.axis === "x";
|
|
201
|
+
const start = horizontal ? bounds.x : bounds.y;
|
|
202
|
+
const size = horizontal ? bounds.width : bounds.height;
|
|
203
|
+
const point = horizontal ? this.dragOperation.position.current.x : this.dragOperation.position.current.y;
|
|
204
|
+
const threshold = Math.min(scroll.threshold ?? 40, size / 2);
|
|
205
|
+
if (threshold <= 0 || point < start || point > start + size) return;
|
|
206
|
+
const strength = point < start + threshold ? -(1 - (point - start) / threshold) : point > start + size - threshold ? 1 - (start + size - point) / threshold : 0;
|
|
207
|
+
const next = Math.max(0, Math.min(scroll.maxOffset(), scroll.offsetRef.current + strength * (scroll.speed ?? 12)));
|
|
208
|
+
if (next !== scroll.offsetRef.current) {
|
|
209
|
+
const before = scroll.offsetRef.current;
|
|
210
|
+
scroll.scrollTo(next);
|
|
211
|
+
const delta = scroll.offsetRef.current - before;
|
|
212
|
+
const shift = this.scrollShift$.peek();
|
|
213
|
+
this.scrollShift$.value = {
|
|
214
|
+
x: shift.x + (horizontal ? delta : 0),
|
|
215
|
+
y: shift.y + (horizontal ? 0 : delta)
|
|
216
|
+
};
|
|
217
|
+
this.refresh();
|
|
218
|
+
}
|
|
219
|
+
}, 16);
|
|
220
|
+
}
|
|
221
|
+
stopAutoScroll() {
|
|
222
|
+
if (this.scrollTimer) clearInterval(this.scrollTimer);
|
|
223
|
+
this.scrollTimer = void 0;
|
|
224
|
+
}
|
|
225
|
+
disposeController() {
|
|
226
|
+
this.destroyed = true;
|
|
227
|
+
this.cancel();
|
|
228
|
+
this.dispose();
|
|
229
|
+
this.listeners.clear();
|
|
230
|
+
this.draggableNodes.clear();
|
|
231
|
+
this.droppableNodes.clear();
|
|
232
|
+
this.destroy();
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
//#endregion
|
|
236
|
+
export { DndController };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Rectangle } from "@dnd-kit/geometry";
|
|
2
|
+
//#region src/geometry.web.ts
|
|
3
|
+
function measure(element) {
|
|
4
|
+
if (!element?.isConnected) return null;
|
|
5
|
+
const rect = element.getBoundingClientRect();
|
|
6
|
+
return rect.width > 0 && rect.height > 0 ? Rectangle.from(rect) : null;
|
|
7
|
+
}
|
|
8
|
+
function dragStyle(x, y) {
|
|
9
|
+
return {
|
|
10
|
+
transform: `translate(${x}px, ${y}px)`,
|
|
11
|
+
touchAction: "none",
|
|
12
|
+
zIndex: x || y ? 1 : 0
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { dragStyle, measure };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { arrayMove } from "./sort.js";
|
|
2
|
+
import { DndContext, SortableContext, SortableList, useDndContext, useDraggable, useDroppable, useSortable } from "./components.js";
|
|
3
|
+
import { closestCenter, closestCorners, defaultCollisionDetection, pointerIntersection, shapeIntersection } from "@dnd-kit/collision";
|
|
4
|
+
export { DndContext, SortableContext, SortableList, arrayMove, closestCenter, closestCorners, defaultCollisionDetection, pointerIntersection, shapeIntersection, useDndContext, useDraggable, useDroppable, useSortable };
|
package/dist/web/sort.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/sort.ts
|
|
2
|
+
/** Return a new order. Invalid indices leave the order unchanged. */
|
|
3
|
+
function arrayMove(items, from, to) {
|
|
4
|
+
const result = [...items];
|
|
5
|
+
if (!Number.isInteger(from) || !Number.isInteger(to) || from < 0 || to < 0 || from >= items.length || to >= items.length || from === to) return result;
|
|
6
|
+
const [item] = result.splice(from, 1);
|
|
7
|
+
result.splice(to, 0, item);
|
|
8
|
+
return result;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { arrayMove };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/** @jsxImportSource @octane-xplat/macos-renderer */
|
|
2
|
+
import { useCallback, useRef, useState } from 'octane'
|
|
3
|
+
import { Text, View, useMeasure } from '@octane-xplat/ui'
|
|
4
|
+
import { SortableList } from '../src/index'
|
|
5
|
+
|
|
6
|
+
/** AppKit scroll ownership stays explicit; all geometry and offsets use top-down points. */
|
|
7
|
+
export default function SortableExample() {
|
|
8
|
+
const [items, setItems] = useState(Array.from({ length: 20 }, (_, index) => `task-${index + 1}`))
|
|
9
|
+
const scrollRef = useRef<any>(null)
|
|
10
|
+
const offsetRef = useRef(0)
|
|
11
|
+
const initialized = useRef(false)
|
|
12
|
+
const measure = useMeasure()
|
|
13
|
+
const bindScroll = useCallback(
|
|
14
|
+
(view: any) => {
|
|
15
|
+
scrollRef.current = view
|
|
16
|
+
measure.ref(view?.contentView ?? null)
|
|
17
|
+
},
|
|
18
|
+
[measure.ref],
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
const top = () => {
|
|
22
|
+
const scroll = scrollRef.current
|
|
23
|
+
const clip = scroll?.contentView
|
|
24
|
+
const content = scroll?.documentView
|
|
25
|
+
if (!clip || !content) {
|
|
26
|
+
return 0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const flipped =
|
|
30
|
+
typeof content.isFlipped === 'function' ? content.isFlipped() : content.isFlipped
|
|
31
|
+
|
|
32
|
+
return flipped
|
|
33
|
+
? Number(clip.bounds.origin.y)
|
|
34
|
+
: Number(content.frame.size.height) -
|
|
35
|
+
Number(clip.bounds.size.height) -
|
|
36
|
+
Number(clip.bounds.origin.y)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<View>
|
|
41
|
+
<Text id="dnd-order">{items.join(',')}</Text>
|
|
42
|
+
<scrollview
|
|
43
|
+
id="dnd-scroll"
|
|
44
|
+
style={{ height: 240 }}
|
|
45
|
+
ref={bindScroll}
|
|
46
|
+
onScroll={() => {
|
|
47
|
+
offsetRef.current = top()
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
<flexboxlayout
|
|
51
|
+
flexDirection="column"
|
|
52
|
+
onLayoutChanged={() => {
|
|
53
|
+
const scroll = scrollRef.current
|
|
54
|
+
if (
|
|
55
|
+
initialized.current ||
|
|
56
|
+
!scroll?.window ||
|
|
57
|
+
scroll.documentView.frame.size.height <= scroll.contentView.bounds.size.height
|
|
58
|
+
) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
initialized.current = true
|
|
63
|
+
const content = scroll.documentView
|
|
64
|
+
const flipped =
|
|
65
|
+
typeof content.isFlipped === 'function' ? content.isFlipped() : content.isFlipped
|
|
66
|
+
|
|
67
|
+
scroll.contentView.scrollToPoint({
|
|
68
|
+
x: 0,
|
|
69
|
+
y: flipped
|
|
70
|
+
? 0
|
|
71
|
+
: Math.max(0, content.frame.size.height - scroll.contentView.bounds.size.height),
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
scroll.reflectScrolledClipView(scroll.contentView)
|
|
75
|
+
measure.ref(scroll.contentView)
|
|
76
|
+
offsetRef.current = top()
|
|
77
|
+
}}
|
|
78
|
+
>
|
|
79
|
+
<SortableList
|
|
80
|
+
items={items}
|
|
81
|
+
onReorder={setItems}
|
|
82
|
+
dnd={{
|
|
83
|
+
autoScroll: {
|
|
84
|
+
bounds: () => measure.bounds,
|
|
85
|
+
offsetRef,
|
|
86
|
+
maxOffset: () => {
|
|
87
|
+
const scroll = scrollRef.current
|
|
88
|
+
return Math.max(
|
|
89
|
+
0,
|
|
90
|
+
Number(scroll?.documentView?.frame?.size?.height ?? 0) -
|
|
91
|
+
Number(scroll?.contentView?.bounds?.size?.height ?? 0),
|
|
92
|
+
)
|
|
93
|
+
},
|
|
94
|
+
scrollTo: (offset) => {
|
|
95
|
+
const scroll = scrollRef.current
|
|
96
|
+
const content = scroll.documentView
|
|
97
|
+
const clip = scroll.contentView
|
|
98
|
+
const flipped =
|
|
99
|
+
typeof content.isFlipped === 'function'
|
|
100
|
+
? content.isFlipped()
|
|
101
|
+
: content.isFlipped
|
|
102
|
+
|
|
103
|
+
const y = flipped
|
|
104
|
+
? offset
|
|
105
|
+
: Math.max(
|
|
106
|
+
0,
|
|
107
|
+
Number(content.frame.size.height) -
|
|
108
|
+
Number(clip.bounds.size.height) -
|
|
109
|
+
offset,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
clip.scrollToPoint({ x: Number(clip.bounds.origin.x), y })
|
|
113
|
+
scroll.reflectScrolledClipView(clip)
|
|
114
|
+
offsetRef.current = top()
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
}}
|
|
118
|
+
renderItem={(id) => (
|
|
119
|
+
<View id={`dnd-${id}`} style={{ height: 64, padding: 12 }}>
|
|
120
|
+
<Text>{id}</Text>
|
|
121
|
+
</View>
|
|
122
|
+
)}
|
|
123
|
+
/>
|
|
124
|
+
</flexboxlayout>
|
|
125
|
+
</scrollview>
|
|
126
|
+
</View>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useState } from 'octane'
|
|
2
|
+
import { Text, View } from '@octane-xplat/ui'
|
|
3
|
+
import { SortableList } from '../src/index'
|
|
4
|
+
|
|
5
|
+
/** Controlled order: drag a row onto another row to commit a reorder. */
|
|
6
|
+
export default function SortableExample() {
|
|
7
|
+
const [items, setItems] = useState(['alpha', 'beta', 'gamma'])
|
|
8
|
+
return (
|
|
9
|
+
<View>
|
|
10
|
+
<Text id="dnd-order">{items.join(',')}</Text>
|
|
11
|
+
<SortableList
|
|
12
|
+
items={items}
|
|
13
|
+
onReorder={setItems}
|
|
14
|
+
renderItem={(id) => (
|
|
15
|
+
<View id={`dnd-${id}`} style={{ height: 64, padding: 12 }}>
|
|
16
|
+
<Text>{String(id)}</Text>
|
|
17
|
+
</View>
|
|
18
|
+
)}
|
|
19
|
+
/>
|
|
20
|
+
</View>
|
|
21
|
+
)
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,91 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octane-xplat/dnd-kit",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "Drag and drop and sortable lists for Octane web and NativeScript",
|
|
5
|
+
"homepage": "https://github.com/octane-xplat/octane-xplat/tree/main/packages/dnd-kit",
|
|
5
6
|
"license": "MIT",
|
|
6
7
|
"repository": {
|
|
7
8
|
"type": "git",
|
|
8
9
|
"url": "https://github.com/octane-xplat/octane-xplat",
|
|
9
10
|
"directory": "packages/dnd-kit"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"types",
|
|
15
|
+
"src",
|
|
16
|
+
"README.md",
|
|
17
|
+
"examples"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"macos": {
|
|
23
|
+
"types": "./types/generated/index.d.ts",
|
|
24
|
+
"default": "./src/index.macos.ts"
|
|
25
|
+
},
|
|
26
|
+
"web": {
|
|
27
|
+
"types": "./types/generated/index.d.ts",
|
|
28
|
+
"default": "./dist/web/index.js"
|
|
29
|
+
},
|
|
30
|
+
"native": {
|
|
31
|
+
"types": "./types/generated/index.d.ts",
|
|
32
|
+
"default": "./dist/native/index.js"
|
|
33
|
+
},
|
|
34
|
+
"types": "./types/generated/index.d.ts",
|
|
35
|
+
"default": "./dist/native/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@dnd-kit/abstract": "0.5.0",
|
|
43
|
+
"@dnd-kit/collision": "0.5.0",
|
|
44
|
+
"@dnd-kit/geometry": "0.5.0",
|
|
45
|
+
"@dnd-kit/state": "0.5.0",
|
|
46
|
+
"@octane-xplat/ui": "0.10.0",
|
|
47
|
+
"abort-controller": "3.0.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@nativescript-community/octane": "0.2.4",
|
|
51
|
+
"@nativescript/core": "9.1.2",
|
|
52
|
+
"@octane-xplat/macos-renderer": "0.10.0",
|
|
53
|
+
"@octanejs/vite-plugin": "0.1.61",
|
|
54
|
+
"@tsrx/typescript-plugin": "0.4.11",
|
|
55
|
+
"octane": "0.6.3",
|
|
56
|
+
"tsrx-typegen": "0.2.2",
|
|
57
|
+
"typescript": "5.9.3",
|
|
58
|
+
"vite": "8.3.0",
|
|
59
|
+
"vitest": "5.0.1"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"@nativescript-community/octane": ">=0.2.1 <1",
|
|
63
|
+
"@nativescript/core": ">=9.1.0 <10",
|
|
64
|
+
"octane": ">=0.6.3 <1"
|
|
65
|
+
},
|
|
66
|
+
"peerDependenciesMeta": {
|
|
67
|
+
"@nativescript-community/octane": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
70
|
+
"@nativescript/core": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"octane": {
|
|
74
|
+
"optional": true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"nativescript": {
|
|
78
|
+
"platforms": {
|
|
79
|
+
"android": "9.1.0",
|
|
80
|
+
"ios": "9.1.0"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"scripts": {
|
|
84
|
+
"build": "vite build && vite build --mode native && pnpm typegen && node ../../scripts/check-native-dist.mjs",
|
|
85
|
+
"typegen": "tsrx-typegen --project tsconfig.json",
|
|
86
|
+
"typecheck": "tsrx-tsc --noEmit -p tsconfig.json && tsrx-tsc --noEmit -p tsconfig.native.json && tsrx-tsc --noEmit -p tsconfig.example.json && tsrx-tsc --noEmit -p tsconfig.macos.json",
|
|
87
|
+
"test": "vitest run",
|
|
88
|
+
"pack:check": "tsrx-typegen --pack-check",
|
|
89
|
+
"test:packed": "pnpm build && node tests/packed-consumer.mjs"
|
|
10
90
|
}
|
|
11
|
-
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AbortController, AbortSignal } from 'abort-controller/dist/abort-controller.js'
|
|
2
|
+
|
|
3
|
+
// The abstract core constructs AbortController at drag begin. AppKit's JSC
|
|
4
|
+
// host does not provide it; install only missing globals and leave other hosts intact.
|
|
5
|
+
const host = globalThis as any
|
|
6
|
+
host.AbortController ??= AbortController
|
|
7
|
+
host.AbortSignal ??= AbortSignal
|