@koobiq/react-components 0.24.0 → 0.25.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.
Files changed (52) hide show
  1. package/dist/components/ContenPanel/ContentPanel.d.ts +3 -2
  2. package/dist/components/ContenPanel/ContentPanel.js +9 -9
  3. package/dist/components/Divider/Divider.d.ts +14 -4
  4. package/dist/components/Divider/Divider.js +23 -8
  5. package/dist/components/Divider/types.d.ts +4 -3
  6. package/dist/components/Navbar/components/NavbarItem.d.ts +4 -0
  7. package/dist/components/Navbar/components/NavbarItem.js +11 -1
  8. package/dist/components/SearchInput/SearchInput.d.ts +1 -1
  9. package/dist/components/Select/Select.d.ts +4 -0
  10. package/dist/components/SelectNext/Select.d.ts +13 -0
  11. package/dist/components/SelectNext/Select.js +258 -0
  12. package/dist/components/SelectNext/Select.module.css.js +23 -0
  13. package/dist/components/SelectNext/SelectContext.d.ts +2 -0
  14. package/dist/components/SelectNext/SelectContext.js +5 -0
  15. package/dist/components/SelectNext/components/SelectList/SelectList.d.ts +37 -0
  16. package/dist/components/SelectNext/components/SelectList/SelectList.js +131 -0
  17. package/dist/components/SelectNext/components/SelectList/SelectList.module.css.js +11 -0
  18. package/dist/components/SelectNext/components/SelectList/index.d.ts +1 -0
  19. package/dist/components/SelectNext/components/SelectOption/SelectOption.d.ts +37 -0
  20. package/dist/components/SelectNext/components/SelectOption/SelectOption.js +48 -0
  21. package/dist/components/SelectNext/components/SelectOption/index.d.ts +1 -0
  22. package/dist/components/SelectNext/components/SelectSection/SelectSection.d.ts +9 -0
  23. package/dist/components/SelectNext/components/SelectSection/SelectSection.js +51 -0
  24. package/dist/components/SelectNext/components/SelectSection/index.d.ts +1 -0
  25. package/dist/components/SelectNext/components/Tag/Tag.d.ts +18 -0
  26. package/dist/components/SelectNext/components/Tag/Tag.js +67 -0
  27. package/dist/components/SelectNext/components/Tag/index.d.ts +1 -0
  28. package/dist/components/SelectNext/components/Tag/intl.json.js +7 -0
  29. package/dist/components/SelectNext/components/Tag/utils.d.ts +3 -0
  30. package/dist/components/SelectNext/components/Tag/utils.js +9 -0
  31. package/dist/components/SelectNext/components/TagGroup/TagGroup.d.ts +13 -0
  32. package/dist/components/SelectNext/components/TagGroup/TagGroup.js +25 -0
  33. package/dist/components/SelectNext/components/TagGroup/TagGroup.module.css.js +20 -0
  34. package/dist/components/SelectNext/components/TagGroup/TagGroupMultiline.d.ts +3 -0
  35. package/dist/components/SelectNext/components/TagGroup/TagGroupMultiline.js +44 -0
  36. package/dist/components/SelectNext/components/TagGroup/TagGroupResponsive.d.ts +3 -0
  37. package/dist/components/SelectNext/components/TagGroup/TagGroupResponsive.js +65 -0
  38. package/dist/components/SelectNext/components/TagGroup/index.d.ts +1 -0
  39. package/dist/components/SelectNext/components/TagGroup/utils.d.ts +1 -0
  40. package/dist/components/SelectNext/components/TagGroup/utils.js +4 -0
  41. package/dist/components/SelectNext/components/index.d.ts +5 -0
  42. package/dist/components/SelectNext/index.d.ts +2 -0
  43. package/dist/components/SelectNext/intl.d.ts +2 -0
  44. package/dist/components/SelectNext/intl.js +21 -0
  45. package/dist/components/SelectNext/types.d.ts +99 -0
  46. package/dist/components/SelectNext/types.js +12 -0
  47. package/dist/components/SelectNext/utils.d.ts +9 -0
  48. package/dist/components/SelectNext/utils.js +26 -0
  49. package/dist/components/index.d.ts +2 -1
  50. package/dist/index.js +8 -1
  51. package/dist/style.css +172 -43
  52. package/package.json +5 -5
@@ -1,5 +1,6 @@
1
- import { type ComponentPropsWithRef, type CSSProperties } from 'react';
2
- import { DialogBody, DialogFooter, DialogHeader, type DialogProps } from '../Dialog';
1
+ import type { CSSProperties, ComponentPropsWithRef } from 'react';
2
+ import { DialogBody, DialogFooter, DialogHeader } from '../Dialog';
3
+ import type { DialogProps } from '../Dialog';
3
4
  declare const ContentPanelComponent: import("react").ForwardRefExoticComponent<{
4
5
  children?: import("react").ReactNode;
5
6
  width?: import("./types").ContentPanelSize | null;
@@ -26,23 +26,23 @@ const ContentPanelComponent = forwardRef(
26
26
  );
27
27
  const {
28
28
  defaultWidth: defaultWidthProp,
29
+ disableExitOnEscapeKeyDown,
29
30
  minWidth: minWidthProp,
30
31
  maxWidth: maxWidthProp,
31
- disableExitOnEscapeKeyDown,
32
- onResetResize,
33
32
  isResizable = false,
34
- width,
35
- onResize,
36
- onResizeEnd,
33
+ hideCloseButton,
37
34
  onResizeStart,
38
- isOpen,
35
+ onResetResize,
39
36
  onOpenChange,
40
37
  defaultOpen,
38
+ onResizeEnd,
39
+ slotProps,
41
40
  className,
42
- style,
43
41
  children,
44
- slotProps,
45
- hideCloseButton,
42
+ onResize,
43
+ isOpen,
44
+ width,
45
+ style,
46
46
  ...other
47
47
  } = panelProps;
48
48
  const {
@@ -1,4 +1,14 @@
1
- import type { ComponentPropsWithRef, ElementType } from 'react';
2
- import type { DividerBaseProps } from './index';
3
- export declare const Divider: import("@koobiq/react-core").PolyForwardComponent<"div", DividerBaseProps, ElementType>;
4
- export type DividerProps<As extends ElementType = 'div'> = ComponentPropsWithRef<typeof Divider<As>>;
1
+ import type { ElementType } from 'react';
2
+ import type { BaseCollection } from '@koobiq/react-primitives';
3
+ import { CollectionNode } from '@koobiq/react-primitives';
4
+ export declare class DividerNode extends CollectionNode<any> {
5
+ static readonly type = "separator";
6
+ filter(collection: BaseCollection<any>, newCollection: BaseCollection<any>): CollectionNode<any> | null;
7
+ }
8
+ export declare const Divider: (props: {
9
+ className?: string;
10
+ display?: import("./types").DividerPropDisplay;
11
+ flexItem?: boolean;
12
+ disablePaddings?: boolean;
13
+ as?: ElementType;
14
+ } & Omit<import("@react-aria/separator").SeparatorProps, "elementType"> & import("react").HTMLAttributes<HTMLElement> & import("react").RefAttributes<HTMLElement>) => import("react").ReactElement | null;
@@ -1,13 +1,27 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
- import { polymorphicForwardRef, clsx } from "@koobiq/react-core";
4
- import { useSeparator } from "@koobiq/react-primitives";
3
+ import { clsx } from "@koobiq/react-core";
4
+ import { createLeafComponent, CollectionNode, useSeparator } from "@koobiq/react-primitives";
5
5
  import s from "./Divider.module.css.js";
6
- const Divider = polymorphicForwardRef(
7
- (props, ref) => {
6
+ const _DividerNode = class _DividerNode extends CollectionNode {
7
+ filter(collection, newCollection) {
8
+ const prevItem = newCollection.getItem(this.prevKey);
9
+ if (prevItem && prevItem.type !== "separator") {
10
+ const clone = this.clone();
11
+ newCollection.addDescendants(clone, collection);
12
+ return clone;
13
+ }
14
+ return null;
15
+ }
16
+ };
17
+ _DividerNode.type = "separator";
18
+ let DividerNode = _DividerNode;
19
+ const Divider = createLeafComponent(
20
+ DividerNode,
21
+ function Separator(props, ref) {
8
22
  const {
9
- as: Tag = "div",
10
23
  orientation = "horizontal",
24
+ as = "div",
11
25
  disablePaddings,
12
26
  flexItem,
13
27
  display,
@@ -17,9 +31,10 @@ const Divider = polymorphicForwardRef(
17
31
  const { separatorProps } = useSeparator({
18
32
  ...other,
19
33
  orientation,
20
- elementType: Tag
34
+ elementType: `${as}`
21
35
  });
22
36
  const hasPaddings = !disablePaddings;
37
+ const Tag = as;
23
38
  return /* @__PURE__ */ jsx(
24
39
  Tag,
25
40
  {
@@ -42,7 +57,7 @@ const Divider = polymorphicForwardRef(
42
57
  );
43
58
  }
44
59
  );
45
- Divider.displayName = "Divider";
46
60
  export {
47
- Divider
61
+ Divider,
62
+ DividerNode
48
63
  };
@@ -1,8 +1,8 @@
1
- import type { ExtendableProps } from '@koobiq/react-core';
1
+ import type { ElementType, HTMLAttributes } from 'react';
2
2
  import type { SeparatorProps } from '@koobiq/react-primitives';
3
3
  export declare const dividerPropDisplay: readonly ["block", "inline", "inlineBlock"];
4
4
  export type DividerPropDisplay = (typeof dividerPropDisplay)[number];
5
- export type DividerBaseProps = ExtendableProps<{
5
+ export type DividerProps = {
6
6
  /** Additional CSS-classes. */
7
7
  className?: string;
8
8
  /** Set the display for the component. */
@@ -17,4 +17,5 @@ export type DividerBaseProps = ExtendableProps<{
17
17
  * If `true`, it disables the default paddings.
18
18
  */
19
19
  disablePaddings?: boolean;
20
- }, Omit<SeparatorProps, 'elementType'>>;
20
+ as?: ElementType;
21
+ } & Omit<SeparatorProps, 'elementType'> & HTMLAttributes<HTMLElement>;
@@ -1,6 +1,10 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import { type LinkBaseProps } from '@koobiq/react-primitives';
3
3
  export type NavbarItemProps = {
4
+ /**
5
+ * Whether the item is active.
6
+ */
7
+ isActive?: boolean;
4
8
  /**
5
9
  * Whether the item is a menu trigger.
6
10
  */
@@ -9,7 +9,16 @@ import { useNavbarState } from "../NavbarContext.js";
9
9
  import { Tooltip } from "../../Tooltip/Tooltip.js";
10
10
  const { listItem, typography } = utilClasses;
11
11
  const NavbarItem = polymorphicForwardRef(
12
- ({ as, className, isMenu = false, icon, badge, children, ...other }, inRef) => {
12
+ ({
13
+ as,
14
+ className,
15
+ isActive,
16
+ isMenu = false,
17
+ icon,
18
+ badge,
19
+ children,
20
+ ...other
21
+ }, inRef) => {
13
22
  const { isCollapsed } = useNavbarState();
14
23
  return /* @__PURE__ */ jsx(
15
24
  Tooltip,
@@ -28,6 +37,7 @@ const NavbarItem = polymorphicForwardRef(
28
37
  s.item,
29
38
  className
30
39
  ),
40
+ "data-selected": isActive || void 0,
31
41
  ...mergeProps(props, other),
32
42
  ref: mergeRefs(props.ref, inRef),
33
43
  children: [
@@ -1,5 +1,5 @@
1
1
  import type { FormFieldProps, FormFieldLabelProps, FormFieldInputProps, FormFieldErrorProps, FormFieldCaptionProps, FormFieldControlGroupProps } from '../FormField';
2
- export declare const SearchInput: import("react").ForwardRefExoticComponent<Omit<Omit<import("@react-types/searchfield").AriaSearchFieldProps, "description" | "validationState">, "caption" | "style" | "className" | `data-${string}` | "startAddon" | "endAddon" | "variant" | "slotProps" | "labelPlacement" | "labelAlign" | "fullWidth" | "isLabelHidden"> & {
2
+ export declare const SearchInput: import("react").ForwardRefExoticComponent<Omit<Omit<import("@koobiq/react-primitives").AriaSearchFieldProps, "description" | "validationState">, "caption" | "style" | "className" | `data-${string}` | "startAddon" | "endAddon" | "variant" | "slotProps" | "labelPlacement" | "labelAlign" | "fullWidth" | "isLabelHidden"> & {
3
3
  className?: string;
4
4
  style?: import("react").CSSProperties;
5
5
  isLabelHidden?: boolean;
@@ -8,5 +8,9 @@ type CompoundedComponent = typeof SelectComponent & {
8
8
  Divider: typeof Divider;
9
9
  ItemText: typeof ListItemText;
10
10
  };
11
+ /**
12
+ * @deprecated
13
+ * This component has been deprecated, please use SelectNext instead.
14
+ */
11
15
  export declare const Select: CompoundedComponent;
12
16
  export {};
@@ -0,0 +1,13 @@
1
+ import { Divider } from '../Divider';
2
+ import type { ListItemText } from '../List';
3
+ import { SelectOption, SelectSection } from './components';
4
+ import { type SelectNextComponent } from './index';
5
+ declare const SelectComponent: SelectNextComponent;
6
+ type CompoundedComponent = typeof SelectComponent & {
7
+ Item: typeof SelectOption;
8
+ Section: typeof SelectSection;
9
+ Divider: typeof Divider;
10
+ ItemText: typeof ListItemText;
11
+ };
12
+ export declare const SelectNext: CompoundedComponent;
13
+ export {};
@@ -0,0 +1,258 @@
1
+ "use client";
2
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
+ import { forwardRef, useCallback } from "react";
4
+ import { useDOMRef, useElementSize, mergeProps } from "@koobiq/react-core";
5
+ import { IconChevronDownS16 } from "@koobiq/react-icons";
6
+ import { CollectionBuilder, Collection, useSelectState, removeDataAttributes, useSlottedContext, FormContext, useSelect, FieldErrorContext } from "@koobiq/react-primitives";
7
+ import { PopoverInner } from "../Popover/PopoverInner.js";
8
+ import s from "./Select.module.css.js";
9
+ import { SelectList } from "./components/SelectList/SelectList.js";
10
+ import { TagGroup } from "./components/TagGroup/TagGroup.js";
11
+ import { SelectOption } from "./components/SelectOption/SelectOption.js";
12
+ import { SelectSection } from "./components/SelectSection/SelectSection.js";
13
+ import { useForm } from "../Form/FormContext.js";
14
+ import { FormFieldClearButton } from "../FormField/FormFieldClearButton/FormFieldClearButton.js";
15
+ import { FormField } from "../FormField/FormField.js";
16
+ import { Divider } from "../Divider/Divider.js";
17
+ import { List } from "../List/List.js";
18
+ function SelectInner({
19
+ state: inState,
20
+ props,
21
+ listBoxRef
22
+ }) {
23
+ const {
24
+ selectedTagsOverflow = "responsive",
25
+ renderValue: renderValueProp,
26
+ "data-testid": testId,
27
+ defaultInputValue,
28
+ labelPlacement,
29
+ onInputChange,
30
+ selectionMode,
31
+ defaultFilter,
32
+ isLabelHidden,
33
+ isSearchable,
34
+ errorMessage,
35
+ placeholder,
36
+ loadingText,
37
+ isClearable,
38
+ noItemsText,
39
+ inputValue,
40
+ labelAlign,
41
+ startAddon,
42
+ isRequired,
43
+ onLoadMore,
44
+ isDisabled,
45
+ fullWidth,
46
+ className,
47
+ isLoading,
48
+ slotProps,
49
+ endAddon,
50
+ caption,
51
+ onClear,
52
+ style,
53
+ label
54
+ } = props;
55
+ const { validationBehavior: formValidationBehavior } = useSlottedContext(FormContext) || {};
56
+ const validationBehavior = props.validationBehavior ?? formValidationBehavior ?? "aria";
57
+ const clearButtonIsHidden = isDisabled || !inState.selectedItems.length;
58
+ const handleClear = useCallback(() => {
59
+ inState.selectionManager.setSelectedKeys(/* @__PURE__ */ new Set());
60
+ onClear?.();
61
+ }, [onClear, inState]);
62
+ const {
63
+ menuProps,
64
+ valueProps,
65
+ triggerProps,
66
+ descriptionProps,
67
+ errorMessageProps,
68
+ labelProps: labelPropsAria,
69
+ ...validation
70
+ } = useSelect(
71
+ removeDataAttributes({
72
+ ...props,
73
+ isDisabled,
74
+ selectionMode,
75
+ validationBehavior,
76
+ allowsEmptyCollection: true
77
+ }),
78
+ inState,
79
+ listBoxRef
80
+ );
81
+ const { isInvalid } = validation;
82
+ const { ref: containerRef, width } = useElementSize();
83
+ const rootProps = mergeProps({
84
+ "data-testid": testId,
85
+ "data-invalid": isInvalid || void 0,
86
+ "data-disabled": isDisabled || void 0,
87
+ "data-required": isRequired || void 0,
88
+ className,
89
+ fullWidth,
90
+ labelPlacement,
91
+ labelAlign,
92
+ style
93
+ });
94
+ const listProps = mergeProps(
95
+ {
96
+ isLoading,
97
+ inputValue,
98
+ onLoadMore,
99
+ noItemsText,
100
+ loadingText,
101
+ isSearchable,
102
+ defaultFilter,
103
+ state: inState,
104
+ onInputChange,
105
+ className: s.list,
106
+ defaultInputValue
107
+ },
108
+ slotProps?.list,
109
+ menuProps
110
+ );
111
+ const labelProps = mergeProps(
112
+ { isHidden: isLabelHidden, children: label, isRequired },
113
+ labelPropsAria,
114
+ slotProps?.label
115
+ );
116
+ const clearButtonProps = mergeProps(
117
+ {
118
+ isClearable,
119
+ onPress: handleClear,
120
+ className: s.clearButton,
121
+ isHidden: clearButtonIsHidden
122
+ },
123
+ slotProps?.clearButton
124
+ );
125
+ const { slotProps: groupSlotProps, ...otherGroup } = slotProps?.group || {};
126
+ const groupProps = mergeProps(
127
+ {
128
+ slotProps: mergeProps(
129
+ {
130
+ endAddon: { className: s.addon },
131
+ startAddon: { className: s.addon }
132
+ },
133
+ groupSlotProps
134
+ ),
135
+ startAddon,
136
+ onMouseDown: (e) => {
137
+ if (e.currentTarget !== e.target || isDisabled) return;
138
+ e.preventDefault();
139
+ listBoxRef?.current?.focus();
140
+ inState.open();
141
+ },
142
+ endAddon: /* @__PURE__ */ jsxs(Fragment, { children: [
143
+ endAddon,
144
+ /* @__PURE__ */ jsx(FormFieldClearButton, { ...clearButtonProps }),
145
+ /* @__PURE__ */ jsx("span", { className: s.chevron, children: /* @__PURE__ */ jsx(IconChevronDownS16, {}) })
146
+ ] }),
147
+ isInvalid,
148
+ isDisabled,
149
+ ref: containerRef
150
+ },
151
+ otherGroup
152
+ );
153
+ const controlProps = mergeProps(
154
+ {
155
+ ref: listBoxRef,
156
+ placeholder
157
+ },
158
+ valueProps,
159
+ triggerProps,
160
+ slotProps?.control
161
+ );
162
+ const popoverProps = mergeProps(
163
+ {
164
+ offset: 4,
165
+ state: inState,
166
+ hideArrow: true,
167
+ type: "listbox",
168
+ maxBlockSize: 256,
169
+ className: s.popover,
170
+ anchorRef: containerRef,
171
+ placement: "bottom start",
172
+ size: Math.max(width, 200)
173
+ },
174
+ slotProps?.popover
175
+ );
176
+ const captionProps = mergeProps(
177
+ { children: caption },
178
+ descriptionProps,
179
+ slotProps?.caption
180
+ );
181
+ const errorProps = mergeProps(
182
+ { children: errorMessage },
183
+ errorMessageProps,
184
+ slotProps?.errorMessage
185
+ );
186
+ const renderDefaultValue = (state, states) => {
187
+ if (!state.selectedItems?.length) return null;
188
+ if (selectionMode === "multiple")
189
+ return /* @__PURE__ */ jsx(
190
+ TagGroup,
191
+ {
192
+ state,
193
+ states,
194
+ selectedTagsOverflow
195
+ }
196
+ );
197
+ return state.selectedItems[0].textValue;
198
+ };
199
+ const renderValue = renderValueProp || renderDefaultValue;
200
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
201
+ /* @__PURE__ */ jsxs(FormField, { ...rootProps, children: [
202
+ /* @__PURE__ */ jsx(FormField.Label, { ...labelProps }),
203
+ /* @__PURE__ */ jsxs("div", { className: s.body, children: [
204
+ /* @__PURE__ */ jsx(FormField.ControlGroup, { ...groupProps, children: /* @__PURE__ */ jsx(FormField.Select, { ...controlProps, children: renderValue(inState, {
205
+ isInvalid,
206
+ isDisabled: props.isDisabled,
207
+ isRequired: props.isRequired
208
+ }) }) }),
209
+ /* @__PURE__ */ jsx(FieldErrorContext.Provider, { value: validation, children: /* @__PURE__ */ jsx(FormField.Error, { ...errorProps }) }),
210
+ /* @__PURE__ */ jsx(FormField.Caption, { ...captionProps })
211
+ ] })
212
+ ] }),
213
+ /* @__PURE__ */ jsx(PopoverInner, { ...popoverProps, children: /* @__PURE__ */ jsx(SelectList, { ...listProps }) })
214
+ ] });
215
+ }
216
+ function StandaloneSelect({
217
+ props: inProps,
218
+ listBoxRef,
219
+ collection
220
+ }) {
221
+ const props = { ...inProps, collection, children: null, items: null };
222
+ const { isDisabled: formIsDisabled } = useForm();
223
+ const isDisabled = inProps?.isDisabled ?? formIsDisabled;
224
+ const state = useSelectState(
225
+ removeDataAttributes({
226
+ ...props,
227
+ isDisabled
228
+ })
229
+ );
230
+ return /* @__PURE__ */ jsx(
231
+ SelectInner,
232
+ {
233
+ state,
234
+ listBoxRef,
235
+ props: { ...props, isDisabled }
236
+ }
237
+ );
238
+ }
239
+ function SelectRender(props, ref) {
240
+ const listBoxRef = useDOMRef(ref);
241
+ return /* @__PURE__ */ jsx(CollectionBuilder, { content: /* @__PURE__ */ jsx(Collection, { ...props }), children: (collection) => /* @__PURE__ */ jsx(
242
+ StandaloneSelect,
243
+ {
244
+ props,
245
+ collection,
246
+ listBoxRef
247
+ }
248
+ ) });
249
+ }
250
+ const SelectComponent = forwardRef(SelectRender);
251
+ const SelectNext = SelectComponent;
252
+ SelectNext.Item = SelectOption;
253
+ SelectNext.Section = SelectSection;
254
+ SelectNext.Divider = Divider;
255
+ SelectNext.ItemText = List.ItemText;
256
+ export {
257
+ SelectNext
258
+ };
@@ -0,0 +1,23 @@
1
+ const addon = "kbq-select-addon-1077d8";
2
+ const chevron = "kbq-select-chevron-5918a1";
3
+ const body = "kbq-select-body-698617";
4
+ const list = "kbq-select-list-51ca7a";
5
+ const popover = "kbq-select-popover-756d4e";
6
+ const clearButton = "kbq-select-clearButton-8498d2";
7
+ const s = {
8
+ addon,
9
+ chevron,
10
+ body,
11
+ list,
12
+ popover,
13
+ clearButton
14
+ };
15
+ export {
16
+ addon,
17
+ body,
18
+ chevron,
19
+ clearButton,
20
+ s as default,
21
+ list,
22
+ popover
23
+ };
@@ -0,0 +1,2 @@
1
+ import type { ListState } from '@koobiq/react-primitives';
2
+ export declare const SelectContext: import("react").Context<ListState<object> | null>;
@@ -0,0 +1,5 @@
1
+ import { createContext } from "react";
2
+ const SelectContext = createContext(null);
3
+ export {
4
+ SelectContext
5
+ };
@@ -0,0 +1,37 @@
1
+ import type { ComponentPropsWithRef, CSSProperties, ReactNode } from 'react';
2
+ import type { SelectState, AriaListBoxProps } from '@koobiq/react-primitives';
3
+ import type { SelectionMode } from '@react-types/select';
4
+ import { type DividerProps } from '../../../Divider';
5
+ import { type SearchInputProps } from '../../../SearchInput';
6
+ export type SelectListProps<T extends object, M extends SelectionMode = 'single'> = {
7
+ state: SelectState<T, M>;
8
+ /** The filter function used to determine if a option should be included in the Select list. */
9
+ defaultFilter?: (textValue: string, inputValue: string) => boolean;
10
+ /** The value of the Select search input (controlled). */
11
+ inputValue?: string;
12
+ /** The default value of the Select search input (uncontrolled). */
13
+ defaultInputValue?: string;
14
+ /** Handler that is called when the Select search input value changes. */
15
+ onInputChange?: (value: string) => void;
16
+ /** Additional CSS-classes. */
17
+ className?: string;
18
+ /** Inline styles. */
19
+ style?: CSSProperties;
20
+ /** The load more spinner to render when loading additional items. */
21
+ isLoading?: boolean;
22
+ /** Handler that is called when more items should be loaded, e.g. while scrolling near the bottom. */
23
+ onLoadMore?: () => void;
24
+ /** Content to display when no items are available. */
25
+ noItemsText?: ReactNode;
26
+ /** Content to display when items are loading. */
27
+ loadingText?: ReactNode;
28
+ /** Enables search input for filtering items in the list. */
29
+ isSearchable?: boolean;
30
+ /** The props used for each slot inside. */
31
+ slotProps?: {
32
+ divider?: DividerProps;
33
+ root?: ComponentPropsWithRef<'div'>;
34
+ 'search-input'?: SearchInputProps;
35
+ };
36
+ } & Omit<AriaListBoxProps<T>, 'children'>;
37
+ export declare function SelectList<T extends object, M extends SelectionMode = 'single'>(props: SelectListProps<T, M>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,131 @@
1
+ "use client";
2
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
3
+ import { useRef } from "react";
4
+ import { useLocalizedStringFormatter, useFilter, useControlledState, useMultiRef, mergeProps, clsx } from "@koobiq/react-core";
5
+ import { useAutocompleteState, useAutocomplete, UNSTABLE_useFilteredListState, useListBox } from "@koobiq/react-primitives";
6
+ import { utilClasses } from "../../../../styles/utility.js";
7
+ import intlMessages from "../../intl.js";
8
+ import { SelectContext } from "../../SelectContext.js";
9
+ import { CollectionRoot } from "../../utils.js";
10
+ import s from "./SelectList.module.css.js";
11
+ import { SearchInput } from "../../../SearchInput/SearchInput.js";
12
+ import { Divider } from "../../../Divider/Divider.js";
13
+ import { ListEmptyState } from "../../../List/components/ListEmptyState/ListEmptyState.js";
14
+ import { ListLoadingState } from "../../../List/components/ListLoadingState/ListLoadingState.js";
15
+ const { list } = utilClasses;
16
+ function SelectList(props) {
17
+ const {
18
+ style,
19
+ isLoading,
20
+ className,
21
+ onLoadMore,
22
+ slotProps,
23
+ inputValue,
24
+ isSearchable,
25
+ onInputChange,
26
+ defaultFilter,
27
+ state: inState,
28
+ defaultInputValue,
29
+ noItemsText: noItemsTextProp,
30
+ loadingText: loadingTextProp
31
+ } = props;
32
+ const t = useLocalizedStringFormatter(intlMessages);
33
+ const domRef = useRef(null);
34
+ const inputRef = useRef(null);
35
+ const collectionRef = useRef(null);
36
+ const { contains } = useFilter({ sensitivity: "base" });
37
+ const [filterText, setFilterText] = useControlledState(
38
+ inputValue,
39
+ defaultInputValue ?? "",
40
+ onInputChange
41
+ );
42
+ const noItemsText = (() => {
43
+ if (noItemsTextProp !== void 0) return noItemsTextProp;
44
+ const hasQuery = isSearchable && filterText.trim().length > 0;
45
+ return hasQuery ? t.format("nothing found") : t.format("empty items");
46
+ })();
47
+ const autocompleteState = useAutocompleteState({
48
+ inputValue: isSearchable ? filterText : "",
49
+ onInputChange: isSearchable ? setFilterText : () => {
50
+ }
51
+ });
52
+ const {
53
+ inputProps,
54
+ collectionProps,
55
+ filter: filterFn,
56
+ collectionRef: mergedCollectionRef
57
+ } = useAutocomplete(
58
+ {
59
+ inputRef,
60
+ collectionRef,
61
+ filter: defaultFilter || contains
62
+ },
63
+ autocompleteState
64
+ );
65
+ const listRef = useMultiRef([mergedCollectionRef, domRef]);
66
+ const state = UNSTABLE_useFilteredListState(
67
+ inState,
68
+ isSearchable ? filterFn : null
69
+ );
70
+ const isEmpty = state.collection.size === 0;
71
+ const { listBoxProps } = useListBox(
72
+ mergeProps(props, isSearchable ? collectionProps : null),
73
+ state,
74
+ domRef
75
+ );
76
+ const rootProps = mergeProps({ className: s.base }, slotProps?.root);
77
+ const listProps = mergeProps(
78
+ {
79
+ style,
80
+ ref: listRef,
81
+ "data-padded": true,
82
+ className: clsx(list, className)
83
+ },
84
+ listBoxProps
85
+ );
86
+ const searchInputProps = mergeProps(
87
+ {
88
+ autoFocus: true,
89
+ fullWidth: true,
90
+ isLabelHidden: true,
91
+ className: s.search,
92
+ placeholder: t.format("search"),
93
+ "aria-label": t.format("search"),
94
+ variant: "transparent"
95
+ },
96
+ slotProps?.["search-input"],
97
+ inputProps
98
+ );
99
+ const loadingText = loadingTextProp ?? t.format("loading");
100
+ const { collection } = state;
101
+ return /* @__PURE__ */ jsxs("div", { ...rootProps, children: [
102
+ isSearchable && /* @__PURE__ */ jsxs(Fragment, { children: [
103
+ /* @__PURE__ */ jsx(SearchInput, { ref: inputRef, ...searchInputProps }),
104
+ /* @__PURE__ */ jsx(Divider, { disablePaddings: true, ...slotProps?.divider })
105
+ ] }),
106
+ /* @__PURE__ */ jsxs("ul", { ...listProps, children: [
107
+ /* @__PURE__ */ jsx(SelectContext.Provider, { value: state, children: /* @__PURE__ */ jsx(CollectionRoot, { collection }) }),
108
+ /* @__PURE__ */ jsx(
109
+ ListEmptyState,
110
+ {
111
+ isEmpty,
112
+ isLoading,
113
+ noItemsText
114
+ }
115
+ ),
116
+ /* @__PURE__ */ jsx(
117
+ ListLoadingState,
118
+ {
119
+ root: domRef.current,
120
+ isLoading,
121
+ onLoadMore,
122
+ loadingText,
123
+ observeDeps: [state.collection]
124
+ }
125
+ )
126
+ ] })
127
+ ] });
128
+ }
129
+ export {
130
+ SelectList
131
+ };
@@ -0,0 +1,11 @@
1
+ const base = "kbq-selectlist-68b1db";
2
+ const search = "kbq-selectlist-search-800542";
3
+ const s = {
4
+ base,
5
+ search
6
+ };
7
+ export {
8
+ base,
9
+ s as default,
10
+ search
11
+ };