@stll/ui 0.38.0 → 0.40.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/README.md +4 -75
- package/dist/components/button.d.ts +2 -2
- package/dist/components/composer.d.ts +9 -1
- package/dist/components/composer.js +19 -2
- package/dist/components/copy-button.d.ts +19 -0
- package/dist/components/copy-button.js +64 -0
- package/dist/components/sidebar.d.ts +1 -1
- package/dist/components/workspace-shell.js +3 -3
- package/dist/icons.d.ts +2 -2
- package/dist/icons.js +2 -2
- package/dist/index.d.ts +3 -5
- package/dist/index.js +2 -4
- package/dist/kanban/index.d.ts +2 -5
- package/dist/kanban/index.js +1 -4
- package/dist/kanban/subgroup-board.d.ts +2 -27
- package/dist/kanban/subgroup-board.js +1 -25
- package/dist/kanban/virtual-cell.d.ts +1 -18
- package/dist/kanban/virtual-cell.js +5 -47
- package/dist/lib/control-size.d.ts +1 -1
- package/package.json +5 -5
- package/dist/kanban/sortable-edge.d.ts +0 -38
- package/dist/kanban/sortable-edge.js +0 -27
- package/dist/kanban/sortable-interactions.d.ts +0 -151
- package/dist/kanban/sortable-interactions.js +0 -527
- package/dist/kanban/sortable-interactions.logic.d.ts +0 -78
- package/dist/kanban/sortable-interactions.logic.js +0 -205
|
@@ -1,527 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { GripVerticalIcon } from "../icons.js";
|
|
3
|
-
import { cn } from "../lib/utils.js";
|
|
4
|
-
import "../lib/overlay-layer.js";
|
|
5
|
-
import { Button } from "../components/button.js";
|
|
6
|
-
import { KANBAN_BOARD_COLLISION_DETECTION, KANBAN_DROP_TARGET_TYPES, clearKanbanKeyboardTarget, getKanbanKeyboardTargetState, isKanbanDropSettled, kanbanKeyboardCoordinates } from "./sortable-interactions.logic.js";
|
|
7
|
-
import { isActiveTouchChange } from "./touch-identity.js";
|
|
8
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
import * as React$1 from "react";
|
|
10
|
-
import { createPortal } from "react-dom";
|
|
11
|
-
import { AutoScrollActivator, DndContext, DragOverlay, KeyboardSensor, MouseSensor, TouchSensor, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
|
|
12
|
-
import { SortableContext, useSortable } from "@dnd-kit/sortable";
|
|
13
|
-
//#region src/kanban/sortable-interactions.tsx
|
|
14
|
-
const KANBAN_MOUSE_ACTIVATION_DISTANCE = 8;
|
|
15
|
-
/** Above sticky board chrome, below app-level floating surfaces. */
|
|
16
|
-
const KANBAN_DRAG_OVERLAY_Z_INDEX = 75;
|
|
17
|
-
const KANBAN_BOARD_AUTO_SCROLL_OPTIONS = {
|
|
18
|
-
acceleration: 10,
|
|
19
|
-
activator: AutoScrollActivator.Pointer,
|
|
20
|
-
threshold: {
|
|
21
|
-
x: .15,
|
|
22
|
-
y: .15
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
const KANBAN_SORTABLE_ACTIVATION_MODES = {
|
|
26
|
-
CARD: "card",
|
|
27
|
-
HANDLE: "handle",
|
|
28
|
-
ITEM: "item"
|
|
29
|
-
};
|
|
30
|
-
const KANBAN_TOUCH_ACTIVATION_CONSTRAINT = {
|
|
31
|
-
delay: 150,
|
|
32
|
-
tolerance: 8
|
|
33
|
-
};
|
|
34
|
-
const KANBAN_KEYBOARD_CODES = {
|
|
35
|
-
cancel: ["Escape"],
|
|
36
|
-
end: [
|
|
37
|
-
"Space",
|
|
38
|
-
"Enter",
|
|
39
|
-
"Tab"
|
|
40
|
-
]
|
|
41
|
-
};
|
|
42
|
-
const KANBAN_KEYBOARD_TARGET_RETRY_LIMIT = 60;
|
|
43
|
-
/** A render commit, not a virtual scroll, so the budget stays short. */
|
|
44
|
-
const KANBAN_DROP_SETTLE_FRAME_LIMIT = 10;
|
|
45
|
-
/**
|
|
46
|
-
* Defers a drop until dnd-kit has published the collision target it computed.
|
|
47
|
-
* Every sensor ends a drag from a single input event, so without this wait the
|
|
48
|
-
* drop resolves against the target published before that event.
|
|
49
|
-
*/
|
|
50
|
-
const endWhenDropTargetSettled = (context, end) => {
|
|
51
|
-
let framesWaited = 0;
|
|
52
|
-
const attempt = () => {
|
|
53
|
-
if (framesWaited >= KANBAN_DROP_SETTLE_FRAME_LIMIT || isKanbanDropSettled(context.current)) {
|
|
54
|
-
end();
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
framesWaited += 1;
|
|
58
|
-
requestAnimationFrame(attempt);
|
|
59
|
-
};
|
|
60
|
-
attempt();
|
|
61
|
-
};
|
|
62
|
-
const hasTouchLists = (event) => "changedTouches" in event && "touches" in event;
|
|
63
|
-
const getTouchIdentifier = (event) => {
|
|
64
|
-
if (!hasTouchLists(event)) return null;
|
|
65
|
-
return event.changedTouches.item(0)?.identifier ?? event.touches.item(0)?.identifier ?? null;
|
|
66
|
-
};
|
|
67
|
-
const getTouchIdentifiers = (touches) => {
|
|
68
|
-
const identifiers = [];
|
|
69
|
-
for (let index = 0; index < touches.length; index += 1) {
|
|
70
|
-
const identifier = touches.item(index)?.identifier;
|
|
71
|
-
if (identifier !== void 0) identifiers.push(identifier);
|
|
72
|
-
}
|
|
73
|
-
return identifiers;
|
|
74
|
-
};
|
|
75
|
-
/**
|
|
76
|
-
* Keeps a delayed touch drag bound to the finger that activated it.
|
|
77
|
-
*
|
|
78
|
-
* dnd-kit's stock touch sensor attaches document-level lifecycle listeners,
|
|
79
|
-
* so a second finger can otherwise move, end, or cancel the active drag. The
|
|
80
|
-
* capture listeners below suppress only secondary touch changes before those
|
|
81
|
-
* listeners receive them; browser scrolling remains native because no default
|
|
82
|
-
* action is prevented here.
|
|
83
|
-
*/
|
|
84
|
-
var KanbanTouchSensor = class extends TouchSensor {
|
|
85
|
-
identityListeners;
|
|
86
|
-
ownerDocument;
|
|
87
|
-
touchIdentifier;
|
|
88
|
-
constructor(props) {
|
|
89
|
-
const identityListeners = new AbortController();
|
|
90
|
-
super({
|
|
91
|
-
...props,
|
|
92
|
-
onAbort: (active) => {
|
|
93
|
-
identityListeners.abort();
|
|
94
|
-
props.onAbort(active);
|
|
95
|
-
},
|
|
96
|
-
onCancel: () => {
|
|
97
|
-
identityListeners.abort();
|
|
98
|
-
props.onCancel();
|
|
99
|
-
},
|
|
100
|
-
onEnd: () => {
|
|
101
|
-
identityListeners.abort();
|
|
102
|
-
endWhenDropTargetSettled(props.context, () => {
|
|
103
|
-
props.onEnd();
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
this.identityListeners = identityListeners;
|
|
108
|
-
this.ownerDocument = getTouchDocument(props.event);
|
|
109
|
-
this.touchIdentifier = getTouchIdentifier(props.event);
|
|
110
|
-
this.ownerDocument.addEventListener("touchmove", this.handleTouchMove, {
|
|
111
|
-
capture: true,
|
|
112
|
-
passive: false,
|
|
113
|
-
signal: identityListeners.signal
|
|
114
|
-
});
|
|
115
|
-
this.ownerDocument.addEventListener("touchend", this.handleTouchEnd, {
|
|
116
|
-
capture: true,
|
|
117
|
-
signal: identityListeners.signal
|
|
118
|
-
});
|
|
119
|
-
this.ownerDocument.addEventListener("touchcancel", this.handleTouchCancel, {
|
|
120
|
-
capture: true,
|
|
121
|
-
signal: identityListeners.signal
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
handleTouchMove = (event) => {
|
|
125
|
-
if (this.isPrimaryTouchChange(event)) return;
|
|
126
|
-
event.stopImmediatePropagation();
|
|
127
|
-
};
|
|
128
|
-
handleTouchEnd = (event) => {
|
|
129
|
-
if (!this.isPrimaryTouchChange(event)) {
|
|
130
|
-
event.stopImmediatePropagation();
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
this.detachIdentityListeners();
|
|
134
|
-
};
|
|
135
|
-
handleTouchCancel = (event) => {
|
|
136
|
-
if (!this.isPrimaryTouchChange(event)) {
|
|
137
|
-
event.stopImmediatePropagation();
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
this.detachIdentityListeners();
|
|
141
|
-
};
|
|
142
|
-
isPrimaryTouchChange = (event) => isActiveTouchChange({
|
|
143
|
-
activeTouchIdentifier: this.touchIdentifier,
|
|
144
|
-
changedTouchIdentifiers: getTouchIdentifiers(event.changedTouches)
|
|
145
|
-
});
|
|
146
|
-
detachIdentityListeners = () => {
|
|
147
|
-
this.identityListeners.abort();
|
|
148
|
-
};
|
|
149
|
-
};
|
|
150
|
-
/** The stock mouse sensor, holding its drop until the board target settles. */
|
|
151
|
-
var KanbanMouseSensor = class extends MouseSensor {
|
|
152
|
-
constructor(props) {
|
|
153
|
-
super({
|
|
154
|
-
...props,
|
|
155
|
-
onEnd: () => {
|
|
156
|
-
endWhenDropTargetSettled(props.context, () => {
|
|
157
|
-
props.onEnd();
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
/**
|
|
164
|
-
* Applies board coordinates without the stock sensor's one-dimensional source
|
|
165
|
-
* scroll clamping. The coordinate getter moves to the typed target and then
|
|
166
|
-
* scrolls that virtual item into view.
|
|
167
|
-
*/
|
|
168
|
-
var KanbanKeyboardSensor = class {
|
|
169
|
-
static activators = KeyboardSensor.activators;
|
|
170
|
-
autoScrollEnabled = false;
|
|
171
|
-
/** Input handling, released as soon as a drag stops accepting keys. */
|
|
172
|
-
listeners = new AbortController();
|
|
173
|
-
/**
|
|
174
|
-
* The drag itself, released only once it resolves. Ending must not stop the
|
|
175
|
-
* queued retry that still has to bring a pending virtual target into view.
|
|
176
|
-
*/
|
|
177
|
-
lifetime = new AbortController();
|
|
178
|
-
props;
|
|
179
|
-
moveSequence = 0;
|
|
180
|
-
referenceCoordinates = null;
|
|
181
|
-
constructor(props) {
|
|
182
|
-
this.props = props;
|
|
183
|
-
props.onStart({
|
|
184
|
-
x: 0,
|
|
185
|
-
y: 0
|
|
186
|
-
});
|
|
187
|
-
const ownerDocument = getTouchDocument(props.event);
|
|
188
|
-
ownerDocument.addEventListener("visibilitychange", this.handleCancel, { signal: this.listeners.signal });
|
|
189
|
-
ownerDocument.defaultView?.addEventListener("resize", this.handleCancel, { signal: this.listeners.signal });
|
|
190
|
-
ownerDocument.addEventListener("keydown", this.handleKeyDown, { signal: this.listeners.signal });
|
|
191
|
-
}
|
|
192
|
-
handleCancel = () => {
|
|
193
|
-
if (this.lifetime.signal.aborted) return;
|
|
194
|
-
this.moveSequence += 1;
|
|
195
|
-
this.listeners.abort();
|
|
196
|
-
this.finish(() => {
|
|
197
|
-
this.props.onCancel();
|
|
198
|
-
});
|
|
199
|
-
};
|
|
200
|
-
finish = (resolve) => {
|
|
201
|
-
clearKanbanKeyboardTarget(this.props.context.current.active?.data.current);
|
|
202
|
-
this.lifetime.abort();
|
|
203
|
-
resolve();
|
|
204
|
-
};
|
|
205
|
-
handleKeyDown = (event) => {
|
|
206
|
-
if (event === this.props.event) return;
|
|
207
|
-
const keyboardCodes = this.props.options.keyboardCodes;
|
|
208
|
-
const cancelCodes = keyboardCodes?.cancel ?? KANBAN_KEYBOARD_CODES.cancel;
|
|
209
|
-
const endCodes = keyboardCodes?.end ?? KANBAN_KEYBOARD_CODES.end;
|
|
210
|
-
if (cancelCodes.some((code) => code === event.code)) {
|
|
211
|
-
event.preventDefault();
|
|
212
|
-
this.handleCancel();
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
if (endCodes.some((code) => code === event.code)) {
|
|
216
|
-
event.preventDefault();
|
|
217
|
-
this.listeners.abort();
|
|
218
|
-
this.endWhenNavigationResolves(0);
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
this.moveSequence += 1;
|
|
222
|
-
this.move(event, this.moveSequence, 0);
|
|
223
|
-
};
|
|
224
|
-
/**
|
|
225
|
-
* A pending target has asked a virtual cell to mount an offscreen row and has
|
|
226
|
-
* published nothing, so the queued move retry, not this keypress, decides
|
|
227
|
-
* where the item lands. Cancel when that retry gives up: the board never
|
|
228
|
-
* reached the row the user navigated to, and the target still published is
|
|
229
|
-
* the one they navigated away from.
|
|
230
|
-
*/
|
|
231
|
-
endWhenNavigationResolves = (framesWaited) => {
|
|
232
|
-
if (this.lifetime.signal.aborted) return;
|
|
233
|
-
const target = getKanbanKeyboardTargetState(this.props.context.current.active?.data.current);
|
|
234
|
-
if (target?.type === "pending") {
|
|
235
|
-
if (framesWaited >= KANBAN_KEYBOARD_TARGET_RETRY_LIMIT) {
|
|
236
|
-
this.finish(() => {
|
|
237
|
-
this.props.onCancel();
|
|
238
|
-
});
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
requestAnimationFrame(() => {
|
|
242
|
-
this.endWhenNavigationResolves(framesWaited + 1);
|
|
243
|
-
});
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
if (framesWaited > 0 && target?.type !== "ready") {
|
|
247
|
-
this.finish(() => {
|
|
248
|
-
this.props.onCancel();
|
|
249
|
-
});
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
endWhenDropTargetSettled(this.props.context, () => {
|
|
253
|
-
const settled = isKanbanDropSettled(this.props.context.current);
|
|
254
|
-
this.finish(() => {
|
|
255
|
-
if (settled) {
|
|
256
|
-
this.props.onEnd();
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
this.props.onCancel();
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
};
|
|
263
|
-
move = (event, sequence, retryCount) => {
|
|
264
|
-
const currentContext = this.props.context.current;
|
|
265
|
-
if (currentContext.active?.id !== this.props.active) {
|
|
266
|
-
requestAnimationFrame(() => {
|
|
267
|
-
if (this.listeners.signal.aborted || this.moveSequence !== sequence) return;
|
|
268
|
-
this.move(event, sequence, retryCount);
|
|
269
|
-
});
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
const collisionRect = currentContext.collisionRect;
|
|
273
|
-
const currentCoordinates = collisionRect ? {
|
|
274
|
-
x: collisionRect.left,
|
|
275
|
-
y: collisionRect.top
|
|
276
|
-
} : {
|
|
277
|
-
x: 0,
|
|
278
|
-
y: 0
|
|
279
|
-
};
|
|
280
|
-
this.referenceCoordinates ??= currentCoordinates;
|
|
281
|
-
const activeData = currentContext.active.data.current;
|
|
282
|
-
const coordinates = this.props.options.coordinateGetter?.(event, {
|
|
283
|
-
active: this.props.active,
|
|
284
|
-
context: currentContext,
|
|
285
|
-
currentCoordinates
|
|
286
|
-
});
|
|
287
|
-
if (coordinates === void 0) {
|
|
288
|
-
if (getKanbanKeyboardTargetState(activeData)?.type !== "pending") return;
|
|
289
|
-
if (retryCount >= KANBAN_KEYBOARD_TARGET_RETRY_LIMIT) {
|
|
290
|
-
clearKanbanKeyboardTarget(activeData);
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
requestAnimationFrame(() => {
|
|
294
|
-
if (this.lifetime.signal.aborted || this.moveSequence !== sequence) return;
|
|
295
|
-
this.move(event, sequence, retryCount + 1);
|
|
296
|
-
});
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
this.props.onMove({
|
|
300
|
-
x: coordinates.x - this.referenceCoordinates.x,
|
|
301
|
-
y: coordinates.y - this.referenceCoordinates.y
|
|
302
|
-
});
|
|
303
|
-
};
|
|
304
|
-
};
|
|
305
|
-
const getTouchDocument = (event) => {
|
|
306
|
-
if (event.target instanceof Node && event.target.ownerDocument) return event.target.ownerDocument;
|
|
307
|
-
return document;
|
|
308
|
-
};
|
|
309
|
-
const KanbanInteractionReadinessContext = React$1.createContext(true);
|
|
310
|
-
/**
|
|
311
|
-
* Register a board-level drop target such as an empty cell or terminal lane.
|
|
312
|
-
*
|
|
313
|
-
* Board consumers should not need to couple their presentation code to the
|
|
314
|
-
* underlying drag-and-drop library just to receive an item from a sortable
|
|
315
|
-
* context.
|
|
316
|
-
*/
|
|
317
|
-
const useKanbanDropTarget = ({ disabled, id, itemIds, navigation, position }) => {
|
|
318
|
-
const interactionReady = React$1.useContext(KanbanInteractionReadinessContext);
|
|
319
|
-
const dropTarget = useDroppable({
|
|
320
|
-
data: {
|
|
321
|
-
itemIds,
|
|
322
|
-
navigation,
|
|
323
|
-
position,
|
|
324
|
-
type: KANBAN_DROP_TARGET_TYPES.CELL
|
|
325
|
-
},
|
|
326
|
-
disabled: !interactionReady || disabled === true,
|
|
327
|
-
id
|
|
328
|
-
});
|
|
329
|
-
return {
|
|
330
|
-
isOver: dropTarget.isOver,
|
|
331
|
-
setNodeRef: dropTarget.setNodeRef
|
|
332
|
-
};
|
|
333
|
-
};
|
|
334
|
-
/**
|
|
335
|
-
* Input-complete drag context for sortable boards.
|
|
336
|
-
*
|
|
337
|
-
* The consumer owns identifiers and the result of a drop; this component owns
|
|
338
|
-
* the sensor activation rules, keyboard navigation, auto-scroll configuration,
|
|
339
|
-
* and overlay lifecycle shared by sortable board UIs.
|
|
340
|
-
*/
|
|
341
|
-
const KanbanSortableBoard = ({ children, onDragEnd, mouseActivationDistance, collisionDetection, keyboardCoordinates, autoScroll, sensors, accessibility, onDragStart, onDragOver, onDragCancel, onInteractionReady, overlay, overlayProps }) => {
|
|
342
|
-
const [activeId, setActiveId] = React$1.useState(null);
|
|
343
|
-
const [interactionReady, setInteractionReady] = React$1.useState(false);
|
|
344
|
-
const interactionReadyNotified = React$1.useRef(false);
|
|
345
|
-
const defaultSensors = useKanbanSortableSensors(keyboardCoordinates, mouseActivationDistance);
|
|
346
|
-
React$1.useEffect(() => {
|
|
347
|
-
const frame = requestAnimationFrame(() => {
|
|
348
|
-
setInteractionReady(true);
|
|
349
|
-
});
|
|
350
|
-
return () => {
|
|
351
|
-
cancelAnimationFrame(frame);
|
|
352
|
-
};
|
|
353
|
-
}, []);
|
|
354
|
-
React$1.useEffect(() => {
|
|
355
|
-
if (!interactionReady || interactionReadyNotified.current) return;
|
|
356
|
-
interactionReadyNotified.current = true;
|
|
357
|
-
onInteractionReady?.();
|
|
358
|
-
}, [interactionReady, onInteractionReady]);
|
|
359
|
-
const handleDragStart = (event) => {
|
|
360
|
-
setActiveId(event.active.id);
|
|
361
|
-
onDragStart?.(event);
|
|
362
|
-
};
|
|
363
|
-
const handleDragEnd = (event) => {
|
|
364
|
-
setActiveId(null);
|
|
365
|
-
onDragEnd(event);
|
|
366
|
-
};
|
|
367
|
-
const handleDragCancel = (event) => {
|
|
368
|
-
setActiveId(null);
|
|
369
|
-
onDragCancel?.(event);
|
|
370
|
-
};
|
|
371
|
-
return /* @__PURE__ */ jsx(KanbanInteractionReadinessContext, {
|
|
372
|
-
value: interactionReady,
|
|
373
|
-
children: /* @__PURE__ */ jsxs(DndContext, {
|
|
374
|
-
autoScroll: autoScroll ?? KANBAN_BOARD_AUTO_SCROLL_OPTIONS,
|
|
375
|
-
...accessibility === void 0 ? {} : { accessibility },
|
|
376
|
-
collisionDetection: collisionDetection ?? KANBAN_BOARD_COLLISION_DETECTION,
|
|
377
|
-
onDragCancel: handleDragCancel,
|
|
378
|
-
onDragEnd: handleDragEnd,
|
|
379
|
-
...onDragOver === void 0 ? {} : { onDragOver },
|
|
380
|
-
onDragStart: handleDragStart,
|
|
381
|
-
sensors: sensors ?? defaultSensors,
|
|
382
|
-
children: [children, overlay && typeof document !== "undefined" ? createPortal(/* @__PURE__ */ jsx(DragOverlay, {
|
|
383
|
-
...overlayProps,
|
|
384
|
-
zIndex: overlayProps?.zIndex ?? KANBAN_DRAG_OVERLAY_Z_INDEX,
|
|
385
|
-
children: overlay(activeId)
|
|
386
|
-
}), document.body) : null]
|
|
387
|
-
})
|
|
388
|
-
});
|
|
389
|
-
};
|
|
390
|
-
const useKanbanSortableSensors = (keyboardCoordinates = kanbanKeyboardCoordinates, mouseActivationDistance = 8) => useSensors(useSensor(KanbanMouseSensor, { activationConstraint: { distance: mouseActivationDistance } }), useSensor(KanbanTouchSensor, { activationConstraint: KANBAN_TOUCH_ACTIVATION_CONSTRAINT }), useSensor(KanbanKeyboardSensor, { coordinateGetter: keyboardCoordinates }));
|
|
391
|
-
/** A vertical card list that preserves native vertical touch scrolling. */
|
|
392
|
-
const KanbanSortableList = ({ className, children, id, items, strategy, disabled, ...props }) => /* @__PURE__ */ jsx(SortableContext, {
|
|
393
|
-
...disabled === void 0 ? {} : { disabled },
|
|
394
|
-
...id === void 0 ? {} : { id },
|
|
395
|
-
items,
|
|
396
|
-
...strategy === void 0 ? {} : { strategy },
|
|
397
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
398
|
-
className: cn("min-h-0 touch-auto overflow-y-auto overscroll-y-contain", className),
|
|
399
|
-
...props,
|
|
400
|
-
children
|
|
401
|
-
})
|
|
402
|
-
});
|
|
403
|
-
/** A horizontal column list that keeps the board pan gesture available. */
|
|
404
|
-
const KanbanSortableColumns = ({ className, children, id, items, strategy, disabled, ...props }) => /* @__PURE__ */ jsx(SortableContext, {
|
|
405
|
-
...disabled === void 0 ? {} : { disabled },
|
|
406
|
-
...id === void 0 ? {} : { id },
|
|
407
|
-
items,
|
|
408
|
-
...strategy === void 0 ? {} : { strategy },
|
|
409
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
410
|
-
className: cn("flex min-h-0 touch-auto overflow-x-auto overscroll-x-contain", className),
|
|
411
|
-
...props,
|
|
412
|
-
children
|
|
413
|
-
})
|
|
414
|
-
});
|
|
415
|
-
/**
|
|
416
|
-
* Connect a sortable item and its separate drag handle without making the
|
|
417
|
-
* item's content a touch-none activation surface.
|
|
418
|
-
*/
|
|
419
|
-
const useKanbanSortable = ({ activation, id, disabled }) => {
|
|
420
|
-
const interactionReady = React$1.useContext(KanbanInteractionReadinessContext);
|
|
421
|
-
const data = React$1.useMemo(() => ({
|
|
422
|
-
navigation: { current: { type: "idle" } },
|
|
423
|
-
type: KANBAN_DROP_TARGET_TYPES.ITEM
|
|
424
|
-
}), []);
|
|
425
|
-
const sortable = useSortable({
|
|
426
|
-
data,
|
|
427
|
-
disabled: !interactionReady || disabled === true,
|
|
428
|
-
id
|
|
429
|
-
});
|
|
430
|
-
const setNodeRef = (element) => {
|
|
431
|
-
sortable.setNodeRef(element);
|
|
432
|
-
if (activation.type === KANBAN_SORTABLE_ACTIVATION_MODES.ITEM) sortable.setActivatorNodeRef(element);
|
|
433
|
-
};
|
|
434
|
-
const bindings = {
|
|
435
|
-
attributes: sortable.attributes,
|
|
436
|
-
listeners: sortable.listeners,
|
|
437
|
-
setActivatorNodeRef: sortable.setActivatorNodeRef
|
|
438
|
-
};
|
|
439
|
-
let activator;
|
|
440
|
-
if (activation.type === KANBAN_SORTABLE_ACTIVATION_MODES.HANDLE) activator = {
|
|
441
|
-
bindings,
|
|
442
|
-
type: KANBAN_SORTABLE_ACTIVATION_MODES.HANDLE
|
|
443
|
-
};
|
|
444
|
-
else if (activation.type === KANBAN_SORTABLE_ACTIVATION_MODES.CARD) activator = {
|
|
445
|
-
bindings,
|
|
446
|
-
type: KANBAN_SORTABLE_ACTIVATION_MODES.CARD
|
|
447
|
-
};
|
|
448
|
-
else activator = {
|
|
449
|
-
attributes: sortable.attributes,
|
|
450
|
-
listeners: sortable.listeners,
|
|
451
|
-
type: KANBAN_SORTABLE_ACTIVATION_MODES.ITEM
|
|
452
|
-
};
|
|
453
|
-
return {
|
|
454
|
-
activator,
|
|
455
|
-
isDragging: sortable.isDragging,
|
|
456
|
-
setNodeRef,
|
|
457
|
-
style: {
|
|
458
|
-
touchAction: activation.type === KANBAN_SORTABLE_ACTIVATION_MODES.ITEM ? "none" : void 0,
|
|
459
|
-
transform: sortable.transform ? `translate3d(${sortable.transform.x}px, ${sortable.transform.y}px, 0)` : void 0,
|
|
460
|
-
transition: sortable.transition
|
|
461
|
-
}
|
|
462
|
-
};
|
|
463
|
-
};
|
|
464
|
-
/**
|
|
465
|
-
* A 44px keyboard-accessible drag activator. The handle is the only board
|
|
466
|
-
* surface that disables touch panning, leaving cards and scroll regions free
|
|
467
|
-
* for ordinary scrolling.
|
|
468
|
-
*/
|
|
469
|
-
const KanbanDragHandle = ({ bindings, label, className, ...props }) => /* @__PURE__ */ jsx(Button, {
|
|
470
|
-
...props,
|
|
471
|
-
...bindings.attributes,
|
|
472
|
-
...bindings.listeners,
|
|
473
|
-
"aria-label": label,
|
|
474
|
-
className: cn("size-11 min-h-11 min-w-11 touch-none sm:size-11", className),
|
|
475
|
-
ref: (element) => bindings.setActivatorNodeRef(element),
|
|
476
|
-
size: "icon-xl",
|
|
477
|
-
tooltip: false,
|
|
478
|
-
type: "button",
|
|
479
|
-
variant: "ghost",
|
|
480
|
-
children: /* @__PURE__ */ jsx(GripVerticalIcon, { "aria-hidden": "true" })
|
|
481
|
-
});
|
|
482
|
-
const KANBAN_CARD_DRAG_SURFACE_INTERACTIVE_SELECTOR = "a,button,input,select,textarea,[contenteditable=true],[role=button],[data-kanban-drag-exempt]";
|
|
483
|
-
const isKanbanCardDragSurfaceInteractiveTarget = (target, activator) => {
|
|
484
|
-
if (!(target instanceof Element)) return false;
|
|
485
|
-
const interactiveTarget = target.closest(KANBAN_CARD_DRAG_SURFACE_INTERACTIVE_SELECTOR);
|
|
486
|
-
return interactiveTarget !== null && interactiveTarget !== activator;
|
|
487
|
-
};
|
|
488
|
-
const getKanbanCardDragSurfaceAttributes = ({ "aria-describedby": _describedBy, "aria-disabled": _disabled, "aria-pressed": _pressed, "aria-roledescription": _roleDescription, role: _role, tabIndex, ...attributes }) => ({
|
|
489
|
-
...attributes,
|
|
490
|
-
tabIndex
|
|
491
|
-
});
|
|
492
|
-
const isKanbanCardDragSurfaceListener = (listener) => typeof listener === "function";
|
|
493
|
-
const getKanbanCardDragSurfaceListeners = (listeners) => {
|
|
494
|
-
const { onKeyDown, onMouseDown, onPointerDown, onTouchStart, ...rest } = listeners;
|
|
495
|
-
const shouldActivate = (event) => !isKanbanCardDragSurfaceInteractiveTarget(event.target, event.currentTarget);
|
|
496
|
-
return {
|
|
497
|
-
...rest,
|
|
498
|
-
...!isKanbanCardDragSurfaceListener(onKeyDown) ? {} : { onKeyDown: (event) => {
|
|
499
|
-
if (shouldActivate(event)) onKeyDown(event);
|
|
500
|
-
} },
|
|
501
|
-
...!isKanbanCardDragSurfaceListener(onMouseDown) ? {} : { onMouseDown: (event) => {
|
|
502
|
-
if (shouldActivate(event)) onMouseDown(event);
|
|
503
|
-
} },
|
|
504
|
-
...!isKanbanCardDragSurfaceListener(onPointerDown) ? {} : { onPointerDown: (event) => {
|
|
505
|
-
if (shouldActivate(event)) onPointerDown(event);
|
|
506
|
-
} },
|
|
507
|
-
...!isKanbanCardDragSurfaceListener(onTouchStart) ? {} : { onTouchStart: (event) => {
|
|
508
|
-
if (shouldActivate(event)) onTouchStart(event);
|
|
509
|
-
} }
|
|
510
|
-
};
|
|
511
|
-
};
|
|
512
|
-
/** A whole-card drag activator that preserves descendant controls and scrolling. */
|
|
513
|
-
const KanbanCardDragSurface = ({ bindings, className, ...props }) => {
|
|
514
|
-
const { listeners, setActivatorNodeRef: setCardActivatorNodeRef } = bindings;
|
|
515
|
-
const setActivatorNodeRef = React$1.useCallback((element) => {
|
|
516
|
-
setCardActivatorNodeRef(element);
|
|
517
|
-
}, [setCardActivatorNodeRef]);
|
|
518
|
-
return /* @__PURE__ */ jsx("div", {
|
|
519
|
-
...props,
|
|
520
|
-
...getKanbanCardDragSurfaceAttributes(bindings.attributes),
|
|
521
|
-
...listeners === void 0 ? {} : getKanbanCardDragSurfaceListeners(listeners),
|
|
522
|
-
className: cn("touch-auto", className),
|
|
523
|
-
ref: setActivatorNodeRef
|
|
524
|
-
});
|
|
525
|
-
};
|
|
526
|
-
//#endregion
|
|
527
|
-
export { KANBAN_BOARD_AUTO_SCROLL_OPTIONS, KANBAN_BOARD_COLLISION_DETECTION, KANBAN_DRAG_OVERLAY_Z_INDEX, KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_SORTABLE_ACTIVATION_MODES, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, KanbanCardDragSurface, KanbanDragHandle, KanbanSortableBoard, KanbanSortableColumns, KanbanSortableList, kanbanKeyboardCoordinates, useKanbanDropTarget, useKanbanSortable, useKanbanSortableSensors };
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { CollisionDetection, KeyboardCoordinateGetter, SensorContext, UniqueIdentifier } from "@dnd-kit/core";
|
|
2
|
-
//#region src/kanban/sortable-interactions.logic.d.ts
|
|
3
|
-
export declare const KANBAN_DROP_TARGET_TYPES: {
|
|
4
|
-
readonly CELL: "kanban-cell";
|
|
5
|
-
readonly ITEM: "kanban-item";
|
|
6
|
-
};
|
|
7
|
-
export type KanbanSortableCellPosition = {
|
|
8
|
-
column: number;
|
|
9
|
-
lane: number;
|
|
10
|
-
};
|
|
11
|
-
export type KanbanVirtualScrollRequest = {
|
|
12
|
-
itemId: UniqueIdentifier;
|
|
13
|
-
type: "item";
|
|
14
|
-
};
|
|
15
|
-
export type KanbanCellVirtualNavigation = {
|
|
16
|
-
type: "static";
|
|
17
|
-
} | {
|
|
18
|
-
requestScroll: (request: KanbanVirtualScrollRequest) => void;
|
|
19
|
-
type: "virtual";
|
|
20
|
-
};
|
|
21
|
-
export type KanbanCellDropData = {
|
|
22
|
-
itemIds: readonly UniqueIdentifier[];
|
|
23
|
-
navigation: KanbanCellVirtualNavigation;
|
|
24
|
-
position: KanbanSortableCellPosition;
|
|
25
|
-
type: "kanban-cell";
|
|
26
|
-
};
|
|
27
|
-
type KanbanKeyboardTargetState = {
|
|
28
|
-
type: "idle";
|
|
29
|
-
} | {
|
|
30
|
-
targetId: UniqueIdentifier;
|
|
31
|
-
type: "pending";
|
|
32
|
-
} | {
|
|
33
|
-
targetId: UniqueIdentifier;
|
|
34
|
-
type: "ready";
|
|
35
|
-
};
|
|
36
|
-
export type KanbanItemDropData = {
|
|
37
|
-
navigation: {
|
|
38
|
-
current: KanbanKeyboardTargetState;
|
|
39
|
-
};
|
|
40
|
-
type: "kanban-item";
|
|
41
|
-
};
|
|
42
|
-
type NavigationCell = KanbanCellDropData & {
|
|
43
|
-
id: UniqueIdentifier;
|
|
44
|
-
};
|
|
45
|
-
export declare const isKanbanCellDropData: (value: unknown) => value is KanbanCellDropData;
|
|
46
|
-
export declare const getKanbanKeyboardTargetState: (value: unknown) => KanbanKeyboardTargetState | undefined;
|
|
47
|
-
/**
|
|
48
|
-
* dnd-kit computes collisions while rendering but publishes the resulting drop
|
|
49
|
-
* target to its sensor context a render later, and resolves a drop from that
|
|
50
|
-
* published value. A drag that ends before the two agree, which every input
|
|
51
|
-
* can do because a single move produces a single render, drops the item on the
|
|
52
|
-
* previously published target.
|
|
53
|
-
*
|
|
54
|
-
* Keyboard navigation names its target outright, so it is compared directly: a
|
|
55
|
-
* pending target is still waiting for a virtual cell to mount an offscreen row
|
|
56
|
-
* and has produced no collision at all, and a ready one is only settled once it
|
|
57
|
-
* is the published target. Until then both the collisions and the published
|
|
58
|
-
* target still describe where the board was before the user navigated away.
|
|
59
|
-
*/
|
|
60
|
-
export declare const isKanbanDropSettled: ({ active, collisions, over }: Pick<SensorContext, "active" | "collisions" | "over">) => boolean;
|
|
61
|
-
export declare const clearKanbanKeyboardTarget: (value: unknown) => void;
|
|
62
|
-
/**
|
|
63
|
-
* Pointer and touch input must be inside a registered board target. Once that
|
|
64
|
-
* boundary is established, closest corners gives stable ranking across cells.
|
|
65
|
-
*/
|
|
66
|
-
export declare const KANBAN_BOARD_COLLISION_DETECTION: CollisionDetection;
|
|
67
|
-
type NavigationDirection = "down" | "left" | "right" | "up";
|
|
68
|
-
type GetKeyboardTargetOptions = {
|
|
69
|
-
activeId: UniqueIdentifier;
|
|
70
|
-
cells: readonly NavigationCell[];
|
|
71
|
-
currentCellId: UniqueIdentifier;
|
|
72
|
-
currentOverId: UniqueIdentifier;
|
|
73
|
-
direction: NavigationDirection;
|
|
74
|
-
};
|
|
75
|
-
export declare const getKanbanKeyboardTarget: ({ activeId, cells, currentCellId, currentOverId, direction }: GetKeyboardTargetOptions) => UniqueIdentifier | undefined;
|
|
76
|
-
/** Ordered two-dimensional navigation over item and empty-cell targets. */
|
|
77
|
-
export declare const kanbanKeyboardCoordinates: KeyboardCoordinateGetter;
|
|
78
|
-
//#endregion
|