From f3ba77571953ba9103dd1dc33cceb14be3685a13 Mon Sep 17 00:00:00 2001 From: Matt Driscoll Date: Thu, 8 May 2025 13:47:28 -0700 Subject: [PATCH 1/2] feat: support shadow dom elements. #15 --- packages/core/src/adapter/element-adapter.ts | 21 +++++++++++-------- packages/core/src/internal-types.ts | 1 + packages/core/src/ledger/lifecycle-manager.ts | 14 +++++++------ .../core/src/make-adapter/make-drop-target.ts | 14 ++++++++++--- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/packages/core/src/adapter/element-adapter.ts b/packages/core/src/adapter/element-adapter.ts index e0d0e04a..f0d00d6e 100644 --- a/packages/core/src/adapter/element-adapter.ts +++ b/packages/core/src/adapter/element-adapter.ts @@ -1,6 +1,5 @@ import { bind } from 'bind-event-listener'; -import { getElementFromPointWithoutHoneypot } from '../honey-pot-fix/get-element-from-point-without-honey-pot'; import { makeHoneyPotFix } from '../honey-pot-fix/make-honey-pot-fix'; import { type AdapterAPI, @@ -131,13 +130,16 @@ const adapter = makeAdapter({ // the closest parent that is a draggable element will be marked as // the `event.target` for the event - const target: EventTarget | null = event.target; + const targets = event.composedPath(); + const target = targets.find( + (t) => t instanceof HTMLElement && draggableRegistry.has(t) + ) as HTMLElement; // this source is only for elements // Note: only HTMLElements can have the "draggable" attribute - if (!(target instanceof HTMLElement)) { - return null; - } + if (!target) { + return null; + } // see if the thing being dragged is owned by us const entry: DraggableArgs | undefined = draggableRegistry.get(target); @@ -201,10 +203,11 @@ const adapter = makeAdapter({ // technically don't need this util, but just being // consistent with how we look up what is under the users // cursor. - const over = getElementFromPointWithoutHoneypot({ - x: input.clientX, - y: input.clientY, - }); + const dragHandleSource = target.getRootNode() as Document | ShadowRoot; + const over = dragHandleSource.elementFromPoint( + input.clientX, + input.clientY + ); // if we are not dragging from the drag handle (or something inside the drag handle) // then we will cancel the active drag diff --git a/packages/core/src/internal-types.ts b/packages/core/src/internal-types.ts index 786c963d..5c89153b 100644 --- a/packages/core/src/internal-types.ts +++ b/packages/core/src/internal-types.ts @@ -386,6 +386,7 @@ export type DropTargetAPI = { getIsOver: (args: { source: DragType['payload']; target: EventTarget | null; + event: Event; input: Input; current: DropTargetRecord[]; }) => DropTargetRecord[]; diff --git a/packages/core/src/ledger/lifecycle-manager.ts b/packages/core/src/ledger/lifecycle-manager.ts index 0764a80f..3bdff857 100644 --- a/packages/core/src/ledger/lifecycle-manager.ts +++ b/packages/core/src/ledger/lifecycle-manager.ts @@ -124,11 +124,12 @@ function start({ : event.target; const nextDropTargets = getDropTargetsOver({ - target, - input, - source: dragType.payload, - current: state.current.dropTargets, - }); + target, + event, + input, + source: dragType.payload, + current: state.current.dropTargets, + }); if (nextDropTargets.length) { // 🩸 must call `event.preventDefault()` to allow a browser drop to occur @@ -308,7 +309,7 @@ function start({ // as we will have already removed the event listener type: 'dragend', - listener(event) { + listener(event: DragEvent) { // In firefox, the position of the "dragend" event can // be a bit different to the last "dragover" event. // Updating the input so we can get the best possible @@ -374,6 +375,7 @@ function getStartLocation({ input, source: dragType.payload, target: event.target, + event, current: [], }); return { diff --git a/packages/core/src/make-adapter/make-drop-target.ts b/packages/core/src/make-adapter/make-drop-target.ts index 11648ba9..ea4be805 100644 --- a/packages/core/src/make-adapter/make-drop-target.ts +++ b/packages/core/src/make-adapter/make-drop-target.ts @@ -72,16 +72,18 @@ export function makeDropTarget({ source, target, input, + event, result = [], }: { source: DragType['payload']; target: EventTarget | null; input: Input; + event: Event | undefined; result?: DropTargetRecord[]; }): DropTargetRecord[] { - if (target == null) { - return result; - } + if (event === undefined) { + return result; + } if (!(target instanceof Element)) { // For "text-selection" drags, the original `target` @@ -90,6 +92,7 @@ export function makeDropTarget({ if (target instanceof Node) { return getActualDropTargets({ source, + event, target: target.parentElement, input, result, @@ -129,6 +132,7 @@ export function makeDropTarget({ source, target: args.element.parentElement, input, + event, result, }); } @@ -150,6 +154,7 @@ export function makeDropTarget({ source, target: args.element.parentElement, input, + event, // Using bubble ordering. Same ordering as `event.getPath()` result: [...result, record], }); @@ -235,16 +240,19 @@ export function makeDropTarget({ source, target, input, + event, current, }: { source: DragType['payload']; target: EventTarget | null; input: Input; + event: Event | undefined; current: DropTargetRecord[]; }): DropTargetRecord[] { const actual: DropTargetRecord[] = getActualDropTargets({ source, target, + event, input, }); From 87bfe6f053504455efbe536cea5b3a65f11444bd Mon Sep 17 00:00:00 2001 From: Matt Driscoll Date: Thu, 8 May 2025 16:04:53 -0700 Subject: [PATCH 2/2] cleanup --- packages/core/src/adapter/element-adapter.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/core/src/adapter/element-adapter.ts b/packages/core/src/adapter/element-adapter.ts index f0d00d6e..3e1a3b37 100644 --- a/packages/core/src/adapter/element-adapter.ts +++ b/packages/core/src/adapter/element-adapter.ts @@ -130,10 +130,11 @@ const adapter = makeAdapter({ // the closest parent that is a draggable element will be marked as // the `event.target` for the event - const targets = event.composedPath(); - const target = targets.find( - (t) => t instanceof HTMLElement && draggableRegistry.has(t) - ) as HTMLElement; + const target = event + .composedPath() + .find( + (t): t is HTMLElement => t instanceof HTMLElement && draggableRegistry.has(t) + ); // this source is only for elements // Note: only HTMLElements can have the "draggable" attribute