@mirohq/design-system-dropdown-menu 4.4.8 → 4.4.10-dropdown-on-pointerup.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.
package/dist/module.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import React, { createContext, useState, useRef, useCallback, useContext, useMemo, useEffect } from 'react';
2
+ import React, { createContext, useState, useRef, useCallback, useContext, useEffect } from 'react';
3
3
  import * as RadixDropdownMenu from '@radix-ui/react-dropdown-menu';
4
4
  import { Portal as Portal$1 } from '@radix-ui/react-dropdown-menu';
5
5
  import { BaseTooltipProvider, useBaseTooltipContext } from '@mirohq/design-system-base-tooltip';
@@ -11,9 +11,11 @@ import { styled, theme } from '@mirohq/design-system-stitches';
11
11
  import { focus, animations } from '@mirohq/design-system-styles';
12
12
  import { Hotkey as Hotkey$1 } from '@mirohq/design-system-base-hotkey';
13
13
  import { useLayoutEffect } from '@mirohq/design-system-use-layout-effect';
14
+ import { useAriaDisabled as useAriaDisabled$1 } from '@mirohq/design-system-use-aria-disabled';
14
15
  import { ScrollArea } from '@mirohq/design-system-scroll-area';
15
16
  import { styles, Thumb } from '@mirohq/design-system-base-switch';
16
- import { isVirtualClick } from '@react-aria/utils';
17
+ import { mergeProps, isVirtualClick } from '@react-aria/utils';
18
+ import { usePress } from '@mirohq/design-system-use-press';
17
19
  import { styles as styles$1, isIconComponent } from '@mirohq/design-system-base-icon';
18
20
 
19
21
  const ItemDescription = styled(Primitive.div, {
@@ -247,29 +249,24 @@ const RightSlot = (props) => {
247
249
  return /* @__PURE__ */ jsx(StyledRightSlot, { ref, ...props });
248
250
  };
249
251
 
250
- const useAriaDisabled = ({
251
- "aria-disabled": ariaDisabled,
252
- onKeyDown,
253
- onSelect,
254
- onPointerMove,
255
- onClick
256
- }, closeOnCheck = true) => useMemo(
257
- () => ({
258
- "aria-disabled": booleanify(ariaDisabled) ? ariaDisabled : void 0,
259
- onKeyDown: (e) => {
260
- if (booleanify(ariaDisabled) && e.code !== "ArrowUp" && e.code !== "ArrowDown" && e.code !== "Escape") {
261
- e.preventDefault();
262
- e.stopPropagation();
263
- return;
264
- }
265
- onKeyDown == null ? void 0 : onKeyDown(e);
266
- },
252
+ const useAriaDisabled = ({ onSelect, ...restProps }, { exceptions, closeOnSelect = true } = {}) => {
253
+ const elementProps = useAriaDisabled$1(restProps, {
254
+ ...exceptions,
255
+ allowArrows: true
256
+ });
257
+ const { "aria-disabled": ariaDisabled, onPointerMove, onClick } = elementProps;
258
+ return {
259
+ ...elementProps,
260
+ // these events need to be manually included
261
+ // bacause useAriaDisabled only removes the events from the props.
262
+ // Radix uses these events to handle the dropdown menu so we need to prevent
263
+ // it from being called when the item is aria-disabled.
267
264
  onSelect: (e) => {
268
265
  if (booleanify(ariaDisabled)) {
269
266
  e.preventDefault();
270
267
  return;
271
268
  }
272
- if (!closeOnCheck) {
269
+ if (!closeOnSelect) {
273
270
  e.preventDefault();
274
271
  }
275
272
  onSelect == null ? void 0 : onSelect(e);
@@ -288,9 +285,8 @@ const useAriaDisabled = ({
288
285
  }
289
286
  onClick == null ? void 0 : onClick(e);
290
287
  }
291
- }),
292
- [ariaDisabled, onKeyDown, onSelect, onPointerMove, onClick, closeOnCheck]
293
- );
288
+ };
289
+ };
294
290
 
295
291
  const Context = createContext({
296
292
  leftSlotMount: () => {
@@ -334,16 +330,15 @@ const CheckboxItem = React.forwardRef(
334
330
  variant = "ghost",
335
331
  ...restProps
336
332
  }, forwardRef) => {
337
- const ariaDisabledProps = useAriaDisabled(restProps, closeOnSelect);
338
- const { "aria-disabled": ariaDisabled } = ariaDisabledProps;
333
+ const elementProps = useAriaDisabled(restProps, { closeOnSelect });
334
+ const { "aria-disabled": ariaDisabled } = restProps;
339
335
  const iconCss = { square: "100%", display: "block" };
340
336
  const isAriaDisabled = booleanify(ariaDisabled != null ? ariaDisabled : false);
341
337
  const disabledUnchecked = (disabled === true || isAriaDisabled) && checked === false;
342
338
  return /* @__PURE__ */ jsx(ItemProvider, { children: /* @__PURE__ */ jsxs(
343
339
  StyledCheckboxItem,
344
340
  {
345
- ...restProps,
346
- ...ariaDisabledProps,
341
+ ...elementProps,
347
342
  ref: forwardRef,
348
343
  checked,
349
344
  disabled,
@@ -460,16 +455,25 @@ const ScrollableContent = ({
460
455
  const DropdownContext = createContext({});
461
456
  const DropdownProvider = ({
462
457
  children,
458
+ open: rootOpen,
463
459
  ...restProps
464
- }) => /* @__PURE__ */ jsx(
465
- DropdownContext.Provider,
466
- {
467
- value: {
468
- ...restProps
469
- },
470
- children
471
- }
472
- );
460
+ }) => {
461
+ const [open, setOpen] = useState(rootOpen);
462
+ const triggerRef = useRef(null);
463
+ return /* @__PURE__ */ jsx(
464
+ DropdownContext.Provider,
465
+ {
466
+ value: {
467
+ ...restProps,
468
+ rootOpen,
469
+ open,
470
+ setOpen,
471
+ triggerRef
472
+ },
473
+ children
474
+ }
475
+ );
476
+ };
473
477
  const useDropdownContext = () => useContext(DropdownContext);
474
478
 
475
479
  const Content = React.forwardRef(
@@ -486,10 +490,11 @@ const Content = React.forwardRef(
486
490
  containerSpacing = "medium",
487
491
  overflow = "visible",
488
492
  maxHeight,
493
+ onInteractOutside,
489
494
  children,
490
495
  ...restProps
491
496
  }, forwardRef) => {
492
- const { direction } = useDropdownContext();
497
+ const { direction, triggerRef } = useDropdownContext();
493
498
  return /* @__PURE__ */ jsx(ContentProvider, { containerSpacing, children: /* @__PURE__ */ jsx(
494
499
  StyledContent,
495
500
  {
@@ -504,6 +509,12 @@ const Content = React.forwardRef(
504
509
  collisionPadding,
505
510
  sticky,
506
511
  hideWhenDetached,
512
+ onInteractOutside: (e) => {
513
+ if (e.target === triggerRef.current) {
514
+ e.preventDefault();
515
+ }
516
+ onInteractOutside == null ? void 0 : onInteractOutside(e);
517
+ },
507
518
  children: /* @__PURE__ */ jsx(
508
519
  ScrollableContent,
509
520
  {
@@ -549,12 +560,11 @@ const StyledItem = styled(RadixDropdownMenu.Item, {
549
560
 
550
561
  const Item = React.forwardRef(
551
562
  ({ disabled = false, variant = "subtle", ...restProps }, forwardRef) => {
552
- const ariaDisabledProps = useAriaDisabled(restProps);
563
+ const elementProps = useAriaDisabled(restProps);
553
564
  return /* @__PURE__ */ jsx(ItemProvider, { children: /* @__PURE__ */ jsx(
554
565
  StyledItem,
555
566
  {
556
- ...restProps,
557
- ...ariaDisabledProps,
567
+ ...elementProps,
558
568
  variant,
559
569
  disabled,
560
570
  ref: forwardRef
@@ -563,10 +573,7 @@ const Item = React.forwardRef(
563
573
  }
564
574
  );
565
575
 
566
- const LinkItem = React.forwardRef(({ children, href, ...restProps }, forwardRef) => {
567
- const ariaDisabledProps = useAriaDisabled(restProps);
568
- return /* @__PURE__ */ jsx(Item, { asChild: true, ref: forwardRef, ...restProps, ...ariaDisabledProps, children: /* @__PURE__ */ jsx("a", { href, children }) });
569
- });
576
+ const LinkItem = React.forwardRef(({ children, href, ...restProps }, forwardRef) => /* @__PURE__ */ jsx(Item, { asChild: true, ref: forwardRef, ...restProps, children: /* @__PURE__ */ jsx("a", { href, children }) }));
570
577
 
571
578
  const StyledRadioGroup = styled(RadixDropdownMenu.RadioGroup, {
572
579
  display: "grid",
@@ -636,23 +643,16 @@ const StyledRadioItem = styled(RadixDropdownMenu.RadioItem, {
636
643
  });
637
644
 
638
645
  const RadioItem = React.forwardRef(({ disabled, children, closeOnSelect = false, ...restProps }, forwardRef) => {
639
- const ariaDisabledProps = useAriaDisabled(restProps, closeOnSelect);
640
- return /* @__PURE__ */ jsx(ItemProvider, { children: /* @__PURE__ */ jsxs(
641
- StyledRadioItem,
642
- {
643
- ...restProps,
644
- ...ariaDisabledProps,
645
- disabled,
646
- ref: forwardRef,
647
- children: [
648
- children,
649
- /* @__PURE__ */ jsx(RightSlot, { children: /* @__PURE__ */ jsxs(StyledRadioContainer, { children: [
650
- /* @__PURE__ */ jsx(StyledPill, {}),
651
- /* @__PURE__ */ jsx(StyledProhibited, { weight: "thin" })
652
- ] }) })
653
- ]
654
- }
655
- ) });
646
+ const elementProps = useAriaDisabled(restProps, {
647
+ closeOnSelect
648
+ });
649
+ return /* @__PURE__ */ jsx(ItemProvider, { children: /* @__PURE__ */ jsxs(StyledRadioItem, { ...elementProps, disabled, ref: forwardRef, children: [
650
+ children,
651
+ /* @__PURE__ */ jsx(RightSlot, { children: /* @__PURE__ */ jsxs(StyledRadioContainer, { children: [
652
+ /* @__PURE__ */ jsx(StyledPill, {}),
653
+ /* @__PURE__ */ jsx(StyledProhibited, { weight: "thin" })
654
+ ] }) })
655
+ ] }) });
656
656
  });
657
657
 
658
658
  const StyledSeparator = styled(RadixDropdownMenu.Separator, {
@@ -679,16 +679,15 @@ const SwitchItem = React.forwardRef(
679
679
  disabled,
680
680
  checked,
681
681
  onChange,
682
- children,
683
682
  closeOnSelect = false,
683
+ children,
684
684
  ...restProps
685
685
  }, forwardRef) => {
686
- const ariaDisabledProps = useAriaDisabled(restProps, closeOnSelect);
686
+ const elementProps = useAriaDisabled(restProps, { closeOnSelect });
687
687
  return /* @__PURE__ */ jsx(ItemProvider, { children: /* @__PURE__ */ jsxs(
688
688
  StyledSwitchItem,
689
689
  {
690
- ...restProps,
691
- ...ariaDisabledProps,
690
+ ...elementProps,
692
691
  disabled,
693
692
  checked,
694
693
  onCheckedChange: onChange,
@@ -721,8 +720,9 @@ const StyledTrigger = styled(RadixDropdownMenu.Trigger, {
721
720
  }
722
721
  });
723
722
 
724
- const Trigger = React.forwardRef(({ asChild = false, onClick, ...restProps }, forwardRef) => {
723
+ const Trigger = React.forwardRef(({ asChild = false, ...restProps }, forwardRef) => {
725
724
  const ref = useRef(null);
725
+ const { setOpen, rootOpen, triggerRef } = useDropdownContext();
726
726
  const handleVirtualClick = (e) => {
727
727
  var _a;
728
728
  if ((e == null ? void 0 : e.nativeEvent) === void 0) {
@@ -743,15 +743,40 @@ const Trigger = React.forwardRef(({ asChild = false, onClick, ...restProps }, fo
743
743
  (_a = ref.current) == null ? void 0 : _a.dispatchEvent(pointerDownEvent);
744
744
  }
745
745
  };
746
+ const { pressProps } = usePress({
747
+ onPress: () => {
748
+ if (rootOpen === void 0) {
749
+ setOpen((open) => !booleanify(open));
750
+ }
751
+ }
752
+ });
753
+ const elementProps = mergeProps(restProps, pressProps);
746
754
  return /* @__PURE__ */ jsx(
747
755
  StyledTrigger,
748
756
  {
749
- ...restProps,
757
+ ...elementProps,
750
758
  onClick: (e) => {
759
+ var _a, _b;
751
760
  handleVirtualClick(e);
752
- onClick == null ? void 0 : onClick(e);
761
+ if (e instanceof MouseEvent) {
762
+ e.preventDefault();
763
+ (_a = elementProps.onClick) == null ? void 0 : _a.call(elementProps, e);
764
+ } else {
765
+ (_b = restProps.onClick) == null ? void 0 : _b.call(restProps, e);
766
+ }
753
767
  },
754
- ref: mergeRefs([ref, forwardRef]),
768
+ onKeyDown: (e) => {
769
+ var _a, _b;
770
+ if ((e == null ? void 0 : e.nativeEvent) instanceof KeyboardEvent) {
771
+ if (!/^(Arrow|Tab|Escape)/.test(e.key)) {
772
+ e.preventDefault();
773
+ }
774
+ (_a = elementProps.onKeyDown) == null ? void 0 : _a.call(elementProps, e);
775
+ } else {
776
+ (_b = restProps.onKeyDown) == null ? void 0 : _b.call(restProps, e);
777
+ }
778
+ },
779
+ ref: mergeRefs([ref, triggerRef, forwardRef]),
755
780
  unstyled: !asChild,
756
781
  asChild
757
782
  }
@@ -772,29 +797,18 @@ const StyledSubTrigger = styled(RadixDropdownMenu.SubTrigger, {
772
797
  });
773
798
 
774
799
  const SubTrigger = React.forwardRef(({ children, disabled = false, ...restProps }, forwardRef) => {
775
- const { onSelect, ...ariaDisabledProps } = useAriaDisabled({
776
- onKeyDown: restProps.onKeyDown,
777
- "aria-disabled": restProps["aria-disabled"]
778
- });
779
- return /* @__PURE__ */ jsxs(
780
- StyledSubTrigger,
781
- {
782
- ...restProps,
783
- ...ariaDisabledProps,
784
- disabled,
785
- ref: forwardRef,
786
- children: [
787
- children,
788
- /* @__PURE__ */ jsx(RightSlot, { children: /* @__PURE__ */ jsx(
789
- StyledIconContainer,
790
- {
791
- "data-testid": process.env.NODE_ENV === "test" ? "submenu-arrow-icon" : void 0,
792
- children: /* @__PURE__ */ jsx(IconChevronRight, { size: "small", weight: "thin" })
793
- }
794
- ) })
795
- ]
796
- }
797
- );
800
+ let { onSelect, ...elementProps } = restProps;
801
+ elementProps = useAriaDisabled(elementProps);
802
+ return /* @__PURE__ */ jsxs(StyledSubTrigger, { ...elementProps, disabled, ref: forwardRef, children: [
803
+ children,
804
+ /* @__PURE__ */ jsx(RightSlot, { children: /* @__PURE__ */ jsx(
805
+ StyledIconContainer,
806
+ {
807
+ "data-testid": process.env.NODE_ENV === "test" ? "submenu-arrow-icon" : void 0,
808
+ children: /* @__PURE__ */ jsx(IconChevronRight, { size: "small", weight: "thin" })
809
+ }
810
+ ) })
811
+ ] });
798
812
  });
799
813
 
800
814
  const StyledSubContent = styled(
@@ -913,39 +927,52 @@ const Root = ({
913
927
  defaultOpen = false,
914
928
  direction,
915
929
  interactOutside = false,
916
- open,
917
930
  onOpen,
918
931
  onClose,
919
932
  ...restProps
920
933
  }) => {
921
934
  const { ignoreNextTooltip } = useBaseTooltipContext();
935
+ const { rootOpen, open, setOpen } = useDropdownContext();
922
936
  const prevOpen = usePrevious(open);
923
937
  useEffect(() => {
924
- if (prevOpen === true && open === false) {
925
- ignoreNextTooltip();
938
+ if (prevOpen !== open) {
939
+ if (open === true) {
940
+ onOpen == null ? void 0 : onOpen();
941
+ } else {
942
+ if (prevOpen === true) {
943
+ ignoreNextTooltip();
944
+ }
945
+ onClose == null ? void 0 : onClose();
946
+ }
926
947
  }
927
- }, [ignoreNextTooltip, open, prevOpen]);
948
+ }, [open, prevOpen, onOpen, onClose, ignoreNextTooltip]);
928
949
  return /* @__PURE__ */ jsx(
929
950
  RadixDropdownMenu.Root,
930
951
  {
931
952
  ...restProps,
932
953
  dir: direction,
933
954
  modal: interactOutside,
934
- open,
955
+ open: (
956
+ // use the root open state if it is defined
957
+ rootOpen != null ? rootOpen : defaultOpen && (prevOpen === void 0 || prevOpen === open) ? (
958
+ // only use defaultOpen in the first render then use the context open state
959
+ // if the open state is the same as the previous one, it is most likely a re-render and we should still use the defaultOpen
960
+ void 0
961
+ ) : (
962
+ // otherwise, use the user open state
963
+ open
964
+ )
965
+ ),
935
966
  defaultOpen,
936
- onOpenChange: (newOpen) => {
937
- if (!newOpen && open === void 0) {
938
- ignoreNextTooltip();
939
- }
940
- newOpen ? onOpen == null ? void 0 : onOpen() : onClose == null ? void 0 : onClose();
941
- }
967
+ onOpenChange: setOpen
942
968
  }
943
969
  );
944
970
  };
945
971
  const DropdownMenu = ({
946
972
  direction = "ltr",
973
+ open,
947
974
  ...restProps
948
- }) => /* @__PURE__ */ jsx(DropdownProvider, { direction, children: /* @__PURE__ */ jsx(BaseTooltipProvider, { children: /* @__PURE__ */ jsx(Root, { direction, ...restProps }) }) });
975
+ }) => /* @__PURE__ */ jsx(DropdownProvider, { direction, open, children: /* @__PURE__ */ jsx(BaseTooltipProvider, { children: /* @__PURE__ */ jsx(Root, { direction, ...restProps }) }) });
949
976
  DropdownMenu.CheckboxItem = CheckboxItem;
950
977
  DropdownMenu.Content = Content;
951
978
  DropdownMenu.Hotkey = Hotkey;