@bsol-oss/react-datatable5 7.6.2 → 7.7.0

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 (3) hide show
  1. package/dist/index.js +2209 -14
  2. package/dist/index.mjs +2201 -6
  3. package/package.json +4 -5
package/dist/index.mjs CHANGED
@@ -10,7 +10,11 @@ import { FaUpDown, FaGripLinesVertical } from 'react-icons/fa6';
10
10
  import { BiDownArrow, BiUpArrow } from 'react-icons/bi';
11
11
  import { CgClose } from 'react-icons/cg';
12
12
  import { IoMdEye, IoMdCheckbox } from 'react-icons/io';
13
- import { monitorForElements, draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
13
+ import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
14
+ import { bind, bindAll } from 'bind-event-listener';
15
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
16
+ import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
17
+ import rafSchd from 'raf-schd';
14
18
  import invariant from 'tiny-invariant';
15
19
  import { HiMiniEllipsisHorizontal, HiChevronLeft, HiChevronRight } from 'react-icons/hi2';
16
20
  import { flexRender, makeStateUpdater, functionalUpdate, useReactTable, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getPaginationRowModel, createColumnHelper } from '@tanstack/react-table';
@@ -24,9 +28,6 @@ import axios from 'axios';
24
28
  import { useDebounce } from '@uidotdev/usehooks';
25
29
  import { useFormContext, useForm, FormProvider } from 'react-hook-form';
26
30
  import dayjs from 'dayjs';
27
- import { dropTargetForExternal } from '@atlaskit/pragmatic-drag-and-drop/external/adapter';
28
- import { getFiles } from '@atlaskit/pragmatic-drag-and-drop/external/file';
29
- import { getText } from '@atlaskit/pragmatic-drag-and-drop/external/text';
30
31
 
31
32
  const DataTableContext = createContext({
32
33
  table: {},
@@ -438,6 +439,1896 @@ const EditSortingButton = ({ text, icon = jsx(MdOutlineSort, {}), title = "Edit
438
439
  return (jsx(Fragment, { children: jsxs(DialogRoot, { size: ["full", "full", "md", "md"], children: [jsx(DialogBackdrop, {}), jsx(DialogTrigger, { children: jsxs(Button$1, { as: "div", variant: "ghost", onClick: sortingModal.onOpen, children: [icon, " ", text] }) }), jsxs(DialogContent, { children: [jsx(DialogCloseTrigger, {}), jsxs(DialogHeader, { children: [jsx(DialogTitle, {}), title] }), jsx(DialogBody, { children: jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(TableSorter, {}), jsx(ResetSortingButton, {})] }) }), jsx(DialogFooter, {})] })] }) }));
439
440
  };
440
441
 
442
+ // pulling this into a separate file so adapter(s) that don't
443
+ // need the honey pot can pay as little as possible for it.
444
+ var honeyPotDataAttribute = 'data-pdnd-honey-pot';
445
+
446
+ function isHoneyPotElement(target) {
447
+ return target instanceof Element && target.hasAttribute(honeyPotDataAttribute);
448
+ }
449
+
450
+ function getElementFromPointWithoutHoneypot(client) {
451
+ // eslint-disable-next-line no-restricted-syntax
452
+ var _document$elementsFro = document.elementsFromPoint(client.x, client.y),
453
+ _document$elementsFro2 = _slicedToArray(_document$elementsFro, 2),
454
+ top = _document$elementsFro2[0],
455
+ second = _document$elementsFro2[1];
456
+ if (!top) {
457
+ return null;
458
+ }
459
+ if (isHoneyPotElement(top)) {
460
+ return second !== null && second !== void 0 ? second : null;
461
+ }
462
+ return top;
463
+ }
464
+
465
+ // Maximum possible z-index
466
+ // https://stackoverflow.com/questions/491052/minimum-and-maximum-value-of-z-index
467
+ var maxZIndex = 2147483647;
468
+
469
+ function ownKeys$2(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
470
+ function _objectSpread$2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$2(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$2(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
471
+ var honeyPotSize = 2;
472
+ var halfHoneyPotSize = honeyPotSize / 2;
473
+
474
+ /**
475
+ * `clientX` and `clientY` can be in sub pixels (eg `2.332`)
476
+ * However, browser hitbox testing is commonly do to the closest pixel.
477
+ *
478
+ * → https://issues.chromium.org/issues/40940531
479
+ *
480
+ * To be sure that the honey pot will be over the `client` position,
481
+ * we `.floor()` `clientX` and`clientY` and then make it `2px` in size.
482
+ **/
483
+ function floorToClosestPixel(point) {
484
+ return {
485
+ x: Math.floor(point.x),
486
+ y: Math.floor(point.y)
487
+ };
488
+ }
489
+
490
+ /**
491
+ * We want to make sure the honey pot sits around the users position.
492
+ * This seemed to be the most resilient while testing.
493
+ */
494
+ function pullBackByHalfHoneyPotSize(point) {
495
+ return {
496
+ x: point.x - halfHoneyPotSize,
497
+ y: point.y - halfHoneyPotSize
498
+ };
499
+ }
500
+
501
+ /**
502
+ * Prevent the honey pot from changing the window size.
503
+ * This is super unlikely to occur, but just being safe.
504
+ */
505
+ function preventGoingBackwardsOffScreen(point) {
506
+ return {
507
+ x: Math.max(point.x, 0),
508
+ y: Math.max(point.y, 0)
509
+ };
510
+ }
511
+
512
+ /**
513
+ * Prevent the honey pot from changing the window size.
514
+ * This is super unlikely to occur, but just being safe.
515
+ */
516
+ function preventGoingForwardsOffScreen(point) {
517
+ return {
518
+ x: Math.min(point.x, window.innerWidth - honeyPotSize),
519
+ y: Math.min(point.y, window.innerHeight - honeyPotSize)
520
+ };
521
+ }
522
+
523
+ /**
524
+ * Create a `2x2` `DOMRect` around the `client` position
525
+ */
526
+ function getHoneyPotRectFor(_ref) {
527
+ var client = _ref.client;
528
+ var point = preventGoingForwardsOffScreen(preventGoingBackwardsOffScreen(pullBackByHalfHoneyPotSize(floorToClosestPixel(client))));
529
+
530
+ // When debugging, it is helpful to
531
+ // make this element a bit bigger
532
+ return DOMRect.fromRect({
533
+ x: point.x,
534
+ y: point.y,
535
+ width: honeyPotSize,
536
+ height: honeyPotSize
537
+ });
538
+ }
539
+ function getRectStyles(_ref2) {
540
+ var clientRect = _ref2.clientRect;
541
+ return {
542
+ left: "".concat(clientRect.left, "px"),
543
+ top: "".concat(clientRect.top, "px"),
544
+ width: "".concat(clientRect.width, "px"),
545
+ height: "".concat(clientRect.height, "px")
546
+ };
547
+ }
548
+ function isWithin(_ref3) {
549
+ var client = _ref3.client,
550
+ clientRect = _ref3.clientRect;
551
+ return (
552
+ // is within horizontal bounds
553
+ client.x >= clientRect.x && client.x <= clientRect.x + clientRect.width &&
554
+ // is within vertical bounds
555
+ client.y >= clientRect.y && client.y <= clientRect.y + clientRect.height
556
+ );
557
+ }
558
+ /**
559
+ * The honey pot fix is designed to get around a painful bug in all browsers.
560
+ *
561
+ * [Overview](https://www.youtube.com/watch?v=udE9qbFTeQg)
562
+ *
563
+ * **Background**
564
+ *
565
+ * When a drag starts, browsers incorrectly think that the users pointer is
566
+ * still depressed where the drag started. Any element that goes under this position
567
+ * will be entered into, causing `"mouseenter"` events and `":hover"` styles to be applied.
568
+ *
569
+ * _This is a violation of the spec_
570
+ *
571
+ * > "From the moment that the user agent is to initiate the drag-and-drop operation,
572
+ * > until the end of the drag-and-drop operation, device input events
573
+ * > (e.g. mouse and keyboard events) must be suppressed."
574
+ * >
575
+ * > - https://html.spec.whatwg.org/multipage/dnd.html#drag-and-drop-processing-model
576
+ *
577
+ * _Some impacts_
578
+ *
579
+ * - `":hover"` styles being applied where they shouldn't (looks messy)
580
+ * - components such as tooltips responding to `"mouseenter"` can show during a drag,
581
+ * and on an element the user isn't even over
582
+ *
583
+ * Bug: https://issues.chromium.org/issues/41129937
584
+ *
585
+ * **Honey pot fix**
586
+ *
587
+ * 1. Create an element where the browser thinks the depressed pointer is
588
+ * to absorb the incorrect pointer events
589
+ * 2. Remove that element when it is no longer needed
590
+ */
591
+ function mountHoneyPot(_ref4) {
592
+ var initial = _ref4.initial;
593
+ var element = document.createElement('div');
594
+ element.setAttribute(honeyPotDataAttribute, 'true');
595
+
596
+ // can shift during the drag thanks to Firefox
597
+ var clientRect = getHoneyPotRectFor({
598
+ client: initial
599
+ });
600
+ Object.assign(element.style, _objectSpread$2(_objectSpread$2({
601
+ // Setting a background color explicitly to avoid any inherited styles.
602
+ // Looks like this could be `opacity: 0`, but worried that _might_
603
+ // cause the element to be ignored on some platforms.
604
+ // When debugging, set backgroundColor to something like "red".
605
+ backgroundColor: 'transparent',
606
+ position: 'fixed',
607
+ // Being explicit to avoid inheriting styles
608
+ padding: 0,
609
+ margin: 0,
610
+ boxSizing: 'border-box'
611
+ }, getRectStyles({
612
+ clientRect: clientRect
613
+ })), {}, {
614
+ // We want this element to absorb pointer events,
615
+ // it's kind of the whole point 😉
616
+ pointerEvents: 'auto',
617
+ // Want to make sure the honey pot is top of everything else.
618
+ // Don't need to worry about native drag previews, as they will
619
+ // have been rendered (and removed) before the honey pot is rendered
620
+ zIndex: maxZIndex
621
+ }));
622
+ document.body.appendChild(element);
623
+
624
+ /**
625
+ * 🦊 In firefox we can get `"pointermove"` events after the drag
626
+ * has started, which is a spec violation.
627
+ * The final `"pointermove"` will reveal where the "depressed" position
628
+ * is for our honey pot fix.
629
+ */
630
+ var unbindPointerMove = bind(window, {
631
+ type: 'pointermove',
632
+ listener: function listener(event) {
633
+ var client = {
634
+ x: event.clientX,
635
+ y: event.clientY
636
+ };
637
+ clientRect = getHoneyPotRectFor({
638
+ client: client
639
+ });
640
+ Object.assign(element.style, getRectStyles({
641
+ clientRect: clientRect
642
+ }));
643
+ },
644
+ // using capture so we are less likely to be impacted by event stopping
645
+ options: {
646
+ capture: true
647
+ }
648
+ });
649
+ return function finish(_ref5) {
650
+ var current = _ref5.current;
651
+ // Don't need this any more
652
+ unbindPointerMove();
653
+
654
+ // If the user is hover the honey pot, we remove it
655
+ // so that the user can continue to interact with the page normally.
656
+ if (isWithin({
657
+ client: current,
658
+ clientRect: clientRect
659
+ })) {
660
+ element.remove();
661
+ return;
662
+ }
663
+ function cleanup() {
664
+ unbindPostDragEvents();
665
+ element.remove();
666
+ }
667
+ var unbindPostDragEvents = bindAll(window, [{
668
+ type: 'pointerdown',
669
+ listener: cleanup
670
+ }, {
671
+ type: 'pointermove',
672
+ listener: cleanup
673
+ }, {
674
+ type: 'focusin',
675
+ listener: cleanup
676
+ }, {
677
+ type: 'focusout',
678
+ listener: cleanup
679
+ },
680
+ // a 'pointerdown' should happen before 'dragstart', but just being super safe
681
+ {
682
+ type: 'dragstart',
683
+ listener: cleanup
684
+ },
685
+ // if the user has dragged something out of the window
686
+ // and then is dragging something back into the window
687
+ // the first events we will see are "dragenter" (and then "dragover").
688
+ // So if we see any of these we need to clear the post drag fix.
689
+ {
690
+ type: 'dragenter',
691
+ listener: cleanup
692
+ }, {
693
+ type: 'dragover',
694
+ listener: cleanup
695
+ }
696
+
697
+ // Not adding a "wheel" event listener, as "wheel" by itself does not
698
+ // resolve the bug.
699
+ ], {
700
+ // Using `capture` so less likely to be impacted by other code stopping events
701
+ capture: true
702
+ });
703
+ };
704
+ }
705
+ function makeHoneyPotFix() {
706
+ var latestPointerMove = null;
707
+ function bindEvents() {
708
+ // For sanity, only collecting this value from when events are first bound.
709
+ // This prevents the case where a super old "pointermove" could be used
710
+ // from a prior interaction.
711
+ latestPointerMove = null;
712
+ return bind(window, {
713
+ type: 'pointermove',
714
+ listener: function listener(event) {
715
+ latestPointerMove = {
716
+ x: event.clientX,
717
+ y: event.clientY
718
+ };
719
+ },
720
+ // listening for pointer move in capture phase
721
+ // so we are less likely to be impacted by events being stopped.
722
+ options: {
723
+ capture: true
724
+ }
725
+ });
726
+ }
727
+ function getOnPostDispatch() {
728
+ var finish = null;
729
+ return function onPostEvent(_ref6) {
730
+ var eventName = _ref6.eventName,
731
+ payload = _ref6.payload;
732
+ // We are adding the honey pot `onDragStart` so we don't
733
+ // impact the creation of the native drag preview.
734
+ if (eventName === 'onDragStart') {
735
+ var _latestPointerMove;
736
+ var input = payload.location.initial.input;
737
+
738
+ // Sometimes there will be no latest "pointermove" (eg iOS).
739
+ // In which case, we use the start position of the drag.
740
+ var initial = (_latestPointerMove = latestPointerMove) !== null && _latestPointerMove !== void 0 ? _latestPointerMove : {
741
+ x: input.clientX,
742
+ y: input.clientY
743
+ };
744
+
745
+ // Don't need to defensively call `finish()` as `onDrop` from
746
+ // one interaction is guaranteed to be called before `onDragStart`
747
+ // of the next.
748
+ finish = mountHoneyPot({
749
+ initial: initial
750
+ });
751
+ }
752
+ if (eventName === 'onDrop') {
753
+ var _finish;
754
+ var _input = payload.location.current.input;
755
+ (_finish = finish) === null || _finish === void 0 || _finish({
756
+ current: {
757
+ x: _input.clientX,
758
+ y: _input.clientY
759
+ }
760
+ });
761
+ finish = null;
762
+ // this interaction is finished, we want to use
763
+ // the latest "pointermove" for each interaction
764
+ latestPointerMove = null;
765
+ }
766
+ };
767
+ }
768
+ return {
769
+ bindEvents: bindEvents,
770
+ getOnPostDispatch: getOnPostDispatch
771
+ };
772
+ }
773
+
774
+ /** Provide a function that you only ever want to be called a single time */
775
+ function once(fn) {
776
+ var cache = null;
777
+ return function wrapped() {
778
+ if (!cache) {
779
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
780
+ args[_key] = arguments[_key];
781
+ }
782
+ var result = fn.apply(this, args);
783
+ cache = {
784
+ result: result
785
+ };
786
+ }
787
+ return cache.result;
788
+ };
789
+ }
790
+
791
+ // using `cache` as our `isFirefox()` result will not change in a browser
792
+
793
+ /**
794
+ * Returns `true` if a `Firefox` browser
795
+ * */
796
+ var isFirefox = once(function isFirefox() {
797
+ if (process.env.NODE_ENV === 'test') {
798
+ return false;
799
+ }
800
+ return navigator.userAgent.includes('Firefox');
801
+ });
802
+
803
+ // using `cache` as our `isSafari()` result will not change in a browser
804
+
805
+ /**
806
+ * Returns `true` if a `Safari` browser.
807
+ * Returns `true` if the browser is running on iOS (they are all Safari).
808
+ * */
809
+ var isSafari = once(function isSafari() {
810
+ if (process.env.NODE_ENV === 'test') {
811
+ return false;
812
+ }
813
+ var _navigator = navigator,
814
+ userAgent = _navigator.userAgent;
815
+ return userAgent.includes('AppleWebKit') && !userAgent.includes('Chrome');
816
+ });
817
+
818
+ /* For "dragenter" events, the browser should set `relatedTarget` to the previous element.
819
+ * For external drag operations, our first "dragenter" event should have a `event.relatedTarget` of `null`.
820
+ *
821
+ * Unfortunately in Safari `event.relatedTarget` is *always* set to `null`
822
+ * Safari bug: https://bugs.webkit.org/show_bug.cgi?id=242627
823
+ * To work around this we count "dragenter" and "dragleave" events */
824
+
825
+ // Using symbols for event properties so we don't clash with
826
+ // anything on the `event` object
827
+ var symbols = {
828
+ isLeavingWindow: Symbol('leaving'),
829
+ isEnteringWindow: Symbol('entering')
830
+ };
831
+ function isEnteringWindowInSafari(_ref) {
832
+ var dragEnter = _ref.dragEnter;
833
+ if (!isSafari()) {
834
+ return false;
835
+ }
836
+ return dragEnter.hasOwnProperty(symbols.isEnteringWindow);
837
+ }
838
+ function isLeavingWindowInSafari(_ref2) {
839
+ var dragLeave = _ref2.dragLeave;
840
+ if (!isSafari()) {
841
+ return false;
842
+ }
843
+ return dragLeave.hasOwnProperty(symbols.isLeavingWindow);
844
+ }
845
+ (function fixSafari() {
846
+ // Don't do anything when server side rendering
847
+ if (typeof window === 'undefined') {
848
+ return;
849
+ }
850
+
851
+ // rather than checking the userAgent for "jsdom" we can do this check
852
+ // so that the check will be removed completely in production code
853
+ if (process.env.NODE_ENV === 'test') {
854
+ return;
855
+ }
856
+ if (!isSafari()) {
857
+ return;
858
+ }
859
+ function getInitialState() {
860
+ return {
861
+ enterCount: 0,
862
+ isOverWindow: false
863
+ };
864
+ }
865
+ var state = getInitialState();
866
+ function resetState() {
867
+ state = getInitialState();
868
+ }
869
+
870
+ // These event listeners are bound _forever_ and _never_ removed
871
+ // We don't bother cleaning up these event listeners (for now)
872
+ // as this workaround is only for Safari
873
+
874
+ // This is how the event count works:
875
+ //
876
+ // lift (+1 enterCount)
877
+ // - dragstart(draggable) [enterCount: 0]
878
+ // - dragenter(draggable) [enterCount: 1]
879
+ // leaving draggable (+0 enterCount)
880
+ // - dragenter(document.body) [enterCount: 2]
881
+ // - dragleave(draggable) [enterCount: 1]
882
+ // leaving window (-1 enterCount)
883
+ // - dragleave(document.body) [enterCount: 0] {leaving the window}
884
+
885
+ // Things to note:
886
+ // - dragenter and dragleave bubble
887
+ // - the first dragenter when entering a window might not be on `window`
888
+ // - it could be on an element that is pressed up against the window
889
+ // - (so we cannot rely on `event.target` values)
890
+
891
+ bindAll(window, [{
892
+ type: 'dragstart',
893
+ listener: function listener() {
894
+ state.enterCount = 0;
895
+ // drag start occurs in the source window
896
+ state.isOverWindow = true;
897
+ // When a drag first starts it will also trigger a "dragenter" on the draggable element
898
+ }
899
+ }, {
900
+ type: 'drop',
901
+ listener: resetState
902
+ }, {
903
+ type: 'dragend',
904
+ listener: resetState
905
+ }, {
906
+ type: 'dragenter',
907
+ listener: function listener(event) {
908
+ if (!state.isOverWindow && state.enterCount === 0) {
909
+ // Patching the `event` object
910
+ // The `event` object is shared with all event listeners for the event
911
+ // @ts-expect-error: adding property to the event object
912
+ event[symbols.isEnteringWindow] = true;
913
+ }
914
+ state.isOverWindow = true;
915
+ state.enterCount++;
916
+ }
917
+ }, {
918
+ type: 'dragleave',
919
+ listener: function listener(event) {
920
+ state.enterCount--;
921
+ if (state.isOverWindow && state.enterCount === 0) {
922
+ // Patching the `event` object as it is shared with all event listeners
923
+ // The `event` object is shared with all event listeners for the event
924
+ // @ts-expect-error: adding property to the event object
925
+ event[symbols.isLeavingWindow] = true;
926
+ state.isOverWindow = false;
927
+ }
928
+ }
929
+ }],
930
+ // using `capture: true` so that adding event listeners
931
+ // in bubble phase will have the correct symbols
932
+ {
933
+ capture: true
934
+ });
935
+ })();
936
+
937
+ /**
938
+ * Does the `EventTarget` look like a `Node` based on "duck typing".
939
+ *
940
+ * Helpful when the `Node` might be outside of the current document
941
+ * so we cannot to an `target instanceof Node` check.
942
+ */
943
+ function isNodeLike(target) {
944
+ return 'nodeName' in target;
945
+ }
946
+
947
+ /**
948
+ * Is an `EventTarget` a `Node` from another `window`?
949
+ */
950
+ function isFromAnotherWindow(eventTarget) {
951
+ return isNodeLike(eventTarget) && eventTarget.ownerDocument !== document;
952
+ }
953
+
954
+ function isLeavingWindow(_ref) {
955
+ var dragLeave = _ref.dragLeave;
956
+ var type = dragLeave.type,
957
+ relatedTarget = dragLeave.relatedTarget;
958
+ if (type !== 'dragleave') {
959
+ return false;
960
+ }
961
+ if (isSafari()) {
962
+ return isLeavingWindowInSafari({
963
+ dragLeave: dragLeave
964
+ });
965
+ }
966
+
967
+ // Standard check: if going to `null` we are leaving the `window`
968
+ if (relatedTarget == null) {
969
+ return true;
970
+ }
971
+
972
+ /**
973
+ * 🦊 Exception: `iframe` in Firefox (`125.0`)
974
+ *
975
+ * Case 1: parent `window` → child `iframe`
976
+ * `dragLeave.relatedTarget` is element _inside_ the child `iframe`
977
+ * (foreign element)
978
+ *
979
+ * Case 2: child `iframe` → parent `window`
980
+ * `dragLeave.relatedTarget` is the `iframe` in the parent `window`
981
+ * (foreign element)
982
+ */
983
+
984
+ if (isFirefox()) {
985
+ return isFromAnotherWindow(relatedTarget);
986
+ }
987
+
988
+ /**
989
+ * 🌏 Exception: `iframe` in Chrome (`124.0`)
990
+ *
991
+ * Case 1: parent `window` → child `iframe`
992
+ * `dragLeave.relatedTarget` is the `iframe` in the parent `window`
993
+ *
994
+ * Case 2: child `iframe` → parent `window`
995
+ * `dragLeave.relatedTarget` is `null` *(standard check)*
996
+ */
997
+
998
+ // Case 2
999
+ // Using `instanceof` check as the element will be in the same `window`
1000
+ return relatedTarget instanceof HTMLIFrameElement;
1001
+ }
1002
+
1003
+ function getBindingsForBrokenDrags(_ref) {
1004
+ var onDragEnd = _ref.onDragEnd;
1005
+ return [
1006
+ // ## Detecting drag ending for removed draggables
1007
+ //
1008
+ // If a draggable element is removed during a drag and the user drops:
1009
+ // 1. if over a valid drop target: we get a "drop" event to know the drag is finished
1010
+ // 2. if not over a valid drop target (or cancelled): we get nothing
1011
+ // The "dragend" event will not fire on the source draggable if it has been
1012
+ // removed from the DOM.
1013
+ // So we need to figure out if a drag operation has finished by looking at other events
1014
+ // We can do this by looking at other events
1015
+
1016
+ // ### First detection: "pointermove" events
1017
+
1018
+ // 1. "pointermove" events cannot fire during a drag and drop operation
1019
+ // according to the spec. So if we get a "pointermove" it means that
1020
+ // the drag and drop operations has finished. So if we get a "pointermove"
1021
+ // we know that the drag is over
1022
+ // 2. 🦊😤 Drag and drop operations are _supposed_ to suppress
1023
+ // other pointer events. However, firefox will allow a few
1024
+ // pointer event to get through after a drag starts.
1025
+ // The most I've seen is 3
1026
+ {
1027
+ type: 'pointermove',
1028
+ listener: function () {
1029
+ var callCount = 0;
1030
+ return function listener() {
1031
+ // Using 20 as it is far bigger than the most observed (3)
1032
+ if (callCount < 20) {
1033
+ callCount++;
1034
+ return;
1035
+ }
1036
+ onDragEnd();
1037
+ };
1038
+ }()
1039
+ },
1040
+ // ### Second detection: "pointerdown" events
1041
+
1042
+ // If we receive this event then we know that a drag operation has finished
1043
+ // and potentially another one is about to start.
1044
+ // Note: `pointerdown` fires on all browsers / platforms before "dragstart"
1045
+ {
1046
+ type: 'pointerdown',
1047
+ listener: onDragEnd
1048
+ }];
1049
+ }
1050
+
1051
+ function getInput(event) {
1052
+ return {
1053
+ altKey: event.altKey,
1054
+ button: event.button,
1055
+ buttons: event.buttons,
1056
+ ctrlKey: event.ctrlKey,
1057
+ metaKey: event.metaKey,
1058
+ shiftKey: event.shiftKey,
1059
+ clientX: event.clientX,
1060
+ clientY: event.clientY,
1061
+ pageX: event.pageX,
1062
+ pageY: event.pageY
1063
+ };
1064
+ }
1065
+
1066
+ var scheduleOnDrag = rafSchd(function (fn) {
1067
+ return fn();
1068
+ });
1069
+ var dragStart = function () {
1070
+ var scheduled = null;
1071
+ function schedule(fn) {
1072
+ var frameId = requestAnimationFrame(function () {
1073
+ scheduled = null;
1074
+ fn();
1075
+ });
1076
+ scheduled = {
1077
+ frameId: frameId,
1078
+ fn: fn
1079
+ };
1080
+ }
1081
+ function flush() {
1082
+ if (scheduled) {
1083
+ cancelAnimationFrame(scheduled.frameId);
1084
+ scheduled.fn();
1085
+ scheduled = null;
1086
+ }
1087
+ }
1088
+ return {
1089
+ schedule: schedule,
1090
+ flush: flush
1091
+ };
1092
+ }();
1093
+ function makeDispatch(_ref) {
1094
+ var source = _ref.source,
1095
+ initial = _ref.initial,
1096
+ dispatchEvent = _ref.dispatchEvent;
1097
+ var previous = {
1098
+ dropTargets: []
1099
+ };
1100
+ function safeDispatch(args) {
1101
+ dispatchEvent(args);
1102
+ previous = {
1103
+ dropTargets: args.payload.location.current.dropTargets
1104
+ };
1105
+ }
1106
+ var dispatch = {
1107
+ start: function start(_ref2) {
1108
+ var nativeSetDragImage = _ref2.nativeSetDragImage;
1109
+ // Ensuring that both `onGenerateDragPreview` and `onDragStart` get the same location.
1110
+ // We do this so that `previous` is`[]` in `onDragStart` (which is logical)
1111
+ var location = {
1112
+ current: initial,
1113
+ previous: previous,
1114
+ initial: initial
1115
+ };
1116
+ // a `onGenerateDragPreview` does _not_ add another entry for `previous`
1117
+ // onDragPreview
1118
+ safeDispatch({
1119
+ eventName: 'onGenerateDragPreview',
1120
+ payload: {
1121
+ source: source,
1122
+ location: location,
1123
+ nativeSetDragImage: nativeSetDragImage
1124
+ }
1125
+ });
1126
+ dragStart.schedule(function () {
1127
+ safeDispatch({
1128
+ eventName: 'onDragStart',
1129
+ payload: {
1130
+ source: source,
1131
+ location: location
1132
+ }
1133
+ });
1134
+ });
1135
+ },
1136
+ dragUpdate: function dragUpdate(_ref3) {
1137
+ var current = _ref3.current;
1138
+ dragStart.flush();
1139
+ scheduleOnDrag.cancel();
1140
+ safeDispatch({
1141
+ eventName: 'onDropTargetChange',
1142
+ payload: {
1143
+ source: source,
1144
+ location: {
1145
+ initial: initial,
1146
+ previous: previous,
1147
+ current: current
1148
+ }
1149
+ }
1150
+ });
1151
+ },
1152
+ drag: function drag(_ref4) {
1153
+ var current = _ref4.current;
1154
+ scheduleOnDrag(function () {
1155
+ dragStart.flush();
1156
+ var location = {
1157
+ initial: initial,
1158
+ previous: previous,
1159
+ current: current
1160
+ };
1161
+ safeDispatch({
1162
+ eventName: 'onDrag',
1163
+ payload: {
1164
+ source: source,
1165
+ location: location
1166
+ }
1167
+ });
1168
+ });
1169
+ },
1170
+ drop: function drop(_ref5) {
1171
+ var current = _ref5.current,
1172
+ updatedSourcePayload = _ref5.updatedSourcePayload;
1173
+ dragStart.flush();
1174
+ scheduleOnDrag.cancel();
1175
+ safeDispatch({
1176
+ eventName: 'onDrop',
1177
+ payload: {
1178
+ source: updatedSourcePayload !== null && updatedSourcePayload !== void 0 ? updatedSourcePayload : source,
1179
+ location: {
1180
+ current: current,
1181
+ previous: previous,
1182
+ initial: initial
1183
+ }
1184
+ }
1185
+ });
1186
+ }
1187
+ };
1188
+ return dispatch;
1189
+ }
1190
+
1191
+ var globalState = {
1192
+ isActive: false
1193
+ };
1194
+ function canStart() {
1195
+ return !globalState.isActive;
1196
+ }
1197
+ function getNativeSetDragImage(event) {
1198
+ if (event.dataTransfer) {
1199
+ // need to use `.bind` as `setDragImage` is required
1200
+ // to be run with `event.dataTransfer` as the "this" context
1201
+ return event.dataTransfer.setDragImage.bind(event.dataTransfer);
1202
+ }
1203
+ return null;
1204
+ }
1205
+ function hasHierarchyChanged(_ref) {
1206
+ var current = _ref.current,
1207
+ next = _ref.next;
1208
+ if (current.length !== next.length) {
1209
+ return true;
1210
+ }
1211
+ // not checking stickiness, data or dropEffect,
1212
+ // just whether the hierarchy has changed
1213
+ for (var i = 0; i < current.length; i++) {
1214
+ if (current[i].element !== next[i].element) {
1215
+ return true;
1216
+ }
1217
+ }
1218
+ return false;
1219
+ }
1220
+ function start(_ref2) {
1221
+ var event = _ref2.event,
1222
+ dragType = _ref2.dragType,
1223
+ getDropTargetsOver = _ref2.getDropTargetsOver,
1224
+ dispatchEvent = _ref2.dispatchEvent;
1225
+ if (!canStart()) {
1226
+ return;
1227
+ }
1228
+ var initial = getStartLocation({
1229
+ event: event,
1230
+ dragType: dragType,
1231
+ getDropTargetsOver: getDropTargetsOver
1232
+ });
1233
+ globalState.isActive = true;
1234
+ var state = {
1235
+ current: initial
1236
+ };
1237
+
1238
+ // Setting initial drop effect for the drag
1239
+ setDropEffectOnEvent({
1240
+ event: event,
1241
+ current: initial.dropTargets
1242
+ });
1243
+ var dispatch = makeDispatch({
1244
+ source: dragType.payload,
1245
+ dispatchEvent: dispatchEvent,
1246
+ initial: initial
1247
+ });
1248
+ function updateState(next) {
1249
+ // only looking at whether hierarchy has changed to determine whether something as 'changed'
1250
+ var hasChanged = hasHierarchyChanged({
1251
+ current: state.current.dropTargets,
1252
+ next: next.dropTargets
1253
+ });
1254
+
1255
+ // Always updating the state to include latest data, dropEffect and stickiness
1256
+ // Only updating consumers if the hierarchy has changed in some way
1257
+ // Consumers can get the latest data by using `onDrag`
1258
+ state.current = next;
1259
+ if (hasChanged) {
1260
+ dispatch.dragUpdate({
1261
+ current: state.current
1262
+ });
1263
+ }
1264
+ }
1265
+ function onUpdateEvent(event) {
1266
+ var input = getInput(event);
1267
+
1268
+ // If we are over the honey pot, we need to get the element
1269
+ // that the user would have been over if not for the honey pot
1270
+ var target = isHoneyPotElement(event.target) ? getElementFromPointWithoutHoneypot({
1271
+ x: input.clientX,
1272
+ y: input.clientY
1273
+ }) : event.target;
1274
+ var nextDropTargets = getDropTargetsOver({
1275
+ target: target,
1276
+ input: input,
1277
+ source: dragType.payload,
1278
+ current: state.current.dropTargets
1279
+ });
1280
+ if (nextDropTargets.length) {
1281
+ // 🩸 must call `event.preventDefault()` to allow a browser drop to occur
1282
+ event.preventDefault();
1283
+ setDropEffectOnEvent({
1284
+ event: event,
1285
+ current: nextDropTargets
1286
+ });
1287
+ }
1288
+ updateState({
1289
+ dropTargets: nextDropTargets,
1290
+ input: input
1291
+ });
1292
+ }
1293
+ function cancel() {
1294
+ // The spec behaviour is that when a drag is cancelled, or when dropping on no drop targets,
1295
+ // a "dragleave" event is fired on the active drop target before a "dragend" event.
1296
+ // We are replicating that behaviour in `cancel` if there are any active drop targets to
1297
+ // ensure consistent behaviour.
1298
+ //
1299
+ // Note: When cancelling, or dropping on no drop targets, a "dragleave" event
1300
+ // will have already cleared the dropTargets to `[]` (as that particular "dragleave" has a `relatedTarget` of `null`)
1301
+
1302
+ if (state.current.dropTargets.length) {
1303
+ updateState({
1304
+ dropTargets: [],
1305
+ input: state.current.input
1306
+ });
1307
+ }
1308
+ dispatch.drop({
1309
+ current: state.current,
1310
+ updatedSourcePayload: null
1311
+ });
1312
+ finish();
1313
+ }
1314
+ function finish() {
1315
+ globalState.isActive = false;
1316
+ unbindEvents();
1317
+ }
1318
+ var unbindEvents = bindAll(window, [{
1319
+ // 👋 Note: we are repurposing the `dragover` event as our `drag` event
1320
+ // this is because firefox does not publish pointer coordinates during
1321
+ // a `drag` event, but does for every other type of drag event
1322
+ // `dragover` fires on all elements that are being dragged over
1323
+ // Because we are binding to `window` - our `dragover` is effectively the same as a `drag`
1324
+ // 🦊😤
1325
+ type: 'dragover',
1326
+ listener: function listener(event) {
1327
+ // We need to regularly calculate the drop targets in order to allow:
1328
+ // - dynamic `canDrop()` checks
1329
+ // - rapid updating `getData()` calls to attach data in response to user input (eg for edge detection)
1330
+ // Sadly we cannot schedule inspecting changes resulting from this event
1331
+ // we need to be able to conditionally cancel the event with `event.preventDefault()`
1332
+ // to enable the correct native drop experience.
1333
+
1334
+ // 1. check to see if anything has changed
1335
+ onUpdateEvent(event);
1336
+
1337
+ // 2. let consumers know a move has occurred
1338
+ // This will include the latest 'input' values
1339
+ dispatch.drag({
1340
+ current: state.current
1341
+ });
1342
+ }
1343
+ }, {
1344
+ type: 'dragenter',
1345
+ listener: onUpdateEvent
1346
+ }, {
1347
+ type: 'dragleave',
1348
+ listener: function listener(event) {
1349
+ if (!isLeavingWindow({
1350
+ dragLeave: event
1351
+ })) {
1352
+ return;
1353
+ }
1354
+
1355
+ /**
1356
+ * At this point we don't know if a drag is being cancelled,
1357
+ * or if a drag is leaving the `window`.
1358
+ *
1359
+ * Both have:
1360
+ * 1. "dragleave" (with `relatedTarget: null`)
1361
+ * 2. "dragend" (a "dragend" can occur when outside the `window`)
1362
+ *
1363
+ * **Clearing drop targets**
1364
+ *
1365
+ * For either case we are clearing the the drop targets
1366
+ *
1367
+ * - cancelling: we clear drop targets in `"dragend"` anyway
1368
+ * - leaving the `window`: we clear the drop targets (to clear stickiness)
1369
+ *
1370
+ * **Leaving the window and finishing the drag**
1371
+ *
1372
+ * _internal drags_
1373
+ *
1374
+ * - The drag continues when the user is outside the `window`
1375
+ * and can resume if the user drags back over the `window`,
1376
+ * or end when the user drops in an external `window`.
1377
+ * - We will get a `"dragend"`, or we can listen for other
1378
+ * events to determine the drag is finished when the user re-enters the `window`).
1379
+ *
1380
+ * _external drags_
1381
+ *
1382
+ * - We conclude the drag operation.
1383
+ * - We have no idea if the user will drag back over the `window`,
1384
+ * or if the drag ends elsewhere.
1385
+ * - We will create a new drag if the user re-enters the `window`.
1386
+ *
1387
+ * **Not updating `input`**
1388
+ *
1389
+ * 🐛 Bug[Chrome] the final `"dragleave"` has default input values (eg `clientX == 0`)
1390
+ * Workaround: intentionally not updating `input` in "dragleave"
1391
+ * rather than the users current input values
1392
+ * - [Conversation](https://twitter.com/alexandereardon/status/1642697633864241152)
1393
+ * - [Bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1429937)
1394
+ **/
1395
+
1396
+ updateState({
1397
+ input: state.current.input,
1398
+ dropTargets: []
1399
+ });
1400
+ if (dragType.startedFrom === 'external') {
1401
+ cancel();
1402
+ }
1403
+ }
1404
+ }, {
1405
+ // A "drop" can only happen if the browser allowed the drop
1406
+ type: 'drop',
1407
+ listener: function listener(event) {
1408
+ // Capture the final input.
1409
+ // We are capturing the final `input` for the
1410
+ // most accurate honey pot experience
1411
+ state.current = {
1412
+ dropTargets: state.current.dropTargets,
1413
+ input: getInput(event)
1414
+ };
1415
+
1416
+ /** If there are no drop targets, then we will get
1417
+ * a "drop" event if:
1418
+ * - `preventUnhandled()` is being used
1419
+ * - there is an unmanaged drop target (eg another library)
1420
+ * In these cases, it's up to the consumer
1421
+ * to handle the drop if it's not over one of our drop targets
1422
+ * - `preventUnhandled()` will cancel the "drop"
1423
+ * - unmanaged drop targets can handle the "drop" how they want to
1424
+ * We won't call `event.preventDefault()` in this call path */
1425
+
1426
+ if (!state.current.dropTargets.length) {
1427
+ cancel();
1428
+ return;
1429
+ }
1430
+ event.preventDefault();
1431
+
1432
+ // applying the latest drop effect to the event
1433
+ setDropEffectOnEvent({
1434
+ event: event,
1435
+ current: state.current.dropTargets
1436
+ });
1437
+ dispatch.drop({
1438
+ current: state.current,
1439
+ // When dropping something native, we need to extract the latest
1440
+ // `.items` from the "drop" event as it is now accessible
1441
+ updatedSourcePayload: dragType.type === 'external' ? dragType.getDropPayload(event) : null
1442
+ });
1443
+ finish();
1444
+ }
1445
+ }, {
1446
+ // "dragend" fires when on the drag source (eg a draggable element)
1447
+ // when the drag is finished.
1448
+ // "dragend" will fire after "drop" (if there was a successful drop)
1449
+ // "dragend" does not fire if the draggable source has been removed during the drag
1450
+ // or for external drag sources (eg files)
1451
+
1452
+ // This "dragend" listener will not fire if there was a successful drop
1453
+ // as we will have already removed the event listener
1454
+
1455
+ type: 'dragend',
1456
+ listener: function listener(event) {
1457
+ // In firefox, the position of the "dragend" event can
1458
+ // be a bit different to the last "dragover" event.
1459
+ // Updating the input so we can get the best possible
1460
+ // information for the honey pot.
1461
+ state.current = {
1462
+ dropTargets: state.current.dropTargets,
1463
+ input: getInput(event)
1464
+ };
1465
+ cancel();
1466
+ }
1467
+ }].concat(_toConsumableArray(getBindingsForBrokenDrags({
1468
+ onDragEnd: cancel
1469
+ }))),
1470
+ // Once we have started a managed drag operation it is important that we see / own all drag events
1471
+ // We got one adoption bug pop up where some code was stopping (`event.stopPropagation()`)
1472
+ // all "drop" events in the bubble phase on the `document.body`.
1473
+ // This meant that we never saw the "drop" event.
1474
+ {
1475
+ capture: true
1476
+ });
1477
+ dispatch.start({
1478
+ nativeSetDragImage: getNativeSetDragImage(event)
1479
+ });
1480
+ }
1481
+ function setDropEffectOnEvent(_ref3) {
1482
+ var _current$;
1483
+ var event = _ref3.event,
1484
+ current = _ref3.current;
1485
+ // setting the `dropEffect` to be the innerMost drop targets dropEffect
1486
+ var innerMost = (_current$ = current[0]) === null || _current$ === void 0 ? void 0 : _current$.dropEffect;
1487
+ if (innerMost != null && event.dataTransfer) {
1488
+ event.dataTransfer.dropEffect = innerMost;
1489
+ }
1490
+ }
1491
+ function getStartLocation(_ref4) {
1492
+ var event = _ref4.event,
1493
+ dragType = _ref4.dragType,
1494
+ getDropTargetsOver = _ref4.getDropTargetsOver;
1495
+ var input = getInput(event);
1496
+
1497
+ // When dragging from outside of the browser,
1498
+ // the drag is not being sourced from any local drop targets
1499
+ if (dragType.startedFrom === 'external') {
1500
+ return {
1501
+ input: input,
1502
+ dropTargets: []
1503
+ };
1504
+ }
1505
+ var dropTargets = getDropTargetsOver({
1506
+ input: input,
1507
+ source: dragType.payload,
1508
+ target: event.target,
1509
+ current: []
1510
+ });
1511
+ return {
1512
+ input: input,
1513
+ dropTargets: dropTargets
1514
+ };
1515
+ }
1516
+ var lifecycle = {
1517
+ canStart: canStart,
1518
+ start: start
1519
+ };
1520
+
1521
+ // Extending `Map` to allow us to link Key and Values together
1522
+
1523
+ var ledger = new Map();
1524
+ function registerUsage(_ref) {
1525
+ var typeKey = _ref.typeKey,
1526
+ mount = _ref.mount;
1527
+ var entry = ledger.get(typeKey);
1528
+ if (entry) {
1529
+ entry.usageCount++;
1530
+ return entry;
1531
+ }
1532
+ var initial = {
1533
+ typeKey: typeKey,
1534
+ unmount: mount(),
1535
+ usageCount: 1
1536
+ };
1537
+ ledger.set(typeKey, initial);
1538
+ return initial;
1539
+ }
1540
+ function register(args) {
1541
+ var entry = registerUsage(args);
1542
+ return function unregister() {
1543
+ entry.usageCount--;
1544
+ if (entry.usageCount > 0) {
1545
+ return;
1546
+ }
1547
+ // Only a single usage left, remove it
1548
+ entry.unmount();
1549
+ ledger.delete(args.typeKey);
1550
+ };
1551
+ }
1552
+
1553
+ /** Create a new combined function that will call all the provided functions */
1554
+ function combine() {
1555
+ for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) {
1556
+ fns[_key] = arguments[_key];
1557
+ }
1558
+ return function cleanup() {
1559
+ fns.forEach(function (fn) {
1560
+ return fn();
1561
+ });
1562
+ };
1563
+ }
1564
+
1565
+ function addAttribute(element, _ref) {
1566
+ var attribute = _ref.attribute,
1567
+ value = _ref.value;
1568
+ element.setAttribute(attribute, value);
1569
+ return function () {
1570
+ return element.removeAttribute(attribute);
1571
+ };
1572
+ }
1573
+
1574
+ function ownKeys$1(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
1575
+ function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1576
+ function _createForOfIteratorHelper$1(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$1(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
1577
+ function _unsupportedIterableToArray$1(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$1(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$1(r, a) : void 0; } }
1578
+ function _arrayLikeToArray$1(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
1579
+ function copyReverse(array) {
1580
+ return array.slice(0).reverse();
1581
+ }
1582
+ function makeDropTarget(_ref) {
1583
+ var typeKey = _ref.typeKey,
1584
+ defaultDropEffect = _ref.defaultDropEffect;
1585
+ var registry = new WeakMap();
1586
+ var dropTargetDataAtt = "data-drop-target-for-".concat(typeKey);
1587
+ var dropTargetSelector = "[".concat(dropTargetDataAtt, "]");
1588
+ function addToRegistry(args) {
1589
+ registry.set(args.element, args);
1590
+ return function () {
1591
+ return registry.delete(args.element);
1592
+ };
1593
+ }
1594
+ function dropTargetForConsumers(args) {
1595
+ // Guardrail: warn if the draggable element is already registered
1596
+ if (process.env.NODE_ENV !== 'production') {
1597
+ var existing = registry.get(args.element);
1598
+ if (existing) {
1599
+ // eslint-disable-next-line no-console
1600
+ console.warn("You have already registered a [".concat(typeKey, "] dropTarget on the same element"), {
1601
+ existing: existing,
1602
+ proposed: args
1603
+ });
1604
+ }
1605
+ if (args.element instanceof HTMLIFrameElement) {
1606
+ // eslint-disable-next-line no-console
1607
+ console.warn("\n We recommend not registering <iframe> elements as drop targets\n as it can result in some strange browser event ordering.\n " // Removing newlines and excessive whitespace
1608
+ .replace(/\s{2,}/g, ' ').trim());
1609
+ }
1610
+ }
1611
+ return combine(addAttribute(args.element, {
1612
+ attribute: dropTargetDataAtt,
1613
+ value: 'true'
1614
+ }), addToRegistry(args));
1615
+ }
1616
+ function getActualDropTargets(_ref2) {
1617
+ var _args$getData, _args$getData2, _args$getDropEffect, _args$getDropEffect2;
1618
+ var source = _ref2.source,
1619
+ target = _ref2.target,
1620
+ input = _ref2.input,
1621
+ _ref2$result = _ref2.result,
1622
+ result = _ref2$result === void 0 ? [] : _ref2$result;
1623
+ if (target == null) {
1624
+ return result;
1625
+ }
1626
+ if (!(target instanceof Element)) {
1627
+ // For "text-selection" drags, the original `target`
1628
+ // is not an `Element`, so we need to start looking from
1629
+ // the parent element
1630
+ if (target instanceof Node) {
1631
+ return getActualDropTargets({
1632
+ source: source,
1633
+ target: target.parentElement,
1634
+ input: input,
1635
+ result: result
1636
+ });
1637
+ }
1638
+
1639
+ // not sure what we are working with,
1640
+ // so we can exit.
1641
+ return result;
1642
+ }
1643
+ var closest = target.closest(dropTargetSelector);
1644
+
1645
+ // Cannot find anything else
1646
+ if (closest == null) {
1647
+ return result;
1648
+ }
1649
+ var args = registry.get(closest);
1650
+
1651
+ // error: something had a dropTargetSelector but we could not
1652
+ // find a match. For now, failing silently
1653
+ if (args == null) {
1654
+ return result;
1655
+ }
1656
+ var feedback = {
1657
+ input: input,
1658
+ source: source,
1659
+ element: args.element
1660
+ };
1661
+
1662
+ // if dropping is not allowed, skip this drop target
1663
+ // and continue looking up the DOM tree
1664
+ if (args.canDrop && !args.canDrop(feedback)) {
1665
+ return getActualDropTargets({
1666
+ source: source,
1667
+ target: args.element.parentElement,
1668
+ input: input,
1669
+ result: result
1670
+ });
1671
+ }
1672
+
1673
+ // calculate our new record
1674
+ var data = (_args$getData = (_args$getData2 = args.getData) === null || _args$getData2 === void 0 ? void 0 : _args$getData2.call(args, feedback)) !== null && _args$getData !== void 0 ? _args$getData : {};
1675
+ var dropEffect = (_args$getDropEffect = (_args$getDropEffect2 = args.getDropEffect) === null || _args$getDropEffect2 === void 0 ? void 0 : _args$getDropEffect2.call(args, feedback)) !== null && _args$getDropEffect !== void 0 ? _args$getDropEffect : defaultDropEffect;
1676
+ var record = {
1677
+ data: data,
1678
+ element: args.element,
1679
+ dropEffect: dropEffect,
1680
+ // we are collecting _actual_ drop targets, so these are
1681
+ // being applied _not_ due to stickiness
1682
+ isActiveDueToStickiness: false
1683
+ };
1684
+ return getActualDropTargets({
1685
+ source: source,
1686
+ target: args.element.parentElement,
1687
+ input: input,
1688
+ // Using bubble ordering. Same ordering as `event.getPath()`
1689
+ result: [].concat(_toConsumableArray(result), [record])
1690
+ });
1691
+ }
1692
+ function notifyCurrent(_ref3) {
1693
+ var eventName = _ref3.eventName,
1694
+ payload = _ref3.payload;
1695
+ var _iterator = _createForOfIteratorHelper$1(payload.location.current.dropTargets),
1696
+ _step;
1697
+ try {
1698
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
1699
+ var _entry$eventName;
1700
+ var record = _step.value;
1701
+ var entry = registry.get(record.element);
1702
+ var args = _objectSpread$1(_objectSpread$1({}, payload), {}, {
1703
+ self: record
1704
+ });
1705
+ entry === null || entry === void 0 || (_entry$eventName = entry[eventName]) === null || _entry$eventName === void 0 || _entry$eventName.call(entry,
1706
+ // I cannot seem to get the types right here.
1707
+ // TS doesn't seem to like that one event can need `nativeSetDragImage`
1708
+ // @ts-expect-error
1709
+ args);
1710
+ }
1711
+ } catch (err) {
1712
+ _iterator.e(err);
1713
+ } finally {
1714
+ _iterator.f();
1715
+ }
1716
+ }
1717
+ var actions = {
1718
+ onGenerateDragPreview: notifyCurrent,
1719
+ onDrag: notifyCurrent,
1720
+ onDragStart: notifyCurrent,
1721
+ onDrop: notifyCurrent,
1722
+ onDropTargetChange: function onDropTargetChange(_ref4) {
1723
+ var payload = _ref4.payload;
1724
+ var isCurrent = new Set(payload.location.current.dropTargets.map(function (record) {
1725
+ return record.element;
1726
+ }));
1727
+ var visited = new Set();
1728
+ var _iterator2 = _createForOfIteratorHelper$1(payload.location.previous.dropTargets),
1729
+ _step2;
1730
+ try {
1731
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1732
+ var _entry$onDropTargetCh;
1733
+ var record = _step2.value;
1734
+ visited.add(record.element);
1735
+ var entry = registry.get(record.element);
1736
+ var isOver = isCurrent.has(record.element);
1737
+ var args = _objectSpread$1(_objectSpread$1({}, payload), {}, {
1738
+ self: record
1739
+ });
1740
+ entry === null || entry === void 0 || (_entry$onDropTargetCh = entry.onDropTargetChange) === null || _entry$onDropTargetCh === void 0 || _entry$onDropTargetCh.call(entry, args);
1741
+
1742
+ // if we cannot find the drop target in the current array, then it has been left
1743
+ if (!isOver) {
1744
+ var _entry$onDragLeave;
1745
+ entry === null || entry === void 0 || (_entry$onDragLeave = entry.onDragLeave) === null || _entry$onDragLeave === void 0 || _entry$onDragLeave.call(entry, args);
1746
+ }
1747
+ }
1748
+ } catch (err) {
1749
+ _iterator2.e(err);
1750
+ } finally {
1751
+ _iterator2.f();
1752
+ }
1753
+ var _iterator3 = _createForOfIteratorHelper$1(payload.location.current.dropTargets),
1754
+ _step3;
1755
+ try {
1756
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1757
+ var _entry$onDropTargetCh2, _entry$onDragEnter;
1758
+ var _record = _step3.value;
1759
+ // already published an update to this drop target
1760
+ if (visited.has(_record.element)) {
1761
+ continue;
1762
+ }
1763
+ // at this point we have a new drop target that is being entered into
1764
+ var _args = _objectSpread$1(_objectSpread$1({}, payload), {}, {
1765
+ self: _record
1766
+ });
1767
+ var _entry = registry.get(_record.element);
1768
+ _entry === null || _entry === void 0 || (_entry$onDropTargetCh2 = _entry.onDropTargetChange) === null || _entry$onDropTargetCh2 === void 0 || _entry$onDropTargetCh2.call(_entry, _args);
1769
+ _entry === null || _entry === void 0 || (_entry$onDragEnter = _entry.onDragEnter) === null || _entry$onDragEnter === void 0 || _entry$onDragEnter.call(_entry, _args);
1770
+ }
1771
+ } catch (err) {
1772
+ _iterator3.e(err);
1773
+ } finally {
1774
+ _iterator3.f();
1775
+ }
1776
+ }
1777
+ };
1778
+ function dispatchEvent(args) {
1779
+ actions[args.eventName](args);
1780
+ }
1781
+ function getIsOver(_ref5) {
1782
+ var source = _ref5.source,
1783
+ target = _ref5.target,
1784
+ input = _ref5.input,
1785
+ current = _ref5.current;
1786
+ var actual = getActualDropTargets({
1787
+ source: source,
1788
+ target: target,
1789
+ input: input
1790
+ });
1791
+
1792
+ // stickiness is only relevant when we have less
1793
+ // drop targets than we did before
1794
+ if (actual.length >= current.length) {
1795
+ return actual;
1796
+ }
1797
+
1798
+ // less 'actual' drop targets than before,
1799
+ // we need to see if 'stickiness' applies
1800
+
1801
+ // An old drop target will continue to be dropped on if:
1802
+ // 1. it has the same parent
1803
+ // 2. nothing exists in it's previous index
1804
+
1805
+ var lastCaptureOrdered = copyReverse(current);
1806
+ var actualCaptureOrdered = copyReverse(actual);
1807
+ var resultCaptureOrdered = [];
1808
+ for (var index = 0; index < lastCaptureOrdered.length; index++) {
1809
+ var _argsForLast$getIsSti;
1810
+ var last = lastCaptureOrdered[index];
1811
+ var fresh = actualCaptureOrdered[index];
1812
+
1813
+ // if a record is in the new index -> use that
1814
+ // it will have the latest data + dropEffect
1815
+ if (fresh != null) {
1816
+ resultCaptureOrdered.push(fresh);
1817
+ continue;
1818
+ }
1819
+
1820
+ // At this point we have no drop target in the old spot
1821
+ // Check to see if we can use a previous sticky drop target
1822
+
1823
+ // The "parent" is the one inside of `resultCaptureOrdered`
1824
+ // (the parent might be a drop target that was sticky)
1825
+ var parent = resultCaptureOrdered[index - 1];
1826
+ var lastParent = lastCaptureOrdered[index - 1];
1827
+
1828
+ // Stickiness is based on parent relationships, so if the parent relationship has change
1829
+ // then we can stop our search
1830
+ if ((parent === null || parent === void 0 ? void 0 : parent.element) !== (lastParent === null || lastParent === void 0 ? void 0 : lastParent.element)) {
1831
+ break;
1832
+ }
1833
+
1834
+ // We need to check whether the old drop target can still be dropped on
1835
+
1836
+ var argsForLast = registry.get(last.element);
1837
+
1838
+ // We cannot drop on a drop target that is no longer mounted
1839
+ if (!argsForLast) {
1840
+ break;
1841
+ }
1842
+ var feedback = {
1843
+ input: input,
1844
+ source: source,
1845
+ element: argsForLast.element
1846
+ };
1847
+
1848
+ // We cannot drop on a drop target that no longer allows being dropped on
1849
+ if (argsForLast.canDrop && !argsForLast.canDrop(feedback)) {
1850
+ break;
1851
+ }
1852
+
1853
+ // We cannot drop on a drop target that is no longer sticky
1854
+ if (!((_argsForLast$getIsSti = argsForLast.getIsSticky) !== null && _argsForLast$getIsSti !== void 0 && _argsForLast$getIsSti.call(argsForLast, feedback))) {
1855
+ break;
1856
+ }
1857
+
1858
+ // Note: intentionally not recollecting `getData()` or `getDropEffect()`
1859
+ // Previous values for `data` and `dropEffect` will be borrowed
1860
+ // This is to prevent things like the 'closest edge' changing when
1861
+ // no longer over a drop target.
1862
+ // We could change our mind on this behaviour in the future
1863
+
1864
+ resultCaptureOrdered.push(_objectSpread$1(_objectSpread$1({}, last), {}, {
1865
+ // making it clear to consumers this drop target is active due to stickiness
1866
+ isActiveDueToStickiness: true
1867
+ }));
1868
+ }
1869
+
1870
+ // return bubble ordered result
1871
+ return copyReverse(resultCaptureOrdered);
1872
+ }
1873
+ return {
1874
+ dropTargetForConsumers: dropTargetForConsumers,
1875
+ getIsOver: getIsOver,
1876
+ dispatchEvent: dispatchEvent
1877
+ };
1878
+ }
1879
+
1880
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
1881
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
1882
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
1883
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
1884
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1885
+ function makeMonitor() {
1886
+ var registry = new Set();
1887
+ var dragging = null;
1888
+ function tryAddToActive(monitor) {
1889
+ if (!dragging) {
1890
+ return;
1891
+ }
1892
+ // Monitor is allowed to monitor events if:
1893
+ // 1. It has no `canMonitor` function (default is that a monitor can listen to everything)
1894
+ // 2. `canMonitor` returns true
1895
+ if (!monitor.canMonitor || monitor.canMonitor(dragging.canMonitorArgs)) {
1896
+ dragging.active.add(monitor);
1897
+ }
1898
+ }
1899
+ function monitorForConsumers(args) {
1900
+ // We are giving each `args` a new reference so that you
1901
+ // can create multiple monitors with the same `args`.
1902
+ var entry = _objectSpread({}, args);
1903
+ registry.add(entry);
1904
+
1905
+ // if there is an active drag we need to see if this new monitor is relevant
1906
+ tryAddToActive(entry);
1907
+ return function cleanup() {
1908
+ registry.delete(entry);
1909
+
1910
+ // We need to stop publishing events during a drag to this monitor!
1911
+ if (dragging) {
1912
+ dragging.active.delete(entry);
1913
+ }
1914
+ };
1915
+ }
1916
+ function dispatchEvent(_ref) {
1917
+ var eventName = _ref.eventName,
1918
+ payload = _ref.payload;
1919
+ if (eventName === 'onGenerateDragPreview') {
1920
+ dragging = {
1921
+ canMonitorArgs: {
1922
+ initial: payload.location.initial,
1923
+ source: payload.source
1924
+ },
1925
+ active: new Set()
1926
+ };
1927
+ var _iterator = _createForOfIteratorHelper(registry),
1928
+ _step;
1929
+ try {
1930
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
1931
+ var monitor = _step.value;
1932
+ tryAddToActive(monitor);
1933
+ }
1934
+ } catch (err) {
1935
+ _iterator.e(err);
1936
+ } finally {
1937
+ _iterator.f();
1938
+ }
1939
+ }
1940
+
1941
+ // This should never happen.
1942
+ if (!dragging) {
1943
+ return;
1944
+ }
1945
+
1946
+ // Creating an array from the set _before_ iterating
1947
+ // This is so that monitors added during the current event will not be called.
1948
+ // This behaviour matches native EventTargets where an event listener
1949
+ // cannot add another event listener during an active event to the same
1950
+ // event target in the same event (for us we have a single global event target)
1951
+ var active = Array.from(dragging.active);
1952
+ for (var _i = 0, _active = active; _i < _active.length; _i++) {
1953
+ var _monitor = _active[_i];
1954
+ // A monitor can be removed by another monitor during an event.
1955
+ // We need to check that the monitor is still registered before calling it
1956
+ if (dragging.active.has(_monitor)) {
1957
+ var _monitor$eventName;
1958
+ // @ts-expect-error: I cannot get this type working!
1959
+ (_monitor$eventName = _monitor[eventName]) === null || _monitor$eventName === void 0 || _monitor$eventName.call(_monitor, payload);
1960
+ }
1961
+ }
1962
+ if (eventName === 'onDrop') {
1963
+ dragging.active.clear();
1964
+ dragging = null;
1965
+ }
1966
+ }
1967
+ return {
1968
+ dispatchEvent: dispatchEvent,
1969
+ monitorForConsumers: monitorForConsumers
1970
+ };
1971
+ }
1972
+
1973
+ function makeAdapter(_ref) {
1974
+ var typeKey = _ref.typeKey,
1975
+ mount = _ref.mount,
1976
+ dispatchEventToSource = _ref.dispatchEventToSource,
1977
+ onPostDispatch = _ref.onPostDispatch,
1978
+ defaultDropEffect = _ref.defaultDropEffect;
1979
+ var monitorAPI = makeMonitor();
1980
+ var dropTargetAPI = makeDropTarget({
1981
+ typeKey: typeKey,
1982
+ defaultDropEffect: defaultDropEffect
1983
+ });
1984
+ function dispatchEvent(args) {
1985
+ // 1. forward the event to source
1986
+ dispatchEventToSource === null || dispatchEventToSource === void 0 || dispatchEventToSource(args);
1987
+
1988
+ // 2. forward the event to relevant dropTargets
1989
+ dropTargetAPI.dispatchEvent(args);
1990
+
1991
+ // 3. forward event to monitors
1992
+ monitorAPI.dispatchEvent(args);
1993
+
1994
+ // 4. post consumer dispatch (used for honey pot fix)
1995
+ onPostDispatch === null || onPostDispatch === void 0 || onPostDispatch(args);
1996
+ }
1997
+ function start(_ref2) {
1998
+ var event = _ref2.event,
1999
+ dragType = _ref2.dragType;
2000
+ lifecycle.start({
2001
+ event: event,
2002
+ dragType: dragType,
2003
+ getDropTargetsOver: dropTargetAPI.getIsOver,
2004
+ dispatchEvent: dispatchEvent
2005
+ });
2006
+ }
2007
+ function registerUsage() {
2008
+ function mountAdapter() {
2009
+ var api = {
2010
+ canStart: lifecycle.canStart,
2011
+ start: start
2012
+ };
2013
+ return mount(api);
2014
+ }
2015
+ return register({
2016
+ typeKey: typeKey,
2017
+ mount: mountAdapter
2018
+ });
2019
+ }
2020
+ return {
2021
+ registerUsage: registerUsage,
2022
+ dropTarget: dropTargetAPI.dropTargetForConsumers,
2023
+ monitor: monitorAPI.monitorForConsumers
2024
+ };
2025
+ }
2026
+
2027
+ // using `cache` as our `isAndroid()` result will not change in a browser
2028
+ var isAndroid = once(function isAndroid() {
2029
+ return navigator.userAgent.toLocaleLowerCase().includes('android');
2030
+ });
2031
+ var androidFallbackText = 'pdnd:android-fallback';
2032
+
2033
+ // Why we put the media types in their own files:
2034
+ //
2035
+ // - we are not putting them all in one file as not all adapters need all types
2036
+ // - we are not putting them in the external helpers as some things just need the
2037
+ // types and not the external functions code
2038
+ var textMediaType = 'text/plain';
2039
+
2040
+ // Why we put the media types in their own files:
2041
+ //
2042
+ // - we are not putting them all in one file as not all adapters need all types
2043
+ // - we are not putting them in the external helpers as some things just need the
2044
+ // types and not the external functions code
2045
+ var URLMediaType = 'text/uri-list';
2046
+
2047
+ /**
2048
+ * This key has been pulled into a separate module
2049
+ * so that the external adapter does not need to import
2050
+ * the element adapter
2051
+ */
2052
+ var elementAdapterNativeDataKey = 'application/vnd.pdnd';
2053
+
2054
+ var draggableRegistry = new WeakMap();
2055
+ function addToRegistry(args) {
2056
+ draggableRegistry.set(args.element, args);
2057
+ return function cleanup() {
2058
+ draggableRegistry.delete(args.element);
2059
+ };
2060
+ }
2061
+ var honeyPotFix = makeHoneyPotFix();
2062
+ var adapter$1 = makeAdapter({
2063
+ typeKey: 'element',
2064
+ defaultDropEffect: 'move',
2065
+ mount: function mount(api) {
2066
+ /** Binding event listeners the `document` rather than `window` so that
2067
+ * this adapter always gets preference over the text adapter.
2068
+ * `document` is the first `EventTarget` under `window`
2069
+ * https://twitter.com/alexandereardon/status/1604658588311465985
2070
+ */
2071
+ return combine(honeyPotFix.bindEvents(), bind(document, {
2072
+ type: 'dragstart',
2073
+ listener: function listener(event) {
2074
+ var _entry$dragHandle, _entry$getInitialData, _entry$getInitialData2, _entry$dragHandle2, _entry$getInitialData3, _entry$getInitialData4;
2075
+ if (!api.canStart(event)) {
2076
+ return;
2077
+ }
2078
+
2079
+ // If the "dragstart" event is cancelled, then a drag won't start
2080
+ // There will be no further drag operation events (eg no "dragend" event)
2081
+ if (event.defaultPrevented) {
2082
+ return;
2083
+ }
2084
+
2085
+ // Technically `dataTransfer` can be `null` according to the types
2086
+ // But that behaviour does not seem to appear in the spec.
2087
+ // If there is not `dataTransfer`, we can assume something is wrong and not
2088
+ // start a drag
2089
+ if (!event.dataTransfer) {
2090
+ // Including this code on "test" and "development" environments:
2091
+ // - Browser tests commonly run against "development" builds
2092
+ // - Unit tests commonly run in "test"
2093
+ if (process.env.NODE_ENV !== 'production') {
2094
+ // eslint-disable-next-line no-console
2095
+ console.warn("\n It appears as though you have are not testing DragEvents correctly.\n\n - If you are unit testing, ensure you have polyfilled DragEvent.\n - If you are browser testing, ensure you are dispatching drag events correctly.\n\n Please see our testing guides for more information:\n https://atlassian.design/components/pragmatic-drag-and-drop/core-package/testing\n ".replace(/ {2}/g, ''));
2096
+ }
2097
+ return;
2098
+ }
2099
+
2100
+ // the closest parent that is a draggable element will be marked as
2101
+ // the `event.target` for the event
2102
+ var target = event.target;
2103
+
2104
+ // this source is only for elements
2105
+ // Note: only HTMLElements can have the "draggable" attribute
2106
+ if (!(target instanceof HTMLElement)) {
2107
+ return null;
2108
+ }
2109
+
2110
+ // see if the thing being dragged is owned by us
2111
+ var entry = draggableRegistry.get(target);
2112
+
2113
+ // no matching element found
2114
+ // → dragging an element with `draggable="true"` that is not controlled by us
2115
+ if (!entry) {
2116
+ return null;
2117
+ }
2118
+
2119
+ /**
2120
+ * A text selection drag _can_ have the `draggable` element be
2121
+ * the `event.target` if the user is dragging the text selection
2122
+ * from the `draggable`.
2123
+ *
2124
+ * To know if the `draggable` is being dragged, we look at whether any
2125
+ * `"text/plain"` data is being dragged. If it is, then a text selection
2126
+ * drag is occurring.
2127
+ *
2128
+ * This behaviour has been validated on:
2129
+ *
2130
+ * - Chrome@128 on Android@14
2131
+ * - Chrome@128 on iOS@17.6.1
2132
+ * - Chrome@128 on Windows@11
2133
+ * - Chrome@128 on MacOS@14.6.1
2134
+ * - Firefox@129 on Windows@11 (not possible for user to select text in a draggable)
2135
+ * - Firefox@129 on MacOS@14.6.1 (not possible for user to select text in a draggable)
2136
+ *
2137
+ * Note: Could usually just use: `event.dataTransfer.types.includes(textMediaType)`
2138
+ * but unfortunately ProseMirror is always setting `""` as the dragged text
2139
+ *
2140
+ * Note: Unfortunately editor is (heavily) leaning on the current functionality today
2141
+ * and unwinding it will be a decent amount of effort. So for now, a text selection
2142
+ * where the `event.target` is a `draggable` element will still trigger the
2143
+ * element adapter.
2144
+ *
2145
+ * // Future state:
2146
+ * if(event.dataTransfer.getData(textMediaType)) {
2147
+ * return;
2148
+ * }
2149
+ *
2150
+ */
2151
+
2152
+ var input = getInput(event);
2153
+ var feedback = {
2154
+ element: entry.element,
2155
+ dragHandle: (_entry$dragHandle = entry.dragHandle) !== null && _entry$dragHandle !== void 0 ? _entry$dragHandle : null,
2156
+ input: input
2157
+ };
2158
+
2159
+ // Check: does the draggable want to allow dragging?
2160
+ if (entry.canDrag && !entry.canDrag(feedback)) {
2161
+ // cancel drag operation if we cannot drag
2162
+ event.preventDefault();
2163
+ return null;
2164
+ }
2165
+
2166
+ // Check: is there a drag handle and is the user using it?
2167
+ if (entry.dragHandle) {
2168
+ // technically don't need this util, but just being
2169
+ // consistent with how we look up what is under the users
2170
+ // cursor.
2171
+ var over = getElementFromPointWithoutHoneypot({
2172
+ x: input.clientX,
2173
+ y: input.clientY
2174
+ });
2175
+
2176
+ // if we are not dragging from the drag handle (or something inside the drag handle)
2177
+ // then we will cancel the active drag
2178
+ if (!entry.dragHandle.contains(over)) {
2179
+ event.preventDefault();
2180
+ return null;
2181
+ }
2182
+ }
2183
+
2184
+ /**
2185
+ * **Goal**
2186
+ * Pass information to other applications
2187
+ *
2188
+ * **Approach**
2189
+ * Put data into the native data store
2190
+ *
2191
+ * **What about the native adapter?**
2192
+ * When the element adapter puts native data into the native data store
2193
+ * the native adapter is not triggered in the current window,
2194
+ * but a native adapter in an external window _can_ be triggered
2195
+ *
2196
+ * **Why bake this into core?**
2197
+ * This functionality could be pulled out and exposed inside of
2198
+ * `onGenerateDragPreview`. But decided to make it a part of the
2199
+ * base API as it felt like a common enough use case and ended
2200
+ * up being a similar amount of code to include this function as
2201
+ * it was to expose the hook for it
2202
+ */
2203
+ var nativeData = (_entry$getInitialData = (_entry$getInitialData2 = entry.getInitialDataForExternal) === null || _entry$getInitialData2 === void 0 ? void 0 : _entry$getInitialData2.call(entry, feedback)) !== null && _entry$getInitialData !== void 0 ? _entry$getInitialData : null;
2204
+ if (nativeData) {
2205
+ for (var _i = 0, _Object$entries = Object.entries(nativeData); _i < _Object$entries.length; _i++) {
2206
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
2207
+ key = _Object$entries$_i[0],
2208
+ data = _Object$entries$_i[1];
2209
+ event.dataTransfer.setData(key, data !== null && data !== void 0 ? data : '');
2210
+ }
2211
+ }
2212
+
2213
+ /**
2214
+ * 📱 For Android devices, a drag operation will not start unless
2215
+ * "text/plain" or "text/uri-list" data exists in the native data store
2216
+ * https://twitter.com/alexandereardon/status/1732189803754713424
2217
+ *
2218
+ * Tested on:
2219
+ * Device: Google Pixel 5
2220
+ * Android version: 14 (November 5, 2023)
2221
+ * Chrome version: 120.0
2222
+ */
2223
+ if (isAndroid() && !event.dataTransfer.types.includes(textMediaType) && !event.dataTransfer.types.includes(URLMediaType)) {
2224
+ event.dataTransfer.setData(textMediaType, androidFallbackText);
2225
+ }
2226
+
2227
+ /**
2228
+ * 1. Must set any media type for `iOS15` to work
2229
+ * 2. We are also doing adding data so that the native adapter
2230
+ * can know that the element adapter has handled this drag
2231
+ *
2232
+ * We used to wrap this `setData()` in a `try/catch` for Firefox,
2233
+ * but it looks like that was not needed.
2234
+ *
2235
+ * Tested using: https://codesandbox.io/s/checking-firefox-throw-behaviour-on-dragstart-qt8h4f
2236
+ *
2237
+ * - ✅ Firefox@70.0 (Oct 2019) on macOS Sonoma
2238
+ * - ✅ Firefox@70.0 (Oct 2019) on macOS Big Sur
2239
+ * - ✅ Firefox@70.0 (Oct 2019) on Windows 10
2240
+ *
2241
+ * // just checking a few more combinations to be super safe
2242
+ *
2243
+ * - ✅ Chrome@78 (Oct 2019) on macOS Big Sur
2244
+ * - ✅ Chrome@78 (Oct 2019) on Windows 10
2245
+ * - ✅ Safari@14.1 on macOS Big Sur
2246
+ */
2247
+ event.dataTransfer.setData(elementAdapterNativeDataKey, '');
2248
+ var payload = {
2249
+ element: entry.element,
2250
+ dragHandle: (_entry$dragHandle2 = entry.dragHandle) !== null && _entry$dragHandle2 !== void 0 ? _entry$dragHandle2 : null,
2251
+ data: (_entry$getInitialData3 = (_entry$getInitialData4 = entry.getInitialData) === null || _entry$getInitialData4 === void 0 ? void 0 : _entry$getInitialData4.call(entry, feedback)) !== null && _entry$getInitialData3 !== void 0 ? _entry$getInitialData3 : {}
2252
+ };
2253
+ var dragType = {
2254
+ type: 'element',
2255
+ payload: payload,
2256
+ startedFrom: 'internal'
2257
+ };
2258
+ api.start({
2259
+ event: event,
2260
+ dragType: dragType
2261
+ });
2262
+ }
2263
+ }));
2264
+ },
2265
+ dispatchEventToSource: function dispatchEventToSource(_ref) {
2266
+ var _draggableRegistry$ge, _draggableRegistry$ge2;
2267
+ var eventName = _ref.eventName,
2268
+ payload = _ref.payload;
2269
+ // During a drag operation, a draggable can be:
2270
+ // - remounted with different functions
2271
+ // - removed completely
2272
+ // So we need to get the latest entry from the registry in order
2273
+ // to call the latest event functions
2274
+
2275
+ (_draggableRegistry$ge = draggableRegistry.get(payload.source.element)) === null || _draggableRegistry$ge === void 0 || (_draggableRegistry$ge2 = _draggableRegistry$ge[eventName]) === null || _draggableRegistry$ge2 === void 0 || _draggableRegistry$ge2.call(_draggableRegistry$ge,
2276
+ // I cannot seem to get the types right here.
2277
+ // TS doesn't seem to like that one event can need `nativeSetDragImage`
2278
+ // @ts-expect-error
2279
+ payload);
2280
+ },
2281
+ onPostDispatch: honeyPotFix.getOnPostDispatch()
2282
+ });
2283
+ var dropTargetForElements = adapter$1.dropTarget;
2284
+ var monitorForElements = adapter$1.monitor;
2285
+ function draggable(args) {
2286
+ // Guardrail: warn if the drag handle is not contained in draggable element
2287
+ if (process.env.NODE_ENV !== 'production') {
2288
+ if (args.dragHandle && !args.element.contains(args.dragHandle)) {
2289
+ // eslint-disable-next-line no-console
2290
+ console.warn('Drag handle element must be contained in draggable element', {
2291
+ element: args.element,
2292
+ dragHandle: args.dragHandle
2293
+ });
2294
+ }
2295
+ }
2296
+ // Guardrail: warn if the draggable element is already registered
2297
+ if (process.env.NODE_ENV !== 'production') {
2298
+ var existing = draggableRegistry.get(args.element);
2299
+ if (existing) {
2300
+ // eslint-disable-next-line no-console
2301
+ console.warn('You have already registered a `draggable` on the same element', {
2302
+ existing: existing,
2303
+ proposed: args
2304
+ });
2305
+ }
2306
+ }
2307
+ return combine(
2308
+ // making the draggable register the adapter rather than drop targets
2309
+ // this is because you *must* have a draggable element to start a drag
2310
+ // but you _might_ not have any drop targets immediately
2311
+ // (You might create drop targets async)
2312
+ adapter$1.registerUsage(), addToRegistry(args), addAttribute(args.element, {
2313
+ attribute: 'draggable',
2314
+ value: 'true'
2315
+ }));
2316
+ }
2317
+
2318
+ /** Common event payload for all events */
2319
+
2320
+ /** A map containing payloads for all events */
2321
+
2322
+ /** Common event payload for all drop target events */
2323
+
2324
+ /** A map containing payloads for all events on drop targets */
2325
+
2326
+ /** Arguments given to all feedback functions (eg `canDrag()`) on for a `draggable()` */
2327
+
2328
+ /** Arguments given to all feedback functions (eg `canDrop()`) on a `dropTargetForElements()` */
2329
+
2330
+ /** Arguments given to all monitor feedback functions (eg `canMonitor()`) for a `monitorForElements` */
2331
+
441
2332
  const CheckboxCard = React.forwardRef(function CheckboxCard(props, ref) {
442
2333
  const { inputProps, label, description, icon, addon, indicator = jsx(CheckboxCard$1.Indicator, {}), indicatorPlacement = "end", ...rest } = props;
443
2334
  const hasContent = label || description || icon;
@@ -694,11 +2585,12 @@ const snakeToLabel = (str) => {
694
2585
  };
695
2586
 
696
2587
  const RecordDisplay = ({ object, boxProps }) => {
2588
+ console.log(object, "dkfos");
697
2589
  if (object === null) {
698
2590
  return jsx(Fragment, { children: "null" });
699
2591
  }
700
- return (jsx(Grid, { rowGap: 1, overflow: "auto", ...boxProps, children: Object.entries(object).map(([field, value]) => {
701
- return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: "auto 1fr", children: [jsx(Text, { color: "gray.400", children: snakeToLabel(field) }), jsx(Text, { children: typeof value === "object" ? JSON.stringify(value) : value })] }, field));
2592
+ return (jsx(Grid, { rowGap: 1, padding: 1, overflow: "auto", ...boxProps, children: Object.entries(object).map(([field, value]) => {
2593
+ return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: "auto 1fr", children: [jsx(Text, { color: "gray.400", children: snakeToLabel(field) }), typeof value === "object" ? (jsx(RecordDisplay, { object: value })) : (jsx(Text, { children: JSON.stringify(value) }))] }, field));
702
2594
  }) }));
703
2595
  };
704
2596
 
@@ -2161,6 +4053,309 @@ const TagPicker = ({ column }) => {
2161
4053
  }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
2162
4054
  };
2163
4055
 
4056
+ function isEnteringWindow(_ref) {
4057
+ var dragEnter = _ref.dragEnter;
4058
+ var type = dragEnter.type,
4059
+ relatedTarget = dragEnter.relatedTarget;
4060
+ if (type !== 'dragenter') {
4061
+ return false;
4062
+ }
4063
+ if (isSafari()) {
4064
+ return isEnteringWindowInSafari({
4065
+ dragEnter: dragEnter
4066
+ });
4067
+ }
4068
+
4069
+ // standard check
4070
+ if (relatedTarget == null) {
4071
+ return true;
4072
+ }
4073
+
4074
+ /**
4075
+ * 🦊 Exception: `iframe` in Firefox (`125.0`)
4076
+ *
4077
+ * Case 1: parent `window` → child `iframe`
4078
+ * `relatedTarget` is the `iframe` element in the parent `window`
4079
+ * (foreign element)
4080
+ *
4081
+ * Case 2: child `iframe` → parent `window`
4082
+ * `relatedTarget` is an element inside the child `iframe`
4083
+ * (foreign element)
4084
+ */
4085
+
4086
+ if (isFirefox()) {
4087
+ return isFromAnotherWindow(relatedTarget);
4088
+ }
4089
+
4090
+ /**
4091
+ * 🌏 Exception: `iframe` in Chrome (`124.0`)
4092
+ *
4093
+ * Case 1: parent `window` → child `iframe`
4094
+ * `relatedTarget` is `null` *(standard check)*
4095
+ *
4096
+ * Case 2: child `iframe` → parent `window`
4097
+ * `relatedTarget` is the `iframe` element in the parent `window`
4098
+ */
4099
+
4100
+ // Case 2
4101
+ // Using `instanceof` check as the element will be in the same `window`
4102
+ return relatedTarget instanceof HTMLIFrameElement;
4103
+ }
4104
+
4105
+ function isAnAvailableType(_ref) {
4106
+ var type = _ref.type,
4107
+ value = _ref.value;
4108
+ // We don't want to expose our private elementAdapter key / value
4109
+ if (type === elementAdapterNativeDataKey) {
4110
+ return false;
4111
+ }
4112
+ // Not exposing "text/plain" if it contains the android fallback text
4113
+ // We _could_ add an `isAndroid()` check, but it's probably safest
4114
+ // to trim this data out, regardless of what OS we see it on.
4115
+ if (type === textMediaType && value === androidFallbackText) {
4116
+ return false;
4117
+ }
4118
+ return true;
4119
+ }
4120
+ function getAvailableTypes(transfer) {
4121
+ return Array.from(transfer.types).filter(function (type) {
4122
+ return isAnAvailableType({
4123
+ type: type,
4124
+ value: transfer.getData(type)
4125
+ });
4126
+ });
4127
+ }
4128
+ function getAvailableItems(dataTransfer) {
4129
+ // item.kind is 'string' | 'file'
4130
+ // For 'string' item.type is the mimeType (eg 'text/plain')
4131
+ // For 'file' item.type is the file type (eg 'image/jpg')
4132
+
4133
+ return Array.from(dataTransfer.items).filter(function (item) {
4134
+ return item.kind === 'file' || isAnAvailableType({
4135
+ type: item.type,
4136
+ value: dataTransfer.getData(item.type)
4137
+ });
4138
+ });
4139
+ }
4140
+ var didDragStartLocally = false;
4141
+ var adapter = makeAdapter({
4142
+ typeKey: 'external',
4143
+ // for external drags, we are generally making a copy of something that is being dragged
4144
+ defaultDropEffect: 'copy',
4145
+ mount: function mount(api) {
4146
+ // Binding to the `window` so that the element adapter
4147
+ // has a chance to get in first on the`document`.
4148
+ // We are giving preference to the element adapter.
4149
+ return bind(window, {
4150
+ type: 'dragenter',
4151
+ listener: function listener(event) {
4152
+ // drag operation was started within the document, it won't be an "external" drag
4153
+ if (didDragStartLocally) {
4154
+ return;
4155
+ }
4156
+
4157
+ // Note: not checking if event was cancelled (`event.defaultPrevented`) as
4158
+ // cancelling a "dragenter" accepts the drag operation (not prevent it)
4159
+
4160
+ // Something has gone wrong with our drag event
4161
+ if (!event.dataTransfer) {
4162
+ // Including this code on "test" and "development" environments:
4163
+ // - Browser tests commonly run against "development" builds
4164
+ // - Unit tests commonly run in "test"
4165
+ if (process.env.NODE_ENV !== 'production') {
4166
+ // eslint-disable-next-line no-console
4167
+ console.warn("\n It appears as though you have are not testing DragEvents correctly.\n\n - If you are unit testing, ensure you have polyfilled DragEvent.\n - If you are browser testing, ensure you are dispatching drag events correctly.\n\n Please see our testing guides for more information:\n https://atlassian.design/components/pragmatic-drag-and-drop/core-package/testing\n ".replace(/ {2}/g, ''));
4168
+ }
4169
+ return;
4170
+ }
4171
+ if (!api.canStart(event)) {
4172
+ return;
4173
+ }
4174
+ if (!isEnteringWindow({
4175
+ dragEnter: event
4176
+ })) {
4177
+ return;
4178
+ }
4179
+
4180
+ // Note: not checking types for `elementAdapterNativeDataKey` as we expect to see that
4181
+ // key when pdnd started the drag in another document
4182
+ var types = getAvailableTypes(event.dataTransfer);
4183
+ if (!types.length) {
4184
+ return;
4185
+ }
4186
+ var locked = {
4187
+ types: types,
4188
+ items: [],
4189
+ getStringData: function getStringData() {
4190
+ return null;
4191
+ }
4192
+ };
4193
+ api.start({
4194
+ event: event,
4195
+ dragType: {
4196
+ type: 'external',
4197
+ startedFrom: 'external',
4198
+ payload: locked,
4199
+ getDropPayload: function getDropPayload(event) {
4200
+ // this would be a platform error
4201
+ // trying to handle it gracefully rather than throwing (for now)
4202
+ if (!event.dataTransfer) {
4203
+ return locked;
4204
+ }
4205
+ var items = getAvailableItems(event.dataTransfer);
4206
+ // need to use `.bind` as `getData` is required
4207
+ // to be run with `event.dataTransfer` as the "this" context
4208
+ var nativeGetData = event.dataTransfer.getData.bind(event.dataTransfer);
4209
+ return {
4210
+ types: types,
4211
+ items: items,
4212
+ // return `null` if there is no result, otherwise string
4213
+ getStringData: function getStringData(mediaType) {
4214
+ // not dragging the requested type
4215
+ // return `null` (no result)
4216
+ if (!types.includes(mediaType)) {
4217
+ return null;
4218
+ }
4219
+
4220
+ // nativeGetData will return `""` when there is no value,
4221
+ // but at this point we know we will only get explicitly set
4222
+ // values back as we have checked the `types`.
4223
+ // `""` can be an explicitly set value.
4224
+ var value = nativeGetData(mediaType);
4225
+
4226
+ // not exposing data for unavailable types
4227
+ if (!isAnAvailableType({
4228
+ type: mediaType,
4229
+ value: value
4230
+ })) {
4231
+ return null;
4232
+ }
4233
+ return value;
4234
+ }
4235
+ };
4236
+ }
4237
+ }
4238
+ });
4239
+ }
4240
+ });
4241
+ }
4242
+ });
4243
+
4244
+ /**
4245
+ * Some events don't make sense for the external adapter
4246
+ *
4247
+ * `onGenerateDragPreview`
4248
+ * The browser creates the drag preview for external drags, so we don't
4249
+ * need an event to generate the preview for _monitors_ or the _dropTarget_
4250
+ *
4251
+ * `onDragStart`
4252
+ * An external drag can never start from in the `window`, so _dropTarget_'s
4253
+ * don't need `onDragStart`
4254
+ */
4255
+
4256
+ function dropTargetForExternal(args) {
4257
+ // not removing unused events, just leaning on the type system
4258
+ return adapter.dropTarget(args);
4259
+ }
4260
+ (function startup() {
4261
+ // server side rendering check
4262
+ if (typeof window === 'undefined') {
4263
+ return;
4264
+ }
4265
+
4266
+ // A shared single usage registration as we want to capture
4267
+ // all external drag operations, even if there are no drop targets
4268
+ // on the page yet
4269
+ adapter.registerUsage();
4270
+ // independent of pdnd, we need to keep track of
4271
+ // all drag operations so that we can know if a drag operation
4272
+ // has started locally
4273
+
4274
+ var idle = {
4275
+ type: 'idle'
4276
+ };
4277
+ var state = idle;
4278
+ function clear() {
4279
+ if (state.type !== 'dragging') {
4280
+ return;
4281
+ }
4282
+ didDragStartLocally = false;
4283
+ state.cleanup();
4284
+ state = idle;
4285
+ }
4286
+ function bindEndEvents() {
4287
+ return bindAll(window, [{
4288
+ type: 'dragend',
4289
+ listener: clear
4290
+ }].concat(_toConsumableArray(getBindingsForBrokenDrags({
4291
+ onDragEnd: clear
4292
+ }))),
4293
+ // we want to make sure we get all the events,
4294
+ // and this helps avoid not seeing events when folks stop
4295
+ // them later on the event path
4296
+ {
4297
+ capture: true
4298
+ });
4299
+ }
4300
+
4301
+ // we always keep this event listener active
4302
+ bind(window, {
4303
+ type: 'dragstart',
4304
+ listener: function listener() {
4305
+ // something bad has happened if this is true!
4306
+ if (state.type !== 'idle') {
4307
+ return;
4308
+ }
4309
+ // set our global flag
4310
+ didDragStartLocally = true;
4311
+ state = {
4312
+ type: 'dragging',
4313
+ cleanup: bindEndEvents()
4314
+ };
4315
+ },
4316
+ // binding in the capture phase so these listeners are called
4317
+ // before our listeners in the adapters `mount` function
4318
+ options: {
4319
+ capture: true
4320
+ }
4321
+ });
4322
+ })();
4323
+
4324
+ /** Common event payload for all events */
4325
+
4326
+ /** A map containing payloads for all events */
4327
+
4328
+ /** Common event payload for all drop target events */
4329
+
4330
+ /** A map containing payloads for all events on drop targets */
4331
+
4332
+ /** Arguments given to all feedback functions (eg `canDrop()`) on a `dropTargetForExternal` */
4333
+
4334
+ /** Arguments given to all monitor feedback functions (eg `canMonitor()`) for a `monitorForExternal` */
4335
+
4336
+ /** Obtain an array of the dragged `File`s */
4337
+ function getFiles(_ref2) {
4338
+ var source = _ref2.source;
4339
+ return source.items
4340
+ // unlike other media types, for files:
4341
+ // item.kind is 'file'
4342
+ // item.type is the type of file eg 'image/jpg'
4343
+ // for other media types, item.type is the mime format
4344
+ .filter(function (item) {
4345
+ return item.kind === 'file';
4346
+ }).map(function (item) {
4347
+ return item.getAsFile();
4348
+ }).filter(function (file) {
4349
+ return file != null;
4350
+ });
4351
+ }
4352
+
4353
+ /* Get the plain text that a user is dragging */
4354
+ function getText(_ref2) {
4355
+ var source = _ref2.source;
4356
+ return source.getStringData(textMediaType);
4357
+ }
4358
+
2164
4359
  const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }, placeholder = "Drop files here or click to upload", }) => {
2165
4360
  const ref = useRef(null);
2166
4361
  const [isDraggedOver, setIsDraggedOver] = useState(false);