@react-fabric/form 1.0.0-beta.3 → 1.0.0-beta.30
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/cjs/form/Form.js +12 -5
- package/dist/cjs/input/ArrayInput.js +35 -23
- package/dist/cjs/input/ColorInput.js +68 -26
- package/dist/cjs/input/ColorPicker.js +0 -33
- package/dist/cjs/input/ColorPicker.module.css +1 -1
- package/dist/cjs/input/Field.js +3 -2
- package/dist/cjs/input/File.module.css +1 -1
- package/dist/cjs/input/Hidden.js +3 -1
- package/dist/cjs/input/RadioGroup.js +6 -3
- package/dist/cjs/input/Switch.js +25 -4
- package/dist/cjs/input/Textarea.js +6 -2
- package/dist/cjs/internal/FieldWrapper.js +3 -1
- package/dist/cjs/internal/InputWrapper.js +7 -10
- package/dist/cjs/select/List.js +41 -20
- package/dist/cjs/select/Options.js +2 -2
- package/dist/cjs/select/Select.js +10 -7
- package/dist/cjs/select/useSelect.js +12 -7
- package/dist/cjs/utils/getColor.js +6 -0
- package/dist/esm/form/Form.js +13 -6
- package/dist/esm/input/ArrayInput.js +37 -25
- package/dist/esm/input/ColorInput.js +70 -28
- package/dist/esm/input/ColorPicker.js +0 -33
- package/dist/esm/input/ColorPicker.module.css +1 -1
- package/dist/esm/input/Field.js +4 -3
- package/dist/esm/input/File.module.css +1 -1
- package/dist/esm/input/Hidden.js +3 -1
- package/dist/esm/input/RadioGroup.js +7 -4
- package/dist/esm/input/Switch.js +27 -6
- package/dist/esm/input/Textarea.js +6 -2
- package/dist/esm/internal/FieldWrapper.js +3 -1
- package/dist/esm/internal/InputWrapper.js +7 -10
- package/dist/esm/select/List.js +42 -21
- package/dist/esm/select/Options.js +2 -2
- package/dist/esm/select/Select.js +10 -7
- package/dist/esm/select/useSelect.js +13 -8
- package/dist/esm/utils/getColor.js +6 -1
- package/dist/types/input/ArrayInput.d.ts +20 -3
- package/dist/types/input/RadioGroup.d.ts +18 -2
- package/dist/types/input/Switch.d.ts +7 -3
- package/dist/types/input/Textarea.d.ts +5 -1
- package/dist/types/internal/InputWrapper.d.ts +1 -1
- package/dist/types/select/List.d.ts +1 -1
- package/dist/types/types/index.d.ts +2 -2
- package/package.json +7 -7
- package/src/form/Form.tsx +13 -5
- package/src/input/ArrayInput.tsx +78 -40
- package/src/input/ColorInput.tsx +96 -31
- package/src/input/ColorPicker.module.css +19 -5
- package/src/input/ColorPicker.tsx +0 -33
- package/src/input/Field.tsx +6 -8
- package/src/input/File.module.css +18 -4
- package/src/input/Hidden.tsx +3 -1
- package/src/input/Input.tsx +1 -1
- package/src/input/Number.tsx +1 -1
- package/src/input/Password.tsx +1 -1
- package/src/input/RadioGroup.tsx +27 -4
- package/src/input/Search.tsx +1 -1
- package/src/input/Switch.tsx +40 -6
- package/src/input/Textarea.tsx +10 -2
- package/src/internal/FieldWrapper.tsx +2 -1
- package/src/internal/InputWrapper.tsx +8 -11
- package/src/select/List.tsx +34 -7
- package/src/select/Options.tsx +1 -1
- package/src/select/Select.tsx +4 -1
- package/src/select/useSelect.tsx +27 -18
- package/src/types/index.ts +5 -2
package/src/input/RadioGroup.tsx
CHANGED
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
import { cloneChildren } from "@react-fabric/core";
|
|
24
25
|
import {
|
|
25
|
-
type CssProp,
|
|
26
26
|
type ChildrenProp,
|
|
27
|
+
type CssProp,
|
|
27
28
|
} from "@react-fabric/core/dist/types/types";
|
|
28
|
-
import {
|
|
29
|
+
import { cloneElement } from "react";
|
|
29
30
|
import { FieldWrapper } from "../internal/FieldWrapper";
|
|
30
31
|
import { type Radio } from "./Radio";
|
|
31
32
|
|
|
@@ -42,6 +43,23 @@ export interface RadioGroupProps extends ChildrenProp<typeof Radio>, CssProp {
|
|
|
42
43
|
* field info
|
|
43
44
|
*/
|
|
44
45
|
info?: string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* field width
|
|
49
|
+
*/
|
|
50
|
+
width?: number | string;
|
|
51
|
+
/**
|
|
52
|
+
* inline label and input
|
|
53
|
+
*/
|
|
54
|
+
inline?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* label width for inline
|
|
57
|
+
*/
|
|
58
|
+
labelWidth?: string;
|
|
59
|
+
/**
|
|
60
|
+
* label width for inline
|
|
61
|
+
*/
|
|
62
|
+
optionWidth?: string;
|
|
45
63
|
/**
|
|
46
64
|
* field name
|
|
47
65
|
*/
|
|
@@ -60,14 +78,19 @@ export const RadioGroup = ({
|
|
|
60
78
|
children,
|
|
61
79
|
name,
|
|
62
80
|
className,
|
|
81
|
+
optionWidth,
|
|
63
82
|
onChange,
|
|
64
83
|
...rest
|
|
65
84
|
}: RadioGroupProps) => {
|
|
66
85
|
return (
|
|
67
86
|
<FieldWrapper {...rest}>
|
|
68
87
|
<div className={className}>
|
|
69
|
-
{
|
|
70
|
-
cloneElement(child
|
|
88
|
+
{cloneChildren(children, (child: AnyObject) =>
|
|
89
|
+
cloneElement(child, {
|
|
90
|
+
name,
|
|
91
|
+
onChange,
|
|
92
|
+
width: optionWidth,
|
|
93
|
+
}),
|
|
71
94
|
)}
|
|
72
95
|
</div>
|
|
73
96
|
</FieldWrapper>
|
package/src/input/Search.tsx
CHANGED
package/src/input/Switch.tsx
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
} from "@react-fabric/core/dist/types/types";
|
|
28
28
|
import classNames from "classnames";
|
|
29
29
|
import {
|
|
30
|
+
Fragment,
|
|
30
31
|
useCallback,
|
|
31
32
|
useDeferredValue,
|
|
32
33
|
useEffect,
|
|
@@ -34,7 +35,7 @@ import {
|
|
|
34
35
|
type ChangeEvent,
|
|
35
36
|
} from "react";
|
|
36
37
|
import { ErrorIcon } from "../internal/ErrorIcon";
|
|
37
|
-
import { getBgClass, getColor } from "../utils";
|
|
38
|
+
import { getBgClass, getColor, getColorClass } from "../utils";
|
|
38
39
|
|
|
39
40
|
export interface SwitchProps extends RefProp<HTMLInputElement> {
|
|
40
41
|
/**
|
|
@@ -71,13 +72,19 @@ export interface SwitchProps extends RefProp<HTMLInputElement> {
|
|
|
71
72
|
/**
|
|
72
73
|
* cutom Switch icon
|
|
73
74
|
*/
|
|
74
|
-
color?: ColorType;
|
|
75
|
+
color?: string | ColorType;
|
|
75
76
|
/**
|
|
76
77
|
* cutom Switch icon
|
|
77
78
|
*/
|
|
78
|
-
defaultColor?: ColorType;
|
|
79
|
+
defaultColor?: string | ColorType;
|
|
79
80
|
|
|
80
81
|
name?: string;
|
|
82
|
+
|
|
83
|
+
onLabel?: string;
|
|
84
|
+
onLabelColor?: string | ColorType;
|
|
85
|
+
|
|
86
|
+
offLabel?: string;
|
|
87
|
+
offLabelColor?: string | ColorType;
|
|
81
88
|
}
|
|
82
89
|
|
|
83
90
|
export const Switch = ({
|
|
@@ -90,6 +97,10 @@ export const Switch = ({
|
|
|
90
97
|
width,
|
|
91
98
|
color,
|
|
92
99
|
name,
|
|
100
|
+
onLabel,
|
|
101
|
+
offLabel,
|
|
102
|
+
onLabelColor,
|
|
103
|
+
offLabelColor,
|
|
93
104
|
defaultColor,
|
|
94
105
|
onChange,
|
|
95
106
|
...rest
|
|
@@ -125,7 +136,7 @@ export const Switch = ({
|
|
|
125
136
|
actualValue && getBgClass(color ? `${color}-500` : "primary-500"),
|
|
126
137
|
!actualValue &&
|
|
127
138
|
(defaultColor ? getBgClass(`${defaultColor}-500`) : "bg-tint-200"),
|
|
128
|
-
"relative
|
|
139
|
+
"relative grid grid-cols-2 items-center h-6 min-w-10 cursor-pointer rounded-full p-1 transition-colors duration-200 ease-in-out",
|
|
129
140
|
)}
|
|
130
141
|
style={{
|
|
131
142
|
backgroundColor: actualValue
|
|
@@ -154,10 +165,33 @@ export const Switch = ({
|
|
|
154
165
|
aria-hidden="true"
|
|
155
166
|
className={classNames(
|
|
156
167
|
!disabled && "shadow-sm",
|
|
157
|
-
actualValue ? "translate-x-
|
|
158
|
-
"pointer-events-none inline-block
|
|
168
|
+
actualValue ? "translate-x-[100%]" : "translate-x-0",
|
|
169
|
+
"pointer-events-none inline-block h-4 start-1 absolute rounded-full bg-white ring-0 transition duration-200 ease-in-out",
|
|
159
170
|
)}
|
|
171
|
+
style={{
|
|
172
|
+
width: "calc(50% - 0.25rem)",
|
|
173
|
+
}}
|
|
160
174
|
/>
|
|
175
|
+
{(!!onLabel || !!offLabel) && (
|
|
176
|
+
<Fragment>
|
|
177
|
+
<span
|
|
178
|
+
className={`whitespace-nowrap text-xs px-1 ${getColorClass(onLabelColor ?? "white")}`}
|
|
179
|
+
style={{
|
|
180
|
+
color: getColor(onLabelColor),
|
|
181
|
+
}}
|
|
182
|
+
>
|
|
183
|
+
{onLabel ?? " "}
|
|
184
|
+
</span>
|
|
185
|
+
<span
|
|
186
|
+
className={`whitespace-nowrap text-xs px-1 ${getColorClass(offLabelColor ?? "base")}`}
|
|
187
|
+
style={{
|
|
188
|
+
color: getColor(offLabelColor),
|
|
189
|
+
}}
|
|
190
|
+
>
|
|
191
|
+
{offLabel ?? " "}
|
|
192
|
+
</span>
|
|
193
|
+
</Fragment>
|
|
194
|
+
)}
|
|
161
195
|
</div>
|
|
162
196
|
<ErrorIcon invalid={invalid} error={error} />
|
|
163
197
|
{label && (
|
package/src/input/Textarea.tsx
CHANGED
|
@@ -49,6 +49,10 @@ export interface TextareaProps
|
|
|
49
49
|
* increment rows on value change
|
|
50
50
|
*/
|
|
51
51
|
variableRows?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* expandable textarea
|
|
54
|
+
*/
|
|
55
|
+
expandable?: boolean;
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
export const Textarea = ({
|
|
@@ -64,6 +68,7 @@ export const Textarea = ({
|
|
|
64
68
|
rows = 5,
|
|
65
69
|
maxRows = 12,
|
|
66
70
|
variableRows,
|
|
71
|
+
expandable,
|
|
67
72
|
onChange,
|
|
68
73
|
onEnterPressed,
|
|
69
74
|
...rest
|
|
@@ -104,6 +109,7 @@ export const Textarea = ({
|
|
|
104
109
|
disabled={disabled}
|
|
105
110
|
required={required}
|
|
106
111
|
wrapperRef={wrapperRef}
|
|
112
|
+
textareaExpandable={expandable}
|
|
107
113
|
textarea
|
|
108
114
|
{...rest}
|
|
109
115
|
>
|
|
@@ -120,10 +126,12 @@ export const Textarea = ({
|
|
|
120
126
|
name={name}
|
|
121
127
|
ref={ref}
|
|
122
128
|
autoComplete="off"
|
|
123
|
-
{
|
|
129
|
+
autoFocus={autoFocus}
|
|
124
130
|
value={actualValue}
|
|
125
131
|
onChange={handleChange}
|
|
126
|
-
onKeyDown={handleEnter(onEnterPressed
|
|
132
|
+
onKeyDown={handleEnter(onEnterPressed, {
|
|
133
|
+
preventDefault: !!onEnterPressed,
|
|
134
|
+
})}
|
|
127
135
|
/>
|
|
128
136
|
</InputWrapper>
|
|
129
137
|
);
|
|
@@ -50,7 +50,7 @@ export const FieldWrapper = ({
|
|
|
50
50
|
>
|
|
51
51
|
{!isInner && (
|
|
52
52
|
<div
|
|
53
|
-
className="flex flex-nowrap flex-content gap-1 py-0.5 px-2"
|
|
53
|
+
className="flex flex-nowrap flex-content items-end gap-1 py-0.5 px-2"
|
|
54
54
|
style={{ width: inline ? labelWidth : undefined }}
|
|
55
55
|
>
|
|
56
56
|
<label
|
|
@@ -73,6 +73,7 @@ export const FieldWrapper = ({
|
|
|
73
73
|
✽
|
|
74
74
|
</span>
|
|
75
75
|
)}
|
|
76
|
+
<div className="flex-1" />
|
|
76
77
|
{appendLabel && <span className="flex-content">{appendLabel}</span>}
|
|
77
78
|
</div>
|
|
78
79
|
)}
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import { FloatingPortal } from "@floating-ui/react";
|
|
25
24
|
import { CoreIcons, Icon } from "@react-fabric/core";
|
|
26
25
|
import { isString } from "@react-fabric/utilities";
|
|
27
26
|
import classNames from "classnames";
|
|
@@ -50,6 +49,7 @@ export const InputWrapper = ({
|
|
|
50
49
|
noOutline,
|
|
51
50
|
noBorder,
|
|
52
51
|
textarea = false,
|
|
52
|
+
textareaExpandable = false,
|
|
53
53
|
"data-inner": isInner,
|
|
54
54
|
"data-open": isOpen,
|
|
55
55
|
// expand autocomplete
|
|
@@ -117,7 +117,11 @@ export const InputWrapper = ({
|
|
|
117
117
|
!noOutline &&
|
|
118
118
|
"after:absolute after:bottom-0 after:h-px after:bg-primary-500 after:mx-auto",
|
|
119
119
|
)}
|
|
120
|
-
onKeyDown={(e) =>
|
|
120
|
+
onKeyDown={(e) =>
|
|
121
|
+
e.key === "Escape" &&
|
|
122
|
+
isExpanded &&
|
|
123
|
+
(setExpanded(false), e.stopPropagation())
|
|
124
|
+
}
|
|
121
125
|
>
|
|
122
126
|
{decorateStart && (
|
|
123
127
|
<div
|
|
@@ -156,7 +160,7 @@ export const InputWrapper = ({
|
|
|
156
160
|
{decorateEnd}
|
|
157
161
|
</div>
|
|
158
162
|
)}
|
|
159
|
-
{
|
|
163
|
+
{textareaExpandable && (
|
|
160
164
|
<Icon
|
|
161
165
|
onClick={() => setExpanded(!isExpanded)}
|
|
162
166
|
icon={isExpanded ? CoreIcons.arrowCollapse : CoreIcons.arrowExpand}
|
|
@@ -173,14 +177,7 @@ export const InputWrapper = ({
|
|
|
173
177
|
className="flex-1 relative min-h-8"
|
|
174
178
|
style={{ width, flexBasis: width }}
|
|
175
179
|
>
|
|
176
|
-
{
|
|
177
|
-
{isExpanded && (
|
|
178
|
-
<FloatingPortal
|
|
179
|
-
root={elRef.current?.closest<HTMLElement>(".theme-base")}
|
|
180
|
-
>
|
|
181
|
-
{el}
|
|
182
|
-
</FloatingPortal>
|
|
183
|
-
)}
|
|
180
|
+
{el}
|
|
184
181
|
</div>
|
|
185
182
|
</Wrapper>
|
|
186
183
|
);
|
package/src/select/List.tsx
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
import { Chip } from "@react-fabric/core";
|
|
33
33
|
import { isArray, isEmpty } from "@react-fabric/utilities";
|
|
34
34
|
import classNames from "classnames";
|
|
35
|
-
import { Fragment, useCallback, useId, useMemo } from "react";
|
|
35
|
+
import { Fragment, useCallback, useId, useLayoutEffect, useMemo } from "react";
|
|
36
36
|
import { FieldWrapper } from "../internal/FieldWrapper";
|
|
37
37
|
import { InputWrapper } from "../internal/InputWrapper";
|
|
38
38
|
import { type SelectProps } from "../types";
|
|
@@ -55,6 +55,7 @@ export const List = <T extends AnyObject = string>({
|
|
|
55
55
|
valueProperty,
|
|
56
56
|
multiple,
|
|
57
57
|
allowCreate,
|
|
58
|
+
searchable,
|
|
58
59
|
createOption,
|
|
59
60
|
matcher,
|
|
60
61
|
renderer,
|
|
@@ -166,9 +167,12 @@ export const List = <T extends AnyObject = string>({
|
|
|
166
167
|
}
|
|
167
168
|
} else if (evt.key === "Backspace") {
|
|
168
169
|
!state.query && handleRemove();
|
|
169
|
-
} else if (["ArrowUp", "ArrowDown"].includes(evt.key)) {
|
|
170
|
-
if (
|
|
171
|
-
|
|
170
|
+
} else if (!searchable || ["ArrowUp", "ArrowDown"].includes(evt.key)) {
|
|
171
|
+
if (
|
|
172
|
+
["ArrowUp", "ArrowDown"].includes(evt.key) &&
|
|
173
|
+
state.activeIndex === null
|
|
174
|
+
) {
|
|
175
|
+
setActiveIndex(state.selectedIndex ?? 0);
|
|
172
176
|
}
|
|
173
177
|
setTimeout(() => {
|
|
174
178
|
props.onKeyDown?.(evt);
|
|
@@ -225,6 +229,15 @@ export const List = <T extends AnyObject = string>({
|
|
|
225
229
|
}
|
|
226
230
|
}, [state.value, state.query, placeholder, renderer]);
|
|
227
231
|
|
|
232
|
+
useLayoutEffect(() => {
|
|
233
|
+
setTimeout(() => {
|
|
234
|
+
state.selectedIndex &&
|
|
235
|
+
listRef.current[state.selectedIndex]?.scrollIntoView({
|
|
236
|
+
block: "center",
|
|
237
|
+
});
|
|
238
|
+
}, 100);
|
|
239
|
+
}, [state.selectedIndex]);
|
|
240
|
+
|
|
228
241
|
return (
|
|
229
242
|
<Wrapper {...wrapperProps}>
|
|
230
243
|
<InputWrapper
|
|
@@ -240,22 +253,34 @@ export const List = <T extends AnyObject = string>({
|
|
|
240
253
|
wrapperRef={refs.setReference}
|
|
241
254
|
>
|
|
242
255
|
<div
|
|
256
|
+
role="none"
|
|
243
257
|
data-select-display="true"
|
|
244
|
-
className=
|
|
258
|
+
className={classNames(
|
|
259
|
+
"group flex-1 py-1 px-2 truncate text-start flex gap-1 relative min-h-5 justify-start",
|
|
260
|
+
multiple ? "flex-wrap" : "flex-nowrap overflow-hidden",
|
|
261
|
+
)}
|
|
262
|
+
{...referenceProps}
|
|
263
|
+
onMouseUp={(e) =>
|
|
264
|
+
e.currentTarget.querySelector<HTMLElement>("input")?.focus()
|
|
265
|
+
}
|
|
245
266
|
>
|
|
246
267
|
{!hideSelected && displayValue}
|
|
247
268
|
<input
|
|
269
|
+
readOnly={!searchable || readOnly}
|
|
248
270
|
disabled={disabled}
|
|
249
271
|
value={state.query ?? ""}
|
|
250
272
|
aria-invalid={invalid}
|
|
251
273
|
data-testid={name}
|
|
252
274
|
name={name}
|
|
275
|
+
size={1}
|
|
276
|
+
ref={ref}
|
|
277
|
+
autoFocus={autoFocus}
|
|
253
278
|
className={classNames(
|
|
254
279
|
"appearance-none bg-transparent outline-none border-none ring-0 flex-1 min-w-24",
|
|
255
280
|
disabled && "cursor-not-allowed pointer-events-none",
|
|
281
|
+
multiple && "min-w-24",
|
|
256
282
|
)}
|
|
257
283
|
placeholder={isEmpty(state.value) ? placeholder : ""}
|
|
258
|
-
{...referenceProps}
|
|
259
284
|
onChange={(evt) => handleQuery(evt.target.value)}
|
|
260
285
|
/>
|
|
261
286
|
</div>
|
|
@@ -277,10 +302,12 @@ export const List = <T extends AnyObject = string>({
|
|
|
277
302
|
{...floatingProps}
|
|
278
303
|
items={state.items}
|
|
279
304
|
active={state.activeIndex}
|
|
305
|
+
valueProperty={valueProperty}
|
|
306
|
+
labelProperty={labelProperty}
|
|
280
307
|
itemRef={setItemRef}
|
|
281
308
|
itemProps={makeItemProps}
|
|
282
309
|
>
|
|
283
|
-
{(item) => renderer?.(item) ??
|
|
310
|
+
{(item, label) => renderer?.(item) ?? label}
|
|
284
311
|
</Options>
|
|
285
312
|
</FloatingFocusManager>
|
|
286
313
|
</Wrapper>
|
package/src/select/Options.tsx
CHANGED
package/src/select/Select.tsx
CHANGED
|
@@ -172,6 +172,9 @@ export const Select = <T extends AnyObject = string>({
|
|
|
172
172
|
return false;
|
|
173
173
|
} else if (state.query) {
|
|
174
174
|
handleQuery("");
|
|
175
|
+
evt.preventDefault();
|
|
176
|
+
evt.stopPropagation();
|
|
177
|
+
return false;
|
|
175
178
|
} else {
|
|
176
179
|
onEnterPressed?.(evt);
|
|
177
180
|
}
|
|
@@ -273,6 +276,7 @@ export const Select = <T extends AnyObject = string>({
|
|
|
273
276
|
"group flex-1 py-1 px-2 truncate text-start flex gap-1 relative min-h-5 justify-start",
|
|
274
277
|
multiple ? "flex-wrap" : "flex-nowrap overflow-hidden",
|
|
275
278
|
)}
|
|
279
|
+
{...referenceProps}
|
|
276
280
|
onMouseUp={(e) =>
|
|
277
281
|
e.currentTarget.querySelector<HTMLElement>("input")?.focus()
|
|
278
282
|
}
|
|
@@ -294,7 +298,6 @@ export const Select = <T extends AnyObject = string>({
|
|
|
294
298
|
multiple && "min-w-24",
|
|
295
299
|
)}
|
|
296
300
|
placeholder={isEmpty(state.value) ? placeholder : ""}
|
|
297
|
-
{...referenceProps}
|
|
298
301
|
onChange={(evt) => handleQuery(evt.target.value)}
|
|
299
302
|
/>
|
|
300
303
|
</div>
|
package/src/select/useSelect.tsx
CHANGED
|
@@ -23,10 +23,12 @@
|
|
|
23
23
|
|
|
24
24
|
import { useDebounce } from "@react-fabric/core";
|
|
25
25
|
import {
|
|
26
|
+
compareValues,
|
|
26
27
|
dedupe,
|
|
27
28
|
EMPTY_ARRAY,
|
|
28
29
|
groupBy,
|
|
29
30
|
isArray,
|
|
31
|
+
isString,
|
|
30
32
|
matchString,
|
|
31
33
|
} from "@react-fabric/utilities";
|
|
32
34
|
import {
|
|
@@ -173,9 +175,9 @@ export const useSelect = ({
|
|
|
173
175
|
if (action.value !== undefined) {
|
|
174
176
|
if (multiple) {
|
|
175
177
|
const values = [];
|
|
176
|
-
if (action.value
|
|
178
|
+
if (isString(action.value))
|
|
177
179
|
values.push(...action.value.split(/,\s?/));
|
|
178
|
-
else
|
|
180
|
+
else values.push(action.value);
|
|
179
181
|
newState.value = [...state.value];
|
|
180
182
|
values.forEach((value: AnyObject) => {
|
|
181
183
|
newState.value = newState.value.includes?.(value)
|
|
@@ -222,6 +224,7 @@ export const useSelect = ({
|
|
|
222
224
|
if (autoComplete && action.query !== undefined) {
|
|
223
225
|
optionList = dedupe([action.query, ...optionList]);
|
|
224
226
|
}
|
|
227
|
+
optionList = optionList.sort(compareValues("asc", labelProperty));
|
|
225
228
|
const grouped = groupBy(optionList, groupProperty, "");
|
|
226
229
|
if (action.open) newState.open = true;
|
|
227
230
|
newState.items = [];
|
|
@@ -229,7 +232,7 @@ export const useSelect = ({
|
|
|
229
232
|
if (allowCreate && action.query)
|
|
230
233
|
newState.items.push({
|
|
231
234
|
___create___: true,
|
|
232
|
-
value:
|
|
235
|
+
value: action.query,
|
|
233
236
|
});
|
|
234
237
|
Object.entries(grouped).forEach(([key, list]) => {
|
|
235
238
|
if (key) {
|
|
@@ -282,24 +285,26 @@ export const useSelect = ({
|
|
|
282
285
|
dispatch({ type: "options", options: optionsRef.current });
|
|
283
286
|
dispatch({
|
|
284
287
|
type: "setValue",
|
|
285
|
-
value: hasValue ?? newOption ??
|
|
288
|
+
value: hasValue ?? newOption ?? deferred,
|
|
286
289
|
});
|
|
287
290
|
}
|
|
288
291
|
if (multiple) {
|
|
289
292
|
optionsRef.current = [];
|
|
290
|
-
const value = (deferred
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
293
|
+
const value = (isArray(deferred) ? deferred : []).map(
|
|
294
|
+
(item: AnyObject) => {
|
|
295
|
+
const newOption =
|
|
296
|
+
(allowCreate || autoComplete) && item
|
|
297
|
+
? createOption(item)
|
|
298
|
+
: undefined;
|
|
299
|
+
const hasValue = options.find(
|
|
300
|
+
(opt: AnyObject) => (opt[valueProperty] ?? opt) === item,
|
|
301
|
+
);
|
|
302
|
+
if (!hasValue && newOption) {
|
|
303
|
+
optionsRef.current.push(newOption);
|
|
304
|
+
}
|
|
305
|
+
return hasValue ?? newOption ?? item;
|
|
306
|
+
},
|
|
307
|
+
);
|
|
303
308
|
optionsRef.current = [...optionsRef.current, ...(options ?? [])];
|
|
304
309
|
dispatch({ type: "options", options: optionsRef.current });
|
|
305
310
|
dispatch({
|
|
@@ -367,7 +372,11 @@ export const useSelect = ({
|
|
|
367
372
|
value: value?.___create___ ? value.value : value,
|
|
368
373
|
});
|
|
369
374
|
if (value?.___create___) {
|
|
370
|
-
|
|
375
|
+
let val = [value.value];
|
|
376
|
+
if (multiple) {
|
|
377
|
+
val = value.value.split(/,\s?/);
|
|
378
|
+
}
|
|
379
|
+
optionsRef.current = [...optionsRef.current, ...val.map(createOption)];
|
|
371
380
|
}
|
|
372
381
|
if (autoComplete) {
|
|
373
382
|
optionsRef.current = dedupe([
|
package/src/types/index.ts
CHANGED
|
@@ -21,9 +21,12 @@
|
|
|
21
21
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
type RefProp,
|
|
26
|
+
type TestProps,
|
|
27
|
+
} from "@react-fabric/core/dist/types/types";
|
|
25
28
|
|
|
26
|
-
export interface InputProps<V = string> {
|
|
29
|
+
export interface InputProps<V = string> extends TestProps {
|
|
27
30
|
/**
|
|
28
31
|
* value
|
|
29
32
|
*/
|