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