@mirohq/design-system-dropdown-menu 3.3.0-dropdown.4 → 3.3.0-dropdown.6

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,12 +1,13 @@
1
- import React, { useMemo, useState } from 'react';
1
+ import React, { createContext, useState, useRef, useCallback, useContext, useEffect, useMemo } from 'react';
2
2
  import * as RadixDropdownMenu from '@radix-ui/react-dropdown-menu';
3
3
  import { Portal as Portal$1 } from '@radix-ui/react-dropdown-menu';
4
- import { IconProhibit, IconCheckMark, IconChevronRight, isIconComponent } from '@mirohq/design-system-icons';
5
- import { booleanify } from '@mirohq/design-system-utils';
4
+ import { IconProhibit, IconCheckMark, IconChevronRight } from '@mirohq/design-system-icons';
5
+ import { addPropsToChildren, booleanify } from '@mirohq/design-system-utils';
6
6
  import { Primitive } from '@mirohq/design-system-primitive';
7
7
  import { styled, theme } from '@mirohq/design-system-stitches';
8
8
  import { focus, animations } from '@mirohq/design-system-styles';
9
9
  import { styles, Thumb } from '@mirohq/design-system-base-switch';
10
+ import { isIconComponent } from '@mirohq/design-system-base-icon';
10
11
 
11
12
  const ItemDescription = styled(Primitive.div, {
12
13
  display: "-webkit-box",
@@ -19,23 +20,140 @@ const ItemDescription = styled(Primitive.div, {
19
20
  color: "$text-neutrals-subtle"
20
21
  });
21
22
 
23
+ const Context$1 = createContext({
24
+ rightSlotMount: () => 0,
25
+ rightSlotDestroy: () => {
26
+ }
27
+ });
28
+ const ContentProvider = ({
29
+ children
30
+ }) => {
31
+ const [maxWidth, setMaxWidth] = useState(0);
32
+ const maxRef = useRef(0);
33
+ const indexRef = useRef(0);
34
+ const widthMapRef = useRef(/* @__PURE__ */ new Map());
35
+ const updateMaxWith = useCallback((value) => {
36
+ maxRef.current = value;
37
+ setMaxWidth(value);
38
+ }, []);
39
+ const rightSlotMount = useCallback(
40
+ (width) => {
41
+ indexRef.current++;
42
+ widthMapRef.current.set(indexRef.current, width);
43
+ if (width > maxRef.current) {
44
+ updateMaxWith(width);
45
+ }
46
+ return indexRef.current;
47
+ },
48
+ [updateMaxWith]
49
+ );
50
+ const rightSlotDestroy = useCallback(
51
+ (index) => {
52
+ widthMapRef.current.delete(index);
53
+ if (widthMapRef.current.size === 0) {
54
+ updateMaxWith(0);
55
+ } else {
56
+ const maximum = Math.max(...Array.from(widthMapRef.current.values()));
57
+ updateMaxWith(maximum);
58
+ }
59
+ },
60
+ [updateMaxWith]
61
+ );
62
+ const formattedChildren = addPropsToChildren(children, () => true, {
63
+ UNSAFE_style: {
64
+ "--right-slot-max-width": `${Math.ceil(maxWidth)}px`
65
+ }
66
+ });
67
+ return /* @__PURE__ */ React.createElement(Context$1.Provider, {
68
+ value: {
69
+ rightSlotMount,
70
+ rightSlotDestroy
71
+ }
72
+ }, formattedChildren);
73
+ };
74
+ const useContent = () => useContext(Context$1);
75
+
22
76
  const LeftSlot = styled(Primitive.div, {
23
77
  display: "flex",
24
78
  placeContent: "center",
25
79
  marginRight: "$100",
26
80
  gridArea: "left-slot"
27
81
  });
28
- const IllustrationSlot = styled(LeftSlot, {
82
+ const StyledIllustrationSlot = styled(LeftSlot, {
29
83
  width: "$13"
30
84
  });
31
- const RightSlot = styled(Primitive.div, {
85
+ const StyledRightSlot = styled(Primitive.div, {
32
86
  display: "flex",
33
87
  alignItems: "center",
34
88
  marginLeft: "auto",
35
89
  paddingLeft: "$200",
36
- gridArea: "right-slot"
90
+ gridArea: "right-slot",
91
+ minWidth: "max-content",
92
+ textAlign: "right",
93
+ "&:empty": {
94
+ paddingLeft: "$none"
95
+ }
96
+ });
97
+
98
+ const Context = createContext({
99
+ leftSlotMount: () => {
100
+ },
101
+ leftSlotDestroy: () => {
102
+ }
103
+ });
104
+ const ItemProvider = ({
105
+ children
106
+ }) => {
107
+ const [hasSlot, setHasSlot] = useState(false);
108
+ const leftSlotMount = useCallback(() => {
109
+ setHasSlot(true);
110
+ }, []);
111
+ const leftSlotDestroy = useCallback(() => {
112
+ setHasSlot(false);
113
+ }, []);
114
+ const formattedChildren = hasSlot ? children : addPropsToChildren(children, () => true, {
115
+ "data-no-left-slot": ""
116
+ });
117
+ return /* @__PURE__ */ React.createElement(Context.Provider, {
118
+ value: {
119
+ leftSlotMount,
120
+ leftSlotDestroy
121
+ }
122
+ }, formattedChildren);
123
+ };
124
+ const useItem = () => useContext(Context);
125
+
126
+ const RightSlot = (props) => {
127
+ const { rightSlotMount, rightSlotDestroy } = useContent();
128
+ const ref = useRef(null);
129
+ useEffect(() => {
130
+ if (ref.current !== null) {
131
+ const width = ref.current.getBoundingClientRect().width;
132
+ const index = rightSlotMount(width);
133
+ return () => rightSlotDestroy(index);
134
+ }
135
+ return () => {
136
+ };
137
+ }, [rightSlotMount, rightSlotDestroy, ref]);
138
+ return /* @__PURE__ */ React.createElement(StyledRightSlot, {
139
+ ref,
140
+ ...props
141
+ });
142
+ };
143
+ const HotkeySlot = styled(RightSlot, {
144
+ color: "$text-neutrals-subtle"
145
+ });
146
+ const IllustrationSlot = React.forwardRef((props, forwardRef) => {
147
+ const { leftSlotMount, leftSlotDestroy } = useItem();
148
+ useEffect(() => {
149
+ leftSlotMount();
150
+ return () => leftSlotDestroy();
151
+ }, [leftSlotMount, leftSlotDestroy]);
152
+ return /* @__PURE__ */ React.createElement(StyledIllustrationSlot, {
153
+ ref: forwardRef,
154
+ ...props
155
+ });
37
156
  });
38
- const HotkeySlot = RightSlot;
39
157
 
40
158
  const itemDefaults = {
41
159
  all: "unset",
@@ -45,18 +163,28 @@ const itemDefaults = {
45
163
  color: "$text-neutrals",
46
164
  borderRadius: "$50",
47
165
  display: "grid",
48
- gridTemplateColumns: "auto 1fr auto",
166
+ gridTemplateColumns: "auto 1fr minmax(auto, var(--right-slot-max-width))",
49
167
  gridTemplateRows: "1fr auto",
50
- gridTemplateAreas: `
51
- 'left-slot item-text right-slot'
52
- 'left-slot item-description right-slot'
53
- `,
54
- alignItems: "center",
55
- minHeight: "$11",
56
- padding: "$100 $150",
168
+ gridTemplateAreas: `'left-slot item-text right-slot'
169
+ 'left-slot item-description right-slot'`,
170
+ alignItems: "start",
171
+ minHeight: "$10",
172
+ padding: "$100 $100",
57
173
  position: "relative",
58
174
  userSelect: "none",
59
175
  cursor: "pointer",
176
+ "&[data-no-left-slot]": {
177
+ gridTemplateColumns: "1fr minmax(auto, var(--right-slot-max-width))",
178
+ gridTemplateRows: "auto",
179
+ gridTemplateAreas: `'item-text right-slot'
180
+ 'item-description right-slot'`
181
+ },
182
+ "&:not(:last-child)": {
183
+ marginBottom: "$50"
184
+ },
185
+ "&:not(:first-child)": {
186
+ marginTop: "$50"
187
+ },
60
188
  ...focus.defaults,
61
189
  '&:disabled, &[aria-disabled="true"], &[data-disabled]': {
62
190
  pointerEvents: "none",
@@ -84,7 +212,9 @@ const itemDefaults = {
84
212
  }
85
213
  };
86
214
 
87
- const StyledIndicator = styled(Primitive.span, {});
215
+ const StyledIndicator = styled(Primitive.span, {
216
+ padding: "4px 6px"
217
+ });
88
218
  const StyledCheckboxItem = styled(RadixDropdownMenu.CheckboxItem, {
89
219
  ...itemDefaults,
90
220
  [`&[data-state="checked"] ${StyledIndicator}`]: {
@@ -128,7 +258,7 @@ const useAriaDisabled = ({ "aria-disabled": ariaDisabled, onKeyDown, onSelect },
128
258
  const CheckboxItem = React.forwardRef(({ children, checked, onChange, disabled, ...restProps }, forwardRef) => {
129
259
  const ariaDisabledProps = useAriaDisabled(restProps, true);
130
260
  const { "aria-disabled": ariaDisabled } = ariaDisabledProps;
131
- return /* @__PURE__ */ React.createElement(StyledCheckboxItem, {
261
+ return /* @__PURE__ */ React.createElement(ItemProvider, null, /* @__PURE__ */ React.createElement(StyledCheckboxItem, {
132
262
  ...restProps,
133
263
  ...ariaDisabledProps,
134
264
  ref: forwardRef,
@@ -138,26 +268,17 @@ const CheckboxItem = React.forwardRef(({ children, checked, onChange, disabled,
138
268
  }, children, /* @__PURE__ */ React.createElement(RightSlot, null, /* @__PURE__ */ React.createElement(StyledIndicator, null, (disabled === true || booleanify(ariaDisabled)) && !checked && /* @__PURE__ */ React.createElement(IconProhibit, {
139
269
  size: "small"
140
270
  }), checked && /* @__PURE__ */ React.createElement(IconCheckMark, {
141
- size: "small"
142
- }))));
271
+ css: { width: "12px", display: "block" }
272
+ })))));
143
273
  });
144
274
 
145
- const GUTTER_TOKEN = 150;
146
- const CONTENT_GUTTER = parseInt(theme.space[GUTTER_TOKEN]);
275
+ const CONTENT_GUTTER = parseInt(theme.space[150]);
147
276
  const CONTENT_OFFSET = parseInt(theme.space[50]);
148
- const ITEM_WITHOUT_RIGHT_SLOT = `[role="menuitem"]:not(:has(${RightSlot}))`;
149
277
  const contentDefaults = {
150
278
  maxWidth: "$125",
151
279
  backgroundColor: "$white",
152
280
  borderRadius: "$50",
153
- padding: `$${GUTTER_TOKEN}`,
154
281
  boxShadow: "$50",
155
- [`&:has(${RightSlot}) > ${ITEM_WITHOUT_RIGHT_SLOT}`]: {
156
- paddingRight: "44px"
157
- },
158
- [`&:has([role="switch"]) > ${ITEM_WITHOUT_RIGHT_SLOT}`]: {
159
- paddingRight: "56px"
160
- },
161
282
  "@media (prefers-reduced-motion: no-preference)": {
162
283
  animationDuration: "150ms",
163
284
  animationTimingFunction: "cubic-bezier(0.25, 0.5, 0.5, 0.9)",
@@ -189,7 +310,28 @@ const contentDefaults = {
189
310
  zIndex: "$dropdownMenu"
190
311
  };
191
312
 
192
- const StyledContent = styled(RadixDropdownMenu.Content, contentDefaults);
313
+ const StyledContent = styled(RadixDropdownMenu.Content, {
314
+ ...contentDefaults,
315
+ variants: {
316
+ containerSpacing: {
317
+ small: {
318
+ '&, [role="menu"]': {
319
+ padding: "$50 $150"
320
+ }
321
+ },
322
+ medium: {
323
+ '&, [role="menu"]': {
324
+ padding: "$150"
325
+ }
326
+ },
327
+ large: {
328
+ '&, [role="menu"]': {
329
+ padding: "$150 $300"
330
+ }
331
+ }
332
+ }
333
+ }
334
+ });
193
335
 
194
336
  const Content = React.forwardRef(
195
337
  ({
@@ -202,8 +344,9 @@ const Content = React.forwardRef(
202
344
  avoidCollisions = true,
203
345
  sticky = "partial",
204
346
  hideWhenDetached = false,
347
+ containerSpacing = "medium",
205
348
  ...restProps
206
- }, forwardRef) => /* @__PURE__ */ React.createElement(StyledContent, {
349
+ }, forwardRef) => /* @__PURE__ */ React.createElement(ContentProvider, null, /* @__PURE__ */ React.createElement(StyledContent, {
207
350
  ...restProps,
208
351
  ref: forwardRef,
209
352
  loop,
@@ -214,21 +357,31 @@ const Content = React.forwardRef(
214
357
  avoidCollisions,
215
358
  collisionPadding,
216
359
  sticky,
217
- hideWhenDetached
218
- })
360
+ hideWhenDetached,
361
+ containerSpacing
362
+ }))
219
363
  );
220
364
 
221
- const StyledItem = styled(RadixDropdownMenu.Item, itemDefaults);
365
+ const StyledItem = styled(RadixDropdownMenu.Item, {
366
+ ...itemDefaults,
367
+ variants: {
368
+ hasRightSlot: {
369
+ true: {
370
+ paddingRight: "$600"
371
+ }
372
+ }
373
+ }
374
+ });
222
375
 
223
376
  const Item = React.forwardRef(
224
377
  ({ disabled = false, ...restProps }, forwardRef) => {
225
378
  const ariaDisabledProps = useAriaDisabled(restProps);
226
- return /* @__PURE__ */ React.createElement(StyledItem, {
379
+ return /* @__PURE__ */ React.createElement(ItemProvider, null, /* @__PURE__ */ React.createElement(StyledItem, {
227
380
  ...restProps,
228
381
  ...ariaDisabledProps,
229
382
  disabled,
230
383
  ref: forwardRef
231
- });
384
+ }));
232
385
  }
233
386
  );
234
387
 
@@ -244,7 +397,9 @@ const LinkItem = React.forwardRef(({ children, href, ...restProps }, forwardRef)
244
397
  }, children));
245
398
  });
246
399
 
247
- const StyledRadioGroup = styled(RadixDropdownMenu.RadioGroup);
400
+ const StyledRadioGroup = styled(RadixDropdownMenu.RadioGroup, {
401
+ marginY: "$50"
402
+ });
248
403
 
249
404
  const RadioGroup = React.forwardRef((props, forwardRef) => {
250
405
  const { onChange, ...restProps } = props;
@@ -263,7 +418,8 @@ const StyledRadioContainer = styled(Primitive.span, {
263
418
  height: "$4",
264
419
  boxSizing: "border-box",
265
420
  border: "1px solid $border-neutrals",
266
- borderRadius: "$half"
421
+ borderRadius: "$half",
422
+ marginTop: "2px"
267
423
  });
268
424
  const StyledPill = styled(Primitive.span, {
269
425
  display: "none",
@@ -313,17 +469,16 @@ const StyledRadioItem = styled(RadixDropdownMenu.RadioItem, {
313
469
 
314
470
  const RadioItem = React.forwardRef(({ disabled = false, children, ...restProps }, forwardRef) => {
315
471
  const ariaDisabledProps = useAriaDisabled(restProps, true);
316
- return /* @__PURE__ */ React.createElement(StyledRadioItem, {
472
+ return /* @__PURE__ */ React.createElement(ItemProvider, null, /* @__PURE__ */ React.createElement(StyledRadioItem, {
317
473
  ...restProps,
318
474
  ...ariaDisabledProps,
319
475
  disabled,
320
476
  ref: forwardRef
321
- }, children, /* @__PURE__ */ React.createElement(RightSlot, null, /* @__PURE__ */ React.createElement(StyledRadioContainer, null, /* @__PURE__ */ React.createElement(StyledPill, null), /* @__PURE__ */ React.createElement(StyledProhibited, null))));
477
+ }, children, /* @__PURE__ */ React.createElement(RightSlot, null, /* @__PURE__ */ React.createElement(StyledRadioContainer, null, /* @__PURE__ */ React.createElement(StyledPill, null), /* @__PURE__ */ React.createElement(StyledProhibited, null)))));
322
478
  });
323
479
 
324
480
  const StyledSeparator = styled(RadixDropdownMenu.Separator, {
325
- borderTop: "1px solid $border-neutrals-subtle",
326
- marginY: "$100"
481
+ borderTop: "1px solid $border-neutrals-subtle"
327
482
  });
328
483
 
329
484
  const Separator = React.forwardRef((props, forwardRef) => /* @__PURE__ */ React.createElement(StyledSeparator, {
@@ -334,7 +489,8 @@ const Separator = React.forwardRef((props, forwardRef) => /* @__PURE__ */ React.
334
489
  const StyledSwitch = styled(Primitive.span, {
335
490
  ...styles.default,
336
491
  width: "$7",
337
- height: "$4"
492
+ height: "$4",
493
+ marginTop: "2px"
338
494
  });
339
495
  const StyledSwitchItem = styled(RadixDropdownMenu.CheckboxItem, {
340
496
  ...itemDefaults,
@@ -350,30 +506,29 @@ const StyledSwitchItem = styled(RadixDropdownMenu.CheckboxItem, {
350
506
  const SwitchItem = React.forwardRef(
351
507
  ({ disabled = false, checked, onChange, children, ...restProps }, forwardRef) => {
352
508
  const ariaDisabledProps = useAriaDisabled(restProps, true);
353
- return /* @__PURE__ */ React.createElement(StyledSwitchItem, {
509
+ return /* @__PURE__ */ React.createElement(ItemProvider, null, /* @__PURE__ */ React.createElement(StyledSwitchItem, {
354
510
  ...restProps,
355
511
  ...ariaDisabledProps,
356
512
  disabled,
357
513
  checked,
358
514
  onCheckedChange: onChange,
359
515
  ref: forwardRef
360
- }, children, /* @__PURE__ */ React.createElement(RightSlot, null, /* @__PURE__ */ React.createElement(StyledSwitch, null, /* @__PURE__ */ React.createElement(Thumb, null))));
516
+ }, children, /* @__PURE__ */ React.createElement(RightSlot, null, /* @__PURE__ */ React.createElement(StyledSwitch, null, /* @__PURE__ */ React.createElement(Thumb, null)))));
361
517
  }
362
518
  );
363
519
 
364
- const defaultStyles = {
365
- boxSizing: "border-box",
366
- cursor: "pointer",
367
- ...focus.defaults
368
- };
369
520
  const StyledTrigger = styled(RadixDropdownMenu.Trigger, {
370
521
  variants: {
371
522
  unstyled: {
372
523
  true: {
373
524
  all: "unset",
374
- ...defaultStyles
525
+ boxSizing: "border-box",
526
+ cursor: "pointer",
527
+ ...focus.defaults
375
528
  },
376
- false: defaultStyles
529
+ false: {
530
+ cursor: "pointer"
531
+ }
377
532
  }
378
533
  }
379
534
  });
@@ -387,7 +542,8 @@ const Trigger = React.forwardRef(({ asChild = false, onPress, onClick, ...restPr
387
542
  }));
388
543
 
389
544
  const StyledIconContainer = styled(Primitive.span, {
390
- color: "$icon-neutrals-with-text"
545
+ color: "$icon-neutrals-with-text",
546
+ marginRight: "-4px"
391
547
  });
392
548
  const StyledSubTrigger = styled(RadixDropdownMenu.SubTrigger, {
393
549
  ...itemDefaults,
@@ -430,7 +586,7 @@ const SubContent = React.forwardRef(
430
586
  hideWhenDetached = false,
431
587
  sticky = "partial",
432
588
  ...restProps
433
- }, forwardRef) => /* @__PURE__ */ React.createElement(StyledSubContent, {
589
+ }, forwardRef) => /* @__PURE__ */ React.createElement(ContentProvider, null, /* @__PURE__ */ React.createElement(StyledSubContent, {
434
590
  ...restProps,
435
591
  ref: forwardRef,
436
592
  sideOffset,
@@ -439,7 +595,7 @@ const SubContent = React.forwardRef(
439
595
  loop,
440
596
  hideWhenDetached,
441
597
  sticky
442
- })
598
+ }))
443
599
  );
444
600
 
445
601
  const StyledSub = styled(RadixDropdownMenu.Sub, {});
@@ -466,7 +622,7 @@ const Portal = (props) => /* @__PURE__ */ React.createElement(Portal$1, {
466
622
  });
467
623
 
468
624
  const StyledIconSlot = styled(LeftSlot, {
469
- square: "$5",
625
+ paddingTop: "2px",
470
626
  variants: {
471
627
  customIcon: {
472
628
  true: {
@@ -477,6 +633,7 @@ const StyledIconSlot = styled(LeftSlot, {
477
633
  });
478
634
 
479
635
  const IconSlot = React.forwardRef(({ children, ...restProps }, forwardRef) => {
636
+ const { leftSlotMount, leftSlotDestroy } = useItem();
480
637
  const child = React.Children.only(children);
481
638
  const isIcon = isIconComponent(child);
482
639
  const formattedChild = isIcon ? React.cloneElement(child, {
@@ -484,6 +641,10 @@ const IconSlot = React.forwardRef(({ children, ...restProps }, forwardRef) => {
484
641
  size: "small",
485
642
  weight: "thin"
486
643
  }) : child;
644
+ useEffect(() => {
645
+ leftSlotMount();
646
+ return () => leftSlotDestroy();
647
+ }, [leftSlotMount, leftSlotDestroy]);
487
648
  return /* @__PURE__ */ React.createElement(StyledIconSlot, {
488
649
  ref: forwardRef,
489
650
  ...restProps,