@incodetech/prizma-core-screens 0.2.3 → 0.2.7
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/CurpEnterScreen.d.ts +7 -0
- package/dist/CurpEnterScreen.js +17 -3
- package/dist/CurpGenerateScreen.d.ts +8 -0
- package/dist/CurpGenerateScreen.js +28 -13
- package/dist/CurpLayout.css +8 -34
- package/dist/CurpStrings.d.ts +16 -2
- package/dist/EkybAddressDetailsScreen.d.ts +7 -0
- package/dist/EkybAddressDetailsScreen.js +25 -7
- package/dist/EkybBusinessDetailsScreen.d.ts +6 -0
- package/dist/EkybBusinessDetailsScreen.js +23 -6
- package/dist/EkybCountryScreen.d.ts +13 -5
- package/dist/EkybCountryScreen.js +27 -9
- package/dist/EkybOwnersScreen.d.ts +8 -0
- package/dist/EkybOwnersScreen.js +26 -3
- package/dist/EkybStrings.d.ts +27 -10
- package/dist/EkycCountryCatalog.d.ts +4 -1
- package/dist/EkycCountryCatalog.js +5 -3
- package/dist/EkycCountryFormScreen.d.ts +12 -3
- package/dist/EkycCountryFormScreen.js +28 -10
- package/dist/EkycDetailsScreen.d.ts +7 -0
- package/dist/EkycDetailsScreen.js +21 -4
- package/dist/EkycStrings.d.ts +14 -2
- package/dist/ElectronicSignatureLayout.css +6 -0
- package/dist/EmailInputStrings.d.ts +11 -1
- package/dist/EmailInputVerifyScreen.d.ts +7 -0
- package/dist/EmailInputVerifyScreen.js +17 -3
- package/dist/FaceMatchComparisonScreen.d.ts +3 -3
- package/dist/FaceMatchLayout.css +21 -12
- package/dist/FormScreen.css +16 -0
- package/dist/FormsLongFormScreen.d.ts +8 -0
- package/dist/FormsLongFormScreen.js +34 -13
- package/dist/FormsStrings.d.ts +11 -1
- package/dist/GeolocationBrowserStepsScreen.d.ts +6 -2
- package/dist/GeolocationBrowserStepsScreen.js +7 -3
- package/dist/GeolocationStrings.d.ts +3 -0
- package/dist/IdCaptureLayout.css +40 -0
- package/dist/ListScreen.d.ts +2 -0
- package/dist/ListScreen.js +1 -1
- package/dist/PhoneInputLayout.css +10 -9
- package/dist/PhoneInputStrings.d.ts +11 -1
- package/dist/PhoneInputVerifyScreen.d.ts +8 -0
- package/dist/PhoneInputVerifyScreen.js +19 -6
- package/dist/QualifiedSignatureAcceptScreen.js +6 -1
- package/dist/QualifiedSignatureDocumentScreen.d.ts +13 -9
- package/dist/QualifiedSignatureDocumentScreen.js +18 -16
- package/dist/QualifiedSignatureLayout.css +76 -0
- package/dist/QualifiedSignatureStrings.d.ts +10 -0
- package/dist/ScreenNav.css +8 -0
- package/dist/ScreenNav.d.ts +15 -2
- package/dist/ScreenNav.js +10 -3
- package/dist/VideoSelfieIdCaptureScreen.d.ts +10 -3
- package/dist/VideoSelfieIdCaptureScreen.js +44 -13
- package/dist/VideoSelfieLayout.css +164 -33
- package/dist/VideoSelfieSelfieCaptureScreen.d.ts +44 -27
- package/dist/VideoSelfieSelfieCaptureScreen.js +65 -39
- package/dist/VideoSelfieSpeakScreen.js +18 -1
- package/dist/VideoSelfieStrings.d.ts +78 -12
- package/dist/VideoSelfieTurnHeadScreen.d.ts +51 -0
- package/dist/VideoSelfieTurnHeadScreen.js +63 -0
- package/dist/VideoSelfieTutorialScreen.js +13 -5
- package/dist/VideoSelfieWaveScreen.d.ts +53 -0
- package/dist/VideoSelfieWaveScreen.js +62 -0
- package/dist/WatchlistBusinessFormScreen.d.ts +11 -7
- package/dist/WatchlistBusinessFormScreen.js +27 -13
- package/dist/WatchlistBusinessStrings.d.ts +21 -7
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/types.d.ts +3 -1
- package/package.json +14 -3
- package/samples/video-selfie-room.png +0 -0
- package/src/CurpEnterScreen.tsx +21 -4
- package/src/CurpGenerateScreen.tsx +46 -22
- package/src/CurpLayout.css +8 -34
- package/src/CurpStrings.ts +22 -2
- package/src/EkybAddressDetailsScreen.tsx +32 -4
- package/src/EkybBusinessDetailsScreen.tsx +23 -5
- package/src/EkybCountryScreen.tsx +28 -7
- package/src/EkybOwnersScreen.tsx +34 -3
- package/src/EkybStrings.ts +29 -10
- package/src/EkycCountryCatalog.ts +9 -4
- package/src/EkycCountryFormScreen.tsx +51 -12
- package/src/EkycDetailsScreen.tsx +22 -1
- package/src/EkycStrings.ts +14 -2
- package/src/ElectronicSignatureLayout.css +6 -0
- package/src/EmailInputStrings.ts +12 -1
- package/src/EmailInputVerifyScreen.tsx +21 -4
- package/src/FaceMatchComparisonScreen.tsx +3 -3
- package/src/FaceMatchLayout.css +21 -12
- package/src/FormScreen.css +16 -0
- package/src/FormsLongFormScreen.tsx +41 -13
- package/src/FormsStrings.ts +12 -1
- package/src/GeolocationBrowserStepsScreen.tsx +6 -3
- package/src/GeolocationStrings.ts +3 -0
- package/src/IdCaptureLayout.css +40 -0
- package/src/ListScreen.tsx +10 -1
- package/src/PhoneInputLayout.css +10 -9
- package/src/PhoneInputStrings.ts +12 -1
- package/src/PhoneInputVerifyScreen.tsx +21 -5
- package/src/QualifiedSignatureAcceptScreen.tsx +12 -1
- package/src/QualifiedSignatureDocumentScreen.tsx +27 -17
- package/src/QualifiedSignatureLayout.css +76 -0
- package/src/QualifiedSignatureStrings.ts +10 -0
- package/src/ScreenNav.css +8 -0
- package/src/ScreenNav.tsx +35 -5
- package/src/VideoSelfieIdCaptureScreen.tsx +116 -30
- package/src/VideoSelfieLayout.css +164 -33
- package/src/VideoSelfieSelfieCaptureScreen.tsx +104 -59
- package/src/VideoSelfieSpeakScreen.tsx +25 -14
- package/src/VideoSelfieStrings.ts +85 -12
- package/src/VideoSelfieTurnHeadScreen.tsx +151 -0
- package/src/VideoSelfieTutorialScreen.tsx +34 -23
- package/src/VideoSelfieWaveScreen.tsx +135 -0
- package/src/WatchlistBusinessFormScreen.tsx +35 -16
- package/src/WatchlistBusinessStrings.ts +21 -7
- package/src/index.ts +14 -0
- package/src/types.ts +3 -1
package/dist/EkybStrings.d.ts
CHANGED
|
@@ -7,13 +7,19 @@
|
|
|
7
7
|
* - `dropdown` — the same selection with the MENU OPEN over the form: search
|
|
8
8
|
* bar plus the country rows (Core's documentation-only `forceOpen`, since a
|
|
9
9
|
* screen is one static spec state and never a live interaction)
|
|
10
|
+
* - `emptyError` — Continue was pressed with no country chosen (GUIDELINES
|
|
11
|
+
* §6-E empty-submit rule, Elena 2026-09-30): the dropdown in Core's error
|
|
12
|
+
* state with `requiredError`, Continue disabled. Not a Figma frame.
|
|
10
13
|
*/
|
|
11
|
-
export type EkybCountryState = 'empty' | 'filled' | 'dropdown';
|
|
14
|
+
export type EkybCountryState = 'empty' | 'filled' | 'dropdown' | 'emptyError';
|
|
12
15
|
/** The two `eKYB.Bdetails` (business identity) sections: every field on its
|
|
13
|
-
* resting empty surface, or every field carrying a value
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export type
|
|
16
|
+
* resting empty surface, or every field carrying a value — plus `emptyError`,
|
|
17
|
+
* Continue pressed with the fields empty (empty-submit rule, 2026-09-30):
|
|
18
|
+
* every required field in Core's error state, Continue disabled. */
|
|
19
|
+
export type EkybBusinessState = 'empty' | 'filled' | 'emptyError';
|
|
20
|
+
/** The two address sections (the SECOND `eKYB.Bdetails` parent). Same axis,
|
|
21
|
+
* same `emptyError` (the optional Address line 2 shows no error). */
|
|
22
|
+
export type EkybAddressState = 'empty' | 'filled' | 'emptyError';
|
|
17
23
|
/**
|
|
18
24
|
* The `eKYB.UBO.*` and `eKYB.director.*` sections — one screen family, because
|
|
19
25
|
* measured against the 390 frames the director frames ARE the UBO frames with
|
|
@@ -33,8 +39,13 @@ export type EkybAddressState = 'empty' | 'filled';
|
|
|
33
39
|
* flight, so EVERY field, both "Add another" links and "Back" go inert and
|
|
34
40
|
* the spinner rides the CTA, never a field (the Phone Input lesson,
|
|
35
41
|
* DEVIATIONS #PI-5)
|
|
42
|
+
* - `uboEmptyError` / `directorEmptyError` — `uboEmpty` / `directorEmpty` after
|
|
43
|
+
* Continue was pressed with the fields empty (GUIDELINES §6-E empty-submit
|
|
44
|
+
* rule, Elena 2026-09-30): the two REQUIRED UBO fields in Core's error state
|
|
45
|
+
* with `requiredError`, the optional Director fields unflagged, Continue
|
|
46
|
+
* disabled. Not Figma frames.
|
|
36
47
|
*/
|
|
37
|
-
export type EkybOwnersState = 'uboEmpty' | 'uboFilled' | 'directorEmpty' | 'directorFilled' | 'uboAdded' | 'loading';
|
|
48
|
+
export type EkybOwnersState = 'uboEmpty' | 'uboFilled' | 'directorEmpty' | 'directorFilled' | 'uboAdded' | 'loading' | 'uboEmptyError' | 'directorEmptyError';
|
|
38
49
|
/**
|
|
39
50
|
* One selectable row in the country / state menus. Runtime data, not copy — the
|
|
40
51
|
* host owns the catalogue (an ISO country list is ~250 entries and a state list
|
|
@@ -47,9 +58,8 @@ export interface EkybOption {
|
|
|
47
58
|
/** The row label as drawn in the open menu. */
|
|
48
59
|
label: string;
|
|
49
60
|
/** Compact face for the CLOSED field when it differs from the menu row —
|
|
50
|
-
* Core's own `PrizmaDropdownOption.fieldLabel`.
|
|
51
|
-
*
|
|
52
|
-
* field. */
|
|
61
|
+
* Core's own `PrizmaDropdownOption.fieldLabel`. The eKYB country list
|
|
62
|
+
* does not need it: rows and field both read "🇺🇸 United States". */
|
|
53
63
|
fieldLabel?: string;
|
|
54
64
|
}
|
|
55
65
|
/** The values the business-identity page carries. Runtime data, never copy. */
|
|
@@ -97,6 +107,13 @@ export interface EkybStrings {
|
|
|
97
107
|
* localizable and never hardcoded in a screen.
|
|
98
108
|
*/
|
|
99
109
|
requiredHint?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Under every empty REQUIRED field once the primary was pressed with it
|
|
112
|
+
* still empty — the `emptyError` states (GUIDELINES §6-E empty-submit rule,
|
|
113
|
+
* Elena 2026-09-30). Core's own `errorText` slot; SDK key
|
|
114
|
+
* `dynamicForms.fieldRequired`.
|
|
115
|
+
*/
|
|
116
|
+
requiredError: string;
|
|
100
117
|
/** Shared "Back" secondary action drawn under "Continue" on every page except
|
|
101
118
|
* `country`. Emits `secondary`. */
|
|
102
119
|
backLabel: string;
|
|
@@ -170,7 +187,7 @@ export interface EkybStrings {
|
|
|
170
187
|
title: string;
|
|
171
188
|
subtitle?: string;
|
|
172
189
|
uboName: EkybFieldStrings;
|
|
173
|
-
/**
|
|
190
|
+
/** Required, like the name (Elena, 2026-09-28); the frames drew no `*`. */
|
|
174
191
|
uboSurname: EkybFieldStrings;
|
|
175
192
|
/** The tertiary link under the UBO block ("Add another UBO (Optional)"). */
|
|
176
193
|
addUboLabel: string;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/** `password`: Core's `PrizmaPassword`, the field with the eye that hides the
|
|
2
|
+
* typed value. For the identifiers a stranger must not read over a shoulder:
|
|
3
|
+
* the SSN / ITIN fields (Elena, 2026-09-28). No requirement checklist. */
|
|
4
|
+
export type EkycFieldKind = 'text' | 'date' | 'phone' | 'dropdown' | 'radio' | 'password';
|
|
2
5
|
export type EkycFieldKey = 'firstName' | 'middleName' | 'middleNameOptional' | 'lastName' | 'surname' | 'maternalSurname' | 'dateOfBirth' | 'email' | 'phone' | 'ssnLast4' | 'ssnOrItin' | 'nationality' | 'cpf' | 'nationalId' | 'taxId' | 'gender' | 'licenseNumber' | 'licenseState' | 'licenseExpiration' | 'street' | 'houseNumber' | 'city' | 'state' | 'stateCode' | 'zipCode' | 'postalCode';
|
|
3
6
|
export interface EkycField {
|
|
4
7
|
key: EkycFieldKey;
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
// Verification", and no variant draws a close in the nav; steps after the
|
|
21
21
|
// first get the archetype's Back button instead of a back arrow (#EKC-2).
|
|
22
22
|
const t = (key, extra = {}) => ({ key, kind: 'text', ...extra });
|
|
23
|
+
/** A hidden-by-default identifier, with the eye to reveal it. */
|
|
24
|
+
const secret = (key, extra = {}) => ({ key, kind: 'password', ...extra });
|
|
23
25
|
const date = (key = 'dateOfBirth', extra = {}) => ({ key, kind: 'date', ...extra });
|
|
24
26
|
// Required fields carry Core's asterisk (`required` + `requiredHint`), the
|
|
25
27
|
// owner's rule (Elena, 2026-09-24, DEVIATIONS #EKC-6): first name, last name or
|
|
@@ -54,7 +56,7 @@ export const EKYC_COUNTRY_CATALOG = [
|
|
|
54
56
|
{
|
|
55
57
|
id: 'us-telco-1', country: 'US', label: 'United States', provider: 'Telco 1', stepper: 3,
|
|
56
58
|
steps: [
|
|
57
|
-
{ node: '2098:9575', fields: [...NAME_PAIR(), email(), ...DOB_PHONE('US'),
|
|
59
|
+
{ node: '2098:9575', fields: [...NAME_PAIR(), email(), ...DOB_PHONE('US'), secret('ssnLast4')] },
|
|
58
60
|
{ node: '5854:76222', section: 'license', fields: [t('licenseNumber'), { key: 'licenseState', kind: 'dropdown', placeholder: 'selectState' }] },
|
|
59
61
|
{ node: '5854:76221', section: 'address', fields: US_ADDRESS },
|
|
60
62
|
],
|
|
@@ -71,7 +73,7 @@ export const EKYC_COUNTRY_CATALOG = [
|
|
|
71
73
|
steps: [
|
|
72
74
|
/* Same First | Last pair as the licence variant; Middle name (Optional)
|
|
73
75
|
follows it and spans (#EKC-5). */
|
|
74
|
-
{ node: '2098:9577', fields: [...NAME_PAIR(), t('middleNameOptional'), ...DOB_PHONE('US'), email(),
|
|
76
|
+
{ node: '2098:9577', fields: [...NAME_PAIR(), t('middleNameOptional'), ...DOB_PHONE('US'), email(), secret('ssnOrItin')] },
|
|
75
77
|
{ node: '5857:34094', section: 'address', fields: US_ADDRESS },
|
|
76
78
|
],
|
|
77
79
|
},
|
|
@@ -90,7 +92,7 @@ export const EKYC_COUNTRY_CATALOG = [
|
|
|
90
92
|
{
|
|
91
93
|
id: 'ca-res-credit', country: 'CA', label: 'Canada', provider: 'Residential credit', stepper: 2,
|
|
92
94
|
steps: [
|
|
93
|
-
{ node: '2098:9570', fields: [...NAME_PAIR(), email(), ...DOB_PHONE('CA'),
|
|
95
|
+
{ node: '2098:9570', fields: [...NAME_PAIR(), email(), ...DOB_PHONE('CA'), secret('ssnOrItin')] },
|
|
94
96
|
{ node: '5857:36450', section: 'address', fields: CODE_ADDRESS('stateCodeCa') },
|
|
95
97
|
],
|
|
96
98
|
},
|
|
@@ -16,11 +16,20 @@ export interface EkycCountryFormScreenProps extends Omit<PrizmaFormScreenProps,
|
|
|
16
16
|
values?: EkycCountryValues;
|
|
17
17
|
/**
|
|
18
18
|
* The state after Continue was pressed with fields still empty: every empty
|
|
19
|
-
* field shows Core's error state and `country.requiredError` under
|
|
20
|
-
* Continue
|
|
21
|
-
*
|
|
19
|
+
* REQUIRED field shows Core's error state and `country.requiredError` under
|
|
20
|
+
* it, and Continue is disabled (GUIDELINES §6-E empty-submit rule, Elena
|
|
21
|
+
* 2026-09-30). Without it Continue stays enabled: validation happens on
|
|
22
|
+
* press, the resting page never greys the button.
|
|
22
23
|
*/
|
|
23
24
|
showErrors?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Field keys whose typed value failed the format check on Continue (an
|
|
27
|
+
* invalid CPF, say). Each keeps its value, shows Core's error state and
|
|
28
|
+
* `country.invalidErrors[key]` under it; Continue stays enabled so the user
|
|
29
|
+
* corrects it and presses again, the CURP precedent (`CurpEnterScreen`'s
|
|
30
|
+
* `invalid`). A key with no message in `invalidErrors` shows no error.
|
|
31
|
+
*/
|
|
32
|
+
invalidFields?: string[];
|
|
24
33
|
/** Dial codes the phone field offers. Runtime data, never copy. */
|
|
25
34
|
phoneCountries?: PrizmaCountry[];
|
|
26
35
|
/** Options for the dropdown fields, keyed by field key. Runtime data. */
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { forwardRef } from 'react';
|
|
4
4
|
import { PrizmaTextField } from '@incodetech/prizma-core-web/text-field';
|
|
5
|
+
import { PrizmaPassword } from '@incodetech/prizma-core-web/password';
|
|
5
6
|
import { PrizmaDateField } from '@incodetech/prizma-core-web/date-field';
|
|
6
7
|
import { PrizmaDropdown } from '@incodetech/prizma-core-web/dropdown';
|
|
7
8
|
import { PrizmaCombined } from '@incodetech/prizma-core-web/combined';
|
|
@@ -23,10 +24,13 @@ import './EkycLayout.css';
|
|
|
23
24
|
* dropdown, radio pair — so a new country is a catalogue entry, never a file.
|
|
24
25
|
*
|
|
25
26
|
* Deliberate, per frame and per owner:
|
|
26
|
-
* - Continue is
|
|
27
|
-
* most frames draw): pressing it with empty fields is the
|
|
28
|
-
* Core's error ring and message under each empty
|
|
29
|
-
*
|
|
27
|
+
* - Continue is enabled on the resting page (Elena, 2026-09-24, overriding the
|
|
28
|
+
* grey button most frames draw): pressing it with empty fields is the
|
|
29
|
+
* `showErrors` state, Core's error ring and message under each empty
|
|
30
|
+
* required field, and THEN Continue is disabled. The "always enabled" half
|
|
31
|
+
* of DEVIATIONS #EKC-4 is superseded by the 2026-09-30 empty-submit rule
|
|
32
|
+
* (GUIDELINES §6-E). The radio pair has no error state in Core, so an empty
|
|
33
|
+
* gender still shows none.
|
|
30
34
|
* - ONE title per step (Elena, 2026-09-24): the personal-data step is "Enter
|
|
31
35
|
* your details" with its subtitle; a licence step is titled "Driver's
|
|
32
36
|
* License details" and an address step "Address details", with nothing
|
|
@@ -53,7 +57,7 @@ const groupRows = (fields) => {
|
|
|
53
57
|
}
|
|
54
58
|
return groups;
|
|
55
59
|
};
|
|
56
|
-
export const EkycCountryFormScreen = forwardRef(({ strings, variant, step = 1, values, showErrors = false, phoneCountries, options, screenId, overrides, onAction, ...shell }, ref) => {
|
|
60
|
+
export const EkycCountryFormScreen = forwardRef(({ strings, variant, step = 1, values, showErrors = false, invalidFields, phoneCountries, options, screenId, overrides, onAction, ...shell }, ref) => {
|
|
57
61
|
const v = typeof variant === 'string' ? ekycCountryVariant(variant) : variant;
|
|
58
62
|
if (!v)
|
|
59
63
|
return null;
|
|
@@ -61,14 +65,21 @@ export const EkycCountryFormScreen = forwardRef(({ strings, variant, step = 1, v
|
|
|
61
65
|
const c = strings.country;
|
|
62
66
|
const stepperState = step <= 1 ? 'Start' : Math.min(step, 6);
|
|
63
67
|
const label = (f) => c.fields[f.key] ?? f.key;
|
|
64
|
-
|
|
68
|
+
// A lone field in its empty-submit error drops its placeholder, as the
|
|
69
|
+
// single-input screens do (Phone, Email and CURP's `emptyError`).
|
|
70
|
+
const lone = s.fields.length === 1;
|
|
71
|
+
const placeholder = (f) => lone && showErrors && !values?.[f.key] ? undefined : f.placeholder ? c.placeholders[f.placeholder] : c.placeholders[f.key];
|
|
65
72
|
const renderField = (f) => {
|
|
66
73
|
// Only a REQUIRED empty field is an error on press (Elena, 2026-09-24,
|
|
67
|
-
// DEVIATIONS #EKC-6): an optional field left blank shows nothing.
|
|
68
|
-
|
|
74
|
+
// DEVIATIONS #EKC-6): an optional field left blank shows nothing. A
|
|
75
|
+
// step's lone field is required by definition, asterisk or not (the
|
|
76
|
+
// single-input rule, as Phone and Email Input: Elena, 2026-10-02).
|
|
77
|
+
const required = Boolean(f.required) || lone;
|
|
78
|
+
const missing = showErrors && required && !values?.[f.key];
|
|
79
|
+
const invalidText = invalidFields?.includes(f.key) ? c.invalidErrors?.[f.key] : undefined;
|
|
69
80
|
const common = {
|
|
70
81
|
key: f.key, label: label(f), required: f.required, requiredHint: strings.details.requiredHint,
|
|
71
|
-
error: missing || undefined, errorText: missing ? c.requiredError :
|
|
82
|
+
error: missing || Boolean(invalidText) || undefined, errorText: missing ? c.requiredError : invalidText,
|
|
72
83
|
};
|
|
73
84
|
switch (f.kind) {
|
|
74
85
|
case 'date':
|
|
@@ -79,13 +90,20 @@ export const EkycCountryFormScreen = forwardRef(({ strings, variant, step = 1, v
|
|
|
79
90
|
}
|
|
80
91
|
case 'dropdown':
|
|
81
92
|
return (_jsx(PrizmaDropdown, { ...common, placeholder: placeholder(f), options: options?.[f.key] ?? [], defaultValue: values?.[f.key] ?? null }));
|
|
93
|
+
case 'password':
|
|
94
|
+
/* The SSN / ITIN fields: Core's Password field, hidden by default, the
|
|
95
|
+
eye reveals it. No requirement checklist — this is an identifier,
|
|
96
|
+
not a password to compose (Elena, 2026-09-28). */
|
|
97
|
+
return (_jsx(PrizmaPassword, { ...common, placeholder: placeholder(f), autoComplete: "off", defaultValue: values?.[f.key] ?? '', showPasswordLabel: c.showValueLabel, hidePasswordLabel: c.hideValueLabel, showHelper: false, showRequirements: false }));
|
|
82
98
|
case 'radio':
|
|
83
99
|
return (_jsx(PrizmaRadioGroup, { name: f.key, legend: label(f), defaultValue: values?.[f.key], className: "ekyc-country__radios", children: c.genderOptions.map(o => (_jsx(PrizmaRadio, { value: o.value, textSize: "m", showText: true, text: o.label }, o.value))) }, f.key));
|
|
84
100
|
default:
|
|
85
101
|
return _jsx(PrizmaTextField, { ...common, placeholder: placeholder(f), autoComplete: "off", defaultValue: values?.[f.key] ?? '' });
|
|
86
102
|
}
|
|
87
103
|
};
|
|
88
|
-
return (_jsx(PrizmaFormScreen, { ref: ref, scrollFields: true, progress: v.stepper > 0 ? (_jsx(PrizmaStepper, { steps: v.stepper, currentState: stepperState, showIcons: false, "aria-label": strings.stepperLabel })) : undefined, title: s.section === 'address' ? c.addressSection : s.section === 'license' ? c.licenseSection : strings.details.title, subtitle: s.section ? undefined : strings.details.subtitle, linkContent: step > 1 ? (_jsx(PrizmaButton, { variant: "secondary", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: c.backLabel })) : undefined, ctaLabel: c.ctaLabel,
|
|
104
|
+
return (_jsx(PrizmaFormScreen, { ref: ref, scrollFields: true, progress: v.stepper > 0 ? (_jsx(PrizmaStepper, { steps: v.stepper, currentState: stepperState, showIcons: false, "aria-label": strings.stepperLabel })) : undefined, title: s.section === 'address' ? c.addressSection : s.section === 'license' ? c.licenseSection : strings.details.title, subtitle: s.section ? undefined : strings.details.subtitle, linkContent: step > 1 ? (_jsx(PrizmaButton, { variant: "secondary", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: c.backLabel })) : undefined, ctaLabel: c.ctaLabel,
|
|
105
|
+
/* Greyed only after the empty submit (2026-09-30 empty-submit rule). */
|
|
106
|
+
ctaDisabled: showErrors, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: { align: overrides?.align ?? 'left', logo: overrides?.logo }, onAction: onAction,
|
|
89
107
|
/* The eKYB desktop shape: catalogue pairs become two lanes at 420 and
|
|
90
108
|
up, Back | Continue share a row. The phone stack is untouched. */
|
|
91
109
|
responsive: true, ...shell, children: groupRows(s.fields).map(group => group.length > 1 ? (_jsx(PrizmaFormRow, { children: group.map(renderField) }, group.map(f => f.key).join('+'))) : (renderField(group[0]))) }));
|
|
@@ -52,6 +52,13 @@ export interface EkycDetailsScreenProps extends Omit<PrizmaFormScreenProps, 'tit
|
|
|
52
52
|
* the label row Figma draws as "First name *" — so Middle name, the one
|
|
53
53
|
* optional field, correctly renders none.
|
|
54
54
|
*
|
|
55
|
+
* `emptyError` is the state after Continue was pressed with the fields still
|
|
56
|
+
* empty (Elena, 2026-09-30, GUIDELINES §6-E empty-submit rule; drawn precedent
|
|
57
|
+
* `FormsFieldScreen`'s `emptyError`): every field renders empty, the three
|
|
58
|
+
* REQUIRED ones carry Core's `error` + `country.requiredError`, Middle name
|
|
59
|
+
* stays unflagged (DEVIATIONS #EKC-6), and Continue is disabled. The resting
|
|
60
|
+
* `default` keeps Continue enabled so the press can happen at all.
|
|
61
|
+
*
|
|
55
62
|
* Figma draws a two-segment journey bar between the nav and the title on every
|
|
56
63
|
* page-1 frame, and it is the only chrome that separates page 1 from page 2.
|
|
57
64
|
* Archetype E had no slot above the title; the gap is now CLOSED in the
|
|
@@ -44,6 +44,13 @@ import './EkycLayout.css';
|
|
|
44
44
|
* the label row Figma draws as "First name *" — so Middle name, the one
|
|
45
45
|
* optional field, correctly renders none.
|
|
46
46
|
*
|
|
47
|
+
* `emptyError` is the state after Continue was pressed with the fields still
|
|
48
|
+
* empty (Elena, 2026-09-30, GUIDELINES §6-E empty-submit rule; drawn precedent
|
|
49
|
+
* `FormsFieldScreen`'s `emptyError`): every field renders empty, the three
|
|
50
|
+
* REQUIRED ones carry Core's `error` + `country.requiredError`, Middle name
|
|
51
|
+
* stays unflagged (DEVIATIONS #EKC-6), and Continue is disabled. The resting
|
|
52
|
+
* `default` keeps Continue enabled so the press can happen at all.
|
|
53
|
+
*
|
|
47
54
|
* Figma draws a two-segment journey bar between the nav and the title on every
|
|
48
55
|
* page-1 frame, and it is the only chrome that separates page 1 from page 2.
|
|
49
56
|
* Archetype E had no slot above the title; the gap is now CLOSED in the
|
|
@@ -53,11 +60,18 @@ import './EkycLayout.css';
|
|
|
53
60
|
* solid brand blue and segment 2 grey, i.e. `steps={2} currentState="Start"`,
|
|
54
61
|
* with the icons row off (the frames draw the bar alone). DEVIATIONS #EK-1.
|
|
55
62
|
*/
|
|
56
|
-
export const EkycDetailsScreen = forwardRef(({ strings, state = 'default', values, screenId = `ekyc-details-${state}`, className, overrides, onAction, ...shell }, ref) => {
|
|
63
|
+
export const EkycDetailsScreen = forwardRef(({ strings, state = 'default', values: valuesProp, screenId = `ekyc-details-${state}`, ctaDisabled, className, overrides, onAction, ...shell }, ref) => {
|
|
57
64
|
// The one field treatment that varies across the three sections: 2101:8159
|
|
58
65
|
// rings First name blue and shows its clear ✕; the other two draw every
|
|
59
66
|
// field resting.
|
|
60
67
|
const focused = state === 'focused';
|
|
68
|
+
// The empty-submit state: every field empty, required ones in error.
|
|
69
|
+
const emptyError = state === 'emptyError';
|
|
70
|
+
const values = emptyError ? undefined : valuesProp;
|
|
71
|
+
// Core's own error treatment, spread onto the REQUIRED fields only.
|
|
72
|
+
const missing = emptyError
|
|
73
|
+
? { error: true, errorText: strings.country.requiredError }
|
|
74
|
+
: {};
|
|
61
75
|
return (_jsxs(PrizmaFormScreen, { ref: ref,
|
|
62
76
|
/* Scopes the single rule that lets the focused field keep the clear ✕
|
|
63
77
|
Figma draws inside it. See EkycLayout.css. */
|
|
@@ -68,7 +82,10 @@ export const EkycDetailsScreen = forwardRef(({ strings, state = 'default', value
|
|
|
68
82
|
`Start` state at `steps={2}`. `showIcons={false}` because the frames
|
|
69
83
|
draw the bar with no glyph row (and it keeps the icon lookup, which
|
|
70
84
|
has no id+2 sequence, out of the render entirely). */
|
|
71
|
-
progress: _jsx(PrizmaStepper, { steps: 2, currentState: "Start", showIcons: false, "aria-label": strings.stepperLabel }), title: strings.details.title, subtitle: strings.details.subtitle, ctaLabel: strings.details.ctaLabel,
|
|
85
|
+
progress: _jsx(PrizmaStepper, { steps: 2, currentState: "Start", showIcons: false, "aria-label": strings.stepperLabel }), title: strings.details.title, subtitle: strings.details.subtitle, ctaLabel: strings.details.ctaLabel,
|
|
86
|
+
/* Disabled only after the empty submit; the resting page keeps it
|
|
87
|
+
enabled so the press can happen. */
|
|
88
|
+
ctaDisabled: emptyError || ctaDisabled, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId,
|
|
72
89
|
/* Every eKYC form frame LEFT-aligns its title block, while the archetype
|
|
73
90
|
defaults to centred. The module supplies its designed alignment through
|
|
74
91
|
the sanctioned override rather than declaring any layout, and a host
|
|
@@ -80,9 +97,9 @@ export const EkycDetailsScreen = forwardRef(({ strings, state = 'default', value
|
|
|
80
97
|
now FOLLOWS Last name, on the phone too (First, Last, Middle, Date of
|
|
81
98
|
birth), the one order change the pairing costs: the frames drew
|
|
82
99
|
First, Middle, Last. DEVIATIONS #EKC-5. */
|
|
83
|
-
responsive: true, ...shell, children: [_jsxs(PrizmaFormRow, { children: [_jsx(PrizmaTextField, { className: focused ? 'prizma-input-textfield--focused' : undefined, label: strings.details.firstNameLabel, required: true, requiredHint: strings.details.requiredHint, defaultValue: values?.firstName ?? '', autoComplete: "off",
|
|
100
|
+
responsive: true, ...shell, children: [_jsxs(PrizmaFormRow, { children: [_jsx(PrizmaTextField, { className: focused ? 'prizma-input-textfield--focused' : undefined, label: strings.details.firstNameLabel, required: true, requiredHint: strings.details.requiredHint, ...missing, defaultValue: values?.firstName ?? '', autoComplete: "off",
|
|
84
101
|
/* Only 2101:8159 draws the ✕, and only in this field. */
|
|
85
|
-
clearable: focused, clearLabel: strings.details.clearLabel }), _jsx(PrizmaTextField, { label: strings.details.lastNameLabel, required: true, requiredHint: strings.details.requiredHint, defaultValue: values?.lastName ?? '', autoComplete: "off", clearable: false })] }), _jsx(PrizmaTextField, { label: strings.details.middleNameLabel, defaultValue: values?.middleName ?? '', autoComplete: "off", clearable: false }), _jsx(PrizmaDateField, { label: strings.details.dateOfBirthLabel, required: true, requiredHint: strings.details.requiredHint, defaultValue: values?.dateOfBirth ?? '', autoComplete: "off" })] }));
|
|
102
|
+
clearable: focused, clearLabel: strings.details.clearLabel }), _jsx(PrizmaTextField, { label: strings.details.lastNameLabel, required: true, requiredHint: strings.details.requiredHint, ...missing, defaultValue: values?.lastName ?? '', autoComplete: "off", clearable: false })] }), _jsx(PrizmaTextField, { label: strings.details.middleNameLabel, defaultValue: values?.middleName ?? '', autoComplete: "off", clearable: false }), _jsx(PrizmaDateField, { label: strings.details.dateOfBirthLabel, required: true, requiredHint: strings.details.requiredHint, ...missing, defaultValue: values?.dateOfBirth ?? '', autoComplete: "off" })] }));
|
|
86
103
|
});
|
|
87
104
|
EkycDetailsScreen.displayName = 'EkycDetailsScreen';
|
|
88
105
|
export default EkycDetailsScreen;
|
package/dist/EkycStrings.d.ts
CHANGED
|
@@ -9,8 +9,12 @@
|
|
|
9
9
|
* the clear ✕ (2101:8159 draws the OS keyboard over the CTA; the
|
|
10
10
|
* keyboard is OS chrome, never a screen element)
|
|
11
11
|
* - `filled` — all four fields resting with their values
|
|
12
|
+
* - `emptyError` — Continue was pressed with the fields empty (GUIDELINES §6-E
|
|
13
|
+
* empty-submit rule, Elena 2026-09-30): the three REQUIRED fields
|
|
14
|
+
* in Core's error state with `country.requiredError`, Middle name
|
|
15
|
+
* (optional) unflagged, and Continue disabled. Not a Figma frame.
|
|
12
16
|
*/
|
|
13
|
-
export type EkycDetailsState = 'default' | 'focused' | 'filled';
|
|
17
|
+
export type EkycDetailsState = 'default' | 'focused' | 'filled' | 'emptyError';
|
|
14
18
|
/**
|
|
15
19
|
* The page-2 sections (`eKYC.default` / `eKYC.filled` / `eKYC.loading`), same
|
|
16
20
|
* layout with the document field set:
|
|
@@ -109,6 +113,10 @@ export interface EkycStrings {
|
|
|
109
113
|
licenseSection: string;
|
|
110
114
|
/** Accessible name of the phone field's dial-code list. */
|
|
111
115
|
countryListLabel: string;
|
|
116
|
+
/** Accessible names for the eye on a `password` field (the SSN / ITIN
|
|
117
|
+
* fields): while the value is hidden, and while it is shown. */
|
|
118
|
+
showValueLabel: string;
|
|
119
|
+
hideValueLabel: string;
|
|
112
120
|
/** The gender radio pair, Argentina. */
|
|
113
121
|
genderOptions: {
|
|
114
122
|
value: string;
|
|
@@ -119,8 +127,12 @@ export interface EkycStrings {
|
|
|
119
127
|
ctaLabel: string;
|
|
120
128
|
/** The secondary button on a step after the first. */
|
|
121
129
|
backLabel: string;
|
|
122
|
-
/** Under every empty field once Continue was pressed
|
|
130
|
+
/** Under every empty REQUIRED field once Continue was pressed: the
|
|
131
|
+
* by-country `showErrors` state and page 1's `emptyError` both read it. */
|
|
123
132
|
requiredError: string;
|
|
133
|
+
/** Under a field whose value failed the format check on Continue, by
|
|
134
|
+
* field key (`invalidFields`). `cpf` is SDK key `dynamicForms.invalidCpf`. */
|
|
135
|
+
invalidErrors?: Record<string, string>;
|
|
124
136
|
};
|
|
125
137
|
/** `eKYC.processing` — spinner over the status line, no button. */
|
|
126
138
|
processing: {
|
|
@@ -47,6 +47,12 @@
|
|
|
47
47
|
border: var(--prizma-border-width-regular) solid var(--prizma-border-neutral-100);
|
|
48
48
|
border-radius: var(--prizma-border-radius-small);
|
|
49
49
|
text-align: start;
|
|
50
|
+
/* Air between the frame and the CTA band. Archetype G's list middle carries
|
|
51
|
+
no bottom gap (its content normally ends well above the band), so a frame
|
|
52
|
+
that fills the middle sat flush against Continue (owner-reported
|
|
53
|
+
2026-09-29). Spacing/16 is the archetype's own scrolling-middle → band gap
|
|
54
|
+
(`.prizma-screen-layout__list--scroll`, ScreenLayout.css). */
|
|
55
|
+
margin-bottom: var(--prizma-spacing-16);
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
/* The agreement's own typography — Body/M Regular on Text/Body/500, the pair
|
|
@@ -8,8 +8,12 @@
|
|
|
8
8
|
* - `filled` — focused field with a complete address
|
|
9
9
|
* - `error` — negative field + clear ✕ + the invalid-format row
|
|
10
10
|
* - `loading` — field greyed while the code is requested, spinner in the CTA
|
|
11
|
+
* - `emptyError` — "Continue" pressed with the field still empty: the field
|
|
12
|
+
* stays empty (no placeholder) in Core's error state with `requiredError`,
|
|
13
|
+
* and the CTA is disabled. GUIDELINES §6-E empty-submit rule (Elena,
|
|
14
|
+
* 2026-09-30).
|
|
11
15
|
*/
|
|
12
|
-
export type EmailInputVerifyState = 'default' | 'typing' | 'filled' | 'error' | 'loading';
|
|
16
|
+
export type EmailInputVerifyState = 'default' | 'typing' | 'filled' | 'error' | 'loading' | 'emptyError';
|
|
13
17
|
/**
|
|
14
18
|
* The `email.OTP.*` sections — same layout, different code-field state:
|
|
15
19
|
* - `typing` — focused field, partial code, CTA enabled, and the line
|
|
@@ -27,6 +31,12 @@ export interface EmailInputStrings {
|
|
|
27
31
|
verifiedLabel: string;
|
|
28
32
|
/** Accessible name for the logo nav row. */
|
|
29
33
|
navLabel?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Error row under the required field when the primary CTA is pressed with it
|
|
36
|
+
* still empty (the verify screen's `emptyError` state): "This field is
|
|
37
|
+
* required". SDK key `dynamicForms.fieldRequired`.
|
|
38
|
+
*/
|
|
39
|
+
requiredError: string;
|
|
30
40
|
/** email.verifyEmail.* */
|
|
31
41
|
verify: {
|
|
32
42
|
/** H2 ("Verify your email"). */
|
|
@@ -41,6 +41,13 @@ export interface EmailInputVerifyScreenProps extends Omit<PrizmaFormScreenProps,
|
|
|
41
41
|
* paints the DISABLED surface (owner definition 2026-07-12), which would grey
|
|
42
42
|
* the four resting states Figma draws white. The field is uncontrolled instead
|
|
43
43
|
* (DEVIATIONS #PI-6).
|
|
44
|
+
*
|
|
45
|
+
* `emptyError` is the empty-submit state (rule from Elena, 2026-09-30,
|
|
46
|
+
* GUIDELINES §6-E empty-submit rule): "Continue" was pressed with nothing
|
|
47
|
+
* typed. The field renders empty with no placeholder, in Core's error state
|
|
48
|
+
* with `requiredError`, and the primary CTA is disabled, following the drawn
|
|
49
|
+
* precedent in `FormsFieldScreen`. The resting `default` keeps the CTA enabled
|
|
50
|
+
* so the user can reach this state.
|
|
44
51
|
*/
|
|
45
52
|
export declare const EmailInputVerifyScreen: React.ForwardRefExoticComponent<EmailInputVerifyScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
46
53
|
export default EmailInputVerifyScreen;
|
|
@@ -31,23 +31,37 @@ import './ScreenLayout.css';
|
|
|
31
31
|
* paints the DISABLED surface (owner definition 2026-07-12), which would grey
|
|
32
32
|
* the four resting states Figma draws white. The field is uncontrolled instead
|
|
33
33
|
* (DEVIATIONS #PI-6).
|
|
34
|
+
*
|
|
35
|
+
* `emptyError` is the empty-submit state (rule from Elena, 2026-09-30,
|
|
36
|
+
* GUIDELINES §6-E empty-submit rule): "Continue" was pressed with nothing
|
|
37
|
+
* typed. The field renders empty with no placeholder, in Core's error state
|
|
38
|
+
* with `requiredError`, and the primary CTA is disabled, following the drawn
|
|
39
|
+
* precedent in `FormsFieldScreen`. The resting `default` keeps the CTA enabled
|
|
40
|
+
* so the user can reach this state.
|
|
34
41
|
*/
|
|
35
42
|
export const EmailInputVerifyScreen = forwardRef(({ strings, state = 'default', value, screenId = `email-input-verify-${state}`, overrides, onAction, ...shell }, ref) => {
|
|
36
43
|
const busy = state === 'loading';
|
|
37
44
|
const invalid = state === 'error';
|
|
45
|
+
// Empty submit: the field drops its placeholder and takes Core's error
|
|
46
|
+
// state with the shared "required" row; the CTA greys.
|
|
47
|
+
const emptyError = state === 'emptyError';
|
|
38
48
|
const focused = state === 'typing' || state === 'filled';
|
|
39
49
|
return (_jsx(PrizmaFormScreen, { ref: ref, title: strings.verify.title, subtitle: strings.verify.subtitle, ctaLabel: strings.verify.ctaLabel,
|
|
40
50
|
/* Figma's `loading` section swaps the CTA label for Core's spinner. */
|
|
41
|
-
ctaLoading: busy, ctaLoadingLabel: strings.verify.ctaLoadingLabel, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell, children: _jsx(PrizmaTextField, { className:
|
|
51
|
+
ctaLoading: busy, ctaDisabled: emptyError, ctaLoadingLabel: strings.verify.ctaLoadingLabel, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell, children: _jsx(PrizmaTextField, { className:
|
|
42
52
|
/* Core's OWN static-focus modifier — the class its CSS already
|
|
43
53
|
implements beside `:focus-within`. `PrizmaTextField` has no
|
|
44
54
|
`forceState` prop the way `PrizmaDropdown` does, so this is how a
|
|
45
55
|
static spec state draws the focus ring without redeclaring any
|
|
46
56
|
styling (DEVIATIONS #PI-7). */
|
|
47
|
-
focused ? 'prizma-input-textfield--focused' : undefined, type: "email", inputMode: "email", autoComplete: "email", "aria-label": strings.verify.fieldLabel, placeholder: strings.verify.placeholder,
|
|
57
|
+
focused ? 'prizma-input-textfield--focused' : undefined, type: "email", inputMode: "email", autoComplete: "email", "aria-label": strings.verify.fieldLabel, placeholder: emptyError ? undefined : strings.verify.placeholder,
|
|
48
58
|
/* Uncontrolled: a screen is one static spec state, so no `onChange`
|
|
49
59
|
is needed and no warning is raised. */
|
|
50
|
-
defaultValue: value ?? '', disabled: busy, error: invalid, errorText: invalid
|
|
60
|
+
defaultValue: emptyError ? '' : value ?? '', disabled: busy, error: invalid || emptyError, errorText: invalid
|
|
61
|
+
? strings.verify.errorText
|
|
62
|
+
: emptyError
|
|
63
|
+
? strings.requiredError
|
|
64
|
+
: undefined,
|
|
51
65
|
/* The clear ✕ is drawn on the `error` section only. */
|
|
52
66
|
clearable: invalid, clearLabel: strings.verify.clearLabel }) }));
|
|
53
67
|
});
|
|
@@ -8,9 +8,9 @@ import './FaceMatchLayout.css';
|
|
|
8
8
|
* contract as `camera` on the capture screens) — Face Match never captures. */
|
|
9
9
|
export type FaceMatchPhotoRole = 'selfie' | 'id' | 'nfc' | 'secondId';
|
|
10
10
|
/** Host-supplied portraits, one per role the chosen variant asks for. A role
|
|
11
|
-
* left out renders the empty state
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* left out renders the empty state (capture missing or not retrievable): a
|
|
12
|
+
* grey Surface/Neutral/100 disc under its usual label tooltip, marked with
|
|
13
|
+
* `.face-match-cluster__photo--empty`. See FaceMatchLayout.css. */
|
|
14
14
|
export type FaceMatchComparisonPhotos = Partial<Record<FaceMatchPhotoRole, ReactNode>>;
|
|
15
15
|
/**
|
|
16
16
|
* Where the comparison is in its own choreography — the module MOVING rather
|
package/dist/FaceMatchLayout.css
CHANGED
|
@@ -57,8 +57,14 @@
|
|
|
57
57
|
|
|
58
58
|
/* The disc's diameter, named once. `--matching`'s rosette and `--animated`'s
|
|
59
59
|
* convergence both have to know it, and a second literal is a second thing to
|
|
60
|
-
* forget. Still a design literal, still DEVIATIONS #FM-22 — just not repeated.
|
|
61
|
-
|
|
60
|
+
* forget. Still a design literal, still DEVIATIONS #FM-22 — just not repeated.
|
|
61
|
+
*
|
|
62
|
+
* 160 at most, and smaller when two discs and their gap do not fit the
|
|
63
|
+
* content column: on a 320 phone the column is 272, so each disc takes
|
|
64
|
+
* (272 − 16) / 2 = 128 (Camila, 2026-09-28). `100cqi` is the screen shell's
|
|
65
|
+
* width (ScreenShell.css, `container-type: size`), less its two Spacing/24
|
|
66
|
+
* gutters. At 390 and up this resolves to 160, unchanged. */
|
|
67
|
+
--face-match-photo: min(160px, calc((100cqi - 2 * var(--prizma-spacing-24) - var(--prizma-spacing-16)) / 2));
|
|
62
68
|
/* Half the distance between two neighbouring discs: what one of them has to
|
|
63
69
|
* travel to reach the pair's centre line. */
|
|
64
70
|
--face-match-half-step: calc((var(--face-match-photo, 160px) + var(--prizma-spacing-16)) / 2);
|
|
@@ -118,16 +124,16 @@
|
|
|
118
124
|
background: var(--prizma-surface-neutral-100);
|
|
119
125
|
}
|
|
120
126
|
|
|
121
|
-
/* No photo
|
|
127
|
+
/* No photo for this role: the capture was never taken, or could not be
|
|
128
|
+
* retrieved.
|
|
122
129
|
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* the
|
|
127
|
-
*
|
|
128
|
-
* so swapping it in is a one-rule change and nothing downstream moves. */
|
|
130
|
+
* Owner call 2026-09-28 (replaces the 2026-09-25 Brand/50 interim): a plain
|
|
131
|
+
* grey disc, Surface/Neutral/100, the same neutral Core puts behind an image
|
|
132
|
+
* that is not there yet (CaptureDigitalId.css, list.css). The callout above it
|
|
133
|
+
* still renders, so the tooltip names which capture is missing. The modifier
|
|
134
|
+
* stays a named state so a richer treatment is still a one-rule change. */
|
|
129
135
|
.face-match-cluster__photo--empty {
|
|
130
|
-
background: var(--prizma-surface-
|
|
136
|
+
background: var(--prizma-surface-neutral-100);
|
|
131
137
|
}
|
|
132
138
|
|
|
133
139
|
.face-match-cluster__photo > img,
|
|
@@ -153,11 +159,14 @@
|
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
.face-match-cluster--matching .face-match-cluster__face + .face-match-cluster__face {
|
|
156
|
-
|
|
162
|
+
/* Figma converged overlap, 44 on the 160 disc; no token (verified absent).
|
|
163
|
+
* Kept as that ratio so the rosette holds its shape on a smaller disc. */
|
|
164
|
+
margin-left: calc(var(--face-match-photo, 160px) * -44 / 160);
|
|
157
165
|
}
|
|
158
166
|
|
|
159
167
|
.face-match-cluster--matching .face-match-cluster__row + .face-match-cluster__row {
|
|
160
|
-
|
|
168
|
+
/* Half a disc: 80 on the 160 disc (`2 × Spacing/40`), proportional below it. */
|
|
169
|
+
margin-top: calc(var(--face-match-photo, 160px) / -2);
|
|
161
170
|
}
|
|
162
171
|
|
|
163
172
|
/* ── The comparison, moving (`phase` on FaceMatchComparisonScreen) ───────────
|
package/dist/FormScreen.css
CHANGED
|
@@ -129,6 +129,22 @@
|
|
|
129
129
|
flex: none;
|
|
130
130
|
width: calc(50% - var(--prizma-spacing-16) / 2);
|
|
131
131
|
min-width: 0;
|
|
132
|
+
position: relative;
|
|
133
|
+
}
|
|
134
|
+
/* An error or helper line under ONE field of a pair made that field taller,
|
|
135
|
+
* and the bottom alignment above lifted its input above its neighbour's
|
|
136
|
+
* (Elena, 2026-10-02: "estos inputs tienen que estar alineados"). The line
|
|
137
|
+
* hangs below its input instead, out of the alignment, and the row reserves
|
|
138
|
+
* its height so the next row does not ride over it. */
|
|
139
|
+
.prizma-form-screen--responsive .prizma-form-screen__row > * > [class$="__error"],
|
|
140
|
+
.prizma-form-screen--responsive .prizma-form-screen__row > * > [class$="__helper"] {
|
|
141
|
+
position: absolute;
|
|
142
|
+
top: 100%;
|
|
143
|
+
left: 0;
|
|
144
|
+
margin-top: var(--prizma-spacing-8);
|
|
145
|
+
}
|
|
146
|
+
.prizma-form-screen--responsive .prizma-form-screen__row:has(> * > [class$="__error"], > * > [class$="__helper"]) {
|
|
147
|
+
padding-bottom: calc(var(--prizma-spacing-8) + var(--prizma-body-m-regular-line-height));
|
|
132
148
|
}
|
|
133
149
|
|
|
134
150
|
/* Continue and Back share a row: Back on the left, Continue on the right, as
|
|
@@ -65,6 +65,14 @@ export interface FormsLongFormScreenProps extends Omit<PrizmaFormScreenProps, 't
|
|
|
65
65
|
* into the CTA band — the half a module stylesheet kept losing. It is a no-op
|
|
66
66
|
* on the short `name` preset, whose rows never overflow. DEVIATIONS #DSC-2,
|
|
67
67
|
* restating #CURP-1.
|
|
68
|
+
*
|
|
69
|
+
* `emptyError` is the GUIDELINES §6-E empty-submit rule (Elena 2026-09-30):
|
|
70
|
+
* the user pressed the CTA with the form still empty. Every REQUIRED row
|
|
71
|
+
* renders empty, with no placeholder, in Core's own error state carrying
|
|
72
|
+
* `strings.requiredError`; optional and unmarked rows stay on their resting
|
|
73
|
+
* surface with no error. The CTA greys there and ONLY there: the resting
|
|
74
|
+
* `default` keeps it enabled, so the user can press it to reach the error —
|
|
75
|
+
* the `FormsFieldScreen` `emptyError` precedent applied to a stack.
|
|
68
76
|
*/
|
|
69
77
|
export declare const FormsLongFormScreen: React.ForwardRefExoticComponent<FormsLongFormScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
70
78
|
export default FormsLongFormScreen;
|