@react-aria/dnd 3.0.0-alpha.0 → 3.0.0-alpha.11

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/dist/types.d.ts CHANGED
@@ -1,22 +1,8 @@
1
- import { AriaButtonProps } from "@react-types/button";
2
- import { DragEndEvent, DragItem, DragMoveEvent, DragStartEvent, DropOperation, DropActivateEvent, DropEnterEvent, DropEvent, DropExitEvent, DropMoveEvent, DragTypes, DroppableCollectionProps, DropTarget, KeyboardDelegate, DropItem } from "@react-types/shared";
3
- import { HTMLAttributes, RefObject, Key } from "react";
1
+ import React, { HTMLAttributes, RefObject, Key } from "react";
2
+ import { DropActivateEvent, DropEnterEvent, DropEvent, DropExitEvent, DropMoveEvent, DropOperation, DragTypes, DroppableCollectionProps, DropTarget, KeyboardDelegate, DragEndEvent, DragItem, DragMoveEvent, DragPreviewRenderer, DragStartEvent, DOMAttributes, DropItem } from "@react-types/shared";
4
3
  import { DroppableCollectionState, DraggableCollectionState } from "@react-stately/dnd";
5
- interface DragOptions {
6
- onDragStart?: (e: DragStartEvent) => void;
7
- onDragMove?: (e: DragMoveEvent) => void;
8
- onDragEnd?: (e: DragEndEvent) => void;
9
- getItems: () => DragItem[];
10
- renderPreview?: (items: DragItem[]) => JSX.Element;
11
- getAllowedDropOperations?: () => DropOperation[];
12
- }
13
- interface DragResult {
14
- dragProps: HTMLAttributes<HTMLElement>;
15
- dragButtonProps: AriaButtonProps;
16
- isDragging: boolean;
17
- }
18
- export function useDrag(options: DragOptions): DragResult;
19
- interface DropOptions {
4
+ import { AriaButtonProps } from "@react-types/button";
5
+ export interface DropOptions {
20
6
  ref: RefObject<HTMLElement>;
21
7
  getDropOperation?: (types: DragTypes, allowedOperations: DropOperation[]) => DropOperation;
22
8
  getDropOperationForPoint?: (types: DragTypes, allowedOperations: DropOperation[], x: number, y: number) => DropOperation;
@@ -26,49 +12,67 @@ interface DropOptions {
26
12
  onDropExit?: (e: DropExitEvent) => void;
27
13
  onDrop?: (e: DropEvent) => void;
28
14
  }
29
- interface DropResult {
15
+ export interface DropResult {
30
16
  dropProps: HTMLAttributes<HTMLElement>;
31
17
  isDropTarget: boolean;
32
18
  }
33
19
  export function useDrop(options: DropOptions): DropResult;
34
- interface DroppableCollectionOptions extends DroppableCollectionProps {
20
+ export interface DroppableCollectionOptions extends DroppableCollectionProps {
35
21
  keyboardDelegate: KeyboardDelegate;
36
22
  getDropTargetFromPoint: (x: number, y: number) => DropTarget | null;
37
23
  }
38
- interface DroppableCollectionResult {
24
+ export interface DroppableCollectionResult {
39
25
  collectionProps: HTMLAttributes<HTMLElement>;
40
26
  }
41
27
  export function useDroppableCollection(props: DroppableCollectionOptions, state: DroppableCollectionState, ref: RefObject<HTMLElement>): DroppableCollectionResult;
42
- interface DroppableItemOptions {
28
+ export interface DroppableItemOptions {
43
29
  target: DropTarget;
44
30
  }
45
- interface DroppableItemResult {
31
+ export interface DroppableItemResult {
46
32
  dropProps: HTMLAttributes<HTMLElement>;
47
33
  }
48
34
  export function useDroppableItem(options: DroppableItemOptions, state: DroppableCollectionState, ref: RefObject<HTMLElement>): DroppableItemResult;
49
- interface DropIndicatorProps {
35
+ export interface DropIndicatorProps {
50
36
  target: DropTarget;
51
37
  }
52
- interface DropIndicatorAria {
38
+ export interface DropIndicatorAria {
53
39
  dropIndicatorProps: HTMLAttributes<HTMLElement>;
54
40
  }
55
41
  export function useDropIndicator(props: DropIndicatorProps, state: DroppableCollectionState, ref: RefObject<HTMLElement>): DropIndicatorAria;
56
- interface DraggableItemProps {
42
+ export interface DragOptions {
43
+ onDragStart?: (e: DragStartEvent) => void;
44
+ onDragMove?: (e: DragMoveEvent) => void;
45
+ onDragEnd?: (e: DragEndEvent) => void;
46
+ getItems: () => DragItem[];
47
+ preview?: RefObject<DragPreviewRenderer>;
48
+ getAllowedDropOperations?: () => DropOperation[];
49
+ }
50
+ export interface DragResult {
51
+ dragProps: HTMLAttributes<HTMLElement>;
52
+ dragButtonProps: AriaButtonProps;
53
+ isDragging: boolean;
54
+ }
55
+ export function useDrag(options: DragOptions): DragResult;
56
+ export interface DraggableItemProps {
57
57
  key: Key;
58
58
  }
59
- interface DraggableItemResult {
59
+ export interface DraggableItemResult {
60
60
  dragProps: HTMLAttributes<HTMLElement>;
61
61
  dragButtonProps: AriaButtonProps;
62
62
  }
63
63
  export function useDraggableItem(props: DraggableItemProps, state: DraggableCollectionState): DraggableItemResult;
64
- interface ClipboardProps {
64
+ export interface DragPreviewProps {
65
+ children: (items: DragItem[]) => JSX.Element;
66
+ }
67
+ export let DragPreview: React.ForwardRefExoticComponent<DragPreviewProps & React.RefAttributes<DragPreviewRenderer>>;
68
+ export interface ClipboardProps {
65
69
  getItems?: () => DragItem[];
66
70
  onCopy?: () => void;
67
71
  onCut?: () => void;
68
72
  onPaste?: (items: DropItem[]) => void;
69
73
  }
70
- interface ClipboardResult {
71
- clipboardProps: HTMLAttributes<HTMLElement>;
74
+ export interface ClipboardResult {
75
+ clipboardProps: DOMAttributes;
72
76
  }
73
77
  export function useClipboard(options: ClipboardProps): ClipboardResult;
74
78
 
@@ -1 +1 @@
1
- {"mappings":"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","sources":["./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/constants.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/utils.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/DragManager.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDrag.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useVirtualDrop.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDrop.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useAutoScroll.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDroppableCollection.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDroppableItem.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDropIndicator.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDraggableItem.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useClipboard.ts","./packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null],"names":[],"version":3,"file":"types.d.ts.map"}
1
+ {"mappings":"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","sources":["packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/constants.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/utils.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/DragManager.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useAutoScroll.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useVirtualDrop.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDrop.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDroppableCollection.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDroppableItem.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDropIndicator.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDrag.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useDraggableItem.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/DragPreview.tsx","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/useClipboard.ts","packages/@react-aria/dnd/src/packages/@react-aria/dnd/src/index.ts","packages/@react-aria/dnd/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,"/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nexport type {DroppableCollectionOptions, DroppableCollectionResult} from './useDroppableCollection';\nexport type {DroppableItemOptions, DroppableItemResult} from './useDroppableItem';\nexport type {DropIndicatorProps, DropIndicatorAria} from './useDropIndicator';\nexport type {DraggableItemProps, DraggableItemResult} from './useDraggableItem';\nexport type {DragPreviewProps} from './DragPreview';\nexport type {DragOptions, DragResult} from './useDrag';\nexport type {DropOptions, DropResult} from './useDrop';\nexport type {ClipboardProps, ClipboardResult} from './useClipboard';\n\nexport {useDrag} from './useDrag';\nexport {useDrop} from './useDrop';\nexport {useDroppableCollection} from './useDroppableCollection';\nexport {useDroppableItem} from './useDroppableItem';\nexport {useDropIndicator} from './useDropIndicator';\nexport {useDraggableItem} from './useDraggableItem';\nexport {useClipboard} from './useClipboard';\nexport {DragPreview} from './DragPreview';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-aria/dnd",
3
- "version": "3.0.0-alpha.0",
3
+ "version": "3.0.0-alpha.11",
4
4
  "description": "Spectrum UI components in React",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/main.js",
@@ -18,23 +18,24 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@babel/runtime": "^7.6.2",
21
- "@react-aria/i18n": "^3.3.0",
22
- "@react-aria/interactions": "^3.3.4",
23
- "@react-aria/live-announcer": "3.0.0-rc.0",
24
- "@react-aria/overlays": "^3.6.2",
25
- "@react-aria/utils": "^3.7.0",
26
- "@react-aria/visually-hidden": "^3.2.1",
27
- "@react-stately/dnd": "3.0.0-alpha.0",
28
- "@react-stately/selection": "^3.4.0",
29
- "@react-types/button": "^3.2.1",
30
- "@react-types/shared": "^3.5.0"
21
+ "@internationalized/string": "^3.0.0",
22
+ "@react-aria/i18n": "^3.5.0",
23
+ "@react-aria/interactions": "^3.10.0",
24
+ "@react-aria/live-announcer": "^3.1.1",
25
+ "@react-aria/overlays": "^3.10.0",
26
+ "@react-aria/utils": "^3.13.2",
27
+ "@react-aria/visually-hidden": "^3.4.0",
28
+ "@react-stately/dnd": "3.0.0-alpha.9",
29
+ "@react-stately/selection": "^3.10.2",
30
+ "@react-types/button": "^3.6.0",
31
+ "@react-types/shared": "^3.14.0"
31
32
  },
32
33
  "peerDependencies": {
33
- "react": "^16.8.0 || ^17.0.0-rc.1",
34
- "react-dom": "^16.8.0 || ^17.0.0-rc.1"
34
+ "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0",
35
+ "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
35
36
  },
36
37
  "publishConfig": {
37
38
  "access": "public"
38
39
  },
39
- "gitHead": "9920ffaa2596a03c4498a15cb940bd2f4ba5cd6a"
40
+ "gitHead": "cd7c0ec917122c7612f653c22f8ed558f8b66ecd"
40
41
  }
@@ -12,8 +12,10 @@
12
12
 
13
13
  import {announce} from '@react-aria/live-announcer';
14
14
  import {ariaHideOutside} from '@react-aria/overlays';
15
- import {DragEndEvent, DragItem, DropActivateEvent, DropEnterEvent, DropEvent, DropExitEvent, DropItem, DropOperation, DropTarget as DroppableCollectionTarget} from '@react-types/shared';
15
+ import {DragEndEvent, DragItem, DropActivateEvent, DropEnterEvent, DropEvent, DropExitEvent, DropItem, DropOperation, DropTarget as DroppableCollectionTarget, FocusableElement} from '@react-types/shared';
16
16
  import {getDragModality, getTypes} from './utils';
17
+ import {getInteractionModality} from '@react-aria/interactions';
18
+ import type {LocalizedStringFormatter} from '@internationalized/string';
17
19
  import {useEffect, useState} from 'react';
18
20
 
19
21
  let dropTargets = new Map<Element, DropTarget>();
@@ -22,7 +24,7 @@ let dragSession: DragSession = null;
22
24
  let subscriptions = new Set<() => void>();
23
25
 
24
26
  interface DropTarget {
25
- element: HTMLElement,
27
+ element: FocusableElement,
26
28
  getDropOperation?: (types: Set<string>, allowedOperations: DropOperation[]) => DropOperation,
27
29
  onDropEnter?: (e: DropEnterEvent, dragTarget: DragTarget) => void,
28
30
  onDropExit?: (e: DropExitEvent) => void,
@@ -42,7 +44,7 @@ export function registerDropTarget(target: DropTarget) {
42
44
  }
43
45
 
44
46
  interface DroppableItem {
45
- element: HTMLElement,
47
+ element: FocusableElement,
46
48
  target: DroppableCollectionTarget,
47
49
  getDropOperation?: (types: Set<string>, allowedOperations: DropOperation[]) => DropOperation
48
50
  }
@@ -55,22 +57,24 @@ export function registerDropItem(item: DroppableItem) {
55
57
  }
56
58
 
57
59
  interface DragTarget {
58
- element: HTMLElement,
60
+ element: FocusableElement,
59
61
  items: DragItem[],
60
62
  allowedDropOperations: DropOperation[],
61
63
  onDragEnd?: (e: DragEndEvent) => void
62
64
  }
63
65
 
64
- export function beginDragging(target: DragTarget, formatMessage: (key: string) => string) {
66
+ export function beginDragging(target: DragTarget, stringFormatter: LocalizedStringFormatter) {
65
67
  if (dragSession) {
66
68
  throw new Error('Cannot begin dragging while already dragging');
67
69
  }
68
70
 
69
- dragSession = new DragSession(target, formatMessage);
71
+ dragSession = new DragSession(target, stringFormatter);
70
72
  requestAnimationFrame(() => {
71
73
  dragSession.setup();
72
-
73
- if (getDragModality() === 'keyboard') {
74
+ if (
75
+ getDragModality() === 'keyboard' ||
76
+ (getDragModality() === 'touch' && getInteractionModality() === 'virtual')
77
+ ) {
74
78
  dragSession.next();
75
79
  }
76
80
  });
@@ -101,6 +105,16 @@ function endDragging() {
101
105
  }
102
106
  }
103
107
 
108
+ export function isValidDropTarget(element: Element): boolean {
109
+ for (let target of dropTargets.keys()) {
110
+ if (target.contains(element)) {
111
+ return true;
112
+ }
113
+ }
114
+
115
+ return false;
116
+ }
117
+
104
118
  const CANCELED_EVENTS = [
105
119
  'pointerdown',
106
120
  'pointermove',
@@ -119,7 +133,9 @@ const CANCELED_EVENTS = [
119
133
  'touchstart',
120
134
  'touchmove',
121
135
  'touchend',
122
- 'keyup'
136
+ 'keyup',
137
+ 'focusin',
138
+ 'focusout'
123
139
  ];
124
140
 
125
141
  const CLICK_EVENTS = [
@@ -141,19 +157,22 @@ class DragSession {
141
157
  currentDropItem: DroppableItem;
142
158
  dropOperation: DropOperation;
143
159
  private mutationObserver: MutationObserver;
144
- private mutationImmediate: NodeJS.Immediate;
145
160
  private restoreAriaHidden: () => void;
146
- private formatMessage: (key: string) => string;
161
+ private stringFormatter: LocalizedStringFormatter;
162
+ private isVirtualClick: boolean;
163
+ private initialFocused: boolean;
147
164
 
148
- constructor(target: DragTarget, formatMessage: (key: string) => string) {
165
+ constructor(target: DragTarget, stringFormatter: LocalizedStringFormatter) {
149
166
  this.dragTarget = target;
150
- this.formatMessage = formatMessage;
167
+ this.stringFormatter = stringFormatter;
151
168
 
152
169
  this.onKeyDown = this.onKeyDown.bind(this);
153
170
  this.onFocus = this.onFocus.bind(this);
154
171
  this.onBlur = this.onBlur.bind(this);
155
172
  this.onClick = this.onClick.bind(this);
173
+ this.onPointerDown = this.onPointerDown.bind(this);
156
174
  this.cancelEvent = this.cancelEvent.bind(this);
175
+ this.initialFocused = false;
157
176
  }
158
177
 
159
178
  setup() {
@@ -161,25 +180,18 @@ class DragSession {
161
180
  window.addEventListener('focus', this.onFocus, true);
162
181
  window.addEventListener('blur', this.onBlur, true);
163
182
  document.addEventListener('click', this.onClick, true);
183
+ document.addEventListener('pointerdown', this.onPointerDown, true);
164
184
 
165
185
  for (let event of CANCELED_EVENTS) {
166
186
  document.addEventListener(event, this.cancelEvent, true);
167
187
  }
168
188
 
169
- this.mutationObserver = new MutationObserver(() => {
170
- // JSDOM has a bug where MutationObserver enters an infinite loop if mutations
171
- // occur inside a MutationObserver callback. If running in Node, wait until
172
- // the next tick to update valid drop targets.
173
- // See https://github.com/jsdom/jsdom/issues/3096
174
- if (typeof setImmediate === 'function') {
175
- this.mutationImmediate = setImmediate(() => this.updateValidDropTargets());
176
- } else {
177
- this.updateValidDropTargets();
178
- }
179
- });
189
+ this.mutationObserver = new MutationObserver(() =>
190
+ this.updateValidDropTargets()
191
+ );
180
192
  this.updateValidDropTargets();
181
193
 
182
- announce(this.formatMessage(MESSAGES[getDragModality()]));
194
+ announce(this.stringFormatter.format(MESSAGES[getDragModality()]));
183
195
  }
184
196
 
185
197
  teardown() {
@@ -187,6 +199,7 @@ class DragSession {
187
199
  window.removeEventListener('focus', this.onFocus, true);
188
200
  window.removeEventListener('blur', this.onBlur, true);
189
201
  document.removeEventListener('click', this.onClick, true);
202
+ document.removeEventListener('pointerdown', this.onPointerDown, true);
190
203
 
191
204
  for (let event of CANCELED_EVENTS) {
192
205
  document.removeEventListener(event, this.cancelEvent, true);
@@ -194,9 +207,6 @@ class DragSession {
194
207
 
195
208
  this.mutationObserver.disconnect();
196
209
  this.restoreAriaHidden();
197
- if (this.mutationImmediate) {
198
- clearImmediate(this.mutationImmediate);
199
- }
200
210
  }
201
211
 
202
212
  onKeyDown(e: KeyboardEvent) {
@@ -272,25 +282,34 @@ class DragSession {
272
282
 
273
283
  onClick(e: MouseEvent) {
274
284
  this.cancelEvent(e);
285
+ if (e.detail === 0 || this.isVirtualClick) {
286
+ if (e.target === this.dragTarget.element) {
287
+ this.cancel();
288
+ return;
289
+ }
275
290
 
276
- if (e.detail !== 0) {
277
- return;
278
- }
279
-
280
- if (e.target === this.dragTarget.element) {
281
- this.cancel();
282
- return;
291
+ let dropTarget = this.validDropTargets.find(target => target.element.contains(e.target as HTMLElement));
292
+ if (dropTarget) {
293
+ let item = dropItems.get(e.target as HTMLElement);
294
+ this.setCurrentDropTarget(dropTarget, item);
295
+ this.drop(item);
296
+ }
283
297
  }
298
+ }
284
299
 
285
- let dropTarget = this.validDropTargets.find(target => target.element.contains(e.target as HTMLElement));
286
- if (dropTarget) {
287
- let item = dropItems.get(e.target as HTMLElement);
288
- this.setCurrentDropTarget(dropTarget, item);
289
- this.drop(item);
290
- }
300
+ onPointerDown(e: PointerEvent) {
301
+ // Android Talkback double tap has e.detail = 1 for onClick. Detect the virtual click in onPointerDown before onClick fires
302
+ // so we can properly perform cancel and drop operations.
303
+ this.cancelEvent(e);
304
+ this.isVirtualClick = isVirtualPointerEvent(e);
291
305
  }
292
306
 
293
307
  cancelEvent(e: Event) {
308
+ // Allow focusin and focusout on the drag target so focus ring works properly.
309
+ if ((e.type === 'focusin' || e.type === 'focusout') && e.target === this.dragTarget?.element) {
310
+ return;
311
+ }
312
+
294
313
  // Allow default for events that might cancel a click event
295
314
  if (!CLICK_EVENTS.includes(e.type)) {
296
315
  e.preventDefault();
@@ -429,6 +448,13 @@ class DragSession {
429
448
 
430
449
  item?.element.focus();
431
450
  this.currentDropItem = item;
451
+
452
+ // Annouce first drop target after drag start announcement finishes.
453
+ // Otherwise, it will never get announced because drag start announcement is assertive.
454
+ if (!this.initialFocused) {
455
+ announce(item?.element.getAttribute('aria-label'), 'polite');
456
+ this.initialFocused = true;
457
+ }
432
458
  }
433
459
  }
434
460
 
@@ -446,6 +472,12 @@ class DragSession {
446
472
  });
447
473
  }
448
474
 
475
+ // Blur and re-focus the drop target so that the focus ring appears.
476
+ if (this.currentDropTarget) {
477
+ this.currentDropTarget.element.blur();
478
+ this.currentDropTarget.element.focus();
479
+ }
480
+
449
481
  this.setCurrentDropTarget(null);
450
482
  endDragging();
451
483
  }
@@ -456,7 +488,7 @@ class DragSession {
456
488
  this.dragTarget.element.focus();
457
489
  }
458
490
 
459
- announce(this.formatMessage('dropCanceled'));
491
+ announce(this.stringFormatter.format('dropCanceled'));
460
492
  }
461
493
 
462
494
  drop(item?: DroppableItem) {
@@ -494,7 +526,7 @@ class DragSession {
494
526
  }
495
527
 
496
528
  this.end();
497
- announce(this.formatMessage('dropComplete'));
529
+ announce(this.stringFormatter.format('dropComplete'));
498
530
  }
499
531
 
500
532
  activate() {
@@ -523,3 +555,19 @@ function findValidDropTargets(options: DragTarget) {
523
555
  return true;
524
556
  });
525
557
  }
558
+
559
+ function isVirtualPointerEvent(event: PointerEvent) {
560
+ // If the pointer size is zero, then we assume it's from a screen reader.
561
+ // Android TalkBack double tap will sometimes return a event with width and height of 1
562
+ // and pointerType === 'mouse' so we need to check for a specific combination of event attributes.
563
+ // Cannot use "event.pressure === 0" as the sole check due to Safari pointer events always returning pressure === 0
564
+ // instead of .5, see https://bugs.webkit.org/show_bug.cgi?id=206216
565
+ return (
566
+ (event.width === 0 && event.height === 0) ||
567
+ (event.width === 1 &&
568
+ event.height === 1 &&
569
+ event.pressure === 0 &&
570
+ event.detail === 0
571
+ )
572
+ );
573
+ }
@@ -0,0 +1,54 @@
1
+ /*
2
+ * Copyright 2020 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import {DragItem, DragPreviewRenderer} from '@react-types/shared';
14
+ import {flushSync} from 'react-dom';
15
+ import React, {RefObject, useImperativeHandle, useRef, useState} from 'react';
16
+
17
+ export interface DragPreviewProps {
18
+ children: (items: DragItem[]) => JSX.Element
19
+ }
20
+
21
+ function DragPreview(props: DragPreviewProps, ref: RefObject<DragPreviewRenderer>) {
22
+ let render = props.children;
23
+ let [children, setChildren] = useState<JSX.Element>(null);
24
+ let domRef = useRef(null);
25
+
26
+ useImperativeHandle(ref, () => (items: DragItem[], callback: (node: HTMLElement) => void) => {
27
+ // This will be called during the onDragStart event by useDrag. We need to render the
28
+ // preview synchronously before this event returns so we can call event.dataTransfer.setDragImage.
29
+ flushSync(() => {
30
+ setChildren(render(items));
31
+ });
32
+
33
+ // Yield back to useDrag to set the drag image.
34
+ callback(domRef.current);
35
+
36
+ // Remove the preview from the DOM after a frame so the browser has time to paint.
37
+ requestAnimationFrame(() => {
38
+ setChildren(null);
39
+ });
40
+ }, [render]);
41
+
42
+ if (!children) {
43
+ return null;
44
+ }
45
+
46
+ return (
47
+ <div style={{zIndex: -100, position: 'absolute', top: 0, left: -100000}} ref={domRef}>
48
+ {children}
49
+ </div>
50
+ );
51
+ }
52
+
53
+ let _DragPreview = React.forwardRef(DragPreview);
54
+ export {_DragPreview as DragPreview};
package/src/constants.ts CHANGED
@@ -10,6 +10,8 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
+ import {DropOperation} from '@react-types/shared';
14
+
13
15
  export enum DROP_OPERATION {
14
16
  none = 0,
15
17
  cancel = 0,
@@ -31,7 +33,7 @@ export const DROP_OPERATION_ALLOWED = {
31
33
 
32
34
  export const EFFECT_ALLOWED = invert(DROP_OPERATION_ALLOWED);
33
35
  export const DROP_EFFECT = invert(DROP_OPERATION);
34
- export const DROP_EFFECT_TO_DROP_OPERATION = {
36
+ export const DROP_EFFECT_TO_DROP_OPERATION: {[name: string]: DropOperation} = {
35
37
  none: 'cancel',
36
38
  link: 'link',
37
39
  copy: 'copy',
package/src/index.ts CHANGED
@@ -10,10 +10,20 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- export * from './useDrag';
14
- export * from './useDrop';
15
- export * from './useDroppableCollection';
16
- export * from './useDroppableItem';
17
- export * from './useDropIndicator';
18
- export * from './useDraggableItem';
19
- export * from './useClipboard';
13
+ export type {DroppableCollectionOptions, DroppableCollectionResult} from './useDroppableCollection';
14
+ export type {DroppableItemOptions, DroppableItemResult} from './useDroppableItem';
15
+ export type {DropIndicatorProps, DropIndicatorAria} from './useDropIndicator';
16
+ export type {DraggableItemProps, DraggableItemResult} from './useDraggableItem';
17
+ export type {DragPreviewProps} from './DragPreview';
18
+ export type {DragOptions, DragResult} from './useDrag';
19
+ export type {DropOptions, DropResult} from './useDrop';
20
+ export type {ClipboardProps, ClipboardResult} from './useClipboard';
21
+
22
+ export {useDrag} from './useDrag';
23
+ export {useDrop} from './useDrop';
24
+ export {useDroppableCollection} from './useDroppableCollection';
25
+ export {useDroppableItem} from './useDroppableItem';
26
+ export {useDropIndicator} from './useDropIndicator';
27
+ export {useDraggableItem} from './useDraggableItem';
28
+ export {useClipboard} from './useClipboard';
29
+ export {DragPreview} from './DragPreview';
@@ -11,20 +11,20 @@
11
11
  */
12
12
 
13
13
  import {chain} from '@react-aria/utils';
14
- import {DragItem, DropItem} from '@react-types/shared';
15
- import {HTMLAttributes, useEffect, useRef} from 'react';
14
+ import {DOMAttributes, DragItem, DropItem} from '@react-types/shared';
16
15
  import {readFromDataTransfer, writeToDataTransfer} from './utils';
16
+ import {useEffect, useRef} from 'react';
17
17
  import {useFocus} from '@react-aria/interactions';
18
18
 
19
- interface ClipboardProps {
19
+ export interface ClipboardProps {
20
20
  getItems?: () => DragItem[],
21
21
  onCopy?: () => void,
22
22
  onCut?: () => void,
23
23
  onPaste?: (items: DropItem[]) => void
24
24
  }
25
25
 
26
- interface ClipboardResult {
27
- clipboardProps: HTMLAttributes<HTMLElement>
26
+ export interface ClipboardResult {
27
+ clipboardProps: DOMAttributes
28
28
  }
29
29
 
30
30
  const globalEvents = new Map();