@socprime/react-ui 0.0.12 → 0.0.13

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/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as AccordionPrimitive from '@radix-ui/react-accordion';
2
2
  import * as React$1 from 'react';
3
- import React__default, { ComponentProps, FC } from 'react';
3
+ import React__default, { ComponentProps, ReactNode, FC } from 'react';
4
4
  import { LucideIcon, LucideProps } from 'lucide-react';
5
5
  import * as class_variance_authority_types from 'class-variance-authority/types';
6
6
  import { VariantProps } from 'class-variance-authority';
@@ -409,7 +409,7 @@ interface MultiSelectOption {
409
409
  interface MultiSelectProps {
410
410
  loading?: boolean;
411
411
  options: MultiSelectOption[];
412
- value: string[];
412
+ value?: string[];
413
413
  placeholder?: string;
414
414
  className?: string;
415
415
  disabled?: boolean;
@@ -427,6 +427,39 @@ interface MultiSelectProps {
427
427
  }
428
428
  declare function MultiSelect({ loading, options, value, placeholder, className, disabled, maxDisplay, maxSelection, searchable, size, dropdownClassName, align, variant, badgeClassNames, id, name, onChange, }: MultiSelectProps): React$1.JSX.Element;
429
429
 
430
+ interface BaseMultiSelectOptionState {
431
+ selected: boolean;
432
+ disabled: boolean;
433
+ toggle: () => void;
434
+ }
435
+ interface BaseMultiSelectValueHelpers {
436
+ remove: (value: string) => void;
437
+ clear: () => void;
438
+ }
439
+ interface BaseMultiSelectProps<T> {
440
+ options: T[];
441
+ value?: string[];
442
+ onChange: (value: string[]) => void;
443
+ getOptionValue: (option: T) => string;
444
+ isOptionDisabled?: (option: T) => boolean;
445
+ renderOption?: (option: T, state: BaseMultiSelectOptionState) => ReactNode;
446
+ renderValue?: (selectedOptions: T[], helpers: BaseMultiSelectValueHelpers) => ReactNode;
447
+ renderEmpty?: () => ReactNode;
448
+ placeholder?: ReactNode;
449
+ loading?: boolean;
450
+ disabled?: boolean;
451
+ open?: boolean;
452
+ onOpenChange?: (open: boolean) => void;
453
+ className?: string;
454
+ dropdownClassName?: string;
455
+ align?: 'start' | 'center' | 'end';
456
+ sideOffset?: number;
457
+ size?: 'sm' | 'default';
458
+ id?: string;
459
+ name?: string;
460
+ }
461
+ declare function BaseMultiSelect<T>({ options, value, onChange, getOptionValue, isOptionDisabled, renderOption, renderValue, renderEmpty, placeholder, loading, disabled, open, onOpenChange, className, dropdownClassName, align, sideOffset, size, id, name, }: BaseMultiSelectProps<T>): React$1.JSX.Element;
462
+
430
463
  interface PageHeaderProps {
431
464
  loading?: boolean;
432
465
  title?: string;
@@ -735,4 +768,4 @@ declare function TreeRow({ className, children, ...props }: ComponentProps<'div'
735
768
  type TreeGuideProps = ComponentProps<typeof TreeGuide>;
736
769
  type TreeRowProps = ComponentProps<typeof TreeRow>;
737
770
 
738
- export { Accordion, type AccordionChevronVariant, AccordionContent, type AccordionContentProps, AccordionItem, type AccordionItemProps, type AccordionProps, AccordionSection, type AccordionSectionProps, AccordionTrigger, type AccordionTriggerProps, AnimatedDots, type AnimatedDotsProps, Aside, AsideHorizontal, type AsideHorizontalProps, type AsideProps, type AsideTab, Badge, type BadgeProps, Button, type ButtonProps, Checkbox, type CheckboxProps, ConditionalContent, type ConditionalContentProps, ConfirmDeleteDialog, type ConfirmDeleteDialogProps, ConfirmDeleteDialog as ConfirmDialog, DefaultDialog, type DefaultDialogProps, DeleteButtonConfirm, type DeleteButtonConfirmProps, Dialog, DialogClose, type DialogCloseProps, DialogContent, type DialogContentProps, DialogDescription, type DialogDescriptionProps, DialogFooter, type DialogFooterProps, DialogHeader, type DialogHeaderProps, DialogOverlay, type DialogOverlayProps, DialogPortal, type DialogPortalProps, type DialogProps, DialogTitle, type DialogTitleProps, DialogTrigger, type DialogTriggerProps, DropdownMenu, DropdownMenuCheckboxItem, type DropdownMenuCheckboxItemProps, DropdownMenuContent, type DropdownMenuContentProps, DropdownMenuGroup, type DropdownMenuGroupProps, DropdownMenuItem, type DropdownMenuItemProps, DropdownMenuLabel, type DropdownMenuLabelProps, DropdownMenuPortal, type DropdownMenuPortalProps, type DropdownMenuProps, DropdownMenuRadioGroup, type DropdownMenuRadioGroupProps, DropdownMenuRadioItem, type DropdownMenuRadioItemProps, DropdownMenuSeparator, type DropdownMenuSeparatorProps, DropdownMenuShortcut, type DropdownMenuShortcutProps, DropdownMenuSub, DropdownMenuSubContent, type DropdownMenuSubContentProps, type DropdownMenuSubProps, DropdownMenuSubTrigger, type DropdownMenuSubTriggerProps, DropdownMenuTrigger, type DropdownMenuTriggerProps, DropdownsCheckbox, type DropdownsCheckboxOption, type DropdownsCheckboxProps, DropdownsSelect, type DropdownsSelectOption, type DropdownsSelectProps, EmptyState, type EmptyStateProps, Field, FieldContent, type FieldContentProps, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorProps, FieldGroup, type FieldGroupProps, FieldLabel, type FieldLabelProps, FieldLegend, type FieldLegendProps, type FieldProps, FieldSeparator, type FieldSeparatorProps, FieldSet, type FieldSetProps, FieldTitle, type FieldTitleProps, FolderTreeExpandTrigger, type FolderTreeExpandTriggerProps, GroupHeaderRow, type GroupHeaderRowProps, HelperText, type HelperTextProps, Input, InputNumber, type InputNumberProps, InputPassword, type InputPasswordProps, type InputProps, Label, LabelInfo, type LabelInfoProps, type LabelProps, MobileNav, type MobileNavItem, type MobileNavProps, MultiSelect, type MultiSelectOption, type MultiSelectProps, PageHeader, type PageHeaderProps, Pagination, PaginationContent, type PaginationContentProps, PaginationEllipsis, type PaginationEllipsisProps, PaginationItem, type PaginationItemProps, PaginationLink, type PaginationLinkProps, PaginationNext, type PaginationNextProps, PaginationPrevious, type PaginationPreviousProps, type PaginationProps, PaginationWrap, type PaginationWrapProps, Progress, type ProgressProps, RadioGroup, RadioGroupItem, type RadioGroupItemProps, type RadioGroupProps, ScrollArea, type ScrollAreaOrientation, type ScrollAreaProps, ScrollBar, SearchInput, SearchInputFields, type SearchInputFieldsProps, type SearchInputProps, Select, SelectContent, type SelectContentProps, SelectDefault, type SelectDefaultProps, SelectGroup, type SelectGroupProps, SelectItem, type SelectItemProps, SelectLabel, type SelectLabelProps, type SelectProps, SelectScrollDownButton, type SelectScrollDownButtonProps, SelectScrollUpButton, type SelectScrollUpButtonProps, SelectSeparator, type SelectSeparatorProps, SelectTrigger, type SelectTriggerProps, SelectValue, type SelectValueProps, Separator, type SeparatorProps, ServerGroupedTableBody, type ServerGroupedTableBodyProps, Skeleton, type SkeletonProps, SkeletonTable, type SkeletonTableProps, Slider, type SliderProps, SortableHeader, type SortableHeaderProps, Spinner, SpinnerCircle, type SpinnerCircleProps, SpinnerCustom, type SpinnerProps, SpinnerSquare, type SpinnerSquareProps, type SuggestionOption, Suggestions, type SuggestionsProps, Switch, type SwitchProps, type TabItem, Table, TableBody, type TableBodyProps, TableCaption, type TableCaptionProps, TableCell, type TableCellProps, TableFooter, type TableFooterProps, TableHead, type TableHeadProps, TableHeader, type TableHeaderProps, type TableProps, TableRow, type TableRowProps, TableWrap, type TableWrapProps, Tabs, type TabsProps, TextTruncate, type TextTruncateProps, Textarea, type TextareaProps, ThemeToggle, type ThemeToggleProps, Toaster, Tooltip, TooltipContent, type TooltipContentProps, TooltipParent, type TooltipParentProps, type TooltipProps, TooltipProvider, type TooltipProviderProps, TooltipTrigger, type TooltipTriggerProps, TreeGuide, type TreeGuideProps, TreeRow, type TreeRowProps, badgeVariants, buttonVariants };
771
+ export { Accordion, type AccordionChevronVariant, AccordionContent, type AccordionContentProps, AccordionItem, type AccordionItemProps, type AccordionProps, AccordionSection, type AccordionSectionProps, AccordionTrigger, type AccordionTriggerProps, AnimatedDots, type AnimatedDotsProps, Aside, AsideHorizontal, type AsideHorizontalProps, type AsideProps, type AsideTab, Badge, type BadgeProps, BaseMultiSelect, type BaseMultiSelectOptionState, type BaseMultiSelectProps, type BaseMultiSelectValueHelpers, Button, type ButtonProps, Checkbox, type CheckboxProps, ConditionalContent, type ConditionalContentProps, ConfirmDeleteDialog, type ConfirmDeleteDialogProps, ConfirmDeleteDialog as ConfirmDialog, DefaultDialog, type DefaultDialogProps, DeleteButtonConfirm, type DeleteButtonConfirmProps, Dialog, DialogClose, type DialogCloseProps, DialogContent, type DialogContentProps, DialogDescription, type DialogDescriptionProps, DialogFooter, type DialogFooterProps, DialogHeader, type DialogHeaderProps, DialogOverlay, type DialogOverlayProps, DialogPortal, type DialogPortalProps, type DialogProps, DialogTitle, type DialogTitleProps, DialogTrigger, type DialogTriggerProps, DropdownMenu, DropdownMenuCheckboxItem, type DropdownMenuCheckboxItemProps, DropdownMenuContent, type DropdownMenuContentProps, DropdownMenuGroup, type DropdownMenuGroupProps, DropdownMenuItem, type DropdownMenuItemProps, DropdownMenuLabel, type DropdownMenuLabelProps, DropdownMenuPortal, type DropdownMenuPortalProps, type DropdownMenuProps, DropdownMenuRadioGroup, type DropdownMenuRadioGroupProps, DropdownMenuRadioItem, type DropdownMenuRadioItemProps, DropdownMenuSeparator, type DropdownMenuSeparatorProps, DropdownMenuShortcut, type DropdownMenuShortcutProps, DropdownMenuSub, DropdownMenuSubContent, type DropdownMenuSubContentProps, type DropdownMenuSubProps, DropdownMenuSubTrigger, type DropdownMenuSubTriggerProps, DropdownMenuTrigger, type DropdownMenuTriggerProps, DropdownsCheckbox, type DropdownsCheckboxOption, type DropdownsCheckboxProps, DropdownsSelect, type DropdownsSelectOption, type DropdownsSelectProps, EmptyState, type EmptyStateProps, Field, FieldContent, type FieldContentProps, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorProps, FieldGroup, type FieldGroupProps, FieldLabel, type FieldLabelProps, FieldLegend, type FieldLegendProps, type FieldProps, FieldSeparator, type FieldSeparatorProps, FieldSet, type FieldSetProps, FieldTitle, type FieldTitleProps, FolderTreeExpandTrigger, type FolderTreeExpandTriggerProps, GroupHeaderRow, type GroupHeaderRowProps, HelperText, type HelperTextProps, Input, InputNumber, type InputNumberProps, InputPassword, type InputPasswordProps, type InputProps, Label, LabelInfo, type LabelInfoProps, type LabelProps, MobileNav, type MobileNavItem, type MobileNavProps, MultiSelect, type MultiSelectOption, type MultiSelectProps, PageHeader, type PageHeaderProps, Pagination, PaginationContent, type PaginationContentProps, PaginationEllipsis, type PaginationEllipsisProps, PaginationItem, type PaginationItemProps, PaginationLink, type PaginationLinkProps, PaginationNext, type PaginationNextProps, PaginationPrevious, type PaginationPreviousProps, type PaginationProps, PaginationWrap, type PaginationWrapProps, Progress, type ProgressProps, RadioGroup, RadioGroupItem, type RadioGroupItemProps, type RadioGroupProps, ScrollArea, type ScrollAreaOrientation, type ScrollAreaProps, ScrollBar, SearchInput, SearchInputFields, type SearchInputFieldsProps, type SearchInputProps, Select, SelectContent, type SelectContentProps, SelectDefault, type SelectDefaultProps, SelectGroup, type SelectGroupProps, SelectItem, type SelectItemProps, SelectLabel, type SelectLabelProps, type SelectProps, SelectScrollDownButton, type SelectScrollDownButtonProps, SelectScrollUpButton, type SelectScrollUpButtonProps, SelectSeparator, type SelectSeparatorProps, SelectTrigger, type SelectTriggerProps, SelectValue, type SelectValueProps, Separator, type SeparatorProps, ServerGroupedTableBody, type ServerGroupedTableBodyProps, Skeleton, type SkeletonProps, SkeletonTable, type SkeletonTableProps, Slider, type SliderProps, SortableHeader, type SortableHeaderProps, Spinner, SpinnerCircle, type SpinnerCircleProps, SpinnerCustom, type SpinnerProps, SpinnerSquare, type SpinnerSquareProps, type SuggestionOption, Suggestions, type SuggestionsProps, Switch, type SwitchProps, type TabItem, Table, TableBody, type TableBodyProps, TableCaption, type TableCaptionProps, TableCell, type TableCellProps, TableFooter, type TableFooterProps, TableHead, type TableHeadProps, TableHeader, type TableHeaderProps, type TableProps, TableRow, type TableRowProps, TableWrap, type TableWrapProps, Tabs, type TabsProps, TextTruncate, type TextTruncateProps, Textarea, type TextareaProps, ThemeToggle, type ThemeToggleProps, Toaster, Tooltip, TooltipContent, type TooltipContentProps, TooltipParent, type TooltipParentProps, type TooltipProps, TooltipProvider, type TooltipProviderProps, TooltipTrigger, type TooltipTriggerProps, TreeGuide, type TreeGuideProps, TreeRow, type TreeRowProps, badgeVariants, buttonVariants };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@socprime/react-ui",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "SOC Prime React UI component library and Storybook design system.",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -0,0 +1,147 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { ChevronDownIcon, Loader2 } from "lucide-react";
3
+ import { useState } from "react";
4
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
5
+ import { Checkbox } from "../Checkbox/Checkbox.js";
6
+ import { ScrollArea } from "../ScrollArea/ScrollArea.js";
7
+ import { cn } from "../../lib/cn.js";
8
+ function BaseMultiSelect({
9
+ options,
10
+ value = [],
11
+ onChange,
12
+ getOptionValue,
13
+ isOptionDisabled,
14
+ renderOption,
15
+ renderValue,
16
+ renderEmpty,
17
+ placeholder = "Select...",
18
+ loading = false,
19
+ disabled = false,
20
+ open,
21
+ onOpenChange,
22
+ className,
23
+ dropdownClassName,
24
+ align = "start",
25
+ sideOffset = 4,
26
+ size = "default",
27
+ id,
28
+ name
29
+ }) {
30
+ const [internalOpen, setInternalOpen] = useState(false);
31
+ const isOpen = open ?? internalOpen;
32
+ const handleOpenChange = (nextOpen) => {
33
+ setInternalOpen(nextOpen);
34
+ onOpenChange?.(nextOpen);
35
+ };
36
+ const toggle = (optionValue) => {
37
+ onChange(
38
+ value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue]
39
+ );
40
+ };
41
+ const helpers = {
42
+ remove: (optionValue) => onChange(value.filter((v) => v !== optionValue)),
43
+ clear: () => onChange([])
44
+ };
45
+ const selectedOptions = options.filter((option) => value.includes(getOptionValue(option)));
46
+ const renderOptionItem = (option) => {
47
+ const optionValue = getOptionValue(option);
48
+ const selected = value.includes(optionValue);
49
+ const optionDisabled = isOptionDisabled?.(option) ?? false;
50
+ const state = {
51
+ selected,
52
+ disabled: optionDisabled,
53
+ toggle: () => {
54
+ if (!optionDisabled) toggle(optionValue);
55
+ }
56
+ };
57
+ return /* @__PURE__ */ jsx(
58
+ "div",
59
+ {
60
+ role: "option",
61
+ "aria-selected": selected,
62
+ "aria-disabled": optionDisabled,
63
+ tabIndex: optionDisabled ? -1 : 0,
64
+ onClick: state.toggle,
65
+ onKeyDown: (e) => {
66
+ if (e.key === "Enter" || e.key === " ") {
67
+ e.preventDefault();
68
+ state.toggle();
69
+ }
70
+ },
71
+ className: cn(
72
+ "flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-xs transition-colors outline-none",
73
+ "hover:bg-hover focus-visible:bg-hover focus-visible:text-default",
74
+ selected && "bg-hover",
75
+ optionDisabled && "cursor-not-allowed opacity-50"
76
+ ),
77
+ children: renderOption ? renderOption(option, state) : /* @__PURE__ */ jsxs(Fragment, { children: [
78
+ /* @__PURE__ */ jsx(
79
+ Checkbox,
80
+ {
81
+ checked: selected,
82
+ disabled: optionDisabled,
83
+ tabIndex: -1,
84
+ className: "pointer-events-none"
85
+ }
86
+ ),
87
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: optionValue })
88
+ ] })
89
+ },
90
+ optionValue
91
+ );
92
+ };
93
+ return /* @__PURE__ */ jsxs(PopoverPrimitive.Root, { open: isOpen, onOpenChange: handleOpenChange, children: [
94
+ /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
95
+ "button",
96
+ {
97
+ type: "button",
98
+ id,
99
+ name,
100
+ disabled,
101
+ "data-size": size,
102
+ "data-state": isOpen ? "open" : "closed",
103
+ className: cn(
104
+ 'border-border bg-secondary data-[placeholder]:text-gray-chateau [&_svg:not([class*="text-"])]:text-gray-chateau flex min-h-9 w-full items-center justify-between gap-2 rounded-md border px-3 py-1 text-xs font-normal transition-[color,box-shadow] outline-none',
105
+ "data-[size=sm]:min-h-8 data-[size=sm]:px-2",
106
+ "focus-visible:border-success focus-visible:ring-success/40 focus-visible:ring-[2px]",
107
+ "data-[state=open]:border-success data-[state=open]:ring-success/40 data-[state=open]:ring-[2px]",
108
+ "disabled:cursor-not-allowed disabled:opacity-50",
109
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0",
110
+ className
111
+ ),
112
+ children: [
113
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-wrap items-center gap-1", children: selectedOptions.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-gray-chateau", children: placeholder }) : renderValue ? renderValue(selectedOptions, helpers) : /* @__PURE__ */ jsx("span", { children: selectedOptions.map(getOptionValue).join(", ") }) }),
114
+ loading ? /* @__PURE__ */ jsx(Loader2, { className: "text-gray-chateau size-4 animate-spin" }) : /* @__PURE__ */ jsx(ChevronDownIcon, { className: "ml-2 size-4 shrink-0 opacity-50" })
115
+ ]
116
+ }
117
+ ) }),
118
+ /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
119
+ PopoverPrimitive.Content,
120
+ {
121
+ align,
122
+ sideOffset,
123
+ className: cn(
124
+ "bg-secondary border-border text-foreground z-50 w-[var(--radix-popover-trigger-width)] rounded-md border shadow-md outline-none",
125
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
126
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
127
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
128
+ "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
129
+ "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
130
+ dropdownClassName
131
+ ),
132
+ children: /* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx(
133
+ "div",
134
+ {
135
+ role: "listbox",
136
+ "aria-multiselectable": "true",
137
+ className: "flex max-h-64 flex-col gap-2 p-3",
138
+ children: options.length === 0 ? renderEmpty?.() ?? /* @__PURE__ */ jsx("div", { className: "text-gray-chateau py-6 text-center text-xs", children: "Nothing found" }) : options.map(renderOptionItem)
139
+ }
140
+ ) })
141
+ }
142
+ ) })
143
+ ] });
144
+ }
145
+ export {
146
+ BaseMultiSelect
147
+ };
@@ -37,9 +37,22 @@ function MultiSelect({
37
37
  () => options.filter((option) => value.includes(option.value)),
38
38
  [options, value]
39
39
  );
40
- const displayedBadges = selectedOptions.slice(0, maxDisplay);
41
- const remainingCount = selectedOptions.length - maxDisplay;
40
+ const orphanValues = useMemo(
41
+ () => value.filter((v) => !options.some((option) => option.value === v)),
42
+ [options, value]
43
+ );
44
+ const allSelected = useMemo(
45
+ () => [...selectedOptions, ...orphanValues.map((v) => ({ label: v, value: v }))],
46
+ [selectedOptions, orphanValues]
47
+ );
48
+ const displayedBadges = allSelected.slice(0, maxDisplay);
49
+ const remainingCount = allSelected.length - maxDisplay;
50
+ const hiddenLabels = allSelected.slice(maxDisplay).map((option) => option.label).join(", ");
42
51
  const isMaxReached = maxSelection !== void 0 && value.length >= maxSelection;
52
+ const handleOpenChange = (nextOpen) => {
53
+ setOpen(nextOpen);
54
+ if (!nextOpen) setSearchQuery("");
55
+ };
43
56
  const handleToggle = (optionValue) => {
44
57
  const isSelected = value.includes(optionValue);
45
58
  if (isSelected) {
@@ -53,7 +66,7 @@ function MultiSelect({
53
66
  onChange(value.filter((v) => v !== optionValue));
54
67
  };
55
68
  const renderSelectedBadges = () => {
56
- if (selectedOptions.length === 0) {
69
+ if (allSelected.length === 0) {
57
70
  return /* @__PURE__ */ jsx("span", { className: "text-gray-chateau", children: placeholder });
58
71
  }
59
72
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -67,7 +80,7 @@ function MultiSelect({
67
80
  },
68
81
  option.value
69
82
  )),
70
- remainingCount > 0 && /* @__PURE__ */ jsxs(Badge, { variant: "outline", children: [
83
+ remainingCount > 0 && /* @__PURE__ */ jsxs(Badge, { variant: "outline", title: hiddenLabels, children: [
71
84
  "+",
72
85
  remainingCount
73
86
  ] })
@@ -76,12 +89,26 @@ function MultiSelect({
76
89
  const renderOptionItem = (option) => {
77
90
  const isSelected = value.includes(option.value);
78
91
  const isDisabled = option.disabled || !isSelected && isMaxReached;
92
+ const handleSelect = () => {
93
+ if (!isDisabled) handleToggle(option.value);
94
+ };
79
95
  return /* @__PURE__ */ jsxs(
80
- "label",
96
+ "div",
81
97
  {
98
+ role: "option",
99
+ "aria-selected": isSelected,
100
+ "aria-disabled": isDisabled,
101
+ tabIndex: isDisabled ? -1 : 0,
102
+ onClick: handleSelect,
103
+ onKeyDown: (e) => {
104
+ if (e.key === "Enter" || e.key === " ") {
105
+ e.preventDefault();
106
+ handleSelect();
107
+ }
108
+ },
82
109
  className: cn(
83
- "flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-xs transition-colors",
84
- "hover:bg-hover focus:bg-hover focus:text-default",
110
+ "flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-xs transition-colors outline-none",
111
+ "hover:bg-hover focus-visible:bg-hover focus-visible:text-default",
85
112
  isSelected && "bg-hover",
86
113
  isDisabled && "cursor-not-allowed opacity-50"
87
114
  ),
@@ -90,8 +117,9 @@ function MultiSelect({
90
117
  Checkbox,
91
118
  {
92
119
  checked: isSelected,
93
- onCheckedChange: () => handleToggle(option.value),
94
- disabled: isDisabled
120
+ disabled: isDisabled,
121
+ tabIndex: -1,
122
+ className: "pointer-events-none"
95
123
  }
96
124
  ),
97
125
  /* @__PURE__ */ jsxs("span", { className: "flex flex-1 items-center gap-2", children: [
@@ -103,7 +131,7 @@ function MultiSelect({
103
131
  option.value
104
132
  );
105
133
  };
106
- return /* @__PURE__ */ jsxs(PopoverPrimitive.Root, { open, onOpenChange: setOpen, children: [
134
+ return /* @__PURE__ */ jsxs(PopoverPrimitive.Root, { open, onOpenChange: handleOpenChange, children: [
107
135
  /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
108
136
  "button",
109
137
  {
@@ -115,6 +143,7 @@ function MultiSelect({
115
143
  "data-state": open ? "open" : "closed",
116
144
  className: cn(
117
145
  'border-border bg-secondary data-[placeholder]:text-gray-chateau [&_svg:not([class*="text-"])]:text-gray-chateau flex min-h-9 w-full items-center justify-between gap-2 rounded-md border px-3 py-1 text-xs font-normal transition-[color,box-shadow] outline-none',
146
+ "data-[size=sm]:min-h-8 data-[size=sm]:px-2",
118
147
  "focus-visible:border-success focus-visible:ring-success/40 focus-visible:ring-[2px]",
119
148
  "data-[state=open]:border-success data-[state=open]:ring-success/40 data-[state=open]:ring-[2px]",
120
149
  "disabled:cursor-not-allowed disabled:opacity-50",
@@ -133,7 +162,7 @@ function MultiSelect({
133
162
  align,
134
163
  sideOffset: 4,
135
164
  className: cn(
136
- "bg-secondary border-border text-foreground z-50 rounded-md border shadow-md outline-none",
165
+ "bg-secondary border-border text-foreground z-50 w-[var(--radix-popover-trigger-width)] rounded-md border shadow-md outline-none",
137
166
  "data-[state=open]:animate-in data-[state=closed]:animate-out",
138
167
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
139
168
  "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
@@ -152,7 +181,31 @@ function MultiSelect({
152
181
  placeholder: "Search..."
153
182
  }
154
183
  ),
155
- /* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx("div", { className: "flex max-h-64 flex-col gap-2", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-gray-chateau py-6 text-center text-xs", children: "Nothing found" }) : filteredOptions.map(renderOptionItem) }) })
184
+ value.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
185
+ /* @__PURE__ */ jsxs("span", { className: "text-2xs text-gray-chateau", children: [
186
+ value.length,
187
+ " selected",
188
+ maxSelection !== void 0 && ` / ${maxSelection}`
189
+ ] }),
190
+ /* @__PURE__ */ jsx(
191
+ "button",
192
+ {
193
+ type: "button",
194
+ onClick: () => onChange([]),
195
+ className: "text-2xs text-gray-chateau hover:text-default cursor-pointer transition-colors",
196
+ children: "Clear all"
197
+ }
198
+ )
199
+ ] }),
200
+ /* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx(
201
+ "div",
202
+ {
203
+ role: "listbox",
204
+ "aria-multiselectable": "true",
205
+ className: "flex max-h-64 flex-col gap-2",
206
+ children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-gray-chateau py-6 text-center text-xs", children: "Nothing found" }) : filteredOptions.map(renderOptionItem)
207
+ }
208
+ ) })
156
209
  ] })
157
210
  }
158
211
  ) })
@@ -1,4 +1,6 @@
1
1
  import { MultiSelect } from "./MultiSelect.js";
2
+ import { BaseMultiSelect } from "./BaseMultiSelect.js";
2
3
  export {
4
+ BaseMultiSelect,
3
5
  MultiSelect
4
6
  };