@myazahq/kyc-sdk-react-native 2.5.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/README.md +277 -7
  2. package/android/build.gradle +30 -16
  3. package/android/consumer-rules.pro +22 -0
  4. package/android/src/main/AndroidManifest.xml +17 -6
  5. package/android/src/main/java/com/margelo/nitro/myazakyc/HybridMyazaFaceDetector.kt +27 -70
  6. package/android/src/main/java/com/margelo/nitro/myazakyc/HybridMyazaTextRecognizer.kt +14 -0
  7. package/android/src/main/java/com/margelo/nitro/myazakyc/MlKitModelReadiness.kt +154 -0
  8. package/app.plugin.js +146 -10
  9. package/ios/HybridMyazaFaceDetector.swift +8 -3
  10. package/ios/HybridMyazaTextRecognizer.swift +8 -0
  11. package/nitrogen/generated/android/c++/JHybridMyazaTextRecognizerSpec.cpp +21 -0
  12. package/nitrogen/generated/android/c++/JHybridMyazaTextRecognizerSpec.hpp +2 -0
  13. package/nitrogen/generated/android/kotlin/com/margelo/nitro/myazakyc/HybridMyazaTextRecognizerSpec.kt +8 -0
  14. package/nitrogen/generated/ios/c++/HybridMyazaTextRecognizerSpecSwift.hpp +16 -0
  15. package/nitrogen/generated/ios/swift/HybridMyazaTextRecognizerSpec.swift +2 -0
  16. package/nitrogen/generated/ios/swift/HybridMyazaTextRecognizerSpec_cxx.swift +31 -0
  17. package/nitrogen/generated/shared/c++/HybridMyazaTextRecognizerSpec.cpp +2 -0
  18. package/nitrogen/generated/shared/c++/HybridMyazaTextRecognizerSpec.hpp +2 -0
  19. package/package.json +30 -9
  20. package/src/MyazaKYC.tsx +4 -11
  21. package/src/assets/fonts/Karla_400Regular.ttf +0 -0
  22. package/src/assets/fonts/Karla_500Medium.ttf +0 -0
  23. package/src/assets/fonts/Karla_600SemiBold.ttf +0 -0
  24. package/src/assets/fonts/Karla_700Bold.ttf +0 -0
  25. package/src/assets/fonts/OFL-Karla.txt +93 -0
  26. package/src/assets/fonts/OFL-SpaceGrotesk.txt +93 -0
  27. package/src/assets/fonts/README.md +12 -0
  28. package/src/assets/fonts/SpaceGrotesk_500Medium.ttf +0 -0
  29. package/src/assets/fonts/SpaceGrotesk_600SemiBold.ttf +0 -0
  30. package/src/assets/fonts/SpaceGrotesk_700Bold.ttf +0 -0
  31. package/src/capture/useAutoCapture.ts +8 -1
  32. package/src/components/CountryField.tsx +8 -0
  33. package/src/components/CountryRegionPicker.tsx +184 -0
  34. package/src/components/DialCodePicker.tsx +47 -68
  35. package/src/components/DialCodeRow.tsx +102 -0
  36. package/src/components/DocumentCropper.tsx +30 -24
  37. package/src/components/DocumentReview.tsx +11 -1
  38. package/src/components/DocumentReviewSide.tsx +6 -2
  39. package/src/components/DocumentReviewZoom.tsx +5 -1
  40. package/src/components/FramedMapPicker.tsx +122 -0
  41. package/src/components/GeoBadge.tsx +34 -0
  42. package/src/components/Icon.tsx +10 -192
  43. package/src/components/KycFlow.tsx +69 -34
  44. package/src/components/LineSkeleton.tsx +100 -0
  45. package/src/components/MapChrome.tsx +67 -0
  46. package/src/components/MapPinMarker.tsx +54 -0
  47. package/src/components/MapPinPicker.tsx +179 -0
  48. package/src/components/MilestoneTrack.tsx +155 -0
  49. package/src/components/MyazaButton.tsx +9 -0
  50. package/src/components/MyazaInput.tsx +17 -1
  51. package/src/components/OptionRow.tsx +22 -3
  52. package/src/components/PhoneNumberInput.tsx +8 -0
  53. package/src/components/PoweredBy.tsx +5 -5
  54. package/src/components/PresenceBlocks.tsx +153 -0
  55. package/src/components/RequiredDocumentPill.tsx +114 -0
  56. package/src/components/StepHeader.tsx +23 -3
  57. package/src/components/StepView.tsx +17 -0
  58. package/src/components/StickyActions.tsx +56 -0
  59. package/src/components/dialCodeRows.ts +64 -0
  60. package/src/components/documentReviewCopy.ts +39 -0
  61. package/src/components/fonts.ts +14 -17
  62. package/src/components/icon-map.ts +176 -0
  63. package/src/components/stepHeaderMeta.tsx +48 -5
  64. package/src/config/addressCollection.ts +125 -0
  65. package/src/config/biometricOptions.ts +100 -0
  66. package/src/config/business.ts +20 -1
  67. package/src/config/businessSteps.ts +8 -2
  68. package/src/config/consentStep.ts +19 -0
  69. package/src/config/documentCaptureMethods.ts +31 -0
  70. package/src/config/proofOfAddress.ts +54 -11
  71. package/src/config/regions.ts +24 -0
  72. package/src/config/stepOrder.ts +79 -5
  73. package/src/config/uploadLimits.ts +35 -0
  74. package/src/config/workflowMerge.ts +13 -5
  75. package/src/index.ts +49 -1
  76. package/src/lib/address-current-location.ts +171 -0
  77. package/src/lib/address-field-modes.ts +119 -0
  78. package/src/lib/address-flow.ts +172 -0
  79. package/src/lib/address-helpers.ts +48 -0
  80. package/src/lib/address-line.ts +76 -0
  81. package/src/lib/address-pin-move.ts +97 -0
  82. package/src/lib/address-step-recovery.ts +63 -0
  83. package/src/lib/authed-image.ts +78 -0
  84. package/src/lib/biometric-copy.ts +51 -0
  85. package/src/lib/captureRing.ts +83 -0
  86. package/src/lib/country-adoption.ts +89 -0
  87. package/src/lib/documentCaptureCheck.ts +136 -0
  88. package/src/lib/inferred-country.ts +65 -0
  89. package/src/lib/livenessLayout.ts +49 -0
  90. package/src/lib/map-frame.ts +159 -0
  91. package/src/lib/map-tiles.ts +143 -0
  92. package/src/lib/model-ready.ts +82 -0
  93. package/src/lib/poa-country-gate.ts +27 -0
  94. package/src/lib/prime-models.ts +50 -0
  95. package/src/lib/resubmit.ts +36 -7
  96. package/src/lib/result-copy.ts +116 -0
  97. package/src/lib/result-wait.ts +53 -0
  98. package/src/lib/review-map-surface.ts +26 -0
  99. package/src/lib/scope.ts +31 -0
  100. package/src/lib/selfie-sharpness.ts +211 -0
  101. package/src/lib/selfie-upload-wait.ts +79 -0
  102. package/src/lib/street-view-fov.ts +42 -0
  103. package/src/lib/webview-available.ts +47 -0
  104. package/src/liveness/avatarSource.ts +59 -0
  105. package/src/liveness/useLiveness.ts +6 -1
  106. package/src/liveness/useModelReady.ts +9 -55
  107. package/src/mrz/extract.ts +71 -4
  108. package/src/mrz/textRecognizer.ts +36 -0
  109. package/src/mrz/useTextModelReady.ts +21 -0
  110. package/src/presence/background-math.ts +100 -0
  111. package/src/presence/background-store.ts +82 -0
  112. package/src/presence/background.ts +165 -0
  113. package/src/presence/foreground-service.ts +193 -0
  114. package/src/presence/fs.ts +51 -0
  115. package/src/presence/geofence.ts +41 -0
  116. package/src/presence/math.ts +44 -0
  117. package/src/presence/post.ts +40 -0
  118. package/src/presence/report.ts +87 -0
  119. package/src/presence/sampler.ts +110 -0
  120. package/src/presence/status.ts +92 -0
  121. package/src/presence/store.ts +94 -0
  122. package/src/presence/tier.ts +36 -0
  123. package/src/presence/watch-wait.ts +81 -0
  124. package/src/screens/AddressCountryControl.tsx +115 -0
  125. package/src/screens/BusinessDetailsFields.tsx +3 -0
  126. package/src/screens/BusinessDetailsStep.tsx +2 -0
  127. package/src/screens/BusinessDocumentSlot.tsx +3 -2
  128. package/src/screens/BusinessDocumentsStep.tsx +4 -55
  129. package/src/screens/CompanyInfoFields.tsx +6 -1
  130. package/src/screens/ConsentStep.tsx +6 -17
  131. package/src/screens/ContactActions.tsx +54 -0
  132. package/src/screens/ContactDestinationField.tsx +4 -0
  133. package/src/screens/ContactEntryPanel.tsx +75 -0
  134. package/src/screens/ContactVerificationStep.tsx +26 -56
  135. package/src/screens/CountrySelectStep.tsx +13 -147
  136. package/src/screens/DocumentCaptureStep.tsx +177 -93
  137. package/src/screens/LivenessAvatar.tsx +33 -16
  138. package/src/screens/LivenessStep.tsx +188 -49
  139. package/src/screens/MrzScanView.tsx +33 -0
  140. package/src/screens/PoaDocumentTypeList.tsx +66 -0
  141. package/src/screens/ProofOfAddressParts.tsx +151 -0
  142. package/src/screens/ProofOfAddressStep.tsx +58 -99
  143. package/src/screens/SubmittedBadge.tsx +25 -0
  144. package/src/screens/SubmittedError.tsx +64 -0
  145. package/src/screens/SubmittedResult.tsx +117 -0
  146. package/src/screens/SubmittedStep.tsx +71 -164
  147. package/src/screens/SubmittedSuccess.tsx +127 -0
  148. package/src/screens/SubmittedWaiting.tsx +45 -0
  149. package/src/screens/address/AddressEntranceStep.tsx +161 -0
  150. package/src/screens/address/AddressIntroGate.tsx +148 -0
  151. package/src/screens/address/AddressMapStub.tsx +50 -0
  152. package/src/screens/address/AddressPinStep.tsx +178 -0
  153. package/src/screens/address/AddressReviewStep.tsx +162 -0
  154. package/src/screens/address/AddressSandboxTabs.tsx +158 -0
  155. package/src/screens/address/AddressSearchField.tsx +115 -0
  156. package/src/screens/address/AddressSearchStep.tsx +94 -0
  157. package/src/screens/address/CurrentLocationRow.tsx +135 -0
  158. package/src/screens/address/DetailsSheet.tsx +175 -0
  159. package/src/screens/address/DetailsSheetFields.tsx +184 -0
  160. package/src/screens/address/EntranceDropzone.tsx +178 -0
  161. package/src/screens/address/EntranceFraming.tsx +66 -0
  162. package/src/screens/address/EntrancePills.tsx +60 -0
  163. package/src/screens/address/FramedStreetView.tsx +155 -0
  164. package/src/screens/address/IntroDisclosures.tsx +210 -0
  165. package/src/screens/address/LabelDecisionRow.tsx +113 -0
  166. package/src/screens/address/PinSummaryRow.tsx +105 -0
  167. package/src/screens/address/ReviewAddressBand.tsx +111 -0
  168. package/src/screens/address/ReviewEntranceThumbs.tsx +64 -0
  169. package/src/screens/address/ReviewMapPicture.tsx +106 -0
  170. package/src/screens/address/SearchResults.tsx +105 -0
  171. package/src/screens/address/SearchScreen.tsx +176 -0
  172. package/src/screens/address/SkipForNow.tsx +43 -0
  173. package/src/screens/address/StreetViewChrome.tsx +81 -0
  174. package/src/screens/address/detail-values.ts +22 -0
  175. package/src/screens/address/fix-source.ts +27 -0
  176. package/src/screens/address/index.ts +8 -0
  177. package/src/screens/address/meta.ts +44 -0
  178. package/src/screens/address/use-address-flow.ts +200 -0
  179. package/src/screens/address/use-label-pin.ts +80 -0
  180. package/src/screens/address/use-pin-actions.ts +192 -0
  181. package/src/screens/consent/model.ts +79 -10
  182. package/src/screens/document/CaptureCheckNotice.tsx +77 -0
  183. package/src/screens/document/UploadPhase.tsx +177 -0
  184. package/src/screens/document/useDocumentCamera.ts +109 -0
  185. package/src/screens/liveness/CaptureRing.tsx +91 -0
  186. package/src/screens/liveness/LivenessCamera.tsx +63 -0
  187. package/src/screens/liveness/LivenessHandover.tsx +43 -0
  188. package/src/screens/liveness/LivenessOutcome.tsx +8 -4
  189. package/src/screens/liveness/SelfiePreview.tsx +31 -7
  190. package/src/screens/liveness/ShutterFlash.tsx +25 -0
  191. package/src/screens/liveness/index.ts +4 -0
  192. package/src/screens/liveness/useSelfieUpload.ts +23 -3
  193. package/src/screens/nfc/NfcScanIllustration.tsx +7 -18
  194. package/src/screens/useAddressPhotoAttach.ts +77 -0
  195. package/src/screens/useBusinessDocumentAttach.ts +93 -0
  196. package/src/screens/usePoaAttach.ts +12 -15
  197. package/src/services/api-types.ts +119 -1
  198. package/src/services/api-verify-types.ts +37 -0
  199. package/src/services/api.ts +149 -3
  200. package/src/services/deviceMetadata.ts +1 -1
  201. package/src/services/location.ts +234 -0
  202. package/src/services/mediaCompress.ts +23 -5
  203. package/src/services/uploadErrors.ts +30 -0
  204. package/src/services/workflowGate.ts +7 -0
  205. package/src/specs/MyazaTextRecognizer.nitro.ts +29 -0
  206. package/src/store/address.ts +97 -0
  207. package/src/store/derive.ts +29 -4
  208. package/src/store/kycStore.ts +120 -5
  209. package/src/store/serverConfig.ts +18 -0
  210. package/src/store/session.ts +23 -4
  211. package/src/store/state.ts +134 -0
  212. package/src/store/submit.ts +18 -1
  213. package/src/types/config.ts +63 -1
  214. package/src/types/verification.ts +12 -0
  215. package/src/types/workflow.ts +97 -1
  216. package/src/assets/liveness/Blink.gif +0 -0
  217. package/src/assets/liveness/Nod.gif +0 -0
  218. package/src/assets/liveness/Smile.gif +0 -0
  219. package/src/assets/liveness/Turn.gif +0 -0
@@ -0,0 +1,93 @@
1
+ Copyright 2019 The Karla Project Authors (https://github.com/googlefonts/karla)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ https://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,93 @@
1
+ Copyright 2020 The Space Grotesk Project Authors (https://github.com/floriankarsten/space-grotesk)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,12 @@
1
+ # Bundled typefaces
2
+
3
+ The seven faces the SDK draws with, and nothing else: Karla 400/500/600/700
4
+ (body) and Space Grotesk 500/600/700 (headings). Both families are Google
5
+ Fonts under the SIL Open Font License 1.1; the licence for each sits beside
6
+ the files (`OFL-Karla.txt`, `OFL-SpaceGrotesk.txt`).
7
+
8
+ They are vendored rather than imported from the `@expo-google-fonts` packages
9
+ because Metro bundles every `require` in a package index whether or not the
10
+ export is used, so those two packages put all 19 of their font files (1.85 MB)
11
+ into every integrator's app for the seven faces the SDK uses. Add a weight here
12
+ only when `config/font-resolve.ts` resolves to it.
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import { useFrameOutput } from 'react-native-vision-camera';
3
3
  import { runOnJS } from 'react-native-worklets';
4
4
 
5
- import { hasTextRecognizer, recognizeAllLines } from '../mrz/textRecognizer';
5
+ import { hasTextRecognizer, primeTextModel, recognizeAllLines } from '../mrz/textRecognizer';
6
6
  import { extractMrz } from '../mrz/extract';
7
7
  import type { MrzScan } from '../mrz/parse';
8
8
  import { DocumentTextGate } from './documentTextGate';
@@ -97,6 +97,13 @@ export function useAutoCapture({
97
97
  // body is the one place that is both.
98
98
  hasTextRecognizer();
99
99
  hasRectDetector();
100
+ // Android fetches the text model through Play Services, so start it here too.
101
+ // The flow primes at open and this is normally a no-op, but the document step
102
+ // can be reached directly in a resumed session. Auto-capture deliberately does
103
+ // NOT gate on readiness: it is an accelerator, the manual shutter is live
104
+ // throughout, so a model that never arrives costs convenience rather than
105
+ // leaving the user stuck.
106
+ primeTextModel();
100
107
 
101
108
  const gate = useMemo(() => new DocumentTextGate(), []);
102
109
  const [guidance, setGuidance] = useState<DocumentGuidance>(INITIAL);
@@ -21,6 +21,8 @@ export function CountryField({
21
21
  value,
22
22
  options,
23
23
  onChange,
24
+ geoCountry,
25
+ grouped,
24
26
  placeholder = 'Select a country',
25
27
  searchPlaceholder = 'Search country',
26
28
  }: {
@@ -29,6 +31,10 @@ export function CountryField({
29
31
  /** The pickable countries — all ISO, or a workflow's registry subset. */
30
32
  options: DialCodeOption[];
31
33
  onChange: (code: string) => void;
34
+ /** The visitor's inferred country, pinned on top of the sheet as "Your location". */
35
+ geoCountry?: string | null;
36
+ /** Region headers between the rows, the country-select step's way. */
37
+ grouped?: boolean;
32
38
  placeholder?: string;
33
39
  searchPlaceholder?: string;
34
40
  }): React.ReactElement {
@@ -75,6 +81,8 @@ export function CountryField({
75
81
  visible={open}
76
82
  options={options}
77
83
  selected={value ?? ''}
84
+ pinned={geoCountry}
85
+ grouped={grouped}
78
86
  searchPlaceholder={searchPlaceholder}
79
87
  onPick={(code) => {
80
88
  setOpen(false);
@@ -0,0 +1,184 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import { Pressable, ScrollView, View } from 'react-native';
3
+
4
+ import { radius, spacing } from '../config/theme';
5
+ import { groupCountriesByRegion, pinGeoRow, regionCountryName } from '../config/regions';
6
+ import { useTheme } from './runtime';
7
+ import { MyazaText } from './Typography';
8
+ import { MyazaInput } from './MyazaInput';
9
+ import { CountryFlag } from './CountryFlag';
10
+ import { Icon } from './Icon';
11
+ import { GeoBadge } from './GeoBadge';
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Searchable, region-grouped country picker for the country-select step. Used
15
+ // when a workflow offers many countries (Global Documents): a flat 200-country
16
+ // list is a scroll, not a chooser, so this adds a pinned search box and
17
+ // continent headers over a bounded scroll area. Mirrors the web SDK's
18
+ // CountryRegionPicker and Flutter's country_region_picker.dart.
19
+ //
20
+ // Split from CountrySelectStep (200-line rule); the step keeps the flat list
21
+ // and the threshold that decides between the two.
22
+ // ---------------------------------------------------------------------------
23
+
24
+ export function CountryRegionPicker({
25
+ countries,
26
+ selected,
27
+ geoCountry,
28
+ onPick,
29
+ }: {
30
+ countries: string[];
31
+ selected: string | null;
32
+ /**
33
+ * The visitor's IP country. Lifted out of its continent to the very top and
34
+ * tagged, so the one country most likely to be theirs is the first thing
35
+ * they see rather than something to scroll for.
36
+ */
37
+ geoCountry?: string | null;
38
+ onPick: (country: string) => void;
39
+ }): React.ReactElement {
40
+ const { colors } = useTheme();
41
+ const [query, setQuery] = useState('');
42
+
43
+ const { pinned, groups } = useMemo(() => {
44
+ const needle = query.trim().toLowerCase();
45
+ const visible = needle
46
+ ? countries.filter(
47
+ (code) =>
48
+ code.toLowerCase().includes(needle) ||
49
+ regionCountryName(code).toLowerCase().includes(needle),
50
+ )
51
+ : countries;
52
+ const split = pinGeoRow(visible, geoCountry, (code) => code);
53
+ return { pinned: split.pinned, groups: groupCountriesByRegion(split.rest) };
54
+ }, [countries, query, geoCountry]);
55
+
56
+ const empty = groups.length === 0 && pinned === null;
57
+
58
+ return (
59
+ // The search box stays put and the list owns its own scroll, so a
60
+ // ~240-country flow does not scroll the search field off the top. That
61
+ // relies on the SHEET rendering this step with `fillsViewport` — inside a
62
+ // scroll view the nested list below would take an unbounded height, outgrow
63
+ // the viewport, and drag the search box off the top with it.
64
+ <View style={{ flex: 1 }}>
65
+ <MyazaInput
66
+ value={query}
67
+ onChangeText={setQuery}
68
+ placeholder="Search countries…"
69
+ autoCapitalize="none"
70
+ prefix={<Icon name="search" size={18} color={colors.textSecondary} />}
71
+ />
72
+ <View style={{ height: spacing.md }} />
73
+
74
+ {empty ? (
75
+ <MyazaText variant="bodyMedium" style={{ textAlign: 'center', marginTop: spacing.lg }}>
76
+ No countries match your search.
77
+ </MyazaText>
78
+ ) : (
79
+ // `nestedScrollEnabled` stays: Android refuses to scroll a nested
80
+ // same-direction list without it, and this is still nested on the
81
+ // flat-list path and inside any future scrolling parent.
82
+ <ScrollView
83
+ nestedScrollEnabled
84
+ keyboardShouldPersistTaps="handled"
85
+ showsVerticalScrollIndicator={false}
86
+ >
87
+ {pinned ? (
88
+ <CountryRow
89
+ code={pinned}
90
+ name={regionCountryName(pinned)}
91
+ selected={pinned === selected}
92
+ badge="Your location"
93
+ onPress={() => onPick(pinned)}
94
+ />
95
+ ) : null}
96
+ {groups.map((group) => (
97
+ <View key={group.region}>
98
+ {/* Uppercase, tracked-out section label — Flutter's region
99
+ header. Lowercase text at the default weight read as another
100
+ list row rather than a divider. */}
101
+ <MyazaText
102
+ variant="bodySmall"
103
+ color={colors.textSecondary}
104
+ style={{
105
+ fontWeight: '700',
106
+ letterSpacing: 0.6,
107
+ paddingHorizontal: spacing.xs,
108
+ paddingVertical: spacing.sm,
109
+ }}
110
+ >
111
+ {group.region.toUpperCase()}
112
+ </MyazaText>
113
+ {group.countries.map((entry) => (
114
+ <CountryRow
115
+ key={entry.code}
116
+ code={entry.code}
117
+ name={entry.name}
118
+ selected={entry.code === selected}
119
+ onPress={() => onPick(entry.code)}
120
+ />
121
+ ))}
122
+ </View>
123
+ ))}
124
+ </ScrollView>
125
+ )}
126
+ </View>
127
+ );
128
+ }
129
+
130
+ /**
131
+ * One selectable country row, shared by the flat list and the region picker
132
+ * so the two cannot drift apart. `badge` tags the pinned geo row; it is the
133
+ * same control in a second position, differing only by the tag.
134
+ */
135
+ export function CountryRow({
136
+ code,
137
+ name,
138
+ selected,
139
+ badge,
140
+ onPress,
141
+ }: {
142
+ code: string;
143
+ name: string;
144
+ selected: boolean;
145
+ badge?: string;
146
+ onPress: () => void;
147
+ }): React.ReactElement {
148
+ const { colors } = useTheme();
149
+ return (
150
+ <Pressable
151
+ onPress={onPress}
152
+ accessibilityRole="radio"
153
+ accessibilityState={{ checked: selected }}
154
+ accessibilityLabel={badge ? `${name}, ${badge.toLowerCase()}` : name}
155
+ // Matches the Flutter SDK's CountryOptionTile exactly — the two had
156
+ // drifted (24px flag / 12px padding here vs 32 / 16 there), which is why
157
+ // the same screen looked like a different component on each platform. The
158
+ // spacing and radius scales are identical across the SDKs, so there is
159
+ // nothing platform-specific to reconcile: `md` means 16 on both.
160
+ style={{
161
+ flexDirection: 'row',
162
+ alignItems: 'center',
163
+ padding: spacing.md,
164
+ borderRadius: radius.md,
165
+ borderWidth: selected ? 1.5 : 1,
166
+ borderColor: selected ? colors.primary : colors.border,
167
+ backgroundColor: selected ? colors.primary50 : colors.background,
168
+ marginBottom: spacing.sm,
169
+ }}
170
+ >
171
+ <CountryFlag country={code} size={32} />
172
+ <View style={{ width: 12 }} />
173
+ <MyazaText variant="label" style={{ flex: 1, fontWeight: '500' }}>
174
+ {name}
175
+ </MyazaText>
176
+ {badge ? <GeoBadge label={badge} /> : null}
177
+ <Icon
178
+ name="chevron-right"
179
+ size={18}
180
+ color={selected ? colors.primary : colors.textSecondary}
181
+ />
182
+ </Pressable>
183
+ );
184
+ }
@@ -13,8 +13,9 @@ import { useTheme } from './runtime';
13
13
  import { MyazaText } from './Typography';
14
14
  import { MyazaInput } from './MyazaInput';
15
15
  import { Icon } from './Icon';
16
- import { CountryFlag } from './CountryFlag';
17
16
  import { FloatingSheet } from './glass/FloatingSheet';
17
+ import { DialCodeDivider, DialCodeRegionHeader, DialCodeRow } from './DialCodeRow';
18
+ import { buildDialCodeItems, dialCodeItemKey, filterDialCodeOptions, type DialCodeItem } from './dialCodeRows';
18
19
 
19
20
  // ---------------------------------------------------------------------------
20
21
  // THE country sheet — the phone field's dial-code picker, generalised.
@@ -33,6 +34,10 @@ import { FloatingSheet } from './glass/FloatingSheet';
33
34
  // The sheet is sized against the space left ABOVE the keyboard, like Flutter's.
34
35
  // The search field autofocuses, so measuring against the full screen would put
35
36
  // every result underneath the keys the moment the user started typing.
37
+ //
38
+ // `grouped` lists the countries under region headers (Africa first), the way
39
+ // the country-select step does — what the address-scope country control asks
40
+ // for. The list itself is built by dialCodeRows.ts.
36
41
  // ---------------------------------------------------------------------------
37
42
 
38
43
  export interface DialCodeOption {
@@ -46,6 +51,8 @@ export function DialCodePicker({
46
51
  visible,
47
52
  options,
48
53
  selected,
54
+ pinned,
55
+ grouped = false,
49
56
  onPick,
50
57
  onClose,
51
58
  searchPlaceholder = 'Search country or code',
@@ -53,6 +60,14 @@ export function DialCodePicker({
53
60
  visible: boolean;
54
61
  options: DialCodeOption[];
55
62
  selected: string;
63
+ /**
64
+ * The visitor's IP country. Lifted out of the alphabet to the top and
65
+ * tagged, so a guess we made on their behalf is visible AS a guess and one
66
+ * tap away rather than buried among two hundred others.
67
+ */
68
+ pinned?: string | null;
69
+ /** Region headers between the rows (the pinned row stays on top). */
70
+ grouped?: boolean;
56
71
  onPick: (code: string) => void;
57
72
  onClose: () => void;
58
73
  searchPlaceholder?: string;
@@ -78,19 +93,13 @@ export function DialCodePicker({
78
93
  const available = screenHeight - keyboard;
79
94
  const maxHeight = Math.min(Math.max(available * 0.85, 240), screenHeight * 0.6);
80
95
 
81
- const filtered = useMemo(() => {
82
- const q = query.trim().toLowerCase();
83
- if (!q) return options;
84
- // Match the name, the ISO code, or the dial code with or without its '+',
85
- // because people search for "+234", "234" and "Nigeria" in equal measure.
86
- const bare = q.replace(/^\+/, '');
87
- return options.filter(
88
- (o) =>
89
- o.name.toLowerCase().includes(q) ||
90
- o.code.toLowerCase() === q ||
91
- (o.dialCode != null && o.dialCode.replace(/^\+/, '').startsWith(bare)),
92
- );
93
- }, [options, query]);
96
+ // Where they appear to be, lifted out of the alphabet. It stays subject to
97
+ // the search, so typing still narrows to what was asked for rather than
98
+ // keeping a row that does not match.
99
+ const rows = useMemo(
100
+ () => buildDialCodeItems(filterDialCodeOptions(options, query), pinned, grouped),
101
+ [options, query, pinned, grouped],
102
+ );
94
103
 
95
104
  const close = (): void => {
96
105
  setQuery('');
@@ -121,67 +130,37 @@ export function DialCodePicker({
121
130
  </View>
122
131
 
123
132
  <FlatList
124
- data={filtered}
125
- keyExtractor={(o) => o.code}
133
+ data={rows.items}
134
+ keyExtractor={dialCodeItemKey}
126
135
  keyboardShouldPersistTaps="handled"
136
+ // A hairline under the pinned row only: the alphabet below it is one
137
+ // list, and a rule between every row is noise.
138
+ ItemSeparatorComponent={({ leadingItem }: { leadingItem: DialCodeItem }) =>
139
+ rows.geo != null && leadingItem.kind === 'row' && leadingItem.option.code === rows.geo.code ? (
140
+ <DialCodeDivider />
141
+ ) : null
142
+ }
127
143
  ListEmptyComponent={
128
144
  <MyazaText variant="bodyMedium" style={{ padding: spacing.lg, textAlign: 'center' }}>
129
145
  No countries match your search.
130
146
  </MyazaText>
131
147
  }
132
- renderItem={({ item }) => (
133
- <CountryRow
134
- option={item}
135
- isSelected={item.code === selected}
136
- onPress={() => {
137
- setQuery('');
138
- onPick(item.code);
139
- }}
140
- />
141
- )}
148
+ renderItem={({ item }) =>
149
+ item.kind === 'header' ? (
150
+ <DialCodeRegionHeader region={item.region} />
151
+ ) : (
152
+ <DialCodeRow
153
+ option={item.option}
154
+ isSelected={item.option.code === selected}
155
+ badge={rows.geo != null && item.option.code === rows.geo.code ? 'Your location' : undefined}
156
+ onPress={() => {
157
+ setQuery('');
158
+ onPick(item.option.code);
159
+ }}
160
+ />
161
+ )
162
+ }
142
163
  />
143
164
  </FloatingSheet>
144
165
  );
145
166
  }
146
-
147
- function CountryRow({
148
- option,
149
- isSelected,
150
- onPress,
151
- }: {
152
- option: DialCodeOption;
153
- isSelected: boolean;
154
- onPress: () => void;
155
- }): React.ReactElement {
156
- const { colors } = useTheme();
157
- return (
158
- <Pressable
159
- onPress={onPress}
160
- accessibilityRole="radio"
161
- accessibilityState={{ checked: isSelected }}
162
- style={{
163
- flexDirection: 'row',
164
- alignItems: 'center',
165
- paddingHorizontal: spacing.md,
166
- // Roomier rows: a country list is a long scan, and cramped rows make
167
- // every tap a precision job. Matches the web dropdown's row height.
168
- paddingVertical: 12,
169
- backgroundColor: isSelected ? colors.primary50 : 'transparent',
170
- }}
171
- >
172
- <CountryFlag country={option.code} size={28} />
173
- <View style={{ width: spacing.md }} />
174
- {/* No line clamp: "Bosnia & Herzegovina" and the like must read in full,
175
- which is what Flutter's Expanded(Text) gives. Full body size (16),
176
- the web dropdown's reading size — 14 read small against the flags. */}
177
- <MyazaText variant="body" style={{ flex: 1 }}>
178
- {option.name}
179
- </MyazaText>
180
- {option.dialCode != null ? (
181
- <MyazaText variant="bodyMedium" color={colors.textSecondary}>
182
- {option.dialCode}
183
- </MyazaText>
184
- ) : null}
185
- </Pressable>
186
- );
187
- }