@sio-group/form-react 0.1.0

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/README.md +783 -0
  3. package/ROADMAP.md +21 -0
  4. package/dist/index.cjs +1919 -0
  5. package/dist/index.d.cts +284 -0
  6. package/dist/index.d.ts +284 -0
  7. package/dist/index.js +1878 -0
  8. package/dist/styles/components/button.css +244 -0
  9. package/dist/styles/components/button.css.map +1 -0
  10. package/dist/styles/components/checkbox.css +90 -0
  11. package/dist/styles/components/checkbox.css.map +1 -0
  12. package/dist/styles/components/color.css +31 -0
  13. package/dist/styles/components/color.css.map +1 -0
  14. package/dist/styles/components/form-field.css +36 -0
  15. package/dist/styles/components/form-field.css.map +1 -0
  16. package/dist/styles/components/form-states.css +80 -0
  17. package/dist/styles/components/form-states.css.map +1 -0
  18. package/dist/styles/components/grid.css +818 -0
  19. package/dist/styles/components/grid.css.map +1 -0
  20. package/dist/styles/components/input.css +112 -0
  21. package/dist/styles/components/input.css.map +1 -0
  22. package/dist/styles/components/link.css +113 -0
  23. package/dist/styles/components/link.css.map +1 -0
  24. package/dist/styles/components/radio.css +104 -0
  25. package/dist/styles/components/radio.css.map +1 -0
  26. package/dist/styles/components/range.css +54 -0
  27. package/dist/styles/components/range.css.map +1 -0
  28. package/dist/styles/components/select.css +37 -0
  29. package/dist/styles/components/select.css.map +1 -0
  30. package/dist/styles/components/upload.css +54 -0
  31. package/dist/styles/components/upload.css.map +1 -0
  32. package/dist/styles/index.css +1733 -0
  33. package/dist/styles/index.css.map +1 -0
  34. package/package.json +42 -0
  35. package/screenshots/contact-form.png +0 -0
  36. package/screenshots/file-input.png +0 -0
  37. package/screenshots/invalid-username.png +0 -0
  38. package/screenshots/number-field.png +0 -0
  39. package/screenshots/radio-field.png +0 -0
  40. package/screenshots/range-field.png +0 -0
  41. package/screenshots/registration-form.png +0 -0
  42. package/screenshots/select-field.png +0 -0
  43. package/screenshots/textarea-field.png +0 -0
  44. package/tsconfig.tsbuildinfo +1 -0
  45. package/tsup.config.ts +8 -0
package/dist/index.js ADDED
@@ -0,0 +1,1878 @@
1
+ // src/components/Form.tsx
2
+ import { useMemo as useMemo2 } from "react";
3
+
4
+ // src/hooks/useForm.ts
5
+ import { useCallback, useState as useState2 } from "react";
6
+
7
+ // src/hooks/useConnectionStatus.ts
8
+ import { useEffect, useState } from "react";
9
+ var useConnectionStatus = () => {
10
+ const [isOnline, setIsOnline] = useState(navigator.onLine);
11
+ useEffect(() => {
12
+ const handleOnline = () => setIsOnline(true);
13
+ const handleOffline = () => setIsOnline(false);
14
+ window.addEventListener("online", handleOnline);
15
+ window.addEventListener("offline", handleOffline);
16
+ return () => {
17
+ window.removeEventListener("online", handleOnline);
18
+ window.removeEventListener("offline", handleOffline);
19
+ };
20
+ }, []);
21
+ return isOnline;
22
+ };
23
+
24
+ // src/utils/slugify.ts
25
+ var slugify = (string, separator = "_") => {
26
+ return string.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9 ]/g, "").replace(/\s+/g, separator);
27
+ };
28
+
29
+ // src/utils/create-field-state.ts
30
+ import {
31
+ dateIsBiggerThan,
32
+ dateIsSmallerThan,
33
+ isBiggerThan,
34
+ isEmail,
35
+ isPattern,
36
+ isRequired,
37
+ isSmallerThan,
38
+ isUrl
39
+ } from "@sio-group/form-validation";
40
+
41
+ // src/utils/parse-date.ts
42
+ var parseDateValue = (val) => {
43
+ if (val instanceof Date) {
44
+ return isNaN(val.getTime()) ? null : val;
45
+ }
46
+ if (typeof val !== "string") {
47
+ return null;
48
+ }
49
+ if (val.trim() === "") {
50
+ return null;
51
+ }
52
+ const timeRegex = /^([0-1]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/;
53
+ if (timeRegex.test(val)) {
54
+ const [hours, minutes, seconds = 0] = val.split(":").map(Number);
55
+ const date2 = /* @__PURE__ */ new Date();
56
+ date2.setHours(hours, minutes, seconds, 0);
57
+ return date2;
58
+ }
59
+ const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
60
+ if (dateRegex.test(val)) {
61
+ const date2 = /* @__PURE__ */ new Date(val + "T00:00:00");
62
+ return isNaN(date2.getTime()) ? null : date2;
63
+ }
64
+ const dateTimeRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
65
+ if (dateTimeRegex.test(val)) {
66
+ const date2 = new Date(val);
67
+ return isNaN(date2.getTime()) ? null : date2;
68
+ }
69
+ const date = new Date(val);
70
+ return isNaN(date.getTime()) ? null : date;
71
+ };
72
+
73
+ // src/utils/create-field-state.ts
74
+ var createFieldState = (name, id, config) => {
75
+ return {
76
+ ...config.config,
77
+ id,
78
+ name,
79
+ type: config.type,
80
+ value: config.config?.defaultValue ?? getDefaultValue(config),
81
+ validations: [
82
+ ...config.config?.validations ?? [],
83
+ ...getDefaultValidations(config)
84
+ ],
85
+ errors: [],
86
+ touched: false,
87
+ focused: false
88
+ };
89
+ };
90
+ function getDefaultValue(config) {
91
+ switch (config.type) {
92
+ case "checkbox":
93
+ return false;
94
+ case "range":
95
+ return config.config.min ?? 0;
96
+ case "select":
97
+ case "creatable":
98
+ return null;
99
+ case "file":
100
+ return [];
101
+ case "color":
102
+ return "#000000";
103
+ case "number":
104
+ case "text":
105
+ default:
106
+ return "";
107
+ }
108
+ }
109
+ function getDefaultValidations(config) {
110
+ const validations = [];
111
+ if (config.config?.required) {
112
+ validations.push(isRequired());
113
+ }
114
+ switch (config.type) {
115
+ case "email":
116
+ validations.push(isEmail());
117
+ break;
118
+ case "number":
119
+ case "range":
120
+ if (config.config?.min) validations.push(isBiggerThan(config.config?.min));
121
+ if (config.config?.max) validations.push(isSmallerThan(config.config?.max));
122
+ break;
123
+ case "date":
124
+ case "datetime-local":
125
+ case "time":
126
+ const min = config.config?.min;
127
+ const max = config.config?.max;
128
+ const parsedMin = parseDateValue(min);
129
+ const parsedMax = parseDateValue(max);
130
+ if (parsedMin) validations.push(dateIsBiggerThan(parsedMin));
131
+ if (parsedMax) validations.push(dateIsSmallerThan(parsedMax));
132
+ break;
133
+ case "url":
134
+ if (config.config?.pattern) validations.push(isPattern(config.config.pattern));
135
+ validations.push(
136
+ isUrl(
137
+ config.config?.allowLocalhost || false,
138
+ config.config?.allowFtp || false,
139
+ config.config?.secureOnly || !(config.config?.allowLocalhost || config.config?.allowFtp)
140
+ )
141
+ );
142
+ break;
143
+ case "text":
144
+ case "tel":
145
+ if (config.config?.pattern) validations.push(isPattern(config.config.pattern));
146
+ break;
147
+ }
148
+ return validations;
149
+ }
150
+
151
+ // src/utils/get-column-classes.ts
152
+ var getColumnClasses = (layout, className) => {
153
+ if (!layout) return "sio-col-xs-12";
154
+ const classes = [];
155
+ if (className) classes.push(className);
156
+ if (layout.sm) classes.push(`sio-col-sm-${layout.sm}`);
157
+ if (layout.md) classes.push(`sio-col-md-${layout.md}`);
158
+ if (layout.lg) classes.push(`sio-col-lg-${layout.lg}`);
159
+ if (layout.order) {
160
+ if (layout.order.sm) classes.push(`sio-order-sm-${layout.order.sm}`);
161
+ if (layout.order.md) classes.push(`sio-order-md-${layout.order.md}`);
162
+ if (layout.order.lg) classes.push(`sio-order-lg-${layout.order.lg}`);
163
+ }
164
+ return classes.join(" ");
165
+ };
166
+
167
+ // src/utils/create-field-props.ts
168
+ var createFieldProps = (field, setters, disabled, renderLayout = false) => {
169
+ const classes = getColumnClasses(field.layout, field.styling?.className);
170
+ const baseProps = {
171
+ id: field.id,
172
+ name: field.name,
173
+ label: field.label,
174
+ placeholder: field.placeholder,
175
+ value: field.value,
176
+ errors: field.errors,
177
+ required: field.required,
178
+ autocomplete: field.autocomplete,
179
+ touched: field.touched,
180
+ focused: field.focused,
181
+ readOnly: field.readOnly,
182
+ disabled,
183
+ icon: field.icon,
184
+ description: field.description,
185
+ onChange: setters.handleChange,
186
+ setFocused: setters.setFocused,
187
+ setTouched: setters.setTouched,
188
+ className: renderLayout ? classes : field.styling?.className,
189
+ style: field.styling?.style
190
+ };
191
+ if (field.type === "textarea") {
192
+ return {
193
+ ...baseProps,
194
+ type: field.type,
195
+ rows: field.rows,
196
+ cols: field.cols
197
+ };
198
+ }
199
+ if (field.type === "file") {
200
+ return {
201
+ ...baseProps,
202
+ type: field.type,
203
+ accept: field.accept,
204
+ multiple: field.multiple ?? false,
205
+ capture: field.capture ?? false,
206
+ onError: setters.setErrors,
207
+ filesize: field.filesize ?? 10240,
208
+ onFileRemove: field.onFileRemove,
209
+ onRemoveAll: field.onRemoveAll
210
+ };
211
+ }
212
+ if (field.type === "range" || field.type === "number") {
213
+ const numberProps = {
214
+ ...baseProps,
215
+ type: field.type,
216
+ min: field.min ?? Number.MIN_SAFE_INTEGER,
217
+ max: field.max ?? Number.MAX_SAFE_INTEGER,
218
+ step: field.step ?? 1
219
+ };
220
+ if (field.type === "number") {
221
+ return {
222
+ ...numberProps,
223
+ spinner: field.spinner ?? true
224
+ };
225
+ }
226
+ if (field.type === "range") {
227
+ return {
228
+ ...numberProps,
229
+ showValue: field.showValue ?? true
230
+ };
231
+ }
232
+ }
233
+ if (field.type === "date" || field.type === "time" || field.type === "datetime-local") {
234
+ return {
235
+ ...baseProps,
236
+ type: field.type,
237
+ min: field.min ?? "",
238
+ max: field.max ?? "",
239
+ step: field.step ?? 1
240
+ };
241
+ }
242
+ if (field.type === "url") {
243
+ return {
244
+ ...baseProps,
245
+ type: field.type,
246
+ allowLocalhost: field.allowLocalhost ?? false,
247
+ allowFtp: field.allowFtp ?? false,
248
+ secureOnly: field.secureOnly ?? !(field.allowLocalhost || field.allowFtp)
249
+ };
250
+ }
251
+ if (field.type === "select" || field.type === "creatable") {
252
+ return {
253
+ ...baseProps,
254
+ type: field.type,
255
+ options: field.options || [],
256
+ multiple: field.multiple
257
+ };
258
+ }
259
+ if (field.type === "radio") {
260
+ return {
261
+ ...baseProps,
262
+ type: field.type,
263
+ options: field.options || [],
264
+ inline: field.inline ?? false
265
+ };
266
+ }
267
+ return { ...baseProps, type: field.type };
268
+ };
269
+
270
+ // src/hooks/useForm.ts
271
+ var useForm = ({ disableWhenOffline } = { disableWhenOffline: true }) => {
272
+ const isOnline = useConnectionStatus();
273
+ const [fields, setFields] = useState2({});
274
+ const [isDirty, setIsDirty] = useState2(false);
275
+ const [isBusy, setIsBusy] = useState2(false);
276
+ const validateField = (value, validations, label) => {
277
+ return validations.map((validation) => validation(value, label)).filter((error) => !!error);
278
+ };
279
+ const validateForm = () => {
280
+ return Object.values(fields).every((field) => field.errors?.length === 0);
281
+ };
282
+ const register = useCallback((name, config, renderLayout) => {
283
+ if (!name) throw new Error("Field name is required");
284
+ const id = slugify(name);
285
+ const existing = fields[name];
286
+ const shouldCreate = !existing || existing.type !== config.type;
287
+ let field;
288
+ if (shouldCreate) {
289
+ field = createFieldState(name, id, config);
290
+ setFields((prevState) => ({
291
+ ...prevState,
292
+ [name]: {
293
+ ...field,
294
+ errors: validateField(field.value, field.validations, field.label)
295
+ }
296
+ }));
297
+ } else {
298
+ field = existing;
299
+ }
300
+ const setters = {
301
+ handleChange: (value) => {
302
+ setIsDirty(true);
303
+ setFields((prevState) => {
304
+ const current = prevState[name];
305
+ if (!current) return prevState;
306
+ return {
307
+ ...prevState,
308
+ [name]: {
309
+ ...current,
310
+ value,
311
+ errors: validateField(value, current.validations, current.label)
312
+ }
313
+ };
314
+ });
315
+ },
316
+ setFocused: (focused) => {
317
+ setFields((prevState) => {
318
+ const current = prevState[name];
319
+ if (!current) return prevState;
320
+ return {
321
+ ...prevState,
322
+ [name]: {
323
+ ...current,
324
+ focused
325
+ }
326
+ };
327
+ });
328
+ },
329
+ setTouched: (touched) => {
330
+ setFields((prevState) => {
331
+ const current = prevState[name];
332
+ if (!current) return prevState;
333
+ return {
334
+ ...prevState,
335
+ [name]: {
336
+ ...current,
337
+ touched
338
+ }
339
+ };
340
+ });
341
+ },
342
+ setErrors: (errors) => {
343
+ setFields((prevState) => {
344
+ const current = prevState[name];
345
+ if (!current) return prevState;
346
+ return {
347
+ ...prevState,
348
+ [name]: {
349
+ ...current,
350
+ errors
351
+ }
352
+ };
353
+ });
354
+ }
355
+ };
356
+ return createFieldProps(
357
+ field,
358
+ setters,
359
+ config.config?.disabled || !isOnline && disableWhenOffline,
360
+ renderLayout
361
+ );
362
+ }, [disableWhenOffline, isOnline, fields]);
363
+ const unregister = (name) => {
364
+ setFields((prevState) => {
365
+ const { [name]: _, ...rest } = prevState;
366
+ return rest;
367
+ });
368
+ };
369
+ const setValue = (name, value) => {
370
+ if (fields[name]) {
371
+ setFields((prevState) => {
372
+ const current = prevState[name];
373
+ if (!current) return prevState;
374
+ return {
375
+ ...prevState,
376
+ [name]: {
377
+ ...current,
378
+ value,
379
+ errors: validateField(
380
+ value,
381
+ prevState[name].validations,
382
+ prevState[name].label
383
+ )
384
+ }
385
+ };
386
+ });
387
+ }
388
+ };
389
+ const getValues = () => {
390
+ return Object.keys(fields).reduce((acc, key) => {
391
+ acc[key] = fields[key].value || null;
392
+ return acc;
393
+ }, {});
394
+ };
395
+ const getValue = (name) => {
396
+ return fields[name]?.value ?? null;
397
+ };
398
+ const reset = () => {
399
+ setFields({});
400
+ setIsDirty(false);
401
+ setIsBusy(false);
402
+ };
403
+ const handleSubmit = async (onSubmit) => {
404
+ if (isBusy) return;
405
+ try {
406
+ setIsBusy(true);
407
+ await onSubmit(getValues());
408
+ } finally {
409
+ setIsBusy(false);
410
+ }
411
+ };
412
+ const getField = (name) => {
413
+ return fields[name] || void 0;
414
+ };
415
+ return {
416
+ register,
417
+ unregister,
418
+ setValue,
419
+ getValues,
420
+ getValue,
421
+ reset,
422
+ isValid: validateForm,
423
+ isDirty: () => isDirty,
424
+ isBusy: () => isBusy,
425
+ submit: handleSubmit,
426
+ getField
427
+ };
428
+ };
429
+
430
+ // src/components/Fields/InputWrapper/index.tsx
431
+ import { memo } from "react";
432
+ import { jsx, jsxs } from "react/jsx-runtime";
433
+ var InputWrapper = ({
434
+ type = "text",
435
+ id,
436
+ label,
437
+ description,
438
+ required = false,
439
+ focused = false,
440
+ disabled = false,
441
+ hasValue = false,
442
+ hasError = false,
443
+ errors = [],
444
+ hideLayout = false,
445
+ className = "",
446
+ style = {},
447
+ children
448
+ }) => {
449
+ const classes = [
450
+ "form-field",
451
+ `form-field__${type}`,
452
+ focused && "form-field--focused",
453
+ hasValue && "form-field--has-value",
454
+ hasError && "form-field--has-errors",
455
+ disabled && "form-field--disabled",
456
+ hideLayout && "form-field--hidden-layout",
457
+ className
458
+ ].filter(Boolean).join(" ");
459
+ return /* @__PURE__ */ jsxs(
460
+ "div",
461
+ {
462
+ className: classes,
463
+ style,
464
+ "aria-required": required,
465
+ "aria-invalid": hasError,
466
+ children: [
467
+ label && /* @__PURE__ */ jsxs("label", { htmlFor: id, id: `${id}-label`, children: [
468
+ label,
469
+ " ",
470
+ required && /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "*" })
471
+ ] }),
472
+ /* @__PURE__ */ jsx("div", { className: `form-field__control`, children }),
473
+ description && /* @__PURE__ */ jsx("div", { className: "form-field__description", children: description }),
474
+ hasError && errors.length > 0 && /* @__PURE__ */ jsx("ul", { className: "form-field__errors", role: "alert", children: [...new Set(errors)].map((x, i) => /* @__PURE__ */ jsx("li", { className: "form-field__errors-item", children: x }, i)) })
475
+ ]
476
+ }
477
+ );
478
+ };
479
+ var InputWrapper_default = memo(InputWrapper);
480
+
481
+ // src/components/Icon/index.tsx
482
+ import { jsx as jsx2 } from "react/jsx-runtime";
483
+ var Icon = ({ icon }) => {
484
+ if (!icon) return null;
485
+ if (typeof icon === "string") {
486
+ return /* @__PURE__ */ jsx2("span", { className: "form-field__icon", children: /* @__PURE__ */ jsx2("i", { className: icon }) });
487
+ }
488
+ switch (icon.type) {
489
+ case "class":
490
+ return /* @__PURE__ */ jsx2("span", { className: "form-field__icon", children: /* @__PURE__ */ jsx2("i", { className: icon.value }) });
491
+ case "emoji":
492
+ return /* @__PURE__ */ jsx2("span", { className: "form-field__icon", children: /* @__PURE__ */ jsx2("span", { children: icon.value }) });
493
+ case "html":
494
+ return /* @__PURE__ */ jsx2("span", { dangerouslySetInnerHTML: { __html: icon.value }, className: "form-field__icon" });
495
+ }
496
+ };
497
+
498
+ // src/components/Fields/Checkbox/index.tsx
499
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
500
+ var Checkbox = ({
501
+ value,
502
+ onChange,
503
+ name,
504
+ id,
505
+ label,
506
+ required,
507
+ setTouched,
508
+ readOnly,
509
+ disabled,
510
+ icon,
511
+ description,
512
+ focused,
513
+ errors,
514
+ touched,
515
+ type,
516
+ className,
517
+ style
518
+ }) => {
519
+ return /* @__PURE__ */ jsxs2(
520
+ InputWrapper_default,
521
+ {
522
+ type,
523
+ id,
524
+ description,
525
+ required,
526
+ focused,
527
+ disabled: disabled || readOnly,
528
+ hasValue: value === true,
529
+ hasError: errors.length > 0 && touched,
530
+ errors,
531
+ className,
532
+ style,
533
+ hideLayout: true,
534
+ children: [
535
+ /* @__PURE__ */ jsx3(Icon, { icon }),
536
+ /* @__PURE__ */ jsxs2("label", { htmlFor: id, children: [
537
+ /* @__PURE__ */ jsx3(
538
+ "input",
539
+ {
540
+ name,
541
+ type,
542
+ id,
543
+ checked: value,
544
+ onChange: (e) => {
545
+ onChange?.(e.target.checked);
546
+ setTouched?.(true);
547
+ },
548
+ readOnly,
549
+ disabled
550
+ }
551
+ ),
552
+ /* @__PURE__ */ jsx3("div", { children: label }),
553
+ " ",
554
+ required && /* @__PURE__ */ jsx3("span", { "aria-hidden": true, children: "*" })
555
+ ] })
556
+ ]
557
+ }
558
+ );
559
+ };
560
+
561
+ // src/components/Fields/Input/Input.tsx
562
+ import { memo as memo2, useMemo } from "react";
563
+
564
+ // src/components/Button/index.tsx
565
+ import React2 from "react";
566
+ import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
567
+ var ButtonComponent = ({
568
+ type = "button",
569
+ label,
570
+ onClick,
571
+ variant = "primary",
572
+ color = "default",
573
+ size = "md",
574
+ block = false,
575
+ loading = false,
576
+ disabled = false,
577
+ className = "",
578
+ ariaLabel = "",
579
+ style = {},
580
+ children
581
+ }) => {
582
+ const isDisabled = disabled || loading;
583
+ const handleClick = (e) => {
584
+ if (isDisabled) {
585
+ e.preventDefault();
586
+ return;
587
+ }
588
+ onClick?.(e);
589
+ };
590
+ const buttonClasses = [
591
+ "btn",
592
+ `btn--${variant}`,
593
+ `btn--${size}`,
594
+ `btn--${color}`,
595
+ block && "btn--block",
596
+ loading && "btn--loading",
597
+ isDisabled && "btn--disabled",
598
+ className
599
+ ].filter(Boolean).join(" ");
600
+ return /* @__PURE__ */ jsx4(
601
+ "button",
602
+ {
603
+ type,
604
+ onClick: handleClick,
605
+ className: buttonClasses,
606
+ style,
607
+ disabled: isDisabled,
608
+ "aria-label": ariaLabel || label,
609
+ "aria-busy": loading,
610
+ "aria-disabled": isDisabled,
611
+ children: loading ? /* @__PURE__ */ jsxs3(Fragment, { children: [
612
+ /* @__PURE__ */ jsx4("span", { className: "btn__spinner", "aria-hidden": "true", children: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx4("circle", { cx: "10", cy: "10", r: "8" }) }) }),
613
+ /* @__PURE__ */ jsx4("span", { className: "btn__loading-text", children: "Processing..." })
614
+ ] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
615
+ children,
616
+ label
617
+ ] })
618
+ }
619
+ );
620
+ };
621
+ var Button = React2.memo(ButtonComponent);
622
+
623
+ // src/components/Fields/Input/NumberInput/index.tsx
624
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
625
+ var NumberInput = ({
626
+ value,
627
+ min,
628
+ max,
629
+ step = 1,
630
+ spinner = true,
631
+ onChange,
632
+ name,
633
+ id,
634
+ placeholder,
635
+ label,
636
+ required,
637
+ autocomplete,
638
+ setTouched,
639
+ setFocused,
640
+ readOnly,
641
+ disabled,
642
+ icon,
643
+ description,
644
+ focused,
645
+ errors,
646
+ touched,
647
+ type,
648
+ className,
649
+ style
650
+ }) => {
651
+ const getPrecision = (step2) => {
652
+ const stepStr = step2.toString();
653
+ if (!stepStr.includes(".")) return 0;
654
+ return stepStr.split(".")[1].length;
655
+ };
656
+ const handleIncrement = () => {
657
+ const newValue = Math.max(min ?? 0, Math.min(Number(value) + step, max ?? Infinity));
658
+ onChange(newValue.toFixed(getPrecision(step)));
659
+ };
660
+ const handleDecrement = () => {
661
+ const newValue = Math.max(Number(value) - step, min ?? -Infinity);
662
+ onChange(newValue.toFixed(getPrecision(step)));
663
+ };
664
+ const handleKeyDown = (e) => {
665
+ if (e.key === "ArrowUp") {
666
+ e.preventDefault();
667
+ handleIncrement();
668
+ } else if (e.key === "ArrowDown") {
669
+ e.preventDefault();
670
+ handleDecrement();
671
+ }
672
+ };
673
+ const handleChange = (e) => {
674
+ let value2 = "";
675
+ if (e.target.value) {
676
+ value2 = e.target.valueAsNumber.toString();
677
+ }
678
+ onChange(value2);
679
+ };
680
+ return /* @__PURE__ */ jsxs4(
681
+ InputWrapper_default,
682
+ {
683
+ type,
684
+ id,
685
+ label,
686
+ description,
687
+ required,
688
+ focused,
689
+ disabled: disabled || readOnly,
690
+ hasValue: !!value,
691
+ hasError: errors.length > 0 && touched,
692
+ errors,
693
+ className,
694
+ style,
695
+ children: [
696
+ spinner && spinner === "horizontal" && /* @__PURE__ */ jsx5(
697
+ Button,
698
+ {
699
+ type: "button",
700
+ variant: "link",
701
+ className: "form-field__spinner-btn",
702
+ onClick: handleDecrement,
703
+ disabled: disabled || min !== void 0 && Number(value) <= min,
704
+ "aria-label": "Decrease value",
705
+ label: "-"
706
+ }
707
+ ),
708
+ /* @__PURE__ */ jsx5(Icon, { icon }),
709
+ /* @__PURE__ */ jsx5(
710
+ "input",
711
+ {
712
+ type: "number",
713
+ value: value !== "" ? Number(value) : "",
714
+ min,
715
+ max,
716
+ step,
717
+ onChange: handleChange,
718
+ onKeyDown: (e) => {
719
+ handleKeyDown(e);
720
+ setTouched?.(true);
721
+ },
722
+ "aria-valuemin": min,
723
+ "aria-valuemax": max,
724
+ "aria-valuenow": Number(value),
725
+ name,
726
+ id,
727
+ placeholder: `${placeholder ?? ""}${!label && required ? " *" : ""}`,
728
+ autoComplete: autocomplete ? autocomplete : "off",
729
+ onBlur: () => {
730
+ setTouched?.(true);
731
+ setFocused?.(false);
732
+ },
733
+ onFocus: () => {
734
+ setFocused?.(true);
735
+ },
736
+ readOnly,
737
+ disabled,
738
+ "aria-label": label || placeholder,
739
+ style: spinner && spinner === "horizontal" ? { textAlign: "center" } : {}
740
+ }
741
+ ),
742
+ spinner && (spinner === "horizontal" ? /* @__PURE__ */ jsx5(
743
+ Button,
744
+ {
745
+ type: "button",
746
+ variant: "link",
747
+ className: "form-field__spinner-btn",
748
+ onClick: handleIncrement,
749
+ disabled: disabled || max !== void 0 && Number(value) >= max,
750
+ "aria-label": "Increase value",
751
+ label: "+"
752
+ }
753
+ ) : /* @__PURE__ */ jsxs4("div", { className: "form-field__spinner", "aria-hidden": "true", children: [
754
+ /* @__PURE__ */ jsx5(
755
+ Button,
756
+ {
757
+ type: "button",
758
+ onClick: handleIncrement,
759
+ disabled: disabled || max !== void 0 && Number(value) >= max,
760
+ "aria-label": "Increase value",
761
+ label: "\u25B2"
762
+ }
763
+ ),
764
+ /* @__PURE__ */ jsx5(
765
+ Button,
766
+ {
767
+ type: "button",
768
+ onClick: handleDecrement,
769
+ disabled: disabled || min !== void 0 && Number(value) <= min,
770
+ "aria-label": "Decrease value",
771
+ label: "\u25BC"
772
+ }
773
+ )
774
+ ] }))
775
+ ]
776
+ }
777
+ );
778
+ };
779
+
780
+ // src/components/Fields/Input/RangeInput/index.tsx
781
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
782
+ var RangeInput = ({
783
+ value,
784
+ min,
785
+ max,
786
+ step = 1,
787
+ showValue = true,
788
+ onChange,
789
+ name,
790
+ id,
791
+ placeholder,
792
+ label,
793
+ required,
794
+ autocomplete,
795
+ setTouched,
796
+ setFocused,
797
+ readOnly,
798
+ disabled,
799
+ icon,
800
+ description,
801
+ focused,
802
+ errors,
803
+ touched,
804
+ type,
805
+ className,
806
+ style
807
+ }) => {
808
+ return /* @__PURE__ */ jsxs5(
809
+ InputWrapper_default,
810
+ {
811
+ type,
812
+ id,
813
+ label,
814
+ description,
815
+ required,
816
+ focused,
817
+ disabled: disabled || readOnly,
818
+ hasValue: !!value,
819
+ hasError: errors.length > 0 && touched,
820
+ errors,
821
+ className,
822
+ style,
823
+ children: [
824
+ /* @__PURE__ */ jsx6(Icon, { icon }),
825
+ showValue && /* @__PURE__ */ jsx6("span", { className: "form-field__range-value", children: Number(value) }),
826
+ /* @__PURE__ */ jsx6(
827
+ "input",
828
+ {
829
+ type,
830
+ name,
831
+ id,
832
+ value: Number(value),
833
+ autoComplete: autocomplete ? autocomplete : "off",
834
+ onChange: (e) => onChange(Number(e.target.value)),
835
+ onBlur: () => {
836
+ if (setTouched) setTouched(true);
837
+ if (setFocused) setFocused(false);
838
+ },
839
+ onFocus: () => {
840
+ if (setFocused) setFocused(true);
841
+ },
842
+ min,
843
+ max,
844
+ step,
845
+ "aria-valuemin": min,
846
+ "aria-valuemax": max,
847
+ "aria-valuenow": Number(value),
848
+ readOnly,
849
+ disabled,
850
+ "aria-label": label || placeholder
851
+ }
852
+ )
853
+ ]
854
+ }
855
+ );
856
+ };
857
+
858
+ // src/components/Fields/Input/DateInput/index.tsx
859
+ import { useRef } from "react";
860
+
861
+ // src/utils/custom-icons.tsx
862
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
863
+ var CustomIcons = {
864
+ Date: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
865
+ /* @__PURE__ */ jsx7("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2", stroke: "currentColor", fill: "none" }),
866
+ /* @__PURE__ */ jsx7("line", { x1: "8", y1: "2", x2: "8", y2: "6", stroke: "currentColor" }),
867
+ /* @__PURE__ */ jsx7("line", { x1: "16", y1: "2", x2: "16", y2: "6", stroke: "currentColor" }),
868
+ /* @__PURE__ */ jsx7("line", { x1: "3", y1: "10", x2: "21", y2: "10", stroke: "currentColor" })
869
+ ] }),
870
+ Time: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
871
+ /* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "10" }),
872
+ /* @__PURE__ */ jsx7("polyline", { points: "12 6 12 12 16 14" }),
873
+ /* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "1", fill: "currentColor", fillOpacity: "0.3", stroke: "none" })
874
+ ] }),
875
+ DateTime: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
876
+ /* @__PURE__ */ jsx7("rect", { x: "2", y: "3", width: "14", height: "14", rx: "2", ry: "2" }),
877
+ /* @__PURE__ */ jsx7("line", { x1: "5", y1: "2", x2: "5", y2: "5" }),
878
+ /* @__PURE__ */ jsx7("line", { x1: "13", y1: "2", x2: "13", y2: "5" }),
879
+ /* @__PURE__ */ jsx7("line", { x1: "2", y1: "7", x2: "16", y2: "7" }),
880
+ /* @__PURE__ */ jsx7("circle", { cx: "19", cy: "15", r: "4" }),
881
+ /* @__PURE__ */ jsx7("polyline", { points: "19 13 19 15 21 16" })
882
+ ] }),
883
+ FileUpload: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
884
+ /* @__PURE__ */ jsx7("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }),
885
+ /* @__PURE__ */ jsx7("polyline", { points: "13 2 13 9 20 9" }),
886
+ /* @__PURE__ */ jsx7("path", { d: "M12 12v6m0-6 2 2m-2-2-2 2" })
887
+ ] }),
888
+ CloudUpload: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
889
+ /* @__PURE__ */ jsx7("path", { d: "M12 16v-6m0 0-2 2m2-2 2 2" }),
890
+ /* @__PURE__ */ jsx7("path", { d: "M16 16h3a4 4 0 0 0 0-8h-1.5A5.5 5.5 0 0 0 7 9a5 5 0 0 0-1 9.8" })
891
+ ] }),
892
+ TrashIcon: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
893
+ /* @__PURE__ */ jsx7("path", { d: "M3 6h18" }),
894
+ /* @__PURE__ */ jsx7("rect", { x: "6", y: "6", width: "12", height: "14", rx: "1", ry: "1" }),
895
+ /* @__PURE__ */ jsx7("path", { d: "M9 3h6" }),
896
+ /* @__PURE__ */ jsx7("path", { d: "M10 3v3M14 3v3" }),
897
+ /* @__PURE__ */ jsx7("line", { x1: "10", y1: "10", x2: "10", y2: "16" }),
898
+ /* @__PURE__ */ jsx7("line", { x1: "14", y1: "10", x2: "14", y2: "16" })
899
+ ] }),
900
+ SimpleTrashIcon: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
901
+ /* @__PURE__ */ jsx7("path", { d: "M3 6h18" }),
902
+ /* @__PURE__ */ jsx7("rect", { x: "6", y: "8", width: "12", height: "12", rx: "1", ry: "1" }),
903
+ /* @__PURE__ */ jsx7("path", { d: "M9 4h6" })
904
+ ] }),
905
+ DeleteTrashIcon: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
906
+ /* @__PURE__ */ jsx7("path", { d: "M3 6h18" }),
907
+ /* @__PURE__ */ jsx7("rect", { x: "6", y: "6", width: "12", height: "14", rx: "1", ry: "1" }),
908
+ /* @__PURE__ */ jsx7("path", { d: "M9 3h6" }),
909
+ /* @__PURE__ */ jsx7("path", { d: "M10 3v3M14 3v3" }),
910
+ /* @__PURE__ */ jsx7("line", { x1: "9", y1: "10", x2: "15", y2: "16" }),
911
+ /* @__PURE__ */ jsx7("line", { x1: "15", y1: "10", x2: "9", y2: "16" })
912
+ ] }),
913
+ FileIcon: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
914
+ /* @__PURE__ */ jsx7("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }),
915
+ /* @__PURE__ */ jsx7("polyline", { points: "13 2 13 9 20 9" })
916
+ ] }),
917
+ Word: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
918
+ /* @__PURE__ */ jsx7("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }),
919
+ /* @__PURE__ */ jsx7("polyline", { points: "13 2 13 9 20 9" }),
920
+ /* @__PURE__ */ jsx7("line", { x1: "8", y1: "13", x2: "16", y2: "13" }),
921
+ /* @__PURE__ */ jsx7("line", { x1: "8", y1: "16", x2: "16", y2: "16" }),
922
+ /* @__PURE__ */ jsx7("line", { x1: "8", y1: "19", x2: "13", y2: "19" })
923
+ ] }),
924
+ Excel: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
925
+ /* @__PURE__ */ jsx7("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }),
926
+ /* @__PURE__ */ jsx7("polyline", { points: "13 2 13 9 20 9" }),
927
+ /* @__PURE__ */ jsx7("rect", { x: "7", y: "12", width: "10", height: "7", rx: "1" }),
928
+ /* @__PURE__ */ jsx7("line", { x1: "7", y1: "15.5", x2: "17", y2: "15.5" }),
929
+ /* @__PURE__ */ jsx7("line", { x1: "11.5", y1: "12", x2: "11.5", y2: "19" })
930
+ ] }),
931
+ PowerPoint: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
932
+ /* @__PURE__ */ jsx7("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }),
933
+ /* @__PURE__ */ jsx7("polyline", { points: "13 2 13 9 20 9" }),
934
+ /* @__PURE__ */ jsx7("rect", { x: "7", y: "12", width: "10", height: "7", rx: "1" }),
935
+ /* @__PURE__ */ jsx7("path", { d: "M9 17l2-3 2 2 2-3" })
936
+ ] }),
937
+ Pdf: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
938
+ /* @__PURE__ */ jsx7("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }),
939
+ /* @__PURE__ */ jsx7("polyline", { points: "13 2 13 9 20 9" }),
940
+ /* @__PURE__ */ jsx7("rect", { x: "7", y: "14", width: "10", height: "4", rx: "1" })
941
+ ] }),
942
+ Image: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
943
+ /* @__PURE__ */ jsx7("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }),
944
+ /* @__PURE__ */ jsx7("polyline", { points: "13 2 13 9 20 9" }),
945
+ /* @__PURE__ */ jsx7("circle", { cx: "9", cy: "13", r: "1.5" }),
946
+ /* @__PURE__ */ jsx7("path", { d: "M7 18l3-3 2 2 3-3 2 4" })
947
+ ] }),
948
+ Audio: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
949
+ /* @__PURE__ */ jsx7("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }),
950
+ /* @__PURE__ */ jsx7("polyline", { points: "13 2 13 9 20 9" }),
951
+ /* @__PURE__ */ jsx7("path", { d: "M8 16v-2" }),
952
+ /* @__PURE__ */ jsx7("path", { d: "M10 17v-4" }),
953
+ /* @__PURE__ */ jsx7("path", { d: "M12 18v-6" }),
954
+ /* @__PURE__ */ jsx7("path", { d: "M14 17v-4" }),
955
+ /* @__PURE__ */ jsx7("path", { d: "M16 16v-2" })
956
+ ] }),
957
+ Video: () => /* @__PURE__ */ jsxs6("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
958
+ /* @__PURE__ */ jsx7("path", { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }),
959
+ /* @__PURE__ */ jsx7("polyline", { points: "13 2 13 9 20 9" }),
960
+ /* @__PURE__ */ jsx7("rect", { x: "7", y: "12", width: "8", height: "6", rx: "1" }),
961
+ /* @__PURE__ */ jsx7("polygon", { points: "11 14 14 15 11 16" })
962
+ ] }),
963
+ Globe: () => /* @__PURE__ */ jsxs6(
964
+ "svg",
965
+ {
966
+ width: "20",
967
+ height: "20",
968
+ viewBox: "0 0 24 24",
969
+ fill: "none",
970
+ stroke: "currentColor",
971
+ strokeWidth: "1.5",
972
+ strokeLinecap: "round",
973
+ strokeLinejoin: "round",
974
+ children: [
975
+ /* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "10" }),
976
+ /* @__PURE__ */ jsx7("path", { d: "M2 12h20" }),
977
+ /* @__PURE__ */ jsx7("path", { d: "M12 2a15.3 15.3 0 0 1 0 20 15.3 15.3 0 0 1 0-20z" })
978
+ ]
979
+ }
980
+ )
981
+ };
982
+
983
+ // src/components/Fields/Input/DateInput/index.tsx
984
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
985
+ var DateInput = ({
986
+ value,
987
+ min,
988
+ max,
989
+ step = 1,
990
+ onChange,
991
+ name,
992
+ id,
993
+ placeholder,
994
+ label,
995
+ required,
996
+ autocomplete,
997
+ setTouched,
998
+ setFocused,
999
+ readOnly,
1000
+ disabled,
1001
+ icon,
1002
+ description,
1003
+ focused,
1004
+ errors,
1005
+ touched,
1006
+ type,
1007
+ className,
1008
+ style
1009
+ }) => {
1010
+ const inputRef = useRef(null);
1011
+ const showPicker = () => {
1012
+ if (inputRef.current) {
1013
+ inputRef.current.focus();
1014
+ if (inputRef.current?.showPicker) {
1015
+ inputRef.current.showPicker();
1016
+ }
1017
+ }
1018
+ };
1019
+ return /* @__PURE__ */ jsxs7(
1020
+ InputWrapper_default,
1021
+ {
1022
+ type,
1023
+ id,
1024
+ label,
1025
+ description,
1026
+ required,
1027
+ focused,
1028
+ disabled: disabled || readOnly,
1029
+ hasValue: !!value,
1030
+ hasError: errors.length > 0 && touched,
1031
+ errors,
1032
+ className,
1033
+ style,
1034
+ children: [
1035
+ /* @__PURE__ */ jsx8(Icon, { icon }),
1036
+ /* @__PURE__ */ jsx8(
1037
+ "input",
1038
+ {
1039
+ ref: inputRef,
1040
+ type,
1041
+ value: (value ?? "").toString(),
1042
+ min,
1043
+ max,
1044
+ step,
1045
+ onChange: (e) => onChange(e.target.value),
1046
+ name,
1047
+ id,
1048
+ placeholder: `${placeholder}${!label && required ? " *" : ""}`,
1049
+ autoComplete: autocomplete ? autocomplete : "off",
1050
+ onBlur: () => {
1051
+ if (setTouched) setTouched(true);
1052
+ if (setFocused) setFocused(false);
1053
+ },
1054
+ onFocus: () => {
1055
+ if (setFocused) setFocused(true);
1056
+ },
1057
+ readOnly,
1058
+ disabled,
1059
+ "aria-label": label || placeholder
1060
+ }
1061
+ ),
1062
+ /* @__PURE__ */ jsx8(
1063
+ Button,
1064
+ {
1065
+ className: "form-field__action",
1066
+ type: "button",
1067
+ onClick: showPicker,
1068
+ disabled,
1069
+ "aria-label": `Open ${type} picker`,
1070
+ label: type === "date" ? CustomIcons.Date() : type === "time" ? CustomIcons.Time() : CustomIcons.DateTime()
1071
+ }
1072
+ )
1073
+ ]
1074
+ }
1075
+ );
1076
+ };
1077
+
1078
+ // src/components/Fields/Input/FileInput/index.tsx
1079
+ import { isValidFile } from "@sio-group/form-validation";
1080
+
1081
+ // src/utils/get-accept-string.ts
1082
+ var getAccept = (accept) => {
1083
+ if (Array.isArray(accept)) {
1084
+ return accept.map((item) => {
1085
+ if (item === "image") return "image/*";
1086
+ if (item === "video") return "video/*";
1087
+ if (item === "audio") return "audio/*";
1088
+ return item;
1089
+ }).join(", ");
1090
+ }
1091
+ if (accept === "image") return "image/*";
1092
+ if (accept === "video") return "video/*";
1093
+ if (accept === "audio") return "audio/*";
1094
+ return accept;
1095
+ };
1096
+
1097
+ // src/utils/get-file-size.ts
1098
+ var getFileSize = (size) => {
1099
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
1100
+ if (size === 0) return "0 Bytes";
1101
+ const i = Math.floor(Math.log(size) / Math.log(1024));
1102
+ return `${Math.round(size / Math.pow(1024, i))} ${sizes[i]}`;
1103
+ };
1104
+
1105
+ // src/utils/file-type-icon.ts
1106
+ var FileTypeIcon = (mime) => {
1107
+ let icon;
1108
+ switch (mime) {
1109
+ case "text/plain":
1110
+ icon = CustomIcons.FileIcon();
1111
+ break;
1112
+ case "text/uri-list":
1113
+ return CustomIcons.Globe();
1114
+ case "application/xls":
1115
+ case "application/vnd.ms-excel":
1116
+ case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
1117
+ case "application/vnd.ms-excel.sheet.macroEnabled.12":
1118
+ case "application/vnd.ms-excel.sheet.binary.macroEnabled.12":
1119
+ icon = CustomIcons.Excel();
1120
+ break;
1121
+ case "application/msword":
1122
+ case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
1123
+ case "application/vnd.ms-word":
1124
+ case "application/vnd.ms-word.document.macroEnabled.12":
1125
+ icon = CustomIcons.Word();
1126
+ break;
1127
+ case "application/vnd.ms-powerpoint":
1128
+ case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
1129
+ case "application/vnd.ms-powerpoint.presentation.macroEnabled.12":
1130
+ case "application/vnd.openxmlformats-officedocument.presentationml.slideshow":
1131
+ icon = CustomIcons.PowerPoint();
1132
+ break;
1133
+ case "application/pdf":
1134
+ icon = CustomIcons.Pdf();
1135
+ break;
1136
+ case "audio/mpeg":
1137
+ case "audio/wav":
1138
+ case "audio/x-wav":
1139
+ case "audio/ogg":
1140
+ case "audio/mp4":
1141
+ icon = CustomIcons.Audio();
1142
+ break;
1143
+ case "image/jpeg":
1144
+ case "image/png":
1145
+ case "image/bmp":
1146
+ case "image/gif":
1147
+ case "image/webp":
1148
+ case "image/svg+xml":
1149
+ case "image/heic":
1150
+ case "image/heif":
1151
+ icon = CustomIcons.Image();
1152
+ break;
1153
+ case "video/mp4":
1154
+ case "video/quicktime":
1155
+ case "video/webm":
1156
+ case "video/x-msvideo":
1157
+ case "video/x-matroska":
1158
+ icon = CustomIcons.Video();
1159
+ break;
1160
+ default:
1161
+ icon = CustomIcons.FileIcon();
1162
+ }
1163
+ return icon;
1164
+ };
1165
+
1166
+ // src/components/Fields/Input/FileInput/index.tsx
1167
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1168
+ var FileInput = ({
1169
+ value,
1170
+ onChange,
1171
+ onError,
1172
+ accept,
1173
+ filesize,
1174
+ multiple = false,
1175
+ capture,
1176
+ onFileRemove,
1177
+ onRemoveAll,
1178
+ name,
1179
+ id,
1180
+ placeholder,
1181
+ label,
1182
+ required,
1183
+ autocomplete,
1184
+ setTouched,
1185
+ setFocused,
1186
+ readOnly,
1187
+ disabled,
1188
+ icon,
1189
+ description,
1190
+ focused,
1191
+ errors,
1192
+ touched,
1193
+ type,
1194
+ className,
1195
+ style
1196
+ }) => {
1197
+ const currentFiles = value ?? [];
1198
+ const handleRemove = (index) => {
1199
+ const removedFile = currentFiles[index];
1200
+ const newFiles = currentFiles.filter((_, i) => i !== index);
1201
+ onChange(newFiles);
1202
+ onFileRemove?.(removedFile, index, newFiles);
1203
+ };
1204
+ const handleRemoveAll = () => {
1205
+ const removedFiles = [...currentFiles];
1206
+ onChange([]);
1207
+ onRemoveAll?.(removedFiles);
1208
+ };
1209
+ const handleChange = (e) => {
1210
+ const files = Array.from(e.target.files ?? []);
1211
+ const validator = isValidFile(filesize, getAccept(accept));
1212
+ let fileList = [...currentFiles];
1213
+ const errorList = [];
1214
+ for (let file of files) {
1215
+ const error = validator(file);
1216
+ if (error) {
1217
+ errorList.push(error);
1218
+ } else {
1219
+ if (multiple) {
1220
+ fileList.push(file);
1221
+ } else {
1222
+ fileList = [file];
1223
+ }
1224
+ }
1225
+ }
1226
+ onChange(fileList);
1227
+ if (onError) onError(errorList ?? []);
1228
+ };
1229
+ return /* @__PURE__ */ jsxs8(Fragment2, { children: [
1230
+ /* @__PURE__ */ jsxs8(
1231
+ InputWrapper_default,
1232
+ {
1233
+ type,
1234
+ id,
1235
+ label,
1236
+ description,
1237
+ required,
1238
+ focused,
1239
+ disabled: disabled || readOnly,
1240
+ hasValue: currentFiles.length > 0,
1241
+ hasError: errors.length > 0 && touched,
1242
+ errors,
1243
+ className,
1244
+ style,
1245
+ children: [
1246
+ /* @__PURE__ */ jsx9(Icon, { icon }),
1247
+ /* @__PURE__ */ jsx9(
1248
+ "input",
1249
+ {
1250
+ type,
1251
+ name,
1252
+ id,
1253
+ placeholder: `${placeholder}${!label && required ? " *" : ""}`,
1254
+ autoComplete: autocomplete ? autocomplete : "off",
1255
+ onChange: handleChange,
1256
+ onBlur: () => {
1257
+ if (setTouched) setTouched(true);
1258
+ if (setFocused) setFocused(false);
1259
+ },
1260
+ onFocus: () => {
1261
+ if (setFocused) setFocused(true);
1262
+ },
1263
+ accept: getAccept(accept),
1264
+ capture,
1265
+ readOnly,
1266
+ disabled,
1267
+ "aria-label": label || placeholder,
1268
+ multiple
1269
+ }
1270
+ ),
1271
+ /* @__PURE__ */ jsx9(
1272
+ Button,
1273
+ {
1274
+ className: "form-field__action",
1275
+ type: "button",
1276
+ onClick: () => {
1277
+ if (setTouched) setTouched(true);
1278
+ document.getElementById(id)?.click();
1279
+ },
1280
+ disabled,
1281
+ "aria-label": "Select files",
1282
+ label: CustomIcons.FileUpload()
1283
+ }
1284
+ )
1285
+ ]
1286
+ }
1287
+ ),
1288
+ currentFiles.length !== 0 && /* @__PURE__ */ jsxs8("div", { className: "form-field__upload-file-section", children: [
1289
+ currentFiles.map((file, index) => /* @__PURE__ */ jsxs8("div", { className: "form-field__upload-file", children: [
1290
+ /* @__PURE__ */ jsxs8("div", { className: "form-field__upload-file-label", children: [
1291
+ FileTypeIcon(file.type || "text/uri-list"),
1292
+ /* @__PURE__ */ jsxs8("span", { children: [
1293
+ file.name,
1294
+ file.size ? ` (${getFileSize(file.size)})` : ""
1295
+ ] })
1296
+ ] }),
1297
+ /* @__PURE__ */ jsx9("div", { className: "form-field__upload-file__buttons", children: /* @__PURE__ */ jsx9(
1298
+ "button",
1299
+ {
1300
+ type: "button",
1301
+ className: "form-field__upload-file-remove-button",
1302
+ onClick: () => handleRemove(index),
1303
+ children: CustomIcons.TrashIcon()
1304
+ }
1305
+ ) })
1306
+ ] }, index)),
1307
+ /* @__PURE__ */ jsx9("div", { className: "form-field__upload-buttons", children: /* @__PURE__ */ jsxs8(
1308
+ "button",
1309
+ {
1310
+ type: "button",
1311
+ className: "form-field__upload-remove-all-button",
1312
+ onClick: handleRemoveAll,
1313
+ children: [
1314
+ CustomIcons.TrashIcon(),
1315
+ /* @__PURE__ */ jsx9("span", { children: "Verwijder alles" })
1316
+ ]
1317
+ }
1318
+ ) })
1319
+ ] })
1320
+ ] });
1321
+ };
1322
+
1323
+ // src/components/Fields/Input/TextInput/index.tsx
1324
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1325
+ var TextInput = ({
1326
+ value,
1327
+ onChange,
1328
+ name,
1329
+ id,
1330
+ placeholder,
1331
+ label,
1332
+ required,
1333
+ autocomplete,
1334
+ setTouched,
1335
+ setFocused,
1336
+ readOnly,
1337
+ disabled,
1338
+ icon,
1339
+ description,
1340
+ focused,
1341
+ errors,
1342
+ touched,
1343
+ type,
1344
+ className,
1345
+ style
1346
+ }) => {
1347
+ return /* @__PURE__ */ jsxs9(
1348
+ InputWrapper_default,
1349
+ {
1350
+ type,
1351
+ id,
1352
+ label,
1353
+ description,
1354
+ required,
1355
+ focused,
1356
+ disabled: disabled || readOnly,
1357
+ hasValue: !!value,
1358
+ hasError: errors.length > 0 && touched,
1359
+ errors,
1360
+ className,
1361
+ style,
1362
+ children: [
1363
+ /* @__PURE__ */ jsx10(Icon, { icon }),
1364
+ /* @__PURE__ */ jsx10(
1365
+ "input",
1366
+ {
1367
+ type,
1368
+ name,
1369
+ id,
1370
+ value,
1371
+ placeholder: `${placeholder ?? ""}${!label && required ? " *" : ""}`,
1372
+ autoComplete: autocomplete ? autocomplete : "off",
1373
+ onChange: (e) => onChange(e.target.value),
1374
+ onBlur: () => {
1375
+ if (setTouched) setTouched(true);
1376
+ if (setFocused) setFocused(false);
1377
+ },
1378
+ onFocus: () => {
1379
+ if (setFocused) setFocused(true);
1380
+ },
1381
+ readOnly,
1382
+ disabled,
1383
+ "aria-label": label || placeholder
1384
+ }
1385
+ )
1386
+ ]
1387
+ }
1388
+ );
1389
+ };
1390
+
1391
+ // src/components/Fields/Input/Input.tsx
1392
+ import { jsx as jsx11 } from "react/jsx-runtime";
1393
+ var Input = memo2(
1394
+ (props) => {
1395
+ const { type = "text" } = props;
1396
+ return useMemo(() => {
1397
+ switch (props.type) {
1398
+ case "number":
1399
+ return /* @__PURE__ */ jsx11(NumberInput, { ...props });
1400
+ case "range":
1401
+ return /* @__PURE__ */ jsx11(RangeInput, { ...props });
1402
+ case "date":
1403
+ case "time":
1404
+ case "datetime-local":
1405
+ return /* @__PURE__ */ jsx11(DateInput, { ...props });
1406
+ case "file":
1407
+ return /* @__PURE__ */ jsx11(FileInput, { ...props });
1408
+ case "hidden":
1409
+ return /* @__PURE__ */ jsx11(
1410
+ "input",
1411
+ {
1412
+ type: props.type,
1413
+ name: props.name,
1414
+ id: props.id,
1415
+ value: props.value
1416
+ }
1417
+ );
1418
+ default:
1419
+ return /* @__PURE__ */ jsx11(TextInput, { ...props });
1420
+ }
1421
+ }, [type, props]);
1422
+ }
1423
+ );
1424
+
1425
+ // src/components/Fields/Radio/index.tsx
1426
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1427
+ var Radio = ({
1428
+ value,
1429
+ onChange,
1430
+ options,
1431
+ inline,
1432
+ name,
1433
+ id,
1434
+ label,
1435
+ required,
1436
+ setTouched,
1437
+ readOnly,
1438
+ disabled,
1439
+ icon,
1440
+ description,
1441
+ focused,
1442
+ errors,
1443
+ touched,
1444
+ type,
1445
+ className,
1446
+ style
1447
+ }) => {
1448
+ return /* @__PURE__ */ jsxs10(
1449
+ InputWrapper_default,
1450
+ {
1451
+ type,
1452
+ id,
1453
+ label,
1454
+ description,
1455
+ required,
1456
+ focused,
1457
+ disabled: disabled || readOnly,
1458
+ hasError: errors.length > 0 && touched,
1459
+ errors,
1460
+ className: `${className ?? ""}${inline ? " form-field__radio-inline" : ""}`,
1461
+ style,
1462
+ hideLayout: true,
1463
+ children: [
1464
+ /* @__PURE__ */ jsx12(Icon, { icon }),
1465
+ options.filter((option) => typeof option === "string" || !option.hide).map((option) => {
1466
+ const opt = typeof option === "string" ? { value: option, label: option } : option;
1467
+ return /* @__PURE__ */ jsxs10(
1468
+ "label",
1469
+ {
1470
+ htmlFor: `${id}-${opt.value}`,
1471
+ className: value === opt.value ? "form-field--has-value" : "",
1472
+ children: [
1473
+ /* @__PURE__ */ jsx12(
1474
+ "input",
1475
+ {
1476
+ name,
1477
+ type,
1478
+ id: `${id}-${opt.value}`,
1479
+ value: opt.value,
1480
+ checked: value === opt.value,
1481
+ onChange: () => {
1482
+ if (onChange) onChange(opt.value);
1483
+ if (setTouched) setTouched(true);
1484
+ },
1485
+ readOnly,
1486
+ disabled: opt.disabled || disabled
1487
+ }
1488
+ ),
1489
+ /* @__PURE__ */ jsx12("div", { children: opt.label })
1490
+ ]
1491
+ },
1492
+ opt.value
1493
+ );
1494
+ })
1495
+ ]
1496
+ }
1497
+ );
1498
+ };
1499
+
1500
+ // src/components/Fields/Select/index.tsx
1501
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1502
+ var Select = ({
1503
+ value,
1504
+ onChange,
1505
+ options,
1506
+ multiple,
1507
+ name,
1508
+ id,
1509
+ placeholder,
1510
+ label,
1511
+ required,
1512
+ autocomplete,
1513
+ setTouched,
1514
+ setFocused,
1515
+ readOnly,
1516
+ disabled,
1517
+ icon,
1518
+ description,
1519
+ focused,
1520
+ errors,
1521
+ touched,
1522
+ type,
1523
+ className,
1524
+ style
1525
+ }) => {
1526
+ const renderOption = (option) => {
1527
+ if (typeof option === "string") {
1528
+ return /* @__PURE__ */ jsx13("option", { value: option, children: option }, option);
1529
+ }
1530
+ if ("options" in option) {
1531
+ return /* @__PURE__ */ jsx13("optgroup", { label: option.label, children: option.options.map(renderOption) }, option.label);
1532
+ }
1533
+ if (option.hide) return null;
1534
+ return /* @__PURE__ */ jsx13(
1535
+ "option",
1536
+ {
1537
+ value: option.value,
1538
+ disabled: option.disabled,
1539
+ children: option.label
1540
+ },
1541
+ option.value
1542
+ );
1543
+ };
1544
+ return /* @__PURE__ */ jsxs11(
1545
+ InputWrapper_default,
1546
+ {
1547
+ type,
1548
+ id,
1549
+ label,
1550
+ description,
1551
+ required,
1552
+ focused,
1553
+ disabled: disabled || readOnly,
1554
+ hasValue: value !== void 0 && value !== null && value !== "",
1555
+ hasError: errors.length > 0 && touched,
1556
+ errors,
1557
+ className: `${className ?? ""} ${multiple ? "form-field__select-multiple" : "form-field__select-single"}`,
1558
+ style,
1559
+ children: [
1560
+ /* @__PURE__ */ jsx13(Icon, { icon }),
1561
+ /* @__PURE__ */ jsxs11(
1562
+ "select",
1563
+ {
1564
+ name,
1565
+ id,
1566
+ value,
1567
+ autoComplete: autocomplete ? autocomplete : "off",
1568
+ onChange: (e) => {
1569
+ if (multiple) {
1570
+ const values = Array.from(e.target.selectedOptions).map((o) => o.value);
1571
+ onChange(values);
1572
+ } else {
1573
+ onChange(e.target.value);
1574
+ }
1575
+ },
1576
+ onBlur: () => {
1577
+ if (setTouched) setTouched(true);
1578
+ if (setFocused) setFocused(false);
1579
+ },
1580
+ onFocus: () => {
1581
+ if (setFocused) setFocused(true);
1582
+ },
1583
+ disabled,
1584
+ multiple,
1585
+ "aria-label": label || placeholder,
1586
+ children: [
1587
+ placeholder && /* @__PURE__ */ jsxs11("option", { value: "", selected: true, disabled: true, children: [
1588
+ placeholder,
1589
+ !label && required ? " *" : ""
1590
+ ] }),
1591
+ options.map(renderOption)
1592
+ ]
1593
+ }
1594
+ )
1595
+ ]
1596
+ }
1597
+ );
1598
+ };
1599
+
1600
+ // src/components/Fields/Textarea/index.tsx
1601
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1602
+ var Textarea = ({
1603
+ value,
1604
+ onChange,
1605
+ rows,
1606
+ cols,
1607
+ name,
1608
+ id,
1609
+ placeholder,
1610
+ label,
1611
+ required,
1612
+ autocomplete,
1613
+ setTouched,
1614
+ setFocused,
1615
+ readOnly,
1616
+ disabled,
1617
+ icon,
1618
+ description,
1619
+ focused,
1620
+ errors,
1621
+ touched,
1622
+ type,
1623
+ className,
1624
+ style
1625
+ }) => {
1626
+ return /* @__PURE__ */ jsxs12(
1627
+ InputWrapper_default,
1628
+ {
1629
+ type,
1630
+ id,
1631
+ label,
1632
+ description,
1633
+ required,
1634
+ focused,
1635
+ disabled: disabled || readOnly,
1636
+ hasValue: !!value,
1637
+ hasError: errors.length > 0 && touched,
1638
+ errors,
1639
+ className,
1640
+ style,
1641
+ children: [
1642
+ /* @__PURE__ */ jsx14(Icon, { icon }),
1643
+ /* @__PURE__ */ jsx14(
1644
+ "textarea",
1645
+ {
1646
+ name,
1647
+ id,
1648
+ value,
1649
+ rows,
1650
+ cols,
1651
+ placeholder: `${placeholder ?? ""}${!label && required ? " *" : ""}`,
1652
+ autoComplete: autocomplete ? autocomplete : "off",
1653
+ onChange: (e) => onChange(e.target.value),
1654
+ onBlur: () => {
1655
+ if (setTouched) setTouched(true);
1656
+ if (setFocused) setFocused(false);
1657
+ },
1658
+ onFocus: () => {
1659
+ if (setFocused) setFocused(true);
1660
+ },
1661
+ readOnly,
1662
+ disabled,
1663
+ "aria-label": label || placeholder
1664
+ }
1665
+ )
1666
+ ]
1667
+ }
1668
+ );
1669
+ };
1670
+
1671
+ // src/components/Link/index.tsx
1672
+ import React4 from "react";
1673
+ import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
1674
+ var LinkComponent = ({
1675
+ label,
1676
+ to = "#",
1677
+ onClick,
1678
+ color = "default",
1679
+ size = "md",
1680
+ block = false,
1681
+ loading = false,
1682
+ disabled = false,
1683
+ className = "",
1684
+ ariaLabel = "",
1685
+ navigate,
1686
+ external = false,
1687
+ style = {},
1688
+ children
1689
+ }) => {
1690
+ const isDisabled = disabled || loading;
1691
+ const isExternal = external || /^(https?:|mailto:|tel:|ftp:)/.test(to);
1692
+ const handleClick = (e) => {
1693
+ if (isDisabled) {
1694
+ e.preventDefault();
1695
+ return;
1696
+ }
1697
+ onClick?.(e);
1698
+ if (!isExternal && navigate) {
1699
+ e.preventDefault();
1700
+ navigate();
1701
+ }
1702
+ };
1703
+ const linkClasses = [
1704
+ "link",
1705
+ `link--${color}`,
1706
+ `btn--${size}`,
1707
+ block && "link--block",
1708
+ loading && "link--loading",
1709
+ isDisabled && "link--disabled",
1710
+ className
1711
+ ].filter(Boolean).join(" ");
1712
+ return /* @__PURE__ */ jsx15(
1713
+ "a",
1714
+ {
1715
+ href: isDisabled ? void 0 : to,
1716
+ onClick: handleClick,
1717
+ className: linkClasses,
1718
+ style,
1719
+ "aria-label": ariaLabel || label,
1720
+ "aria-busy": loading,
1721
+ "aria-disabled": isDisabled,
1722
+ target: isExternal ? "_blank" : void 0,
1723
+ rel: isExternal ? "noopener noreferrer" : void 0,
1724
+ children: loading ? /* @__PURE__ */ jsxs13(Fragment3, { children: [
1725
+ /* @__PURE__ */ jsx15("span", { className: "btn__spinner", "aria-hidden": "true", children: /* @__PURE__ */ jsx15("svg", { viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx15("circle", { cx: "10", cy: "10", r: "8" }) }) }),
1726
+ /* @__PURE__ */ jsx15("span", { className: "btn__loading-text", children: "Processing..." })
1727
+ ] }) : /* @__PURE__ */ jsxs13(Fragment3, { children: [
1728
+ children,
1729
+ label && /* @__PURE__ */ jsx15("span", { className: "btn__label", children: label })
1730
+ ] })
1731
+ }
1732
+ );
1733
+ };
1734
+ var Link = React4.memo(LinkComponent);
1735
+
1736
+ // src/components/Form.tsx
1737
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
1738
+ import { createElement } from "react";
1739
+ var DefaultContainer = ({ children, ...props }) => /* @__PURE__ */ jsx16("form", { ...props, noValidate: true, children });
1740
+ var DefaultButtonContainer = ({ children }) => /* @__PURE__ */ jsx16("div", { className: "btn-group", children });
1741
+ var Form = ({
1742
+ fields,
1743
+ layout = [],
1744
+ submitShow = true,
1745
+ submitAction,
1746
+ submitLabel = "Bewaar",
1747
+ cancelShow = false,
1748
+ cancelAction,
1749
+ cancelLabel = "Annuleren",
1750
+ buttons = [],
1751
+ extraValidation = () => true,
1752
+ className,
1753
+ style,
1754
+ disableWhenOffline = false,
1755
+ container: Container = DefaultContainer,
1756
+ buttonContainer: ButtonContainer = DefaultButtonContainer
1757
+ }) => {
1758
+ const { register, getValues, isValid, isBusy, isDirty, reset, submit } = useForm({
1759
+ disableWhenOffline
1760
+ });
1761
+ const loadElement = (field, renderLayout = false) => {
1762
+ switch (field.type) {
1763
+ case "textarea":
1764
+ return /* @__PURE__ */ createElement(Textarea, { ...register(field.name, field, renderLayout), key: field.name });
1765
+ case "checkbox":
1766
+ return /* @__PURE__ */ createElement(Checkbox, { ...register(field.name, field, renderLayout), key: field.name });
1767
+ case "radio":
1768
+ return /* @__PURE__ */ createElement(Radio, { ...register(field.name, field, renderLayout), key: field.name });
1769
+ case "select":
1770
+ return /* @__PURE__ */ createElement(Select, { ...register(field.name, field, renderLayout), key: field.name });
1771
+ case "text":
1772
+ case "search":
1773
+ case "email":
1774
+ case "tel":
1775
+ case "password":
1776
+ case "url":
1777
+ case "number":
1778
+ case "range":
1779
+ case "date":
1780
+ case "time":
1781
+ case "datetime-local":
1782
+ case "color":
1783
+ case "file":
1784
+ case "hidden":
1785
+ return /* @__PURE__ */ createElement(Input, { ...register(field.name, field, renderLayout), key: field.name });
1786
+ default:
1787
+ return /* @__PURE__ */ jsxs14("div", { children: [
1788
+ field.type,
1789
+ " to implement"
1790
+ ] }, field.name);
1791
+ }
1792
+ };
1793
+ const renderFields = () => {
1794
+ const target = layout?.length ? layout : fields;
1795
+ const hasLayout = layout?.length !== 0 || fields.some((f) => f.config.layout);
1796
+ const content = target.map((element) => {
1797
+ if ("fields" in element) {
1798
+ const classes = getColumnClasses(element.layout, element.layout?.className);
1799
+ return /* @__PURE__ */ jsx16(
1800
+ "div",
1801
+ {
1802
+ className: classes,
1803
+ style: element.layout?.style,
1804
+ children: element.fields.map((name) => {
1805
+ const field = fieldMap.get(name);
1806
+ return field ? loadElement(field) : null;
1807
+ })
1808
+ },
1809
+ element.fields.join("-")
1810
+ );
1811
+ }
1812
+ return loadElement(element, hasLayout);
1813
+ });
1814
+ return hasLayout ? /* @__PURE__ */ jsx16("div", { className: "sio-row", children: content }) : content;
1815
+ };
1816
+ const fieldMap = useMemo2(() => {
1817
+ const map = /* @__PURE__ */ new Map();
1818
+ fields.forEach((f) => map.set(f.name, f));
1819
+ return map;
1820
+ }, [fields]);
1821
+ const handleCancel = () => {
1822
+ cancelAction?.();
1823
+ reset();
1824
+ };
1825
+ const handleSubmit = async () => {
1826
+ await submit(() => submitAction(getValues()));
1827
+ reset();
1828
+ };
1829
+ const renderButton = (props, i) => {
1830
+ return props.type === "link" ? /* @__PURE__ */ createElement(Link, { ...props, key: i }) : /* @__PURE__ */ createElement(Button, { ...props, key: i });
1831
+ };
1832
+ const renderButtons = () => {
1833
+ return submitShow || cancelShow || buttons.length ? /* @__PURE__ */ jsxs14(ButtonContainer, { children: [
1834
+ submitShow && /* @__PURE__ */ jsx16(
1835
+ Button,
1836
+ {
1837
+ type: "submit",
1838
+ onClick: handleSubmit,
1839
+ variant: "primary",
1840
+ label: submitLabel,
1841
+ loading: isBusy(),
1842
+ disabled: !isValid() || !extraValidation(getValues())
1843
+ }
1844
+ ),
1845
+ cancelShow && /* @__PURE__ */ jsx16(
1846
+ Button,
1847
+ {
1848
+ type: "button",
1849
+ onClick: handleCancel,
1850
+ variant: "secondary",
1851
+ label: cancelLabel,
1852
+ disabled: !isDirty()
1853
+ }
1854
+ ),
1855
+ buttons?.map(renderButton)
1856
+ ] }) : null;
1857
+ };
1858
+ return /* @__PURE__ */ jsxs14(Container, { className, style, noValidate: true, children: [
1859
+ renderFields(),
1860
+ renderButtons()
1861
+ ] });
1862
+ };
1863
+ export {
1864
+ Button,
1865
+ Checkbox,
1866
+ DateInput,
1867
+ FileInput,
1868
+ Form,
1869
+ Input,
1870
+ Link,
1871
+ NumberInput,
1872
+ Radio,
1873
+ RangeInput,
1874
+ Select,
1875
+ TextInput,
1876
+ Textarea,
1877
+ useForm
1878
+ };