kelt-ui-kit-react 2.0.1 → 2.0.3
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/dist/_core/type/generiqueType.d.ts +4 -0
- package/dist/badge/Badge.d.ts +3 -1
- package/dist/button/Button.d.ts +1 -1
- package/dist/button/button.interface.d.ts +1 -2
- package/dist/dataTable/DataTable.d.ts +17 -14
- package/dist/dataTable/dataTable.interface.d.ts +24 -19
- package/dist/dataTable/dataTableActions/DataTableAction.d.ts +3 -5
- package/dist/dataTable/dataTableColumn/DataTableColumn.d.ts +13 -7
- package/dist/dataTable/dataTableColumn/dataTableColumnFilter/DataTableColumnFilter.d.ts +10 -0
- package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDate/DataTableColumnFilterDate.d.ts +9 -0
- package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDateRange/dataTableColumnFilterDateRange.d.ts +9 -0
- package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterEnum/DataTableColumnFilterEnum.d.ts +13 -0
- package/dist/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterString/DataTableColumnFilterString.d.ts +9 -0
- package/dist/dataTable/dataTableColumn/dataTableColumnSort/DataTableColumnSort.d.ts +11 -0
- package/dist/dataTable/dataTableFilters/DataTableFilters.d.ts +7 -0
- package/dist/dataTable/dataTableLoading/DataTableLoading.d.ts +1 -3
- package/dist/dataTable/dataTableRow/DataTableRow.d.ts +5 -6
- package/dist/dataTable/dataTableRow/dataTableRowOverlay/DataTableRowOverlay.d.ts +12 -0
- package/dist/dataTable/dataTableRow/dataTableRowValue/DataTableRowValue.d.ts +11 -0
- package/dist/expands/expand/expand.d.ts +1 -1
- package/dist/form/Form.d.ts +1 -2
- package/dist/form/form.enum.d.ts +2 -2
- package/dist/form/form.interface.d.ts +2 -4
- package/dist/form/input/Input.d.ts +3 -0
- package/dist/form/inputNumber/InputNumber.d.ts +0 -2
- package/dist/grid/col/Col.d.ts +6 -3
- package/dist/grid/col/colStyled/ColStyled.d.ts +5 -7
- package/dist/grid/grid.interface.d.ts +5 -9
- package/dist/header/Header.d.ts +1 -1
- package/dist/header/header.interface.d.ts +1 -2
- package/dist/icon/Icon.d.ts +1 -1
- package/dist/icon/icon.interface.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3740 -3443
- package/dist/menus/menu/Menu.d.ts +0 -1
- package/dist/overlayPanel/OverlayPanel.d.ts +4 -2
- package/dist/overlayPanel/overlayPanelStyled/OverlayPanelStyled.d.ts +2 -0
- package/dist/select/Select.d.ts +6 -2
- package/dist/select/selectOption.interface.d.ts +1 -0
- package/dist/style.css +1 -1
- package/dist/tabs/Tabs.d.ts +2 -1
- package/dist/toaster/store/useToasterStore.d.ts +0 -1
- package/index.html +2 -1
- package/package/package.json +56 -0
- package/package/src/sidebar/Sidebar.tsx +208 -0
- package/package/src/sidebar/sidebar.css +104 -0
- package/package.json +1 -1
- package/src/_core/type/generiqueType.tsx +4 -0
- package/src/badge/Badge.tsx +9 -1
- package/src/badge/badge.css +4 -0
- package/src/button/Button.tsx +1 -3
- package/src/button/button.css +2 -2
- package/src/button/button.interface.tsx +1 -2
- package/src/card/card.css +25 -5
- package/src/card/cardAction/CardAction.tsx +4 -4
- package/src/damier/Damier.tsx +7 -16
- package/src/damier/damier.css +4 -11
- package/src/dataTable/DataTable.tsx +685 -542
- package/src/dataTable/DataTable.view.tsx +48 -24
- package/src/dataTable/dataTable.css +134 -159
- package/src/dataTable/dataTable.interface.ts +25 -19
- package/src/dataTable/dataTableActions/DataTableAction.tsx +14 -25
- package/src/dataTable/dataTableColumn/DataTableColumn.tsx +64 -14
- package/src/dataTable/dataTableColumn/dataTableColumnFilter/DataTableColumnFilter.tsx +36 -0
- package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilter.css +0 -0
- package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDate/DataTableColumnFilterDate.tsx +39 -0
- package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterDateRange/dataTableColumnFilterDateRange.tsx +80 -0
- package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterEnum/DataTableColumnFilterEnum.tsx +89 -0
- package/src/dataTable/dataTableColumn/dataTableColumnFilter/dataTableColumnFilterString/DataTableColumnFilterString.tsx +37 -0
- package/src/dataTable/dataTableColumn/dataTableColumnSort/DataTableColumnSort.tsx +42 -0
- package/src/dataTable/dataTableFilters/DataTableFilters.tsx +91 -0
- package/src/dataTable/dataTableFilters/dataTableFilters.css +16 -0
- package/src/dataTable/dataTableLoading/DataTableLoading.tsx +4 -15
- package/src/dataTable/dataTableRow/DataTableRow.tsx +64 -180
- package/src/dataTable/dataTableRow/dataTableRowOverlay/DataTableRowOverlay.tsx +80 -0
- package/src/dataTable/dataTableRow/dataTableRowValue/DataTableRowValue.tsx +123 -0
- package/src/expands/Expands.tsx +2 -16
- package/src/expands/expand/expand.tsx +5 -122
- package/src/expands/expands.css +3 -8
- package/src/form/Form.tsx +25 -125
- package/src/form/Form.view.tsx +1 -9
- package/src/form/form.css +1 -38
- package/src/form/form.enum.ts +1 -1
- package/src/form/form.interface.tsx +2 -7
- package/src/form/input/Input.tsx +61 -7
- package/src/form/input/input.css +23 -1
- package/src/form/inputNumber/InputNumber.tsx +6 -11
- package/src/form/inputPrice/InputPrice.tsx +2 -4
- package/src/grid/col/Col.tsx +7 -5
- package/src/grid/col/colStyled/ColStyled.tsx +7 -21
- package/src/grid/grid.interface.tsx +5 -11
- package/src/header/Header.tsx +2 -4
- package/src/header/header.css +0 -17
- package/src/header/header.interface.tsx +1 -2
- package/src/icon/Icon.tsx +6 -2
- package/src/icon/icon.interface.tsx +1 -0
- package/src/index.css +12 -58
- package/src/index.ts +2 -1
- package/src/menus/Menus.tsx +0 -1
- package/src/menus/menu/Menu.tsx +1 -2
- package/src/overlayPanel/OverlayPanel.tsx +71 -18
- package/src/overlayPanel/overlay.context.tsx +6 -4
- package/src/overlayPanel/overlayPanel.css +10 -1
- package/src/overlayPanel/overlayPanelStyled/OverlayPanelStyled.tsx +7 -2
- package/src/select/Select.tsx +178 -41
- package/src/select/select.css +94 -13
- package/src/select/selectOption.interface.ts +1 -0
- package/src/sidebar/Sidebar.tsx +5 -107
- package/src/sidebar/sidebar.css +1 -18
- package/src/tabs/Tabs.tsx +20 -1
- package/src/tabs/tabs.css +3 -9
- package/src/toaster/Toaster.tsx +2 -7
- package/src/toaster/Toaster.view.tsx +0 -1
- package/src/toaster/store/useToasterStore.tsx +0 -2
- package/src/toaster/toaster.css +2 -7
package/src/expands/expands.css
CHANGED
|
@@ -39,12 +39,10 @@
|
|
|
39
39
|
height: 300px;
|
|
40
40
|
flex: 1;
|
|
41
41
|
min-height: 200px;
|
|
42
|
-
|
|
43
42
|
.expand-header {
|
|
44
|
-
background-color:
|
|
43
|
+
background-color: #1d3758;
|
|
45
44
|
color: #fff;
|
|
46
45
|
}
|
|
47
|
-
|
|
48
46
|
.expand-header-custom {
|
|
49
47
|
.expand-header--children {
|
|
50
48
|
display: flex;
|
|
@@ -67,7 +65,6 @@
|
|
|
67
65
|
padding: 15px;
|
|
68
66
|
color: #333;
|
|
69
67
|
background-color: #fff;
|
|
70
|
-
|
|
71
68
|
&.expand-header-custom {
|
|
72
69
|
margin-bottom: 1rem;
|
|
73
70
|
}
|
|
@@ -80,15 +77,13 @@
|
|
|
80
77
|
.expand-header-title-left {
|
|
81
78
|
margin-right: 0.5rem;
|
|
82
79
|
text-transform: uppercase;
|
|
83
|
-
font-size:
|
|
80
|
+
font-size: 14px;
|
|
84
81
|
font-weight: 500;
|
|
85
82
|
}
|
|
86
83
|
}
|
|
87
|
-
|
|
88
84
|
& .expand-footer {
|
|
89
85
|
padding: 15px;
|
|
90
86
|
}
|
|
91
|
-
|
|
92
87
|
& .expand-body {
|
|
93
88
|
display: none;
|
|
94
89
|
flex: 1;
|
|
@@ -99,4 +94,4 @@
|
|
|
99
94
|
flex-direction: column;
|
|
100
95
|
}
|
|
101
96
|
}
|
|
102
|
-
}
|
|
97
|
+
}
|
package/src/form/Form.tsx
CHANGED
|
@@ -9,38 +9,12 @@ import { Button } from "../button/Button";
|
|
|
9
9
|
import { Icon } from "../icon/Icon";
|
|
10
10
|
import { Select } from "../select/Select"; // <--- ton composant
|
|
11
11
|
import "./form.css";
|
|
12
|
-
import {
|
|
13
|
-
FormInterface,
|
|
14
|
-
FormMode,
|
|
15
|
-
FormValuesInterface,
|
|
16
|
-
} from "./form.interface";
|
|
12
|
+
import { FormInterface, FormValuesInterface } from "./form.interface";
|
|
17
13
|
import { Input } from "./input/Input";
|
|
18
|
-
import { InputPrice } from "./inputPrice/InputPrice";
|
|
19
14
|
import { TextArea } from "./textArea/TextArea";
|
|
20
|
-
import { Col } from "../grid/col/Col";
|
|
21
|
-
import { Row } from "../grid/row/Row";
|
|
22
|
-
import { TypeInputEnum } from "./form.enum";
|
|
23
|
-
|
|
24
|
-
const euroFormatter = new Intl.NumberFormat("fr-FR", {
|
|
25
|
-
style: "currency",
|
|
26
|
-
currency: "EUR",
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
type FormFieldContainerProps = {
|
|
30
|
-
field: FormInterface;
|
|
31
|
-
gridEnabled: boolean;
|
|
32
|
-
children: React.ReactNode;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const FormFieldContainer = ({
|
|
36
|
-
field,
|
|
37
|
-
gridEnabled,
|
|
38
|
-
children,
|
|
39
|
-
}: FormFieldContainerProps) =>
|
|
40
|
-
gridEnabled ? <Col {...field.col}>{children}</Col> : <>{children}</>;
|
|
41
15
|
|
|
42
16
|
export type FormProps<
|
|
43
|
-
T extends { [key: string]: string | number | boolean | Date | string[] }
|
|
17
|
+
T extends { [key: string]: string | number | boolean | Date | string[] },
|
|
44
18
|
> = {
|
|
45
19
|
id?: string;
|
|
46
20
|
className?: string;
|
|
@@ -50,7 +24,6 @@ export type FormProps<
|
|
|
50
24
|
children?: React.ReactNode;
|
|
51
25
|
initialForm: FormInterface[];
|
|
52
26
|
disabledSubmit?: boolean;
|
|
53
|
-
mode?: FormMode;
|
|
54
27
|
onSubmit?: (values: FormValuesInterface<T>) => void;
|
|
55
28
|
onChange?: (values: FormValuesInterface<T>) => void;
|
|
56
29
|
};
|
|
@@ -67,7 +40,6 @@ export const DynamicForm = forwardRef(
|
|
|
67
40
|
onChange,
|
|
68
41
|
hideSubmit,
|
|
69
42
|
disabledSubmit = false,
|
|
70
|
-
mode = "edit",
|
|
71
43
|
className,
|
|
72
44
|
}: FormProps<T>,
|
|
73
45
|
ref: React.Ref<{
|
|
@@ -77,7 +49,7 @@ export const DynamicForm = forwardRef(
|
|
|
77
49
|
getValues?: () => FormValuesInterface<T>;
|
|
78
50
|
updateFormValue?: (values: FormValuesInterface<T>) => void;
|
|
79
51
|
setBtnDisabledSubmit?: (disabled: boolean) => void;
|
|
80
|
-
}
|
|
52
|
+
}>,
|
|
81
53
|
) => {
|
|
82
54
|
const [btnDisabledSubmit, setBtnDisabledSubmit] = useState(disabledSubmit);
|
|
83
55
|
const [values, setValues] = useState<FormValuesInterface<T>>(() => {
|
|
@@ -95,7 +67,7 @@ export const DynamicForm = forwardRef(
|
|
|
95
67
|
const handleChangeInput = useCallback(
|
|
96
68
|
(
|
|
97
69
|
event: React.ChangeEvent<HTMLInputElement>,
|
|
98
|
-
forminterface: FormInterface
|
|
70
|
+
forminterface: FormInterface,
|
|
99
71
|
) => {
|
|
100
72
|
const { name, type, checked, value } = event.target;
|
|
101
73
|
const newValue = type === "checkbox" ? checked : value;
|
|
@@ -112,7 +84,7 @@ export const DynamicForm = forwardRef(
|
|
|
112
84
|
return updatedValues;
|
|
113
85
|
});
|
|
114
86
|
},
|
|
115
|
-
[onChange]
|
|
87
|
+
[onChange],
|
|
116
88
|
);
|
|
117
89
|
const handleChangeTextArea = useCallback(
|
|
118
90
|
(name: string, value: string, forminterface: FormInterface) => {
|
|
@@ -128,14 +100,14 @@ export const DynamicForm = forwardRef(
|
|
|
128
100
|
return updatedValues;
|
|
129
101
|
});
|
|
130
102
|
},
|
|
131
|
-
[onChange]
|
|
103
|
+
[onChange],
|
|
132
104
|
);
|
|
133
105
|
/** Gestion des <select> */
|
|
134
106
|
const handleChangeSelect = useCallback(
|
|
135
107
|
(
|
|
136
108
|
newValue: string | string[],
|
|
137
109
|
name: string,
|
|
138
|
-
forminterface: FormInterface
|
|
110
|
+
forminterface: FormInterface,
|
|
139
111
|
) => {
|
|
140
112
|
if (forminterface.onChange) {
|
|
141
113
|
forminterface.onChange(newValue, name);
|
|
@@ -147,7 +119,7 @@ export const DynamicForm = forwardRef(
|
|
|
147
119
|
return updatedValues;
|
|
148
120
|
});
|
|
149
121
|
},
|
|
150
|
-
[onChange]
|
|
122
|
+
[onChange],
|
|
151
123
|
);
|
|
152
124
|
|
|
153
125
|
const handleSubmit = useCallback(
|
|
@@ -157,7 +129,7 @@ export const DynamicForm = forwardRef(
|
|
|
157
129
|
onSubmit(values);
|
|
158
130
|
}
|
|
159
131
|
},
|
|
160
|
-
[onSubmit, values]
|
|
132
|
+
[onSubmit, values],
|
|
161
133
|
);
|
|
162
134
|
|
|
163
135
|
const resetForm = () => {
|
|
@@ -190,7 +162,7 @@ export const DynamicForm = forwardRef(
|
|
|
190
162
|
const getValues = () => values;
|
|
191
163
|
|
|
192
164
|
const updateFormValue: (values: FormValuesInterface<T>) => void = (
|
|
193
|
-
values
|
|
165
|
+
values,
|
|
194
166
|
) => {
|
|
195
167
|
setValues((prevValues) => ({
|
|
196
168
|
...prevValues,
|
|
@@ -207,52 +179,6 @@ export const DynamicForm = forwardRef(
|
|
|
207
179
|
setBtnDisabledSubmit,
|
|
208
180
|
}));
|
|
209
181
|
|
|
210
|
-
const gridEnabled = initialForm.some((field) => field.col !== undefined);
|
|
211
|
-
const FieldsContainer = gridEnabled ? Row : React.Fragment;
|
|
212
|
-
const getReadValue = (field: FormInterface): React.ReactNode => {
|
|
213
|
-
const value = values[field.name];
|
|
214
|
-
|
|
215
|
-
if (field.formatReadValue) {
|
|
216
|
-
return field.formatReadValue(value ?? "");
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (field.type === TypeInputEnum.SELECT) {
|
|
220
|
-
const selectedValues = Array.isArray(value) ? value : [value];
|
|
221
|
-
const labels = selectedValues
|
|
222
|
-
.map(
|
|
223
|
-
(selectedValue) =>
|
|
224
|
-
field.options?.find((option) => option.value === selectedValue)
|
|
225
|
-
?.label ?? selectedValue,
|
|
226
|
-
)
|
|
227
|
-
.filter((selectedValue) => selectedValue !== undefined);
|
|
228
|
-
|
|
229
|
-
return labels.join(", ") || "-";
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (field.type === TypeInputEnum.PRICE) {
|
|
233
|
-
const amount = Number(value);
|
|
234
|
-
return value === "" || value === undefined || Number.isNaN(amount)
|
|
235
|
-
? "-"
|
|
236
|
-
: euroFormatter.format(amount);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (typeof value === "boolean") {
|
|
240
|
-
return value ? "Oui" : "Non";
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (value instanceof Date) {
|
|
244
|
-
return value.toLocaleDateString();
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (Array.isArray(value)) {
|
|
248
|
-
return value.join(", ") || "-";
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return value === undefined || value === null || value === ""
|
|
252
|
-
? "-"
|
|
253
|
-
: String(value);
|
|
254
|
-
};
|
|
255
|
-
|
|
256
182
|
return (
|
|
257
183
|
<form
|
|
258
184
|
autoComplete={autoComplete ?? "off"}
|
|
@@ -260,36 +186,25 @@ export const DynamicForm = forwardRef(
|
|
|
260
186
|
className={className ?? ""}
|
|
261
187
|
>
|
|
262
188
|
<div className="form-content">
|
|
263
|
-
<FieldsContainer>
|
|
264
189
|
{initialForm.map((v, key) => {
|
|
265
190
|
const required = v.onRequired
|
|
266
191
|
? v.onRequired(v.value)
|
|
267
|
-
: v.required ?? false;
|
|
192
|
+
: (v.required ?? false);
|
|
268
193
|
const disabled = v.onDisabled
|
|
269
194
|
? v.onDisabled(v.value)
|
|
270
|
-
: v.disabled ?? false;
|
|
195
|
+
: (v.disabled ?? false);
|
|
271
196
|
|
|
272
197
|
return (
|
|
273
|
-
<
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
198
|
+
<div
|
|
199
|
+
key={key}
|
|
200
|
+
className={`d-flex flex-column ${
|
|
201
|
+
v.className ?? ""
|
|
202
|
+
} form-group form-group-${v.type}`}
|
|
203
|
+
>
|
|
279
204
|
{v.label && <label>{v.label}</label>}
|
|
280
205
|
{v.icon && <Icon classIcon={v.icon} />}
|
|
281
206
|
|
|
282
|
-
{
|
|
283
|
-
<div
|
|
284
|
-
className={`form-read-value ${
|
|
285
|
-
v.type === TypeInputEnum.TEXTAREA
|
|
286
|
-
? "form-read-value--textarea"
|
|
287
|
-
: ""
|
|
288
|
-
}`}
|
|
289
|
-
>
|
|
290
|
-
{getReadValue(v)}
|
|
291
|
-
</div>
|
|
292
|
-
) : v.type === "select" ? (
|
|
207
|
+
{v.type === "select" ? (
|
|
293
208
|
<Select
|
|
294
209
|
id={v.id ?? v.name}
|
|
295
210
|
label={undefined}
|
|
@@ -297,6 +212,8 @@ export const DynamicForm = forwardRef(
|
|
|
297
212
|
options={v.options ?? []}
|
|
298
213
|
disabled={disabled}
|
|
299
214
|
multiple={v.multiple}
|
|
215
|
+
usePortal={v.usePortal}
|
|
216
|
+
searchable={v.searchable}
|
|
300
217
|
value={values[v.name] as any}
|
|
301
218
|
required={required}
|
|
302
219
|
defaultValue={v.value as string | string[]}
|
|
@@ -321,22 +238,6 @@ export const DynamicForm = forwardRef(
|
|
|
321
238
|
handleChangeTextArea(name, value, v)
|
|
322
239
|
}
|
|
323
240
|
/>
|
|
324
|
-
) : v.type === TypeInputEnum.PRICE ? (
|
|
325
|
-
<InputPrice
|
|
326
|
-
id={v.id ?? v.name}
|
|
327
|
-
ref={(el) => (inputRefs.current[v.name] = el)}
|
|
328
|
-
name={v.name}
|
|
329
|
-
placeholder={v.placeholder ?? ""}
|
|
330
|
-
autoComplete={v.autoComplete}
|
|
331
|
-
tabIndex={0}
|
|
332
|
-
disabled={disabled}
|
|
333
|
-
autoFocus={v.focus ?? false}
|
|
334
|
-
required={required}
|
|
335
|
-
value={String(values[v.name] ?? "")}
|
|
336
|
-
onChange={(value) =>
|
|
337
|
-
handleChangeTextArea(v.name, value, v)
|
|
338
|
-
}
|
|
339
|
-
/>
|
|
340
241
|
) : (
|
|
341
242
|
<Input
|
|
342
243
|
id={v.id ?? v.name}
|
|
@@ -350,6 +251,7 @@ export const DynamicForm = forwardRef(
|
|
|
350
251
|
autoFocus={v.focus ?? false}
|
|
351
252
|
required={required}
|
|
352
253
|
step={v.step ?? "0.01"}
|
|
254
|
+
disabledDebounce={true}
|
|
353
255
|
value={values[v.name] as string | number}
|
|
354
256
|
checked={
|
|
355
257
|
v.type === "checkbox" ? !!values[v.name] : undefined
|
|
@@ -360,15 +262,13 @@ export const DynamicForm = forwardRef(
|
|
|
360
262
|
onInvalid={v.onInvalid ? v.onInvalid : undefined}
|
|
361
263
|
/>
|
|
362
264
|
)}
|
|
363
|
-
|
|
364
|
-
</FormFieldContainer>
|
|
265
|
+
</div>
|
|
365
266
|
);
|
|
366
267
|
})}
|
|
367
268
|
{children}
|
|
368
|
-
</FieldsContainer>
|
|
369
269
|
</div>
|
|
370
270
|
<div className="d-flex justify-content-end form-footer">
|
|
371
|
-
{
|
|
271
|
+
{!hideSubmit && (
|
|
372
272
|
<Button
|
|
373
273
|
id={`button-${id}`}
|
|
374
274
|
disabled={btnDisabledSubmit}
|
|
@@ -378,5 +278,5 @@ export const DynamicForm = forwardRef(
|
|
|
378
278
|
</div>
|
|
379
279
|
</form>
|
|
380
280
|
);
|
|
381
|
-
}
|
|
281
|
+
},
|
|
382
282
|
);
|
package/src/form/Form.view.tsx
CHANGED
|
@@ -18,14 +18,12 @@ export const FormView = (): JSX.Element => {
|
|
|
18
18
|
name: "nom",
|
|
19
19
|
type: TypeInputEnum.PASSWORD,
|
|
20
20
|
required: true,
|
|
21
|
-
col: { xs: 12, md: 6 },
|
|
22
21
|
},
|
|
23
22
|
{
|
|
24
23
|
value: 30,
|
|
25
24
|
label: "Age",
|
|
26
25
|
name: "age",
|
|
27
26
|
type: TypeInputEnum.NUMBER,
|
|
28
|
-
col: { xs: 12, md: 6 },
|
|
29
27
|
},
|
|
30
28
|
{
|
|
31
29
|
value: false,
|
|
@@ -57,11 +55,5 @@ export const FormView = (): JSX.Element => {
|
|
|
57
55
|
const handleSubmit = (values: FormValuesInterface<FormData>) => {
|
|
58
56
|
console.log("Form Submitted: ", values);
|
|
59
57
|
};
|
|
60
|
-
return
|
|
61
|
-
<DynamicForm
|
|
62
|
-
mode="edit"
|
|
63
|
-
onSubmit={handleSubmit}
|
|
64
|
-
initialForm={initialValues}
|
|
65
|
-
/>
|
|
66
|
-
);
|
|
58
|
+
return <DynamicForm onSubmit={handleSubmit} initialForm={initialValues} />;
|
|
67
59
|
};
|
package/src/form/form.css
CHANGED
|
@@ -6,7 +6,7 @@ input {
|
|
|
6
6
|
min-width: 250px;
|
|
7
7
|
|
|
8
8
|
&:focus-visible {
|
|
9
|
-
outline:
|
|
9
|
+
outline: 0px;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -70,41 +70,4 @@ form {
|
|
|
70
70
|
button {
|
|
71
71
|
margin-top: 1rem;
|
|
72
72
|
}
|
|
73
|
-
|
|
74
|
-
.form-read-value {
|
|
75
|
-
width: 100%;
|
|
76
|
-
min-width: 250px;
|
|
77
|
-
min-height: calc(1em + 1rem + 2px);
|
|
78
|
-
box-sizing: border-box;
|
|
79
|
-
border: 1px solid transparent;
|
|
80
|
-
border-radius: 4px;
|
|
81
|
-
margin: 0.25rem 0;
|
|
82
|
-
padding: 0.5rem 1rem;
|
|
83
|
-
font-size: 0.8rem;
|
|
84
|
-
line-height: normal;
|
|
85
|
-
overflow-wrap: anywhere;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.form-read-value--textarea {
|
|
89
|
-
min-height: 3.25rem;
|
|
90
|
-
white-space: pre-wrap;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.grid-row {
|
|
94
|
-
|
|
95
|
-
.form-group,
|
|
96
|
-
.input-container,
|
|
97
|
-
.select-container,
|
|
98
|
-
.form-read-value {
|
|
99
|
-
min-width: 0;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
input:not([type="checkbox"]):not([type="radio"]),
|
|
103
|
-
.form-control-textarea,
|
|
104
|
-
.form-read-value {
|
|
105
|
-
box-sizing: border-box;
|
|
106
|
-
min-width: 0;
|
|
107
|
-
width: 100%;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
73
|
}
|
package/src/form/form.enum.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { TypeInputEnum } from "./form.enum";
|
|
2
|
-
import { GridBreakpoints } from "../grid/grid.interface";
|
|
3
|
-
|
|
4
|
-
export type FormMode = "read" | "edit";
|
|
5
2
|
|
|
6
3
|
export type FormValuesInterface<
|
|
7
4
|
T extends { [key: string]: string | number | boolean | Date | string[] }
|
|
@@ -26,12 +23,10 @@ export interface FormInterface {
|
|
|
26
23
|
condition?: FormCondition;
|
|
27
24
|
icon?: string;
|
|
28
25
|
multiple?: boolean;
|
|
26
|
+
usePortal?: boolean;
|
|
27
|
+
searchable?: boolean;
|
|
29
28
|
options?: { value: string; label: string }[]; // <--- pour les <option>
|
|
30
29
|
className?: string;
|
|
31
|
-
col?: GridBreakpoints;
|
|
32
|
-
formatReadValue?: (
|
|
33
|
-
value: string | number | boolean | Date | string[]
|
|
34
|
-
) => React.ReactNode;
|
|
35
30
|
autoComplete?: string;
|
|
36
31
|
step?: string;
|
|
37
32
|
onChange?: (
|
package/src/form/input/Input.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { forwardRef, useState } from "react";
|
|
1
|
+
import { forwardRef, useRef, useState } from "react";
|
|
2
2
|
import { Icon } from "../../icon/Icon";
|
|
3
3
|
import { TypeInputEnum } from "../form.enum";
|
|
4
4
|
import "./input.css";
|
|
@@ -15,12 +15,15 @@ export interface InputProps {
|
|
|
15
15
|
disabled?: boolean;
|
|
16
16
|
autoFocus?: boolean;
|
|
17
17
|
required?: boolean;
|
|
18
|
+
disabledDebounce?: boolean;
|
|
18
19
|
minLength?: number;
|
|
19
20
|
maxLength?: number;
|
|
21
|
+
width?: string;
|
|
20
22
|
autoComplete?: string;
|
|
21
23
|
step?: string;
|
|
22
24
|
tabIndex?: number;
|
|
23
25
|
checked?: boolean;
|
|
26
|
+
showClearButton?: boolean;
|
|
24
27
|
handleKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
25
28
|
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
26
29
|
onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
|
|
@@ -34,11 +37,13 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
34
37
|
name,
|
|
35
38
|
type = TypeInputEnum.TEXT,
|
|
36
39
|
value,
|
|
40
|
+
width,
|
|
37
41
|
onInvalid,
|
|
38
42
|
placeholder,
|
|
39
43
|
className,
|
|
40
44
|
inputMode,
|
|
41
45
|
minLength,
|
|
46
|
+
disabledDebounce = false,
|
|
42
47
|
maxLength,
|
|
43
48
|
autoFocus = false,
|
|
44
49
|
disabled = false,
|
|
@@ -47,18 +52,61 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
47
52
|
tabIndex = 0,
|
|
48
53
|
step,
|
|
49
54
|
checked,
|
|
55
|
+
showClearButton = false,
|
|
50
56
|
onChange,
|
|
51
57
|
onBlur,
|
|
52
58
|
onClick,
|
|
53
59
|
handleKeyDown,
|
|
54
60
|
},
|
|
55
|
-
ref
|
|
61
|
+
ref,
|
|
56
62
|
) => {
|
|
57
63
|
// Si le type est password, on utilise l'input de type password
|
|
58
64
|
const [showPassword, setShowPassword] = useState(false);
|
|
65
|
+
const [localValue, setLocalValue] = useState(value ?? "");
|
|
66
|
+
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
67
|
+
|
|
68
|
+
const triggerOnChange = (nextValue: string) => {
|
|
69
|
+
if (!onChange) return;
|
|
70
|
+
|
|
71
|
+
const syntheticEvent = {
|
|
72
|
+
target: { value: nextValue, name, id },
|
|
73
|
+
currentTarget: { value: nextValue, name, id },
|
|
74
|
+
} as unknown as React.ChangeEvent<HTMLInputElement>;
|
|
75
|
+
|
|
76
|
+
onChange(syntheticEvent);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
80
|
+
const value = e.target.value; // 👈 capturer avant le setTimeout
|
|
81
|
+
setLocalValue(value);
|
|
82
|
+
if (!onChange) return;
|
|
83
|
+
if (disabledDebounce) {
|
|
84
|
+
onChange(e);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
88
|
+
debounceRef.current = setTimeout(() => {
|
|
89
|
+
onChange({ ...e, target: { ...e.target, value } }); // 👈 passer la valeur capturée
|
|
90
|
+
}, 300);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const handleClear = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
94
|
+
e.stopPropagation();
|
|
95
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
96
|
+
setLocalValue("");
|
|
97
|
+
triggerOnChange("");
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const hasValue = String(localValue ?? "").length > 0;
|
|
101
|
+
const hasClearButtonSlot = showClearButton && type === TypeInputEnum.TEXT;
|
|
102
|
+
const canShowClearButton =
|
|
103
|
+
showClearButton && hasValue && !disabled && type === TypeInputEnum.TEXT;
|
|
59
104
|
|
|
60
105
|
return (
|
|
61
|
-
<div
|
|
106
|
+
<div
|
|
107
|
+
className={`input-container ${`input-container-${type}`} `}
|
|
108
|
+
style={{ width }}
|
|
109
|
+
>
|
|
62
110
|
<input name={`hide-${name}`} type="text" style={{ display: "none" }} />
|
|
63
111
|
|
|
64
112
|
<input
|
|
@@ -68,7 +116,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
68
116
|
inputMode={inputMode ?? (type === "number" ? "numeric" : "text")}
|
|
69
117
|
type={showPassword ? TypeInputEnum.TEXT : type}
|
|
70
118
|
spellCheck="false"
|
|
71
|
-
value={
|
|
119
|
+
value={localValue}
|
|
72
120
|
placeholder={placeholder}
|
|
73
121
|
disabled={disabled}
|
|
74
122
|
required={required}
|
|
@@ -78,7 +126,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
78
126
|
autoFocus={autoFocus}
|
|
79
127
|
minLength={minLength}
|
|
80
128
|
maxLength={maxLength}
|
|
81
|
-
onChange={
|
|
129
|
+
onChange={handleChange}
|
|
82
130
|
checked={checked}
|
|
83
131
|
onKeyDown={handleKeyDown}
|
|
84
132
|
onBlur={onBlur}
|
|
@@ -86,10 +134,16 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
86
134
|
e.stopPropagation();
|
|
87
135
|
onClick && onClick(e);
|
|
88
136
|
}}
|
|
89
|
-
className={`input-field ${className ?? ""}`}
|
|
137
|
+
className={`input-field ${hasClearButtonSlot ? "with-clear-button" : ""} ${className ?? ""}`}
|
|
90
138
|
onInvalid={onInvalid}
|
|
91
139
|
/>
|
|
92
140
|
|
|
141
|
+
{canShowClearButton && (
|
|
142
|
+
<div onClick={handleClear} className="input-clear-icon" role="button">
|
|
143
|
+
<Icon classIcon="bi-x-circle" />
|
|
144
|
+
</div>
|
|
145
|
+
)}
|
|
146
|
+
|
|
93
147
|
{type === TypeInputEnum.PASSWORD && (
|
|
94
148
|
<div
|
|
95
149
|
onClick={() => setShowPassword(!showPassword)}
|
|
@@ -100,7 +154,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
100
154
|
)}
|
|
101
155
|
</div>
|
|
102
156
|
);
|
|
103
|
-
}
|
|
157
|
+
},
|
|
104
158
|
);
|
|
105
159
|
|
|
106
160
|
Input.displayName = "Input";
|
package/src/form/input/input.css
CHANGED
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
position: relative;
|
|
3
3
|
min-width: 250px;
|
|
4
4
|
width: 100%;
|
|
5
|
+
|
|
5
6
|
&.input-container-radio,
|
|
6
7
|
&.input-container-checkbox {
|
|
7
8
|
min-width: 10px;
|
|
8
9
|
width: 10px;
|
|
10
|
+
|
|
9
11
|
input {
|
|
10
12
|
width: 10px;
|
|
11
13
|
min-width: 10px;
|
|
12
14
|
}
|
|
13
15
|
}
|
|
16
|
+
|
|
14
17
|
.input-password-icon {
|
|
15
18
|
position: absolute;
|
|
16
19
|
right: 10px;
|
|
@@ -19,8 +22,27 @@
|
|
|
19
22
|
display: flex;
|
|
20
23
|
align-items: center;
|
|
21
24
|
}
|
|
25
|
+
|
|
26
|
+
.input-clear-icon {
|
|
27
|
+
position: absolute;
|
|
28
|
+
right: 8px;
|
|
29
|
+
width: 24px;
|
|
30
|
+
height: 100%;
|
|
31
|
+
top: 0;
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
z-index: 2;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.with-clear-button {
|
|
40
|
+
padding-right: 40px;
|
|
41
|
+
}
|
|
42
|
+
|
|
22
43
|
input {
|
|
23
44
|
width: 100%;
|
|
24
45
|
font-size: 0.8rem;
|
|
46
|
+
box-sizing: border-box;
|
|
25
47
|
}
|
|
26
|
-
}
|
|
48
|
+
}
|