@react-fabric/form 1.0.0-beta.61 → 1.0.0-beta.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/_colorPicker.css +35 -5
- package/css/_file.css +2 -2
- package/dist/cjs/builder/FileField.js +14 -11
- package/dist/cjs/builder/SchemaEditor.js +1 -1
- package/dist/cjs/builder/components/SchemaArrayForm.js +2 -4
- package/dist/cjs/builder/components/SchemaField.js +3 -3
- package/dist/cjs/form/Controller.js +1 -1
- package/dist/cjs/form/Form.js +42 -41
- package/dist/cjs/form/useForm.js +32 -0
- package/dist/cjs/hooks/useFileUploader.js +44 -32
- package/dist/cjs/hooks/useFormBuilder.js +3 -3
- package/dist/cjs/i18n/index.js +4 -4
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/input/ArrayInput.js +66 -19
- package/dist/cjs/input/AvatarInput.js +21 -16
- package/dist/cjs/input/Checkbox.js +1 -1
- package/dist/cjs/input/ColorInput.js +26 -19
- package/dist/cjs/input/ColorPicker.js +16 -9
- package/dist/cjs/input/DateInput.js +3 -3
- package/dist/cjs/input/Field.js +1 -1
- package/dist/cjs/input/File.js +1 -1
- package/dist/cjs/input/Hidden.js +2 -11
- package/dist/cjs/input/Input.js +1 -1
- package/dist/cjs/input/Number.js +1 -1
- package/dist/cjs/input/Password.js +1 -1
- package/dist/cjs/input/Radio.js +1 -1
- package/dist/cjs/input/RadioGroup.js +7 -3
- package/dist/cjs/input/RangeSlider.js +1 -1
- package/dist/cjs/input/Search.js +1 -1
- package/dist/cjs/input/Slider.js +1 -1
- package/dist/cjs/input/Switch.js +4 -4
- package/dist/cjs/input/Textarea.js +1 -1
- package/dist/cjs/internal/InputWrapper.js +2 -2
- package/dist/cjs/ranger/index.js +5 -5
- package/dist/cjs/select/AutoComplete.js +4 -2
- package/dist/cjs/select/DualList.js +3 -3
- package/dist/cjs/select/List.js +7 -4
- package/dist/cjs/select/Options.js +5 -4
- package/dist/cjs/select/Select.js +5 -3
- package/dist/cjs/select/useSelect.js +15 -13
- package/dist/esm/builder/FileField.js +14 -11
- package/dist/esm/builder/SchemaEditor.js +1 -1
- package/dist/esm/builder/components/SchemaArrayForm.js +2 -4
- package/dist/esm/builder/components/SchemaField.js +3 -3
- package/dist/esm/form/Controller.js +1 -1
- package/dist/esm/form/Form.js +45 -43
- package/dist/esm/form/useForm.js +32 -0
- package/dist/esm/hooks/useFileUploader.js +45 -33
- package/dist/esm/hooks/useFormBuilder.js +3 -3
- package/dist/esm/i18n/index.js +2 -2
- package/dist/esm/index.js +2 -1
- package/dist/esm/input/ArrayInput.js +66 -19
- package/dist/esm/input/AvatarInput.js +21 -16
- package/dist/esm/input/Checkbox.js +1 -1
- package/dist/esm/input/ColorInput.js +27 -20
- package/dist/esm/input/ColorPicker.js +17 -10
- package/dist/esm/input/DateInput.js +3 -3
- package/dist/esm/input/Field.js +1 -1
- package/dist/esm/input/File.js +1 -1
- package/dist/esm/input/Hidden.js +3 -12
- package/dist/esm/input/Input.js +1 -1
- package/dist/esm/input/Number.js +1 -1
- package/dist/esm/input/Password.js +1 -1
- package/dist/esm/input/Radio.js +1 -1
- package/dist/esm/input/RadioGroup.js +7 -3
- package/dist/esm/input/RangeSlider.js +1 -1
- package/dist/esm/input/Search.js +1 -1
- package/dist/esm/input/Slider.js +1 -1
- package/dist/esm/input/Switch.js +4 -4
- package/dist/esm/input/Textarea.js +1 -1
- package/dist/esm/internal/InputWrapper.js +2 -2
- package/dist/esm/ranger/index.js +5 -5
- package/dist/esm/select/AutoComplete.js +4 -2
- package/dist/esm/select/DualList.js +3 -3
- package/dist/esm/select/List.js +8 -5
- package/dist/esm/select/Options.js +5 -4
- package/dist/esm/select/Select.js +6 -4
- package/dist/esm/select/useSelect.js +15 -13
- package/dist/types/builder/FileField.d.ts +2 -1
- package/dist/types/builder/SchemaEditor.d.ts +1 -1
- package/dist/types/form/Controller.d.ts +1 -1
- package/dist/types/form/Form.d.ts +7 -14
- package/dist/types/form/useForm.d.ts +11 -0
- package/dist/types/hooks/useFileUploader.d.ts +4 -2
- package/dist/types/index.d.ts +3 -2
- package/dist/types/input/ArrayInput.d.ts +5 -4
- package/dist/types/input/AvatarInput.d.ts +2 -2
- package/dist/types/input/Checkbox.d.ts +2 -2
- package/dist/types/input/ColorInput.d.ts +1 -1
- package/dist/types/input/ColorPicker.d.ts +5 -1
- package/dist/types/input/DateInput.d.ts +1 -1
- package/dist/types/input/Field.d.ts +1 -1
- package/dist/types/input/File.d.ts +1 -1
- package/dist/types/input/Hidden.d.ts +4 -12
- package/dist/types/input/Input.d.ts +1 -1
- package/dist/types/input/Number.d.ts +1 -1
- package/dist/types/input/Password.d.ts +1 -1
- package/dist/types/input/Radio.d.ts +2 -2
- package/dist/types/input/RadioGroup.d.ts +7 -3
- package/dist/types/input/RangeSlider.d.ts +1 -1
- package/dist/types/input/Search.d.ts +1 -1
- package/dist/types/input/Slider.d.ts +1 -1
- package/dist/types/input/Switch.d.ts +2 -2
- package/dist/types/input/Textarea.d.ts +1 -1
- package/dist/types/select/AutoComplete.d.ts +1 -1
- package/dist/types/select/DualList.d.ts +1 -1
- package/dist/types/select/List.d.ts +1 -1
- package/dist/types/select/Select.d.ts +1 -1
- package/dist/types/types/index.d.ts +3 -3
- package/dist/types/types/schema.d.ts +1 -1
- package/package.json +14 -14
- package/src/builder/FileField.tsx +5 -3
- package/src/builder/SchemaEditor.tsx +2 -2
- package/src/builder/components/SchemaArrayForm.tsx +1 -3
- package/src/builder/components/SchemaField.tsx +3 -3
- package/src/form/Controller.tsx +1 -1
- package/src/form/Form.tsx +21 -43
- package/src/form/useForm.ts +44 -0
- package/src/hooks/useFileUploader.ts +41 -29
- package/src/i18n/index.ts +2 -2
- package/src/index.ts +3 -7
- package/src/input/ArrayInput.tsx +20 -10
- package/src/input/AvatarInput.tsx +12 -12
- package/src/input/Checkbox.tsx +2 -2
- package/src/input/ColorInput.tsx +29 -45
- package/src/input/ColorPicker.tsx +42 -49
- package/src/input/DateInput.tsx +3 -3
- package/src/input/Field.tsx +2 -2
- package/src/input/File.tsx +1 -1
- package/src/input/Hidden.tsx +5 -25
- package/src/input/Input.tsx +1 -1
- package/src/input/Number.tsx +1 -1
- package/src/input/Password.tsx +1 -1
- package/src/input/Radio.tsx +2 -2
- package/src/input/RadioGroup.tsx +11 -3
- package/src/input/RangeSlider.tsx +1 -1
- package/src/input/Search.tsx +1 -1
- package/src/input/Slider.tsx +1 -1
- package/src/input/Switch.tsx +6 -6
- package/src/input/Textarea.tsx +1 -1
- package/src/internal/InputWrapper.tsx +1 -2
- package/src/select/AutoComplete.tsx +13 -52
- package/src/select/DualList.tsx +3 -3
- package/src/select/List.tsx +31 -69
- package/src/select/Options.tsx +4 -3
- package/src/select/Select.tsx +19 -41
- package/src/select/useSelect.tsx +24 -69
- package/src/types/index.ts +3 -3
- package/src/types/schema.ts +1 -1
- /package/dist/cjs/i18n/{ar.json.js → ar/form.json.js} +0 -0
- /package/dist/cjs/i18n/{en.json.js → en/form.json.js} +0 -0
- /package/dist/esm/i18n/{ar.json.js → ar/form.json.js} +0 -0
- /package/dist/esm/i18n/{en.json.js → en/form.json.js} +0 -0
- /package/src/i18n/{ar.json → ar/form.json} +0 -0
- /package/src/i18n/{en.json → en/form.json} +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* React Fabric
|
|
3
|
+
* @version: 1.0.0
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* The MIT License (MIT)
|
|
7
|
+
* Copyright (c) 2026 Adarsh Pastakia
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
10
|
+
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
11
|
+
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
12
|
+
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
13
|
+
* subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
16
|
+
* portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
19
|
+
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
20
|
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { useFormContext, useWatch } from "react-hook-form";
|
|
25
|
+
|
|
26
|
+
export const useForm = <K extends KeyValue = KeyValue>() => {
|
|
27
|
+
const { formState, getValues, setValue, watch, reset, resetField, setError, setFocus } = useFormContext<K>();
|
|
28
|
+
const values = useWatch<K>();
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
values: {
|
|
32
|
+
...values,
|
|
33
|
+
...getValues(),
|
|
34
|
+
},
|
|
35
|
+
formState,
|
|
36
|
+
getValues,
|
|
37
|
+
setValue,
|
|
38
|
+
watch,
|
|
39
|
+
reset,
|
|
40
|
+
resetField,
|
|
41
|
+
setError,
|
|
42
|
+
setFocus,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
import { isArray, isObject, isString, uuid } from "@react-fabric/utilities";
|
|
25
25
|
import { type AxiosRequestConfig } from "axios";
|
|
26
|
-
import { useCallback, useReducer } from "react";
|
|
26
|
+
import { useCallback, useEffect, useReducer } from "react";
|
|
27
27
|
|
|
28
28
|
export type UploadHandler = (
|
|
29
29
|
data: FormData,
|
|
@@ -54,6 +54,7 @@ type UploaderActions =
|
|
|
54
54
|
| { type: "stop"; key: string; path: string }
|
|
55
55
|
| { type: "error"; key: string; error: string }
|
|
56
56
|
| { type: "progress"; key: string; progress: number }
|
|
57
|
+
| { type: "init"; initialList?: string | FileInfo | FileInfo[] }
|
|
57
58
|
| { type: "remove"; key: string }
|
|
58
59
|
| { type: "abort"; key: string };
|
|
59
60
|
|
|
@@ -76,7 +77,13 @@ type UploaderActions =
|
|
|
76
77
|
export const useFileUploader = (
|
|
77
78
|
uploader: UploadHandler,
|
|
78
79
|
initialList?: string | FileInfo | FileInfo[],
|
|
79
|
-
|
|
80
|
+
{
|
|
81
|
+
multiple = true,
|
|
82
|
+
onChange,
|
|
83
|
+
}: {
|
|
84
|
+
multiple?: boolean;
|
|
85
|
+
onChange?: (files: FileInfo[] | FileInfo | null) => void;
|
|
86
|
+
} = {},
|
|
80
87
|
) => {
|
|
81
88
|
const [state, dispatch] = useReducer(
|
|
82
89
|
(state: UploaderState, action: UploaderActions) => {
|
|
@@ -119,6 +126,29 @@ export const useFileUploader = (
|
|
|
119
126
|
if (action.type === "remove") {
|
|
120
127
|
state.files.delete(action.key);
|
|
121
128
|
}
|
|
129
|
+
if (action.type === "init") {
|
|
130
|
+
state.files = new Map();
|
|
131
|
+
if (isString(action.initialList)) {
|
|
132
|
+
const key = uuid();
|
|
133
|
+
state.files.set(key, {
|
|
134
|
+
key,
|
|
135
|
+
path: action.initialList,
|
|
136
|
+
filename: "",
|
|
137
|
+
size: 0,
|
|
138
|
+
mime: "",
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (isObject(action.initialList)) {
|
|
142
|
+
const key = uuid();
|
|
143
|
+
state.files.set(key, { ...(action.initialList as AnyObject), key });
|
|
144
|
+
}
|
|
145
|
+
if (isArray(action.initialList)) {
|
|
146
|
+
action.initialList.forEach((file) => {
|
|
147
|
+
const key = uuid();
|
|
148
|
+
state.files.set(key, { ...file, key });
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
122
152
|
state.list = Array.from(state.files.values())
|
|
123
153
|
.map((file) => {
|
|
124
154
|
return (
|
|
@@ -134,40 +164,23 @@ export const useFileUploader = (
|
|
|
134
164
|
);
|
|
135
165
|
})
|
|
136
166
|
.filter(Boolean) as FileInfo[];
|
|
167
|
+
if (action.type === "remove" || action.type === "stop") {
|
|
168
|
+
setTimeout(() => {
|
|
169
|
+
onChange?.(multiple ? state.list : state.list[0] ?? null);
|
|
170
|
+
}, 100);
|
|
171
|
+
}
|
|
137
172
|
return { ...state };
|
|
138
173
|
},
|
|
139
174
|
{
|
|
140
175
|
files: new Map(),
|
|
141
176
|
count: 0,
|
|
142
177
|
} as UploaderState,
|
|
143
|
-
(state: UploaderState) => {
|
|
144
|
-
if (initialList) {
|
|
145
|
-
if (isString(initialList)) {
|
|
146
|
-
const key = uuid();
|
|
147
|
-
state.files.set(key, {
|
|
148
|
-
key,
|
|
149
|
-
path: initialList,
|
|
150
|
-
filename: "",
|
|
151
|
-
size: 0,
|
|
152
|
-
mime: "",
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
if (isObject(initialList)) {
|
|
156
|
-
const key = uuid();
|
|
157
|
-
state.files.set(key, { ...(initialList as AnyObject), key });
|
|
158
|
-
}
|
|
159
|
-
if (isArray(initialList)) {
|
|
160
|
-
initialList.forEach((file) => {
|
|
161
|
-
const key = uuid();
|
|
162
|
-
state.files.set(key, { ...file, key });
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
state.list = Array.from(state.files.values());
|
|
167
|
-
return state;
|
|
168
|
-
},
|
|
169
178
|
);
|
|
170
179
|
|
|
180
|
+
useEffect(() => {
|
|
181
|
+
dispatch({ type: "init", initialList });
|
|
182
|
+
}, [initialList]);
|
|
183
|
+
|
|
171
184
|
const doUpload = useCallback(async (key: string, file: File) => {
|
|
172
185
|
const data = new FormData();
|
|
173
186
|
data.append("file", file);
|
|
@@ -244,7 +257,6 @@ export const useFileUploader = (
|
|
|
244
257
|
remove,
|
|
245
258
|
retry,
|
|
246
259
|
pending: state.count,
|
|
247
|
-
list: state.list,
|
|
248
260
|
files: Array.from(state.files.values()),
|
|
249
261
|
};
|
|
250
262
|
};
|
package/src/i18n/index.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -24,19 +24,15 @@
|
|
|
24
24
|
import "./i18n";
|
|
25
25
|
|
|
26
26
|
export { Controller } from "./form/Controller";
|
|
27
|
-
export { Form,
|
|
27
|
+
export { Form, type FormRef } from "./form/Form";
|
|
28
|
+
export { useForm } from "./form/useForm";
|
|
28
29
|
|
|
29
30
|
export { SchemaEditor } from "./builder/SchemaEditor";
|
|
30
31
|
|
|
31
32
|
export { useFileUploader } from "./hooks/useFileUploader";
|
|
32
33
|
export { useFormBuilder } from "./hooks/useFormBuilder";
|
|
33
34
|
|
|
34
|
-
export {
|
|
35
|
-
DATA_TYPES,
|
|
36
|
-
SCHEMA_CUSTOM_LIST,
|
|
37
|
-
type FormSchema,
|
|
38
|
-
type SchemaDef,
|
|
39
|
-
} from "./types/schema";
|
|
35
|
+
export { DATA_TYPES, SCHEMA_CUSTOM_LIST, type FormSchema, type SchemaDef } from "./types/schema";
|
|
40
36
|
|
|
41
37
|
export { ArrayInput } from "./input/ArrayInput";
|
|
42
38
|
export { AvatarInput } from "./input/AvatarInput";
|
package/src/input/ArrayInput.tsx
CHANGED
|
@@ -51,7 +51,7 @@ export interface ArrayInputProps<T extends AnyObject = string> {
|
|
|
51
51
|
/**
|
|
52
52
|
* append to label end
|
|
53
53
|
*/
|
|
54
|
-
appendLabel?:
|
|
54
|
+
appendLabel?: React.ReactElement | string | number | boolean;
|
|
55
55
|
/**
|
|
56
56
|
* info label at bottom
|
|
57
57
|
*/
|
|
@@ -91,20 +91,27 @@ export interface ArrayInputProps<T extends AnyObject = string> {
|
|
|
91
91
|
enableSorting?: boolean;
|
|
92
92
|
children:
|
|
93
93
|
| React.ReactNode
|
|
94
|
-
| ((props: {
|
|
94
|
+
| ((props: {
|
|
95
|
+
index: number;
|
|
96
|
+
name: string;
|
|
97
|
+
item: T;
|
|
98
|
+
onChange: (val: false | undefined | T) => void;
|
|
99
|
+
}) => React.ReactNode);
|
|
95
100
|
/**
|
|
96
101
|
* add item button label
|
|
97
102
|
*/
|
|
98
103
|
addLabel?: string;
|
|
99
104
|
buttonPosition?: "top" | "bottom" | "both";
|
|
100
105
|
arrayRef?: Ref<{
|
|
101
|
-
addItem: (
|
|
106
|
+
addItem: (
|
|
107
|
+
item: false | undefined | T | Promise<false | undefined | T>,
|
|
108
|
+
) => void;
|
|
102
109
|
removeItem: (idx: number) => void;
|
|
103
110
|
}>;
|
|
104
111
|
/**
|
|
105
112
|
* add new item
|
|
106
113
|
*/
|
|
107
|
-
onAdd?: () => T
|
|
114
|
+
onAdd?: () => false | undefined | T | Promise<false | undefined | T>;
|
|
108
115
|
/**
|
|
109
116
|
* on item remove
|
|
110
117
|
*/
|
|
@@ -147,7 +154,7 @@ export interface ArrayInputProps<T extends AnyObject = string> {
|
|
|
147
154
|
* It also supports drag-and-drop sorting using `@dnd-kit/core` and `@dnd-kit/sortable` for a better user experience when reordering items.
|
|
148
155
|
*
|
|
149
156
|
* @param {ArrayInputProps<T>} props - The properties for the ArrayInput component.
|
|
150
|
-
* @returns {
|
|
157
|
+
* @returns {React.ReactElement} The rendered ArrayInput component.
|
|
151
158
|
*
|
|
152
159
|
* @example
|
|
153
160
|
* ```jsx
|
|
@@ -235,9 +242,9 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
235
242
|
);
|
|
236
243
|
|
|
237
244
|
const handleAdd = useCallback(
|
|
238
|
-
(item?: T) => {
|
|
245
|
+
async (item?: Promise<false | undefined | T>) => {
|
|
239
246
|
if (!item) return;
|
|
240
|
-
append(item);
|
|
247
|
+
append((await item) as T);
|
|
241
248
|
setTimeout(() => {
|
|
242
249
|
form.setFocus(
|
|
243
250
|
`${name}.${fields.length}${focusName ? "." + focusName : ""}`,
|
|
@@ -261,12 +268,11 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
261
268
|
);
|
|
262
269
|
|
|
263
270
|
useImperativeHandle(arrayRef, () => ({
|
|
264
|
-
addItem: handleAdd,
|
|
271
|
+
addItem: (t) => handleAdd(Promise.resolve(t)),
|
|
265
272
|
removeItem: remove,
|
|
266
273
|
}));
|
|
267
274
|
|
|
268
275
|
const Wrapper = useCallback(
|
|
269
|
-
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
270
276
|
({ children }: { children: React.ReactNode }) => {
|
|
271
277
|
if (enableSorting) {
|
|
272
278
|
// pass id list to dnd context
|
|
@@ -364,7 +370,7 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
364
370
|
size="sm"
|
|
365
371
|
aria-label="Add item"
|
|
366
372
|
icon="icon-[mdi--plus-circle-outline]"
|
|
367
|
-
onClick={() => handleAdd(onAdd?.())}
|
|
373
|
+
onClick={() => handleAdd(Promise.resolve(onAdd?.()))}
|
|
368
374
|
data-invalid={!!error}
|
|
369
375
|
disabled={!!disabled || readOnly || fields.length > maxItems}
|
|
370
376
|
className={classNames(
|
|
@@ -411,6 +417,10 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
411
417
|
index,
|
|
412
418
|
item: item as any,
|
|
413
419
|
name: `${name}.${index}`,
|
|
420
|
+
onChange: async (val) => {
|
|
421
|
+
const result = await Promise.resolve(val);
|
|
422
|
+
result && form.setValue(`${name}.${index}`, result);
|
|
423
|
+
},
|
|
414
424
|
})
|
|
415
425
|
: cloneChildren(children, (child: AnyObject) =>
|
|
416
426
|
cloneElement(
|
|
@@ -75,7 +75,7 @@ export interface Props extends RefProp {
|
|
|
75
75
|
* It also provides a way to remove the uploaded file and shows upload progress.
|
|
76
76
|
*
|
|
77
77
|
* @param {Props} props - The properties for the AvatarInput component.
|
|
78
|
-
* @returns {
|
|
78
|
+
* @returns {React.ReactElement} - The rendered AvatarInput component.
|
|
79
79
|
*/
|
|
80
80
|
export const AvatarInput = ({
|
|
81
81
|
size = "6rem",
|
|
@@ -88,17 +88,21 @@ export const AvatarInput = ({
|
|
|
88
88
|
variant,
|
|
89
89
|
fileUrl,
|
|
90
90
|
uploadHandler,
|
|
91
|
+
onChange,
|
|
91
92
|
...rest
|
|
92
93
|
}: Props) => {
|
|
93
|
-
const { files,
|
|
94
|
+
const { files, upload, remove } = useFileUploader(
|
|
94
95
|
async (data, config) => await uploadHandler?.(data, config),
|
|
95
|
-
value,
|
|
96
|
-
|
|
96
|
+
value ?? defaultValue,
|
|
97
|
+
{
|
|
98
|
+
multiple: false,
|
|
99
|
+
onChange: (files: AnyObject) => onChange?.(files?.path ?? null),
|
|
100
|
+
},
|
|
97
101
|
);
|
|
98
102
|
|
|
99
103
|
const [base64, setBase64] = useState("");
|
|
100
104
|
useEffect(() => {
|
|
101
|
-
if (
|
|
105
|
+
if (files?.length) {
|
|
102
106
|
const file = files?.[0]?.file;
|
|
103
107
|
void (
|
|
104
108
|
file &&
|
|
@@ -116,7 +120,7 @@ export const AvatarInput = ({
|
|
|
116
120
|
} else {
|
|
117
121
|
setBase64(fileUrl?.(defaultValue ?? "") ?? defaultValue ?? "");
|
|
118
122
|
}
|
|
119
|
-
}, [files,
|
|
123
|
+
}, [files, defaultValue]);
|
|
120
124
|
|
|
121
125
|
useEffect(() => {
|
|
122
126
|
!value &&
|
|
@@ -126,7 +130,7 @@ export const AvatarInput = ({
|
|
|
126
130
|
}, [value, defaultValue]);
|
|
127
131
|
|
|
128
132
|
return (
|
|
129
|
-
<div className="flex flex-nowrap items-end overflow-hidden">
|
|
133
|
+
<div className="flex flex-nowrap items-end overflow-hidden p-px">
|
|
130
134
|
<div
|
|
131
135
|
className={classNames(
|
|
132
136
|
"inline-block leading-none relative outline overflow-hidden",
|
|
@@ -153,11 +157,7 @@ export const AvatarInput = ({
|
|
|
153
157
|
/>
|
|
154
158
|
</div>
|
|
155
159
|
</div>
|
|
156
|
-
<HiddenInput
|
|
157
|
-
hiddenValue={list?.[0]?.path}
|
|
158
|
-
defaultValue={defaultValue}
|
|
159
|
-
{...rest}
|
|
160
|
-
/>
|
|
160
|
+
<HiddenInput value={files?.[0]?.path} {...rest} />
|
|
161
161
|
{files.map((file, idx) => (
|
|
162
162
|
<div key={idx} className="px-2 py-1 flex-1 overflow-hidden">
|
|
163
163
|
<div className="flex flex-nowrap gap-1 items-center">
|
package/src/input/Checkbox.tsx
CHANGED
|
@@ -38,7 +38,7 @@ interface CheckboxProps extends RefProp<HTMLInputElement> {
|
|
|
38
38
|
/**
|
|
39
39
|
* checkbox label
|
|
40
40
|
*/
|
|
41
|
-
label?:
|
|
41
|
+
label?: React.ReactElement | string;
|
|
42
42
|
/**
|
|
43
43
|
* checked
|
|
44
44
|
*/
|
|
@@ -88,7 +88,7 @@ interface CheckboxProps extends RefProp<HTMLInputElement> {
|
|
|
88
88
|
* It also provides an error icon to indicate validation errors.
|
|
89
89
|
*
|
|
90
90
|
* @param {CheckboxProps} props - The properties for the Checkbox component.
|
|
91
|
-
* @returns {
|
|
91
|
+
* @returns {React.ReactElement} The rendered Checkbox component.
|
|
92
92
|
*/
|
|
93
93
|
export const Checkbox = ({
|
|
94
94
|
ref,
|
package/src/input/ColorInput.tsx
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
autoUpdate,
|
|
27
27
|
flip,
|
|
28
28
|
FloatingArrow,
|
|
29
|
+
FloatingFocusManager,
|
|
29
30
|
offset,
|
|
30
31
|
shift,
|
|
31
32
|
useClick,
|
|
@@ -35,22 +36,12 @@ import {
|
|
|
35
36
|
} from "@floating-ui/react";
|
|
36
37
|
import { Icon } from "@react-fabric/core";
|
|
37
38
|
import { type RefProp } from "@react-fabric/core/dist/types/types";
|
|
38
|
-
import {
|
|
39
|
-
startTransition,
|
|
40
|
-
useCallback,
|
|
41
|
-
useDeferredValue,
|
|
42
|
-
useEffect,
|
|
43
|
-
useRef,
|
|
44
|
-
useState,
|
|
45
|
-
} from "react";
|
|
39
|
+
import { startTransition, useCallback, useDeferredValue, useEffect, useRef, useState } from "react";
|
|
46
40
|
import { InputWrapper } from "../internal/InputWrapper";
|
|
47
41
|
import { type InputProps } from "../types";
|
|
48
42
|
import { ColorPicker, type ColorProps } from "./ColorPicker";
|
|
49
43
|
|
|
50
|
-
export interface ColorInputProps
|
|
51
|
-
extends InputProps,
|
|
52
|
-
Omit<ColorProps, "onChange">,
|
|
53
|
-
RefProp {
|
|
44
|
+
export interface ColorInputProps extends InputProps, Omit<ColorProps, "onChange">, RefProp {
|
|
54
45
|
/**
|
|
55
46
|
* show eydrop picker
|
|
56
47
|
*/
|
|
@@ -68,7 +59,7 @@ export interface ColorInputProps
|
|
|
68
59
|
* and handling the color selection state.
|
|
69
60
|
*
|
|
70
61
|
* @param {ColorInputProps} props - The properties for the ColorInput component.
|
|
71
|
-
* @returns {
|
|
62
|
+
* @returns {React.ReactElement} - The rendered ColorInput component.
|
|
72
63
|
*/
|
|
73
64
|
export const ColorInput = ({
|
|
74
65
|
ref,
|
|
@@ -130,10 +121,7 @@ export const ColorInput = ({
|
|
|
130
121
|
referencePress: true,
|
|
131
122
|
});
|
|
132
123
|
|
|
133
|
-
const { getReferenceProps, getFloatingProps } = useInteractions([
|
|
134
|
-
dismiss,
|
|
135
|
-
click,
|
|
136
|
-
]);
|
|
124
|
+
const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, click]);
|
|
137
125
|
|
|
138
126
|
return (
|
|
139
127
|
<InputWrapper
|
|
@@ -167,34 +155,32 @@ export const ColorInput = ({
|
|
|
167
155
|
pointerEvents: disabled ? "none" : undefined,
|
|
168
156
|
}}
|
|
169
157
|
>
|
|
170
|
-
{!actualValue &&
|
|
171
|
-
<Icon size="md" className="text-muted" icon="icon-[mdi--palette]" />
|
|
172
|
-
)}
|
|
158
|
+
{!actualValue && <Icon size="md" className="text-muted" icon="icon-[mdi--palette]" />}
|
|
173
159
|
</div>
|
|
174
160
|
</button>
|
|
175
161
|
{isOpen && (
|
|
176
|
-
<
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
{...rest}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
</
|
|
162
|
+
<FloatingFocusManager context={context} closeOnFocusOut>
|
|
163
|
+
<div
|
|
164
|
+
ref={refs.setFloating}
|
|
165
|
+
style={{
|
|
166
|
+
zIndex: "var(--z-popover)",
|
|
167
|
+
...floatingStyles,
|
|
168
|
+
}}
|
|
169
|
+
data-ref="dropdownBody"
|
|
170
|
+
{...getFloatingProps()}
|
|
171
|
+
>
|
|
172
|
+
<ColorPicker {...rest} onChange={handleChange} defaultColor={defaultColor} value={actualValue} />
|
|
173
|
+
<FloatingArrow
|
|
174
|
+
ref={arrowRef}
|
|
175
|
+
context={context}
|
|
176
|
+
strokeWidth={0.5}
|
|
177
|
+
className="stroke-muted"
|
|
178
|
+
style={{
|
|
179
|
+
fill: actualValue || "var(--bg-color-base)",
|
|
180
|
+
}}
|
|
181
|
+
/>
|
|
182
|
+
</div>
|
|
183
|
+
</FloatingFocusManager>
|
|
198
184
|
)}
|
|
199
185
|
{!disabled && showPicker && (
|
|
200
186
|
<Icon
|
|
@@ -202,9 +188,7 @@ export const ColorInput = ({
|
|
|
202
188
|
icon="icon-[mdi--eyedropper]"
|
|
203
189
|
onClick={() =>
|
|
204
190
|
(window as AnyObject).EyeDropper &&
|
|
205
|
-
new (window as AnyObject).EyeDropper()
|
|
206
|
-
.open()
|
|
207
|
-
.then((resp: AnyObject) => handleChange(resp.sRGBHex))
|
|
191
|
+
new (window as AnyObject).EyeDropper().open().then((resp: AnyObject) => handleChange(resp.sRGBHex))
|
|
208
192
|
}
|
|
209
193
|
/>
|
|
210
194
|
)}
|
|
@@ -21,17 +21,9 @@
|
|
|
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
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
startTransition,
|
|
28
|
-
useCallback,
|
|
29
|
-
useDeferredValue,
|
|
30
|
-
useEffect,
|
|
31
|
-
useState,
|
|
32
|
-
type FC,
|
|
33
|
-
} from "react";
|
|
34
|
-
import { SketchPicker } from "react-color";
|
|
24
|
+
import chroma from "chroma-js";
|
|
25
|
+
import { memo, startTransition, useCallback, useDeferredValue, useEffect, useState, type FC } from "react";
|
|
26
|
+
import { BlockPicker, SketchPicker } from "react-color";
|
|
35
27
|
|
|
36
28
|
export interface ColorProps {
|
|
37
29
|
/**
|
|
@@ -46,6 +38,10 @@ export interface ColorProps {
|
|
|
46
38
|
* hide alpha value
|
|
47
39
|
*/
|
|
48
40
|
hideAlpha?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* show only swatches, hide the color picker
|
|
43
|
+
*/
|
|
44
|
+
picker?: "default" | "swatches";
|
|
49
45
|
/**
|
|
50
46
|
* color value
|
|
51
47
|
*/
|
|
@@ -57,16 +53,16 @@ export interface ColorProps {
|
|
|
57
53
|
}
|
|
58
54
|
|
|
59
55
|
const DEFAULT_SWATCHES = [
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
56
|
+
chroma.mix("#d7323a", "#171a1c", 0.5, "lab").hex(),
|
|
57
|
+
chroma.mix("#ff781c", "#171a1c", 0.5, "lab").hex(),
|
|
58
|
+
chroma.mix("#f7b731", "#171a1c", 0.5, "lab").hex(),
|
|
59
|
+
chroma.mix("#88ab1b", "#171a1c", 0.5, "lab").hex(),
|
|
60
|
+
chroma.mix("#22aa85", "#171a1c", 0.5, "lab").hex(),
|
|
61
|
+
chroma.mix("#399bec", "#171a1c", 0.5, "lab").hex(),
|
|
62
|
+
chroma.mix("#4862c8", "#171a1c", 0.5, "lab").hex(),
|
|
63
|
+
chroma.mix("#aa66cf", "#171a1c", 0.5, "lab").hex(),
|
|
64
|
+
chroma.mix("#f43f7b", "#171a1c", 0.5, "lab").hex(),
|
|
65
|
+
chroma.mix("#a37f4f", "#171a1c", 0.5, "lab").hex(),
|
|
70
66
|
|
|
71
67
|
"#d7323a",
|
|
72
68
|
"#ff781c",
|
|
@@ -79,16 +75,16 @@ const DEFAULT_SWATCHES = [
|
|
|
79
75
|
"#f43f7b",
|
|
80
76
|
"#a37f4f",
|
|
81
77
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
78
|
+
chroma.mix("#d7323a", "#f1f3f4", 0.5, "lab").hex(),
|
|
79
|
+
chroma.mix("#ff781c", "#f1f3f4", 0.5, "lab").hex(),
|
|
80
|
+
chroma.mix("#f7b731", "#f1f3f4", 0.5, "lab").hex(),
|
|
81
|
+
chroma.mix("#88ab1b", "#f1f3f4", 0.5, "lab").hex(),
|
|
82
|
+
chroma.mix("#22aa85", "#f1f3f4", 0.5, "lab").hex(),
|
|
83
|
+
chroma.mix("#399bec", "#f1f3f4", 0.5, "lab").hex(),
|
|
84
|
+
chroma.mix("#4862c8", "#f1f3f4", 0.5, "lab").hex(),
|
|
85
|
+
chroma.mix("#aa66cf", "#f1f3f4", 0.5, "lab").hex(),
|
|
86
|
+
chroma.mix("#f43f7b", "#f1f3f4", 0.5, "lab").hex(),
|
|
87
|
+
chroma.mix("#a37f4f", "#f1f3f4", 0.5, "lab").hex(),
|
|
92
88
|
|
|
93
89
|
"#171a1c",
|
|
94
90
|
"#2d3439",
|
|
@@ -108,19 +104,12 @@ const DEFAULT_SWATCHES = [
|
|
|
108
104
|
* The component uses the `react-color` library for the color picker functionality.
|
|
109
105
|
*
|
|
110
106
|
* @param {ColorProps} props - The properties for the ColorPicker component.
|
|
111
|
-
* @returns {
|
|
107
|
+
* @returns {React.ReactElement} The rendered ColorPicker component.
|
|
112
108
|
*
|
|
113
109
|
* @see {@link https://react-color.github.io/react-color/} for more details on the color picker library.
|
|
114
110
|
*/
|
|
115
|
-
// eslint-disable-next-line react/display-name
|
|
116
111
|
export const ColorPicker: FC<ColorProps> = memo(
|
|
117
|
-
({
|
|
118
|
-
value,
|
|
119
|
-
onChange,
|
|
120
|
-
hideAlpha,
|
|
121
|
-
defaultColor = "#fff",
|
|
122
|
-
swatches = DEFAULT_SWATCHES,
|
|
123
|
-
}: ColorProps) => {
|
|
112
|
+
({ value, onChange, hideAlpha, defaultColor = "#fff", swatches = DEFAULT_SWATCHES, picker = "default" }: ColorProps) => {
|
|
124
113
|
const [actualValue, setActualValue] = useState("");
|
|
125
114
|
const deferred = useDeferredValue(value ?? defaultColor);
|
|
126
115
|
|
|
@@ -136,13 +125,21 @@ export const ColorPicker: FC<ColorProps> = memo(
|
|
|
136
125
|
[onChange],
|
|
137
126
|
);
|
|
138
127
|
|
|
128
|
+
const E = (picker === "swatches" ? BlockPicker : SketchPicker) as unknown as FC<any>;
|
|
129
|
+
|
|
139
130
|
return (
|
|
140
131
|
<div
|
|
141
132
|
role="none"
|
|
133
|
+
className="fabric-colorPicker-container"
|
|
142
134
|
// prevent default on mouse down to avoid selection issues
|
|
143
135
|
onMouseDown={(e) => e.preventDefault()}
|
|
136
|
+
style={
|
|
137
|
+
{
|
|
138
|
+
"--color-selected": value,
|
|
139
|
+
} as any
|
|
140
|
+
}
|
|
144
141
|
>
|
|
145
|
-
<
|
|
142
|
+
<E
|
|
146
143
|
width="16rem"
|
|
147
144
|
className={"fabric-colorPicker"}
|
|
148
145
|
styles={
|
|
@@ -166,8 +163,7 @@ export const ColorPicker: FC<ColorProps> = memo(
|
|
|
166
163
|
},
|
|
167
164
|
picker: {
|
|
168
165
|
backgroundColor: "var(--fabric-bg)",
|
|
169
|
-
boxShadow:
|
|
170
|
-
"0 0 0 1px var(--color-shadow), 0 0 8px var(--fabric-shadow)",
|
|
166
|
+
boxShadow: "0 0 0 1px var(--color-shadow), 0 0 8px var(--fabric-shadow)",
|
|
171
167
|
},
|
|
172
168
|
checkboard: {
|
|
173
169
|
white: "transparent",
|
|
@@ -177,14 +173,11 @@ export const ColorPicker: FC<ColorProps> = memo(
|
|
|
177
173
|
} as AnyObject
|
|
178
174
|
}
|
|
179
175
|
color={actualValue}
|
|
176
|
+
colors={swatches}
|
|
180
177
|
presetColors={swatches}
|
|
181
178
|
disableAlpha={hideAlpha}
|
|
182
|
-
onChange={({ rgb: { a = 1, ...rgb } }) =>
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
onChangeComplete={({ rgb: { a = 1, ...rgb } }) =>
|
|
186
|
-
handleChange(Color(rgb).alpha(a)[a < 1 ? "hexa" : "hex"]())
|
|
187
|
-
}
|
|
179
|
+
onChange={({ rgb: { a = 1, ...rgb } }) => setActualValue(chroma(rgb).alpha(a).hex())}
|
|
180
|
+
onChangeComplete={({ rgb: { a = 1, ...rgb } }) => handleChange(chroma(rgb).alpha(a).hex())}
|
|
188
181
|
/>
|
|
189
182
|
</div>
|
|
190
183
|
);
|