@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.
- package/dist/components/ContenPanel/ContentPanel.d.ts +3 -2
- package/dist/components/ContenPanel/ContentPanel.js +9 -9
- package/dist/components/Divider/Divider.d.ts +14 -4
- package/dist/components/Divider/Divider.js +23 -8
- package/dist/components/Divider/types.d.ts +4 -3
- package/dist/components/Navbar/components/NavbarItem.d.ts +4 -0
- package/dist/components/Navbar/components/NavbarItem.js +11 -1
- package/dist/components/SearchInput/SearchInput.d.ts +1 -1
- package/dist/components/Select/Select.d.ts +4 -0
- package/dist/components/SelectNext/Select.d.ts +13 -0
- package/dist/components/SelectNext/Select.js +258 -0
- package/dist/components/SelectNext/Select.module.css.js +23 -0
- package/dist/components/SelectNext/SelectContext.d.ts +2 -0
- package/dist/components/SelectNext/SelectContext.js +5 -0
- package/dist/components/SelectNext/components/SelectList/SelectList.d.ts +37 -0
- package/dist/components/SelectNext/components/SelectList/SelectList.js +131 -0
- package/dist/components/SelectNext/components/SelectList/SelectList.module.css.js +11 -0
- package/dist/components/SelectNext/components/SelectList/index.d.ts +1 -0
- package/dist/components/SelectNext/components/SelectOption/SelectOption.d.ts +37 -0
- package/dist/components/SelectNext/components/SelectOption/SelectOption.js +48 -0
- package/dist/components/SelectNext/components/SelectOption/index.d.ts +1 -0
- package/dist/components/SelectNext/components/SelectSection/SelectSection.d.ts +9 -0
- package/dist/components/SelectNext/components/SelectSection/SelectSection.js +51 -0
- package/dist/components/SelectNext/components/SelectSection/index.d.ts +1 -0
- package/dist/components/SelectNext/components/Tag/Tag.d.ts +18 -0
- package/dist/components/SelectNext/components/Tag/Tag.js +67 -0
- package/dist/components/SelectNext/components/Tag/index.d.ts +1 -0
- package/dist/components/SelectNext/components/Tag/intl.json.js +7 -0
- package/dist/components/SelectNext/components/Tag/utils.d.ts +3 -0
- package/dist/components/SelectNext/components/Tag/utils.js +9 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroup.d.ts +13 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroup.js +25 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroup.module.css.js +20 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroupMultiline.d.ts +3 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroupMultiline.js +44 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroupResponsive.d.ts +3 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroupResponsive.js +65 -0
- package/dist/components/SelectNext/components/TagGroup/index.d.ts +1 -0
- package/dist/components/SelectNext/components/TagGroup/utils.d.ts +1 -0
- package/dist/components/SelectNext/components/TagGroup/utils.js +4 -0
- package/dist/components/SelectNext/components/index.d.ts +5 -0
- package/dist/components/SelectNext/index.d.ts +2 -0
- package/dist/components/SelectNext/intl.d.ts +2 -0
- package/dist/components/SelectNext/intl.js +21 -0
- package/dist/components/SelectNext/types.d.ts +99 -0
- package/dist/components/SelectNext/types.js +12 -0
- package/dist/components/SelectNext/utils.d.ts +9 -0
- package/dist/components/SelectNext/utils.js +26 -0
- package/dist/components/index.d.ts +2 -1
- package/dist/index.js +8 -1
- package/dist/style.css +172 -43
- package/package.json +5 -5
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DialogBody, DialogFooter, DialogHeader
|
|
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
|
-
|
|
35
|
-
onResize,
|
|
36
|
-
onResizeEnd,
|
|
33
|
+
hideCloseButton,
|
|
37
34
|
onResizeStart,
|
|
38
|
-
|
|
35
|
+
onResetResize,
|
|
39
36
|
onOpenChange,
|
|
40
37
|
defaultOpen,
|
|
38
|
+
onResizeEnd,
|
|
39
|
+
slotProps,
|
|
41
40
|
className,
|
|
42
|
-
style,
|
|
43
41
|
children,
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
onResize,
|
|
43
|
+
isOpen,
|
|
44
|
+
width,
|
|
45
|
+
style,
|
|
46
46
|
...other
|
|
47
47
|
} = panelProps;
|
|
48
48
|
const {
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
export
|
|
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 {
|
|
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
|
|
7
|
-
(
|
|
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:
|
|
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 {
|
|
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
|
|
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
|
-
|
|
20
|
+
as?: ElementType;
|
|
21
|
+
} & Omit<SeparatorProps, 'elementType'> & HTMLAttributes<HTMLElement>;
|
|
@@ -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
|
-
({
|
|
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-
|
|
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,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
|
+
};
|