@react-fabric/form 1.0.0-beta.4 → 1.0.0-beta.41
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} +26 -15
- package/{src/input/File.module.css → css/_file.css} +20 -6
- package/css/styles.css +27 -0
- package/dist/cjs/builder/FileField.js +37 -25
- package/dist/cjs/builder/FormField.js +44 -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 +413 -0
- package/dist/cjs/form/Controller.js +1 -1
- package/dist/cjs/form/Form.js +19 -10
- package/dist/cjs/hooks/useFormBuilder.js +27 -15
- package/dist/cjs/index.js +9 -2
- package/dist/cjs/input/ArrayInput.js +36 -25
- package/dist/cjs/input/AvatarInput.js +1 -1
- package/dist/cjs/input/Checkbox.js +5 -4
- package/dist/cjs/input/ColorInput.js +70 -28
- package/dist/cjs/input/ColorPicker.js +1 -35
- package/dist/cjs/input/DateInput.js +183 -0
- package/dist/cjs/input/Field.js +4 -4
- package/dist/cjs/input/File.js +2 -3
- package/dist/cjs/input/Hidden.js +3 -1
- 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 +6 -3
- package/dist/cjs/input/{Range.js → RangeSlider.js} +3 -3
- package/dist/cjs/input/Search.js +1 -1
- package/dist/cjs/input/Slider.js +1 -1
- package/dist/cjs/input/Switch.js +27 -5
- package/dist/cjs/input/Textarea.js +7 -3
- package/dist/cjs/internal/ErrorIcon.js +1 -1
- package/dist/cjs/internal/FieldWrapper.js +4 -3
- package/dist/cjs/internal/InputWrapper.js +14 -16
- package/dist/cjs/select/AutoComplete.js +9 -6
- package/dist/cjs/select/List.js +41 -20
- package/dist/cjs/select/Options.js +2 -2
- package/dist/cjs/select/Select.js +15 -9
- package/dist/cjs/select/useSelect.js +15 -8
- package/{src/input/ColorPicker.module.css → dist/cjs/types/schema.js} +18 -27
- package/dist/cjs/utils/getColor.js +6 -0
- package/dist/esm/builder/FileField.js +39 -27
- package/dist/esm/builder/FormField.js +44 -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 +413 -0
- package/dist/esm/form/Controller.js +1 -1
- package/dist/esm/form/Form.js +19 -10
- package/dist/esm/hooks/useFormBuilder.js +25 -13
- package/dist/esm/index.js +4 -1
- package/dist/esm/input/ArrayInput.js +38 -27
- package/dist/esm/input/AvatarInput.js +1 -1
- package/dist/esm/input/Checkbox.js +5 -4
- package/dist/esm/input/ColorInput.js +72 -30
- package/dist/esm/input/ColorPicker.js +1 -35
- package/dist/esm/input/DateInput.js +183 -0
- package/dist/esm/input/Field.js +5 -5
- package/dist/esm/input/File.js +2 -3
- package/dist/esm/input/Hidden.js +3 -1
- 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 -4
- package/dist/esm/input/{Range.js → RangeSlider.js} +3 -3
- package/dist/esm/input/Search.js +1 -1
- package/dist/esm/input/Slider.js +1 -1
- package/dist/esm/input/Switch.js +29 -7
- package/dist/esm/input/Textarea.js +7 -3
- package/dist/esm/internal/ErrorIcon.js +1 -1
- package/dist/esm/internal/FieldWrapper.js +4 -3
- package/dist/esm/internal/InputWrapper.js +14 -16
- package/dist/esm/select/AutoComplete.js +9 -6
- package/dist/esm/select/List.js +42 -21
- package/dist/esm/select/Options.js +2 -2
- package/dist/esm/select/Select.js +15 -9
- package/dist/esm/select/useSelect.js +16 -9
- package/dist/esm/types/schema.js +41 -0
- 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 +1 -1
- package/dist/types/hooks/useFormBuilder.d.ts +3 -1
- package/dist/types/index.d.ts +4 -2
- package/dist/types/input/ArrayInput.d.ts +20 -3
- package/dist/types/input/Checkbox.d.ts +4 -3
- package/dist/types/input/ColorInput.d.ts +1 -1
- package/dist/types/input/DateInput.d.ts +19 -0
- package/dist/types/input/RadioGroup.d.ts +18 -2
- package/dist/types/input/{Range.d.ts → RangeSlider.d.ts} +1 -1
- 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/AutoComplete.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/select/useSelect.d.ts +2 -1
- package/dist/types/types/index.d.ts +17 -5
- package/dist/types/types/schema.d.ts +79 -33
- package/package.json +10 -7
- package/src/builder/FileField.tsx +53 -27
- package/src/builder/FormField.tsx +45 -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 +435 -0
- package/src/form/Controller.tsx +2 -2
- package/src/form/Form.tsx +15 -8
- package/src/hooks/useFormBuilder.tsx +29 -15
- package/src/index.ts +10 -2
- package/src/input/ArrayInput.tsx +80 -42
- package/src/input/AvatarInput.tsx +1 -1
- package/src/input/Checkbox.tsx +5 -4
- package/src/input/ColorInput.tsx +102 -34
- package/src/input/ColorPicker.tsx +1 -35
- package/src/input/DateInput.tsx +248 -0
- package/src/input/Field.tsx +9 -11
- package/src/input/File.tsx +3 -6
- package/src/input/Hidden.tsx +4 -1
- package/src/input/Input.tsx +2 -2
- package/src/input/Number.tsx +2 -2
- package/src/input/Password.tsx +2 -2
- package/src/input/Radio.tsx +1 -1
- package/src/input/RadioGroup.tsx +27 -4
- package/src/input/{Range.tsx → RangeSlider.tsx} +2 -2
- package/src/input/Search.tsx +2 -2
- package/src/input/Slider.tsx +1 -1
- package/src/input/Switch.tsx +42 -6
- package/src/input/Textarea.tsx +11 -3
- package/src/internal/ErrorIcon.tsx +1 -1
- package/src/internal/FieldWrapper.tsx +3 -3
- package/src/internal/InputWrapper.tsx +21 -20
- package/src/select/AutoComplete.tsx +4 -1
- package/src/select/List.tsx +37 -8
- package/src/select/Options.tsx +1 -1
- package/src/select/Select.tsx +9 -3
- package/src/select/useSelect.tsx +30 -19
- package/src/types/index.ts +22 -7
- package/src/types/schema.ts +96 -41
- 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
|
@@ -21,38 +21,47 @@
|
|
|
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 { EmptyContent } from "@react-fabric/core";
|
|
24
25
|
import { isEmpty, isNil, yup } from "@react-fabric/utilities";
|
|
25
26
|
import { Fragment, useMemo } from "react";
|
|
26
27
|
import { FormField } from "../builder/FormField";
|
|
27
|
-
import { type
|
|
28
|
+
import { type BaseSelectProps } from "../types";
|
|
29
|
+
import { DATA_TYPES, type FormSchema, type SchemaDef } from "../types/schema";
|
|
28
30
|
import { type UploadHandler } from "./useFileUploader";
|
|
29
31
|
|
|
30
|
-
const makeYupField = (field:
|
|
31
|
-
let yupField: AnyObject = yup.string();
|
|
32
|
-
if (field.datatype ===
|
|
32
|
+
const makeYupField = (field: SchemaDef) => {
|
|
33
|
+
let yupField: AnyObject = yup.string().trim();
|
|
34
|
+
if (field.datatype === DATA_TYPES.SCHEMA) {
|
|
33
35
|
const child: yup.ObjectShape = Object.fromEntries(
|
|
34
36
|
field.schema.map((field) => [field.id, makeYupField(field)]),
|
|
35
37
|
);
|
|
36
38
|
yupField = yup.object(child);
|
|
37
39
|
}
|
|
38
|
-
if (field.datatype ===
|
|
40
|
+
if (field.datatype === DATA_TYPES.BOOL) {
|
|
41
|
+
yupField = yup.boolean();
|
|
42
|
+
if (field.required)
|
|
43
|
+
yupField = yupField.test({
|
|
44
|
+
test: (value: boolean) => !!value,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
39
47
|
if (
|
|
40
|
-
field.datatype ===
|
|
41
|
-
field.datatype ===
|
|
42
|
-
field.datatype === "range"
|
|
48
|
+
field.datatype === DATA_TYPES.NUMBER ||
|
|
49
|
+
field.datatype === DATA_TYPES.RANGE
|
|
43
50
|
) {
|
|
44
51
|
yupField = yup.number();
|
|
45
52
|
!isNil(field.min) && (yupField = yupField.min(field.min));
|
|
46
53
|
!isNil(field.max) && (yupField = yupField.max(field.max));
|
|
47
54
|
|
|
48
|
-
if (field.datatype ===
|
|
55
|
+
if (field.datatype === DATA_TYPES.RANGE) yupField = yup.array(yupField);
|
|
49
56
|
}
|
|
50
|
-
if (field.datatype ===
|
|
51
|
-
field.options &&
|
|
57
|
+
if (field.datatype === DATA_TYPES.STRING) {
|
|
58
|
+
field.options &&
|
|
59
|
+
!field.allowCustom &&
|
|
60
|
+
(yupField = yupField.oneOf(field.options));
|
|
52
61
|
field.regex && (yupField = yupField.matches(new RegExp(field.regex)));
|
|
53
62
|
}
|
|
54
63
|
|
|
55
|
-
if (field.datatype ===
|
|
64
|
+
if (field.datatype === DATA_TYPES.FILE) {
|
|
56
65
|
yupField = yup
|
|
57
66
|
.object({
|
|
58
67
|
filename: yup.string().required(),
|
|
@@ -83,13 +92,14 @@ const makeYupField = (field: FormSchema) => {
|
|
|
83
92
|
return yupField.label(field.label);
|
|
84
93
|
};
|
|
85
94
|
|
|
86
|
-
export const useFormBuilder = (
|
|
87
|
-
schema: FormSchema
|
|
95
|
+
export const useFormBuilder = <T extends AnyObject = string>(
|
|
96
|
+
schema: FormSchema,
|
|
88
97
|
options: {
|
|
89
98
|
prefix?: string;
|
|
90
99
|
inline?: boolean;
|
|
91
100
|
fileUrl?: (path: string) => string;
|
|
92
101
|
uploadHandler?: UploadHandler;
|
|
102
|
+
optionLists?: KeyValue<BaseSelectProps<T>>;
|
|
93
103
|
} = {},
|
|
94
104
|
) => {
|
|
95
105
|
const filteredSchema = useMemo(
|
|
@@ -106,11 +116,12 @@ export const useFormBuilder = (
|
|
|
106
116
|
<Fragment>
|
|
107
117
|
{filteredSchema.map((field, idx) => (
|
|
108
118
|
<div className="mb-4" key={field.id}>
|
|
109
|
-
{field.datatype ===
|
|
119
|
+
{field.datatype === DATA_TYPES.SCHEMA ? null : (
|
|
110
120
|
<FormField
|
|
111
121
|
{...field}
|
|
112
122
|
autoFocus={idx === 0}
|
|
113
123
|
fileUrl={options.fileUrl}
|
|
124
|
+
optionLists={options.optionLists}
|
|
114
125
|
uploadHandler={options.uploadHandler}
|
|
115
126
|
inline={options.inline}
|
|
116
127
|
prefix={options.prefix}
|
|
@@ -118,6 +129,9 @@ export const useFormBuilder = (
|
|
|
118
129
|
)}
|
|
119
130
|
</div>
|
|
120
131
|
))}
|
|
132
|
+
{filteredSchema.length === 0 && (
|
|
133
|
+
<EmptyContent message="No schema defined" />
|
|
134
|
+
)}
|
|
121
135
|
</Fragment>
|
|
122
136
|
);
|
|
123
137
|
|
package/src/index.ts
CHANGED
|
@@ -26,15 +26,23 @@ import "./i18n";
|
|
|
26
26
|
export { Controller } from "./form/Controller";
|
|
27
27
|
export { Form, type FormRef } from "./form/Form";
|
|
28
28
|
|
|
29
|
+
export { SchemaEditor } from "./builder/SchemaEditor";
|
|
30
|
+
|
|
29
31
|
export { useFileUploader } from "./hooks/useFileUploader";
|
|
30
32
|
export { useFormBuilder } from "./hooks/useFormBuilder";
|
|
31
33
|
|
|
32
|
-
export {
|
|
34
|
+
export {
|
|
35
|
+
DATA_TYPES,
|
|
36
|
+
SCHEMA_CUSTOM_LIST,
|
|
37
|
+
type FormSchema,
|
|
38
|
+
type SchemaDef,
|
|
39
|
+
} from "./types/schema";
|
|
33
40
|
|
|
34
41
|
export { ArrayInput } from "./input/ArrayInput";
|
|
35
42
|
export { Checkbox } from "./input/Checkbox";
|
|
36
43
|
export { ColorInput } from "./input/ColorInput";
|
|
37
44
|
export { ColorPicker } from "./input/ColorPicker";
|
|
45
|
+
export { DateInput } from "./input/DateInput";
|
|
38
46
|
export { Field } from "./input/Field";
|
|
39
47
|
export { FileInput } from "./input/File";
|
|
40
48
|
export { HiddenInput } from "./input/Hidden";
|
|
@@ -43,7 +51,7 @@ export { Number } from "./input/Number";
|
|
|
43
51
|
export { Password } from "./input/Password";
|
|
44
52
|
export { Radio } from "./input/Radio";
|
|
45
53
|
export { RadioGroup } from "./input/RadioGroup";
|
|
46
|
-
export {
|
|
54
|
+
export { RangeSlider } from "./input/RangeSlider";
|
|
47
55
|
export { Search } from "./input/Search";
|
|
48
56
|
export { Slider } from "./input/Slider";
|
|
49
57
|
export { Switch } from "./input/Switch";
|
package/src/input/ArrayInput.tsx
CHANGED
|
@@ -23,26 +23,31 @@
|
|
|
23
23
|
|
|
24
24
|
import { DndContext, type DragEndEvent } from "@dnd-kit/core";
|
|
25
25
|
import { SortableContext, useSortable } from "@dnd-kit/sortable";
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
Button,
|
|
28
|
+
cloneChildren,
|
|
29
|
+
CoreIcons,
|
|
30
|
+
Icon,
|
|
31
|
+
Tooltip,
|
|
32
|
+
} from "@react-fabric/core";
|
|
27
33
|
import { isString } from "@react-fabric/utilities";
|
|
28
34
|
import classNames from "classnames";
|
|
29
35
|
import {
|
|
30
|
-
Children,
|
|
31
36
|
cloneElement,
|
|
32
37
|
useCallback,
|
|
33
38
|
useImperativeHandle,
|
|
34
39
|
useMemo,
|
|
35
40
|
type PropsWithChildren,
|
|
36
41
|
type ReactNode,
|
|
37
|
-
type
|
|
42
|
+
type Ref,
|
|
38
43
|
} from "react";
|
|
39
44
|
import { useFieldArray, useFormContext } from "react-hook-form";
|
|
40
45
|
import { useTranslation } from "react-i18next";
|
|
41
46
|
import { FieldWrapper } from "../internal/FieldWrapper";
|
|
42
|
-
import classes from "./ArrayInput.module.css";
|
|
43
47
|
|
|
44
48
|
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
|
|
45
49
|
import { CSS } from "@dnd-kit/utilities";
|
|
50
|
+
|
|
46
51
|
export interface ArrayInputProps {
|
|
47
52
|
/**
|
|
48
53
|
* input label
|
|
@@ -77,6 +82,10 @@ export interface ArrayInputProps {
|
|
|
77
82
|
* minimum required length
|
|
78
83
|
*/
|
|
79
84
|
minItems?: number;
|
|
85
|
+
/**
|
|
86
|
+
* maximum length
|
|
87
|
+
*/
|
|
88
|
+
maxItems?: number;
|
|
80
89
|
/**
|
|
81
90
|
* field name to focus on add
|
|
82
91
|
*/
|
|
@@ -92,11 +101,12 @@ export interface ArrayInputProps {
|
|
|
92
101
|
* add item button label
|
|
93
102
|
*/
|
|
94
103
|
addLabel?: string;
|
|
104
|
+
buttonPosition?: "top" | "bottom" | "both";
|
|
95
105
|
/**
|
|
96
106
|
* fixed length list
|
|
97
107
|
*/
|
|
98
108
|
fixedList?: boolean;
|
|
99
|
-
arrayRef?:
|
|
109
|
+
arrayRef?: Ref<{
|
|
100
110
|
addItem: (item: AnyObject) => void;
|
|
101
111
|
removeItem: (idx: number) => void;
|
|
102
112
|
}>;
|
|
@@ -104,6 +114,19 @@ export interface ArrayInputProps {
|
|
|
104
114
|
* Add item
|
|
105
115
|
*/
|
|
106
116
|
onAdd?: () => AnyObject;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* field width
|
|
120
|
+
*/
|
|
121
|
+
width?: number | string;
|
|
122
|
+
/**
|
|
123
|
+
* inline label and input
|
|
124
|
+
*/
|
|
125
|
+
inline?: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* label width for inline
|
|
128
|
+
*/
|
|
129
|
+
labelWidth?: string;
|
|
107
130
|
}
|
|
108
131
|
|
|
109
132
|
export const ArrayInput = ({
|
|
@@ -112,12 +135,14 @@ export const ArrayInput = ({
|
|
|
112
135
|
addLabel,
|
|
113
136
|
fixedList,
|
|
114
137
|
focusName = "",
|
|
138
|
+
buttonPosition = "bottom",
|
|
115
139
|
onAdd,
|
|
116
140
|
arrayRef,
|
|
117
141
|
enableSorting,
|
|
118
142
|
disabled = false,
|
|
119
143
|
readOnly = false,
|
|
120
144
|
minItems = 0,
|
|
145
|
+
maxItems = Number.MAX_SAFE_INTEGER,
|
|
121
146
|
...rest
|
|
122
147
|
}: ArrayInputProps) => {
|
|
123
148
|
const { t } = useTranslation("form");
|
|
@@ -227,9 +252,55 @@ export const ArrayInput = ({
|
|
|
227
252
|
// @ts-expect-error ignore
|
|
228
253
|
SortableItem.displayName = "SortableItem";
|
|
229
254
|
|
|
255
|
+
const addButton = useMemo(
|
|
256
|
+
() => (
|
|
257
|
+
<div className="flex justify-end">
|
|
258
|
+
<Tooltip
|
|
259
|
+
color="danger-200"
|
|
260
|
+
content={
|
|
261
|
+
isString(error)
|
|
262
|
+
? `${error}`
|
|
263
|
+
: (t(
|
|
264
|
+
error?.key,
|
|
265
|
+
error?.values
|
|
266
|
+
? {
|
|
267
|
+
...error?.values,
|
|
268
|
+
label: t(
|
|
269
|
+
error.values?.label ?? "form:badkey",
|
|
270
|
+
error.values?.path,
|
|
271
|
+
),
|
|
272
|
+
}
|
|
273
|
+
: {},
|
|
274
|
+
) as string)
|
|
275
|
+
}
|
|
276
|
+
>
|
|
277
|
+
<Button
|
|
278
|
+
size="sm"
|
|
279
|
+
aria-label="Add item"
|
|
280
|
+
icon={CoreIcons.insert}
|
|
281
|
+
onClick={() => handleAdd(onAdd?.())}
|
|
282
|
+
data-invalid={!!error}
|
|
283
|
+
disabled={!!disabled || readOnly || fields.length > maxItems}
|
|
284
|
+
className={classNames("fabric-addButton", "me-10")}
|
|
285
|
+
>
|
|
286
|
+
{addLabel ?? t("addArray")}
|
|
287
|
+
</Button>
|
|
288
|
+
</Tooltip>
|
|
289
|
+
</div>
|
|
290
|
+
),
|
|
291
|
+
[error, fields, handleAdd, disabled, readOnly, addLabel, maxItems],
|
|
292
|
+
);
|
|
293
|
+
|
|
230
294
|
return (
|
|
231
|
-
<div className={
|
|
232
|
-
<FieldWrapper
|
|
295
|
+
<div className={"fabric-arrayInput"}>
|
|
296
|
+
<FieldWrapper
|
|
297
|
+
{...rest}
|
|
298
|
+
appendLabel={
|
|
299
|
+
<div className="-me-2">
|
|
300
|
+
{!fixedList && onAdd && buttonPosition !== "bottom" && addButton}
|
|
301
|
+
</div>
|
|
302
|
+
}
|
|
303
|
+
>
|
|
233
304
|
<Wrapper>
|
|
234
305
|
{fields.map((item, index) => (
|
|
235
306
|
<SortableItem
|
|
@@ -242,7 +313,7 @@ export const ArrayInput = ({
|
|
|
242
313
|
index,
|
|
243
314
|
name: `${name}.${index}`,
|
|
244
315
|
})
|
|
245
|
-
:
|
|
316
|
+
: cloneChildren(children, (child: AnyObject) =>
|
|
246
317
|
cloneElement(
|
|
247
318
|
child,
|
|
248
319
|
Object.assign(
|
|
@@ -279,40 +350,7 @@ export const ArrayInput = ({
|
|
|
279
350
|
))}
|
|
280
351
|
</Wrapper>
|
|
281
352
|
</FieldWrapper>
|
|
282
|
-
{!fixedList && onAdd &&
|
|
283
|
-
<div className="flex justify-end">
|
|
284
|
-
<Tooltip
|
|
285
|
-
color="danger"
|
|
286
|
-
content={
|
|
287
|
-
isString(error)
|
|
288
|
-
? `${error}`
|
|
289
|
-
: (t(
|
|
290
|
-
error?.key,
|
|
291
|
-
error?.values
|
|
292
|
-
? {
|
|
293
|
-
...error?.values,
|
|
294
|
-
label: t(
|
|
295
|
-
error.values?.label ?? "form:badkey",
|
|
296
|
-
error.values?.path,
|
|
297
|
-
),
|
|
298
|
-
}
|
|
299
|
-
: {},
|
|
300
|
-
) as string)
|
|
301
|
-
}
|
|
302
|
-
>
|
|
303
|
-
<Button
|
|
304
|
-
aria-label="Add item"
|
|
305
|
-
icon={CoreIcons.insert}
|
|
306
|
-
onClick={() => handleAdd(onAdd())}
|
|
307
|
-
data-invalid={!!error}
|
|
308
|
-
disabled={!!disabled || readOnly}
|
|
309
|
-
className={classNames(classes.addButton, "me-10")}
|
|
310
|
-
>
|
|
311
|
-
{addLabel ?? t("addArray")}
|
|
312
|
-
</Button>
|
|
313
|
-
</Tooltip>
|
|
314
|
-
</div>
|
|
315
|
-
)}
|
|
353
|
+
{!fixedList && onAdd && buttonPosition !== "top" && addButton}
|
|
316
354
|
</div>
|
|
317
355
|
);
|
|
318
356
|
};
|
|
@@ -99,7 +99,7 @@ export const AvatarInput = ({
|
|
|
99
99
|
<div className="flex flex-nowrap items-end">
|
|
100
100
|
<div className="inline-block leading-none rounded-full relative outline overflow-hidden">
|
|
101
101
|
<Avatar name="temp" size={size} avatar={base64} />
|
|
102
|
-
<div className="absolute inset-x-0 bottom-0 cursor-pointer bg-
|
|
102
|
+
<div className="absolute inset-x-0 bottom-0 cursor-pointer bg-black/20 hover:bg-black/50 text-white text-xs text-center py-1">
|
|
103
103
|
<span>Edit</span>
|
|
104
104
|
<input
|
|
105
105
|
type="file"
|
package/src/input/Checkbox.tsx
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
} from "react";
|
|
35
35
|
import { ErrorIcon } from "../internal/ErrorIcon";
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
interface CheckboxProps extends RefProp<HTMLInputElement> {
|
|
38
38
|
/**
|
|
39
39
|
* checkbox label
|
|
40
40
|
*/
|
|
@@ -50,8 +50,7 @@ export interface CheckboxProps extends RefProp<HTMLInputElement> {
|
|
|
50
50
|
/**
|
|
51
51
|
* on checked change
|
|
52
52
|
*/
|
|
53
|
-
onChange?: (checked: boolean
|
|
54
|
-
|
|
53
|
+
onChange?: (checked: boolean) => void;
|
|
55
54
|
/**
|
|
56
55
|
* disabled input
|
|
57
56
|
*/
|
|
@@ -94,6 +93,8 @@ export const Checkbox = ({
|
|
|
94
93
|
width,
|
|
95
94
|
icon,
|
|
96
95
|
iconChecked,
|
|
96
|
+
// @ts-expect-error ignore
|
|
97
|
+
required,
|
|
97
98
|
onChange,
|
|
98
99
|
...rest
|
|
99
100
|
}: CheckboxProps) => {
|
|
@@ -150,7 +151,7 @@ export const Checkbox = ({
|
|
|
150
151
|
<Icon
|
|
151
152
|
className={classNames(
|
|
152
153
|
"p-0.5",
|
|
153
|
-
actualValue && icon && !iconChecked && "bg-primary-500 text-white",
|
|
154
|
+
actualValue && icon && !iconChecked && "bg-primary-500 text-white!",
|
|
154
155
|
)}
|
|
155
156
|
size="1.25em"
|
|
156
157
|
color={invalid ? "danger" : "primary"}
|
package/src/input/ColorInput.tsx
CHANGED
|
@@ -21,7 +21,19 @@
|
|
|
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
|
+
arrow,
|
|
26
|
+
autoUpdate,
|
|
27
|
+
flip,
|
|
28
|
+
FloatingArrow,
|
|
29
|
+
offset,
|
|
30
|
+
shift,
|
|
31
|
+
useClick,
|
|
32
|
+
useDismiss,
|
|
33
|
+
useFloating,
|
|
34
|
+
useInteractions,
|
|
35
|
+
} from "@floating-ui/react";
|
|
36
|
+
import { CoreIcons, Icon } from "@react-fabric/core";
|
|
25
37
|
import { type RefProp } from "@react-fabric/core/dist/types/types";
|
|
26
38
|
import { isString } from "@react-fabric/utilities";
|
|
27
39
|
import classNames from "classnames";
|
|
@@ -30,12 +42,16 @@ import {
|
|
|
30
42
|
useCallback,
|
|
31
43
|
useDeferredValue,
|
|
32
44
|
useEffect,
|
|
45
|
+
useRef,
|
|
33
46
|
useState,
|
|
34
47
|
} from "react";
|
|
35
48
|
import { type InputProps } from "../types";
|
|
36
49
|
import { ColorPicker, type ColorProps } from "./ColorPicker";
|
|
37
50
|
|
|
38
|
-
export interface ColorInputProps
|
|
51
|
+
export interface ColorInputProps
|
|
52
|
+
extends InputProps,
|
|
53
|
+
Omit<ColorProps, "onChange">,
|
|
54
|
+
RefProp {
|
|
39
55
|
/**
|
|
40
56
|
* show eydrop picker
|
|
41
57
|
*/
|
|
@@ -69,17 +85,49 @@ export const ColorInput = ({
|
|
|
69
85
|
const handleChange = useCallback(
|
|
70
86
|
(e?: string) => {
|
|
71
87
|
setActualValue(e ?? defaultColor);
|
|
72
|
-
onChange != null && startTransition(() => onChange(e));
|
|
88
|
+
onChange != null && startTransition(() => onChange(e ?? null));
|
|
73
89
|
},
|
|
74
90
|
[onChange],
|
|
75
91
|
);
|
|
76
92
|
|
|
93
|
+
const arrowRef = useRef(null);
|
|
94
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
95
|
+
const { refs, floatingStyles, context } = useFloating({
|
|
96
|
+
open: isOpen,
|
|
97
|
+
onOpenChange: (open, _, reason) => {
|
|
98
|
+
if (reason === "reference-press") return;
|
|
99
|
+
setIsOpen(open);
|
|
100
|
+
},
|
|
101
|
+
strategy: "fixed",
|
|
102
|
+
placement: "bottom",
|
|
103
|
+
whileElementsMounted: autoUpdate,
|
|
104
|
+
middleware: [
|
|
105
|
+
shift({ padding: 8 }),
|
|
106
|
+
flip(),
|
|
107
|
+
offset(9),
|
|
108
|
+
arrow({
|
|
109
|
+
element: arrowRef,
|
|
110
|
+
}),
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
const click = useClick(context, {
|
|
114
|
+
enabled: !disabled,
|
|
115
|
+
});
|
|
116
|
+
const dismiss = useDismiss(context, {
|
|
117
|
+
referencePress: true,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const { getReferenceProps, getFloatingProps } = useInteractions([
|
|
121
|
+
dismiss,
|
|
122
|
+
click,
|
|
123
|
+
]);
|
|
124
|
+
|
|
77
125
|
return (
|
|
78
126
|
<div
|
|
79
127
|
className={classNames(
|
|
80
128
|
"flex-content min-h-[1.5em] min-w-[3.5em] self-stretch flex items-center outline-tint-200 rounded",
|
|
81
129
|
!disabled && "bg-base",
|
|
82
|
-
!noOutline && "bg-
|
|
130
|
+
!noOutline && "bg-(--fabric-input) outline overflow-hidden",
|
|
83
131
|
)}
|
|
84
132
|
>
|
|
85
133
|
{decorateStart && (
|
|
@@ -92,36 +140,56 @@ export const ColorInput = ({
|
|
|
92
140
|
{decorateStart}
|
|
93
141
|
</div>
|
|
94
142
|
)}
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
143
|
+
<button
|
|
144
|
+
data-ref="button"
|
|
145
|
+
className="flex-1 flex items-center"
|
|
146
|
+
ref={refs.setReference}
|
|
147
|
+
{...getReferenceProps()}
|
|
148
|
+
data-inner-clickable="true"
|
|
149
|
+
data-dropdown-open={isOpen ? true : undefined}
|
|
150
|
+
>
|
|
151
|
+
<div
|
|
152
|
+
role="none"
|
|
153
|
+
className="h-[1.5em] min-w-[1.5em] flex-1 flex items-center justify-center self-stretch cursor-pointer m-[0.25em] rounded outline outline-tint-100"
|
|
154
|
+
style={{
|
|
155
|
+
backgroundColor: actualValue,
|
|
156
|
+
opacity: disabled ? 0.65 : 1,
|
|
157
|
+
pointerEvents: disabled ? "none" : undefined,
|
|
158
|
+
}}
|
|
159
|
+
>
|
|
160
|
+
{!actualValue && (
|
|
161
|
+
<Icon
|
|
162
|
+
size="md"
|
|
163
|
+
className="text-muted"
|
|
164
|
+
icon={CoreIcons.colorSwatch}
|
|
165
|
+
/>
|
|
166
|
+
)}
|
|
167
|
+
</div>
|
|
168
|
+
</button>
|
|
169
|
+
{isOpen && (
|
|
170
|
+
<div
|
|
171
|
+
ref={refs.setFloating}
|
|
172
|
+
style={{
|
|
173
|
+
zIndex: "var(--z-popover)",
|
|
174
|
+
...floatingStyles,
|
|
175
|
+
}}
|
|
176
|
+
data-ref="dropdownBody"
|
|
177
|
+
{...getFloatingProps()}
|
|
178
|
+
>
|
|
179
|
+
<ColorPicker
|
|
180
|
+
{...rest}
|
|
181
|
+
onChange={handleChange}
|
|
182
|
+
defaultColor={defaultColor}
|
|
183
|
+
value={actualValue}
|
|
184
|
+
/>
|
|
185
|
+
<FloatingArrow
|
|
186
|
+
ref={arrowRef}
|
|
187
|
+
context={context}
|
|
188
|
+
strokeWidth={0.5}
|
|
189
|
+
className="fill-base stroke-muted"
|
|
190
|
+
/>
|
|
191
|
+
</div>
|
|
192
|
+
)}
|
|
125
193
|
{!disabled && showPicker && (
|
|
126
194
|
<Icon
|
|
127
195
|
icon={CoreIcons.colorPicker}
|
|
@@ -32,7 +32,6 @@ import {
|
|
|
32
32
|
type FC,
|
|
33
33
|
} from "react";
|
|
34
34
|
import { SketchPicker } from "react-color";
|
|
35
|
-
import classes from "./ColorPicker.module.css";
|
|
36
35
|
|
|
37
36
|
export interface ColorProps {
|
|
38
37
|
/**
|
|
@@ -130,17 +129,14 @@ export const ColorPicker: FC<ColorProps> = memo(
|
|
|
130
129
|
return (
|
|
131
130
|
<SketchPicker
|
|
132
131
|
width="16rem"
|
|
133
|
-
className={
|
|
132
|
+
className={"fabric-colorPicker"}
|
|
134
133
|
styles={
|
|
135
134
|
{
|
|
136
135
|
default: {
|
|
137
136
|
hue: {
|
|
138
|
-
borderRadius: "99px",
|
|
139
137
|
boxShadow: "0 0 1px 1px var(--color-shadow)",
|
|
140
138
|
},
|
|
141
139
|
alpha: {
|
|
142
|
-
height: "1rem",
|
|
143
|
-
borderRadius: "99px",
|
|
144
140
|
backgroundColor: "var(--fabric-bg)",
|
|
145
141
|
boxShadow: "0 0 1px 1px var(--color-shadow)",
|
|
146
142
|
},
|
|
@@ -158,36 +154,6 @@ export const ColorPicker: FC<ColorProps> = memo(
|
|
|
158
154
|
boxShadow:
|
|
159
155
|
"0 0 0 1px var(--color-shadow), 0 0 8px var(--fabric-shadow)",
|
|
160
156
|
},
|
|
161
|
-
Alpha: {
|
|
162
|
-
alpha: {
|
|
163
|
-
paddingRight: "calc(1rem - 2px)",
|
|
164
|
-
},
|
|
165
|
-
slider: {
|
|
166
|
-
width: "calc(1rem - 2px)",
|
|
167
|
-
borderRadius: "99px",
|
|
168
|
-
height: "calc(1rem - 2px)",
|
|
169
|
-
transform: "none",
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
Hue: {
|
|
173
|
-
hue: {
|
|
174
|
-
paddingRight: "calc(1rem - 2px)",
|
|
175
|
-
},
|
|
176
|
-
slider: {
|
|
177
|
-
width: "calc(1rem - 2px)",
|
|
178
|
-
borderRadius: "99px",
|
|
179
|
-
height: "calc(1rem - 2px)",
|
|
180
|
-
transform: "none",
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
Saturation: {
|
|
184
|
-
circle: {
|
|
185
|
-
width: "0.5rem",
|
|
186
|
-
borderRadius: "99px",
|
|
187
|
-
height: "0.5rem",
|
|
188
|
-
transform: "translate(-0.25rem, -0.25rem)",
|
|
189
|
-
},
|
|
190
|
-
},
|
|
191
157
|
checkboard: {
|
|
192
158
|
white: "transparent",
|
|
193
159
|
black: "red",
|