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
@@ -10,10 +10,15 @@ import { renderFieldFlowIcon } from '../../icons/renderIcon';
10
10
  import { useFieldMotion } from '../../motion/useFieldMotion';
11
11
  import { FieldFlowAffordance } from '../FieldFlowAffordance';
12
12
  import { FieldFlowPasswordStrength } from '../FieldFlowPasswordStrength';
13
+ import { FieldFlowInfoTip } from '../FieldFlowInfoTip';
13
14
  import {
14
15
  affordanceKindFromFieldType,
15
16
  type FieldFlowAffordanceKind,
16
17
  } from '../../utils/affordance';
18
+ import {
19
+ autofillRoleFromFieldType,
20
+ getAutofillProps,
21
+ } from '../../autofill/profiles';
17
22
  import { createStyles, iconColorFor, labelColorFor } from './styles';
18
23
  import type { FieldFlowInputProps } from './types';
19
24
 
@@ -58,6 +63,10 @@ export const FieldFlowInput = forwardRef<TextInput, FieldFlowInputProps>(functio
58
63
  prefix,
59
64
  suffix,
60
65
  motion = true,
66
+ autofill,
67
+ inputAccessoryViewID,
68
+ helperStatus,
69
+ infoTip,
61
70
  maxLength,
62
71
  showCharacterCount,
63
72
  onSubmitEditing,
@@ -97,6 +106,11 @@ export const FieldFlowInput = forwardRef<TextInput, FieldFlowInputProps>(functio
97
106
  [type, required, rules],
98
107
  );
99
108
 
109
+ const autofillProps = useMemo(() => {
110
+ const role = autofill ?? autofillRoleFromFieldType(type);
111
+ return role ? getAutofillProps(role) : undefined;
112
+ }, [autofill, type]);
113
+
100
114
  const resolvedError = errorText ?? localError;
101
115
  const state = useFieldState({
102
116
  isFocused,
@@ -271,18 +285,56 @@ export const FieldFlowInput = forwardRef<TextInput, FieldFlowInputProps>(functio
271
285
  return <View style={side === 'left' ? styles.iconSlotLeft : styles.iconSlotRight}>{affix}</View>;
272
286
  };
273
287
 
288
+ const focusRing = theme.appearance?.focusRing ?? 'softGlow';
289
+ const showFocusRing = motion && focusRing !== 'underlinePulse';
290
+ const resolvedHelperStatus =
291
+ helperStatus ??
292
+ (resolvedError ? 'error' : successText ? 'success' : helperText ? 'info' : 'none');
293
+
294
+ const helperIconName =
295
+ resolvedHelperStatus === 'success'
296
+ ? 'check'
297
+ : resolvedHelperStatus === 'error' || resolvedHelperStatus === 'warning'
298
+ ? 'alert'
299
+ : resolvedHelperStatus === 'info'
300
+ ? 'info'
301
+ : null;
302
+
303
+ const helperIconColor =
304
+ resolvedHelperStatus === 'success'
305
+ ? theme.colors.success
306
+ : resolvedHelperStatus === 'error'
307
+ ? theme.colors.error
308
+ : resolvedHelperStatus === 'warning'
309
+ ? theme.colors.warning
310
+ : theme.colors.info;
311
+
312
+ const helperTextStyle =
313
+ resolvedError
314
+ ? styles.errorText
315
+ : successText
316
+ ? styles.successText
317
+ : resolvedHelperStatus === 'warning'
318
+ ? styles.warningText
319
+ : resolvedHelperStatus === 'info' && helperText
320
+ ? styles.infoText
321
+ : styles.helperText;
322
+
274
323
  return (
275
324
  <View style={[styles.wrapper, containerStyle]} testID={testID}>
276
325
  {showExternalLabel ? (
277
- <Text style={[styles.label, labelStyle]}>
278
- {label}
279
- {required ? ' *' : ''}
280
- </Text>
326
+ <View style={styles.labelRow}>
327
+ <Text style={[styles.label, labelStyle]}>
328
+ {label}
329
+ {required ? ' *' : ''}
330
+ </Text>
331
+ {infoTip ? <FieldFlowInfoTip tip={infoTip} theme={themeOverride} /> : null}
332
+ </View>
281
333
  ) : null}
282
334
 
283
335
  <Animated.View style={fieldMotion.containerStyle}>
284
336
  <View style={[styles.inputContainer, inputContainerStyle]}>
285
- {motion ? (
337
+ {showFocusRing ? (
286
338
  <Animated.View
287
339
  pointerEvents="none"
288
340
  style={[
@@ -290,10 +342,9 @@ export const FieldFlowInput = forwardRef<TextInput, FieldFlowInputProps>(functio
290
342
  {
291
343
  opacity: fieldMotion.glowOpacity.interpolate({
292
344
  inputRange: [0, 1],
293
- outputRange: [0, 0.22],
345
+ outputRange: [0, focusRing === 'solid' ? 1 : 0.22],
294
346
  }),
295
347
  borderColor: theme.colors.borderFocused,
296
- borderRadius: theme.spacing.borderRadius + 2,
297
348
  },
298
349
  ]}
299
350
  />
@@ -332,12 +383,14 @@ export const FieldFlowInput = forwardRef<TextInput, FieldFlowInputProps>(functio
332
383
  placeholderTextColor={theme.colors.placeholder}
333
384
  keyboardType={fieldConfig.keyboardType}
334
385
  secureTextEntry={fieldConfig.secureTextEntry && !showPassword}
335
- autoCapitalize={fieldConfig.autoCapitalize}
336
- autoCorrect={fieldConfig.autoCorrect}
386
+ autoCapitalize={autofillProps?.autoCapitalize ?? fieldConfig.autoCapitalize}
387
+ autoCorrect={autofillProps?.autoCorrect ?? fieldConfig.autoCorrect}
337
388
  multiline={fieldConfig.multiline && type !== 'chat'}
338
389
  maxLength={maxLength}
339
390
  returnKeyType={fieldConfig.multiline ? 'default' : 'done'}
391
+ inputAccessoryViewID={inputAccessoryViewID}
340
392
  style={[styles.input, inputStyle]}
393
+ {...autofillProps}
341
394
  {...rest}
342
395
  />
343
396
 
@@ -383,13 +436,18 @@ export const FieldFlowInput = forwardRef<TextInput, FieldFlowInputProps>(functio
383
436
 
384
437
  {(helperText || resolvedError || successText || (showCharacterCount && maxLength)) && (
385
438
  <Animated.View style={[styles.footerRow, { opacity: fieldMotion.messageOpacity }]}>
386
- <View style={{ flex: 1 }}>
439
+ <View style={styles.helperRow}>
440
+ {helperIconName && (resolvedError || successText || helperText) ? (
441
+ <View style={{ marginTop: 1 }}>
442
+ {renderFieldFlowIcon(helperIconName, helperIconColor, 13)}
443
+ </View>
444
+ ) : null}
387
445
  {resolvedError ? (
388
- <Text style={[styles.errorText, errorStyle, helperStyle]}>{resolvedError}</Text>
446
+ <Text style={[helperTextStyle, errorStyle, helperStyle]}>{resolvedError}</Text>
389
447
  ) : successText ? (
390
- <Text style={[styles.successText, helperStyle]}>{successText}</Text>
448
+ <Text style={[helperTextStyle, helperStyle]}>{successText}</Text>
391
449
  ) : helperText ? (
392
- <Text style={[styles.helperText, helperStyle]}>{helperText}</Text>
450
+ <Text style={[helperTextStyle, helperStyle]}>{helperText}</Text>
393
451
  ) : null}
394
452
  </View>
395
453
  {showCharacterCount && maxLength ? (
@@ -1,5 +1,6 @@
1
1
  import { StyleSheet } from 'react-native';
2
2
  import type { FieldFlowState, FieldFlowTheme, FieldFlowVariant } from '../../types';
3
+ import { surfaceShadow } from '../../theme/appearance';
3
4
 
4
5
  export function borderColorFor(theme: FieldFlowTheme, state: FieldFlowState): string {
5
6
  switch (state) {
@@ -33,34 +34,51 @@ export function createStyles(
33
34
  const isUnderline = variant === 'underline';
34
35
  const isFilled = variant === 'filled';
35
36
  const isFloating = variant === 'floating';
37
+ const appearance = theme.appearance;
38
+ const surface = appearance?.surface ?? 'flat';
39
+ const focusRing = appearance?.focusRing ?? 'softGlow';
36
40
  const borderW = state === 'focused' ? theme.spacing.borderWidthFocused : theme.spacing.borderWidth;
41
+ const shadow = !isUnderline ? surfaceShadow(surface) : null;
42
+
43
+ let backgroundColor = theme.colors.background;
44
+ if (state === 'disabled') backgroundColor = theme.colors.backgroundDisabled;
45
+ else if (isFilled || surface === 'soft') backgroundColor = theme.colors.surfaceMuted ?? theme.colors.backgroundDisabled;
46
+ else if (surface === 'inset') backgroundColor = theme.colors.surfaceMuted ?? theme.colors.backgroundDisabled;
47
+ else if (surface === 'elevated') backgroundColor = theme.colors.surfaceElevated ?? theme.colors.background;
48
+ else if (isUnderline) backgroundColor = 'transparent';
49
+
50
+ const glowPad = focusRing === 'solid' ? 2 : focusRing === 'softGlow' ? 3 : 0;
37
51
 
38
52
  return StyleSheet.create({
39
53
  wrapper: {
40
54
  marginBottom: theme.spacing.gap * 2,
41
55
  },
56
+ labelRow: {
57
+ flexDirection: 'row',
58
+ alignItems: 'center',
59
+ gap: 6,
60
+ marginBottom: theme.spacing.gap / 1.5,
61
+ },
42
62
  label: {
43
63
  fontSize: theme.typography.labelFontSize,
44
- marginBottom: theme.spacing.gap / 1.5,
45
64
  color: labelColorFor(theme, state),
46
65
  fontWeight: '500',
47
66
  fontFamily: theme.typography.fontFamily,
67
+ flexShrink: 1,
48
68
  },
49
69
  inputContainer: {
50
70
  position: 'relative',
51
71
  overflow: 'visible',
52
72
  flexDirection: 'row',
53
73
  alignItems: multiline ? 'flex-start' : 'center',
54
- backgroundColor: state === 'disabled'
55
- ? theme.colors.backgroundDisabled
56
- : isFilled
57
- ? theme.colors.backgroundDisabled
58
- : isUnderline
59
- ? 'transparent'
60
- : theme.colors.background,
74
+ backgroundColor,
61
75
  borderRadius: isUnderline ? 0 : theme.spacing.borderRadius,
62
- borderWidth: isUnderline ? 0 : isFilled ? 0 : borderW,
63
- borderBottomWidth: isUnderline ? borderW + (state === 'focused' ? 0.5 : 0) : isFilled ? 0 : borderW,
76
+ borderWidth: isUnderline ? 0 : isFilled && surface !== 'inset' ? 0 : borderW,
77
+ borderBottomWidth: isUnderline
78
+ ? borderW + (state === 'focused' && focusRing === 'underlinePulse' ? 1 : state === 'focused' ? 0.5 : 0)
79
+ : isFilled && surface !== 'inset'
80
+ ? 0
81
+ : borderW,
64
82
  borderColor: borderColorFor(theme, state),
65
83
  paddingHorizontal: theme.spacing.paddingHorizontal,
66
84
  paddingVertical: multiline ? theme.spacing.paddingVertical : 0,
@@ -68,14 +86,16 @@ export function createStyles(
68
86
  ? undefined
69
87
  : theme.spacing.paddingVertical * 2 + theme.typography.fontSize + 6 + (isFloating ? 6 : 0),
70
88
  paddingTop: isFloating && !multiline ? theme.spacing.paddingVertical + 6 : undefined,
89
+ ...(shadow ?? null),
71
90
  },
72
91
  focusGlow: {
73
92
  position: 'absolute',
74
- top: -3,
75
- left: -3,
76
- right: -3,
77
- bottom: -3,
78
- borderWidth: 3,
93
+ top: -glowPad,
94
+ left: -glowPad,
95
+ right: -glowPad,
96
+ bottom: -glowPad,
97
+ borderWidth: focusRing === 'solid' ? 2 : focusRing === 'softGlow' ? 3 : 0,
98
+ borderRadius: theme.spacing.borderRadius + glowPad,
79
99
  },
80
100
  affixText: {
81
101
  fontSize: theme.typography.fontSize,
@@ -86,7 +106,9 @@ export function createStyles(
86
106
  floatingLabel: {
87
107
  position: 'absolute',
88
108
  left: theme.spacing.paddingHorizontal,
89
- backgroundColor: isFilled ? theme.colors.backgroundDisabled : theme.colors.background,
109
+ backgroundColor: isFilled || surface === 'soft' || surface === 'inset'
110
+ ? theme.colors.surfaceMuted ?? theme.colors.backgroundDisabled
111
+ : theme.colors.background,
90
112
  paddingHorizontal: 4,
91
113
  zIndex: 2,
92
114
  fontFamily: theme.typography.fontFamily,
@@ -114,8 +136,16 @@ export function createStyles(
114
136
  },
115
137
  footerRow: {
116
138
  flexDirection: 'row',
139
+ alignItems: 'flex-start',
117
140
  justifyContent: 'space-between',
118
141
  marginTop: theme.spacing.gap / 1.5,
142
+ gap: 6,
143
+ },
144
+ helperRow: {
145
+ flex: 1,
146
+ flexDirection: 'row',
147
+ alignItems: 'flex-start',
148
+ gap: 6,
119
149
  },
120
150
  helperText: {
121
151
  fontSize: theme.typography.helperFontSize,
@@ -135,6 +165,18 @@ export function createStyles(
135
165
  flexShrink: 1,
136
166
  fontFamily: theme.typography.fontFamily,
137
167
  },
168
+ warningText: {
169
+ fontSize: theme.typography.helperFontSize,
170
+ color: theme.colors.warning,
171
+ flexShrink: 1,
172
+ fontFamily: theme.typography.fontFamily,
173
+ },
174
+ infoText: {
175
+ fontSize: theme.typography.helperFontSize,
176
+ color: theme.colors.info,
177
+ flexShrink: 1,
178
+ fontFamily: theme.typography.fontFamily,
179
+ },
138
180
  charCount: {
139
181
  fontSize: theme.typography.helperFontSize,
140
182
  color: theme.colors.placeholder,
@@ -4,6 +4,7 @@ import type { FieldFlowFieldType, FieldFlowRules, FieldFlowVariant, DeepPartial,
4
4
  import type { FieldFlowIconSource } from '../../icons';
5
5
  import type { FieldFlowAffordanceChip, FieldFlowAffordanceKind } from '../../utils/affordance';
6
6
  import type { PasswordStrengthRule } from '../../utils/passwordStrength';
7
+ import type { FieldFlowAutofillRole } from '../../autofill/profiles';
7
8
 
8
9
  export interface FieldFlowInputProps
9
10
  extends Omit<TextInputProps, 'style' | 'onChangeText' | 'onFocus' | 'onBlur' | 'onSubmitEditing'> {
@@ -89,6 +90,26 @@ export interface FieldFlowInputProps
89
90
  */
90
91
  motion?: boolean;
91
92
 
93
+ /**
94
+ * Platform autofill role (`email`, `password`, `oneTimeCode`, …).
95
+ * When omitted, a sensible default is inferred from `type` (email/phone/password).
96
+ * Pass `off` to disable. See `autofillProfiles` for screen bundles.
97
+ */
98
+ autofill?: FieldFlowAutofillRole;
99
+
100
+ /**
101
+ * iOS keyboard accessory id — pair with `FieldFlowKeyboardToolbar` `nativeID`.
102
+ */
103
+ inputAccessoryViewID?: string;
104
+
105
+ /**
106
+ * Soft status icon beside helper / success / warning copy.
107
+ * Error state always shows an alert icon when helperStatus is unset.
108
+ */
109
+ helperStatus?: 'info' | 'success' | 'warning' | 'error' | 'none';
110
+ /** Tip text — renders a `FieldFlowInfoTip` next to the label. */
111
+ infoTip?: string;
112
+
92
113
  maxLength?: number;
93
114
  showCharacterCount?: boolean;
94
115
 
@@ -0,0 +1,150 @@
1
+ import React, { useMemo } from 'react';
2
+ import {
3
+ InputAccessoryView,
4
+ Keyboard,
5
+ Platform,
6
+ Pressable,
7
+ StyleSheet,
8
+ Text,
9
+ View,
10
+ type ViewStyle,
11
+ } from 'react-native';
12
+ import { useFieldFlowTheme, mergeDeep } from '../../theme/ThemeProvider';
13
+ import { defaultTheme } from '../../theme/defaultTheme';
14
+ import type { DeepPartial, FieldFlowTheme } from '../../types';
15
+
16
+ export interface FieldFlowKeyboardToolbarProps {
17
+ /** Must match `inputAccessoryViewID` on each TextInput (iOS). */
18
+ nativeID: string;
19
+ onPrevious?: () => void;
20
+ onNext?: () => void;
21
+ onDone?: () => void;
22
+ canPrevious?: boolean;
23
+ canNext?: boolean;
24
+ previousLabel?: string;
25
+ nextLabel?: string;
26
+ doneLabel?: string;
27
+ /** Also render a floating bar on Android (above keyboard region via absolute layout in parent). */
28
+ androidFloating?: boolean;
29
+ visible?: boolean;
30
+ containerStyle?: ViewStyle;
31
+ theme?: DeepPartial<FieldFlowTheme>;
32
+ testID?: string;
33
+ }
34
+
35
+ /**
36
+ * Prev / Next / Done accessory above the keyboard.
37
+ * iOS: native `InputAccessoryView`. Android: optional floating bar (`androidFloating`).
38
+ * Pair with `useKeyboardManager` focus helpers.
39
+ */
40
+ export function FieldFlowKeyboardToolbar({
41
+ nativeID,
42
+ onPrevious,
43
+ onNext,
44
+ onDone,
45
+ canPrevious = true,
46
+ canNext = true,
47
+ previousLabel = 'Previous',
48
+ nextLabel = 'Next',
49
+ doneLabel = 'Done',
50
+ androidFloating = true,
51
+ visible = true,
52
+ containerStyle,
53
+ theme: themeOverride,
54
+ testID,
55
+ }: FieldFlowKeyboardToolbarProps) {
56
+ const contextTheme = useFieldFlowTheme();
57
+ const theme = useMemo(
58
+ () => (themeOverride ? mergeDeep(contextTheme ?? defaultTheme, themeOverride) : contextTheme ?? defaultTheme),
59
+ [contextTheme, themeOverride],
60
+ );
61
+ const styles = useMemo(() => createStyles(theme), [theme]);
62
+
63
+ const bar = (
64
+ <View style={[styles.bar, containerStyle]} testID={testID}>
65
+ <Pressable
66
+ onPress={onPrevious}
67
+ disabled={!canPrevious || !onPrevious}
68
+ style={[styles.btn, (!canPrevious || !onPrevious) && styles.btnDisabled]}
69
+ accessibilityRole="button"
70
+ accessibilityLabel={previousLabel}
71
+ >
72
+ <Text style={styles.btnText}>{previousLabel}</Text>
73
+ </Pressable>
74
+ <Pressable
75
+ onPress={onNext}
76
+ disabled={!canNext || !onNext}
77
+ style={[styles.btn, (!canNext || !onNext) && styles.btnDisabled]}
78
+ accessibilityRole="button"
79
+ accessibilityLabel={nextLabel}
80
+ >
81
+ <Text style={styles.btnText}>{nextLabel}</Text>
82
+ </Pressable>
83
+ <View style={{ flex: 1 }} />
84
+ <Pressable
85
+ onPress={() => {
86
+ onDone?.();
87
+ Keyboard.dismiss();
88
+ }}
89
+ style={styles.done}
90
+ accessibilityRole="button"
91
+ accessibilityLabel={doneLabel}
92
+ >
93
+ <Text style={styles.doneText}>{doneLabel}</Text>
94
+ </Pressable>
95
+ </View>
96
+ );
97
+
98
+ if (!visible) return null;
99
+
100
+ if (Platform.OS === 'ios') {
101
+ return (
102
+ <InputAccessoryView nativeID={nativeID} backgroundColor={theme.colors.backgroundDisabled}>
103
+ {bar}
104
+ </InputAccessoryView>
105
+ );
106
+ }
107
+
108
+ if (!androidFloating) return null;
109
+ return <View style={styles.androidWrap}>{bar}</View>;
110
+ }
111
+
112
+ /** Stable default accessory id for FieldFlow forms. */
113
+ export const FIELD_FLOW_KEYBOARD_TOOLBAR_ID = 'fieldflow-keyboard-toolbar';
114
+
115
+ function createStyles(theme: FieldFlowTheme) {
116
+ return StyleSheet.create({
117
+ androidWrap: {
118
+ borderTopWidth: StyleSheet.hairlineWidth,
119
+ borderTopColor: theme.colors.border,
120
+ },
121
+ bar: {
122
+ flexDirection: 'row',
123
+ alignItems: 'center',
124
+ paddingHorizontal: 10,
125
+ paddingVertical: 8,
126
+ backgroundColor: theme.colors.backgroundDisabled,
127
+ borderTopWidth: StyleSheet.hairlineWidth,
128
+ borderTopColor: theme.colors.border,
129
+ gap: 4,
130
+ },
131
+ btn: { paddingHorizontal: 10, paddingVertical: 6 },
132
+ btnDisabled: { opacity: 0.35 },
133
+ btnText: {
134
+ fontSize: theme.typography.helperFontSize + 1,
135
+ color: theme.colors.borderFocused,
136
+ fontWeight: '600',
137
+ },
138
+ done: {
139
+ paddingHorizontal: 12,
140
+ paddingVertical: 6,
141
+ borderRadius: 8,
142
+ backgroundColor: theme.colors.borderFocused,
143
+ },
144
+ doneText: {
145
+ fontSize: theme.typography.helperFontSize + 1,
146
+ color: '#fff',
147
+ fontWeight: '700',
148
+ },
149
+ });
150
+ }
@@ -0,0 +1,5 @@
1
+ export {
2
+ FieldFlowKeyboardToolbar,
3
+ FIELD_FLOW_KEYBOARD_TOOLBAR_ID,
4
+ } from './FieldFlowKeyboardToolbar';
5
+ export type { FieldFlowKeyboardToolbarProps } from './FieldFlowKeyboardToolbar';
@@ -0,0 +1,105 @@
1
+ import React, { useEffect, useMemo, useRef } from 'react';
2
+ import { Animated, Easing, StyleSheet, View, type ViewStyle } from 'react-native';
3
+ import { useFieldFlowTheme, mergeDeep } from '../../theme/ThemeProvider';
4
+ import { defaultTheme } from '../../theme/defaultTheme';
5
+ import { useReducedMotion } from '../../motion/useReducedMotion';
6
+ import type { DeepPartial, FieldFlowTheme, FieldFlowVariant } from '../../types';
7
+
8
+ export interface FieldFlowSkeletonProps {
9
+ /** How many fake fields to show. Default: 3. */
10
+ count?: number;
11
+ /** Match your form variant for realistic height. */
12
+ variant?: FieldFlowVariant;
13
+ /** Show label bars. Default: true. */
14
+ showLabels?: boolean;
15
+ /** Multiline taller block on last item. */
16
+ lastMultiline?: boolean;
17
+ containerStyle?: ViewStyle;
18
+ theme?: DeepPartial<FieldFlowTheme>;
19
+ testID?: string;
20
+ }
21
+
22
+ /**
23
+ * Soft shimmer placeholders while a form hydrates (draft / API).
24
+ */
25
+ export function FieldFlowSkeleton({
26
+ count = 3,
27
+ variant = 'outlined',
28
+ showLabels = true,
29
+ lastMultiline = false,
30
+ containerStyle,
31
+ theme: themeOverride,
32
+ testID,
33
+ }: FieldFlowSkeletonProps) {
34
+ const contextTheme = useFieldFlowTheme();
35
+ const theme = useMemo(
36
+ () => (themeOverride ? mergeDeep(contextTheme ?? defaultTheme, themeOverride) : contextTheme ?? defaultTheme),
37
+ [contextTheme, themeOverride],
38
+ );
39
+ const styles = useMemo(() => createStyles(theme, variant), [theme, variant]);
40
+ const reducedMotion = useReducedMotion();
41
+ const pulse = useRef(new Animated.Value(0.45)).current;
42
+
43
+ useEffect(() => {
44
+ if (reducedMotion) {
45
+ pulse.setValue(0.55);
46
+ return;
47
+ }
48
+ const loop = Animated.loop(
49
+ Animated.sequence([
50
+ Animated.timing(pulse, {
51
+ toValue: 0.9,
52
+ duration: 700,
53
+ easing: Easing.inOut(Easing.quad),
54
+ useNativeDriver: true,
55
+ }),
56
+ Animated.timing(pulse, {
57
+ toValue: 0.45,
58
+ duration: 700,
59
+ easing: Easing.inOut(Easing.quad),
60
+ useNativeDriver: true,
61
+ }),
62
+ ]),
63
+ );
64
+ loop.start();
65
+ return () => loop.stop();
66
+ }, [reducedMotion, pulse]);
67
+
68
+ return (
69
+ <View style={[styles.wrap, containerStyle]} testID={testID} accessibilityLabel="Loading form">
70
+ {Array.from({ length: count }, (_, i) => {
71
+ const tall = lastMultiline && i === count - 1;
72
+ return (
73
+ <View key={i} style={styles.item}>
74
+ {showLabels ? <Animated.View style={[styles.label, { opacity: pulse }]} /> : null}
75
+ <Animated.View style={[styles.field, tall && styles.fieldTall, { opacity: pulse }]} />
76
+ </View>
77
+ );
78
+ })}
79
+ </View>
80
+ );
81
+ }
82
+
83
+ function createStyles(theme: FieldFlowTheme, variant: FieldFlowVariant) {
84
+ const height =
85
+ theme.spacing.paddingVertical * 2 + theme.typography.fontSize + 6 + (variant === 'floating' ? 6 : 0);
86
+ return StyleSheet.create({
87
+ wrap: { marginBottom: theme.spacing.gap },
88
+ item: { marginBottom: theme.spacing.gap * 2 },
89
+ label: {
90
+ width: '32%',
91
+ height: theme.typography.labelFontSize,
92
+ borderRadius: 4,
93
+ backgroundColor: theme.colors.backgroundDisabled,
94
+ marginBottom: theme.spacing.gap,
95
+ },
96
+ field: {
97
+ height,
98
+ borderRadius: theme.spacing.borderRadius,
99
+ backgroundColor: theme.colors.backgroundDisabled,
100
+ borderWidth: StyleSheet.hairlineWidth,
101
+ borderColor: theme.colors.border,
102
+ },
103
+ fieldTall: { height: 88 },
104
+ });
105
+ }
@@ -0,0 +1,2 @@
1
+ export { FieldFlowSkeleton } from './FieldFlowSkeleton';
2
+ export type { FieldFlowSkeletonProps } from './FieldFlowSkeleton';
@@ -1,9 +1,10 @@
1
- import React from 'react';
1
+ import React, { useRef } from 'react';
2
2
  import { KeyboardAvoidingView, Platform, ScrollView, StyleSheet, ViewStyle } from 'react-native';
3
3
  import type { UseKeyboardManagerResult } from '../../hooks/useKeyboardManager';
4
4
 
5
5
  export interface KeyboardAwareFormWrapperProps {
6
- keyboardManager: Pick<UseKeyboardManagerResult, 'scrollViewRef'>;
6
+ /** Optional — omit when you only need keyboard-avoiding scroll without Next/Done chaining. */
7
+ keyboardManager?: Pick<UseKeyboardManagerResult, 'scrollViewRef'>;
7
8
  children: React.ReactNode;
8
9
  contentContainerStyle?: ViewStyle;
9
10
  style?: ViewStyle;
@@ -13,7 +14,7 @@ export interface KeyboardAwareFormWrapperProps {
13
14
  * Wrap your form fields in this instead of a plain ScrollView. It automatically
14
15
  * keeps the focused field visible above the keyboard and animates smoothly on
15
16
  * both iOS and Android; pass it the same `keyboardManager` you got from
16
- * `useKeyboardManager()`.
17
+ * `useKeyboardManager()` when you want auto-scroll + Next/Done focus.
17
18
  */
18
19
  export function KeyboardAwareFormWrapper({
19
20
  keyboardManager,
@@ -21,6 +22,9 @@ export function KeyboardAwareFormWrapper({
21
22
  contentContainerStyle,
22
23
  style,
23
24
  }: KeyboardAwareFormWrapperProps) {
25
+ const fallbackScrollRef = useRef<ScrollView>(null);
26
+ const scrollRef = keyboardManager?.scrollViewRef ?? fallbackScrollRef;
27
+
24
28
  return (
25
29
  <KeyboardAvoidingView
26
30
  style={[styles.flex, style]}
@@ -28,7 +32,7 @@ export function KeyboardAwareFormWrapper({
28
32
  keyboardVerticalOffset={Platform.OS === 'ios' ? 64 : 0}
29
33
  >
30
34
  <ScrollView
31
- ref={keyboardManager.scrollViewRef}
35
+ ref={scrollRef}
32
36
  keyboardShouldPersistTaps="handled"
33
37
  contentContainerStyle={[styles.content, contentContainerStyle]}
34
38
  showsVerticalScrollIndicator={false}
@@ -44,3 +44,20 @@ export type {
44
44
  UseFieldFlowDirtyGuardOptions,
45
45
  UseFieldFlowDirtyGuardResult,
46
46
  } from './useFieldFlowDirtyGuard';
47
+
48
+ export { useFieldFlowCompleteness } from './useFieldFlowCompleteness';
49
+ export type {
50
+ UseFieldFlowCompletenessOptions,
51
+ UseFieldFlowCompletenessResult,
52
+ } from './useFieldFlowCompleteness';
53
+
54
+ export { useFieldFlowSubmitQueue } from './useFieldFlowSubmitQueue';
55
+ export type {
56
+ FieldFlowSubmitJob,
57
+ FieldFlowSubmitQueueStorage,
58
+ UseFieldFlowSubmitQueueOptions,
59
+ UseFieldFlowSubmitQueueResult,
60
+ } from './useFieldFlowSubmitQueue';
61
+
62
+ export { useSmartPaste } from './useSmartPaste';
63
+ export type { UseSmartPasteOptions } from './useSmartPaste';