@mirohq/design-system-combobox 0.1.0-combobox.7 → 0.1.0-combobox.9

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/main.js CHANGED
@@ -13,10 +13,12 @@ var designSystemInput = require('@mirohq/design-system-input');
13
13
  var reactUseControllableState = require('@radix-ui/react-use-controllable-state');
14
14
  var designSystemIcons = require('@mirohq/design-system-icons');
15
15
  var designSystemScrollArea = require('@mirohq/design-system-scroll-area');
16
+ var designSystemPrimitive = require('@mirohq/design-system-primitive');
16
17
  var utils = require('@react-aria/utils');
17
18
  var designSystemUseAriaDisabled = require('@mirohq/design-system-use-aria-disabled');
19
+ var designSystemUseLayoutEffect = require('@mirohq/design-system-use-layout-effect');
18
20
  var designSystemStyles = require('@mirohq/design-system-styles');
19
- var designSystemPrimitive = require('@mirohq/design-system-primitive');
21
+ var reactDom = require('react-dom');
20
22
  var designSystemBaseButton = require('@mirohq/design-system-base-button');
21
23
 
22
24
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -118,6 +120,7 @@ const ComboboxProvider = ({
118
120
  });
119
121
  const [filteredItems, setFilteredItems] = React.useState(/* @__PURE__ */ new Set());
120
122
  const [searchValue, setSearchValue] = React.useState("");
123
+ const [itemValueTextMap, setItemValueTextMap] = React.useState(/* @__PURE__ */ new Map());
121
124
  const { valid: formFieldValid } = designSystemBaseForm.useFormFieldContext();
122
125
  return /* @__PURE__ */ jsxRuntime.jsx(
123
126
  ComboboxContext.Provider,
@@ -139,7 +142,9 @@ const ComboboxProvider = ({
139
142
  searchValue,
140
143
  setSearchValue,
141
144
  filteredItems,
142
- setFilteredItems
145
+ setFilteredItems,
146
+ itemValueTextMap,
147
+ setItemValueTextMap
143
148
  },
144
149
  children
145
150
  }
@@ -167,25 +172,48 @@ const StyledActionButton = designSystemStitches.styled(designSystemInput.Input.A
167
172
 
168
173
  const TriggerActionButton = ({
169
174
  openActionLabel,
175
+ closeActionLabel,
170
176
  clearActionLabel,
171
177
  size
172
178
  }) => {
173
- const { setOpenState, value = [], setValue } = useComboboxContext();
179
+ const { openState, setOpenState, value = [], setValue } = useComboboxContext();
174
180
  const isEmpty = value.length === 0;
175
- const ActionButtonIcon = isEmpty ? designSystemIcons.IconChevronDown : designSystemIcons.IconCross;
176
- const label = isEmpty ? openActionLabel : clearActionLabel;
177
- const onActionButtonClick = React.useCallback(
181
+ const onToggleClick = React.useCallback(
178
182
  (event) => {
179
- if (!isEmpty) {
180
- setValue([]);
181
- } else {
182
- setOpenState((prevOpen = false) => !prevOpen);
183
+ if (openState) {
184
+ setOpenState(false);
183
185
  }
184
186
  event.stopPropagation();
185
187
  },
186
- [isEmpty, setValue, setOpenState]
188
+ [setOpenState, openState]
189
+ );
190
+ const onClearClick = React.useCallback(
191
+ (event) => {
192
+ setValue([]);
193
+ event.stopPropagation();
194
+ },
195
+ [setValue]
196
+ );
197
+ if (isEmpty) {
198
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixPopover.Trigger, { asChild: true, "aria-haspopup": "listbox", children: /* @__PURE__ */ jsxRuntime.jsx(
199
+ StyledActionButton,
200
+ {
201
+ label: openState ? closeActionLabel : openActionLabel,
202
+ size,
203
+ onClick: onToggleClick,
204
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconChevronDown, { size: "small", weight: "thin" })
205
+ }
206
+ ) });
207
+ }
208
+ return /* @__PURE__ */ jsxRuntime.jsx(
209
+ StyledActionButton,
210
+ {
211
+ label: clearActionLabel,
212
+ size,
213
+ onClick: onClearClick,
214
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconCross, { size: "small", weight: "thin" })
215
+ }
187
216
  );
188
- return /* @__PURE__ */ jsxRuntime.jsx(StyledActionButton, { label, size, onClick: onActionButtonClick, children: /* @__PURE__ */ jsxRuntime.jsx(ActionButtonIcon, { size: "small", weight: "thin" }) });
189
217
  };
190
218
 
191
219
  const Trigger = React__default["default"].forwardRef(
@@ -197,6 +225,7 @@ const Trigger = React__default["default"].forwardRef(
197
225
  "aria-invalid": ariaInvalid,
198
226
  placeholder,
199
227
  openActionLabel,
228
+ closeActionLabel,
200
229
  clearActionLabel,
201
230
  onChange,
202
231
  css,
@@ -217,7 +246,6 @@ const Trigger = React__default["default"].forwardRef(
217
246
  } = useComboboxContext();
218
247
  const {
219
248
  formElementId,
220
- ariaDescribedBy: formFieldContextDescribedBy,
221
249
  ariaInvalid: formFieldAriaInvalid,
222
250
  valid: formFieldValid,
223
251
  label,
@@ -229,10 +257,8 @@ const Trigger = React__default["default"].forwardRef(
229
257
  ...restProps,
230
258
  "aria-disabled": ariaDisabled,
231
259
  "aria-invalid": ariaInvalid != null ? ariaInvalid : formFieldAriaInvalid,
232
- "aria-describedby": designSystemUtils.stringAttrValue(
233
- ariaDescribedBy,
234
- formFieldContextDescribedBy
235
- ),
260
+ // todo MDS-1011: use formFieldContextDescribedBy after removing form context from BaseInput
261
+ "aria-describedby": ariaDescribedBy,
236
262
  valid,
237
263
  disabled,
238
264
  readOnly,
@@ -291,6 +317,7 @@ const Trigger = React__default["default"].forwardRef(
291
317
  TriggerActionButton,
292
318
  {
293
319
  openActionLabel,
320
+ closeActionLabel,
294
321
  clearActionLabel,
295
322
  size
296
323
  }
@@ -306,6 +333,9 @@ const Trigger = React__default["default"].forwardRef(
306
333
  }
307
334
  );
308
335
 
336
+ const NoResultPlaceholder = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
337
+ padding: "$100"
338
+ });
309
339
  const StyledContent = designSystemStitches.styled(RadixPopover__namespace.Content, {
310
340
  backgroundColor: "$background-neutrals-container",
311
341
  borderRadius: "$50",
@@ -363,7 +393,23 @@ const StyledItem = designSystemStitches.styled(react.ComboboxItem, {
363
393
  const Item = React__default["default"].forwardRef(
364
394
  ({ disabled = false, value, textValue, children, ...restProps }, forwardRef) => {
365
395
  const { "aria-disabled": ariaDisabled, ...restAriaDisabledProps } = designSystemUseAriaDisabled.useAriaDisabled(restProps, { allowArrows: true });
366
- const { autoFilter, filteredItems, triggerRef, inputRef } = useComboboxContext();
396
+ const {
397
+ autoFilter,
398
+ filteredItems,
399
+ setItemValueTextMap,
400
+ triggerRef,
401
+ inputRef
402
+ } = useComboboxContext();
403
+ designSystemUseLayoutEffect.useLayoutEffect(() => {
404
+ const textToSet = textValue !== void 0 ? textValue : typeof children === "string" ? children : "";
405
+ setItemValueTextMap((prevState) => new Map(prevState.set(value, textToSet)));
406
+ return () => {
407
+ setItemValueTextMap((prevState) => {
408
+ prevState.delete(value);
409
+ return new Map(prevState);
410
+ });
411
+ };
412
+ }, [setItemValueTextMap, value, textValue, children]);
367
413
  if (autoFilter !== false && !filteredItems.has(value)) {
368
414
  return null;
369
415
  }
@@ -435,13 +481,35 @@ const getChildrenItemValues = (componentChildren) => {
435
481
  return values;
436
482
  };
437
483
 
484
+ const useDocumentFragment = () => {
485
+ const [fragment, setFragment] = React__default["default"].useState();
486
+ designSystemUseLayoutEffect.useLayoutEffect(() => {
487
+ setFragment(new DocumentFragment());
488
+ }, []);
489
+ return fragment;
490
+ };
491
+
492
+ const useInvisibleContent = () => {
493
+ const fragment = useDocumentFragment();
494
+ return React.useCallback(
495
+ (children) => fragment !== void 0 ? reactDom.createPortal(/* @__PURE__ */ jsxRuntime.jsx("div", { children }), fragment) : null,
496
+ [fragment]
497
+ );
498
+ };
499
+
438
500
  const CONTENT_OFFSET = parseInt(designSystemStitches.theme.space[50]);
439
501
  const isInsideRef = (element, ref) => {
440
502
  var _a, _b;
441
503
  return (_b = element != null && ((_a = ref.current) == null ? void 0 : _a.contains(element))) != null ? _b : false;
442
504
  };
443
505
  const Content = React__default["default"].forwardRef(
444
- ({ sideOffset = CONTENT_OFFSET, maxHeight, children, ...restProps }, forwardRef) => {
506
+ ({
507
+ sideOffset = CONTENT_OFFSET,
508
+ maxHeight,
509
+ overflow,
510
+ children,
511
+ ...restProps
512
+ }, forwardRef) => {
445
513
  const {
446
514
  triggerRef,
447
515
  contentRef,
@@ -450,7 +518,8 @@ const Content = React__default["default"].forwardRef(
450
518
  setFilteredItems,
451
519
  searchValue,
452
520
  noResultsText,
453
- direction
521
+ direction,
522
+ openState
454
523
  } = useComboboxContext();
455
524
  React.useEffect(() => {
456
525
  const childrenItemValues = getChildrenItemValues(children);
@@ -462,11 +531,20 @@ const Content = React__default["default"].forwardRef(
462
531
  )
463
532
  );
464
533
  }, [children, autoFilter, setFilteredItems, searchValue]);
465
- const content = filteredItems.size === 0 ? noResultsText : children;
534
+ const getInvisibleContent = useInvisibleContent();
535
+ if (!openState) {
536
+ return getInvisibleContent(children);
537
+ }
538
+ const content = filteredItems.size === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
539
+ /* @__PURE__ */ jsxRuntime.jsx(NoResultPlaceholder, { children: noResultsText }),
540
+ getInvisibleContent(children)
541
+ ] }) : children;
466
542
  return /* @__PURE__ */ jsxRuntime.jsx(
467
543
  StyledContent,
468
544
  {
545
+ asChild: true,
469
546
  ...restProps,
547
+ dir: direction,
470
548
  sideOffset,
471
549
  ref: designSystemUtils.mergeRefs([forwardRef, contentRef]),
472
550
  onOpenAutoFocus: (event) => event.preventDefault(),
@@ -478,7 +556,7 @@ const Content = React__default["default"].forwardRef(
478
556
  event.preventDefault();
479
557
  }
480
558
  },
481
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystemScrollArea.ScrollArea, { type: "always", dir: direction, children: [
559
+ children: /* @__PURE__ */ jsxRuntime.jsx(react.ComboboxList, { role: "listbox", children: overflow === "auto" ? /* @__PURE__ */ jsxRuntime.jsxs(designSystemScrollArea.ScrollArea, { type: "always", dir: direction, children: [
482
560
  /* @__PURE__ */ jsxRuntime.jsx(
483
561
  designSystemScrollArea.ScrollArea.Viewport,
484
562
  {
@@ -489,7 +567,7 @@ const Content = React__default["default"].forwardRef(
489
567
  }
490
568
  ),
491
569
  /* @__PURE__ */ jsxRuntime.jsx(designSystemScrollArea.ScrollArea.Scrollbar, { orientation: "vertical", children: /* @__PURE__ */ jsxRuntime.jsx(designSystemScrollArea.ScrollArea.Thumb, {}) })
492
- ] })
570
+ ] }) : content })
493
571
  }
494
572
  );
495
573
  }
@@ -497,6 +575,8 @@ const Content = React__default["default"].forwardRef(
497
575
 
498
576
  const Portal = (props) => /* @__PURE__ */ jsxRuntime.jsx(RadixPopover.Portal, { ...props });
499
577
 
578
+ const StyledGroup = designSystemStitches.styled(react.Group);
579
+
500
580
  const Group = React__default["default"].forwardRef(({ children, ...rest }, forwardRef) => {
501
581
  const { autoFilter, filteredItems } = useComboboxContext();
502
582
  const childValues = React.useMemo(
@@ -511,10 +591,11 @@ const Group = React__default["default"].forwardRef(({ children, ...rest }, forwa
511
591
  ),
512
592
  [childValues, filteredItems, autoFilter]
513
593
  );
594
+ const getInvisibleContent = useInvisibleContent();
514
595
  if (!hasVisibleChildren) {
515
- return null;
596
+ return getInvisibleContent(children);
516
597
  }
517
- return /* @__PURE__ */ jsxRuntime.jsx(react.Group, { ...rest, ref: forwardRef, children });
598
+ return /* @__PURE__ */ jsxRuntime.jsx(StyledGroup, { ...rest, ref: forwardRef, children });
518
599
  });
519
600
 
520
601
  const StyledGroupLabel = designSystemStitches.styled(react.GroupLabel, {
@@ -533,13 +614,13 @@ const StyledChip = designSystemStitches.styled(designSystemPrimitive.Primitive.d
533
614
  gap: "$50",
534
615
  whiteSpace: "nowrap",
535
616
  maxWidth: "$35",
536
- background: "$gray-100",
537
- color: "$gray-900"
617
+ backgroundColor: "$background-neutrals-subtle",
618
+ color: "$text-neutrals"
538
619
  });
539
620
  const StyledChipButton = designSystemStitches.styled(designSystemBaseButton.BaseButton, {
621
+ color: "$icon-neutrals-inactive",
540
622
  ...designSystemStyles.focus.css({
541
- boxShadow: "$focus-small-outline",
542
- borderColor: "$blue-400 !important"
623
+ boxShadow: "$focus-small-outline"
543
624
  })
544
625
  });
545
626
  const StyledChipContent = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
@@ -557,9 +638,9 @@ const StyledLeftSlot = designSystemStitches.styled(designSystemPrimitive.Primiti
557
638
  const LeftSlot = StyledLeftSlot;
558
639
 
559
640
  const Chip = React__default["default"].forwardRef(
560
- ({ children, disabled = false, onRemove, removeChipAriaLabel, ...restProps }, forwardRef) => /* @__PURE__ */ jsxRuntime.jsxs(StyledChip, { ...restProps, ref: forwardRef, children: [
641
+ ({ children, disabled = false, onRemove, removeAriaLabel, ...restProps }, forwardRef) => /* @__PURE__ */ jsxRuntime.jsxs(StyledChip, { ...restProps, ref: forwardRef, children: [
561
642
  /* @__PURE__ */ jsxRuntime.jsx(StyledChipContent, { children }),
562
- !designSystemUtils.booleanify(disabled) && /* @__PURE__ */ jsxRuntime.jsx(StyledChipButton, { onClick: onRemove, "aria-label": removeChipAriaLabel, children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconCross, { size: "small", weight: "thin", color: "gray-500" }) })
643
+ !designSystemUtils.booleanify(disabled) && /* @__PURE__ */ jsxRuntime.jsx(StyledChipButton, { onClick: onRemove, "aria-label": removeAriaLabel, children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconCross, { size: "small", weight: "thin", "aria-hidden": true }) })
563
644
  ] })
564
645
  );
565
646
  Chip.LeftSlot = LeftSlot;
@@ -568,31 +649,42 @@ const StyledValue = designSystemStitches.styled(Chip, {
568
649
  marginTop: "$50"
569
650
  });
570
651
 
571
- const Value = ({ removeChipAriaLabel }) => {
652
+ const Value = ({ unselectAriaLabel }) => {
572
653
  const {
573
654
  value = [],
574
655
  setValue,
575
656
  disabled,
576
- "aria-disabled": ariaDisabled
657
+ "aria-disabled": ariaDisabled,
658
+ itemValueTextMap
577
659
  } = useComboboxContext();
578
660
  const isDisabled = ariaDisabled === true || disabled;
579
- const onItemRemove = (item) => {
580
- setValue((prevValue) => prevValue == null ? void 0 : prevValue.filter((value2) => value2 !== item));
581
- };
582
- if (value.length === 0) {
583
- return null;
584
- }
585
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: value.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
586
- StyledValue,
587
- {
588
- onRemove: () => onItemRemove(item),
589
- disabled: isDisabled,
590
- removeChipAriaLabel,
591
- "data-testid": process.env.NODE_ENV === "test" ? "combobox-value-".concat(item) : void 0,
592
- children: item
661
+ const onItemRemove = React.useCallback(
662
+ (item) => {
663
+ setValue((prevValue) => prevValue == null ? void 0 : prevValue.filter((value2) => value2 !== item));
593
664
  },
594
- item
595
- )) });
665
+ [setValue]
666
+ );
667
+ const getItemText = React.useCallback(
668
+ (itemValue) => {
669
+ const textValue = itemValueTextMap.get(itemValue);
670
+ if (textValue === void 0 || textValue === "") {
671
+ return null;
672
+ }
673
+ return /* @__PURE__ */ jsxRuntime.jsx(
674
+ StyledValue,
675
+ {
676
+ onRemove: () => onItemRemove(itemValue),
677
+ disabled: isDisabled,
678
+ removeAriaLabel: "".concat(unselectAriaLabel, " ").concat(textValue),
679
+ "data-testid": process.env.NODE_ENV === "test" ? "combobox-value-".concat(itemValue) : void 0,
680
+ children: textValue
681
+ },
682
+ itemValue
683
+ );
684
+ },
685
+ [isDisabled, itemValueTextMap, onItemRemove, unselectAriaLabel]
686
+ );
687
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: value.map(getItemText) });
596
688
  };
597
689
 
598
690
  const StyledSeparator = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {