rn-inputforge 0.5.0 → 0.5.1

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 (277) hide show
  1. package/README.md +236 -0
  2. package/lib/commonjs/a11y/audit.js +72 -0
  3. package/lib/commonjs/a11y/audit.js.map +1 -0
  4. package/lib/commonjs/a11y/index.js +13 -0
  5. package/lib/commonjs/a11y/index.js.map +1 -0
  6. package/lib/commonjs/autofill/index.js +25 -0
  7. package/lib/commonjs/autofill/index.js.map +1 -0
  8. package/lib/commonjs/autofill/profiles.js +199 -0
  9. package/lib/commonjs/autofill/profiles.js.map +1 -0
  10. package/lib/commonjs/components/FieldFlowA11yAudit/FieldFlowA11yAudit.js +99 -0
  11. package/lib/commonjs/components/FieldFlowA11yAudit/FieldFlowA11yAudit.js.map +1 -0
  12. package/lib/commonjs/components/FieldFlowA11yAudit/index.js +13 -0
  13. package/lib/commonjs/components/FieldFlowA11yAudit/index.js.map +1 -0
  14. package/lib/commonjs/components/FieldFlowAuthActions/FieldFlowAuthActions.js +130 -0
  15. package/lib/commonjs/components/FieldFlowAuthActions/FieldFlowAuthActions.js.map +1 -0
  16. package/lib/commonjs/components/FieldFlowAuthActions/index.js +13 -0
  17. package/lib/commonjs/components/FieldFlowAuthActions/index.js.map +1 -0
  18. package/lib/commonjs/components/FieldFlowCompleteness/FieldFlowCompleteness.js +100 -0
  19. package/lib/commonjs/components/FieldFlowCompleteness/FieldFlowCompleteness.js.map +1 -0
  20. package/lib/commonjs/components/FieldFlowCompleteness/index.js +13 -0
  21. package/lib/commonjs/components/FieldFlowCompleteness/index.js.map +1 -0
  22. package/lib/commonjs/components/FieldFlowFormHeader/FieldFlowFormHeader.js +102 -0
  23. package/lib/commonjs/components/FieldFlowFormHeader/FieldFlowFormHeader.js.map +1 -0
  24. package/lib/commonjs/components/FieldFlowFormHeader/index.js +13 -0
  25. package/lib/commonjs/components/FieldFlowFormHeader/index.js.map +1 -0
  26. package/lib/commonjs/components/FieldFlowInfoTip/FieldFlowInfoTip.js +121 -0
  27. package/lib/commonjs/components/FieldFlowInfoTip/FieldFlowInfoTip.js.map +1 -0
  28. package/lib/commonjs/components/FieldFlowInfoTip/index.js +13 -0
  29. package/lib/commonjs/components/FieldFlowInfoTip/index.js.map +1 -0
  30. package/lib/commonjs/components/FieldFlowInlineAlert/FieldFlowInlineAlert.js +142 -0
  31. package/lib/commonjs/components/FieldFlowInlineAlert/FieldFlowInlineAlert.js.map +1 -0
  32. package/lib/commonjs/components/FieldFlowInlineAlert/index.js +13 -0
  33. package/lib/commonjs/components/FieldFlowInlineAlert/index.js.map +1 -0
  34. package/lib/commonjs/components/FieldFlowInput/FieldFlowInput.js +44 -18
  35. package/lib/commonjs/components/FieldFlowInput/FieldFlowInput.js.map +1 -1
  36. package/lib/commonjs/components/FieldFlowInput/styles.js +49 -13
  37. package/lib/commonjs/components/FieldFlowInput/styles.js.map +1 -1
  38. package/lib/commonjs/components/FieldFlowKeyboardToolbar/FieldFlowKeyboardToolbar.js +137 -0
  39. package/lib/commonjs/components/FieldFlowKeyboardToolbar/FieldFlowKeyboardToolbar.js.map +1 -0
  40. package/lib/commonjs/components/FieldFlowKeyboardToolbar/index.js +19 -0
  41. package/lib/commonjs/components/FieldFlowKeyboardToolbar/index.js.map +1 -0
  42. package/lib/commonjs/components/FieldFlowSkeleton/FieldFlowSkeleton.js +101 -0
  43. package/lib/commonjs/components/FieldFlowSkeleton/FieldFlowSkeleton.js.map +1 -0
  44. package/lib/commonjs/components/FieldFlowSkeleton/index.js +13 -0
  45. package/lib/commonjs/components/FieldFlowSkeleton/index.js.map +1 -0
  46. package/lib/commonjs/components/KeyboardAwareFormWrapper/KeyboardAwareFormWrapper.js +6 -4
  47. package/lib/commonjs/components/KeyboardAwareFormWrapper/KeyboardAwareFormWrapper.js.map +1 -1
  48. package/lib/commonjs/hooks/index.js +21 -0
  49. package/lib/commonjs/hooks/index.js.map +1 -1
  50. package/lib/commonjs/hooks/useFieldFlowCompleteness.js +46 -0
  51. package/lib/commonjs/hooks/useFieldFlowCompleteness.js.map +1 -0
  52. package/lib/commonjs/hooks/useFieldFlowSubmitQueue.js +145 -0
  53. package/lib/commonjs/hooks/useFieldFlowSubmitQueue.js.map +1 -0
  54. package/lib/commonjs/hooks/useKeyboardManager.js +15 -0
  55. package/lib/commonjs/hooks/useKeyboardManager.js.map +1 -1
  56. package/lib/commonjs/hooks/useSmartPaste.js +27 -0
  57. package/lib/commonjs/hooks/useSmartPaste.js.map +1 -0
  58. package/lib/commonjs/index.js +144 -0
  59. package/lib/commonjs/index.js.map +1 -1
  60. package/lib/commonjs/paste/index.js +19 -0
  61. package/lib/commonjs/paste/index.js.map +1 -0
  62. package/lib/commonjs/paste/smartPaste.js +113 -0
  63. package/lib/commonjs/paste/smartPaste.js.map +1 -0
  64. package/lib/commonjs/schema/FieldFlowSchemaForm.js +219 -0
  65. package/lib/commonjs/schema/FieldFlowSchemaForm.js.map +1 -0
  66. package/lib/commonjs/schema/index.js +13 -0
  67. package/lib/commonjs/schema/index.js.map +1 -0
  68. package/lib/commonjs/schema/types.js +6 -0
  69. package/lib/commonjs/schema/types.js.map +1 -0
  70. package/lib/commonjs/theme/ThemeProvider.js +65 -4
  71. package/lib/commonjs/theme/ThemeProvider.js.map +1 -1
  72. package/lib/commonjs/theme/appearance.js +93 -0
  73. package/lib/commonjs/theme/appearance.js.map +1 -0
  74. package/lib/commonjs/theme/defaultTheme.js +17 -2
  75. package/lib/commonjs/theme/defaultTheme.js.map +1 -1
  76. package/lib/commonjs/theme/index.js +19 -0
  77. package/lib/commonjs/theme/index.js.map +1 -1
  78. package/lib/commonjs/types/globals.d.js +2 -0
  79. package/lib/commonjs/types/globals.d.js.map +1 -0
  80. package/lib/module/a11y/audit.js +68 -0
  81. package/lib/module/a11y/audit.js.map +1 -0
  82. package/lib/module/a11y/index.js +4 -0
  83. package/lib/module/a11y/index.js.map +1 -0
  84. package/lib/module/autofill/index.js +4 -0
  85. package/lib/module/autofill/index.js.map +1 -0
  86. package/lib/module/autofill/profiles.js +193 -0
  87. package/lib/module/autofill/profiles.js.map +1 -0
  88. package/lib/module/components/FieldFlowA11yAudit/FieldFlowA11yAudit.js +94 -0
  89. package/lib/module/components/FieldFlowA11yAudit/FieldFlowA11yAudit.js.map +1 -0
  90. package/lib/module/components/FieldFlowA11yAudit/index.js +4 -0
  91. package/lib/module/components/FieldFlowA11yAudit/index.js.map +1 -0
  92. package/lib/module/components/FieldFlowAuthActions/FieldFlowAuthActions.js +125 -0
  93. package/lib/module/components/FieldFlowAuthActions/FieldFlowAuthActions.js.map +1 -0
  94. package/lib/module/components/FieldFlowAuthActions/index.js +4 -0
  95. package/lib/module/components/FieldFlowAuthActions/index.js.map +1 -0
  96. package/lib/module/components/FieldFlowCompleteness/FieldFlowCompleteness.js +95 -0
  97. package/lib/module/components/FieldFlowCompleteness/FieldFlowCompleteness.js.map +1 -0
  98. package/lib/module/components/FieldFlowCompleteness/index.js +4 -0
  99. package/lib/module/components/FieldFlowCompleteness/index.js.map +1 -0
  100. package/lib/module/components/FieldFlowFormHeader/FieldFlowFormHeader.js +97 -0
  101. package/lib/module/components/FieldFlowFormHeader/FieldFlowFormHeader.js.map +1 -0
  102. package/lib/module/components/FieldFlowFormHeader/index.js +4 -0
  103. package/lib/module/components/FieldFlowFormHeader/index.js.map +1 -0
  104. package/lib/module/components/FieldFlowInfoTip/FieldFlowInfoTip.js +116 -0
  105. package/lib/module/components/FieldFlowInfoTip/FieldFlowInfoTip.js.map +1 -0
  106. package/lib/module/components/FieldFlowInfoTip/index.js +4 -0
  107. package/lib/module/components/FieldFlowInfoTip/index.js.map +1 -0
  108. package/lib/module/components/FieldFlowInlineAlert/FieldFlowInlineAlert.js +137 -0
  109. package/lib/module/components/FieldFlowInlineAlert/FieldFlowInlineAlert.js.map +1 -0
  110. package/lib/module/components/FieldFlowInlineAlert/index.js +4 -0
  111. package/lib/module/components/FieldFlowInlineAlert/index.js.map +1 -0
  112. package/lib/module/components/FieldFlowInput/FieldFlowInput.js +44 -18
  113. package/lib/module/components/FieldFlowInput/FieldFlowInput.js.map +1 -1
  114. package/lib/module/components/FieldFlowInput/styles.js +49 -13
  115. package/lib/module/components/FieldFlowInput/styles.js.map +1 -1
  116. package/lib/module/components/FieldFlowKeyboardToolbar/FieldFlowKeyboardToolbar.js +131 -0
  117. package/lib/module/components/FieldFlowKeyboardToolbar/FieldFlowKeyboardToolbar.js.map +1 -0
  118. package/lib/module/components/FieldFlowKeyboardToolbar/index.js +4 -0
  119. package/lib/module/components/FieldFlowKeyboardToolbar/index.js.map +1 -0
  120. package/lib/module/components/FieldFlowSkeleton/FieldFlowSkeleton.js +96 -0
  121. package/lib/module/components/FieldFlowSkeleton/FieldFlowSkeleton.js.map +1 -0
  122. package/lib/module/components/FieldFlowSkeleton/index.js +4 -0
  123. package/lib/module/components/FieldFlowSkeleton/index.js.map +1 -0
  124. package/lib/module/components/KeyboardAwareFormWrapper/KeyboardAwareFormWrapper.js +5 -3
  125. package/lib/module/components/KeyboardAwareFormWrapper/KeyboardAwareFormWrapper.js.map +1 -1
  126. package/lib/module/hooks/index.js +3 -0
  127. package/lib/module/hooks/index.js.map +1 -1
  128. package/lib/module/hooks/useFieldFlowCompleteness.js +42 -0
  129. package/lib/module/hooks/useFieldFlowCompleteness.js.map +1 -0
  130. package/lib/module/hooks/useFieldFlowSubmitQueue.js +141 -0
  131. package/lib/module/hooks/useFieldFlowSubmitQueue.js.map +1 -0
  132. package/lib/module/hooks/useKeyboardManager.js +15 -0
  133. package/lib/module/hooks/useKeyboardManager.js.map +1 -1
  134. package/lib/module/hooks/useSmartPaste.js +23 -0
  135. package/lib/module/hooks/useSmartPaste.js.map +1 -0
  136. package/lib/module/index.js +17 -2
  137. package/lib/module/index.js.map +1 -1
  138. package/lib/module/paste/index.js +4 -0
  139. package/lib/module/paste/index.js.map +1 -0
  140. package/lib/module/paste/smartPaste.js +108 -0
  141. package/lib/module/paste/smartPaste.js.map +1 -0
  142. package/lib/module/schema/FieldFlowSchemaForm.js +214 -0
  143. package/lib/module/schema/FieldFlowSchemaForm.js.map +1 -0
  144. package/lib/module/schema/index.js +4 -0
  145. package/lib/module/schema/index.js.map +1 -0
  146. package/lib/module/schema/types.js +4 -0
  147. package/lib/module/schema/types.js.map +1 -0
  148. package/lib/module/theme/ThemeProvider.js +66 -5
  149. package/lib/module/theme/ThemeProvider.js.map +1 -1
  150. package/lib/module/theme/appearance.js +87 -0
  151. package/lib/module/theme/appearance.js.map +1 -0
  152. package/lib/module/theme/defaultTheme.js +17 -2
  153. package/lib/module/theme/defaultTheme.js.map +1 -1
  154. package/lib/module/theme/index.js +1 -0
  155. package/lib/module/theme/index.js.map +1 -1
  156. package/lib/module/types/globals.d.js +2 -0
  157. package/lib/module/types/globals.d.js.map +1 -0
  158. package/lib/typescript/a11y/audit.d.ts +32 -0
  159. package/lib/typescript/a11y/audit.d.ts.map +1 -0
  160. package/lib/typescript/a11y/index.d.ts +3 -0
  161. package/lib/typescript/a11y/index.d.ts.map +1 -0
  162. package/lib/typescript/autofill/index.d.ts +3 -0
  163. package/lib/typescript/autofill/index.d.ts.map +1 -0
  164. package/lib/typescript/autofill/profiles.d.ts +48 -0
  165. package/lib/typescript/autofill/profiles.d.ts.map +1 -0
  166. package/lib/typescript/components/FieldFlowA11yAudit/FieldFlowA11yAudit.d.ts +21 -0
  167. package/lib/typescript/components/FieldFlowA11yAudit/FieldFlowA11yAudit.d.ts.map +1 -0
  168. package/lib/typescript/components/FieldFlowA11yAudit/index.d.ts +3 -0
  169. package/lib/typescript/components/FieldFlowA11yAudit/index.d.ts.map +1 -0
  170. package/lib/typescript/components/FieldFlowAuthActions/FieldFlowAuthActions.d.ts +29 -0
  171. package/lib/typescript/components/FieldFlowAuthActions/FieldFlowAuthActions.d.ts.map +1 -0
  172. package/lib/typescript/components/FieldFlowAuthActions/index.d.ts +3 -0
  173. package/lib/typescript/components/FieldFlowAuthActions/index.d.ts.map +1 -0
  174. package/lib/typescript/components/FieldFlowCompleteness/FieldFlowCompleteness.d.ts +25 -0
  175. package/lib/typescript/components/FieldFlowCompleteness/FieldFlowCompleteness.d.ts.map +1 -0
  176. package/lib/typescript/components/FieldFlowCompleteness/index.d.ts +3 -0
  177. package/lib/typescript/components/FieldFlowCompleteness/index.d.ts.map +1 -0
  178. package/lib/typescript/components/FieldFlowFormHeader/FieldFlowFormHeader.d.ts +23 -0
  179. package/lib/typescript/components/FieldFlowFormHeader/FieldFlowFormHeader.d.ts.map +1 -0
  180. package/lib/typescript/components/FieldFlowFormHeader/index.d.ts +3 -0
  181. package/lib/typescript/components/FieldFlowFormHeader/index.d.ts.map +1 -0
  182. package/lib/typescript/components/FieldFlowInfoTip/FieldFlowInfoTip.d.ts +19 -0
  183. package/lib/typescript/components/FieldFlowInfoTip/FieldFlowInfoTip.d.ts.map +1 -0
  184. package/lib/typescript/components/FieldFlowInfoTip/index.d.ts +3 -0
  185. package/lib/typescript/components/FieldFlowInfoTip/index.d.ts.map +1 -0
  186. package/lib/typescript/components/FieldFlowInlineAlert/FieldFlowInlineAlert.d.ts +22 -0
  187. package/lib/typescript/components/FieldFlowInlineAlert/FieldFlowInlineAlert.d.ts.map +1 -0
  188. package/lib/typescript/components/FieldFlowInlineAlert/index.d.ts +3 -0
  189. package/lib/typescript/components/FieldFlowInlineAlert/index.d.ts.map +1 -0
  190. package/lib/typescript/components/FieldFlowInput/FieldFlowInput.d.ts.map +1 -1
  191. package/lib/typescript/components/FieldFlowInput/styles.d.ts +36 -1
  192. package/lib/typescript/components/FieldFlowInput/styles.d.ts.map +1 -1
  193. package/lib/typescript/components/FieldFlowInput/types.d.ts +18 -0
  194. package/lib/typescript/components/FieldFlowInput/types.d.ts.map +1 -1
  195. package/lib/typescript/components/FieldFlowKeyboardToolbar/FieldFlowKeyboardToolbar.d.ts +30 -0
  196. package/lib/typescript/components/FieldFlowKeyboardToolbar/FieldFlowKeyboardToolbar.d.ts.map +1 -0
  197. package/lib/typescript/components/FieldFlowKeyboardToolbar/index.d.ts +3 -0
  198. package/lib/typescript/components/FieldFlowKeyboardToolbar/index.d.ts.map +1 -0
  199. package/lib/typescript/components/FieldFlowSkeleton/FieldFlowSkeleton.d.ts +21 -0
  200. package/lib/typescript/components/FieldFlowSkeleton/FieldFlowSkeleton.d.ts.map +1 -0
  201. package/lib/typescript/components/FieldFlowSkeleton/index.d.ts +3 -0
  202. package/lib/typescript/components/FieldFlowSkeleton/index.d.ts.map +1 -0
  203. package/lib/typescript/components/KeyboardAwareFormWrapper/KeyboardAwareFormWrapper.d.ts +3 -2
  204. package/lib/typescript/components/KeyboardAwareFormWrapper/KeyboardAwareFormWrapper.d.ts.map +1 -1
  205. package/lib/typescript/hooks/index.d.ts +6 -0
  206. package/lib/typescript/hooks/index.d.ts.map +1 -1
  207. package/lib/typescript/hooks/useFieldFlowCompleteness.d.ts +28 -0
  208. package/lib/typescript/hooks/useFieldFlowCompleteness.d.ts.map +1 -0
  209. package/lib/typescript/hooks/useFieldFlowSubmitQueue.d.ts +45 -0
  210. package/lib/typescript/hooks/useFieldFlowSubmitQueue.d.ts.map +1 -0
  211. package/lib/typescript/hooks/useKeyboardManager.d.ts +6 -0
  212. package/lib/typescript/hooks/useKeyboardManager.d.ts.map +1 -1
  213. package/lib/typescript/hooks/useSmartPaste.d.ts +14 -0
  214. package/lib/typescript/hooks/useSmartPaste.d.ts.map +1 -0
  215. package/lib/typescript/index.d.ts +28 -4
  216. package/lib/typescript/index.d.ts.map +1 -1
  217. package/lib/typescript/paste/index.d.ts +3 -0
  218. package/lib/typescript/paste/index.d.ts.map +1 -0
  219. package/lib/typescript/paste/smartPaste.d.ts +32 -0
  220. package/lib/typescript/paste/smartPaste.d.ts.map +1 -0
  221. package/lib/typescript/schema/FieldFlowSchemaForm.d.ts +28 -0
  222. package/lib/typescript/schema/FieldFlowSchemaForm.d.ts.map +1 -0
  223. package/lib/typescript/schema/index.d.ts +4 -0
  224. package/lib/typescript/schema/index.d.ts.map +1 -0
  225. package/lib/typescript/schema/types.d.ts +43 -0
  226. package/lib/typescript/schema/types.d.ts.map +1 -0
  227. package/lib/typescript/theme/ThemeProvider.d.ts +18 -4
  228. package/lib/typescript/theme/ThemeProvider.d.ts.map +1 -1
  229. package/lib/typescript/theme/appearance.d.ts +19 -0
  230. package/lib/typescript/theme/appearance.d.ts.map +1 -0
  231. package/lib/typescript/theme/defaultTheme.d.ts.map +1 -1
  232. package/lib/typescript/theme/index.d.ts +1 -0
  233. package/lib/typescript/theme/index.d.ts.map +1 -1
  234. package/lib/typescript/types/index.d.ts +26 -0
  235. package/lib/typescript/types/index.d.ts.map +1 -1
  236. package/package.json +2 -2
  237. package/src/a11y/audit.ts +99 -0
  238. package/src/a11y/index.ts +7 -0
  239. package/src/autofill/index.ts +10 -0
  240. package/src/autofill/profiles.ts +224 -0
  241. package/src/components/FieldFlowA11yAudit/FieldFlowA11yAudit.tsx +112 -0
  242. package/src/components/FieldFlowA11yAudit/index.ts +2 -0
  243. package/src/components/FieldFlowAuthActions/FieldFlowAuthActions.tsx +146 -0
  244. package/src/components/FieldFlowAuthActions/index.ts +6 -0
  245. package/src/components/FieldFlowCompleteness/FieldFlowCompleteness.tsx +109 -0
  246. package/src/components/FieldFlowCompleteness/index.ts +2 -0
  247. package/src/components/FieldFlowFormHeader/FieldFlowFormHeader.tsx +106 -0
  248. package/src/components/FieldFlowFormHeader/index.ts +2 -0
  249. package/src/components/FieldFlowInfoTip/FieldFlowInfoTip.tsx +120 -0
  250. package/src/components/FieldFlowInfoTip/index.ts +2 -0
  251. package/src/components/FieldFlowInlineAlert/FieldFlowInlineAlert.tsx +134 -0
  252. package/src/components/FieldFlowInlineAlert/index.ts +2 -0
  253. package/src/components/FieldFlowInput/FieldFlowInput.tsx +71 -13
  254. package/src/components/FieldFlowInput/styles.ts +58 -16
  255. package/src/components/FieldFlowInput/types.ts +21 -0
  256. package/src/components/FieldFlowKeyboardToolbar/FieldFlowKeyboardToolbar.tsx +150 -0
  257. package/src/components/FieldFlowKeyboardToolbar/index.ts +5 -0
  258. package/src/components/FieldFlowSkeleton/FieldFlowSkeleton.tsx +105 -0
  259. package/src/components/FieldFlowSkeleton/index.ts +2 -0
  260. package/src/components/KeyboardAwareFormWrapper/KeyboardAwareFormWrapper.tsx +8 -4
  261. package/src/hooks/index.ts +17 -0
  262. package/src/hooks/useFieldFlowCompleteness.ts +69 -0
  263. package/src/hooks/useFieldFlowSubmitQueue.ts +206 -0
  264. package/src/hooks/useKeyboardManager.ts +26 -0
  265. package/src/hooks/useSmartPaste.ts +33 -0
  266. package/src/index.ts +90 -0
  267. package/src/paste/index.ts +7 -0
  268. package/src/paste/smartPaste.ts +132 -0
  269. package/src/schema/FieldFlowSchemaForm.tsx +274 -0
  270. package/src/schema/index.ts +8 -0
  271. package/src/schema/types.ts +63 -0
  272. package/src/theme/ThemeProvider.tsx +96 -7
  273. package/src/theme/appearance.ts +105 -0
  274. package/src/theme/defaultTheme.ts +11 -0
  275. package/src/theme/index.ts +1 -0
  276. package/src/types/globals.d.ts +2 -0
  277. package/src/types/index.ts +28 -0
@@ -0,0 +1,69 @@
1
+ import { useMemo } from 'react';
2
+
3
+ export interface UseFieldFlowCompletenessOptions<T extends Record<string, string>> {
4
+ values: T;
5
+ /** Required field keys (or dynamic list). */
6
+ requiredFields: (keyof T)[];
7
+ /** Optional: treat as filled when custom predicate returns true. */
8
+ isFilled?: (field: keyof T, value: string, values: T) => boolean;
9
+ /** Seconds users typically need per empty required field (for estimate). Default: 8. */
10
+ secondsPerField?: number;
11
+ }
12
+
13
+ export interface UseFieldFlowCompletenessResult<T extends Record<string, string>> {
14
+ total: number;
15
+ filled: number;
16
+ remaining: number;
17
+ /** 0–1 */
18
+ progress: number;
19
+ /** 0–100 */
20
+ percent: number;
21
+ remainingFields: (keyof T)[];
22
+ filledFields: (keyof T)[];
23
+ isComplete: boolean;
24
+ /** Rough seconds left based on empty required fields. */
25
+ estimatedSecondsLeft: number;
26
+ }
27
+
28
+ function defaultFilled(value: string): boolean {
29
+ return value.trim().length > 0;
30
+ }
31
+
32
+ /**
33
+ * Live form completeness for required fields — powers `FieldFlowCompleteness`.
34
+ */
35
+ export function useFieldFlowCompleteness<T extends Record<string, string>>({
36
+ values,
37
+ requiredFields,
38
+ isFilled,
39
+ secondsPerField = 8,
40
+ }: UseFieldFlowCompletenessOptions<T>): UseFieldFlowCompletenessResult<T> {
41
+ return useMemo(() => {
42
+ const filledFields: (keyof T)[] = [];
43
+ const remainingFields: (keyof T)[] = [];
44
+
45
+ for (const field of requiredFields) {
46
+ const value = values[field] ?? '';
47
+ const ok = isFilled ? isFilled(field, value, values) : defaultFilled(value);
48
+ if (ok) filledFields.push(field);
49
+ else remainingFields.push(field);
50
+ }
51
+
52
+ const total = requiredFields.length;
53
+ const filled = filledFields.length;
54
+ const remaining = remainingFields.length;
55
+ const progress = total === 0 ? 1 : filled / total;
56
+
57
+ return {
58
+ total,
59
+ filled,
60
+ remaining,
61
+ progress,
62
+ percent: Math.round(progress * 100),
63
+ remainingFields,
64
+ filledFields,
65
+ isComplete: remaining === 0,
66
+ estimatedSecondsLeft: remaining * secondsPerField,
67
+ };
68
+ }, [values, requiredFields, isFilled, secondsPerField]);
69
+ }
@@ -0,0 +1,206 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+
3
+ export interface FieldFlowSubmitJob<T = unknown> {
4
+ id: string;
5
+ payload: T;
6
+ createdAt: number;
7
+ attempts: number;
8
+ lastError?: string;
9
+ }
10
+
11
+ export interface FieldFlowSubmitQueueStorage {
12
+ getItem: (key: string) => Promise<string | null> | string | null;
13
+ setItem: (key: string, value: string) => Promise<void> | void;
14
+ removeItem: (key: string) => Promise<void> | void;
15
+ }
16
+
17
+ export interface UseFieldFlowSubmitQueueOptions<T> {
18
+ /** Unique storage key. */
19
+ key: string;
20
+ /** Persist queue (AsyncStorage / MMKV). Optional — in-memory if omitted. */
21
+ storage?: FieldFlowSubmitQueueStorage;
22
+ /** Actually send the payload. Throw / return false to keep in queue. */
23
+ submit: (payload: T) => Promise<void | boolean>;
24
+ /** Max attempts before parking as failed. Default: 5. */
25
+ maxAttempts?: number;
26
+ /** Auto-flush when online. Default: true. */
27
+ flushOnOnline?: boolean;
28
+ /** Called after a successful flush of one job. */
29
+ onSuccess?: (job: FieldFlowSubmitJob<T>) => void;
30
+ /** Called when a job exceeds maxAttempts. */
31
+ onGiveUp?: (job: FieldFlowSubmitJob<T>) => void;
32
+ }
33
+
34
+ export interface UseFieldFlowSubmitQueueResult<T> {
35
+ queue: FieldFlowSubmitJob<T>[];
36
+ pendingCount: number;
37
+ isFlushing: boolean;
38
+ isOnline: boolean;
39
+ /** Enqueue a payload (and try flush if online). */
40
+ enqueue: (payload: T) => Promise<string>;
41
+ /** Process the queue now. */
42
+ flush: () => Promise<void>;
43
+ clear: () => Promise<void>;
44
+ remove: (id: string) => Promise<void>;
45
+ }
46
+
47
+ function createId(): string {
48
+ return `ffq_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
49
+ }
50
+
51
+ /**
52
+ * Offline-friendly submit queue — persist failed / offline form posts and retry.
53
+ */
54
+ export function useFieldFlowSubmitQueue<T>({
55
+ key,
56
+ storage,
57
+ submit,
58
+ maxAttempts = 5,
59
+ flushOnOnline = true,
60
+ onSuccess,
61
+ onGiveUp,
62
+ }: UseFieldFlowSubmitQueueOptions<T>): UseFieldFlowSubmitQueueResult<T> {
63
+ const [queue, setQueue] = useState<FieldFlowSubmitJob<T>[]>([]);
64
+ const [isFlushing, setIsFlushing] = useState(false);
65
+ const [isOnline, setIsOnline] = useState(true);
66
+ const queueRef = useRef(queue);
67
+ queueRef.current = queue;
68
+ const hydrated = useRef(false);
69
+
70
+ const persist = useCallback(
71
+ async (next: FieldFlowSubmitJob<T>[]) => {
72
+ setQueue(next);
73
+ queueRef.current = next;
74
+ if (!storage) return;
75
+ if (next.length === 0) await storage.removeItem(key);
76
+ else await storage.setItem(key, JSON.stringify(next));
77
+ },
78
+ [storage, key],
79
+ );
80
+
81
+ useEffect(() => {
82
+ let cancelled = false;
83
+ (async () => {
84
+ if (!storage) {
85
+ hydrated.current = true;
86
+ return;
87
+ }
88
+ try {
89
+ const raw = await storage.getItem(key);
90
+ if (cancelled || !raw) {
91
+ hydrated.current = true;
92
+ return;
93
+ }
94
+ const parsed = JSON.parse(raw) as FieldFlowSubmitJob<T>[];
95
+ if (!cancelled && Array.isArray(parsed)) {
96
+ setQueue(parsed);
97
+ queueRef.current = parsed;
98
+ }
99
+ } catch {
100
+ /* ignore corrupt */
101
+ } finally {
102
+ hydrated.current = true;
103
+ }
104
+ })();
105
+ return () => {
106
+ cancelled = true;
107
+ };
108
+ }, [storage, key]);
109
+
110
+ useEffect(() => {
111
+ // NetInfo-free: use RN global if present, else assume online
112
+ type NetInfoLike = {
113
+ addEventListener?: (cb: (s: { isConnected?: boolean | null }) => void) => { remove: () => void };
114
+ fetch?: () => Promise<{ isConnected?: boolean | null }>;
115
+ };
116
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
117
+ const NetInfo = (globalThis as any).NetInfo as NetInfoLike | undefined;
118
+ if (!NetInfo?.addEventListener) return;
119
+
120
+ const sub = NetInfo.addEventListener(state => {
121
+ const online = state.isConnected !== false;
122
+ setIsOnline(online);
123
+ });
124
+ NetInfo.fetch?.().then(s => setIsOnline(s.isConnected !== false)).catch(() => undefined);
125
+ return () => sub?.remove();
126
+ }, []);
127
+
128
+ const flush = useCallback(async () => {
129
+ if (isFlushing) return;
130
+ setIsFlushing(true);
131
+ try {
132
+ let next = [...queueRef.current];
133
+ while (next.length > 0) {
134
+ const job = next[0];
135
+ try {
136
+ const result = await submit(job.payload);
137
+ if (result === false) throw new Error('Submit returned false');
138
+ onSuccess?.(job);
139
+ next = next.slice(1);
140
+ await persist(next);
141
+ } catch (err) {
142
+ const message = err instanceof Error ? err.message : 'Submit failed';
143
+ const updated: FieldFlowSubmitJob<T> = {
144
+ ...job,
145
+ attempts: job.attempts + 1,
146
+ lastError: message,
147
+ };
148
+ if (updated.attempts >= maxAttempts) {
149
+ onGiveUp?.(updated);
150
+ next = next.slice(1);
151
+ } else {
152
+ next = [updated, ...next.slice(1)];
153
+ }
154
+ await persist(next);
155
+ break;
156
+ }
157
+ }
158
+ } finally {
159
+ setIsFlushing(false);
160
+ }
161
+ }, [isFlushing, submit, persist, maxAttempts, onSuccess, onGiveUp]);
162
+
163
+ useEffect(() => {
164
+ if (!flushOnOnline || !isOnline || !hydrated.current) return;
165
+ if (queueRef.current.length === 0) return;
166
+ void flush();
167
+ }, [isOnline, flushOnOnline, flush]);
168
+
169
+ const enqueue = useCallback(
170
+ async (payload: T) => {
171
+ const id = createId();
172
+ const job: FieldFlowSubmitJob<T> = {
173
+ id,
174
+ payload,
175
+ createdAt: Date.now(),
176
+ attempts: 0,
177
+ };
178
+ await persist([...queueRef.current, job]);
179
+ if (isOnline) void flush();
180
+ return id;
181
+ },
182
+ [persist, isOnline, flush],
183
+ );
184
+
185
+ const clear = useCallback(async () => {
186
+ await persist([]);
187
+ }, [persist]);
188
+
189
+ const remove = useCallback(
190
+ async (id: string) => {
191
+ await persist(queueRef.current.filter(j => j.id !== id));
192
+ },
193
+ [persist],
194
+ );
195
+
196
+ return {
197
+ queue,
198
+ pendingCount: queue.length,
199
+ isFlushing,
200
+ isOnline,
201
+ enqueue,
202
+ flush,
203
+ clear,
204
+ remove,
205
+ };
206
+ }
@@ -13,7 +13,13 @@ export interface UseKeyboardManagerResult {
13
13
  unregisterField: (id: string) => void;
14
14
  /** Call from a field's onSubmitEditing to move focus to the next registered field, or submit if it's last. */
15
15
  focusNext: (id: string) => void;
16
+ /** Move focus to the previous field in `order` (no-op on first). */
17
+ focusPrevious: (id: string) => void;
16
18
  focusField: (id: string) => void;
19
+ /** Index helpers for keyboard toolbar enablement. */
20
+ getFieldIndex: (id: string) => number;
21
+ canGoPrevious: (id: string) => boolean;
22
+ canGoNext: (id: string) => boolean;
17
23
  /** Attach to the surrounding ScrollView so FieldFlow can scroll the active field into view. */
18
24
  scrollViewRef: React.RefObject<ScrollView | null>;
19
25
  /** returnKeyType to use for a field given its position ("next" for all but the last, "done" for the last). */
@@ -85,6 +91,22 @@ export function useKeyboardManager({
85
91
  [order, focusField, onSubmit],
86
92
  );
87
93
 
94
+ const focusPrevious = useCallback(
95
+ (id: string) => {
96
+ const currentIndex = order.indexOf(id);
97
+ const prevId = order[currentIndex - 1];
98
+ if (prevId) focusField(prevId);
99
+ },
100
+ [order, focusField],
101
+ );
102
+
103
+ const getFieldIndex = useCallback((id: string) => order.indexOf(id), [order]);
104
+ const canGoPrevious = useCallback((id: string) => order.indexOf(id) > 0, [order]);
105
+ const canGoNext = useCallback((id: string) => {
106
+ const i = order.indexOf(id);
107
+ return i >= 0 && i < order.length - 1;
108
+ }, [order]);
109
+
88
110
  const getReturnKeyType = useCallback(
89
111
  (id: string): 'next' | 'done' => {
90
112
  const isLast = order.indexOf(id) === order.length - 1;
@@ -97,7 +119,11 @@ export function useKeyboardManager({
97
119
  registerField,
98
120
  unregisterField,
99
121
  focusNext,
122
+ focusPrevious,
100
123
  focusField,
124
+ getFieldIndex,
125
+ canGoPrevious,
126
+ canGoNext,
101
127
  scrollViewRef,
102
128
  getReturnKeyType,
103
129
  onSubmit: () => onSubmit?.(),
@@ -0,0 +1,33 @@
1
+ import { useCallback } from 'react';
2
+ import {
3
+ applySmartPaste,
4
+ routeSmartPaste,
5
+ type FieldFlowPasteResult,
6
+ type FieldFlowPasteTargets,
7
+ } from '../paste/smartPaste';
8
+
9
+ export interface UseSmartPasteOptions {
10
+ targets: FieldFlowPasteTargets;
11
+ minConfidence?: number;
12
+ onRouted?: (result: FieldFlowPasteResult) => void;
13
+ }
14
+
15
+ /**
16
+ * Hook helper for smart paste — call `handlePaste(text)` from Clipboard or a paste event.
17
+ */
18
+ export function useSmartPaste({
19
+ targets,
20
+ minConfidence = 0.7,
21
+ onRouted,
22
+ }: UseSmartPasteOptions) {
23
+ const handlePaste = useCallback(
24
+ (text: string) => {
25
+ const result = applySmartPaste(text, targets, minConfidence);
26
+ onRouted?.(result);
27
+ return result;
28
+ },
29
+ [targets, minConfidence, onRouted],
30
+ );
31
+
32
+ return { handlePaste, routeSmartPaste };
33
+ }
package/src/index.ts CHANGED
@@ -94,6 +94,47 @@ export type {
94
94
  FieldFlowPoint,
95
95
  } from './components/FieldFlowSignature';
96
96
 
97
+ export { FieldFlowCompleteness } from './components/FieldFlowCompleteness';
98
+ export type { FieldFlowCompletenessProps } from './components/FieldFlowCompleteness';
99
+
100
+ export { FieldFlowAuthActions } from './components/FieldFlowAuthActions';
101
+ export type {
102
+ FieldFlowAuthActionsProps,
103
+ FieldFlowAuthAction,
104
+ FieldFlowAuthProvider,
105
+ } from './components/FieldFlowAuthActions';
106
+
107
+ export {
108
+ FieldFlowKeyboardToolbar,
109
+ FIELD_FLOW_KEYBOARD_TOOLBAR_ID,
110
+ } from './components/FieldFlowKeyboardToolbar';
111
+ export type { FieldFlowKeyboardToolbarProps } from './components/FieldFlowKeyboardToolbar';
112
+
113
+ export { FieldFlowA11yAudit } from './components/FieldFlowA11yAudit';
114
+ export type { FieldFlowA11yAuditProps } from './components/FieldFlowA11yAudit';
115
+
116
+ export { FieldFlowInlineAlert } from './components/FieldFlowInlineAlert';
117
+ export type { FieldFlowInlineAlertProps, FieldFlowAlertTone } from './components/FieldFlowInlineAlert';
118
+
119
+ export { FieldFlowSkeleton } from './components/FieldFlowSkeleton';
120
+ export type { FieldFlowSkeletonProps } from './components/FieldFlowSkeleton';
121
+
122
+ export { FieldFlowFormHeader } from './components/FieldFlowFormHeader';
123
+ export type { FieldFlowFormHeaderProps } from './components/FieldFlowFormHeader';
124
+
125
+ export { FieldFlowInfoTip } from './components/FieldFlowInfoTip';
126
+ export type { FieldFlowInfoTipProps } from './components/FieldFlowInfoTip';
127
+
128
+ export { FieldFlowSchemaForm } from './schema';
129
+ export type {
130
+ FieldFlowSchemaFormProps,
131
+ FieldFlowSchemaShowWhenFn,
132
+ FieldFlowFormSchema,
133
+ FieldFlowSchemaField,
134
+ FieldFlowSchemaFieldType,
135
+ FieldFlowSchemaSection,
136
+ } from './schema';
137
+
97
138
  // Adapters (optional peers: react-hook-form)
98
139
  export {
99
140
  FieldFlowController,
@@ -113,6 +154,9 @@ export {
113
154
  darkTheme,
114
155
  themePresets,
115
156
  getThemePreset,
157
+ applyAppearance,
158
+ defaultAppearance,
159
+ surfaceShadow,
116
160
  } from './theme';
117
161
  export type { FieldFlowThemeProviderProps, FieldFlowThemePresetName } from './theme';
118
162
 
@@ -130,6 +174,9 @@ export {
130
174
  useFieldFlowDraft,
131
175
  useFieldFlowSteps,
132
176
  useFieldFlowDirtyGuard,
177
+ useFieldFlowCompleteness,
178
+ useFieldFlowSubmitQueue,
179
+ useSmartPaste,
133
180
  } from './hooks';
134
181
  export type {
135
182
  UseFieldFlowFormOptions,
@@ -157,8 +204,45 @@ export type {
157
204
  UseFieldFlowStepsResult,
158
205
  UseFieldFlowDirtyGuardOptions,
159
206
  UseFieldFlowDirtyGuardResult,
207
+ UseFieldFlowCompletenessOptions,
208
+ UseFieldFlowCompletenessResult,
209
+ FieldFlowSubmitJob,
210
+ FieldFlowSubmitQueueStorage,
211
+ UseFieldFlowSubmitQueueOptions,
212
+ UseFieldFlowSubmitQueueResult,
213
+ UseSmartPasteOptions,
160
214
  } from './hooks';
161
215
 
216
+ // Autofill
217
+ export {
218
+ getAutofillProps,
219
+ autofillRoleFromFieldType,
220
+ autofillProfiles,
221
+ } from './autofill';
222
+ export type {
223
+ FieldFlowAutofillRole,
224
+ FieldFlowAutofillProps,
225
+ FieldFlowAutofillProfileName,
226
+ } from './autofill';
227
+
228
+ // Smart paste
229
+ export { routeSmartPaste, applySmartPaste } from './paste';
230
+ export type {
231
+ FieldFlowPasteKind,
232
+ FieldFlowPasteResult,
233
+ FieldFlowAddressPaste,
234
+ FieldFlowPasteTargets,
235
+ } from './paste';
236
+
237
+ // A11y audit
238
+ export { runA11yAudit } from './a11y';
239
+ export type {
240
+ FieldFlowA11ySeverity,
241
+ FieldFlowA11yIssue,
242
+ FieldFlowA11yFieldSnapshot,
243
+ FieldFlowA11yAuditInput,
244
+ } from './a11y';
245
+
162
246
  // i18n
163
247
  export {
164
248
  validationMessageCatalogs,
@@ -269,5 +353,11 @@ export type {
269
353
  FieldFlowTypography,
270
354
  FieldFlowAnimationConfig,
271
355
  FieldFlowTheme,
356
+ FieldFlowAppearance,
357
+ FieldFlowDensity,
358
+ FieldFlowControlSize,
359
+ FieldFlowSurface,
360
+ FieldFlowShape,
361
+ FieldFlowFocusRing,
272
362
  DeepPartial,
273
363
  } from './types';
@@ -0,0 +1,7 @@
1
+ export { routeSmartPaste, applySmartPaste } from './smartPaste';
2
+ export type {
3
+ FieldFlowPasteKind,
4
+ FieldFlowPasteResult,
5
+ FieldFlowAddressPaste,
6
+ FieldFlowPasteTargets,
7
+ } from './smartPaste';
@@ -0,0 +1,132 @@
1
+ export type FieldFlowPasteKind =
2
+ | 'otp'
3
+ | 'card'
4
+ | 'email'
5
+ | 'phone'
6
+ | 'address'
7
+ | 'url'
8
+ | 'unknown';
9
+
10
+ export interface FieldFlowAddressPaste {
11
+ street?: string;
12
+ city?: string;
13
+ state?: string;
14
+ postalCode?: string;
15
+ country?: string;
16
+ raw: string;
17
+ }
18
+
19
+ export interface FieldFlowPasteResult {
20
+ kind: FieldFlowPasteKind;
21
+ /** Primary value for a single target field. */
22
+ value: string;
23
+ /** Digits-only for OTP / card / phone when applicable. */
24
+ raw?: string;
25
+ address?: FieldFlowAddressPaste;
26
+ confidence: number;
27
+ }
28
+
29
+ function digitsOnly(s: string): string {
30
+ return s.replace(/\D/g, '');
31
+ }
32
+
33
+ /**
34
+ * Classify clipboard / pasted text and extract a structured value.
35
+ * Pure — no Clipboard permission required; call from `onPaste` or after reading clipboard.
36
+ */
37
+ export function routeSmartPaste(text: string): FieldFlowPasteResult {
38
+ const trimmed = text.trim();
39
+ if (!trimmed) {
40
+ return { kind: 'unknown', value: '', confidence: 0 };
41
+ }
42
+
43
+ const digits = digitsOnly(trimmed);
44
+
45
+ // OTP: 4–8 digits, little else
46
+ if (/^\d{4,8}$/.test(digits) && digits.length === trimmed.replace(/\s/g, '').length) {
47
+ return { kind: 'otp', value: digits, raw: digits, confidence: 0.95 };
48
+ }
49
+
50
+ // Card: 13–19 digits (spaces/dashes ok)
51
+ if (digits.length >= 13 && digits.length <= 19 && /^[\d\s-]+$/.test(trimmed)) {
52
+ return { kind: 'card', value: digits, raw: digits, confidence: 0.9 };
53
+ }
54
+
55
+ // Email
56
+ if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed)) {
57
+ return { kind: 'email', value: trimmed.toLowerCase(), confidence: 0.98 };
58
+ }
59
+
60
+ // URL
61
+ if (/^https?:\/\//i.test(trimmed) || /^www\./i.test(trimmed)) {
62
+ return {
63
+ kind: 'url',
64
+ value: trimmed.startsWith('http') ? trimmed : `https://${trimmed}`,
65
+ confidence: 0.9,
66
+ };
67
+ }
68
+
69
+ // Phone: 7–15 digits with optional + and punctuation
70
+ if (
71
+ digits.length >= 7 &&
72
+ digits.length <= 15 &&
73
+ /^[+]?[\d\s().-]{7,22}$/.test(trimmed) &&
74
+ !/[a-zA-Z]{3,}/.test(trimmed)
75
+ ) {
76
+ return { kind: 'phone', value: trimmed, raw: digits, confidence: 0.85 };
77
+ }
78
+
79
+ // Multi-line address-ish
80
+ const lines = trimmed
81
+ .split(/\r?\n/)
82
+ .map(l => l.trim())
83
+ .filter(Boolean);
84
+ if (lines.length >= 2) {
85
+ const postalMatch = trimmed.match(/\b([A-Z]{1,2}\d[A-Z\d]?\s*\d[A-Z]{2}|\d{5}(?:-\d{4})?)\b/i);
86
+ const address: FieldFlowAddressPaste = {
87
+ street: lines[0],
88
+ city: lines[1]?.replace(/,.*$/, '').trim(),
89
+ state: lines[1]?.includes(',')
90
+ ? lines[1].split(',')[1]?.trim().split(/\s+/)[0]
91
+ : undefined,
92
+ postalCode: postalMatch?.[1],
93
+ raw: trimmed,
94
+ };
95
+ return {
96
+ kind: 'address',
97
+ value: lines[0],
98
+ address,
99
+ confidence: 0.7,
100
+ };
101
+ }
102
+
103
+ return { kind: 'unknown', value: trimmed, confidence: 0.2 };
104
+ }
105
+
106
+ export type FieldFlowPasteTargets = Partial<
107
+ Record<FieldFlowPasteKind, (result: FieldFlowPasteResult) => void>
108
+ > & {
109
+ /** Called when kind is address and you want field-level writes. */
110
+ addressFields?: (address: FieldFlowAddressPaste) => void;
111
+ };
112
+
113
+ /**
114
+ * Route paste into field setters. Returns true if a handler ran with confidence ≥ minConfidence.
115
+ */
116
+ export function applySmartPaste(
117
+ text: string,
118
+ targets: FieldFlowPasteTargets,
119
+ minConfidence = 0.7,
120
+ ): FieldFlowPasteResult {
121
+ const result = routeSmartPaste(text);
122
+ if (result.confidence < minConfidence) return result;
123
+
124
+ if (result.kind === 'address' && result.address && targets.addressFields) {
125
+ targets.addressFields(result.address);
126
+ return result;
127
+ }
128
+
129
+ const handler = targets[result.kind];
130
+ if (handler) handler(result);
131
+ return result;
132
+ }