@dreamtree-org/twreact-ui 2.0.4 → 2.0.6

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 (60) hide show
  1. package/README.md +12 -4
  2. package/ai-skills/dreamtree-ui.md +4 -3
  3. package/dist/ai-schema.json +135 -0
  4. package/dist/charts/index.d.ts +2 -1
  5. package/dist/charts/index.js +298 -13
  6. package/dist/components/charts/ChartFrame.d.ts +1 -0
  7. package/dist/components/charts/ChartFrame.d.ts.map +1 -1
  8. package/dist/components/charts/ScatterChart.d.ts +4 -0
  9. package/dist/components/charts/ScatterChart.d.ts.map +1 -0
  10. package/dist/components/charts/ScatterTooltip.d.ts +14 -0
  11. package/dist/components/charts/ScatterTooltip.d.ts.map +1 -0
  12. package/dist/components/charts/scatterData.d.ts +17 -0
  13. package/dist/components/charts/scatterData.d.ts.map +1 -0
  14. package/dist/components/core/Popover.d.ts.map +1 -1
  15. package/dist/components/feedback/Tour.d.ts.map +1 -1
  16. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  17. package/dist/components/utility/Sortable.d.ts.map +1 -1
  18. package/dist/components/utility/SortableGroup.d.ts +15 -0
  19. package/dist/components/utility/SortableGroup.d.ts.map +1 -0
  20. package/dist/esm/charts/index.js +1 -0
  21. package/dist/esm/components/charts/ChartFrame.js +6 -6
  22. package/dist/esm/components/charts/ScatterChart.js +204 -0
  23. package/dist/esm/components/charts/ScatterTooltip.js +61 -0
  24. package/dist/esm/components/charts/scatterData.js +43 -0
  25. package/dist/esm/components/core/Accordion.js +2 -2
  26. package/dist/esm/components/core/DatePicker.js +3 -3
  27. package/dist/esm/components/core/DateRangePicker.js +3 -3
  28. package/dist/esm/components/core/Form.js +3 -3
  29. package/dist/esm/components/core/LocationPicker.js +1 -1
  30. package/dist/esm/components/core/Popover.js +1 -1
  31. package/dist/esm/components/core/Select.js +16 -16
  32. package/dist/esm/components/core/Table/Table.js +1 -1
  33. package/dist/esm/components/core/internal/Calendar.js +2 -2
  34. package/dist/esm/components/feedback/Drawer.js +5 -5
  35. package/dist/esm/components/feedback/Tour.js +1 -1
  36. package/dist/esm/components/rich-text/RichTextEditor.js +2 -2
  37. package/dist/esm/components/rich-text/RichTextToolbar.js +1 -1
  38. package/dist/esm/components/utility/Pagination.js +1 -1
  39. package/dist/esm/components/utility/Sortable.js +70 -48
  40. package/dist/esm/components/utility/SortableGroup.js +48 -0
  41. package/dist/esm/hooks/useSortable.js +96 -30
  42. package/dist/esm/hooks/useSortableGroup.js +268 -0
  43. package/dist/esm/index.js +1 -0
  44. package/dist/hooks/useSortable.d.ts +12 -3
  45. package/dist/hooks/useSortable.d.ts.map +1 -1
  46. package/dist/hooks/useSortableGroup.d.ts +43 -0
  47. package/dist/hooks/useSortableGroup.d.ts.map +1 -0
  48. package/dist/index.css +1 -1
  49. package/dist/index.d.ts +2 -1
  50. package/dist/index.esm.css +1 -1
  51. package/dist/index.esm.js +904 -513
  52. package/dist/index.js +904 -512
  53. package/dist/rich-text/index.js +3 -3
  54. package/dist/types/charts.d.ts +28 -0
  55. package/dist/types/charts.d.ts.map +1 -1
  56. package/dist/types/index.d.ts +33 -0
  57. package/dist/types/index.d.ts.map +1 -1
  58. package/doc/README.md +2 -0
  59. package/mcp/catalog.snapshot.json +248 -28
  60. package/package.json +1 -1
@@ -5,7 +5,25 @@ import { useLatestRef } from './useLatestRef.js';
5
5
 
6
6
  // Internal (not exported). Keyboard + pointer reordering for Sortable. Both
7
7
  // work on a draft list of keys while the user is moving an item and only call
8
- // `commit(fromIndex, toIndex)` when the item is dropped.
8
+ // `commit(fromIndex, toIndex)` when the item is dropped. Inside a SortableGroup
9
+ // they also get a `cross` object (see useSortableGroup.js) that takes over when
10
+ // the item is carried into another list; without one they behave as before.
11
+ var defaultGetKey = function defaultGetKey(item, index) {
12
+ var _ref, _item$id;
13
+ return (_ref = (_item$id = item === null || item === void 0 ? void 0 : item.id) !== null && _item$id !== void 0 ? _item$id : item === null || item === void 0 ? void 0 : item.key) !== null && _ref !== void 0 ? _ref : index;
14
+ };
15
+ var defaultGetItemLabel = function defaultGetItemLabel(item, index) {
16
+ var _ref2, _ref3, _item$label;
17
+ return typeof item === "string" || typeof item === "number" ? String(item) : (_ref2 = (_ref3 = (_item$label = item === null || item === void 0 ? void 0 : item.label) !== null && _item$label !== void 0 ? _item$label : item === null || item === void 0 ? void 0 : item.title) !== null && _ref3 !== void 0 ? _ref3 : item === null || item === void 0 ? void 0 : item.name) !== null && _ref2 !== void 0 ? _ref2 : "Item ".concat(index + 1);
18
+ };
19
+ function arrayMove(list, from, to) {
20
+ var next = list.slice();
21
+ var _next$splice = next.splice(from, 1),
22
+ _next$splice2 = _slicedToArray(_next$splice, 1),
23
+ moved = _next$splice2[0];
24
+ next.splice(to, 0, moved);
25
+ return next;
26
+ }
9
27
  function moveKey(keys, key, toIndex) {
10
28
  var next = keys.filter(function (k) {
11
29
  return k !== key;
@@ -26,6 +44,17 @@ var DEFAULT_SORTABLE_MESSAGES = {
26
44
  },
27
45
  cancelled: function cancelled(label, position) {
28
46
  return "Reorder cancelled. ".concat(label, " returned to position ").concat(position, ".");
47
+ },
48
+ // Only used inside a SortableGroup.
49
+ groupInstructions: "Use the arrow keys across the list (Left and Right in a vertical list) to carry it to the previous or next list.",
50
+ movedToList: function movedToList(label, list, position, total) {
51
+ return "".concat(label, " moved to ").concat(list, ", position ").concat(position, " of ").concat(total, ".");
52
+ },
53
+ droppedInList: function droppedInList(label, list, position, total) {
54
+ return "".concat(label, " dropped in ").concat(list, " at position ").concat(position, " of ").concat(total, ".");
55
+ },
56
+ refused: function refused(label, list) {
57
+ return "".concat(label, " cannot be dropped in ").concat(list, ".");
29
58
  }
30
59
  };
31
60
  var PREV_KEYS = {
@@ -36,13 +65,31 @@ var NEXT_KEYS = {
36
65
  vertical: ["ArrowDown"],
37
66
  horizontal: ["ArrowRight"]
38
67
  };
39
- function useSortableKeyboard(_ref) {
40
- var keys = _ref.keys,
41
- setDraft = _ref.setDraft,
42
- commit = _ref.commit,
43
- announce = _ref.announce,
44
- labelFor = _ref.labelFor,
45
- orientation = _ref.orientation;
68
+ // Cross-axis arrows step between the lists of a SortableGroup.
69
+ var LIST_KEYS = {
70
+ vertical: {
71
+ ArrowLeft: -1,
72
+ ArrowRight: 1
73
+ },
74
+ horizontal: {
75
+ ArrowUp: -1,
76
+ ArrowDown: 1
77
+ }
78
+ };
79
+ var stepOf = function stepOf(e, orientation, cross) {
80
+ return {
81
+ delta: PREV_KEYS[orientation].includes(e.key) ? -1 : NEXT_KEYS[orientation].includes(e.key) ? 1 : 0,
82
+ list: cross ? LIST_KEYS[orientation][e.key] || 0 : 0
83
+ };
84
+ };
85
+ function useSortableKeyboard(_ref4) {
86
+ var keys = _ref4.keys,
87
+ setDraft = _ref4.setDraft,
88
+ commit = _ref4.commit,
89
+ announce = _ref4.announce,
90
+ labelFor = _ref4.labelFor,
91
+ orientation = _ref4.orientation,
92
+ cross = _ref4.cross;
46
93
  var _useState = useState(null),
47
94
  _useState2 = _slicedToArray(_useState, 2),
48
95
  grabbed = _useState2[0],
@@ -60,21 +107,27 @@ function useSortableKeyboard(_ref) {
60
107
  setGrabbed(key);
61
108
  setDraft(keys);
62
109
  announce("grabbed", labelFor(key), index + 1, total);
63
- } else {
64
- setGrabbed(null);
65
- commit(origin.current, index);
66
- announce("dropped", labelFor(key), index + 1, total);
110
+ return;
67
111
  }
112
+ var crossed = cross === null || cross === void 0 ? void 0 : cross.drop(key);
113
+ if (crossed === "refused") return;
114
+ setGrabbed(null);
115
+ if (crossed) return;
116
+ commit(origin.current, index);
117
+ announce("dropped", labelFor(key), index + 1, total);
68
118
  } else if (grabbed === key && e.key === "Escape") {
69
119
  e.preventDefault();
70
120
  setGrabbed(null);
71
121
  setDraft(null);
122
+ cross === null || cross === void 0 || cross.cancel();
72
123
  announce("cancelled", labelFor(key), origin.current + 1, total);
73
124
  } else if (grabbed === key) {
74
- var delta = PREV_KEYS[orientation].includes(e.key) ? -1 : NEXT_KEYS[orientation].includes(e.key) ? 1 : 0;
75
- if (!delta) return;
125
+ var step = stepOf(e, orientation, cross);
126
+ if (!step.delta && !step.list) return;
76
127
  e.preventDefault();
77
- var to = Math.max(0, Math.min(total - 1, index + delta));
128
+ if (step.list) return cross.step(key, step.list);
129
+ if (cross !== null && cross !== void 0 && cross.nudge(key, step.delta)) return;
130
+ var to = Math.max(0, Math.min(total - 1, index + step.delta));
78
131
  if (to === index) return;
79
132
  setDraft(moveKey(keys, key, to));
80
133
  announce("moved", labelFor(key), to + 1, total);
@@ -84,7 +137,8 @@ function useSortableKeyboard(_ref) {
84
137
  var cancel = useCallback(function () {
85
138
  setGrabbed(null);
86
139
  setDraft(null);
87
- }, [setDraft]);
140
+ cross === null || cross === void 0 || cross.cancel();
141
+ }, [setDraft, cross]);
88
142
  return {
89
143
  grabbed: grabbed,
90
144
  keyDownFor: keyDownFor,
@@ -130,13 +184,14 @@ var raf = function raf(cb) {
130
184
  var caf = function caf(id) {
131
185
  return typeof window.cancelAnimationFrame === "function" ? window.cancelAnimationFrame(id) : clearTimeout(id);
132
186
  };
133
- function useSortablePointer(_ref2) {
134
- var keys = _ref2.keys,
135
- setDraft = _ref2.setDraft,
136
- commit = _ref2.commit,
137
- nodeFor = _ref2.nodeFor,
138
- orientation = _ref2.orientation,
139
- disabled = _ref2.disabled;
187
+ function useSortablePointer(_ref5) {
188
+ var keys = _ref5.keys,
189
+ setDraft = _ref5.setDraft,
190
+ commit = _ref5.commit,
191
+ nodeFor = _ref5.nodeFor,
192
+ orientation = _ref5.orientation,
193
+ disabled = _ref5.disabled,
194
+ cross = _ref5.cross;
140
195
  var _useState3 = useState(null),
141
196
  _useState4 = _slicedToArray(_useState3, 2),
142
197
  dragging = _useState4[0],
@@ -146,7 +201,8 @@ function useSortablePointer(_ref2) {
146
201
  keys: keys,
147
202
  commit: commit,
148
203
  nodeFor: nodeFor,
149
- orientation: orientation
204
+ orientation: orientation,
205
+ cross: cross
150
206
  });
151
207
  var end = useCallback(function () {
152
208
  var _session$current;
@@ -175,9 +231,9 @@ function useSortablePointer(_ref2) {
175
231
  // `longPress`: on touch, wait LONG_PRESS_DELAY before picking the item up (used
176
232
  // when the whole item is the drag source, so the list still scrolls on swipe).
177
233
  var startFor = function startFor(key) {
178
- var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
179
- _ref3$longPress = _ref3.longPress,
180
- longPress = _ref3$longPress === void 0 ? false : _ref3$longPress;
234
+ var _ref6 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
235
+ _ref6$longPress = _ref6.longPress,
236
+ longPress = _ref6$longPress === void 0 ? false : _ref6$longPress;
181
237
  return function (e) {
182
238
  if (disabled || e.button > 0) return;
183
239
  var start = {
@@ -190,6 +246,12 @@ function useSortablePointer(_ref2) {
190
246
  var point = start;
191
247
  var pressTimer = null;
192
248
  var frame = null;
249
+ // Over another list of the group, the source list keeps its original order
250
+ // and the target list shows where the item would land.
251
+ var track = function track() {
252
+ var _latest$current$cross;
253
+ if ((_latest$current$cross = latest.current.cross) !== null && _latest$current$cross !== void 0 && _latest$current$cross.over(point, key)) setDraft(null);else setDraft(moveKey(latest.current.keys, key, targetIndex(point, key)));
254
+ };
193
255
  var scrollTarget = function scrollTarget() {
194
256
  return getScrollParent(latest.current.nodeFor(key), latest.current.orientation);
195
257
  };
@@ -214,7 +276,7 @@ function useSortablePointer(_ref2) {
214
276
  } else if (typeof window.scrollBy === "function") {
215
277
  window.scrollBy(dx, dy);
216
278
  }
217
- setDraft(moveKey(latest.current.keys, key, targetIndex(point, key)));
279
+ track();
218
280
  frame = raf(_autoScroll);
219
281
  };
220
282
  var activate = function activate() {
@@ -236,20 +298,24 @@ function useSortablePointer(_ref2) {
236
298
  if (distance < DRAG_THRESHOLD) return;
237
299
  activate();
238
300
  }
239
- setDraft(moveKey(latest.current.keys, key, targetIndex(point, key)));
301
+ track();
240
302
  if (frame === null) frame = raf(_autoScroll);
241
303
  };
242
304
  var onUp = function onUp() {
305
+ var _latest$current$cross2;
243
306
  end();
244
307
  if (!active) return;
245
308
  setDragging(null);
309
+ if ((_latest$current$cross2 = latest.current.cross) !== null && _latest$current$cross2 !== void 0 && _latest$current$cross2.release()) return;
246
310
  latest.current.commit(from, latest.current.keys.indexOf(key));
247
311
  };
248
312
  var onCancel = function onCancel() {
313
+ var _latest$current$cross3;
249
314
  end();
250
315
  if (!active) return;
251
316
  setDragging(null);
252
317
  setDraft(null);
318
+ (_latest$current$cross3 = latest.current.cross) === null || _latest$current$cross3 === void 0 || _latest$current$cross3.cancel();
253
319
  };
254
320
  // Once a touch drag is live, stop the browser from scrolling (and from firing
255
321
  // pointercancel); before that, let the page scroll normally.
@@ -287,4 +353,4 @@ function useSortablePointer(_ref2) {
287
353
  };
288
354
  }
289
355
 
290
- export { AUTO_SCROLL_EDGE, DEFAULT_SORTABLE_MESSAGES, DRAG_THRESHOLD, LONG_PRESS_DELAY, LONG_PRESS_TOLERANCE, edgeSpeed, getScrollParent, moveKey, useSortableKeyboard, useSortablePointer };
356
+ export { AUTO_SCROLL_EDGE, DEFAULT_SORTABLE_MESSAGES, DRAG_THRESHOLD, LONG_PRESS_DELAY, LONG_PRESS_TOLERANCE, arrayMove, defaultGetItemLabel, defaultGetKey, edgeSpeed, getScrollParent, moveKey, useSortableKeyboard, useSortablePointer };
@@ -0,0 +1,268 @@
1
+ 'use client';
2
+ import { slicedToArray as _slicedToArray, toConsumableArray as _toConsumableArray, objectSpread2 as _objectSpread2 } from '../_virtual/_rollupPluginBabelHelpers.js';
3
+ import { useRef, useState, useMemo, createContext, useContext, useEffect, useLayoutEffect } from 'react';
4
+ import { useLatestRef } from './useLatestRef.js';
5
+
6
+ // Internal (not exported). Cross-list moves for Sortable lists inside a
7
+ // SortableGroup. The group holds one "carry": the item on its way from one list
8
+ // to another, the target `{ listId, index }` and whether `canDrop` allows it.
9
+ // The target list draws a placeholder from it; nothing is committed until the
10
+ // drop, so a refused target is never shown as a success.
11
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
12
+ var SortableGroupContext = /*#__PURE__*/createContext(null);
13
+ var documentOrder = function documentOrder(a, b) {
14
+ return a === b ? 0 : a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
15
+ };
16
+ var contains = function contains(rect, point) {
17
+ return point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom;
18
+ };
19
+ /** Insertion index for `point` among the items of a list (midpoint hit-test). */
20
+ function indexAt(list, point) {
21
+ var index = list.itemKeys.findIndex(function (k) {
22
+ var _list$nodeFor;
23
+ var rect = (_list$nodeFor = list.nodeFor(k)) === null || _list$nodeFor === void 0 ? void 0 : _list$nodeFor.getBoundingClientRect();
24
+ if (!rect) return false;
25
+ return list.orientation === "horizontal" ? point.x < rect.left + rect.width / 2 : point.y < rect.top + rect.height / 2;
26
+ });
27
+ return index === -1 ? list.itemKeys.length : index;
28
+ }
29
+ /** State + stable API behind <SortableGroup>. */
30
+ function useSortableGroupState(_ref) {
31
+ var onMove = _ref.onMove,
32
+ canDrop = _ref.canDrop;
33
+ var lists = useRef(new Map());
34
+ var carryRef = useRef(null);
35
+ var focusRef = useRef(null);
36
+ var _useState = useState(null),
37
+ _useState2 = _slicedToArray(_useState, 2),
38
+ carry = _useState2[0],
39
+ setCarryState = _useState2[1];
40
+ var latest = useLatestRef({
41
+ onMove: onMove,
42
+ canDrop: canDrop
43
+ });
44
+ var api = useMemo(function () {
45
+ var setCarry = function setCarry(next) {
46
+ carryRef.current = next;
47
+ setCarryState(next);
48
+ return next;
49
+ };
50
+ var read = function read(id) {
51
+ var _lists$current$get;
52
+ return (_lists$current$get = lists.current.get(id)) === null || _lists$current$get === void 0 ? void 0 : _lists$current$get();
53
+ };
54
+ return {
55
+ pendingFocus: function pendingFocus() {
56
+ return focusRef.current;
57
+ },
58
+ clearFocus: function clearFocus() {
59
+ focusRef.current = null;
60
+ },
61
+ read: read,
62
+ current: function current() {
63
+ return carryRef.current;
64
+ },
65
+ register: function register(id, reader) {
66
+ lists.current.set(id, reader);
67
+ return function () {
68
+ if (lists.current.get(id) === reader) lists.current["delete"](id);
69
+ };
70
+ },
71
+ /** List ids in document order (only lists that are mounted). */
72
+ order: function order() {
73
+ return _toConsumableArray(lists.current.keys()).filter(function (id) {
74
+ var _read;
75
+ return (_read = read(id)) === null || _read === void 0 ? void 0 : _read.node;
76
+ }).sort(function (a, b) {
77
+ return documentOrder(read(a).node, read(b).node);
78
+ });
79
+ },
80
+ aim: function aim(from, item, target) {
81
+ var c = carryRef.current;
82
+ if (c && c.from.listId === from.listId && c.target.listId === target.listId && c.target.index === target.index) return c;
83
+ var test = latest.current.canDrop;
84
+ return setCarry({
85
+ from: from,
86
+ item: item,
87
+ target: target,
88
+ allowed: test ? Boolean(test(item, target, from)) : true
89
+ });
90
+ },
91
+ clear: function clear() {
92
+ if (carryRef.current) setCarry(null);
93
+ },
94
+ drop: function drop(c, focus) {
95
+ var _latest$current$onMov, _latest$current;
96
+ setCarry(null);
97
+ focusRef.current = focus || null;
98
+ (_latest$current$onMov = (_latest$current = latest.current).onMove) === null || _latest$current$onMov === void 0 || _latest$current$onMov.call(_latest$current, {
99
+ item: c.item,
100
+ from: c.from,
101
+ to: c.target
102
+ });
103
+ }
104
+ };
105
+ }, [latest]);
106
+ return useMemo(function () {
107
+ return {
108
+ api: api,
109
+ carry: carry
110
+ };
111
+ }, [api, carry]);
112
+ }
113
+ function makeCross(api, latest) {
114
+ var me = function me() {
115
+ return latest.current;
116
+ };
117
+ var origin = function origin(key) {
118
+ var m = me();
119
+ var index = m.itemKeys.indexOf(key);
120
+ return {
121
+ from: {
122
+ listId: m.listId,
123
+ index: index
124
+ },
125
+ item: m.items[index]
126
+ };
127
+ };
128
+ var say = function say(kind, key) {
129
+ var _me;
130
+ for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
131
+ args[_key - 2] = arguments[_key];
132
+ }
133
+ return (_me = me()).announce.apply(_me, [kind, me().labelFor(key)].concat(args));
134
+ };
135
+ var aimAt = function aimAt(key, target) {
136
+ var _origin = origin(key),
137
+ from = _origin.from,
138
+ item = _origin.item;
139
+ var next = api.aim(from, item, target);
140
+ var list = api.read(target.listId);
141
+ if (next.allowed) say("movedToList", key, list.label, target.index + 1, list.items.length + 1);else say("refused", key, list.label);
142
+ };
143
+ return {
144
+ // Pointer: true while the pointer is over another list of the group.
145
+ over: function over(point, key) {
146
+ var id = api.order().find(function (other) {
147
+ return other !== me().listId && contains(api.read(other).node.getBoundingClientRect(), point);
148
+ });
149
+ if (id === undefined) {
150
+ api.clear();
151
+ return false;
152
+ }
153
+ var _origin2 = origin(key),
154
+ from = _origin2.from,
155
+ item = _origin2.item;
156
+ api.aim(from, item, {
157
+ listId: id,
158
+ index: indexAt(api.read(id), point)
159
+ });
160
+ return true;
161
+ },
162
+ // Pointer drop: true when the drop was handled here (moved, or refused and dropped nowhere).
163
+ release: function release() {
164
+ var c = api.current();
165
+ if (!c) return false;
166
+ if (c.allowed) api.drop(c);else api.clear();
167
+ return true;
168
+ },
169
+ // Keyboard: carry the item to the previous (-1) or next (1) list.
170
+ step: function step(key, dir) {
171
+ var m = me();
172
+ var ids = api.order();
173
+ var c = api.current();
174
+ var nextId = ids[ids.indexOf(c ? c.target.listId : m.listId) + dir];
175
+ if (nextId === undefined) return;
176
+ m.setDraft(null);
177
+ if (nextId === m.listId) {
178
+ api.clear();
179
+ say("moved", key, m.itemKeys.indexOf(key) + 1, m.itemKeys.length);
180
+ return;
181
+ }
182
+ var index = c ? c.target.index : m.keys.indexOf(key);
183
+ aimAt(key, {
184
+ listId: nextId,
185
+ index: Math.min(index, api.read(nextId).items.length)
186
+ });
187
+ },
188
+ // Keyboard: move within the target list; false when the item is still in its own list.
189
+ nudge: function nudge(key, delta) {
190
+ var c = api.current();
191
+ if (!c) return false;
192
+ var size = api.read(c.target.listId).items.length;
193
+ var index = Math.max(0, Math.min(size, c.target.index + delta));
194
+ if (index !== c.target.index) aimAt(key, {
195
+ listId: c.target.listId,
196
+ index: index
197
+ });
198
+ return true;
199
+ },
200
+ // Keyboard drop: "dropped", "refused" (keep carrying) or false (in-list drop).
201
+ drop: function drop(key) {
202
+ var c = api.current();
203
+ if (!c) return false;
204
+ var list = api.read(c.target.listId);
205
+ if (!c.allowed) {
206
+ say("refused", key, list.label);
207
+ return "refused";
208
+ }
209
+ api.drop(c, {
210
+ listId: c.target.listId,
211
+ key: list.getKey(c.item, c.target.index)
212
+ });
213
+ say("droppedInList", key, list.label, c.target.index + 1, list.items.length + 1);
214
+ return "dropped";
215
+ },
216
+ cancel: function cancel() {
217
+ return api.clear();
218
+ }
219
+ };
220
+ }
221
+ /**
222
+ * Wires one Sortable into the surrounding SortableGroup (if any). Outside a
223
+ * group, or without an `id`, it returns `{ cross: undefined }` and the list
224
+ * behaves exactly like a standalone Sortable.
225
+ */
226
+ function useSortableGroupMember(options) {
227
+ var _group$api;
228
+ var group = useContext(SortableGroupContext);
229
+ var latest = useLatestRef(options);
230
+ var listId = options.listId,
231
+ itemKeys = options.itemKeys,
232
+ nodeFor = options.nodeFor;
233
+ var api = listId == null ? null : (_group$api = group === null || group === void 0 ? void 0 : group.api) !== null && _group$api !== void 0 ? _group$api : null;
234
+ useEffect(function () {
235
+ return api ? api.register(listId, function () {
236
+ return _objectSpread2(_objectSpread2({}, latest.current), {}, {
237
+ node: latest.current.listRef.current
238
+ });
239
+ }) : undefined;
240
+ }, [api, listId, latest]);
241
+ var cross = useMemo(function () {
242
+ return api ? makeCross(api, latest) : undefined;
243
+ }, [api, latest]);
244
+ // After a keyboard drop the moved item mounts here; keep focus on it.
245
+ var signature = itemKeys.join("\0");
246
+ useIsomorphicLayoutEffect(function () {
247
+ var pending = api === null || api === void 0 ? void 0 : api.pendingFocus();
248
+ if (!pending || pending.listId !== listId) return;
249
+ var node = nodeFor(pending.key);
250
+ if (node) {
251
+ api.clearFocus();
252
+ node.focus();
253
+ }
254
+ }, [api, listId, signature, nodeFor]);
255
+ var carry = api ? group.carry : null;
256
+ return {
257
+ cross: cross,
258
+ // Where another list's item would land in this list.
259
+ incoming: carry && carry.target.listId === listId ? {
260
+ index: carry.target.index,
261
+ allowed: carry.allowed
262
+ } : null,
263
+ // This list's item currently aimed at another list.
264
+ outgoing: carry && carry.from.listId === listId ? carry : null
265
+ };
266
+ }
267
+
268
+ export { SortableGroupContext, indexAt, useSortableGroupMember, useSortableGroupState };
package/dist/esm/index.js CHANGED
@@ -57,6 +57,7 @@ export { default as FileUpload } from './components/utility/FileUpload.js';
57
57
  export { Condition } from './components/utility/Condition.js';
58
58
  export { Carousel } from './components/utility/Carousel.js';
59
59
  export { default as Sortable } from './components/utility/Sortable.js';
60
+ export { default as SortableGroup } from './components/utility/SortableGroup.js';
60
61
  export { default as PullToRefresh } from './components/utility/PullToRefresh.js';
61
62
  export { default as AppShell } from './components/blocks/AppShell.js';
62
63
  export { default as PageHeader } from './components/blocks/PageHeader.js';
@@ -1,39 +1,48 @@
1
+ export function arrayMove(list: any, from: any, to: any): any;
1
2
  export function moveKey(keys: any, key: any, toIndex: any): any;
2
- export function useSortableKeyboard({ keys, setDraft, commit, announce, labelFor, orientation }: {
3
+ export function useSortableKeyboard({ keys, setDraft, commit, announce, labelFor, orientation, cross }: {
3
4
  keys: any;
4
5
  setDraft: any;
5
6
  commit: any;
6
7
  announce: any;
7
8
  labelFor: any;
8
9
  orientation: any;
10
+ cross: any;
9
11
  }): {
10
12
  grabbed: null;
11
- keyDownFor: (key: any) => (e: any) => void;
13
+ keyDownFor: (key: any) => (e: any) => any;
12
14
  cancel: () => void;
13
15
  };
14
16
  /** Nearest scrollable ancestor along `axis`, or `null` for the window. */
15
17
  export function getScrollParent(node: any, axis: any): any;
16
18
  /** Scroll speed (px/frame, signed) for a coordinate near the [start, end] edges. */
17
19
  export function edgeSpeed(pos: any, start: any, end: any, edge?: number): number;
18
- export function useSortablePointer({ keys, setDraft, commit, nodeFor, orientation, disabled }: {
20
+ export function useSortablePointer({ keys, setDraft, commit, nodeFor, orientation, disabled, cross }: {
19
21
  keys: any;
20
22
  setDraft: any;
21
23
  commit: any;
22
24
  nodeFor: any;
23
25
  orientation: any;
24
26
  disabled: any;
27
+ cross: any;
25
28
  }): {
26
29
  dragging: null;
27
30
  startFor: (key: any, { longPress }?: {
28
31
  longPress?: boolean | undefined;
29
32
  }) => (e: any) => void;
30
33
  };
34
+ export function defaultGetKey(item: any, index: any): any;
35
+ export function defaultGetItemLabel(item: any, index: any): any;
31
36
  export namespace DEFAULT_SORTABLE_MESSAGES {
32
37
  let instructions: string;
33
38
  function grabbed(label: any, position: any, total: any): string;
34
39
  function moved(label: any, position: any, total: any): string;
35
40
  function dropped(label: any, position: any, total: any): string;
36
41
  function cancelled(label: any, position: any): string;
42
+ let groupInstructions: string;
43
+ function movedToList(label: any, list: any, position: any, total: any): string;
44
+ function droppedInList(label: any, list: any, position: any, total: any): string;
45
+ function refused(label: any, list: any): string;
37
46
  }
38
47
  export const DRAG_THRESHOLD: 4;
39
48
  export const LONG_PRESS_DELAY: 250;
@@ -1 +1 @@
1
- {"version":3,"file":"useSortable.d.ts","sourceRoot":"","sources":["../../src/hooks/useSortable.js"],"names":[],"mappings":"AAOA,gEAIC;AAcD;;;;;;;;;+BAK+B,MAAC;;EAqC/B;AAqBD,0EAA0E;AAC1E,2DAOC;AAED,oFAAoF;AACpF,iFAIC;AAOD;;;;;;;;;;;WAwByD,MAAC;EAgGzD;;;IAtNU,gEAAmF;IACrF,8DAAiF;IAC/E,gEAAmF;IACjF,sDAAoF;;AAoDjG,6BAA8B,CAAC,CAAC;AAGhC,+BAAgC,GAAG,CAAC;AACpC,mCAAoC,CAAC,CAAC;AAGtC,+BAAgC,EAAE,CAAC"}
1
+ {"version":3,"file":"useSortable.d.ts","sourceRoot":"","sources":["../../src/hooks/useSortable.js"],"names":[],"mappings":"AAaA,8DAKC;AAED,gEAIC;AA0BD;;;;;;;;;;+BAK+B,MAAC;;EA4C/B;AAqBD,0EAA0E;AAC1E,2DAOC;AAED,oFAAoF;AACpF,iFAIC;AAOD;;;;;;;;;;;;WAwByD,MAAC;EAyGzD;AAtQM,0DAAqE;AACrE,gEACgI;;;IAkB5H,gEAAmF;IACrF,8DAAiF;IAC/E,gEAAmF;IACjF,sDAAoF;;IAGlF,+EAAgG;IAC9F,iFAAoG;IAC1G,gDAAyD;;AAkEpE,6BAA8B,CAAC,CAAC;AAGhC,+BAAgC,GAAG,CAAC;AACpC,mCAAoC,CAAC,CAAC;AAGtC,+BAAgC,EAAE,CAAC"}
@@ -0,0 +1,43 @@
1
+ /** Insertion index for `point` among the items of a list (midpoint hit-test). */
2
+ export function indexAt(list: any, point: any): any;
3
+ /** State + stable API behind <SortableGroup>. */
4
+ export function useSortableGroupState({ onMove, canDrop }: {
5
+ onMove: any;
6
+ canDrop: any;
7
+ }): {
8
+ api: {
9
+ pendingFocus: () => null;
10
+ clearFocus: () => void;
11
+ read: (id: any) => any;
12
+ current: () => null;
13
+ register(id: any, reader: any): () => void;
14
+ /** List ids in document order (only lists that are mounted). */
15
+ order: () => any[];
16
+ aim(from: any, item: any, target: any): any;
17
+ clear: () => void;
18
+ drop(c: any, focus: any): void;
19
+ };
20
+ carry: null;
21
+ };
22
+ /**
23
+ * Wires one Sortable into the surrounding SortableGroup (if any). Outside a
24
+ * group, or without an `id`, it returns `{ cross: undefined }` and the list
25
+ * behaves exactly like a standalone Sortable.
26
+ */
27
+ export function useSortableGroupMember(options: any): {
28
+ cross: {
29
+ over(point: any, key: any): boolean;
30
+ release(): boolean;
31
+ step(key: any, dir: any): void;
32
+ nudge(key: any, delta: any): boolean;
33
+ drop(key: any): false | "refused" | "dropped";
34
+ cancel: () => any;
35
+ } | undefined;
36
+ incoming: {
37
+ index: any;
38
+ allowed: any;
39
+ } | null;
40
+ outgoing: any;
41
+ };
42
+ export const SortableGroupContext: import("react").Context<null>;
43
+ //# sourceMappingURL=useSortableGroup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSortableGroup.d.ts","sourceRoot":"","sources":["../../src/hooks/useSortableGroup.js"],"names":[],"mappings":"AAmBA,iFAAiF;AACjF,oDAOC;AAED,iDAAiD;AACjD;;;;;;;;;;QA2BM,gEAAgE;;;;;;;EAqBrE;AAgFD;;;;GAIG;AACH;;;;;;;;;;;;;;EAiCC;AAzLD,iEAAwD"}