@react-fabric/form 1.0.0-beta.5 → 1.0.0-beta.51
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/{src/input/ArrayInput.module.css → css/_arrayInput.css} +8 -8
- package/css/_colorPicker.css +65 -0
- package/{src/internal/Field.module.css → css/_field.css} +64 -29
- package/{src/input/File.module.css → css/_file.css} +21 -6
- package/css/styles.css +27 -0
- package/dist/cjs/builder/FileField.js +37 -25
- package/dist/cjs/builder/FormField.js +50 -34
- package/dist/cjs/builder/SchemaEditor.js +72 -0
- package/dist/cjs/builder/components/AddSchemaFields.js +62 -0
- package/dist/cjs/builder/components/SchemaArrayForm.js +143 -0
- package/dist/cjs/builder/components/SchemaField.js +414 -0
- package/dist/cjs/form/Controller.js +1 -1
- package/dist/cjs/form/Form.js +11 -6
- package/dist/cjs/hooks/useFormBuilder.js +27 -15
- package/dist/cjs/index.js +11 -2
- package/dist/cjs/input/ArrayInput.js +61 -33
- package/dist/cjs/input/AvatarInput.js +9 -8
- package/dist/cjs/input/Checkbox.js +6 -5
- package/dist/cjs/input/ColorInput.js +95 -56
- package/dist/cjs/input/ColorPicker.js +1 -35
- package/dist/cjs/input/DateInput.js +186 -0
- package/dist/cjs/input/Field.js +5 -4
- package/dist/cjs/input/File.js +4 -7
- package/dist/cjs/input/Hidden.js +3 -1
- package/dist/cjs/input/Input.js +11 -7
- package/dist/cjs/input/Number.js +9 -7
- package/dist/cjs/input/Password.js +10 -8
- package/dist/cjs/input/Radio.js +2 -2
- package/dist/cjs/input/RadioGroup.js +6 -3
- package/dist/cjs/input/{Range.js → RangeSlider.js} +5 -5
- package/dist/cjs/input/Search.js +16 -16
- package/dist/cjs/input/Slider.js +3 -3
- package/dist/cjs/input/Switch.js +30 -7
- package/dist/cjs/input/Textarea.js +13 -4
- package/dist/cjs/internal/ErrorIcon.js +1 -1
- package/dist/cjs/internal/FieldWrapper.js +11 -4
- package/dist/cjs/internal/InputWrapper.js +19 -16
- package/dist/cjs/select/AutoComplete.js +12 -8
- package/dist/cjs/select/DualList.js +4 -1
- package/dist/cjs/select/List.js +45 -20
- package/dist/cjs/select/Options.js +2 -2
- package/dist/cjs/select/Select.js +14 -4
- package/dist/cjs/select/useSelect.js +10 -6
- package/dist/cjs/types/schema.js +43 -0
- package/dist/cjs/utils/eventHandlers.js +11 -5
- package/dist/cjs/utils/getColor.js +6 -0
- package/dist/esm/builder/FileField.js +39 -27
- package/dist/esm/builder/FormField.js +50 -34
- package/dist/esm/builder/SchemaEditor.js +72 -0
- package/dist/esm/builder/components/AddSchemaFields.js +62 -0
- package/dist/esm/builder/components/SchemaArrayForm.js +143 -0
- package/dist/esm/builder/components/SchemaField.js +414 -0
- package/dist/esm/form/Controller.js +1 -1
- package/dist/esm/form/Form.js +11 -6
- package/dist/esm/hooks/useFormBuilder.js +25 -13
- package/dist/esm/index.js +5 -1
- package/dist/esm/input/ArrayInput.js +61 -33
- package/dist/esm/input/AvatarInput.js +9 -8
- package/dist/esm/input/Checkbox.js +6 -5
- package/dist/esm/input/ColorInput.js +97 -58
- package/dist/esm/input/ColorPicker.js +1 -35
- package/dist/esm/input/DateInput.js +186 -0
- package/dist/esm/input/Field.js +6 -5
- package/dist/esm/input/File.js +6 -9
- package/dist/esm/input/Hidden.js +3 -1
- package/dist/esm/input/Input.js +13 -9
- package/dist/esm/input/Number.js +11 -9
- package/dist/esm/input/Password.js +12 -10
- package/dist/esm/input/Radio.js +2 -2
- package/dist/esm/input/RadioGroup.js +7 -4
- package/dist/esm/input/{Range.js → RangeSlider.js} +5 -5
- package/dist/esm/input/Search.js +18 -18
- package/dist/esm/input/Slider.js +3 -3
- package/dist/esm/input/Switch.js +32 -9
- package/dist/esm/input/Textarea.js +14 -5
- package/dist/esm/internal/ErrorIcon.js +1 -1
- package/dist/esm/internal/FieldWrapper.js +11 -4
- package/dist/esm/internal/InputWrapper.js +19 -16
- package/dist/esm/select/AutoComplete.js +12 -8
- package/dist/esm/select/DualList.js +4 -1
- package/dist/esm/select/List.js +46 -21
- package/dist/esm/select/Options.js +2 -2
- package/dist/esm/select/Select.js +14 -4
- package/dist/esm/select/useSelect.js +11 -7
- package/{src/input/ColorPicker.module.css → dist/esm/types/schema.js} +18 -27
- package/dist/esm/utils/eventHandlers.js +11 -5
- package/dist/esm/utils/getColor.js +6 -1
- package/dist/types/builder/FileField.d.ts +4 -2
- package/dist/types/builder/FormField.d.ts +3 -1
- package/dist/types/builder/SchemaEditor.d.ts +2 -0
- package/dist/types/builder/components/AddSchemaFields.d.ts +2 -0
- package/dist/types/builder/components/SchemaArrayForm.d.ts +2 -0
- package/dist/types/builder/components/SchemaField.d.ts +10 -0
- package/dist/types/form/Controller.d.ts +2 -2
- package/dist/types/form/Form.d.ts +5 -1
- package/dist/types/hooks/useFormBuilder.d.ts +3 -1
- package/dist/types/index.d.ts +5 -2
- package/dist/types/input/ArrayInput.d.ts +39 -6
- package/dist/types/input/AvatarInput.d.ts +6 -3
- package/dist/types/input/Checkbox.d.ts +4 -4
- package/dist/types/input/ColorInput.d.ts +2 -2
- package/dist/types/input/ColorPicker.d.ts +1 -1
- package/dist/types/input/DateInput.d.ts +19 -0
- package/dist/types/input/Field.d.ts +0 -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/Radio.d.ts +0 -1
- package/dist/types/input/RadioGroup.d.ts +18 -3
- package/dist/types/input/{Range.d.ts → RangeSlider.d.ts} +1 -1
- package/dist/types/input/Search.d.ts +5 -1
- package/dist/types/input/Switch.d.ts +7 -4
- package/dist/types/input/Textarea.d.ts +5 -1
- package/dist/types/internal/FieldWrapper.d.ts +1 -1
- package/dist/types/internal/InputWrapper.d.ts +1 -1
- package/dist/types/ranger/index.d.ts +2 -2
- package/dist/types/select/AutoComplete.d.ts +1 -1
- package/dist/types/select/DualList.d.ts +6 -2
- package/dist/types/select/List.d.ts +1 -1
- package/dist/types/select/Select.d.ts +1 -1
- package/dist/types/select/useSelect.d.ts +7 -15
- package/dist/types/types/index.d.ts +28 -7
- package/dist/types/types/schema.d.ts +78 -33
- package/dist/types/utils/eventHandlers.d.ts +1 -1
- package/package.json +15 -12
- package/src/builder/FileField.tsx +53 -27
- package/src/builder/FormField.tsx +52 -32
- package/src/builder/SchemaEditor.tsx +72 -0
- package/src/builder/components/AddSchemaFields.tsx +74 -0
- package/src/builder/components/SchemaArrayForm.tsx +158 -0
- package/src/builder/components/SchemaField.tsx +436 -0
- package/src/form/Controller.tsx +3 -3
- package/src/form/Form.tsx +14 -5
- package/src/hooks/useFormBuilder.tsx +29 -15
- package/src/index.ts +11 -2
- package/src/input/ArrayInput.tsx +130 -54
- package/src/input/AvatarInput.tsx +12 -8
- package/src/input/Checkbox.tsx +6 -5
- package/src/input/ColorInput.tsx +113 -69
- package/src/input/ColorPicker.tsx +2 -36
- package/src/input/DateInput.tsx +250 -0
- package/src/input/Field.tsx +10 -11
- package/src/input/File.tsx +7 -14
- package/src/input/Hidden.tsx +4 -1
- package/src/input/Input.tsx +15 -10
- package/src/input/Number.tsx +10 -10
- package/src/input/Password.tsx +13 -12
- package/src/input/Radio.tsx +2 -2
- package/src/input/RadioGroup.tsx +27 -4
- package/src/input/{Range.tsx → RangeSlider.tsx} +4 -4
- package/src/input/Search.tsx +20 -19
- package/src/input/Slider.tsx +3 -3
- package/src/input/Switch.tsx +43 -7
- package/src/input/Textarea.tsx +19 -5
- package/src/internal/ErrorIcon.tsx +1 -1
- package/src/internal/FieldWrapper.tsx +8 -4
- package/src/internal/InputWrapper.tsx +36 -20
- package/src/select/AutoComplete.tsx +5 -1
- package/src/select/DualList.tsx +8 -0
- package/src/select/List.tsx +41 -8
- package/src/select/Options.tsx +1 -1
- package/src/select/Select.tsx +13 -3
- package/src/select/useSelect.tsx +13 -5
- package/src/types/index.ts +34 -8
- package/src/types/schema.ts +96 -41
- package/src/utils/eventHandlers.ts +9 -3
- package/dist/cjs/input/ArrayInput.module.css +0 -1
- package/dist/cjs/input/ColorPicker.module.css +0 -1
- package/dist/cjs/input/File.module.css +0 -1
- package/dist/cjs/internal/Field.module.css +0 -1
- package/dist/esm/input/ArrayInput.module.css +0 -1
- package/dist/esm/input/ColorPicker.module.css +0 -1
- package/dist/esm/input/File.module.css +0 -1
- package/dist/esm/internal/Field.module.css +0 -1
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>
|
|
@@ -97,7 +97,7 @@ export interface RangeProps
|
|
|
97
97
|
/**
|
|
98
98
|
* Number Range input
|
|
99
99
|
*/
|
|
100
|
-
export const
|
|
100
|
+
export const RangeSlider = ({
|
|
101
101
|
error,
|
|
102
102
|
name,
|
|
103
103
|
value,
|
|
@@ -141,7 +141,7 @@ export const Range = ({
|
|
|
141
141
|
const handleChange = useCallback(
|
|
142
142
|
(val: [number, number]) => {
|
|
143
143
|
setActualValue(val ?? [min, max]);
|
|
144
|
-
onChange?.(val ??
|
|
144
|
+
onChange?.(val ?? null);
|
|
145
145
|
},
|
|
146
146
|
[onChange, min, max],
|
|
147
147
|
);
|
|
@@ -190,7 +190,7 @@ export const Range = ({
|
|
|
190
190
|
>
|
|
191
191
|
<div
|
|
192
192
|
className={classNames(
|
|
193
|
-
"flex-
|
|
193
|
+
"flex-1 order-3 flex items-center select-none z-0",
|
|
194
194
|
vertical && "flex-col w-8",
|
|
195
195
|
invalid ? "text-danger-500" : "text-primary-600",
|
|
196
196
|
)}
|
|
@@ -201,7 +201,7 @@ export const Range = ({
|
|
|
201
201
|
<div
|
|
202
202
|
ref={rangerInstance.trackElRef}
|
|
203
203
|
className={classNames(
|
|
204
|
-
"flex-
|
|
204
|
+
"flex-1 relative flex items-center",
|
|
205
205
|
vertical ? "my-2 w-8" : "mx-2 h-8",
|
|
206
206
|
)}
|
|
207
207
|
style={{ height: vertical ? height : undefined }}
|
package/src/input/Search.tsx
CHANGED
|
@@ -28,14 +28,13 @@ import {
|
|
|
28
28
|
useCallback,
|
|
29
29
|
useDeferredValue,
|
|
30
30
|
useEffect,
|
|
31
|
-
useMemo,
|
|
32
31
|
useRef,
|
|
33
32
|
useState,
|
|
34
33
|
type ChangeEvent,
|
|
35
34
|
} from "react";
|
|
36
35
|
import { InputWrapper } from "../internal/InputWrapper";
|
|
37
36
|
import { type InputProps } from "../types";
|
|
38
|
-
import {
|
|
37
|
+
import { useHandleEnter } from "../utils";
|
|
39
38
|
|
|
40
39
|
export interface SearchProps extends InputProps, RefProp<HTMLInputElement> {
|
|
41
40
|
/**
|
|
@@ -46,6 +45,10 @@ export interface SearchProps extends InputProps, RefProp<HTMLInputElement> {
|
|
|
46
45
|
* search on value change
|
|
47
46
|
*/
|
|
48
47
|
searchOnChange?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* hide search action handle
|
|
50
|
+
*/
|
|
51
|
+
hideHandle?: boolean;
|
|
49
52
|
/**
|
|
50
53
|
* search handler
|
|
51
54
|
*/
|
|
@@ -63,10 +66,11 @@ export const Search = ({
|
|
|
63
66
|
searching,
|
|
64
67
|
placeholder,
|
|
65
68
|
autoFocus,
|
|
69
|
+
hideHandle,
|
|
66
70
|
allowClear = true,
|
|
67
|
-
searchOnChange =
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
searchOnChange = false,
|
|
72
|
+
onBlur,
|
|
73
|
+
onFocus,
|
|
70
74
|
onSearch,
|
|
71
75
|
onChange,
|
|
72
76
|
onEnterPressed,
|
|
@@ -82,10 +86,7 @@ export const Search = ({
|
|
|
82
86
|
250,
|
|
83
87
|
);
|
|
84
88
|
|
|
85
|
-
const handleEnterPressed =
|
|
86
|
-
() => handleEnter(handleSearch),
|
|
87
|
-
[handleSearch],
|
|
88
|
-
);
|
|
89
|
+
const handleEnterPressed = useHandleEnter(handleSearch);
|
|
89
90
|
|
|
90
91
|
useEffect(() => {
|
|
91
92
|
setActualValue(deferred ?? "");
|
|
@@ -96,10 +97,10 @@ export const Search = ({
|
|
|
96
97
|
const value = e?.target.value;
|
|
97
98
|
refValue.current = value ?? "";
|
|
98
99
|
setActualValue(value ?? "");
|
|
99
|
-
onChange?.(value ??
|
|
100
|
+
onChange?.(value ?? null);
|
|
100
101
|
|
|
101
|
-
// value was cleared so force fire onSearch
|
|
102
|
-
if (searchOnChange) {
|
|
102
|
+
// when e is undefined value was cleared so force fire onSearch
|
|
103
|
+
if (!e || searchOnChange) {
|
|
103
104
|
handleSearch();
|
|
104
105
|
}
|
|
105
106
|
},
|
|
@@ -108,21 +109,19 @@ export const Search = ({
|
|
|
108
109
|
|
|
109
110
|
return (
|
|
110
111
|
<InputWrapper
|
|
111
|
-
showClear={!!actualValue}
|
|
112
|
+
showClear={!!actualValue && !disabled && !readOnly}
|
|
112
113
|
onClear={handleChange}
|
|
113
114
|
allowClear={allowClear}
|
|
114
115
|
invalid={invalid}
|
|
115
116
|
readOnly={readOnly}
|
|
116
117
|
disabled={disabled}
|
|
117
118
|
required={required}
|
|
118
|
-
|
|
119
|
-
decorateEnd={
|
|
119
|
+
actionButton={
|
|
120
120
|
<Fragment>
|
|
121
|
-
{decorateEnd}
|
|
122
121
|
{searching && (
|
|
123
122
|
<Icon className="p-2" icon={CoreIcons.spinner} animate="spin" />
|
|
124
123
|
)}
|
|
125
|
-
{!searching && (
|
|
124
|
+
{!searching && !hideHandle && (
|
|
126
125
|
<Button
|
|
127
126
|
tabIndex={-1}
|
|
128
127
|
variant="link"
|
|
@@ -137,7 +136,7 @@ export const Search = ({
|
|
|
137
136
|
{...rest}
|
|
138
137
|
>
|
|
139
138
|
<input
|
|
140
|
-
className="appearance-none bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0"
|
|
139
|
+
className="appearance-none bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0 peer"
|
|
141
140
|
aria-invalid={invalid}
|
|
142
141
|
aria-disabled={disabled}
|
|
143
142
|
aria-readonly={readOnly}
|
|
@@ -150,8 +149,10 @@ export const Search = ({
|
|
|
150
149
|
type="search"
|
|
151
150
|
ref={ref}
|
|
152
151
|
autoComplete="off"
|
|
153
|
-
{
|
|
152
|
+
autoFocus={autoFocus}
|
|
154
153
|
value={actualValue}
|
|
154
|
+
onBlur={onBlur}
|
|
155
|
+
onFocus={onFocus}
|
|
155
156
|
onChange={handleChange}
|
|
156
157
|
onKeyDown={handleEnterPressed}
|
|
157
158
|
/>
|
package/src/input/Slider.tsx
CHANGED
|
@@ -146,7 +146,7 @@ export const Slider = ({
|
|
|
146
146
|
(value: number) => {
|
|
147
147
|
const val = useInfinity && value === max ? Infinity : value;
|
|
148
148
|
setActualValue(val ?? 0);
|
|
149
|
-
onChange?.(val ??
|
|
149
|
+
onChange?.(val ?? null);
|
|
150
150
|
},
|
|
151
151
|
[onChange, max, useInfinity],
|
|
152
152
|
);
|
|
@@ -194,7 +194,7 @@ export const Slider = ({
|
|
|
194
194
|
>
|
|
195
195
|
<div
|
|
196
196
|
className={classNames(
|
|
197
|
-
"flex-
|
|
197
|
+
"flex-1 order-3 flex items-center select-none relative z-0",
|
|
198
198
|
vertical && "flex-col w-8",
|
|
199
199
|
invalid ? "text-danger-500" : "text-primary-600",
|
|
200
200
|
)}
|
|
@@ -205,7 +205,7 @@ export const Slider = ({
|
|
|
205
205
|
<div
|
|
206
206
|
ref={rangerInstance.trackElRef}
|
|
207
207
|
className={classNames(
|
|
208
|
-
"flex-
|
|
208
|
+
"flex-1 relative flex items-center",
|
|
209
209
|
vertical ? "my-2 w-8" : "mx-2 h-8",
|
|
210
210
|
)}
|
|
211
211
|
style={{ height: vertical ? height : undefined }}
|
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,7 +97,13 @@ export const Switch = ({
|
|
|
90
97
|
width,
|
|
91
98
|
color,
|
|
92
99
|
name,
|
|
100
|
+
onLabel,
|
|
101
|
+
offLabel,
|
|
102
|
+
onLabelColor,
|
|
103
|
+
offLabelColor,
|
|
93
104
|
defaultColor,
|
|
105
|
+
// @ts-expect-error ignore
|
|
106
|
+
required,
|
|
94
107
|
onChange,
|
|
95
108
|
...rest
|
|
96
109
|
}: SwitchProps) => {
|
|
@@ -125,7 +138,7 @@ export const Switch = ({
|
|
|
125
138
|
actualValue && getBgClass(color ? `${color}-500` : "primary-500"),
|
|
126
139
|
!actualValue &&
|
|
127
140
|
(defaultColor ? getBgClass(`${defaultColor}-500`) : "bg-tint-200"),
|
|
128
|
-
"relative
|
|
141
|
+
"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
142
|
)}
|
|
130
143
|
style={{
|
|
131
144
|
backgroundColor: actualValue
|
|
@@ -154,14 +167,37 @@ export const Switch = ({
|
|
|
154
167
|
aria-hidden="true"
|
|
155
168
|
className={classNames(
|
|
156
169
|
!disabled && "shadow-sm",
|
|
157
|
-
actualValue ? "translate-x-
|
|
158
|
-
"pointer-events-none inline-block
|
|
170
|
+
actualValue ? "translate-x-[100%]" : "translate-x-0",
|
|
171
|
+
"pointer-events-none inline-block h-4 start-1 absolute rounded-full bg-white ring-0 transition duration-200 ease-in-out",
|
|
159
172
|
)}
|
|
173
|
+
style={{
|
|
174
|
+
width: "calc(50% - 0.25rem)",
|
|
175
|
+
}}
|
|
160
176
|
/>
|
|
177
|
+
{(!!onLabel || !!offLabel) && (
|
|
178
|
+
<Fragment>
|
|
179
|
+
<span
|
|
180
|
+
className={`whitespace-nowrap text-xs px-1 ${getColorClass(onLabelColor ?? "white")}`}
|
|
181
|
+
style={{
|
|
182
|
+
color: getColor(onLabelColor),
|
|
183
|
+
}}
|
|
184
|
+
>
|
|
185
|
+
{onLabel ?? " "}
|
|
186
|
+
</span>
|
|
187
|
+
<span
|
|
188
|
+
className={`whitespace-nowrap text-xs px-1 ${getColorClass(offLabelColor ?? "base")}`}
|
|
189
|
+
style={{
|
|
190
|
+
color: getColor(offLabelColor),
|
|
191
|
+
}}
|
|
192
|
+
>
|
|
193
|
+
{offLabel ?? " "}
|
|
194
|
+
</span>
|
|
195
|
+
</Fragment>
|
|
196
|
+
)}
|
|
161
197
|
</div>
|
|
162
198
|
<ErrorIcon invalid={invalid} error={error} />
|
|
163
199
|
{label && (
|
|
164
|
-
<span className="flex-initial leading-
|
|
200
|
+
<span className="flex-initial leading-tight truncate">{label}</span>
|
|
165
201
|
)}
|
|
166
202
|
</label>
|
|
167
203
|
);
|
package/src/input/Textarea.tsx
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
} from "react";
|
|
33
33
|
import { InputWrapper } from "../internal/InputWrapper";
|
|
34
34
|
import { type InputProps } from "../types";
|
|
35
|
-
import {
|
|
35
|
+
import { useHandleEnter } from "../utils";
|
|
36
36
|
|
|
37
37
|
export interface TextareaProps
|
|
38
38
|
extends InputProps,
|
|
@@ -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,9 @@ export const Textarea = ({
|
|
|
64
68
|
rows = 5,
|
|
65
69
|
maxRows = 12,
|
|
66
70
|
variableRows,
|
|
71
|
+
expandable,
|
|
72
|
+
onBlur,
|
|
73
|
+
onFocus,
|
|
67
74
|
onChange,
|
|
68
75
|
onEnterPressed,
|
|
69
76
|
...rest
|
|
@@ -81,7 +88,7 @@ export const Textarea = ({
|
|
|
81
88
|
(e?: ChangeEvent<HTMLTextAreaElement>) => {
|
|
82
89
|
const value = e?.target.value;
|
|
83
90
|
setActualValue(value ?? "");
|
|
84
|
-
onChange?.(value ??
|
|
91
|
+
onChange?.(value ?? null);
|
|
85
92
|
},
|
|
86
93
|
[onChange],
|
|
87
94
|
);
|
|
@@ -95,15 +102,20 @@ export const Textarea = ({
|
|
|
95
102
|
}
|
|
96
103
|
}, [actualValue, variableRows, rows, maxRows]);
|
|
97
104
|
|
|
105
|
+
const handleEnterPressed = useHandleEnter(onEnterPressed, {
|
|
106
|
+
preventDefault: !!onEnterPressed,
|
|
107
|
+
});
|
|
108
|
+
|
|
98
109
|
return (
|
|
99
110
|
<InputWrapper
|
|
100
|
-
showClear={!!actualValue}
|
|
111
|
+
showClear={!!actualValue && !disabled && !readOnly}
|
|
101
112
|
onClear={handleChange}
|
|
102
113
|
invalid={invalid}
|
|
103
114
|
readOnly={readOnly}
|
|
104
115
|
disabled={disabled}
|
|
105
116
|
required={required}
|
|
106
117
|
wrapperRef={wrapperRef}
|
|
118
|
+
textareaExpandable={expandable}
|
|
107
119
|
textarea
|
|
108
120
|
{...rest}
|
|
109
121
|
>
|
|
@@ -120,10 +132,12 @@ export const Textarea = ({
|
|
|
120
132
|
name={name}
|
|
121
133
|
ref={ref}
|
|
122
134
|
autoComplete="off"
|
|
123
|
-
{
|
|
135
|
+
autoFocus={autoFocus}
|
|
124
136
|
value={actualValue}
|
|
137
|
+
onBlur={onBlur}
|
|
138
|
+
onFocus={onFocus}
|
|
125
139
|
onChange={handleChange}
|
|
126
|
-
onKeyDown={
|
|
140
|
+
onKeyDown={handleEnterPressed}
|
|
127
141
|
/>
|
|
128
142
|
</InputWrapper>
|
|
129
143
|
);
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import classNames from "classnames";
|
|
25
|
-
import
|
|
25
|
+
import { ErrorIcon } from "./ErrorIcon";
|
|
26
26
|
|
|
27
27
|
export const FieldWrapper = ({
|
|
28
28
|
label,
|
|
@@ -36,21 +36,23 @@ export const FieldWrapper = ({
|
|
|
36
36
|
children,
|
|
37
37
|
listing,
|
|
38
38
|
className,
|
|
39
|
+
invalid,
|
|
40
|
+
error,
|
|
39
41
|
"data-inner": isInner,
|
|
40
42
|
}: KeyValue) => {
|
|
41
43
|
return (
|
|
42
44
|
<div
|
|
43
45
|
className={classNames(
|
|
44
|
-
|
|
46
|
+
"fabric-fieldWrapper",
|
|
45
47
|
className,
|
|
46
48
|
inline ? "flex flex-nowrap gap-1" : "block",
|
|
47
49
|
)}
|
|
48
50
|
data-ref="fieldWrapper"
|
|
49
51
|
style={{ width, flexBasis: width }}
|
|
50
52
|
>
|
|
51
|
-
{!isInner && (
|
|
53
|
+
{!isInner && label && (
|
|
52
54
|
<div
|
|
53
|
-
className="flex flex-nowrap flex-content gap-1 py-0.5 px-2"
|
|
55
|
+
className="flex flex-nowrap flex-content items-end gap-1 py-0.5 px-2"
|
|
54
56
|
style={{ width: inline ? labelWidth : undefined }}
|
|
55
57
|
>
|
|
56
58
|
<label
|
|
@@ -73,6 +75,8 @@ export const FieldWrapper = ({
|
|
|
73
75
|
✽
|
|
74
76
|
</span>
|
|
75
77
|
)}
|
|
78
|
+
<ErrorIcon invalid={invalid} error={error} />
|
|
79
|
+
<div className="flex-1" />
|
|
76
80
|
{appendLabel && <span className="flex-content">{appendLabel}</span>}
|
|
77
81
|
</div>
|
|
78
82
|
)}
|
|
@@ -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";
|
|
@@ -35,7 +34,6 @@ import {
|
|
|
35
34
|
} from "react";
|
|
36
35
|
import { Fragment } from "react/jsx-runtime";
|
|
37
36
|
import { ErrorIcon } from "./ErrorIcon";
|
|
38
|
-
import classes from "./Field.module.css";
|
|
39
37
|
import { FieldWrapper } from "./FieldWrapper";
|
|
40
38
|
|
|
41
39
|
export const InputWrapper = ({
|
|
@@ -45,11 +43,15 @@ export const InputWrapper = ({
|
|
|
45
43
|
showClear,
|
|
46
44
|
decorateStart,
|
|
47
45
|
decorateEnd,
|
|
46
|
+
decorateEndShowWhenEmpty,
|
|
47
|
+
decorateEndHideWhenEmpty,
|
|
48
48
|
children,
|
|
49
49
|
onClear,
|
|
50
50
|
noOutline,
|
|
51
51
|
noBorder,
|
|
52
|
+
actionButton,
|
|
52
53
|
textarea = false,
|
|
54
|
+
textareaExpandable = false,
|
|
53
55
|
"data-inner": isInner,
|
|
54
56
|
"data-open": isOpen,
|
|
55
57
|
// expand autocomplete
|
|
@@ -102,12 +104,12 @@ export const InputWrapper = ({
|
|
|
102
104
|
role="none"
|
|
103
105
|
ref={wrapperRef}
|
|
104
106
|
className={classNames(
|
|
105
|
-
|
|
106
|
-
invalid &&
|
|
107
|
+
"fabric-inputWrapper",
|
|
108
|
+
invalid && "fabric-invalidWrapper",
|
|
107
109
|
!noOutline &&
|
|
108
110
|
!noBorder &&
|
|
109
|
-
"bg-
|
|
110
|
-
"flex flex-nowrap items-center",
|
|
111
|
+
"bg-(--fabric-input) outline overflow-hidden",
|
|
112
|
+
"flex flex-nowrap items-center flex-1",
|
|
111
113
|
textarea ? "rounded-capped group" : "rounded",
|
|
112
114
|
isExpanded
|
|
113
115
|
? "fixed inset-4 z-[99]"
|
|
@@ -117,13 +119,17 @@ export const InputWrapper = ({
|
|
|
117
119
|
!noOutline &&
|
|
118
120
|
"after:absolute after:bottom-0 after:h-px after:bg-primary-500 after:mx-auto",
|
|
119
121
|
)}
|
|
120
|
-
onKeyDown={(e) =>
|
|
122
|
+
onKeyDown={(e) =>
|
|
123
|
+
e.key === "Escape" &&
|
|
124
|
+
isExpanded &&
|
|
125
|
+
(setExpanded(false), e.stopPropagation())
|
|
126
|
+
}
|
|
121
127
|
>
|
|
122
128
|
{decorateStart && (
|
|
123
129
|
<div
|
|
124
130
|
onClickCapture={doFocus}
|
|
125
131
|
className={classNames(
|
|
126
|
-
|
|
132
|
+
"fabric-decorate",
|
|
127
133
|
"text-muted leading-none flex-content",
|
|
128
134
|
isString(decorateStart) && "px-1",
|
|
129
135
|
)}
|
|
@@ -139,7 +145,7 @@ export const InputWrapper = ({
|
|
|
139
145
|
onClick={handleClear}
|
|
140
146
|
className={classNames(
|
|
141
147
|
"text-tint-500 hover:text-tint-700 p-1 z-1 flex-content",
|
|
142
|
-
|
|
148
|
+
"fabric-inputClear",
|
|
143
149
|
textarea && "self-start mt-1 me-1",
|
|
144
150
|
)}
|
|
145
151
|
/>
|
|
@@ -148,15 +154,29 @@ export const InputWrapper = ({
|
|
|
148
154
|
<div
|
|
149
155
|
onClickCapture={doFocus}
|
|
150
156
|
className={classNames(
|
|
151
|
-
|
|
157
|
+
"fabric-decorate",
|
|
152
158
|
"text-muted leading-none flex-content",
|
|
153
159
|
isString(decorateEnd) && "px-1",
|
|
160
|
+
decorateEndHideWhenEmpty && "peer-placeholder-shown:hidden",
|
|
161
|
+
decorateEndShowWhenEmpty &&
|
|
162
|
+
"hidden peer-placeholder-shown:inline-block",
|
|
154
163
|
)}
|
|
155
164
|
>
|
|
156
165
|
{decorateEnd}
|
|
157
166
|
</div>
|
|
158
167
|
)}
|
|
159
|
-
{
|
|
168
|
+
{actionButton && (
|
|
169
|
+
<div
|
|
170
|
+
onClickCapture={doFocus}
|
|
171
|
+
className={classNames(
|
|
172
|
+
"fabric-decorate",
|
|
173
|
+
"text-muted leading-none flex-content",
|
|
174
|
+
)}
|
|
175
|
+
>
|
|
176
|
+
{actionButton}
|
|
177
|
+
</div>
|
|
178
|
+
)}
|
|
179
|
+
{textareaExpandable && (
|
|
160
180
|
<Icon
|
|
161
181
|
onClick={() => setExpanded(!isExpanded)}
|
|
162
182
|
icon={isExpanded ? CoreIcons.arrowCollapse : CoreIcons.arrowExpand}
|
|
@@ -170,17 +190,13 @@ export const InputWrapper = ({
|
|
|
170
190
|
<Wrapper {...wrapperProps}>
|
|
171
191
|
<div
|
|
172
192
|
ref={elRef}
|
|
173
|
-
className=
|
|
193
|
+
className={classNames(
|
|
194
|
+
"relative min-h-8 flex flex-col flex-nowrap",
|
|
195
|
+
width ? "flex-auto" : "flex-1",
|
|
196
|
+
)}
|
|
174
197
|
style={{ width, flexBasis: width }}
|
|
175
198
|
>
|
|
176
|
-
{
|
|
177
|
-
{isExpanded && (
|
|
178
|
-
<FloatingPortal
|
|
179
|
-
root={elRef.current?.closest<HTMLElement>(".theme-base")}
|
|
180
|
-
>
|
|
181
|
-
{el}
|
|
182
|
-
</FloatingPortal>
|
|
183
|
-
)}
|
|
199
|
+
{el}
|
|
184
200
|
</div>
|
|
185
201
|
</Wrapper>
|
|
186
202
|
);
|
|
@@ -80,6 +80,7 @@ export const AutoComplete = ({
|
|
|
80
80
|
onInput,
|
|
81
81
|
onFocus,
|
|
82
82
|
onBlur,
|
|
83
|
+
onQuery,
|
|
83
84
|
onEnterPressed,
|
|
84
85
|
...rest
|
|
85
86
|
}: AutoCompleteProps) => {
|
|
@@ -104,6 +105,7 @@ export const AutoComplete = ({
|
|
|
104
105
|
multiple,
|
|
105
106
|
onChange,
|
|
106
107
|
onSelect,
|
|
108
|
+
onQuery,
|
|
107
109
|
});
|
|
108
110
|
|
|
109
111
|
const dropdownKey = useId();
|
|
@@ -291,7 +293,9 @@ export const AutoComplete = ({
|
|
|
291
293
|
data-testid={name}
|
|
292
294
|
name={name}
|
|
293
295
|
size={1}
|
|
296
|
+
ref={ref}
|
|
294
297
|
onInput={onInput}
|
|
298
|
+
autoFocus={autoFocus}
|
|
295
299
|
rows={!multiple && expandOnEdit && state.open ? 5 : 1}
|
|
296
300
|
className={classNames(
|
|
297
301
|
"appearance-none bg-transparent outline-none border-none ring-0 flex-1 resize-none",
|
|
@@ -328,7 +332,7 @@ export const AutoComplete = ({
|
|
|
328
332
|
>
|
|
329
333
|
<Options
|
|
330
334
|
ref={refs.setFloating}
|
|
331
|
-
className="outline shadow-lg max-h-[40vh] z-
|
|
335
|
+
className="outline shadow-lg max-h-[40vh] z-(--z-popover)"
|
|
332
336
|
style={{
|
|
333
337
|
width: refs.reference.current?.getBoundingClientRect().width,
|
|
334
338
|
...floatingStyles,
|
package/src/select/DualList.tsx
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import { Button, ButtonGroup, CoreIcons } from "@react-fabric/core";
|
|
25
25
|
import { type RefProp } from "@react-fabric/core/dist/types/types";
|
|
26
26
|
import {
|
|
27
|
+
type ReactElement,
|
|
27
28
|
useCallback,
|
|
28
29
|
useDeferredValue,
|
|
29
30
|
useEffect,
|
|
@@ -68,6 +69,10 @@ export interface DualListProps<T>
|
|
|
68
69
|
* value property name
|
|
69
70
|
*/
|
|
70
71
|
valueProperty?: keyof T;
|
|
72
|
+
/**
|
|
73
|
+
* empty list display
|
|
74
|
+
*/
|
|
75
|
+
emptyDisplay?: ReactElement;
|
|
71
76
|
/**
|
|
72
77
|
* item renderer
|
|
73
78
|
*/
|
|
@@ -82,6 +87,7 @@ export const DualList = <T extends AnyObject = string>({
|
|
|
82
87
|
ref,
|
|
83
88
|
value,
|
|
84
89
|
options,
|
|
90
|
+
emptyDisplay,
|
|
85
91
|
groupProperty,
|
|
86
92
|
height = "18rem",
|
|
87
93
|
labelProperty = "label" as AnyObject,
|
|
@@ -210,6 +216,7 @@ export const DualList = <T extends AnyObject = string>({
|
|
|
210
216
|
error={error}
|
|
211
217
|
height={height}
|
|
212
218
|
options={leftOptions}
|
|
219
|
+
emptyDisplay={emptyDisplay}
|
|
213
220
|
groupProperty={groupProperty}
|
|
214
221
|
labelProperty={labelProperty}
|
|
215
222
|
valueProperty={valueProperty}
|
|
@@ -268,6 +275,7 @@ export const DualList = <T extends AnyObject = string>({
|
|
|
268
275
|
allowClear
|
|
269
276
|
height={height}
|
|
270
277
|
options={rightOptions}
|
|
278
|
+
emptyDisplay={emptyDisplay}
|
|
271
279
|
groupProperty={groupProperty}
|
|
272
280
|
labelProperty={labelProperty}
|
|
273
281
|
valueProperty={valueProperty}
|