@mirohq/design-system-combobox 0.1.0-combobox.1 → 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,35 +4,121 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var React = require('react');
7
+ var react = require('@ariakit/react');
7
8
  var designSystemBaseForm = require('@mirohq/design-system-base-form');
8
- var interactions = require('@react-aria/interactions');
9
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 reactPopover = require('@radix-ui/react-popover');
15
- var react = require('@ariakit/react');
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
 
26
+ function _interopNamespace(e) {
27
+ if (e && e.__esModule) return e;
28
+ var n = Object.create(null);
29
+ if (e) {
30
+ Object.keys(e).forEach(function (k) {
31
+ if (k !== 'default') {
32
+ var d = Object.getOwnPropertyDescriptor(e, k);
33
+ Object.defineProperty(n, k, d.get ? d : {
34
+ enumerable: true,
35
+ get: function () { return e[k]; }
36
+ });
37
+ }
38
+ });
39
+ }
40
+ n["default"] = e;
41
+ return Object.freeze(n);
42
+ }
43
+
19
44
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
45
+ var RadixPopover__namespace = /*#__PURE__*/_interopNamespace(RadixPopover);
20
46
 
21
- 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
+ });
22
81
 
23
82
  const ComboboxContext = React.createContext({});
24
83
  const ComboboxProvider = ({
25
84
  children,
85
+ open: openProp,
26
86
  defaultOpen,
87
+ onOpen,
88
+ onClose,
27
89
  valid,
28
90
  value: valueProp,
29
91
  defaultValue: defaultValueProp,
92
+ onValueChange,
93
+ onSearchValueChange,
94
+ autoFilter = true,
30
95
  ...restProps
31
96
  }) => {
32
- const [openState, setOpenState] = React.useState(defaultOpen);
33
- const [value, setValue] = React.useState(valueProp);
97
+ const triggerRef = React.useRef(null);
98
+ const inputRef = React.useRef(null);
99
+ const contentRef = React.useRef(null);
34
100
  const [defaultValue, setDefaultValue] = React.useState(defaultValueProp);
35
- const [searchValue, setSearchValue] = React.useState();
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());
36
122
  const { valid: formFieldValid } = designSystemBaseForm.useFormFieldContext();
37
123
  return /* @__PURE__ */ jsxRuntime.jsx(
38
124
  ComboboxContext.Provider,
@@ -46,8 +132,21 @@ const ComboboxProvider = ({
46
132
  setValue,
47
133
  setDefaultValue,
48
134
  defaultValue,
135
+ onSearchValueChange,
136
+ triggerRef,
137
+ inputRef,
138
+ contentRef,
139
+ autoFilter,
49
140
  searchValue,
50
- setSearchValue
141
+ setSearchValue,
142
+ filteredItems,
143
+ setFilteredItems,
144
+ itemValueTextMap,
145
+ setItemValueTextMap,
146
+ placeholder,
147
+ setPlaceholder,
148
+ size,
149
+ setSize
51
150
  },
52
151
  children
53
152
  }
@@ -55,6 +154,70 @@ const ComboboxProvider = ({
55
154
  };
56
155
  const useComboboxContext = () => React.useContext(ComboboxContext);
57
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
+ };
220
+
58
221
  const Trigger = React__default["default"].forwardRef(
59
222
  ({
60
223
  id,
@@ -63,142 +226,536 @@ const Trigger = React__default["default"].forwardRef(
63
226
  "aria-describedby": ariaDescribedBy,
64
227
  "aria-invalid": ariaInvalid,
65
228
  placeholder,
66
- onHoverChange,
67
- onHoverStart,
68
- onHoverEnd,
229
+ openActionLabel,
230
+ closeActionLabel,
231
+ clearActionLabel,
232
+ onChange,
69
233
  ...restProps
70
234
  }, forwardRef) => {
71
235
  const {
72
236
  "aria-disabled": ariaDisabled,
73
237
  valid: comboboxValid,
74
238
  disabled,
75
- value
239
+ value = [],
240
+ readOnly,
241
+ triggerRef,
242
+ inputRef,
243
+ onSearchValueChange,
244
+ searchValue,
245
+ setSearchValue,
246
+ setOpenState,
247
+ setSize,
248
+ setPlaceholder
76
249
  } = useComboboxContext();
77
250
  const {
78
251
  formElementId,
79
- ariaDescribedBy: formFieldContextDescribedBy,
80
252
  ariaInvalid: formFieldAriaInvalid,
81
253
  valid: formFieldValid
82
254
  } = designSystemBaseForm.useFormFieldContext();
255
+ React.useEffect(() => {
256
+ setSize(size);
257
+ }, [size, setSize]);
258
+ React.useEffect(() => {
259
+ setPlaceholder(placeholder);
260
+ }, [setPlaceholder, placeholder]);
83
261
  const valid = formFieldValid != null ? formFieldValid : comboboxValid;
84
- const { hoverProps } = interactions.useHover({
85
- onHoverStart,
86
- onHoverEnd,
87
- onHoverChange: (isHovering) => {
88
- onHoverChange == null ? void 0 : onHoverChange(isHovering);
89
- }
90
- });
91
- const commonProps = {
262
+ const inputProps = {
92
263
  ...restProps,
93
- ref: forwardRef,
94
264
  "aria-disabled": ariaDisabled,
95
265
  "aria-invalid": ariaInvalid != null ? ariaInvalid : formFieldAriaInvalid,
96
- "aria-describedby": designSystemUtils.stringAttrValue(
97
- ariaDescribedBy,
98
- formFieldContextDescribedBy
99
- ),
266
+ // todo MDS-1011: use formFieldContextDescribedBy after removing form context from BaseInput
267
+ "aria-describedby": ariaDescribedBy,
100
268
  valid,
101
269
  disabled,
270
+ readOnly,
102
271
  invalid: designSystemUtils.booleanishAttrValue(valid),
103
272
  id: id != null ? id : formElementId,
104
- placeholder: value === void 0 ? placeholder : void 0
273
+ placeholder: value.length === 0 ? placeholder : void 0
105
274
  };
106
- const variants = {
107
- 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
+ }
108
288
  };
109
- return /* @__PURE__ */ jsxRuntime.jsxs(StyledTrigger, { ...hoverProps, ...commonProps, ...variants, children: [
110
- children,
111
- /* @__PURE__ */ jsxRuntime.jsx(designSystemInput.Input.ActionButton, { label: "custom label", children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconChevronDown, { size: "small", weight: "thin" }) })
112
- ] });
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
+ );
113
333
  }
114
334
  );
115
335
 
116
- 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, {
117
340
  backgroundColor: "$background-neutrals-container",
118
341
  borderRadius: "$50",
119
342
  boxShadow: "$50",
120
- 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",
121
349
  padding: "$50",
122
- zIndex: "$select"
350
+ boxSizing: "border-box",
351
+ outline: "1px solid transparent"
123
352
  });
124
353
 
125
- const Content = React__default["default"].forwardRef(({ children, ...restProps }, forwardRef) => {
126
- const { open, openState } = useComboboxContext();
127
- if (!designSystemUtils.booleanify(open != null ? open : openState))
128
- return null;
129
- return /* @__PURE__ */ jsxRuntime.jsx(StyledContent, { ...restProps, ref: forwardRef, children });
354
+ const StyledItemCheck = designSystemStitches.styled(designSystemPrimitive.Primitive.span, {
355
+ color: "$icon-primary"
130
356
  });
131
-
132
- const StyledItem = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
357
+ const StyledItem = designSystemStitches.styled(react.ComboboxItem, {
358
+ display: "grid",
359
+ gridTemplateColumns: "20px 1fr",
133
360
  borderRadius: "$50",
134
361
  boxSizing: "border-box",
135
362
  color: "$text-neutrals",
136
363
  cursor: "pointer",
137
364
  fontSize: "$175",
138
- lineHeight: 1.5,
365
+ lineHeight: "20px",
139
366
  position: "relative",
140
367
  userSelect: "none",
141
- padding: "6px 0",
142
- paddingInline: "$150 $100",
143
- '&:hover:not([aria-disabled="true"])': {
144
- background: "$background-primary-subtle-hover",
145
- 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"
146
390
  }
147
391
  });
148
392
 
149
393
  const Item = React__default["default"].forwardRef(
150
- ({ value, textValue, children, ...restProps }, forwardRef) => {
151
- const { value: comboboxValue } = useComboboxContext();
152
- const isSelected = comboboxValue === value;
153
- return /* @__PURE__ */ jsxRuntime.jsxs(StyledItem, { ref: forwardRef, ...restProps, children: [
154
- isSelected && /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconCheckMark, { size: "small", weight: "thin" }),
155
- children
156
- ] });
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
+ );
157
591
  }
158
592
  );
159
593
 
160
- const Portal = (props) => /* @__PURE__ */ jsxRuntime.jsx(reactPopover.Portal, { ...props });
594
+ const Portal = (props) => /* @__PURE__ */ jsxRuntime.jsx(RadixPopover.Portal, { ...props });
161
595
 
162
- const StyledGroup = designSystemStitches.styled(react.Group, {});
596
+ const StyledGroup = designSystemStitches.styled(react.Group);
163
597
 
164
- 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
+ });
165
618
 
166
- const StyledGroupLabel = designSystemStitches.styled(react.GroupLabel, {});
619
+ const StyledGroupLabel = designSystemStitches.styled(react.GroupLabel, {
620
+ padding: "6px $100",
621
+ color: "$text-neutrals-subtle"
622
+ });
167
623
 
168
624
  const GroupLabel = React__default["default"].forwardRef((props, forwardRef) => /* @__PURE__ */ jsxRuntime.jsx(StyledGroupLabel, { ...props, ref: forwardRef }));
169
625
 
170
- const StyledValue = designSystemStitches.styled(designSystemPrimitive.Primitive.span, {});
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
+ });
171
650
 
172
- const Value = React__default["default"].forwardRef(
173
- (props, forwardRef) => {
174
- const { value } = useComboboxContext();
175
- const isEmpty = value === void 0;
176
- if (isEmpty) {
177
- return null;
178
- }
179
- return /* @__PURE__ */ jsxRuntime.jsx(StyledValue, { ref: forwardRef, ...props, children: value });
180
- }
651
+ const StyledLeftSlot = designSystemStitches.styled(designSystemPrimitive.Primitive.span, {
652
+ order: -1,
653
+ marginRight: "$50"
654
+ });
655
+
656
+ const LeftSlot = StyledLeftSlot;
657
+
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
+ ] })
181
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
+ });
182
721
 
183
- const StyledComboboxContent = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {});
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
+ });
184
730
 
185
731
  const Root = React__default["default"].forwardRef(
186
- ({
187
- onOpen,
188
- onClose,
189
- onValueChange,
190
- value: valueProp,
191
- children,
192
- ...restProps
193
- }, forwardRef) => {
732
+ ({ value: valueProp, onValueChange, name, children, ...restProps }, forwardRef) => {
733
+ var _a;
194
734
  const {
735
+ openState,
736
+ setOpenState,
737
+ defaultValue,
738
+ value = [],
739
+ setValue,
195
740
  required,
196
741
  readOnly,
197
742
  "aria-disabled": ariaDisabled,
198
743
  disabled,
199
- direction
744
+ direction,
745
+ size,
746
+ placeholder,
747
+ triggerRef
200
748
  } = useComboboxContext();
201
- const { setRequired, setDisabled, setAriaDisabled, setReadOnly } = designSystemBaseForm.useFormFieldContext();
749
+ const {
750
+ setRequired,
751
+ setDisabled,
752
+ setAriaDisabled,
753
+ setReadOnly,
754
+ label,
755
+ isFloatingLabel,
756
+ focused,
757
+ formElementRef
758
+ } = designSystemBaseForm.useFormFieldContext();
202
759
  React.useEffect(() => {
203
760
  setRequired == null ? void 0 : setRequired(required);
204
761
  setDisabled == null ? void 0 : setDisabled(disabled);
@@ -214,7 +771,63 @@ const Root = React__default["default"].forwardRef(
214
771
  setAriaDisabled,
215
772
  setReadOnly
216
773
  ]);
217
- return /* @__PURE__ */ jsxRuntime.jsx(StyledComboboxContent, { ...restProps, ref: forwardRef, dir: direction, children });
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
+ ] });
218
831
  }
219
832
  );
220
833
  const Combobox = React__default["default"].forwardRef(
@@ -228,21 +841,33 @@ const Combobox = React__default["default"].forwardRef(
228
841
  required,
229
842
  value,
230
843
  defaultValue,
844
+ onOpen,
845
+ onClose,
846
+ onSearchValueChange,
847
+ onValueChange,
231
848
  direction = "ltr",
849
+ autoFilter = true,
850
+ noResultsText,
232
851
  ...restProps
233
852
  }, forwardRef) => /* @__PURE__ */ jsxRuntime.jsx(
234
853
  ComboboxProvider,
235
854
  {
236
855
  defaultValue,
237
856
  value,
857
+ onValueChange,
858
+ onSearchValueChange,
238
859
  defaultOpen,
239
860
  open,
861
+ onOpen,
862
+ onClose,
240
863
  valid,
241
864
  required,
242
865
  disabled,
243
866
  readOnly,
244
867
  "aria-disabled": ariaDisabled,
245
868
  direction,
869
+ autoFilter,
870
+ noResultsText,
246
871
  children: /* @__PURE__ */ jsxRuntime.jsx(Root, { ...restProps, value, ref: forwardRef })
247
872
  }
248
873
  )
@@ -254,6 +879,12 @@ Combobox.Item = Item;
254
879
  Combobox.Group = Group;
255
880
  Combobox.GroupLabel = GroupLabel;
256
881
  Combobox.Value = Value;
882
+ Combobox.Separator = Separator;
883
+
884
+ var types = /*#__PURE__*/Object.freeze({
885
+ __proto__: null
886
+ });
257
887
 
258
888
  exports.Combobox = Combobox;
889
+ exports.ComboboxTypes = types;
259
890
  //# sourceMappingURL=main.js.map