@mirohq/design-system-dropdown-menu 3.3.0-dropdown.3 → 3.3.0-dropdown.5

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, 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 } from '@mirohq/design-system-icons';
4
+ import { IconProhibit, IconCheckMark, IconChevronRight } from '@mirohq/design-system-icons';
5
5
  import { 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",
@@ -25,18 +26,20 @@ const LeftSlot = styled(Primitive.div, {
25
26
  marginRight: "$100",
26
27
  gridArea: "left-slot"
27
28
  });
28
- const IconSlot = styled(LeftSlot, {
29
- width: "$6"
30
- });
31
29
  const IllustrationSlot = styled(LeftSlot, {
32
30
  width: "$13"
33
31
  });
34
- const RightSlot = styled(Primitive.div, {
32
+ const StyledRightSlot = styled(Primitive.div, {
35
33
  display: "flex",
36
34
  alignItems: "center",
37
35
  marginLeft: "auto",
38
36
  paddingLeft: "$200",
39
- gridArea: "right-slot"
37
+ gridArea: "right-slot",
38
+ minWidth: "max-content",
39
+ textAlign: "right",
40
+ "&:empty": {
41
+ paddingLeft: "$none"
42
+ }
40
43
  });
41
44
 
42
45
  const itemDefaults = {
@@ -49,16 +52,26 @@ const itemDefaults = {
49
52
  display: "grid",
50
53
  gridTemplateColumns: "auto 1fr auto",
51
54
  gridTemplateRows: "1fr auto",
52
- gridTemplateAreas: `
53
- 'left-slot item-text right-slot'
54
- 'left-slot item-description right-slot'
55
- `,
56
- alignItems: "center",
57
- minHeight: "$11",
58
- padding: "$100 $150",
55
+ gridTemplateAreas: `'left-slot item-text right-slot'
56
+ 'left-slot item-description right-slot'`,
57
+ alignItems: "start",
58
+ minHeight: "$10",
59
+ padding: "$100 $100",
59
60
  position: "relative",
60
61
  userSelect: "none",
61
62
  cursor: "pointer",
63
+ "&[data-no-left-slot]": {
64
+ gridTemplateColumns: "1fr auto",
65
+ gridTemplateRows: "auto",
66
+ gridTemplateAreas: `'item-text right-slot'
67
+ 'item-description right-slot'`
68
+ },
69
+ "&:not(:last-child)": {
70
+ marginBottom: "$50"
71
+ },
72
+ "&:not(:first-child)": {
73
+ marginTop: "$50"
74
+ },
62
75
  ...focus.defaults,
63
76
  '&:disabled, &[aria-disabled="true"], &[data-disabled]': {
64
77
  pointerEvents: "none",
@@ -86,7 +99,9 @@ const itemDefaults = {
86
99
  }
87
100
  };
88
101
 
89
- const StyledIndicator = styled(Primitive.span, {});
102
+ const StyledIndicator = styled(Primitive.span, {
103
+ padding: "4px 6px"
104
+ });
90
105
  const StyledCheckboxItem = styled(RadixDropdownMenu.CheckboxItem, {
91
106
  ...itemDefaults,
92
107
  [`&[data-state="checked"] ${StyledIndicator}`]: {
@@ -103,6 +118,53 @@ const StyledCheckboxItem = styled(RadixDropdownMenu.CheckboxItem, {
103
118
  }
104
119
  });
105
120
 
121
+ const Context = createContext({
122
+ counter: {
123
+ right: 0,
124
+ left: 0
125
+ },
126
+ increaseCounter: () => {
127
+ },
128
+ decreaseCounter: () => {
129
+ }
130
+ });
131
+ const SlotsProvider = ({
132
+ children
133
+ }) => {
134
+ const [counter, setCounter] = useState({
135
+ right: 0,
136
+ left: 0
137
+ });
138
+ return /* @__PURE__ */ React.createElement(Context.Provider, {
139
+ value: {
140
+ counter,
141
+ increaseCounter: (side) => {
142
+ setCounter((counter2) => ({
143
+ ...counter2,
144
+ [side]: counter2[side] + 1
145
+ }));
146
+ },
147
+ decreaseCounter: (side) => setCounter((counter2) => ({
148
+ ...counter2,
149
+ [side]: counter2[side] - 1
150
+ }))
151
+ }
152
+ }, children);
153
+ };
154
+ const useSlots = () => useContext(Context);
155
+
156
+ const RightSlot = (props) => {
157
+ const { increaseCounter, decreaseCounter } = useSlots();
158
+ useEffect(() => {
159
+ increaseCounter("right");
160
+ return () => decreaseCounter("right");
161
+ }, []);
162
+ return /* @__PURE__ */ React.createElement(StyledRightSlot, {
163
+ ...props
164
+ });
165
+ };
166
+ const HotkeySlot = RightSlot;
167
+
106
168
  const useAriaDisabled = ({ "aria-disabled": ariaDisabled, onKeyDown, onSelect }, preventDefault = false) => useMemo(
107
169
  () => ({
108
170
  "aria-disabled": booleanify(ariaDisabled) ? ariaDisabled : void 0,
@@ -140,26 +202,17 @@ const CheckboxItem = React.forwardRef(({ children, checked, onChange, disabled,
140
202
  }, children, /* @__PURE__ */ React.createElement(RightSlot, null, /* @__PURE__ */ React.createElement(StyledIndicator, null, (disabled === true || booleanify(ariaDisabled)) && !checked && /* @__PURE__ */ React.createElement(IconProhibit, {
141
203
  size: "small"
142
204
  }), checked && /* @__PURE__ */ React.createElement(IconCheckMark, {
143
- size: "small"
205
+ css: { width: "12px", display: "block" }
144
206
  }))));
145
207
  });
146
208
 
147
- const GUTTER_TOKEN = 150;
148
- const CONTENT_GUTTER = parseInt(theme.space[GUTTER_TOKEN]);
209
+ const CONTENT_GUTTER = parseInt(theme.space[150]);
149
210
  const CONTENT_OFFSET = parseInt(theme.space[50]);
150
- const ITEM_WITHOUT_RIGHT_SLOT = `[role="menuitem"]:not(:has(${RightSlot}))`;
151
211
  const contentDefaults = {
152
212
  maxWidth: "$125",
153
213
  backgroundColor: "$white",
154
214
  borderRadius: "$50",
155
- padding: `$${GUTTER_TOKEN}`,
156
215
  boxShadow: "$50",
157
- [`&:has(${RightSlot}) > ${ITEM_WITHOUT_RIGHT_SLOT}`]: {
158
- paddingRight: "44px"
159
- },
160
- [`&:has([role="switch"]) > ${ITEM_WITHOUT_RIGHT_SLOT}`]: {
161
- paddingRight: "56px"
162
- },
163
216
  "@media (prefers-reduced-motion: no-preference)": {
164
217
  animationDuration: "150ms",
165
218
  animationTimingFunction: "cubic-bezier(0.25, 0.5, 0.5, 0.9)",
@@ -191,7 +244,28 @@ const contentDefaults = {
191
244
  zIndex: "$dropdownMenu"
192
245
  };
193
246
 
194
- const StyledContent = styled(RadixDropdownMenu.Content, contentDefaults);
247
+ const StyledContent = styled(RadixDropdownMenu.Content, {
248
+ ...contentDefaults,
249
+ variants: {
250
+ containerSpacing: {
251
+ small: {
252
+ '&, [role="menu"]': {
253
+ padding: "$50 $150"
254
+ }
255
+ },
256
+ medium: {
257
+ '&, [role="menu"]': {
258
+ padding: "$150"
259
+ }
260
+ },
261
+ large: {
262
+ '&, [role="menu"]': {
263
+ padding: "$150 $300"
264
+ }
265
+ }
266
+ }
267
+ }
268
+ });
195
269
 
196
270
  const Content = React.forwardRef(
197
271
  ({
@@ -204,8 +278,9 @@ const Content = React.forwardRef(
204
278
  avoidCollisions = true,
205
279
  sticky = "partial",
206
280
  hideWhenDetached = false,
281
+ containerSpacing = "medium",
207
282
  ...restProps
208
- }, forwardRef) => /* @__PURE__ */ React.createElement(StyledContent, {
283
+ }, forwardRef) => /* @__PURE__ */ React.createElement(SlotsProvider, null, /* @__PURE__ */ React.createElement(StyledContent, {
209
284
  ...restProps,
210
285
  ref: forwardRef,
211
286
  loop,
@@ -216,20 +291,32 @@ const Content = React.forwardRef(
216
291
  avoidCollisions,
217
292
  collisionPadding,
218
293
  sticky,
219
- hideWhenDetached
220
- })
294
+ hideWhenDetached,
295
+ containerSpacing
296
+ }))
221
297
  );
222
298
 
223
- const StyledItem = styled(RadixDropdownMenu.Item, itemDefaults);
299
+ const StyledItem = styled(RadixDropdownMenu.Item, {
300
+ ...itemDefaults,
301
+ variants: {
302
+ hasRightSlot: {
303
+ true: {
304
+ paddingRight: "$600"
305
+ }
306
+ }
307
+ }
308
+ });
224
309
 
225
310
  const Item = React.forwardRef(
226
311
  ({ disabled = false, ...restProps }, forwardRef) => {
312
+ const { counter } = useSlots();
227
313
  const ariaDisabledProps = useAriaDisabled(restProps);
228
314
  return /* @__PURE__ */ React.createElement(StyledItem, {
229
315
  ...restProps,
230
316
  ...ariaDisabledProps,
231
317
  disabled,
232
- ref: forwardRef
318
+ ref: forwardRef,
319
+ hasRightSlot: counter.right > 0
233
320
  });
234
321
  }
235
322
  );
@@ -246,7 +333,9 @@ const LinkItem = React.forwardRef(({ children, href, ...restProps }, forwardRef)
246
333
  }, children));
247
334
  });
248
335
 
249
- const StyledRadioGroup = styled(RadixDropdownMenu.RadioGroup);
336
+ const StyledRadioGroup = styled(RadixDropdownMenu.RadioGroup, {
337
+ marginY: "$50"
338
+ });
250
339
 
251
340
  const RadioGroup = React.forwardRef((props, forwardRef) => {
252
341
  const { onChange, ...restProps } = props;
@@ -265,7 +354,8 @@ const StyledRadioContainer = styled(Primitive.span, {
265
354
  height: "$4",
266
355
  boxSizing: "border-box",
267
356
  border: "1px solid $border-neutrals",
268
- borderRadius: "$half"
357
+ borderRadius: "$half",
358
+ marginTop: "2px"
269
359
  });
270
360
  const StyledPill = styled(Primitive.span, {
271
361
  display: "none",
@@ -324,8 +414,7 @@ const RadioItem = React.forwardRef(({ disabled = false, children, ...restProps }
324
414
  });
325
415
 
326
416
  const StyledSeparator = styled(RadixDropdownMenu.Separator, {
327
- borderTop: "1px solid $border-neutrals-subtle",
328
- marginY: "$100"
417
+ borderTop: "1px solid $border-neutrals-subtle"
329
418
  });
330
419
 
331
420
  const Separator = React.forwardRef((props, forwardRef) => /* @__PURE__ */ React.createElement(StyledSeparator, {
@@ -336,7 +425,8 @@ const Separator = React.forwardRef((props, forwardRef) => /* @__PURE__ */ React.
336
425
  const StyledSwitch = styled(Primitive.span, {
337
426
  ...styles.default,
338
427
  width: "$7",
339
- height: "$4"
428
+ height: "$4",
429
+ marginTop: "2px"
340
430
  });
341
431
  const StyledSwitchItem = styled(RadixDropdownMenu.CheckboxItem, {
342
432
  ...itemDefaults,
@@ -363,19 +453,18 @@ const SwitchItem = React.forwardRef(
363
453
  }
364
454
  );
365
455
 
366
- const defaultStyles = {
367
- boxSizing: "border-box",
368
- cursor: "pointer",
369
- ...focus.defaults
370
- };
371
456
  const StyledTrigger = styled(RadixDropdownMenu.Trigger, {
372
457
  variants: {
373
458
  unstyled: {
374
459
  true: {
375
460
  all: "unset",
376
- ...defaultStyles
461
+ boxSizing: "border-box",
462
+ cursor: "pointer",
463
+ ...focus.defaults
377
464
  },
378
- false: defaultStyles
465
+ false: {
466
+ cursor: "pointer"
467
+ }
379
468
  }
380
469
  }
381
470
  });
@@ -388,21 +477,18 @@ const Trigger = React.forwardRef(({ asChild = false, onPress, onClick, ...restPr
388
477
  asChild
389
478
  }));
390
479
 
480
+ const StyledIconContainer = styled(Primitive.span, {
481
+ color: "$icon-neutrals-with-text",
482
+ marginRight: "-4px"
483
+ });
391
484
  const StyledSubTrigger = styled(RadixDropdownMenu.SubTrigger, {
392
485
  ...itemDefaults,
393
- '&[data-state="open"]': itemDefaults["&:hover"]
486
+ '&[data-state="open"]': itemDefaults["&:hover"],
487
+ [`&[data-state="open"] ${StyledIconContainer}, &:hover ${StyledIconContainer}`]: {
488
+ color: "$icon-primary-hover"
489
+ }
394
490
  });
395
491
 
396
- const ArrowIcon = () => /* @__PURE__ */ React.createElement("svg", {
397
- width: "16",
398
- height: "16",
399
- viewBox: "0 0 16 16",
400
- fill: "currentColor",
401
- xmlns: "http://www.w3.org/2000/svg",
402
- "data-testid": "submenu-arrow-icon"
403
- }, /* @__PURE__ */ React.createElement("path", {
404
- d: "M5.29289 3.29289C5.68342 2.90237 6.31658 2.90237 6.70711 3.29289L11.4142 8L6.70711 12.7071C6.31658 13.0976 5.68342 13.0976 5.29289 12.7071C4.90237 12.3166 4.90237 11.6834 5.29289 11.2929L8.58579 8L5.29289 4.70711C4.90237 4.31658 4.90237 3.68342 5.29289 3.29289Z"
405
- }));
406
492
  const SubTrigger = React.forwardRef(({ children, disabled = false, ...restProps }, forwardRef) => {
407
493
  const { onSelect, ...ariaDisabledProps } = useAriaDisabled({
408
494
  onKeyDown: restProps.onKeyDown,
@@ -413,7 +499,12 @@ const SubTrigger = React.forwardRef(({ children, disabled = false, ...restProps
413
499
  ...ariaDisabledProps,
414
500
  disabled,
415
501
  ref: forwardRef
416
- }, children, /* @__PURE__ */ React.createElement(RightSlot, null, /* @__PURE__ */ React.createElement(ArrowIcon, null)));
502
+ }, children, /* @__PURE__ */ React.createElement(RightSlot, null, /* @__PURE__ */ React.createElement(StyledIconContainer, {
503
+ "data-testid": process.env.NODE_ENV === "test" ? "submenu-arrow-icon" : void 0
504
+ }, /* @__PURE__ */ React.createElement(IconChevronRight, {
505
+ size: "small",
506
+ weight: "thin"
507
+ }))));
417
508
  });
418
509
 
419
510
  const StyledSubContent = styled(
@@ -431,7 +522,7 @@ const SubContent = React.forwardRef(
431
522
  hideWhenDetached = false,
432
523
  sticky = "partial",
433
524
  ...restProps
434
- }, forwardRef) => /* @__PURE__ */ React.createElement(StyledSubContent, {
525
+ }, forwardRef) => /* @__PURE__ */ React.createElement(SlotsProvider, null, /* @__PURE__ */ React.createElement(StyledSubContent, {
435
526
  ...restProps,
436
527
  ref: forwardRef,
437
528
  sideOffset,
@@ -440,7 +531,7 @@ const SubContent = React.forwardRef(
440
531
  loop,
441
532
  hideWhenDetached,
442
533
  sticky
443
- })
534
+ }))
444
535
  );
445
536
 
446
537
  const StyledSub = styled(RadixDropdownMenu.Sub, {});
@@ -466,6 +557,32 @@ const Portal = (props) => /* @__PURE__ */ React.createElement(Portal$1, {
466
557
  ...props
467
558
  });
468
559
 
560
+ const StyledIconSlot = styled(LeftSlot, {
561
+ paddingTop: "2px",
562
+ variants: {
563
+ customIcon: {
564
+ true: {
565
+ square: "$icon-200"
566
+ }
567
+ }
568
+ }
569
+ });
570
+
571
+ const IconSlot = React.forwardRef(({ children, ...restProps }, forwardRef) => {
572
+ const child = React.Children.only(children);
573
+ const isIcon = isIconComponent(child);
574
+ const formattedChild = isIcon ? React.cloneElement(child, {
575
+ ...child.props,
576
+ size: "small",
577
+ weight: "thin"
578
+ }) : child;
579
+ return /* @__PURE__ */ React.createElement(StyledIconSlot, {
580
+ ref: forwardRef,
581
+ ...restProps,
582
+ customIcon: !isIcon
583
+ }, formattedChild);
584
+ });
585
+
469
586
  const DropdownMenu = ({
470
587
  defaultOpen = false,
471
588
  direction = "ltr",
@@ -491,6 +608,7 @@ const DropdownMenu = ({
491
608
  };
492
609
  DropdownMenu.CheckboxItem = CheckboxItem;
493
610
  DropdownMenu.Content = Content;
611
+ DropdownMenu.HotkeySlot = HotkeySlot;
494
612
  DropdownMenu.IconSlot = IconSlot;
495
613
  DropdownMenu.IllustrationSlot = IllustrationSlot;
496
614
  DropdownMenu.Item = Item;