@incodetech/prizma-core-screens 0.2.14 → 0.2.20
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/DigitalIdProvidersDocumentSelectionScreen.d.ts +3 -3
- package/dist/DigitalIdProvidersDocumentSelectionScreen.js +4 -3
- package/dist/DigitalIdProvidersLayout.css +0 -12
- package/dist/DigitalIdProvidersRedirectScreen.d.ts +2 -3
- package/dist/DigitalIdProvidersRedirectScreen.js +3 -4
- package/dist/DigitalIdProvidersStrings.d.ts +4 -0
- package/dist/FaceCaptureLayout.css +150 -0
- package/dist/FormScreen.css +35 -0
- package/dist/IdCaptureLayout.css +63 -0
- package/dist/RotateToPortraitScreen.css +162 -0
- package/dist/RotateToPortraitScreen.d.ts +64 -0
- package/dist/RotateToPortraitScreen.js +68 -0
- package/dist/RotateToPortraitStrings.d.ts +8 -0
- package/dist/RotateToPortraitStrings.js +20 -0
- package/dist/ScreenLayout.css +200 -0
- package/dist/ScreenShell.css +13 -0
- package/dist/TutorialScreen.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/styles.css +1 -0
- package/package.json +9 -3
- package/samples/digital-id-providers/audkenni.png +0 -0
- package/samples/digital-id-providers/bankid-cz.png +0 -0
- package/samples/digital-id-providers/bankid-se.png +0 -0
- package/samples/digital-id-providers/ca-dmv-wallet.png +0 -0
- package/samples/digital-id-providers/digidentity.png +0 -0
- package/samples/digital-id-providers/diia.png +0 -0
- package/samples/digital-id-providers/edo.png +0 -0
- package/samples/digital-id-providers/eparaksts.png +0 -0
- package/samples/digital-id-providers/evrotrust.png +0 -0
- package/samples/digital-id-providers/freja.png +0 -0
- package/samples/digital-id-providers/ftn.png +0 -0
- package/samples/digital-id-providers/handy-signatur.png +0 -0
- package/samples/digital-id-providers/idin.png +0 -0
- package/samples/digital-id-providers/itsme.png +0 -0
- package/samples/digital-id-providers/mitid.png +0 -0
- package/samples/digital-id-providers/mobile-id.png +0 -0
- package/samples/digital-id-providers/mojeid.png +0 -0
- package/samples/digital-id-providers/oneid.png +0 -0
- package/samples/digital-id-providers/smart-id.png +0 -0
- package/samples/digital-id-providers/spid.png +0 -0
- package/samples/digital-id-providers/swissid.png +0 -0
- package/samples/digital-id-providers/uae-pass.png +0 -0
- package/samples/digital-id-providers/verimi.png +0 -0
- package/src/DigitalIdProvidersDocumentSelectionScreen.tsx +4 -3
- package/src/DigitalIdProvidersLayout.css +0 -12
- package/src/DigitalIdProvidersRedirectScreen.tsx +2 -9
- package/src/DigitalIdProvidersStrings.ts +4 -0
- package/src/FaceCaptureLayout.css +150 -0
- package/src/FormScreen.css +35 -0
- package/src/IdCaptureLayout.css +63 -0
- package/src/RotateToPortraitScreen.css +162 -0
- package/src/RotateToPortraitScreen.tsx +162 -0
- package/src/RotateToPortraitStrings.ts +28 -0
- package/src/ScreenLayout.css +200 -0
- package/src/ScreenShell.css +13 -0
- package/src/TutorialScreen.tsx +4 -1
- package/src/index.ts +11 -0
- package/src/styles.css +1 -0
|
@@ -22,9 +22,9 @@ export interface DigitalIdProvidersDocumentSelectionScreenProps extends Omit<Pri
|
|
|
22
22
|
* Figma: `Document Chooser` (27753:8099) and the full list (27703:4895).
|
|
23
23
|
*
|
|
24
24
|
* Two of Core's card lists, each under a section label, after a "Viewing
|
|
25
|
-
* options for" country line with Core's flag. Every row is Core's;
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* options for" country line with Core's flag. Every row is Core's; a
|
|
26
|
+
* provider leads with its logo from the backend catalog, or Core's generic
|
|
27
|
+
* `digital-id-web` card icon when it has none (DEVIATIONS #DIP-1), and the Identity Card
|
|
28
28
|
* row has no second line, which Core's row cannot draw (#DIP-3).
|
|
29
29
|
*/
|
|
30
30
|
export declare const DigitalIdProvidersDocumentSelectionScreen: React.ForwardRefExoticComponent<DigitalIdProvidersDocumentSelectionScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -12,9 +12,9 @@ import './DigitalIdProvidersLayout.css';
|
|
|
12
12
|
* Figma: `Document Chooser` (27753:8099) and the full list (27703:4895).
|
|
13
13
|
*
|
|
14
14
|
* Two of Core's card lists, each under a section label, after a "Viewing
|
|
15
|
-
* options for" country line with Core's flag. Every row is Core's;
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* options for" country line with Core's flag. Every row is Core's; a
|
|
16
|
+
* provider leads with its logo from the backend catalog, or Core's generic
|
|
17
|
+
* `digital-id-web` card icon when it has none (DEVIATIONS #DIP-1), and the Identity Card
|
|
18
18
|
* row has no second line, which Core's row cannot draw (#DIP-3).
|
|
19
19
|
*/
|
|
20
20
|
export const DigitalIdProvidersDocumentSelectionScreen = forwardRef(({ strings, providerCount, onOptionSelect, screenId = 'digital-id-providers-document-selection', overrides, onAction, ...shell }, ref) => {
|
|
@@ -29,6 +29,7 @@ export const DigitalIdProvidersDocumentSelectionScreen = forwardRef(({ strings,
|
|
|
29
29
|
{ icon: 'passport', title: copy.passportLabel, onClick: () => choose({ kind: 'passport' }) },
|
|
30
30
|
] })] }), _jsxs("section", { className: "digital-id-providers-section", children: [_jsx("p", { className: "digital-id-providers-section__label", children: copy.providersSectionLabel }), _jsx(PrizmaCardListVerificationOptions, { items: providers.map(provider => ({
|
|
31
31
|
icon: 'digital-id-web',
|
|
32
|
+
logo: provider.logo,
|
|
32
33
|
title: provider.label,
|
|
33
34
|
onClick: () => choose({ kind: 'provider', providerId: provider.id }),
|
|
34
35
|
})) })] })] }) }));
|
|
@@ -45,15 +45,3 @@
|
|
|
45
45
|
line-height: var(--prizma-body-m-regular-line-height);
|
|
46
46
|
letter-spacing: var(--prizma-body-m-regular-letter-spacing);
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
/* Redirecting — the spinner and its copy sit at the middle of the screen.
|
|
50
|
-
* With the header hidden, archetype C still reserves the nav row above the
|
|
51
|
-
* content and centres the column in what is left, so the block lands ~63px
|
|
52
|
-
* low. Mirroring that reserve below — status bar, the nav's gap and height,
|
|
53
|
-
* the column's own top padding (ScreenNav.css, ScreenLayout.css) — balances
|
|
54
|
-
* it on the shell's midline. */
|
|
55
|
-
.digital-id-providers-redirect .prizma-screen-layout__content--centered {
|
|
56
|
-
padding-bottom: calc(
|
|
57
|
-
var(--pcs-status-bar, 47px) + var(--prizma-spacing-12) + 44px + var(--prizma-spacing-24)
|
|
58
|
-
);
|
|
59
|
-
}
|
|
@@ -3,7 +3,6 @@ import { type PrizmaProcessingScreenProps } from './ProcessingScreen';
|
|
|
3
3
|
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
4
4
|
import type { DigitalIdProvidersStrings } from './DigitalIdProvidersStrings';
|
|
5
5
|
import './ScreenLayout.css';
|
|
6
|
-
import './DigitalIdProvidersLayout.css';
|
|
7
6
|
export interface DigitalIdProvidersRedirectScreenProps extends Omit<PrizmaProcessingScreenProps, 'status' | 'title' | 'subtitle' | 'verifiedLabel' | 'navLabel'> {
|
|
8
7
|
/** Module copy — this screen reads the `redirecting` slice. */
|
|
9
8
|
strings: DigitalIdProvidersStrings;
|
|
@@ -17,8 +16,8 @@ export interface DigitalIdProvidersRedirectScreenProps extends Omit<PrizmaProces
|
|
|
17
16
|
* archetype (GUIDELINES.md §6-C). Figma: the `1-18-1-id-hold-on` instance in
|
|
18
17
|
* the web full flow (27707:9281), with the module's own copy. The Web SDK's
|
|
19
18
|
* `digitalIdRedirect` phases `loading` and `redirecting` both look like this.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* Built like Core's other processing screens: the archetype as-is, with the
|
|
20
|
+
* logo nav and the footer tag (DEVIATIONS #DIP-9).
|
|
22
21
|
*/
|
|
23
22
|
export declare const DigitalIdProvidersRedirectScreen: React.ForwardRefExoticComponent<DigitalIdProvidersRedirectScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
24
23
|
export default DigitalIdProvidersRedirectScreen;
|
|
@@ -3,16 +3,15 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { forwardRef } from 'react';
|
|
4
4
|
import { PrizmaProcessingScreen } from './ProcessingScreen';
|
|
5
5
|
import './ScreenLayout.css';
|
|
6
|
-
import './DigitalIdProvidersLayout.css';
|
|
7
6
|
/**
|
|
8
7
|
* Digital ID Providers — "Redirecting for verification…", the wait before the
|
|
9
8
|
* browser leaves for the provider's site, on the `PrizmaProcessingScreen`
|
|
10
9
|
* archetype (GUIDELINES.md §6-C). Figma: the `1-18-1-id-hold-on` instance in
|
|
11
10
|
* the web full flow (27707:9281), with the module's own copy. The Web SDK's
|
|
12
11
|
* `digitalIdRedirect` phases `loading` and `redirecting` both look like this.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* Built like Core's other processing screens: the archetype as-is, with the
|
|
13
|
+
* logo nav and the footer tag (DEVIATIONS #DIP-9).
|
|
15
14
|
*/
|
|
16
|
-
export const DigitalIdProvidersRedirectScreen = forwardRef(({ strings, screenId = 'digital-id-providers-redirecting',
|
|
15
|
+
export const DigitalIdProvidersRedirectScreen = forwardRef(({ strings, screenId = 'digital-id-providers-redirecting', overrides, onAction, ...shell }, ref) => (_jsx(PrizmaProcessingScreen, { ref: ref, status: "loading", title: strings.redirecting.title, subtitle: strings.redirecting.subtitle, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell })));
|
|
17
16
|
DigitalIdProvidersRedirectScreen.displayName = 'DigitalIdProvidersRedirectScreen';
|
|
18
17
|
export default DigitalIdProvidersRedirectScreen;
|
|
@@ -5,6 +5,10 @@ export interface DigitalIdProvidersOption {
|
|
|
5
5
|
id: string;
|
|
6
6
|
/** "iDIN", "itsme", "CA DMV Wallet"… */
|
|
7
7
|
label: string;
|
|
8
|
+
/** The provider's logo tile (an image URL), from the backend catalog.
|
|
9
|
+
* Absent → Core's generic `digital-id-web` card icon. Samples ship under
|
|
10
|
+
* `samples/digital-id-providers/`. */
|
|
11
|
+
logo?: string;
|
|
8
12
|
}
|
|
9
13
|
/** What the person picked: a physical document, or a provider by its id. */
|
|
10
14
|
export type DigitalIdProvidersSelection = {
|
|
@@ -50,6 +50,156 @@
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/* ── Landscape phones: the ring holds its 335, the stack changes axis ────────
|
|
54
|
+
* The capture half of ScreenLayout.css's landscape block (#F-39). A phone
|
|
55
|
+
* held sideways is 375 to 440 tall and the portrait stack needs ~557 (nav,
|
|
56
|
+
* Spacing/40, the 335 ring, Spacing/32, instruction, footer): on the 844 x
|
|
57
|
+
* 390 frame the ring ran 48 past the bottom of the panel, the instruction and
|
|
58
|
+
* the shutter were below the frame entirely and the bottom-anchored tag drew
|
|
59
|
+
* across the ring (measured on the Core Lab canvas, 2026-10-20). The ring is
|
|
60
|
+
* not what gives ground (#20, Camila 2026-10-14) and nothing stacked under it
|
|
61
|
+
* can fit, so the component's column becomes two ZONES side by side: the ring
|
|
62
|
+
* at the left, vertically centred, the instruction beside it filling the rest,
|
|
63
|
+
* and on the manual screen the shutter at the right edge. 375 − 335 leaves 20 of air
|
|
64
|
+
* above and below the ring on the shortest phone, so it fits at full size.
|
|
65
|
+
*
|
|
66
|
+
* The instruction stays INSIDE `PrizmaSelfieCapture` (#12/#14): the root
|
|
67
|
+
* changes axis, the way #20 already re-seats its padding and gap from this
|
|
68
|
+
* file, and no copy leaves the component. Three decisions:
|
|
69
|
+
*
|
|
70
|
+
* · The ring is pinned to the LEFT edge, not centred with its neighbours, so
|
|
71
|
+
* it is in the same place on every live state (auto has an instruction
|
|
72
|
+
* beside it, manual an instruction and a shutter); once it has dissolved
|
|
73
|
+
* into the spinner or the verdict mark there is nothing beside it and the
|
|
74
|
+
* stage centres: a ring that moves as the
|
|
75
|
+
* step advances is the glitch #VS-24 exists for. The uploading / processing
|
|
76
|
+
* spinner therefore dissolves in the ring's own seat at the left, with the
|
|
77
|
+
* right zone empty for the second it lasts.
|
|
78
|
+
* · The instruction takes whatever width is left and centres in it. On the
|
|
79
|
+
* 844 panel that is 437; on the 667 SE it is 172 beside a shutter, which
|
|
80
|
+
* wraps the manual line to five lines of H4 (104 tall) inside a 375 panel.
|
|
81
|
+
* · The SHUTTER sits at the right edge, where the thumb is on a phone held
|
|
82
|
+
* sideways: the same seat every native camera app gives it in landscape.
|
|
83
|
+
* Beside the ring would put it under the user's palm.
|
|
84
|
+
*
|
|
85
|
+
* The content column stops reserving the footer under the ring
|
|
86
|
+
* (ScreenLayout.css's block): with the reserve the ring had 328 to sit in;
|
|
87
|
+
* the tag itself goes, see below. The "Need more time" notice sits on the
|
|
88
|
+
* right zone's rail. Outside the query not one declaration
|
|
89
|
+
* exists. DEVIATIONS #F-39. */
|
|
90
|
+
@container pcs-screen ((orientation: landscape) and (max-height: 500px)) {
|
|
91
|
+
/* The root becomes the frame the zones are anchored in. Anchored, not a
|
|
92
|
+
* flex row: Core Lab's scene engine centres the IN-FLOW children of a row
|
|
93
|
+
* as a group and draws the stage from its own pinned box, which put the
|
|
94
|
+
* instruction across the ring on the canvas while the browser drew it
|
|
95
|
+
* right. Anchored boxes are the one layout the engine reproduces exactly
|
|
96
|
+
* (the tag, the capture strip and the notice already rely on it), and the
|
|
97
|
+
* browser lays them out the same way, so the canvas IS the SDK. */
|
|
98
|
+
.prizma-screen-layout__content--capture > .prizma-selfie-capture {
|
|
99
|
+
position: relative;
|
|
100
|
+
display: block;
|
|
101
|
+
width: 100%;
|
|
102
|
+
max-width: none;
|
|
103
|
+
height: 100%;
|
|
104
|
+
padding: 0;
|
|
105
|
+
/* The ring's measure, stated once: Core's own Capture / Selfie frame width
|
|
106
|
+
* (SelfieCapture.css caps the ROOT at 335 and the stage takes 100% of it;
|
|
107
|
+
* with the root now the full width the cap moves to the stage, same
|
|
108
|
+
* number, same source). A host that must fit the ring between its own
|
|
109
|
+
* bars overrides this one property (Core Lab does, `[data-pcs-safe]`). */
|
|
110
|
+
--pcs-ring: 335px; /* hardcoded — Core's Capture / Selfie frame width; not a token */
|
|
111
|
+
/* The instruction's box beside the ring: 320 at most (the width a two-line
|
|
112
|
+
* H4 instruction takes), less when the column has less, and on manual
|
|
113
|
+
* capture less the shutter's 112 rail at the right edge. */
|
|
114
|
+
--pcs-instruction: min(320px, calc(100% - var(--pcs-ring) - var(--prizma-spacing-24)));
|
|
115
|
+
/* Ring, Spacing/24, instruction: ONE pair, centred on the column. Round 2
|
|
116
|
+
* pinned the ring at the left edge and let the instruction float in the
|
|
117
|
+
* middle of whatever was left, which at 844 put the words 230 from the
|
|
118
|
+
* ring (Camila, 2026-10-23: "the face frame looks too separate from the
|
|
119
|
+
* feedback"). Still anchored boxes, not a flex row, for the canvas. */
|
|
120
|
+
--pcs-pair: calc(var(--pcs-ring) + var(--prizma-spacing-24) + var(--pcs-instruction));
|
|
121
|
+
--pcs-pair-left: calc((100% - var(--pcs-pair)) / 2);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* Manual capture: the pair centres in what is left of the shutter's rail. */
|
|
125
|
+
.prizma-screen-layout__content--capture > .prizma-selfie-capture:has(> .prizma-selfie-capture__shutter) {
|
|
126
|
+
--pcs-instruction: min(320px, calc(100% - var(--pcs-ring) - var(--prizma-spacing-24) - var(--prizma-icon-size-3xl) - 2 * var(--prizma-spacing-24)));
|
|
127
|
+
--pcs-pair-left: calc((100% - var(--prizma-icon-size-3xl) - 2 * var(--prizma-spacing-24) - var(--pcs-pair)) / 2);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* The ring: the pair's left edge, centred on the panel's height. */
|
|
131
|
+
.prizma-screen-layout__content--capture > .prizma-selfie-capture > .prizma-selfie-capture__stage {
|
|
132
|
+
position: absolute;
|
|
133
|
+
left: var(--pcs-pair-left);
|
|
134
|
+
top: calc(50% - var(--pcs-ring) / 2);
|
|
135
|
+
width: var(--pcs-ring);
|
|
136
|
+
height: var(--pcs-ring); /* the same measure, stated outright so an engine without aspect-ratio draws the square */
|
|
137
|
+
max-width: none;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* A stage with nothing beside it centres: uploading, processing and the
|
|
141
|
+
* success verdict have dissolved the ring into a spinner or a mark and
|
|
142
|
+
* carry no instruction, no shutter, so there is no second zone to hold
|
|
143
|
+
* (Camila, 2026-10-21: "it has space to be in the centre, so it should").
|
|
144
|
+
* The live capture states keep the ring at the left so it never moves
|
|
145
|
+
* between them; the dissolve is the one step where the stage changes
|
|
146
|
+
* anyway. */
|
|
147
|
+
.prizma-screen-layout__content--capture
|
|
148
|
+
> .prizma-selfie-capture:not(
|
|
149
|
+
:has(> .prizma-selfie-capture__feedback, > .prizma-selfie-capture__shutter, > .prizma-selfie-capture__status)
|
|
150
|
+
)
|
|
151
|
+
> .prizma-selfie-capture__stage {
|
|
152
|
+
left: calc(50% - var(--pcs-ring) / 2);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* The instruction (and overlay mode's status band): Spacing/24 right of the
|
|
156
|
+
* ring, in its own box, vertically centred on the ring's axis, the words
|
|
157
|
+
* starting at the box's left edge so they read as the ring's caption rather
|
|
158
|
+
* than as a second column. */
|
|
159
|
+
.prizma-screen-layout__content--capture > .prizma-selfie-capture > .prizma-selfie-capture__status,
|
|
160
|
+
.prizma-screen-layout__content--capture > .prizma-selfie-capture > .prizma-selfie-capture__feedback {
|
|
161
|
+
position: absolute;
|
|
162
|
+
top: 0;
|
|
163
|
+
bottom: 0;
|
|
164
|
+
left: calc(var(--pcs-pair-left) + var(--pcs-ring) + var(--prizma-spacing-24));
|
|
165
|
+
width: var(--pcs-instruction);
|
|
166
|
+
right: auto;
|
|
167
|
+
margin: 0;
|
|
168
|
+
max-width: none;
|
|
169
|
+
display: flex;
|
|
170
|
+
align-items: center;
|
|
171
|
+
justify-content: flex-start;
|
|
172
|
+
text-align: start;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* The shutter: right edge, centred on the panel's height. 64 is the strip's
|
|
176
|
+
* own measure (`--pcs-capture-chrome-space` reserves the same token). */
|
|
177
|
+
.prizma-screen-layout__content--capture > .prizma-selfie-capture > .prizma-selfie-capture__shutter {
|
|
178
|
+
position: absolute;
|
|
179
|
+
right: 0;
|
|
180
|
+
top: calc(50% - var(--prizma-icon-size-3xl) / 2);
|
|
181
|
+
width: var(--prizma-icon-size-3xl);
|
|
182
|
+
max-width: none;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* The verified tag goes on landscape capture screens (Camila, 2026-10-21:
|
|
186
|
+
* "somewhere at the bottom or not at all"). Bottom centre, its one seat, is
|
|
187
|
+
* where the ring's lower edge is: on the SE the ring spans 20 to 355 and the
|
|
188
|
+
* tag 329 to 359. Moving the ring off centre to clear it would put the ring
|
|
189
|
+
* in a different place on this screen than on the uploading one, and a
|
|
190
|
+
* feed-open capture screen already drops the client logo for the same
|
|
191
|
+
* reason (dense, 2026-08-18): the tag comes back on the very next screen. */
|
|
192
|
+
.prizma-screen-shell:has(> .prizma-screen-layout__content--capture) .prizma-screen-layout__footer {
|
|
193
|
+
display: none;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* The notice keeps the rail the tag used to reserve, in the right zone. */
|
|
197
|
+
.prizma-screen-shell .prizma-screen-layout__capture-notice {
|
|
198
|
+
left: 50%;
|
|
199
|
+
bottom: var(--prizma-spacing-16);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
53
203
|
/* ── Big panels: the ring grows to the column and the stack moves down ───────
|
|
54
204
|
* The mirror of the block above, and the capture counterpart of the tutorial's
|
|
55
205
|
* #F-36. On the 768 × 1024 iPad the column widens to 468 but the stack kept
|
package/dist/FormScreen.css
CHANGED
|
@@ -91,6 +91,41 @@
|
|
|
91
91
|
flex-shrink: 0;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
/* ── Short panels: a field stack that does not fit pans ──────────────────────
|
|
95
|
+
* The same decision archetype G's list took in #F-38, for archetype E. The
|
|
96
|
+
* stack is `flex: 1; min-height: 0`, so on a short panel it shrinks to what
|
|
97
|
+
* the title block and the CTA leave, and its rows, which keep their height,
|
|
98
|
+
* run straight on under the anchored CTA: on the closed iPhone Duo (678,
|
|
99
|
+
* measured 2026-10-29, the day the Duo presets opened to every module) eKYC's
|
|
100
|
+
* "Enter your details" drew Continue across its Date of Birth field and the
|
|
101
|
+
* empty-fields error painted its "This field is required" over the verified
|
|
102
|
+
* tag; Advanced Signature's accept screen lost its third required checkbox
|
|
103
|
+
* entirely on the open panel (626) while "Finish signing" showed enabled.
|
|
104
|
+
* The archetype already owns the answer as `scrollFields` (`--scroll`), opted
|
|
105
|
+
* into by the screens that know they are long (CURP, the consents, eKYB,
|
|
106
|
+
* the long forms, OCR review); a short panel is the same situation decided
|
|
107
|
+
* by the panel rather than the screen, so under 720 every stack takes the
|
|
108
|
+
* variant's declarations: the rows pan, Spacing/16 of air stays above the
|
|
109
|
+
* CTA, no scrollbar is drawn, and the title, the CTA and the tag hold still.
|
|
110
|
+
* Rows keep their intrinsic height for the same reason the variant's do
|
|
111
|
+
* (#QS-1). `--end` keeps hanging its rows off the bottom when they fit.
|
|
112
|
+
* Outside the query not one declaration exists. DEVIATIONS #F-40. */
|
|
113
|
+
@container pcs-screen (max-height: 720px) {
|
|
114
|
+
.prizma-form-screen__fields {
|
|
115
|
+
overflow-y: auto;
|
|
116
|
+
margin-bottom: var(--prizma-spacing-16);
|
|
117
|
+
scrollbar-width: none;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.prizma-form-screen__fields::-webkit-scrollbar {
|
|
121
|
+
display: none;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.prizma-form-screen__fields > * {
|
|
125
|
+
flex-shrink: 0;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
94
129
|
/* CTA column: primary, then the optional tertiary link below it. Core's
|
|
95
130
|
* `PrizmaButtonGroup` owns this primary → tertiary rhythm at Spacing/12, so the
|
|
96
131
|
* same value is used here rather than a new one (the archetype composes two
|
package/dist/IdCaptureLayout.css
CHANGED
|
@@ -312,3 +312,66 @@
|
|
|
312
312
|
.id-capture-on-surface .prizma-id-capture__encrypted {
|
|
313
313
|
color: var(--prizma-text-body-800-primary);
|
|
314
314
|
}
|
|
315
|
+
|
|
316
|
+
/* ── Short panels: the verdict still shrinks, the manual stage keeps its caption
|
|
317
|
+
* Two more rows for the 720 line (SHORT-PANELS.md), found the day the iPhone
|
|
318
|
+
* Duo presets opened to every module (2026-10-29), both on the open panel
|
|
319
|
+
* (626) and neither at 678 or above.
|
|
320
|
+
*
|
|
321
|
+
* (a) The result screens with a captured still (every error verdict, the
|
|
322
|
+
* success verdicts, Classification) run on archetype F, whose column pans
|
|
323
|
+
* under 720 (#F-37). The still is Core's `PrizmaIdCapture` in its filled
|
|
324
|
+
* state: 342 wide, its height from the variant's aspect, the encrypted row
|
|
325
|
+
* under it. At 626 the stack is 21 to 39px too tall, so the column panned and
|
|
326
|
+
* the still lost its bottom border and its caption, or the caption was
|
|
327
|
+
* squashed to a sliver (the row is a flex child with no floor). Step 1 of the
|
|
328
|
+
* order of concessions, the same mechanism as the vertical stage frame above:
|
|
329
|
+
* the still is the one part of the column that gives up height, its aspect
|
|
330
|
+
* ratio narrows the width to match, every other child keeps its height, and
|
|
331
|
+
* the caption stays a full row. With room to spare the still never shrinks.
|
|
332
|
+
* DEVIATIONS #IDC-33.
|
|
333
|
+
*
|
|
334
|
+
* (b) On the manual stages the strip carries the numbered tooltip above the
|
|
335
|
+
* shutter (`PrizmaCaptureManual`, absolute, `bottom: 100%` of the strip).
|
|
336
|
+
* The viewfinder column reserves the strip's footprint
|
|
337
|
+
* (`--pcs-capture-chrome-space`, ScreenLayout.css) but not the tooltip's, so
|
|
338
|
+
* on a panel short enough for the frame to sit flush on that reserve the
|
|
339
|
+
* tooltip landed on the "All data is encrypted" row under the frame. When the
|
|
340
|
+
* strip has a tooltip, the column reserves it too: the multiline Tooltip's
|
|
341
|
+
* two lines plus its Spacing/16 padding, plus the zone's Spacing/8 gap. The
|
|
342
|
+
* shortfall goes where this stylesheet already sends it, the frame. At 844
|
|
343
|
+
* the bottom band has that much slack and the frame would not move, but the
|
|
344
|
+
* rule is gated with the rest so the reference stays byte-identical.
|
|
345
|
+
* DEVIATIONS #IDC-34. */
|
|
346
|
+
@container pcs-screen (max-height: 720px) {
|
|
347
|
+
.id-capture-on-surface .prizma-screen-layout__content--centered > :not(.prizma-id-capture) {
|
|
348
|
+
flex-shrink: 0;
|
|
349
|
+
}
|
|
350
|
+
.id-capture-on-surface .prizma-screen-layout__content--centered > .prizma-id-capture {
|
|
351
|
+
flex: 0 1 auto;
|
|
352
|
+
min-height: 0;
|
|
353
|
+
}
|
|
354
|
+
.id-capture-on-surface .prizma-screen-layout__content--centered > .prizma-id-capture > :not(.prizma-id-capture__frame) {
|
|
355
|
+
flex-shrink: 0;
|
|
356
|
+
}
|
|
357
|
+
.id-capture-on-surface .prizma-screen-layout__content--centered > .prizma-id-capture > .prizma-id-capture__frame {
|
|
358
|
+
flex: 0 1 auto;
|
|
359
|
+
min-height: 0;
|
|
360
|
+
width: auto;
|
|
361
|
+
max-width: 100%;
|
|
362
|
+
/* The still's natural height at the column's width (the column is capped
|
|
363
|
+
* at 390 on any panel, less its two Spacing/24 gutters), so with room to
|
|
364
|
+
* spare nothing changes and under pressure it is the first to give. */
|
|
365
|
+
flex-basis: calc((min(100cqw, 390px) - 2 * var(--prizma-spacing-24)) * 220 / 350);
|
|
366
|
+
}
|
|
367
|
+
.id-capture-on-surface .prizma-screen-layout__content--centered > .prizma-id-capture--passport > .prizma-id-capture__frame {
|
|
368
|
+
flex-basis: calc((min(100cqw, 390px) - 2 * var(--prizma-spacing-24)) * 254 / 350);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.prizma-screen-shell:has(.prizma-screen-layout__capture-strip .prizma-capture-manual__tooltip-zone) .prizma-viewfinder__content {
|
|
372
|
+
padding-bottom: calc(
|
|
373
|
+
var(--pcs-capture-chrome-space) + var(--prizma-spacing-8) +
|
|
374
|
+
2 * var(--prizma-tooltip-m-line-height) + 2 * var(--prizma-spacing-16)
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/* Rotate to portrait — the prompt a capture screen shows on a phone held
|
|
2
|
+
* sideways (RotateToPortraitScreen.tsx, DEVIATIONS #F-42).
|
|
3
|
+
*
|
|
4
|
+
* ONLY what the foundation does not already own. The column, its centring,
|
|
5
|
+
* the glyph slot and its ink, the Title's own 16 / 12 rhythm and 420 cap all
|
|
6
|
+
* come from `ScreenLayout.css` and Core's Title. What is new here is the
|
|
7
|
+
* glyph's motion and the landscape seat of the column. Every value is a token
|
|
8
|
+
* except the bank's stroke weight, which is stated once and said so.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/* ── The live region wrapper ─────────────────────────────────────────────────
|
|
12
|
+
* Full width so Core's Title centres inside it exactly as it would as a direct
|
|
13
|
+
* child of the centred column (the Title is `width: 100%` capped at its own
|
|
14
|
+
* Title/Max-width and centres with `margin-inline: auto`). */
|
|
15
|
+
.prizma-rotate-to-portrait__status {
|
|
16
|
+
width: 100%;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* ── The mark: Title/Icon/Size, the status mark's box ────────────────────────
|
|
20
|
+
* Sits inside the foundation's `__glyph` row, which centres it and sets the
|
|
21
|
+
* ink (`__glyph--neutral` → Icon/Neutral/800). Two layers share the box: the
|
|
22
|
+
* turn (variant A) and the static icon (variant C), one shown at a time. */
|
|
23
|
+
.prizma-rotate-to-portrait__mark {
|
|
24
|
+
position: relative;
|
|
25
|
+
display: block;
|
|
26
|
+
width: var(--prizma-title-icon-size);
|
|
27
|
+
height: var(--prizma-title-icon-size);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.prizma-rotate-to-portrait__turn {
|
|
31
|
+
position: absolute;
|
|
32
|
+
inset: 0;
|
|
33
|
+
display: block;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* The arc layer and Core's `mobile` icon fill the box; the arc runs past the
|
|
37
|
+
* 24 grid on two sides (its radius is the phone's half diagonal plus the
|
|
38
|
+
* stroke), so the layer must not clip. The bank icon ships `width="24"`
|
|
39
|
+
* attributes; CSS sizes it to the box, as `__glyph > svg` does for the
|
|
40
|
+
* Wi-Fi mark. */
|
|
41
|
+
.prizma-rotate-to-portrait__turn > svg {
|
|
42
|
+
position: absolute;
|
|
43
|
+
inset: 0;
|
|
44
|
+
display: block;
|
|
45
|
+
width: 100%;
|
|
46
|
+
height: 100%;
|
|
47
|
+
overflow: visible;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* The phone turns about its own centre (the icon's 12,12). At rest it is the
|
|
51
|
+
* way the phone is held: top edge to the left, −90. */
|
|
52
|
+
.prizma-rotate-to-portrait__phone {
|
|
53
|
+
transform-origin: 50% 50%;
|
|
54
|
+
transform: rotate(-90deg);
|
|
55
|
+
animation: prizma-rotate-to-portrait-turn var(--prizma-motion-duration-loop) linear infinite;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* The arc the top edge travels, and the arrowhead where it lands. Drawn at
|
|
59
|
+
* the bank's own outline weight on the bank's 24 grid, so at Title/Icon/Size
|
|
60
|
+
* it reads as one stroke with the phone. Always the icon's own colour, never
|
|
61
|
+
* faded in or out (Camila, 2026-11-03: a colour that fades while the phone
|
|
62
|
+
* turns, and an arrowhead whose ink arrives late, is not the design). The arc
|
|
63
|
+
* is REVEALED by its dash, not by opacity; what is not drawn yet is hidden
|
|
64
|
+
* with `visibility`, which steps and never fades, and also hides the round
|
|
65
|
+
* cap a fully offset dash would otherwise show as a dot at the path's end. */
|
|
66
|
+
.prizma-rotate-to-portrait__arc-path,
|
|
67
|
+
.prizma-rotate-to-portrait__arc-head {
|
|
68
|
+
stroke: currentColor;
|
|
69
|
+
stroke-width: 1.8; /* hardcoded — the icon bank's outline stroke on its 24 grid (core/icons/bank); not a token */
|
|
70
|
+
stroke-linecap: round;
|
|
71
|
+
stroke-linejoin: round;
|
|
72
|
+
visibility: hidden;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.prizma-rotate-to-portrait__arc-path {
|
|
76
|
+
stroke-dasharray: 100;
|
|
77
|
+
stroke-dashoffset: 100;
|
|
78
|
+
animation: prizma-rotate-to-portrait-arc var(--prizma-motion-duration-loop) linear infinite;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.prizma-rotate-to-portrait__arc-head {
|
|
82
|
+
animation: prizma-rotate-to-portrait-head var(--prizma-motion-duration-loop) linear infinite;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* Held the other way (top edge to the right, +90): the phone starts there and
|
|
86
|
+
* the arc mirrors about the box's centre, so the glyph turns the way the
|
|
87
|
+
* person has to. */
|
|
88
|
+
.prizma-rotate-to-portrait__mark--top-right .prizma-rotate-to-portrait__phone {
|
|
89
|
+
transform: rotate(90deg);
|
|
90
|
+
animation-name: prizma-rotate-to-portrait-turn-from-right;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.prizma-rotate-to-portrait__mark--top-right .prizma-rotate-to-portrait__arc {
|
|
94
|
+
transform: scaleX(-1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* One cycle is Motion/Duration/Loop (3200, the ID tutorial illustration's
|
|
98
|
+
* loop): hold at the held angle, turn on Easing/Standard while the arc draws
|
|
99
|
+
* under it, hold upright with the arrowhead on, then start again on a cut.
|
|
100
|
+
* Nothing fades: the phone keeps its ink the whole way, the arc appears as it
|
|
101
|
+
* is drawn and the arrowhead the moment the arc reaches it (Camila,
|
|
102
|
+
* 2026-11-03). The turn's percentages are the playground's, measured as the
|
|
103
|
+
* read Camila picked (round 2, 2026-10-29); the fade-out that used to mask
|
|
104
|
+
* the loop's reset is gone with the rest of the fades. */
|
|
105
|
+
@keyframes prizma-rotate-to-portrait-turn {
|
|
106
|
+
0%, 15% { transform: rotate(-90deg); animation-timing-function: var(--prizma-motion-easing-standard); }
|
|
107
|
+
55%, 100% { transform: rotate(0deg); }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@keyframes prizma-rotate-to-portrait-turn-from-right {
|
|
111
|
+
0%, 15% { transform: rotate(90deg); animation-timing-function: var(--prizma-motion-easing-standard); }
|
|
112
|
+
55%, 100% { transform: rotate(0deg); }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@keyframes prizma-rotate-to-portrait-arc {
|
|
116
|
+
0%, 14.9% { stroke-dashoffset: 100; visibility: hidden; }
|
|
117
|
+
15% { stroke-dashoffset: 100; visibility: visible; animation-timing-function: var(--prizma-motion-easing-standard); }
|
|
118
|
+
55%, 100% { stroke-dashoffset: 0; visibility: visible; }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@keyframes prizma-rotate-to-portrait-head {
|
|
122
|
+
0%, 54.9% { visibility: hidden; }
|
|
123
|
+
55%, 100% { visibility: visible; }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* ── Reduced motion: variant C ───────────────────────────────────────────────
|
|
127
|
+
* Core's static `rotate-phone` bank icon says the same thing without moving.
|
|
128
|
+
* Same media query every Core component with motion uses (Button, Capture
|
|
129
|
+
* manual, the ID feedback illustration). The static icon is a direct child of
|
|
130
|
+
* the mark, sized to the box like the turn. */
|
|
131
|
+
.prizma-rotate-to-portrait__static {
|
|
132
|
+
display: none;
|
|
133
|
+
width: 100%;
|
|
134
|
+
height: 100%;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@media (prefers-reduced-motion: reduce) {
|
|
138
|
+
.prizma-rotate-to-portrait__turn {
|
|
139
|
+
display: none;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.prizma-rotate-to-portrait__static {
|
|
143
|
+
display: block;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* ── Landscape phones: the column's seat ─────────────────────────────────────
|
|
148
|
+
* The same line as every landscape rule (#F-39, LANDSCAPE.md). In portrait the
|
|
149
|
+
* column wears the foundation's `--no-nav` reserve (status bar + Spacing/24)
|
|
150
|
+
* and nothing is declared here. Sideways, the column takes the seat the
|
|
151
|
+
* result and tutorial columns take: Spacing/8 under the status-bar reserve
|
|
152
|
+
* (47 by default, the host's value otherwise) and Spacing/16 off the bottom,
|
|
153
|
+
* the playground's measured values. The Title then centres in what is left:
|
|
154
|
+
* glyph 40, Spacing/16, H2 28, Spacing/12, two lines of H5 37 = 133 in the
|
|
155
|
+
* 375 SE's 304. (0,2,0) so it outranks `--no-nav`'s own (0,1,0) regardless of
|
|
156
|
+
* import order. Outside the query not one declaration exists. */
|
|
157
|
+
@container pcs-screen ((orientation: landscape) and (max-height: 500px)) {
|
|
158
|
+
.prizma-screen-shell .prizma-rotate-to-portrait__content {
|
|
159
|
+
padding-top: calc(var(--pcs-status-bar, 47px) + var(--prizma-spacing-8));
|
|
160
|
+
padding-bottom: var(--prizma-spacing-16);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type PrizmaScreenShellProps } from './ScreenShell';
|
|
3
|
+
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
4
|
+
import type { RotateToPortraitStrings } from './RotateToPortraitStrings';
|
|
5
|
+
import './ScreenLayout.css';
|
|
6
|
+
import './RotateToPortraitScreen.css';
|
|
7
|
+
/**
|
|
8
|
+
* Where the phone's TOP edge points while it is held sideways. The SDK reads
|
|
9
|
+
* the device angle (−90 or +90) and the glyph turns the phone back upright
|
|
10
|
+
* from that side, so it always turns the way the person has to; the arc
|
|
11
|
+
* beside it mirrors with it (playground DECISION.md, round 2).
|
|
12
|
+
*/
|
|
13
|
+
export type RotateToPortraitTopEdge = 'left' | 'right';
|
|
14
|
+
export interface RotateToPortraitScreenProps extends Omit<PrizmaScreenShellProps, 'dark' | 'title' | 'children'> {
|
|
15
|
+
/** The prompt's copy. Shared by every capture module, see the contract. */
|
|
16
|
+
strings: RotateToPortraitStrings;
|
|
17
|
+
/** Which side the phone's top edge is on. Default `left`. */
|
|
18
|
+
topEdge?: RotateToPortraitTopEdge;
|
|
19
|
+
screenId?: string;
|
|
20
|
+
overrides?: PrizmaScreenOverrides;
|
|
21
|
+
/** Accepted for parity with every other screen; this one has no action.
|
|
22
|
+
* Turning the phone is the action, and the camera reopens on its own. */
|
|
23
|
+
onAction?: PrizmaScreenActionHandler;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Rotate to portrait — the prompt a capture screen shows on a phone held
|
|
27
|
+
* sideways. Shared by every capture module; Face Capture is the first consumer.
|
|
28
|
+
*
|
|
29
|
+
* Capture screens ALWAYS stay portrait (Camila, 2026-11-03). While the person
|
|
30
|
+
* is on one (every `capturing-*` state, the extend-time offer, manual) and the
|
|
31
|
+
* phone is held sideways, the SDK closes the camera and shows this screen in
|
|
32
|
+
* its place; the camera reopens on its own when the phone is upright again.
|
|
33
|
+
* This is the "essential" exception of WCAG 2.1 SC 1.3.4 Orientation the
|
|
34
|
+
* accessibility auditors agreed to on 2026-10-26 (precedent: Bicycle Health
|
|
35
|
+
* accepted portrait-only capture). The sideways capture layout in
|
|
36
|
+
* `FaceCaptureLayout.css` (#F-39) stays as the longer-term full-compliance
|
|
37
|
+
* track and is never reached while this screen is shown.
|
|
38
|
+
*
|
|
39
|
+
* Anatomy: archetype C (Processing, GUIDELINES.md §6-C) under the landscape
|
|
40
|
+
* rules of `LANDSCAPE.md`: no logo nav, no verified tag, the status-bar
|
|
41
|
+
* reserve kept, the Title centred in what is left of the height, Core's own
|
|
42
|
+
* 420 max. Camera closed, so it is an ordinary screen on the app theme, like
|
|
43
|
+
* uploading (the 2026-08-18 rule): no theme pin. The screen is only ever shown
|
|
44
|
+
* in a landscape shell, but it renders the same centred stack in the portrait
|
|
45
|
+
* reference frame, which is how Latest designs shows every screen in its grid,
|
|
46
|
+
* so nothing here hides outside the landscape query.
|
|
47
|
+
*
|
|
48
|
+
* The glyph is variant A of the playground
|
|
49
|
+
* (`artefactos/playgrounds/2026-10-29__rotate-to-portrait-prompt`): Core's
|
|
50
|
+
* `mobile` bank icon turning about its centre from the way the phone is held
|
|
51
|
+
* to upright, with the arc its top edge travels drawn beside it and the
|
|
52
|
+
* arrowhead landing where the top ends up, at Title/Icon/Size (40, the status
|
|
53
|
+
* mark's box), Icon/Neutral/800, on Core's loop duration and standard easing.
|
|
54
|
+
* It rides the foundation's `__glyph` slot above the Title, the same seat the
|
|
55
|
+
* Wi-Fi mark takes on every noConnection screen (DEVIATIONS #10), because
|
|
56
|
+
* Core's `PrizmaTitle.icon` allowlist is `status | spinner | none`. Under
|
|
57
|
+
* `prefers-reduced-motion: reduce` it is Core's static `rotate-phone` icon
|
|
58
|
+
* (variant C). The glyph is decorative; the Title is a polite live region so
|
|
59
|
+
* a screen reader hears the headline when the prompt appears.
|
|
60
|
+
*
|
|
61
|
+
* No button: turning the phone is the action. DEVIATIONS #F-42.
|
|
62
|
+
*/
|
|
63
|
+
export declare const RotateToPortraitScreen: React.ForwardRefExoticComponent<RotateToPortraitScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
64
|
+
export default RotateToPortraitScreen;
|