@react-fabric/form 1.0.0-beta.56 → 1.0.0-beta.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/_field.css +2 -1
- package/dist/cjs/form/Form.js +24 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/input/ArrayInput.js +34 -13
- package/dist/cjs/input/AvatarInput.js +17 -10
- package/dist/cjs/input/ColorInput.js +1 -0
- package/dist/cjs/input/Hidden.js +4 -3
- package/dist/cjs/input/Slider.js +2 -2
- package/dist/cjs/input/Textarea.js +1 -1
- package/dist/cjs/select/DualList.js +16 -8
- package/dist/cjs/select/List.js +5 -2
- package/dist/cjs/select/Options.js +49 -42
- package/dist/cjs/select/Select.js +4 -2
- package/dist/cjs/select/useSelect.js +14 -7
- package/dist/esm/form/Form.js +26 -3
- package/dist/esm/index.js +1 -1
- package/dist/esm/input/ArrayInput.js +35 -14
- package/dist/esm/input/AvatarInput.js +17 -10
- package/dist/esm/input/ColorInput.js +1 -0
- package/dist/esm/input/Hidden.js +4 -3
- package/dist/esm/input/Slider.js +2 -2
- package/dist/esm/input/Textarea.js +1 -1
- package/dist/esm/select/DualList.js +16 -8
- package/dist/esm/select/List.js +5 -2
- package/dist/esm/select/Options.js +49 -42
- package/dist/esm/select/Select.js +4 -2
- package/dist/esm/select/useSelect.js +14 -7
- package/dist/types/form/Form.d.ts +11 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/input/ArrayInput.d.ts +5 -8
- package/dist/types/input/AvatarInput.d.ts +6 -1
- package/dist/types/input/Hidden.d.ts +5 -1
- package/dist/types/select/List.d.ts +1 -1
- package/dist/types/select/Options.d.ts +2 -1
- package/dist/types/select/Select.d.ts +1 -1
- package/dist/types/select/useSelect.d.ts +4 -1
- package/dist/types/types/index.d.ts +4 -0
- package/package.json +20 -21
- package/src/form/Form.tsx +34 -2
- package/src/index.ts +1 -1
- package/src/input/ArrayInput.tsx +55 -21
- package/src/input/AvatarInput.tsx +32 -5
- package/src/input/ColorInput.tsx +1 -0
- package/src/input/Hidden.tsx +9 -5
- package/src/input/Slider.tsx +4 -4
- package/src/input/Textarea.tsx +1 -1
- package/src/select/DualList.tsx +4 -8
- package/src/select/List.tsx +3 -0
- package/src/select/Options.tsx +47 -43
- package/src/select/Select.tsx +2 -0
- package/src/select/useSelect.tsx +15 -6
- package/src/types/index.ts +4 -0
|
@@ -65,4 +65,15 @@ export interface FormProps<K extends KeyValue = KeyValue> {
|
|
|
65
65
|
* @see {@link https://github.com/jquense/yup} for more details on the Yup validation schema.
|
|
66
66
|
*/
|
|
67
67
|
export declare const Form: <K extends KeyValue>({ formRef, schema, children, defaultValues, onSubmit, onChange, ...rest }: PropsWithChildren<FormProps<K>>) => import("react/jsx-runtime").JSX.Element;
|
|
68
|
+
export declare const useForm: <K extends KeyValue = KeyValue>() => {
|
|
69
|
+
values: import("react-hook-form").DeepPartialSkipArrayKey<K> & K;
|
|
70
|
+
formState: FormState<K>;
|
|
71
|
+
getValues: import("react-hook-form").UseFormGetValues<K>;
|
|
72
|
+
setValue: import("react-hook-form").UseFormSetValue<K>;
|
|
73
|
+
watch: import("react-hook-form").UseFormWatch<K>;
|
|
74
|
+
reset: import("react-hook-form").UseFormReset<K>;
|
|
75
|
+
resetField: import("react-hook-form").UseFormResetField<K>;
|
|
76
|
+
setError: import("react-hook-form").UseFormSetError<K>;
|
|
77
|
+
setFocus: import("react-hook-form").UseFormSetFocus<K>;
|
|
78
|
+
};
|
|
68
79
|
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./i18n";
|
|
2
2
|
export { Controller } from "./form/Controller";
|
|
3
|
-
export { Form, type FormRef } from "./form/Form";
|
|
3
|
+
export { Form, useForm, type FormRef } from "./form/Form";
|
|
4
4
|
export { SchemaEditor } from "./builder/SchemaEditor";
|
|
5
5
|
export { useFileUploader } from "./hooks/useFileUploader";
|
|
6
6
|
export { useFormBuilder } from "./hooks/useFormBuilder";
|
|
@@ -47,16 +47,13 @@ export interface ArrayInputProps<T extends AnyObject = string> {
|
|
|
47
47
|
children: React.ReactNode | ((props: {
|
|
48
48
|
index: number;
|
|
49
49
|
name: string;
|
|
50
|
+
item: T;
|
|
50
51
|
}) => ReactNode);
|
|
51
52
|
/**
|
|
52
53
|
* add item button label
|
|
53
54
|
*/
|
|
54
55
|
addLabel?: string;
|
|
55
56
|
buttonPosition?: "top" | "bottom" | "both";
|
|
56
|
-
/**
|
|
57
|
-
* fixed length list
|
|
58
|
-
*/
|
|
59
|
-
fixedList?: boolean;
|
|
60
57
|
arrayRef?: Ref<{
|
|
61
58
|
addItem: (item: T) => void;
|
|
62
59
|
removeItem: (idx: number) => void;
|
|
@@ -64,7 +61,7 @@ export interface ArrayInputProps<T extends AnyObject = string> {
|
|
|
64
61
|
/**
|
|
65
62
|
* add new item
|
|
66
63
|
*/
|
|
67
|
-
onAdd?: () =>
|
|
64
|
+
onAdd?: () => T;
|
|
68
65
|
/**
|
|
69
66
|
* on item remove
|
|
70
67
|
*/
|
|
@@ -76,11 +73,11 @@ export interface ArrayInputProps<T extends AnyObject = string> {
|
|
|
76
73
|
/**
|
|
77
74
|
* can remove item
|
|
78
75
|
*/
|
|
79
|
-
canRemove?: (props: {
|
|
76
|
+
canRemove?: false | "newonly" | ((props: {
|
|
80
77
|
item: T;
|
|
81
78
|
index: number;
|
|
82
79
|
lastItem: boolean;
|
|
83
|
-
}) => boolean;
|
|
80
|
+
}) => boolean);
|
|
84
81
|
/**
|
|
85
82
|
* field width
|
|
86
83
|
*/
|
|
@@ -133,4 +130,4 @@ export interface ArrayInputProps<T extends AnyObject = string> {
|
|
|
133
130
|
* @see {@link https://react-hook-form.com/api/usefieldarray} for more details on `useFieldArray`.
|
|
134
131
|
* @see {@link https://react-dnd.github.io/react-dnd/about} for more details on DnD context and sorting.
|
|
135
132
|
*/
|
|
136
|
-
export declare const ArrayInput: <T extends AnyObject = string>({ name, children, addLabel,
|
|
133
|
+
export declare const ArrayInput: <T extends AnyObject = string>({ name, children, addLabel, focusName, buttonPosition, onAdd, onRemove, onBeforeRemove, canRemove, arrayRef, enableSorting, disabled, readOnly, minItems, maxItems, ...rest }: ArrayInputProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type RefProp } from "@react-fabric/core/dist/types/types";
|
|
2
2
|
import { type UploadHandler } from "../hooks/useFileUploader";
|
|
3
|
+
import { AvatarProps } from "@react-fabric/core/dist/types/components/avatar/Avatar";
|
|
3
4
|
export interface Props extends RefProp {
|
|
4
5
|
/**
|
|
5
6
|
* field name
|
|
@@ -17,6 +18,10 @@ export interface Props extends RefProp {
|
|
|
17
18
|
* avatar name
|
|
18
19
|
*/
|
|
19
20
|
avatarName?: string;
|
|
21
|
+
rounded?: boolean;
|
|
22
|
+
variant?: AvatarProps["variant"];
|
|
23
|
+
fallbackIcon?: AvatarProps["fallbackIcon"];
|
|
24
|
+
avatarClassName?: AvatarProps["className"];
|
|
20
25
|
size?: string | number;
|
|
21
26
|
/**
|
|
22
27
|
* upload handler to store file in temp storage
|
|
@@ -43,4 +48,4 @@ export interface Props extends RefProp {
|
|
|
43
48
|
* @param {Props} props - The properties for the AvatarInput component.
|
|
44
49
|
* @returns {JSX.Element} - The rendered AvatarInput component.
|
|
45
50
|
*/
|
|
46
|
-
export declare const AvatarInput: ({ size, avatarName, value, defaultValue, fileUrl, uploadHandler, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
51
|
+
export declare const AvatarInput: ({ size, avatarName, avatarClassName, value, rounded, defaultValue, fallbackIcon, variant, fileUrl, uploadHandler, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -7,6 +7,10 @@ interface Props {
|
|
|
7
7
|
* hidden value will fire change for form update
|
|
8
8
|
*/
|
|
9
9
|
hiddenValue?: AnyObject;
|
|
10
|
+
/**
|
|
11
|
+
* default avatar image
|
|
12
|
+
*/
|
|
13
|
+
defaultValue?: string;
|
|
10
14
|
/**
|
|
11
15
|
* form onChange handler
|
|
12
16
|
*/
|
|
@@ -20,5 +24,5 @@ interface Props {
|
|
|
20
24
|
* @param {Object} props - Component properties.
|
|
21
25
|
* @returns {JSX.Element} The rendered hidden input field and error icon.
|
|
22
26
|
*/
|
|
23
|
-
export declare const HiddenInput: ({ hiddenValue, onChange, invalid, error, value, name, }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
export declare const HiddenInput: ({ hiddenValue, defaultValue, onChange, invalid, error, value, name, }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
24
28
|
export {};
|
|
@@ -7,6 +7,6 @@ import { type SelectProps } from "../types";
|
|
|
7
7
|
* @param {SelectProps<T>} props - The properties for the List component.
|
|
8
8
|
* @returns {JSX.Element} The rendered List component.
|
|
9
9
|
*/
|
|
10
|
-
export declare const List: <T extends AnyObject = string>({ ref, name, value, readOnly, disabled, required, placeholder, autoFocus, options, height, groupProperty, labelProperty, valueProperty, sortProperty, multiple, allowCreate, searchable, createOption, matcher, renderer, onQuery, onChange, onSelect, onEnterPressed, emptyDisplay, invalid, error, allowClear, decorateStart, decorateEnd, "data-inner": isInner, "data-hide-selected": hideSelected, ...rest }: Omit<SelectProps<T>, "defaultOpen" | "hideHandle"> & {
|
|
10
|
+
export declare const List: <T extends AnyObject = string>({ ref, name, value, readOnly, disabled, required, placeholder, autoFocus, options, height, groupProperty, labelProperty, valueProperty, infoProperty, sortProperty, multiple, allowCreate, searchable, createOption, matcher, renderer, onQuery, onChange, onSelect, onEnterPressed, emptyDisplay, invalid, error, allowClear, decorateStart, decorateEnd, "data-inner": isInner, "data-hide-selected": hideSelected, ...rest }: Omit<SelectProps<T>, "defaultOpen" | "hideHandle"> & {
|
|
11
11
|
height?: string | number;
|
|
12
12
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ReactElement, type ReactNode } from "react";
|
|
2
|
-
export declare const Options: ({ ref, style, items, active, className, itemRef, empty, valueProperty, labelProperty, itemProps, children, ...rest }: {
|
|
2
|
+
export declare const Options: ({ ref, style, items, active, className, itemRef, empty, info, valueProperty, labelProperty, itemProps, children, ...rest }: {
|
|
3
3
|
ref: AnyObject;
|
|
4
|
+
info?: AnyObject;
|
|
4
5
|
itemRef: AnyObject;
|
|
5
6
|
style?: AnyObject;
|
|
6
7
|
items: AnyObject[];
|
|
@@ -7,4 +7,4 @@ import { type SelectProps } from "../types";
|
|
|
7
7
|
* @param {SelectProps<T>} props - The properties for the Select component.
|
|
8
8
|
* @returns {JSX.Element} The rendered Select component.
|
|
9
9
|
*/
|
|
10
|
-
export declare const Select: <T extends AnyObject = string>({ ref, name, value, invalid, readOnly, disabled, required, placeholder, autoFocus, error, options, defaultOpen, hideHandle, groupProperty, labelProperty, valueProperty, sortProperty, multiple, searchable, allowCreate, emptyDisplay, createOption, matcher, renderer, onQuery, onChange, onSelect, onEnterPressed, ...rest }: SelectProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare const Select: <T extends AnyObject = string>({ ref, name, value, invalid, readOnly, disabled, required, placeholder, autoFocus, error, options, defaultOpen, hideHandle, groupProperty, labelProperty, valueProperty, sortProperty, infoProperty, multiple, searchable, allowCreate, emptyDisplay, createOption, matcher, renderer, onQuery, onChange, onSelect, onEnterPressed, ...rest }: SelectProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,15 +4,17 @@ interface State {
|
|
|
4
4
|
open: boolean;
|
|
5
5
|
loading: boolean;
|
|
6
6
|
activeIndex: number | null;
|
|
7
|
+
activeItem: AnyObject;
|
|
7
8
|
selectedIndex: number | null;
|
|
8
9
|
value: AnyObject;
|
|
9
10
|
query?: string;
|
|
10
11
|
items: AnyObject[];
|
|
11
12
|
}
|
|
12
|
-
export declare const useSelect: ({ options, value,
|
|
13
|
+
export declare const useSelect: ({ options, value, autoComplete, alwaysOpen, defaultOpen, multiple, allowCreate, groupProperty, valueProperty, labelProperty, sortProperty, createOption, matcher, onQuery, onChange, onSelect, }: {
|
|
13
14
|
value?: AnyObject;
|
|
14
15
|
options?: AnyObject[];
|
|
15
16
|
multiple?: boolean;
|
|
17
|
+
alwaysOpen?: boolean;
|
|
16
18
|
defaultOpen?: boolean;
|
|
17
19
|
allowCreate?: boolean;
|
|
18
20
|
groupProperty?: AnyObject;
|
|
@@ -29,6 +31,7 @@ export declare const useSelect: ({ options, value, defaultOpen, autoComplete, mu
|
|
|
29
31
|
state: State | {
|
|
30
32
|
value: any;
|
|
31
33
|
activeIndex: null;
|
|
34
|
+
activeItem: null;
|
|
32
35
|
selectedIndex: any;
|
|
33
36
|
multiple: boolean;
|
|
34
37
|
emptyValue: AnyObject;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-fabric/form",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.58",
|
|
4
4
|
"description": "RUF: Form package",
|
|
5
5
|
"author": "Adarsh Pastakia <adarshpastakia@outlook.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,33 +35,32 @@
|
|
|
35
35
|
"watch": "npm-run-all -p watch:rollup watch:dts"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@dnd-kit/core": "
|
|
39
|
-
"@dnd-kit/modifiers": "
|
|
40
|
-
"@dnd-kit/sortable": "
|
|
41
|
-
"@dnd-kit/utilities": "
|
|
42
|
-
"@floating-ui/react": "
|
|
43
|
-
"@hookform/resolvers": "
|
|
44
|
-
"@react-fabric/core": "^1.0.0-beta.
|
|
45
|
-
"@react-fabric/date": "^1.0.0-beta.
|
|
46
|
-
"@react-fabric/utilities": "^1.0.0-beta.
|
|
47
|
-
"classnames": "
|
|
48
|
-
"color": "
|
|
49
|
-
"react-color": "
|
|
50
|
-
"react-hook-form": "
|
|
38
|
+
"@dnd-kit/core": "~6.3.1",
|
|
39
|
+
"@dnd-kit/modifiers": "~9.0.0",
|
|
40
|
+
"@dnd-kit/sortable": "~10.0.0",
|
|
41
|
+
"@dnd-kit/utilities": "~3.2.2",
|
|
42
|
+
"@floating-ui/react": "~0.27.16",
|
|
43
|
+
"@hookform/resolvers": "~5.2.2",
|
|
44
|
+
"@react-fabric/core": "^1.0.0-beta.58",
|
|
45
|
+
"@react-fabric/date": "^1.0.0-beta.58",
|
|
46
|
+
"@react-fabric/utilities": "^1.0.0-beta.58",
|
|
47
|
+
"classnames": "~2.5.1",
|
|
48
|
+
"color": "~5.0.2",
|
|
49
|
+
"react-color": "~2.19.3",
|
|
50
|
+
"react-hook-form": "~7.65.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"i18next": "
|
|
54
|
-
"react": "
|
|
55
|
-
"react-dom": "
|
|
56
|
-
"react-i18next": "
|
|
53
|
+
"i18next": "~25.6.0",
|
|
54
|
+
"react": "~19.2.0",
|
|
55
|
+
"react-dom": "~19.2.0",
|
|
56
|
+
"react-i18next": "~16.2.1"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@types/
|
|
60
|
-
"@types/react-color": "^3.0.12"
|
|
59
|
+
"@types/react-color": "~3.0.13"
|
|
61
60
|
},
|
|
62
61
|
"engines": {
|
|
63
62
|
"node": ">=18.12.0",
|
|
64
63
|
"npm": ">=8.19.0"
|
|
65
64
|
},
|
|
66
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "7e66f8c498e37a40e410ecafff2ea6b31505dc1a"
|
|
67
66
|
}
|
package/src/form/Form.tsx
CHANGED
|
@@ -29,13 +29,16 @@ import {
|
|
|
29
29
|
useEffect,
|
|
30
30
|
useImperativeHandle,
|
|
31
31
|
useRef,
|
|
32
|
+
useState,
|
|
32
33
|
useTransition,
|
|
33
34
|
type PropsWithChildren,
|
|
34
35
|
type Ref,
|
|
35
36
|
} from "react";
|
|
36
37
|
import {
|
|
37
38
|
FormProvider,
|
|
38
|
-
|
|
39
|
+
useFormContext,
|
|
40
|
+
useForm as useFormHook,
|
|
41
|
+
useWatch,
|
|
39
42
|
type DefaultValues,
|
|
40
43
|
type FormState,
|
|
41
44
|
} from "react-hook-form";
|
|
@@ -120,7 +123,7 @@ export const Form = <K extends KeyValue>({
|
|
|
120
123
|
...rest
|
|
121
124
|
}: PropsWithChildren<FormProps<K>>) => {
|
|
122
125
|
const ref = useRef<HTMLFormElement>(null);
|
|
123
|
-
const form =
|
|
126
|
+
const form = useFormHook<K>({
|
|
124
127
|
shouldFocusError: true,
|
|
125
128
|
resolver: schema && (yupResolver(schema) as AnyObject),
|
|
126
129
|
defaultValues: defaultValues as DefaultValues<K>,
|
|
@@ -202,3 +205,32 @@ export const Form = <K extends KeyValue>({
|
|
|
202
205
|
</FormProvider>
|
|
203
206
|
);
|
|
204
207
|
};
|
|
208
|
+
|
|
209
|
+
export const useForm = <K extends KeyValue = KeyValue>() => {
|
|
210
|
+
const {
|
|
211
|
+
formState,
|
|
212
|
+
getValues,
|
|
213
|
+
setValue,
|
|
214
|
+
watch,
|
|
215
|
+
reset,
|
|
216
|
+
resetField,
|
|
217
|
+
setError,
|
|
218
|
+
setFocus,
|
|
219
|
+
} = useFormContext<K>();
|
|
220
|
+
const values = useWatch<K>();
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
values: {
|
|
224
|
+
...values,
|
|
225
|
+
...getValues(),
|
|
226
|
+
},
|
|
227
|
+
formState,
|
|
228
|
+
getValues,
|
|
229
|
+
setValue,
|
|
230
|
+
watch,
|
|
231
|
+
reset,
|
|
232
|
+
resetField,
|
|
233
|
+
setError,
|
|
234
|
+
setFocus,
|
|
235
|
+
};
|
|
236
|
+
};
|
package/src/index.ts
CHANGED
package/src/input/ArrayInput.tsx
CHANGED
|
@@ -34,9 +34,12 @@ import { isFalse, isString } from "@react-fabric/utilities";
|
|
|
34
34
|
import classNames from "classnames";
|
|
35
35
|
import {
|
|
36
36
|
cloneElement,
|
|
37
|
+
use,
|
|
37
38
|
useCallback,
|
|
39
|
+
useEffect,
|
|
38
40
|
useImperativeHandle,
|
|
39
41
|
useMemo,
|
|
42
|
+
useState,
|
|
40
43
|
type PropsWithChildren,
|
|
41
44
|
type ReactNode,
|
|
42
45
|
type Ref,
|
|
@@ -96,16 +99,12 @@ export interface ArrayInputProps<T extends AnyObject = string> {
|
|
|
96
99
|
enableSorting?: boolean;
|
|
97
100
|
children:
|
|
98
101
|
| React.ReactNode
|
|
99
|
-
| ((props: { index: number; name: string }) => ReactNode);
|
|
102
|
+
| ((props: { index: number; name: string; item: T }) => ReactNode);
|
|
100
103
|
/**
|
|
101
104
|
* add item button label
|
|
102
105
|
*/
|
|
103
106
|
addLabel?: string;
|
|
104
107
|
buttonPosition?: "top" | "bottom" | "both";
|
|
105
|
-
/**
|
|
106
|
-
* fixed length list
|
|
107
|
-
*/
|
|
108
|
-
fixedList?: boolean;
|
|
109
108
|
arrayRef?: Ref<{
|
|
110
109
|
addItem: (item: T) => void;
|
|
111
110
|
removeItem: (idx: number) => void;
|
|
@@ -113,7 +112,7 @@ export interface ArrayInputProps<T extends AnyObject = string> {
|
|
|
113
112
|
/**
|
|
114
113
|
* add new item
|
|
115
114
|
*/
|
|
116
|
-
onAdd?: () =>
|
|
115
|
+
onAdd?: () => T;
|
|
117
116
|
/**
|
|
118
117
|
* on item remove
|
|
119
118
|
*/
|
|
@@ -125,7 +124,10 @@ export interface ArrayInputProps<T extends AnyObject = string> {
|
|
|
125
124
|
/**
|
|
126
125
|
* can remove item
|
|
127
126
|
*/
|
|
128
|
-
canRemove?:
|
|
127
|
+
canRemove?:
|
|
128
|
+
| false
|
|
129
|
+
| "newonly"
|
|
130
|
+
| ((props: { item: T; index: number; lastItem: boolean }) => boolean);
|
|
129
131
|
|
|
130
132
|
/**
|
|
131
133
|
* field width
|
|
@@ -184,7 +186,6 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
184
186
|
name,
|
|
185
187
|
children,
|
|
186
188
|
addLabel,
|
|
187
|
-
fixedList,
|
|
188
189
|
focusName = "",
|
|
189
190
|
buttonPosition = "bottom",
|
|
190
191
|
onAdd,
|
|
@@ -211,6 +212,11 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
211
212
|
control: form.control,
|
|
212
213
|
});
|
|
213
214
|
|
|
215
|
+
const [initialList, setInitialList] = useState<string[]>([]);
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
setInitialList(fields.map((f) => f.__ID__));
|
|
218
|
+
}, []);
|
|
219
|
+
|
|
214
220
|
const error = useMemo<AnyObject>(
|
|
215
221
|
() =>
|
|
216
222
|
form.formState.errors[name]?.message ??
|
|
@@ -218,8 +224,27 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
218
224
|
[form.formState.errors],
|
|
219
225
|
);
|
|
220
226
|
|
|
227
|
+
const removeCheck = useCallback(
|
|
228
|
+
(item: T, index: number) => {
|
|
229
|
+
if (canRemove === false) return false;
|
|
230
|
+
if (canRemove === "newonly") {
|
|
231
|
+
return initialList.includes((item as any).__ID__) ? false : true;
|
|
232
|
+
}
|
|
233
|
+
if (typeof canRemove === "function") {
|
|
234
|
+
return canRemove({
|
|
235
|
+
item,
|
|
236
|
+
index,
|
|
237
|
+
lastItem: index + 1 === fields.length,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
return true;
|
|
241
|
+
},
|
|
242
|
+
[canRemove, initialList, fields],
|
|
243
|
+
);
|
|
244
|
+
|
|
221
245
|
const handleAdd = useCallback(
|
|
222
|
-
(item
|
|
246
|
+
(item?: T) => {
|
|
247
|
+
if (!item) return;
|
|
223
248
|
append(item);
|
|
224
249
|
setTimeout(() => {
|
|
225
250
|
form.setFocus(
|
|
@@ -349,14 +374,26 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
349
374
|
onClick={() => handleAdd(onAdd?.())}
|
|
350
375
|
data-invalid={!!error}
|
|
351
376
|
disabled={!!disabled || readOnly || fields.length > maxItems}
|
|
352
|
-
className={classNames(
|
|
377
|
+
className={classNames(
|
|
378
|
+
"fabric-addButton",
|
|
379
|
+
canRemove !== false && "me-10",
|
|
380
|
+
)}
|
|
353
381
|
>
|
|
354
|
-
{addLabel ?? t("addArray")}
|
|
382
|
+
{addLabel ?? t("form:addArray")}
|
|
355
383
|
</Button>
|
|
356
384
|
</Tooltip>
|
|
357
385
|
</div>
|
|
358
386
|
),
|
|
359
|
-
[
|
|
387
|
+
[
|
|
388
|
+
error,
|
|
389
|
+
fields,
|
|
390
|
+
handleAdd,
|
|
391
|
+
canRemove,
|
|
392
|
+
disabled,
|
|
393
|
+
readOnly,
|
|
394
|
+
addLabel,
|
|
395
|
+
maxItems,
|
|
396
|
+
],
|
|
360
397
|
);
|
|
361
398
|
|
|
362
399
|
return (
|
|
@@ -365,7 +402,7 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
365
402
|
{...rest}
|
|
366
403
|
appendLabel={
|
|
367
404
|
<div className="-me-2">
|
|
368
|
-
{
|
|
405
|
+
{onAdd && buttonPosition !== "bottom" && addButton}
|
|
369
406
|
</div>
|
|
370
407
|
}
|
|
371
408
|
>
|
|
@@ -379,6 +416,7 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
379
416
|
{typeof children === "function"
|
|
380
417
|
? children({
|
|
381
418
|
index,
|
|
419
|
+
item: item as any,
|
|
382
420
|
name: `${name}.${index}`,
|
|
383
421
|
})
|
|
384
422
|
: cloneChildren(children, (child: AnyObject) =>
|
|
@@ -403,7 +441,7 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
403
441
|
),
|
|
404
442
|
),
|
|
405
443
|
)}
|
|
406
|
-
{
|
|
444
|
+
{canRemove !== false && (
|
|
407
445
|
<Button
|
|
408
446
|
aria-label="Remove item"
|
|
409
447
|
icon={CoreIcons.remove}
|
|
@@ -414,20 +452,16 @@ export const ArrayInput = <T extends AnyObject = string>({
|
|
|
414
452
|
disabled ||
|
|
415
453
|
readOnly ||
|
|
416
454
|
fields.length <= minItems ||
|
|
417
|
-
|
|
418
|
-
item: item as T,
|
|
419
|
-
index,
|
|
420
|
-
lastItem: index + 1 === fields.length,
|
|
421
|
-
}) !== false
|
|
455
|
+
removeCheck(item as any, index) === false
|
|
422
456
|
}
|
|
423
|
-
onClick={() => handleRemove(item as
|
|
457
|
+
onClick={() => handleRemove(item as any, index)}
|
|
424
458
|
/>
|
|
425
459
|
)}
|
|
426
460
|
</SortableItem>
|
|
427
461
|
))}
|
|
428
462
|
</Wrapper>
|
|
429
463
|
</FieldWrapper>
|
|
430
|
-
{
|
|
464
|
+
{onAdd && buttonPosition !== "top" && addButton}
|
|
431
465
|
</div>
|
|
432
466
|
);
|
|
433
467
|
};
|
|
@@ -26,6 +26,8 @@ import { type RefProp } from "@react-fabric/core/dist/types/types";
|
|
|
26
26
|
import { useEffect, useState } from "react";
|
|
27
27
|
import { useFileUploader, type UploadHandler } from "../hooks/useFileUploader";
|
|
28
28
|
import { HiddenInput } from "./Hidden";
|
|
29
|
+
import { AvatarProps } from "@react-fabric/core/dist/types/components/avatar/Avatar";
|
|
30
|
+
import classNames from "classnames";
|
|
29
31
|
|
|
30
32
|
export interface Props extends RefProp {
|
|
31
33
|
/**
|
|
@@ -44,6 +46,10 @@ export interface Props extends RefProp {
|
|
|
44
46
|
* avatar name
|
|
45
47
|
*/
|
|
46
48
|
avatarName?: string;
|
|
49
|
+
rounded?: boolean;
|
|
50
|
+
variant?: AvatarProps["variant"];
|
|
51
|
+
fallbackIcon?: AvatarProps["fallbackIcon"];
|
|
52
|
+
avatarClassName?: AvatarProps["className"];
|
|
47
53
|
size?: string | number;
|
|
48
54
|
/**
|
|
49
55
|
* upload handler to store file in temp storage
|
|
@@ -74,8 +80,12 @@ export interface Props extends RefProp {
|
|
|
74
80
|
export const AvatarInput = ({
|
|
75
81
|
size = "6rem",
|
|
76
82
|
avatarName,
|
|
83
|
+
avatarClassName,
|
|
77
84
|
value,
|
|
85
|
+
rounded,
|
|
78
86
|
defaultValue,
|
|
87
|
+
fallbackIcon,
|
|
88
|
+
variant,
|
|
79
89
|
fileUrl,
|
|
80
90
|
uploadHandler,
|
|
81
91
|
...rest
|
|
@@ -117,9 +127,23 @@ export const AvatarInput = ({
|
|
|
117
127
|
|
|
118
128
|
return (
|
|
119
129
|
<div className="flex flex-nowrap items-end overflow-hidden">
|
|
120
|
-
<div
|
|
121
|
-
|
|
122
|
-
|
|
130
|
+
<div
|
|
131
|
+
className={classNames(
|
|
132
|
+
"inline-block leading-none relative outline overflow-hidden",
|
|
133
|
+
rounded && "rounded-full",
|
|
134
|
+
!rounded && "rounded",
|
|
135
|
+
)}
|
|
136
|
+
>
|
|
137
|
+
<Avatar
|
|
138
|
+
name={avatarName ?? "temp"}
|
|
139
|
+
size={size}
|
|
140
|
+
avatar={base64}
|
|
141
|
+
rounded={rounded}
|
|
142
|
+
variant={variant}
|
|
143
|
+
fallbackIcon={fallbackIcon}
|
|
144
|
+
className={avatarClassName}
|
|
145
|
+
/>
|
|
146
|
+
<div className="absolute inset-x-0 bottom-0 cursor-pointer opacity-50 bg-black/50 hover:opacity-90 text-white text-xs text-center py-1">
|
|
123
147
|
<span>Edit</span>
|
|
124
148
|
<input
|
|
125
149
|
type="file"
|
|
@@ -129,11 +153,14 @@ export const AvatarInput = ({
|
|
|
129
153
|
/>
|
|
130
154
|
</div>
|
|
131
155
|
</div>
|
|
132
|
-
<HiddenInput
|
|
156
|
+
<HiddenInput
|
|
157
|
+
hiddenValue={list?.[0]?.path}
|
|
158
|
+
defaultValue={defaultValue}
|
|
159
|
+
{...rest}
|
|
160
|
+
/>
|
|
133
161
|
{files.map((file, idx) => (
|
|
134
162
|
<div key={idx} className="px-2 py-1 flex-1 overflow-hidden">
|
|
135
163
|
<div className="flex flex-nowrap gap-1 items-center">
|
|
136
|
-
<div className="flex-initial truncate pe-2">{file.filename}</div>
|
|
137
164
|
{file.error && (
|
|
138
165
|
<div className="flex-1 truncate px-2">
|
|
139
166
|
<span className="text-danger-600">{file.error}</span>
|
package/src/input/ColorInput.tsx
CHANGED
package/src/input/Hidden.tsx
CHANGED
|
@@ -33,6 +33,10 @@ interface Props {
|
|
|
33
33
|
* hidden value will fire change for form update
|
|
34
34
|
*/
|
|
35
35
|
hiddenValue?: AnyObject;
|
|
36
|
+
/**
|
|
37
|
+
* default avatar image
|
|
38
|
+
*/
|
|
39
|
+
defaultValue?: string;
|
|
36
40
|
/**
|
|
37
41
|
* form onChange handler
|
|
38
42
|
*/
|
|
@@ -49,6 +53,7 @@ interface Props {
|
|
|
49
53
|
*/
|
|
50
54
|
export const HiddenInput = ({
|
|
51
55
|
hiddenValue,
|
|
56
|
+
defaultValue,
|
|
52
57
|
onChange,
|
|
53
58
|
// @ts-expect-error ignore
|
|
54
59
|
// eslint-disable-next-line react/prop-types
|
|
@@ -62,11 +67,10 @@ export const HiddenInput = ({
|
|
|
62
67
|
name,
|
|
63
68
|
}: Props) => {
|
|
64
69
|
useEffect(() => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}, [hiddenValue]);
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
onChange?.(hiddenValue ?? defaultValue);
|
|
72
|
+
}, 50);
|
|
73
|
+
}, [hiddenValue, defaultValue]);
|
|
70
74
|
return (
|
|
71
75
|
<Fragment>
|
|
72
76
|
<input type="hidden" onChange={onChange} value={value} name={name} />
|
package/src/input/Slider.tsx
CHANGED
|
@@ -214,8 +214,8 @@ export const Slider = ({
|
|
|
214
214
|
<div
|
|
215
215
|
ref={rangerInstance.trackElRef}
|
|
216
216
|
className={classNames(
|
|
217
|
-
"
|
|
218
|
-
vertical ? "my-2 w-8" : "mx-2 h-8",
|
|
217
|
+
"relative flex items-center",
|
|
218
|
+
vertical ? "my-2 w-8" : "flex-1 mx-2 h-8",
|
|
219
219
|
)}
|
|
220
220
|
style={{ height: vertical ? height : undefined }}
|
|
221
221
|
>
|
|
@@ -262,10 +262,10 @@ export const Slider = ({
|
|
|
262
262
|
{displayValue && (
|
|
263
263
|
<div
|
|
264
264
|
className={classNames(
|
|
265
|
-
"bg-invert text-invert py-px px-2 text-xs absolute rounded z-[5] whitespace-nowrap",
|
|
265
|
+
"bg-invert text-invert py-px px-2 text-xs absolute rounded z-[5] whitespace-nowrap pointer-events-none",
|
|
266
266
|
"before:absolute before:h-1.5 before:w-1.5 before:z-[-1] before:bg-invert before:top-1/2 before:-translate-y-1/2 before:rotate-45",
|
|
267
267
|
vertical
|
|
268
|
-
? "end-0 ltr:translate-x-full rtl:-translate-x-full translate-y-2"
|
|
268
|
+
? "end-0 ltr:translate-x-full rtl:-translate-x-full translate-y-2 ltr:before:-translate-x-[0.125rem] rtl:before:translate-x-[0.125rem] before:start-0"
|
|
269
269
|
: "top-1/2 -translate-y-1/2",
|
|
270
270
|
!vertical &&
|
|
271
271
|
(percentage > 50
|
package/src/input/Textarea.tsx
CHANGED
|
@@ -131,7 +131,7 @@ export const Textarea = ({
|
|
|
131
131
|
{...rest}
|
|
132
132
|
>
|
|
133
133
|
<textarea
|
|
134
|
-
className="appearance-none self-stretch bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0 min-h-
|
|
134
|
+
className="appearance-none self-stretch bg-transparent py-1 px-2 flex-1 border-none outline-none ring-0 min-h-12 resize-none"
|
|
135
135
|
aria-invalid={invalid}
|
|
136
136
|
aria-disabled={disabled}
|
|
137
137
|
aria-readonly={readOnly}
|