@react-fabric/form 1.0.0-beta.55 → 1.0.0-beta.57
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/_field.css +1 -1
- package/dist/cjs/builder/FileField.js +2 -2
- package/dist/cjs/input/AvatarInput.js +18 -16
- package/dist/cjs/input/ColorInput.js +6 -3
- package/dist/cjs/input/DateInput.js +6 -4
- package/dist/cjs/input/Hidden.js +4 -3
- package/dist/cjs/input/Input.js +6 -4
- package/dist/cjs/input/Number.js +6 -4
- package/dist/cjs/input/Password.js +6 -4
- package/dist/cjs/input/Search.js +6 -4
- package/dist/cjs/input/Slider.js +2 -2
- package/dist/cjs/input/Textarea.js +7 -5
- package/dist/cjs/select/AutoComplete.js +1 -2
- package/dist/cjs/select/List.js +5 -2
- package/dist/cjs/select/Options.js +49 -42
- package/dist/cjs/select/Select.js +4 -2
- package/dist/cjs/select/useSelect.js +14 -7
- package/dist/esm/builder/FileField.js +3 -3
- package/dist/esm/input/AvatarInput.js +19 -17
- package/dist/esm/input/ColorInput.js +6 -3
- package/dist/esm/input/DateInput.js +6 -4
- package/dist/esm/input/Hidden.js +4 -3
- package/dist/esm/input/Input.js +6 -4
- package/dist/esm/input/Number.js +6 -4
- package/dist/esm/input/Password.js +6 -4
- package/dist/esm/input/Search.js +6 -4
- package/dist/esm/input/Slider.js +2 -2
- package/dist/esm/input/Textarea.js +7 -5
- package/dist/esm/select/AutoComplete.js +1 -2
- package/dist/esm/select/List.js +5 -2
- package/dist/esm/select/Options.js +49 -42
- package/dist/esm/select/Select.js +4 -2
- package/dist/esm/select/useSelect.js +14 -7
- package/dist/types/input/AvatarInput.d.ts +5 -1
- package/dist/types/input/DateInput.d.ts +1 -1
- package/dist/types/input/Hidden.d.ts +5 -1
- 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/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/Textarea.d.ts +1 -1
- package/dist/types/select/List.d.ts +1 -1
- package/dist/types/select/Options.d.ts +2 -1
- package/dist/types/select/Select.d.ts +1 -1
- package/dist/types/select/useSelect.d.ts +4 -1
- package/dist/types/types/index.d.ts +8 -0
- package/package.json +4 -4
- package/src/builder/FileField.tsx +9 -3
- package/src/input/AvatarInput.tsx +23 -11
- package/src/input/ColorInput.tsx +6 -3
- package/src/input/DateInput.tsx +4 -3
- package/src/input/Hidden.tsx +9 -5
- package/src/input/Input.tsx +4 -3
- package/src/input/Number.tsx +4 -3
- package/src/input/Password.tsx +4 -3
- package/src/input/RangeSlider.tsx +1 -1
- package/src/input/Search.tsx +4 -3
- package/src/input/Slider.tsx +8 -5
- package/src/input/Textarea.tsx +5 -4
- package/src/select/AutoComplete.tsx +1 -1
- package/src/select/List.tsx +3 -0
- package/src/select/Options.tsx +47 -43
- package/src/select/Select.tsx +2 -0
- package/src/select/useSelect.tsx +15 -6
- package/src/types/index.ts +8 -0
package/src/input/Hidden.tsx
CHANGED
|
@@ -33,6 +33,10 @@ interface Props {
|
|
|
33
33
|
* hidden value will fire change for form update
|
|
34
34
|
*/
|
|
35
35
|
hiddenValue?: AnyObject;
|
|
36
|
+
/**
|
|
37
|
+
* default avatar image
|
|
38
|
+
*/
|
|
39
|
+
defaultValue?: string;
|
|
36
40
|
/**
|
|
37
41
|
* form onChange handler
|
|
38
42
|
*/
|
|
@@ -49,6 +53,7 @@ interface Props {
|
|
|
49
53
|
*/
|
|
50
54
|
export const HiddenInput = ({
|
|
51
55
|
hiddenValue,
|
|
56
|
+
defaultValue,
|
|
52
57
|
onChange,
|
|
53
58
|
// @ts-expect-error ignore
|
|
54
59
|
// eslint-disable-next-line react/prop-types
|
|
@@ -62,11 +67,10 @@ export const HiddenInput = ({
|
|
|
62
67
|
name,
|
|
63
68
|
}: Props) => {
|
|
64
69
|
useEffect(() => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}, [hiddenValue]);
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
onChange?.(hiddenValue ?? defaultValue);
|
|
72
|
+
}, 50);
|
|
73
|
+
}, [hiddenValue, defaultValue]);
|
|
70
74
|
return (
|
|
71
75
|
<Fragment>
|
|
72
76
|
<input type="hidden" onChange={onChange} value={value} name={name} />
|
package/src/input/Input.tsx
CHANGED
|
@@ -58,6 +58,7 @@ export const Input = ({
|
|
|
58
58
|
disabled,
|
|
59
59
|
required,
|
|
60
60
|
placeholder,
|
|
61
|
+
defaultValue,
|
|
61
62
|
autoFocus,
|
|
62
63
|
error,
|
|
63
64
|
monospace,
|
|
@@ -69,7 +70,7 @@ export const Input = ({
|
|
|
69
70
|
...rest
|
|
70
71
|
}: TextInputProps) => {
|
|
71
72
|
const [actualValue, setActualValue] = useState("");
|
|
72
|
-
const deferred = useDeferredValue(value);
|
|
73
|
+
const deferred = useDeferredValue(value ?? defaultValue);
|
|
73
74
|
|
|
74
75
|
const handleEnterPressed = useHandleEnter(onEnterPressed);
|
|
75
76
|
|
|
@@ -79,11 +80,11 @@ export const Input = ({
|
|
|
79
80
|
|
|
80
81
|
const handleChange = useCallback(
|
|
81
82
|
(e?: ChangeEvent<HTMLInputElement>) => {
|
|
82
|
-
const value = e?.target.value;
|
|
83
|
+
const value = e?.target.value ?? defaultValue;
|
|
83
84
|
setActualValue(value ?? "");
|
|
84
85
|
onChange?.(value ?? null);
|
|
85
86
|
},
|
|
86
|
-
[
|
|
87
|
+
[onChange, defaultValue],
|
|
87
88
|
);
|
|
88
89
|
|
|
89
90
|
return (
|
package/src/input/Number.tsx
CHANGED
|
@@ -66,6 +66,7 @@ export const Number = ({
|
|
|
66
66
|
disabled,
|
|
67
67
|
required,
|
|
68
68
|
placeholder,
|
|
69
|
+
defaultValue,
|
|
69
70
|
autoFocus,
|
|
70
71
|
name,
|
|
71
72
|
min,
|
|
@@ -78,7 +79,7 @@ export const Number = ({
|
|
|
78
79
|
...rest
|
|
79
80
|
}: NumberProps) => {
|
|
80
81
|
const [actualValue, setActualValue] = useState<"" | number>("");
|
|
81
|
-
const deferred = useDeferredValue(value);
|
|
82
|
+
const deferred = useDeferredValue(value ?? defaultValue);
|
|
82
83
|
|
|
83
84
|
const handleEnterPressed = useHandleEnter(onEnterPressed);
|
|
84
85
|
|
|
@@ -88,11 +89,11 @@ export const Number = ({
|
|
|
88
89
|
|
|
89
90
|
const handleChange = useCallback(
|
|
90
91
|
(e?: ChangeEvent<HTMLInputElement>) => {
|
|
91
|
-
const number = e?.target.valueAsNumber;
|
|
92
|
+
const number = e?.target.valueAsNumber ?? defaultValue;
|
|
92
93
|
setActualValue(number ?? "");
|
|
93
94
|
onChange?.(number ?? null);
|
|
94
95
|
},
|
|
95
|
-
[onChange],
|
|
96
|
+
[onChange, defaultValue],
|
|
96
97
|
);
|
|
97
98
|
|
|
98
99
|
return (
|
package/src/input/Password.tsx
CHANGED
|
@@ -63,6 +63,7 @@ export const Password = ({
|
|
|
63
63
|
disabled,
|
|
64
64
|
required,
|
|
65
65
|
placeholder,
|
|
66
|
+
defaultValue,
|
|
66
67
|
autoFocus,
|
|
67
68
|
showToggle,
|
|
68
69
|
onBlur,
|
|
@@ -75,7 +76,7 @@ export const Password = ({
|
|
|
75
76
|
const [show, setShow] = useState(false);
|
|
76
77
|
|
|
77
78
|
const [actualValue, setActualValue] = useState("");
|
|
78
|
-
const deferred = useDeferredValue(value);
|
|
79
|
+
const deferred = useDeferredValue(value ?? defaultValue);
|
|
79
80
|
|
|
80
81
|
const handleEnterPressed = useHandleEnter(onEnterPressed);
|
|
81
82
|
|
|
@@ -85,11 +86,11 @@ export const Password = ({
|
|
|
85
86
|
|
|
86
87
|
const handleChange = useCallback(
|
|
87
88
|
(e?: ChangeEvent<HTMLInputElement>) => {
|
|
88
|
-
const value = e?.target.value;
|
|
89
|
+
const value = e?.target.value ?? defaultValue;
|
|
89
90
|
setActualValue(value ?? "");
|
|
90
91
|
onChange?.(value ?? null);
|
|
91
92
|
},
|
|
92
|
-
[onChange],
|
|
93
|
+
[onChange, defaultValue],
|
|
93
94
|
);
|
|
94
95
|
|
|
95
96
|
return (
|
|
@@ -38,7 +38,7 @@ import { type InputProps } from "../types";
|
|
|
38
38
|
export interface RangeProps
|
|
39
39
|
extends Omit<
|
|
40
40
|
InputProps<[number, number]>,
|
|
41
|
-
"placeholder" | "allowClear" | "children"
|
|
41
|
+
"placeholder" | "allowClear" | "children" | "defaultValue"
|
|
42
42
|
> {
|
|
43
43
|
/**
|
|
44
44
|
* min value
|
package/src/input/Search.tsx
CHANGED
|
@@ -74,6 +74,7 @@ export const Search = ({
|
|
|
74
74
|
required,
|
|
75
75
|
searching,
|
|
76
76
|
placeholder,
|
|
77
|
+
defaultValue,
|
|
77
78
|
autoFocus,
|
|
78
79
|
hideHandle,
|
|
79
80
|
allowClear = true,
|
|
@@ -86,7 +87,7 @@ export const Search = ({
|
|
|
86
87
|
...rest
|
|
87
88
|
}: SearchProps) => {
|
|
88
89
|
const [actualValue, setActualValue] = useState("");
|
|
89
|
-
const deferred = useDeferredValue(value);
|
|
90
|
+
const deferred = useDeferredValue(value ?? defaultValue);
|
|
90
91
|
|
|
91
92
|
const refValue = useRef("");
|
|
92
93
|
const handleSearch = useDebounce(
|
|
@@ -103,7 +104,7 @@ export const Search = ({
|
|
|
103
104
|
|
|
104
105
|
const handleChange = useCallback(
|
|
105
106
|
(e?: ChangeEvent<HTMLInputElement>) => {
|
|
106
|
-
const value = e?.target.value;
|
|
107
|
+
const value = e?.target.value ?? defaultValue;
|
|
107
108
|
refValue.current = value ?? "";
|
|
108
109
|
setActualValue(value ?? "");
|
|
109
110
|
onChange?.(value ?? null);
|
|
@@ -113,7 +114,7 @@ export const Search = ({
|
|
|
113
114
|
handleSearch();
|
|
114
115
|
}
|
|
115
116
|
},
|
|
116
|
-
[onChange, searchOnChange, handleSearch],
|
|
117
|
+
[onChange, searchOnChange, handleSearch, defaultValue],
|
|
117
118
|
);
|
|
118
119
|
|
|
119
120
|
return (
|
package/src/input/Slider.tsx
CHANGED
|
@@ -36,7 +36,10 @@ import { useRanger } from "../ranger";
|
|
|
36
36
|
import { type InputProps } from "../types";
|
|
37
37
|
|
|
38
38
|
export interface SliderProps
|
|
39
|
-
extends Omit<
|
|
39
|
+
extends Omit<
|
|
40
|
+
InputProps<number>,
|
|
41
|
+
"placeholder" | "allowClear" | "children" | "defaultValue"
|
|
42
|
+
> {
|
|
40
43
|
/**
|
|
41
44
|
* min value
|
|
42
45
|
*/
|
|
@@ -211,8 +214,8 @@ export const Slider = ({
|
|
|
211
214
|
<div
|
|
212
215
|
ref={rangerInstance.trackElRef}
|
|
213
216
|
className={classNames(
|
|
214
|
-
"
|
|
215
|
-
vertical ? "my-2 w-8" : "mx-2 h-8",
|
|
217
|
+
"relative flex items-center",
|
|
218
|
+
vertical ? "my-2 w-8" : "flex-1 mx-2 h-8",
|
|
216
219
|
)}
|
|
217
220
|
style={{ height: vertical ? height : undefined }}
|
|
218
221
|
>
|
|
@@ -259,10 +262,10 @@ export const Slider = ({
|
|
|
259
262
|
{displayValue && (
|
|
260
263
|
<div
|
|
261
264
|
className={classNames(
|
|
262
|
-
"bg-invert text-invert py-px px-2 text-xs absolute rounded z-[5] whitespace-nowrap",
|
|
265
|
+
"bg-invert text-invert py-px px-2 text-xs absolute rounded z-[5] whitespace-nowrap pointer-events-none",
|
|
263
266
|
"before:absolute before:h-1.5 before:w-1.5 before:z-[-1] before:bg-invert before:top-1/2 before:-translate-y-1/2 before:rotate-45",
|
|
264
267
|
vertical
|
|
265
|
-
? "end-0 ltr:translate-x-full rtl:-translate-x-full translate-y-2"
|
|
268
|
+
? "end-0 ltr:translate-x-full rtl:-translate-x-full translate-y-2 ltr:before:-translate-x-[0.125rem] rtl:before:translate-x-[0.125rem] before:start-0"
|
|
266
269
|
: "top-1/2 -translate-y-1/2",
|
|
267
270
|
!vertical &&
|
|
268
271
|
(percentage > 50
|
package/src/input/Textarea.tsx
CHANGED
|
@@ -74,6 +74,7 @@ export const Textarea = ({
|
|
|
74
74
|
disabled,
|
|
75
75
|
required,
|
|
76
76
|
placeholder,
|
|
77
|
+
defaultValue,
|
|
77
78
|
autoFocus,
|
|
78
79
|
rows = 5,
|
|
79
80
|
maxRows = 12,
|
|
@@ -87,7 +88,7 @@ export const Textarea = ({
|
|
|
87
88
|
}: TextareaProps) => {
|
|
88
89
|
const [actualValue, setActualValue] = useState("");
|
|
89
90
|
const [fixedRows, setFixedRows] = useState(rows);
|
|
90
|
-
const deferred = useDeferredValue(value);
|
|
91
|
+
const deferred = useDeferredValue(value ?? defaultValue);
|
|
91
92
|
const wrapperRef = useRef(null);
|
|
92
93
|
|
|
93
94
|
useEffect(() => {
|
|
@@ -96,11 +97,11 @@ export const Textarea = ({
|
|
|
96
97
|
|
|
97
98
|
const handleChange = useCallback(
|
|
98
99
|
(e?: ChangeEvent<HTMLTextAreaElement>) => {
|
|
99
|
-
const value = e?.target.value;
|
|
100
|
+
const value = e?.target.value ?? defaultValue;
|
|
100
101
|
setActualValue(value ?? "");
|
|
101
102
|
onChange?.(value ?? null);
|
|
102
103
|
},
|
|
103
|
-
[onChange],
|
|
104
|
+
[onChange, defaultValue],
|
|
104
105
|
);
|
|
105
106
|
|
|
106
107
|
useEffect(() => {
|
|
@@ -130,7 +131,7 @@ export const Textarea = ({
|
|
|
130
131
|
{...rest}
|
|
131
132
|
>
|
|
132
133
|
<textarea
|
|
133
|
-
className="appearance-none self-stretch bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0 min-h-
|
|
134
|
+
className="appearance-none self-stretch bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0 min-h-12 resize-none"
|
|
134
135
|
aria-invalid={invalid}
|
|
135
136
|
aria-disabled={disabled}
|
|
136
137
|
aria-readonly={readOnly}
|
package/src/select/List.tsx
CHANGED
|
@@ -61,6 +61,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
61
61
|
groupProperty,
|
|
62
62
|
labelProperty,
|
|
63
63
|
valueProperty,
|
|
64
|
+
infoProperty,
|
|
64
65
|
sortProperty,
|
|
65
66
|
multiple,
|
|
66
67
|
allowCreate,
|
|
@@ -106,6 +107,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
106
107
|
value,
|
|
107
108
|
options,
|
|
108
109
|
multiple,
|
|
110
|
+
alwaysOpen: true,
|
|
109
111
|
groupProperty,
|
|
110
112
|
labelProperty,
|
|
111
113
|
valueProperty,
|
|
@@ -320,6 +322,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
320
322
|
itemRef={setItemRef}
|
|
321
323
|
itemProps={makeItemProps}
|
|
322
324
|
empty={emptyDisplay}
|
|
325
|
+
info={state.activeItem?.[infoProperty ?? "info"]}
|
|
323
326
|
>
|
|
324
327
|
{(item, label) => renderer?.(item) ?? label}
|
|
325
328
|
</Options>
|
package/src/select/Options.tsx
CHANGED
|
@@ -34,6 +34,7 @@ export const Options = ({
|
|
|
34
34
|
className,
|
|
35
35
|
itemRef,
|
|
36
36
|
empty,
|
|
37
|
+
info,
|
|
37
38
|
valueProperty = "id",
|
|
38
39
|
labelProperty = "label",
|
|
39
40
|
itemProps,
|
|
@@ -41,6 +42,7 @@ export const Options = ({
|
|
|
41
42
|
...rest
|
|
42
43
|
}: {
|
|
43
44
|
ref: AnyObject;
|
|
45
|
+
info?: AnyObject;
|
|
44
46
|
itemRef: AnyObject;
|
|
45
47
|
style?: AnyObject;
|
|
46
48
|
items: AnyObject[];
|
|
@@ -55,29 +57,48 @@ export const Options = ({
|
|
|
55
57
|
return (
|
|
56
58
|
<div
|
|
57
59
|
ref={ref}
|
|
58
|
-
className={classNames(
|
|
59
|
-
"bg-base select-none overflow-x-hidden overflow-y-auto",
|
|
60
|
-
className,
|
|
61
|
-
)}
|
|
60
|
+
className={classNames("bg-base select-none flex flex-col", className)}
|
|
62
61
|
style={style}
|
|
63
62
|
{...rest}
|
|
64
63
|
>
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
64
|
+
<div className={classNames("overflow-x-hidden overflow-y-auto flex-1")}>
|
|
65
|
+
{items.length === 0 &&
|
|
66
|
+
(empty ?? (
|
|
67
|
+
<EmptyContent message={<Trans i18nKey="form:select.emptyList" />} />
|
|
68
|
+
))}
|
|
69
|
+
{items.map((item, index) => {
|
|
70
|
+
if (item.___group___)
|
|
71
|
+
return (
|
|
72
|
+
<p
|
|
73
|
+
key={index}
|
|
74
|
+
className="px-2 py-1 text-muted text-xs sticky -top-px z-2 bg-base border-t"
|
|
75
|
+
>
|
|
76
|
+
{item.label}
|
|
77
|
+
</p>
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (item.___create___)
|
|
81
|
+
return (
|
|
82
|
+
<div
|
|
83
|
+
role="none"
|
|
84
|
+
key={index}
|
|
85
|
+
tabIndex={active === index ? 0 : -1}
|
|
86
|
+
ref={(el: AnyObject) => itemRef(index, el)}
|
|
87
|
+
data-active={active === index ? true : undefined}
|
|
88
|
+
className={classNames(
|
|
89
|
+
"block text-start truncate px-2 py-1 leading-normal cursor-pointer select-none",
|
|
90
|
+
"data-[active]:bg-primary-200 data-[selected]:bg-primary-600 data-[selected]:text-white data-[active]:data-[selected]:underline",
|
|
91
|
+
)}
|
|
92
|
+
{...itemProps(item)}
|
|
93
|
+
>
|
|
94
|
+
<Trans
|
|
95
|
+
i18nKey="form:select.createOption"
|
|
96
|
+
values={{ query: item.value ?? item }}
|
|
97
|
+
components={[<strong key="t0">query</strong>]}
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
79
101
|
|
|
80
|
-
if (item.___create___)
|
|
81
102
|
return (
|
|
82
103
|
<div
|
|
83
104
|
role="none"
|
|
@@ -86,36 +107,19 @@ export const Options = ({
|
|
|
86
107
|
ref={(el: AnyObject) => itemRef(index, el)}
|
|
87
108
|
data-active={active === index ? true : undefined}
|
|
88
109
|
className={classNames(
|
|
89
|
-
"block text-start truncate px-2 py-1 leading-normal cursor-pointer
|
|
110
|
+
"block text-start truncate px-2 py-1 leading-normal cursor-pointer",
|
|
90
111
|
"data-[active]:bg-primary-200 data-[selected]:bg-primary-600 data-[selected]:text-white data-[active]:data-[selected]:underline",
|
|
91
112
|
)}
|
|
92
113
|
{...itemProps(item)}
|
|
93
114
|
>
|
|
94
|
-
|
|
95
|
-
i18nKey="form:select.createOption"
|
|
96
|
-
values={{ query: item.value ?? item }}
|
|
97
|
-
components={[<strong key="t0">query</strong>]}
|
|
98
|
-
/>
|
|
115
|
+
{children(item, item[labelProperty] ?? item)}
|
|
99
116
|
</div>
|
|
100
117
|
);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
tabIndex={active === index ? 0 : -1}
|
|
107
|
-
ref={(el: AnyObject) => itemRef(index, el)}
|
|
108
|
-
data-active={active === index ? true : undefined}
|
|
109
|
-
className={classNames(
|
|
110
|
-
"block text-start truncate px-2 py-1 leading-normal cursor-pointer",
|
|
111
|
-
"data-[active]:bg-primary-200 data-[selected]:bg-primary-600 data-[selected]:text-white data-[active]:data-[selected]:underline",
|
|
112
|
-
)}
|
|
113
|
-
{...itemProps(item)}
|
|
114
|
-
>
|
|
115
|
-
{children(item, item[labelProperty] ?? item)}
|
|
116
|
-
</div>
|
|
117
|
-
);
|
|
118
|
-
})}
|
|
118
|
+
})}
|
|
119
|
+
</div>
|
|
120
|
+
{info && (
|
|
121
|
+
<div className="px-2 py-1 text-sm bg-dimmed text-muted">{info}</div>
|
|
122
|
+
)}
|
|
119
123
|
</div>
|
|
120
124
|
);
|
|
121
125
|
};
|
package/src/select/Select.tsx
CHANGED
|
@@ -70,6 +70,7 @@ export const Select = <T extends AnyObject = string>({
|
|
|
70
70
|
labelProperty = "label" as AnyObject,
|
|
71
71
|
valueProperty = "id" as AnyObject,
|
|
72
72
|
sortProperty,
|
|
73
|
+
infoProperty,
|
|
73
74
|
multiple,
|
|
74
75
|
searchable,
|
|
75
76
|
allowCreate,
|
|
@@ -357,6 +358,7 @@ export const Select = <T extends AnyObject = string>({
|
|
|
357
358
|
itemRef={setItemRef}
|
|
358
359
|
itemProps={makeItemProps}
|
|
359
360
|
empty={emptyDisplay}
|
|
361
|
+
info={state.activeItem?.[infoProperty ?? "info"]}
|
|
360
362
|
>
|
|
361
363
|
{(item, label) => renderer?.(item) ?? label}
|
|
362
364
|
</Options>
|
package/src/select/useSelect.tsx
CHANGED
|
@@ -65,6 +65,7 @@ interface State {
|
|
|
65
65
|
open: boolean;
|
|
66
66
|
loading: boolean;
|
|
67
67
|
activeIndex: number | null;
|
|
68
|
+
activeItem: AnyObject;
|
|
68
69
|
selectedIndex: number | null;
|
|
69
70
|
value: AnyObject;
|
|
70
71
|
// filter
|
|
@@ -76,8 +77,9 @@ interface State {
|
|
|
76
77
|
export const useSelect = ({
|
|
77
78
|
options = EMPTY_ARRAY,
|
|
78
79
|
value,
|
|
79
|
-
defaultOpen = false,
|
|
80
80
|
autoComplete,
|
|
81
|
+
alwaysOpen = false,
|
|
82
|
+
defaultOpen = false,
|
|
81
83
|
multiple = false,
|
|
82
84
|
allowCreate = false,
|
|
83
85
|
groupProperty = "",
|
|
@@ -93,6 +95,7 @@ export const useSelect = ({
|
|
|
93
95
|
value?: AnyObject;
|
|
94
96
|
options?: AnyObject[];
|
|
95
97
|
multiple?: boolean;
|
|
98
|
+
alwaysOpen?: boolean;
|
|
96
99
|
defaultOpen?: boolean;
|
|
97
100
|
allowCreate?: boolean;
|
|
98
101
|
groupProperty?: AnyObject;
|
|
@@ -149,12 +152,16 @@ export const useSelect = ({
|
|
|
149
152
|
};
|
|
150
153
|
}
|
|
151
154
|
if (action.type === "close") {
|
|
152
|
-
return { ...state, activeIndex: null, open: false };
|
|
155
|
+
return { ...state, activeIndex: null, activeItem: null, open: false };
|
|
153
156
|
}
|
|
154
157
|
if (action.type === "active" && state.open) {
|
|
155
158
|
if (autoComplete && action.index !== null)
|
|
156
159
|
state.query = state.items[action.index];
|
|
157
|
-
return {
|
|
160
|
+
return {
|
|
161
|
+
...state,
|
|
162
|
+
activeIndex: action.index,
|
|
163
|
+
activeItem: state.items[action.index ?? -1],
|
|
164
|
+
};
|
|
158
165
|
}
|
|
159
166
|
if (action.type === "setValue") {
|
|
160
167
|
return {
|
|
@@ -170,6 +177,7 @@ export const useSelect = ({
|
|
|
170
177
|
...state,
|
|
171
178
|
value: state.emptyValue,
|
|
172
179
|
activeIndex: null,
|
|
180
|
+
activeItem: null,
|
|
173
181
|
selectedIndex: autoComplete
|
|
174
182
|
? state.multiple
|
|
175
183
|
? action.value?.length
|
|
@@ -192,7 +200,7 @@ export const useSelect = ({
|
|
|
192
200
|
newState.value = action.value;
|
|
193
201
|
}
|
|
194
202
|
}
|
|
195
|
-
if (!state.multiple) newState.open =
|
|
203
|
+
if (!state.multiple) newState.open = alwaysOpen;
|
|
196
204
|
fireChange(newState.value);
|
|
197
205
|
return newState;
|
|
198
206
|
}
|
|
@@ -261,9 +269,10 @@ export const useSelect = ({
|
|
|
261
269
|
{
|
|
262
270
|
multiple,
|
|
263
271
|
emptyValue,
|
|
264
|
-
open: defaultOpen,
|
|
272
|
+
open: alwaysOpen || defaultOpen,
|
|
265
273
|
loading: false,
|
|
266
274
|
activeIndex: null,
|
|
275
|
+
activeItem: null,
|
|
267
276
|
selectedIndex: null,
|
|
268
277
|
value: emptyValue,
|
|
269
278
|
// filter
|
|
@@ -407,7 +416,7 @@ export const useSelect = ({
|
|
|
407
416
|
}, []);
|
|
408
417
|
|
|
409
418
|
const setActiveIndex = useCallback((index: number | null) => {
|
|
410
|
-
dispatch({ type: "active", index });
|
|
419
|
+
index && index > -1 && dispatch({ type: "active", index });
|
|
411
420
|
}, []);
|
|
412
421
|
|
|
413
422
|
return {
|
package/src/types/index.ts
CHANGED
|
@@ -32,6 +32,10 @@ export interface InputProps<V = string> extends TestProps {
|
|
|
32
32
|
* value
|
|
33
33
|
*/
|
|
34
34
|
value?: V | null;
|
|
35
|
+
/**
|
|
36
|
+
* default value
|
|
37
|
+
*/
|
|
38
|
+
defaultValue?: V | null;
|
|
35
39
|
/**
|
|
36
40
|
* change handler
|
|
37
41
|
*/
|
|
@@ -150,6 +154,10 @@ export interface BaseSelectProps<T extends AnyObject = string> {
|
|
|
150
154
|
* value property name
|
|
151
155
|
*/
|
|
152
156
|
valueProperty?: keyof T;
|
|
157
|
+
/**
|
|
158
|
+
* value property name
|
|
159
|
+
*/
|
|
160
|
+
infoProperty?: keyof T;
|
|
153
161
|
/**
|
|
154
162
|
* value property name
|
|
155
163
|
*/
|