@incodetech/prizma-core-screens 0.2.7 → 0.2.14
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.
- package/dist/BiometricConsentScreen.d.ts +95 -0
- package/dist/BiometricConsentScreen.js +91 -0
- package/dist/BiometricConsentStrings.d.ts +84 -0
- package/dist/BiometricConsentStrings.js +31 -0
- package/dist/CaptureScreen.d.ts +13 -0
- package/dist/CaptureScreen.js +2 -2
- package/dist/DemoScreensLayout.css +16 -0
- package/dist/DemoScreensRedirectScreen.d.ts +6 -1
- package/dist/DemoScreensRedirectScreen.js +3 -2
- package/dist/DemoScreensStrings.d.ts +5 -0
- package/dist/DigitalIdDeviceWalletsDocumentSelectionScreen.d.ts +34 -0
- package/dist/DigitalIdDeviceWalletsDocumentSelectionScreen.js +47 -0
- package/dist/DigitalIdDeviceWalletsResultScreen.d.ts +28 -0
- package/dist/DigitalIdDeviceWalletsResultScreen.js +23 -0
- package/dist/DigitalIdDeviceWalletsStrings.d.ts +55 -0
- package/dist/DigitalIdDeviceWalletsStrings.js +19 -0
- package/dist/DigitalIdProvidersDocumentSelectionScreen.d.ts +31 -0
- package/dist/DigitalIdProvidersDocumentSelectionScreen.js +37 -0
- package/dist/DigitalIdProvidersErrorScreen.d.ts +33 -0
- package/dist/DigitalIdProvidersErrorScreen.js +33 -0
- package/dist/DigitalIdProvidersLayout.css +59 -0
- package/dist/DigitalIdProvidersRedirectScreen.d.ts +24 -0
- package/dist/DigitalIdProvidersRedirectScreen.js +18 -0
- package/dist/DigitalIdProvidersStrings.d.ts +72 -0
- package/dist/DigitalIdProvidersStrings.js +15 -0
- package/dist/DigitalIdUploadErrorScreen.d.ts +31 -0
- package/dist/DigitalIdUploadErrorScreen.js +26 -0
- package/dist/DigitalIdUploadFileTooLargeScreen.d.ts +27 -0
- package/dist/DigitalIdUploadFileTooLargeScreen.js +21 -0
- package/dist/DigitalIdUploadReviewScreen.d.ts +57 -0
- package/dist/DigitalIdUploadReviewScreen.js +44 -0
- package/dist/DigitalIdUploadStrings.d.ts +64 -0
- package/dist/DigitalIdUploadStrings.js +19 -0
- package/dist/DigitalIdUploadTutorialScreen.d.ts +28 -0
- package/dist/DigitalIdUploadTutorialScreen.js +23 -0
- package/dist/DocumentCaptureIllustration.d.ts +1 -1
- package/dist/EkybCountryScreen.d.ts +6 -6
- package/dist/EkybCountryScreen.js +20 -7
- package/dist/EkybStrings.d.ts +6 -1
- package/dist/ErrorScreensScreen.d.ts +5 -2
- package/dist/ErrorScreensScreen.js +15 -4
- package/dist/ErrorScreensStrings.d.ts +17 -2
- package/dist/ErrorScreensStrings.js +18 -10
- package/dist/FaceCaptureCapturingScreen.d.ts +63 -0
- package/dist/FaceCaptureCapturingScreen.js +62 -2
- package/dist/FaceCaptureLayout.css +69 -4
- package/dist/FaceCaptureStrings.d.ts +23 -0
- package/dist/FormScreen.css +14 -0
- package/dist/FormScreen.d.ts +28 -0
- package/dist/FormScreen.js +3 -2
- package/dist/IdCaptureLayout.css +165 -2
- package/dist/IdCaptureStageScreen.d.ts +47 -0
- package/dist/IdCaptureStageScreen.js +39 -3
- package/dist/IdCaptureStrings.d.ts +19 -0
- package/dist/ListScreen.d.ts +19 -0
- package/dist/ListScreen.js +7 -2
- package/dist/LoaderScreen.d.ts +7 -5
- package/dist/LoaderScreen.js +7 -5
- package/dist/LoadersStrings.d.ts +18 -5
- package/dist/OcrReviewErrorScreen.d.ts +30 -0
- package/dist/OcrReviewErrorScreen.js +24 -0
- package/dist/OcrReviewLayout.css +24 -0
- package/dist/OcrReviewLoadingScreen.d.ts +25 -0
- package/dist/OcrReviewLoadingScreen.js +19 -0
- package/dist/OcrReviewScreen.d.ts +76 -0
- package/dist/OcrReviewScreen.js +65 -0
- package/dist/OcrReviewStrings.d.ts +47 -0
- package/dist/OcrReviewStrings.js +17 -0
- package/dist/OcrReviewSuccessScreen.d.ts +30 -0
- package/dist/OcrReviewSuccessScreen.js +24 -0
- package/dist/PermissionsAllowScreen.d.ts +8 -11
- package/dist/PermissionsAllowScreen.js +8 -11
- package/dist/PermissionsAskScreen.d.ts +41 -0
- package/dist/PermissionsAskScreen.js +43 -0
- package/dist/PermissionsBrowserStepsScreen.d.ts +9 -2
- package/dist/PermissionsBrowserStepsScreen.js +12 -3
- package/dist/PermissionsLayout.css +47 -0
- package/dist/PermissionsStrings.d.ts +20 -9
- package/dist/PermissionsStrings.js +10 -4
- package/dist/PhoneInputOtpScreen.d.ts +8 -0
- package/dist/PhoneInputOtpScreen.js +26 -19
- package/dist/PhoneInputStrings.d.ts +11 -3
- package/dist/PhoneInputVerifyScreen.js +21 -5
- package/dist/QualifiedSignatureDocumentScreen.d.ts +8 -5
- package/dist/QualifiedSignatureDocumentScreen.js +9 -6
- package/dist/QualifiedSignatureResultScreen.d.ts +16 -13
- package/dist/QualifiedSignatureResultScreen.js +17 -18
- package/dist/QualifiedSignatureStrings.d.ts +11 -4
- package/dist/ResultScreen.d.ts +8 -0
- package/dist/ResultScreen.js +14 -3
- package/dist/ReusabilityCredentialSelectionScreen.d.ts +95 -0
- package/dist/ReusabilityCredentialSelectionScreen.js +94 -0
- package/dist/ReusabilityLayout.css +241 -0
- package/dist/ReusabilityPrivacyPolicyScreen.d.ts +55 -0
- package/dist/ReusabilityPrivacyPolicyScreen.js +44 -0
- package/dist/ReusabilityStrings.d.ts +85 -0
- package/dist/ReusabilityStrings.js +37 -0
- package/dist/ReviewScreen.d.ts +38 -12
- package/dist/ReviewScreen.js +41 -8
- package/dist/ScreenLayout.css +382 -6
- package/dist/VideoSelfieErrorScreen.js +1 -1
- package/dist/VideoSelfieIdCaptureScreen.js +1 -1
- package/dist/VideoSelfieLayout.css +304 -2
- package/dist/VideoSelfieSelfieCaptureScreen.js +1 -1
- package/dist/VideoSelfieSpeakScreen.js +1 -1
- package/dist/VideoSelfieStrings.d.ts +4 -1
- package/dist/VideoSelfieTurnHeadScreen.js +14 -11
- package/dist/VideoSelfieTutorialScreen.d.ts +9 -0
- package/dist/VideoSelfieTutorialScreen.js +10 -1
- package/dist/VideoSelfieWaveScreen.js +1 -1
- package/dist/ViewfinderScreen.css +36 -0
- package/dist/flows.d.ts +8 -0
- package/dist/flows.js +17 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +17 -0
- package/dist/styles.css +4 -0
- package/package.json +94 -3
- package/samples/video-selfie-camera-wide.jpg +0 -0
- package/samples/video-selfie-room-wide.jpg +0 -0
- package/src/BiometricConsentScreen.tsx +192 -0
- package/src/BiometricConsentStrings.ts +119 -0
- package/src/CaptureScreen.tsx +17 -0
- package/src/DemoScreensLayout.css +16 -0
- package/src/DemoScreensRedirectScreen.tsx +14 -6
- package/src/DemoScreensStrings.ts +5 -0
- package/src/DigitalIdDeviceWalletsDocumentSelectionScreen.tsx +108 -0
- package/src/DigitalIdDeviceWalletsResultScreen.tsx +76 -0
- package/src/DigitalIdDeviceWalletsStrings.ts +80 -0
- package/src/DigitalIdProvidersDocumentSelectionScreen.tsx +112 -0
- package/src/DigitalIdProvidersErrorScreen.tsx +104 -0
- package/src/DigitalIdProvidersLayout.css +59 -0
- package/src/DigitalIdProvidersRedirectScreen.tsx +65 -0
- package/src/DigitalIdProvidersStrings.ts +98 -0
- package/src/DigitalIdUploadErrorScreen.tsx +83 -0
- package/src/DigitalIdUploadFileTooLargeScreen.tsx +67 -0
- package/src/DigitalIdUploadReviewScreen.tsx +119 -0
- package/src/DigitalIdUploadStrings.ts +88 -0
- package/src/DigitalIdUploadTutorialScreen.tsx +59 -0
- package/src/DocumentCaptureIllustration.tsx +1 -1
- package/src/EkybCountryScreen.tsx +23 -6
- package/src/EkybStrings.ts +6 -1
- package/src/ErrorScreensScreen.tsx +15 -4
- package/src/ErrorScreensStrings.ts +37 -12
- package/src/FaceCaptureCapturingScreen.tsx +102 -13
- package/src/FaceCaptureLayout.css +69 -4
- package/src/FaceCaptureStrings.ts +24 -0
- package/src/FormScreen.css +14 -0
- package/src/FormScreen.tsx +34 -0
- package/src/IdCaptureLayout.css +165 -2
- package/src/IdCaptureStageScreen.tsx +75 -0
- package/src/IdCaptureStrings.ts +19 -0
- package/src/ListScreen.tsx +48 -9
- package/src/LoaderScreen.tsx +7 -5
- package/src/LoadersStrings.ts +18 -5
- package/src/OcrReviewErrorScreen.tsx +53 -0
- package/src/OcrReviewLayout.css +24 -0
- package/src/OcrReviewLoadingScreen.tsx +48 -0
- package/src/OcrReviewScreen.tsx +190 -0
- package/src/OcrReviewStrings.ts +69 -0
- package/src/OcrReviewSuccessScreen.tsx +52 -0
- package/src/PermissionsAllowScreen.tsx +9 -10
- package/src/PermissionsAskScreen.tsx +105 -0
- package/src/PermissionsBrowserStepsScreen.tsx +11 -3
- package/src/PermissionsLayout.css +47 -0
- package/src/PermissionsStrings.ts +42 -12
- package/src/PhoneInputOtpScreen.tsx +23 -3
- package/src/PhoneInputStrings.ts +11 -3
- package/src/PhoneInputVerifyScreen.tsx +24 -4
- package/src/QualifiedSignatureDocumentScreen.tsx +9 -7
- package/src/QualifiedSignatureResultScreen.tsx +28 -26
- package/src/QualifiedSignatureStrings.ts +11 -4
- package/src/ResultScreen.tsx +33 -2
- package/src/ReusabilityCredentialSelectionScreen.tsx +246 -0
- package/src/ReusabilityLayout.css +241 -0
- package/src/ReusabilityPrivacyPolicyScreen.tsx +109 -0
- package/src/ReusabilityStrings.ts +127 -0
- package/src/ReviewScreen.tsx +96 -27
- package/src/ScreenLayout.css +382 -6
- package/src/VideoSelfieErrorScreen.tsx +1 -1
- package/src/VideoSelfieIdCaptureScreen.tsx +9 -1
- package/src/VideoSelfieLayout.css +304 -2
- package/src/VideoSelfieSelfieCaptureScreen.tsx +9 -1
- package/src/VideoSelfieSpeakScreen.tsx +9 -1
- package/src/VideoSelfieStrings.ts +4 -2
- package/src/VideoSelfieTurnHeadScreen.tsx +25 -14
- package/src/VideoSelfieTutorialScreen.tsx +11 -0
- package/src/VideoSelfieWaveScreen.tsx +9 -1
- package/src/ViewfinderScreen.css +36 -0
- package/src/flows.ts +25 -0
- package/src/index.ts +116 -3
- package/src/styles.css +4 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type PrizmaFormScreenProps } from './FormScreen';
|
|
3
|
+
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
4
|
+
import type { BiometricConsentState, BiometricConsentStrings } from './BiometricConsentStrings';
|
|
5
|
+
import './ScreenLayout.css';
|
|
6
|
+
export interface BiometricConsentScreenProps extends Omit<PrizmaFormScreenProps, 'title' | 'subtitle' | 'ctaLabel' | 'ctaDisabled' | 'verifiedLabel' | 'children' | 'navLabel' | 'linkLabel' | 'linkDisabled' | 'linkContent' | 'overlay' | 'fieldsOffset' | 'fieldsGap' | 'fieldsAlign' | 'scrollFields'> {
|
|
7
|
+
/** Module copy — this screen reads the `consent` and `quit` slices. */
|
|
8
|
+
strings: BiometricConsentStrings;
|
|
9
|
+
/** Which of the two section states to render. Default `default`. */
|
|
10
|
+
state?: BiometricConsentState;
|
|
11
|
+
/**
|
|
12
|
+
* Cancel was pressed: present the quit confirmation over the consent. The
|
|
13
|
+
* consent underneath keeps its `state` — the box is whatever the person had.
|
|
14
|
+
* Its two answers: the confirm emits `cta` (the session ends), the dismiss
|
|
15
|
+
* emits `secondary` (back to the consent). DEVIATIONS #BC-7.
|
|
16
|
+
*/
|
|
17
|
+
quitConfirm?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* The box was ticked or unticked. A REAL change event from Core's own
|
|
20
|
+
* `<input type="checkbox">` — the card is a `<label>`, so tapping the copy
|
|
21
|
+
* toggles it too, which is the behaviour the request named ("tapping the body
|
|
22
|
+
* also toggles the checkbox"). The screen stays controlled by `state`; this
|
|
23
|
+
* only reports the press so a host (or the Core Lab prototype) can move the
|
|
24
|
+
* state itself. The sibling consent screen forwards no such handler and its
|
|
25
|
+
* prototype had to listen on a wrapper instead — this closes that gap for this
|
|
26
|
+
* module.
|
|
27
|
+
*/
|
|
28
|
+
onConsentChange?: (checked: boolean) => void;
|
|
29
|
+
screenId?: string;
|
|
30
|
+
overrides?: PrizmaScreenOverrides;
|
|
31
|
+
onAction?: PrizmaScreenActionHandler;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Biometric Consent — the mandatory biometric-processing consent, built on the
|
|
35
|
+
* Form archetype (GUIDELINES.md §6-E, `PrizmaFormScreen`).
|
|
36
|
+
*
|
|
37
|
+
* ONE screen for the whole `biometricConsent` section (2001:16315): the two
|
|
38
|
+
* state frames (`empty` 2001:16361, `checked` 2001:16372) share an identical
|
|
39
|
+
* skeleton — nav → Title (H2 + H5) → one consent card → Continue → Cancel →
|
|
40
|
+
* tag — and differ ONLY in whether the box is ticked and the CTA released.
|
|
41
|
+
* Plus the quit confirmation (`quitConfirm`), a Core sheet or dialog presented
|
|
42
|
+
* over either state when Cancel is pressed.
|
|
43
|
+
*
|
|
44
|
+
* WHY ARCHETYPE E. The same reason the sibling consent screen gives: a
|
|
45
|
+
* `PrizmaCheckbox` is a real `<input type="checkbox">` that joins the form, and
|
|
46
|
+
* the gated CTA is the whole point of a consent screen — `PrizmaListScreen` has
|
|
47
|
+
* no `ctaDisabled` slot. E also carries the one tertiary action under the
|
|
48
|
+
* primary (`linkLabel`), which is exactly where the frame draws Cancel.
|
|
49
|
+
*
|
|
50
|
+
* THE CARD SITS AT THE BOTTOM OF THE COLUMN, NOT UNDER THE TITLE. The frame's
|
|
51
|
+
* middle (2001:15150) is a `justify-between` column: the Title block at the top,
|
|
52
|
+
* the consent card flush against the CTA band with the frame's Spacing/16
|
|
53
|
+
* between them, and everything in between left empty. That is the opposite of
|
|
54
|
+
* every other Form consumer, whose stack hangs off the title, so the screen
|
|
55
|
+
* SELECTS it through the archetype's `fieldsAlign="end"` slot rather than
|
|
56
|
+
* declaring a layout of its own — the value lives once, in `FormScreen.css`.
|
|
57
|
+
* DEVIATIONS #BC-1.
|
|
58
|
+
*
|
|
59
|
+
* Five things are deliberate:
|
|
60
|
+
*
|
|
61
|
+
* 1. The consent card is Core's `PrizmaCheckbox size="L"` — the component IS
|
|
62
|
+
* the tinted container Figma draws (padding, radius, `Surface/Brand/50`,
|
|
63
|
+
* the 28×28 box, the Size-S body). Its `segments` carry the inline
|
|
64
|
+
* "Incode's Privacy Policy" link, which opens the document without toggling
|
|
65
|
+
* the box. Nothing about the card is composed here.
|
|
66
|
+
* 2. The box is CONTROLLED by `state`, like every other spec state in this
|
|
67
|
+
* package, and the real change event is forwarded through `onConsentChange`
|
|
68
|
+
* so a host can drive it. `disabled` is NOT used — the frame draws the card
|
|
69
|
+
* on the live surface in both states (#PI-6: never borrow a semantic state
|
|
70
|
+
* to make something inert).
|
|
71
|
+
* 3. The CTA is gated by `ctaDisabled`, Core's own
|
|
72
|
+
* `button/primary/surface|text/disabled` treatment, until the box is ticked
|
|
73
|
+
* — the behaviour the requesting engineer asked for and the two sibling
|
|
74
|
+
* consents already ship. The frame paints Continue blue in both states;
|
|
75
|
+
* recorded, not resolved silently (DEVIATIONS #BC-2).
|
|
76
|
+
* 4. Cancel is the archetype's `tertiary-link` button and emits `secondary`.
|
|
77
|
+
* The frame draws it as the Button group's "Tertiary CTA" slot in body-800
|
|
78
|
+
* ink with no underline on the ES/PT copies and in brand blue on the EN one
|
|
79
|
+
* — Core ships one L tertiary (underlined, `button/tertiary/text/default`)
|
|
80
|
+
* and the component wins (DEVIATIONS #BC-4).
|
|
81
|
+
* 5. The quit confirmation rides archetype E's `overlay` slot: the screen owns
|
|
82
|
+
* the scrim and the placement (the foundation's `__sheet-scrim` /
|
|
83
|
+
* `__modal-panel` recipes), Core owns the card — `PrizmaModalContent`,
|
|
84
|
+
* the `default` variant exactly as the design system documents it: close
|
|
85
|
+
* icon, title, optional subtitle, and its own `vertical-v1` Button Group
|
|
86
|
+
* (Quit over Cancel). Placed the way Core's presenter places a modal —
|
|
87
|
+
* pinned to the bottom of the frame with a Spacing/12 margin, never
|
|
88
|
+
* centred — on EVERY platform. The owner ruled out a bottom sheet on the
|
|
89
|
+
* phone, then a centred card (Camila, 2026-10-13): "use the default modal
|
|
90
|
+
* … so we try with an existing component". The close icon dismisses, the
|
|
91
|
+
* same as Cancel. Nothing is drawn behind it that the consent did not
|
|
92
|
+
* already draw. DEVIATIONS #BC-7, #BC-8.
|
|
93
|
+
*/
|
|
94
|
+
export declare const BiometricConsentScreen: React.ForwardRefExoticComponent<BiometricConsentScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
95
|
+
export default BiometricConsentScreen;
|
|
@@ -0,0 +1,91 @@
|
|
|
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 { PrizmaCheckbox } from '@incodetech/prizma-core-web/checkbox';
|
|
5
|
+
import { PrizmaModalContent } from '@incodetech/prizma-core-web/modal';
|
|
6
|
+
import { PrizmaFormScreen } from './FormScreen';
|
|
7
|
+
import './ScreenLayout.css';
|
|
8
|
+
/**
|
|
9
|
+
* Biometric Consent — the mandatory biometric-processing consent, built on the
|
|
10
|
+
* Form archetype (GUIDELINES.md §6-E, `PrizmaFormScreen`).
|
|
11
|
+
*
|
|
12
|
+
* ONE screen for the whole `biometricConsent` section (2001:16315): the two
|
|
13
|
+
* state frames (`empty` 2001:16361, `checked` 2001:16372) share an identical
|
|
14
|
+
* skeleton — nav → Title (H2 + H5) → one consent card → Continue → Cancel →
|
|
15
|
+
* tag — and differ ONLY in whether the box is ticked and the CTA released.
|
|
16
|
+
* Plus the quit confirmation (`quitConfirm`), a Core sheet or dialog presented
|
|
17
|
+
* over either state when Cancel is pressed.
|
|
18
|
+
*
|
|
19
|
+
* WHY ARCHETYPE E. The same reason the sibling consent screen gives: a
|
|
20
|
+
* `PrizmaCheckbox` is a real `<input type="checkbox">` that joins the form, and
|
|
21
|
+
* the gated CTA is the whole point of a consent screen — `PrizmaListScreen` has
|
|
22
|
+
* no `ctaDisabled` slot. E also carries the one tertiary action under the
|
|
23
|
+
* primary (`linkLabel`), which is exactly where the frame draws Cancel.
|
|
24
|
+
*
|
|
25
|
+
* THE CARD SITS AT THE BOTTOM OF THE COLUMN, NOT UNDER THE TITLE. The frame's
|
|
26
|
+
* middle (2001:15150) is a `justify-between` column: the Title block at the top,
|
|
27
|
+
* the consent card flush against the CTA band with the frame's Spacing/16
|
|
28
|
+
* between them, and everything in between left empty. That is the opposite of
|
|
29
|
+
* every other Form consumer, whose stack hangs off the title, so the screen
|
|
30
|
+
* SELECTS it through the archetype's `fieldsAlign="end"` slot rather than
|
|
31
|
+
* declaring a layout of its own — the value lives once, in `FormScreen.css`.
|
|
32
|
+
* DEVIATIONS #BC-1.
|
|
33
|
+
*
|
|
34
|
+
* Five things are deliberate:
|
|
35
|
+
*
|
|
36
|
+
* 1. The consent card is Core's `PrizmaCheckbox size="L"` — the component IS
|
|
37
|
+
* the tinted container Figma draws (padding, radius, `Surface/Brand/50`,
|
|
38
|
+
* the 28×28 box, the Size-S body). Its `segments` carry the inline
|
|
39
|
+
* "Incode's Privacy Policy" link, which opens the document without toggling
|
|
40
|
+
* the box. Nothing about the card is composed here.
|
|
41
|
+
* 2. The box is CONTROLLED by `state`, like every other spec state in this
|
|
42
|
+
* package, and the real change event is forwarded through `onConsentChange`
|
|
43
|
+
* so a host can drive it. `disabled` is NOT used — the frame draws the card
|
|
44
|
+
* on the live surface in both states (#PI-6: never borrow a semantic state
|
|
45
|
+
* to make something inert).
|
|
46
|
+
* 3. The CTA is gated by `ctaDisabled`, Core's own
|
|
47
|
+
* `button/primary/surface|text/disabled` treatment, until the box is ticked
|
|
48
|
+
* — the behaviour the requesting engineer asked for and the two sibling
|
|
49
|
+
* consents already ship. The frame paints Continue blue in both states;
|
|
50
|
+
* recorded, not resolved silently (DEVIATIONS #BC-2).
|
|
51
|
+
* 4. Cancel is the archetype's `tertiary-link` button and emits `secondary`.
|
|
52
|
+
* The frame draws it as the Button group's "Tertiary CTA" slot in body-800
|
|
53
|
+
* ink with no underline on the ES/PT copies and in brand blue on the EN one
|
|
54
|
+
* — Core ships one L tertiary (underlined, `button/tertiary/text/default`)
|
|
55
|
+
* and the component wins (DEVIATIONS #BC-4).
|
|
56
|
+
* 5. The quit confirmation rides archetype E's `overlay` slot: the screen owns
|
|
57
|
+
* the scrim and the placement (the foundation's `__sheet-scrim` /
|
|
58
|
+
* `__modal-panel` recipes), Core owns the card — `PrizmaModalContent`,
|
|
59
|
+
* the `default` variant exactly as the design system documents it: close
|
|
60
|
+
* icon, title, optional subtitle, and its own `vertical-v1` Button Group
|
|
61
|
+
* (Quit over Cancel). Placed the way Core's presenter places a modal —
|
|
62
|
+
* pinned to the bottom of the frame with a Spacing/12 margin, never
|
|
63
|
+
* centred — on EVERY platform. The owner ruled out a bottom sheet on the
|
|
64
|
+
* phone, then a centred card (Camila, 2026-10-13): "use the default modal
|
|
65
|
+
* … so we try with an existing component". The close icon dismisses, the
|
|
66
|
+
* same as Cancel. Nothing is drawn behind it that the consent did not
|
|
67
|
+
* already draw. DEVIATIONS #BC-7, #BC-8.
|
|
68
|
+
*/
|
|
69
|
+
export const BiometricConsentScreen = forwardRef(({ strings, state = 'default', quitConfirm = false, onConsentChange, screenId = quitConfirm ? 'biometric-consent-quit' : `biometric-consent-${state}`, overrides, onAction, ...shell }, ref) => {
|
|
70
|
+
const accepted = state === 'accepted';
|
|
71
|
+
const quit = quitConfirm ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "prizma-screen-layout__sheet-scrim", "aria-hidden": "true" }), _jsx("div", { className: "prizma-screen-layout__modal-panel", children: _jsx(PrizmaModalContent, { variant: "default", title: strings.quit.title, subtitle: strings.quit.subtitle, closeLabel: strings.quit.closeLabel, onClose: () => onAction?.({ type: 'secondary', screenId }), buttonGroupProps: {
|
|
72
|
+
primaryLabel: strings.quit.confirmLabel,
|
|
73
|
+
secondaryLabel: strings.quit.dismissLabel,
|
|
74
|
+
onPrimaryClick: () => onAction?.({ type: 'cta', screenId }),
|
|
75
|
+
onSecondaryClick: () => onAction?.({ type: 'secondary', screenId }),
|
|
76
|
+
} }) })] })) : undefined;
|
|
77
|
+
return (_jsx(PrizmaFormScreen, { ref: ref, title: strings.consent.title, subtitle: strings.consent.subtitle,
|
|
78
|
+
/* The card hangs off the CTA band, not the title — the frame's
|
|
79
|
+
justify-between middle. Selected from the archetype, not declared. */
|
|
80
|
+
fieldsAlign: "end", ctaLabel: strings.consent.ctaLabel,
|
|
81
|
+
/* "Continue" stays inert until the box is ticked. */
|
|
82
|
+
ctaDisabled: !accepted, linkLabel: strings.consent.cancelLabel, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides,
|
|
83
|
+
/* With the sheet up, the consent's own buttons are under the scrim and
|
|
84
|
+
must not report: the sheet's two answers are the only actions. */
|
|
85
|
+
onAction: quitConfirm ? undefined : onAction, overlay: quit, ...shell, children: _jsx(PrizmaCheckbox, { size: "L", checked: accepted,
|
|
86
|
+
/* Mandatory for a11y (`aria-required`); the L container never paints
|
|
87
|
+
a `*` and the frame draws none. */
|
|
88
|
+
required: true, "aria-label": strings.consent.ariaLabel, segments: strings.consent.body, onCheckedChange: quitConfirm ? undefined : onConsentChange }) }));
|
|
89
|
+
});
|
|
90
|
+
BiometricConsentScreen.displayName = 'BiometricConsentScreen';
|
|
91
|
+
export default BiometricConsentScreen;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { PrizmaConsentSegment } from '@incodetech/prizma-core-web/checkbox';
|
|
2
|
+
/**
|
|
3
|
+
* The two states the section draws. Both share ONE layout — nav → Title →
|
|
4
|
+
* (space) → consent card → Continue → Cancel → tag — and differ only in whether
|
|
5
|
+
* the box is ticked and, with it, whether Continue is released:
|
|
6
|
+
*
|
|
7
|
+
* - `default` — `biometricConsent.empty` (2001:16361): the box unticked.
|
|
8
|
+
* Continue is DISABLED. The frame paints it brand blue; the
|
|
9
|
+
* requesting engineer asked for it greyed until the box is
|
|
10
|
+
* ticked, "like in Data Sharing Consent" (Uros, #uxp-design
|
|
11
|
+
* 2026-09-02), which is also what the two sibling consent
|
|
12
|
+
* screens do. DEVIATIONS #BC-2 — flip `ctaDisabled` in the
|
|
13
|
+
* screen if the frame is the final word.
|
|
14
|
+
* - `accepted` — `biometricConsent.checked` (2001:16372): the box ticked,
|
|
15
|
+
* Continue released to brand blue.
|
|
16
|
+
*
|
|
17
|
+
* There is NO refusal state. With Continue gated, "pressed with nothing ticked"
|
|
18
|
+
* cannot happen, and the file draws no such frame — the sibling modules' added
|
|
19
|
+
* `rejected` state is deliberately not copied here (DEVIATIONS #BC-3).
|
|
20
|
+
*
|
|
21
|
+
* The quit confirmation is NOT a third state: it is a dialog presented over
|
|
22
|
+
* either state (`quitConfirm` on the screen), because what is underneath — the
|
|
23
|
+
* box empty or ticked — is whatever the person had before they pressed Cancel.
|
|
24
|
+
*/
|
|
25
|
+
export type BiometricConsentState = 'default' | 'accepted';
|
|
26
|
+
export interface BiometricConsentStrings {
|
|
27
|
+
/** "verified by" attribution in the footer tag. */
|
|
28
|
+
verifiedLabel: string;
|
|
29
|
+
/** Accessible name for the logo nav row. */
|
|
30
|
+
navLabel?: string;
|
|
31
|
+
/** The `biometricConsent` section. */
|
|
32
|
+
consent: {
|
|
33
|
+
/** H2 ("Request for Biometric Processing"). Centered, per the section. */
|
|
34
|
+
title: string;
|
|
35
|
+
/** H5 under the title ("Your verification is powered by Incode…"). The
|
|
36
|
+
* section draws one on every frame. */
|
|
37
|
+
subtitle: string;
|
|
38
|
+
/**
|
|
39
|
+
* The consent card's copy, as ordered segments: a plain string renders as
|
|
40
|
+
* body copy, an object renders as an inline `<a>` that opens the document
|
|
41
|
+
* WITHOUT toggling the box. Core's own `PrizmaConsentSegment` contract — the
|
|
42
|
+
* multi-link path on `PrizmaCheckbox size="L"` — so a consent citing two
|
|
43
|
+
* documents stays expressible (#PI-10: each link is separately actionable).
|
|
44
|
+
* In production this body arrives from the backend.
|
|
45
|
+
*/
|
|
46
|
+
body: PrizmaConsentSegment[];
|
|
47
|
+
/** Accessible name for the box — the card copy is a paragraph, too long to
|
|
48
|
+
* serve as one. */
|
|
49
|
+
ariaLabel?: string;
|
|
50
|
+
/** Primary CTA ("Continue"). Disabled until the box is ticked. */
|
|
51
|
+
ctaLabel: string;
|
|
52
|
+
/** The tertiary action under Continue ("Cancel"). Declining is a hard stop:
|
|
53
|
+
* the session cannot process the person's biometrics without this consent. */
|
|
54
|
+
cancelLabel: string;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The confirmation presented when Cancel is pressed, before the session ends.
|
|
58
|
+
*
|
|
59
|
+
* NOT IN THE FIGMA FILE, and not in the shipped Web SDK either — today
|
|
60
|
+
* `manager.cancel()` ends the session the moment Cancel is tapped. Added at
|
|
61
|
+
* the owner's request (Camila, 2026-10-13): Cancel is irreversible here, the
|
|
62
|
+
* person cannot be verified without the consent, and a mis-tap on the
|
|
63
|
+
* tertiary under Continue should not cost them the session. It is Core's
|
|
64
|
+
* Modal, `default` variant, on EVERY platform — the existing component as
|
|
65
|
+
* the design system documents it, close icon and all, pinned to the bottom
|
|
66
|
+
* of the frame the way Core's presenter places it; not a bottom sheet and
|
|
67
|
+
* not a centred card (owner calls, same day). The copy is the
|
|
68
|
+
* SDK's own close dialog (`page.close.confirmQuit` / `page.close.confirm` /
|
|
69
|
+
* `page.close.cancel`), so nothing is invented. DEVIATIONS #BC-7.
|
|
70
|
+
*/
|
|
71
|
+
quit: {
|
|
72
|
+
/** Dialog title ("Are you sure you want to quit?"). */
|
|
73
|
+
title: string;
|
|
74
|
+
/** Optional supporting line. The SDK's close dialog carries none. */
|
|
75
|
+
subtitle?: string;
|
|
76
|
+
/** The destructive confirmation ("Quit") — primary, on top. */
|
|
77
|
+
confirmLabel: string;
|
|
78
|
+
/** Dismiss and stay on the consent ("Cancel") — secondary, below it. */
|
|
79
|
+
dismissLabel: string;
|
|
80
|
+
/** Accessible name of the card's close icon ("Close"), which also
|
|
81
|
+
* dismisses. Core's Default modal always draws the icon. */
|
|
82
|
+
closeLabel: string;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Biometric Consent — copy contract.
|
|
2
|
+
//
|
|
3
|
+
// The mandatory biometric consent the BACKEND decides to show — at the start of
|
|
4
|
+
// a flow, or right after ID capture — when the session comes from a protected
|
|
5
|
+
// geography (Illinois BIPA and the handful of states like it), or when the state
|
|
6
|
+
// on the captured ID says so. It is NOT the User Consent / Data Sharing Consent
|
|
7
|
+
// module: it is the flow builder's "Required biometric consent" setting, it uses
|
|
8
|
+
// its own endpoint, and declining it is a hard stop. Uros Milivojevic
|
|
9
|
+
// (#uxp-design, 2026-09-01): "Compared to User Consent it has a Cancel button
|
|
10
|
+
// next to Continue, a subtitle, and a long consent body loaded from the BE with
|
|
11
|
+
// tappable links (tapping the body also toggles the checkbox)."
|
|
12
|
+
//
|
|
13
|
+
// Figma: `Biometric Consent Screen` (vXvIMQF5DSJgkQHhFAQcWC), section
|
|
14
|
+
// `biometricConsent` (2001:16315). ONE screen, drawn across:
|
|
15
|
+
// · 2001:16361 `biometricConsent.empty` the master — box unticked
|
|
16
|
+
// · 2001:16372 `biometricConsent.checked` the box ticked
|
|
17
|
+
// · `🔧 Behavior`, `🖤 Dark mode`, `🇪🇸 ES`, `🇵🇹 PT` and the six device
|
|
18
|
+
// sections are the same two states re-presented: dark is token-driven
|
|
19
|
+
// (`[data-prizma-theme='dark']`), the locales are the host's locale pack,
|
|
20
|
+
// and the widths are excluded by the no-per-width-variants rule (DEVIATIONS
|
|
21
|
+
// #17).
|
|
22
|
+
//
|
|
23
|
+
// The screen is: nav → Title (H2 + H5 subtitle) → one consent card pinned to
|
|
24
|
+
// the BOTTOM of the column → Continue → Cancel → tag. No disclosure paragraph —
|
|
25
|
+
// unlike the consent screen the two sibling modules share, the legal body here
|
|
26
|
+
// lives INSIDE the card, and the backend supplies it.
|
|
27
|
+
//
|
|
28
|
+
// No hardcoded English anywhere in a screen: every visible string arrives here,
|
|
29
|
+
// so the host's locale pack drives the module (the Figma file ships ES + PT
|
|
30
|
+
// columns beside the EN one).
|
|
31
|
+
export {};
|
package/dist/CaptureScreen.d.ts
CHANGED
|
@@ -27,6 +27,19 @@ export interface PrizmaCaptureScreenProps extends Omit<PrizmaScreenShellProps, '
|
|
|
27
27
|
manualFeedbackText?: string;
|
|
28
28
|
/** Per-state status copy (uploading / success / error / warning). */
|
|
29
29
|
statusLabels?: Partial<Record<PrizmaSelfieCaptureState, string>>;
|
|
30
|
+
/**
|
|
31
|
+
* A notice band above the footer — a Snackbar the module raises over the live
|
|
32
|
+
* feed without taking the camera away (Face Capture's "Need more time?" offer
|
|
33
|
+
* is the first consumer).
|
|
34
|
+
*
|
|
35
|
+
* ANCHORED, like the footer and the control strip, and for the same reason:
|
|
36
|
+
* the owner's rule is that anchored chrome sits at the same position on every
|
|
37
|
+
* screen (2026-08-18). Flowing it would push Core's ring up, and the ring
|
|
38
|
+
* offset is the one thing this archetype is forbidden to touch
|
|
39
|
+
* (DEVIATIONS #12). It rides the empty band under the instruction line, which
|
|
40
|
+
* is where the module Figma puts it.
|
|
41
|
+
*/
|
|
42
|
+
notice?: ReactNode;
|
|
30
43
|
/** "verified by" attribution copy for the footer tag. */
|
|
31
44
|
verifiedLabel: string;
|
|
32
45
|
navLabel?: string;
|
package/dist/CaptureScreen.js
CHANGED
|
@@ -19,12 +19,12 @@ import './ScreenLayout.css';
|
|
|
19
19
|
* loading and result screens of a capture module use this archetype too —
|
|
20
20
|
* not the centered Processing archetype (DEVIATIONS #11).
|
|
21
21
|
*/
|
|
22
|
-
export const PrizmaCaptureScreen = forwardRef(({ showHeader, showFooter = true, cameraOpen = true, state, camera, feedbackText, isManual, manualFeedbackText, statusLabels, verifiedLabel, navLabel, screenId, overrides, onAction, ...shell }, ref) => (
|
|
22
|
+
export const PrizmaCaptureScreen = forwardRef(({ showHeader, showFooter = true, cameraOpen = true, state, camera, feedbackText, isManual, manualFeedbackText, statusLabels, notice, verifiedLabel, navLabel, screenId, overrides, onAction, ...shell }, ref) => (
|
|
23
23
|
// Pin light ONLY while the camera feed is open: Core paints the live
|
|
24
24
|
// capture area with Static inks because "the capture screen stays WHITE in
|
|
25
25
|
// both modes — light is needed for the shot" (SelfieCapture.css, owner
|
|
26
26
|
// 2026-07-14). Feed-closed screens are ordinary screens and follow the app.
|
|
27
27
|
// DEVIATIONS #F-27.
|
|
28
|
-
_jsxs(PrizmaScreenShell, { ref: ref, theme: cameraOpen ? 'light' : undefined, ...shell, children: [_jsx(PrizmaScreenNav, { reserved: !(showHeader ?? (cameraOpen ? Boolean(overrides?.logo) : true)), logo: overrides?.logo, navLabel: navLabel }), _jsxs("div", { className: "prizma-screen-layout__content prizma-screen-layout__content--capture", children: [_jsx(PrizmaSelfieCapture, { state: state, camera: camera, showFeedback: Boolean(feedbackText ?? manualFeedbackText), feedbackText: feedbackText, isManual: isManual, manualFeedbackText: manualFeedbackText, statusLabels: statusLabels }), showFooter ? (_jsx("div", { className: "prizma-screen-layout__footer prizma-screen-layout__footer--pinned", children: _jsx(PrizmaTag, { label: verifiedLabel }) })) : null] })] })));
|
|
28
|
+
_jsxs(PrizmaScreenShell, { ref: ref, theme: cameraOpen ? 'light' : undefined, ...shell, children: [_jsx(PrizmaScreenNav, { reserved: !(showHeader ?? (cameraOpen ? Boolean(overrides?.logo) : true)), logo: overrides?.logo, navLabel: navLabel }), _jsxs("div", { className: "prizma-screen-layout__content prizma-screen-layout__content--capture", children: [_jsx(PrizmaSelfieCapture, { state: state, camera: camera, showFeedback: Boolean(feedbackText ?? manualFeedbackText), feedbackText: feedbackText, isManual: isManual, manualFeedbackText: manualFeedbackText, statusLabels: statusLabels }), notice ? (_jsx("div", { className: "prizma-screen-layout__capture-notice", children: notice })) : null, showFooter ? (_jsx("div", { className: "prizma-screen-layout__footer prizma-screen-layout__footer--pinned", children: _jsx(PrizmaTag, { label: verifiedLabel }) })) : null] })] })));
|
|
29
29
|
PrizmaCaptureScreen.displayName = 'PrizmaCaptureScreen';
|
|
30
30
|
export default PrizmaCaptureScreen;
|
|
@@ -389,6 +389,22 @@
|
|
|
389
389
|
background: var(--prizma-surface-neutral-50);
|
|
390
390
|
align-items: center;
|
|
391
391
|
justify-content: center;
|
|
392
|
+
/* The card hugs its content and is taller than a short window: on the Duo
|
|
393
|
+
* open full screen (626) unsafe centring put 90px of it above the page and
|
|
394
|
+
* 90 below, heading cut off (sweep 2026-10-20). `safe` starts the card at
|
|
395
|
+
* the top of the page when it does not fit, and does nothing when it does
|
|
396
|
+
* (#F-37, same mechanism). The plain `center` is the fallback. */
|
|
397
|
+
justify-content: safe center;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* …and under 720 the page scrolls, as a desktop page does when the window is
|
|
401
|
+
* shorter than its content. The shell is `overflow: hidden` for the screens
|
|
402
|
+
* that pin chrome to its edges; this page pins nothing, the tag rides in the
|
|
403
|
+
* card's band. */
|
|
404
|
+
@container pcs-screen (max-height: 720px) {
|
|
405
|
+
.prizma-screen-shell.demo-screens-redirect {
|
|
406
|
+
overflow-y: auto;
|
|
407
|
+
}
|
|
392
408
|
}
|
|
393
409
|
|
|
394
410
|
.demo-screens-redirect__card {
|
|
@@ -13,8 +13,13 @@ import './DemoScreensLayout.css';
|
|
|
13
13
|
* - `resend` "Link sent!", resend available
|
|
14
14
|
* - `resent` "Link sent!" with the "resent" snackbar
|
|
15
15
|
* - `tooMany` "Too many attempts"
|
|
16
|
+
* - `invalidUuid` the link's UUID was rejected (expired or unknown): no leg
|
|
17
|
+
* to offer, only the error. One message for Flows and
|
|
18
|
+
* Workflows alike, since the backend answers the same way for
|
|
19
|
+
* both (Elena, 2026-10-21: web SDK 2.0 showed "QR code
|
|
20
|
+
* expired" for Flows and "Session expired" with 2.0 off).
|
|
16
21
|
*/
|
|
17
|
-
export type DemoScreensRedirectStage = 'qr' | 'sms' | 'smsFilled' | 'sent' | 'resend' | 'resent' | 'tooMany';
|
|
22
|
+
export type DemoScreensRedirectStage = 'qr' | 'sms' | 'smsFilled' | 'sent' | 'resend' | 'resent' | 'tooMany' | 'invalidUuid';
|
|
18
23
|
export interface DemoScreensRedirectScreenProps extends Omit<PrizmaScreenShellProps, 'dark' | 'title' | 'children'> {
|
|
19
24
|
/** Family copy — this screen reads the `redirect` slice. */
|
|
20
25
|
strings: DemoScreensStrings;
|
|
@@ -31,8 +31,9 @@ export const DemoScreensRedirectScreen = forwardRef(({ strings, stage = 'qr', sm
|
|
|
31
31
|
{ code: 'RS', name: 'Serbia', dialCode: '+381', flag: '' },
|
|
32
32
|
].find(c => c.code === r.countryCode);
|
|
33
33
|
const subtitle = sms ? r.subtitle : desktop ? r.subtitleQrDesktop : r.subtitleQrOnly;
|
|
34
|
-
const
|
|
35
|
-
|
|
34
|
+
const invalid = stage === 'invalidUuid';
|
|
35
|
+
const verdict = stage === 'sent' || stage === 'resend' || stage === 'resent' || stage === 'tooMany' || invalid;
|
|
36
|
+
return (_jsxs(PrizmaScreenShell, { ref: ref, "data-screen-id": screenId, className: ['demo-screens-redirect', className ?? ''].filter(Boolean).join(' '), ...shell, children: [stage === 'resent' ? (_jsx("div", { className: "demo-screens-toast demo-screens-toast--desktop", children: _jsx(PrizmaSnackbar, { state: "success", children: r.sent.resentSnackbar }) })) : null, _jsxs("div", { className: "demo-screens-redirect__card", children: [_jsx(PrizmaScreenNav, { logo: overrides?.logo, navLabel: strings.navLabel }), _jsxs("div", { className: "prizma-screen-layout__content demo-screens-redirect__content", children: [invalid ? null : _jsx(PrizmaTitle, { variant: "centered", title: r.title, showSubtitle: true, subtitle: subtitle }), sms && !invalid ? (_jsxs("div", { className: "demo-screens-tabs", role: "tablist", children: [_jsx("button", { type: "button", role: "tab", "aria-selected": !onSms, className: ['demo-screens-tabs__tab', !onSms ? 'demo-screens-tabs__tab--active' : ''].join(' '), onClick: () => onAction?.({ type: 'secondary', screenId }), children: r.tabs.qr }), _jsx("button", { type: "button", role: "tab", "aria-selected": onSms, className: ['demo-screens-tabs__tab', onSms ? 'demo-screens-tabs__tab--active' : ''].join(' '), onClick: () => onAction?.({ type: 'tertiary', screenId }), children: r.tabs.sms })] })) : null, stage === 'qr' ? (_jsxs("div", { className: "demo-screens-redirect__leg", children: [sms ? _jsx("p", { className: "demo-screens-redirect__hint", children: r.qrHint }) : null, _jsx("div", { className: "demo-screens-redirect__qr", "aria-label": r.tabs.qr, children: qr })] })) : null, stage === 'sms' || stage === 'smsFilled' ? (_jsxs("div", { className: "demo-screens-redirect__leg demo-screens-redirect__leg--form", children: [_jsx("p", { className: "demo-screens-redirect__hint", children: r.smsHint }), _jsx(PrizmaCombined, { "aria-label": r.phoneLabel, placeholder: r.phonePlaceholder, defaultValue: stage === 'smsFilled' ? r.phoneValue : '', defaultCountry: country, showRequiredMarker: false }, stage), _jsx(PrizmaButton, { variant: "primary", size: "L", disabled: stage !== 'smsFilled', onClick: () => onAction?.({ type: 'cta', screenId }), children: r.sendLabel })] })) : null, verdict ? (_jsxs("div", { className: "demo-screens-redirect__leg demo-screens-redirect__leg--verdict", children: [invalid ? (_jsx(PrizmaTitle, { variant: "centered", title: r.invalidUuid.title, showSubtitle: true, subtitle: r.invalidUuid.subtitle, icon: { type: 'status', status: 'error' } })) : stage === 'tooMany' ? (_jsx(PrizmaTitle, { variant: "centered", title: r.tooMany.title, showSubtitle: true, subtitle: r.tooMany.subtitle, icon: { type: 'status', status: 'error' } })) : (_jsx(PrizmaTitle, { variant: "centered", title: r.sent.title, showSubtitle: true, subtitle: `${r.sent.toPrefix} ${country?.dialCode ?? ''} ${r.phoneValue}`.trim(), icon: { type: 'status', status: 'success' } })), invalid ? null : stage === 'tooMany' ? (_jsx(PrizmaButton, { variant: "tertiary-link", size: "L", onClick: () => onAction?.({ type: 'tertiary', screenId }), children: r.tooMany.changeLabel })) : stage === 'sent' || stage === 'resent' ? (_jsx(PrizmaButton, { variant: "tertiary-link", size: "L", disabled: true, children: r.sent.resendIn })) : (_jsx(PrizmaButton, { variant: "tertiary-link", size: "L", onClick: () => onAction?.({ type: 'cta', screenId }), children: r.sent.resend }))] })) : null] }), _jsxs("div", { className: "prizma-screen-layout__band demo-screens-redirect__band", children: [desktop && !verdict ? (_jsxs(_Fragment, { children: [_jsx(PrizmaDisclaimer, { text: r.orLabel }), _jsx("div", { className: "prizma-screen-layout__band__ctas", children: _jsx(PrizmaButton, { variant: "secondary", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: r.desktopLabel }) })] })) : null, _jsx("div", { className: "prizma-screen-layout__band__tag", children: _jsx(PrizmaTag, { label: strings.verifiedLabel }) })] })] })] }));
|
|
36
37
|
});
|
|
37
38
|
DemoScreensRedirectScreen.displayName = 'DemoScreensRedirectScreen';
|
|
38
39
|
export default DemoScreensRedirectScreen;
|
|
@@ -150,6 +150,11 @@ export interface DemoScreensStrings {
|
|
|
150
150
|
subtitle: string;
|
|
151
151
|
changeLabel: string;
|
|
152
152
|
};
|
|
153
|
+
/** The link's UUID was rejected: the same copy for Flows and Workflows. */
|
|
154
|
+
invalidUuid: {
|
|
155
|
+
title: string;
|
|
156
|
+
subtitle: string;
|
|
157
|
+
};
|
|
153
158
|
};
|
|
154
159
|
/** WEB · `demo_2` — the front door: language, the wordmark, one CTA. */
|
|
155
160
|
start: {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type PrizmaListScreenProps } from './ListScreen';
|
|
3
|
+
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
4
|
+
import type { DigitalIdDeviceWalletsOption, DigitalIdDeviceWalletsPlatformWallet, DigitalIdDeviceWalletsStrings } from './DigitalIdDeviceWalletsStrings';
|
|
5
|
+
import './ScreenLayout.css';
|
|
6
|
+
export interface DigitalIdDeviceWalletsDocumentSelectionScreenProps extends Omit<PrizmaListScreenProps, 'title' | 'subtitle' | 'children' | 'listAlign' | 'verifiedLabel' | 'navLabel'> {
|
|
7
|
+
/** Module copy — this screen reads the `documentSelection` slice. */
|
|
8
|
+
strings: DigitalIdDeviceWalletsStrings;
|
|
9
|
+
/** Which wallet row the list carries. Default `apple` (iOS); `google` on
|
|
10
|
+
* Android; `digital-id` on web, where the row comes last with no tag. */
|
|
11
|
+
wallet?: DigitalIdDeviceWalletsPlatformWallet;
|
|
12
|
+
/** Fired with the chosen option; `onAction` still reports the tap. Named
|
|
13
|
+
* `onOptionSelect`, not `onSelect` — the latter is a native <div> event the
|
|
14
|
+
* shell already passes through. */
|
|
15
|
+
onOptionSelect?: (option: DigitalIdDeviceWalletsOption) => void;
|
|
16
|
+
screenId?: string;
|
|
17
|
+
overrides?: PrizmaScreenOverrides;
|
|
18
|
+
onAction?: PrizmaScreenActionHandler;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Digital ID Device Wallets — choose how to verify, with the device wallet
|
|
22
|
+
* first, built on the `PrizmaListScreen` archetype (GUIDELINES.md §6-G).
|
|
23
|
+
* Figma: `Digital IDs - Latest Design` (u7N5Zq4bfOwiVbpKHKmSPE), section
|
|
24
|
+
* `iOS Apple Wallet`, frame `1-1-1-how to verify` (26106:12647).
|
|
25
|
+
*
|
|
26
|
+
* The same screen as `IdCaptureDocumentSelectionScreen` with one more row: on
|
|
27
|
+
* iOS and Android the wallet on top, carrying Core's ⚡ Instant tag; on web a
|
|
28
|
+
* plain Digital ID row last (`[Web] Device Wallets`, 26106:13011). It is its own screen rather
|
|
29
|
+
* than a flag on ID Capture's so that ID Capture's chooser stays exactly what
|
|
30
|
+
* that module ships. Every piece is Core's — the row, the tag and the
|
|
31
|
+
* `apple-wallet` / `google-wallet` card icons (§10).
|
|
32
|
+
*/
|
|
33
|
+
export declare const DigitalIdDeviceWalletsDocumentSelectionScreen: React.ForwardRefExoticComponent<DigitalIdDeviceWalletsDocumentSelectionScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
34
|
+
export default DigitalIdDeviceWalletsDocumentSelectionScreen;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import { PrizmaCardListVerificationOptions } from '@incodetech/prizma-core-web/card-list';
|
|
5
|
+
import { PrizmaListScreen } from './ListScreen';
|
|
6
|
+
import './ScreenLayout.css';
|
|
7
|
+
/**
|
|
8
|
+
* Digital ID Device Wallets — choose how to verify, with the device wallet
|
|
9
|
+
* first, built on the `PrizmaListScreen` archetype (GUIDELINES.md §6-G).
|
|
10
|
+
* Figma: `Digital IDs - Latest Design` (u7N5Zq4bfOwiVbpKHKmSPE), section
|
|
11
|
+
* `iOS Apple Wallet`, frame `1-1-1-how to verify` (26106:12647).
|
|
12
|
+
*
|
|
13
|
+
* The same screen as `IdCaptureDocumentSelectionScreen` with one more row: on
|
|
14
|
+
* iOS and Android the wallet on top, carrying Core's ⚡ Instant tag; on web a
|
|
15
|
+
* plain Digital ID row last (`[Web] Device Wallets`, 26106:13011). It is its own screen rather
|
|
16
|
+
* than a flag on ID Capture's so that ID Capture's chooser stays exactly what
|
|
17
|
+
* that module ships. Every piece is Core's — the row, the tag and the
|
|
18
|
+
* `apple-wallet` / `google-wallet` card icons (§10).
|
|
19
|
+
*/
|
|
20
|
+
export const DigitalIdDeviceWalletsDocumentSelectionScreen = forwardRef(({ strings, wallet = 'apple', onOptionSelect, screenId = 'digital-id-device-wallets-document-selection', overrides, onAction, ...shell }, ref) => {
|
|
21
|
+
const choose = (option) => {
|
|
22
|
+
onOptionSelect?.(option);
|
|
23
|
+
onAction?.({ type: 'cta', screenId });
|
|
24
|
+
};
|
|
25
|
+
const copy = strings.documentSelection;
|
|
26
|
+
return (_jsx(PrizmaListScreen, { ref: ref, title: copy.title, subtitle: copy.subtitle, listAlign: "end", verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell, children: _jsx(PrizmaCardListVerificationOptions, { items: wallet === 'digital-id'
|
|
27
|
+
? [
|
|
28
|
+
// Web: the documents first, the plain Digital ID row last.
|
|
29
|
+
{ icon: 'id', title: copy.idLabel, onClick: () => choose('id') },
|
|
30
|
+
{ icon: 'passport', title: copy.passportLabel, onClick: () => choose('passport') },
|
|
31
|
+
{ icon: 'digital-id', title: copy.digitalIdLabel, onClick: () => choose('wallet') },
|
|
32
|
+
]
|
|
33
|
+
: [
|
|
34
|
+
{
|
|
35
|
+
icon: wallet === 'apple' ? 'apple-wallet' : 'google-wallet',
|
|
36
|
+
title: wallet === 'apple' ? copy.appleWalletLabel : copy.googleWalletLabel,
|
|
37
|
+
hasTag: true,
|
|
38
|
+
tagLabel: copy.instantLabel,
|
|
39
|
+
onClick: () => choose('wallet'),
|
|
40
|
+
},
|
|
41
|
+
{ icon: 'id', title: copy.idLabel, onClick: () => choose('id') },
|
|
42
|
+
{ icon: 'passport', title: copy.passportLabel, onClick: () => choose('passport') },
|
|
43
|
+
] }) }));
|
|
44
|
+
});
|
|
45
|
+
DigitalIdDeviceWalletsDocumentSelectionScreen.displayName =
|
|
46
|
+
'DigitalIdDeviceWalletsDocumentSelectionScreen';
|
|
47
|
+
export default DigitalIdDeviceWalletsDocumentSelectionScreen;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type PrizmaResultScreenProps } from './ResultScreen';
|
|
3
|
+
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
4
|
+
import type { DigitalIdDeviceWalletsResultState, DigitalIdDeviceWalletsStrings } from './DigitalIdDeviceWalletsStrings';
|
|
5
|
+
import './ScreenLayout.css';
|
|
6
|
+
export interface DigitalIdDeviceWalletsResultScreenProps extends Omit<PrizmaResultScreenProps, 'status' | 'title' | 'subtitle' | 'ctaLabel' | 'secondaryCtaLabel' | 'verifiedLabel' | 'navLabel'> {
|
|
7
|
+
/** Module copy — this screen reads the `success` or `error` slice. */
|
|
8
|
+
strings: DigitalIdDeviceWalletsStrings;
|
|
9
|
+
/** Which verdict the wallet hand-back landed on. */
|
|
10
|
+
state: DigitalIdDeviceWalletsResultState;
|
|
11
|
+
screenId?: string;
|
|
12
|
+
overrides?: PrizmaScreenOverrides;
|
|
13
|
+
onAction?: PrizmaScreenActionHandler;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Digital ID Device Wallets — the verdict after the wallet hands the ID back,
|
|
17
|
+
* built on the `PrizmaResultScreen` archetype (GUIDELINES.md §6-F).
|
|
18
|
+
*
|
|
19
|
+
* `error` is `Digital ID Generic Error` (26540:5685): status icon, title and
|
|
20
|
+
* subtitle centred in the full height, one CTA near the bottom, no logo nav and
|
|
21
|
+
* no verified tag. `success` has no frame — the section's `Success?` decision
|
|
22
|
+
* goes straight to the next module — so it is the same recipe with the
|
|
23
|
+
* positive mark and no button: it moves on by itself after 3 s, the way Face
|
|
24
|
+
* Capture's success does (DEVIATIONS.md #DIW-1). On web the error can carry a
|
|
25
|
+
* second button, "Choose another method", back to the chooser (#DIW-5).
|
|
26
|
+
*/
|
|
27
|
+
export declare const DigitalIdDeviceWalletsResultScreen: React.ForwardRefExoticComponent<DigitalIdDeviceWalletsResultScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
28
|
+
export default DigitalIdDeviceWalletsResultScreen;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import { PrizmaResultScreen } from './ResultScreen';
|
|
5
|
+
import './ScreenLayout.css';
|
|
6
|
+
/**
|
|
7
|
+
* Digital ID Device Wallets — the verdict after the wallet hands the ID back,
|
|
8
|
+
* built on the `PrizmaResultScreen` archetype (GUIDELINES.md §6-F).
|
|
9
|
+
*
|
|
10
|
+
* `error` is `Digital ID Generic Error` (26540:5685): status icon, title and
|
|
11
|
+
* subtitle centred in the full height, one CTA near the bottom, no logo nav and
|
|
12
|
+
* no verified tag. `success` has no frame — the section's `Success?` decision
|
|
13
|
+
* goes straight to the next module — so it is the same recipe with the
|
|
14
|
+
* positive mark and no button: it moves on by itself after 3 s, the way Face
|
|
15
|
+
* Capture's success does (DEVIATIONS.md #DIW-1). On web the error can carry a
|
|
16
|
+
* second button, "Choose another method", back to the chooser (#DIW-5).
|
|
17
|
+
*/
|
|
18
|
+
export const DigitalIdDeviceWalletsResultScreen = forwardRef(({ strings, state, screenId = `digital-id-device-wallets-${state}`, showHeader = false, showFooter = false, overrides, onAction, ...shell }, ref) => {
|
|
19
|
+
const copy = state === 'success' ? strings.success : strings.error;
|
|
20
|
+
return (_jsx(PrizmaResultScreen, { ref: ref, status: state, title: copy.title, subtitle: copy.subtitle, ctaLabel: copy.ctaLabel, secondaryCtaLabel: state === 'error' ? strings.error.secondaryCtaLabel : undefined, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, showHeader: showHeader, showFooter: showFooter, screenId: screenId, overrides: overrides, onAction: onAction, ...shell }));
|
|
21
|
+
});
|
|
22
|
+
DigitalIdDeviceWalletsResultScreen.displayName = 'DigitalIdDeviceWalletsResultScreen';
|
|
23
|
+
export default DigitalIdDeviceWalletsResultScreen;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Which wallet row the chooser offers. iOS shows Apple Wallet and Android
|
|
2
|
+
* Google Wallet, first and tagged Instant; web shows a plain Digital ID row
|
|
3
|
+
* last (`[Web] Device Wallets`, 26106:13011), which opens the browser's
|
|
4
|
+
* wallet sheet. */
|
|
5
|
+
export type DigitalIdDeviceWalletsPlatformWallet = 'apple' | 'google' | 'digital-id';
|
|
6
|
+
/** The two verdicts the wallet hand-back can land on. */
|
|
7
|
+
export type DigitalIdDeviceWalletsResultState = 'success' | 'error';
|
|
8
|
+
/** What the person picked on the chooser. `wallet` stays in this module; `id`
|
|
9
|
+
* and `passport` hand off to ID Capture. */
|
|
10
|
+
export type DigitalIdDeviceWalletsOption = 'wallet' | 'id' | 'passport';
|
|
11
|
+
export interface DigitalIdDeviceWalletsStrings {
|
|
12
|
+
/** Accessible name for the logo nav region (i18n — no baked-in English). */
|
|
13
|
+
navLabel?: string;
|
|
14
|
+
/** "verified by" attribution copy for the footer tag. */
|
|
15
|
+
verifiedLabel: string;
|
|
16
|
+
/** `1-1-1-how to verify` (node 26106:12647). */
|
|
17
|
+
documentSelection: {
|
|
18
|
+
/** "Select how to verify" */
|
|
19
|
+
title: string;
|
|
20
|
+
subtitle?: string;
|
|
21
|
+
/** "Apple Wallet" */
|
|
22
|
+
appleWalletLabel: string;
|
|
23
|
+
/** "Google Wallet" — the Android row. */
|
|
24
|
+
googleWalletLabel: string;
|
|
25
|
+
/** "Digital ID" — the web row. */
|
|
26
|
+
digitalIdLabel: string;
|
|
27
|
+
/** "Instant" — the tag under the wallet row. */
|
|
28
|
+
instantLabel: string;
|
|
29
|
+
/** "Identity Card" */
|
|
30
|
+
idLabel: string;
|
|
31
|
+
/** "Passport" */
|
|
32
|
+
passportLabel: string;
|
|
33
|
+
};
|
|
34
|
+
/** `Successfully verified` (node 26598:16374) — no button (DEVIATIONS.md #DIW-1). */
|
|
35
|
+
success: {
|
|
36
|
+
/** "Identity successfully verified" — the NFC / OCR Review success title. */
|
|
37
|
+
title: string;
|
|
38
|
+
subtitle?: string;
|
|
39
|
+
/** No button by default: like Face Capture's success, the flow moves on by
|
|
40
|
+
* itself after 3 s. Set it only for a host that waits for a tap. */
|
|
41
|
+
ctaLabel?: string;
|
|
42
|
+
};
|
|
43
|
+
/** `Digital ID Generic Error` (node 26540:5685). */
|
|
44
|
+
error: {
|
|
45
|
+
/** "Couldn't verify your ID" */
|
|
46
|
+
title: string;
|
|
47
|
+
/** "Please try again" */
|
|
48
|
+
subtitle?: string;
|
|
49
|
+
/** "Try again" */
|
|
50
|
+
ctaLabel: string;
|
|
51
|
+
/** "Choose another method" — web only: back to the chooser, the SDK's
|
|
52
|
+
* `deviceWalletUseAnotherMethod()`. Absent, the screen has one button. */
|
|
53
|
+
secondaryCtaLabel?: string;
|
|
54
|
+
};
|
|
55
|
+
}
|