@viveksinghind/narrative-form-native 1.0.2 → 1.0.4

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/package.json CHANGED
@@ -1,53 +1,53 @@
1
1
  {
2
- "name": "@viveksinghind/narrative-form-native",
3
- "version": "1.0.2",
4
- "description": "React Native components for narrative-form — typewriter-style sign-up flow",
5
- "author": "Vivek Singh <vivekSinghInd>",
6
- "license": "MIT",
7
- "main": "dist/index.js",
8
- "types": "dist/index.d.ts",
9
- "sideEffects": false,
10
- "files": [
11
- "dist"
12
- ],
13
- "exports": {
14
- ".": {
15
- "require": "./dist/index.js",
16
- "import": "./dist/index.js",
17
- "types": "./dist/index.d.ts"
2
+ "name": "@viveksinghind/narrative-form-native",
3
+ "version": "1.0.4",
4
+ "description": "React Native components for narrative-form — typewriter-style sign-up flow",
5
+ "author": "Vivek Singh <vivekSinghInd>",
6
+ "license": "MIT",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "sideEffects": false,
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "exports": {
14
+ ".": {
15
+ "require": "./dist/index.js",
16
+ "import": "./dist/index.js",
17
+ "types": "./dist/index.d.ts"
18
+ }
19
+ },
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "dev": "tsc --watch",
23
+ "typecheck": "tsc --noEmit",
24
+ "clean": "rimraf dist"
25
+ },
26
+ "dependencies": {
27
+ "@viveksinghind/narrative-form-core": "workspace:*"
28
+ },
29
+ "peerDependencies": {
30
+ "react": ">=17.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/react": "^18.3.1",
34
+ "@types/react-native": "0.70.0",
35
+ "rimraf": "^5.0.5",
36
+ "tsup": "^8.0.2",
37
+ "typescript": "^5.4.5"
38
+ },
39
+ "keywords": [
40
+ "react-native",
41
+ "narrative-form",
42
+ "typewriter",
43
+ "form",
44
+ "onboarding",
45
+ "signup",
46
+ "typescript"
47
+ ],
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "https://github.com/vivekSinghInd/narrative-form.git",
51
+ "directory": "packages/native"
18
52
  }
19
- },
20
- "dependencies": {
21
- "@viveksinghind/narrative-form-core": "1.0.2"
22
- },
23
- "peerDependencies": {
24
- "react": ">=17.0.0"
25
- },
26
- "devDependencies": {
27
- "@types/react": "^18.3.1",
28
- "@types/react-native": "0.70.0",
29
- "rimraf": "^5.0.5",
30
- "tsup": "^8.0.2",
31
- "typescript": "^5.4.5"
32
- },
33
- "keywords": [
34
- "react-native",
35
- "narrative-form",
36
- "typewriter",
37
- "form",
38
- "onboarding",
39
- "signup",
40
- "typescript"
41
- ],
42
- "repository": {
43
- "type": "git",
44
- "url": "https://github.com/vivekSinghInd/narrative-form.git",
45
- "directory": "packages/native"
46
- },
47
- "scripts": {
48
- "build": "tsc",
49
- "dev": "tsc --watch",
50
- "typecheck": "tsc --noEmit",
51
- "clean": "rimraf dist"
52
- }
53
53
  }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Vivek Singh
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/dist/index.mjs DELETED
@@ -1,621 +0,0 @@
1
- import { createContext, useState, useRef, useCallback, useMemo, useEffect, useContext } from 'react';
2
- import { StyleSheet, Animated, Text, Keyboard, View, TouchableOpacity, TextInput, ScrollView } from 'react-native';
3
- import { FormStateEngine, fetchFormConfig, validateField, hasAsyncValidation, validateFieldAsync, mergeStrings } from '@viveksinghind/narrative-form-core';
4
- import { jsx, jsxs } from 'react/jsx-runtime';
5
-
6
- // src/components/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
- var ThemeContext = createContext({
102
- theme: void 0,
103
- isDark: false
104
- });
105
- var useTheme = () => useContext(ThemeContext);
106
- var ThemeProvider = ({ theme, children }) => {
107
- const value = useMemo(() => {
108
- return {
109
- theme,
110
- isDark: !!(theme == null ? void 0 : theme.mode) && theme.mode === "dark"
111
- };
112
- }, [theme]);
113
- return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children });
114
- };
115
- var ErrorMessage = ({ message, config }) => {
116
- var _a;
117
- const { theme } = useTheme();
118
- const opacity = useRef(new Animated.Value(0)).current;
119
- const translateY = useRef(new Animated.Value(-10)).current;
120
- useEffect(() => {
121
- if (message) {
122
- Animated.parallel([
123
- Animated.timing(opacity, {
124
- toValue: 1,
125
- duration: 200,
126
- useNativeDriver: true
127
- }),
128
- Animated.timing(translateY, {
129
- toValue: 0,
130
- duration: 200,
131
- useNativeDriver: true
132
- })
133
- ]).start();
134
- } else {
135
- opacity.setValue(0);
136
- translateY.setValue(-10);
137
- }
138
- }, [message, opacity, translateY]);
139
- if (!message) return null;
140
- return /* @__PURE__ */ jsx(Animated.View, { style: { opacity, transform: [{ translateY }] }, children: /* @__PURE__ */ jsx(Text, { style: [styles.errorText, { color: ((_a = theme == null ? void 0 : theme.colors) == null ? void 0 : _a.error) || "#d32f2f" }], children: message }) });
141
- };
142
- var styles = StyleSheet.create({
143
- errorText: {
144
- fontSize: 14,
145
- marginTop: 4,
146
- marginBottom: 8
147
- }
148
- });
149
- var Line = ({
150
- field,
151
- status,
152
- value,
153
- allValues,
154
- typewriter,
155
- editable,
156
- locked,
157
- editLabel,
158
- onTypingComplete,
159
- onConfirm,
160
- onEdit,
161
- onError,
162
- onChange,
163
- onFocus,
164
- onBlur
165
- }) => {
166
- var _a, _b;
167
- const { theme, isDark } = useTheme();
168
- const [typedPrompt, setTypedPrompt] = useState("");
169
- const [localValue, setLocalValue] = useState(value ? String(value) : "");
170
- const [errorMsg, setErrorMsg] = useState(null);
171
- const [isValidating, setIsValidating] = useState(false);
172
- const inputRef = useRef(null);
173
- const opacity = useRef(new Animated.Value(0)).current;
174
- useEffect(() => {
175
- Animated.timing(opacity, {
176
- toValue: 1,
177
- duration: 300,
178
- useNativeDriver: true
179
- }).start();
180
- }, [opacity]);
181
- useEffect(() => {
182
- if (value !== void 0 && String(value) !== localValue) {
183
- setLocalValue(String(value));
184
- }
185
- }, [value]);
186
- useEffect(() => {
187
- var _a2;
188
- if (status !== "typing") return;
189
- if (!typewriter.enabled) {
190
- setTypedPrompt(field.prompt);
191
- onTypingComplete(field.key);
192
- return;
193
- }
194
- let i = 0;
195
- const interval = setInterval(() => {
196
- setTypedPrompt(field.prompt.slice(0, i + 1));
197
- i++;
198
- if (i >= field.prompt.length) {
199
- clearInterval(interval);
200
- onTypingComplete(field.key);
201
- }
202
- }, (_a2 = typewriter.delayMs) != null ? _a2 : 30);
203
- return () => clearInterval(interval);
204
- }, [status, field.prompt, field.key, typewriter, onTypingComplete]);
205
- useEffect(() => {
206
- if (status === "active" || status === "editing") {
207
- setTimeout(() => {
208
- var _a2;
209
- (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
210
- }, 50);
211
- }
212
- }, [status]);
213
- const handleConfirm = useCallback(async () => {
214
- const syncResult = validateField(field, localValue);
215
- if (!syncResult.valid) {
216
- setErrorMsg(syncResult.error || "Invalid input");
217
- onError(field.key, syncResult.error || "Invalid input");
218
- return;
219
- }
220
- if (hasAsyncValidation(field)) {
221
- setIsValidating(true);
222
- const asyncResult = await validateFieldAsync(field, localValue);
223
- setIsValidating(false);
224
- if (!asyncResult.valid) {
225
- setErrorMsg(asyncResult.error || "Invalid input");
226
- onError(field.key, asyncResult.error || "Invalid input");
227
- return;
228
- }
229
- }
230
- setErrorMsg(null);
231
- Keyboard.dismiss();
232
- onConfirm(field.key, localValue);
233
- }, [field, localValue, onError, onConfirm]);
234
- const textColor = ((_a = theme == null ? void 0 : theme.colors) == null ? void 0 : _a.text) || (isDark ? "#fff" : "#000");
235
- const primaryColor = ((_b = theme == null ? void 0 : theme.colors) == null ? void 0 : _b.primary) || "#007bff";
236
- const isConfirmed = status === "confirmed";
237
- const isActive = status === "active" || status === "editing";
238
- return /* @__PURE__ */ jsxs(Animated.View, { style: [styles2.container, { opacity }], children: [
239
- /* @__PURE__ */ jsxs(View, { style: styles2.promptRow, children: [
240
- /* @__PURE__ */ jsx(Text, { style: [styles2.prompt, { color: textColor }], children: status === "typing" ? typedPrompt : field.prompt }),
241
- isConfirmed && /* @__PURE__ */ jsx(Text, { style: [styles2.value, { color: primaryColor }], children: localValue }),
242
- isConfirmed && editable && !locked && /* @__PURE__ */ jsx(TouchableOpacity, { onPress: () => onEdit(field.key), style: styles2.editBtn, children: /* @__PURE__ */ jsx(Text, { style: [styles2.editBtnText, { color: primaryColor }], children: editLabel }) })
243
- ] }),
244
- isActive && /* @__PURE__ */ jsx(View, { style: styles2.inputRow, children: /* @__PURE__ */ jsx(
245
- TextInput,
246
- {
247
- ref: inputRef,
248
- style: [
249
- styles2.input,
250
- { color: textColor, borderBottomColor: isValidating ? "#ccc" : primaryColor }
251
- ],
252
- value: localValue,
253
- onChangeText: (text) => {
254
- setLocalValue(text);
255
- onChange(field.key, text);
256
- if (errorMsg) setErrorMsg(null);
257
- },
258
- onFocus: () => onFocus(field.key),
259
- onBlur: () => onBlur(field.key, localValue),
260
- onSubmitEditing: handleConfirm,
261
- keyboardType: field.type === "email" ? "email-address" : "default",
262
- secureTextEntry: field.type === "password",
263
- returnKeyType: "next",
264
- editable: !isValidating
265
- }
266
- ) }),
267
- /* @__PURE__ */ jsx(ErrorMessage, { message: errorMsg })
268
- ] });
269
- };
270
- var styles2 = StyleSheet.create({
271
- container: {
272
- marginVertical: 12
273
- },
274
- promptRow: {
275
- flexDirection: "row",
276
- alignItems: "center",
277
- flexWrap: "wrap"
278
- },
279
- prompt: {
280
- fontSize: 18,
281
- marginRight: 8
282
- },
283
- value: {
284
- fontSize: 18,
285
- fontWeight: "600",
286
- marginRight: 8
287
- },
288
- editBtn: {
289
- marginLeft: 8,
290
- paddingHorizontal: 8,
291
- paddingVertical: 4,
292
- borderRadius: 4,
293
- backgroundColor: "rgba(0,0,0,0.05)"
294
- },
295
- editBtnText: {
296
- fontSize: 12,
297
- fontWeight: "bold"
298
- },
299
- inputRow: {
300
- marginTop: 8
301
- },
302
- input: {
303
- fontSize: 18,
304
- paddingVertical: 8,
305
- borderBottomWidth: 2
306
- }
307
- });
308
- var ToastContext = createContext({
309
- showToast: () => {
310
- }
311
- });
312
- var useToast = () => useContext(ToastContext);
313
- var ToastProvider = ({ children }) => {
314
- const [toast, setToast] = useState(null);
315
- const showToast = useCallback((message, type = "info") => {
316
- setToast({ message, type });
317
- setTimeout(() => setToast(null), 3e3);
318
- }, []);
319
- return /* @__PURE__ */ jsx(ToastContext.Provider, { value: { showToast }, children: /* @__PURE__ */ jsxs(View, { style: styles3.container, children: [
320
- children,
321
- toast && /* @__PURE__ */ jsx(View, { style: [styles3.toast, toast.type === "error" ? styles3.toastError : styles3.toastSuccess], children: /* @__PURE__ */ jsx(Text, { style: styles3.toastText, children: toast.message }) })
322
- ] }) });
323
- };
324
- var styles3 = StyleSheet.create({
325
- container: {
326
- flex: 1
327
- },
328
- toast: {
329
- position: "absolute",
330
- bottom: 40,
331
- left: 20,
332
- right: 20,
333
- padding: 16,
334
- borderRadius: 8,
335
- backgroundColor: "#333",
336
- alignItems: "center"
337
- },
338
- toastError: {
339
- backgroundColor: "#d32f2f"
340
- },
341
- toastSuccess: {
342
- backgroundColor: "#2e7d32"
343
- },
344
- toastText: {
345
- color: "#fff",
346
- fontSize: 14
347
- }
348
- });
349
- var WelcomeScreen = ({ welcome, typewriter, onStart }) => {
350
- var _a, _b;
351
- const { theme, isDark } = useTheme();
352
- const opacity = useRef(new Animated.Value(0)).current;
353
- const [typedTitle, setTypedTitle] = useState("");
354
- useEffect(() => {
355
- Animated.timing(opacity, {
356
- toValue: 1,
357
- duration: 500,
358
- useNativeDriver: true
359
- }).start();
360
- }, [opacity]);
361
- useEffect(() => {
362
- var _a2;
363
- if (!typewriter.enabled) {
364
- setTypedTitle(welcome.title);
365
- return;
366
- }
367
- let i = 0;
368
- const interval = setInterval(() => {
369
- setTypedTitle(welcome.title.slice(0, i + 1));
370
- i++;
371
- if (i >= welcome.title.length) {
372
- clearInterval(interval);
373
- }
374
- }, (_a2 = typewriter.delayMs) != null ? _a2 : 30);
375
- return () => clearInterval(interval);
376
- }, [welcome.title, typewriter]);
377
- const textColor = ((_a = theme == null ? void 0 : theme.colors) == null ? void 0 : _a.text) || (isDark ? "#fff" : "#000");
378
- const primaryColor = ((_b = theme == null ? void 0 : theme.colors) == null ? void 0 : _b.primary) || "#007bff";
379
- return /* @__PURE__ */ jsxs(Animated.View, { style: [styles4.container, { opacity }], children: [
380
- /* @__PURE__ */ jsx(Text, { style: [styles4.title, { color: textColor }], children: typedTitle }),
381
- welcome.subtitle && /* @__PURE__ */ jsx(Text, { style: [styles4.subtitle, { color: textColor, opacity: 0.7 }], children: welcome.subtitle }),
382
- /* @__PURE__ */ jsx(
383
- TouchableOpacity,
384
- {
385
- style: [styles4.button, { backgroundColor: primaryColor }],
386
- onPress: onStart,
387
- accessibilityRole: "button",
388
- children: /* @__PURE__ */ jsx(Text, { style: styles4.buttonText, children: welcome.startLabel || "Start" })
389
- }
390
- )
391
- ] });
392
- };
393
- var styles4 = StyleSheet.create({
394
- container: {
395
- flex: 1,
396
- justifyContent: "center",
397
- alignItems: "flex-start",
398
- padding: 20
399
- },
400
- title: {
401
- fontSize: 28,
402
- fontWeight: "bold",
403
- marginBottom: 8
404
- },
405
- subtitle: {
406
- fontSize: 16,
407
- marginBottom: 24
408
- },
409
- button: {
410
- paddingHorizontal: 24,
411
- paddingVertical: 12,
412
- borderRadius: 8
413
- },
414
- buttonText: {
415
- color: "#fff",
416
- fontSize: 16,
417
- fontWeight: "600"
418
- }
419
- });
420
- var DoneScreen = ({ done, values, meta }) => {
421
- var _a;
422
- const { theme, isDark } = useTheme();
423
- const opacity = useRef(new Animated.Value(0)).current;
424
- useEffect(() => {
425
- Animated.timing(opacity, {
426
- toValue: 1,
427
- duration: 500,
428
- useNativeDriver: true
429
- }).start();
430
- }, [opacity]);
431
- const textColor = ((_a = theme == null ? void 0 : theme.colors) == null ? void 0 : _a.text) || (isDark ? "#fff" : "#000");
432
- return /* @__PURE__ */ jsxs(Animated.View, { style: [styles5.container, { opacity }], children: [
433
- /* @__PURE__ */ jsx(Text, { style: [styles5.title, { color: textColor }], children: done.title }),
434
- done.subtitle && /* @__PURE__ */ jsx(Text, { style: [styles5.subtitle, { color: textColor, opacity: 0.7 }], children: done.subtitle })
435
- ] });
436
- };
437
- var styles5 = StyleSheet.create({
438
- container: {
439
- padding: 20,
440
- marginTop: 20
441
- },
442
- title: {
443
- fontSize: 24,
444
- fontWeight: "bold",
445
- marginBottom: 8
446
- },
447
- subtitle: {
448
- fontSize: 16
449
- }
450
- });
451
- var NarrativeFormInner = (props) => {
452
- var _a, _b, _c;
453
- const { isDark } = useTheme();
454
- const i18n = useMemo(() => mergeStrings(props.strings), [props.strings]);
455
- const { config: dynamicConfig, loading, error, retry } = useDynamicForm({ fieldsUrl: props.fieldsUrl, fieldsUrlHeaders: props.fieldsUrlHeaders });
456
- const resolvedConfig = useMemo(() => {
457
- if (props.fields) return { fields: props.fields };
458
- if (props.formConfig) return props.formConfig;
459
- if (dynamicConfig) return dynamicConfig;
460
- return null;
461
- }, [props.fields, props.formConfig, dynamicConfig]);
462
- const fields = (_a = resolvedConfig == null ? void 0 : resolvedConfig.fields) != null ? _a : [];
463
- const welcome = (_b = props.welcome) != null ? _b : resolvedConfig && "welcome" in resolvedConfig ? resolvedConfig.welcome : void 0;
464
- const done = (_c = props.done) != null ? _c : resolvedConfig && "done" in resolvedConfig ? resolvedConfig.done : void 0;
465
- const effectiveTypewriter = useMemo(() => {
466
- var _a2, _b2;
467
- return {
468
- ...props.typewriter,
469
- enabled: props.reducedMotion ? false : (_b2 = (_a2 = props.typewriter) == null ? void 0 : _a2.enabled) != null ? _b2 : true
470
- };
471
- }, [props.typewriter, props.reducedMotion]);
472
- const {
473
- snapshot,
474
- startTyping,
475
- activateField,
476
- confirmField,
477
- editField,
478
- reconfirmField,
479
- next,
480
- focusField,
481
- reset,
482
- getValues,
483
- getMeta
484
- } = useFormState(fields);
485
- const showWelcome = (welcome == null ? void 0 : welcome.show) !== false && welcome !== void 0;
486
- const [welcomeDismissed, setWelcomeDismissed] = useState(!showWelcome);
487
- const hasStartedRef = useRef(false);
488
- useEffect(() => {
489
- if (!welcomeDismissed || hasStartedRef.current || fields.length === 0) return;
490
- hasStartedRef.current = true;
491
- const firstField = fields.find((f) => snapshot.statuses[f.key] !== "confirmed");
492
- if (firstField) {
493
- startTyping(firstField.key);
494
- }
495
- }, [welcomeDismissed, fields, startTyping, snapshot.statuses]);
496
- const handleConfirm = useCallback((key, value) => {
497
- var _a2, _b2;
498
- const status = snapshot.statuses[key];
499
- if (status === "editing") {
500
- reconfirmField(key, value);
501
- } else {
502
- confirmField(key, value);
503
- }
504
- (_b2 = (_a2 = props.callbacks) == null ? void 0 : _a2.onFieldComplete) == null ? void 0 : _b2.call(_a2, key, value, 0);
505
- const currentIndex = fields.findIndex((f) => f.key === key);
506
- for (let i = currentIndex + 1; i < fields.length; i++) {
507
- const nextField = fields[i];
508
- if (!nextField || snapshot.statuses[nextField.key] === "confirmed") continue;
509
- startTyping(nextField.key);
510
- break;
511
- }
512
- }, [snapshot, fields, confirmField, reconfirmField, startTyping, props.callbacks]);
513
- const visibleFields = useMemo(() => {
514
- return fields.filter((field) => {
515
- const status = snapshot.statuses[field.key];
516
- return status === "typing" || status === "active" || status === "confirmed" || status === "editing";
517
- });
518
- }, [fields, snapshot.statuses]);
519
- const scrollViewRef = useRef(null);
520
- useEffect(() => {
521
- if (visibleFields.length > 0) {
522
- setTimeout(() => {
523
- var _a2;
524
- (_a2 = scrollViewRef.current) == null ? void 0 : _a2.scrollToEnd({ animated: true });
525
- }, 100);
526
- }
527
- }, [visibleFields.length]);
528
- return /* @__PURE__ */ jsxs(
529
- ScrollView,
530
- {
531
- ref: scrollViewRef,
532
- style: [styles6.container, isDark ? styles6.darkContainer : styles6.lightContainer],
533
- contentContainerStyle: styles6.content,
534
- keyboardShouldPersistTaps: "handled",
535
- children: [
536
- !welcomeDismissed && welcome && /* @__PURE__ */ jsx(
537
- WelcomeScreen,
538
- {
539
- welcome,
540
- typewriter: effectiveTypewriter,
541
- onStart: () => setWelcomeDismissed(true)
542
- }
543
- ),
544
- welcomeDismissed && /* @__PURE__ */ jsx(View, { style: styles6.formBody, children: visibleFields.map((field) => {
545
- var _a2, _b2, _c2, _d, _e;
546
- return /* @__PURE__ */ jsx(
547
- Line,
548
- {
549
- field,
550
- status: (_a2 = snapshot.statuses[field.key]) != null ? _a2 : "idle",
551
- value: (_c2 = (_b2 = props.values) == null ? void 0 : _b2[field.key]) != null ? _c2 : snapshot.values[field.key],
552
- allValues: snapshot.values,
553
- typewriter: effectiveTypewriter,
554
- editable: (_d = props.editable) != null ? _d : true,
555
- locked: false,
556
- editLabel: (_e = props.editLabel) != null ? _e : i18n.editLabel,
557
- onTypingComplete: (k) => activateField(k),
558
- onConfirm: handleConfirm,
559
- onEdit: (k) => {
560
- var _a3, _b3;
561
- editField(k);
562
- (_b3 = (_a3 = props.callbacks) == null ? void 0 : _a3.onEdit) == null ? void 0 : _b3.call(_a3, k);
563
- },
564
- onError: (k, err) => {
565
- var _a3, _b3;
566
- return (_b3 = (_a3 = props.callbacks) == null ? void 0 : _a3.onError) == null ? void 0 : _b3.call(_a3, k, err);
567
- },
568
- onChange: (k, v) => {
569
- var _a3, _b3;
570
- return (_b3 = (_a3 = props.callbacks) == null ? void 0 : _a3.onChange) == null ? void 0 : _b3.call(_a3, k, v);
571
- },
572
- onFocus: (k) => {
573
- var _a3, _b3;
574
- return (_b3 = (_a3 = props.callbacks) == null ? void 0 : _a3.onFieldFocus) == null ? void 0 : _b3.call(_a3, k);
575
- },
576
- onBlur: (k, v) => {
577
- var _a3, _b3;
578
- return (_b3 = (_a3 = props.callbacks) == null ? void 0 : _a3.onFieldBlur) == null ? void 0 : _b3.call(_a3, k, v);
579
- }
580
- },
581
- field.key
582
- );
583
- }) }),
584
- snapshot.isComplete && done && /* @__PURE__ */ jsx(
585
- DoneScreen,
586
- {
587
- done,
588
- values: snapshot.values,
589
- meta: getMeta(),
590
- typewriter: effectiveTypewriter
591
- }
592
- )
593
- ]
594
- }
595
- );
596
- };
597
- var NarrativeForm = (props) => {
598
- return /* @__PURE__ */ jsx(ThemeProvider, { theme: props.theme, children: /* @__PURE__ */ jsx(ToastProvider, { children: /* @__PURE__ */ jsx(NarrativeFormInner, { ...props }) }) });
599
- };
600
- var styles6 = StyleSheet.create({
601
- container: {
602
- flex: 1
603
- },
604
- lightContainer: {
605
- backgroundColor: "#ffffff"
606
- },
607
- darkContainer: {
608
- backgroundColor: "#121212"
609
- },
610
- content: {
611
- padding: 20,
612
- flexGrow: 1
613
- },
614
- formBody: {
615
- flex: 1
616
- }
617
- });
618
-
619
- export { DoneScreen, ErrorMessage, Line, NarrativeForm, ThemeProvider, ToastProvider, WelcomeScreen, useDynamicForm, useFormState, useTheme, useToast };
620
- //# sourceMappingURL=index.mjs.map
621
- //# sourceMappingURL=index.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/useFormState.ts","../src/hooks/useDynamicForm.ts","../src/components/ThemeProvider.tsx","../src/components/ErrorMessage.tsx","../src/components/Line.tsx","../src/components/ToastProvider.tsx","../src/components/WelcomeScreen.tsx","../src/components/DoneScreen.tsx","../src/components/NarrativeForm.tsx"],"names":["useState","useCallback","useMemo","useRef","useEffect","jsx","Animated","_a","styles","Text","StyleSheet","createContext","useContext","jsxs","View","TouchableOpacity","_b","_c"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\r\n * React hook wrapping the core FormStateEngine.\r\n *\r\n * @remarks\r\n * Bridges the framework-agnostic FormStateEngine with React's\r\n * state management. Each state mutation in the engine triggers\r\n * a React re-render via `useSyncExternalStore`-like pattern.\r\n */\r\n\r\nimport { useState, useRef, useCallback, useMemo } from \"react\";\r\nimport type { NarrativeField, NarrativeFieldValues, NarrativeMeta } from \"@viveksinghind/narrative-form-core\";\r\nimport { FormStateEngine } from \"@viveksinghind/narrative-form-core\";\r\nimport type { FieldStatus, FormStateSnapshot } from \"@viveksinghind/narrative-form-core\";\r\n\r\n/** Return value of the useFormState hook. */\r\nexport interface UseFormStateResult {\r\n /** Current snapshot of the form state. */\r\n snapshot: FormStateSnapshot;\r\n /** Start the typewriter animation for a field. */\r\n startTyping: (key: string) => void;\r\n /** Mark a field as active (typewriter done, input visible). */\r\n activateField: (key: string) => void;\r\n /** Confirm a field with a value. */\r\n confirmField: (key: string, value: string | string[]) => void;\r\n /** Reopen a confirmed field for editing. */\r\n editField: (key: string) => void;\r\n /** Re-confirm a field after editing. */\r\n reconfirmField: (key: string, value: string | string[]) => void;\r\n /** Move to the next field. */\r\n next: () => void;\r\n /** Focus a specific field by key. */\r\n focusField: (key: string) => void;\r\n /** Reset all form state. */\r\n reset: () => void;\r\n /** Get all confirmed values. */\r\n getValues: () => NarrativeFieldValues;\r\n /** Get analytics metadata. */\r\n getMeta: (formId?: string, formVersion?: number) => NarrativeMeta;\r\n}\r\n\r\n/**\r\n * React hook that manages the narrative form state.\r\n *\r\n * @param fields - Ordered array of field configurations\r\n * @returns Form state and mutation methods\r\n */\r\nexport function useFormState(fields: readonly NarrativeField[]): UseFormStateResult {\r\n // Use a counter to force re-renders when the engine mutates\r\n const [, setTick] = useState(0);\r\n\r\n const engineRef = useRef<FormStateEngine | null>(null);\r\n\r\n // Lazily initialise the engine\r\n if (engineRef.current === null) {\r\n engineRef.current = new FormStateEngine(fields, () => {\r\n setTick((t) => t + 1);\r\n });\r\n }\r\n\r\n const engine = engineRef.current;\r\n\r\n // Stable method references\r\n const startTyping = useCallback((key: string) => engine.startTyping(key), [engine]);\r\n const activateField = useCallback((key: string) => engine.activateField(key), [engine]);\r\n const confirmField = useCallback(\r\n (key: string, value: string | string[]) => engine.confirmField(key, value),\r\n [engine],\r\n );\r\n const editField = useCallback((key: string) => engine.editField(key), [engine]);\r\n const reconfirmField = useCallback(\r\n (key: string, value: string | string[]) => engine.reconfirmField(key, value),\r\n [engine],\r\n );\r\n const next = useCallback(() => engine.next(), [engine]);\r\n const focusField = useCallback((key: string) => engine.focusField(key), [engine]);\r\n const reset = useCallback(() => engine.reset(), [engine]);\r\n const getValues = useCallback(() => engine.getValues(), [engine]);\r\n const getMeta = useCallback(\r\n (formId?: string, formVersion?: number) => engine.getMeta(formId, formVersion),\r\n [engine],\r\n );\r\n\r\n const snapshot = engine.getSnapshot();\r\n\r\n return useMemo(\r\n () => ({\r\n snapshot,\r\n startTyping,\r\n activateField,\r\n confirmField,\r\n editField,\r\n reconfirmField,\r\n next,\r\n focusField,\r\n reset,\r\n getValues,\r\n getMeta,\r\n }),\r\n // snapshot changes every tick, which is what we want\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n [snapshot],\r\n );\r\n}\r\n","import { useState, useEffect, useCallback } from \"react\";\r\nimport type { NarrativeFormConfig } from \"@viveksinghind/narrative-form-core\";\r\nimport { fetchFormConfig, ConfigFetchError } from \"@viveksinghind/narrative-form-core\";\r\n\r\nexport interface UseDynamicFormProps {\r\n fieldsUrl?: string;\r\n fieldsUrlHeaders?: Record<string, string>;\r\n formConfig?: NarrativeFormConfig;\r\n onFetchError?: (error: Error) => void;\r\n}\r\n\r\nexport interface UseDynamicFormResult {\r\n config: NarrativeFormConfig | null;\r\n loading: boolean;\r\n error: Error | null;\r\n retry: () => void;\r\n}\r\n\r\n/**\r\n * Hook to manage fetching and parsing server-driven form configuration.\r\n */\r\nexport function useDynamicForm({\r\n fieldsUrl,\r\n fieldsUrlHeaders,\r\n formConfig,\r\n onFetchError,\r\n}: UseDynamicFormProps): UseDynamicFormResult {\r\n const [config, setConfig] = useState<NarrativeFormConfig | null>(formConfig ?? null);\r\n const [loading, setLoading] = useState<boolean>(!!fieldsUrl && !formConfig);\r\n const [error, setError] = useState<Error | null>(null);\r\n const [retryCount, setRetryCount] = useState(0);\r\n\r\n useEffect(() => {\r\n // If a complete config is passed via props, use it immediately\r\n if (formConfig) {\r\n setConfig(formConfig);\r\n setLoading(false);\r\n setError(null);\r\n return;\r\n }\r\n\r\n if (!fieldsUrl) {\r\n return;\r\n }\r\n\r\n let isMounted = true;\r\n setLoading(true);\r\n setError(null);\r\n\r\n fetchFormConfig(fieldsUrl, { headers: fieldsUrlHeaders })\r\n .then((data) => {\r\n if (isMounted) {\r\n setConfig(data);\r\n setLoading(false);\r\n }\r\n })\r\n .catch((err: Error) => {\r\n if (isMounted) {\r\n setError(err);\r\n setLoading(false);\r\n onFetchError?.(err);\r\n }\r\n });\r\n\r\n return () => {\r\n isMounted = false;\r\n };\r\n }, [fieldsUrl, fieldsUrlHeaders, formConfig, retryCount, onFetchError]);\r\n\r\n const retry = useCallback(() => {\r\n if (fieldsUrl && !formConfig) {\r\n setRetryCount((c) => c + 1);\r\n }\r\n }, [fieldsUrl, formConfig]);\r\n\r\n return { config, loading, error, retry };\r\n}\r\n","import React, { createContext, useContext, useMemo } from \"react\";\nimport type { NarrativeTheme } from \"@viveksinghind/narrative-form-core\";\n\nexport interface ThemeContextValue {\n theme: NarrativeTheme | undefined;\n isDark: boolean;\n}\n\nconst ThemeContext = createContext<ThemeContextValue>({\n theme: undefined,\n isDark: false,\n});\n\nexport const useTheme = () => useContext(ThemeContext);\n\nexport interface ThemeProviderProps {\n theme?: NarrativeTheme;\n children: React.ReactNode;\n}\n\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({ theme, children }) => {\n const value = useMemo(() => {\n // In React Native we can check Appearance.getColorScheme() if we want auto dark mode,\n // but for now we just rely on the theme prop.\n return {\n theme,\n isDark: !!theme?.mode && theme.mode === \"dark\",\n };\n }, [theme]);\n\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n};\n","import React, { useEffect, useRef } from \"react\";\nimport { Animated, Text, StyleSheet } from \"react-native\";\nimport type { NarrativeErrorDisplay } from \"@viveksinghind/narrative-form-core\";\nimport { useTheme } from \"./ThemeProvider\";\n\nexport interface ErrorMessageProps {\n message: string | null;\n config?: NarrativeErrorDisplay;\n}\n\nexport const ErrorMessage: React.FC<ErrorMessageProps> = ({ message, config }) => {\n const { theme } = useTheme();\n const opacity = useRef(new Animated.Value(0)).current;\n const translateY = useRef(new Animated.Value(-10)).current;\n\n useEffect(() => {\n if (message) {\n Animated.parallel([\n Animated.timing(opacity, {\n toValue: 1,\n duration: 200,\n useNativeDriver: true,\n }),\n Animated.timing(translateY, {\n toValue: 0,\n duration: 200,\n useNativeDriver: true,\n })\n ]).start();\n } else {\n opacity.setValue(0);\n translateY.setValue(-10);\n }\n }, [message, opacity, translateY]);\n\n if (!message) return null;\n\n return (\n <Animated.View style={{ opacity, transform: [{ translateY }] }}>\n <Text style={[styles.errorText, { color: theme?.colors?.error || \"#d32f2f\" }]}>\n {message}\n </Text>\n </Animated.View>\n );\n};\n\nconst styles = StyleSheet.create({\n errorText: {\n fontSize: 14,\n marginTop: 4,\n marginBottom: 8,\n }\n});\n","import React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { Animated, View, Text, TextInput, TouchableOpacity, StyleSheet, Easing, Keyboard } from \"react-native\";\nimport type { NarrativeField, FieldStatus, NarrativeTypewriter, NarrativeFieldValues } from \"@viveksinghind/narrative-form-core\";\nimport { validateField, validateFieldAsync, hasAsyncValidation } from \"@viveksinghind/narrative-form-core\";\nimport { ErrorMessage } from \"./ErrorMessage\";\nimport { useTheme } from \"./ThemeProvider\";\n\nexport interface LineProps {\n field: NarrativeField;\n status: FieldStatus;\n value: any;\n allValues: NarrativeFieldValues;\n typewriter: NarrativeTypewriter;\n editable: boolean;\n locked: boolean;\n editLabel: string;\n onTypingComplete: (key: string) => void;\n onConfirm: (key: string, value: string) => void;\n onEdit: (key: string) => void;\n onError: (key: string, error: string) => void;\n onChange: (key: string, value: string) => void;\n onFocus: (key: string) => void;\n onBlur: (key: string, value: string) => void;\n}\n\nexport const Line: React.FC<LineProps> = ({\n field,\n status,\n value,\n allValues,\n typewriter,\n editable,\n locked,\n editLabel,\n onTypingComplete,\n onConfirm,\n onEdit,\n onError,\n onChange,\n onFocus,\n onBlur,\n}) => {\n const { theme, isDark } = useTheme();\n \n const [typedPrompt, setTypedPrompt] = useState(\"\");\n const [localValue, setLocalValue] = useState(value ? String(value) : \"\");\n const [errorMsg, setErrorMsg] = useState<string | null>(null);\n const [isValidating, setIsValidating] = useState(false);\n \n const inputRef = useRef<TextInput>(null);\n const opacity = useRef(new Animated.Value(0)).current;\n\n // Fade in on mount\n useEffect(() => {\n Animated.timing(opacity, {\n toValue: 1,\n duration: 300,\n useNativeDriver: true,\n }).start();\n }, [opacity]);\n\n // Sync external value\n useEffect(() => {\n if (value !== undefined && String(value) !== localValue) {\n setLocalValue(String(value));\n }\n }, [value]);\n\n // Typewriter effect\n useEffect(() => {\n if (status !== \"typing\") return;\n \n if (!typewriter.enabled) {\n setTypedPrompt(field.prompt);\n onTypingComplete(field.key);\n return;\n }\n\n let i = 0;\n const interval = setInterval(() => {\n setTypedPrompt(field.prompt.slice(0, i + 1));\n i++;\n if (i >= field.prompt.length) {\n clearInterval(interval);\n onTypingComplete(field.key);\n }\n }, typewriter.delayMs ?? 30);\n\n return () => clearInterval(interval);\n }, [status, field.prompt, field.key, typewriter, onTypingComplete]);\n\n // Focus input when active\n useEffect(() => {\n if (status === \"active\" || status === \"editing\") {\n setTimeout(() => {\n inputRef.current?.focus();\n }, 50); // slight delay for layout\n }\n }, [status]);\n\n const handleConfirm = useCallback(async () => {\n // Sync validation\n const syncResult = validateField(field, localValue);\n if (!syncResult.valid) {\n setErrorMsg(syncResult.error || \"Invalid input\");\n onError(field.key, syncResult.error || \"Invalid input\");\n return;\n }\n\n // Async validation\n if (hasAsyncValidation(field)) {\n setIsValidating(true);\n const asyncResult = await validateFieldAsync(field, localValue);\n setIsValidating(false);\n \n if (!asyncResult.valid) {\n setErrorMsg(asyncResult.error || \"Invalid input\");\n onError(field.key, asyncResult.error || \"Invalid input\");\n return;\n }\n }\n\n setErrorMsg(null);\n Keyboard.dismiss();\n onConfirm(field.key, localValue);\n }, [field, localValue, onError, onConfirm]);\n\n const textColor = theme?.colors?.text || (isDark ? \"#fff\" : \"#000\");\n const primaryColor = theme?.colors?.primary || \"#007bff\";\n\n const isConfirmed = status === \"confirmed\";\n const isActive = status === \"active\" || status === \"editing\";\n\n return (\n <Animated.View style={[styles.container, { opacity }]}>\n <View style={styles.promptRow}>\n <Text style={[styles.prompt, { color: textColor }]}>\n {status === \"typing\" ? typedPrompt : field.prompt}\n </Text>\n \n {isConfirmed && (\n <Text style={[styles.value, { color: primaryColor }]}>{localValue}</Text>\n )}\n \n {isConfirmed && editable && !locked && (\n <TouchableOpacity onPress={() => onEdit(field.key)} style={styles.editBtn}>\n <Text style={[styles.editBtnText, { color: primaryColor }]}>{editLabel}</Text>\n </TouchableOpacity>\n )}\n </View>\n\n {isActive && (\n <View style={styles.inputRow}>\n <TextInput\n ref={inputRef}\n style={[\n styles.input,\n { color: textColor, borderBottomColor: isValidating ? \"#ccc\" : primaryColor }\n ]}\n value={localValue}\n onChangeText={(text) => {\n setLocalValue(text);\n onChange(field.key, text);\n if (errorMsg) setErrorMsg(null);\n }}\n onFocus={() => onFocus(field.key)}\n onBlur={() => onBlur(field.key, localValue)}\n onSubmitEditing={handleConfirm}\n keyboardType={field.type === \"email\" ? \"email-address\" : \"default\"}\n secureTextEntry={field.type === \"password\"}\n returnKeyType=\"next\"\n editable={!isValidating}\n />\n </View>\n )}\n \n <ErrorMessage message={errorMsg} />\n </Animated.View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: {\n marginVertical: 12,\n },\n promptRow: {\n flexDirection: \"row\",\n alignItems: \"center\",\n flexWrap: \"wrap\",\n },\n prompt: {\n fontSize: 18,\n marginRight: 8,\n },\n value: {\n fontSize: 18,\n fontWeight: \"600\",\n marginRight: 8,\n },\n editBtn: {\n marginLeft: 8,\n paddingHorizontal: 8,\n paddingVertical: 4,\n borderRadius: 4,\n backgroundColor: \"rgba(0,0,0,0.05)\",\n },\n editBtnText: {\n fontSize: 12,\n fontWeight: \"bold\",\n },\n inputRow: {\n marginTop: 8,\n },\n input: {\n fontSize: 18,\n paddingVertical: 8,\n borderBottomWidth: 2,\n }\n});\n","import React, { createContext, useContext, useState, useCallback } from \"react\";\nimport { View, Text, StyleSheet, Animated } from \"react-native\";\n\nexport interface ToastContextValue {\n showToast: (message: string, type?: \"error\" | \"success\" | \"info\") => void;\n}\n\nconst ToastContext = createContext<ToastContextValue>({\n showToast: () => {},\n});\n\nexport const useToast = () => useContext(ToastContext);\n\nexport const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n const [toast, setToast] = useState<{ message: string; type: \"error\" | \"success\" | \"info\" } | null>(null);\n\n const showToast = useCallback((message: string, type: \"error\" | \"success\" | \"info\" = \"info\") => {\n setToast({ message, type });\n setTimeout(() => setToast(null), 3000);\n }, []);\n\n return (\n <ToastContext.Provider value={{ showToast }}>\n <View style={styles.container}>\n {children}\n {toast && (\n <View style={[styles.toast, toast.type === \"error\" ? styles.toastError : styles.toastSuccess]}>\n <Text style={styles.toastText}>{toast.message}</Text>\n </View>\n )}\n </View>\n </ToastContext.Provider>\n );\n};\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n },\n toast: {\n position: \"absolute\",\n bottom: 40,\n left: 20,\n right: 20,\n padding: 16,\n borderRadius: 8,\n backgroundColor: \"#333\",\n alignItems: \"center\",\n },\n toastError: {\n backgroundColor: \"#d32f2f\",\n },\n toastSuccess: {\n backgroundColor: \"#2e7d32\",\n },\n toastText: {\n color: \"#fff\",\n fontSize: 14,\n },\n});\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { Animated, View, Text, TouchableOpacity, StyleSheet } from \"react-native\";\nimport type { NarrativeWelcome, NarrativeTypewriter } from \"@viveksinghind/narrative-form-core\";\nimport { useTheme } from \"./ThemeProvider\";\n\nexport interface WelcomeScreenProps {\n welcome: NarrativeWelcome;\n typewriter: NarrativeTypewriter;\n onStart: () => void;\n}\n\nexport const WelcomeScreen: React.FC<WelcomeScreenProps> = ({ welcome, typewriter, onStart }) => {\n const { theme, isDark } = useTheme();\n const opacity = useRef(new Animated.Value(0)).current;\n const [typedTitle, setTypedTitle] = useState(\"\");\n \n useEffect(() => {\n Animated.timing(opacity, {\n toValue: 1,\n duration: 500,\n useNativeDriver: true,\n }).start();\n }, [opacity]);\n\n useEffect(() => {\n if (!typewriter.enabled) {\n setTypedTitle(welcome.title);\n return;\n }\n\n let i = 0;\n const interval = setInterval(() => {\n setTypedTitle(welcome.title.slice(0, i + 1));\n i++;\n if (i >= welcome.title.length) {\n clearInterval(interval);\n }\n }, typewriter.delayMs ?? 30);\n\n return () => clearInterval(interval);\n }, [welcome.title, typewriter]);\n\n const textColor = theme?.colors?.text || (isDark ? \"#fff\" : \"#000\");\n const primaryColor = theme?.colors?.primary || \"#007bff\";\n\n return (\n <Animated.View style={[styles.container, { opacity }]}>\n <Text style={[styles.title, { color: textColor }]}>{typedTitle}</Text>\n {welcome.subtitle && (\n <Text style={[styles.subtitle, { color: textColor, opacity: 0.7 }]}>{welcome.subtitle}</Text>\n )}\n <TouchableOpacity \n style={[styles.button, { backgroundColor: primaryColor }]} \n onPress={onStart}\n accessibilityRole=\"button\"\n >\n <Text style={styles.buttonText}>{welcome.startLabel || \"Start\"}</Text>\n </TouchableOpacity>\n </Animated.View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n justifyContent: \"center\",\n alignItems: \"flex-start\",\n padding: 20,\n },\n title: {\n fontSize: 28,\n fontWeight: \"bold\",\n marginBottom: 8,\n },\n subtitle: {\n fontSize: 16,\n marginBottom: 24,\n },\n button: {\n paddingHorizontal: 24,\n paddingVertical: 12,\n borderRadius: 8,\n },\n buttonText: {\n color: \"#fff\",\n fontSize: 16,\n fontWeight: \"600\",\n }\n});\n","import React, { useEffect, useRef } from \"react\";\nimport { Animated, View, Text, StyleSheet } from \"react-native\";\nimport type { NarrativeDone, NarrativeFieldValues, NarrativeMeta, NarrativeTypewriter } from \"@viveksinghind/narrative-form-core\";\nimport { useTheme } from \"./ThemeProvider\";\n\nexport interface DoneScreenProps {\n done: NarrativeDone;\n values: NarrativeFieldValues;\n meta: NarrativeMeta;\n typewriter: NarrativeTypewriter;\n}\n\nexport const DoneScreen: React.FC<DoneScreenProps> = ({ done, values, meta }) => {\n const { theme, isDark } = useTheme();\n const opacity = useRef(new Animated.Value(0)).current;\n\n useEffect(() => {\n Animated.timing(opacity, {\n toValue: 1,\n duration: 500,\n useNativeDriver: true,\n }).start();\n }, [opacity]);\n\n const textColor = theme?.colors?.text || (isDark ? \"#fff\" : \"#000\");\n\n return (\n <Animated.View style={[styles.container, { opacity }]}>\n <Text style={[styles.title, { color: textColor }]}>{done.title}</Text>\n {done.subtitle && (\n <Text style={[styles.subtitle, { color: textColor, opacity: 0.7 }]}>{done.subtitle}</Text>\n )}\n </Animated.View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: {\n padding: 20,\n marginTop: 20,\n },\n title: {\n fontSize: 24,\n fontWeight: \"bold\",\n marginBottom: 8,\n },\n subtitle: {\n fontSize: 16,\n }\n});\n","import React, { useCallback, useEffect, useRef, useState, useMemo } from \"react\";\nimport { View, StyleSheet, ScrollView } from \"react-native\";\nimport type {\n NarrativeField,\n NarrativeTheme,\n NarrativeTypewriter,\n NarrativeWelcome,\n NarrativeDone,\n NarrativeCallbacks,\n NarrativeFieldValues,\n NarrativeMeta,\n NarrativeRefHandle,\n NarrativeI18n,\n NarrativeFormConfig,\n NarrativeCrossFieldValidator,\n} from \"@viveksinghind/narrative-form-core\";\nimport { mergeStrings } from \"@viveksinghind/narrative-form-core\";\nimport { useFormState } from \"../hooks/useFormState\";\nimport { useDynamicForm } from \"../hooks/useDynamicForm\";\nimport { Line } from \"./Line\";\nimport { ToastProvider } from \"./ToastProvider\";\nimport { ThemeProvider, useTheme } from \"./ThemeProvider\";\nimport { WelcomeScreen } from \"./WelcomeScreen\";\nimport { DoneScreen } from \"./DoneScreen\";\n\nexport interface NarrativeFormProps {\n fields?: NarrativeField[];\n fieldsUrl?: string;\n fieldsUrlHeaders?: Record<string, string>;\n formConfig?: NarrativeFormConfig;\n theme?: NarrativeTheme;\n typewriter?: NarrativeTypewriter;\n welcome?: NarrativeWelcome;\n done?: NarrativeDone;\n editable?: boolean;\n editLabel?: string;\n callbacks?: NarrativeCallbacks;\n formRef?: React.Ref<NarrativeRefHandle>;\n defaultValues?: NarrativeFieldValues;\n values?: NarrativeFieldValues;\n strings?: Partial<NarrativeI18n>;\n locale?: string;\n direction?: \"ltr\" | \"rtl\";\n crossFieldValidators?: NarrativeCrossFieldValidator[];\n reducedMotion?: boolean;\n}\n\nconst NarrativeFormInner: React.FC<NarrativeFormProps> = (props) => {\n const { isDark } = useTheme();\n const i18n = useMemo(() => mergeStrings(props.strings), [props.strings]);\n\n const { config: dynamicConfig, loading, error, retry } =\n useDynamicForm({ fieldsUrl: props.fieldsUrl, fieldsUrlHeaders: props.fieldsUrlHeaders });\n\n const resolvedConfig = useMemo(() => {\n if (props.fields) return { fields: props.fields };\n if (props.formConfig) return props.formConfig;\n if (dynamicConfig) return dynamicConfig;\n return null;\n }, [props.fields, props.formConfig, dynamicConfig]);\n\n const fields = resolvedConfig?.fields ?? [];\n const welcome = props.welcome ?? (resolvedConfig && \"welcome\" in resolvedConfig ? (resolvedConfig as any).welcome : undefined);\n const done = props.done ?? (resolvedConfig && \"done\" in resolvedConfig ? (resolvedConfig as any).done : undefined);\n\n const effectiveTypewriter = useMemo<NarrativeTypewriter>(() => ({\n ...props.typewriter,\n enabled: props.reducedMotion ? false : (props.typewriter?.enabled ?? true),\n }), [props.typewriter, props.reducedMotion]);\n\n const {\n snapshot,\n startTyping,\n activateField,\n confirmField,\n editField,\n reconfirmField,\n next,\n focusField,\n reset,\n getValues,\n getMeta,\n } = useFormState(fields);\n\n const showWelcome = welcome?.show !== false && welcome !== undefined;\n const [welcomeDismissed, setWelcomeDismissed] = useState(!showWelcome);\n \n const hasStartedRef = useRef(false);\n\n useEffect(() => {\n if (!welcomeDismissed || hasStartedRef.current || fields.length === 0) return;\n hasStartedRef.current = true;\n const firstField = fields.find((f) => snapshot.statuses[f.key] !== \"confirmed\");\n if (firstField) {\n startTyping(firstField.key);\n }\n }, [welcomeDismissed, fields, startTyping, snapshot.statuses]);\n\n const handleConfirm = useCallback((key: string, value: string) => {\n const status = snapshot.statuses[key];\n if (status === \"editing\") {\n reconfirmField(key, value);\n } else {\n confirmField(key, value);\n }\n props.callbacks?.onFieldComplete?.(key, value, 0);\n\n const currentIndex = fields.findIndex((f) => f.key === key);\n for (let i = currentIndex + 1; i < fields.length; i++) {\n const nextField = fields[i];\n if (!nextField || snapshot.statuses[nextField.key] === \"confirmed\") continue;\n startTyping(nextField.key);\n break;\n }\n }, [snapshot, fields, confirmField, reconfirmField, startTyping, props.callbacks]);\n\n const visibleFields = useMemo(() => {\n return fields.filter((field) => {\n const status = snapshot.statuses[field.key];\n return status === \"typing\" || status === \"active\" || status === \"confirmed\" || status === \"editing\";\n });\n }, [fields, snapshot.statuses]);\n\n const scrollViewRef = useRef<ScrollView>(null);\n\n useEffect(() => {\n if (visibleFields.length > 0) {\n setTimeout(() => {\n scrollViewRef.current?.scrollToEnd({ animated: true });\n }, 100);\n }\n }, [visibleFields.length]);\n\n return (\n <ScrollView \n ref={scrollViewRef}\n style={[styles.container, isDark ? styles.darkContainer : styles.lightContainer]}\n contentContainerStyle={styles.content}\n keyboardShouldPersistTaps=\"handled\"\n >\n {!welcomeDismissed && welcome && (\n <WelcomeScreen\n welcome={welcome}\n typewriter={effectiveTypewriter}\n onStart={() => setWelcomeDismissed(true)}\n />\n )}\n\n {welcomeDismissed && (\n <View style={styles.formBody}>\n {visibleFields.map((field) => (\n <Line\n key={field.key}\n field={field}\n status={snapshot.statuses[field.key] ?? \"idle\"}\n value={props.values?.[field.key] ?? snapshot.values[field.key]}\n allValues={snapshot.values}\n typewriter={effectiveTypewriter}\n editable={props.editable ?? true}\n locked={false}\n editLabel={props.editLabel ?? i18n.editLabel}\n onTypingComplete={(k) => activateField(k)}\n onConfirm={handleConfirm}\n onEdit={(k) => {\n editField(k);\n props.callbacks?.onEdit?.(k);\n }}\n onError={(k, err) => props.callbacks?.onError?.(k, err)}\n onChange={(k, v) => props.callbacks?.onChange?.(k, v)}\n onFocus={(k) => props.callbacks?.onFieldFocus?.(k)}\n onBlur={(k, v) => props.callbacks?.onFieldBlur?.(k, v)}\n />\n ))}\n </View>\n )}\n\n {snapshot.isComplete && done && (\n <DoneScreen\n done={done}\n values={snapshot.values}\n meta={getMeta()}\n typewriter={effectiveTypewriter}\n />\n )}\n </ScrollView>\n );\n};\n\nexport const NarrativeForm: React.FC<NarrativeFormProps> = (props) => {\n return (\n <ThemeProvider theme={props.theme}>\n <ToastProvider>\n <NarrativeFormInner {...props} />\n </ToastProvider>\n </ThemeProvider>\n );\n};\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n },\n lightContainer: {\n backgroundColor: \"#ffffff\",\n },\n darkContainer: {\n backgroundColor: \"#121212\",\n },\n content: {\n padding: 20,\n flexGrow: 1,\n },\n formBody: {\n flex: 1,\n }\n});\n"]}