@incodetech/prizma-core-screens 0.2.4 → 0.2.12

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 (243) hide show
  1. package/dist/BiometricConsentScreen.d.ts +95 -0
  2. package/dist/BiometricConsentScreen.js +91 -0
  3. package/dist/BiometricConsentStrings.d.ts +84 -0
  4. package/dist/BiometricConsentStrings.js +31 -0
  5. package/dist/CaptureScreen.d.ts +13 -0
  6. package/dist/CaptureScreen.js +2 -2
  7. package/dist/CurpEnterScreen.d.ts +7 -0
  8. package/dist/CurpEnterScreen.js +17 -3
  9. package/dist/CurpGenerateScreen.d.ts +8 -0
  10. package/dist/CurpGenerateScreen.js +28 -13
  11. package/dist/CurpLayout.css +8 -34
  12. package/dist/CurpStrings.d.ts +16 -2
  13. package/dist/DemoScreensLayout.css +16 -0
  14. package/dist/DemoScreensRedirectScreen.d.ts +6 -1
  15. package/dist/DemoScreensRedirectScreen.js +3 -2
  16. package/dist/DemoScreensStrings.d.ts +5 -0
  17. package/dist/DigitalIdUploadErrorScreen.d.ts +31 -0
  18. package/dist/DigitalIdUploadErrorScreen.js +26 -0
  19. package/dist/DigitalIdUploadFileTooLargeScreen.d.ts +27 -0
  20. package/dist/DigitalIdUploadFileTooLargeScreen.js +21 -0
  21. package/dist/DigitalIdUploadReviewScreen.d.ts +57 -0
  22. package/dist/DigitalIdUploadReviewScreen.js +44 -0
  23. package/dist/DigitalIdUploadStrings.d.ts +64 -0
  24. package/dist/DigitalIdUploadStrings.js +19 -0
  25. package/dist/DigitalIdUploadTutorialScreen.d.ts +28 -0
  26. package/dist/DigitalIdUploadTutorialScreen.js +23 -0
  27. package/dist/DocumentCaptureIllustration.d.ts +1 -1
  28. package/dist/EkybAddressDetailsScreen.d.ts +7 -0
  29. package/dist/EkybAddressDetailsScreen.js +25 -7
  30. package/dist/EkybBusinessDetailsScreen.d.ts +6 -0
  31. package/dist/EkybBusinessDetailsScreen.js +23 -6
  32. package/dist/EkybCountryScreen.d.ts +13 -5
  33. package/dist/EkybCountryScreen.js +41 -10
  34. package/dist/EkybOwnersScreen.d.ts +8 -0
  35. package/dist/EkybOwnersScreen.js +26 -3
  36. package/dist/EkybStrings.d.ts +32 -10
  37. package/dist/EkycCountryCatalog.d.ts +4 -1
  38. package/dist/EkycCountryCatalog.js +5 -3
  39. package/dist/EkycCountryFormScreen.d.ts +12 -3
  40. package/dist/EkycCountryFormScreen.js +28 -10
  41. package/dist/EkycDetailsScreen.d.ts +7 -0
  42. package/dist/EkycDetailsScreen.js +21 -4
  43. package/dist/EkycStrings.d.ts +14 -2
  44. package/dist/ElectronicSignatureLayout.css +6 -0
  45. package/dist/EmailInputStrings.d.ts +11 -1
  46. package/dist/EmailInputVerifyScreen.d.ts +7 -0
  47. package/dist/EmailInputVerifyScreen.js +17 -3
  48. package/dist/ErrorScreensScreen.d.ts +5 -2
  49. package/dist/ErrorScreensScreen.js +15 -4
  50. package/dist/ErrorScreensStrings.d.ts +17 -2
  51. package/dist/ErrorScreensStrings.js +18 -10
  52. package/dist/FaceCaptureCapturingScreen.d.ts +63 -0
  53. package/dist/FaceCaptureCapturingScreen.js +62 -2
  54. package/dist/FaceCaptureLayout.css +69 -4
  55. package/dist/FaceCaptureStrings.d.ts +23 -0
  56. package/dist/FaceMatchComparisonScreen.d.ts +3 -3
  57. package/dist/FaceMatchLayout.css +21 -12
  58. package/dist/FormScreen.css +30 -0
  59. package/dist/FormScreen.d.ts +28 -0
  60. package/dist/FormScreen.js +3 -2
  61. package/dist/FormsLongFormScreen.d.ts +8 -0
  62. package/dist/FormsLongFormScreen.js +34 -13
  63. package/dist/FormsStrings.d.ts +11 -1
  64. package/dist/GeolocationBrowserStepsScreen.d.ts +6 -2
  65. package/dist/GeolocationBrowserStepsScreen.js +7 -3
  66. package/dist/GeolocationStrings.d.ts +3 -0
  67. package/dist/IdCaptureLayout.css +205 -2
  68. package/dist/IdCaptureStageScreen.d.ts +47 -0
  69. package/dist/IdCaptureStageScreen.js +39 -3
  70. package/dist/IdCaptureStrings.d.ts +19 -0
  71. package/dist/ListScreen.d.ts +21 -0
  72. package/dist/ListScreen.js +7 -2
  73. package/dist/LoaderScreen.d.ts +7 -5
  74. package/dist/LoaderScreen.js +7 -5
  75. package/dist/LoadersStrings.d.ts +18 -5
  76. package/dist/OcrReviewErrorScreen.d.ts +30 -0
  77. package/dist/OcrReviewErrorScreen.js +24 -0
  78. package/dist/OcrReviewLayout.css +24 -0
  79. package/dist/OcrReviewLoadingScreen.d.ts +25 -0
  80. package/dist/OcrReviewLoadingScreen.js +19 -0
  81. package/dist/OcrReviewScreen.d.ts +76 -0
  82. package/dist/OcrReviewScreen.js +65 -0
  83. package/dist/OcrReviewStrings.d.ts +47 -0
  84. package/dist/OcrReviewStrings.js +17 -0
  85. package/dist/OcrReviewSuccessScreen.d.ts +30 -0
  86. package/dist/OcrReviewSuccessScreen.js +24 -0
  87. package/dist/PermissionsAllowScreen.d.ts +8 -11
  88. package/dist/PermissionsAllowScreen.js +8 -11
  89. package/dist/PermissionsAskScreen.d.ts +41 -0
  90. package/dist/PermissionsAskScreen.js +43 -0
  91. package/dist/PermissionsBrowserStepsScreen.d.ts +9 -2
  92. package/dist/PermissionsBrowserStepsScreen.js +12 -3
  93. package/dist/PermissionsLayout.css +47 -0
  94. package/dist/PermissionsStrings.d.ts +20 -9
  95. package/dist/PermissionsStrings.js +10 -4
  96. package/dist/PhoneInputLayout.css +10 -9
  97. package/dist/PhoneInputOtpScreen.d.ts +8 -0
  98. package/dist/PhoneInputOtpScreen.js +26 -19
  99. package/dist/PhoneInputStrings.d.ts +22 -4
  100. package/dist/PhoneInputVerifyScreen.d.ts +8 -0
  101. package/dist/PhoneInputVerifyScreen.js +36 -7
  102. package/dist/QualifiedSignatureAcceptScreen.js +6 -1
  103. package/dist/QualifiedSignatureDocumentScreen.d.ts +17 -10
  104. package/dist/QualifiedSignatureDocumentScreen.js +22 -17
  105. package/dist/QualifiedSignatureLayout.css +76 -0
  106. package/dist/QualifiedSignatureResultScreen.d.ts +16 -13
  107. package/dist/QualifiedSignatureResultScreen.js +17 -18
  108. package/dist/QualifiedSignatureStrings.d.ts +19 -2
  109. package/dist/ResultScreen.d.ts +8 -0
  110. package/dist/ResultScreen.js +14 -3
  111. package/dist/ReusabilityCredentialSelectionScreen.d.ts +95 -0
  112. package/dist/ReusabilityCredentialSelectionScreen.js +94 -0
  113. package/dist/ReusabilityLayout.css +241 -0
  114. package/dist/ReusabilityPrivacyPolicyScreen.d.ts +55 -0
  115. package/dist/ReusabilityPrivacyPolicyScreen.js +44 -0
  116. package/dist/ReusabilityStrings.d.ts +85 -0
  117. package/dist/ReusabilityStrings.js +37 -0
  118. package/dist/ReviewScreen.d.ts +38 -12
  119. package/dist/ReviewScreen.js +41 -8
  120. package/dist/ScreenLayout.css +382 -6
  121. package/dist/ScreenNav.css +8 -0
  122. package/dist/ScreenNav.d.ts +15 -2
  123. package/dist/ScreenNav.js +10 -3
  124. package/dist/VideoSelfieErrorScreen.js +1 -1
  125. package/dist/VideoSelfieIdCaptureScreen.d.ts +10 -3
  126. package/dist/VideoSelfieIdCaptureScreen.js +45 -14
  127. package/dist/VideoSelfieLayout.css +467 -34
  128. package/dist/VideoSelfieSelfieCaptureScreen.d.ts +44 -27
  129. package/dist/VideoSelfieSelfieCaptureScreen.js +65 -39
  130. package/dist/VideoSelfieSpeakScreen.js +19 -2
  131. package/dist/VideoSelfieStrings.d.ts +82 -13
  132. package/dist/VideoSelfieTurnHeadScreen.d.ts +51 -0
  133. package/dist/VideoSelfieTurnHeadScreen.js +66 -0
  134. package/dist/VideoSelfieTutorialScreen.d.ts +9 -0
  135. package/dist/VideoSelfieTutorialScreen.js +22 -5
  136. package/dist/VideoSelfieWaveScreen.d.ts +53 -0
  137. package/dist/VideoSelfieWaveScreen.js +62 -0
  138. package/dist/ViewfinderScreen.css +36 -0
  139. package/dist/WatchlistBusinessFormScreen.d.ts +11 -7
  140. package/dist/WatchlistBusinessFormScreen.js +27 -13
  141. package/dist/WatchlistBusinessStrings.d.ts +21 -7
  142. package/dist/flows.d.ts +8 -0
  143. package/dist/flows.js +17 -0
  144. package/dist/index.d.ts +19 -1
  145. package/dist/index.js +14 -0
  146. package/dist/styles.css +3 -0
  147. package/dist/types.d.ts +3 -1
  148. package/package.json +79 -3
  149. package/samples/video-selfie-camera-wide.jpg +0 -0
  150. package/samples/video-selfie-room-wide.jpg +0 -0
  151. package/samples/video-selfie-room.png +0 -0
  152. package/src/BiometricConsentScreen.tsx +192 -0
  153. package/src/BiometricConsentStrings.ts +119 -0
  154. package/src/CaptureScreen.tsx +17 -0
  155. package/src/CurpEnterScreen.tsx +21 -4
  156. package/src/CurpGenerateScreen.tsx +46 -22
  157. package/src/CurpLayout.css +8 -34
  158. package/src/CurpStrings.ts +22 -2
  159. package/src/DemoScreensLayout.css +16 -0
  160. package/src/DemoScreensRedirectScreen.tsx +14 -6
  161. package/src/DemoScreensStrings.ts +5 -0
  162. package/src/DigitalIdUploadErrorScreen.tsx +83 -0
  163. package/src/DigitalIdUploadFileTooLargeScreen.tsx +67 -0
  164. package/src/DigitalIdUploadReviewScreen.tsx +119 -0
  165. package/src/DigitalIdUploadStrings.ts +88 -0
  166. package/src/DigitalIdUploadTutorialScreen.tsx +59 -0
  167. package/src/DocumentCaptureIllustration.tsx +1 -1
  168. package/src/EkybAddressDetailsScreen.tsx +32 -4
  169. package/src/EkybBusinessDetailsScreen.tsx +23 -5
  170. package/src/EkybCountryScreen.tsx +45 -7
  171. package/src/EkybOwnersScreen.tsx +34 -3
  172. package/src/EkybStrings.ts +34 -10
  173. package/src/EkycCountryCatalog.ts +9 -4
  174. package/src/EkycCountryFormScreen.tsx +51 -12
  175. package/src/EkycDetailsScreen.tsx +22 -1
  176. package/src/EkycStrings.ts +14 -2
  177. package/src/ElectronicSignatureLayout.css +6 -0
  178. package/src/EmailInputStrings.ts +12 -1
  179. package/src/EmailInputVerifyScreen.tsx +21 -4
  180. package/src/ErrorScreensScreen.tsx +15 -4
  181. package/src/ErrorScreensStrings.ts +37 -12
  182. package/src/FaceCaptureCapturingScreen.tsx +102 -13
  183. package/src/FaceCaptureLayout.css +69 -4
  184. package/src/FaceCaptureStrings.ts +24 -0
  185. package/src/FaceMatchComparisonScreen.tsx +3 -3
  186. package/src/FaceMatchLayout.css +21 -12
  187. package/src/FormScreen.css +30 -0
  188. package/src/FormScreen.tsx +34 -0
  189. package/src/FormsLongFormScreen.tsx +41 -13
  190. package/src/FormsStrings.ts +12 -1
  191. package/src/GeolocationBrowserStepsScreen.tsx +6 -3
  192. package/src/GeolocationStrings.ts +3 -0
  193. package/src/IdCaptureLayout.css +205 -2
  194. package/src/IdCaptureStageScreen.tsx +75 -0
  195. package/src/IdCaptureStrings.ts +19 -0
  196. package/src/ListScreen.tsx +58 -10
  197. package/src/LoaderScreen.tsx +7 -5
  198. package/src/LoadersStrings.ts +18 -5
  199. package/src/OcrReviewErrorScreen.tsx +53 -0
  200. package/src/OcrReviewLayout.css +24 -0
  201. package/src/OcrReviewLoadingScreen.tsx +48 -0
  202. package/src/OcrReviewScreen.tsx +190 -0
  203. package/src/OcrReviewStrings.ts +69 -0
  204. package/src/OcrReviewSuccessScreen.tsx +52 -0
  205. package/src/PermissionsAllowScreen.tsx +9 -10
  206. package/src/PermissionsAskScreen.tsx +105 -0
  207. package/src/PermissionsBrowserStepsScreen.tsx +11 -3
  208. package/src/PermissionsLayout.css +47 -0
  209. package/src/PermissionsStrings.ts +42 -12
  210. package/src/PhoneInputLayout.css +10 -9
  211. package/src/PhoneInputOtpScreen.tsx +23 -3
  212. package/src/PhoneInputStrings.ts +23 -4
  213. package/src/PhoneInputVerifyScreen.tsx +41 -5
  214. package/src/QualifiedSignatureAcceptScreen.tsx +12 -1
  215. package/src/QualifiedSignatureDocumentScreen.tsx +31 -19
  216. package/src/QualifiedSignatureLayout.css +76 -0
  217. package/src/QualifiedSignatureResultScreen.tsx +28 -26
  218. package/src/QualifiedSignatureStrings.ts +19 -2
  219. package/src/ResultScreen.tsx +33 -2
  220. package/src/ReusabilityCredentialSelectionScreen.tsx +246 -0
  221. package/src/ReusabilityLayout.css +241 -0
  222. package/src/ReusabilityPrivacyPolicyScreen.tsx +109 -0
  223. package/src/ReusabilityStrings.ts +127 -0
  224. package/src/ReviewScreen.tsx +96 -27
  225. package/src/ScreenLayout.css +382 -6
  226. package/src/ScreenNav.css +8 -0
  227. package/src/ScreenNav.tsx +35 -5
  228. package/src/VideoSelfieErrorScreen.tsx +1 -1
  229. package/src/VideoSelfieIdCaptureScreen.tsx +125 -31
  230. package/src/VideoSelfieLayout.css +467 -34
  231. package/src/VideoSelfieSelfieCaptureScreen.tsx +110 -57
  232. package/src/VideoSelfieSpeakScreen.tsx +34 -15
  233. package/src/VideoSelfieStrings.ts +89 -14
  234. package/src/VideoSelfieTurnHeadScreen.tsx +162 -0
  235. package/src/VideoSelfieTutorialScreen.tsx +45 -23
  236. package/src/VideoSelfieWaveScreen.tsx +143 -0
  237. package/src/ViewfinderScreen.css +36 -0
  238. package/src/WatchlistBusinessFormScreen.tsx +35 -16
  239. package/src/WatchlistBusinessStrings.ts +21 -7
  240. package/src/flows.ts +25 -0
  241. package/src/index.ts +88 -3
  242. package/src/styles.css +3 -0
  243. package/src/types.ts +3 -1
@@ -19,16 +19,21 @@ import './QualifiedSignatureLayout.css';
19
19
  *
20
20
  * Archetype G is the fit: its `__list` middle is "content filling the space
21
21
  * between the title block and the CTA band", which is exactly what a document
22
- * page is, and both sections carry no CTA at all so the band never renders. The
22
+ * page is, and the band carries only the "Back" secondary (delta 1). The
23
23
  * body is allowed to scroll inside that middle — one module rule RELEASING an
24
24
  * overflow constraint, declaring no spacing or size, the same idiom as CURP's
25
25
  * taller-than-844 form (DEVIATIONS #CURP-1).
26
26
  *
27
- * THREE deltas from the frames, all reported rather than worked around:
28
- * 1. Both sections draw a back chevron at the nav's left (and `terms` replaces
29
- * the logo row with a chevron + heading bar). GUIDELINES §3 stands: SDK
30
- * screens carry no dismiss or back affordance — the standing ruling of
31
- * DEVIATIONS #PI-9, which is not re-litigated per module.
27
+ * THREE deltas from the frames:
28
+ * 1. Both sections draw a back chevron at the nav's left. These are viewers
29
+ * the user opened from the accept screen, so they need a way back (owner
30
+ * call 2026-09-29). It ships as a full-width SECONDARY "Back" button in the
31
+ * CTA band instead, emitting `secondary` (owner call 2026-10-08): the person
32
+ * reads and returns to sign, and a real button at the thumb is easier to
33
+ * find than a chevron. "Back" over "Done" because nothing is finished here;
34
+ * the signature still waits on the accept screen. The nav stays logo-only.
35
+ * `terms` replacing the logo row with a chevron + heading bar is still not
36
+ * followed — the title stays the archetype's H2 below the nav.
32
37
  * 2. `viewdoc` draws NO heading. GUIDELINES §4 is explicit that every screen has
33
38
  * exactly one H2, and archetype G has no title-less path, so the screen
34
39
  * carries one and the Figma frame is the side to change. (An archetype
@@ -37,20 +42,20 @@ import './QualifiedSignatureLayout.css';
37
42
  * for attribution chrome (#PI-8, #F-30, #F-34), so both variants keep the
38
43
  * header and the footer and nothing shifts between states.
39
44
  *
40
- * `terms` is LEFT-aligned, as Figma draws it: a centred heading over a
41
- * left-aligned wall of legal text reads as a mistake. The alignment rides the
42
- * sanctioned `overrides.align` path (types.ts) — nothing is re-styled here — and
43
- * an explicit host override still wins. The #GEO-2 precedent.
45
+ * Both variants frame the page in the box Electronic Signature's review screen
46
+ * uses, so the title is CENTRED on both, like that screen (owner call
47
+ * 2026-09-29, "take reference from other screens"). Figma's `QSign.T&C` draws
48
+ * the title left over an unframed wall of text; once the text sits in its own
49
+ * left-aligned frame the centred title no longer reads as a mistake. An
50
+ * explicit `overrides.align` from the host still wins.
44
51
  */
45
52
  export const QualifiedSignatureDocumentScreen = forwardRef(({ strings, variant = 'document', body, screenId = `qualified-signature-document-${variant}`, overrides, onAction, ...shell }, ref) => {
46
53
  const copy = variant === 'terms' ? strings.document.terms : strings.document.document;
47
- // The legal wall is left-aligned in Figma; the contract page keeps the
48
- // archetype's centred default. An explicit `overrides.align` still wins.
49
- const alignedOverrides = {
50
- ...overrides,
51
- align: overrides?.align ?? (variant === 'terms' ? 'left' : 'centered'),
52
- };
53
- return (_jsx(PrizmaListScreen, { ref: ref, title: copy.title, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: alignedOverrides, onAction: onAction, ...shell, children: _jsx("div", { className: "qualified-signature-document", children: body }) }));
54
+ return (_jsx(PrizmaListScreen, { ref: ref, title: copy.title, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, secondaryCtaLabel: strings.document.backLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell, children: _jsx("div", { className: [
55
+ 'qualified-signature-document',
56
+ 'qualified-signature-document--framed',
57
+ `qualified-signature-document--${variant}`,
58
+ ].join(' '), role: "region", "aria-label": copy.title, tabIndex: 0, children: body }) }));
54
59
  });
55
60
  QualifiedSignatureDocumentScreen.displayName = 'QualifiedSignatureDocumentScreen';
56
61
  export default QualifiedSignatureDocumentScreen;
@@ -57,6 +57,26 @@
57
57
  display: flex;
58
58
  flex-direction: column;
59
59
  gap: var(--prizma-spacing-4);
60
+ /* The clauses sit at the BOTTOM of the column, on the primary button, not
61
+ * under the document row (Elena, 2026-09-30). The fields are a flex column,
62
+ * so the auto margin takes the free space; when the clauses outgrow the frame
63
+ * (the five-clause reading) there is none and the stack scrolls as before. */
64
+ margin-top: auto;
65
+ }
66
+
67
+ /* The required legend leading the group. Core ships no caption block outside a
68
+ * field, so the line binds the clause copy's own Size-S tokens in the secondary
69
+ * ink — no new size, no new colour. Spacing/8 more below it than the clauses
70
+ * keep between themselves, so it reads as the group's header. */
71
+ .qualified-signature-terms__legend {
72
+ margin: 0 0 var(--prizma-spacing-8);
73
+ font-family: var(--prizma-checkbox-radio-family);
74
+ font-weight: var(--prizma-checkbox-radio-s-font-weight);
75
+ font-size: var(--prizma-checkbox-radio-s-font-size);
76
+ line-height: var(--prizma-checkbox-radio-s-line-height);
77
+ letter-spacing: var(--prizma-checkbox-radio-s-letter-spacing);
78
+ color: var(--prizma-text-body-500-secondary);
79
+ text-align: left;
60
80
  }
61
81
 
62
82
  /* ── (c) Uploaded-file preview card ──────────────────────────────────────────
@@ -181,6 +201,62 @@
181
201
  overscroll-behavior: contain;
182
202
  }
183
203
 
204
+ /* The document FRAME — the two full-surface document screens draw the page
205
+ * inside the same box Electronic Signature's review screen uses
206
+ * (`.electronic-signature-document`): `Border/Neutral/100` hairline,
207
+ * `Border/Radius/small`, `Surface/Neutral/0`, clipped so the page scrolls INSIDE
208
+ * it. Without it the contract image floated loose on the screen and the legal
209
+ * text ran edge to edge as one grey wall (owner-reported 2026-09-29: "take
210
+ * reference from other screens"). A modifier, not the base class, because the
211
+ * gated-form exploration reuses `.qualified-signature-document` inside its own
212
+ * popup, which already carries a frame.
213
+ *
214
+ * Spacing/16 bottom margin: the gap Electronic Signature's frame keeps above the
215
+ * CTA band, here kept above the anchored tag so the frame never touches it.
216
+ */
217
+ .qualified-signature-document--framed {
218
+ box-sizing: border-box;
219
+ background-color: var(--prizma-surface-neutral-0);
220
+ border: var(--prizma-border-width-regular) solid var(--prizma-border-neutral-100);
221
+ border-radius: var(--prizma-border-radius-small);
222
+ margin-bottom: var(--prizma-spacing-16);
223
+ }
224
+
225
+ /* `terms` — a TEXT agreement needs a gutter inside the frame (Spacing/16) and
226
+ * the paragraph rhythm Electronic Signature uses (Spacing/12 between blocks). */
227
+ .qualified-signature-document--terms {
228
+ padding: var(--prizma-spacing-16);
229
+ text-align: start;
230
+ }
231
+
232
+ .qualified-signature-document--terms > * {
233
+ margin: 0;
234
+ }
235
+
236
+ .qualified-signature-document.qualified-signature-document--terms > * + * {
237
+ /* Doubled class: `__prose` resets `margin: 0` later in this file at the
238
+ same specificity, which would otherwise swallow the rhythm. */
239
+ margin-top: var(--prizma-spacing-12);
240
+ }
241
+
242
+ /* Section headings inside the form — Headline/H5 on Text/Body/800, the same
243
+ * pair as `.electronic-signature-document h4`. */
244
+ .qualified-signature-document--terms h4 {
245
+ font-family: var(--prizma-headline-family);
246
+ font-weight: var(--prizma-headline-h5-font-weight);
247
+ font-size: var(--prizma-headline-h5-font-size);
248
+ line-height: var(--prizma-headline-h5-line-height);
249
+ letter-spacing: var(--prizma-headline-h5-letter-spacing);
250
+ color: var(--prizma-text-body-800-primary);
251
+ }
252
+
253
+ /* Inside the frame the prose drops to Text/Body/500, the secondary ink every
254
+ * block of Core prose uses (`CardList.css`, `Card.css`) — the heading carries
255
+ * the hierarchy, as in Electronic Signature. */
256
+ .qualified-signature-document--terms .qualified-signature-document__prose {
257
+ color: var(--prizma-text-body-500-secondary);
258
+ }
259
+
184
260
  /* The contract page is host-supplied media (an <img> / <canvas> of the rendered
185
261
  * PDF, GUIDELINES §10's `cameraSurface` idiom) — it fills the column width and
186
262
  * keeps its own aspect. */
@@ -3,11 +3,16 @@ import { type PrizmaResultScreenProps } from './ResultScreen';
3
3
  import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
4
4
  import type { QualifiedSignatureResultVariant, QualifiedSignatureStrings } from './QualifiedSignatureStrings';
5
5
  import './ScreenLayout.css';
6
- export interface QualifiedSignatureResultScreenProps extends Omit<PrizmaResultScreenProps, 'status' | 'title' | 'subtitle' | 'glyph' | 'bandContent' | 'disclaimer' | 'ctaLabel' | 'secondaryCtaLabel' | 'verifiedLabel' | 'navLabel'> {
6
+ export interface QualifiedSignatureResultScreenProps extends Omit<PrizmaResultScreenProps, 'status' | 'title' | 'subtitle' | 'glyph' | 'bandContent' | 'disclaimer' | 'ctaLabel' | 'secondaryCtaLabel' | 'progress' | 'verifiedLabel' | 'navLabel'> {
7
7
  /** Module copy — this screen reads the `result` slice its `variant` names. */
8
8
  strings: QualifiedSignatureStrings;
9
9
  /** Which verdict section to render. Default `signed`. */
10
10
  variant?: QualifiedSignatureResultVariant;
11
+ /** `signed` · `signedPartner` only — draw the "document downloaded" Snackbar,
12
+ * the state after the person pressed the download control. HOST state, like
13
+ * Error screens' `copied`: the host sets it on the `secondary` action and
14
+ * clears it when its own timer runs out. Default `false`. */
15
+ downloaded?: boolean;
11
16
  screenId?: string;
12
17
  overrides?: PrizmaScreenOverrides;
13
18
  onAction?: PrizmaScreenActionHandler;
@@ -20,8 +25,10 @@ export interface QualifiedSignatureResultScreenProps extends Omit<PrizmaResultSc
20
25
  * nav → centred status mark + title block → CTA band → anchored tag — and differ
21
26
  * in status, copy and which actions exist:
22
27
  * - `signed` — `QSign.success` (10196:67485): the positive mark over a
23
- * `Button group` 124 tall = the "Continue" primary plus the "Download PDF"
24
- * underlined link.
28
+ * STACKED pair — "Continue" primary above a "Download PDF" OUTLINED
29
+ * secondary. Figma draws the download as an underlined link; it ships as the
30
+ * partner's secondary Button instead (owner call 2026-10-08, "make the
31
+ * generic one look like Namirial"), so both success endings read alike.
25
32
  * - `signedPlain` — `QSign.success` (10196:67494): the SAME mark and line
26
33
  * with no actions at all, so the band never renders and the screen reads as
27
34
  * the pure §6-C verdict.
@@ -50,16 +57,12 @@ export interface QualifiedSignatureResultScreenProps extends Omit<PrizmaResultSc
50
57
  * The owner rule settles the split in favour of keeping it (#PI-8, #F-30) so
51
58
  * nothing shifts between states.
52
59
  *
53
- * ONE reported delta: on `signed`, Figma puts "Download PDF" BELOW the primary,
54
- * at Core's `PrizmaButtonGroup` Spacing/12. Archetype F has no tertiary-link
55
- * slot — its only band opening above the buttons is `bandContent` — so Core's
56
- * own `tertiary-link` Button is composed there and lands ABOVE the primary at
57
- * the band's Spacing/32 (16 + 16). Ink, semantics and the distinct `secondary`
58
- * action are all correct (#PI-10); only the position moves. #GEO-1 fixes the
59
- * tertiary link's position PER ARCHETYPE and F has never declared one — the
60
- * archetype request is logged instead of a local override. `signedPartner` is
61
- * unaffected: its download control is a real outlined secondary Button, which
62
- * the archetype already places correctly.
60
+ * The download confirmation. Pressing "Download PDF" / "Download document"
61
+ * emits `secondary`; the host then sets `downloaded` and the screen raises a
62
+ * success Snackbar ("Document downloaded") in the archetype's `progress` slot,
63
+ * between the nav and the content, the same slot and component Error screens
64
+ * use for "link copied" (owner call 2026-10-08). Dismissal is the host's: the
65
+ * Snackbar is presentational (snackbar.md §9 item 6).
63
66
  */
64
67
  export declare const QualifiedSignatureResultScreen: React.ForwardRefExoticComponent<QualifiedSignatureResultScreenProps & React.RefAttributes<HTMLDivElement>>;
65
68
  export default QualifiedSignatureResultScreen;
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { forwardRef } from 'react';
4
- import { PrizmaButton } from '@incodetech/prizma-core-web/button';
4
+ import { PrizmaSnackbar } from '@incodetech/prizma-core-web/snackbar';
5
5
  import { PrizmaResultScreen } from './ResultScreen';
6
6
  import './ScreenLayout.css';
7
7
  /**
@@ -12,8 +12,10 @@ import './ScreenLayout.css';
12
12
  * nav → centred status mark + title block → CTA band → anchored tag — and differ
13
13
  * in status, copy and which actions exist:
14
14
  * - `signed` — `QSign.success` (10196:67485): the positive mark over a
15
- * `Button group` 124 tall = the "Continue" primary plus the "Download PDF"
16
- * underlined link.
15
+ * STACKED pair — "Continue" primary above a "Download PDF" OUTLINED
16
+ * secondary. Figma draws the download as an underlined link; it ships as the
17
+ * partner's secondary Button instead (owner call 2026-10-08, "make the
18
+ * generic one look like Namirial"), so both success endings read alike.
17
19
  * - `signedPlain` — `QSign.success` (10196:67494): the SAME mark and line
18
20
  * with no actions at all, so the band never renders and the screen reads as
19
21
  * the pure §6-C verdict.
@@ -42,18 +44,14 @@ import './ScreenLayout.css';
42
44
  * The owner rule settles the split in favour of keeping it (#PI-8, #F-30) so
43
45
  * nothing shifts between states.
44
46
  *
45
- * ONE reported delta: on `signed`, Figma puts "Download PDF" BELOW the primary,
46
- * at Core's `PrizmaButtonGroup` Spacing/12. Archetype F has no tertiary-link
47
- * slot — its only band opening above the buttons is `bandContent` — so Core's
48
- * own `tertiary-link` Button is composed there and lands ABOVE the primary at
49
- * the band's Spacing/32 (16 + 16). Ink, semantics and the distinct `secondary`
50
- * action are all correct (#PI-10); only the position moves. #GEO-1 fixes the
51
- * tertiary link's position PER ARCHETYPE and F has never declared one — the
52
- * archetype request is logged instead of a local override. `signedPartner` is
53
- * unaffected: its download control is a real outlined secondary Button, which
54
- * the archetype already places correctly.
47
+ * The download confirmation. Pressing "Download PDF" / "Download document"
48
+ * emits `secondary`; the host then sets `downloaded` and the screen raises a
49
+ * success Snackbar ("Document downloaded") in the archetype's `progress` slot,
50
+ * between the nav and the content, the same slot and component Error screens
51
+ * use for "link copied" (owner call 2026-10-08). Dismissal is the host's: the
52
+ * Snackbar is presentational (snackbar.md §9 item 6).
55
53
  */
56
- export const QualifiedSignatureResultScreen = forwardRef(({ strings, variant = 'signed', screenId = `qualified-signature-result-${variant}`, overrides, onAction, ...shell }, ref) => {
54
+ export const QualifiedSignatureResultScreen = forwardRef(({ strings, variant = 'signed', downloaded = false, screenId = `qualified-signature-result-${variant}`, overrides, onAction, ...shell }, ref) => {
57
55
  // One slice per frame — nothing is shared between variants, so the frames
58
56
  // can never collapse into each other visually.
59
57
  const signedCopy = variant === 'signed' ? strings.result.signed : undefined;
@@ -63,14 +61,15 @@ export const QualifiedSignatureResultScreen = forwardRef(({ strings, variant = '
63
61
  partnerCopy ??
64
62
  retryCopy ??
65
63
  (variant === 'error' ? strings.result.error : strings.result.signedPlain);
66
- return (_jsx(PrizmaResultScreen, { ref: ref, status: variant === 'error' || variant === 'errorRetry' ? 'warning' : 'success', title: copy.title, subtitle: copy.subtitle,
64
+ return (_jsx(PrizmaResultScreen, { ref: ref, status: variant === 'error' || variant === 'errorRetry' ? 'warning' : 'success', title: copy.title, subtitle: copy.subtitle, progress: downloaded && (signedCopy?.downloadLabel || partnerCopy) ? (_jsx(PrizmaSnackbar, { state: "success", contentResizing: "fill", children: strings.result.downloadedLabel })) : undefined,
67
65
  /* "Continue" · "Done" · "Try again" — the archetype's own primary. */
68
66
  ctaLabel: signedCopy?.ctaLabel ?? partnerCopy?.ctaLabel ?? retryCopy?.ctaLabel,
69
- /* The partner's outlined "Download document", below the primary. */
70
- secondaryCtaLabel: partnerCopy?.secondaryCtaLabel,
67
+ /* The outlined download, below the primary: "Download PDF" on the
68
+ generic ending, "Download document" on the partner's. */
69
+ secondaryCtaLabel: signedCopy?.downloadLabel ?? partnerCopy?.secondaryCtaLabel,
71
70
  /* The partner's "Signed by …" row — the band's centred text slot, which
72
71
  puts it above the button pair exactly as Figma draws it. */
73
- disclaimer: partnerCopy?.signedByLabel, bandContent: signedCopy?.downloadLabel ? (_jsx(PrizmaButton, { variant: "tertiary-link", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: signedCopy.downloadLabel })) : undefined, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell }));
72
+ disclaimer: partnerCopy?.signedByLabel, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell }));
74
73
  });
75
74
  QualifiedSignatureResultScreen.displayName = 'QualifiedSignatureResultScreen';
76
75
  export default QualifiedSignatureResultScreen;
@@ -33,7 +33,8 @@ export type QualifiedSignatureDocumentVariant = 'document' | 'terms';
33
33
  * The FIVE verdict frames. Both purple parents draw success twice and error
34
34
  * twice, and each pair differs in what the signer can do next:
35
35
  * - `signed` — `QSign.success` (10196:67485): the positive mark with
36
- * "Continue" and a "Download PDF" underlined link
36
+ * "Continue" primary above a "Download PDF" outlined secondary (was an
37
+ * underlined link in Figma; owner call 2026-10-08, matches the partner)
37
38
  * - `signedPlain` — `QSign.success` (10196:67494): the same mark and line
38
39
  * with NO actions at all
39
40
  * - `signedPartner` — the `x Namirial` parent's own success frame (6086:40135),
@@ -128,6 +129,12 @@ export interface QualifiedSignatureStrings {
128
129
  viewLabel: string;
129
130
  /** Accessible name for the consent stack. */
130
131
  termsLabel?: string;
132
+ /** Suffix appended to every clause, all of them required ("*"). Localizable,
133
+ * never baked into the clause copy — Data Sharing Consent's `requiredHint`. */
134
+ requiredHint?: string;
135
+ /** The line that leads the clause group and explains the marker ("All terms
136
+ * marked with * are required."). Only drawn alongside `requiredHint`. */
137
+ requiredLegend?: string;
131
138
  /** The generic five-clause reading. */
132
139
  accept: QualifiedSignatureAcceptCopy;
133
140
  /** The partner two-clause reading. */
@@ -148,6 +155,12 @@ export interface QualifiedSignatureStrings {
148
155
  terms: {
149
156
  title: string;
150
157
  };
158
+ /** The way back on both document screens
159
+ * ("Back") — they are opened from the accept screen, so they carry a way
160
+ * back to it. It is the label of a full-width SECONDARY button in the CTA
161
+ * band (owner call 2026-10-08, was the nav chevron) and emits
162
+ * `secondary`. Omit it and no way back renders. */
163
+ backLabel?: string;
151
164
  };
152
165
  /** The two in-flight screens. */
153
166
  processing: {
@@ -181,7 +194,8 @@ export interface QualifiedSignatureStrings {
181
194
  subtitle?: string;
182
195
  /** Primary CTA ("Continue"). */
183
196
  ctaLabel: string;
184
- /** Underlined tertiary link ("Download PDF"). Emits `secondary`. */
197
+ /** OUTLINED secondary below the primary ("Download PDF"), the same
198
+ * control as the partner's "Download document". Emits `secondary`. */
185
199
  downloadLabel?: string;
186
200
  };
187
201
  /** QSign.success drawn with no actions. */
@@ -206,6 +220,9 @@ export interface QualifiedSignatureStrings {
206
220
  * `secondary`. A real Button, not `signed`'s underlined link. */
207
221
  secondaryCtaLabel: string;
208
222
  };
223
+ /** The success Snackbar raised after either download control was pressed
224
+ * ("Document downloaded"). Shared by `signed` and `signedPartner`. */
225
+ downloadedLabel: string;
209
226
  /** QSign.AcceptSign.error ("Something went wrong"). Figma draws no button. */
210
227
  error: {
211
228
  title: string;
@@ -64,6 +64,14 @@ export interface PrizmaResultScreenProps extends Omit<PrizmaScreenShellProps, 'd
64
64
  * job (Face Match's verdict Snackbar). DEVIATIONS #VS-17.
65
65
  */
66
66
  linkLabel?: string;
67
+ /**
68
+ * Where the tertiary link sits in the stack. `below` (default) is archetype
69
+ * A's position; `above` puts it over the primary CTA, which is what the
70
+ * permission frames draw ("Quit process" over "Allow permission",
71
+ * DEVIATIONS #GEN-3, #VS-17). The slot those rows escalated: the archetype
72
+ * still owns both positions, a screen only picks one of them.
73
+ */
74
+ linkPosition?: 'below' | 'above';
67
75
  /** "verified by" attribution copy for the footer tag. */
68
76
  verifiedLabel: string;
69
77
  navLabel?: string;
@@ -26,12 +26,23 @@ import './ScreenLayout.css';
26
26
  * `ProcessingScreen` stays the pure spinner/no-CTA case; reach for this one as
27
27
  * soon as a result screen needs a button.
28
28
  */
29
- export const PrizmaResultScreen = forwardRef(({ progress, status = 'none', title, subtitle, glyph, children, bandContent, disclaimer, ctaOrientation = 'stacked', ctaLabel, secondaryCtaLabel, linkLabel, verifiedLabel, navLabel, screenId, showHeader = true, showFooter = true, overrides, onAction, ...shell }, ref) => (_jsxs(PrizmaScreenShell, { ref: ref, ...shell, children: [_jsx(PrizmaScreenNav, { reserved: !showHeader, logo: overrides?.logo, navLabel: navLabel }), progress ? (_jsx("div", { className: "prizma-screen-layout__progress", children: progress })) : null, _jsxs("div", { className: "prizma-screen-layout__content prizma-screen-layout__content--centered", children: [glyph, _jsx(PrizmaTitle, { variant: overrides?.align === 'left' ? 'left' : 'centered', title: title, showSubtitle: Boolean(subtitle), subtitle: subtitle, icon: status === 'loading'
29
+ export const PrizmaResultScreen = forwardRef(({ progress, status = 'none', title, subtitle, glyph, children, bandContent, disclaimer, ctaOrientation = 'stacked', ctaLabel, secondaryCtaLabel, linkLabel, linkPosition = 'below', verifiedLabel, navLabel, screenId, showHeader = true, showFooter = true, overrides, onAction, ...shell }, ref) => (_jsxs(PrizmaScreenShell, { ref: ref, ...shell, children: [_jsx(PrizmaScreenNav, { reserved: !showHeader, logo: overrides?.logo, navLabel: navLabel }), progress ? (_jsx("div", { className: "prizma-screen-layout__progress", children: progress })) : null, _jsxs("div", { className: "prizma-screen-layout__content prizma-screen-layout__content--centered", children: [glyph, _jsx(PrizmaTitle, { variant: overrides?.align === 'left' ? 'left' : 'centered', title: title, showSubtitle: Boolean(subtitle), subtitle: subtitle, icon: status === 'loading'
30
30
  ? { type: 'spinner' }
31
31
  : status === 'none'
32
32
  ? { type: 'none' }
33
- : { type: 'status', status } }), children] }), ctaLabel || secondaryCtaLabel || linkLabel || disclaimer || bandContent ? (_jsxs("div", { className: "prizma-screen-layout__band prizma-screen-layout__band--result", children: [bandContent ? (_jsx("div", { className: "prizma-screen-layout__band__content", children: bandContent })) : null, disclaimer ? _jsx(PrizmaDisclaimer, { text: disclaimer }) : null, _jsxs("div", { className: ctaOrientation === 'row'
33
+ : { type: 'status', status } }), children] }), ctaLabel || secondaryCtaLabel || linkLabel || disclaimer || bandContent ? (_jsxs("div", { className: [
34
+ 'prizma-screen-layout__band',
35
+ 'prizma-screen-layout__band--result',
36
+ // No footer tag to reserve `--pcs-footer-space` for — same gap the
37
+ // Review archetype's `--bare` fallback exists for (ScreenLayout.css).
38
+ // Every existing F consumer always shows the tag, so this has never
39
+ // fired before; without it the CTA sits ~40px further from the
40
+ // bottom than Figma's flat Spacing/24 draws.
41
+ !showFooter ? 'prizma-screen-layout__band--bare' : '',
42
+ ]
43
+ .filter(Boolean)
44
+ .join(' '), children: [bandContent ? (_jsx("div", { className: "prizma-screen-layout__band__content", children: bandContent })) : null, disclaimer ? _jsx(PrizmaDisclaimer, { text: disclaimer }) : null, _jsxs("div", { className: ctaOrientation === 'row'
34
45
  ? 'prizma-screen-layout__band__ctas prizma-screen-layout__band__ctas--row'
35
- : 'prizma-screen-layout__band__ctas', children: [ctaLabel ? (_jsx(PrizmaButton, { variant: "primary", size: "L", onClick: () => onAction?.({ type: 'cta', screenId }), children: ctaLabel })) : null, secondaryCtaLabel ? (_jsx(PrizmaButton, { variant: "secondary", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: secondaryCtaLabel })) : null, linkLabel ? (_jsx(PrizmaButton, { variant: "tertiary-link", size: "L", onClick: () => onAction?.({ type: 'tertiary', screenId }), children: linkLabel })) : null] })] })) : null, showFooter ? (_jsx("div", { className: "prizma-screen-layout__footer", children: _jsx(PrizmaTag, { label: verifiedLabel }) })) : null] })));
46
+ : 'prizma-screen-layout__band__ctas', children: [linkLabel && linkPosition === 'above' ? (_jsx(PrizmaButton, { variant: "tertiary-link", size: "L", onClick: () => onAction?.({ type: 'tertiary', screenId }), children: linkLabel })) : null, ctaLabel ? (_jsx(PrizmaButton, { variant: "primary", size: "L", onClick: () => onAction?.({ type: 'cta', screenId }), children: ctaLabel })) : null, secondaryCtaLabel ? (_jsx(PrizmaButton, { variant: "secondary", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: secondaryCtaLabel })) : null, linkLabel && linkPosition === 'below' ? (_jsx(PrizmaButton, { variant: "tertiary-link", size: "L", onClick: () => onAction?.({ type: 'tertiary', screenId }), children: linkLabel })) : null] })] })) : null, showFooter ? (_jsx("div", { className: "prizma-screen-layout__footer", children: _jsx(PrizmaTag, { label: verifiedLabel }) })) : null] })));
36
47
  PrizmaResultScreen.displayName = 'PrizmaResultScreen';
37
48
  export default PrizmaResultScreen;
@@ -0,0 +1,95 @@
1
+ import React from 'react';
2
+ import { type PrizmaListScreenProps } from './ListScreen';
3
+ import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
4
+ import type { ReusableCredential, ReusabilityStrings } from './ReusabilityStrings';
5
+ import './ScreenLayout.css';
6
+ import './ReusabilityLayout.css';
7
+ /** The sentinel the SDK submits for the capture row (`SCAN_NEW_DOCUMENT`,
8
+ * `identityReuseStateMachine.ts`): `{ accepted: false }`, then ID Capture. */
9
+ export declare const REUSABILITY_SCAN_NEW: "scanNew";
10
+ export type ReusabilitySelection = string | typeof REUSABILITY_SCAN_NEW;
11
+ export interface ReusabilityCredentialSelectionScreenProps extends Omit<PrizmaListScreenProps, 'status' | 'title' | 'subtitle' | 'glyph' | 'children' | 'listAlign' | 'scrollList' | 'disclaimer' | 'ctaLabel' | 'secondaryCtaLabel' | 'linkLabel' | 'secondaryLinkLabel' | 'overlay' | 'verifiedLabel' | 'navLabel'> {
12
+ /** Module copy — this screen reads the `selection` and `sharedDetails` slices. */
13
+ strings: ReusabilityStrings;
14
+ /**
15
+ * The documents the network found for this person, best match FIRST — the
16
+ * backend orders them and the first row wears the "Recommended" pill (SDK
17
+ * `recommended={index === 0}`). One or more; the frame draws two
18
+ * (`Multiple documents`) and one (`Single document`).
19
+ */
20
+ credentials: ReusableCredential[];
21
+ /**
22
+ * "What data will be shared?" was pressed: Core's bottom sheet listing the
23
+ * recipient's data request is presented over the dimmed selection
24
+ * (`shared info`, 7877:68927). Its one button emits `cta` and closes it.
25
+ */
26
+ sharedDetails?: boolean;
27
+ /**
28
+ * Fired with the chosen credential's id, or `REUSABILITY_SCAN_NEW` for the
29
+ * capture row; `onAction` still reports the tap as `cta`. Named like ID
30
+ * Capture's `onDocumentSelect` — `onSelect` is a native <div> event the shell
31
+ * already passes through.
32
+ */
33
+ onCredentialSelect?: (selection: ReusabilitySelection) => void;
34
+ screenId?: string;
35
+ overrides?: PrizmaScreenOverrides;
36
+ onAction?: PrizmaScreenActionHandler;
37
+ }
38
+ /**
39
+ * Reusability (Incode Bridge) — choose the document to reuse, built on the
40
+ * List archetype (GUIDELINES.md §6-G, `PrizmaListScreen`).
41
+ *
42
+ * ONE screen for three of the section's four frames: `Multiple documents`
43
+ * (7877:68816) and `Single document` (7877:68875) are the same skeleton — nav →
44
+ * Title (H2 + H5) → the credential list → "Scan a new document" → two tertiary
45
+ * links → tag — differing only in how many rows the network returned; and
46
+ * `Shared data` (7877:68927) is that screen with Core's bottom sheet presented
47
+ * over it (`sharedDetails`).
48
+ *
49
+ * WHY ARCHETYPE G. The rows ARE the actions — tapping a document advances the
50
+ * session with no confirm step (consent review 2026-09-16: "remove the confirm
51
+ * button: selecting a document advances the user immediately"; the Web SDK's
52
+ * ENG-57939 built exactly that) — so there is no primary CTA, and G is the one
53
+ * archetype whose band may carry links alone. ID Capture's document chooser is
54
+ * the same shape on the same archetype.
55
+ *
56
+ * Six things are deliberate:
57
+ *
58
+ * 1. The rows are composed here from Core's tokens, not from Core's
59
+ * `PrizmaCardListVerificationOptions`. The frame calls them "Verification
60
+ * options card list", but a reusable credential has a different anatomy —
61
+ * type label + status pill, flag + masked number, verified date — and the
62
+ * capture row is one line with a pill. Core ships neither that row nor a
63
+ * plain status pill; both are proposed (DEVIATIONS #RU-1, #RU-2) and the
64
+ * rules live once in `ReusabilityLayout.css`.
65
+ * 2. Every row is a real `<button>` that emits `cta` and names its credential
66
+ * through `onCredentialSelect` — the one-click rule. No radio, no selected
67
+ * state: the frame draws none and the decision was to drop them. The SDK's
68
+ * shipped `role="radio"` + confirm is the generation BEFORE this frame.
69
+ * 3. The first row wears "Recommended", because the backend sorts best match
70
+ * first; the capture row wears "Slowest". The pills are the frame's own
71
+ * fills on Core tokens; their 12px type is the one value Core's scale
72
+ * cannot express (#RU-2).
73
+ * 4. The flag is Core's raster bank (`PrizmaCountryFlag`, 24×18), never the
74
+ * frame's emoji glyph (owner decision 2026-07-12). A country outside the
75
+ * bank falls back to the emoji the host supplies — Core's own fallback rule
76
+ * (#RU-3).
77
+ * 5. The two links ride the archetype's band: "What data will be shared?" in
78
+ * `linkLabel` (emits `secondary`) and "Incode’s Privacy Policy" in the new
79
+ * `secondaryLinkLabel` slot (emits `tertiary`) — two non-primary actions a
80
+ * host must tell apart (#PI-10), so each has its own action. The band's
81
+ * flat Spacing/16 stands between them where the frame's Button group
82
+ * tightens the pair by 8 (#RU-4).
83
+ * 6. The sheet rides the archetype's new `overlay` slot — the same contract E
84
+ * gained for Biometric Consent (#BC-8): the screen owns the scrim and the
85
+ * anchoring (the foundation's `__sheet-scrim` / `__sheet-panel`), Core owns
86
+ * the panel — `PrizmaBottomSheetContent variant="dialog"` with its H1
87
+ * title, H5 subtitle, the bullet list in `body`, and its own Button Group
88
+ * reduced to "Understood". With the sheet up the rows and links are under
89
+ * the scrim and do not report (#RU-5).
90
+ *
91
+ * The nav keeps the logo and draws no close: the frame's top-right ✕ is the
92
+ * SDK page chrome, not a Prizma screen control (GUIDELINES §3; #RU-6).
93
+ */
94
+ export declare const ReusabilityCredentialSelectionScreen: React.ForwardRefExoticComponent<ReusabilityCredentialSelectionScreenProps & React.RefAttributes<HTMLDivElement>>;
95
+ export default ReusabilityCredentialSelectionScreen;
@@ -0,0 +1,94 @@
1
+ 'use client';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { forwardRef } from 'react';
4
+ import { PrizmaBottomSheetContent } from '@incodetech/prizma-core-web/bottom-sheet';
5
+ import { PrizmaCountryFlag } from '@incodetech/prizma-core-web/combined';
6
+ import { PrizmaListScreen } from './ListScreen';
7
+ import './ScreenLayout.css';
8
+ import './ReusabilityLayout.css';
9
+ /** The sentinel the SDK submits for the capture row (`SCAN_NEW_DOCUMENT`,
10
+ * `identityReuseStateMachine.ts`): `{ accepted: false }`, then ID Capture. */
11
+ export const REUSABILITY_SCAN_NEW = 'scanNew';
12
+ /**
13
+ * Reusability (Incode Bridge) — choose the document to reuse, built on the
14
+ * List archetype (GUIDELINES.md §6-G, `PrizmaListScreen`).
15
+ *
16
+ * ONE screen for three of the section's four frames: `Multiple documents`
17
+ * (7877:68816) and `Single document` (7877:68875) are the same skeleton — nav →
18
+ * Title (H2 + H5) → the credential list → "Scan a new document" → two tertiary
19
+ * links → tag — differing only in how many rows the network returned; and
20
+ * `Shared data` (7877:68927) is that screen with Core's bottom sheet presented
21
+ * over it (`sharedDetails`).
22
+ *
23
+ * WHY ARCHETYPE G. The rows ARE the actions — tapping a document advances the
24
+ * session with no confirm step (consent review 2026-09-16: "remove the confirm
25
+ * button: selecting a document advances the user immediately"; the Web SDK's
26
+ * ENG-57939 built exactly that) — so there is no primary CTA, and G is the one
27
+ * archetype whose band may carry links alone. ID Capture's document chooser is
28
+ * the same shape on the same archetype.
29
+ *
30
+ * Six things are deliberate:
31
+ *
32
+ * 1. The rows are composed here from Core's tokens, not from Core's
33
+ * `PrizmaCardListVerificationOptions`. The frame calls them "Verification
34
+ * options card list", but a reusable credential has a different anatomy —
35
+ * type label + status pill, flag + masked number, verified date — and the
36
+ * capture row is one line with a pill. Core ships neither that row nor a
37
+ * plain status pill; both are proposed (DEVIATIONS #RU-1, #RU-2) and the
38
+ * rules live once in `ReusabilityLayout.css`.
39
+ * 2. Every row is a real `<button>` that emits `cta` and names its credential
40
+ * through `onCredentialSelect` — the one-click rule. No radio, no selected
41
+ * state: the frame draws none and the decision was to drop them. The SDK's
42
+ * shipped `role="radio"` + confirm is the generation BEFORE this frame.
43
+ * 3. The first row wears "Recommended", because the backend sorts best match
44
+ * first; the capture row wears "Slowest". The pills are the frame's own
45
+ * fills on Core tokens; their 12px type is the one value Core's scale
46
+ * cannot express (#RU-2).
47
+ * 4. The flag is Core's raster bank (`PrizmaCountryFlag`, 24×18), never the
48
+ * frame's emoji glyph (owner decision 2026-07-12). A country outside the
49
+ * bank falls back to the emoji the host supplies — Core's own fallback rule
50
+ * (#RU-3).
51
+ * 5. The two links ride the archetype's band: "What data will be shared?" in
52
+ * `linkLabel` (emits `secondary`) and "Incode’s Privacy Policy" in the new
53
+ * `secondaryLinkLabel` slot (emits `tertiary`) — two non-primary actions a
54
+ * host must tell apart (#PI-10), so each has its own action. The band's
55
+ * flat Spacing/16 stands between them where the frame's Button group
56
+ * tightens the pair by 8 (#RU-4).
57
+ * 6. The sheet rides the archetype's new `overlay` slot — the same contract E
58
+ * gained for Biometric Consent (#BC-8): the screen owns the scrim and the
59
+ * anchoring (the foundation's `__sheet-scrim` / `__sheet-panel`), Core owns
60
+ * the panel — `PrizmaBottomSheetContent variant="dialog"` with its H1
61
+ * title, H5 subtitle, the bullet list in `body`, and its own Button Group
62
+ * reduced to "Understood". With the sheet up the rows and links are under
63
+ * the scrim and do not report (#RU-5).
64
+ *
65
+ * The nav keeps the logo and draws no close: the frame's top-right ✕ is the
66
+ * SDK page chrome, not a Prizma screen control (GUIDELINES §3; #RU-6).
67
+ */
68
+ export const ReusabilityCredentialSelectionScreen = forwardRef(({ strings, credentials, sharedDetails = false, onCredentialSelect, screenId = sharedDetails
69
+ ? 'reusability-shared-details'
70
+ : `reusability-selection-${credentials.length > 1 ? 'multiple' : 'single'}`, overrides, onAction, ...shell }, ref) => {
71
+ const { selection, sharedDetails: shared } = strings;
72
+ const choose = (choice) => {
73
+ if (sharedDetails)
74
+ return;
75
+ onCredentialSelect?.(choice);
76
+ onAction?.({ type: 'cta', screenId });
77
+ };
78
+ const sheet = sharedDetails ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "prizma-screen-layout__sheet-scrim", "aria-hidden": "true" }), _jsx("div", { className: "prizma-screen-layout__sheet-panel", children: _jsx(PrizmaBottomSheetContent, { variant: "dialog", title: shared.title, subtitle: shared.subtitle, body: _jsx("ul", { className: "reusability-shared-list", children: shared.items.map((item) => (_jsx("li", { children: item }, item))) }), buttonGroupProps: {
79
+ primaryLabel: shared.ctaLabel,
80
+ showSecondary: false,
81
+ onPrimaryClick: () => onAction?.({ type: 'cta', screenId }),
82
+ } }) })] })) : undefined;
83
+ return (_jsx(PrizmaListScreen, { ref: ref, title: selection.title, subtitle: selection.subtitle, linkLabel: selection.sharedDataLink, secondaryLinkLabel: selection.privacyPolicyLink, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides,
84
+ /* With the sheet up, the links are under the scrim and must not
85
+ report: the sheet's "Understood" is the only action. */
86
+ onAction: sharedDetails ? undefined : onAction, overlay: sheet, ...shell, children: _jsxs("div", { className: "reusability-credentials", role: "group", "aria-label": selection.listLabel, children: [_jsx("div", { className: "reusability-credentials__group", children: credentials.map((credential, index) => (_jsxs("button", { type: "button", className: "reusability-credential", onClick: () => choose(credential.id), tabIndex: sharedDetails ? -1 : undefined, children: [_jsxs("span", { className: "reusability-credential__head", children: [_jsx("span", { className: "reusability-credential__type", children: selection.documentType[credential.documentType] }), index === 0 ? (_jsx("span", { className: "reusability-pill reusability-pill--recommended", children: selection.recommendedTag })) : null] }), _jsxs("span", { className: "reusability-credential__number", children: [_jsx("span", { className: "reusability-credential__flag", "aria-hidden": "true", children: _jsx(PrizmaCountryFlag, { country: {
87
+ code: credential.countryCode,
88
+ name: credential.countryCode,
89
+ dialCode: '',
90
+ flag: credential.countryFlag ?? '',
91
+ } }) }), _jsx("span", { children: credential.maskedNumber })] }), _jsxs("span", { className: "reusability-credential__verified", children: [_jsx("span", { children: selection.verifiedPrefix }), " ", _jsx("span", { children: credential.verifiedOn })] })] }, credential.id))) }), _jsx("div", { className: "reusability-credentials__group", children: _jsx("button", { type: "button", className: "reusability-credential", onClick: () => choose(REUSABILITY_SCAN_NEW), tabIndex: sharedDetails ? -1 : undefined, children: _jsxs("span", { className: "reusability-credential__head", children: [_jsx("span", { className: "reusability-credential__type", children: selection.scanNewLabel }), _jsx("span", { className: "reusability-pill reusability-pill--neutral", children: selection.slowestTag })] }) }) })] }) }));
92
+ });
93
+ ReusabilityCredentialSelectionScreen.displayName = 'ReusabilityCredentialSelectionScreen';
94
+ export default ReusabilityCredentialSelectionScreen;