@mirohq/design-system-combobox 0.1.0-combobox.9 → 0.1.0
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 +212 -142
- package/dist/main.js.map +1 -1
- package/dist/module.js +214 -144
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +83 -5
- package/package.json +10 -10
package/dist/module.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import React, { createContext,
|
|
2
|
+
import React, { createContext, useRef, useState, useContext, useCallback, useEffect, useMemo } from 'react';
|
|
3
3
|
import { Combobox as Combobox$1, ComboboxItem, ComboboxItemCheck, ComboboxList, Group as Group$1, GroupLabel as GroupLabel$1, ComboboxProvider as ComboboxProvider$1 } from '@ariakit/react';
|
|
4
4
|
import { useFormFieldContext, FloatingLabel } from '@mirohq/design-system-base-form';
|
|
5
|
-
import * as RadixPopover from '@radix-ui/react-popover';
|
|
6
|
-
import { Anchor, Trigger as Trigger$1, Portal as Portal$1 } from '@radix-ui/react-popover';
|
|
7
5
|
import { booleanishAttrValue, mergeRefs, booleanify } from '@mirohq/design-system-utils';
|
|
6
|
+
import * as RadixPopover from '@radix-ui/react-popover';
|
|
7
|
+
import { Trigger as Trigger$1, Anchor, Portal as Portal$1 } from '@radix-ui/react-popover';
|
|
8
8
|
import { styled, theme } from '@mirohq/design-system-stitches';
|
|
9
9
|
import { Input } from '@mirohq/design-system-input';
|
|
10
10
|
import { useControllableState } from '@radix-ui/react-use-controllable-state';
|
|
@@ -18,14 +18,10 @@ import { focus } from '@mirohq/design-system-styles';
|
|
|
18
18
|
import { createPortal } from 'react-dom';
|
|
19
19
|
import { BaseButton } from '@mirohq/design-system-base-button';
|
|
20
20
|
|
|
21
|
-
const StyledAnchor = styled(Anchor, {
|
|
22
|
-
position: "relative",
|
|
23
|
-
width: "100%"
|
|
24
|
-
});
|
|
25
21
|
const StyledInput = styled(Input, {
|
|
26
22
|
flexWrap: "wrap",
|
|
27
23
|
flexGrow: 1,
|
|
28
|
-
gap: "
|
|
24
|
+
gap: "$50",
|
|
29
25
|
overflowY: "scroll",
|
|
30
26
|
"&[data-valid], &[data-invalid]": {
|
|
31
27
|
// we don't need a bigger padding here as Input component will render its own icon
|
|
@@ -94,6 +90,8 @@ const ComboboxProvider = ({
|
|
|
94
90
|
});
|
|
95
91
|
const [filteredItems, setFilteredItems] = useState(/* @__PURE__ */ new Set());
|
|
96
92
|
const [searchValue, setSearchValue] = useState("");
|
|
93
|
+
const [size, setSize] = useState();
|
|
94
|
+
const [placeholder, setPlaceholder] = useState();
|
|
97
95
|
const [itemValueTextMap, setItemValueTextMap] = useState(/* @__PURE__ */ new Map());
|
|
98
96
|
const { valid: formFieldValid } = useFormFieldContext();
|
|
99
97
|
return /* @__PURE__ */ jsx(
|
|
@@ -118,7 +116,11 @@ const ComboboxProvider = ({
|
|
|
118
116
|
filteredItems,
|
|
119
117
|
setFilteredItems,
|
|
120
118
|
itemValueTextMap,
|
|
121
|
-
setItemValueTextMap
|
|
119
|
+
setItemValueTextMap,
|
|
120
|
+
placeholder,
|
|
121
|
+
setPlaceholder,
|
|
122
|
+
size,
|
|
123
|
+
setSize
|
|
122
124
|
},
|
|
123
125
|
children
|
|
124
126
|
}
|
|
@@ -202,7 +204,6 @@ const Trigger = React.forwardRef(
|
|
|
202
204
|
closeActionLabel,
|
|
203
205
|
clearActionLabel,
|
|
204
206
|
onChange,
|
|
205
|
-
css,
|
|
206
207
|
...restProps
|
|
207
208
|
}, forwardRef) => {
|
|
208
209
|
const {
|
|
@@ -216,16 +217,21 @@ const Trigger = React.forwardRef(
|
|
|
216
217
|
onSearchValueChange,
|
|
217
218
|
searchValue,
|
|
218
219
|
setSearchValue,
|
|
219
|
-
setOpenState
|
|
220
|
+
setOpenState,
|
|
221
|
+
setSize,
|
|
222
|
+
setPlaceholder
|
|
220
223
|
} = useComboboxContext();
|
|
221
224
|
const {
|
|
222
225
|
formElementId,
|
|
223
226
|
ariaInvalid: formFieldAriaInvalid,
|
|
224
|
-
valid: formFieldValid
|
|
225
|
-
label,
|
|
226
|
-
isFloatingLabel,
|
|
227
|
-
focused
|
|
227
|
+
valid: formFieldValid
|
|
228
228
|
} = useFormFieldContext();
|
|
229
|
+
useEffect(() => {
|
|
230
|
+
setSize(size);
|
|
231
|
+
}, [size, setSize]);
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
setPlaceholder(placeholder);
|
|
234
|
+
}, [setPlaceholder, placeholder]);
|
|
229
235
|
const valid = formFieldValid != null ? formFieldValid : comboboxValid;
|
|
230
236
|
const inputProps = {
|
|
231
237
|
...restProps,
|
|
@@ -240,8 +246,6 @@ const Trigger = React.forwardRef(
|
|
|
240
246
|
id: id != null ? id : formElementId,
|
|
241
247
|
placeholder: value.length === 0 ? placeholder : void 0
|
|
242
248
|
};
|
|
243
|
-
const shouldUseFloatingLabel = label !== null && isFloatingLabel;
|
|
244
|
-
const isFloating = placeholder !== void 0 || value.length !== 0 || focused || searchValue !== "";
|
|
245
249
|
const scrollIntoView = (event) => {
|
|
246
250
|
var _a;
|
|
247
251
|
const trigger = triggerRef == null ? void 0 : triggerRef.current;
|
|
@@ -261,47 +265,43 @@ const Trigger = React.forwardRef(
|
|
|
261
265
|
onSearchValueChange == null ? void 0 : onSearchValueChange(e.target.value);
|
|
262
266
|
onChange == null ? void 0 : onChange(e);
|
|
263
267
|
};
|
|
264
|
-
return /* @__PURE__ */
|
|
265
|
-
|
|
268
|
+
return /* @__PURE__ */ jsx(
|
|
269
|
+
Anchor,
|
|
266
270
|
{
|
|
267
271
|
ref: mergeRefs([triggerRef, forwardRef]),
|
|
268
|
-
css,
|
|
269
272
|
onClick: () => {
|
|
270
273
|
if (!booleanify(disabled) && !booleanify(ariaDisabled) && !booleanify(readOnly)) {
|
|
271
274
|
setOpenState(true);
|
|
272
275
|
}
|
|
273
276
|
},
|
|
274
|
-
children:
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
}
|
|
303
|
-
)
|
|
304
|
-
]
|
|
277
|
+
children: /* @__PURE__ */ jsx(
|
|
278
|
+
Combobox$1,
|
|
279
|
+
{
|
|
280
|
+
render: /* @__PURE__ */ jsxs(
|
|
281
|
+
StyledInput,
|
|
282
|
+
{
|
|
283
|
+
...inputProps,
|
|
284
|
+
value: searchValue,
|
|
285
|
+
size,
|
|
286
|
+
ref: inputRef,
|
|
287
|
+
onChange: onInputChange,
|
|
288
|
+
onFocus: scrollIntoView,
|
|
289
|
+
children: [
|
|
290
|
+
children,
|
|
291
|
+
/* @__PURE__ */ jsx(
|
|
292
|
+
TriggerActionButton,
|
|
293
|
+
{
|
|
294
|
+
openActionLabel,
|
|
295
|
+
closeActionLabel,
|
|
296
|
+
clearActionLabel,
|
|
297
|
+
size
|
|
298
|
+
}
|
|
299
|
+
)
|
|
300
|
+
]
|
|
301
|
+
}
|
|
302
|
+
)
|
|
303
|
+
}
|
|
304
|
+
)
|
|
305
305
|
}
|
|
306
306
|
);
|
|
307
307
|
}
|
|
@@ -372,7 +372,8 @@ const Item = React.forwardRef(
|
|
|
372
372
|
filteredItems,
|
|
373
373
|
setItemValueTextMap,
|
|
374
374
|
triggerRef,
|
|
375
|
-
inputRef
|
|
375
|
+
inputRef,
|
|
376
|
+
value: comboboxValue = []
|
|
376
377
|
} = useComboboxContext();
|
|
377
378
|
useLayoutEffect(() => {
|
|
378
379
|
const textToSet = textValue !== void 0 ? textValue : typeof children === "string" ? children : "";
|
|
@@ -398,6 +399,7 @@ const Item = React.forwardRef(
|
|
|
398
399
|
restProps.onClick(event);
|
|
399
400
|
}
|
|
400
401
|
};
|
|
402
|
+
const isSelected = comboboxValue.includes(value);
|
|
401
403
|
return /* @__PURE__ */ jsxs(
|
|
402
404
|
StyledItem,
|
|
403
405
|
{
|
|
@@ -409,10 +411,12 @@ const Item = React.forwardRef(
|
|
|
409
411
|
ref: forwardRef,
|
|
410
412
|
value,
|
|
411
413
|
onClick: scrollIntoView,
|
|
414
|
+
"aria-selected": isSelected,
|
|
412
415
|
children: [
|
|
413
416
|
/* @__PURE__ */ jsx(
|
|
414
417
|
ComboboxItemCheck,
|
|
415
418
|
{
|
|
419
|
+
checked: isSelected,
|
|
416
420
|
render: ({ style, ...props }) => (
|
|
417
421
|
// AriakitComboboxItemCheck adds its owm inline styles which we want to omit here
|
|
418
422
|
/* @__PURE__ */ jsx(StyledItemCheck, { ...props })
|
|
@@ -478,9 +482,16 @@ const isInsideRef = (element, ref) => {
|
|
|
478
482
|
};
|
|
479
483
|
const Content = React.forwardRef(
|
|
480
484
|
({
|
|
485
|
+
side = "bottom",
|
|
481
486
|
sideOffset = CONTENT_OFFSET,
|
|
487
|
+
align = "center",
|
|
488
|
+
alignOffset = 0,
|
|
489
|
+
collisionPadding = 0,
|
|
490
|
+
avoidCollisions = true,
|
|
491
|
+
sticky = "partial",
|
|
492
|
+
hideWhenDetached = true,
|
|
493
|
+
overflow = "visible",
|
|
482
494
|
maxHeight,
|
|
483
|
-
overflow,
|
|
484
495
|
children,
|
|
485
496
|
...restProps
|
|
486
497
|
}, forwardRef) => {
|
|
@@ -519,7 +530,14 @@ const Content = React.forwardRef(
|
|
|
519
530
|
asChild: true,
|
|
520
531
|
...restProps,
|
|
521
532
|
dir: direction,
|
|
533
|
+
side,
|
|
522
534
|
sideOffset,
|
|
535
|
+
align,
|
|
536
|
+
alignOffset,
|
|
537
|
+
avoidCollisions,
|
|
538
|
+
collisionPadding,
|
|
539
|
+
sticky,
|
|
540
|
+
hideWhenDetached,
|
|
523
541
|
ref: mergeRefs([forwardRef, contentRef]),
|
|
524
542
|
onOpenAutoFocus: (event) => event.preventDefault(),
|
|
525
543
|
onInteractOutside: (event) => {
|
|
@@ -619,10 +637,6 @@ const Chip = React.forwardRef(
|
|
|
619
637
|
);
|
|
620
638
|
Chip.LeftSlot = LeftSlot;
|
|
621
639
|
|
|
622
|
-
const StyledValue = styled(Chip, {
|
|
623
|
-
marginTop: "$50"
|
|
624
|
-
});
|
|
625
|
-
|
|
626
640
|
const Value = ({ unselectAriaLabel }) => {
|
|
627
641
|
const {
|
|
628
642
|
value = [],
|
|
@@ -645,9 +659,12 @@ const Value = ({ unselectAriaLabel }) => {
|
|
|
645
659
|
return null;
|
|
646
660
|
}
|
|
647
661
|
return /* @__PURE__ */ jsx(
|
|
648
|
-
|
|
662
|
+
Chip,
|
|
649
663
|
{
|
|
650
|
-
onRemove: () =>
|
|
664
|
+
onRemove: (e) => {
|
|
665
|
+
onItemRemove(itemValue);
|
|
666
|
+
e.stopPropagation();
|
|
667
|
+
},
|
|
651
668
|
disabled: isDisabled,
|
|
652
669
|
removeAriaLabel: "".concat(unselectAriaLabel, " ").concat(textValue),
|
|
653
670
|
"data-testid": process.env.NODE_ENV === "test" ? "combobox-value-".concat(itemValue) : void 0,
|
|
@@ -676,53 +693,71 @@ const Separator = React.forwardRef((props, forwardRef) => {
|
|
|
676
693
|
return /* @__PURE__ */ jsx(StyledSeparator, { ...props, ref: forwardRef, "aria-hidden": true });
|
|
677
694
|
});
|
|
678
695
|
|
|
679
|
-
const
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
696
|
+
const StyledNativeSelect = styled(Primitive.select, {
|
|
697
|
+
// if we support autoComplete, we would have to use visually-hidden styles here
|
|
698
|
+
display: "none"
|
|
699
|
+
});
|
|
700
|
+
const StyledComboboxContent = styled(Primitive.div, {
|
|
701
|
+
position: "relative",
|
|
702
|
+
width: "100%"
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
const Root = React.forwardRef(
|
|
706
|
+
({ value: valueProp, onValueChange, name, children, ...restProps }, forwardRef) => {
|
|
707
|
+
var _a;
|
|
708
|
+
const {
|
|
709
|
+
openState,
|
|
710
|
+
setOpenState,
|
|
711
|
+
defaultValue,
|
|
712
|
+
value = [],
|
|
713
|
+
setValue,
|
|
714
|
+
required,
|
|
715
|
+
readOnly,
|
|
716
|
+
"aria-disabled": ariaDisabled,
|
|
717
|
+
disabled,
|
|
718
|
+
direction,
|
|
719
|
+
size,
|
|
720
|
+
placeholder,
|
|
721
|
+
triggerRef
|
|
722
|
+
} = useComboboxContext();
|
|
723
|
+
const {
|
|
724
|
+
setRequired,
|
|
725
|
+
setDisabled,
|
|
726
|
+
setAriaDisabled,
|
|
727
|
+
setReadOnly,
|
|
728
|
+
label,
|
|
729
|
+
isFloatingLabel,
|
|
730
|
+
focused,
|
|
731
|
+
formElementRef
|
|
732
|
+
} = useFormFieldContext();
|
|
733
|
+
useEffect(() => {
|
|
734
|
+
setRequired == null ? void 0 : setRequired(required);
|
|
735
|
+
setDisabled == null ? void 0 : setDisabled(disabled);
|
|
736
|
+
setAriaDisabled == null ? void 0 : setAriaDisabled(ariaDisabled);
|
|
737
|
+
setReadOnly == null ? void 0 : setReadOnly(readOnly);
|
|
738
|
+
}, [
|
|
739
|
+
readOnly,
|
|
740
|
+
disabled,
|
|
741
|
+
ariaDisabled,
|
|
742
|
+
required,
|
|
743
|
+
setRequired,
|
|
744
|
+
setDisabled,
|
|
745
|
+
setAriaDisabled,
|
|
746
|
+
setReadOnly
|
|
747
|
+
]);
|
|
748
|
+
const shouldUseFloatingLabel = label !== null && isFloatingLabel;
|
|
749
|
+
const isFloating = placeholder !== void 0 || value.length !== 0 || focused;
|
|
750
|
+
const onSetSelectedValue = (newValue) => {
|
|
751
|
+
setValue(typeof newValue === "string" ? [newValue] : newValue);
|
|
752
|
+
};
|
|
753
|
+
const onOpenChange = (value2) => {
|
|
754
|
+
if (!booleanify(readOnly)) {
|
|
755
|
+
setOpenState(value2);
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
const isFormControl = Boolean((_a = triggerRef.current) == null ? void 0 : _a.closest("form"));
|
|
759
|
+
return /* @__PURE__ */ jsxs(RadixPopover.Root, { open: openState, onOpenChange, children: [
|
|
760
|
+
/* @__PURE__ */ jsx(
|
|
726
761
|
ComboboxProvider$1,
|
|
727
762
|
{
|
|
728
763
|
open: openState,
|
|
@@ -730,51 +765,86 @@ const Root = ({
|
|
|
730
765
|
defaultSelectedValue: defaultValue,
|
|
731
766
|
selectedValue: value,
|
|
732
767
|
setSelectedValue: onSetSelectedValue,
|
|
733
|
-
children
|
|
768
|
+
children: /* @__PURE__ */ jsxs(
|
|
769
|
+
StyledComboboxContent,
|
|
770
|
+
{
|
|
771
|
+
ref: forwardRef,
|
|
772
|
+
...restProps,
|
|
773
|
+
dir: direction,
|
|
774
|
+
"data-form-element": "select",
|
|
775
|
+
children: [
|
|
776
|
+
shouldUseFloatingLabel && /* @__PURE__ */ jsx(FloatingLabel, { floating: isFloating, size, children: label }),
|
|
777
|
+
children
|
|
778
|
+
]
|
|
779
|
+
}
|
|
780
|
+
)
|
|
781
|
+
}
|
|
782
|
+
),
|
|
783
|
+
isFormControl && /* @__PURE__ */ jsx(
|
|
784
|
+
StyledNativeSelect,
|
|
785
|
+
{
|
|
786
|
+
multiple: true,
|
|
787
|
+
autoComplete: "off",
|
|
788
|
+
name,
|
|
789
|
+
tabIndex: -1,
|
|
790
|
+
"aria-hidden": "true",
|
|
791
|
+
ref: formElementRef,
|
|
792
|
+
required,
|
|
793
|
+
disabled,
|
|
794
|
+
"aria-disabled": ariaDisabled,
|
|
795
|
+
value,
|
|
796
|
+
onChange: () => {
|
|
797
|
+
},
|
|
798
|
+
children: value.length === 0 ? /* @__PURE__ */ jsx("option", { value: "" }) : (
|
|
799
|
+
// since we don't support autoComplete we can render here only selected values
|
|
800
|
+
value.map((itemValue) => /* @__PURE__ */ jsx("option", { value: itemValue, children: itemValue }, itemValue))
|
|
801
|
+
)
|
|
734
802
|
}
|
|
735
803
|
)
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
const Combobox = (
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
valid,
|
|
744
|
-
disabled,
|
|
745
|
-
readOnly,
|
|
746
|
-
required,
|
|
747
|
-
value,
|
|
748
|
-
defaultValue,
|
|
749
|
-
onOpen,
|
|
750
|
-
onClose,
|
|
751
|
-
onSearchValueChange,
|
|
752
|
-
onValueChange,
|
|
753
|
-
direction = "ltr",
|
|
754
|
-
autoFilter = true,
|
|
755
|
-
noResultsText,
|
|
756
|
-
...restProps
|
|
757
|
-
}) => /* @__PURE__ */ jsx(
|
|
758
|
-
ComboboxProvider,
|
|
759
|
-
{
|
|
760
|
-
defaultValue,
|
|
761
|
-
value,
|
|
762
|
-
onValueChange,
|
|
763
|
-
onSearchValueChange,
|
|
764
|
-
defaultOpen,
|
|
804
|
+
] });
|
|
805
|
+
}
|
|
806
|
+
);
|
|
807
|
+
const Combobox = React.forwardRef(
|
|
808
|
+
({
|
|
809
|
+
"aria-disabled": ariaDisabled,
|
|
810
|
+
defaultOpen = false,
|
|
765
811
|
open,
|
|
766
|
-
onOpen,
|
|
767
|
-
onClose,
|
|
768
812
|
valid,
|
|
769
|
-
required,
|
|
770
813
|
disabled,
|
|
771
814
|
readOnly,
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
815
|
+
required,
|
|
816
|
+
value,
|
|
817
|
+
defaultValue,
|
|
818
|
+
onOpen,
|
|
819
|
+
onClose,
|
|
820
|
+
onSearchValueChange,
|
|
821
|
+
onValueChange,
|
|
822
|
+
direction = "ltr",
|
|
823
|
+
autoFilter = true,
|
|
775
824
|
noResultsText,
|
|
776
|
-
|
|
777
|
-
}
|
|
825
|
+
...restProps
|
|
826
|
+
}, forwardRef) => /* @__PURE__ */ jsx(
|
|
827
|
+
ComboboxProvider,
|
|
828
|
+
{
|
|
829
|
+
defaultValue,
|
|
830
|
+
value,
|
|
831
|
+
onValueChange,
|
|
832
|
+
onSearchValueChange,
|
|
833
|
+
defaultOpen,
|
|
834
|
+
open,
|
|
835
|
+
onOpen,
|
|
836
|
+
onClose,
|
|
837
|
+
valid,
|
|
838
|
+
required,
|
|
839
|
+
disabled,
|
|
840
|
+
readOnly,
|
|
841
|
+
"aria-disabled": ariaDisabled,
|
|
842
|
+
direction,
|
|
843
|
+
autoFilter,
|
|
844
|
+
noResultsText,
|
|
845
|
+
children: /* @__PURE__ */ jsx(Root, { ...restProps, value, ref: forwardRef })
|
|
846
|
+
}
|
|
847
|
+
)
|
|
778
848
|
);
|
|
779
849
|
Combobox.Portal = Portal;
|
|
780
850
|
Combobox.Trigger = Trigger;
|