@stll/ui 0.9.1 → 0.12.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.
Files changed (39) hide show
  1. package/README.md +90 -15
  2. package/dist/components/breadcrumb.d.ts +1 -1
  3. package/dist/components/button-variants.d.ts +2 -2
  4. package/dist/components/button.d.ts +1 -1
  5. package/dist/components/combobox.js +1 -1
  6. package/dist/components/command.d.ts +1 -1
  7. package/dist/components/command.js +1 -1
  8. package/dist/components/date-picker-popover.js +1 -1
  9. package/dist/components/input-group.d.ts +1 -1
  10. package/dist/components/pagination.d.ts +1 -1
  11. package/dist/components/pagination.js +1 -1
  12. package/dist/components/select.d.ts +1 -1
  13. package/dist/components/select.js +8 -10
  14. package/dist/components/workspace-shell.d.ts +77 -0
  15. package/dist/components/workspace-shell.js +106 -0
  16. package/dist/index.d.ts +7 -6
  17. package/dist/index.js +11 -10
  18. package/dist/inspector/chrome.d.ts +5 -1
  19. package/dist/inspector/chrome.js +14 -2
  20. package/dist/inspector/index.d.ts +2 -2
  21. package/dist/inspector/index.js +2 -2
  22. package/dist/inspector/layout-tokens.d.ts +5 -1
  23. package/dist/inspector/layout-tokens.js +5 -1
  24. package/dist/inspector/tabs.d.ts +1 -1
  25. package/dist/kanban/index.d.ts +4 -3
  26. package/dist/kanban/index.js +3 -2
  27. package/dist/kanban/sortable-interactions.d.ts +75 -13
  28. package/dist/kanban/sortable-interactions.js +345 -28
  29. package/dist/kanban/sortable-interactions.logic.d.ts +79 -0
  30. package/dist/kanban/sortable-interactions.logic.js +205 -0
  31. package/dist/kanban/virtual-cell.d.ts +19 -2
  32. package/dist/kanban/virtual-cell.js +53 -7
  33. package/dist/lib/control-size.d.ts +1 -1
  34. package/dist/lib/overlay-layer.d.ts +2 -1
  35. package/dist/lib/overlay-layer.js +2 -1
  36. package/dist/review/review-comment-card.js +1 -1
  37. package/package.json +7 -7
  38. package/dist/components/application-shell.d.ts +0 -27
  39. package/dist/components/application-shell.js +0 -25
@@ -1,19 +1,64 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/utils.js";
3
+ import "../lib/overlay-layer.js";
3
4
  import { Button } from "../components/button.js";
5
+ import { KANBAN_BOARD_COLLISION_DETECTION, KANBAN_DROP_TARGET_TYPES, clearKanbanKeyboardTarget, getKanbanKeyboardTargetState, isKanbanDropSettled, kanbanKeyboardCoordinates } from "./sortable-interactions.logic.js";
4
6
  import { isActiveTouchChange } from "./touch-identity.js";
5
7
  import { GripVerticalIcon } from "lucide-react";
6
8
  import { jsx, jsxs } from "react/jsx-runtime";
7
9
  import * as React$1 from "react";
8
10
  import { createPortal } from "react-dom";
9
- import { DndContext, DragOverlay, KeyboardSensor, MouseSensor, TouchSensor, useSensor, useSensors } from "@dnd-kit/core";
10
- import { SortableContext, sortableKeyboardCoordinates, useSortable } from "@dnd-kit/sortable";
11
+ import { AutoScrollActivator, DndContext, DragOverlay, KeyboardSensor, MouseSensor, TouchSensor, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
12
+ import { SortableContext, useSortable } from "@dnd-kit/sortable";
11
13
  //#region src/kanban/sortable-interactions.tsx
12
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
+ };
13
30
  const KANBAN_TOUCH_ACTIVATION_CONSTRAINT = {
14
31
  delay: 150,
15
32
  tolerance: 8
16
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
+ };
17
62
  const hasTouchLists = (event) => "changedTouches" in event && "touches" in event;
18
63
  const getTouchIdentifier = (event) => {
19
64
  if (!hasTouchLists(event)) return null;
@@ -54,7 +99,9 @@ var KanbanTouchSensor = class extends TouchSensor {
54
99
  },
55
100
  onEnd: () => {
56
101
  identityListeners.abort();
57
- props.onEnd();
102
+ endWhenDropTargetSettled(props.context, () => {
103
+ props.onEnd();
104
+ });
58
105
  }
59
106
  });
60
107
  this.identityListeners = identityListeners;
@@ -100,10 +147,190 @@ var KanbanTouchSensor = class extends TouchSensor {
100
147
  this.identityListeners.abort();
101
148
  };
102
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
+ };
103
305
  const getTouchDocument = (event) => {
104
306
  if (event.target instanceof Node && event.target.ownerDocument) return event.target.ownerDocument;
105
307
  return document;
106
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
+ };
107
334
  /**
108
335
  * Input-complete drag context for sortable boards.
109
336
  *
@@ -111,9 +338,24 @@ const getTouchDocument = (event) => {
111
338
  * the sensor activation rules, keyboard navigation, auto-scroll configuration,
112
339
  * and overlay lifecycle shared by sortable board UIs.
113
340
  */
114
- const KanbanSortableBoard = ({ children, onDragEnd, collisionDetection, keyboardCoordinates, autoScroll, sensors, accessibility, onDragStart, onDragCancel, overlay, overlayProps }) => {
341
+ const KanbanSortableBoard = ({ children, onDragEnd, collisionDetection, keyboardCoordinates, autoScroll, sensors, accessibility, onDragStart, onDragOver, onDragCancel, onInteractionReady, overlay, overlayProps }) => {
115
342
  const [activeId, setActiveId] = React$1.useState(null);
343
+ const [interactionReady, setInteractionReady] = React$1.useState(false);
344
+ const interactionReadyNotified = React$1.useRef(false);
116
345
  const defaultSensors = useKanbanSortableSensors(keyboardCoordinates);
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]);
117
359
  const handleDragStart = (event) => {
118
360
  setActiveId(event.active.id);
119
361
  onDragStart?.(event);
@@ -126,21 +368,26 @@ const KanbanSortableBoard = ({ children, onDragEnd, collisionDetection, keyboard
126
368
  setActiveId(null);
127
369
  onDragCancel?.(event);
128
370
  };
129
- return /* @__PURE__ */ jsxs(DndContext, {
130
- ...autoScroll === void 0 ? {} : { autoScroll },
131
- ...accessibility === void 0 ? {} : { accessibility },
132
- ...collisionDetection === void 0 ? {} : { collisionDetection },
133
- onDragCancel: handleDragCancel,
134
- onDragEnd: handleDragEnd,
135
- onDragStart: handleDragStart,
136
- sensors: sensors ?? defaultSensors,
137
- children: [children, overlay && typeof document !== "undefined" ? createPortal(/* @__PURE__ */ jsx(DragOverlay, {
138
- ...overlayProps,
139
- children: overlay(activeId)
140
- }), document.body) : null]
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
+ })
141
388
  });
142
389
  };
143
- const useKanbanSortableSensors = (keyboardCoordinates = sortableKeyboardCoordinates) => useSensors(useSensor(MouseSensor, { activationConstraint: { distance: 8 } }), useSensor(KanbanTouchSensor, { activationConstraint: KANBAN_TOUCH_ACTIVATION_CONSTRAINT }), useSensor(KeyboardSensor, { coordinateGetter: keyboardCoordinates }));
390
+ const useKanbanSortableSensors = (keyboardCoordinates = kanbanKeyboardCoordinates) => useSensors(useSensor(KanbanMouseSensor, { activationConstraint: { distance: 8 } }), useSensor(KanbanTouchSensor, { activationConstraint: KANBAN_TOUCH_ACTIVATION_CONSTRAINT }), useSensor(KanbanKeyboardSensor, { coordinateGetter: keyboardCoordinates }));
144
391
  /** A vertical card list that preserves native vertical touch scrolling. */
145
392
  const KanbanSortableList = ({ className, children, id, items, strategy, disabled, ...props }) => /* @__PURE__ */ jsx(SortableContext, {
146
393
  ...disabled === void 0 ? {} : { disabled },
@@ -169,22 +416,48 @@ const KanbanSortableColumns = ({ className, children, id, items, strategy, disab
169
416
  * Connect a sortable item and its separate drag handle without making the
170
417
  * item's content a touch-none activation surface.
171
418
  */
172
- const useKanbanSortable = ({ id, disabled }) => {
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
+ }), []);
173
425
  const sortable = useSortable({
174
- id,
175
- ...disabled === void 0 ? {} : { disabled }
426
+ data,
427
+ disabled: !interactionReady || disabled === true,
428
+ id
176
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
+ };
177
453
  return {
454
+ activator,
178
455
  isDragging: sortable.isDragging,
179
- setNodeRef: sortable.setNodeRef,
456
+ setNodeRef,
180
457
  style: {
458
+ touchAction: activation.type === KANBAN_SORTABLE_ACTIVATION_MODES.ITEM ? "none" : void 0,
181
459
  transform: sortable.transform ? `translate3d(${sortable.transform.x}px, ${sortable.transform.y}px, 0)` : void 0,
182
460
  transition: sortable.transition
183
- },
184
- dragHandle: {
185
- attributes: sortable.attributes,
186
- listeners: sortable.listeners,
187
- setActivatorNodeRef: sortable.setActivatorNodeRef
188
461
  }
189
462
  };
190
463
  };
@@ -198,7 +471,7 @@ const KanbanDragHandle = ({ bindings, label, className, ...props }) => /* @__PUR
198
471
  ...bindings.attributes,
199
472
  ...bindings.listeners,
200
473
  "aria-label": label,
201
- className: cn("size-11 touch-none sm:size-11", className),
474
+ className: cn("size-11 min-h-11 min-w-11 touch-none sm:size-11", className),
202
475
  ref: (element) => bindings.setActivatorNodeRef(element),
203
476
  size: "icon-xl",
204
477
  tooltip: false,
@@ -206,5 +479,49 @@ const KanbanDragHandle = ({ bindings, label, className, ...props }) => /* @__PUR
206
479
  variant: "ghost",
207
480
  children: /* @__PURE__ */ jsx(GripVerticalIcon, { "aria-hidden": "true" })
208
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
+ };
209
526
  //#endregion
210
- export { KANBAN_MOUSE_ACTIVATION_DISTANCE, KANBAN_TOUCH_ACTIVATION_CONSTRAINT, KanbanDragHandle, KanbanSortableBoard, KanbanSortableColumns, KanbanSortableList, useKanbanSortable, useKanbanSortableSensors };
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 };
@@ -0,0 +1,79 @@
1
+ import { CollisionDetection, KeyboardCoordinateGetter, SensorContext, UniqueIdentifier } from "@dnd-kit/core";
2
+ //#region src/kanban/sortable-interactions.logic.d.ts
3
+ declare const KANBAN_DROP_TARGET_TYPES: {
4
+ readonly CELL: "kanban-cell";
5
+ readonly ITEM: "kanban-item";
6
+ };
7
+ type KanbanSortableCellPosition = {
8
+ column: number;
9
+ lane: number;
10
+ };
11
+ type KanbanVirtualScrollRequest = {
12
+ itemId: UniqueIdentifier;
13
+ type: "item";
14
+ };
15
+ type KanbanCellVirtualNavigation = {
16
+ type: "static";
17
+ } | {
18
+ requestScroll: (request: KanbanVirtualScrollRequest) => void;
19
+ type: "virtual";
20
+ };
21
+ 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
+ type KanbanItemDropData = {
37
+ navigation: {
38
+ current: KanbanKeyboardTargetState;
39
+ };
40
+ type: "kanban-item";
41
+ };
42
+ type NavigationCell = KanbanCellDropData & {
43
+ id: UniqueIdentifier;
44
+ };
45
+ declare const isKanbanCellDropData: (value: unknown) => value is KanbanCellDropData;
46
+ 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
+ declare const isKanbanDropSettled: ({ active, collisions, over }: Pick<SensorContext, "active" | "collisions" | "over">) => boolean;
61
+ 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
+ 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
+ declare const getKanbanKeyboardTarget: ({ activeId, cells, currentCellId, currentOverId, direction }: GetKeyboardTargetOptions) => UniqueIdentifier | undefined;
76
+ /** Ordered two-dimensional navigation over item and empty-cell targets. */
77
+ declare const kanbanKeyboardCoordinates: KeyboardCoordinateGetter;
78
+ //#endregion
79
+ export { KANBAN_BOARD_COLLISION_DETECTION, KANBAN_DROP_TARGET_TYPES, KanbanCellDropData, KanbanCellVirtualNavigation, KanbanItemDropData, KanbanSortableCellPosition, KanbanVirtualScrollRequest, clearKanbanKeyboardTarget, getKanbanKeyboardTarget, getKanbanKeyboardTargetState, isKanbanCellDropData, isKanbanDropSettled, kanbanKeyboardCoordinates };