@tachui/forms 0.7.0-alpha1 → 0.7.1-alpha

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.
@@ -0,0 +1,1799 @@
1
+ import { createSignal as E, createEffect as j, h as s, text as b, defaultChildrenRenderer as Le, useLifecycle as Ve, setupOutsideClickDetection as Te, isSignal as Ae } from "@tachui/core";
2
+ import { createFormState as Oe, createField as ee } from "./state/index.js";
3
+ function he(e, t) {
4
+ return Array.isArray(e) ? e.flatMap((n) => pe(n, t)) : pe(e, t);
5
+ }
6
+ function pe(e, t) {
7
+ if (e == null)
8
+ return [];
9
+ if (typeof e == "object" && "type" in e && e.type === "component") {
10
+ const n = {
11
+ ...e,
12
+ props: {
13
+ ...e.props,
14
+ _formContext: t
15
+ }
16
+ }, l = e.render.bind(n)();
17
+ return Array.isArray(l) ? l : [l];
18
+ }
19
+ return Le(e);
20
+ }
21
+ const Pe = (e) => {
22
+ const {
23
+ onSubmit: t,
24
+ onChange: n,
25
+ validation: r = {
26
+ validateOn: "blur",
27
+ stopOnFirstError: !1,
28
+ debounceMs: 300
29
+ },
30
+ initialValues: l = {},
31
+ resetOnSubmit: d = !1,
32
+ preserveValues: v = !1,
33
+ children: w,
34
+ ...F
35
+ } = e, g = Oe(l), [T, S] = E("idle"), A = async (h) => {
36
+ if (h && h.preventDefault(), !!t)
37
+ try {
38
+ if (S("idle"), await g.validateForm()) {
39
+ const u = g.watch();
40
+ await t(u, g.state), S("success"), d && g.resetForm();
41
+ } else
42
+ S("error");
43
+ } catch (o) {
44
+ S("error"), console.error("Form submission error:", o);
45
+ }
46
+ };
47
+ j(() => {
48
+ if (n) {
49
+ const h = g.state, o = Object.keys(h.fields).filter((u) => h.fields[u].dirty);
50
+ if (o.length > 0) {
51
+ const u = o[o.length - 1], k = h.fields[u];
52
+ n(u, k.value, k);
53
+ }
54
+ }
55
+ });
56
+ const C = {
57
+ register: g.register,
58
+ unregister: g.unregister,
59
+ setValue: g.setValue,
60
+ getValue: g.getValue,
61
+ getError: g.getError,
62
+ validateField: g.validateField,
63
+ validation: r,
64
+ onChange: n
65
+ };
66
+ return {
67
+ type: "component",
68
+ id: F.id || "form",
69
+ render: () => s(
70
+ "form",
71
+ {
72
+ ...F,
73
+ onsubmit: A,
74
+ novalidate: !0,
75
+ // We handle validation ourselves
76
+ "data-tachui-form": !0,
77
+ "data-form-state": g.state.valid ? "valid" : "invalid",
78
+ "data-form-submitting": g.state.submitting,
79
+ "data-submission-result": T()
80
+ },
81
+ ...he(w, C)
82
+ ),
83
+ props: e,
84
+ cleanup: [
85
+ () => {
86
+ v || g.resetForm();
87
+ }
88
+ ]
89
+ };
90
+ }, Re = (e) => {
91
+ const {
92
+ title: t,
93
+ description: n,
94
+ header: r,
95
+ footer: l,
96
+ style: d = "automatic",
97
+ spacing: v = 12,
98
+ collapsible: w = !1,
99
+ collapsed: F = !1,
100
+ onToggle: g,
101
+ accessibilityLabel: T,
102
+ accessibilityRole: S = "group",
103
+ children: A,
104
+ ...C
105
+ } = e, [m, h] = E(F), o = () => {
106
+ const a = !m();
107
+ h(a), g && g(a);
108
+ }, u = (a) => a ? typeof a == "string" ? a : typeof a == "function" ? a() : a : null, k = () => {
109
+ const a = {
110
+ marginBottom: "20px",
111
+ border: "none",
112
+ // Remove default fieldset border
113
+ padding: "0",
114
+ // Remove default fieldset padding
115
+ margin: "0 0 20px 0"
116
+ // Override default fieldset margin
117
+ };
118
+ switch (d) {
119
+ case "grouped":
120
+ return {
121
+ ...a,
122
+ backgroundColor: "#ffffff",
123
+ border: "1px solid #e0e0e0",
124
+ borderRadius: "12px",
125
+ overflow: "hidden"
126
+ };
127
+ case "inset":
128
+ return {
129
+ ...a,
130
+ backgroundColor: "#f8f9fa",
131
+ border: "1px solid #e9ecef",
132
+ borderRadius: "8px",
133
+ margin: "0 16px 20px 16px"
134
+ };
135
+ case "sidebar":
136
+ return {
137
+ ...a,
138
+ borderLeft: "3px solid #007AFF",
139
+ paddingLeft: "16px",
140
+ backgroundColor: "#f8f9fa",
141
+ borderRadius: "0 8px 8px 0"
142
+ };
143
+ case "plain":
144
+ return a;
145
+ default:
146
+ return {
147
+ ...a,
148
+ backgroundColor: "#ffffff",
149
+ border: "1px solid #f0f0f0",
150
+ borderRadius: "8px"
151
+ };
152
+ }
153
+ }, O = () => {
154
+ const a = {
155
+ fontSize: "16px",
156
+ fontWeight: "600",
157
+ color: "#1a1a1a",
158
+ margin: "0 0 12px 0"
159
+ };
160
+ switch (d) {
161
+ case "grouped":
162
+ case "inset":
163
+ return {
164
+ ...a,
165
+ padding: "12px 16px 0 16px",
166
+ backgroundColor: "#f8f9fa",
167
+ borderBottom: "1px solid #e9ecef"
168
+ };
169
+ case "sidebar":
170
+ return {
171
+ ...a,
172
+ fontSize: "14px",
173
+ textTransform: "uppercase",
174
+ letterSpacing: "0.5px",
175
+ color: "#666",
176
+ marginBottom: "8px"
177
+ };
178
+ default:
179
+ return {
180
+ ...a,
181
+ padding: "0 0 8px 0"
182
+ };
183
+ }
184
+ }, f = () => {
185
+ const a = {
186
+ display: "flex",
187
+ flexDirection: "column",
188
+ gap: `${v}px`
189
+ };
190
+ switch (d) {
191
+ case "grouped":
192
+ case "inset":
193
+ return {
194
+ ...a,
195
+ padding: "16px"
196
+ };
197
+ case "sidebar":
198
+ return {
199
+ ...a,
200
+ padding: "8px 0"
201
+ };
202
+ default:
203
+ return {
204
+ ...a,
205
+ padding: "12px"
206
+ };
207
+ }
208
+ }, x = () => {
209
+ const a = {
210
+ fontSize: "14px",
211
+ color: "#666",
212
+ margin: "8px 0 0 0"
213
+ };
214
+ switch (d) {
215
+ case "grouped":
216
+ case "inset":
217
+ return {
218
+ ...a,
219
+ padding: "0 16px 12px 16px",
220
+ backgroundColor: "#f8f9fa",
221
+ borderTop: "1px solid #e9ecef"
222
+ };
223
+ default:
224
+ return {
225
+ ...a,
226
+ padding: "0 0 4px 0"
227
+ };
228
+ }
229
+ }, c = () => {
230
+ const a = t || u(r);
231
+ if (!a) return [];
232
+ const z = O();
233
+ if (w) {
234
+ const R = m() ? "▶" : "▼";
235
+ return [
236
+ s(
237
+ "legend",
238
+ {
239
+ style: {
240
+ ...z,
241
+ cursor: "pointer",
242
+ display: "flex",
243
+ alignItems: "center",
244
+ gap: "8px"
245
+ },
246
+ onclick: o
247
+ },
248
+ s(
249
+ "span",
250
+ {
251
+ style: {
252
+ fontSize: "12px",
253
+ color: "#666"
254
+ }
255
+ },
256
+ b(R)
257
+ ),
258
+ ...typeof a == "string" ? [b(a)] : [a.render()].flat()
259
+ )
260
+ ];
261
+ }
262
+ return [
263
+ s(
264
+ "legend",
265
+ { style: z },
266
+ ...typeof a == "string" ? [b(a)] : [a.render()].flat()
267
+ )
268
+ ];
269
+ }, p = () => !n || m() ? [] : [
270
+ s(
271
+ "div",
272
+ {
273
+ style: {
274
+ fontSize: "14px",
275
+ color: "#666",
276
+ marginBottom: "12px",
277
+ padding: d === "grouped" || d === "inset" ? "0 16px" : "0"
278
+ }
279
+ },
280
+ b(n)
281
+ )
282
+ ], $ = () => w && m() ? [] : [
283
+ s(
284
+ "div",
285
+ {
286
+ style: f()
287
+ },
288
+ ...he(A, e._formContext)
289
+ )
290
+ ], L = () => {
291
+ const a = u(l);
292
+ return !a || m() ? [] : [
293
+ s(
294
+ "div",
295
+ {
296
+ style: x()
297
+ },
298
+ ...typeof a == "string" ? [b(a)] : [a.render()].flat()
299
+ )
300
+ ];
301
+ };
302
+ return {
303
+ type: "component",
304
+ id: C.id || "form-section",
305
+ render: () => s(
306
+ "fieldset",
307
+ {
308
+ ...C,
309
+ style: k(),
310
+ "aria-label": T,
311
+ role: S,
312
+ "data-tachui-form-section": !0,
313
+ "data-collapsible": w,
314
+ "data-collapsed": m(),
315
+ "data-style": d
316
+ },
317
+ ...c(),
318
+ ...p(),
319
+ ...$(),
320
+ ...L()
321
+ ),
322
+ props: e
323
+ };
324
+ }, Ne = {
325
+ /**
326
+ * Create a form with automatic field registration
327
+ */
328
+ createAutoForm: (e) => (console.log("Auto form creation:", e), Pe),
329
+ /**
330
+ * Form validation utilities
331
+ */
332
+ validation: {
333
+ /**
334
+ * Create a validation schema from field definitions
335
+ */
336
+ createSchema: (e) => ({
337
+ fields: e,
338
+ validate: async (t) => ({ valid: !0, errors: {} })
339
+ })
340
+ },
341
+ /**
342
+ * Form serialization utilities
343
+ */
344
+ serialize: {
345
+ /**
346
+ * Convert form values to FormData
347
+ */
348
+ toFormData: (e) => {
349
+ const t = new FormData();
350
+ return Object.entries(e).forEach(([n, r]) => {
351
+ r != null && (r instanceof File || r instanceof Blob ? t.append(n, r) : Array.isArray(r) ? r.forEach((l, d) => {
352
+ t.append(`${n}[${d}]`, String(l));
353
+ }) : t.append(n, String(r)));
354
+ }), t;
355
+ },
356
+ /**
357
+ * Convert form values to URL search params
358
+ */
359
+ toURLSearchParams: (e) => {
360
+ const t = new URLSearchParams();
361
+ return Object.entries(e).forEach(([n, r]) => {
362
+ r != null && (Array.isArray(r) ? r.forEach((l) => t.append(n, String(l))) : t.append(n, String(r)));
363
+ }), t;
364
+ },
365
+ /**
366
+ * Convert form values to JSON
367
+ */
368
+ toJSON: (e) => JSON.stringify(e, null, 2)
369
+ }
370
+ }, be = (e) => {
371
+ const {
372
+ name: t,
373
+ label: n,
374
+ disabled: r = !1,
375
+ required: l = !1,
376
+ checked: d,
377
+ defaultChecked: v = !1,
378
+ indeterminate: w = !1,
379
+ validation: F,
380
+ onChange: g,
381
+ onBlur: T,
382
+ onFocus: S,
383
+ error: A,
384
+ helperText: C,
385
+ ...m
386
+ } = e, h = e._formContext, o = ee(t, d ?? v, F);
387
+ h && h.register(t, F);
388
+ const [u, k] = E(!1);
389
+ d !== void 0 && j(() => {
390
+ o.value() !== d && o.setValue(d);
391
+ });
392
+ const O = (L) => {
393
+ const a = L.target.checked;
394
+ o.setValue(a), h && h.setValue(t, a), g && g(t, a, o);
395
+ }, f = (L) => {
396
+ k(!0), o.onFocus(), S && S(t, o.value());
397
+ }, x = (L) => {
398
+ k(!1), o.onBlur(), T && T(t, o.value());
399
+ }, c = A || o.error() || h?.getError(t), p = (L) => {
400
+ if (L.key === " " || L.key === "Enter") {
401
+ L.preventDefault();
402
+ const _ = L.target;
403
+ _.checked = !_.checked, O(L);
404
+ }
405
+ };
406
+ return {
407
+ type: "component",
408
+ id: m.id || `checkbox-${t}`,
409
+ render: () => s(
410
+ "div",
411
+ {
412
+ ...m,
413
+ class: `tachui-checkbox ${m.class || ""}`.trim(),
414
+ "data-tachui-checkbox-container": !0,
415
+ "data-field-state": c ? "error" : o.validating() ? "validating" : "valid",
416
+ "data-checked": o.value(),
417
+ "data-indeterminate": w,
418
+ "data-disabled": r
419
+ },
420
+ // Checkbox input and label wrapper
421
+ s(
422
+ "label",
423
+ {
424
+ "data-tachui-checkbox-label": !0,
425
+ "data-focused": u(),
426
+ "data-disabled": r
427
+ },
428
+ // Hidden native checkbox for accessibility
429
+ s("input", {
430
+ type: "checkbox",
431
+ id: m.id || t,
432
+ name: t,
433
+ checked: o.value(),
434
+ disabled: r,
435
+ required: l,
436
+ onchange: O,
437
+ onfocus: f,
438
+ onblur: x,
439
+ onkeydown: p,
440
+ "aria-invalid": !!c,
441
+ "aria-describedby": [c ? `${t}-error` : null, C ? `${t}-helper` : null].filter(Boolean).join(" ") || void 0,
442
+ "data-tachui-checkbox-input": !0,
443
+ style: {
444
+ position: "absolute",
445
+ opacity: "0",
446
+ width: "1px",
447
+ height: "1px",
448
+ margin: "-1px",
449
+ padding: "0",
450
+ border: "0",
451
+ clip: "rect(0,0,0,0)"
452
+ }
453
+ }),
454
+ // Custom checkbox visual
455
+ s(
456
+ "div",
457
+ {
458
+ "data-tachui-checkbox-visual": !0,
459
+ "data-checked": o.value(),
460
+ "data-indeterminate": w,
461
+ "data-focused": u(),
462
+ "data-disabled": r,
463
+ "data-error": !!c,
464
+ "aria-hidden": "true",
465
+ role: "presentation"
466
+ },
467
+ ...o.value() || w ? [
468
+ s(
469
+ "div",
470
+ {
471
+ "data-tachui-checkbox-indicator": !0,
472
+ "data-type": w ? "indeterminate" : "checked"
473
+ },
474
+ b(w ? "−" : "✓")
475
+ )
476
+ ] : []
477
+ ),
478
+ ...n ? [
479
+ s(
480
+ "span",
481
+ {
482
+ "data-tachui-checkbox-text": !0,
483
+ "data-disabled": r
484
+ },
485
+ b(n),
486
+ ...l ? [
487
+ s(
488
+ "span",
489
+ {
490
+ "aria-label": "required",
491
+ "data-required-indicator": !0
492
+ },
493
+ b(" *")
494
+ )
495
+ ] : []
496
+ )
497
+ ] : []
498
+ ),
499
+ ...c ? [
500
+ s(
501
+ "div",
502
+ {
503
+ id: `${t}-error`,
504
+ role: "alert",
505
+ "aria-live": "polite",
506
+ "data-tachui-error": !0
507
+ },
508
+ b(c)
509
+ )
510
+ ] : [],
511
+ ...C && !c ? [
512
+ s(
513
+ "div",
514
+ {
515
+ id: `${t}-helper`,
516
+ "data-tachui-helper": !0
517
+ },
518
+ b(C)
519
+ )
520
+ ] : [],
521
+ ...o.validating() ? [
522
+ s(
523
+ "div",
524
+ {
525
+ "data-tachui-validation-spinner": !0,
526
+ "aria-label": "Validating..."
527
+ },
528
+ b("⏳")
529
+ )
530
+ ] : []
531
+ ),
532
+ props: e,
533
+ cleanup: [
534
+ () => {
535
+ h && h.unregister(t);
536
+ }
537
+ ]
538
+ };
539
+ }, Me = (e) => {
540
+ const { size: t = "medium", ...n } = e, r = {
541
+ ...n,
542
+ class: `tachui-switch tachui-switch-${t} ${n.class || ""}`.trim()
543
+ }, l = be(r);
544
+ return {
545
+ ...l,
546
+ render: () => {
547
+ const d = l.render();
548
+ return Array.isArray(d) ? d.map((v) => ({
549
+ ...v,
550
+ props: {
551
+ ...v.props,
552
+ "data-tachui-switch": !0,
553
+ "data-switch-size": t
554
+ }
555
+ })) : {
556
+ ...d,
557
+ props: {
558
+ ...d.props,
559
+ "data-tachui-switch": !0,
560
+ "data-switch-size": t
561
+ }
562
+ };
563
+ }
564
+ };
565
+ }, _e = (e) => {
566
+ const {
567
+ name: t,
568
+ label: n,
569
+ options: r,
570
+ value: l,
571
+ defaultValue: d = [],
572
+ onChange: v,
573
+ validation: w,
574
+ error: F,
575
+ helperText: g,
576
+ disabled: T = !1,
577
+ required: S = !1,
578
+ direction: A = "vertical",
579
+ ...C
580
+ } = e, m = ee(t, l ?? d, w), h = (u, k) => {
581
+ const O = m.value() || [];
582
+ let f;
583
+ k ? f = [...O, u] : f = O.filter((x) => x !== u), m.setValue(f), v && v(t, f, u);
584
+ };
585
+ return {
586
+ type: "component",
587
+ id: C.id || `checkbox-group-${t}`,
588
+ render: () => s(
589
+ "fieldset",
590
+ {
591
+ ...C,
592
+ "data-tachui-checkbox-group": !0,
593
+ "data-direction": A,
594
+ "data-disabled": T
595
+ },
596
+ ...n ? [
597
+ s(
598
+ "legend",
599
+ {
600
+ "data-tachui-group-label": !0
601
+ },
602
+ b(n),
603
+ ...S ? [
604
+ s(
605
+ "span",
606
+ {
607
+ "aria-label": "required",
608
+ "data-required-indicator": !0
609
+ },
610
+ b(" *")
611
+ )
612
+ ] : []
613
+ )
614
+ ] : [],
615
+ // Checkbox options
616
+ s(
617
+ "div",
618
+ {
619
+ "data-tachui-checkbox-options": !0,
620
+ "data-direction": A
621
+ },
622
+ ...r.flatMap((u, k) => {
623
+ const f = be({
624
+ name: `${t}-${k}`,
625
+ label: u.label,
626
+ checked: (m.value() || []).includes(u.value),
627
+ disabled: T || u.disabled,
628
+ onChange: (x, c) => h(u.value, c)
629
+ }).render();
630
+ return Array.isArray(f) ? f : [f];
631
+ })
632
+ ),
633
+ ...F ? [
634
+ s(
635
+ "div",
636
+ {
637
+ id: `${t}-error`,
638
+ role: "alert",
639
+ "aria-live": "polite",
640
+ "data-tachui-error": !0
641
+ },
642
+ b(F)
643
+ )
644
+ ] : [],
645
+ ...g && !F ? [
646
+ s(
647
+ "div",
648
+ {
649
+ id: `${t}-helper`,
650
+ "data-tachui-helper": !0
651
+ },
652
+ b(g)
653
+ )
654
+ ] : []
655
+ ),
656
+ props: e
657
+ };
658
+ }, Ie = (e) => {
659
+ const {
660
+ name: t,
661
+ value: n,
662
+ label: r,
663
+ checked: l,
664
+ groupName: d,
665
+ disabled: v = !1,
666
+ required: w = !1,
667
+ validation: F,
668
+ onChange: g,
669
+ onBlur: T,
670
+ onFocus: S,
671
+ error: A,
672
+ helperText: C,
673
+ ...m
674
+ } = e, h = e._formContext, o = d || t, u = ee(o, l ? n : void 0, F);
675
+ h && h.register(o, F);
676
+ const [k, O] = E(!1), f = () => u.value() === n, x = (a) => {
677
+ a.target.checked && (u.setValue(n), h && h.setValue(o, n), g && g(o, n, u));
678
+ }, c = (a) => {
679
+ O(!0), u.onFocus(), S && S(o, u.value());
680
+ }, p = (a) => {
681
+ O(!1), u.onBlur(), T && T(o, u.value());
682
+ }, $ = A || u.error() || h?.getError(o), L = (a) => {
683
+ (a.key === " " || a.key === "Enter") && (a.preventDefault(), x(a));
684
+ };
685
+ return {
686
+ type: "component",
687
+ id: m.id || `radio-${o}-${n}`,
688
+ render: () => s(
689
+ "div",
690
+ {
691
+ ...m,
692
+ class: `tachui-radio ${m.class || ""}`.trim(),
693
+ "data-tachui-radio-container": !0,
694
+ "data-field-state": $ ? "error" : u.validating() ? "validating" : "valid",
695
+ "data-checked": f(),
696
+ "data-disabled": v
697
+ },
698
+ // Radio input and label wrapper
699
+ s(
700
+ "label",
701
+ {
702
+ "data-tachui-radio-label": !0,
703
+ "data-focused": k(),
704
+ "data-disabled": v
705
+ },
706
+ // Hidden native radio for accessibility
707
+ s("input", {
708
+ type: "radio",
709
+ id: m.id || `${o}-${n}`,
710
+ name: o,
711
+ value: n,
712
+ checked: f(),
713
+ disabled: v,
714
+ required: w,
715
+ onchange: x,
716
+ onfocus: c,
717
+ onblur: p,
718
+ onkeydown: L,
719
+ "aria-invalid": !!$,
720
+ "aria-describedby": [
721
+ $ ? `${o}-error` : null,
722
+ C ? `${o}-helper` : null
723
+ ].filter(Boolean).join(" ") || void 0,
724
+ "data-tachui-radio-input": !0,
725
+ style: {
726
+ position: "absolute",
727
+ opacity: "0",
728
+ width: "1px",
729
+ height: "1px",
730
+ margin: "-1px",
731
+ padding: "0",
732
+ border: "0",
733
+ clip: "rect(0,0,0,0)"
734
+ }
735
+ }),
736
+ // Custom radio visual
737
+ s(
738
+ "div",
739
+ {
740
+ "data-tachui-radio-visual": !0,
741
+ "data-checked": f(),
742
+ "data-focused": k(),
743
+ "data-disabled": v,
744
+ "data-error": !!$,
745
+ "aria-hidden": "true",
746
+ role: "presentation"
747
+ },
748
+ ...f() ? [
749
+ s("div", {
750
+ "data-tachui-radio-dot": !0
751
+ })
752
+ ] : []
753
+ ),
754
+ ...r ? [
755
+ s(
756
+ "span",
757
+ {
758
+ "data-tachui-radio-text": !0,
759
+ "data-disabled": v
760
+ },
761
+ b(r),
762
+ ...w ? [
763
+ s(
764
+ "span",
765
+ {
766
+ "aria-label": "required",
767
+ "data-required-indicator": !0
768
+ },
769
+ b(" *")
770
+ )
771
+ ] : []
772
+ )
773
+ ] : []
774
+ )
775
+ ),
776
+ props: e,
777
+ cleanup: [
778
+ () => {
779
+ }
780
+ ]
781
+ };
782
+ }, ze = (e) => {
783
+ const {
784
+ name: t,
785
+ label: n,
786
+ options: r,
787
+ value: l,
788
+ defaultValue: d,
789
+ onChange: v,
790
+ validation: w,
791
+ error: F,
792
+ helperText: g,
793
+ disabled: T = !1,
794
+ required: S = !1,
795
+ direction: A = "vertical",
796
+ ...C
797
+ } = e, m = e._formContext, h = ee(t, l ?? d, w);
798
+ m && m.register(t, w), l !== void 0 && j(() => {
799
+ h.value() !== l && h.setValue(l);
800
+ });
801
+ const o = (f) => {
802
+ h.setValue(f), m && m.setValue(t, f), v && v(t, f);
803
+ }, u = (f) => {
804
+ const x = r.findIndex((p) => p.value === h.value());
805
+ let c = x;
806
+ switch (f.key) {
807
+ case "ArrowDown":
808
+ case "ArrowRight":
809
+ f.preventDefault(), c = (x + 1) % r.length;
810
+ break;
811
+ case "ArrowUp":
812
+ case "ArrowLeft":
813
+ f.preventDefault(), c = x === 0 ? r.length - 1 : x - 1;
814
+ break;
815
+ case "Home":
816
+ f.preventDefault(), c = 0;
817
+ break;
818
+ case "End":
819
+ f.preventDefault(), c = r.length - 1;
820
+ break;
821
+ default:
822
+ return;
823
+ }
824
+ for (; r[c]?.disabled && (f.key === "ArrowDown" || f.key === "ArrowRight" ? c = (c + 1) % r.length : c = c === 0 ? r.length - 1 : c - 1, c !== x); )
825
+ ;
826
+ r[c]?.disabled || (o(r[c].value), setTimeout(() => {
827
+ const p = document.querySelector(
828
+ `input[name="${t}"][value="${r[c].value}"]`
829
+ );
830
+ p && p.focus();
831
+ }, 0));
832
+ }, k = F || h.error();
833
+ return {
834
+ type: "component",
835
+ id: C.id || `radio-group-${t}`,
836
+ render: () => s(
837
+ "fieldset",
838
+ {
839
+ ...C,
840
+ "data-tachui-radio-group": !0,
841
+ "data-direction": A,
842
+ "data-disabled": T,
843
+ role: "radiogroup",
844
+ "aria-invalid": !!k,
845
+ "aria-describedby": [k ? `${t}-error` : null, g ? `${t}-helper` : null].filter(Boolean).join(" ") || void 0,
846
+ onkeydown: u
847
+ },
848
+ ...n ? [
849
+ s(
850
+ "legend",
851
+ {
852
+ "data-tachui-group-label": !0
853
+ },
854
+ b(n),
855
+ ...S ? [
856
+ s(
857
+ "span",
858
+ {
859
+ "aria-label": "required",
860
+ "data-required-indicator": !0
861
+ },
862
+ b(" *")
863
+ )
864
+ ] : []
865
+ )
866
+ ] : [],
867
+ // Radio options
868
+ s(
869
+ "div",
870
+ {
871
+ "data-tachui-radio-options": !0,
872
+ "data-direction": A
873
+ },
874
+ ...r.flatMap((f, x) => {
875
+ const p = Ie({
876
+ name: `${t}-${x}`,
877
+ groupName: t,
878
+ value: f.value,
879
+ label: f.label,
880
+ checked: h.value() === f.value,
881
+ disabled: T || f.disabled,
882
+ required: S,
883
+ onChange: () => o(f.value),
884
+ _formContext: m
885
+ }).render();
886
+ return Array.isArray(p) ? p : [p];
887
+ })
888
+ ),
889
+ ...k ? [
890
+ s(
891
+ "div",
892
+ {
893
+ id: `${t}-error`,
894
+ role: "alert",
895
+ "aria-live": "polite",
896
+ "data-tachui-error": !0
897
+ },
898
+ b(k)
899
+ )
900
+ ] : [],
901
+ ...g && !k ? [
902
+ s(
903
+ "div",
904
+ {
905
+ id: `${t}-helper`,
906
+ "data-tachui-helper": !0
907
+ },
908
+ b(g)
909
+ )
910
+ ] : []
911
+ ),
912
+ props: e,
913
+ cleanup: [
914
+ () => {
915
+ m && m.unregister(t);
916
+ }
917
+ ]
918
+ };
919
+ }, ge = (e) => {
920
+ const {
921
+ name: t,
922
+ label: n,
923
+ options: r,
924
+ multiple: l = !1,
925
+ searchable: d = !1,
926
+ clearable: v = !1,
927
+ placeholder: w = l ? "Select options..." : "Select an option...",
928
+ noOptionsMessage: F = "No options available",
929
+ loadingMessage: g = "Loading...",
930
+ maxMenuHeight: T = 200,
931
+ disabled: S = !1,
932
+ required: A = !1,
933
+ value: C,
934
+ defaultValue: m,
935
+ validation: h,
936
+ onChange: o,
937
+ onBlur: u,
938
+ onFocus: k,
939
+ error: O,
940
+ helperText: f,
941
+ ...x
942
+ } = e, c = e._formContext, p = ee(t, C ?? m, h);
943
+ c && c.register(t, h);
944
+ const [$, L] = E(!1), [_, a] = E(!1), [z, R] = E(""), [N, H] = E(-1), [ne] = E(!1);
945
+ C !== void 0 && j(() => {
946
+ p.value() !== C && p.setValue(C);
947
+ });
948
+ const I = () => {
949
+ if (!d || !z())
950
+ return r;
951
+ const i = z().toLowerCase();
952
+ return r.filter(
953
+ (y) => y.label.toLowerCase().includes(i) || String(y.value).toLowerCase().includes(i)
954
+ );
955
+ }, ae = () => {
956
+ const i = p.value();
957
+ if (l)
958
+ return !i || !Array.isArray(i) || i.length === 0 ? w : r.filter((P) => i.includes(P.value)).map((P) => P.label).join(", ");
959
+ {
960
+ if (i == null || i === "")
961
+ return w;
962
+ const y = r.find((P) => P.value === i);
963
+ return y ? y.label : String(i);
964
+ }
965
+ }, Q = (i) => {
966
+ if (i.disabled) return;
967
+ let y;
968
+ if (l) {
969
+ const P = p.value() || [];
970
+ P.includes(i.value) ? y = P.filter((le) => le !== i.value) : y = [...P, i.value];
971
+ } else
972
+ y = i.value, L(!1), R("");
973
+ p.setValue(y), c && c.setValue(t, y), o && o(t, y, p);
974
+ }, K = () => {
975
+ if (S) return;
976
+ const i = !$();
977
+ L(i), i && (H(-1), d && R(""));
978
+ }, te = (i) => {
979
+ const y = i.target;
980
+ R(y.value), H(-1);
981
+ }, X = (i) => {
982
+ const y = I();
983
+ switch (i.key) {
984
+ case "Enter":
985
+ i.preventDefault(), $() ? N() >= 0 && y[N()] && Q(y[N()]) : K();
986
+ break;
987
+ case " ":
988
+ (!d || !$()) && (i.preventDefault(), K());
989
+ break;
990
+ case "Escape":
991
+ i.preventDefault(), L(!1), R("");
992
+ break;
993
+ case "ArrowDown":
994
+ if (i.preventDefault(), !$())
995
+ K();
996
+ else {
997
+ const P = Math.min(N() + 1, y.length - 1);
998
+ H(P);
999
+ }
1000
+ break;
1001
+ case "ArrowUp":
1002
+ if (i.preventDefault(), $()) {
1003
+ const P = Math.max(N() - 1, -1);
1004
+ H(P);
1005
+ }
1006
+ break;
1007
+ case "Home":
1008
+ $() && (i.preventDefault(), H(0));
1009
+ break;
1010
+ case "End":
1011
+ $() && (i.preventDefault(), H(y.length - 1));
1012
+ break;
1013
+ case "Backspace":
1014
+ v && !d && p.value() !== null && (i.preventDefault(), re());
1015
+ break;
1016
+ }
1017
+ }, B = () => {
1018
+ a(!0), p.onFocus(), k && k(t, p.value());
1019
+ }, D = (i) => {
1020
+ requestAnimationFrame(() => {
1021
+ const y = i.relatedTarget;
1022
+ i.target.closest("[data-tachui-select-container]")?.contains(y) || (a(!1), L(!1), p.onBlur(), u && u(t, p.value()));
1023
+ });
1024
+ }, re = () => {
1025
+ const i = l ? [] : null;
1026
+ p.setValue(i), c && c.setValue(t, i), o && o(t, i, p);
1027
+ }, G = (i) => {
1028
+ const y = p.value();
1029
+ return l ? Array.isArray(y) && y.includes(i.value) : y === i.value;
1030
+ }, M = O || p.error() || c?.getError(t), W = {
1031
+ type: "component",
1032
+ id: x.id || `select-${t}`,
1033
+ cleanup: [],
1034
+ render: () => ({
1035
+ type: "element",
1036
+ tag: "div",
1037
+ props: {
1038
+ ...x,
1039
+ class: `tachui-select ${x.class || ""}`.trim(),
1040
+ "data-tachui-select-container": !0,
1041
+ "data-field-state": M ? "error" : p.validating() ? "validating" : "valid",
1042
+ "data-open": $(),
1043
+ "data-disabled": S,
1044
+ "data-multiple": l,
1045
+ "data-searchable": d
1046
+ },
1047
+ children: [
1048
+ // Label
1049
+ ...n ? [
1050
+ s(
1051
+ "label",
1052
+ {
1053
+ for: x.id || t,
1054
+ "data-tachui-label": !0,
1055
+ "data-required": A
1056
+ },
1057
+ b(n),
1058
+ ...A ? [
1059
+ s(
1060
+ "span",
1061
+ {
1062
+ "aria-label": "required",
1063
+ "data-required-indicator": !0
1064
+ },
1065
+ b(" *")
1066
+ )
1067
+ ] : []
1068
+ )
1069
+ ] : [],
1070
+ // Select trigger
1071
+ {
1072
+ type: "element",
1073
+ tag: "div",
1074
+ props: {
1075
+ id: x.id || t,
1076
+ tabindex: S ? -1 : 0,
1077
+ role: "combobox",
1078
+ "aria-expanded": $(),
1079
+ "aria-haspopup": "listbox",
1080
+ "aria-invalid": !!M,
1081
+ "aria-describedby": [M ? `${t}-error` : null, f ? `${t}-helper` : null].filter(Boolean).join(" ") || void 0,
1082
+ onclick: K,
1083
+ onkeydown: X,
1084
+ onfocus: B,
1085
+ onblur: D,
1086
+ "data-tachui-select-trigger": !0,
1087
+ "data-focused": _(),
1088
+ "data-disabled": S,
1089
+ "data-error": !!M
1090
+ },
1091
+ children: [
1092
+ // Display value
1093
+ {
1094
+ type: "element",
1095
+ tag: "div",
1096
+ props: {
1097
+ "data-tachui-select-value": !0,
1098
+ "data-placeholder": !p.value() || l && (!p.value() || p.value().length === 0)
1099
+ },
1100
+ children: [b(ae())]
1101
+ },
1102
+ // Actions (clear, dropdown arrow)
1103
+ {
1104
+ type: "element",
1105
+ tag: "div",
1106
+ props: {
1107
+ "data-tachui-select-actions": !0
1108
+ },
1109
+ children: [
1110
+ // Clear button
1111
+ ...v && p.value() && (!l || Array.isArray(p.value()) && p.value().length > 0) ? [
1112
+ {
1113
+ type: "element",
1114
+ tag: "button",
1115
+ props: {
1116
+ type: "button",
1117
+ onclick: (i) => {
1118
+ i.stopPropagation(), re();
1119
+ },
1120
+ "aria-label": "Clear selection",
1121
+ "data-tachui-select-clear": !0
1122
+ },
1123
+ children: [b("×")]
1124
+ }
1125
+ ] : [],
1126
+ // Dropdown arrow
1127
+ {
1128
+ type: "element",
1129
+ tag: "div",
1130
+ props: {
1131
+ "data-tachui-select-arrow": !0,
1132
+ "data-open": $()
1133
+ },
1134
+ children: [b("▼")]
1135
+ }
1136
+ ]
1137
+ }
1138
+ ]
1139
+ },
1140
+ // Dropdown menu
1141
+ ...$() ? [
1142
+ {
1143
+ type: "element",
1144
+ tag: "div",
1145
+ props: {
1146
+ "data-tachui-select-dropdown": !0,
1147
+ style: {
1148
+ maxHeight: `${T}px`
1149
+ }
1150
+ },
1151
+ children: [
1152
+ // Search input
1153
+ ...d ? [
1154
+ {
1155
+ type: "element",
1156
+ tag: "div",
1157
+ props: {
1158
+ "data-tachui-select-search": !0
1159
+ },
1160
+ children: [
1161
+ {
1162
+ type: "element",
1163
+ tag: "input",
1164
+ props: {
1165
+ type: "text",
1166
+ placeholder: "Search...",
1167
+ value: z(),
1168
+ oninput: te,
1169
+ "data-tachui-select-search-input": !0
1170
+ }
1171
+ }
1172
+ ]
1173
+ }
1174
+ ] : [],
1175
+ // Options list
1176
+ {
1177
+ type: "element",
1178
+ tag: "div",
1179
+ props: {
1180
+ role: "listbox",
1181
+ "aria-multiselectable": l,
1182
+ "data-tachui-select-options": !0
1183
+ },
1184
+ children: I().length > 0 ? I().map((i, y) => ({
1185
+ type: "element",
1186
+ tag: "div",
1187
+ props: {
1188
+ role: "option",
1189
+ "aria-selected": G(i),
1190
+ "aria-disabled": i.disabled,
1191
+ onclick: () => Q(i),
1192
+ "data-tachui-select-option": !0,
1193
+ "data-selected": G(i),
1194
+ "data-highlighted": N() === y,
1195
+ "data-disabled": i.disabled,
1196
+ "data-group": i.group
1197
+ },
1198
+ children: [
1199
+ // Selection indicator for multiple
1200
+ ...l ? [
1201
+ {
1202
+ type: "element",
1203
+ tag: "div",
1204
+ props: {
1205
+ "data-tachui-select-checkbox": !0,
1206
+ "data-checked": G(i)
1207
+ },
1208
+ children: [b(G(i) ? "✓" : "")]
1209
+ }
1210
+ ] : [],
1211
+ // Option label
1212
+ b(i.label)
1213
+ ]
1214
+ })) : [
1215
+ {
1216
+ type: "element",
1217
+ tag: "div",
1218
+ props: {
1219
+ "data-tachui-select-no-options": !0
1220
+ },
1221
+ children: [b(ne() ? g : F)]
1222
+ }
1223
+ ]
1224
+ }
1225
+ ]
1226
+ }
1227
+ ] : [],
1228
+ // Error message
1229
+ ...M ? [
1230
+ {
1231
+ type: "element",
1232
+ tag: "div",
1233
+ props: {
1234
+ id: `${t}-error`,
1235
+ role: "alert",
1236
+ "aria-live": "polite",
1237
+ "data-tachui-error": !0
1238
+ },
1239
+ children: [b(M)]
1240
+ }
1241
+ ] : [],
1242
+ // Helper text
1243
+ ...f && !M ? [
1244
+ {
1245
+ type: "element",
1246
+ tag: "div",
1247
+ props: {
1248
+ id: `${t}-helper`,
1249
+ "data-tachui-helper": !0
1250
+ },
1251
+ children: [b(f)]
1252
+ }
1253
+ ] : []
1254
+ ]
1255
+ }),
1256
+ props: e
1257
+ };
1258
+ return W.cleanup || (W.cleanup = []), W.cleanup.push(() => {
1259
+ c && c.unregister(t);
1260
+ }), Ve(W, {
1261
+ onDOMReady: (i, y) => {
1262
+ y && Te(
1263
+ W,
1264
+ () => {
1265
+ $() && (L(!1), a(!1), p.onBlur(), u && u(t, p.value()));
1266
+ },
1267
+ "[data-tachui-select-container]"
1268
+ );
1269
+ }
1270
+ }), W;
1271
+ }, Ue = (e) => ge({ ...e, multiple: !0 }), je = (e) => ge({ ...e, searchable: !0 }), Y = {
1272
+ /**
1273
+ * Phone number formatter (US format)
1274
+ */
1275
+ phone: (e) => {
1276
+ const t = e.replace(/\D/g, "");
1277
+ return t.length <= 3 ? t : t.length <= 6 ? `(${t.slice(0, 3)}) ${t.slice(3)}` : `(${t.slice(0, 3)}) ${t.slice(3, 6)}-${t.slice(6, 10)}`;
1278
+ },
1279
+ /**
1280
+ * Credit card formatter
1281
+ */
1282
+ creditCard: (e) => e.replace(/\D/g, "").replace(/(\d{4})(?=\d)/g, "$1 "),
1283
+ /**
1284
+ * Currency formatter
1285
+ */
1286
+ currency: (e) => {
1287
+ const t = parseFloat(e.replace(/[^\d.]/g, ""));
1288
+ return Number.isNaN(t) ? "" : new Intl.NumberFormat("en-US", {
1289
+ style: "currency",
1290
+ currency: "USD"
1291
+ }).format(t);
1292
+ },
1293
+ /**
1294
+ * Uppercase formatter
1295
+ */
1296
+ uppercase: (e) => e.toUpperCase(),
1297
+ /**
1298
+ * Lowercase formatter
1299
+ */
1300
+ lowercase: (e) => e.toLowerCase(),
1301
+ /**
1302
+ * Title case formatter
1303
+ */
1304
+ titleCase: (e) => e.replace(
1305
+ /\w\S*/g,
1306
+ (t) => t.charAt(0).toUpperCase() + t.substr(1).toLowerCase()
1307
+ ),
1308
+ /**
1309
+ * Social Security Number formatter
1310
+ */
1311
+ ssn: (e) => {
1312
+ const t = e.replace(/\D/g, "");
1313
+ return t.length <= 3 ? t : t.length <= 5 ? `${t.slice(0, 3)}-${t.slice(3)}` : `${t.slice(0, 3)}-${t.slice(3, 5)}-${t.slice(5, 9)}`;
1314
+ },
1315
+ /**
1316
+ * Postal code formatter (US ZIP)
1317
+ */
1318
+ postalCode: (e) => {
1319
+ const t = e.replace(/\D/g, "");
1320
+ return t.length <= 5 ? t : `${t.slice(0, 5)}-${t.slice(5, 9)}`;
1321
+ },
1322
+ /**
1323
+ * Decimal number formatter
1324
+ */
1325
+ decimal: (e = 2) => (t) => {
1326
+ const n = parseFloat(t.replace(/[^\d.-]/g, ""));
1327
+ return Number.isNaN(n) ? "" : n.toFixed(e);
1328
+ },
1329
+ /**
1330
+ * Percentage formatter
1331
+ */
1332
+ percentage: (e) => {
1333
+ const t = parseFloat(e.replace(/[^\d.-]/g, ""));
1334
+ return Number.isNaN(t) ? "" : `${t}%`;
1335
+ },
1336
+ /**
1337
+ * Custom formatter factory
1338
+ */
1339
+ custom: (e) => e
1340
+ }, Z = {
1341
+ /**
1342
+ * Phone number parser - extracts digits only
1343
+ */
1344
+ phone: (e) => e.replace(/\D/g, ""),
1345
+ /**
1346
+ * Credit card parser - extracts digits only
1347
+ */
1348
+ creditCard: (e) => e.replace(/\D/g, ""),
1349
+ /**
1350
+ * Currency parser - extracts numeric value
1351
+ */
1352
+ currency: (e) => {
1353
+ const t = e.match(/[\d.-]+/);
1354
+ return t ? t[0] : "";
1355
+ },
1356
+ /**
1357
+ * SSN parser - extracts digits only
1358
+ */
1359
+ ssn: (e) => e.replace(/\D/g, ""),
1360
+ /**
1361
+ * Postal code parser - extracts digits only
1362
+ */
1363
+ postalCode: (e) => e.replace(/\D/g, ""),
1364
+ /**
1365
+ * Decimal parser - extracts number
1366
+ */
1367
+ decimal: (e) => {
1368
+ const t = e.match(/^-?\d*\.?\d*/);
1369
+ return t ? t[0] : "";
1370
+ },
1371
+ /**
1372
+ * Percentage parser - extracts number without %
1373
+ */
1374
+ percentage: (e) => e.replace(/[^\d.-]/g, ""),
1375
+ /**
1376
+ * No-op parser (returns value unchanged)
1377
+ */
1378
+ none: (e) => e,
1379
+ /**
1380
+ * Custom parser factory
1381
+ */
1382
+ custom: (e) => e
1383
+ }, se = (e, t) => e === void 0 ? t : typeof e == "function" || Ae(e) ? e() : e, q = (e) => {
1384
+ const {
1385
+ name: t,
1386
+ label: n,
1387
+ placeholder: r,
1388
+ type: l = "text",
1389
+ multiline: d = !1,
1390
+ rows: v = 3,
1391
+ minLength: w,
1392
+ maxLength: F,
1393
+ pattern: g,
1394
+ autocomplete: T,
1395
+ spellcheck: S = !0,
1396
+ disabled: A = !1,
1397
+ required: C = !1,
1398
+ validation: m,
1399
+ value: h,
1400
+ defaultValue: o = "",
1401
+ onChange: u,
1402
+ onBlur: k,
1403
+ onFocus: O,
1404
+ error: f,
1405
+ helperText: x,
1406
+ // New enhanced features
1407
+ keyboardType: c = "default",
1408
+ returnKeyType: p,
1409
+ autoCapitalize: $,
1410
+ autoFocus: L = !1,
1411
+ accessibilityLabel: _,
1412
+ accessibilityHint: a,
1413
+ accessibilityRole: z = "textbox",
1414
+ formatter: R,
1415
+ parser: N,
1416
+ validateOnChange: H = !1,
1417
+ validateOnBlur: ne = !0,
1418
+ font: I,
1419
+ textAlign: ae,
1420
+ text: Q,
1421
+ placeholderSignal: K,
1422
+ disabledSignal: te,
1423
+ ...X
1424
+ } = e, B = e._formContext, D = ee(t, h ?? o, m);
1425
+ B && B.register(t, m);
1426
+ const [re, G] = E(!1), [M, W] = E(0), [i, y] = E(""), [P, le] = E(""), [me, ye] = E(!1);
1427
+ j(() => {
1428
+ if (Q) {
1429
+ const V = se(Q, "");
1430
+ y(V), V !== D.value() && D.setValue(V);
1431
+ }
1432
+ }), j(() => {
1433
+ K && le(se(K, ""));
1434
+ }), j(() => {
1435
+ te && ye(se(te, !1));
1436
+ }), h !== void 0 && j(() => {
1437
+ D.value() !== h && D.setValue(h);
1438
+ }), j(() => {
1439
+ const V = D.value() || "";
1440
+ W(String(V).length);
1441
+ });
1442
+ const de = (V) => {
1443
+ if (R)
1444
+ try {
1445
+ return R(V);
1446
+ } catch (U) {
1447
+ return console.warn("TextField formatter error:", U), V;
1448
+ }
1449
+ return V;
1450
+ }, ve = (V) => {
1451
+ if (N)
1452
+ try {
1453
+ return N(V);
1454
+ } catch (U) {
1455
+ return console.warn("TextField parser error:", U), V;
1456
+ }
1457
+ return V;
1458
+ }, xe = (V) => {
1459
+ const U = V.target, ce = U.value, ie = ve(ce), ue = de(ie);
1460
+ if (D.setValue(ie), ue !== ce && U) {
1461
+ const fe = U.selectionStart || 0;
1462
+ U.value = ue, U.setSelectionRange(fe, fe);
1463
+ }
1464
+ B && B.setValue(t, ie), H && D.validate(), u && u(t, ie, D);
1465
+ }, ke = (V) => {
1466
+ G(!0), D.onFocus(), O && O(t, D.value());
1467
+ }, Ce = (V) => {
1468
+ G(!1), D.onBlur(), ne && D.validate(), k && k(t, D.value());
1469
+ }, we = (V) => {
1470
+ V.key === "Enter" && !d && (V.preventDefault(), B?.submitForm && B.submitForm());
1471
+ }, J = f || D.error() || B?.getError(t), Fe = K ? P() : r, Se = te ? me() : A, $e = Q ? i() : D.value() || "", De = de($e), oe = {
1472
+ id: X.id || t,
1473
+ name: t,
1474
+ value: De,
1475
+ placeholder: Fe,
1476
+ disabled: Se,
1477
+ required: C,
1478
+ minlength: w,
1479
+ maxlength: F,
1480
+ pattern: g,
1481
+ autocomplete: T,
1482
+ spellcheck: S,
1483
+ oninput: xe,
1484
+ onfocus: ke,
1485
+ onblur: Ce,
1486
+ onkeydown: we,
1487
+ // Enhanced accessibility
1488
+ "aria-invalid": !!J,
1489
+ "aria-describedby": [
1490
+ J ? `${t}-error` : null,
1491
+ x ? `${t}-helper` : null,
1492
+ F ? `${t}-counter` : null,
1493
+ a ? `${t}-hint` : null
1494
+ ].filter(Boolean).join(" ") || void 0,
1495
+ "aria-label": _,
1496
+ role: z,
1497
+ // Mobile features
1498
+ inputMode: c !== "default" ? c : void 0,
1499
+ enterKeyHint: p,
1500
+ autoCapitalize: $,
1501
+ autoFocus: L,
1502
+ // Data attributes for styling and debugging
1503
+ "data-tachui-textfield": !0,
1504
+ "data-field-name": t,
1505
+ "data-field-type": l,
1506
+ "data-field-valid": !J,
1507
+ "data-field-touched": D.touched(),
1508
+ "data-field-dirty": D.dirty(),
1509
+ "data-field-focused": re(),
1510
+ "data-field-validating": D.validating(),
1511
+ "data-field-has-formatter": !!R,
1512
+ "data-field-has-parser": !!N,
1513
+ // Typography styling
1514
+ style: {
1515
+ ...I?.family && { fontFamily: I.family },
1516
+ ...I?.size && { fontSize: typeof I.size == "number" ? `${I.size}px` : I.size },
1517
+ ...I?.weight && { fontWeight: I.weight },
1518
+ ...I?.style && { fontStyle: I.style },
1519
+ ...ae && { textAlign: ae }
1520
+ // Additional styling can be applied via modifiers
1521
+ }
1522
+ };
1523
+ return l && !d && (oe.type = l), {
1524
+ type: "component",
1525
+ id: X.id || `textfield-${t}`,
1526
+ render: () => s(
1527
+ "div",
1528
+ {
1529
+ ...X,
1530
+ class: `tachui-textfield ${X.class || ""}`.trim(),
1531
+ "data-tachui-textfield-container": !0,
1532
+ "data-field-state": J ? "error" : D.validating() ? "validating" : "valid"
1533
+ },
1534
+ ...n ? [
1535
+ s(
1536
+ "label",
1537
+ {
1538
+ for: oe.id,
1539
+ "data-tachui-label": !0,
1540
+ "data-required": C
1541
+ },
1542
+ b(n),
1543
+ ...C ? [
1544
+ s(
1545
+ "span",
1546
+ {
1547
+ "aria-label": "required",
1548
+ "data-required-indicator": !0
1549
+ },
1550
+ b(" *")
1551
+ )
1552
+ ] : []
1553
+ )
1554
+ ] : [],
1555
+ // Input field
1556
+ s(d ? "textarea" : "input", {
1557
+ ...oe,
1558
+ ...d ? { rows: v } : {}
1559
+ }),
1560
+ ...F ? [
1561
+ s(
1562
+ "div",
1563
+ {
1564
+ id: `${t}-counter`,
1565
+ "data-tachui-character-counter": !0,
1566
+ "data-over-limit": M() > F
1567
+ },
1568
+ b(`${M()}/${F}`)
1569
+ )
1570
+ ] : [],
1571
+ ...J ? [
1572
+ s(
1573
+ "div",
1574
+ {
1575
+ id: `${t}-error`,
1576
+ role: "alert",
1577
+ "aria-live": "polite",
1578
+ "data-tachui-error": !0
1579
+ },
1580
+ b(J)
1581
+ )
1582
+ ] : [],
1583
+ ...x && !J ? [
1584
+ s(
1585
+ "div",
1586
+ {
1587
+ id: `${t}-helper`,
1588
+ "data-tachui-helper": !0
1589
+ },
1590
+ b(x)
1591
+ )
1592
+ ] : [],
1593
+ ...a ? [
1594
+ s(
1595
+ "div",
1596
+ {
1597
+ id: `${t}-hint`,
1598
+ "data-tachui-accessibility-hint": !0,
1599
+ "aria-hidden": "true"
1600
+ },
1601
+ b(a)
1602
+ )
1603
+ ] : [],
1604
+ ...D.validating() ? [
1605
+ s(
1606
+ "div",
1607
+ {
1608
+ "data-tachui-validation-spinner": !0,
1609
+ "aria-label": "Validating...",
1610
+ "aria-live": "polite"
1611
+ },
1612
+ b("⏳")
1613
+ )
1614
+ ] : []
1615
+ ),
1616
+ props: e,
1617
+ cleanup: [
1618
+ () => {
1619
+ B && B.unregister(t);
1620
+ }
1621
+ ]
1622
+ };
1623
+ }, He = (e) => q({
1624
+ ...e,
1625
+ type: "email",
1626
+ keyboardType: "email",
1627
+ validation: {
1628
+ rules: ["required", "email"],
1629
+ validateOn: "blur",
1630
+ ...e.validation
1631
+ },
1632
+ accessibilityRole: "textbox",
1633
+ accessibilityLabel: e.accessibilityLabel || "Email address"
1634
+ }), Ke = (e) => {
1635
+ const {
1636
+ showStrengthIndicator: t = !1,
1637
+ strongValidation: n = !1,
1638
+ minLength: r,
1639
+ ...l
1640
+ } = e, d = ["required"];
1641
+ return n ? d.push("strongPassword") : (d.push("minLength"), d.push({ name: "minLength", options: { minLength: r || 6 } })), q({
1642
+ ...l,
1643
+ type: "password",
1644
+ validation: {
1645
+ rules: d,
1646
+ validateOn: "change",
1647
+ ...e.validation
1648
+ },
1649
+ accessibilityLabel: e.accessibilityLabel || "Password"
1650
+ });
1651
+ }, We = (e) => q({
1652
+ ...e,
1653
+ type: "search",
1654
+ keyboardType: "search",
1655
+ placeholder: e.placeholder || "Search...",
1656
+ accessibilityRole: "searchbox",
1657
+ accessibilityLabel: e.accessibilityLabel || "Search"
1658
+ }), Ge = (e) => q({
1659
+ ...e,
1660
+ type: "url",
1661
+ keyboardType: "url",
1662
+ validation: {
1663
+ rules: ["url"],
1664
+ validateOn: "blur",
1665
+ ...e.validation
1666
+ },
1667
+ accessibilityLabel: e.accessibilityLabel || "Website URL"
1668
+ }), Je = (e) => {
1669
+ const { format: t = "us", ...n } = e;
1670
+ return q({
1671
+ ...n,
1672
+ type: "tel",
1673
+ keyboardType: "phone",
1674
+ formatter: Y.phone,
1675
+ parser: Z.phone,
1676
+ validation: {
1677
+ rules: ["phone"],
1678
+ validateOn: "blur",
1679
+ ...e.validation
1680
+ },
1681
+ accessibilityLabel: e.accessibilityLabel || "Phone number"
1682
+ });
1683
+ }, Qe = (e) => {
1684
+ const { min: t, max: n, precision: r = 0, currency: l = !1, ...d } = e, v = ["numeric"];
1685
+ return t !== void 0 && (v.push("min"), v.push({ name: "min", options: { min: t } })), n !== void 0 && (v.push("max"), v.push({ name: "max", options: { max: n } })), q({
1686
+ ...d,
1687
+ type: "number",
1688
+ keyboardType: "numeric",
1689
+ formatter: l ? Y.currency : r > 0 ? Y.decimal(r) : void 0,
1690
+ parser: l ? Z.currency : Z.decimal,
1691
+ validation: {
1692
+ rules: v,
1693
+ validateOn: "blur",
1694
+ ...e.validation
1695
+ },
1696
+ accessibilityLabel: e.accessibilityLabel || "Number"
1697
+ });
1698
+ }, Xe = (e) => q({
1699
+ ...e,
1700
+ type: "text",
1701
+ keyboardType: "numeric",
1702
+ formatter: Y.creditCard,
1703
+ parser: Z.creditCard,
1704
+ maxLength: 19,
1705
+ // 16 digits + 3 spaces
1706
+ validation: {
1707
+ rules: ["creditCard"],
1708
+ validateOn: "blur",
1709
+ ...e.validation
1710
+ },
1711
+ accessibilityLabel: e.accessibilityLabel || "Credit card number"
1712
+ }), Ye = (e) => q({
1713
+ ...e,
1714
+ type: "text",
1715
+ keyboardType: "numeric",
1716
+ formatter: Y.ssn,
1717
+ parser: Z.ssn,
1718
+ maxLength: 11,
1719
+ // 9 digits + 2 hyphens
1720
+ validation: {
1721
+ rules: ["ssn"],
1722
+ validateOn: "blur",
1723
+ ...e.validation
1724
+ },
1725
+ accessibilityLabel: e.accessibilityLabel || "Social Security Number"
1726
+ }), Ze = (e) => q({
1727
+ ...e,
1728
+ type: "text",
1729
+ keyboardType: "numeric",
1730
+ formatter: Y.postalCode,
1731
+ parser: Z.postalCode,
1732
+ maxLength: 10,
1733
+ // 5 or 9 digits + hyphen
1734
+ validation: {
1735
+ rules: ["zipCode"],
1736
+ // Use zipCode to match test expectation
1737
+ validateOn: "blur",
1738
+ ...e.validation
1739
+ },
1740
+ accessibilityLabel: e.accessibilityLabel || "Postal code"
1741
+ }), et = (e) => q({
1742
+ ...e,
1743
+ multiline: !0,
1744
+ accessibilityLabel: e.accessibilityLabel || "Text area"
1745
+ }), tt = (e) => {
1746
+ const { min: t, max: n, ...r } = e, l = ["date"];
1747
+ return t && l.push({ name: "min", options: { min: new Date(t) } }), n && l.push({ name: "max", options: { max: new Date(n) } }), q({
1748
+ ...r,
1749
+ type: "date",
1750
+ validation: {
1751
+ rules: l,
1752
+ validateOn: "blur",
1753
+ ...e.validation
1754
+ },
1755
+ accessibilityLabel: e.accessibilityLabel || "Date"
1756
+ });
1757
+ }, at = (e) => q({
1758
+ ...e,
1759
+ type: "time",
1760
+ validation: {
1761
+ rules: ["time"],
1762
+ validateOn: "blur",
1763
+ ...e.validation
1764
+ },
1765
+ accessibilityLabel: e.accessibilityLabel || "Time"
1766
+ }), rt = (e) => q({
1767
+ ...e,
1768
+ type: "color",
1769
+ accessibilityLabel: e.accessibilityLabel || "Color picker"
1770
+ });
1771
+ export {
1772
+ be as C,
1773
+ tt as D,
1774
+ He as E,
1775
+ Pe as F,
1776
+ Ue as M,
1777
+ Qe as N,
1778
+ Ke as P,
1779
+ Ie as R,
1780
+ Me as S,
1781
+ et as T,
1782
+ Ge as U,
1783
+ Re as a,
1784
+ Ne as b,
1785
+ _e as c,
1786
+ ze as d,
1787
+ je as e,
1788
+ ge as f,
1789
+ rt as g,
1790
+ Xe as h,
1791
+ Je as i,
1792
+ Ze as j,
1793
+ We as k,
1794
+ Ye as l,
1795
+ q as m,
1796
+ at as n,
1797
+ Y as o,
1798
+ Z as p
1799
+ };