@react-fabric/form 1.0.0-beta.61 → 1.0.0-beta.63
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/css/_colorPicker.css +35 -5
- package/css/_file.css +2 -2
- package/dist/cjs/builder/FileField.js +14 -11
- package/dist/cjs/builder/SchemaEditor.js +1 -1
- package/dist/cjs/builder/components/SchemaArrayForm.js +2 -4
- package/dist/cjs/builder/components/SchemaField.js +3 -3
- package/dist/cjs/form/Controller.js +1 -1
- package/dist/cjs/form/Form.js +42 -41
- package/dist/cjs/form/useForm.js +32 -0
- package/dist/cjs/hooks/useFileUploader.js +44 -32
- package/dist/cjs/hooks/useFormBuilder.js +3 -3
- package/dist/cjs/i18n/index.js +4 -4
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/input/ArrayInput.js +66 -19
- package/dist/cjs/input/AvatarInput.js +21 -16
- package/dist/cjs/input/Checkbox.js +1 -1
- package/dist/cjs/input/ColorInput.js +26 -19
- package/dist/cjs/input/ColorPicker.js +16 -9
- package/dist/cjs/input/DateInput.js +3 -3
- package/dist/cjs/input/Field.js +1 -1
- package/dist/cjs/input/File.js +1 -1
- package/dist/cjs/input/Hidden.js +2 -11
- package/dist/cjs/input/Input.js +1 -1
- package/dist/cjs/input/Number.js +1 -1
- package/dist/cjs/input/Password.js +1 -1
- package/dist/cjs/input/Radio.js +1 -1
- package/dist/cjs/input/RadioGroup.js +7 -3
- package/dist/cjs/input/RangeSlider.js +1 -1
- package/dist/cjs/input/Search.js +1 -1
- package/dist/cjs/input/Slider.js +1 -1
- package/dist/cjs/input/Switch.js +4 -4
- package/dist/cjs/input/Textarea.js +1 -1
- package/dist/cjs/internal/InputWrapper.js +2 -2
- package/dist/cjs/ranger/index.js +5 -5
- package/dist/cjs/select/AutoComplete.js +4 -2
- package/dist/cjs/select/DualList.js +3 -3
- package/dist/cjs/select/List.js +7 -4
- package/dist/cjs/select/Options.js +5 -4
- package/dist/cjs/select/Select.js +5 -3
- package/dist/cjs/select/useSelect.js +15 -13
- package/dist/esm/builder/FileField.js +14 -11
- package/dist/esm/builder/SchemaEditor.js +1 -1
- package/dist/esm/builder/components/SchemaArrayForm.js +2 -4
- package/dist/esm/builder/components/SchemaField.js +3 -3
- package/dist/esm/form/Controller.js +1 -1
- package/dist/esm/form/Form.js +45 -43
- package/dist/esm/form/useForm.js +32 -0
- package/dist/esm/hooks/useFileUploader.js +45 -33
- package/dist/esm/hooks/useFormBuilder.js +3 -3
- package/dist/esm/i18n/index.js +2 -2
- package/dist/esm/index.js +2 -1
- package/dist/esm/input/ArrayInput.js +66 -19
- package/dist/esm/input/AvatarInput.js +21 -16
- package/dist/esm/input/Checkbox.js +1 -1
- package/dist/esm/input/ColorInput.js +27 -20
- package/dist/esm/input/ColorPicker.js +17 -10
- package/dist/esm/input/DateInput.js +3 -3
- package/dist/esm/input/Field.js +1 -1
- package/dist/esm/input/File.js +1 -1
- package/dist/esm/input/Hidden.js +3 -12
- package/dist/esm/input/Input.js +1 -1
- package/dist/esm/input/Number.js +1 -1
- package/dist/esm/input/Password.js +1 -1
- package/dist/esm/input/Radio.js +1 -1
- package/dist/esm/input/RadioGroup.js +7 -3
- package/dist/esm/input/RangeSlider.js +1 -1
- package/dist/esm/input/Search.js +1 -1
- package/dist/esm/input/Slider.js +1 -1
- package/dist/esm/input/Switch.js +4 -4
- package/dist/esm/input/Textarea.js +1 -1
- package/dist/esm/internal/InputWrapper.js +2 -2
- package/dist/esm/ranger/index.js +5 -5
- package/dist/esm/select/AutoComplete.js +4 -2
- package/dist/esm/select/DualList.js +3 -3
- package/dist/esm/select/List.js +8 -5
- package/dist/esm/select/Options.js +5 -4
- package/dist/esm/select/Select.js +6 -4
- package/dist/esm/select/useSelect.js +15 -13
- package/dist/types/builder/FileField.d.ts +2 -1
- package/dist/types/builder/SchemaEditor.d.ts +1 -1
- package/dist/types/form/Controller.d.ts +1 -1
- package/dist/types/form/Form.d.ts +7 -14
- package/dist/types/form/useForm.d.ts +11 -0
- package/dist/types/hooks/useFileUploader.d.ts +4 -2
- package/dist/types/index.d.ts +3 -2
- package/dist/types/input/ArrayInput.d.ts +5 -4
- package/dist/types/input/AvatarInput.d.ts +2 -2
- package/dist/types/input/Checkbox.d.ts +2 -2
- package/dist/types/input/ColorInput.d.ts +1 -1
- package/dist/types/input/ColorPicker.d.ts +5 -1
- package/dist/types/input/DateInput.d.ts +1 -1
- package/dist/types/input/Field.d.ts +1 -1
- package/dist/types/input/File.d.ts +1 -1
- package/dist/types/input/Hidden.d.ts +4 -12
- package/dist/types/input/Input.d.ts +1 -1
- package/dist/types/input/Number.d.ts +1 -1
- package/dist/types/input/Password.d.ts +1 -1
- package/dist/types/input/Radio.d.ts +2 -2
- package/dist/types/input/RadioGroup.d.ts +7 -3
- package/dist/types/input/RangeSlider.d.ts +1 -1
- package/dist/types/input/Search.d.ts +1 -1
- package/dist/types/input/Slider.d.ts +1 -1
- package/dist/types/input/Switch.d.ts +2 -2
- package/dist/types/input/Textarea.d.ts +1 -1
- package/dist/types/select/AutoComplete.d.ts +1 -1
- package/dist/types/select/DualList.d.ts +1 -1
- package/dist/types/select/List.d.ts +1 -1
- package/dist/types/select/Select.d.ts +1 -1
- package/dist/types/types/index.d.ts +3 -3
- package/dist/types/types/schema.d.ts +1 -1
- package/package.json +14 -14
- package/src/builder/FileField.tsx +5 -3
- package/src/builder/SchemaEditor.tsx +2 -2
- package/src/builder/components/SchemaArrayForm.tsx +1 -3
- package/src/builder/components/SchemaField.tsx +3 -3
- package/src/form/Controller.tsx +1 -1
- package/src/form/Form.tsx +21 -43
- package/src/form/useForm.ts +44 -0
- package/src/hooks/useFileUploader.ts +41 -29
- package/src/i18n/index.ts +2 -2
- package/src/index.ts +3 -7
- package/src/input/ArrayInput.tsx +20 -10
- package/src/input/AvatarInput.tsx +12 -12
- package/src/input/Checkbox.tsx +2 -2
- package/src/input/ColorInput.tsx +29 -45
- package/src/input/ColorPicker.tsx +42 -49
- package/src/input/DateInput.tsx +3 -3
- package/src/input/Field.tsx +2 -2
- package/src/input/File.tsx +1 -1
- package/src/input/Hidden.tsx +5 -25
- package/src/input/Input.tsx +1 -1
- package/src/input/Number.tsx +1 -1
- package/src/input/Password.tsx +1 -1
- package/src/input/Radio.tsx +2 -2
- package/src/input/RadioGroup.tsx +11 -3
- package/src/input/RangeSlider.tsx +1 -1
- package/src/input/Search.tsx +1 -1
- package/src/input/Slider.tsx +1 -1
- package/src/input/Switch.tsx +6 -6
- package/src/input/Textarea.tsx +1 -1
- package/src/internal/InputWrapper.tsx +1 -2
- package/src/select/AutoComplete.tsx +13 -52
- package/src/select/DualList.tsx +3 -3
- package/src/select/List.tsx +31 -69
- package/src/select/Options.tsx +4 -3
- package/src/select/Select.tsx +19 -41
- package/src/select/useSelect.tsx +24 -69
- package/src/types/index.ts +3 -3
- package/src/types/schema.ts +1 -1
- /package/dist/cjs/i18n/{ar.json.js → ar/form.json.js} +0 -0
- /package/dist/cjs/i18n/{en.json.js → en/form.json.js} +0 -0
- /package/dist/esm/i18n/{ar.json.js → ar/form.json.js} +0 -0
- /package/dist/esm/i18n/{en.json.js → en/form.json.js} +0 -0
- /package/src/i18n/{ar.json → ar/form.json} +0 -0
- /package/src/i18n/{en.json → en/form.json} +0 -0
package/src/select/List.tsx
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
useTypeahead,
|
|
31
31
|
} from "@floating-ui/react";
|
|
32
32
|
import { Chip } from "@react-fabric/core";
|
|
33
|
-
import { isArray, isEmpty } from "@react-fabric/utilities";
|
|
33
|
+
import { getByPath, isArray, isEmpty } from "@react-fabric/utilities";
|
|
34
34
|
import classNames from "classnames";
|
|
35
35
|
import { Fragment, useCallback, useId, useLayoutEffect, useMemo } from "react";
|
|
36
36
|
import { FieldWrapper } from "../internal/FieldWrapper";
|
|
@@ -45,7 +45,7 @@ import { useSelect } from "./useSelect";
|
|
|
45
45
|
* and custom rendering of options.
|
|
46
46
|
*
|
|
47
47
|
* @param {SelectProps<T>} props - The properties for the List component.
|
|
48
|
-
* @returns {
|
|
48
|
+
* @returns {React.ReactElement} The rendered List component.
|
|
49
49
|
*/
|
|
50
50
|
export const List = <T extends AnyObject = string>({
|
|
51
51
|
ref,
|
|
@@ -59,8 +59,8 @@ export const List = <T extends AnyObject = string>({
|
|
|
59
59
|
options,
|
|
60
60
|
height,
|
|
61
61
|
groupProperty,
|
|
62
|
-
labelProperty,
|
|
63
|
-
valueProperty,
|
|
62
|
+
labelProperty = "label" as AnyObject,
|
|
63
|
+
valueProperty = "value" as AnyObject,
|
|
64
64
|
infoProperty,
|
|
65
65
|
sortProperty,
|
|
66
66
|
multiple,
|
|
@@ -88,37 +88,25 @@ export const List = <T extends AnyObject = string>({
|
|
|
88
88
|
height?: string | number;
|
|
89
89
|
}) => {
|
|
90
90
|
const Wrapper = useMemo(() => (isInner ? Fragment : FieldWrapper), [isInner]);
|
|
91
|
-
const wrapperProps = useMemo(
|
|
92
|
-
() => (isInner ? {} : { ...rest }),
|
|
93
|
-
[isInner, rest],
|
|
94
|
-
);
|
|
91
|
+
const wrapperProps = useMemo(() => (isInner ? {} : { ...rest }), [isInner, rest]);
|
|
95
92
|
|
|
96
|
-
const {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
valueProperty,
|
|
114
|
-
sortProperty,
|
|
115
|
-
allowCreate,
|
|
116
|
-
createOption,
|
|
117
|
-
matcher,
|
|
118
|
-
onChange,
|
|
119
|
-
onSelect,
|
|
120
|
-
onQuery,
|
|
121
|
-
});
|
|
93
|
+
const { state, listRef, listContentRef, macthOption, handleChange, handleRemove, handleQuery, setItemRef, setActiveIndex } =
|
|
94
|
+
useSelect({
|
|
95
|
+
value,
|
|
96
|
+
options,
|
|
97
|
+
multiple,
|
|
98
|
+
alwaysOpen: true,
|
|
99
|
+
groupProperty,
|
|
100
|
+
labelProperty,
|
|
101
|
+
valueProperty,
|
|
102
|
+
sortProperty,
|
|
103
|
+
allowCreate,
|
|
104
|
+
createOption,
|
|
105
|
+
matcher,
|
|
106
|
+
onChange,
|
|
107
|
+
onSelect,
|
|
108
|
+
onQuery,
|
|
109
|
+
});
|
|
122
110
|
|
|
123
111
|
const dropdownKey = useId();
|
|
124
112
|
|
|
@@ -152,9 +140,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
152
140
|
},
|
|
153
141
|
});
|
|
154
142
|
|
|
155
|
-
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions(
|
|
156
|
-
[navigation, typeahead],
|
|
157
|
-
);
|
|
143
|
+
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([navigation, typeahead]);
|
|
158
144
|
|
|
159
145
|
const referenceProps = useMemo(() => {
|
|
160
146
|
const props: AnyObject = getReferenceProps();
|
|
@@ -162,9 +148,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
162
148
|
return {
|
|
163
149
|
...props,
|
|
164
150
|
onBlur(evt: React.FocusEvent) {
|
|
165
|
-
if (
|
|
166
|
-
evt.relatedTarget?.closest(`[data-select-dropdown="${dropdownKey}"]`)
|
|
167
|
-
) {
|
|
151
|
+
if (evt.relatedTarget?.closest(`[data-select-dropdown="${dropdownKey}"]`)) {
|
|
168
152
|
refs.domReference.current?.querySelector("input")?.focus();
|
|
169
153
|
return;
|
|
170
154
|
}
|
|
@@ -183,10 +167,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
183
167
|
} else if (evt.key === "Backspace") {
|
|
184
168
|
!state.query && handleRemove();
|
|
185
169
|
} else if (!searchable || ["ArrowUp", "ArrowDown"].includes(evt.key)) {
|
|
186
|
-
if (
|
|
187
|
-
["ArrowUp", "ArrowDown"].includes(evt.key) &&
|
|
188
|
-
state.activeIndex === null
|
|
189
|
-
) {
|
|
170
|
+
if (["ArrowUp", "ArrowDown"].includes(evt.key) && state.activeIndex === null) {
|
|
190
171
|
setActiveIndex(state.selectedIndex ?? 0);
|
|
191
172
|
}
|
|
192
173
|
setTimeout(() => {
|
|
@@ -195,14 +176,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
195
176
|
}
|
|
196
177
|
},
|
|
197
178
|
};
|
|
198
|
-
}, [
|
|
199
|
-
getReferenceProps,
|
|
200
|
-
onEnterPressed,
|
|
201
|
-
handleQuery,
|
|
202
|
-
refs,
|
|
203
|
-
state.query,
|
|
204
|
-
state.activeIndex,
|
|
205
|
-
]);
|
|
179
|
+
}, [getReferenceProps, onEnterPressed, handleQuery, refs, state.query, state.activeIndex]);
|
|
206
180
|
|
|
207
181
|
const floatingProps = useMemo(() => {
|
|
208
182
|
return getFloatingProps({
|
|
@@ -212,9 +186,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
212
186
|
|
|
213
187
|
const makeItemProps = useCallback(
|
|
214
188
|
(item: AnyObject) => {
|
|
215
|
-
const selected = isArray(state.value)
|
|
216
|
-
? state.value?.includes?.(item)
|
|
217
|
-
: state.value === item;
|
|
189
|
+
const selected = isArray(state.value) ? state.value?.includes?.(item) : state.value === item;
|
|
218
190
|
return {
|
|
219
191
|
...getItemProps({
|
|
220
192
|
"data-selected": selected ? true : undefined,
|
|
@@ -236,11 +208,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
236
208
|
</Chip>
|
|
237
209
|
));
|
|
238
210
|
} else if (!isEmpty(state.value) && !state.query) {
|
|
239
|
-
return (
|
|
240
|
-
<span>
|
|
241
|
-
{renderer?.(state.value) ?? state.value[labelProperty] ?? state.value}
|
|
242
|
-
</span>
|
|
243
|
-
);
|
|
211
|
+
return <span>{renderer?.(state.value) ?? state.value[labelProperty] ?? state.value}</span>;
|
|
244
212
|
}
|
|
245
213
|
}, [state.value, state.query, placeholder, renderer]);
|
|
246
214
|
|
|
@@ -275,9 +243,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
275
243
|
multiple ? "flex-wrap" : "flex-nowrap overflow-hidden",
|
|
276
244
|
)}
|
|
277
245
|
{...referenceProps}
|
|
278
|
-
onMouseUp={(e) =>
|
|
279
|
-
e.currentTarget.querySelector<HTMLElement>("input")?.focus()
|
|
280
|
-
}
|
|
246
|
+
onMouseUp={(e) => e.currentTarget.querySelector<HTMLElement>("input")?.focus()}
|
|
281
247
|
>
|
|
282
248
|
{!hideSelected && displayValue}
|
|
283
249
|
<input
|
|
@@ -300,11 +266,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
300
266
|
/>
|
|
301
267
|
</div>
|
|
302
268
|
</InputWrapper>
|
|
303
|
-
<FloatingFocusManager
|
|
304
|
-
context={context}
|
|
305
|
-
initialFocus={-1}
|
|
306
|
-
visuallyHiddenDismiss
|
|
307
|
-
>
|
|
269
|
+
<FloatingFocusManager context={context} initialFocus={-1} visuallyHiddenDismiss closeOnFocusOut>
|
|
308
270
|
<Options
|
|
309
271
|
ref={refs.setFloating}
|
|
310
272
|
className={classNames(
|
|
@@ -322,7 +284,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
322
284
|
itemRef={setItemRef}
|
|
323
285
|
itemProps={makeItemProps}
|
|
324
286
|
empty={emptyDisplay}
|
|
325
|
-
info={state.activeItem
|
|
287
|
+
info={getByPath(state.activeItem, infoProperty ?? "info")}
|
|
326
288
|
>
|
|
327
289
|
{(item, label) => renderer?.(item) ?? label}
|
|
328
290
|
</Options>
|
package/src/select/Options.tsx
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
import { EmptyContent } from "@react-fabric/core";
|
|
25
25
|
import { type ReactElement } from "@react-fabric/core/dist/types/types";
|
|
26
|
+
import { getByPath } from "@react-fabric/utilities";
|
|
26
27
|
import classNames from "classnames";
|
|
27
28
|
import { Trans } from "react-i18next";
|
|
28
29
|
|
|
@@ -57,7 +58,7 @@ export const Options = ({
|
|
|
57
58
|
return (
|
|
58
59
|
<div
|
|
59
60
|
ref={ref}
|
|
60
|
-
className={classNames("bg-
|
|
61
|
+
className={classNames("bg-default select-none flex flex-col", className)}
|
|
61
62
|
style={style}
|
|
62
63
|
{...rest}
|
|
63
64
|
>
|
|
@@ -71,7 +72,7 @@ export const Options = ({
|
|
|
71
72
|
return (
|
|
72
73
|
<p
|
|
73
74
|
key={index}
|
|
74
|
-
className="px-2 py-1 text-muted text-xs sticky -top-px z-2 bg-
|
|
75
|
+
className="px-2 py-1 text-muted text-xs sticky -top-px z-2 bg-default border-t"
|
|
75
76
|
>
|
|
76
77
|
{item.label}
|
|
77
78
|
</p>
|
|
@@ -112,7 +113,7 @@ export const Options = ({
|
|
|
112
113
|
)}
|
|
113
114
|
{...itemProps(item)}
|
|
114
115
|
>
|
|
115
|
-
{children(item, item
|
|
116
|
+
{children(item, getByPath(item, labelProperty) ?? `${item}`)}
|
|
116
117
|
</div>
|
|
117
118
|
);
|
|
118
119
|
})}
|
package/src/select/Select.tsx
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
useTypeahead,
|
|
37
37
|
} from "@floating-ui/react";
|
|
38
38
|
import { Chip, Icon } from "@react-fabric/core";
|
|
39
|
-
import { isArray, isEmpty } from "@react-fabric/utilities";
|
|
39
|
+
import { getByPath, isArray, isEmpty } from "@react-fabric/utilities";
|
|
40
40
|
import classNames from "classnames";
|
|
41
41
|
import { useCallback, useId, useLayoutEffect, useMemo } from "react";
|
|
42
42
|
import { InputWrapper } from "../internal/InputWrapper";
|
|
@@ -50,7 +50,7 @@ import { useSelect } from "./useSelect";
|
|
|
50
50
|
* and custom rendering of options.
|
|
51
51
|
*
|
|
52
52
|
* @param {SelectProps<T>} props - The properties for the Select component.
|
|
53
|
-
* @returns {
|
|
53
|
+
* @returns {React.ReactElement} The rendered Select component.
|
|
54
54
|
*/
|
|
55
55
|
export const Select = <T extends AnyObject = string>({
|
|
56
56
|
ref,
|
|
@@ -68,7 +68,7 @@ export const Select = <T extends AnyObject = string>({
|
|
|
68
68
|
hideHandle,
|
|
69
69
|
groupProperty,
|
|
70
70
|
labelProperty = "label" as AnyObject,
|
|
71
|
-
valueProperty = "
|
|
71
|
+
valueProperty = "value" as AnyObject,
|
|
72
72
|
sortProperty,
|
|
73
73
|
infoProperty,
|
|
74
74
|
multiple,
|
|
@@ -152,16 +152,16 @@ export const Select = <T extends AnyObject = string>({
|
|
|
152
152
|
onMatch(index) {
|
|
153
153
|
state.open && setActiveIndex(index);
|
|
154
154
|
|
|
155
|
-
!searchable &&
|
|
156
|
-
!multiple &&
|
|
157
|
-
!state.open &&
|
|
158
|
-
handleChange(listContentRef.current[index]);
|
|
155
|
+
!searchable && !multiple && !state.open && handleChange(listContentRef.current[index]);
|
|
159
156
|
},
|
|
160
157
|
});
|
|
161
158
|
|
|
162
|
-
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions(
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([
|
|
160
|
+
dismiss,
|
|
161
|
+
searchable ? undefined : click,
|
|
162
|
+
navigation,
|
|
163
|
+
typeahead,
|
|
164
|
+
]);
|
|
165
165
|
|
|
166
166
|
const referenceProps = useMemo(() => {
|
|
167
167
|
const props: AnyObject = getReferenceProps();
|
|
@@ -169,9 +169,7 @@ export const Select = <T extends AnyObject = string>({
|
|
|
169
169
|
return {
|
|
170
170
|
...props,
|
|
171
171
|
onBlur(evt: React.FocusEvent) {
|
|
172
|
-
if (
|
|
173
|
-
evt.relatedTarget?.closest(`[data-select-dropdown="${dropdownKey}"]`)
|
|
174
|
-
) {
|
|
172
|
+
if (evt.relatedTarget?.closest(`[data-select-dropdown="${dropdownKey}"]`)) {
|
|
175
173
|
refs.domReference.current?.querySelector("input")?.focus();
|
|
176
174
|
return;
|
|
177
175
|
}
|
|
@@ -198,10 +196,7 @@ export const Select = <T extends AnyObject = string>({
|
|
|
198
196
|
} else if (evt.key === "Backspace") {
|
|
199
197
|
!state.query && handleRemove();
|
|
200
198
|
} else if (!searchable || ["ArrowUp", "ArrowDown"].includes(evt.key)) {
|
|
201
|
-
if (
|
|
202
|
-
["ArrowUp", "ArrowDown"].includes(evt.key) &&
|
|
203
|
-
state.activeIndex === null
|
|
204
|
-
) {
|
|
199
|
+
if (["ArrowUp", "ArrowDown"].includes(evt.key) && state.activeIndex === null) {
|
|
205
200
|
setActiveIndex(state.selectedIndex);
|
|
206
201
|
}
|
|
207
202
|
setTimeout(() => {
|
|
@@ -210,14 +205,7 @@ export const Select = <T extends AnyObject = string>({
|
|
|
210
205
|
}
|
|
211
206
|
},
|
|
212
207
|
};
|
|
213
|
-
}, [
|
|
214
|
-
getReferenceProps,
|
|
215
|
-
onEnterPressed,
|
|
216
|
-
handleQuery,
|
|
217
|
-
refs,
|
|
218
|
-
state.query,
|
|
219
|
-
state.activeIndex,
|
|
220
|
-
]);
|
|
208
|
+
}, [getReferenceProps, onEnterPressed, handleQuery, refs, state.query, state.activeIndex]);
|
|
221
209
|
|
|
222
210
|
const floatingProps = useMemo(() => {
|
|
223
211
|
return getFloatingProps({
|
|
@@ -227,9 +215,7 @@ export const Select = <T extends AnyObject = string>({
|
|
|
227
215
|
|
|
228
216
|
const makeItemProps = useCallback(
|
|
229
217
|
(item: AnyObject) => {
|
|
230
|
-
const selected = isArray(state.value)
|
|
231
|
-
? state.value?.includes?.(item)
|
|
232
|
-
: state.value === item;
|
|
218
|
+
const selected = isArray(state.value) ? state.value?.includes?.(item) : state.value === item;
|
|
233
219
|
return getItemProps({
|
|
234
220
|
"data-selected": selected ? true : undefined,
|
|
235
221
|
onClick() {
|
|
@@ -292,9 +278,7 @@ export const Select = <T extends AnyObject = string>({
|
|
|
292
278
|
multiple ? "flex-wrap" : "flex-nowrap overflow-hidden",
|
|
293
279
|
)}
|
|
294
280
|
{...referenceProps}
|
|
295
|
-
onMouseUp={(e) =>
|
|
296
|
-
e.currentTarget.querySelector<HTMLElement>("input")?.focus()
|
|
297
|
-
}
|
|
281
|
+
onMouseUp={(e) => e.currentTarget.querySelector<HTMLElement>("input")?.focus()}
|
|
298
282
|
>
|
|
299
283
|
{displayValue}
|
|
300
284
|
<input
|
|
@@ -329,19 +313,13 @@ export const Select = <T extends AnyObject = string>({
|
|
|
329
313
|
)}
|
|
330
314
|
{state.loading && (
|
|
331
315
|
<Icon
|
|
332
|
-
className={classNames(
|
|
333
|
-
"flex-content p-2 z-0 order-9 text-muted pointer-events-none",
|
|
334
|
-
)}
|
|
316
|
+
className={classNames("flex-content p-2 z-0 order-9 text-muted pointer-events-none")}
|
|
335
317
|
icon="icon-[svg-spinners--eclipse]"
|
|
336
318
|
/>
|
|
337
319
|
)}
|
|
338
320
|
{state.open && !state.loading && (
|
|
339
|
-
<FloatingPortal>
|
|
340
|
-
<FloatingFocusManager
|
|
341
|
-
context={context}
|
|
342
|
-
initialFocus={-1}
|
|
343
|
-
visuallyHiddenDismiss
|
|
344
|
-
>
|
|
321
|
+
<FloatingPortal root={refs.domReference.current?.closest<HTMLElement>(".theme-base") ?? undefined}>
|
|
322
|
+
<FloatingFocusManager context={context} initialFocus={-1} visuallyHiddenDismiss closeOnFocusOut>
|
|
345
323
|
<Options
|
|
346
324
|
ref={refs.setFloating}
|
|
347
325
|
className="outline shadow-lg max-h-[40vh] z-(--z-popover)"
|
|
@@ -357,7 +335,7 @@ export const Select = <T extends AnyObject = string>({
|
|
|
357
335
|
itemRef={setItemRef}
|
|
358
336
|
itemProps={makeItemProps}
|
|
359
337
|
empty={emptyDisplay}
|
|
360
|
-
info={state.activeItem
|
|
338
|
+
info={getByPath(state.activeItem, infoProperty ?? "info")}
|
|
361
339
|
>
|
|
362
340
|
{(item, label) => renderer?.(item) ?? label}
|
|
363
341
|
</Options>
|
package/src/select/useSelect.tsx
CHANGED
|
@@ -22,23 +22,8 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { useDebounce } from "@react-fabric/core";
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
dedupe,
|
|
28
|
-
EMPTY_ARRAY,
|
|
29
|
-
groupBy,
|
|
30
|
-
isArray,
|
|
31
|
-
isString,
|
|
32
|
-
matchString,
|
|
33
|
-
} from "@react-fabric/utilities";
|
|
34
|
-
import {
|
|
35
|
-
useCallback,
|
|
36
|
-
useDeferredValue,
|
|
37
|
-
useEffect,
|
|
38
|
-
useMemo,
|
|
39
|
-
useReducer,
|
|
40
|
-
useRef,
|
|
41
|
-
} from "react";
|
|
25
|
+
import { compareValues, dedupe, EMPTY_ARRAY, groupBy, isArray, isString, matchString } from "@react-fabric/utilities";
|
|
26
|
+
import { useCallback, useDeferredValue, useEffect, useMemo, useReducer, useRef } from "react";
|
|
42
27
|
import { getSelectedValue, makeOption } from "./helpers";
|
|
43
28
|
|
|
44
29
|
type StateActions =
|
|
@@ -121,10 +106,7 @@ export const useSelect = ({
|
|
|
121
106
|
|
|
122
107
|
const macthOption = useCallback(
|
|
123
108
|
(item: AnyObject, query: string) => {
|
|
124
|
-
return (
|
|
125
|
-
matcher?.(item, query) ??
|
|
126
|
-
matchString(item[labelProperty] ?? item, query)
|
|
127
|
-
);
|
|
109
|
+
return matcher?.(item, query) ?? matchString(item[labelProperty] ?? item, query);
|
|
128
110
|
},
|
|
129
111
|
[matcher],
|
|
130
112
|
);
|
|
@@ -142,9 +124,7 @@ export const useSelect = ({
|
|
|
142
124
|
const [state, dispatch] = useReducer(
|
|
143
125
|
(state: State, action: StateActions) => {
|
|
144
126
|
if (action.type === "open") {
|
|
145
|
-
const index = state.items.indexOf(
|
|
146
|
-
state.multiple ? state.value[0] : state.value,
|
|
147
|
-
);
|
|
127
|
+
const index = state.items.indexOf(state.multiple ? state.value[0] : state.value);
|
|
148
128
|
return {
|
|
149
129
|
...state,
|
|
150
130
|
open: true,
|
|
@@ -155,8 +135,7 @@ export const useSelect = ({
|
|
|
155
135
|
return { ...state, activeIndex: null, activeItem: null, open: false };
|
|
156
136
|
}
|
|
157
137
|
if (action.type === "active" && state.open) {
|
|
158
|
-
if (autoComplete && action.index !== null)
|
|
159
|
-
state.query = state.items[action.index];
|
|
138
|
+
if (autoComplete && action.index !== null) state.query = state.items[action.index];
|
|
160
139
|
return {
|
|
161
140
|
...state,
|
|
162
141
|
activeIndex: action.index,
|
|
@@ -167,9 +146,7 @@ export const useSelect = ({
|
|
|
167
146
|
return {
|
|
168
147
|
...state,
|
|
169
148
|
value: action.value,
|
|
170
|
-
selectedIndex: state.items.indexOf(
|
|
171
|
-
state.multiple ? action.value[0] : action.value,
|
|
172
|
-
),
|
|
149
|
+
selectedIndex: state.items.indexOf(state.multiple ? action.value[0] : action.value),
|
|
173
150
|
};
|
|
174
151
|
}
|
|
175
152
|
if (action.type === "changeValue") {
|
|
@@ -178,17 +155,12 @@ export const useSelect = ({
|
|
|
178
155
|
value: state.emptyValue,
|
|
179
156
|
activeIndex: null,
|
|
180
157
|
activeItem: null,
|
|
181
|
-
selectedIndex: autoComplete
|
|
182
|
-
? state.multiple
|
|
183
|
-
? action.value?.length
|
|
184
|
-
: 0
|
|
185
|
-
: state.items.indexOf(action.value),
|
|
158
|
+
selectedIndex: autoComplete ? (state.multiple ? action.value?.length : 0) : state.items.indexOf(action.value),
|
|
186
159
|
};
|
|
187
160
|
if (action.value !== undefined) {
|
|
188
161
|
if (multiple) {
|
|
189
162
|
const values = [];
|
|
190
|
-
if (isString(action.value))
|
|
191
|
-
values.push(...action.value.split(/,\s?/));
|
|
163
|
+
if (isString(action.value)) values.push(...action.value.split(/,\s?/));
|
|
192
164
|
else values.push(action.value);
|
|
193
165
|
newState.value = [...state.value];
|
|
194
166
|
values.forEach((value: AnyObject) => {
|
|
@@ -236,8 +208,7 @@ export const useSelect = ({
|
|
|
236
208
|
if (autoComplete && action.query !== undefined) {
|
|
237
209
|
optionList = dedupe([action.query, ...optionList]);
|
|
238
210
|
}
|
|
239
|
-
if (sortProperty)
|
|
240
|
-
optionList = optionList.sort(compareValues("asc", sortProperty));
|
|
211
|
+
if (sortProperty) optionList = optionList.sort(compareValues("asc", sortProperty));
|
|
241
212
|
const grouped = groupBy(optionList, groupProperty, "");
|
|
242
213
|
if (action.open) newState.open = true;
|
|
243
214
|
newState.items = [];
|
|
@@ -254,9 +225,7 @@ export const useSelect = ({
|
|
|
254
225
|
newState.items.push(...list);
|
|
255
226
|
});
|
|
256
227
|
if (action.setActive) {
|
|
257
|
-
const index = newState.items.findIndex(
|
|
258
|
-
(opt: AnyObject) => !opt.___group___,
|
|
259
|
-
);
|
|
228
|
+
const index = newState.items.findIndex((opt: AnyObject) => !opt.___group___);
|
|
260
229
|
newState.activeIndex = index >= 0 ? index : null;
|
|
261
230
|
} else {
|
|
262
231
|
newState.activeIndex = null;
|
|
@@ -266,7 +235,8 @@ export const useSelect = ({
|
|
|
266
235
|
}
|
|
267
236
|
return state;
|
|
268
237
|
},
|
|
269
|
-
{
|
|
238
|
+
{},
|
|
239
|
+
() => ({
|
|
270
240
|
multiple,
|
|
271
241
|
emptyValue,
|
|
272
242
|
open: alwaysOpen || defaultOpen,
|
|
@@ -279,18 +249,13 @@ export const useSelect = ({
|
|
|
279
249
|
query: undefined,
|
|
280
250
|
// dropdown items
|
|
281
251
|
items: [],
|
|
282
|
-
},
|
|
252
|
+
}),
|
|
283
253
|
);
|
|
284
254
|
|
|
285
255
|
useEffect(() => {
|
|
286
256
|
if (!multiple) {
|
|
287
|
-
const newOption =
|
|
288
|
-
|
|
289
|
-
? createOption(deferred)
|
|
290
|
-
: undefined;
|
|
291
|
-
const hasValue = options.find(
|
|
292
|
-
(opt: AnyObject) => (opt[valueProperty] ?? opt) === deferred,
|
|
293
|
-
);
|
|
257
|
+
const newOption = (allowCreate || autoComplete) && deferred ? createOption(deferred) : undefined;
|
|
258
|
+
const hasValue = options.find((opt: AnyObject) => (opt[valueProperty] ?? opt) === deferred);
|
|
294
259
|
optionsRef.current = options;
|
|
295
260
|
// if current value missing in list inject it
|
|
296
261
|
if (!hasValue && newOption) {
|
|
@@ -304,21 +269,14 @@ export const useSelect = ({
|
|
|
304
269
|
}
|
|
305
270
|
if (multiple) {
|
|
306
271
|
optionsRef.current = [];
|
|
307
|
-
const value = (isArray(deferred) ? deferred : []).map(
|
|
308
|
-
(item
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
);
|
|
316
|
-
if (!hasValue && newOption) {
|
|
317
|
-
optionsRef.current.push(newOption);
|
|
318
|
-
}
|
|
319
|
-
return hasValue ?? newOption ?? item;
|
|
320
|
-
},
|
|
321
|
-
);
|
|
272
|
+
const value = (isArray(deferred) ? deferred : []).map((item: AnyObject) => {
|
|
273
|
+
const newOption = (allowCreate || autoComplete) && item ? createOption(item) : undefined;
|
|
274
|
+
const hasValue = options.find((opt: AnyObject) => (opt[valueProperty] ?? opt) === item);
|
|
275
|
+
if (!hasValue && newOption) {
|
|
276
|
+
optionsRef.current.push(newOption);
|
|
277
|
+
}
|
|
278
|
+
return hasValue ?? newOption ?? item;
|
|
279
|
+
});
|
|
322
280
|
optionsRef.current = [...optionsRef.current, ...(options ?? [])];
|
|
323
281
|
dispatch({ type: "options", options: optionsRef.current });
|
|
324
282
|
dispatch({
|
|
@@ -394,10 +352,7 @@ export const useSelect = ({
|
|
|
394
352
|
optionsRef.current = [...optionsRef.current, ...val.map(createOption)];
|
|
395
353
|
}
|
|
396
354
|
if (autoComplete) {
|
|
397
|
-
optionsRef.current = dedupe([
|
|
398
|
-
...(isArray(values) ? values : [values]),
|
|
399
|
-
...optionsRef.current,
|
|
400
|
-
]);
|
|
355
|
+
optionsRef.current = dedupe([...(isArray(values) ? values : [values]), ...optionsRef.current]);
|
|
401
356
|
}
|
|
402
357
|
dispatch({ type: "options", options: optionsRef.current });
|
|
403
358
|
}, []);
|
package/src/types/index.ts
CHANGED
|
@@ -69,15 +69,15 @@ export interface InputProps<V = string> extends TestProps {
|
|
|
69
69
|
/**
|
|
70
70
|
* append to label end
|
|
71
71
|
*/
|
|
72
|
-
appendLabel?:
|
|
72
|
+
appendLabel?: React.ReactElement | string | number | boolean;
|
|
73
73
|
/**
|
|
74
74
|
*
|
|
75
75
|
*/
|
|
76
|
-
decorateStart?:
|
|
76
|
+
decorateStart?: React.ReactElement | string | number | boolean;
|
|
77
77
|
/**
|
|
78
78
|
*
|
|
79
79
|
*/
|
|
80
|
-
decorateEnd?:
|
|
80
|
+
decorateEnd?: React.ReactElement | string | number | boolean;
|
|
81
81
|
decorateEndShowWhenEmpty?: boolean;
|
|
82
82
|
decorateEndHideWhenEmpty?: boolean;
|
|
83
83
|
/**
|
package/src/types/schema.ts
CHANGED
|
@@ -148,7 +148,7 @@ export interface SchemaEditorProps {
|
|
|
148
148
|
/**
|
|
149
149
|
* footer actions
|
|
150
150
|
*/
|
|
151
|
-
children?: Elements<
|
|
151
|
+
children?: Elements<React.ReactElement> | Array<Elements<React.ReactElement>>;
|
|
152
152
|
|
|
153
153
|
onChange?: (schema: FormSchema) => void;
|
|
154
154
|
onSubmit?: (schema: FormSchema) => void;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|