@mirohq/design-system-combobox 0.1.0-combobox.0 → 0.1.0-combobox.10

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
@@ -4,15 +4,22 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var React = require('react');
7
- var interactions = require('@react-aria/interactions');
8
- var designSystemUtils = require('@mirohq/design-system-utils');
7
+ var react = require('@ariakit/react');
9
8
  var designSystemBaseForm = require('@mirohq/design-system-base-form');
9
+ var designSystemUtils = require('@mirohq/design-system-utils');
10
+ var RadixPopover = require('@radix-ui/react-popover');
11
+ var designSystemStitches = require('@mirohq/design-system-stitches');
10
12
  var designSystemInput = require('@mirohq/design-system-input');
13
+ var reactUseControllableState = require('@radix-ui/react-use-controllable-state');
11
14
  var designSystemIcons = require('@mirohq/design-system-icons');
12
- var designSystemStitches = require('@mirohq/design-system-stitches');
15
+ var designSystemScrollArea = require('@mirohq/design-system-scroll-area');
13
16
  var designSystemPrimitive = require('@mirohq/design-system-primitive');
14
- var Ariakit = require('@ariakit/react');
15
- var reactPopover = require('@radix-ui/react-popover');
17
+ var utils = require('@react-aria/utils');
18
+ var designSystemUseAriaDisabled = require('@mirohq/design-system-use-aria-disabled');
19
+ var designSystemUseLayoutEffect = require('@mirohq/design-system-use-layout-effect');
20
+ var designSystemStyles = require('@mirohq/design-system-styles');
21
+ var reactDom = require('react-dom');
22
+ var designSystemBaseButton = require('@mirohq/design-system-base-button');
16
23
 
17
24
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
18
25
 
@@ -35,9 +42,181 @@ function _interopNamespace(e) {
35
42
  }
36
43
 
37
44
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
38
- var Ariakit__namespace = /*#__PURE__*/_interopNamespace(Ariakit);
45
+ var RadixPopover__namespace = /*#__PURE__*/_interopNamespace(RadixPopover);
39
46
 
40
- const StyledTrigger = designSystemStitches.styled(designSystemInput.Input, {});
47
+ const StyledInput = designSystemStitches.styled(designSystemInput.Input, {
48
+ flexWrap: "wrap",
49
+ flexGrow: 1,
50
+ gap: "$50",
51
+ overflowY: "scroll",
52
+ "&[data-valid], &[data-invalid]": {
53
+ // we don't need a bigger padding here as Input component will render its own icon
54
+ paddingRight: "$100"
55
+ },
56
+ "& input": {
57
+ minWidth: "$8",
58
+ flexBasis: 0,
59
+ flexGrow: 1
60
+ },
61
+ variants: {
62
+ size: {
63
+ large: {
64
+ minHeight: "$10",
65
+ height: "auto",
66
+ padding: "5px $100",
67
+ paddingRight: "$500"
68
+ },
69
+ "x-large": {
70
+ minHeight: "$12",
71
+ height: "auto",
72
+ padding: "5px $100",
73
+ paddingRight: "$500"
74
+ }
75
+ }
76
+ },
77
+ defaultVariants: {
78
+ size: "large"
79
+ }
80
+ });
81
+
82
+ const ComboboxContext = React.createContext({});
83
+ const ComboboxProvider = ({
84
+ children,
85
+ open: openProp,
86
+ defaultOpen,
87
+ onOpen,
88
+ onClose,
89
+ valid,
90
+ value: valueProp,
91
+ defaultValue: defaultValueProp,
92
+ onValueChange,
93
+ onSearchValueChange,
94
+ autoFilter = true,
95
+ ...restProps
96
+ }) => {
97
+ const triggerRef = React.useRef(null);
98
+ const inputRef = React.useRef(null);
99
+ const contentRef = React.useRef(null);
100
+ const [defaultValue, setDefaultValue] = React.useState(defaultValueProp);
101
+ const [openState = false, setOpenState] = reactUseControllableState.useControllableState({
102
+ prop: openProp,
103
+ defaultProp: defaultOpen,
104
+ onChange: (state) => {
105
+ if (state) {
106
+ onOpen == null ? void 0 : onOpen();
107
+ } else {
108
+ onClose == null ? void 0 : onClose();
109
+ }
110
+ }
111
+ });
112
+ const [value, setValue] = reactUseControllableState.useControllableState({
113
+ prop: valueProp,
114
+ defaultProp: defaultValueProp,
115
+ onChange: onValueChange
116
+ });
117
+ const [filteredItems, setFilteredItems] = React.useState(/* @__PURE__ */ new Set());
118
+ const [searchValue, setSearchValue] = React.useState("");
119
+ const [size, setSize] = React.useState();
120
+ const [placeholder, setPlaceholder] = React.useState();
121
+ const [itemValueTextMap, setItemValueTextMap] = React.useState(/* @__PURE__ */ new Map());
122
+ const { valid: formFieldValid } = designSystemBaseForm.useFormFieldContext();
123
+ return /* @__PURE__ */ jsxRuntime.jsx(
124
+ ComboboxContext.Provider,
125
+ {
126
+ value: {
127
+ ...restProps,
128
+ valid: valid != null ? valid : formFieldValid,
129
+ openState,
130
+ setOpenState,
131
+ value,
132
+ setValue,
133
+ setDefaultValue,
134
+ defaultValue,
135
+ onSearchValueChange,
136
+ triggerRef,
137
+ inputRef,
138
+ contentRef,
139
+ autoFilter,
140
+ searchValue,
141
+ setSearchValue,
142
+ filteredItems,
143
+ setFilteredItems,
144
+ itemValueTextMap,
145
+ setItemValueTextMap,
146
+ placeholder,
147
+ setPlaceholder,
148
+ size,
149
+ setSize
150
+ },
151
+ children
152
+ }
153
+ );
154
+ };
155
+ const useComboboxContext = () => React.useContext(ComboboxContext);
156
+
157
+ const StyledActionButton = designSystemStitches.styled(designSystemInput.Input.ActionButton, {
158
+ position: "absolute",
159
+ right: "$100",
160
+ variants: {
161
+ size: {
162
+ large: {
163
+ top: "5px"
164
+ },
165
+ "x-large": {
166
+ top: "9px"
167
+ }
168
+ }
169
+ },
170
+ defaultVariants: {
171
+ size: "large"
172
+ }
173
+ });
174
+
175
+ const TriggerActionButton = ({
176
+ openActionLabel,
177
+ closeActionLabel,
178
+ clearActionLabel,
179
+ size
180
+ }) => {
181
+ const { openState, setOpenState, value = [], setValue } = useComboboxContext();
182
+ const isEmpty = value.length === 0;
183
+ const onToggleClick = React.useCallback(
184
+ (event) => {
185
+ if (openState) {
186
+ setOpenState(false);
187
+ }
188
+ event.stopPropagation();
189
+ },
190
+ [setOpenState, openState]
191
+ );
192
+ const onClearClick = React.useCallback(
193
+ (event) => {
194
+ setValue([]);
195
+ event.stopPropagation();
196
+ },
197
+ [setValue]
198
+ );
199
+ if (isEmpty) {
200
+ return /* @__PURE__ */ jsxRuntime.jsx(RadixPopover.Trigger, { asChild: true, "aria-haspopup": "listbox", children: /* @__PURE__ */ jsxRuntime.jsx(
201
+ StyledActionButton,
202
+ {
203
+ label: openState ? closeActionLabel : openActionLabel,
204
+ size,
205
+ onClick: onToggleClick,
206
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconChevronDown, { size: "small", weight: "thin" })
207
+ }
208
+ ) });
209
+ }
210
+ return /* @__PURE__ */ jsxRuntime.jsx(
211
+ StyledActionButton,
212
+ {
213
+ label: clearActionLabel,
214
+ size,
215
+ onClick: onClearClick,
216
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconCross, { size: "small", weight: "thin" })
217
+ }
218
+ );
219
+ };
41
220
 
42
221
  const Trigger = React__default["default"].forwardRef(
43
222
  ({
@@ -45,103 +224,667 @@ const Trigger = React__default["default"].forwardRef(
45
224
  children,
46
225
  size = "large",
47
226
  "aria-describedby": ariaDescribedBy,
48
- onHoverChange,
49
- onHoverStart,
50
- onHoverEnd,
227
+ "aria-invalid": ariaInvalid,
228
+ placeholder,
229
+ openActionLabel,
230
+ closeActionLabel,
231
+ clearActionLabel,
232
+ onChange,
51
233
  ...restProps
52
234
  }, forwardRef) => {
235
+ const {
236
+ "aria-disabled": ariaDisabled,
237
+ valid: comboboxValid,
238
+ disabled,
239
+ value = [],
240
+ readOnly,
241
+ triggerRef,
242
+ inputRef,
243
+ onSearchValueChange,
244
+ searchValue,
245
+ setSearchValue,
246
+ setOpenState,
247
+ setSize,
248
+ setPlaceholder
249
+ } = useComboboxContext();
53
250
  const {
54
251
  formElementId,
55
- ariaDescribedBy: formFieldContextDescribedBy,
56
- ariaInvalid,
252
+ ariaInvalid: formFieldAriaInvalid,
57
253
  valid: formFieldValid
58
254
  } = designSystemBaseForm.useFormFieldContext();
59
- const valid = formFieldValid;
60
- const { hoverProps } = interactions.useHover({
61
- onHoverStart,
62
- onHoverEnd,
63
- onHoverChange: (isHovering) => {
64
- onHoverChange == null ? void 0 : onHoverChange(isHovering);
65
- }
66
- });
67
- const commonProps = {
255
+ React.useEffect(() => {
256
+ setSize(size);
257
+ }, [size, setSize]);
258
+ React.useEffect(() => {
259
+ setPlaceholder(placeholder);
260
+ }, [setPlaceholder, placeholder]);
261
+ const valid = formFieldValid != null ? formFieldValid : comboboxValid;
262
+ const inputProps = {
68
263
  ...restProps,
69
- ref: forwardRef,
70
- "aria-invalid": ariaInvalid,
71
- "aria-describedby": designSystemUtils.stringAttrValue(
72
- ariaDescribedBy,
73
- formFieldContextDescribedBy
74
- ),
264
+ "aria-disabled": ariaDisabled,
265
+ "aria-invalid": ariaInvalid != null ? ariaInvalid : formFieldAriaInvalid,
266
+ // todo MDS-1011: use formFieldContextDescribedBy after removing form context from BaseInput
267
+ "aria-describedby": ariaDescribedBy,
75
268
  valid,
269
+ disabled,
270
+ readOnly,
76
271
  invalid: designSystemUtils.booleanishAttrValue(valid),
77
- id: id != null ? id : formElementId
272
+ id: id != null ? id : formElementId,
273
+ placeholder: value.length === 0 ? placeholder : void 0
78
274
  };
79
- const variants = {
80
- size
275
+ const scrollIntoView = (event) => {
276
+ var _a;
277
+ const trigger = triggerRef == null ? void 0 : triggerRef.current;
278
+ const baseInput = (_a = inputRef == null ? void 0 : inputRef.current) == null ? void 0 : _a.parentElement;
279
+ if (baseInput != null && trigger != null) {
280
+ event.preventDefault();
281
+ baseInput.scrollTo({
282
+ top: trigger.scrollHeight
283
+ });
284
+ }
285
+ if (restProps.onFocus !== void 0) {
286
+ restProps.onFocus(event);
287
+ }
81
288
  };
82
- return /* @__PURE__ */ jsxRuntime.jsxs(StyledTrigger, { ...hoverProps, ...commonProps, ...variants, children: [
83
- children,
84
- /* @__PURE__ */ jsxRuntime.jsx(designSystemInput.Input.ActionButton, { label: "custom label", children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconChevronDown, { size: "small", weight: "thin" }) })
85
- ] });
289
+ const onInputChange = (e) => {
290
+ setSearchValue(e.target.value);
291
+ onSearchValueChange == null ? void 0 : onSearchValueChange(e.target.value);
292
+ onChange == null ? void 0 : onChange(e);
293
+ };
294
+ return /* @__PURE__ */ jsxRuntime.jsx(
295
+ RadixPopover.Anchor,
296
+ {
297
+ ref: designSystemUtils.mergeRefs([triggerRef, forwardRef]),
298
+ onClick: () => {
299
+ if (!designSystemUtils.booleanify(disabled) && !designSystemUtils.booleanify(ariaDisabled) && !designSystemUtils.booleanify(readOnly)) {
300
+ setOpenState(true);
301
+ }
302
+ },
303
+ children: /* @__PURE__ */ jsxRuntime.jsx(
304
+ react.Combobox,
305
+ {
306
+ render: /* @__PURE__ */ jsxRuntime.jsxs(
307
+ StyledInput,
308
+ {
309
+ ...inputProps,
310
+ value: searchValue,
311
+ size,
312
+ ref: inputRef,
313
+ onChange: onInputChange,
314
+ onFocus: scrollIntoView,
315
+ children: [
316
+ children,
317
+ /* @__PURE__ */ jsxRuntime.jsx(
318
+ TriggerActionButton,
319
+ {
320
+ openActionLabel,
321
+ closeActionLabel,
322
+ clearActionLabel,
323
+ size
324
+ }
325
+ )
326
+ ]
327
+ }
328
+ )
329
+ }
330
+ )
331
+ }
332
+ );
86
333
  }
87
334
  );
88
335
 
89
- const StyledContent = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
336
+ const NoResultPlaceholder = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
337
+ padding: "$100"
338
+ });
339
+ const StyledContent = designSystemStitches.styled(RadixPopover__namespace.Content, {
90
340
  backgroundColor: "$background-neutrals-container",
91
341
  borderRadius: "$50",
92
342
  boxShadow: "$50",
93
- minWidth: "var(--radix-select-trigger-width)",
343
+ fontSize: "$175",
344
+ fontWeight: "normal",
345
+ lineHeight: "20px",
346
+ width: "var(--radix-popover-trigger-width)",
347
+ zIndex: "$select",
348
+ overflowY: "auto",
94
349
  padding: "$50",
95
- zIndex: "$select"
350
+ boxSizing: "border-box",
351
+ outline: "1px solid transparent"
96
352
  });
97
353
 
98
- const Content = React__default["default"].forwardRef(({ children, ...restProps }, forwardRef) => /* @__PURE__ */ jsxRuntime.jsx(StyledContent, { ...restProps, ref: forwardRef, children }));
99
-
100
- const StyledItem = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
354
+ const StyledItemCheck = designSystemStitches.styled(designSystemPrimitive.Primitive.span, {
355
+ color: "$icon-primary"
356
+ });
357
+ const StyledItem = designSystemStitches.styled(react.ComboboxItem, {
358
+ display: "grid",
359
+ gridTemplateColumns: "20px 1fr",
101
360
  borderRadius: "$50",
102
361
  boxSizing: "border-box",
103
362
  color: "$text-neutrals",
104
363
  cursor: "pointer",
105
364
  fontSize: "$175",
106
- lineHeight: 1.5,
365
+ lineHeight: "20px",
107
366
  position: "relative",
108
367
  userSelect: "none",
109
- padding: "6px 0",
110
- paddingInline: "$150 $100",
111
- '&:hover:not([aria-disabled="true"])': {
112
- background: "$background-primary-subtle-hover",
113
- color: "$text-primary-hover"
368
+ padding: "6px $100 6px $150",
369
+ ...designSystemStyles.focus.css({
370
+ boxShadow: "$focus-small"
371
+ }),
372
+ '&:not([aria-disabled="true"])': {
373
+ _hover: {
374
+ background: "$background-primary-subtle-hover",
375
+ color: "$text-primary-hover",
376
+ ["".concat(StyledItemCheck)]: {
377
+ color: "$icon-primary-hover"
378
+ }
379
+ }
380
+ },
381
+ "&:disabled, &[aria-disabled=true], &[data-disabled]": {
382
+ cursor: "default",
383
+ color: "$text-neutrals-disabled",
384
+ ["".concat(StyledItemCheck)]: {
385
+ color: "$icon-neutrals-disabled"
386
+ }
387
+ },
388
+ '&[aria-selected="true"]:not(:disabled,[aria-disabled=true],[data-disabled])': {
389
+ color: "$text-primary-selected"
114
390
  }
115
391
  });
116
392
 
117
- const StyledItemIndicator = designSystemStitches.styled(Ariakit__namespace.ComboboxItemCheck, {});
118
-
119
393
  const Item = React__default["default"].forwardRef(
120
- ({ textValue, children, ...restProps }, forwardRef) => /* @__PURE__ */ jsxRuntime.jsxs(StyledItem, { ref: forwardRef, ...restProps, children: [
121
- /* @__PURE__ */ jsxRuntime.jsx(StyledItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconCheckMark, { size: "small" }) }),
122
- children
123
- ] })
394
+ ({ disabled = false, value, textValue, children, ...restProps }, forwardRef) => {
395
+ const { "aria-disabled": ariaDisabled, ...restAriaDisabledProps } = designSystemUseAriaDisabled.useAriaDisabled(restProps, { allowArrows: true });
396
+ const {
397
+ autoFilter,
398
+ filteredItems,
399
+ setItemValueTextMap,
400
+ triggerRef,
401
+ inputRef,
402
+ value: comboboxValue = []
403
+ } = useComboboxContext();
404
+ designSystemUseLayoutEffect.useLayoutEffect(() => {
405
+ const textToSet = textValue !== void 0 ? textValue : typeof children === "string" ? children : "";
406
+ setItemValueTextMap((prevState) => new Map(prevState.set(value, textToSet)));
407
+ return () => {
408
+ setItemValueTextMap((prevState) => {
409
+ prevState.delete(value);
410
+ return new Map(prevState);
411
+ });
412
+ };
413
+ }, [setItemValueTextMap, value, textValue, children]);
414
+ if (autoFilter !== false && !filteredItems.has(value)) {
415
+ return null;
416
+ }
417
+ const scrollIntoView = (event) => {
418
+ var _a;
419
+ if (((_a = inputRef == null ? void 0 : inputRef.current) == null ? void 0 : _a.parentElement) != null && (triggerRef == null ? void 0 : triggerRef.current) != null) {
420
+ inputRef.current.parentElement.scrollTo({
421
+ top: triggerRef.current.scrollHeight
422
+ });
423
+ }
424
+ if (restProps.onClick !== void 0) {
425
+ restProps.onClick(event);
426
+ }
427
+ };
428
+ const isSelected = comboboxValue.includes(value);
429
+ return /* @__PURE__ */ jsxRuntime.jsxs(
430
+ StyledItem,
431
+ {
432
+ ...utils.mergeProps(restProps, restAriaDisabledProps),
433
+ focusable: true,
434
+ hideOnClick: false,
435
+ accessibleWhenDisabled: designSystemUtils.booleanify(ariaDisabled),
436
+ disabled: designSystemUtils.booleanify(ariaDisabled) || disabled,
437
+ ref: forwardRef,
438
+ value,
439
+ onClick: scrollIntoView,
440
+ "aria-selected": isSelected,
441
+ children: [
442
+ /* @__PURE__ */ jsxRuntime.jsx(
443
+ react.ComboboxItemCheck,
444
+ {
445
+ checked: isSelected,
446
+ render: ({ style, ...props }) => (
447
+ // AriakitComboboxItemCheck adds its owm inline styles which we want to omit here
448
+ /* @__PURE__ */ jsxRuntime.jsx(StyledItemCheck, { ...props })
449
+ ),
450
+ children: /* @__PURE__ */ jsxRuntime.jsx(
451
+ designSystemIcons.IconCheckMark,
452
+ {
453
+ size: "small",
454
+ "data-testid": process.env.NODE_ENV === "test" ? "combobox-item-check" : void 0
455
+ }
456
+ )
457
+ }
458
+ ),
459
+ children
460
+ ]
461
+ }
462
+ );
463
+ }
464
+ );
465
+
466
+ const itemType = React__default["default"].createElement(Item).type;
467
+ const getChildrenItemValues = (componentChildren) => {
468
+ const values = [];
469
+ const recurse = (children) => {
470
+ React__default["default"].Children.forEach(children, (child) => {
471
+ if (!React__default["default"].isValidElement(child)) {
472
+ return;
473
+ }
474
+ if (child.type === itemType) {
475
+ const props = child.props;
476
+ values.push(props.value);
477
+ return;
478
+ }
479
+ if (child.props.children) {
480
+ recurse(child.props.children);
481
+ }
482
+ });
483
+ };
484
+ recurse(componentChildren);
485
+ return values;
486
+ };
487
+
488
+ const useDocumentFragment = () => {
489
+ const [fragment, setFragment] = React__default["default"].useState();
490
+ designSystemUseLayoutEffect.useLayoutEffect(() => {
491
+ setFragment(new DocumentFragment());
492
+ }, []);
493
+ return fragment;
494
+ };
495
+
496
+ const useInvisibleContent = () => {
497
+ const fragment = useDocumentFragment();
498
+ return React.useCallback(
499
+ (children) => fragment !== void 0 ? reactDom.createPortal(/* @__PURE__ */ jsxRuntime.jsx("div", { children }), fragment) : null,
500
+ [fragment]
501
+ );
502
+ };
503
+
504
+ const CONTENT_OFFSET = parseInt(designSystemStitches.theme.space[50]);
505
+ const isInsideRef = (element, ref) => {
506
+ var _a, _b;
507
+ return (_b = element != null && ((_a = ref.current) == null ? void 0 : _a.contains(element))) != null ? _b : false;
508
+ };
509
+ const Content = React__default["default"].forwardRef(
510
+ ({
511
+ side = "bottom",
512
+ sideOffset = CONTENT_OFFSET,
513
+ align = "center",
514
+ alignOffset = 0,
515
+ collisionPadding = 0,
516
+ avoidCollisions = true,
517
+ sticky = "partial",
518
+ hideWhenDetached = true,
519
+ overflow = "visible",
520
+ maxHeight,
521
+ children,
522
+ ...restProps
523
+ }, forwardRef) => {
524
+ const {
525
+ triggerRef,
526
+ contentRef,
527
+ autoFilter,
528
+ filteredItems,
529
+ setFilteredItems,
530
+ searchValue,
531
+ noResultsText,
532
+ direction,
533
+ openState
534
+ } = useComboboxContext();
535
+ React.useEffect(() => {
536
+ const childrenItemValues = getChildrenItemValues(children);
537
+ setFilteredItems(
538
+ new Set(
539
+ autoFilter === false ? childrenItemValues : childrenItemValues.filter(
540
+ (child) => child.toLowerCase().includes(searchValue.toLowerCase())
541
+ )
542
+ )
543
+ );
544
+ }, [children, autoFilter, setFilteredItems, searchValue]);
545
+ const getInvisibleContent = useInvisibleContent();
546
+ if (!openState) {
547
+ return getInvisibleContent(children);
548
+ }
549
+ const content = filteredItems.size === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
550
+ /* @__PURE__ */ jsxRuntime.jsx(NoResultPlaceholder, { children: noResultsText }),
551
+ getInvisibleContent(children)
552
+ ] }) : children;
553
+ return /* @__PURE__ */ jsxRuntime.jsx(
554
+ StyledContent,
555
+ {
556
+ asChild: true,
557
+ ...restProps,
558
+ dir: direction,
559
+ side,
560
+ sideOffset,
561
+ align,
562
+ alignOffset,
563
+ avoidCollisions,
564
+ collisionPadding,
565
+ sticky,
566
+ hideWhenDetached,
567
+ ref: designSystemUtils.mergeRefs([forwardRef, contentRef]),
568
+ onOpenAutoFocus: (event) => event.preventDefault(),
569
+ onInteractOutside: (event) => {
570
+ const target = event.target;
571
+ const isTrigger = isInsideRef(target, triggerRef);
572
+ const isContent = isInsideRef(target, contentRef);
573
+ if (isTrigger || isContent) {
574
+ event.preventDefault();
575
+ }
576
+ },
577
+ children: /* @__PURE__ */ jsxRuntime.jsx(react.ComboboxList, { role: "listbox", children: overflow === "auto" ? /* @__PURE__ */ jsxRuntime.jsxs(designSystemScrollArea.ScrollArea, { type: "always", dir: direction, children: [
578
+ /* @__PURE__ */ jsxRuntime.jsx(
579
+ designSystemScrollArea.ScrollArea.Viewport,
580
+ {
581
+ availableHeight: "var(--radix-popover-content-available-height)",
582
+ verticalGap: "var(--space-50) * 2",
583
+ maxHeight,
584
+ children: content
585
+ }
586
+ ),
587
+ /* @__PURE__ */ jsxRuntime.jsx(designSystemScrollArea.ScrollArea.Scrollbar, { orientation: "vertical", children: /* @__PURE__ */ jsxRuntime.jsx(designSystemScrollArea.ScrollArea.Thumb, {}) })
588
+ ] }) : content })
589
+ }
590
+ );
591
+ }
124
592
  );
125
593
 
126
- const Portal = (props) => /* @__PURE__ */ jsxRuntime.jsx(reactPopover.Portal, { ...props });
594
+ const Portal = (props) => /* @__PURE__ */ jsxRuntime.jsx(RadixPopover.Portal, { ...props });
127
595
 
128
- const StyledGroup = designSystemStitches.styled(Ariakit.Group, {});
596
+ const StyledGroup = designSystemStitches.styled(react.Group);
129
597
 
130
- const Group = React__default["default"].forwardRef((props, forwardRef) => /* @__PURE__ */ jsxRuntime.jsx(StyledGroup, { ...props, ref: forwardRef }));
598
+ const Group = React__default["default"].forwardRef(({ children, ...rest }, forwardRef) => {
599
+ const { autoFilter, filteredItems } = useComboboxContext();
600
+ const childValues = React.useMemo(
601
+ // don't perform calculation if auto filter is disabled
602
+ () => autoFilter !== false ? getChildrenItemValues(children) : [],
603
+ [children, autoFilter]
604
+ );
605
+ const hasVisibleChildren = React.useMemo(
606
+ () => (
607
+ // don't perform calculation if auto filter is disabled
608
+ autoFilter !== false ? childValues.some((value) => filteredItems.has(value)) : true
609
+ ),
610
+ [childValues, filteredItems, autoFilter]
611
+ );
612
+ const getInvisibleContent = useInvisibleContent();
613
+ if (!hasVisibleChildren) {
614
+ return getInvisibleContent(children);
615
+ }
616
+ return /* @__PURE__ */ jsxRuntime.jsx(StyledGroup, { ...rest, ref: forwardRef, children });
617
+ });
131
618
 
132
- const StyledGroupLabel = designSystemStitches.styled(Ariakit.GroupLabel, {});
619
+ const StyledGroupLabel = designSystemStitches.styled(react.GroupLabel, {
620
+ padding: "6px $100",
621
+ color: "$text-neutrals-subtle"
622
+ });
133
623
 
134
624
  const GroupLabel = React__default["default"].forwardRef((props, forwardRef) => /* @__PURE__ */ jsxRuntime.jsx(StyledGroupLabel, { ...props, ref: forwardRef }));
135
625
 
136
- const StyledCombobox = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {});
626
+ const StyledChip = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
627
+ fontSize: "$150",
628
+ padding: "$50 $100",
629
+ borderRadius: "$round",
630
+ display: "flex",
631
+ alignItems: "center",
632
+ gap: "$50",
633
+ whiteSpace: "nowrap",
634
+ maxWidth: "$35",
635
+ backgroundColor: "$background-neutrals-subtle",
636
+ color: "$text-neutrals"
637
+ });
638
+ const StyledChipButton = designSystemStitches.styled(designSystemBaseButton.BaseButton, {
639
+ color: "$icon-neutrals-inactive",
640
+ ...designSystemStyles.focus.css({
641
+ boxShadow: "$focus-small-outline"
642
+ })
643
+ });
644
+ const StyledChipContent = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
645
+ textOverflow: "ellipsis",
646
+ whiteSpace: "nowrap",
647
+ overflow: "hidden",
648
+ lineHeight: 1.3
649
+ });
650
+
651
+ const StyledLeftSlot = designSystemStitches.styled(designSystemPrimitive.Primitive.span, {
652
+ order: -1,
653
+ marginRight: "$50"
654
+ });
655
+
656
+ const LeftSlot = StyledLeftSlot;
137
657
 
138
- const Combobox = React__default["default"].forwardRef((props, forwardRef) => /* @__PURE__ */ jsxRuntime.jsx(StyledCombobox, { ...props, ref: forwardRef }));
658
+ const Chip = React__default["default"].forwardRef(
659
+ ({ children, disabled = false, onRemove, removeAriaLabel, ...restProps }, forwardRef) => /* @__PURE__ */ jsxRuntime.jsxs(StyledChip, { ...restProps, ref: forwardRef, children: [
660
+ /* @__PURE__ */ jsxRuntime.jsx(StyledChipContent, { children }),
661
+ !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 }) })
662
+ ] })
663
+ );
664
+ Chip.LeftSlot = LeftSlot;
665
+
666
+ const Value = ({ unselectAriaLabel }) => {
667
+ const {
668
+ value = [],
669
+ setValue,
670
+ disabled,
671
+ "aria-disabled": ariaDisabled,
672
+ itemValueTextMap
673
+ } = useComboboxContext();
674
+ const isDisabled = ariaDisabled === true || disabled;
675
+ const onItemRemove = React.useCallback(
676
+ (item) => {
677
+ setValue((prevValue) => prevValue == null ? void 0 : prevValue.filter((value2) => value2 !== item));
678
+ },
679
+ [setValue]
680
+ );
681
+ const getItemText = React.useCallback(
682
+ (itemValue) => {
683
+ const textValue = itemValueTextMap.get(itemValue);
684
+ if (textValue === void 0 || textValue === "") {
685
+ return null;
686
+ }
687
+ return /* @__PURE__ */ jsxRuntime.jsx(
688
+ Chip,
689
+ {
690
+ onRemove: (e) => {
691
+ onItemRemove(itemValue);
692
+ e.stopPropagation();
693
+ },
694
+ disabled: isDisabled,
695
+ removeAriaLabel: "".concat(unselectAriaLabel, " ").concat(textValue),
696
+ "data-testid": process.env.NODE_ENV === "test" ? "combobox-value-".concat(itemValue) : void 0,
697
+ children: textValue
698
+ },
699
+ itemValue
700
+ );
701
+ },
702
+ [isDisabled, itemValueTextMap, onItemRemove, unselectAriaLabel]
703
+ );
704
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: value.map(getItemText) });
705
+ };
706
+
707
+ const StyledSeparator = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
708
+ backgroundColor: "$border-neutrals-subtle",
709
+ height: "1px",
710
+ width: "100%",
711
+ margin: "$100 0"
712
+ });
713
+
714
+ const Separator = React__default["default"].forwardRef((props, forwardRef) => {
715
+ const { autoFilter, searchValue } = useComboboxContext();
716
+ if (autoFilter === true && searchValue.length > 0) {
717
+ return null;
718
+ }
719
+ return /* @__PURE__ */ jsxRuntime.jsx(StyledSeparator, { ...props, ref: forwardRef, "aria-hidden": true });
720
+ });
721
+
722
+ const StyledNativeSelect = designSystemStitches.styled(designSystemPrimitive.Primitive.select, {
723
+ // if we support autoComplete, we would have to use visually-hidden styles here
724
+ display: "none"
725
+ });
726
+ const StyledComboboxContent = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
727
+ position: "relative",
728
+ width: "100%"
729
+ });
730
+
731
+ const Root = React__default["default"].forwardRef(
732
+ ({ value: valueProp, onValueChange, name, children, ...restProps }, forwardRef) => {
733
+ var _a;
734
+ const {
735
+ openState,
736
+ setOpenState,
737
+ defaultValue,
738
+ value = [],
739
+ setValue,
740
+ required,
741
+ readOnly,
742
+ "aria-disabled": ariaDisabled,
743
+ disabled,
744
+ direction,
745
+ size,
746
+ placeholder,
747
+ triggerRef
748
+ } = useComboboxContext();
749
+ const {
750
+ setRequired,
751
+ setDisabled,
752
+ setAriaDisabled,
753
+ setReadOnly,
754
+ label,
755
+ isFloatingLabel,
756
+ focused,
757
+ formElementRef
758
+ } = designSystemBaseForm.useFormFieldContext();
759
+ React.useEffect(() => {
760
+ setRequired == null ? void 0 : setRequired(required);
761
+ setDisabled == null ? void 0 : setDisabled(disabled);
762
+ setAriaDisabled == null ? void 0 : setAriaDisabled(ariaDisabled);
763
+ setReadOnly == null ? void 0 : setReadOnly(readOnly);
764
+ }, [
765
+ readOnly,
766
+ disabled,
767
+ ariaDisabled,
768
+ required,
769
+ setRequired,
770
+ setDisabled,
771
+ setAriaDisabled,
772
+ setReadOnly
773
+ ]);
774
+ const shouldUseFloatingLabel = label !== null && isFloatingLabel;
775
+ const isFloating = placeholder !== void 0 || value.length !== 0 || focused;
776
+ const onSetSelectedValue = (newValue) => {
777
+ setValue(typeof newValue === "string" ? [newValue] : newValue);
778
+ };
779
+ const onOpenChange = (value2) => {
780
+ if (!designSystemUtils.booleanify(readOnly)) {
781
+ setOpenState(value2);
782
+ }
783
+ };
784
+ const isFormControl = Boolean((_a = triggerRef.current) == null ? void 0 : _a.closest("form"));
785
+ return /* @__PURE__ */ jsxRuntime.jsxs(RadixPopover__namespace.Root, { open: openState, onOpenChange, children: [
786
+ /* @__PURE__ */ jsxRuntime.jsx(
787
+ react.ComboboxProvider,
788
+ {
789
+ open: openState,
790
+ setOpen: onOpenChange,
791
+ defaultSelectedValue: defaultValue,
792
+ selectedValue: value,
793
+ setSelectedValue: onSetSelectedValue,
794
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
795
+ StyledComboboxContent,
796
+ {
797
+ ref: forwardRef,
798
+ ...restProps,
799
+ dir: direction,
800
+ "data-form-element": "select",
801
+ children: [
802
+ shouldUseFloatingLabel && /* @__PURE__ */ jsxRuntime.jsx(designSystemBaseForm.FloatingLabel, { floating: isFloating, size, children: label }),
803
+ children
804
+ ]
805
+ }
806
+ )
807
+ }
808
+ ),
809
+ isFormControl && /* @__PURE__ */ jsxRuntime.jsx(
810
+ StyledNativeSelect,
811
+ {
812
+ multiple: true,
813
+ autoComplete: "off",
814
+ name,
815
+ tabIndex: -1,
816
+ "aria-hidden": "true",
817
+ ref: formElementRef,
818
+ required,
819
+ disabled,
820
+ "aria-disabled": ariaDisabled,
821
+ value,
822
+ onChange: () => {
823
+ },
824
+ children: value.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("option", { value: "" }) : (
825
+ // since we don't support autoComplete we can render here only selected values
826
+ value.map((itemValue) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: itemValue, children: itemValue }, itemValue))
827
+ )
828
+ }
829
+ )
830
+ ] });
831
+ }
832
+ );
833
+ const Combobox = React__default["default"].forwardRef(
834
+ ({
835
+ "aria-disabled": ariaDisabled,
836
+ defaultOpen = false,
837
+ open,
838
+ valid,
839
+ disabled,
840
+ readOnly,
841
+ required,
842
+ value,
843
+ defaultValue,
844
+ onOpen,
845
+ onClose,
846
+ onSearchValueChange,
847
+ onValueChange,
848
+ direction = "ltr",
849
+ autoFilter = true,
850
+ noResultsText,
851
+ ...restProps
852
+ }, forwardRef) => /* @__PURE__ */ jsxRuntime.jsx(
853
+ ComboboxProvider,
854
+ {
855
+ defaultValue,
856
+ value,
857
+ onValueChange,
858
+ onSearchValueChange,
859
+ defaultOpen,
860
+ open,
861
+ onOpen,
862
+ onClose,
863
+ valid,
864
+ required,
865
+ disabled,
866
+ readOnly,
867
+ "aria-disabled": ariaDisabled,
868
+ direction,
869
+ autoFilter,
870
+ noResultsText,
871
+ children: /* @__PURE__ */ jsxRuntime.jsx(Root, { ...restProps, value, ref: forwardRef })
872
+ }
873
+ )
874
+ );
139
875
  Combobox.Portal = Portal;
140
876
  Combobox.Trigger = Trigger;
141
877
  Combobox.Content = Content;
142
878
  Combobox.Item = Item;
143
879
  Combobox.Group = Group;
144
880
  Combobox.GroupLabel = GroupLabel;
881
+ Combobox.Value = Value;
882
+ Combobox.Separator = Separator;
883
+
884
+ var types = /*#__PURE__*/Object.freeze({
885
+ __proto__: null
886
+ });
145
887
 
146
888
  exports.Combobox = Combobox;
889
+ exports.ComboboxTypes = types;
147
890
  //# sourceMappingURL=main.js.map