MCPcopy Create free account
hub / github.com/adobe/react-spectrum / dragAndDrop

Function dragAndDrop

packages/@react-spectrum/s2/test/utils/dragAndDrop.ts:93–151  ·  view source on GitHub ↗
(
  source: Element,
  target: Element,
  options?: DragAndDropOptions
)

Source from the content-addressed store, hash-verified

91 * dispatching the full DragEvent lifecycle with synthetic events instead.
92 */
93export async function dragAndDrop(
94 source: Element,
95 target: Element,
96 options?: DragAndDropOptions
97): Promise<void> {
98 if (server.browser !== 'chromium') {
99 await userEvent.dragAndDrop(source, target, options);
100 return;
101 }
102
103 let {dataTransfer, proxy} = createWritableDataTransfer();
104
105 let sourcePos = resolveClientPosition(source, options?.sourcePosition);
106 let targetPos = resolveClientPosition(target, options?.targetPosition);
107
108 // Patch DragEvent.prototype.dataTransfer to return our proxy whenever the
109 // event carries our real dataTransfer. This is the only reliable way to make
110 // effectAllowed/dropEffect writable in Chromium for synthetic events.
111 let origDesc = Object.getOwnPropertyDescriptor(DragEvent.prototype, 'dataTransfer')!;
112 Object.defineProperty(DragEvent.prototype, 'dataTransfer', {
113 get() {
114 let real = origDesc.get!.call(this);
115 return real === dataTransfer ? proxy : real;
116 },
117 configurable: true
118 });
119
120 try {
121 // Dispatch dragstart so useDrag populates the DataTransfer with items and sets effectAllowed.
122 source.dispatchEvent(
123 new DragEvent('dragstart', {dataTransfer, bubbles: true, cancelable: true, ...sourcePos})
124 );
125
126 // Allow React state updates from the dragstart handler to flush.
127 await new Promise(resolve => requestAnimationFrame(resolve));
128
129 target.dispatchEvent(
130 new DragEvent('dragenter', {dataTransfer, bubbles: true, cancelable: true, ...targetPos})
131 );
132 target.dispatchEvent(
133 new DragEvent('dragover', {dataTransfer, bubbles: true, cancelable: true, ...targetPos})
134 );
135
136 // In a real browser drag, the drop event only fires when dropEffect is not 'none'.
137 // useDrop sets dropEffect during dragenter/dragover based on getDropOperation.
138 if (proxy.dropEffect !== 'none') {
139 target.dispatchEvent(
140 new DragEvent('drop', {dataTransfer, bubbles: true, cancelable: true, ...targetPos})
141 );
142 }
143
144 source.dispatchEvent(
145 new DragEvent('dragend', {dataTransfer, bubbles: true, cancelable: true, ...targetPos})
146 );
147 } finally {
148 // Restore the original dataTransfer getter.
149 Object.defineProperty(DragEvent.prototype, 'dataTransfer', origDesc);
150 }

Callers 1

Calls 2

resolveClientPositionFunction · 0.85

Tested by

no test coverage detected