@viveksinghind/narrative-form-react 1.0.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,1809 @@
1
+ import React, { createContext, useState, useRef, useCallback, useEffect, useContext, useMemo } from 'react';
2
+ import { validateField, hasAsyncValidation, validateFieldAsync, FormStateEngine, mergeStrings, fetchFormConfig } from '@viveksinghind/narrative-form-core';
3
+ export { FormStateEngine, clearValidators, defaultStrings, getRegisteredValidatorNames, getValidator, hasAsyncValidation, hasValidator, mergeStrings, registerBuiltinValidators, registerValidator, unregisterValidator, validateField, validateFieldAsync } from '@viveksinghind/narrative-form-core';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ // src/NarrativeForm.tsx
7
+ function useFormState(fields) {
8
+ const [, setTick] = useState(0);
9
+ const engineRef = useRef(null);
10
+ if (engineRef.current === null) {
11
+ engineRef.current = new FormStateEngine(fields, () => {
12
+ setTick((t) => t + 1);
13
+ });
14
+ }
15
+ const engine = engineRef.current;
16
+ const startTyping = useCallback((key) => engine.startTyping(key), [engine]);
17
+ const activateField = useCallback((key) => engine.activateField(key), [engine]);
18
+ const confirmField = useCallback(
19
+ (key, value) => engine.confirmField(key, value),
20
+ [engine]
21
+ );
22
+ const editField = useCallback((key) => engine.editField(key), [engine]);
23
+ const reconfirmField = useCallback(
24
+ (key, value) => engine.reconfirmField(key, value),
25
+ [engine]
26
+ );
27
+ const next = useCallback(() => engine.next(), [engine]);
28
+ const focusField = useCallback((key) => engine.focusField(key), [engine]);
29
+ const reset = useCallback(() => engine.reset(), [engine]);
30
+ const getValues = useCallback(() => engine.getValues(), [engine]);
31
+ const getMeta = useCallback(
32
+ (formId, formVersion) => engine.getMeta(formId, formVersion),
33
+ [engine]
34
+ );
35
+ const snapshot = engine.getSnapshot();
36
+ return useMemo(
37
+ () => ({
38
+ snapshot,
39
+ startTyping,
40
+ activateField,
41
+ confirmField,
42
+ editField,
43
+ reconfirmField,
44
+ next,
45
+ focusField,
46
+ reset,
47
+ getValues,
48
+ getMeta
49
+ }),
50
+ // snapshot changes every tick, which is what we want
51
+ // eslint-disable-next-line react-hooks/exhaustive-deps
52
+ [snapshot]
53
+ );
54
+ }
55
+ function useDynamicForm({
56
+ fieldsUrl,
57
+ fieldsUrlHeaders,
58
+ formConfig,
59
+ onFetchError
60
+ }) {
61
+ const [config, setConfig] = useState(formConfig != null ? formConfig : null);
62
+ const [loading, setLoading] = useState(!!fieldsUrl && !formConfig);
63
+ const [error, setError] = useState(null);
64
+ const [retryCount, setRetryCount] = useState(0);
65
+ useEffect(() => {
66
+ if (formConfig) {
67
+ setConfig(formConfig);
68
+ setLoading(false);
69
+ setError(null);
70
+ return;
71
+ }
72
+ if (!fieldsUrl) {
73
+ return;
74
+ }
75
+ let isMounted = true;
76
+ setLoading(true);
77
+ setError(null);
78
+ fetchFormConfig(fieldsUrl, { headers: fieldsUrlHeaders }).then((data) => {
79
+ if (isMounted) {
80
+ setConfig(data);
81
+ setLoading(false);
82
+ }
83
+ }).catch((err) => {
84
+ if (isMounted) {
85
+ setError(err);
86
+ setLoading(false);
87
+ onFetchError == null ? void 0 : onFetchError(err);
88
+ }
89
+ });
90
+ return () => {
91
+ isMounted = false;
92
+ };
93
+ }, [fieldsUrl, fieldsUrlHeaders, formConfig, retryCount, onFetchError]);
94
+ const retry = useCallback(() => {
95
+ if (fieldsUrl && !formConfig) {
96
+ setRetryCount((c) => c + 1);
97
+ }
98
+ }, [fieldsUrl, formConfig]);
99
+ return { config, loading, error, retry };
100
+ }
101
+ function prefersReducedMotion() {
102
+ if (typeof window === "undefined") return false;
103
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
104
+ }
105
+ function useTypewriter(options) {
106
+ const { text, speed = 38, enabled = true, pauseAfter = 100, onComplete } = options;
107
+ const [charIndex, setCharIndex] = useState(0);
108
+ const [isComplete, setIsComplete] = useState(false);
109
+ const intervalRef = useRef(null);
110
+ const pauseTimeoutRef = useRef(null);
111
+ const onCompleteRef = useRef(onComplete);
112
+ onCompleteRef.current = onComplete;
113
+ const cleanup = useCallback(() => {
114
+ if (intervalRef.current !== null) {
115
+ clearInterval(intervalRef.current);
116
+ intervalRef.current = null;
117
+ }
118
+ if (pauseTimeoutRef.current !== null) {
119
+ clearTimeout(pauseTimeoutRef.current);
120
+ pauseTimeoutRef.current = null;
121
+ }
122
+ }, []);
123
+ useEffect(() => {
124
+ var _a;
125
+ if (!enabled || prefersReducedMotion() || text.length === 0) {
126
+ setCharIndex(text.length);
127
+ setIsComplete(true);
128
+ (_a = onCompleteRef.current) == null ? void 0 : _a.call(onCompleteRef);
129
+ return;
130
+ }
131
+ setCharIndex(0);
132
+ setIsComplete(false);
133
+ intervalRef.current = setInterval(() => {
134
+ setCharIndex((prev) => {
135
+ const next = prev + 1;
136
+ if (next >= text.length) {
137
+ if (intervalRef.current !== null) {
138
+ clearInterval(intervalRef.current);
139
+ intervalRef.current = null;
140
+ }
141
+ pauseTimeoutRef.current = setTimeout(() => {
142
+ var _a2;
143
+ setIsComplete(true);
144
+ (_a2 = onCompleteRef.current) == null ? void 0 : _a2.call(onCompleteRef);
145
+ }, pauseAfter);
146
+ return text.length;
147
+ }
148
+ return next;
149
+ });
150
+ }, speed);
151
+ return cleanup;
152
+ }, [text, speed, enabled, pauseAfter, cleanup]);
153
+ return {
154
+ displayedText: text.slice(0, charIndex),
155
+ isTyping: charIndex < text.length && !isComplete,
156
+ isComplete
157
+ };
158
+ }
159
+ var Cursor = React.memo(function Cursor2({
160
+ cursorChar = "|",
161
+ className
162
+ }) {
163
+ const classes = ["ns-cursor", className].filter(Boolean).join(" ");
164
+ return /* @__PURE__ */ jsx("span", { className: classes, "aria-hidden": "true", children: cursorChar });
165
+ });
166
+ var Prose = React.memo(function Prose2({
167
+ text,
168
+ animate = true,
169
+ speed = 38,
170
+ cursor = true,
171
+ cursorChar = "|",
172
+ pauseAfter = 100,
173
+ onComplete,
174
+ className
175
+ }) {
176
+ const { displayedText, isTyping, isComplete } = useTypewriter({
177
+ text,
178
+ speed,
179
+ enabled: animate,
180
+ pauseAfter,
181
+ onComplete
182
+ });
183
+ const classes = [
184
+ "ns-prose",
185
+ isTyping ? "ns-prose--typing" : void 0,
186
+ className
187
+ ].filter(Boolean).join(" ");
188
+ return /* @__PURE__ */ jsxs("span", { className: classes, children: [
189
+ displayedText,
190
+ cursor && isTyping && /* @__PURE__ */ jsx(Cursor, { cursorChar })
191
+ ] });
192
+ });
193
+ var EnterButton = React.memo(function EnterButton2({
194
+ onConfirm,
195
+ label = "\u21B5",
196
+ className
197
+ }) {
198
+ const classes = ["ns-enter-btn", className].filter(Boolean).join(" ");
199
+ return /* @__PURE__ */ jsx(
200
+ "button",
201
+ {
202
+ type: "button",
203
+ className: classes,
204
+ onClick: onConfirm,
205
+ "aria-label": "Confirm",
206
+ children: label
207
+ }
208
+ );
209
+ });
210
+ var InlineInput = function InlineInput2({
211
+ fieldKey,
212
+ type = "text",
213
+ placeholder,
214
+ defaultValue = "",
215
+ suffix,
216
+ sanitise,
217
+ onConfirm,
218
+ onChange,
219
+ onFocus,
220
+ onBlur,
221
+ onEscape,
222
+ inputClassName,
223
+ className
224
+ }) {
225
+ const [value, setValue] = useState(defaultValue);
226
+ const [isFocused, setIsFocused] = useState(false);
227
+ const inputRef = useRef(null);
228
+ useEffect(() => {
229
+ var _a;
230
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
231
+ }, []);
232
+ const applyValue = useCallback(
233
+ (raw) => {
234
+ const cleaned = sanitise ? sanitise(raw) : raw;
235
+ setValue(cleaned);
236
+ onChange == null ? void 0 : onChange(cleaned);
237
+ },
238
+ [sanitise, onChange]
239
+ );
240
+ const handleChange = (e) => {
241
+ applyValue(e.target.value);
242
+ };
243
+ const handlePaste = useCallback(
244
+ (e) => {
245
+ if (!sanitise) return;
246
+ e.preventDefault();
247
+ const pasted = e.clipboardData.getData("text");
248
+ applyValue(pasted);
249
+ },
250
+ [sanitise, applyValue]
251
+ );
252
+ const handleKeyDown = (e) => {
253
+ if (e.key === "Enter") {
254
+ e.preventDefault();
255
+ onConfirm(value);
256
+ } else if (e.key === "Escape") {
257
+ e.preventDefault();
258
+ onEscape == null ? void 0 : onEscape();
259
+ }
260
+ };
261
+ const handleFocus = () => {
262
+ setIsFocused(true);
263
+ onFocus == null ? void 0 : onFocus();
264
+ };
265
+ const handleBlur = () => {
266
+ setIsFocused(false);
267
+ onBlur == null ? void 0 : onBlur(value);
268
+ };
269
+ const handleConfirmClick = () => {
270
+ onConfirm(value);
271
+ };
272
+ const wrapClasses = ["ns-input-wrap", className].filter(Boolean).join(" ");
273
+ const inputClasses = [
274
+ "ns-input",
275
+ `ns-input--${type}`,
276
+ isFocused ? "ns-input--focused" : void 0,
277
+ inputClassName
278
+ ].filter(Boolean).join(" ");
279
+ const inputMode = (() => {
280
+ switch (type) {
281
+ case "tel":
282
+ return "tel";
283
+ case "email":
284
+ return "email";
285
+ case "number":
286
+ return "numeric";
287
+ default:
288
+ return void 0;
289
+ }
290
+ })();
291
+ return /* @__PURE__ */ jsxs("span", { className: wrapClasses, children: [
292
+ /* @__PURE__ */ jsx(
293
+ "input",
294
+ {
295
+ ref: inputRef,
296
+ id: `ns-field-${fieldKey}`,
297
+ className: inputClasses,
298
+ type: type === "number" ? "text" : type,
299
+ inputMode,
300
+ value,
301
+ placeholder,
302
+ onChange: handleChange,
303
+ onKeyDown: handleKeyDown,
304
+ onFocus: handleFocus,
305
+ onBlur: handleBlur,
306
+ onPaste: handlePaste,
307
+ autoComplete: "off",
308
+ "aria-label": fieldKey,
309
+ "aria-invalid": void 0
310
+ }
311
+ ),
312
+ /* @__PURE__ */ jsx(EnterButton, { onConfirm: handleConfirmClick }),
313
+ suffix && /* @__PURE__ */ jsx("span", { className: "ns-suffix", children: suffix })
314
+ ] });
315
+ };
316
+ var EditIcon = React.memo(function EditIcon2({
317
+ onEdit,
318
+ label = "Edit",
319
+ className
320
+ }) {
321
+ const classes = ["ns-edit-btn", className].filter(Boolean).join(" ");
322
+ return /* @__PURE__ */ jsx(
323
+ "button",
324
+ {
325
+ type: "button",
326
+ className: classes,
327
+ onClick: onEdit,
328
+ "aria-label": label,
329
+ title: label,
330
+ children: /* @__PURE__ */ jsxs(
331
+ "svg",
332
+ {
333
+ width: "14",
334
+ height: "14",
335
+ viewBox: "0 0 24 24",
336
+ fill: "none",
337
+ stroke: "currentColor",
338
+ strokeWidth: "2",
339
+ strokeLinecap: "round",
340
+ strokeLinejoin: "round",
341
+ "aria-hidden": "true",
342
+ children: [
343
+ /* @__PURE__ */ jsx("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" }),
344
+ /* @__PURE__ */ jsx("path", { d: "m15 5 4 4" })
345
+ ]
346
+ }
347
+ )
348
+ }
349
+ );
350
+ });
351
+ var FilledValue = React.memo(function FilledValue2({
352
+ value,
353
+ suffix,
354
+ editable = true,
355
+ onEdit,
356
+ editLabel = "Edit",
357
+ className
358
+ }) {
359
+ const classes = ["ns-filled-wrap", className].filter(Boolean).join(" ");
360
+ return /* @__PURE__ */ jsxs("span", { className: classes, children: [
361
+ /* @__PURE__ */ jsx("span", { className: "ns-filled-value", children: value }),
362
+ suffix && /* @__PURE__ */ jsx("span", { className: "ns-suffix", children: suffix }),
363
+ editable && onEdit && /* @__PURE__ */ jsx(EditIcon, { onEdit, label: editLabel })
364
+ ] });
365
+ });
366
+ var ErrorMessage = React.memo(function ErrorMessage2({
367
+ message,
368
+ display = {},
369
+ className
370
+ }) {
371
+ var _a, _b, _c, _d, _e;
372
+ const mode = (_a = display.mode) != null ? _a : "inline";
373
+ if (mode === "toast" || mode === "shake") {
374
+ return null;
375
+ }
376
+ const position = (_b = display.position) != null ? _b : "below";
377
+ const animateIn = (_c = display.animateIn) != null ? _c : "fadeUp";
378
+ const showIcon = (_d = display.icon) != null ? _d : false;
379
+ const iconChar = (_e = display.iconChar) != null ? _e : "\u26A0";
380
+ const isTooltip = mode === "tooltip";
381
+ const isInlineShake = mode === "inline+shake";
382
+ const wrapClasses = [
383
+ "ns-error-wrap",
384
+ isTooltip ? "ns-error-wrap--tooltip" : "ns-error-wrap--inline",
385
+ `ns-error-wrap--${position}`,
386
+ animateIn === "fadeUp" ? "ns-animate-fade-up" : void 0,
387
+ animateIn === "slideDown" ? "ns-animate-slide-down" : void 0,
388
+ className
389
+ ].filter(Boolean).join(" ");
390
+ const textClasses = [
391
+ "ns-error-text",
392
+ isInlineShake ? "ns-error-text--shake" : void 0
393
+ ].filter(Boolean).join(" ");
394
+ return /* @__PURE__ */ jsx("div", { className: wrapClasses, role: "alert", "aria-live": "assertive", children: /* @__PURE__ */ jsxs("span", { className: textClasses, children: [
395
+ showIcon && /* @__PURE__ */ jsxs("span", { className: "ns-error-icon", "aria-hidden": "true", children: [
396
+ iconChar,
397
+ " "
398
+ ] }),
399
+ message
400
+ ] }) });
401
+ });
402
+ var ChipsField = function ChipsField2({
403
+ fieldKey,
404
+ options,
405
+ defaultValue,
406
+ autoAdvance = false,
407
+ onConfirm,
408
+ onChange,
409
+ className
410
+ }) {
411
+ const [selected, setSelected] = useState(defaultValue != null ? defaultValue : null);
412
+ const [focusedIndex, setFocusedIndex] = useState(0);
413
+ const chipsRef = useRef([]);
414
+ const handleSelect = useCallback(
415
+ (option) => {
416
+ setSelected(option);
417
+ onChange == null ? void 0 : onChange(option);
418
+ if (autoAdvance) {
419
+ onConfirm(option);
420
+ }
421
+ },
422
+ [autoAdvance, onConfirm, onChange]
423
+ );
424
+ const handleConfirm = useCallback(() => {
425
+ if (selected !== null) {
426
+ onConfirm(selected);
427
+ }
428
+ }, [selected, onConfirm]);
429
+ const handleKeyDown = useCallback(
430
+ (e, index) => {
431
+ var _a, _b;
432
+ switch (e.key) {
433
+ case "Enter":
434
+ case " ": {
435
+ e.preventDefault();
436
+ const option = options[index];
437
+ if (option) handleSelect(option);
438
+ break;
439
+ }
440
+ case "ArrowRight":
441
+ case "ArrowDown": {
442
+ e.preventDefault();
443
+ const nextIndex = (index + 1) % options.length;
444
+ setFocusedIndex(nextIndex);
445
+ (_a = chipsRef.current[nextIndex]) == null ? void 0 : _a.focus();
446
+ break;
447
+ }
448
+ case "ArrowLeft":
449
+ case "ArrowUp": {
450
+ e.preventDefault();
451
+ const prevIndex = (index - 1 + options.length) % options.length;
452
+ setFocusedIndex(prevIndex);
453
+ (_b = chipsRef.current[prevIndex]) == null ? void 0 : _b.focus();
454
+ break;
455
+ }
456
+ }
457
+ },
458
+ [handleSelect, options]
459
+ );
460
+ const wrapClasses = ["ns-chips-wrap", className].filter(Boolean).join(" ");
461
+ return /* @__PURE__ */ jsxs("span", { className: wrapClasses, role: "listbox", "aria-label": fieldKey, children: [
462
+ options.map((option, index) => {
463
+ const chipClasses = [
464
+ "ns-chip",
465
+ selected === option ? "ns-chip--active" : void 0
466
+ ].filter(Boolean).join(" ");
467
+ return /* @__PURE__ */ jsx(
468
+ "button",
469
+ {
470
+ ref: (el) => {
471
+ chipsRef.current[index] = el;
472
+ },
473
+ type: "button",
474
+ className: chipClasses,
475
+ onClick: () => handleSelect(option),
476
+ onKeyDown: (e) => handleKeyDown(e, index),
477
+ "aria-selected": selected === option,
478
+ role: "option",
479
+ tabIndex: index === focusedIndex ? 0 : -1,
480
+ children: option
481
+ },
482
+ option
483
+ );
484
+ }),
485
+ !autoAdvance && selected !== null && /* @__PURE__ */ jsx(
486
+ "button",
487
+ {
488
+ type: "button",
489
+ className: "ns-enter-btn",
490
+ onClick: handleConfirm,
491
+ "aria-label": "Confirm",
492
+ style: { opacity: 1, transform: "none" },
493
+ children: "\u21B5"
494
+ }
495
+ )
496
+ ] });
497
+ };
498
+ var MultiChipsField = function MultiChipsField2({
499
+ fieldKey,
500
+ options,
501
+ defaultValue,
502
+ onConfirm,
503
+ onChange,
504
+ className
505
+ }) {
506
+ const [selected, setSelected] = useState(
507
+ new Set(defaultValue != null ? defaultValue : [])
508
+ );
509
+ const [hoveredIndex, setHoveredIndex] = useState(null);
510
+ const handleToggle = useCallback(
511
+ (option) => {
512
+ setSelected((prev) => {
513
+ const next = new Set(prev);
514
+ if (next.has(option)) {
515
+ next.delete(option);
516
+ } else {
517
+ next.add(option);
518
+ }
519
+ const value = Array.from(next).join(", ");
520
+ onChange == null ? void 0 : onChange(value);
521
+ return next;
522
+ });
523
+ },
524
+ [onChange]
525
+ );
526
+ const handleConfirm = useCallback(() => {
527
+ if (selected.size > 0) {
528
+ onConfirm(Array.from(selected).join(", "));
529
+ }
530
+ }, [selected, onConfirm]);
531
+ const handleKeyDown = useCallback(
532
+ (e, option) => {
533
+ if (e.key === "Enter" && selected.size > 0) {
534
+ e.preventDefault();
535
+ handleConfirm();
536
+ } else if (e.key === " ") {
537
+ e.preventDefault();
538
+ handleToggle(option);
539
+ }
540
+ },
541
+ [handleToggle, handleConfirm, selected.size]
542
+ );
543
+ const wrapClasses = ["ns-chips-wrap", className].filter(Boolean).join(" ");
544
+ return /* @__PURE__ */ jsxs("span", { className: wrapClasses, children: [
545
+ options.map((option, index) => {
546
+ const isSelected = selected.has(option);
547
+ const chipClasses = [
548
+ "ns-chip",
549
+ isSelected ? "ns-chip--active" : void 0,
550
+ hoveredIndex === index ? "ns-chip--hover" : void 0
551
+ ].filter(Boolean).join(" ");
552
+ return /* @__PURE__ */ jsx(
553
+ "button",
554
+ {
555
+ type: "button",
556
+ className: chipClasses,
557
+ onClick: () => handleToggle(option),
558
+ onKeyDown: (e) => handleKeyDown(e, option),
559
+ onMouseEnter: () => setHoveredIndex(index),
560
+ onMouseLeave: () => setHoveredIndex(null),
561
+ "aria-pressed": isSelected,
562
+ role: "option",
563
+ children: option
564
+ },
565
+ option
566
+ );
567
+ }),
568
+ selected.size > 0 && /* @__PURE__ */ jsx(
569
+ "button",
570
+ {
571
+ type: "button",
572
+ className: "ns-enter-btn",
573
+ onClick: handleConfirm,
574
+ "aria-label": "Confirm",
575
+ children: "\u21B5"
576
+ }
577
+ )
578
+ ] });
579
+ };
580
+ var SelectField = function SelectField2({
581
+ fieldKey,
582
+ options,
583
+ placeholder = "Select\u2026",
584
+ defaultValue = "",
585
+ autoAdvance = false,
586
+ onConfirm,
587
+ onChange,
588
+ onFocus,
589
+ onBlur,
590
+ inputClassName,
591
+ className
592
+ }) {
593
+ const [value, setValue] = useState(defaultValue);
594
+ const selectRef = useRef(null);
595
+ useEffect(() => {
596
+ var _a;
597
+ (_a = selectRef.current) == null ? void 0 : _a.focus();
598
+ }, []);
599
+ const handleChange = useCallback(
600
+ (e) => {
601
+ const newValue = e.target.value;
602
+ setValue(newValue);
603
+ onChange == null ? void 0 : onChange(newValue);
604
+ if (autoAdvance && newValue !== "") {
605
+ onConfirm(newValue);
606
+ }
607
+ },
608
+ [autoAdvance, onConfirm, onChange]
609
+ );
610
+ const handleKeyDown = useCallback(
611
+ (e) => {
612
+ if (e.key === "Enter" && value !== "") {
613
+ e.preventDefault();
614
+ onConfirm(value);
615
+ }
616
+ },
617
+ [value, onConfirm]
618
+ );
619
+ const handleConfirmClick = useCallback(() => {
620
+ if (value !== "") {
621
+ onConfirm(value);
622
+ }
623
+ }, [value, onConfirm]);
624
+ const wrapClasses = ["ns-select-wrap", className].filter(Boolean).join(" ");
625
+ const selectClasses = ["ns-select", inputClassName].filter(Boolean).join(" ");
626
+ return /* @__PURE__ */ jsxs("span", { className: wrapClasses, children: [
627
+ /* @__PURE__ */ jsxs(
628
+ "select",
629
+ {
630
+ ref: selectRef,
631
+ id: `ns-field-${fieldKey}`,
632
+ className: selectClasses,
633
+ value,
634
+ onChange: handleChange,
635
+ onKeyDown: handleKeyDown,
636
+ onFocus: () => onFocus == null ? void 0 : onFocus(),
637
+ onBlur: () => onBlur == null ? void 0 : onBlur(value),
638
+ "aria-label": fieldKey,
639
+ children: [
640
+ /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
641
+ options.map((option) => /* @__PURE__ */ jsx("option", { value: option, children: option }, option))
642
+ ]
643
+ }
644
+ ),
645
+ !autoAdvance && value !== "" && /* @__PURE__ */ jsx(
646
+ "button",
647
+ {
648
+ type: "button",
649
+ className: "ns-enter-btn",
650
+ onClick: handleConfirmClick,
651
+ "aria-label": "Confirm",
652
+ children: "\u21B5"
653
+ }
654
+ )
655
+ ] });
656
+ };
657
+ var OtpField = function OtpField2({
658
+ fieldKey,
659
+ otpLength = 6,
660
+ autoAdvance = true,
661
+ onRequest,
662
+ onVerify,
663
+ onConfirm,
664
+ onChange,
665
+ resendLabel = "Resend code",
666
+ resendDelay = 30,
667
+ className
668
+ }) {
669
+ const [digits, setDigits] = useState(Array.from({ length: otpLength }, () => ""));
670
+ const [activeIndex, setActiveIndex] = useState(0);
671
+ const [timer, setTimer] = useState(resendDelay);
672
+ const [canResend, setCanResend] = useState(false);
673
+ const inputRefs = useRef([]);
674
+ const timerRef = useRef(null);
675
+ const hasRequestedRef = useRef(false);
676
+ useEffect(() => {
677
+ if (!hasRequestedRef.current) {
678
+ hasRequestedRef.current = true;
679
+ onRequest == null ? void 0 : onRequest();
680
+ }
681
+ }, [onRequest]);
682
+ useEffect(() => {
683
+ if (resendDelay <= 0) {
684
+ setCanResend(true);
685
+ return;
686
+ }
687
+ setTimer(resendDelay);
688
+ setCanResend(false);
689
+ timerRef.current = setInterval(() => {
690
+ setTimer((prev) => {
691
+ if (prev <= 1) {
692
+ if (timerRef.current !== null) {
693
+ clearInterval(timerRef.current);
694
+ timerRef.current = null;
695
+ }
696
+ setCanResend(true);
697
+ return 0;
698
+ }
699
+ return prev - 1;
700
+ });
701
+ }, 1e3);
702
+ return () => {
703
+ if (timerRef.current !== null) {
704
+ clearInterval(timerRef.current);
705
+ timerRef.current = null;
706
+ }
707
+ };
708
+ }, [resendDelay]);
709
+ useEffect(() => {
710
+ var _a;
711
+ (_a = inputRefs.current[0]) == null ? void 0 : _a.focus();
712
+ }, []);
713
+ const getOtpString = useCallback(
714
+ (d) => d.join(""),
715
+ []
716
+ );
717
+ const handleDigitChange = useCallback(
718
+ (index, value) => {
719
+ const digit = value.replace(/\D/g, "").slice(-1);
720
+ setDigits((prev) => {
721
+ var _a;
722
+ const next = [...prev];
723
+ next[index] = digit;
724
+ const otpString = getOtpString(next);
725
+ onChange == null ? void 0 : onChange(otpString);
726
+ if (digit !== "" && index < otpLength - 1) {
727
+ (_a = inputRefs.current[index + 1]) == null ? void 0 : _a.focus();
728
+ setActiveIndex(index + 1);
729
+ }
730
+ if (next.every((d) => d !== "")) {
731
+ onVerify == null ? void 0 : onVerify(otpString);
732
+ if (autoAdvance) {
733
+ setTimeout(() => onConfirm(otpString), 0);
734
+ }
735
+ }
736
+ return next;
737
+ });
738
+ },
739
+ [otpLength, autoAdvance, onConfirm, onVerify, onChange, getOtpString]
740
+ );
741
+ const handleKeyDown = useCallback(
742
+ (index, e) => {
743
+ var _a, _b;
744
+ if (e.key === "Backspace") {
745
+ e.preventDefault();
746
+ setDigits((prev) => {
747
+ var _a2;
748
+ const next = [...prev];
749
+ if (next[index] !== "") {
750
+ next[index] = "";
751
+ onChange == null ? void 0 : onChange(getOtpString(next));
752
+ } else if (index > 0) {
753
+ next[index - 1] = "";
754
+ (_a2 = inputRefs.current[index - 1]) == null ? void 0 : _a2.focus();
755
+ setActiveIndex(index - 1);
756
+ onChange == null ? void 0 : onChange(getOtpString(next));
757
+ }
758
+ return next;
759
+ });
760
+ } else if (e.key === "Enter") {
761
+ e.preventDefault();
762
+ const otpString = getOtpString(digits);
763
+ if (digits.every((d) => d !== "")) {
764
+ onConfirm(otpString);
765
+ }
766
+ } else if (e.key === "ArrowLeft" && index > 0) {
767
+ e.preventDefault();
768
+ (_a = inputRefs.current[index - 1]) == null ? void 0 : _a.focus();
769
+ setActiveIndex(index - 1);
770
+ } else if (e.key === "ArrowRight" && index < otpLength - 1) {
771
+ e.preventDefault();
772
+ (_b = inputRefs.current[index + 1]) == null ? void 0 : _b.focus();
773
+ setActiveIndex(index + 1);
774
+ }
775
+ },
776
+ [digits, otpLength, onConfirm, onChange, getOtpString]
777
+ );
778
+ const handlePaste = useCallback(
779
+ (e) => {
780
+ e.preventDefault();
781
+ const pastedData = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, otpLength);
782
+ if (pastedData.length === 0) return;
783
+ setDigits((prev) => {
784
+ var _a;
785
+ const next = [...prev];
786
+ for (let i = 0; i < pastedData.length; i++) {
787
+ const char = pastedData[i];
788
+ if (char !== void 0) {
789
+ next[i] = char;
790
+ }
791
+ }
792
+ const otpString = getOtpString(next);
793
+ onChange == null ? void 0 : onChange(otpString);
794
+ const nextEmptyIndex = next.findIndex((d) => d === "");
795
+ const focusIndex = nextEmptyIndex === -1 ? otpLength - 1 : nextEmptyIndex;
796
+ (_a = inputRefs.current[focusIndex]) == null ? void 0 : _a.focus();
797
+ setActiveIndex(focusIndex);
798
+ if (next.every((d) => d !== "")) {
799
+ onVerify == null ? void 0 : onVerify(otpString);
800
+ if (autoAdvance) {
801
+ setTimeout(() => onConfirm(otpString), 0);
802
+ }
803
+ }
804
+ return next;
805
+ });
806
+ },
807
+ [otpLength, autoAdvance, onConfirm, onVerify, onChange, getOtpString]
808
+ );
809
+ const handleResend = useCallback(() => {
810
+ var _a;
811
+ if (!canResend) return;
812
+ setCanResend(false);
813
+ setTimer(resendDelay);
814
+ setDigits(Array.from({ length: otpLength }, () => ""));
815
+ setActiveIndex(0);
816
+ (_a = inputRefs.current[0]) == null ? void 0 : _a.focus();
817
+ onRequest == null ? void 0 : onRequest();
818
+ timerRef.current = setInterval(() => {
819
+ setTimer((prev) => {
820
+ if (prev <= 1) {
821
+ if (timerRef.current !== null) {
822
+ clearInterval(timerRef.current);
823
+ timerRef.current = null;
824
+ }
825
+ setCanResend(true);
826
+ return 0;
827
+ }
828
+ return prev - 1;
829
+ });
830
+ }, 1e3);
831
+ }, [canResend, resendDelay, otpLength, onRequest]);
832
+ const handleFocus = useCallback((index) => {
833
+ setActiveIndex(index);
834
+ }, []);
835
+ const wrapClasses = ["ns-otp-wrap", className].filter(Boolean).join(" ");
836
+ return /* @__PURE__ */ jsxs("span", { className: wrapClasses, children: [
837
+ /* @__PURE__ */ jsx("span", { className: "ns-otp-boxes", children: digits.map((digit, index) => {
838
+ const boxClasses = [
839
+ "ns-otp-box",
840
+ digit !== "" ? "ns-otp-box--filled" : void 0,
841
+ activeIndex === index ? "ns-otp-box--active" : void 0
842
+ ].filter(Boolean).join(" ");
843
+ return /* @__PURE__ */ jsx(
844
+ "input",
845
+ {
846
+ ref: (el) => {
847
+ inputRefs.current[index] = el;
848
+ },
849
+ className: boxClasses,
850
+ type: "text",
851
+ inputMode: "numeric",
852
+ maxLength: 1,
853
+ value: digit,
854
+ onChange: (e) => handleDigitChange(index, e.target.value),
855
+ onKeyDown: (e) => handleKeyDown(index, e),
856
+ onPaste: handlePaste,
857
+ onFocus: () => handleFocus(index),
858
+ autoComplete: "one-time-code",
859
+ "aria-label": `Digit ${String(index + 1)}`
860
+ },
861
+ index
862
+ );
863
+ }) }),
864
+ !autoAdvance && digits.every((d) => d !== "") && /* @__PURE__ */ jsx(
865
+ "button",
866
+ {
867
+ type: "button",
868
+ className: "ns-enter-btn",
869
+ onClick: () => onConfirm(getOtpString(digits)),
870
+ "aria-label": "Confirm",
871
+ children: "\u21B5"
872
+ }
873
+ ),
874
+ /* @__PURE__ */ jsx("span", { className: "ns-otp-resend-wrap", children: canResend ? /* @__PURE__ */ jsx(
875
+ "button",
876
+ {
877
+ type: "button",
878
+ className: "ns-otp-resend",
879
+ onClick: handleResend,
880
+ children: resendLabel
881
+ }
882
+ ) : /* @__PURE__ */ jsx("span", { className: "ns-otp-resend ns-otp-resend--disabled", children: /* @__PURE__ */ jsxs("span", { className: "ns-otp-timer", children: [
883
+ "Resend in ",
884
+ String(timer),
885
+ "s"
886
+ ] }) }) })
887
+ ] });
888
+ };
889
+ var PasswordField = function PasswordField2({
890
+ showToggle = true,
891
+ inputClassName,
892
+ ...props
893
+ }) {
894
+ const [visible, setVisible] = useState(false);
895
+ const toggleVisibility = () => {
896
+ setVisible((prev) => !prev);
897
+ };
898
+ const combinedClassName = [
899
+ inputClassName,
900
+ "ns-input--password"
901
+ ].filter(Boolean).join(" ");
902
+ return /* @__PURE__ */ jsxs("span", { className: "ns-password-wrap", children: [
903
+ /* @__PURE__ */ jsx(
904
+ InlineInput,
905
+ {
906
+ ...props,
907
+ type: visible ? "text" : "password",
908
+ inputClassName: combinedClassName
909
+ }
910
+ ),
911
+ showToggle && /* @__PURE__ */ jsx(
912
+ "button",
913
+ {
914
+ type: "button",
915
+ className: "ns-password-toggle",
916
+ onClick: toggleVisibility,
917
+ "aria-label": visible ? "Hide password" : "Show password",
918
+ tabIndex: -1,
919
+ children: visible ? "Hide" : "Show"
920
+ }
921
+ )
922
+ ] });
923
+ };
924
+ var DateField = function DateField2({
925
+ fieldKey,
926
+ placeholder,
927
+ defaultValue,
928
+ suffix,
929
+ onConfirm,
930
+ onChange,
931
+ onFocus,
932
+ onBlur,
933
+ inputClassName,
934
+ className
935
+ }) {
936
+ return /* @__PURE__ */ jsx(
937
+ InlineInput,
938
+ {
939
+ fieldKey,
940
+ type: "date",
941
+ placeholder,
942
+ defaultValue,
943
+ suffix,
944
+ onConfirm,
945
+ onChange,
946
+ onFocus,
947
+ onBlur,
948
+ inputClassName,
949
+ className
950
+ }
951
+ );
952
+ };
953
+ var ToastContext = createContext(null);
954
+ var useToast = () => {
955
+ const context = useContext(ToastContext);
956
+ if (!context) {
957
+ throw new Error("useToast must be used within a ToastProvider");
958
+ }
959
+ return context;
960
+ };
961
+ var ToastProvider = ({ children }) => {
962
+ const [toasts, setToasts] = useState([]);
963
+ const showToast = useCallback((message, icon = false, iconChar = "\u26A0") => {
964
+ const id = Math.random().toString(36).substring(2, 9);
965
+ setToasts((prev) => [...prev, { id, message, icon, iconChar }]);
966
+ setTimeout(() => {
967
+ setToasts((prev) => prev.filter((t) => t.id !== id));
968
+ }, 3e3);
969
+ }, []);
970
+ const hideToast = useCallback((id) => {
971
+ setToasts((prev) => prev.filter((t) => t.id !== id));
972
+ }, []);
973
+ return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: { showToast, hideToast }, children: [
974
+ children,
975
+ toasts.length > 0 && /* @__PURE__ */ jsx("div", { className: "ns-toast-container", "aria-live": "polite", children: toasts.map((toast) => /* @__PURE__ */ jsxs("div", { className: "ns-toast ns-animate-fade-up", children: [
976
+ toast.icon && /* @__PURE__ */ jsxs("span", { className: "ns-toast-icon", children: [
977
+ toast.iconChar,
978
+ " "
979
+ ] }),
980
+ /* @__PURE__ */ jsx("span", { className: "ns-toast-message", children: toast.message }),
981
+ /* @__PURE__ */ jsx(
982
+ "button",
983
+ {
984
+ type: "button",
985
+ className: "ns-toast-close",
986
+ onClick: () => hideToast(toast.id),
987
+ "aria-label": "Close",
988
+ children: "\xD7"
989
+ }
990
+ )
991
+ ] }, toast.id)) })
992
+ ] });
993
+ };
994
+ function renderFieldInput({
995
+ field,
996
+ status,
997
+ value,
998
+ handleConfirm,
999
+ handleChange,
1000
+ handleFocus,
1001
+ handleBlur
1002
+ }) {
1003
+ var _a, _b, _c, _d;
1004
+ const editValue = status === "editing" && value !== void 0 ? String(value) : field.defaultValue;
1005
+ switch (field.type) {
1006
+ case "chips":
1007
+ return /* @__PURE__ */ jsx(
1008
+ ChipsField,
1009
+ {
1010
+ fieldKey: field.key,
1011
+ options: (_a = field.options) != null ? _a : [],
1012
+ defaultValue: editValue,
1013
+ autoAdvance: field.autoAdvance,
1014
+ onConfirm: handleConfirm,
1015
+ onChange: handleChange,
1016
+ className: field.inputClassName
1017
+ }
1018
+ );
1019
+ case "multi-chips":
1020
+ return /* @__PURE__ */ jsx(
1021
+ MultiChipsField,
1022
+ {
1023
+ fieldKey: field.key,
1024
+ options: (_b = field.options) != null ? _b : [],
1025
+ defaultValue: status === "editing" && Array.isArray(value) ? value : editValue == null ? void 0 : editValue.split(", ").filter(Boolean),
1026
+ onConfirm: handleConfirm,
1027
+ onChange: handleChange,
1028
+ className: field.inputClassName
1029
+ }
1030
+ );
1031
+ case "select":
1032
+ return /* @__PURE__ */ jsx(
1033
+ SelectField,
1034
+ {
1035
+ fieldKey: field.key,
1036
+ options: (_c = field.options) != null ? _c : [],
1037
+ placeholder: field.placeholder,
1038
+ defaultValue: editValue,
1039
+ autoAdvance: field.autoAdvance,
1040
+ onConfirm: handleConfirm,
1041
+ onChange: handleChange,
1042
+ onFocus: handleFocus,
1043
+ onBlur: handleBlur,
1044
+ inputClassName: field.inputClassName
1045
+ }
1046
+ );
1047
+ case "otp":
1048
+ return /* @__PURE__ */ jsx(
1049
+ OtpField,
1050
+ {
1051
+ fieldKey: field.key,
1052
+ otpLength: field.otpLength,
1053
+ autoAdvance: (_d = field.autoAdvance) != null ? _d : true,
1054
+ onRequest: field.onRequest,
1055
+ onVerify: field.onVerify,
1056
+ onConfirm: handleConfirm,
1057
+ onChange: handleChange,
1058
+ resendLabel: field.resendLabel,
1059
+ resendDelay: field.resendDelay,
1060
+ className: field.inputClassName
1061
+ }
1062
+ );
1063
+ case "password":
1064
+ return /* @__PURE__ */ jsx(
1065
+ PasswordField,
1066
+ {
1067
+ fieldKey: field.key,
1068
+ placeholder: field.placeholder,
1069
+ defaultValue: editValue,
1070
+ suffix: field.suffix,
1071
+ onConfirm: handleConfirm,
1072
+ onChange: handleChange,
1073
+ onFocus: handleFocus,
1074
+ onBlur: handleBlur,
1075
+ inputClassName: field.inputClassName
1076
+ }
1077
+ );
1078
+ case "date":
1079
+ return /* @__PURE__ */ jsx(
1080
+ DateField,
1081
+ {
1082
+ fieldKey: field.key,
1083
+ placeholder: field.placeholder,
1084
+ defaultValue: editValue,
1085
+ suffix: field.suffix,
1086
+ onConfirm: handleConfirm,
1087
+ onChange: handleChange,
1088
+ onFocus: handleFocus,
1089
+ onBlur: handleBlur,
1090
+ inputClassName: field.inputClassName
1091
+ }
1092
+ );
1093
+ // text, tel, email, number — all use InlineInput with the appropriate type
1094
+ default:
1095
+ return /* @__PURE__ */ jsx(
1096
+ InlineInput,
1097
+ {
1098
+ fieldKey: field.key,
1099
+ type: field.type,
1100
+ placeholder: field.placeholder,
1101
+ defaultValue: editValue,
1102
+ suffix: field.suffix,
1103
+ sanitise: field.sanitise,
1104
+ onConfirm: handleConfirm,
1105
+ onChange: handleChange,
1106
+ onFocus: handleFocus,
1107
+ onBlur: handleBlur,
1108
+ inputClassName: field.inputClassName
1109
+ }
1110
+ );
1111
+ }
1112
+ }
1113
+ var Line = React.memo(function Line2({
1114
+ field,
1115
+ status,
1116
+ value,
1117
+ allValues = {},
1118
+ typewriter,
1119
+ editable = true,
1120
+ locked = false,
1121
+ editLabel = "Edit",
1122
+ onTypingComplete,
1123
+ onConfirm,
1124
+ onEdit,
1125
+ onError,
1126
+ onChange,
1127
+ onFocus,
1128
+ onBlur
1129
+ }) {
1130
+ var _a, _b, _c, _d, _e;
1131
+ const [error, setError] = useState(null);
1132
+ const [shake, setShake] = useState(false);
1133
+ const [asyncState, setAsyncState] = useState("idle");
1134
+ const abortRef = useRef(null);
1135
+ const { showToast } = useToast();
1136
+ const isFieldEditable = field.editable !== false && editable && !locked;
1137
+ const shouldAnimate = field.animate !== false && (typewriter == null ? void 0 : typewriter.enabled) !== false;
1138
+ const handleTypingComplete = useCallback(() => {
1139
+ onTypingComplete(field.key);
1140
+ }, [field.key, onTypingComplete]);
1141
+ const handleConfirm = useCallback(
1142
+ (val) => {
1143
+ var _a2, _b2, _c2, _d2;
1144
+ (_a2 = abortRef.current) == null ? void 0 : _a2.call(abortRef);
1145
+ abortRef.current = null;
1146
+ const result = validateField(val, field.validation, allValues);
1147
+ if (!result.valid) {
1148
+ const firstError = (_b2 = result.errors[0]) != null ? _b2 : "Validation failed";
1149
+ setError(firstError);
1150
+ setAsyncState("idle");
1151
+ onError == null ? void 0 : onError(field.key, firstError);
1152
+ const display = (_c2 = field.validation) == null ? void 0 : _c2.errorDisplay;
1153
+ const mode = (_d2 = display == null ? void 0 : display.mode) != null ? _d2 : "inline";
1154
+ if (mode === "shake" || mode === "inline+shake") {
1155
+ setShake(false);
1156
+ setTimeout(() => setShake(true), 10);
1157
+ }
1158
+ if (mode === "toast") {
1159
+ showToast(firstError, display == null ? void 0 : display.icon, display == null ? void 0 : display.iconChar);
1160
+ }
1161
+ return;
1162
+ }
1163
+ if (hasAsyncValidation(field.validation)) {
1164
+ setAsyncState("validating");
1165
+ setError(null);
1166
+ const handle = validateFieldAsync(val, field.validation, allValues);
1167
+ abortRef.current = handle.abort;
1168
+ handle.promise.then((asyncResult) => {
1169
+ var _a3;
1170
+ if (!asyncResult.valid) {
1171
+ const firstError = (_a3 = asyncResult.errors[0]) != null ? _a3 : "Validation failed";
1172
+ setError(firstError);
1173
+ setAsyncState("invalid");
1174
+ onError == null ? void 0 : onError(field.key, firstError);
1175
+ } else {
1176
+ setAsyncState("valid");
1177
+ setError(null);
1178
+ setTimeout(() => {
1179
+ setAsyncState("idle");
1180
+ onConfirm(field.key, val);
1181
+ }, 300);
1182
+ }
1183
+ }).catch(() => {
1184
+ setAsyncState("idle");
1185
+ });
1186
+ return;
1187
+ }
1188
+ setError(null);
1189
+ setShake(false);
1190
+ setAsyncState("idle");
1191
+ onConfirm(field.key, val);
1192
+ },
1193
+ [field.key, field.validation, allValues, onConfirm, onError, showToast]
1194
+ );
1195
+ const handleEdit = useCallback(() => {
1196
+ var _a2;
1197
+ setError(null);
1198
+ setShake(false);
1199
+ setAsyncState("idle");
1200
+ (_a2 = abortRef.current) == null ? void 0 : _a2.call(abortRef);
1201
+ onEdit(field.key);
1202
+ }, [field.key, onEdit]);
1203
+ const handleChange = useCallback(
1204
+ (val) => {
1205
+ var _a2, _b2, _c2;
1206
+ const clearOn = (_c2 = (_b2 = (_a2 = field.validation) == null ? void 0 : _a2.errorDisplay) == null ? void 0 : _b2.clearOn) != null ? _c2 : "onChange";
1207
+ if (clearOn === "onChange" && error !== null) {
1208
+ setError(null);
1209
+ setShake(false);
1210
+ setAsyncState("idle");
1211
+ }
1212
+ onChange == null ? void 0 : onChange(field.key, val);
1213
+ },
1214
+ [field.key, onChange, error, (_b = (_a = field.validation) == null ? void 0 : _a.errorDisplay) == null ? void 0 : _b.clearOn]
1215
+ );
1216
+ const handleFocus = useCallback(() => {
1217
+ var _a2, _b2, _c2;
1218
+ const clearOn = (_c2 = (_b2 = (_a2 = field.validation) == null ? void 0 : _a2.errorDisplay) == null ? void 0 : _b2.clearOn) != null ? _c2 : "onChange";
1219
+ if (clearOn === "onFocus" && error !== null) {
1220
+ setError(null);
1221
+ setShake(false);
1222
+ setAsyncState("idle");
1223
+ }
1224
+ onFocus == null ? void 0 : onFocus(field.key);
1225
+ }, [field.key, onFocus, error, (_d = (_c = field.validation) == null ? void 0 : _c.errorDisplay) == null ? void 0 : _d.clearOn]);
1226
+ const handleBlur = useCallback(
1227
+ (val) => {
1228
+ onBlur == null ? void 0 : onBlur(field.key, val);
1229
+ },
1230
+ [field.key, onBlur]
1231
+ );
1232
+ const lineClasses = [
1233
+ "ns-line",
1234
+ `ns-line-${field.key}`,
1235
+ status === "active" || status === "editing" ? "ns-line--active" : void 0,
1236
+ status === "confirmed" ? "ns-line--confirmed" : void 0,
1237
+ status === "editing" ? "ns-line--editing" : void 0,
1238
+ error !== null ? "ns-line--error" : void 0,
1239
+ shake ? "ns-line--shake" : void 0,
1240
+ field.className
1241
+ ].filter(Boolean).join(" ");
1242
+ const showInput = status === "active" || status === "editing";
1243
+ const showFilled = status === "confirmed";
1244
+ return /* @__PURE__ */ jsxs("div", { className: lineClasses, role: "group", "aria-label": field.prefix, children: [
1245
+ /* @__PURE__ */ jsx(
1246
+ Prose,
1247
+ {
1248
+ text: field.prefix,
1249
+ animate: status === "typing" && shouldAnimate,
1250
+ speed: typewriter == null ? void 0 : typewriter.speed,
1251
+ cursor: typewriter == null ? void 0 : typewriter.cursor,
1252
+ cursorChar: typewriter == null ? void 0 : typewriter.cursorChar,
1253
+ pauseAfter: typewriter == null ? void 0 : typewriter.pauseAfter,
1254
+ onComplete: status === "typing" ? handleTypingComplete : void 0
1255
+ }
1256
+ ),
1257
+ showInput && renderFieldInput({
1258
+ field,
1259
+ status,
1260
+ value,
1261
+ handleConfirm,
1262
+ handleChange,
1263
+ handleFocus,
1264
+ handleBlur
1265
+ }),
1266
+ showInput && asyncState === "validating" && /* @__PURE__ */ jsx("span", { className: "ns-loading-indicator", "aria-label": "Validating" }),
1267
+ showInput && asyncState === "valid" && /* @__PURE__ */ jsx("span", { className: "ns-success-indicator", "aria-label": "Valid", children: "\u2713" }),
1268
+ showFilled && /* @__PURE__ */ jsx(
1269
+ FilledValue,
1270
+ {
1271
+ value: String(value != null ? value : ""),
1272
+ suffix: field.suffix,
1273
+ editable: isFieldEditable,
1274
+ onEdit: handleEdit,
1275
+ editLabel
1276
+ }
1277
+ ),
1278
+ error !== null && showInput && /* @__PURE__ */ jsx(
1279
+ ErrorMessage,
1280
+ {
1281
+ message: error,
1282
+ display: (_e = field.validation) == null ? void 0 : _e.errorDisplay
1283
+ }
1284
+ )
1285
+ ] });
1286
+ });
1287
+ var ThemeContext = createContext({
1288
+ theme: {},
1289
+ isDark: false
1290
+ });
1291
+ function useTheme() {
1292
+ return useContext(ThemeContext);
1293
+ }
1294
+ var TOKEN_TO_CSS_VAR = {
1295
+ background: "--ns-bg",
1296
+ textColor: "--ns-text",
1297
+ inputBorderColor: "--ns-border",
1298
+ placeholderColor: "--ns-placeholder-color",
1299
+ errorColor: "--ns-error",
1300
+ filledColor: "--ns-filled-color",
1301
+ cursorColor: "--ns-cursor-color",
1302
+ successColor: "--ns-success-color",
1303
+ loadingColor: "--ns-loading-color",
1304
+ fontFamily: "--ns-font-family",
1305
+ uiFontFamily: "--ns-ui-font",
1306
+ fontSize: "--ns-font-size",
1307
+ mobileFontSize: "--ns-mobile-font-size",
1308
+ inputFontStyle: "--ns-input-font-style",
1309
+ lineGap: "--ns-line-gap",
1310
+ pagePadding: "--ns-page-padding",
1311
+ buttonRadius: "--ns-btn-radius",
1312
+ buttonBackground: "--ns-btn-bg",
1313
+ buttonColor: "--ns-btn-color",
1314
+ enterBtnSize: "--ns-enter-size",
1315
+ chipBorderRadius: "--ns-chip-radius",
1316
+ chipBorderColor: "--ns-chip-border",
1317
+ chipActiveBackground: "--ns-chip-active-bg",
1318
+ chipActiveColor: "--ns-chip-active-color",
1319
+ chipFontStyle: "--ns-chip-font-style"
1320
+ };
1321
+ function themeToCssVars(theme) {
1322
+ const style = {};
1323
+ for (const [tokenName, cssVar] of Object.entries(TOKEN_TO_CSS_VAR)) {
1324
+ const value = theme[tokenName];
1325
+ if (typeof value === "string" && value.length > 0) {
1326
+ style[cssVar] = value;
1327
+ }
1328
+ }
1329
+ return style;
1330
+ }
1331
+ function usePrefersDark() {
1332
+ const [prefersDark, setPrefersDark] = useState(() => {
1333
+ if (typeof window === "undefined") return false;
1334
+ return window.matchMedia("(prefers-color-scheme: dark)").matches;
1335
+ });
1336
+ useEffect(() => {
1337
+ if (typeof window === "undefined") return;
1338
+ const mql = window.matchMedia("(prefers-color-scheme: dark)");
1339
+ const handler = (e) => {
1340
+ setPrefersDark(e.matches);
1341
+ };
1342
+ mql.addEventListener("change", handler);
1343
+ return () => mql.removeEventListener("change", handler);
1344
+ }, []);
1345
+ return prefersDark;
1346
+ }
1347
+ var ThemeProvider = function ThemeProvider2({
1348
+ theme = {},
1349
+ children
1350
+ }) {
1351
+ const systemPrefersDark = usePrefersDark();
1352
+ const isDark = useMemo(() => {
1353
+ if (theme.mode === "dark") return true;
1354
+ if (theme.mode === "auto") return systemPrefersDark;
1355
+ return false;
1356
+ }, [theme.mode, systemPrefersDark]);
1357
+ const resolvedTheme = useMemo(() => {
1358
+ if (isDark && theme.dark) {
1359
+ return { ...theme, ...theme.dark };
1360
+ }
1361
+ return theme;
1362
+ }, [theme, isDark]);
1363
+ const cssVars = useMemo(() => themeToCssVars(resolvedTheme), [resolvedTheme]);
1364
+ const contextValue = useMemo(
1365
+ () => ({ theme: resolvedTheme, isDark }),
1366
+ [resolvedTheme, isDark]
1367
+ );
1368
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { style: cssVars, className: isDark ? "ns-root--dark" : void 0, children }) });
1369
+ };
1370
+ var WelcomeScreen = React.memo(
1371
+ function WelcomeScreen2({ welcome, typewriter, onStart, className }) {
1372
+ var _a, _b;
1373
+ const heading = (_a = welcome.heading) != null ? _a : "Welcome";
1374
+ const subtext = welcome.subtext;
1375
+ const ctaLabel = (_b = welcome.ctaLabel) != null ? _b : "Let\u2019s go \u2192";
1376
+ const shouldAnimate = (typewriter == null ? void 0 : typewriter.enabled) !== false;
1377
+ const handleClick = useCallback(() => {
1378
+ onStart();
1379
+ }, [onStart]);
1380
+ const wrapperClasses = ["ns-welcome", className].filter(Boolean).join(" ");
1381
+ return /* @__PURE__ */ jsxs("div", { className: wrapperClasses, children: [
1382
+ /* @__PURE__ */ jsx("h1", { className: "ns-welcome-heading", children: /* @__PURE__ */ jsx(
1383
+ Prose,
1384
+ {
1385
+ text: heading,
1386
+ animate: shouldAnimate,
1387
+ speed: typewriter == null ? void 0 : typewriter.speed,
1388
+ cursor: typewriter == null ? void 0 : typewriter.cursor,
1389
+ cursorChar: typewriter == null ? void 0 : typewriter.cursorChar
1390
+ }
1391
+ ) }),
1392
+ subtext && /* @__PURE__ */ jsx("p", { className: "ns-welcome-subtext", children: subtext }),
1393
+ /* @__PURE__ */ jsx(
1394
+ "button",
1395
+ {
1396
+ type: "button",
1397
+ className: "ns-welcome-cta",
1398
+ onClick: handleClick,
1399
+ children: ctaLabel
1400
+ }
1401
+ )
1402
+ ] });
1403
+ }
1404
+ );
1405
+ function interpolateMessage(template, values) {
1406
+ return template.replace(/\{(\w+)\}/g, (_match, key) => {
1407
+ const val = values[key];
1408
+ if (Array.isArray(val)) return val.join(", ");
1409
+ return typeof val === "string" ? val : `{${key}}`;
1410
+ });
1411
+ }
1412
+ var DoneScreen = React.memo(
1413
+ function DoneScreen2({ done, values, meta, typewriter, className }) {
1414
+ var _a;
1415
+ const [submitState, setSubmitState] = useState("default");
1416
+ const [errorMessage, setErrorMessage] = useState(null);
1417
+ const ctaLabel = (_a = done.ctaLabel) != null ? _a : "Continue \u2192";
1418
+ const shouldAnimate = (typewriter == null ? void 0 : typewriter.enabled) !== false;
1419
+ const resolvedMessage = (() => {
1420
+ if (typeof done.message === "function") {
1421
+ return done.message(values);
1422
+ }
1423
+ if (typeof done.message === "string") {
1424
+ return interpolateMessage(done.message, values);
1425
+ }
1426
+ return "You\u2019re all set!";
1427
+ })();
1428
+ const handleSubmit = useCallback(async () => {
1429
+ if (!done.onSubmit || submitState === "loading" || submitState === "success") {
1430
+ return;
1431
+ }
1432
+ setSubmitState("loading");
1433
+ setErrorMessage(null);
1434
+ try {
1435
+ await done.onSubmit(values, meta);
1436
+ setSubmitState("success");
1437
+ } catch (err) {
1438
+ const msg = err instanceof Error ? err.message : "Something went wrong. Please try again.";
1439
+ setErrorMessage(msg);
1440
+ setSubmitState("error");
1441
+ }
1442
+ }, [done, values, meta, submitState]);
1443
+ const wrapperClasses = ["ns-done", className].filter(Boolean).join(" ");
1444
+ const ctaClasses = [
1445
+ "ns-done-cta",
1446
+ submitState === "loading" ? "ns-done-cta--loading" : void 0,
1447
+ submitState === "success" ? "ns-done-cta--success" : void 0,
1448
+ submitState === "error" ? "ns-done-cta--error" : void 0
1449
+ ].filter(Boolean).join(" ");
1450
+ const buttonLabel = (() => {
1451
+ switch (submitState) {
1452
+ case "loading":
1453
+ return "Please wait\u2026";
1454
+ case "success":
1455
+ return "\u2713 Done";
1456
+ case "error":
1457
+ return "Try again";
1458
+ default:
1459
+ return ctaLabel;
1460
+ }
1461
+ })();
1462
+ return /* @__PURE__ */ jsxs("div", { className: wrapperClasses, children: [
1463
+ /* @__PURE__ */ jsx("div", { className: "ns-done-message", children: /* @__PURE__ */ jsx(
1464
+ Prose,
1465
+ {
1466
+ text: resolvedMessage,
1467
+ animate: shouldAnimate,
1468
+ speed: typewriter == null ? void 0 : typewriter.speed,
1469
+ cursor: typewriter == null ? void 0 : typewriter.cursor,
1470
+ cursorChar: typewriter == null ? void 0 : typewriter.cursorChar
1471
+ }
1472
+ ) }),
1473
+ done.onSubmit && /* @__PURE__ */ jsxs(
1474
+ "button",
1475
+ {
1476
+ type: "button",
1477
+ className: ctaClasses,
1478
+ onClick: handleSubmit,
1479
+ disabled: submitState === "loading" || submitState === "success",
1480
+ children: [
1481
+ submitState === "loading" && /* @__PURE__ */ jsx("span", { className: "ns-loading-indicator", "aria-hidden": "true" }),
1482
+ buttonLabel
1483
+ ]
1484
+ }
1485
+ ),
1486
+ errorMessage !== null && /* @__PURE__ */ jsx("p", { className: "ns-done-error", children: errorMessage })
1487
+ ] });
1488
+ }
1489
+ );
1490
+ var NarrativeFormInner = function NarrativeFormInner2({
1491
+ fields: staticFields,
1492
+ fieldsUrl,
1493
+ fieldsUrlHeaders,
1494
+ formConfig,
1495
+ typewriter,
1496
+ welcome: welcomeProp,
1497
+ done: doneProp,
1498
+ editable = true,
1499
+ editLabel,
1500
+ className,
1501
+ callbacks,
1502
+ formRef,
1503
+ defaultValues,
1504
+ values: controlledValues,
1505
+ strings: stringsProp,
1506
+ locale,
1507
+ direction: directionProp,
1508
+ crossFieldValidators,
1509
+ loadingComponent,
1510
+ errorComponent,
1511
+ onFetchError,
1512
+ retryLabel,
1513
+ reducedMotion
1514
+ }) {
1515
+ var _a;
1516
+ const { isDark } = useTheme();
1517
+ const i18n = useMemo(() => mergeStrings(stringsProp), [stringsProp]);
1518
+ const direction = useMemo(() => {
1519
+ var _a2;
1520
+ if (directionProp) return directionProp;
1521
+ if (locale) {
1522
+ const rtlLocales = ["ar", "he", "fa", "ur"];
1523
+ const lang = (_a2 = locale.split("-")[0]) == null ? void 0 : _a2.toLowerCase();
1524
+ if (lang && rtlLocales.includes(lang)) return "rtl";
1525
+ }
1526
+ return "ltr";
1527
+ }, [directionProp, locale]);
1528
+ const { config: dynamicConfig, loading: dynamicLoading, error: dynamicError, retry } = useDynamicForm({ fieldsUrl, fieldsUrlHeaders, onFetchError });
1529
+ const resolvedConfig = useMemo(() => {
1530
+ if (staticFields) return { fields: staticFields };
1531
+ if (formConfig) return formConfig;
1532
+ if (dynamicConfig) return dynamicConfig;
1533
+ return null;
1534
+ }, [staticFields, formConfig, dynamicConfig]);
1535
+ const fields = (_a = resolvedConfig == null ? void 0 : resolvedConfig.fields) != null ? _a : [];
1536
+ const welcome = welcomeProp != null ? welcomeProp : resolvedConfig && "welcome" in resolvedConfig ? resolvedConfig.welcome : void 0;
1537
+ const done = doneProp != null ? doneProp : resolvedConfig && "done" in resolvedConfig ? resolvedConfig.done : void 0;
1538
+ const effectiveTypewriter = useMemo(() => {
1539
+ var _a2;
1540
+ return {
1541
+ ...typewriter,
1542
+ enabled: reducedMotion ? false : (_a2 = typewriter == null ? void 0 : typewriter.enabled) != null ? _a2 : true
1543
+ };
1544
+ }, [typewriter, reducedMotion]);
1545
+ const {
1546
+ snapshot,
1547
+ startTyping,
1548
+ activateField,
1549
+ confirmField,
1550
+ editField,
1551
+ reconfirmField,
1552
+ next,
1553
+ focusField,
1554
+ reset,
1555
+ getValues,
1556
+ getMeta
1557
+ } = useFormState(fields);
1558
+ const showWelcome = (welcome == null ? void 0 : welcome.show) !== false && welcome !== void 0;
1559
+ const [welcomeDismissed, setWelcomeDismissed] = useState(!showWelcome);
1560
+ const [isSubmitting, setIsSubmitting] = useState(false);
1561
+ const hasStartedRef = useRef(false);
1562
+ const defaultsAppliedRef = useRef(false);
1563
+ useEffect(() => {
1564
+ if (defaultsAppliedRef.current || !defaultValues) return;
1565
+ defaultsAppliedRef.current = true;
1566
+ for (const field of fields) {
1567
+ const val = defaultValues[field.key];
1568
+ if (val !== void 0) {
1569
+ startTyping(field.key);
1570
+ activateField(field.key);
1571
+ confirmField(field.key, val);
1572
+ }
1573
+ }
1574
+ }, [defaultValues, fields, startTyping, activateField, confirmField]);
1575
+ useEffect(() => {
1576
+ if (!welcomeDismissed) return;
1577
+ if (hasStartedRef.current) return;
1578
+ if (fields.length === 0) return;
1579
+ hasStartedRef.current = true;
1580
+ const firstField = fields.find((f) => snapshot.statuses[f.key] !== "confirmed");
1581
+ if (firstField) {
1582
+ startTyping(firstField.key);
1583
+ }
1584
+ }, [welcomeDismissed, fields, startTyping, snapshot.statuses]);
1585
+ useEffect(() => {
1586
+ if (!formRef) return;
1587
+ const handle = {
1588
+ next,
1589
+ getValues,
1590
+ reset: () => {
1591
+ setWelcomeDismissed(!showWelcome);
1592
+ hasStartedRef.current = false;
1593
+ defaultsAppliedRef.current = false;
1594
+ reset();
1595
+ },
1596
+ focusField
1597
+ };
1598
+ if (typeof formRef === "function") {
1599
+ formRef(handle);
1600
+ } else if (formRef && "current" in formRef) {
1601
+ formRef.current = handle;
1602
+ }
1603
+ }, [formRef, next, getValues, reset, focusField, showWelcome]);
1604
+ const handleWelcomeStart = useCallback(() => {
1605
+ setWelcomeDismissed(true);
1606
+ }, []);
1607
+ const handleTypingComplete = useCallback(
1608
+ (key) => {
1609
+ activateField(key);
1610
+ },
1611
+ [activateField]
1612
+ );
1613
+ const handleConfirm = useCallback(
1614
+ (key, value) => {
1615
+ var _a2, _b;
1616
+ const status = snapshot.statuses[key];
1617
+ const finalValue = (controlledValues == null ? void 0 : controlledValues[key]) !== void 0 ? String(controlledValues[key]) : value;
1618
+ if (status === "editing") {
1619
+ reconfirmField(key, finalValue);
1620
+ } else {
1621
+ confirmField(key, finalValue);
1622
+ }
1623
+ (_a2 = callbacks == null ? void 0 : callbacks.onFieldComplete) == null ? void 0 : _a2.call(callbacks, key, finalValue, 0);
1624
+ const updatedValues = { ...snapshot.values, [key]: finalValue };
1625
+ const visibleFieldKeys = fields.filter((f) => {
1626
+ if (!f.showIf) return true;
1627
+ return f.showIf(updatedValues);
1628
+ }).map((f) => f.key);
1629
+ const allConfirmed = visibleFieldKeys.every(
1630
+ (k) => k === key || snapshot.statuses[k] === "confirmed"
1631
+ );
1632
+ if (allConfirmed) {
1633
+ const finalValues = {};
1634
+ for (const k of visibleFieldKeys) {
1635
+ const v = k === key ? finalValue : snapshot.values[k];
1636
+ if (v !== void 0) finalValues[k] = v;
1637
+ }
1638
+ (_b = callbacks == null ? void 0 : callbacks.onComplete) == null ? void 0 : _b.call(callbacks, finalValues, getMeta());
1639
+ } else {
1640
+ const currentIndex = fields.findIndex((f) => f.key === key);
1641
+ for (let i = currentIndex + 1; i < fields.length; i++) {
1642
+ const nextField = fields[i];
1643
+ if (!nextField) continue;
1644
+ if (snapshot.statuses[nextField.key] === "confirmed") continue;
1645
+ const nextUpdatedValues = { ...snapshot.values, [key]: finalValue };
1646
+ if (nextField.showIf && !nextField.showIf(nextUpdatedValues)) continue;
1647
+ startTyping(nextField.key);
1648
+ break;
1649
+ }
1650
+ }
1651
+ },
1652
+ [snapshot, fields, confirmField, reconfirmField, startTyping, callbacks, getMeta, controlledValues]
1653
+ );
1654
+ const handleEdit = useCallback(
1655
+ (key) => {
1656
+ var _a2;
1657
+ editField(key);
1658
+ (_a2 = callbacks == null ? void 0 : callbacks.onEdit) == null ? void 0 : _a2.call(callbacks, key);
1659
+ },
1660
+ [editField, callbacks]
1661
+ );
1662
+ const handleError = useCallback(
1663
+ (key, message) => {
1664
+ var _a2;
1665
+ (_a2 = callbacks == null ? void 0 : callbacks.onError) == null ? void 0 : _a2.call(callbacks, key, message);
1666
+ },
1667
+ [callbacks]
1668
+ );
1669
+ const handleChange = useCallback(
1670
+ (key, value) => {
1671
+ var _a2;
1672
+ (_a2 = callbacks == null ? void 0 : callbacks.onChange) == null ? void 0 : _a2.call(callbacks, key, value);
1673
+ },
1674
+ [callbacks]
1675
+ );
1676
+ const handleFocus = useCallback(
1677
+ (key) => {
1678
+ var _a2;
1679
+ (_a2 = callbacks == null ? void 0 : callbacks.onFieldFocus) == null ? void 0 : _a2.call(callbacks, key);
1680
+ },
1681
+ [callbacks]
1682
+ );
1683
+ const handleBlur = useCallback(
1684
+ (key, value) => {
1685
+ var _a2;
1686
+ (_a2 = callbacks == null ? void 0 : callbacks.onFieldBlur) == null ? void 0 : _a2.call(callbacks, key, value);
1687
+ },
1688
+ [callbacks]
1689
+ );
1690
+ useEffect(() => {
1691
+ const onDropOff = callbacks == null ? void 0 : callbacks.onDropOff;
1692
+ if (!onDropOff) return;
1693
+ if (typeof window === "undefined") return;
1694
+ const handleVisibility = () => {
1695
+ if (document.visibilityState === "hidden" && !snapshot.isComplete) {
1696
+ const activeField = fields.find(
1697
+ (f) => snapshot.statuses[f.key] === "active" || snapshot.statuses[f.key] === "editing"
1698
+ );
1699
+ if (activeField) {
1700
+ onDropOff(activeField.key);
1701
+ }
1702
+ }
1703
+ };
1704
+ document.addEventListener("visibilitychange", handleVisibility);
1705
+ return () => document.removeEventListener("visibilitychange", handleVisibility);
1706
+ }, [callbacks, snapshot, fields]);
1707
+ const visibleFields = useMemo(() => {
1708
+ return fields.filter((field) => {
1709
+ const status = snapshot.statuses[field.key];
1710
+ const isStarted = status === "typing" || status === "active" || status === "confirmed" || status === "editing";
1711
+ if (!isStarted) return false;
1712
+ if (field.showIf && !field.showIf(snapshot.values)) return false;
1713
+ return true;
1714
+ });
1715
+ }, [fields, snapshot.statuses, snapshot.values]);
1716
+ const lockedFields = useMemo(() => {
1717
+ const locked = /* @__PURE__ */ new Set();
1718
+ for (let i = 0; i < fields.length; i++) {
1719
+ const field = fields[i];
1720
+ if (!field) continue;
1721
+ if (field.lockPrevious && (snapshot.statuses[field.key] === "active" || snapshot.statuses[field.key] === "typing" || snapshot.statuses[field.key] === "editing" || snapshot.statuses[field.key] === "confirmed")) {
1722
+ for (let j = 0; j < i; j++) {
1723
+ const prev = fields[j];
1724
+ if (prev) locked.add(prev.key);
1725
+ }
1726
+ }
1727
+ }
1728
+ return locked;
1729
+ }, [fields, snapshot.statuses]);
1730
+ const showDone = (done == null ? void 0 : done.show) !== false && done !== void 0 && snapshot.isComplete;
1731
+ if (fieldsUrl && dynamicLoading) {
1732
+ return /* @__PURE__ */ jsx("div", { className: "ns-root", children: loadingComponent != null ? loadingComponent : /* @__PURE__ */ jsx("div", { className: "ns-loading-indicator", "aria-label": "Loading form" }) });
1733
+ }
1734
+ if (fieldsUrl && dynamicError) {
1735
+ return /* @__PURE__ */ jsx("div", { className: "ns-root", children: errorComponent != null ? errorComponent : /* @__PURE__ */ jsxs("div", { className: "ns-done", children: [
1736
+ /* @__PURE__ */ jsx("p", { className: "ns-error-text", children: i18n.fetchErrorMessage }),
1737
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ns-done-cta", onClick: retry, children: retryLabel != null ? retryLabel : i18n.retryLabel })
1738
+ ] }) });
1739
+ }
1740
+ const rootClasses = [
1741
+ "ns-root",
1742
+ snapshot.isComplete ? "ns-root--complete" : void 0,
1743
+ isDark ? "ns-root--dark" : void 0,
1744
+ isSubmitting ? "ns-root--submitting" : void 0,
1745
+ className
1746
+ ].filter(Boolean).join(" ");
1747
+ return /* @__PURE__ */ jsxs("div", { className: rootClasses, dir: direction, lang: locale, children: [
1748
+ !welcomeDismissed && welcome && /* @__PURE__ */ jsx(
1749
+ WelcomeScreen,
1750
+ {
1751
+ welcome,
1752
+ typewriter: effectiveTypewriter,
1753
+ onStart: handleWelcomeStart
1754
+ }
1755
+ ),
1756
+ welcomeDismissed && /* @__PURE__ */ jsx("div", { className: "ns-letter", role: "form", "aria-label": "Narrative form", children: visibleFields.map((field) => {
1757
+ var _a2, _b;
1758
+ return /* @__PURE__ */ jsx(
1759
+ Line,
1760
+ {
1761
+ field,
1762
+ status: (_a2 = snapshot.statuses[field.key]) != null ? _a2 : "idle",
1763
+ value: (_b = controlledValues == null ? void 0 : controlledValues[field.key]) != null ? _b : snapshot.values[field.key],
1764
+ allValues: snapshot.values,
1765
+ typewriter: effectiveTypewriter,
1766
+ editable,
1767
+ locked: lockedFields.has(field.key),
1768
+ editLabel: editLabel != null ? editLabel : i18n.editLabel,
1769
+ onTypingComplete: handleTypingComplete,
1770
+ onConfirm: handleConfirm,
1771
+ onEdit: handleEdit,
1772
+ onError: handleError,
1773
+ onChange: handleChange,
1774
+ onFocus: handleFocus,
1775
+ onBlur: handleBlur
1776
+ },
1777
+ field.key
1778
+ );
1779
+ }) }),
1780
+ showDone && done && /* @__PURE__ */ jsx(
1781
+ DoneScreen,
1782
+ {
1783
+ done,
1784
+ values: snapshot.values,
1785
+ meta: getMeta(),
1786
+ typewriter: effectiveTypewriter
1787
+ }
1788
+ )
1789
+ ] });
1790
+ };
1791
+ var NarrativeForm = function NarrativeForm2(props) {
1792
+ return /* @__PURE__ */ jsx(ThemeProvider, { theme: props.theme, children: /* @__PURE__ */ jsx(ToastProvider, { children: /* @__PURE__ */ jsx(NarrativeFormInner, { ...props }) }) });
1793
+ };
1794
+ var TextField = function TextField2(props) {
1795
+ return /* @__PURE__ */ jsx(InlineInput, { ...props, type: "text" });
1796
+ };
1797
+ var TelField = function TelField2(props) {
1798
+ return /* @__PURE__ */ jsx(InlineInput, { ...props, type: "tel" });
1799
+ };
1800
+ var EmailField = function EmailField2(props) {
1801
+ return /* @__PURE__ */ jsx(InlineInput, { ...props, type: "email" });
1802
+ };
1803
+ var NumberField = function NumberField2(props) {
1804
+ return /* @__PURE__ */ jsx(InlineInput, { ...props, type: "number" });
1805
+ };
1806
+
1807
+ export { ChipsField, Cursor, DoneScreen, EditIcon, EmailField, EnterButton, ErrorMessage, FilledValue, InlineInput, Line, MultiChipsField, NarrativeForm, NumberField, OtpField, PasswordField, Prose, SelectField, TelField, TextField, ThemeProvider, WelcomeScreen, useFormState, useTheme, useTypewriter };
1808
+ //# sourceMappingURL=index.mjs.map
1809
+ //# sourceMappingURL=index.mjs.map