@smileid/usesmileid 12.0.0-beta01 → 12.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 (403) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +701 -89
  3. package/dist/camera/camera_defaults.d.ts +14 -9
  4. package/dist/camera/camera_defaults.d.ts.map +1 -1
  5. package/dist/camera/camera_defaults.js +11 -9
  6. package/dist/camera/camera_defaults.js.map +1 -1
  7. package/dist/camera/orientation_degrees.d.ts +5 -6
  8. package/dist/camera/orientation_degrees.d.ts.map +1 -1
  9. package/dist/camera/orientation_degrees.js +5 -6
  10. package/dist/camera/orientation_degrees.js.map +1 -1
  11. package/dist/core/models/document_capture_mode.d.ts +8 -0
  12. package/dist/core/models/document_capture_mode.d.ts.map +1 -1
  13. package/dist/core/models/document_capture_mode.js +24 -0
  14. package/dist/core/models/document_capture_mode.js.map +1 -1
  15. package/dist/core/models/document_type.d.ts +2 -2
  16. package/dist/core/models/document_type.d.ts.map +1 -1
  17. package/dist/core/models/document_type.js +6 -4
  18. package/dist/core/models/document_type.js.map +1 -1
  19. package/dist/core/models/result.d.ts +9 -8
  20. package/dist/core/models/result.d.ts.map +1 -1
  21. package/dist/core/models/result.js +5 -6
  22. package/dist/core/models/result.js.map +1 -1
  23. package/dist/data/api/interceptors/smile_auth_interceptor.js +1 -1
  24. package/dist/data/api/interceptors/smile_auth_interceptor.js.map +1 -1
  25. package/dist/data/api/interceptors/smile_integrity_interceptor.d.ts +11 -0
  26. package/dist/data/api/interceptors/smile_integrity_interceptor.d.ts.map +1 -1
  27. package/dist/data/api/interceptors/smile_integrity_interceptor.js +13 -0
  28. package/dist/data/api/interceptors/smile_integrity_interceptor.js.map +1 -1
  29. package/dist/data/api/interceptors/smile_request_mac_interceptor.d.ts +8 -0
  30. package/dist/data/api/interceptors/smile_request_mac_interceptor.d.ts.map +1 -1
  31. package/dist/data/api/interceptors/smile_request_mac_interceptor.js +11 -0
  32. package/dist/data/api/interceptors/smile_request_mac_interceptor.js.map +1 -1
  33. package/dist/data/compression/compressible_asset.d.ts +41 -0
  34. package/dist/data/compression/compressible_asset.d.ts.map +1 -0
  35. package/dist/data/compression/compressible_asset.js +34 -0
  36. package/dist/data/compression/compressible_asset.js.map +1 -0
  37. package/dist/data/compression/payload_compression_config.d.ts +36 -0
  38. package/dist/data/compression/payload_compression_config.d.ts.map +1 -0
  39. package/dist/data/compression/payload_compression_config.js +52 -0
  40. package/dist/data/compression/payload_compression_config.js.map +1 -0
  41. package/dist/data/compression/payload_compression_runner.d.ts +29 -0
  42. package/dist/data/compression/payload_compression_runner.d.ts.map +1 -0
  43. package/dist/data/compression/payload_compression_runner.js +55 -0
  44. package/dist/data/compression/payload_compression_runner.js.map +1 -0
  45. package/dist/data/compression/payload_compressor.d.ts +40 -0
  46. package/dist/data/compression/payload_compressor.d.ts.map +1 -0
  47. package/dist/data/compression/payload_compressor.js +126 -0
  48. package/dist/data/compression/payload_compressor.js.map +1 -0
  49. package/dist/data/compression/uri_compressible_asset.d.ts +23 -0
  50. package/dist/data/compression/uri_compressible_asset.d.ts.map +1 -0
  51. package/dist/data/compression/uri_compressible_asset.js +77 -0
  52. package/dist/data/compression/uri_compressible_asset.js.map +1 -0
  53. package/dist/data/dsl/builder/cache_config_builder.d.ts +2 -1
  54. package/dist/data/dsl/builder/cache_config_builder.d.ts.map +1 -1
  55. package/dist/data/dsl/builder/cache_config_builder.js +2 -1
  56. package/dist/data/dsl/builder/cache_config_builder.js.map +1 -1
  57. package/dist/data/dsl/builder/config_builder.d.ts +40 -14
  58. package/dist/data/dsl/builder/config_builder.d.ts.map +1 -1
  59. package/dist/data/dsl/builder/config_builder.js +40 -14
  60. package/dist/data/dsl/builder/config_builder.js.map +1 -1
  61. package/dist/data/dsl/builder/interceptor_config_builder.d.ts +9 -7
  62. package/dist/data/dsl/builder/interceptor_config_builder.d.ts.map +1 -1
  63. package/dist/data/dsl/builder/interceptor_config_builder.js +9 -7
  64. package/dist/data/dsl/builder/interceptor_config_builder.js.map +1 -1
  65. package/dist/data/dsl/builder/retry_config_builder.d.ts +16 -1
  66. package/dist/data/dsl/builder/retry_config_builder.d.ts.map +1 -1
  67. package/dist/data/dsl/builder/retry_config_builder.js +16 -1
  68. package/dist/data/dsl/builder/retry_config_builder.js.map +1 -1
  69. package/dist/data/dsl/builder/timeout_config_builder.d.ts +4 -0
  70. package/dist/data/dsl/builder/timeout_config_builder.d.ts.map +1 -1
  71. package/dist/data/dsl/builder/timeout_config_builder.js +4 -0
  72. package/dist/data/dsl/builder/timeout_config_builder.js.map +1 -1
  73. package/dist/data/dsl/use_smile_id_network_builder.d.ts +17 -0
  74. package/dist/data/dsl/use_smile_id_network_builder.d.ts.map +1 -1
  75. package/dist/data/dsl/use_smile_id_network_builder.js +17 -0
  76. package/dist/data/dsl/use_smile_id_network_builder.js.map +1 -1
  77. package/dist/data/factory/networking_factory.d.ts.map +1 -1
  78. package/dist/data/factory/networking_factory.js +11 -1
  79. package/dist/data/factory/networking_factory.js.map +1 -1
  80. package/dist/data/repository/use_smile_id_repository_impl.d.ts +6 -0
  81. package/dist/data/repository/use_smile_id_repository_impl.d.ts.map +1 -1
  82. package/dist/data/repository/use_smile_id_repository_impl.js +82 -8
  83. package/dist/data/repository/use_smile_id_repository_impl.js.map +1 -1
  84. package/dist/data/security/request_canonicalizer.d.ts.map +1 -1
  85. package/dist/data/security/request_canonicalizer.js +14 -2
  86. package/dist/data/security/request_canonicalizer.js.map +1 -1
  87. package/dist/data/security/security_policy.d.ts +43 -0
  88. package/dist/data/security/security_policy.d.ts.map +1 -0
  89. package/dist/data/security/security_policy.js +61 -0
  90. package/dist/data/security/security_policy.js.map +1 -0
  91. package/dist/data/util/retry_util.d.ts +1 -1
  92. package/dist/data/util/retry_util.d.ts.map +1 -1
  93. package/dist/data/util/retry_util.js +2 -1
  94. package/dist/data/util/retry_util.js.map +1 -1
  95. package/dist/data/util/use_smile_id_token_decoder.d.ts +22 -0
  96. package/dist/data/util/use_smile_id_token_decoder.d.ts.map +1 -1
  97. package/dist/data/util/use_smile_id_token_decoder.js +58 -24
  98. package/dist/data/util/use_smile_id_token_decoder.js.map +1 -1
  99. package/dist/l10n/strings_en.d.ts +2 -1
  100. package/dist/l10n/strings_en.d.ts.map +1 -1
  101. package/dist/l10n/strings_en.js +2 -1
  102. package/dist/l10n/strings_en.js.map +1 -1
  103. package/dist/l10n/use_smile_id_localizations.d.ts +1 -0
  104. package/dist/l10n/use_smile_id_localizations.d.ts.map +1 -1
  105. package/dist/l10n/use_smile_id_localizations.js +3 -0
  106. package/dist/l10n/use_smile_id_localizations.js.map +1 -1
  107. package/dist/metadata/builder_configuration.d.ts +39 -0
  108. package/dist/metadata/builder_configuration.d.ts.map +1 -0
  109. package/dist/metadata/builder_configuration.js +34 -0
  110. package/dist/metadata/builder_configuration.js.map +1 -0
  111. package/dist/metadata/captured_image_properties.d.ts +11 -0
  112. package/dist/metadata/captured_image_properties.d.ts.map +1 -0
  113. package/dist/metadata/captured_image_properties.js +11 -0
  114. package/dist/metadata/captured_image_properties.js.map +1 -0
  115. package/dist/metadata/device_orientation_collector.d.ts +17 -0
  116. package/dist/metadata/device_orientation_collector.d.ts.map +1 -0
  117. package/dist/metadata/device_orientation_collector.js +66 -0
  118. package/dist/metadata/device_orientation_collector.js.map +1 -0
  119. package/dist/metadata/geolocation.d.ts +20 -0
  120. package/dist/metadata/geolocation.d.ts.map +1 -0
  121. package/dist/metadata/geolocation.js +40 -0
  122. package/dist/metadata/geolocation.js.map +1 -0
  123. package/dist/metadata/metadata_configuration_mappers.d.ts +48 -0
  124. package/dist/metadata/metadata_configuration_mappers.d.ts.map +1 -0
  125. package/dist/metadata/metadata_configuration_mappers.js +171 -0
  126. package/dist/metadata/metadata_configuration_mappers.js.map +1 -0
  127. package/dist/metadata/model_configuration.d.ts +41 -0
  128. package/dist/metadata/model_configuration.d.ts.map +1 -0
  129. package/dist/metadata/model_configuration.js +44 -0
  130. package/dist/metadata/model_configuration.js.map +1 -0
  131. package/dist/metadata/optional_native_modules.d.ts +79 -3
  132. package/dist/metadata/optional_native_modules.d.ts.map +1 -1
  133. package/dist/metadata/optional_native_modules.js +108 -3
  134. package/dist/metadata/optional_native_modules.js.map +1 -1
  135. package/dist/metadata/use_smile_id_metadata.d.ts +45 -7
  136. package/dist/metadata/use_smile_id_metadata.d.ts.map +1 -1
  137. package/dist/metadata/use_smile_id_metadata.js +85 -13
  138. package/dist/metadata/use_smile_id_metadata.js.map +1 -1
  139. package/dist/metadata/use_smile_id_metadata_factory.d.ts +37 -0
  140. package/dist/metadata/use_smile_id_metadata_factory.d.ts.map +1 -1
  141. package/dist/metadata/use_smile_id_metadata_factory.js +184 -12
  142. package/dist/metadata/use_smile_id_metadata_factory.js.map +1 -1
  143. package/dist/presentation/assets/svg/document_shimmer_strings.d.ts +14 -0
  144. package/dist/presentation/assets/svg/document_shimmer_strings.d.ts.map +1 -0
  145. package/dist/presentation/assets/svg/document_shimmer_strings.js +14 -0
  146. package/dist/presentation/assets/svg/document_shimmer_strings.js.map +1 -0
  147. package/dist/presentation/assets/svg/instruction_svg_strings.d.ts +12 -4
  148. package/dist/presentation/assets/svg/instruction_svg_strings.d.ts.map +1 -1
  149. package/dist/presentation/assets/svg/instruction_svg_strings.js +19 -8
  150. package/dist/presentation/assets/svg/instruction_svg_strings.js.map +1 -1
  151. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.d.ts +0 -5
  152. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.d.ts.map +1 -1
  153. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.js +0 -5
  154. package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.js.map +1 -1
  155. package/dist/presentation/components/icons/index.d.ts +24 -8
  156. package/dist/presentation/components/icons/index.d.ts.map +1 -1
  157. package/dist/presentation/components/icons/index.js +31 -11
  158. package/dist/presentation/components/icons/index.js.map +1 -1
  159. package/dist/presentation/components/use_smile_id_attribution.d.ts +1 -1
  160. package/dist/presentation/components/use_smile_id_button.d.ts +2 -2
  161. package/dist/presentation/components/use_smile_id_button.js +4 -4
  162. package/dist/presentation/components/use_smile_id_button.js.map +1 -1
  163. package/dist/presentation/components/use_smile_id_capture_content.d.ts +13 -0
  164. package/dist/presentation/components/use_smile_id_capture_content.d.ts.map +1 -1
  165. package/dist/presentation/components/use_smile_id_capture_content.js +15 -9
  166. package/dist/presentation/components/use_smile_id_capture_content.js.map +1 -1
  167. package/dist/presentation/components/use_smile_id_captured_document_image.d.ts +2 -3
  168. package/dist/presentation/components/use_smile_id_captured_document_image.d.ts.map +1 -1
  169. package/dist/presentation/components/use_smile_id_captured_document_image.js +1 -3
  170. package/dist/presentation/components/use_smile_id_captured_document_image.js.map +1 -1
  171. package/dist/presentation/components/use_smile_id_document_capture_controls.d.ts +12 -6
  172. package/dist/presentation/components/use_smile_id_document_capture_controls.d.ts.map +1 -1
  173. package/dist/presentation/components/use_smile_id_document_capture_controls.js +59 -16
  174. package/dist/presentation/components/use_smile_id_document_capture_controls.js.map +1 -1
  175. package/dist/presentation/components/use_smile_id_document_overlay.d.ts +22 -5
  176. package/dist/presentation/components/use_smile_id_document_overlay.d.ts.map +1 -1
  177. package/dist/presentation/components/use_smile_id_document_overlay.js +80 -40
  178. package/dist/presentation/components/use_smile_id_document_overlay.js.map +1 -1
  179. package/dist/presentation/components/use_smile_id_document_shimmer.d.ts +15 -0
  180. package/dist/presentation/components/use_smile_id_document_shimmer.d.ts.map +1 -0
  181. package/dist/presentation/components/use_smile_id_document_shimmer.js +23 -0
  182. package/dist/presentation/components/use_smile_id_document_shimmer.js.map +1 -0
  183. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts.map +1 -1
  184. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js +1 -3
  185. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js.map +1 -1
  186. package/dist/presentation/components/use_smile_id_guideline_thumbnail.d.ts.map +1 -1
  187. package/dist/presentation/components/use_smile_id_guideline_thumbnail.js +84 -1
  188. package/dist/presentation/components/use_smile_id_guideline_thumbnail.js.map +1 -1
  189. package/dist/presentation/components/use_smile_id_instructions_hero.d.ts +3 -1
  190. package/dist/presentation/components/use_smile_id_instructions_hero.d.ts.map +1 -1
  191. package/dist/presentation/components/use_smile_id_instructions_hero.js +18 -3
  192. package/dist/presentation/components/use_smile_id_instructions_hero.js.map +1 -1
  193. package/dist/presentation/components/use_smile_id_oval_border_palette.d.ts.map +1 -1
  194. package/dist/presentation/components/use_smile_id_oval_border_palette.js +7 -3
  195. package/dist/presentation/components/use_smile_id_oval_border_palette.js.map +1 -1
  196. package/dist/presentation/flow/dsl/builder/config_builder.d.ts +12 -0
  197. package/dist/presentation/flow/dsl/builder/config_builder.d.ts.map +1 -1
  198. package/dist/presentation/flow/dsl/builder/config_builder.js +12 -0
  199. package/dist/presentation/flow/dsl/builder/config_builder.js.map +1 -1
  200. package/dist/presentation/flow/dsl/builder/ml_builder.d.ts +13 -4
  201. package/dist/presentation/flow/dsl/builder/ml_builder.d.ts.map +1 -1
  202. package/dist/presentation/flow/dsl/builder/ml_builder.js +3 -2
  203. package/dist/presentation/flow/dsl/builder/ml_builder.js.map +1 -1
  204. package/dist/presentation/flow/dsl/builder/screens_builder.d.ts +111 -10
  205. package/dist/presentation/flow/dsl/builder/screens_builder.d.ts.map +1 -1
  206. package/dist/presentation/flow/dsl/builder/screens_builder.js +111 -10
  207. package/dist/presentation/flow/dsl/builder/screens_builder.js.map +1 -1
  208. package/dist/presentation/flow/dsl/builder/theme_builder.d.ts +15 -2
  209. package/dist/presentation/flow/dsl/builder/theme_builder.d.ts.map +1 -1
  210. package/dist/presentation/flow/dsl/builder/theme_builder.js +15 -2
  211. package/dist/presentation/flow/dsl/builder/theme_builder.js.map +1 -1
  212. package/dist/presentation/flow/dsl/use_smile_id_builder.d.ts +6 -4
  213. package/dist/presentation/flow/dsl/use_smile_id_builder.d.ts.map +1 -1
  214. package/dist/presentation/flow/dsl/use_smile_id_builder.js.map +1 -1
  215. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts +62 -36
  216. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts.map +1 -1
  217. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js +62 -36
  218. package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js.map +1 -1
  219. package/dist/presentation/flow/flow_navigation_manager.d.ts +39 -4
  220. package/dist/presentation/flow/flow_navigation_manager.d.ts.map +1 -1
  221. package/dist/presentation/flow/flow_navigation_manager.js +141 -10
  222. package/dist/presentation/flow/flow_navigation_manager.js.map +1 -1
  223. package/dist/presentation/flow/model/instruction_guideline.d.ts +9 -0
  224. package/dist/presentation/flow/model/instruction_guideline.d.ts.map +1 -1
  225. package/dist/presentation/flow/model/instructions_defaults.d.ts +11 -2
  226. package/dist/presentation/flow/model/instructions_defaults.d.ts.map +1 -1
  227. package/dist/presentation/flow/model/instructions_defaults.js +73 -25
  228. package/dist/presentation/flow/model/instructions_defaults.js.map +1 -1
  229. package/dist/presentation/flow/screen/orchestrated_capture_screen.d.ts.map +1 -1
  230. package/dist/presentation/flow/screen/orchestrated_capture_screen.js +36 -12
  231. package/dist/presentation/flow/screen/orchestrated_capture_screen.js.map +1 -1
  232. package/dist/presentation/flow/screen/orchestrated_instructions_screen.js +1 -1
  233. package/dist/presentation/flow/screen/orchestrated_instructions_screen.js.map +1 -1
  234. package/dist/presentation/flow/screen/orchestrated_preview_screen.d.ts.map +1 -1
  235. package/dist/presentation/flow/screen/orchestrated_preview_screen.js +3 -1
  236. package/dist/presentation/flow/screen/orchestrated_preview_screen.js.map +1 -1
  237. package/dist/presentation/flow/screen/orchestrated_processing_screen.js +3 -3
  238. package/dist/presentation/flow/screen/orchestrated_processing_screen.js.map +1 -1
  239. package/dist/presentation/flow/validation/job_type_validator.d.ts.map +1 -1
  240. package/dist/presentation/flow/validation/job_type_validator.js +14 -0
  241. package/dist/presentation/flow/validation/job_type_validator.js.map +1 -1
  242. package/dist/presentation/screen/helpers/capture_screen_helpers.d.ts.map +1 -1
  243. package/dist/presentation/screen/helpers/capture_screen_helpers.js +1 -0
  244. package/dist/presentation/screen/helpers/capture_screen_helpers.js.map +1 -1
  245. package/dist/presentation/screen/helpers/instructions_screen_helpers.d.ts +1 -0
  246. package/dist/presentation/screen/helpers/instructions_screen_helpers.d.ts.map +1 -1
  247. package/dist/presentation/screen/helpers/instructions_screen_helpers.js +6 -2
  248. package/dist/presentation/screen/helpers/instructions_screen_helpers.js.map +1 -1
  249. package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js +3 -0
  250. package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js.map +1 -1
  251. package/dist/presentation/screen/use_smile_id_capture_screen.d.ts +17 -1
  252. package/dist/presentation/screen/use_smile_id_capture_screen.d.ts.map +1 -1
  253. package/dist/presentation/screen/use_smile_id_capture_screen.js +153 -18
  254. package/dist/presentation/screen/use_smile_id_capture_screen.js.map +1 -1
  255. package/dist/presentation/screen/use_smile_id_document_preview_screen.d.ts +2 -3
  256. package/dist/presentation/screen/use_smile_id_document_preview_screen.d.ts.map +1 -1
  257. package/dist/presentation/screen/use_smile_id_document_preview_screen.js +16 -11
  258. package/dist/presentation/screen/use_smile_id_document_preview_screen.js.map +1 -1
  259. package/dist/presentation/screen/use_smile_id_instructions_screen.d.ts +2 -0
  260. package/dist/presentation/screen/use_smile_id_instructions_screen.d.ts.map +1 -1
  261. package/dist/presentation/screen/use_smile_id_instructions_screen.js +2 -1
  262. package/dist/presentation/screen/use_smile_id_instructions_screen.js.map +1 -1
  263. package/dist/presentation/screen/use_smile_id_preview_screen.d.ts +7 -6
  264. package/dist/presentation/screen/use_smile_id_preview_screen.d.ts.map +1 -1
  265. package/dist/presentation/screen/use_smile_id_preview_screen.js +9 -8
  266. package/dist/presentation/screen/use_smile_id_preview_screen.js.map +1 -1
  267. package/dist/presentation/screen/use_smile_id_processing_screen.d.ts +2 -3
  268. package/dist/presentation/screen/use_smile_id_processing_screen.d.ts.map +1 -1
  269. package/dist/presentation/screen/use_smile_id_processing_screen.js +3 -2
  270. package/dist/presentation/screen/use_smile_id_processing_screen.js.map +1 -1
  271. package/dist/presentation/theme/theme.d.ts +1 -1
  272. package/dist/presentation/theme/theme.d.ts.map +1 -1
  273. package/dist/presentation/theme/theme.js +20 -18
  274. package/dist/presentation/theme/theme.js.map +1 -1
  275. package/dist/presentation/utils/force_max_brightness.d.ts +4 -4
  276. package/package.json +26 -6
  277. package/src/__tests__/react_native_mock.tsx +8 -0
  278. package/src/camera/camera_defaults.ts +11 -9
  279. package/src/camera/orientation_degrees.ts +5 -6
  280. package/src/core/models/__tests__/document_type.test.ts +6 -4
  281. package/src/core/models/document_capture_mode.ts +27 -0
  282. package/src/core/models/document_type.ts +6 -4
  283. package/src/core/models/result.ts +9 -8
  284. package/src/data/api/interceptors/__tests__/smile_integrity_interceptor.test.ts +37 -1
  285. package/src/data/api/interceptors/__tests__/smile_request_mac_interceptor.test.ts +59 -1
  286. package/src/data/api/interceptors/smile_auth_interceptor.ts +1 -1
  287. package/src/data/api/interceptors/smile_integrity_interceptor.ts +20 -0
  288. package/src/data/api/interceptors/smile_request_mac_interceptor.ts +13 -0
  289. package/src/data/compression/__tests__/payload_compressor.test.ts +200 -0
  290. package/src/data/compression/__tests__/payload_compressor_real_jpeg.test.ts +222 -0
  291. package/src/data/compression/compressible_asset.ts +62 -0
  292. package/src/data/compression/payload_compression_config.ts +53 -0
  293. package/src/data/compression/payload_compression_runner.ts +102 -0
  294. package/src/data/compression/payload_compressor.ts +164 -0
  295. package/src/data/compression/uri_compressible_asset.ts +85 -0
  296. package/src/data/dsl/builder/cache_config_builder.ts +3 -1
  297. package/src/data/dsl/builder/config_builder.ts +45 -14
  298. package/src/data/dsl/builder/interceptor_config_builder.ts +9 -7
  299. package/src/data/dsl/builder/retry_config_builder.ts +22 -1
  300. package/src/data/dsl/builder/timeout_config_builder.ts +7 -0
  301. package/src/data/dsl/use_smile_id_network_builder.ts +17 -0
  302. package/src/data/factory/networking_factory.ts +14 -1
  303. package/src/data/repository/__tests__/network_retries.test.ts +117 -0
  304. package/src/data/repository/use_smile_id_repository_impl.ts +96 -9
  305. package/src/data/security/__tests__/security_policy.test.ts +96 -0
  306. package/src/data/security/__tests__/smile_id_crypto_manager.test.ts +18 -0
  307. package/src/data/security/request_canonicalizer.ts +15 -2
  308. package/src/data/security/security_policy.ts +70 -0
  309. package/src/data/util/__tests__/use_smile_id_token_decoder.test.ts +57 -1
  310. package/src/data/util/retry_util.ts +3 -2
  311. package/src/data/util/use_smile_id_token_decoder.ts +76 -28
  312. package/src/l10n/strings_en.ts +2 -1
  313. package/src/l10n/use_smile_id_localizations.ts +3 -0
  314. package/src/metadata/__tests__/device_orientation_collector.test.ts +15 -0
  315. package/src/metadata/__tests__/metadata_configuration_mappers.test.ts +215 -0
  316. package/src/metadata/__tests__/metadata_configuration_objects.test.ts +85 -0
  317. package/src/metadata/__tests__/metadata_device_context.test.ts +147 -0
  318. package/src/metadata/__tests__/metadata_golden_fixture.json +13 -0
  319. package/src/metadata/__tests__/metadata_payload_golden.test.ts +193 -0
  320. package/src/metadata/__tests__/use_smile_id_metadata.test.ts +18 -24
  321. package/src/metadata/builder_configuration.ts +63 -0
  322. package/src/metadata/captured_image_properties.ts +10 -0
  323. package/src/metadata/device_orientation_collector.ts +75 -0
  324. package/src/metadata/geolocation.ts +46 -0
  325. package/src/metadata/metadata_configuration_mappers.ts +234 -0
  326. package/src/metadata/model_configuration.ts +68 -0
  327. package/src/metadata/optional_native_modules.ts +157 -3
  328. package/src/metadata/use_smile_id_metadata.ts +140 -17
  329. package/src/metadata/use_smile_id_metadata_factory.ts +195 -11
  330. package/src/presentation/assets/si_ess_animation_all_directions.json +1300 -286
  331. package/src/presentation/assets/svg/document_shimmer_strings.ts +17 -0
  332. package/src/presentation/assets/svg/instruction_svg_strings.ts +34 -12
  333. package/src/presentation/components/__tests__/enhanced_smart_selfie_animation_frames.test.ts +1 -3
  334. package/src/presentation/components/__tests__/use_smile_id_enhanced_smart_selfie_clip.test.tsx +3 -4
  335. package/src/presentation/components/__tests__/use_smile_id_guideline_thumbnail.test.tsx +34 -1
  336. package/src/presentation/components/__tests__/use_smile_id_instructions_hero.test.tsx +27 -0
  337. package/src/presentation/components/__tests__/use_smile_id_oval_border_palette.test.ts +7 -5
  338. package/src/presentation/components/helpers/enhanced_smart_selfie_animation_frames.ts +0 -6
  339. package/src/presentation/components/icons/index.tsx +65 -18
  340. package/src/presentation/components/use_smile_id_attribution.tsx +1 -1
  341. package/src/presentation/components/use_smile_id_button.tsx +4 -4
  342. package/src/presentation/components/use_smile_id_capture_content.tsx +36 -12
  343. package/src/presentation/components/use_smile_id_captured_document_image.tsx +3 -8
  344. package/src/presentation/components/use_smile_id_document_capture_controls.tsx +103 -39
  345. package/src/presentation/components/use_smile_id_document_overlay.tsx +134 -44
  346. package/src/presentation/components/use_smile_id_document_shimmer.tsx +51 -0
  347. package/src/presentation/components/use_smile_id_enhanced_smart_selfie_clip.tsx +0 -3
  348. package/src/presentation/components/use_smile_id_guideline_thumbnail.tsx +131 -2
  349. package/src/presentation/components/use_smile_id_instructions_hero.tsx +100 -59
  350. package/src/presentation/components/use_smile_id_oval_border_palette.ts +7 -3
  351. package/src/presentation/flow/__tests__/document_flow_navigation.test.ts +200 -1
  352. package/src/presentation/flow/dsl/builder/config_builder.ts +14 -0
  353. package/src/presentation/flow/dsl/builder/ml_builder.ts +13 -4
  354. package/src/presentation/flow/dsl/builder/screens_builder.ts +111 -10
  355. package/src/presentation/flow/dsl/builder/theme_builder.ts +19 -2
  356. package/src/presentation/flow/dsl/use_smile_id_builder.tsx +6 -4
  357. package/src/presentation/flow/dsl/use_smile_id_flow_builder.ts +62 -36
  358. package/src/presentation/flow/flow_navigation_manager.ts +179 -13
  359. package/src/presentation/flow/model/instruction_guideline.ts +6 -0
  360. package/src/presentation/flow/model/instructions_defaults.ts +103 -25
  361. package/src/presentation/flow/screen/orchestrated_capture_screen.tsx +43 -10
  362. package/src/presentation/flow/screen/orchestrated_instructions_screen.tsx +1 -0
  363. package/src/presentation/flow/screen/orchestrated_preview_screen.tsx +4 -2
  364. package/src/presentation/flow/screen/orchestrated_processing_screen.tsx +3 -3
  365. package/src/presentation/flow/validation/__tests__/job_type_validator.test.ts +64 -0
  366. package/src/presentation/flow/validation/job_type_validator.ts +24 -0
  367. package/src/presentation/screen/__tests__/instructions_screen_helpers.test.ts +15 -3
  368. package/src/presentation/screen/__tests__/use_smile_id_capture_screen.test.tsx +6 -4
  369. package/src/presentation/screen/helpers/capture_screen_helpers.ts +1 -0
  370. package/src/presentation/screen/helpers/instructions_screen_helpers.ts +7 -2
  371. package/src/presentation/screen/helpers/scan_state_to_overlay_state.ts +3 -0
  372. package/src/presentation/screen/use_smile_id_capture_screen.tsx +234 -36
  373. package/src/presentation/screen/use_smile_id_document_preview_screen.tsx +32 -22
  374. package/src/presentation/screen/use_smile_id_instructions_screen.tsx +4 -0
  375. package/src/presentation/screen/use_smile_id_preview_screen.tsx +9 -9
  376. package/src/presentation/screen/use_smile_id_processing_screen.tsx +7 -7
  377. package/src/presentation/theme/theme.ts +21 -19
  378. package/src/presentation/utils/force_max_brightness.tsx +4 -4
  379. package/dist/camera/frame_processor_plugin.d.ts +0 -28
  380. package/dist/camera/frame_processor_plugin.d.ts.map +0 -1
  381. package/dist/camera/frame_processor_plugin.js +0 -21
  382. package/dist/camera/frame_processor_plugin.js.map +0 -1
  383. package/dist/camera/use_smile_id_frame_processor.d.ts +0 -38
  384. package/dist/camera/use_smile_id_frame_processor.d.ts.map +0 -1
  385. package/dist/camera/use_smile_id_frame_processor.js +0 -2
  386. package/dist/camera/use_smile_id_frame_processor.js.map +0 -1
  387. package/dist/presentation/components/use_smile_id_document_frame_glyph.d.ts +0 -17
  388. package/dist/presentation/components/use_smile_id_document_frame_glyph.d.ts.map +0 -1
  389. package/dist/presentation/components/use_smile_id_document_frame_glyph.js +0 -17
  390. package/dist/presentation/components/use_smile_id_document_frame_glyph.js.map +0 -1
  391. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.d.ts +0 -24
  392. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.d.ts.map +0 -1
  393. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.js +0 -91
  394. package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.js.map +0 -1
  395. package/dist/presentation/components/use_smile_id_instruction_card.d.ts +0 -31
  396. package/dist/presentation/components/use_smile_id_instruction_card.d.ts.map +0 -1
  397. package/dist/presentation/components/use_smile_id_instruction_card.js +0 -43
  398. package/dist/presentation/components/use_smile_id_instruction_card.js.map +0 -1
  399. package/dist/presentation/screen/helpers/use_document_orientation_lock.d.ts +0 -24
  400. package/dist/presentation/screen/helpers/use_document_orientation_lock.d.ts.map +0 -1
  401. package/dist/presentation/screen/helpers/use_document_orientation_lock.js +0 -47
  402. package/dist/presentation/screen/helpers/use_document_orientation_lock.js.map +0 -1
  403. package/src/presentation/components/use_smile_id_document_frame_glyph.tsx +0 -162
@@ -1,5 +1,6 @@
1
1
  import { memo } from "react";
2
2
  import { StyleSheet, Text, View } from "react-native";
3
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
3
4
  import Svg, { Path } from "react-native-svg";
4
5
  import type { UseSmileIDTheme } from "../theme/theme";
5
6
  import { useUseSmileIDTheme } from "../theme/theme_context";
@@ -7,7 +8,10 @@ import {
7
8
  isDocumentCaptureActive,
8
9
  type UseSmileIDOverlayState as OverlayState,
9
10
  } from "../state/use_smile_id_overlay_state";
10
- import { UseSmileIDDocumentFrameGlyph } from "./use_smile_id_document_frame_glyph";
11
+ import type { DocumentType } from "../../core/models/document_type";
12
+ import { UseSmileIDOvalBorderPalette } from "./use_smile_id_oval_border_palette";
13
+ import { UseSmileIDDocumentShimmer } from "./use_smile_id_document_shimmer";
14
+ import { UseSmileIDCaptureSpinner } from "./use_smile_id_capture_spinner";
11
15
 
12
16
  export type UseSmileIDDocumentOverlayProps = {
13
17
  readonly state: OverlayState;
@@ -15,6 +19,10 @@ export type UseSmileIDDocumentOverlayProps = {
15
19
  readonly containerHeight: number;
16
20
  /** Optional aspect ratio hint — e.g. CR-80 ID card = 1.586. */
17
21
  readonly knownIdAspectRatio?: number;
22
+ /** Document type — selects the in-frame shimmer skeleton. */
23
+ readonly documentTypeKind?: DocumentType["kind"];
24
+ /** Generic-document back side — swaps the front skeleton for the back. */
25
+ readonly isBackSide?: boolean;
18
26
  /**
19
27
  * Coaching copy shown in the dark pill below the frame. Rendered here so it
20
28
  * tracks the frame geometry instead of a fixed screen offset.
@@ -28,50 +36,88 @@ export type UseSmileIDDocumentOverlayProps = {
28
36
  const CHIP_TOP_GAP = 16;
29
37
 
30
38
  /**
31
- * Fraction of the container width the document frame spans, per orientation.
32
- * Matches the Figma capture frames: landscape ID-1 card ≈ 0.53 of the (wide)
33
- * screen; portrait booklet / passport ≈ 0.68 of the (narrow) screen.
39
+ * Frame spans ≤71% of container width, height capped at 61% (re-deriving width
40
+ * from aspect when the cap bites — keeps a wide ID-1 card from overflowing in
41
+ * landscape). One ratio pair drives both orientations.
34
42
  */
35
- const FRAME_WIDTH_FRACTION_LANDSCAPE = 0.53;
36
- const FRAME_WIDTH_FRACTION_PORTRAIT = 0.68;
43
+ const FRAME_MAX_WIDTH_RATIO = 0.71;
44
+ const FRAME_MAX_HEIGHT_RATIO = 0.61;
37
45
  /** Frame corner radius (matches the bordered frame's `borderRadius`). */
38
- const FRAME_CORNER_RADIUS = 8;
46
+ const FRAME_CORNER_RADIUS = 16;
47
+ /** Guide-rect border thickness; drawn straddling the frame edge (centred stroke, matching the other SDKs). */
48
+ const FRAME_BORDER_WIDTH = 4;
49
+ /** Capture-progress spinner shown beside the frame (landscape) or bottom-centre (portrait). */
50
+ const SPINNER_SIZE = 48;
51
+ /** Portrait spinner gap above the safe-area bottom (spacing.large) — matches the shutter row. */
52
+ const PORTRAIT_SPINNER_BOTTOM_GAP = 24;
53
+
54
+ /** Default document aspect (CR-80 ID-1 card) when no known ratio is supplied. */
55
+ export const DEFAULT_DOCUMENT_ASPECT = 1.586;
56
+
39
57
  /**
40
- * Faint black tint over the WHOLE live feed (net ~0.15 inside the frame). A
41
- * component constant, not a theme colour — the surround dim (`documentOverlayScrim`)
42
- * is the partner-overridable layer.
58
+ * Centred document guide rectangle (container px) for a document [aspect] and
59
+ * viewport. Single source of truth shared by the overlay (draws the frame) and
60
+ * the capture screen (derives the native crop region), so the saved capture
61
+ * matches the frame the user saw.
62
+ */
63
+ export function documentGuideRect(
64
+ aspect: number,
65
+ containerWidth: number,
66
+ containerHeight: number,
67
+ ): {
68
+ readonly left: number;
69
+ readonly top: number;
70
+ readonly width: number;
71
+ readonly height: number;
72
+ } {
73
+ let width = containerWidth * FRAME_MAX_WIDTH_RATIO;
74
+ let height = width / aspect;
75
+ const maxHeight = containerHeight * FRAME_MAX_HEIGHT_RATIO;
76
+ if (height > maxHeight) {
77
+ height = maxHeight;
78
+ width = height * aspect;
79
+ }
80
+ return {
81
+ left: (containerWidth - width) / 2,
82
+ top: (containerHeight - height) / 2,
83
+ width,
84
+ height,
85
+ };
86
+ }
87
+ /**
88
+ * Faint black tint over the whole live feed (~0.15 inside the frame). Component
89
+ * constant, not a theme colour — the surround dim is the overridable layer.
43
90
  */
44
91
  const DOCUMENT_CAMERA_TINT = "#00000026"; // black @15%
45
92
  /** Fallback surround dim when the theme omits `documentOverlayScrim`. */
46
93
  const DEFAULT_DOCUMENT_OVERLAY_SCRIM = "#00000066"; // black @40%
47
94
 
48
95
  /**
49
- * Document capture frame — two-layer dim (faint full-feed tint + darker surround
50
- * outside the cutout, ~0.15 inside / ~0.49 outside) plus a border that flips to
51
- * `ovalActive` on `DOCUMENT_READY`. The cutout is one even-odd path, NOT a `<Mask>`:
52
- * masks rasterize the full-screen layer to a bitmap on the UI thread per invalidation,
53
- * freezing the camera preview. Respects `knownIdAspectRatio`; the frame stays centred.
96
+ * Document capture frame — two-layer dim + a border that flips to `ovalActive`
97
+ * on `DOCUMENT_READY`. The cutout is one even-odd path, NOT a `<Mask>` (masks
98
+ * rasterize the full-screen layer per invalidation, freezing the preview).
54
99
  */
55
100
  export function UseSmileIDDocumentOverlay(
56
101
  props: UseSmileIDDocumentOverlayProps,
57
102
  ) {
58
103
  const themeFromContext = useUseSmileIDTheme();
59
104
  const theme = props.theme ?? themeFromContext;
60
- const aspect = props.knownIdAspectRatio ?? 1.586;
61
- const isLandscapeFrame = aspect >= 1;
62
- const frameWidth =
63
- props.containerWidth *
64
- (isLandscapeFrame
65
- ? FRAME_WIDTH_FRACTION_LANDSCAPE
66
- : FRAME_WIDTH_FRACTION_PORTRAIT);
67
- const frameHeight = frameWidth / aspect;
68
- const left = (props.containerWidth - frameWidth) / 2;
69
- const top = (props.containerHeight - frameHeight) / 2;
70
- // Two-state border: neutral light while idle/positioning, green once committing.
105
+ const insets = useSafeAreaInsets();
106
+ const aspect = props.knownIdAspectRatio ?? DEFAULT_DOCUMENT_ASPECT;
107
+ const isPortrait = aspect < 1;
108
+ const {
109
+ left,
110
+ top,
111
+ width: frameWidth,
112
+ height: frameHeight,
113
+ } = documentGuideRect(aspect, props.containerWidth, props.containerHeight);
114
+ // Three-state border, shared with the selfie oval (UseSmileIDOvalBorderPalette):
115
+ // green once the document is correctly framed (ready / capturing / processing),
116
+ // red while detected but mispositioned (too far / close / off-centre / not
117
+ // steady), neutral while idle.
71
118
  const captureActive = isDocumentCaptureActive(props.state);
72
- const borderColor = captureActive
73
- ? theme.colors.ovalActive
74
- : theme.colors.stroke;
119
+ const borderColor =
120
+ theme.colors[UseSmileIDOvalBorderPalette.tokenFor(props.state, false)];
75
121
  const surroundColor =
76
122
  theme.colors.documentOverlayScrim ?? DEFAULT_DOCUMENT_OVERLAY_SCRIM;
77
123
 
@@ -104,37 +150,81 @@ export function UseSmileIDDocumentOverlay(
104
150
  cornerRadius={FRAME_CORNER_RADIUS}
105
151
  color={surroundColor}
106
152
  />
107
- {/* In-frame document glyph (placeholder for the per-type capture Lottie). */}
153
+ {/* In-frame document shimmer — per-type skeleton hint while positioning. */}
108
154
  {!captureActive ? (
109
155
  <View
110
156
  style={{
157
+ // Inset 10% per axis so the shimmer guide never touches the frame edge.
111
158
  position: "absolute",
112
- left,
113
- top,
114
- width: frameWidth,
115
- height: frameHeight,
159
+ left: left + frameWidth * 0.1,
160
+ top: top + frameHeight * 0.1,
161
+ width: frameWidth * 0.8,
162
+ height: frameHeight * 0.8,
116
163
  }}
117
164
  pointerEvents="none"
118
165
  >
119
- <UseSmileIDDocumentFrameGlyph
120
- width={frameWidth}
121
- height={frameHeight}
122
- isLandscape={isLandscapeFrame}
166
+ <UseSmileIDDocumentShimmer
167
+ width={frameWidth * 0.8}
168
+ height={frameHeight * 0.8}
169
+ isBackSide={props.isBackSide ?? false}
170
+ {...(props.documentTypeKind !== undefined
171
+ ? { documentTypeKind: props.documentTypeKind }
172
+ : {})}
123
173
  />
124
174
  </View>
125
175
  ) : null}
126
176
  <View
127
177
  style={{
128
178
  position: "absolute",
129
- left,
130
- top,
131
- width: frameWidth,
132
- height: frameHeight,
133
- borderWidth: 1.5,
134
- borderRadius: FRAME_CORNER_RADIUS,
179
+ left: left - FRAME_BORDER_WIDTH / 2,
180
+ top: top - FRAME_BORDER_WIDTH / 2,
181
+ width: frameWidth + FRAME_BORDER_WIDTH,
182
+ height: frameHeight + FRAME_BORDER_WIDTH,
183
+ borderWidth: FRAME_BORDER_WIDTH,
184
+ borderRadius: FRAME_CORNER_RADIUS + FRAME_BORDER_WIDTH / 2,
135
185
  borderColor,
136
186
  }}
137
187
  />
188
+ {/* Capture-progress spinner: beside the frame in landscape; bottom-centre in portrait
189
+ (e.g. Green Book), where the near-full-width frame leaves no side margin. */}
190
+ {captureActive ? (
191
+ isPortrait ? (
192
+ <View
193
+ style={{
194
+ position: "absolute",
195
+ left: 0,
196
+ right: 0,
197
+ bottom: insets.bottom + PORTRAIT_SPINNER_BOTTOM_GAP,
198
+ alignItems: "center",
199
+ }}
200
+ pointerEvents="none"
201
+ >
202
+ <UseSmileIDCaptureSpinner
203
+ size={SPINNER_SIZE}
204
+ color={theme.colors.ovalActive}
205
+ testID="si_document_capture_spinner"
206
+ />
207
+ </View>
208
+ ) : (
209
+ <View
210
+ style={{
211
+ position: "absolute",
212
+ left:
213
+ left +
214
+ frameWidth +
215
+ (props.containerWidth - (left + frameWidth) - SPINNER_SIZE) / 2,
216
+ top: top + (frameHeight - SPINNER_SIZE) / 2,
217
+ }}
218
+ pointerEvents="none"
219
+ >
220
+ <UseSmileIDCaptureSpinner
221
+ size={SPINNER_SIZE}
222
+ color={theme.colors.ovalActive}
223
+ testID="si_document_capture_spinner"
224
+ />
225
+ </View>
226
+ )
227
+ ) : null}
138
228
  {/* Coaching pill, anchored just below the frame (Figma off-black pill). */}
139
229
  {props.feedbackText ? (
140
230
  <View
@@ -0,0 +1,51 @@
1
+ import { memo } from "react";
2
+ import { SvgXml } from "react-native-svg";
3
+ import type { DocumentType } from "../../core/models/document_type";
4
+ import {
5
+ SI_DOCUMENT_BACK_SHIMMER,
6
+ SI_DOCUMENT_FRONT_SHIMMER,
7
+ SI_DOCUMENT_GREEN_BOOK_SHIMMER,
8
+ SI_DOCUMENT_PASSPORT_SHIMMER,
9
+ } from "../assets/svg/document_shimmer_strings";
10
+
11
+ /** Translucent in-frame document shimmer — the per-type "align here" skeleton, scaled to fit the capture frame. */
12
+ export type UseSmileIDDocumentShimmerProps = {
13
+ readonly width: number;
14
+ readonly height: number;
15
+ /** Selects the skeleton; the green book and passport ignore `isBackSide`. */
16
+ readonly documentTypeKind?: DocumentType["kind"];
17
+ /** Generic documents only: show the back-side skeleton instead of the front. */
18
+ readonly isBackSide?: boolean;
19
+ readonly testID?: string;
20
+ };
21
+
22
+ /** Shimmer skeleton for a document type + side. Only generic documents have front/back; passport and green book ignore the side. */
23
+ export function documentShimmerXml(
24
+ documentTypeKind: DocumentType["kind"] | undefined,
25
+ isBackSide: boolean,
26
+ ): string {
27
+ switch (documentTypeKind) {
28
+ case "passport":
29
+ return SI_DOCUMENT_PASSPORT_SHIMMER;
30
+ case "southAfricaGreenBook":
31
+ return SI_DOCUMENT_GREEN_BOOK_SHIMMER;
32
+ default:
33
+ return isBackSide ? SI_DOCUMENT_BACK_SHIMMER : SI_DOCUMENT_FRONT_SHIMMER;
34
+ }
35
+ }
36
+
37
+ export const UseSmileIDDocumentShimmer = memo(
38
+ function UseSmileIDDocumentShimmer(props: UseSmileIDDocumentShimmerProps) {
39
+ const { width, height, documentTypeKind, isBackSide = false } = props;
40
+ if (width <= 0 || height <= 0) return null;
41
+ // Default preserveAspectRatio (meet) fits the skeleton in the frame, undistorted.
42
+ return (
43
+ <SvgXml
44
+ xml={documentShimmerXml(documentTypeKind, isBackSide)}
45
+ width={width}
46
+ height={height}
47
+ {...(props.testID !== undefined ? { testID: props.testID } : {})}
48
+ />
49
+ );
50
+ },
51
+ );
@@ -5,7 +5,6 @@ import type { AnimationObject } from "lottie-react-native";
5
5
  import { useReducedMotion } from "../utils/use_reduced_motion";
6
6
  import { FaceOvalDefaults } from "./face_oval_defaults";
7
7
  import {
8
- ENHANCED_SMART_SELFIE_ANIMATION_OPACITY,
9
8
  ENHANCED_SMART_SELFIE_ANIMATION_SPEED,
10
9
  ENHANCED_SMART_SELFIE_TOTAL_FRAMES,
11
10
  } from "./helpers/enhanced_smart_selfie_animation_frames";
@@ -56,8 +55,6 @@ export function UseSmileIDEnhancedSmartSelfieClip(
56
55
  top: ovalCenterY - size / 2 + VERTICAL_ALIGNMENT_OFFSET,
57
56
  width: size,
58
57
  height: size,
59
- // Translucent so the face stays the focal point behind the arrow cue.
60
- opacity: ENHANCED_SMART_SELFIE_ANIMATION_OPACITY,
61
58
  };
62
59
 
63
60
  if (reducedMotion) {
@@ -1,4 +1,5 @@
1
- import { StyleSheet, Text, View } from "react-native";
1
+ import { useState } from "react";
2
+ import { StyleSheet, Text, View, type LayoutChangeEvent } from "react-native";
2
3
  import type { UseSmileIDTheme } from "../theme/theme";
3
4
  import { useUseSmileIDTheme } from "../theme/theme_context";
4
5
  import { useUseSmileIDLocalizations } from "../../l10n/use_smile_id_localizations_provider";
@@ -17,6 +18,15 @@ const BADGE_ICON_SIZE = 14;
17
18
  // The badge overhangs the top-end corner of the card.
18
19
  const BADGE_OVERHANG = -10;
19
20
 
21
+ // Document card SVGs carry a transparent bleed around the visible card (3px
22
+ // L/R, 2px top, 4px bottom); the tile offsets the SVG by it so the card fills
23
+ // the framed box exactly.
24
+ const DOC_CARD_RADIUS = 4;
25
+ const DOC_BLEED_X = 3;
26
+ const DOC_BLEED_TOP = 2;
27
+ const DOC_BLEED_BOTTOM = 4;
28
+ const DOC_BADGE_OVERHANG = -8;
29
+
20
30
  export type UseSmileIDGuidelineThumbnailProps = {
21
31
  readonly guideline: InstructionGuideline;
22
32
  readonly theme?: UseSmileIDTheme;
@@ -33,12 +43,96 @@ export function UseSmileIDGuidelineThumbnail({
33
43
  const themeFromContext = useUseSmileIDTheme();
34
44
  const theme = themeProp ?? themeFromContext;
35
45
  const localizations = useUseSmileIDLocalizations();
46
+ // Measured card width — the card scales to its column, so the SVG size and
47
+ // bleed offset scale with it.
48
+ const [measuredCardWidth, setMeasuredCardWidth] = useState(0);
36
49
  const allowed = guideline.status === "allowed";
37
50
  const Illustration = guideline.image;
38
51
  const Badge = allowed ? SiFilledCheckCircle : SiFilledCloseCircle;
39
52
  const badgeLabel = allowed
40
53
  ? localizations.siCdGuidelineAllowed
41
54
  : localizations.siCdGuidelineBlocked;
55
+ const caption = guideline.label(localizations);
56
+
57
+ // Document tile: one of four equal columns (so all four fit one row); the
58
+ // self-contained card SVG fills the column, framed by a border + shadow with
59
+ // an overhanging badge (no pill).
60
+ if (guideline.card) {
61
+ const { width: figmaCardWidth, height: figmaCardHeight } = guideline.card;
62
+ const scale =
63
+ measuredCardWidth > 0 ? measuredCardWidth / figmaCardWidth : 0;
64
+ return (
65
+ <View style={styles.documentTile}>
66
+ {/* No `overflow: hidden` so the badge can overhang the card corner. */}
67
+ <View style={[styles.documentCardWrap, { maxWidth: figmaCardWidth }]}>
68
+ <View
69
+ style={[
70
+ styles.documentCard,
71
+ {
72
+ aspectRatio: figmaCardWidth / figmaCardHeight,
73
+ backgroundColor: theme.colors.cardBackground,
74
+ },
75
+ ]}
76
+ onLayout={(event: LayoutChangeEvent) => {
77
+ const width = event.nativeEvent.layout.width;
78
+ setMeasuredCardWidth((previous) =>
79
+ Math.abs(previous - width) < 0.5 ? previous : width,
80
+ );
81
+ }}
82
+ >
83
+ {scale > 0 ? (
84
+ <View
85
+ style={{
86
+ position: "absolute",
87
+ left: -DOC_BLEED_X * scale,
88
+ top: -DOC_BLEED_TOP * scale,
89
+ }}
90
+ >
91
+ <Illustration
92
+ width={(figmaCardWidth + DOC_BLEED_X * 2) * scale}
93
+ height={
94
+ (figmaCardHeight + DOC_BLEED_TOP + DOC_BLEED_BOTTOM) * scale
95
+ }
96
+ />
97
+ </View>
98
+ ) : null}
99
+ {/* Border drawn over the art so the SVG can't paint over it. */}
100
+ <View
101
+ pointerEvents="none"
102
+ style={[
103
+ styles.documentCardBorder,
104
+ { borderColor: theme.colors.stroke },
105
+ ]}
106
+ />
107
+ </View>
108
+ <View
109
+ style={[
110
+ styles.badge,
111
+ styles.documentBadge,
112
+ { backgroundColor: theme.colors.cardBackground },
113
+ ]}
114
+ accessibilityRole="image"
115
+ accessibilityLabel={badgeLabel}
116
+ >
117
+ <Badge size={BADGE_ICON_SIZE} />
118
+ </View>
119
+ </View>
120
+ <Text
121
+ numberOfLines={1}
122
+ style={{
123
+ ...theme.typography.cardCaption,
124
+ fontSize: 10,
125
+ lineHeight: 12,
126
+ color: theme.colors.cardText,
127
+ textAlign: "center",
128
+ marginTop: theme.spacing.extraSmall,
129
+ }}
130
+ >
131
+ {caption}
132
+ </Text>
133
+ </View>
134
+ );
135
+ }
42
136
 
43
137
  return (
44
138
  <View style={styles.container}>
@@ -86,7 +180,7 @@ export function UseSmileIDGuidelineThumbnail({
86
180
  marginTop: theme.spacing.extraSmall,
87
181
  }}
88
182
  >
89
- {guideline.label(localizations)}
183
+ {caption}
90
184
  </Text>
91
185
  </View>
92
186
  );
@@ -131,4 +225,39 @@ const styles = StyleSheet.create({
131
225
  shadowOffset: { width: 0, height: 1 },
132
226
  elevation: 1,
133
227
  },
228
+ // One of four equal columns so the document guidelines always fit one row.
229
+ documentTile: {
230
+ width: "25%",
231
+ alignItems: "center",
232
+ paddingHorizontal: 3,
233
+ },
234
+ // Capped at the artwork's natural width (inline maxWidth) so it never grows
235
+ // past its design size on wide screens.
236
+ documentCardWrap: {
237
+ width: "100%",
238
+ alignSelf: "center",
239
+ },
240
+ documentCard: {
241
+ width: "100%",
242
+ borderRadius: DOC_CARD_RADIUS,
243
+ // No `overflow: hidden` — would clip the SVG's bleed and the shadow.
244
+ shadowColor: "#000000",
245
+ shadowOpacity: 0.1,
246
+ shadowRadius: 3,
247
+ shadowOffset: { width: 0, height: 1 },
248
+ elevation: 1,
249
+ },
250
+ documentCardBorder: {
251
+ position: "absolute",
252
+ top: 0,
253
+ bottom: 0,
254
+ start: 0,
255
+ end: 0,
256
+ borderRadius: DOC_CARD_RADIUS,
257
+ borderWidth: 1,
258
+ },
259
+ documentBadge: {
260
+ top: DOC_BADGE_OVERHANG,
261
+ end: DOC_BADGE_OVERHANG,
262
+ },
134
263
  });