@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
|
@@ -46,6 +46,13 @@ export interface CurpEnterScreenProps extends Omit<PrizmaFormScreenProps, 'title
|
|
|
46
46
|
* `linkContent` slot: no primitive is invented, no layout is declared, and the
|
|
47
47
|
* two actions stay distinguishable (`cta` vs `secondary`, the #PI-10 rule).
|
|
48
48
|
* The gap is reported for promotion โ see the module's DEVIATIONS rows.
|
|
49
|
+
*
|
|
50
|
+
* `emptyError` is the empty-submit state (rule from Elena, 2026-09-30,
|
|
51
|
+
* GUIDELINES ยง6-E empty-submit rule): "Continue" was pressed with nothing
|
|
52
|
+
* typed. The field renders empty with no placeholder, in Core's error state
|
|
53
|
+
* with `requiredError`, and the primary CTA is disabled, following the drawn
|
|
54
|
+
* precedent in `FormsFieldScreen`. The resting `default` keeps the CTA enabled
|
|
55
|
+
* so the user can reach this state.
|
|
49
56
|
*/
|
|
50
57
|
export declare const CurpEnterScreen: React.ForwardRefExoticComponent<CurpEnterScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
51
58
|
export default CurpEnterScreen;
|
package/dist/CurpEnterScreen.js
CHANGED
|
@@ -37,6 +37,13 @@ import './CurpLayout.css';
|
|
|
37
37
|
* `linkContent` slot: no primitive is invented, no layout is declared, and the
|
|
38
38
|
* two actions stay distinguishable (`cta` vs `secondary`, the #PI-10 rule).
|
|
39
39
|
* The gap is reported for promotion โ see the module's DEVIATIONS rows.
|
|
40
|
+
*
|
|
41
|
+
* `emptyError` is the empty-submit state (rule from Elena, 2026-09-30,
|
|
42
|
+
* GUIDELINES ยง6-E empty-submit rule): "Continue" was pressed with nothing
|
|
43
|
+
* typed. The field renders empty with no placeholder, in Core's error state
|
|
44
|
+
* with `requiredError`, and the primary CTA is disabled, following the drawn
|
|
45
|
+
* precedent in `FormsFieldScreen`. The resting `default` keeps the CTA enabled
|
|
46
|
+
* so the user can reach this state.
|
|
40
47
|
*/
|
|
41
48
|
export const CurpEnterScreen = forwardRef(({ strings, state = 'default', value, screenId = `curp-enter-${state}`, className, overrides, onAction, ...shell }, ref) => {
|
|
42
49
|
// Figma treats the five sections as four distinct field treatments:
|
|
@@ -47,6 +54,9 @@ export const CurpEnterScreen = forwardRef(({ strings, state = 'default', value,
|
|
|
47
54
|
// surface.
|
|
48
55
|
const busy = state === 'loading';
|
|
49
56
|
const invalid = state === 'error';
|
|
57
|
+
// Empty submit: the field stays empty, drops its placeholder and takes
|
|
58
|
+
// Core's error state with the shared "required" row; the CTA greys.
|
|
59
|
+
const emptyError = state === 'emptyError';
|
|
50
60
|
const focused = state === 'focused' || state === 'filled';
|
|
51
61
|
return (_jsx(PrizmaFormScreen, { ref: ref,
|
|
52
62
|
/* Scopes the one module rule that lets the `error` section keep the
|
|
@@ -63,11 +73,15 @@ export const CurpEnterScreen = forwardRef(({ strings, state = 'default', value,
|
|
|
63
73
|
.filter(Boolean)
|
|
64
74
|
.join(' '), title: strings.enter.title, subtitle: strings.enter.subtitle, ctaLabel: strings.enter.ctaLabel,
|
|
65
75
|
/* The `loading` section swaps the CTA label for Core's spinner. */
|
|
66
|
-
ctaLoading: busy, ctaLoadingLabel: strings.enter.ctaLoadingLabel, linkContent: _jsx(PrizmaButton, { variant: "secondary", size: "L",
|
|
76
|
+
ctaLoading: busy, ctaDisabled: emptyError, ctaLoadingLabel: strings.enter.ctaLoadingLabel, linkContent: _jsx(PrizmaButton, { variant: "secondary", size: "L",
|
|
67
77
|
/* Figma greys this action too while the lookup runs. */
|
|
68
|
-
disabled: busy, onClick: () => onAction?.({ type: 'secondary', screenId }), children: strings.enter.noCurpLabel }), verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell, children: _jsx(PrizmaTextField, { className: focused ? 'prizma-input-textfield--focused' : undefined, "aria-label": strings.enter.fieldLabel, placeholder: strings.enter.placeholder, defaultValue: value ?? '',
|
|
78
|
+
disabled: busy, onClick: () => onAction?.({ type: 'secondary', screenId }), children: strings.enter.noCurpLabel }), verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell, children: _jsx(PrizmaTextField, { className: focused ? 'prizma-input-textfield--focused' : undefined, "aria-label": strings.enter.fieldLabel, placeholder: emptyError ? undefined : strings.enter.placeholder, defaultValue: emptyError ? '' : value ?? '',
|
|
69
79
|
/* A CURP is an 18-character uppercase key. */
|
|
70
|
-
autoCapitalize: "characters", autoComplete: "off", spellCheck: false, disabled: busy, error: invalid, errorText: invalid
|
|
80
|
+
autoCapitalize: "characters", autoComplete: "off", spellCheck: false, disabled: busy, error: invalid || emptyError, errorText: invalid
|
|
81
|
+
? strings.enter.errorText
|
|
82
|
+
: emptyError
|
|
83
|
+
? strings.requiredError
|
|
84
|
+
: undefined,
|
|
71
85
|
/* The clear โ is drawn only on the error section (76:36434); the
|
|
72
86
|
`filled` section (79:1553) draws none. Core still owns WHEN it
|
|
73
87
|
shows โ its `--show` state needs a value in the field. */
|
|
@@ -42,6 +42,14 @@ export interface CurpGenerateScreenProps extends Omit<PrizmaFormScreenProps, 'ti
|
|
|
42
42
|
* The `dropdown` section IS the open-menu spec state, which Core exposes as the
|
|
43
43
|
* documentation-only `forceOpen` (a screen is one static state, never a live
|
|
44
44
|
* interaction) โ the same mechanism Phone Input's `countryCode` section uses.
|
|
45
|
+
*
|
|
46
|
+
* `emptyError` is the empty-submit state (rule from Elena, 2026-09-30,
|
|
47
|
+
* GUIDELINES ยง6-E empty-submit rule): "Generate" was pressed with the form
|
|
48
|
+
* empty. All six fields carry the required `*`, so all six render empty with no
|
|
49
|
+
* placeholder, in Core's error state with `requiredError`; no menu is open and
|
|
50
|
+
* the primary CTA is disabled, following the drawn precedent in
|
|
51
|
+
* `FormsFieldScreen`. The resting `default` keeps the CTA enabled so the user
|
|
52
|
+
* can reach this state.
|
|
45
53
|
*/
|
|
46
54
|
export declare const CurpGenerateScreen: React.ForwardRefExoticComponent<CurpGenerateScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
47
55
|
export default CurpGenerateScreen;
|
|
@@ -29,29 +29,44 @@ import './CurpLayout.css';
|
|
|
29
29
|
* The `dropdown` section IS the open-menu spec state, which Core exposes as the
|
|
30
30
|
* documentation-only `forceOpen` (a screen is one static state, never a live
|
|
31
31
|
* interaction) โ the same mechanism Phone Input's `countryCode` section uses.
|
|
32
|
+
*
|
|
33
|
+
* `emptyError` is the empty-submit state (rule from Elena, 2026-09-30,
|
|
34
|
+
* GUIDELINES ยง6-E empty-submit rule): "Generate" was pressed with the form
|
|
35
|
+
* empty. All six fields carry the required `*`, so all six render empty with no
|
|
36
|
+
* placeholder, in Core's error state with `requiredError`; no menu is open and
|
|
37
|
+
* the primary CTA is disabled, following the drawn precedent in
|
|
38
|
+
* `FormsFieldScreen`. The resting `default` keeps the CTA enabled so the user
|
|
39
|
+
* can reach this state.
|
|
32
40
|
*/
|
|
33
41
|
export const CurpGenerateScreen = forwardRef(({ strings, state = 'default', values, genders = [], states = [], screenId = `curp-generate-${state}`, className, overrides, onAction, ...shell }, ref) => {
|
|
34
42
|
const copy = strings.generate;
|
|
43
|
+
// Empty submit: every required field drops its value and placeholder and
|
|
44
|
+
// takes Core's error state with the shared "required" row; the CTA greys.
|
|
45
|
+
const emptyError = state === 'emptyError';
|
|
46
|
+
const ph = (placeholder) => (emptyError ? undefined : placeholder);
|
|
47
|
+
const err = {
|
|
48
|
+
error: emptyError,
|
|
49
|
+
errorText: emptyError ? strings.requiredError : undefined,
|
|
50
|
+
};
|
|
35
51
|
return (_jsxs(PrizmaFormScreen, { ref: ref,
|
|
36
|
-
/*
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
className: [
|
|
52
|
+
/* The six-field stack scrolls inside the 844 frame through the
|
|
53
|
+
foundation's `scrollFields` (overflow + the Spacing/16 that keeps the
|
|
54
|
+
cut clear of "Generate"). EVERY section gets it, `dropdown` included:
|
|
55
|
+
Figma draws "Generate" clear and unobstructed under the open menu.
|
|
56
|
+
It replaces the module's old `--scroll` rule, which scrolled but
|
|
57
|
+
carried no spacing, so the last field ran flush into the button.
|
|
58
|
+
`--menu-open` (CurpLayout.css) flips Core's absolutely-positioned
|
|
59
|
+
menu above its trigger on the one section that forces it open, so
|
|
60
|
+
the three gender rows stay inside the scrolling column. */
|
|
61
|
+
scrollFields: true, className: [
|
|
46
62
|
'curp-generate',
|
|
47
|
-
'curp-generate--scroll',
|
|
48
63
|
state === 'dropdown' ? 'curp-generate--menu-open' : '',
|
|
49
64
|
className,
|
|
50
65
|
]
|
|
51
66
|
.filter(Boolean)
|
|
52
|
-
.join(' '), title: copy.title, subtitle: copy.subtitle, ctaLabel: copy.ctaLabel, ctaLoadingLabel: copy.ctaLoadingLabel, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell, children: [_jsx(PrizmaTextField, { label: copy.firstName.label, placeholder: copy.firstName.placeholder, required: true, requiredHint: strings.requiredHint, autoComplete: "off", defaultValue: values?.firstName ?? '' }), _jsx(PrizmaTextField, { label: copy.firstLastName.label, placeholder: copy.firstLastName.placeholder, required: true, requiredHint: strings.requiredHint, autoComplete: "off", defaultValue: values?.firstLastName ?? '' }), _jsx(PrizmaTextField, { label: copy.secondLastName.label, placeholder: copy.secondLastName.placeholder, required: true, requiredHint: strings.requiredHint, autoComplete: "off", defaultValue: values?.secondLastName ?? '' }), _jsx(PrizmaDropdown, { label: copy.gender.label, placeholder: copy.gender.placeholder, required: true, requiredHint: strings.requiredHint, options: genders, defaultValue: values?.gender ?? null, searchPlaceholder: copy.gender.searchPlaceholder,
|
|
67
|
+
.join(' '), title: copy.title, subtitle: copy.subtitle, ctaLabel: copy.ctaLabel, ctaDisabled: emptyError, ctaLoadingLabel: copy.ctaLoadingLabel, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell, children: [_jsx(PrizmaTextField, { label: copy.firstName.label, placeholder: ph(copy.firstName.placeholder), required: true, requiredHint: strings.requiredHint, autoComplete: "off", defaultValue: emptyError ? '' : values?.firstName ?? '', ...err }), _jsx(PrizmaTextField, { label: copy.firstLastName.label, placeholder: ph(copy.firstLastName.placeholder), required: true, requiredHint: strings.requiredHint, autoComplete: "off", defaultValue: emptyError ? '' : values?.firstLastName ?? '', ...err }), _jsx(PrizmaTextField, { label: copy.secondLastName.label, placeholder: ph(copy.secondLastName.placeholder), required: true, requiredHint: strings.requiredHint, autoComplete: "off", defaultValue: emptyError ? '' : values?.secondLastName ?? '', ...err }), _jsx(PrizmaDropdown, { label: copy.gender.label, placeholder: ph(copy.gender.placeholder), required: true, requiredHint: strings.requiredHint, options: genders, defaultValue: emptyError ? null : values?.gender ?? null, ...err, searchPlaceholder: copy.gender.searchPlaceholder,
|
|
53
68
|
/* The `dropdown` section is the open Gender menu. */
|
|
54
|
-
forceOpen: state === 'dropdown' }), _jsx(PrizmaDateField, { label: copy.dateOfBirth.label, placeholder: copy.dateOfBirth.placeholder, required: true, requiredHint: strings.requiredHint, calendarLabel: copy.dateOfBirth.calendarLabel, defaultValue: values?.dateOfBirth ?? '' }), _jsx(PrizmaDropdown, { label: copy.birthState.label, placeholder: copy.birthState.placeholder, required: true, requiredHint: strings.requiredHint, options: states, defaultValue: values?.birthState ?? null, searchable: true, searchPlaceholder: copy.birthState.searchPlaceholder })] }));
|
|
69
|
+
forceOpen: state === 'dropdown' }), _jsx(PrizmaDateField, { label: copy.dateOfBirth.label, placeholder: ph(copy.dateOfBirth.placeholder), required: true, requiredHint: strings.requiredHint, calendarLabel: copy.dateOfBirth.calendarLabel, defaultValue: emptyError ? '' : values?.dateOfBirth ?? '', ...err }), _jsx(PrizmaDropdown, { label: copy.birthState.label, placeholder: ph(copy.birthState.placeholder), required: true, requiredHint: strings.requiredHint, options: states, defaultValue: emptyError ? null : values?.birthState ?? null, ...err, searchable: true, searchPlaceholder: copy.birthState.searchPlaceholder })] }));
|
|
55
70
|
});
|
|
56
71
|
CurpGenerateScreen.displayName = 'CurpGenerateScreen';
|
|
57
72
|
export default CurpGenerateScreen;
|
package/dist/CurpLayout.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* CURP โ module layout additions.
|
|
2
2
|
*
|
|
3
|
-
*
|
|
3
|
+
* TWO rules, and none of them declares spacing: the content column, the 24px
|
|
4
4
|
* gutters, the title โ fields Spacing/32, the field gaps, the CTA column and
|
|
5
5
|
* the anchored footer all stay the foundation's (`ScreenLayout.css`,
|
|
6
6
|
* `FormScreen.css`). Nothing here re-declares an archetype value, invents a
|
|
@@ -10,40 +10,14 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
/* โโ The generator's field stack is taller than the screen โโโโโโโโโโโโโโโโโโโ
|
|
13
|
-
* `CURP.Gene.default` is a 1051-tall frame
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* one or two fields โ so the surplus is silently clipped by `ScreenShell`'s
|
|
21
|
-
* `overflow: hidden`, and (because the fields cannot shrink below
|
|
22
|
-
* `--prizma-input-size-field-height`) it first PAINTS OVER the sibling CTA.
|
|
23
|
-
* Screens are authored at 390ร844 and never reflow (README / DEVIATIONS #17),
|
|
24
|
-
* so growing the frame is not an option either.
|
|
25
|
-
*
|
|
26
|
-
* The stack is therefore allowed to scroll INSIDE the column: the title, the
|
|
27
|
-
* CTA and the anchored tag stay put and the six fields pan, which is the
|
|
28
|
-
* closest a fixed 844 frame gets to Figma's taller page. It adds NO padding, NO
|
|
29
|
-
* gap and NO size of its own.
|
|
30
|
-
*
|
|
31
|
-
* Applied to EVERY `CURP.Gene.*` section including `dropdown`. The earlier
|
|
32
|
-
* build withheld it from `dropdown` to keep Core's absolutely-positioned menu
|
|
33
|
-
* from being clipped, and that traded one clipped element for a worse one: with
|
|
34
|
-
* `overflow: visible` the 548-tall stack overflowed its box and painted the
|
|
35
|
-
* open menu straight across the "Generate" button, which Figma (2058:16373)
|
|
36
|
-
* draws clear and unobstructed under the menu. The CTA is never allowed to be
|
|
37
|
-
* overlapped; the menu is handled by the next rule instead.
|
|
38
|
-
*
|
|
39
|
-
* FOUNDATION REQUEST: promote this to `FormScreen.css` as a
|
|
40
|
-
* `.prizma-form-screen__fields--scroll` variant (or make overflow the default),
|
|
41
|
-
* driven by a `scrollFields` prop on `PrizmaFormScreen`. Every long-form module
|
|
42
|
-
* still to come in Wave 3 โ eKYC, eKYB, address entry โ will hit the same wall.
|
|
13
|
+
* `CURP.Gene.default` is a 1051-tall frame (six 78px labelled fields at
|
|
14
|
+
* Spacing/16), so at 390ร844 the stack scrolls inside the column. That is the
|
|
15
|
+
* foundation's `scrollFields` on `PrizmaFormScreen` now (FormScreen.css
|
|
16
|
+
* `__fields--scroll`), which also carries the Spacing/16 between the cut and
|
|
17
|
+
* the CTA. The module used to hand-roll `overflow-y: auto` here with no
|
|
18
|
+
* spacing, so the last field ran flush into "Generate" (Elena, 2026-09-30).
|
|
19
|
+
* Removed in favour of the foundation rule.
|
|
43
20
|
*/
|
|
44
|
-
.curp-generate--scroll .prizma-form-screen__fields {
|
|
45
|
-
overflow-y: auto;
|
|
46
|
-
}
|
|
47
21
|
|
|
48
22
|
/* โโ The open Gender menu must stay inside the scrolling column โโโโโโโโโโโโโโ
|
|
49
23
|
* `CURP.Gene.dropdown` exists to show the three gender rows, so they may not be
|
package/dist/CurpStrings.d.ts
CHANGED
|
@@ -11,15 +11,23 @@
|
|
|
11
11
|
* - `error` โ negative field + clear โ + the "Invalid CURP" row
|
|
12
12
|
* - `loading` โ both actions inert while the lookup runs; the spinner rides the
|
|
13
13
|
* CTA, never the field (the Phone Input lesson, DEVIATIONS #PI-5)
|
|
14
|
+
* - `emptyError` โ "Continue" pressed with the field still empty: the field
|
|
15
|
+
* stays empty (no placeholder) in Core's error state with `requiredError`,
|
|
16
|
+
* and the CTA is disabled. GUIDELINES ยง6-E empty-submit rule (Elena,
|
|
17
|
+
* 2026-09-30).
|
|
14
18
|
*/
|
|
15
|
-
export type CurpEnterState = 'default' | 'focused' | 'filled' | 'error' | 'loading';
|
|
19
|
+
export type CurpEnterState = 'default' | 'focused' | 'filled' | 'error' | 'loading' | 'emptyError';
|
|
16
20
|
/**
|
|
17
21
|
* The `CURP.Gene.*` form sections โ the six-field generator:
|
|
18
22
|
* - `default` โ every field empty on its placeholder
|
|
19
23
|
* - `dropdown` โ the Gender menu open over the form (Core's `forceOpen`)
|
|
20
24
|
* - `filled` โ every field carrying a value
|
|
25
|
+
* - `emptyError` โ "Generate" pressed with the form still empty: every required
|
|
26
|
+
* field stays empty (no placeholder) in Core's error state with
|
|
27
|
+
* `requiredError`, no menu is open, and the CTA is disabled. GUIDELINES ยง6-E
|
|
28
|
+
* empty-submit rule (Elena, 2026-09-30).
|
|
21
29
|
*/
|
|
22
|
-
export type CurpGenerateState = 'default' | 'dropdown' | 'filled';
|
|
30
|
+
export type CurpGenerateState = 'default' | 'dropdown' | 'filled' | 'emptyError';
|
|
23
31
|
/**
|
|
24
32
|
* The two spinner sections. `verifying` is `CURP.EnterCURP.veryfing` (the
|
|
25
33
|
* Figma layer name carries the typo); `generating` is `CURP.Gene.generating`.
|
|
@@ -73,6 +81,12 @@ export interface CurpStrings {
|
|
|
73
81
|
* the marker is localizable and never hardcoded in a screen.
|
|
74
82
|
*/
|
|
75
83
|
requiredHint?: string;
|
|
84
|
+
/**
|
|
85
|
+
* Error row under every required field left empty when the primary CTA is
|
|
86
|
+
* pressed (the `emptyError` state of the entry and generator forms):
|
|
87
|
+
* "This field is required". SDK key `dynamicForms.fieldRequired`.
|
|
88
|
+
*/
|
|
89
|
+
requiredError: string;
|
|
76
90
|
/** CURP.EnterCURP.{default,focused,filled,error,loading} */
|
|
77
91
|
enter: {
|
|
78
92
|
/** H2 ("Enter your CURP"). */
|
|
@@ -56,6 +56,13 @@ export interface EkybAddressDetailsScreenProps extends Omit<PrizmaFormScreenProp
|
|
|
56
56
|
* segment 2 solid, segment 3 grey) is Core's `PrizmaStepper` at
|
|
57
57
|
* `currentState={2}`, composed into the archetype's `progress` slot. This is
|
|
58
58
|
* step 2 of 3.
|
|
59
|
+
*
|
|
60
|
+
* `emptyError` is Continue pressed with the fields still empty (Elena,
|
|
61
|
+
* 2026-09-30, GUIDELINES ยง6-E empty-submit rule; precedent `FormsFieldScreen`'s
|
|
62
|
+
* `emptyError`): every field renders empty, the five REQUIRED ones (State
|
|
63
|
+
* included) in Core's `error` state with `requiredError` and no placeholder,
|
|
64
|
+
* Address line 2 unflagged (optional, DEVIATIONS #EKC-6's rule), and Continue
|
|
65
|
+
* disabled. `empty` keeps Continue enabled so the press can happen.
|
|
59
66
|
*/
|
|
60
67
|
export declare const EkybAddressDetailsScreen: React.ForwardRefExoticComponent<EkybAddressDetailsScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
61
68
|
export default EkybAddressDetailsScreen;
|
|
@@ -46,22 +46,40 @@ import './ScreenLayout.css';
|
|
|
46
46
|
* segment 2 solid, segment 3 grey) is Core's `PrizmaStepper` at
|
|
47
47
|
* `currentState={2}`, composed into the archetype's `progress` slot. This is
|
|
48
48
|
* step 2 of 3.
|
|
49
|
+
*
|
|
50
|
+
* `emptyError` is Continue pressed with the fields still empty (Elena,
|
|
51
|
+
* 2026-09-30, GUIDELINES ยง6-E empty-submit rule; precedent `FormsFieldScreen`'s
|
|
52
|
+
* `emptyError`): every field renders empty, the five REQUIRED ones (State
|
|
53
|
+
* included) in Core's `error` state with `requiredError` and no placeholder,
|
|
54
|
+
* Address line 2 unflagged (optional, DEVIATIONS #EKC-6's rule), and Continue
|
|
55
|
+
* disabled. `empty` keeps Continue enabled so the press can happen.
|
|
49
56
|
*/
|
|
50
|
-
export const EkybAddressDetailsScreen = forwardRef(({ strings, state = 'empty', values, states = [], screenId = `ekyb-address-${state}`, className, overrides, onAction, ...shell }, ref) => {
|
|
57
|
+
export const EkybAddressDetailsScreen = forwardRef(({ strings, state = 'empty', values: valuesProp, states = [], screenId = `ekyb-address-${state}`, ctaDisabled, className, overrides, onAction, ...shell }, ref) => {
|
|
51
58
|
const copy = strings.address;
|
|
59
|
+
const emptyError = state === 'emptyError';
|
|
60
|
+
const values = emptyError ? undefined : valuesProp;
|
|
61
|
+
// Core's own error treatment, spread AFTER each required field's own
|
|
62
|
+
// placeholder so the error state shows none (the `FormsFieldScreen`
|
|
63
|
+
// precedent). Address line 2 never receives it.
|
|
64
|
+
const missing = emptyError
|
|
65
|
+
? { error: true, errorText: strings.requiredError, placeholder: undefined }
|
|
66
|
+
: {};
|
|
52
67
|
return (_jsxs(PrizmaFormScreen, { ref: ref, className: ['ekyb-address', className].filter(Boolean).join(' '),
|
|
53
68
|
/* The archetype's own scrolling field stack โ the six-field column is
|
|
54
69
|
548 tall against a middle that cannot be. No module CSS. */
|
|
55
70
|
scrollFields: true,
|
|
56
71
|
/* Step 2 of 3. `showIcons={false}`: the eKYB bar is a bare 5px rail. */
|
|
57
|
-
progress: _jsx(PrizmaStepper, { steps: 3, currentState: 2, showIcons: false, "aria-label": strings.stepperLabel }), title: copy.title, subtitle: copy.subtitle, ctaLabel: copy.ctaLabel,
|
|
58
|
-
/*
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
progress: _jsx(PrizmaStepper, { steps: 3, currentState: 2, showIcons: false, "aria-label": strings.stepperLabel }), title: copy.title, subtitle: copy.subtitle, ctaLabel: copy.ctaLabel,
|
|
73
|
+
/* Disabled only after the empty submit; `empty` keeps it enabled. */
|
|
74
|
+
ctaDisabled: emptyError || ctaDisabled, linkContent: _jsx(PrizmaButton, { variant: "secondary", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: strings.backLabel }), verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: { align: overrides?.align ?? 'left', logo: overrides?.logo }, onAction: onAction,
|
|
75
|
+
/* Exploration ekyb-desktop: on a wide frame the fields pair up in
|
|
76
|
+
three rows, Street + House number, Address line 2 + City (Elena,
|
|
77
|
+
2026-09-28), and State + Postal code (Figma 6407:43637). On the
|
|
78
|
+
phone nothing changes. */
|
|
79
|
+
responsive: true, ...shell, children: [_jsxs(PrizmaFormRow, { children: [_jsx(PrizmaTextField, { label: copy.street.label, placeholder: copy.street.placeholder, required: true, requiredHint: strings.requiredHint, ...missing, autoComplete: "off", defaultValue: values?.street ?? '' }), _jsx(PrizmaTextField, { label: copy.houseNumber.label, placeholder: copy.houseNumber.placeholder, required: true, requiredHint: strings.requiredHint, ...missing, autoComplete: "off", defaultValue: values?.houseNumber ?? '' })] }), _jsxs(PrizmaFormRow, { children: [_jsx(PrizmaTextField, { label: copy.addressLine2.label, placeholder: copy.addressLine2.placeholder, autoComplete: "off", defaultValue: values?.addressLine2 ?? '' }), _jsx(PrizmaTextField, { label: copy.city.label, placeholder: copy.city.placeholder, required: true, requiredHint: strings.requiredHint, ...missing, autoComplete: "off", defaultValue: values?.city ?? '' })] }), _jsxs(PrizmaFormRow, { children: [_jsx(PrizmaDropdown, { label: copy.state.label, placeholder: copy.state.placeholder, required: true, requiredHint: strings.requiredHint, ...missing, options: states,
|
|
62
80
|
/* Both sections draw the placeholder unless the host supplies a
|
|
63
81
|
value โ see the docstring note on 6340:38197. */
|
|
64
|
-
defaultValue: values?.state ?? null }), _jsx(PrizmaTextField, { label: copy.postalCode.label, placeholder: copy.postalCode.placeholder, required: true, requiredHint: strings.requiredHint, autoComplete: "off", defaultValue: values?.postalCode ?? '' })] })] }));
|
|
82
|
+
defaultValue: values?.state ?? null }), _jsx(PrizmaTextField, { label: copy.postalCode.label, placeholder: copy.postalCode.placeholder, required: true, requiredHint: strings.requiredHint, ...missing, autoComplete: "off", defaultValue: values?.postalCode ?? '' })] })] }));
|
|
65
83
|
});
|
|
66
84
|
EkybAddressDetailsScreen.displayName = 'EkybAddressDetailsScreen';
|
|
67
85
|
export default EkybAddressDetailsScreen;
|
|
@@ -50,6 +50,12 @@ export interface EkybBusinessDetailsScreenProps extends Omit<PrizmaFormScreenPro
|
|
|
50
50
|
* bar is at `currentState="Start"`: segment 1 filled, segments 2 and 3 grey,
|
|
51
51
|
* exactly what 5919:68599 renders. Both offsets around it live in
|
|
52
52
|
* `ScreenLayout.css`, never here.
|
|
53
|
+
*
|
|
54
|
+
* `emptyError` is Continue pressed with the fields still empty (Elena,
|
|
55
|
+
* 2026-09-30, GUIDELINES ยง6-E empty-submit rule; precedent `FormsFieldScreen`'s
|
|
56
|
+
* `emptyError`): both REQUIRED fields render empty in Core's `error` state with
|
|
57
|
+
* `requiredError` under them, and Continue is disabled. `empty` keeps Continue
|
|
58
|
+
* enabled so the press can happen.
|
|
53
59
|
*/
|
|
54
60
|
export declare const EkybBusinessDetailsScreen: React.ForwardRefExoticComponent<EkybBusinessDetailsScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
55
61
|
export default EkybBusinessDetailsScreen;
|
|
@@ -4,7 +4,7 @@ import { forwardRef } from 'react';
|
|
|
4
4
|
import { PrizmaTextField } from '@incodetech/prizma-core-web/text-field';
|
|
5
5
|
import { PrizmaButton } from '@incodetech/prizma-core-web/button';
|
|
6
6
|
import { PrizmaStepper } from '@incodetech/prizma-core-web/stepper';
|
|
7
|
-
import { PrizmaFormScreen
|
|
7
|
+
import { PrizmaFormScreen } from './FormScreen';
|
|
8
8
|
import './ScreenLayout.css';
|
|
9
9
|
/**
|
|
10
10
|
* eKYB โ step 1 of the wizard, the company's identity, built on the Form
|
|
@@ -42,19 +42,36 @@ import './ScreenLayout.css';
|
|
|
42
42
|
* bar is at `currentState="Start"`: segment 1 filled, segments 2 and 3 grey,
|
|
43
43
|
* exactly what 5919:68599 renders. Both offsets around it live in
|
|
44
44
|
* `ScreenLayout.css`, never here.
|
|
45
|
+
*
|
|
46
|
+
* `emptyError` is Continue pressed with the fields still empty (Elena,
|
|
47
|
+
* 2026-09-30, GUIDELINES ยง6-E empty-submit rule; precedent `FormsFieldScreen`'s
|
|
48
|
+
* `emptyError`): both REQUIRED fields render empty in Core's `error` state with
|
|
49
|
+
* `requiredError` under them, and Continue is disabled. `empty` keeps Continue
|
|
50
|
+
* enabled so the press can happen.
|
|
45
51
|
*/
|
|
46
|
-
export const EkybBusinessDetailsScreen = forwardRef(({ strings, state = 'empty', values, screenId = `ekyb-business-${state}`, overrides, onAction, ...shell }, ref) => {
|
|
52
|
+
export const EkybBusinessDetailsScreen = forwardRef(({ strings, state = 'empty', values: valuesProp, screenId = `ekyb-business-${state}`, ctaDisabled, overrides, onAction, ...shell }, ref) => {
|
|
47
53
|
const copy = strings.business;
|
|
48
|
-
|
|
54
|
+
const emptyError = state === 'emptyError';
|
|
55
|
+
const values = emptyError ? undefined : valuesProp;
|
|
56
|
+
// Core's own error treatment, spread onto the REQUIRED fields only; the
|
|
57
|
+
// error state shows no placeholder (the `FormsFieldScreen` precedent).
|
|
58
|
+
const missing = emptyError
|
|
59
|
+
? { error: true, errorText: strings.requiredError, placeholder: undefined }
|
|
60
|
+
: {};
|
|
61
|
+
return (_jsxs(PrizmaFormScreen, { ref: ref,
|
|
49
62
|
/* Step 1 of 3. `showIcons={false}` because the eKYB frames draw the bar
|
|
50
63
|
as a bare 5px rail with no glyph row. */
|
|
51
|
-
progress: _jsx(PrizmaStepper, { steps: 3, currentState: "Start", showIcons: false, "aria-label": strings.stepperLabel }), title: copy.title, subtitle: copy.subtitle, ctaLabel: copy.ctaLabel,
|
|
64
|
+
progress: _jsx(PrizmaStepper, { steps: 3, currentState: "Start", showIcons: false, "aria-label": strings.stepperLabel }), title: copy.title, subtitle: copy.subtitle, ctaLabel: copy.ctaLabel,
|
|
65
|
+
/* Disabled only after the empty submit; `empty` keeps it enabled. */
|
|
66
|
+
ctaDisabled: emptyError || ctaDisabled, linkContent: _jsx(PrizmaButton, { variant: "secondary", size: "L", onClick: () => onAction?.({ type: 'secondary', screenId }), children: strings.backLabel }), verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId,
|
|
52
67
|
/* Left-aligned title block, the alignment every eKYB frame draws; a host
|
|
53
68
|
`align` still wins (#GEO-2). */
|
|
54
69
|
overrides: { align: overrides?.align ?? 'left', logo: overrides?.logo }, onAction: onAction,
|
|
55
70
|
/* Exploration ekyb-desktop: on a tablet or desktop frame the two
|
|
56
|
-
fields
|
|
57
|
-
|
|
71
|
+
fields stay on two rows, each spanning the column (Elena,
|
|
72
|
+
2026-09-28); `responsive` still pairs Continue and Back. On the
|
|
73
|
+
phone nothing changes. */
|
|
74
|
+
responsive: true, ...shell, children: [_jsx(PrizmaTextField, { label: copy.businessName.label, placeholder: copy.businessName.placeholder, required: true, requiredHint: strings.requiredHint, ...missing, autoComplete: "off", defaultValue: values?.businessName ?? '' }), _jsx(PrizmaTextField, { label: copy.taxId.label, placeholder: copy.taxId.placeholder, required: true, requiredHint: strings.requiredHint, ...missing, autoComplete: "off", defaultValue: values?.taxId ?? '' })] }));
|
|
58
75
|
});
|
|
59
76
|
EkybBusinessDetailsScreen.displayName = 'EkybBusinessDetailsScreen';
|
|
60
77
|
export default EkybBusinessDetailsScreen;
|
|
@@ -39,14 +39,22 @@ export interface EkybCountryScreenProps extends Omit<PrizmaFormScreenProps, 'tit
|
|
|
39
39
|
* live interaction) โ the same mechanism Phone Input's `countryCode` and
|
|
40
40
|
* CURP's `Gene.dropdown` sections use. The search bar Figma draws inside the
|
|
41
41
|
* menu is Core's own `searchable`.
|
|
42
|
-
* 3.
|
|
43
|
-
*
|
|
44
|
-
* "
|
|
45
|
-
*
|
|
46
|
-
* because Core still ships no country-flag primitive
|
|
42
|
+
* 3. Menu rows and the closed field read the same "๐บ๐ธ United States": flag
|
|
43
|
+
* and country name, no dial code. Figma 5707:54174 draws the rows with
|
|
44
|
+
* Phone Input's "+1" prefixes, dropped by the owner (Elena, 2026-09-28)
|
|
45
|
+
* because a country of registration has no phone prefix. The flag travels
|
|
46
|
+
* inside the label text because Core still ships no country-flag primitive
|
|
47
|
+
* (#PI-3).
|
|
47
48
|
*
|
|
48
49
|
* This page is the only eKYB form page with NO "Back" secondary and NO Stepper โ
|
|
49
50
|
* it is step 0, before the three-step wizard starts.
|
|
51
|
+
*
|
|
52
|
+
* `emptyError` is Continue pressed with no country chosen (Elena, 2026-09-30,
|
|
53
|
+
* GUIDELINES ยง6-E empty-submit rule; precedent `FormsFieldScreen`'s
|
|
54
|
+
* `emptyError`): the dropdown renders empty, with no placeholder, in Core's
|
|
55
|
+
* `error` state with `requiredError` under it, and Continue is disabled. The
|
|
56
|
+
* field draws no `*`, but it is the page's only input and the flow cannot go on
|
|
57
|
+
* without it, so it is treated as required. `empty` keeps Continue enabled.
|
|
50
58
|
*/
|
|
51
59
|
export declare const EkybCountryScreen: React.ForwardRefExoticComponent<EkybCountryScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
52
60
|
export default EkybCountryScreen;
|
|
@@ -26,26 +26,44 @@ import './ScreenLayout.css';
|
|
|
26
26
|
* live interaction) โ the same mechanism Phone Input's `countryCode` and
|
|
27
27
|
* CURP's `Gene.dropdown` sections use. The search bar Figma draws inside the
|
|
28
28
|
* menu is Core's own `searchable`.
|
|
29
|
-
* 3.
|
|
30
|
-
*
|
|
31
|
-
* "
|
|
32
|
-
*
|
|
33
|
-
* because Core still ships no country-flag primitive
|
|
29
|
+
* 3. Menu rows and the closed field read the same "๐บ๐ธ United States": flag
|
|
30
|
+
* and country name, no dial code. Figma 5707:54174 draws the rows with
|
|
31
|
+
* Phone Input's "+1" prefixes, dropped by the owner (Elena, 2026-09-28)
|
|
32
|
+
* because a country of registration has no phone prefix. The flag travels
|
|
33
|
+
* inside the label text because Core still ships no country-flag primitive
|
|
34
|
+
* (#PI-3).
|
|
34
35
|
*
|
|
35
36
|
* This page is the only eKYB form page with NO "Back" secondary and NO Stepper โ
|
|
36
37
|
* it is step 0, before the three-step wizard starts.
|
|
38
|
+
*
|
|
39
|
+
* `emptyError` is Continue pressed with no country chosen (Elena, 2026-09-30,
|
|
40
|
+
* GUIDELINES ยง6-E empty-submit rule; precedent `FormsFieldScreen`'s
|
|
41
|
+
* `emptyError`): the dropdown renders empty, with no placeholder, in Core's
|
|
42
|
+
* `error` state with `requiredError` under it, and Continue is disabled. The
|
|
43
|
+
* field draws no `*`, but it is the page's only input and the flow cannot go on
|
|
44
|
+
* without it, so it is treated as required. `empty` keeps Continue enabled.
|
|
37
45
|
*/
|
|
38
|
-
export const EkybCountryScreen = forwardRef(({ strings, state = 'empty', countries = [], value, screenId = `ekyb-country-${state}`, overrides, onAction, ...shell }, ref) => {
|
|
46
|
+
export const EkybCountryScreen = forwardRef(({ strings, state = 'empty', countries = [], value, screenId = `ekyb-country-${state}`, ctaDisabled, overrides, onAction, ...shell }, ref) => {
|
|
39
47
|
const copy = strings.country;
|
|
40
48
|
// `empty` is the only section drawn on the placeholder; both other sections
|
|
41
49
|
// draw a chosen country in the closed field.
|
|
42
|
-
const
|
|
43
|
-
|
|
50
|
+
const emptyError = state === 'emptyError';
|
|
51
|
+
const selected = state === 'empty' || emptyError ? null : (value ?? countries[0]?.value ?? null);
|
|
52
|
+
return (_jsx(PrizmaFormScreen, { ref: ref, title: copy.title, subtitle: copy.subtitle, ctaLabel: copy.ctaLabel,
|
|
53
|
+
/* Disabled only after the empty submit; `empty` keeps it enabled. */
|
|
54
|
+
ctaDisabled: emptyError || ctaDisabled, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId,
|
|
44
55
|
/* Every eKYB form frame LEFT-aligns its title block, while the archetype
|
|
45
56
|
defaults to centred. The module supplies its designed alignment
|
|
46
57
|
through the sanctioned override rather than declaring any layout of
|
|
47
58
|
its own, and a host that passes `align` still wins (#GEO-2). */
|
|
48
|
-
overrides: { align: overrides?.align ?? 'left', logo: overrides?.logo }, onAction: onAction, ...shell, children: _jsx(PrizmaDropdown, { label: copy.field.label,
|
|
59
|
+
overrides: { align: overrides?.align ?? 'left', logo: overrides?.logo }, onAction: onAction, ...shell, children: _jsx(PrizmaDropdown, { label: copy.field.label,
|
|
60
|
+
/* Required, but UNMARKED: a single-input screen shows no asterisk
|
|
61
|
+
and no legend (Core pattern "Optimistic submission", single-input
|
|
62
|
+
screens; Elena 2026-09-30). The requirement surfaces on submit,
|
|
63
|
+
through the empty-submit error. */
|
|
64
|
+
/* The error state draws the field with nothing in it, not even the
|
|
65
|
+
placeholder (the `FormsFieldScreen` precedent). */
|
|
66
|
+
placeholder: emptyError ? undefined : copy.field.placeholder, error: emptyError, errorText: emptyError ? strings.requiredError : undefined, options: countries,
|
|
49
67
|
/* Uncontrolled: a screen is one static spec state, so no `onChange` is
|
|
50
68
|
needed. Core's `readOnly`/`disabled` are NOT used to freeze it โ
|
|
51
69
|
they paint the DISABLED grey surface on a section Figma draws white
|
|
@@ -38,6 +38,14 @@ export interface EkybOwnersScreenProps extends Omit<PrizmaFormScreenProps, 'titl
|
|
|
38
38
|
* - `loading` 5663:94390 โ `directorFilled` with the submission in
|
|
39
39
|
* flight: every field, both "Add another" links and "Back" go inert, and the
|
|
40
40
|
* spinner rides the CTA, never a field (the Phone Input lesson, #PI-5)
|
|
41
|
+
* - `uboEmptyError` / `directorEmptyError` (no frame) โ `uboEmpty` /
|
|
42
|
+
* `directorEmpty` after Continue was pressed with the fields still empty
|
|
43
|
+
* (Elena, 2026-09-30, GUIDELINES ยง6-E empty-submit rule; precedent
|
|
44
|
+
* `FormsFieldScreen`'s `emptyError`): every field renders empty, the two
|
|
45
|
+
* REQUIRED UBO fields in Core's `error` state with `requiredError` and no
|
|
46
|
+
* placeholder, the optional Director fields unflagged, and Continue
|
|
47
|
+
* disabled. The `*Empty` states keep Continue enabled so the press can
|
|
48
|
+
* happen.
|
|
41
49
|
*
|
|
42
50
|
* Four things are deliberate:
|
|
43
51
|
*
|
package/dist/EkybOwnersScreen.js
CHANGED
|
@@ -30,6 +30,14 @@ import './ScreenLayout.css';
|
|
|
30
30
|
* - `loading` 5663:94390 โ `directorFilled` with the submission in
|
|
31
31
|
* flight: every field, both "Add another" links and "Back" go inert, and the
|
|
32
32
|
* spinner rides the CTA, never a field (the Phone Input lesson, #PI-5)
|
|
33
|
+
* - `uboEmptyError` / `directorEmptyError` (no frame) โ `uboEmpty` /
|
|
34
|
+
* `directorEmpty` after Continue was pressed with the fields still empty
|
|
35
|
+
* (Elena, 2026-09-30, GUIDELINES ยง6-E empty-submit rule; precedent
|
|
36
|
+
* `FormsFieldScreen`'s `emptyError`): every field renders empty, the two
|
|
37
|
+
* REQUIRED UBO fields in Core's `error` state with `requiredError` and no
|
|
38
|
+
* placeholder, the optional Director fields unflagged, and Continue
|
|
39
|
+
* disabled. The `*Empty` states keep Continue enabled so the press can
|
|
40
|
+
* happen.
|
|
33
41
|
*
|
|
34
42
|
* Four things are deliberate:
|
|
35
43
|
*
|
|
@@ -65,24 +73,39 @@ import './ScreenLayout.css';
|
|
|
65
73
|
* distinguishes `loading` from `directorFilled` above the fold, so it is not
|
|
66
74
|
* optional chrome.
|
|
67
75
|
*/
|
|
68
|
-
export const EkybOwnersScreen = forwardRef(({ strings, state = 'uboEmpty', values, screenId = `ekyb-owners-${state}`, className, overrides, onAction, ...shell }, ref) => {
|
|
76
|
+
export const EkybOwnersScreen = forwardRef(({ strings, state = 'uboEmpty', values: valuesProp, screenId = `ekyb-owners-${state}`, ctaDisabled, className, overrides, onAction, ...shell }, ref) => {
|
|
69
77
|
const copy = strings.owners;
|
|
70
78
|
const busy = state === 'loading';
|
|
71
79
|
const secondUbo = state === 'uboAdded';
|
|
72
|
-
const
|
|
80
|
+
const emptyError = state === 'uboEmptyError' || state === 'directorEmptyError';
|
|
81
|
+
const values = emptyError ? undefined : valuesProp;
|
|
82
|
+
const showDirector = state === 'directorEmpty' ||
|
|
83
|
+
state === 'directorFilled' ||
|
|
84
|
+
state === 'directorEmptyError' ||
|
|
85
|
+
secondUbo ||
|
|
86
|
+
busy;
|
|
87
|
+
// Core's own error treatment, spread AFTER each required UBO field's own
|
|
88
|
+
// placeholder so the error state shows none (the `FormsFieldScreen`
|
|
89
|
+
// precedent). The Director fields are optional and never receive it.
|
|
90
|
+
const missing = emptyError
|
|
91
|
+
? { error: true, errorText: strings.requiredError, placeholder: undefined }
|
|
92
|
+
: {};
|
|
73
93
|
return (_jsxs(PrizmaFormScreen, { ref: ref, className: ['ekyb-owners', className].filter(Boolean).join(' '),
|
|
74
94
|
/* The archetype's own scrolling field stack โ two titled blocks, four
|
|
75
95
|
fields and two links do not fit a 844 frame. No module CSS. */
|
|
76
96
|
scrollFields: true,
|
|
77
97
|
/* Step 3 of 3, and GREEN across all three once the submission runs. */
|
|
78
98
|
progress: _jsx(PrizmaStepper, { steps: 3, currentState: busy ? 'Completed' : 3, showIcons: false, "aria-label": strings.stepperLabel, completedValueText: strings.stepperCompletedLabel }), title: copy.title, subtitle: copy.subtitle, ctaLabel: copy.ctaLabel,
|
|
99
|
+
/* Disabled only after the empty submit; the `*Empty` states keep it
|
|
100
|
+
enabled. */
|
|
101
|
+
ctaDisabled: emptyError || ctaDisabled,
|
|
79
102
|
/* `loading` swaps the CTA label for Core's designed spinner. */
|
|
80
103
|
ctaLoading: busy, ctaLoadingLabel: copy.ctaLoadingLabel, linkContent: _jsx(PrizmaButton, { variant: "secondary", size: "L",
|
|
81
104
|
/* 5663:94390 greys "Back" while the submission runs. */
|
|
82
105
|
disabled: busy, onClick: () => onAction?.({ type: 'secondary', screenId }), children: strings.backLabel }), verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: { align: overrides?.align ?? 'left', logo: overrides?.logo }, onAction: onAction,
|
|
83
106
|
/* Exploration ekyb-desktop: name + surname share a row per block on a
|
|
84
107
|
wide frame; on the phone nothing changes. */
|
|
85
|
-
responsive: true, ...shell, children: [_jsxs(PrizmaFormRow, { children: [_jsx(PrizmaTextField, { label: copy.uboName.label, placeholder: copy.uboName.placeholder, required: true, requiredHint: strings.requiredHint, autoComplete: "off", defaultValue: values?.uboName ?? '', disabled: busy }), _jsx(PrizmaTextField, { label: copy.uboSurname.label, placeholder: copy.uboSurname.placeholder, autoComplete: "off", defaultValue: values?.uboSurname ?? '', disabled: busy })] }), secondUbo ? (_jsxs(_Fragment, { children: [_jsxs(PrizmaFormRow, { children: [_jsx(PrizmaTextField, { label: copy.uboName.label, placeholder: copy.uboName.placeholder, required: true, requiredHint: strings.requiredHint, autoComplete: "off", defaultValue: values?.secondUboName ?? '' }), _jsx(PrizmaTextField, { label: copy.uboSurname.label, placeholder: copy.uboSurname.placeholder, autoComplete: "off", defaultValue: values?.secondUboSurname ?? '' })] }), copy.removeUboLabel ? (_jsx(PrizmaButton, { variant: "tertiary-link", size: "L", onClick: () => onAction?.({ type: 'tertiary', screenId: `${screenId}-remove-ubo` }), children: copy.removeUboLabel })) : null] })) : null, _jsx(PrizmaButton, { variant: "tertiary-link", size: "L", disabled: busy,
|
|
108
|
+
responsive: true, ...shell, children: [_jsxs(PrizmaFormRow, { children: [_jsx(PrizmaTextField, { label: copy.uboName.label, placeholder: copy.uboName.placeholder, required: true, requiredHint: strings.requiredHint, ...missing, autoComplete: "off", defaultValue: values?.uboName ?? '', disabled: busy }), _jsx(PrizmaTextField, { label: copy.uboSurname.label, placeholder: copy.uboSurname.placeholder, required: true, requiredHint: strings.requiredHint, ...missing, autoComplete: "off", defaultValue: values?.uboSurname ?? '', disabled: busy })] }), secondUbo ? (_jsxs(_Fragment, { children: [_jsxs(PrizmaFormRow, { children: [_jsx(PrizmaTextField, { label: copy.uboName.label, placeholder: copy.uboName.placeholder, required: true, requiredHint: strings.requiredHint, autoComplete: "off", defaultValue: values?.secondUboName ?? '' }), _jsx(PrizmaTextField, { label: copy.uboSurname.label, placeholder: copy.uboSurname.placeholder, required: true, requiredHint: strings.requiredHint, autoComplete: "off", defaultValue: values?.secondUboSurname ?? '' })] }), copy.removeUboLabel ? (_jsx(PrizmaButton, { variant: "tertiary-link", size: "L", onClick: () => onAction?.({ type: 'tertiary', screenId: `${screenId}-remove-ubo` }), children: copy.removeUboLabel })) : null] })) : null, _jsx(PrizmaButton, { variant: "tertiary-link", size: "L", disabled: busy,
|
|
86
109
|
/* Action-qualified id: the two "Add anotherโฆ" links are different
|
|
87
110
|
flows and must stay distinguishable (#PI-10), but the action
|
|
88
111
|
contract has no per-action discriminator yet. */
|