@viveksinghind/narrative-form-native 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/dist/components/DoneScreen.d.ts +10 -0
  4. package/dist/components/DoneScreen.d.ts.map +1 -0
  5. package/dist/components/DoneScreen.js +33 -0
  6. package/dist/components/DoneScreen.js.map +1 -0
  7. package/dist/components/ErrorMessage.d.ts +8 -0
  8. package/dist/components/ErrorMessage.d.ts.map +1 -0
  9. package/dist/components/ErrorMessage.js +40 -0
  10. package/dist/components/ErrorMessage.js.map +1 -0
  11. package/dist/components/Line.d.ts +21 -0
  12. package/dist/components/Line.d.ts.map +1 -0
  13. package/dist/components/Line.js +130 -0
  14. package/dist/components/Line.js.map +1 -0
  15. package/dist/components/NarrativeForm.d.ts +25 -0
  16. package/dist/components/NarrativeForm.d.ts.map +1 -0
  17. package/dist/components/NarrativeForm.js +113 -0
  18. package/dist/components/NarrativeForm.js.map +1 -0
  19. package/dist/components/ThemeProvider.d.ts +13 -0
  20. package/dist/components/ThemeProvider.d.ts.map +1 -0
  21. package/dist/components/ThemeProvider.js +19 -0
  22. package/dist/components/ThemeProvider.js.map +1 -0
  23. package/dist/components/ToastProvider.d.ts +9 -0
  24. package/dist/components/ToastProvider.d.ts.map +1 -0
  25. package/dist/components/ToastProvider.js +41 -0
  26. package/dist/components/ToastProvider.js.map +1 -0
  27. package/dist/components/WelcomeScreen.d.ts +9 -0
  28. package/dist/components/WelcomeScreen.d.ts.map +1 -0
  29. package/dist/components/WelcomeScreen.js +63 -0
  30. package/dist/components/WelcomeScreen.js.map +1 -0
  31. package/dist/hooks/useDynamicForm.d.ts +18 -0
  32. package/dist/hooks/useDynamicForm.d.ts.map +1 -0
  33. package/dist/hooks/useDynamicForm.js +50 -0
  34. package/dist/hooks/useDynamicForm.js.map +1 -0
  35. package/dist/hooks/useFormState.d.ts +43 -0
  36. package/dist/hooks/useFormState.d.ts.map +1 -0
  37. package/dist/hooks/useFormState.js +57 -0
  38. package/dist/hooks/useFormState.js.map +1 -0
  39. package/dist/hooks/useTypewriter.d.ts +46 -0
  40. package/dist/hooks/useTypewriter.d.ts.map +1 -0
  41. package/dist/hooks/useTypewriter.js +94 -0
  42. package/dist/hooks/useTypewriter.js.map +1 -0
  43. package/dist/index.d.ts +10 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +10 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/index.mjs +621 -0
  48. package/dist/index.mjs.map +1 -0
  49. package/package.json +53 -0
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ import type { NarrativeWelcome, NarrativeTypewriter } from "@viveksinghind/narrative-form-core";
3
+ export interface WelcomeScreenProps {
4
+ welcome: NarrativeWelcome;
5
+ typewriter: NarrativeTypewriter;
6
+ onStart: () => void;
7
+ }
8
+ export declare const WelcomeScreen: React.FC<WelcomeScreenProps>;
9
+ //# sourceMappingURL=WelcomeScreen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WelcomeScreen.d.ts","sourceRoot":"","sources":["../../src/components/WelcomeScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAE3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAGhG,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,UAAU,EAAE,mBAAmB,CAAC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAiDtD,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { Animated, Text, TouchableOpacity, StyleSheet } from "react-native";
4
+ import { useTheme } from "./ThemeProvider";
5
+ export const WelcomeScreen = ({ welcome, typewriter, onStart }) => {
6
+ const { theme, isDark } = useTheme();
7
+ const opacity = useRef(new Animated.Value(0)).current;
8
+ const [typedTitle, setTypedTitle] = useState("");
9
+ useEffect(() => {
10
+ Animated.timing(opacity, {
11
+ toValue: 1,
12
+ duration: 500,
13
+ useNativeDriver: true,
14
+ }).start();
15
+ }, [opacity]);
16
+ useEffect(() => {
17
+ var _a;
18
+ if (!typewriter.enabled) {
19
+ setTypedTitle(welcome.heading || "");
20
+ return;
21
+ }
22
+ let i = 0;
23
+ const interval = setInterval(() => {
24
+ setTypedTitle((welcome.heading || "").slice(0, i + 1));
25
+ i++;
26
+ if (i >= (welcome.heading || "").length) {
27
+ clearInterval(interval);
28
+ }
29
+ }, (_a = typewriter.speed) !== null && _a !== void 0 ? _a : 30);
30
+ return () => clearInterval(interval);
31
+ }, [welcome.heading, typewriter]);
32
+ const textColor = (theme === null || theme === void 0 ? void 0 : theme.textColor) || (isDark ? "#fff" : "#000");
33
+ const primaryColor = (theme === null || theme === void 0 ? void 0 : theme.buttonBackground) || "#007bff";
34
+ return (_jsxs(Animated.View, { style: [styles.container, { opacity }], children: [_jsx(Text, { style: [styles.title, { color: textColor }], children: typedTitle }), welcome.subtext && (_jsx(Text, { style: [styles.subtitle, { color: textColor, opacity: 0.7 }], children: welcome.subtext })), _jsx(TouchableOpacity, { style: [styles.button, { backgroundColor: primaryColor }], onPress: onStart, accessibilityRole: "button", children: _jsx(Text, { style: styles.buttonText, children: welcome.ctaLabel || "Start" }) })] }));
35
+ };
36
+ const styles = StyleSheet.create({
37
+ container: {
38
+ flex: 1,
39
+ justifyContent: "center",
40
+ alignItems: "flex-start",
41
+ padding: 20,
42
+ },
43
+ title: {
44
+ fontSize: 28,
45
+ fontWeight: "bold",
46
+ marginBottom: 8,
47
+ },
48
+ subtitle: {
49
+ fontSize: 16,
50
+ marginBottom: 24,
51
+ },
52
+ button: {
53
+ paddingHorizontal: 24,
54
+ paddingVertical: 12,
55
+ borderRadius: 8,
56
+ },
57
+ buttonText: {
58
+ color: "#fff",
59
+ fontSize: 16,
60
+ fontWeight: "600",
61
+ }
62
+ });
63
+ //# sourceMappingURL=WelcomeScreen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WelcomeScreen.js","sourceRoot":"","sources":["../../src/components/WelcomeScreen.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { NarrativeFormConfig } from "@viveksinghind/narrative-form-core";
2
+ export interface UseDynamicFormProps {
3
+ fieldsUrl?: string;
4
+ fieldsUrlHeaders?: Record<string, string>;
5
+ formConfig?: NarrativeFormConfig;
6
+ onFetchError?: (error: Error) => void;
7
+ }
8
+ export interface UseDynamicFormResult {
9
+ config: NarrativeFormConfig | null;
10
+ loading: boolean;
11
+ error: Error | null;
12
+ retry: () => void;
13
+ }
14
+ /**
15
+ * Hook to manage fetching and parsing server-driven form configuration.
16
+ */
17
+ export declare function useDynamicForm({ fieldsUrl, fieldsUrlHeaders, formConfig, onFetchError, }: UseDynamicFormProps): UseDynamicFormResult;
18
+ //# sourceMappingURL=useDynamicForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDynamicForm.d.ts","sourceRoot":"","sources":["../../src/hooks/useDynamicForm.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAG9E,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,YAAY,GACb,EAAE,mBAAmB,GAAG,oBAAoB,CAkD5C"}
@@ -0,0 +1,50 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+ import { fetchFormConfig } from "@viveksinghind/narrative-form-core";
3
+ /**
4
+ * Hook to manage fetching and parsing server-driven form configuration.
5
+ */
6
+ export function useDynamicForm({ fieldsUrl, fieldsUrlHeaders, formConfig, onFetchError, }) {
7
+ const [config, setConfig] = useState(formConfig !== null && formConfig !== void 0 ? formConfig : null);
8
+ const [loading, setLoading] = useState(!!fieldsUrl && !formConfig);
9
+ const [error, setError] = useState(null);
10
+ const [retryCount, setRetryCount] = useState(0);
11
+ useEffect(() => {
12
+ // If a complete config is passed via props, use it immediately
13
+ if (formConfig) {
14
+ setConfig(formConfig);
15
+ setLoading(false);
16
+ setError(null);
17
+ return;
18
+ }
19
+ if (!fieldsUrl) {
20
+ return;
21
+ }
22
+ let isMounted = true;
23
+ setLoading(true);
24
+ setError(null);
25
+ fetchFormConfig(fieldsUrl, { headers: fieldsUrlHeaders })
26
+ .then((data) => {
27
+ if (isMounted) {
28
+ setConfig(data);
29
+ setLoading(false);
30
+ }
31
+ })
32
+ .catch((err) => {
33
+ if (isMounted) {
34
+ setError(err);
35
+ setLoading(false);
36
+ onFetchError === null || onFetchError === void 0 ? void 0 : onFetchError(err);
37
+ }
38
+ });
39
+ return () => {
40
+ isMounted = false;
41
+ };
42
+ }, [fieldsUrl, fieldsUrlHeaders, formConfig, retryCount, onFetchError]);
43
+ const retry = useCallback(() => {
44
+ if (fieldsUrl && !formConfig) {
45
+ setRetryCount((c) => c + 1);
46
+ }
47
+ }, [fieldsUrl, formConfig]);
48
+ return { config, loading, error, retry };
49
+ }
50
+ //# sourceMappingURL=useDynamicForm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDynamicForm.js","sourceRoot":"","sources":["../../src/hooks/useDynamicForm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAoB,MAAM,oCAAoC,CAAC;AAgBvF;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,EAC7B,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,YAAY,GACQ;IACpB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAA6B,UAAU,aAAV,UAAU,cAAV,UAAU,GAAI,IAAI,CAAC,CAAC;IACrF,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAU,CAAC,CAAC,SAAS,IAAI,CAAC,UAAU,CAAC,CAAC;IAC5E,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IACvD,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEhD,SAAS,CAAC,GAAG,EAAE;QACb,+DAA+D;QAC/D,IAAI,UAAU,EAAE,CAAC;YACf,SAAS,CAAC,UAAU,CAAC,CAAC;YACtB,UAAU,CAAC,KAAK,CAAC,CAAC;YAClB,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,OAAO;QACT,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,IAAI,SAAS,GAAG,IAAI,CAAC;QACrB,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEf,eAAe,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;aACtD,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACb,IAAI,SAAS,EAAE,CAAC;gBACd,SAAS,CAAC,IAAI,CAAC,CAAC;gBAChB,UAAU,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;YACpB,IAAI,SAAS,EAAE,CAAC;gBACd,QAAQ,CAAC,GAAG,CAAC,CAAC;gBACd,UAAU,CAAC,KAAK,CAAC,CAAC;gBAClB,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAG,GAAG,CAAC,CAAC;YACtB,CAAC;QACH,CAAC,CAAC,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,KAAK,CAAC;QACpB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,gBAAgB,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;IAExE,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,IAAI,SAAS,IAAI,CAAC,UAAU,EAAE,CAAC;YAC7B,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;IAE5B,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * React hook wrapping the core FormStateEngine.
3
+ *
4
+ * @remarks
5
+ * Bridges the framework-agnostic FormStateEngine with React's
6
+ * state management. Each state mutation in the engine triggers
7
+ * a React re-render via `useSyncExternalStore`-like pattern.
8
+ */
9
+ import type { NarrativeField, NarrativeFieldValues, NarrativeMeta } from "@viveksinghind/narrative-form-core";
10
+ import type { FormStateSnapshot } from "@viveksinghind/narrative-form-core";
11
+ /** Return value of the useFormState hook. */
12
+ export interface UseFormStateResult {
13
+ /** Current snapshot of the form state. */
14
+ snapshot: FormStateSnapshot;
15
+ /** Start the typewriter animation for a field. */
16
+ startTyping: (key: string) => void;
17
+ /** Mark a field as active (typewriter done, input visible). */
18
+ activateField: (key: string) => void;
19
+ /** Confirm a field with a value. */
20
+ confirmField: (key: string, value: string | string[]) => void;
21
+ /** Reopen a confirmed field for editing. */
22
+ editField: (key: string) => void;
23
+ /** Re-confirm a field after editing. */
24
+ reconfirmField: (key: string, value: string | string[]) => void;
25
+ /** Move to the next field. */
26
+ next: () => void;
27
+ /** Focus a specific field by key. */
28
+ focusField: (key: string) => void;
29
+ /** Reset all form state. */
30
+ reset: () => void;
31
+ /** Get all confirmed values. */
32
+ getValues: () => NarrativeFieldValues;
33
+ /** Get analytics metadata. */
34
+ getMeta: (formId?: string, formVersion?: number) => NarrativeMeta;
35
+ }
36
+ /**
37
+ * React hook that manages the narrative form state.
38
+ *
39
+ * @param fields - Ordered array of field configurations
40
+ * @returns Form state and mutation methods
41
+ */
42
+ export declare function useFormState(fields: readonly NarrativeField[]): UseFormStateResult;
43
+ //# sourceMappingURL=useFormState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFormState.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormState.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAE9G,OAAO,KAAK,EAAe,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAEzF,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IACjC,0CAA0C;IAC1C,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,kDAAkD;IAClD,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,+DAA+D;IAC/D,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,oCAAoC;IACpC,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;IAC9D,4CAA4C;IAC5C,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,wCAAwC;IACxC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;IAChE,8BAA8B;IAC9B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,qCAAqC;IACrC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,4BAA4B;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,gCAAgC;IAChC,SAAS,EAAE,MAAM,oBAAoB,CAAC;IACtC,8BAA8B;IAC9B,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,aAAa,CAAC;CACnE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,GAAG,kBAAkB,CAwDlF"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * React hook wrapping the core FormStateEngine.
3
+ *
4
+ * @remarks
5
+ * Bridges the framework-agnostic FormStateEngine with React's
6
+ * state management. Each state mutation in the engine triggers
7
+ * a React re-render via `useSyncExternalStore`-like pattern.
8
+ */
9
+ import { useState, useRef, useCallback, useMemo } from "react";
10
+ import { FormStateEngine } from "@viveksinghind/narrative-form-core";
11
+ /**
12
+ * React hook that manages the narrative form state.
13
+ *
14
+ * @param fields - Ordered array of field configurations
15
+ * @returns Form state and mutation methods
16
+ */
17
+ export function useFormState(fields) {
18
+ // Use a counter to force re-renders when the engine mutates
19
+ const [, setTick] = useState(0);
20
+ const engineRef = useRef(null);
21
+ // Lazily initialise the engine
22
+ if (engineRef.current === null) {
23
+ engineRef.current = new FormStateEngine(fields, () => {
24
+ setTick((t) => t + 1);
25
+ });
26
+ }
27
+ const engine = engineRef.current;
28
+ // Stable method references
29
+ const startTyping = useCallback((key) => engine.startTyping(key), [engine]);
30
+ const activateField = useCallback((key) => engine.activateField(key), [engine]);
31
+ const confirmField = useCallback((key, value) => engine.confirmField(key, value), [engine]);
32
+ const editField = useCallback((key) => engine.editField(key), [engine]);
33
+ const reconfirmField = useCallback((key, value) => engine.reconfirmField(key, value), [engine]);
34
+ const next = useCallback(() => engine.next(), [engine]);
35
+ const focusField = useCallback((key) => engine.focusField(key), [engine]);
36
+ const reset = useCallback(() => engine.reset(), [engine]);
37
+ const getValues = useCallback(() => engine.getValues(), [engine]);
38
+ const getMeta = useCallback((formId, formVersion) => engine.getMeta(formId, formVersion), [engine]);
39
+ const snapshot = engine.getSnapshot();
40
+ return useMemo(() => ({
41
+ snapshot,
42
+ startTyping,
43
+ activateField,
44
+ confirmField,
45
+ editField,
46
+ reconfirmField,
47
+ next,
48
+ focusField,
49
+ reset,
50
+ getValues,
51
+ getMeta,
52
+ }),
53
+ // snapshot changes every tick, which is what we want
54
+ // eslint-disable-next-line react-hooks/exhaustive-deps
55
+ [snapshot]);
56
+ }
57
+ //# sourceMappingURL=useFormState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFormState.js","sourceRoot":"","sources":["../../src/hooks/useFormState.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Core typewriter animation hook for narrative-form.
3
+ *
4
+ * @remarks
5
+ * Animates a string character by character to create the "letter being written"
6
+ * effect. Cleans up the interval on unmount to prevent memory leaks.
7
+ * Respects `prefers-reduced-motion` — skips animation entirely if set.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * const { displayedText, isTyping, isComplete } = useTypewriter({
12
+ * text: "My name is",
13
+ * speed: 38,
14
+ * });
15
+ * ```
16
+ */
17
+ /** Configuration options for the useTypewriter hook. */
18
+ export interface UseTypewriterOptions {
19
+ /** The full text to type out. */
20
+ text: string;
21
+ /** Milliseconds per character. Default: 38 */
22
+ speed?: number;
23
+ /** Whether animation is enabled. Default: true */
24
+ enabled?: boolean;
25
+ /** Milliseconds to pause after typing completes before signalling done. Default: 100 */
26
+ pauseAfter?: number;
27
+ /** Callback fired when typing is fully complete (after pause). */
28
+ onComplete?: () => void;
29
+ }
30
+ /** Return value of the useTypewriter hook. */
31
+ export interface UseTypewriterResult {
32
+ /** The currently visible portion of the text. */
33
+ displayedText: string;
34
+ /** Whether the typewriter is actively typing characters. */
35
+ isTyping: boolean;
36
+ /** Whether typing is fully complete (including the post-typing pause). */
37
+ isComplete: boolean;
38
+ }
39
+ /**
40
+ * React hook that animates text character by character.
41
+ *
42
+ * @param options - Typewriter configuration
43
+ * @returns Object with displayedText, isTyping, and isComplete
44
+ */
45
+ export declare function useTypewriter(options: UseTypewriterOptions): UseTypewriterResult;
46
+ //# sourceMappingURL=useTypewriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTypewriter.d.ts","sourceRoot":"","sources":["../../src/hooks/useTypewriter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,wDAAwD;AACxD,MAAM,WAAW,oBAAoB;IACnC,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,aAAa,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,UAAU,EAAE,OAAO,CAAC;CACrB;AAWD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CAoEhF"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Core typewriter animation hook for narrative-form.
3
+ *
4
+ * @remarks
5
+ * Animates a string character by character to create the "letter being written"
6
+ * effect. Cleans up the interval on unmount to prevent memory leaks.
7
+ * Respects `prefers-reduced-motion` — skips animation entirely if set.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * const { displayedText, isTyping, isComplete } = useTypewriter({
12
+ * text: "My name is",
13
+ * speed: 38,
14
+ * });
15
+ * ```
16
+ */
17
+ import { useState, useEffect, useRef, useCallback } from "react";
18
+ /**
19
+ * Check if the user prefers reduced motion.
20
+ * Guarded for SSR — returns false if `window` is not available.
21
+ */
22
+ function prefersReducedMotion() {
23
+ if (typeof window === "undefined")
24
+ return false;
25
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
26
+ }
27
+ /**
28
+ * React hook that animates text character by character.
29
+ *
30
+ * @param options - Typewriter configuration
31
+ * @returns Object with displayedText, isTyping, and isComplete
32
+ */
33
+ export function useTypewriter(options) {
34
+ const { text, speed = 38, enabled = true, pauseAfter = 100, onComplete } = options;
35
+ const [charIndex, setCharIndex] = useState(0);
36
+ const [isComplete, setIsComplete] = useState(false);
37
+ const intervalRef = useRef(null);
38
+ const pauseTimeoutRef = useRef(null);
39
+ const onCompleteRef = useRef(onComplete);
40
+ // Keep onComplete ref fresh without triggering effect re-runs
41
+ onCompleteRef.current = onComplete;
42
+ // Clean up helper
43
+ const cleanup = useCallback(() => {
44
+ if (intervalRef.current !== null) {
45
+ clearInterval(intervalRef.current);
46
+ intervalRef.current = null;
47
+ }
48
+ if (pauseTimeoutRef.current !== null) {
49
+ clearTimeout(pauseTimeoutRef.current);
50
+ pauseTimeoutRef.current = null;
51
+ }
52
+ }, []);
53
+ useEffect(() => {
54
+ var _a;
55
+ // If animation is disabled or user prefers reduced motion, show everything instantly
56
+ if (!enabled || prefersReducedMotion() || text.length === 0) {
57
+ setCharIndex(text.length);
58
+ setIsComplete(true);
59
+ (_a = onCompleteRef.current) === null || _a === void 0 ? void 0 : _a.call(onCompleteRef);
60
+ return;
61
+ }
62
+ // Reset for new text
63
+ setCharIndex(0);
64
+ setIsComplete(false);
65
+ intervalRef.current = setInterval(() => {
66
+ setCharIndex((prev) => {
67
+ const next = prev + 1;
68
+ if (next >= text.length) {
69
+ // All characters typed — clear interval, start pause
70
+ if (intervalRef.current !== null) {
71
+ clearInterval(intervalRef.current);
72
+ intervalRef.current = null;
73
+ }
74
+ // Pause before signalling completion
75
+ pauseTimeoutRef.current = setTimeout(() => {
76
+ var _a;
77
+ setIsComplete(true);
78
+ (_a = onCompleteRef.current) === null || _a === void 0 ? void 0 : _a.call(onCompleteRef);
79
+ }, pauseAfter);
80
+ return text.length;
81
+ }
82
+ return next;
83
+ });
84
+ }, speed);
85
+ // Cleanup on unmount or text/speed/enabled change
86
+ return cleanup;
87
+ }, [text, speed, enabled, pauseAfter, cleanup]);
88
+ return {
89
+ displayedText: text.slice(0, charIndex),
90
+ isTyping: charIndex < text.length && !isComplete,
91
+ isComplete,
92
+ };
93
+ }
94
+ //# sourceMappingURL=useTypewriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTypewriter.js","sourceRoot":"","sources":["../../src/hooks/useTypewriter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export * from "./components/NarrativeForm";
2
+ export * from "./components/ThemeProvider";
3
+ export * from "./components/ToastProvider";
4
+ export * from "./components/WelcomeScreen";
5
+ export * from "./components/DoneScreen";
6
+ export * from "./components/Line";
7
+ export * from "./components/ErrorMessage";
8
+ export * from "./hooks/useFormState";
9
+ export * from "./hooks/useDynamicForm";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export * from "./components/NarrativeForm";
2
+ export * from "./components/ThemeProvider";
3
+ export * from "./components/ToastProvider";
4
+ export * from "./components/WelcomeScreen";
5
+ export * from "./components/DoneScreen";
6
+ export * from "./components/Line";
7
+ export * from "./components/ErrorMessage";
8
+ export * from "./hooks/useFormState";
9
+ export * from "./hooks/useDynamicForm";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC"}