@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/ArrayInput.tsx
CHANGED
|
@@ -23,27 +23,32 @@
|
|
|
23
23
|
|
|
24
24
|
import { DndContext, type DragEndEvent } from "@dnd-kit/core";
|
|
25
25
|
import { SortableContext, useSortable } from "@dnd-kit/sortable";
|
|
26
|
-
import {
|
|
27
|
-
|
|
26
|
+
import {
|
|
27
|
+
Button,
|
|
28
|
+
cloneChildren,
|
|
29
|
+
CoreIcons,
|
|
30
|
+
Icon,
|
|
31
|
+
Tooltip,
|
|
32
|
+
} from "@react-fabric/core";
|
|
33
|
+
import { isFalse, 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";
|
|
46
|
-
|
|
50
|
+
|
|
51
|
+
export interface ArrayInputProps<T extends AnyObject = string> {
|
|
47
52
|
/**
|
|
48
53
|
* input label
|
|
49
54
|
*/
|
|
@@ -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,34 +101,65 @@ 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?:
|
|
100
|
-
addItem: (item:
|
|
109
|
+
arrayRef?: Ref<{
|
|
110
|
+
addItem: (item: T) => void;
|
|
101
111
|
removeItem: (idx: number) => void;
|
|
102
112
|
}>;
|
|
103
113
|
/**
|
|
104
|
-
*
|
|
114
|
+
* add new item
|
|
105
115
|
*/
|
|
106
116
|
onAdd?: () => AnyObject;
|
|
117
|
+
/**
|
|
118
|
+
* on item remove
|
|
119
|
+
*/
|
|
120
|
+
onRemove?: (item: T, idx: number) => void;
|
|
121
|
+
/**
|
|
122
|
+
* before item remove
|
|
123
|
+
*/
|
|
124
|
+
onBeforeRemove?: (item: T, idx: number) => Promise<boolean> | boolean;
|
|
125
|
+
/**
|
|
126
|
+
* can remove item
|
|
127
|
+
*/
|
|
128
|
+
canRemove?: (props: { item: T; index: number; lastItem: boolean }) => boolean;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* field width
|
|
132
|
+
*/
|
|
133
|
+
width?: number | string;
|
|
134
|
+
/**
|
|
135
|
+
* inline label and input
|
|
136
|
+
*/
|
|
137
|
+
inline?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* label width for inline
|
|
140
|
+
*/
|
|
141
|
+
labelWidth?: string;
|
|
107
142
|
}
|
|
108
143
|
|
|
109
|
-
export const ArrayInput = ({
|
|
144
|
+
export const ArrayInput = <T extends AnyObject = string>({
|
|
110
145
|
name,
|
|
111
146
|
children,
|
|
112
147
|
addLabel,
|
|
113
148
|
fixedList,
|
|
114
149
|
focusName = "",
|
|
150
|
+
buttonPosition = "bottom",
|
|
115
151
|
onAdd,
|
|
152
|
+
onRemove,
|
|
153
|
+
onBeforeRemove,
|
|
154
|
+
canRemove,
|
|
116
155
|
arrayRef,
|
|
117
156
|
enableSorting,
|
|
118
157
|
disabled = false,
|
|
119
158
|
readOnly = false,
|
|
120
159
|
minItems = 0,
|
|
160
|
+
maxItems = Number.MAX_SAFE_INTEGER,
|
|
121
161
|
...rest
|
|
122
|
-
}: ArrayInputProps) => {
|
|
162
|
+
}: ArrayInputProps<T>) => {
|
|
123
163
|
const { t } = useTranslation("form");
|
|
124
164
|
const form = useFormContext();
|
|
125
165
|
|
|
@@ -128,6 +168,7 @@ export const ArrayInput = ({
|
|
|
128
168
|
|
|
129
169
|
const { fields, append, remove, move } = useFieldArray({
|
|
130
170
|
name,
|
|
171
|
+
keyName: "__ID__",
|
|
131
172
|
control: form.control,
|
|
132
173
|
});
|
|
133
174
|
|
|
@@ -139,7 +180,7 @@ export const ArrayInput = ({
|
|
|
139
180
|
);
|
|
140
181
|
|
|
141
182
|
const handleAdd = useCallback(
|
|
142
|
-
(item:
|
|
183
|
+
(item: T) => {
|
|
143
184
|
append(item);
|
|
144
185
|
setTimeout(() => {
|
|
145
186
|
form.setFocus(
|
|
@@ -150,6 +191,19 @@ export const ArrayInput = ({
|
|
|
150
191
|
[name, fields, focusName],
|
|
151
192
|
);
|
|
152
193
|
|
|
194
|
+
const handleRemove = useCallback(
|
|
195
|
+
(item: T, index: number) => {
|
|
196
|
+
const ret = onBeforeRemove?.(item, index);
|
|
197
|
+
void Promise.resolve(ret).then((b) => {
|
|
198
|
+
if (!isFalse(b)) {
|
|
199
|
+
remove(index);
|
|
200
|
+
onRemove?.(item, index);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
},
|
|
204
|
+
[remove, onRemove, onBeforeRemove],
|
|
205
|
+
);
|
|
206
|
+
|
|
153
207
|
useImperativeHandle(arrayRef, () => ({
|
|
154
208
|
addItem: handleAdd,
|
|
155
209
|
removeItem: remove,
|
|
@@ -159,7 +213,7 @@ export const ArrayInput = ({
|
|
|
159
213
|
({ children }: PropsWithChildren) => {
|
|
160
214
|
if (enableSorting) {
|
|
161
215
|
// pass id list to dnd context
|
|
162
|
-
const idMap = fields.map((item) => item.
|
|
216
|
+
const idMap = fields.map((item) => item.__ID__);
|
|
163
217
|
const handleDragEnd = (e: DragEndEvent) => {
|
|
164
218
|
if (e.over && e.active.id !== e.over.id) {
|
|
165
219
|
// find index of item and drop over
|
|
@@ -227,14 +281,60 @@ export const ArrayInput = ({
|
|
|
227
281
|
// @ts-expect-error ignore
|
|
228
282
|
SortableItem.displayName = "SortableItem";
|
|
229
283
|
|
|
284
|
+
const addButton = useMemo(
|
|
285
|
+
() => (
|
|
286
|
+
<div className="flex justify-end">
|
|
287
|
+
<Tooltip
|
|
288
|
+
color="danger-200"
|
|
289
|
+
content={
|
|
290
|
+
isString(error)
|
|
291
|
+
? `${error}`
|
|
292
|
+
: (t(
|
|
293
|
+
error?.key,
|
|
294
|
+
error?.values
|
|
295
|
+
? {
|
|
296
|
+
...error?.values,
|
|
297
|
+
label: t(
|
|
298
|
+
error.values?.label ?? "form:badkey",
|
|
299
|
+
error.values?.path,
|
|
300
|
+
),
|
|
301
|
+
}
|
|
302
|
+
: {},
|
|
303
|
+
) as string)
|
|
304
|
+
}
|
|
305
|
+
>
|
|
306
|
+
<Button
|
|
307
|
+
size="sm"
|
|
308
|
+
aria-label="Add item"
|
|
309
|
+
icon={CoreIcons.insert}
|
|
310
|
+
onClick={() => handleAdd(onAdd?.())}
|
|
311
|
+
data-invalid={!!error}
|
|
312
|
+
disabled={!!disabled || readOnly || fields.length > maxItems}
|
|
313
|
+
className={classNames("fabric-addButton", "me-10")}
|
|
314
|
+
>
|
|
315
|
+
{addLabel ?? t("addArray")}
|
|
316
|
+
</Button>
|
|
317
|
+
</Tooltip>
|
|
318
|
+
</div>
|
|
319
|
+
),
|
|
320
|
+
[error, fields, handleAdd, disabled, readOnly, addLabel, maxItems],
|
|
321
|
+
);
|
|
322
|
+
|
|
230
323
|
return (
|
|
231
|
-
<div className={
|
|
232
|
-
<FieldWrapper
|
|
324
|
+
<div className={"fabric-arrayInput"}>
|
|
325
|
+
<FieldWrapper
|
|
326
|
+
{...rest}
|
|
327
|
+
appendLabel={
|
|
328
|
+
<div className="-me-2">
|
|
329
|
+
{!fixedList && onAdd && buttonPosition !== "bottom" && addButton}
|
|
330
|
+
</div>
|
|
331
|
+
}
|
|
332
|
+
>
|
|
233
333
|
<Wrapper>
|
|
234
334
|
{fields.map((item, index) => (
|
|
235
335
|
<SortableItem
|
|
236
|
-
key={item.
|
|
237
|
-
id={item.
|
|
336
|
+
key={item.__ID__}
|
|
337
|
+
id={item.__ID__}
|
|
238
338
|
className="flex items-center flex-nowrap gap-2 mb-1"
|
|
239
339
|
>
|
|
240
340
|
{typeof children === "function"
|
|
@@ -242,7 +342,7 @@ export const ArrayInput = ({
|
|
|
242
342
|
index,
|
|
243
343
|
name: `${name}.${index}`,
|
|
244
344
|
})
|
|
245
|
-
:
|
|
345
|
+
: cloneChildren(children, (child: AnyObject) =>
|
|
246
346
|
cloneElement(
|
|
247
347
|
child,
|
|
248
348
|
Object.assign(
|
|
@@ -271,48 +371,24 @@ export const ArrayInput = ({
|
|
|
271
371
|
color="danger"
|
|
272
372
|
variant="link"
|
|
273
373
|
className="self-end"
|
|
274
|
-
disabled={
|
|
275
|
-
|
|
374
|
+
disabled={
|
|
375
|
+
disabled ||
|
|
376
|
+
readOnly ||
|
|
377
|
+
fields.length <= minItems ||
|
|
378
|
+
canRemove?.({
|
|
379
|
+
item: item as T,
|
|
380
|
+
index,
|
|
381
|
+
lastItem: index + 1 === fields.length,
|
|
382
|
+
}) !== false
|
|
383
|
+
}
|
|
384
|
+
onClick={() => handleRemove(item as T, index)}
|
|
276
385
|
/>
|
|
277
386
|
)}
|
|
278
387
|
</SortableItem>
|
|
279
388
|
))}
|
|
280
389
|
</Wrapper>
|
|
281
390
|
</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
|
-
)}
|
|
391
|
+
{!fixedList && onAdd && buttonPosition !== "top" && addButton}
|
|
316
392
|
</div>
|
|
317
393
|
);
|
|
318
394
|
};
|
|
@@ -37,14 +37,17 @@ export interface Props extends RefProp {
|
|
|
37
37
|
*/
|
|
38
38
|
value?: string;
|
|
39
39
|
/**
|
|
40
|
-
* avatar
|
|
40
|
+
* avatar name
|
|
41
41
|
*/
|
|
42
|
-
|
|
42
|
+
avatarName?: string;
|
|
43
43
|
size?: string | number;
|
|
44
44
|
/**
|
|
45
45
|
* upload handler to store file in temp storage
|
|
46
46
|
*/
|
|
47
47
|
uploadHandler: UploadHandler;
|
|
48
|
+
/**
|
|
49
|
+
* file stream path
|
|
50
|
+
*/
|
|
48
51
|
fileUrl?: (path: string) => string;
|
|
49
52
|
/**
|
|
50
53
|
* change handler
|
|
@@ -57,15 +60,16 @@ export interface Props extends RefProp {
|
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
export const AvatarInput = ({
|
|
60
|
-
src,
|
|
61
63
|
size = "6rem",
|
|
64
|
+
avatarName,
|
|
65
|
+
value,
|
|
62
66
|
fileUrl,
|
|
63
67
|
uploadHandler,
|
|
64
68
|
...rest
|
|
65
69
|
}: Props) => {
|
|
66
70
|
const { files, list, upload, remove } = useFileUploader(
|
|
67
71
|
async (data, config) => await uploadHandler?.(data, config),
|
|
68
|
-
|
|
72
|
+
value,
|
|
69
73
|
false,
|
|
70
74
|
);
|
|
71
75
|
|
|
@@ -92,14 +96,14 @@ export const AvatarInput = ({
|
|
|
92
96
|
}, [files, list]);
|
|
93
97
|
|
|
94
98
|
useEffect(() => {
|
|
95
|
-
|
|
96
|
-
}, [
|
|
99
|
+
value && setBase64(fileUrl?.(value) ?? value);
|
|
100
|
+
}, [value]);
|
|
97
101
|
|
|
98
102
|
return (
|
|
99
103
|
<div className="flex flex-nowrap items-end">
|
|
100
104
|
<div className="inline-block leading-none rounded-full relative outline overflow-hidden">
|
|
101
|
-
<Avatar name="temp" size={size} avatar={base64} />
|
|
102
|
-
<div className="absolute inset-x-0 bottom-0 cursor-pointer bg-
|
|
105
|
+
<Avatar name={avatarName ?? "temp"} size={size} avatar={base64} />
|
|
106
|
+
<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
107
|
<span>Edit</span>
|
|
104
108
|
<input
|
|
105
109
|
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"}
|
|
@@ -158,7 +159,7 @@ export const Checkbox = ({
|
|
|
158
159
|
/>
|
|
159
160
|
<ErrorIcon invalid={invalid} error={error} />
|
|
160
161
|
{label && (
|
|
161
|
-
<span className="flex-initial leading-
|
|
162
|
+
<span className="flex-initial leading-tight truncate">{label}</span>
|
|
162
163
|
)}
|
|
163
164
|
</label>
|
|
164
165
|
);
|
package/src/input/ColorInput.tsx
CHANGED
|
@@ -21,21 +21,36 @@
|
|
|
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
|
-
import { isString } from "@react-fabric/utilities";
|
|
27
|
-
import classNames from "classnames";
|
|
28
38
|
import {
|
|
29
39
|
startTransition,
|
|
30
40
|
useCallback,
|
|
31
41
|
useDeferredValue,
|
|
32
42
|
useEffect,
|
|
43
|
+
useRef,
|
|
33
44
|
useState,
|
|
34
45
|
} from "react";
|
|
46
|
+
import { InputWrapper } from "../internal/InputWrapper";
|
|
35
47
|
import { type InputProps } from "../types";
|
|
36
48
|
import { ColorPicker, type ColorProps } from "./ColorPicker";
|
|
37
49
|
|
|
38
|
-
export interface ColorInputProps
|
|
50
|
+
export interface ColorInputProps
|
|
51
|
+
extends InputProps,
|
|
52
|
+
Omit<ColorProps, "onChange">,
|
|
53
|
+
RefProp {
|
|
39
54
|
/**
|
|
40
55
|
* show eydrop picker
|
|
41
56
|
*/
|
|
@@ -46,14 +61,14 @@ export const ColorInput = ({
|
|
|
46
61
|
ref,
|
|
47
62
|
required,
|
|
48
63
|
disabled,
|
|
49
|
-
|
|
64
|
+
readOnly,
|
|
50
65
|
invalid,
|
|
51
66
|
error,
|
|
52
67
|
value,
|
|
53
68
|
showPicker,
|
|
54
69
|
defaultColor = "",
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
onBlur,
|
|
71
|
+
onFocus,
|
|
57
72
|
onChange,
|
|
58
73
|
// @ts-expect-error ignore
|
|
59
74
|
noOutline,
|
|
@@ -69,59 +84,107 @@ export const ColorInput = ({
|
|
|
69
84
|
const handleChange = useCallback(
|
|
70
85
|
(e?: string) => {
|
|
71
86
|
setActualValue(e ?? defaultColor);
|
|
72
|
-
onChange != null && startTransition(() => onChange(e));
|
|
87
|
+
onChange != null && startTransition(() => onChange(e ?? null));
|
|
73
88
|
},
|
|
74
89
|
[onChange],
|
|
75
90
|
);
|
|
76
91
|
|
|
92
|
+
const arrowRef = useRef(null);
|
|
93
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
94
|
+
const { refs, floatingStyles, context } = useFloating({
|
|
95
|
+
open: isOpen,
|
|
96
|
+
onOpenChange: (open, _, reason) => {
|
|
97
|
+
if (reason === "reference-press") return;
|
|
98
|
+
setIsOpen(open);
|
|
99
|
+
},
|
|
100
|
+
strategy: "fixed",
|
|
101
|
+
placement: "bottom",
|
|
102
|
+
whileElementsMounted: autoUpdate,
|
|
103
|
+
middleware: [
|
|
104
|
+
shift({ padding: 8 }),
|
|
105
|
+
flip(),
|
|
106
|
+
offset(9),
|
|
107
|
+
arrow({
|
|
108
|
+
element: arrowRef,
|
|
109
|
+
}),
|
|
110
|
+
],
|
|
111
|
+
});
|
|
112
|
+
const click = useClick(context, {
|
|
113
|
+
enabled: !disabled && !readOnly,
|
|
114
|
+
});
|
|
115
|
+
const dismiss = useDismiss(context, {
|
|
116
|
+
referencePress: true,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const { getReferenceProps, getFloatingProps } = useInteractions([
|
|
120
|
+
dismiss,
|
|
121
|
+
click,
|
|
122
|
+
]);
|
|
123
|
+
|
|
77
124
|
return (
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
125
|
+
<InputWrapper
|
|
126
|
+
showClear={actualValue !== defaultColor && !disabled && !readOnly}
|
|
127
|
+
onClear={handleChange}
|
|
128
|
+
invalid={invalid}
|
|
129
|
+
readOnly={readOnly}
|
|
130
|
+
disabled={disabled}
|
|
131
|
+
required={required}
|
|
132
|
+
error={error}
|
|
133
|
+
{...rest}
|
|
84
134
|
>
|
|
85
|
-
|
|
135
|
+
<button
|
|
136
|
+
data-ref="button"
|
|
137
|
+
className="flex-1 flex items-center"
|
|
138
|
+
ref={refs.setReference}
|
|
139
|
+
{...getReferenceProps({
|
|
140
|
+
onBlur,
|
|
141
|
+
onFocus,
|
|
142
|
+
})}
|
|
143
|
+
data-inner-clickable="true"
|
|
144
|
+
data-dropdown-open={isOpen ? true : undefined}
|
|
145
|
+
>
|
|
86
146
|
<div
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
147
|
+
role="none"
|
|
148
|
+
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"
|
|
149
|
+
style={{
|
|
150
|
+
backgroundColor: actualValue,
|
|
151
|
+
opacity: disabled ? 0.65 : 1,
|
|
152
|
+
pointerEvents: disabled ? "none" : undefined,
|
|
153
|
+
}}
|
|
154
|
+
>
|
|
155
|
+
{!actualValue && (
|
|
156
|
+
<Icon
|
|
157
|
+
size="md"
|
|
158
|
+
className="text-muted"
|
|
159
|
+
icon={CoreIcons.colorSwatch}
|
|
160
|
+
/>
|
|
90
161
|
)}
|
|
162
|
+
</div>
|
|
163
|
+
</button>
|
|
164
|
+
{isOpen && (
|
|
165
|
+
<div
|
|
166
|
+
ref={refs.setFloating}
|
|
167
|
+
style={{
|
|
168
|
+
zIndex: "var(--z-popover)",
|
|
169
|
+
...floatingStyles,
|
|
170
|
+
}}
|
|
171
|
+
data-ref="dropdownBody"
|
|
172
|
+
{...getFloatingProps()}
|
|
91
173
|
>
|
|
92
|
-
|
|
174
|
+
<ColorPicker
|
|
175
|
+
{...rest}
|
|
176
|
+
onChange={handleChange}
|
|
177
|
+
defaultColor={defaultColor}
|
|
178
|
+
value={actualValue}
|
|
179
|
+
/>
|
|
180
|
+
<FloatingArrow
|
|
181
|
+
ref={arrowRef}
|
|
182
|
+
context={context}
|
|
183
|
+
strokeWidth={0.5}
|
|
184
|
+
className="fill-base stroke-muted"
|
|
185
|
+
/>
|
|
93
186
|
</div>
|
|
94
187
|
)}
|
|
95
|
-
<Dropdown showArrow disabled={disabled}>
|
|
96
|
-
<button data-ref="button" className="flex-1 flex items-center">
|
|
97
|
-
<div
|
|
98
|
-
role="none"
|
|
99
|
-
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"
|
|
100
|
-
style={{
|
|
101
|
-
backgroundColor: actualValue,
|
|
102
|
-
opacity: disabled ? 0.65 : 1,
|
|
103
|
-
pointerEvents: disabled ? "none" : undefined,
|
|
104
|
-
}}
|
|
105
|
-
onClick={(e) =>
|
|
106
|
-
(e.currentTarget.nextElementSibling as HTMLElement)?.focus()
|
|
107
|
-
}
|
|
108
|
-
>
|
|
109
|
-
{!actualValue && (
|
|
110
|
-
<Icon
|
|
111
|
-
size="md"
|
|
112
|
-
className="text-muted"
|
|
113
|
-
icon={CoreIcons.colorSwatch}
|
|
114
|
-
/>
|
|
115
|
-
)}
|
|
116
|
-
</div>
|
|
117
|
-
</button>
|
|
118
|
-
<ColorPicker
|
|
119
|
-
{...rest}
|
|
120
|
-
onChange={handleChange}
|
|
121
|
-
defaultColor={defaultColor}
|
|
122
|
-
value={actualValue}
|
|
123
|
-
/>
|
|
124
|
-
</Dropdown>
|
|
125
188
|
{!disabled && showPicker && (
|
|
126
189
|
<Icon
|
|
127
190
|
icon={CoreIcons.colorPicker}
|
|
@@ -133,25 +196,6 @@ export const ColorInput = ({
|
|
|
133
196
|
}
|
|
134
197
|
/>
|
|
135
198
|
)}
|
|
136
|
-
|
|
137
|
-
<div
|
|
138
|
-
className={classNames(
|
|
139
|
-
"text-muted leading-none flex-content",
|
|
140
|
-
isString(decorateEnd) && "px-2",
|
|
141
|
-
)}
|
|
142
|
-
>
|
|
143
|
-
{decorateEnd}
|
|
144
|
-
</div>
|
|
145
|
-
)}
|
|
146
|
-
{!disabled && allowClear && actualValue !== defaultColor && (
|
|
147
|
-
<Icon
|
|
148
|
-
icon={CoreIcons.close}
|
|
149
|
-
onClick={() => handleChange()}
|
|
150
|
-
className={classNames(
|
|
151
|
-
"text-tint-500 hover:text-tint-700 p-[0.25em] flex-content",
|
|
152
|
-
)}
|
|
153
|
-
/>
|
|
154
|
-
)}
|
|
155
|
-
</div>
|
|
199
|
+
</InputWrapper>
|
|
156
200
|
);
|
|
157
201
|
};
|