foldkit 0.42.0 → 0.43.1

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.
@@ -0,0 +1,511 @@
1
+ import { Array, Effect, Equal, Equivalence, Function, Match as M, Option, Schema as S, Stream, pipe, } from 'effect';
2
+ import * as Command from '../../command';
3
+ import { html } from '../../html';
4
+ import { m } from '../../message';
5
+ import { makeSubscriptions } from '../../runtime/subscription';
6
+ import { ts } from '../../schema';
7
+ import { evo } from '../../struct';
8
+ import * as Task from '../../task';
9
+ // MODEL
10
+ const Orientation = S.Literal('Horizontal', 'Vertical');
11
+ const ScreenPoint = S.Struct({
12
+ screenX: S.Number,
13
+ screenY: S.Number,
14
+ });
15
+ const ClientPoint = S.Struct({
16
+ clientX: S.Number,
17
+ clientY: S.Number,
18
+ });
19
+ const DropTarget = S.Struct({
20
+ containerId: S.String,
21
+ index: S.Number,
22
+ });
23
+ const Idle = ts('Idle');
24
+ const Pending = ts('Pending', {
25
+ itemId: S.String,
26
+ containerId: S.String,
27
+ index: S.Number,
28
+ origin: ScreenPoint,
29
+ });
30
+ const Dragging = ts('Dragging', {
31
+ itemId: S.String,
32
+ sourceContainerId: S.String,
33
+ sourceIndex: S.Number,
34
+ origin: ScreenPoint,
35
+ current: ClientPoint,
36
+ maybeDropTarget: S.OptionFromSelf(DropTarget),
37
+ });
38
+ const KeyboardDragging = ts('KeyboardDragging', {
39
+ itemId: S.String,
40
+ sourceContainerId: S.String,
41
+ sourceIndex: S.Number,
42
+ targetContainerId: S.String,
43
+ targetIndex: S.Number,
44
+ });
45
+ const DragState = S.Union(Idle, Pending, Dragging, KeyboardDragging);
46
+ /** Schema for the drag-and-drop component's state, tracking its unique ID, orientation, and current drag phase. */
47
+ export const Model = S.Struct({
48
+ id: S.String,
49
+ orientation: Orientation,
50
+ activationThreshold: S.Number,
51
+ dragState: DragState,
52
+ });
53
+ // MESSAGE
54
+ /** The user pressed a pointer on a draggable item. */
55
+ export const PressedDraggable = m('PressedDraggable', {
56
+ itemId: S.String,
57
+ containerId: S.String,
58
+ index: S.Number,
59
+ screenX: S.Number,
60
+ screenY: S.Number,
61
+ });
62
+ /** The pointer moved during a drag, with collision detection results. */
63
+ export const MovedPointer = m('MovedPointer', {
64
+ screenX: S.Number,
65
+ screenY: S.Number,
66
+ clientX: S.Number,
67
+ clientY: S.Number,
68
+ maybeDropTarget: S.OptionFromSelf(DropTarget),
69
+ });
70
+ /** The pointer was released. */
71
+ export const ReleasedPointer = m('ReleasedPointer');
72
+ /** Escape was pressed during a drag. */
73
+ export const CancelledDrag = m('CancelledDrag');
74
+ /** The user activated keyboard drag with Space or Enter on a focused draggable. */
75
+ export const ActivatedKeyboardDrag = m('ActivatedKeyboardDrag', {
76
+ itemId: S.String,
77
+ containerId: S.String,
78
+ index: S.Number,
79
+ });
80
+ /** The ResolveKeyboardMove Command resolved the next keyboard drag position. */
81
+ export const ResolvedKeyboardMove = m('ResolvedKeyboardMove', {
82
+ targetContainerId: S.String,
83
+ targetIndex: S.Number,
84
+ });
85
+ /** The user confirmed a keyboard drop with Space or Enter. */
86
+ export const ConfirmedKeyboardDrop = m('ConfirmedKeyboardDrop');
87
+ /** The user pressed an arrow key during keyboard drag. */
88
+ export const PressedArrowKey = m('PressedArrowKey', {
89
+ direction: S.Literal('Up', 'Down', 'Left', 'Right', 'NextContainer', 'PreviousContainer'),
90
+ });
91
+ /** An animation frame fired during auto-scroll. */
92
+ export const CompletedAutoScroll = m('CompletedAutoScroll');
93
+ /** The FocusItem Command completed. */
94
+ export const CompletedFocusItem = m('CompletedFocusItem');
95
+ /** Union of all messages the drag-and-drop component can produce. */
96
+ export const Message = S.Union(PressedDraggable, MovedPointer, ReleasedPointer, CancelledDrag, ActivatedKeyboardDrag, ResolvedKeyboardMove, ConfirmedKeyboardDrop, PressedArrowKey, CompletedAutoScroll, CompletedFocusItem);
97
+ // OUT MESSAGE
98
+ /** Emitted when a drag completes with a valid drop target. The parent uses this to commit the reorder. */
99
+ export const Reordered = ts('Reordered', {
100
+ itemId: S.String,
101
+ fromContainerId: S.String,
102
+ fromIndex: S.Number,
103
+ toContainerId: S.String,
104
+ toIndex: S.Number,
105
+ });
106
+ /** Emitted when a drag is cancelled via Escape or pointer release without a drop target. */
107
+ export const Cancelled = ts('Cancelled');
108
+ /** Union of all out-messages the drag-and-drop component can emit to its parent. */
109
+ export const OutMessage = S.Union(Reordered, Cancelled);
110
+ // INIT
111
+ /** Configuration for creating a drag-and-drop model with `init`. */
112
+ const DEFAULT_ACTIVATION_THRESHOLD_PIXELS = 5;
113
+ /** Creates an initial drag-and-drop model. Starts in the Idle state with Vertical orientation and 5px activation threshold by default. */
114
+ export const init = (config) => ({
115
+ id: config.id,
116
+ orientation: config.orientation ?? 'Vertical',
117
+ activationThreshold: config.activationThreshold ?? DEFAULT_ACTIVATION_THRESHOLD_PIXELS,
118
+ dragState: Idle(),
119
+ });
120
+ /** Resolves the next keyboard drag position by querying the DOM for adjacent sortable items and containers. */
121
+ export const ResolveKeyboardMove = Command.define('ResolveKeyboardMove', ResolvedKeyboardMove);
122
+ /** Focuses a draggable item by ID after keyboard drop or cancel. */
123
+ export const FocusItem = Command.define('FocusItem', CompletedFocusItem);
124
+ const focusItem = (itemId) => FocusItem(Task.focus(`[data-draggable-id="${itemId}"]`).pipe(Effect.ignore, Effect.as(CompletedFocusItem())));
125
+ const resolveWithinContainer = (config) => {
126
+ const container = document.querySelector(`[data-droppable-id="${config.containerId}"]`);
127
+ if (!container) {
128
+ return ResolvedKeyboardMove({
129
+ targetContainerId: config.containerId,
130
+ targetIndex: config.currentIndex,
131
+ });
132
+ }
133
+ const itemCount = pipe(container.querySelectorAll('[data-sortable-id]'), Array.fromIterable, Array.filter(({ dataset }) => dataset['sortableId'] !== config.itemId), Array.length);
134
+ const nextIndex = config.isForward
135
+ ? Math.min(config.currentIndex + 1, itemCount)
136
+ : Math.max(config.currentIndex - 1, 0);
137
+ return ResolvedKeyboardMove({
138
+ targetContainerId: config.containerId,
139
+ targetIndex: nextIndex,
140
+ });
141
+ };
142
+ const resolveBetweenContainers = (config) => {
143
+ const allContainers = Array.fromIterable(document.querySelectorAll('[data-droppable-id]'));
144
+ const currentContainerIndex = pipe(allContainers, Array.findFirstIndex(({ dataset }) => dataset['droppableId'] === config.currentContainerId), Option.getOrElse(() => 0));
145
+ const nextContainerIndex = config.isForward
146
+ ? Math.min(currentContainerIndex + 1, allContainers.length - 1)
147
+ : Math.max(currentContainerIndex - 1, 0);
148
+ const nextContainerId = allContainers[nextContainerIndex]?.dataset['droppableId'] ??
149
+ config.currentContainerId;
150
+ return ResolvedKeyboardMove({
151
+ targetContainerId: nextContainerId,
152
+ targetIndex: 0,
153
+ });
154
+ };
155
+ const resolveKeyboardMoveTarget = (config) => Effect.sync(() => M.value(config.direction).pipe(M.withReturnType(), M.whenOr('Down', 'Right', () => resolveWithinContainer({
156
+ itemId: config.itemId,
157
+ containerId: config.currentContainerId,
158
+ currentIndex: config.currentIndex,
159
+ isForward: true,
160
+ })), M.whenOr('Up', 'Left', () => resolveWithinContainer({
161
+ itemId: config.itemId,
162
+ containerId: config.currentContainerId,
163
+ currentIndex: config.currentIndex,
164
+ isForward: false,
165
+ })), M.when('NextContainer', () => resolveBetweenContainers({
166
+ currentContainerId: config.currentContainerId,
167
+ isForward: true,
168
+ })), M.when('PreviousContainer', () => resolveBetweenContainers({
169
+ currentContainerId: config.currentContainerId,
170
+ isForward: false,
171
+ })), M.exhaustive));
172
+ const withUpdateReturn = M.withReturnType();
173
+ /** Processes a drag-and-drop message and returns the next model, commands, and an optional out-message for the parent. */
174
+ export const update = (model, message) => M.value(message).pipe(withUpdateReturn, M.tagsExhaustive({
175
+ PressedDraggable: ({ itemId, containerId, index, screenX, screenY }) => [
176
+ evo(model, {
177
+ dragState: () => Pending({
178
+ itemId,
179
+ containerId,
180
+ index,
181
+ origin: { screenX, screenY },
182
+ }),
183
+ }),
184
+ [],
185
+ Option.none(),
186
+ ],
187
+ MovedPointer: ({ screenX, screenY, clientX, clientY, maybeDropTarget }) => M.value(model.dragState).pipe(withUpdateReturn, M.tag('Pending', pending => {
188
+ const deltaX = screenX - pending.origin.screenX;
189
+ const deltaY = screenY - pending.origin.screenY;
190
+ const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
191
+ if (distance < model.activationThreshold) {
192
+ return [model, [], Option.none()];
193
+ }
194
+ return [
195
+ evo(model, {
196
+ dragState: () => Dragging({
197
+ itemId: pending.itemId,
198
+ sourceContainerId: pending.containerId,
199
+ sourceIndex: pending.index,
200
+ origin: pending.origin,
201
+ current: { clientX, clientY },
202
+ maybeDropTarget,
203
+ }),
204
+ }),
205
+ [],
206
+ Option.none(),
207
+ ];
208
+ }), M.tag('Dragging', dragging => [
209
+ evo(model, {
210
+ dragState: () => Dragging({
211
+ ...dragging,
212
+ current: { clientX, clientY },
213
+ maybeDropTarget,
214
+ }),
215
+ }),
216
+ [],
217
+ Option.none(),
218
+ ]), M.orElse(() => [model, [], Option.none()])),
219
+ ReleasedPointer: () => M.value(model.dragState).pipe(withUpdateReturn, M.tag('Pending', () => [
220
+ evo(model, { dragState: () => Idle() }),
221
+ [],
222
+ Option.none(),
223
+ ]), M.tag('Dragging', dragging => Option.match(dragging.maybeDropTarget, {
224
+ onNone: () => [
225
+ evo(model, { dragState: () => Idle() }),
226
+ [],
227
+ Option.some(Cancelled()),
228
+ ],
229
+ onSome: dropTarget => [
230
+ evo(model, { dragState: () => Idle() }),
231
+ [],
232
+ Option.some(Reordered({
233
+ itemId: dragging.itemId,
234
+ fromContainerId: dragging.sourceContainerId,
235
+ fromIndex: dragging.sourceIndex,
236
+ toContainerId: dropTarget.containerId,
237
+ toIndex: dropTarget.index,
238
+ })),
239
+ ],
240
+ })), M.orElse(() => [model, [], Option.none()])),
241
+ CancelledDrag: () => {
242
+ const maybeFocusCommand = Option.liftPredicate(model.dragState, dragState => dragState._tag === 'KeyboardDragging').pipe(Option.map(({ itemId }) => focusItem(itemId)));
243
+ const maybeOutMessage = Option.liftPredicate(model.dragState._tag, _tag => _tag === 'Dragging' || _tag === 'KeyboardDragging').pipe(Option.map(() => Cancelled()));
244
+ return [
245
+ evo(model, { dragState: () => Idle() }),
246
+ Option.toArray(maybeFocusCommand),
247
+ maybeOutMessage,
248
+ ];
249
+ },
250
+ ActivatedKeyboardDrag: ({ itemId, containerId, index }) => [
251
+ evo(model, {
252
+ dragState: () => KeyboardDragging({
253
+ itemId,
254
+ sourceContainerId: containerId,
255
+ sourceIndex: index,
256
+ targetContainerId: containerId,
257
+ targetIndex: index,
258
+ }),
259
+ }),
260
+ [],
261
+ Option.none(),
262
+ ],
263
+ ResolvedKeyboardMove: ({ targetContainerId, targetIndex }) => M.value(model.dragState).pipe(withUpdateReturn, M.tag('KeyboardDragging', keyboardDragging => [
264
+ evo(model, {
265
+ dragState: () => KeyboardDragging({
266
+ ...keyboardDragging,
267
+ targetContainerId,
268
+ targetIndex,
269
+ }),
270
+ }),
271
+ [],
272
+ Option.none(),
273
+ ]), M.orElse(() => [model, [], Option.none()])),
274
+ ConfirmedKeyboardDrop: () => M.value(model.dragState).pipe(withUpdateReturn, M.tag('KeyboardDragging', keyboardDragging => [
275
+ evo(model, { dragState: () => Idle() }),
276
+ [focusItem(keyboardDragging.itemId)],
277
+ Option.some(Reordered({
278
+ itemId: keyboardDragging.itemId,
279
+ fromContainerId: keyboardDragging.sourceContainerId,
280
+ fromIndex: keyboardDragging.sourceIndex,
281
+ toContainerId: keyboardDragging.targetContainerId,
282
+ toIndex: keyboardDragging.targetIndex,
283
+ })),
284
+ ]), M.orElse(() => [model, [], Option.none()])),
285
+ PressedArrowKey: ({ direction }) => M.value(model.dragState).pipe(withUpdateReturn, M.tag('KeyboardDragging', keyboardDragging => [
286
+ model,
287
+ [
288
+ ResolveKeyboardMove(resolveKeyboardMoveTarget({
289
+ itemId: keyboardDragging.itemId,
290
+ currentContainerId: keyboardDragging.targetContainerId,
291
+ currentIndex: keyboardDragging.targetIndex,
292
+ direction,
293
+ })),
294
+ ],
295
+ Option.none(),
296
+ ]), M.orElse(() => [model, [], Option.none()])),
297
+ CompletedAutoScroll: () => [model, [], Option.none()],
298
+ CompletedFocusItem: () => [model, [], Option.none()],
299
+ }));
300
+ // SUBSCRIPTION
301
+ const DragActivity = S.Literal('Idle', 'Active');
302
+ const PointerDragActivity = S.Literal('Idle', 'Active');
303
+ const KeyboardDragActivity = S.Literal('Idle', 'Active');
304
+ const resolveDropTarget = (clientX, clientY, orientation) => {
305
+ const maybeContainer = pipe(document.elementsFromPoint(clientX, clientY), Array.fromIterable, Array.findFirst(element => element.hasAttribute('data-droppable-id')));
306
+ return Option.flatMap(maybeContainer, container => {
307
+ const containerId = container.getAttribute('data-droppable-id');
308
+ if (!containerId) {
309
+ return Option.none();
310
+ }
311
+ const sortableItems = Array.fromIterable(container.querySelectorAll('[data-sortable-id]'));
312
+ const insertionIndex = pipe(sortableItems, Array.findFirstIndex(item => {
313
+ const rect = item.getBoundingClientRect();
314
+ return M.value(orientation).pipe(M.when('Vertical', () => clientY < rect.top + rect.height / 2), M.when('Horizontal', () => clientX < rect.left + rect.width / 2), M.exhaustive);
315
+ }), Option.getOrElse(() => sortableItems.length));
316
+ return Option.some({ containerId, index: insertionIndex });
317
+ });
318
+ };
319
+ const DEFAULT_AUTO_SCROLL_EDGE_PIXELS = 40;
320
+ const DEFAULT_AUTO_SCROLL_MAX_SPEED = 15;
321
+ const autoScroll = (clientY) => {
322
+ const viewportHeight = window.innerHeight;
323
+ const distanceFromTop = clientY;
324
+ const distanceFromBottom = viewportHeight - clientY;
325
+ if (distanceFromTop < DEFAULT_AUTO_SCROLL_EDGE_PIXELS) {
326
+ const speed = DEFAULT_AUTO_SCROLL_MAX_SPEED *
327
+ (1 - distanceFromTop / DEFAULT_AUTO_SCROLL_EDGE_PIXELS);
328
+ window.scrollBy(0, -speed);
329
+ }
330
+ else if (distanceFromBottom < DEFAULT_AUTO_SCROLL_EDGE_PIXELS) {
331
+ const speed = DEFAULT_AUTO_SCROLL_MAX_SPEED *
332
+ (1 - distanceFromBottom / DEFAULT_AUTO_SCROLL_EDGE_PIXELS);
333
+ window.scrollBy(0, speed);
334
+ }
335
+ };
336
+ const pointerDragActivityFromModel = (model) => M.value(model.dragState).pipe(M.withReturnType(), M.tag('Pending', 'Dragging', () => 'Active'), M.orElse(() => 'Idle'));
337
+ const dragActivityFromModel = (model) => M.value(model.dragState).pipe(M.withReturnType(), M.tag('Idle', () => 'Idle'), M.orElse(() => 'Active'));
338
+ const keyboardDragActivityFromModel = (model) => M.value(model.dragState).pipe(M.withReturnType(), M.tag('KeyboardDragging', () => 'Active'), M.orElse(() => 'Idle'));
339
+ /** Schema describing the subscription dependencies for document-level drag tracking. */
340
+ export const SubscriptionDeps = S.Struct({
341
+ documentPointer: S.Struct({
342
+ dragActivity: PointerDragActivity,
343
+ orientation: Orientation,
344
+ }),
345
+ documentEscape: S.Struct({ dragActivity: DragActivity }),
346
+ documentKeyboard: S.Struct({ dragActivity: KeyboardDragActivity }),
347
+ autoScroll: S.Struct({
348
+ isDragging: S.Boolean,
349
+ clientY: S.Number,
350
+ }),
351
+ });
352
+ /** Document-level subscriptions for pointer and keyboard events during drag operations. */
353
+ export const subscriptions = makeSubscriptions(SubscriptionDeps)({
354
+ documentPointer: {
355
+ modelToDependencies: model => ({
356
+ dragActivity: pointerDragActivityFromModel(model),
357
+ orientation: model.orientation,
358
+ }),
359
+ dependenciesToStream: ({ dragActivity, orientation }) => {
360
+ const pointerEvents = Stream.merge(Stream.fromEventListener(document, 'pointermove').pipe(Stream.mapEffect(event => Effect.sync(() => MovedPointer({
361
+ screenX: event.screenX,
362
+ screenY: event.screenY,
363
+ clientX: event.clientX,
364
+ clientY: event.clientY,
365
+ maybeDropTarget: resolveDropTarget(event.clientX, event.clientY, orientation),
366
+ })))), Stream.fromEventListener(document, 'pointerup').pipe(Stream.map(() => ReleasedPointer())));
367
+ // NOTE: prevents text selection and locks cursor to grabbing during
368
+ // pointer drag. Uses a <style> element for cursor because inline styles
369
+ // on <html> don't override descendant elements' cursor values.
370
+ const documentDragStyles = Stream.async(_emit => {
371
+ document.documentElement.style.setProperty('user-select', 'none');
372
+ document.documentElement.style.setProperty('-webkit-user-select', 'none');
373
+ const cursorStyle = document.createElement('style');
374
+ cursorStyle.textContent = '* { cursor: grabbing !important; }';
375
+ document.head.appendChild(cursorStyle);
376
+ return Effect.sync(() => {
377
+ document.documentElement.style.removeProperty('user-select');
378
+ document.documentElement.style.removeProperty('-webkit-user-select');
379
+ cursorStyle.remove();
380
+ });
381
+ });
382
+ return Stream.when(Stream.merge(pointerEvents, documentDragStyles), () => dragActivity === 'Active');
383
+ },
384
+ },
385
+ documentEscape: {
386
+ modelToDependencies: model => ({
387
+ dragActivity: dragActivityFromModel(model),
388
+ }),
389
+ dependenciesToStream: ({ dragActivity }) => Stream.when(Stream.fromEventListener(document, 'keydown').pipe(Stream.filter(({ key }) => key === 'Escape'), Stream.map(() => CancelledDrag())), () => dragActivity === 'Active'),
390
+ },
391
+ documentKeyboard: {
392
+ modelToDependencies: model => ({
393
+ dragActivity: keyboardDragActivityFromModel(model),
394
+ }),
395
+ dependenciesToStream: ({ dragActivity }) => Stream.when(Stream.fromEventListener(document, 'keydown').pipe(Stream.mapEffect((event) => Effect.sync(() => {
396
+ // NOTE: the draggable's OnKeyDownPreventDefault calls preventDefault on
397
+ // the Space that activates keyboard drag — skip it here so the same
398
+ // keypress doesn't also confirm the drop in the same tick.
399
+ if (event.defaultPrevented) {
400
+ return Option.none();
401
+ }
402
+ if (event.key === 'Tab') {
403
+ event.preventDefault();
404
+ return Option.some(PressedArrowKey({
405
+ direction: event.shiftKey
406
+ ? 'PreviousContainer'
407
+ : 'NextContainer',
408
+ }));
409
+ }
410
+ if (event.key === ' ' || event.key === 'Enter') {
411
+ event.preventDefault();
412
+ return Option.some(ConfirmedKeyboardDrop());
413
+ }
414
+ return Option.map(arrowKeyToDirection(event.key), direction => {
415
+ event.preventDefault();
416
+ return PressedArrowKey({ direction });
417
+ });
418
+ })), Stream.filterMap(Function.identity)), () => dragActivity === 'Active'),
419
+ },
420
+ autoScroll: {
421
+ modelToDependencies: model => ({
422
+ isDragging: model.dragState._tag === 'Dragging',
423
+ clientY: model.dragState._tag === 'Dragging'
424
+ ? model.dragState.current.clientY
425
+ : 0,
426
+ }),
427
+ equivalence: Equivalence.struct({ isDragging: Equivalence.boolean }),
428
+ dependenciesToStream: ({ isDragging }, readDependencies) => Stream.when(Stream.async(emit => {
429
+ let animationFrameId = 0;
430
+ const step = () => {
431
+ autoScroll(readDependencies().clientY);
432
+ emit.single(CompletedAutoScroll());
433
+ animationFrameId = requestAnimationFrame(step);
434
+ };
435
+ animationFrameId = requestAnimationFrame(step);
436
+ return Effect.sync(() => cancelAnimationFrame(animationFrameId));
437
+ }), () => isDragging),
438
+ },
439
+ });
440
+ // VIEW
441
+ const LEFT_MOUSE_BUTTON = 0;
442
+ const arrowKeyToDirection = (key) => M.value(key).pipe(M.withReturnType(), M.when('ArrowUp', () => 'Up'), M.when('ArrowDown', () => 'Down'), M.when('ArrowLeft', () => 'Left'), M.when('ArrowRight', () => 'Right'), M.option);
443
+ /** Returns attributes the parent attaches to a draggable element. Handles pointer-down, keyboard activation, and ARIA. */
444
+ export const draggable = (config) => {
445
+ const { AriaRoleDescription, DataAttribute, OnKeyDownPreventDefault, OnPointerDown, Role, Style, Tabindex, } = html();
446
+ const isKeyboardDragActivationKey = (key) => key === ' ' || key === 'Enter';
447
+ const handleKeyDown = (key) => {
448
+ if (isKeyboardDragActivationKey(key) &&
449
+ config.model.dragState._tag === 'Idle') {
450
+ return Option.some(config.toParentMessage(ActivatedKeyboardDrag({
451
+ itemId: config.itemId,
452
+ containerId: config.containerId,
453
+ index: config.index,
454
+ })));
455
+ }
456
+ return Option.none();
457
+ };
458
+ return [
459
+ DataAttribute('draggable-id', config.itemId),
460
+ DataAttribute('sortable-id', config.itemId),
461
+ Role('option'),
462
+ AriaRoleDescription('draggable'),
463
+ Tabindex(0),
464
+ OnPointerDown((_pointerType, button, screenX, screenY) => pipe(button, Option.liftPredicate(Equal.equals(LEFT_MOUSE_BUTTON)), Option.map(() => config.toParentMessage(PressedDraggable({
465
+ itemId: config.itemId,
466
+ containerId: config.containerId,
467
+ index: config.index,
468
+ screenX,
469
+ screenY,
470
+ }))))),
471
+ OnKeyDownPreventDefault(handleKeyDown),
472
+ Style({
473
+ 'touch-action': 'none',
474
+ 'user-select': 'none',
475
+ '-webkit-user-select': 'none',
476
+ }),
477
+ ];
478
+ };
479
+ /** Returns attributes the parent attaches to a droppable container element. */
480
+ export const droppable = (containerId, label) => {
481
+ const { AriaLabel, DataAttribute, Role } = html();
482
+ return [
483
+ DataAttribute('droppable-id', containerId),
484
+ Role('listbox'),
485
+ ...(label ? [AriaLabel(label)] : []),
486
+ ];
487
+ };
488
+ /** Returns attributes the parent attaches to a sortable item element. Typically combined with `draggable`. */
489
+ export const sortable = (itemId) => {
490
+ const { DataAttribute } = html();
491
+ return [DataAttribute('sortable-id', itemId)];
492
+ };
493
+ const ghostTransform = (clientX, clientY) => `translate3d(${String(clientX)}px, ${String(clientY)}px, 0)`;
494
+ /** Returns positioning styles for the ghost element, or None when not dragging with a pointer. */
495
+ export const ghostStyle = (model) => M.value(model.dragState).pipe(M.tag('Dragging', dragging => ({
496
+ position: 'fixed',
497
+ top: '0',
498
+ left: '0',
499
+ transform: ghostTransform(dragging.current.clientX, dragging.current.clientY),
500
+ 'pointer-events': 'none',
501
+ 'z-index': '9999',
502
+ })), M.option);
503
+ /** Returns true when the component is actively dragging (pointer or keyboard). */
504
+ export const isDragging = ({ dragState: { _tag } }) => _tag === 'Dragging' || _tag === 'KeyboardDragging';
505
+ /** Returns the ID of the item currently being dragged or pending, if any. */
506
+ export const maybeDraggedItemId = (model) => M.value(model.dragState).pipe(M.tag('Pending', pending => pending.itemId), M.tag('Dragging', dragging => dragging.itemId), M.tag('KeyboardDragging', keyboardDragging => keyboardDragging.itemId), M.option);
507
+ /** Returns the current drop target, if any. Populated during pointer drag (from collision detection) and keyboard drag (from resolved position). */
508
+ export const maybeDropTarget = (model) => M.value(model.dragState).pipe(M.tag('Dragging', dragging => dragging.maybeDropTarget), M.tag('KeyboardDragging', keyboardDragging => Option.some({
509
+ containerId: keyboardDragging.targetContainerId,
510
+ index: keyboardDragging.targetIndex,
511
+ })), M.orElse(() => Option.none()));
@@ -0,0 +1,3 @@
1
+ export { init, update, draggable, droppable, sortable, ghostStyle, isDragging, maybeDraggedItemId, maybeDropTarget, subscriptions, SubscriptionDeps, Model, Message, OutMessage, PressedDraggable, MovedPointer, ReleasedPointer, CancelledDrag, ActivatedKeyboardDrag, ResolvedKeyboardMove, ConfirmedKeyboardDrop, PressedArrowKey, CompletedAutoScroll, CompletedFocusItem, FocusItem, ResolveKeyboardMove, Reordered, Cancelled, } from './index';
2
+ export type { InitConfig, DraggableConfig, DraggableMessage } from './index';
3
+ //# sourceMappingURL=public.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/dragAndDrop/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,SAAS,EACT,SAAS,EACT,QAAQ,EACR,UAAU,EACV,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,KAAK,EACL,OAAO,EACP,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,aAAa,EACb,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,SAAS,EACT,mBAAmB,EACnB,SAAS,EACT,SAAS,GACV,MAAM,SAAS,CAAA;AAEhB,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA"}
@@ -0,0 +1 @@
1
+ export { init, update, draggable, droppable, sortable, ghostStyle, isDragging, maybeDraggedItemId, maybeDropTarget, subscriptions, SubscriptionDeps, Model, Message, OutMessage, PressedDraggable, MovedPointer, ReleasedPointer, CancelledDrag, ActivatedKeyboardDrag, ResolvedKeyboardMove, ConfirmedKeyboardDrop, PressedArrowKey, CompletedAutoScroll, CompletedFocusItem, FocusItem, ResolveKeyboardMove, Reordered, Cancelled, } from './index';
@@ -2,6 +2,7 @@ export * as Button from './button/public';
2
2
  export * as Checkbox from './checkbox/public';
3
3
  export * as Combobox from './combobox/public';
4
4
  export * as Dialog from './dialog/public';
5
+ export * as DragAndDrop from './dragAndDrop/public';
5
6
  export * as Disclosure from './disclosure/public';
6
7
  export * as Fieldset from './fieldset/public';
7
8
  export * as Input from './input/public';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAA;AACvC,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,IAAI,MAAM,eAAe,CAAA;AACrC,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,IAAI,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,WAAW,MAAM,sBAAsB,CAAA;AACnD,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAA;AACvC,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,IAAI,MAAM,eAAe,CAAA;AACrC,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,IAAI,MAAM,eAAe,CAAA"}
package/dist/ui/index.js CHANGED
@@ -2,6 +2,7 @@ export * as Button from './button/public';
2
2
  export * as Checkbox from './checkbox/public';
3
3
  export * as Combobox from './combobox/public';
4
4
  export * as Dialog from './dialog/public';
5
+ export * as DragAndDrop from './dragAndDrop/public';
5
6
  export * as Disclosure from './disclosure/public';
6
7
  export * as Fieldset from './fieldset/public';
7
8
  export * as Input from './input/public';
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/ui/listbox/shared.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/ui/listbox/shared.ts"],"names":[],"mappings":"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"}
@@ -128,7 +128,6 @@ export const closedModel = (model) => constrainedEvo(model, {
128
128
  isOpen: () => false,
129
129
  transitionState: () => model.isAnimated ? 'LeaveStart' : 'Idle',
130
130
  maybeActiveItemIndex: () => Option.none(),
131
- activationTrigger: () => 'Keyboard',
132
131
  searchQuery: () => '',
133
132
  searchVersion: () => 0,
134
133
  maybeLastPointerPosition: () => Option.none(),
@@ -387,11 +386,16 @@ export const makeView = (behavior) => (config) => {
387
386
  const firstEnabledIndex = findFirstEnabledIndex(items.length, 0, isItemDisabledByIndex)(0, 1);
388
387
  const lastEnabledIndex = findFirstEnabledIndex(items.length, 0, isItemDisabledByIndex)(items.length - 1, -1);
389
388
  const selectedItemIndex = behavior.selectedItemIndex(config.model, items, itemToValue);
390
- const handleButtonKeyDown = (key) => M.value(key).pipe(M.whenOr('Enter', ' ', 'ArrowDown', () => Option.some(toParentMessage(Opened({
391
- maybeActiveItemIndex: Option.orElse(selectedItemIndex, () => Option.some(firstEnabledIndex)),
392
- })))), M.when('ArrowUp', () => Option.some(toParentMessage(Opened({
393
- maybeActiveItemIndex: Option.orElse(selectedItemIndex, () => Option.some(lastEnabledIndex)),
394
- })))), M.orElse(() => Option.none()));
389
+ const handleButtonKeyDown = (key) => {
390
+ if (isOpen) {
391
+ return handleItemsKeyDown(key);
392
+ }
393
+ return M.value(key).pipe(M.whenOr('Enter', ' ', 'ArrowDown', () => Option.some(toParentMessage(Opened({
394
+ maybeActiveItemIndex: Option.orElse(selectedItemIndex, () => Option.some(firstEnabledIndex)),
395
+ })))), M.when('ArrowUp', () => Option.some(toParentMessage(Opened({
396
+ maybeActiveItemIndex: Option.orElse(selectedItemIndex, () => Option.some(lastEnabledIndex)),
397
+ })))), M.orElse(() => Option.none()));
398
+ };
395
399
  const handleButtonPointerDown = (pointerType, button) => Option.some(toParentMessage(PressedPointerOnButton({
396
400
  pointerType,
397
401
  button,
@@ -448,15 +452,24 @@ export const makeView = (behavior) => (config) => {
448
452
  onSome: index => [AriaActiveDescendant(itemId(id, index))],
449
453
  });
450
454
  const hooks = anchor
451
- ? anchorHooks({ buttonId: `${id}-button`, anchor })
455
+ ? anchorHooks({
456
+ buttonId: `${id}-button`,
457
+ anchor,
458
+ focusAfterPosition: true,
459
+ })
452
460
  : undefined;
461
+ const focusOnInsert = (element) => {
462
+ if (element instanceof HTMLElement) {
463
+ element.focus();
464
+ }
465
+ };
453
466
  const anchorAttributes = hooks
454
467
  ? [
455
468
  Style({ position: 'absolute', margin: '0', visibility: 'hidden' }),
456
469
  OnInsert(hooks.onInsert),
457
470
  OnDestroy(hooks.onDestroy),
458
471
  ]
459
- : [];
472
+ : [OnInsert(focusOnInsert)];
460
473
  const itemsContainerAttributes = [
461
474
  Id(`${id}-items`),
462
475
  Role('listbox'),