@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
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import { IconMobile, IconRotatePhone } from '@incodetech/prizma-core-icons';
|
|
5
|
+
import { PrizmaTitle } from '@incodetech/prizma-core-web/title';
|
|
6
|
+
import { PrizmaScreenShell } from './ScreenShell';
|
|
7
|
+
import './ScreenLayout.css';
|
|
8
|
+
import './RotateToPortraitScreen.css';
|
|
9
|
+
/**
|
|
10
|
+
* Rotate to portrait — the prompt a capture screen shows on a phone held
|
|
11
|
+
* sideways. Shared by every capture module; Face Capture is the first consumer.
|
|
12
|
+
*
|
|
13
|
+
* Capture screens ALWAYS stay portrait (Camila, 2026-11-03). While the person
|
|
14
|
+
* is on one (every `capturing-*` state, the extend-time offer, manual) and the
|
|
15
|
+
* phone is held sideways, the SDK closes the camera and shows this screen in
|
|
16
|
+
* its place; the camera reopens on its own when the phone is upright again.
|
|
17
|
+
* This is the "essential" exception of WCAG 2.1 SC 1.3.4 Orientation the
|
|
18
|
+
* accessibility auditors agreed to on 2026-10-26 (precedent: Bicycle Health
|
|
19
|
+
* accepted portrait-only capture). The sideways capture layout in
|
|
20
|
+
* `FaceCaptureLayout.css` (#F-39) stays as the longer-term full-compliance
|
|
21
|
+
* track and is never reached while this screen is shown.
|
|
22
|
+
*
|
|
23
|
+
* Anatomy: archetype C (Processing, GUIDELINES.md §6-C) under the landscape
|
|
24
|
+
* rules of `LANDSCAPE.md`: no logo nav, no verified tag, the status-bar
|
|
25
|
+
* reserve kept, the Title centred in what is left of the height, Core's own
|
|
26
|
+
* 420 max. Camera closed, so it is an ordinary screen on the app theme, like
|
|
27
|
+
* uploading (the 2026-08-18 rule): no theme pin. The screen is only ever shown
|
|
28
|
+
* in a landscape shell, but it renders the same centred stack in the portrait
|
|
29
|
+
* reference frame, which is how Latest designs shows every screen in its grid,
|
|
30
|
+
* so nothing here hides outside the landscape query.
|
|
31
|
+
*
|
|
32
|
+
* The glyph is variant A of the playground
|
|
33
|
+
* (`artefactos/playgrounds/2026-10-29__rotate-to-portrait-prompt`): Core's
|
|
34
|
+
* `mobile` bank icon turning about its centre from the way the phone is held
|
|
35
|
+
* to upright, with the arc its top edge travels drawn beside it and the
|
|
36
|
+
* arrowhead landing where the top ends up, at Title/Icon/Size (40, the status
|
|
37
|
+
* mark's box), Icon/Neutral/800, on Core's loop duration and standard easing.
|
|
38
|
+
* It rides the foundation's `__glyph` slot above the Title, the same seat the
|
|
39
|
+
* Wi-Fi mark takes on every noConnection screen (DEVIATIONS #10), because
|
|
40
|
+
* Core's `PrizmaTitle.icon` allowlist is `status | spinner | none`. Under
|
|
41
|
+
* `prefers-reduced-motion: reduce` it is Core's static `rotate-phone` icon
|
|
42
|
+
* (variant C). The glyph is decorative; the Title is a polite live region so
|
|
43
|
+
* a screen reader hears the headline when the prompt appears.
|
|
44
|
+
*
|
|
45
|
+
* No button: turning the phone is the action. DEVIATIONS #F-42.
|
|
46
|
+
*/
|
|
47
|
+
export const RotateToPortraitScreen = forwardRef(({ strings, topEdge = 'left', screenId = 'rotate-to-portrait', overrides,
|
|
48
|
+
// No CTA here, so nothing ever fires it; destructured so it stays off
|
|
49
|
+
// the shell's DOM node, like `screenId`.
|
|
50
|
+
onAction, className, ...shell }, ref) => {
|
|
51
|
+
void screenId;
|
|
52
|
+
void onAction;
|
|
53
|
+
const left = overrides?.align === 'left';
|
|
54
|
+
return (_jsx(PrizmaScreenShell, { ref: ref, className: ['prizma-rotate-to-portrait', className].filter(Boolean).join(' '), ...shell, children: _jsxs("div", { className: "prizma-screen-layout__content prizma-screen-layout__content--centered prizma-screen-layout__content--no-nav prizma-rotate-to-portrait__content", children: [_jsx("span", { className: [
|
|
55
|
+
'prizma-screen-layout__glyph',
|
|
56
|
+
'prizma-screen-layout__glyph--neutral',
|
|
57
|
+
left ? 'prizma-screen-layout__glyph--left' : '',
|
|
58
|
+
]
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.join(' '), "aria-hidden": "true", children: _jsxs("span", { className: [
|
|
61
|
+
'prizma-rotate-to-portrait__mark',
|
|
62
|
+
topEdge === 'right' ? 'prizma-rotate-to-portrait__mark--top-right' : '',
|
|
63
|
+
]
|
|
64
|
+
.filter(Boolean)
|
|
65
|
+
.join(' '), children: [_jsxs("span", { className: "prizma-rotate-to-portrait__turn", children: [_jsxs("svg", { className: "prizma-rotate-to-portrait__arc", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("path", { className: "prizma-rotate-to-portrait__arc-path", pathLength: 100, d: "M -2.5 12 A 14.5 14.5 0 0 1 12 -2.5" }), _jsx("path", { className: "prizma-rotate-to-portrait__arc-head", d: "M 9.7 -4.9 L 12 -2.5 L 9.7 -0.1" })] }), _jsx(IconMobile, { className: "prizma-rotate-to-portrait__phone" })] }), _jsx(IconRotatePhone, { className: "prizma-rotate-to-portrait__static" })] }) }), _jsx("div", { className: "prizma-rotate-to-portrait__status", role: "status", "aria-live": "polite", children: _jsx(PrizmaTitle, { variant: left ? 'left' : 'centered', title: strings.title, showSubtitle: Boolean(strings.subtitle), subtitle: strings.subtitle, icon: { type: 'none' } }) })] }) }));
|
|
66
|
+
});
|
|
67
|
+
RotateToPortraitScreen.displayName = 'RotateToPortraitScreen';
|
|
68
|
+
export default RotateToPortraitScreen;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface RotateToPortraitStrings {
|
|
2
|
+
/** H2 — "Turn your phone upright". */
|
|
3
|
+
title: string;
|
|
4
|
+
/** H5 — "Hold it vertically to continue with your verification."
|
|
5
|
+
* Optional: a host that only wants the headline omits it and the Title
|
|
6
|
+
* renders alone, Core's own `showSubtitle` toggle. */
|
|
7
|
+
subtitle?: string;
|
|
8
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Rotate to portrait — copy contract.
|
|
2
|
+
//
|
|
3
|
+
// NOT a module. The one prompt every capture module shows while the phone is
|
|
4
|
+
// held sideways (Face Capture today; ID Capture, Document Capture and Video
|
|
5
|
+
// Selfie as they adopt it). Capture screens stay portrait: this screen is one
|
|
6
|
+
// step before them, shown while the phone is sideways, and the camera opens
|
|
7
|
+
// once the phone is upright, so there is no button and no action in the contract
|
|
8
|
+
// (Camila, 2026-11-03; the auditors' WCAG 2.1 SC 1.3.4 reading of 2026-10-26,
|
|
9
|
+
// "essential" exception for the capture screens).
|
|
10
|
+
//
|
|
11
|
+
// The copy is module-agnostic on purpose: one sentence pair serves every
|
|
12
|
+
// capture module, so a host writes it once. Same rule as every other contract
|
|
13
|
+
// here: all copy via props, no hardcoded English (GUIDELINES.md §9).
|
|
14
|
+
//
|
|
15
|
+
// ⚠️ The English below the type is PROPOSED copy from the playground
|
|
16
|
+
// (artefactos/playgrounds/2026-10-29__rotate-to-portrait-prompt). Before this
|
|
17
|
+
// screen ships in the SDK the two strings must come from the SDK's own
|
|
18
|
+
// localization tables; nothing here is hand-translated, and no language is
|
|
19
|
+
// added to this file.
|
|
20
|
+
export {};
|
package/dist/ScreenLayout.css
CHANGED
|
@@ -829,6 +829,206 @@
|
|
|
829
829
|
}
|
|
830
830
|
}
|
|
831
831
|
|
|
832
|
+
/* ── Landscape phones: the stack keeps its order, the ring changes axis ──────
|
|
833
|
+
* WCAG 2.1 SC 1.3.4 Orientation (AA) asks every screen to work held sideways,
|
|
834
|
+
* and a phone held sideways is 375 to 440 tall (the phone catalog rotated:
|
|
835
|
+
* iPhone SE 667 x 375, the 844 x 390 reference, Large Android 915 x 412,
|
|
836
|
+
* Pro Max 956 x 440). Measured against the stacks the short-panel rules fit
|
|
837
|
+
* into 626: a capture screen needs ~557, a tutorial ~700. So two things give
|
|
838
|
+
* ground that no short panel asked for: the tutorial loses its illustration,
|
|
839
|
+
* and the capture screen turns its ring and its instruction side by side
|
|
840
|
+
* (FaceCaptureLayout.css). Everything else keeps the portrait order, title
|
|
841
|
+
* over copy over button, compacted (Camila, 2026-10-21: top-down, not side by
|
|
842
|
+
* side; the tag always centred; the button closer to the bottom).
|
|
843
|
+
*
|
|
844
|
+
* THE LINE is the shell's own shape, never the browser viewport (a 390 shell
|
|
845
|
+
* in a 1400 window is portrait): `orientation: landscape` with a 500 height
|
|
846
|
+
* cap. The cap keeps the rules off tablets, desktop windows and the iPhone
|
|
847
|
+
* Duo open full screen (626), which already have their own answers (#21,
|
|
848
|
+
* #VS-32, #F-37) and are wider than they are tall. 500 has slack above the
|
|
849
|
+
* 440 ceiling and under the 626 floor. Every rule below lives inside the one
|
|
850
|
+
* query, so outside it not one declaration exists and the portrait render is
|
|
851
|
+
* byte-identical. Exploration `face-capture-landscape` (Camila, 2026-10-20);
|
|
852
|
+
* the developer-facing list is LANDSCAPE.md. DEVIATIONS #F-39.
|
|
853
|
+
*
|
|
854
|
+
* What never changes, in either orientation: the H2, the CTA, the live
|
|
855
|
+
* instruction and where it lives (#12/#14), the status and verdict copy, and
|
|
856
|
+
* the tag's seat: bottom centre, Spacing/16 up, on every screen that has one. */
|
|
857
|
+
@container pcs-screen ((orientation: landscape) and (max-height: 500px)) {
|
|
858
|
+
/* The status-bar reserve STAYS (`--pcs-status-bar`, 47 by default, the
|
|
859
|
+
* host's own value otherwise). Round 2 had zeroed it on the argument that an
|
|
860
|
+
* iPhone draws no status bar in landscape; Camila's QA of the canvas
|
|
861
|
+
* (2026-10-21) found the result screens' status mark sitting in the system
|
|
862
|
+
* bar's row (the Lab's pills at 25 to 35, Elena's landscape reference keeps
|
|
863
|
+
* a 54 bar), which no device would allow. The reserve is the one line every
|
|
864
|
+
* screen already respects in portrait, so it is kept rather than replaced
|
|
865
|
+
* by a landscape-only offset. The capture screens are unaffected: their nav
|
|
866
|
+
* is hidden below and the ring is placed on the panel's height. */
|
|
867
|
+
|
|
868
|
+
/* Capture screens drop the nav row entirely. It is already reserved and
|
|
869
|
+
* empty on a feed-open capture screen (the 2026-08-18 header rule), and a
|
|
870
|
+
* 335 ring plus the 56 row does not fit in 375. A client logo opt-in goes
|
|
871
|
+
* with it in landscape: there is no row to hold it. */
|
|
872
|
+
.prizma-screen-shell:has(> .prizma-screen-layout__content--capture) > .prizma-screen-nav {
|
|
873
|
+
display: none;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/* …and the capture column stops reserving the footer under the ring: with
|
|
877
|
+
* the reserve the ring had 328 to sit in. (0,3,0), the reserve's own
|
|
878
|
+
* specificity, later in the file. FaceCaptureLayout.css says what happens
|
|
879
|
+
* to the tag there. */
|
|
880
|
+
.prizma-screen-shell .prizma-screen-layout__content.prizma-screen-layout__content--capture {
|
|
881
|
+
padding-bottom: 0;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/* ARCHETYPE A (tutorial). The illustration goes: it is the one element that
|
|
885
|
+
* carries no task information (step 1 of the order), and in landscape it is
|
|
886
|
+
* also the only one that cannot fit above a title block and a CTA at any
|
|
887
|
+
* size that still reads (Camila, 2026-10-21: "remove it to have more space,
|
|
888
|
+
* it's not adding essential information"). Its slot stays as the flexible
|
|
889
|
+
* middle, so the band keeps sitting at the bottom of the column, above the
|
|
890
|
+
* tag, where the portrait has it; the title block stays under the logo nav.
|
|
891
|
+
* Measured on the SE (375): nav 56, title block 77, disclaimer and CTA 105,
|
|
892
|
+
* the tag's reserve 62, Spacing/16 twice: 316. The disclaimer fit, and
|
|
893
|
+
* stayed until 2026-11-03, when Camila took it off the landscape tutorial
|
|
894
|
+
* as well (below): with the art gone the line between the subtitle and the
|
|
895
|
+
* CTA read as a second subtitle, and the task is in the title block.
|
|
896
|
+
* Addressed by the archetype's own `--tutorial` class (TutorialScreen.tsx),
|
|
897
|
+
* not by `:has()` on the illustration slot: Core Lab's converter drops
|
|
898
|
+
* hidden subtrees before the scene is laid out, so a rule that needed the
|
|
899
|
+
* hidden art to match would vanish on the canvas. */
|
|
900
|
+
.prizma-screen-shell .prizma-screen-layout__content--tutorial {
|
|
901
|
+
/* The logo nav is gone in landscape (below), so the column reserves the
|
|
902
|
+
* status bar itself, Spacing/8 under it like the result screens. */
|
|
903
|
+
padding-top: calc(var(--pcs-status-bar, 47px) + var(--prizma-spacing-8));
|
|
904
|
+
/* The column centres its children (the band below is the one that is
|
|
905
|
+
* narrower than the column). `align-items` on the parent rather than
|
|
906
|
+
* `align-self` or `margin-inline: auto` on the band: Core Lab's converter
|
|
907
|
+
* reads a flex container's alignment and ignores per-child margins and
|
|
908
|
+
* `align-self`, so the first take drew the 420 band at the left edge on
|
|
909
|
+
* the canvas while the browser centred it (Camila, 2026-10-21). */
|
|
910
|
+
align-items: center;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/* Every other child keeps the full column: `align-items: center` would
|
|
914
|
+
* otherwise shrink the title block to its content. */
|
|
915
|
+
.prizma-screen-layout__content--tutorial > :not(.prizma-screen-layout__band) {
|
|
916
|
+
width: 100%;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.prizma-screen-layout__content--tutorial > .prizma-screen-layout__flex > [class*='prizma-illustration-'] {
|
|
920
|
+
display: none;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
/* The disclaimer goes with the art (Camila, 2026-11-03): title, subtitle,
|
|
924
|
+
* CTA. Portrait keeps it; outside the query this rule does not exist. */
|
|
925
|
+
.prizma-screen-layout__content--tutorial > .prizma-screen-layout__band > .prizma-disclaimer {
|
|
926
|
+
display: none;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
/* The slot that held the art keeps only its flexible height, not its
|
|
930
|
+
* Spacing/16 padding above and below: with the illustration gone those 32
|
|
931
|
+
* are empty, and on the SE they were what pushed the CTA onto the tag once
|
|
932
|
+
* the status bar came back (QA 2026-10-21). SE budget: nav 91, Spacing/16,
|
|
933
|
+
* title block 76, band 109, the tag's reserve 62: 354 of 375. */
|
|
934
|
+
.prizma-screen-shell .prizma-screen-layout__content--tutorial > .prizma-screen-layout__flex {
|
|
935
|
+
padding-block: 0;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/* The actions take Elena's landscape column: 420, centred (Core Lab
|
|
939
|
+
* recipes, landscape, read off the Document Capture reference 6701:8042).
|
|
940
|
+
* A CTA stretched across 796 reads as a bar, not a button; 420 is the
|
|
941
|
+
* Title's own max width, so the axis is one. The band's tag is anchored to
|
|
942
|
+
* the shell and already centres. */
|
|
943
|
+
/* (0,3,0) on purpose: Core Lab's device CSS caps `.prizma-screen-layout__band`
|
|
944
|
+
* at the panel's column with a (0,2,0) rule declared later, and at 844 that
|
|
945
|
+
* read as "no cap" on the canvas while the browser kept 420. */
|
|
946
|
+
.prizma-screen-shell .prizma-screen-layout__content--tutorial > .prizma-screen-layout__band {
|
|
947
|
+
width: 100%;
|
|
948
|
+
max-width: 420px; /* hardcoded — the actions column of Elena's landscape reference, equal to Core's Title max width */
|
|
949
|
+
gap: var(--prizma-spacing-8); /* Elena's first concession, the same rhythm as the result band below */
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
/* ARCHETYPE F (result with a CTA band). The logo nav goes instead of the
|
|
953
|
+
* status mark: the mark is the one thing that tells a warning from a
|
|
954
|
+
* failure, the logo is the client's presence and comes back on the next
|
|
955
|
+
* screen (Camila, 2026-10-21: remove the logo or the icon, keep the text,
|
|
956
|
+
* bring the button down). The title block centres in what is left above the
|
|
957
|
+
* band; the band keeps its portrait seat at the bottom, above the tag, with
|
|
958
|
+
* #F-37's compact rhythm already in force under 720. Measured on the SE:
|
|
959
|
+
* title block with its mark 153, band 101, the tag's reserve 62, Spacing/16:
|
|
960
|
+
* 332 in 375. The genericErrors family has no nav to begin with. */
|
|
961
|
+
.prizma-screen-shell:has(> .prizma-screen-layout__band--result) > .prizma-screen-nav {
|
|
962
|
+
display: none;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/* The title block sits at a FIXED offset under the status bar and the band
|
|
966
|
+
* at the bottom: Spacing/8 under the reserve clears the bar on both frames
|
|
967
|
+
* (mark at 55 with 47; Elena's bar ends at 54). Not `safe center`: the
|
|
968
|
+
* portrait column centres the title block in the free height, which on the
|
|
969
|
+
* SE left the mark 2.9 px inside the bar and 12.1 when the subtitle wrapped,
|
|
970
|
+
* and Core Lab's converter does not centre a column's children at all, so
|
|
971
|
+
* the canvas and the browser disagreed about where the mark was. A fixed
|
|
972
|
+
* seat is the same on both. SE budget, worst case (two-line subtitle):
|
|
973
|
+
* 55 + 132 + 16 + 109 + 62 = 374 of 375, with the band's gap conceded
|
|
974
|
+
* below. */
|
|
975
|
+
.prizma-screen-shell:has(> .prizma-screen-layout__band--result) > .prizma-screen-layout__content {
|
|
976
|
+
padding-top: calc(var(--pcs-status-bar, 47px) + var(--prizma-spacing-8));
|
|
977
|
+
justify-content: flex-start;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/* Same 420 column for the result band, centred. The band stays full width
|
|
981
|
+
* and centres its own rows (disclaimer, CTAs, extra content), each capped
|
|
982
|
+
* at 420: `align-items` on a flex column is what Core Lab's converter reads,
|
|
983
|
+
* while `margin-inline: auto` on the band, or `align-items` on the shell
|
|
984
|
+
* (whose anchored footer and tag it lays out by hand), centred in the
|
|
985
|
+
* browser and pinned the band left on the canvas (Camila, 2026-10-21).
|
|
986
|
+
* (0,3,0) for the same reason as the tutorial band above. */
|
|
987
|
+
.prizma-screen-shell:has(> .prizma-screen-layout__band--result) > .prizma-screen-layout__band--result {
|
|
988
|
+
width: 100%;
|
|
989
|
+
align-items: center;
|
|
990
|
+
box-sizing: border-box;
|
|
991
|
+
/* Elena's first concession (Core Lab recipes, landscape): gaps 16 to 8
|
|
992
|
+
* before anything else goes. It is what keeps the two-line result stack
|
|
993
|
+
* inside the 375 SE under the restored status bar. */
|
|
994
|
+
gap: var(--prizma-spacing-8);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
.prizma-screen-shell:has(> .prizma-screen-layout__band--result) > .prizma-screen-layout__band--result > * {
|
|
998
|
+
width: 100%;
|
|
999
|
+
max-width: 420px; /* hardcoded — Elena's actions column, equal to Core's Title max width */
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
/* NO LOGO, NO TAG on any landscape screen (Camila, 2026-10-23: "they take
|
|
1003
|
+
* up space that could be used by the content"). The nav row (the client
|
|
1004
|
+
* logo's seat) and the verified tag go on every family; the capture screens
|
|
1005
|
+
* had already dropped both. The columns that reserved the tag's 62 at the
|
|
1006
|
+
* bottom keep Spacing/16 instead, and the result band sits Spacing/16 off
|
|
1007
|
+
* the bottom; the capture column keeps its 0 so the ring's centre does not
|
|
1008
|
+
* move. The status bar stays reserved by the columns themselves. */
|
|
1009
|
+
.prizma-screen-shell > .prizma-screen-nav,
|
|
1010
|
+
.prizma-screen-shell .prizma-screen-layout__footer,
|
|
1011
|
+
.prizma-screen-shell .prizma-screen-layout__band__tag {
|
|
1012
|
+
display: none;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
.prizma-screen-shell:has(.prizma-screen-layout__band__tag) .prizma-screen-layout__content:not(.prizma-screen-layout__content--capture) {
|
|
1016
|
+
padding-bottom: var(--prizma-spacing-16);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
.prizma-screen-shell:has(> .prizma-screen-layout__band--result) > .prizma-screen-layout__band--result {
|
|
1020
|
+
margin-bottom: var(--prizma-spacing-16);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/* The band's disclaimer ("2 attempts remaining", "Stay still…") stays on
|
|
1024
|
+
* one line: in the 420 column every disclaimer the module ships fits, and
|
|
1025
|
+
* Core Lab's converter wrapped it to its first word otherwise (Camila,
|
|
1026
|
+
* 2026-10-23: "remaining attempts should always be in one line"). */
|
|
1027
|
+
.prizma-screen-layout__band .prizma-disclaimer__text {
|
|
1028
|
+
white-space: nowrap;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
832
1032
|
/* ── Anchored-chrome layering ─────────────────────────────────────────────────
|
|
833
1033
|
* The camera HUD bands lift themselves to `z-index: 1` so their copy paints
|
|
834
1034
|
* above `PrizmaIdCapture`'s scrim (an absolutely positioned box-shadow that
|
package/dist/ScreenShell.css
CHANGED
|
@@ -25,6 +25,19 @@
|
|
|
25
25
|
* layout paint` does both without forcing a composited layer the way
|
|
26
26
|
* `transform` would. */
|
|
27
27
|
contain: layout paint;
|
|
28
|
+
/* And it is the WINDOW Core's presenters size their overlays to. The Modal
|
|
29
|
+
* and Bottom sheet presenters draw their scrim `position: fixed` with
|
|
30
|
+
* `height: var(--prizma-overlay-height, 100dvh)` and pin the panel to the
|
|
31
|
+
* scrim's bottom, so a host whose fixed children land inside a box smaller
|
|
32
|
+
* than the viewport has to say so. Unsaid, the scrim inside this shell was
|
|
33
|
+
* the browser's height and the sheet sat at the browser's bottom edge, below
|
|
34
|
+
* the frame: on the closed iPhone Duo (678) Qualified Signature's certificate
|
|
35
|
+
* popups showed only the sheet's title peeking in at the bottom, on the open
|
|
36
|
+
* panel (626) nothing but scrim (measured 2026-10-29). 100% of the shell is
|
|
37
|
+
* the window, whatever the panel; on a real device the shell IS the viewport
|
|
38
|
+
* and the value reads the same. DEVIATIONS #F-41. */
|
|
39
|
+
--prizma-overlay-top: 0px;
|
|
40
|
+
--prizma-overlay-height: 100%;
|
|
28
41
|
}
|
|
29
42
|
|
|
30
43
|
/* Camera viewfinder screens — always a dark stage regardless of theme.
|
package/dist/TutorialScreen.js
CHANGED
|
@@ -19,6 +19,6 @@ import './ScreenLayout.css';
|
|
|
19
19
|
* `PrizmaButtonGroup` would put 12 between the slots but cannot forward
|
|
20
20
|
* `loadingLabel`, which the loading tutorials need — DEVIATIONS #F-32.
|
|
21
21
|
*/
|
|
22
|
-
export const PrizmaTutorialScreen = forwardRef(({ progress, title, subtitle, disclaimer, ctaLabel, ctaLoading = false, ctaLoadingLabel, secondaryCtaLabel, linkLabel, verifiedLabel, illustration, overlay, navLabel, screenId, showHeader = true, showFooter = true, overrides, onAction, ...shell }, ref) => (_jsxs(PrizmaScreenShell, { ref: ref, ...shell, children: [_jsx(PrizmaScreenNav, { reserved: !showHeader, logo: overrides?.logo, navLabel: navLabel }), progress ? (_jsx("div", { className: "prizma-screen-layout__progress", children: progress })) : null, _jsxs("div", { className: "prizma-screen-layout__content", children: [_jsx(PrizmaTitle, { variant: overrides?.align === 'left' ? 'left' : 'centered', title: title, showSubtitle: Boolean(subtitle), subtitle: subtitle }), _jsx("div", { className: "prizma-screen-layout__flex", children: illustration }), _jsxs("div", { className: "prizma-screen-layout__band", children: [disclaimer ? _jsx(PrizmaDisclaimer, { text: disclaimer }) : null, secondaryCtaLabel ? (_jsx(PrizmaButton, { variant: "secondary", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: secondaryCtaLabel })) : null, ctaLabel ? (_jsx(PrizmaButton, { variant: "primary", size: "L", loading: ctaLoading, loadingLabel: ctaLoadingLabel, onClick: () => onAction?.({ type: 'cta', screenId }), children: ctaLabel })) : null, linkLabel ? (_jsx(PrizmaButton, { variant: "tertiary-link", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: linkLabel })) : null, showFooter ? (_jsx("div", { className: "prizma-screen-layout__band__tag", children: _jsx(PrizmaTag, { label: verifiedLabel }) })) : null] })] }), overlay] })));
|
|
22
|
+
export const PrizmaTutorialScreen = forwardRef(({ progress, title, subtitle, disclaimer, ctaLabel, ctaLoading = false, ctaLoadingLabel, secondaryCtaLabel, linkLabel, verifiedLabel, illustration, overlay, navLabel, screenId, showHeader = true, showFooter = true, overrides, onAction, ...shell }, ref) => (_jsxs(PrizmaScreenShell, { ref: ref, ...shell, children: [_jsx(PrizmaScreenNav, { reserved: !showHeader, logo: overrides?.logo, navLabel: navLabel }), progress ? (_jsx("div", { className: "prizma-screen-layout__progress", children: progress })) : null, _jsxs("div", { className: "prizma-screen-layout__content prizma-screen-layout__content--tutorial", children: [_jsx(PrizmaTitle, { variant: overrides?.align === 'left' ? 'left' : 'centered', title: title, showSubtitle: Boolean(subtitle), subtitle: subtitle }), _jsx("div", { className: "prizma-screen-layout__flex", children: illustration }), _jsxs("div", { className: "prizma-screen-layout__band", children: [disclaimer ? _jsx(PrizmaDisclaimer, { text: disclaimer }) : null, secondaryCtaLabel ? (_jsx(PrizmaButton, { variant: "secondary", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: secondaryCtaLabel })) : null, ctaLabel ? (_jsx(PrizmaButton, { variant: "primary", size: "L", loading: ctaLoading, loadingLabel: ctaLoadingLabel, onClick: () => onAction?.({ type: 'cta', screenId }), children: ctaLabel })) : null, linkLabel ? (_jsx(PrizmaButton, { variant: "tertiary-link", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: linkLabel })) : null, showFooter ? (_jsx("div", { className: "prizma-screen-layout__band__tag", children: _jsx(PrizmaTag, { label: verifiedLabel }) })) : null] })] }), overlay] })));
|
|
23
23
|
PrizmaTutorialScreen.displayName = 'PrizmaTutorialScreen';
|
|
24
24
|
export default PrizmaTutorialScreen;
|
package/dist/index.d.ts
CHANGED
|
@@ -166,6 +166,8 @@ export { type LoadersStrings, type LoadersVariant, type LoadersCopy } from './Lo
|
|
|
166
166
|
export { LoaderScreen, type LoaderScreenProps } from './LoaderScreen';
|
|
167
167
|
export { type ErrorScreensStrings, type ErrorScreensVariant, type ErrorScreensCopy, } from './ErrorScreensStrings';
|
|
168
168
|
export { ErrorScreensScreen, type ErrorScreensScreenProps } from './ErrorScreensScreen';
|
|
169
|
+
export { type RotateToPortraitStrings } from './RotateToPortraitStrings';
|
|
170
|
+
export { RotateToPortraitScreen, type RotateToPortraitScreenProps, type RotateToPortraitTopEdge, } from './RotateToPortraitScreen';
|
|
169
171
|
export { type DemoScreensStrings, type DemoScreensLanguage, type DemoScreensOption, } from './DemoScreensStrings';
|
|
170
172
|
export { DemoScreensConfigScreen, type DemoScreensConfigScreenProps, type DemoScreensConfigState, } from './DemoScreensConfigScreen';
|
|
171
173
|
export { DemoScreensTermsScreen, type DemoScreensTermsScreenProps, } from './DemoScreensTermsScreen';
|
package/dist/index.js
CHANGED
|
@@ -145,6 +145,7 @@ export { PermissionsAllowScreen, } from './PermissionsAllowScreen';
|
|
|
145
145
|
export { PermissionsBrowserStepsScreen, } from './PermissionsBrowserStepsScreen';
|
|
146
146
|
export { LoaderScreen } from './LoaderScreen';
|
|
147
147
|
export { ErrorScreensScreen } from './ErrorScreensScreen';
|
|
148
|
+
export { RotateToPortraitScreen, } from './RotateToPortraitScreen';
|
|
148
149
|
export { DemoScreensConfigScreen, } from './DemoScreensConfigScreen';
|
|
149
150
|
export { DemoScreensTermsScreen, } from './DemoScreensTermsScreen';
|
|
150
151
|
export { DemoScreensLaunchScreen, } from './DemoScreensLaunchScreen';
|
package/dist/styles.css
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@incodetech/prizma-core-screens",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.20",
|
|
4
4
|
"description": "Prizma Design System — SDK module screens: composed, responsive, brand-themeable React screens built from @incodetech/prizma-core-web.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -665,6 +665,11 @@
|
|
|
665
665
|
"types": "./dist/ReviewScreen.d.ts",
|
|
666
666
|
"import": "./dist/ReviewScreen.js"
|
|
667
667
|
},
|
|
668
|
+
"./rotate-to-portrait-screen": {
|
|
669
|
+
"source": "./src/RotateToPortraitScreen.tsx",
|
|
670
|
+
"types": "./dist/RotateToPortraitScreen.d.ts",
|
|
671
|
+
"import": "./dist/RotateToPortraitScreen.js"
|
|
672
|
+
},
|
|
668
673
|
"./screen-nav": {
|
|
669
674
|
"source": "./src/ScreenNav.tsx",
|
|
670
675
|
"types": "./dist/ScreenNav.d.ts",
|
|
@@ -795,6 +800,7 @@
|
|
|
795
800
|
"./phone-input-layout.css": "./dist/PhoneInputLayout.css",
|
|
796
801
|
"./qualified-signature-layout.css": "./dist/QualifiedSignatureLayout.css",
|
|
797
802
|
"./reusability-layout.css": "./dist/ReusabilityLayout.css",
|
|
803
|
+
"./rotate-to-portrait-screen.css": "./dist/RotateToPortraitScreen.css",
|
|
798
804
|
"./screen-layout.css": "./dist/ScreenLayout.css",
|
|
799
805
|
"./screen-nav.css": "./dist/ScreenNav.css",
|
|
800
806
|
"./screen-shell.css": "./dist/ScreenShell.css",
|
|
@@ -841,8 +847,8 @@
|
|
|
841
847
|
},
|
|
842
848
|
"dependencies": {
|
|
843
849
|
"@incodetech/prizma-core-icons": "^0.4.0",
|
|
844
|
-
"@incodetech/prizma-core-tokens": "^0.
|
|
845
|
-
"@incodetech/prizma-core-web": "^0.
|
|
850
|
+
"@incodetech/prizma-core-tokens": "^0.18.0",
|
|
851
|
+
"@incodetech/prizma-core-web": "^0.18.0"
|
|
846
852
|
},
|
|
847
853
|
"devDependencies": {
|
|
848
854
|
"@types/react": "^18.3.12",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -33,9 +33,9 @@ export interface DigitalIdProvidersDocumentSelectionScreenProps
|
|
|
33
33
|
* Figma: `Document Chooser` (27753:8099) and the full list (27703:4895).
|
|
34
34
|
*
|
|
35
35
|
* Two of Core's card lists, each under a section label, after a "Viewing
|
|
36
|
-
* options for" country line with Core's flag. Every row is Core's;
|
|
37
|
-
*
|
|
38
|
-
*
|
|
36
|
+
* options for" country line with Core's flag. Every row is Core's; a
|
|
37
|
+
* provider leads with its logo from the backend catalog, or Core's generic
|
|
38
|
+
* `digital-id-web` card icon when it has none (DEVIATIONS #DIP-1), and the Identity Card
|
|
39
39
|
* row has no second line, which Core's row cannot draw (#DIP-3).
|
|
40
40
|
*/
|
|
41
41
|
export const DigitalIdProvidersDocumentSelectionScreen = forwardRef<
|
|
@@ -97,6 +97,7 @@ export const DigitalIdProvidersDocumentSelectionScreen = forwardRef<
|
|
|
97
97
|
<PrizmaCardListVerificationOptions
|
|
98
98
|
items={providers.map(provider => ({
|
|
99
99
|
icon: 'digital-id-web' as const,
|
|
100
|
+
logo: provider.logo,
|
|
100
101
|
title: provider.label,
|
|
101
102
|
onClick: () => choose({ kind: 'provider', providerId: provider.id }),
|
|
102
103
|
}))}
|
|
@@ -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 { PrizmaProcessingScreen, type PrizmaProcessingScreenProps } from './Proc
|
|
|
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
|
|
|
8
7
|
export interface DigitalIdProvidersRedirectScreenProps
|
|
9
8
|
extends Omit<
|
|
@@ -23,8 +22,8 @@ export interface DigitalIdProvidersRedirectScreenProps
|
|
|
23
22
|
* archetype (GUIDELINES.md §6-C). Figma: the `1-18-1-id-hold-on` instance in
|
|
24
23
|
* the web full flow (27707:9281), with the module's own copy. The Web SDK's
|
|
25
24
|
* `digitalIdRedirect` phases `loading` and `redirecting` both look like this.
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* Built like Core's other processing screens: the archetype as-is, with the
|
|
26
|
+
* logo nav and the footer tag (DEVIATIONS #DIP-9).
|
|
28
27
|
*/
|
|
29
28
|
export const DigitalIdProvidersRedirectScreen = forwardRef<
|
|
30
29
|
HTMLDivElement,
|
|
@@ -34,11 +33,8 @@ export const DigitalIdProvidersRedirectScreen = forwardRef<
|
|
|
34
33
|
{
|
|
35
34
|
strings,
|
|
36
35
|
screenId = 'digital-id-providers-redirecting',
|
|
37
|
-
showHeader = false,
|
|
38
|
-
showFooter = false,
|
|
39
36
|
overrides,
|
|
40
37
|
onAction,
|
|
41
|
-
className,
|
|
42
38
|
...shell
|
|
43
39
|
},
|
|
44
40
|
ref,
|
|
@@ -50,12 +46,9 @@ export const DigitalIdProvidersRedirectScreen = forwardRef<
|
|
|
50
46
|
subtitle={strings.redirecting.subtitle}
|
|
51
47
|
verifiedLabel={strings.verifiedLabel}
|
|
52
48
|
navLabel={strings.navLabel}
|
|
53
|
-
showHeader={showHeader}
|
|
54
|
-
showFooter={showFooter}
|
|
55
49
|
screenId={screenId}
|
|
56
50
|
overrides={overrides}
|
|
57
51
|
onAction={onAction}
|
|
58
|
-
className={['digital-id-providers-redirect', className].filter(Boolean).join(' ')}
|
|
59
52
|
{...shell}
|
|
60
53
|
/>
|
|
61
54
|
),
|
|
@@ -26,6 +26,10 @@ export interface DigitalIdProvidersOption {
|
|
|
26
26
|
id: string;
|
|
27
27
|
/** "iDIN", "itsme", "CA DMV Wallet"… */
|
|
28
28
|
label: string;
|
|
29
|
+
/** The provider's logo tile (an image URL), from the backend catalog.
|
|
30
|
+
* Absent → Core's generic `digital-id-web` card icon. Samples ship under
|
|
31
|
+
* `samples/digital-id-providers/`. */
|
|
32
|
+
logo?: string;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
/** What the person picked: a physical document, or a provider by its id. */
|