@incodetech/prizma-core-screens 0.1.3 → 0.2.3

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.
Files changed (80) hide show
  1. package/dist/DemoScreensConfigScreen.d.ts +36 -0
  2. package/dist/DemoScreensConfigScreen.js +30 -0
  3. package/dist/DemoScreensConfigSheetScreen.d.ts +39 -0
  4. package/dist/DemoScreensConfigSheetScreen.js +33 -0
  5. package/dist/DemoScreensEditSheetScreen.d.ts +30 -0
  6. package/dist/DemoScreensEditSheetScreen.js +28 -0
  7. package/dist/DemoScreensEndScreen.d.ts +9 -21
  8. package/dist/DemoScreensEndScreen.js +9 -14
  9. package/dist/DemoScreensLaunchScreen.d.ts +28 -0
  10. package/dist/DemoScreensLaunchScreen.js +26 -0
  11. package/dist/DemoScreensLayout.css +542 -0
  12. package/dist/DemoScreensRedirectScreen.d.ts +50 -0
  13. package/dist/DemoScreensRedirectScreen.js +38 -0
  14. package/dist/DemoScreensResultScreen.d.ts +52 -0
  15. package/dist/DemoScreensResultScreen.js +46 -0
  16. package/dist/DemoScreensRunningScreen.d.ts +22 -0
  17. package/dist/DemoScreensRunningScreen.js +16 -0
  18. package/dist/DemoScreensSettingsScreen.d.ts +37 -0
  19. package/dist/DemoScreensSettingsScreen.js +40 -0
  20. package/dist/DemoScreensSplashScreen.d.ts +27 -0
  21. package/dist/DemoScreensSplashScreen.js +25 -0
  22. package/dist/DemoScreensStartScreen.d.ts +38 -0
  23. package/dist/DemoScreensStartScreen.js +37 -0
  24. package/dist/DemoScreensStrings.d.ts +192 -0
  25. package/dist/DemoScreensStrings.js +11 -11
  26. package/dist/DemoScreensTermsScreen.d.ts +28 -0
  27. package/dist/DemoScreensTermsScreen.js +26 -0
  28. package/dist/EkybAddressDetailsScreen.js +9 -5
  29. package/dist/EkybBusinessDetailsScreen.js +6 -3
  30. package/dist/EkybOwnersScreen.d.ts +4 -0
  31. package/dist/EkybOwnersScreen.js +13 -5
  32. package/dist/EkybStrings.d.ts +12 -1
  33. package/dist/EkycCountryCatalog.d.ts +46 -0
  34. package/dist/EkycCountryCatalog.js +139 -0
  35. package/dist/EkycCountryFormScreen.d.ts +36 -0
  36. package/dist/EkycCountryFormScreen.js +94 -0
  37. package/dist/EkycDetailsScreen.js +11 -4
  38. package/dist/EkycLayout.css +23 -0
  39. package/dist/EkycLicenseScreen.js +7 -3
  40. package/dist/EkycStrings.d.ts +26 -0
  41. package/dist/FaceMatchComparisonScreen.d.ts +4 -2
  42. package/dist/FaceMatchComparisonScreen.js +3 -1
  43. package/dist/FaceMatchLayout.css +53 -3
  44. package/dist/FormScreen.css +74 -0
  45. package/dist/FormScreen.d.ts +17 -0
  46. package/dist/FormScreen.js +12 -1
  47. package/dist/index.d.ts +15 -2
  48. package/dist/index.js +13 -0
  49. package/dist/styles.css +1 -0
  50. package/package.json +62 -1
  51. package/src/DemoScreensConfigScreen.tsx +101 -0
  52. package/src/DemoScreensConfigSheetScreen.tsx +120 -0
  53. package/src/DemoScreensEditSheetScreen.tsx +103 -0
  54. package/src/DemoScreensEndScreen.tsx +14 -38
  55. package/src/DemoScreensLaunchScreen.tsx +96 -0
  56. package/src/DemoScreensLayout.css +542 -0
  57. package/src/DemoScreensRedirectScreen.tsx +190 -0
  58. package/src/DemoScreensResultScreen.tsx +115 -0
  59. package/src/DemoScreensRunningScreen.tsx +45 -0
  60. package/src/DemoScreensSettingsScreen.tsx +101 -0
  61. package/src/DemoScreensSplashScreen.tsx +47 -0
  62. package/src/DemoScreensStartScreen.tsx +105 -0
  63. package/src/DemoScreensStrings.ts +204 -11
  64. package/src/DemoScreensTermsScreen.tsx +82 -0
  65. package/src/EkybAddressDetailsScreen.tsx +7 -1
  66. package/src/EkybBusinessDetailsScreen.tsx +6 -1
  67. package/src/EkybOwnersScreen.tsx +46 -2
  68. package/src/EkybStrings.ts +12 -0
  69. package/src/EkycCountryCatalog.ts +199 -0
  70. package/src/EkycCountryFormScreen.tsx +184 -0
  71. package/src/EkycDetailsScreen.tsx +29 -20
  72. package/src/EkycLayout.css +23 -0
  73. package/src/EkycLicenseScreen.tsx +22 -16
  74. package/src/EkycStrings.ts +25 -0
  75. package/src/FaceMatchComparisonScreen.tsx +11 -3
  76. package/src/FaceMatchLayout.css +53 -3
  77. package/src/FormScreen.css +74 -0
  78. package/src/FormScreen.tsx +27 -1
  79. package/src/index.ts +65 -1
  80. package/src/styles.css +1 -0
@@ -30,13 +30,38 @@
30
30
  flex-direction: column;
31
31
  align-items: center;
32
32
 
33
+ /* The stage is exactly as wide as the discs at rest, and it clips.
34
+ *
35
+ * The entrance throw below is a flat 200px, chosen so a disc clears the edge
36
+ * of a 390 screen. On a phone that works: the discs start outside the screen
37
+ * and fly in. On a desktop viewport 200px clears nothing, so instead of an
38
+ * entrance you watch two discs sit 576px apart and glide together to 176 —
39
+ * the move reads as a mistake rather than an arrival (Camila, 2026-09-25).
40
+ *
41
+ * Rather than scale the throw per viewport, the stage stops being the
42
+ * viewport. `fit-content` makes it the width of the resting pair, which
43
+ * centres via the auto margins; anything thrown past that edge is clipped.
44
+ * The arithmetic: a disc at rest sits 88px off centre, +200 puts its centre
45
+ * at 288 and its inner edge at 208, against a half-stage of ~168. Hidden,
46
+ * with room to spare, at every viewport. No magic number and no new token —
47
+ * the discs define their own stage, and desktop now plays what the phone
48
+ * always played.
49
+ *
50
+ * `clip` rather than `hidden` on purpose: `hidden` on one axis forces the
51
+ * other to `auto` and quietly makes this a scroll container. Nothing
52
+ * legitimately overflows — the callouts are in normal flow, and the
53
+ * converge moves every disc inward and up — so there is nothing to lose. */
54
+ width: fit-content;
55
+ margin-inline: auto;
56
+ overflow: clip;
57
+
33
58
  /* The disc's diameter, named once. `--matching`'s rosette and `--animated`'s
34
59
  * convergence both have to know it, and a second literal is a second thing to
35
60
  * forget. Still a design literal, still DEVIATIONS #FM-22 — just not repeated. */
36
61
  --face-match-photo: 160px;
37
62
  /* Half the distance between two neighbouring discs: what one of them has to
38
63
  * travel to reach the pair's centre line. */
39
- --face-match-half-step: calc((var(--face-match-photo) + var(--prizma-spacing-16)) / 2);
64
+ --face-match-half-step: calc((var(--face-match-photo, 160px) + var(--prizma-spacing-16)) / 2);
40
65
  }
41
66
 
42
67
  .face-match-cluster__row {
@@ -73,13 +98,38 @@
73
98
  * for component geometry. DEVIATIONS.md #FM-22. */
74
99
  .face-match-cluster__photo {
75
100
  flex-shrink: 0;
76
- width: var(--face-match-photo);
77
- height: var(--face-match-photo);
101
+ /* The fallback is load-bearing, not defensive noise. The diameter is
102
+ inherited from `.face-match-cluster`, so for the frame before that
103
+ ancestor's rule applies — or in any host that renders a disc outside the
104
+ cluster — `var()` resolves to nothing, `width` is dropped, and the box
105
+ falls back to auto. A portrait then paints at its INTRINSIC size, which is
106
+ landscape for most cameras: the disc flashes wide before snapping to 160.
107
+ Naming the same literal here costs nothing and removes the flash. */
108
+ width: var(--face-match-photo, 160px);
109
+ height: var(--face-match-photo, 160px);
110
+ /* Belt and braces: whatever resolves for width, the disc is never an
111
+ ellipse. A circle that is briefly the wrong SIZE is a non-event; one that
112
+ is briefly the wrong SHAPE reads as broken. */
113
+ aspect-ratio: 1;
78
114
  border-radius: var(--prizma-border-radius-full);
79
115
  overflow: hidden;
116
+ /* Backstop behind the host's pixels while they load, and under anything
117
+ with transparency. NOT the empty state — that is the modifier below. */
80
118
  background: var(--prizma-surface-neutral-100);
81
119
  }
82
120
 
121
+ /* No photo supplied for this role.
122
+ *
123
+ * INTERIM (2026-09-25, owner call): colour is the whole state for now, so the
124
+ * slot reads as a portrait that belongs here rather than an undesigned hole.
125
+ * Brand/50 is the same disc PrizmaIllustrationAvatar sits on, which is where
126
+ * the designed state is most likely to land. The real treatment (bust,
127
+ * outline, or copy) replaces this rule; the modifier and its class name stay,
128
+ * so swapping it in is a one-rule change and nothing downstream moves. */
129
+ .face-match-cluster__photo--empty {
130
+ background: var(--prizma-surface-brand-50);
131
+ }
132
+
83
133
  .face-match-cluster__photo > img,
84
134
  .face-match-cluster__photo > video,
85
135
  .face-match-cluster__photo > svg {
@@ -49,6 +49,17 @@
49
49
  .prizma-form-screen__fields--scroll {
50
50
  overflow-y: auto;
51
51
  margin-bottom: var(--prizma-spacing-16);
52
+ /* No scrollbar drawn, on any platform. A phone paints none; a desktop with a
53
+ * mouse paints a permanent 15px track INSIDE the column, which narrows every
54
+ * row's box: the two lanes of a `row / 2-col` pair came out short of the
55
+ * title and the CTA above and below them, and the last link sat half under
56
+ * the track (eKYB owners on the 1440 frame, Elena 2026-09-24). The stack
57
+ * still scrolls — wheel, trackpad, keyboard — it just shows no chrome for
58
+ * it, like the SDK on a phone. DEVIATIONS #EKB-6. */
59
+ scrollbar-width: none;
60
+ }
61
+ .prizma-form-screen__fields--scroll::-webkit-scrollbar {
62
+ display: none;
52
63
  }
53
64
 
54
65
  /* Rows in a scrolling stack keep their intrinsic height. A flex item defaults to
@@ -76,3 +87,66 @@
76
87
  flex-direction: column;
77
88
  gap: var(--prizma-spacing-12);
78
89
  }
90
+
91
+ /* ── Responsive field rows (tablet and desktop) ──────────────────────────────
92
+ * Exploration `ekyb-desktop` (Elena, 2026-09-24, Figma TWgYZVhurQCizfC4tfLEut
93
+ * section 6062:9990 "eKYB, Happy path, Desktop"): the eKYB forms designed for
94
+ * desktop keep the archetype (stepper, title, field stack, Continue + Back, tag)
95
+ * and only change the SHAPE of the field stack. Her frames keep a 420 column
96
+ * (the same measure as Title/Max-width and Button/Size/L/Max-width) and draw
97
+ * `row / 2-col`: two fields of 202 with Spacing/16 between, and Back | Continue
98
+ * on one row at the same split. Opt-in per screen through `responsive` on
99
+ * `PrizmaFormScreen` and `PrizmaFormRow` around the pair, so every phone screen
100
+ * and every other module is byte-identical.
101
+ *
102
+ * The threshold is a CONTAINER query on the shell (`pcs-screen`, ScreenShell.css),
103
+ * not a viewport one: the same screen framed at 390 stays a single column, and
104
+ * framed on a tablet or desktop panel (shell 468 = 420 column + the two
105
+ * Spacing/24 gutters) it takes the two-lane shape. 420 is the first width at
106
+ * which the column IS the designed desktop column. */
107
+ .prizma-form-screen__row {
108
+ display: flex;
109
+ flex-direction: column;
110
+ gap: var(--pfs-fields-gap, var(--prizma-spacing-16));
111
+ }
112
+
113
+ @container pcs-screen (min-width: 420px) {
114
+ /* Flex + explicit widths rather than grid or `flex: 1`: the canvas converter
115
+ * reads flex direction, gap and computed widths, and ignores grid and grow
116
+ * (docs/core-lab-pencil-conversion-gotchas.md), so this is the one shape that
117
+ * is identical in the browser and on the canvas. Each lane is half the
118
+ * column less half the Spacing/16 gap: 202 on the 420 column, as drawn. */
119
+ .prizma-form-screen--responsive .prizma-form-screen__row {
120
+ flex-direction: row;
121
+ /* Bottom-aligned: when one label wraps to two lines ("UBO (Unique
122
+ * Beneficial Owner) name") the two INPUTS still sit on one line and the
123
+ * long label hangs above; top-aligned, the field itself dropped by a line
124
+ * (Elena, 2026-09-24). */
125
+ align-items: flex-end;
126
+ gap: var(--prizma-spacing-16);
127
+ }
128
+ .prizma-form-screen--responsive .prizma-form-screen__row > * {
129
+ flex: none;
130
+ width: calc(50% - var(--prizma-spacing-16) / 2);
131
+ min-width: 0;
132
+ }
133
+
134
+ /* Continue and Back share a row: Back on the left, Continue on the right, as
135
+ * her frames draw it. The DOM order (primary first, for focus and for the
136
+ * phone stack) is untouched; only the visual order flips. A screen with one
137
+ * button (country) keeps it full width. */
138
+ .prizma-form-screen--responsive .prizma-form-screen__cta {
139
+ flex-direction: row-reverse;
140
+ justify-content: flex-start;
141
+ gap: var(--prizma-spacing-16);
142
+ }
143
+ .prizma-form-screen--responsive .prizma-form-screen__cta > .prizma-button {
144
+ flex: none;
145
+ width: calc(50% - var(--prizma-spacing-16) / 2);
146
+ min-width: 0;
147
+ max-width: none;
148
+ }
149
+ .prizma-form-screen--responsive .prizma-form-screen__cta > .prizma-button:only-child {
150
+ width: 100%;
151
+ }
152
+ }
@@ -86,11 +86,28 @@ export interface PrizmaFormScreenProps extends Omit<PrizmaScreenShellProps, 'dar
86
86
  * eKYB, Data Sharing Consent); it is the archetype's now. DEVIATIONS #DSC-2.
87
87
  */
88
88
  scrollFields?: boolean;
89
+ /**
90
+ * Let the field stack change SHAPE on a wide screen: `PrizmaFormRow` pairs
91
+ * become two lanes and Continue + Back share a row, once the shell's own
92
+ * container is at least 600 wide (FormScreen.css). Off by default, so every
93
+ * phone screen is untouched. Exploration `ekyb-desktop`, 2026-09-24.
94
+ */
95
+ responsive?: boolean;
89
96
  navLabel?: string;
90
97
  screenId?: string;
91
98
  overrides?: PrizmaScreenOverrides;
92
99
  onAction?: PrizmaScreenActionHandler;
93
100
  }
101
+ /**
102
+ * Two (or one) related fields that share a row on a wide screen and stack on a
103
+ * phone — street + house number, name + surname. A plain wrapper: it carries no
104
+ * spacing of its own beyond the stack's gap, and it only does anything inside a
105
+ * `PrizmaFormScreen` with `responsive`.
106
+ */
107
+ export declare function PrizmaFormRow({ children, className }: {
108
+ children?: ReactNode;
109
+ className?: string;
110
+ }): React.JSX.Element;
94
111
  /**
95
112
  * Archetype E — Form / Input (GUIDELINES.md §6-E).
96
113
  * Nav → title block → field stack → CTA → verified tag. Module states
@@ -8,13 +8,24 @@ import { PrizmaScreenShell } from './ScreenShell';
8
8
  import { PrizmaScreenNav } from './ScreenNav';
9
9
  import './ScreenLayout.css';
10
10
  import './FormScreen.css';
11
+ /**
12
+ * Two (or one) related fields that share a row on a wide screen and stack on a
13
+ * phone — street + house number, name + surname. A plain wrapper: it carries no
14
+ * spacing of its own beyond the stack's gap, and it only does anything inside a
15
+ * `PrizmaFormScreen` with `responsive`.
16
+ */
17
+ export function PrizmaFormRow({ children, className }) {
18
+ return (_jsx("div", { className: ['prizma-form-screen__row', className].filter(Boolean).join(' '), children: children }));
19
+ }
11
20
  /**
12
21
  * Archetype E — Form / Input (GUIDELINES.md §6-E).
13
22
  * Nav → title block → field stack → CTA → verified tag. Module states
14
23
  * (typing / filled / loading) are separate screens sharing this identical
15
24
  * layout, changing only field content.
16
25
  */
17
- export const PrizmaFormScreen = forwardRef(({ progress, title, subtitle, ctaLabel, ctaDisabled, ctaLoading = false, ctaLoadingLabel, linkLabel, linkContent, verifiedLabel, children, fieldsOffset, fieldsGap, scrollFields = false, navLabel, screenId, showHeader = true, showFooter = true, overrides, onAction, ...shell }, ref) => (_jsxs(PrizmaScreenShell, { ref: ref, ...shell, children: [_jsx(PrizmaScreenNav, { reserved: !showHeader, logo: overrides?.logo, navLabel: navLabel }), _jsxs("div", { className: "prizma-screen-layout__content", children: [progress ? (_jsx("div", { className: "prizma-screen-layout__progress", children: progress })) : null, _jsx(PrizmaTitle, { variant: overrides?.align === 'left' ? 'left' : 'centered', title: title, showSubtitle: Boolean(subtitle), subtitle: subtitle }), _jsx("div", { className: [
26
+ export const PrizmaFormScreen = forwardRef(({ progress, title, subtitle, ctaLabel, ctaDisabled, ctaLoading = false, ctaLoadingLabel, linkLabel, linkContent, verifiedLabel, children, fieldsOffset, fieldsGap, scrollFields = false, responsive = false, navLabel, screenId, showHeader = true, showFooter = true, overrides, onAction, ...shell }, ref) => (_jsxs(PrizmaScreenShell, { ref: ref, ...shell, className: [shell.className, responsive ? 'prizma-form-screen--responsive' : null]
27
+ .filter(Boolean)
28
+ .join(' ') || undefined, children: [_jsx(PrizmaScreenNav, { reserved: !showHeader, logo: overrides?.logo, navLabel: navLabel }), _jsxs("div", { className: "prizma-screen-layout__content", children: [progress ? (_jsx("div", { className: "prizma-screen-layout__progress", children: progress })) : null, _jsx(PrizmaTitle, { variant: overrides?.align === 'left' ? 'left' : 'centered', title: title, showSubtitle: Boolean(subtitle), subtitle: subtitle }), _jsx("div", { className: [
18
29
  'prizma-form-screen__fields',
19
30
  scrollFields ? 'prizma-form-screen__fields--scroll' : null,
20
31
  ]
package/dist/index.d.ts CHANGED
@@ -89,7 +89,9 @@ export { FormsLongFormScreen, type FormsLongFormScreenProps } from './FormsLongF
89
89
  export { FormsSuccessScreen, type FormsSuccessScreenProps } from './FormsSuccessScreen';
90
90
  export { type DataSharingConsentState, type DataSharingConsentItemStrings, type DataSharingConsentStrings, } from './DataSharingConsentStrings';
91
91
  export { DataSharingConsentConsentScreen, type DataSharingConsentConsentScreenProps } from './DataSharingConsentConsentScreen';
92
- export { type EkycDetailsState, type EkycLicenseState, type EkycLicenseStateOption, type EkycDetailsValues, type EkycLicenseValues, type EkycStrings, } from './EkycStrings';
92
+ export { type EkycDetailsState, type EkycLicenseState, type EkycLicenseStateOption, type EkycDetailsValues, type EkycLicenseValues, type EkycStrings, type EkycCountryValues, } from './EkycStrings';
93
+ export { EKYC_COUNTRY_CATALOG, ekycCountryVariant, type EkycCountryVariant, type EkycCountryStep, type EkycField, type EkycFieldKey, type EkycFieldKind, } from './EkycCountryCatalog';
94
+ export { EkycCountryFormScreen, type EkycCountryFormScreenProps } from './EkycCountryFormScreen';
93
95
  export { EkycDetailsScreen, type EkycDetailsScreenProps } from './EkycDetailsScreen';
94
96
  export { EkycErrorScreen, type EkycErrorScreenProps } from './EkycErrorScreen';
95
97
  export { EkycLicenseScreen, type EkycLicenseScreenProps } from './EkycLicenseScreen';
@@ -139,7 +141,18 @@ export { type LoadersStrings, type LoadersVariant, type LoadersCopy } from './Lo
139
141
  export { LoaderScreen, type LoaderScreenProps } from './LoaderScreen';
140
142
  export { type ErrorScreensStrings, type ErrorScreensVariant, type ErrorScreensCopy, } from './ErrorScreensStrings';
141
143
  export { ErrorScreensScreen, type ErrorScreensScreenProps } from './ErrorScreensScreen';
142
- export { type DemoScreensStrings } from './DemoScreensStrings';
144
+ export { type DemoScreensStrings, type DemoScreensLanguage, type DemoScreensOption, } from './DemoScreensStrings';
145
+ export { DemoScreensConfigScreen, type DemoScreensConfigScreenProps, type DemoScreensConfigState, } from './DemoScreensConfigScreen';
146
+ export { DemoScreensTermsScreen, type DemoScreensTermsScreenProps, } from './DemoScreensTermsScreen';
147
+ export { DemoScreensLaunchScreen, type DemoScreensLaunchScreenProps, } from './DemoScreensLaunchScreen';
148
+ export { DemoScreensConfigSheetScreen, type DemoScreensConfigSheetScreenProps, type DemoScreensConfigSheetState, } from './DemoScreensConfigSheetScreen';
149
+ export { DemoScreensEditSheetScreen, type DemoScreensEditSheetScreenProps, type DemoScreensEditSheetState, } from './DemoScreensEditSheetScreen';
150
+ export { DemoScreensRedirectScreen, type DemoScreensRedirectScreenProps, type DemoScreensRedirectStage, } from './DemoScreensRedirectScreen';
151
+ export { DemoScreensSplashScreen, type DemoScreensSplashScreenProps, } from './DemoScreensSplashScreen';
152
+ export { DemoScreensStartScreen, type DemoScreensStartScreenProps, } from './DemoScreensStartScreen';
153
+ export { DemoScreensSettingsScreen, type DemoScreensSettingsScreenProps, } from './DemoScreensSettingsScreen';
154
+ export { DemoScreensRunningScreen, type DemoScreensRunningScreenProps, } from './DemoScreensRunningScreen';
155
+ export { DemoScreensResultScreen, type DemoScreensResultScreenProps, type DemoScreensResultStatus, } from './DemoScreensResultScreen';
143
156
  export { DemoScreensEndScreen, type DemoScreensEndScreenProps, } from './DemoScreensEndScreen';
144
157
  export { faceCaptureFlow, faceCaptureBranches, type FaceCaptureFlowStep, type FaceCaptureFlowVariant, type FaceCaptureScreenProps, faceMatchFlow, faceMatchBranches, type FaceMatchFlowStep, type FaceMatchFlowVariant, type FaceMatchScreenProps, } from './flows';
145
158
  export { documentCaptureFlow, documentCaptureCameraFlow, documentCaptureUploadFlow, documentCaptureBranchesByMethod, documentCaptureBranches, type DocumentCaptureFlowStep, type DocumentCaptureFlowVariant, type DocumentCaptureScreenProps, idCaptureFlow, idCapturePassportFlow, idCaptureBranches, idCaptureVerticalOf, type IdCaptureFlowStep, type IdCaptureFlowVariant, type IdCaptureScreenProps, } from './flows';
package/dist/index.js CHANGED
@@ -82,6 +82,8 @@ export { FormsFieldScreen } from './FormsFieldScreen';
82
82
  export { FormsLongFormScreen } from './FormsLongFormScreen';
83
83
  export { FormsSuccessScreen } from './FormsSuccessScreen';
84
84
  export { DataSharingConsentConsentScreen } from './DataSharingConsentConsentScreen';
85
+ export { EKYC_COUNTRY_CATALOG, ekycCountryVariant, } from './EkycCountryCatalog';
86
+ export { EkycCountryFormScreen } from './EkycCountryFormScreen';
85
87
  export { EkycDetailsScreen } from './EkycDetailsScreen';
86
88
  export { EkycErrorScreen } from './EkycErrorScreen';
87
89
  export { EkycLicenseScreen } from './EkycLicenseScreen';
@@ -124,6 +126,17 @@ export { PermissionsAllowScreen, } from './PermissionsAllowScreen';
124
126
  export { PermissionsBrowserStepsScreen, } from './PermissionsBrowserStepsScreen';
125
127
  export { LoaderScreen } from './LoaderScreen';
126
128
  export { ErrorScreensScreen } from './ErrorScreensScreen';
129
+ export { DemoScreensConfigScreen, } from './DemoScreensConfigScreen';
130
+ export { DemoScreensTermsScreen, } from './DemoScreensTermsScreen';
131
+ export { DemoScreensLaunchScreen, } from './DemoScreensLaunchScreen';
132
+ export { DemoScreensConfigSheetScreen, } from './DemoScreensConfigSheetScreen';
133
+ export { DemoScreensEditSheetScreen, } from './DemoScreensEditSheetScreen';
134
+ export { DemoScreensRedirectScreen, } from './DemoScreensRedirectScreen';
135
+ export { DemoScreensSplashScreen, } from './DemoScreensSplashScreen';
136
+ export { DemoScreensStartScreen, } from './DemoScreensStartScreen';
137
+ export { DemoScreensSettingsScreen, } from './DemoScreensSettingsScreen';
138
+ export { DemoScreensRunningScreen, } from './DemoScreensRunningScreen';
139
+ export { DemoScreensResultScreen, } from './DemoScreensResultScreen';
127
140
  export { DemoScreensEndScreen, } from './DemoScreensEndScreen';
128
141
  // ── Flows (module screen sequences — powers the FlowPlayer prototypes) ──────
129
142
  export { faceCaptureFlow, faceCaptureBranches, faceMatchFlow, faceMatchBranches, } from './flows';
package/dist/styles.css CHANGED
@@ -15,6 +15,7 @@
15
15
  @import './CaptureOverlay.css';
16
16
  @import './CurpLayout.css';
17
17
  @import './DataSharingConsentLayout.css';
18
+ @import './DemoScreensLayout.css';
18
19
  @import './DocumentCaptureLayout.css';
19
20
  @import './EkycLayout.css';
20
21
  @import './ElectronicSignatureLayout.css';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@incodetech/prizma-core-screens",
3
- "version": "0.1.3",
3
+ "version": "0.2.3",
4
4
  "description": "Prizma Design System — SDK module screens: composed, responsive, brand-themeable React screens built from @incodetech/prizma-core-web.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -55,11 +55,66 @@
55
55
  "types": "./dist/DataSharingConsentConsentScreen.d.ts",
56
56
  "import": "./dist/DataSharingConsentConsentScreen.js"
57
57
  },
58
+ "./demo-screens-config-screen": {
59
+ "source": "./src/DemoScreensConfigScreen.tsx",
60
+ "types": "./dist/DemoScreensConfigScreen.d.ts",
61
+ "import": "./dist/DemoScreensConfigScreen.js"
62
+ },
63
+ "./demo-screens-config-sheet-screen": {
64
+ "source": "./src/DemoScreensConfigSheetScreen.tsx",
65
+ "types": "./dist/DemoScreensConfigSheetScreen.d.ts",
66
+ "import": "./dist/DemoScreensConfigSheetScreen.js"
67
+ },
68
+ "./demo-screens-edit-sheet-screen": {
69
+ "source": "./src/DemoScreensEditSheetScreen.tsx",
70
+ "types": "./dist/DemoScreensEditSheetScreen.d.ts",
71
+ "import": "./dist/DemoScreensEditSheetScreen.js"
72
+ },
58
73
  "./demo-screens-end-screen": {
59
74
  "source": "./src/DemoScreensEndScreen.tsx",
60
75
  "types": "./dist/DemoScreensEndScreen.d.ts",
61
76
  "import": "./dist/DemoScreensEndScreen.js"
62
77
  },
78
+ "./demo-screens-launch-screen": {
79
+ "source": "./src/DemoScreensLaunchScreen.tsx",
80
+ "types": "./dist/DemoScreensLaunchScreen.d.ts",
81
+ "import": "./dist/DemoScreensLaunchScreen.js"
82
+ },
83
+ "./demo-screens-redirect-screen": {
84
+ "source": "./src/DemoScreensRedirectScreen.tsx",
85
+ "types": "./dist/DemoScreensRedirectScreen.d.ts",
86
+ "import": "./dist/DemoScreensRedirectScreen.js"
87
+ },
88
+ "./demo-screens-result-screen": {
89
+ "source": "./src/DemoScreensResultScreen.tsx",
90
+ "types": "./dist/DemoScreensResultScreen.d.ts",
91
+ "import": "./dist/DemoScreensResultScreen.js"
92
+ },
93
+ "./demo-screens-running-screen": {
94
+ "source": "./src/DemoScreensRunningScreen.tsx",
95
+ "types": "./dist/DemoScreensRunningScreen.d.ts",
96
+ "import": "./dist/DemoScreensRunningScreen.js"
97
+ },
98
+ "./demo-screens-settings-screen": {
99
+ "source": "./src/DemoScreensSettingsScreen.tsx",
100
+ "types": "./dist/DemoScreensSettingsScreen.d.ts",
101
+ "import": "./dist/DemoScreensSettingsScreen.js"
102
+ },
103
+ "./demo-screens-splash-screen": {
104
+ "source": "./src/DemoScreensSplashScreen.tsx",
105
+ "types": "./dist/DemoScreensSplashScreen.d.ts",
106
+ "import": "./dist/DemoScreensSplashScreen.js"
107
+ },
108
+ "./demo-screens-start-screen": {
109
+ "source": "./src/DemoScreensStartScreen.tsx",
110
+ "types": "./dist/DemoScreensStartScreen.d.ts",
111
+ "import": "./dist/DemoScreensStartScreen.js"
112
+ },
113
+ "./demo-screens-terms-screen": {
114
+ "source": "./src/DemoScreensTermsScreen.tsx",
115
+ "types": "./dist/DemoScreensTermsScreen.d.ts",
116
+ "import": "./dist/DemoScreensTermsScreen.js"
117
+ },
63
118
  "./document-capture-capture-screen": {
64
119
  "source": "./src/DocumentCaptureCaptureScreen.tsx",
65
120
  "types": "./dist/DocumentCaptureCaptureScreen.d.ts",
@@ -145,6 +200,11 @@
145
200
  "types": "./dist/EkybSuccessScreen.d.ts",
146
201
  "import": "./dist/EkybSuccessScreen.js"
147
202
  },
203
+ "./ekyc-country-form-screen": {
204
+ "source": "./src/EkycCountryFormScreen.tsx",
205
+ "types": "./dist/EkycCountryFormScreen.d.ts",
206
+ "import": "./dist/EkycCountryFormScreen.js"
207
+ },
148
208
  "./ekyc-details-screen": {
149
209
  "source": "./src/EkycDetailsScreen.tsx",
150
210
  "types": "./dist/EkycDetailsScreen.d.ts",
@@ -624,6 +684,7 @@
624
684
  "./capture-overlay.css": "./dist/CaptureOverlay.css",
625
685
  "./curp-layout.css": "./dist/CurpLayout.css",
626
686
  "./data-sharing-consent-layout.css": "./dist/DataSharingConsentLayout.css",
687
+ "./demo-screens-layout.css": "./dist/DemoScreensLayout.css",
627
688
  "./document-capture-layout.css": "./dist/DocumentCaptureLayout.css",
628
689
  "./ekyc-layout.css": "./dist/EkycLayout.css",
629
690
  "./electronic-signature-layout.css": "./dist/ElectronicSignatureLayout.css",
@@ -0,0 +1,101 @@
1
+ import React, { forwardRef } from 'react';
2
+ import { PrizmaButton } from '@incodetech/prizma-core-web/button';
3
+ import { PrizmaTextField } from '@incodetech/prizma-core-web/text-field';
4
+ import { PrizmaDropdown } from '@incodetech/prizma-core-web/dropdown';
5
+ import { PrizmaScreenShell, type PrizmaScreenShellProps } from './ScreenShell';
6
+ import { PrizmaScreenNav } from './ScreenNav';
7
+ import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
8
+ import type { DemoScreensStrings } from './DemoScreensStrings';
9
+ import './ScreenLayout.css';
10
+ import './DemoScreensLayout.css';
11
+
12
+ /**
13
+ * The five states the `Configuration` section draws:
14
+ * - `empty` `demo_2` — placeholders, CTA disabled
15
+ * - `filled` `demo_4` — Client ID typed, environment chosen
16
+ * - `environmentOpen` `demo_4` — the environment menu open
17
+ * - `custom` `demo_3` — environment "Custom" reveals the URL field
18
+ * - `error` `Error Client ID` — the backend rejected the ID
19
+ */
20
+ export type DemoScreensConfigState = 'empty' | 'filled' | 'environmentOpen' | 'custom' | 'error';
21
+
22
+ export interface DemoScreensConfigScreenProps
23
+ extends Omit<PrizmaScreenShellProps, 'dark' | 'title' | 'children'> {
24
+ /** Family copy — this screen reads the `config` slice. */
25
+ strings: DemoScreensStrings;
26
+ state?: DemoScreensConfigState;
27
+ screenId?: string;
28
+ overrides?: PrizmaScreenOverrides;
29
+ onAction?: PrizmaScreenActionHandler;
30
+ }
31
+
32
+ /**
33
+ * Demo screens · NATIVE — the configuration form, `Configuration` (2010:4704)
34
+ * in `Demo App - Latest Design`: the logo nav, Client ID, Environment, and a
35
+ * URL field once the environment is Custom. Continue stays disabled until
36
+ * both fields hold a value.
37
+ *
38
+ * Archetype E's shape without E's title: the frame draws no heading, and
39
+ * `PrizmaFormScreen` insists on one (DEVIATIONS #GEN-13), so the screen
40
+ * composes the nav and E's layout classes itself. Fields and CTA are Core's.
41
+ * The keyboard on the typing frames is OS chrome and is not drawn (#DC-20).
42
+ */
43
+ export const DemoScreensConfigScreen = forwardRef<HTMLDivElement, DemoScreensConfigScreenProps>(
44
+ (
45
+ { strings, state = 'empty', screenId = `demo-screens-config-${state}`, overrides, onAction, ...shell },
46
+ ref,
47
+ ) => {
48
+ const c = strings.config;
49
+ const filled = state !== 'empty';
50
+ const custom = state === 'custom';
51
+ const environment =
52
+ state === 'empty' ? null : custom ? c.customEnvironment : c.environments[0]?.value ?? null;
53
+ return (
54
+ <PrizmaScreenShell ref={ref} data-screen-id={screenId} {...shell}>
55
+ <PrizmaScreenNav logo={overrides?.logo} navLabel={strings.navLabel} />
56
+ <div className="prizma-screen-layout__content">
57
+ <div className="demo-screens-config__fields">
58
+ {/* `defaultValue`, never `readOnly`: Core paints a read-only field on
59
+ the disabled surface, and the frame shows a live field. `key`
60
+ re-mounts it per state so the default takes. */}
61
+ <PrizmaTextField
62
+ key={state}
63
+ label={c.clientIdLabel}
64
+ placeholder={c.clientIdPlaceholder}
65
+ defaultValue={filled ? c.clientIdValue : ''}
66
+ error={state === 'error'}
67
+ errorText={state === 'error' ? c.clientIdError : undefined}
68
+ showRequiredMarker={false}
69
+ />
70
+ <PrizmaDropdown
71
+ label={c.environmentLabel}
72
+ placeholder={c.environmentPlaceholder}
73
+ options={c.environments}
74
+ value={environment}
75
+ showRequiredMarker={false}
76
+ forceOpen={state === 'environmentOpen'}
77
+ />
78
+ {custom ? (
79
+ <PrizmaTextField label={c.urlLabel} defaultValue={c.urlValue} showRequiredMarker={false} />
80
+ ) : null}
81
+ </div>
82
+ </div>
83
+ <div className="prizma-screen-layout__band prizma-screen-layout__band--bare demo-screens-band">
84
+ <div className="prizma-screen-layout__band__ctas">
85
+ <PrizmaButton
86
+ variant="primary"
87
+ size="L"
88
+ disabled={!filled || state === 'error'}
89
+ onClick={() => onAction?.({ type: 'cta', screenId })}
90
+ >
91
+ {c.ctaLabel}
92
+ </PrizmaButton>
93
+ </div>
94
+ </div>
95
+ </PrizmaScreenShell>
96
+ );
97
+ },
98
+ );
99
+ DemoScreensConfigScreen.displayName = 'DemoScreensConfigScreen';
100
+
101
+ export default DemoScreensConfigScreen;
@@ -0,0 +1,120 @@
1
+ import React, { forwardRef, type ReactNode } from 'react';
2
+ import { PrizmaButton } from '@incodetech/prizma-core-web/button';
3
+ import { PrizmaTitle } from '@incodetech/prizma-core-web/title';
4
+ import { PrizmaNavigation } from '@incodetech/prizma-core-web/navigation';
5
+ import { PrizmaDropdown } from '@incodetech/prizma-core-web/dropdown';
6
+ import { PrizmaSnackbar } from '@incodetech/prizma-core-web/snackbar';
7
+ import { PrizmaBottomSheetContent } from '@incodetech/prizma-core-web/bottom-sheet';
8
+ import { PrizmaScreenShell, type PrizmaScreenShellProps } from './ScreenShell';
9
+ import type { PrizmaScreenActionHandler } from './types';
10
+ import type { DemoScreensStrings } from './DemoScreensStrings';
11
+ import './ScreenLayout.css';
12
+ import './DemoScreensLayout.css';
13
+
14
+ /**
15
+ * The four states of the `Demo config screen` row (2118:20999):
16
+ * - `default` "Build Predefined", Save disabled
17
+ * - `flowOpen` the flow menu open, with its search
18
+ * - `selected` "uxv2" chosen, Save live
19
+ * - `saved` back from the edit sheet: "settings saved" snackbar
20
+ */
21
+ export type DemoScreensConfigSheetState = 'default' | 'flowOpen' | 'selected' | 'saved';
22
+
23
+ export interface DemoScreensConfigSheetScreenProps
24
+ extends Omit<PrizmaScreenShellProps, 'dark' | 'title' | 'children'> {
25
+ /** Family copy — this screen reads the `configSheet` slice. */
26
+ strings: DemoScreensStrings;
27
+ state?: DemoScreensConfigSheetState;
28
+ screenId?: string;
29
+ onAction?: PrizmaScreenActionHandler;
30
+ }
31
+
32
+ /** Scrim + Core's sheet panel, the way Document Capture's method sheet does it
33
+ * (DEVIATIONS #DC-30): the screen owns the scrim, Core owns the panel. */
34
+ export const DemoScreensSheet: React.FC<{ ariaLabel: string; children: ReactNode }> = ({ ariaLabel, children }) => (
35
+ <>
36
+ <div className="demo-screens-sheet-scrim" aria-hidden="true" />
37
+ <div className="demo-screens-sheet-panel">
38
+ <PrizmaBottomSheetContent variant="dialog" ariaLabel={ariaLabel} showButtonGroup={false} body={children} />
39
+ </div>
40
+ </>
41
+ );
42
+
43
+ /**
44
+ * Demo screens · NATIVE — the configuration sheet the Launch menu opens
45
+ * (`Configuration › Demo config screen`, 2118:20999): choose the flow to run,
46
+ * read which Client ID and environment are set, or go edit them.
47
+ *
48
+ * Core's bottom sheet carries the panel; inside it Navigation (close only),
49
+ * a left Title, a searchable Dropdown, two read-only lines, and a CTA band of
50
+ * primary → tertiary link → build caption. The sheet's own header slot is not
51
+ * used because the frame puts the nav row ABOVE the title.
52
+ */
53
+ export const DemoScreensConfigSheetScreen = forwardRef<HTMLDivElement, DemoScreensConfigSheetScreenProps>(
54
+ (
55
+ { strings, state = 'default', screenId = `demo-screens-config-sheet-${state}`, onAction, ...shell },
56
+ ref,
57
+ ) => {
58
+ const s = strings.configSheet;
59
+ const options = [{ value: s.flowValue, label: s.flowValue }, ...s.flows];
60
+ const value = state === 'selected' ? s.flowSelected : s.flowValue;
61
+ return (
62
+ <PrizmaScreenShell ref={ref} data-screen-id={screenId} {...shell}>
63
+ {state === 'saved' ? (
64
+ <div className="demo-screens-toast">
65
+ <PrizmaSnackbar state="success" contentResizing="fill" isMultiline>
66
+ {s.savedSnackbar}
67
+ </PrizmaSnackbar>
68
+ </div>
69
+ ) : null}
70
+ <DemoScreensSheet ariaLabel={s.title}>
71
+ <div className="demo-screens-sheet__nav">
72
+ <PrizmaNavigation
73
+ showIncodeLogo={false}
74
+ showRightIcon
75
+ closeLabel={s.closeLabel}
76
+ onRightIconClick={() => onAction?.({ type: 'help', screenId })}
77
+ aria-label={s.title}
78
+ />
79
+ </div>
80
+ <div className="demo-screens-sheet__title">
81
+ <PrizmaTitle variant="left" title={s.title} showSubtitle subtitle={s.subtitle} />
82
+ </div>
83
+ <div className="demo-screens-sheet__fields">
84
+ <PrizmaDropdown
85
+ label={s.flowLabel}
86
+ options={options}
87
+ value={value}
88
+ showRequiredMarker={false}
89
+ searchable
90
+ searchPlaceholder={s.searchPlaceholder}
91
+ clearSearchLabel={s.clearSearchLabel}
92
+ forceOpen={state === 'flowOpen'}
93
+ />
94
+ <div className="demo-screens-sheet__lines">
95
+ <p className="demo-screens-sheet__line">{s.clientIdLine}</p>
96
+ <p className="demo-screens-sheet__line">{s.environmentLine}</p>
97
+ </div>
98
+ </div>
99
+ <div className="demo-screens-sheet__band">
100
+ <PrizmaButton
101
+ variant="primary"
102
+ size="L"
103
+ disabled={state !== 'selected'}
104
+ onClick={() => onAction?.({ type: 'cta', screenId })}
105
+ >
106
+ {s.saveLabel}
107
+ </PrizmaButton>
108
+ <PrizmaButton variant="tertiary-link" size="L" onClick={() => onAction?.({ type: 'tertiary', screenId })}>
109
+ {s.editLinkLabel}
110
+ </PrizmaButton>
111
+ <p className="demo-screens-build">{s.buildLabel}</p>
112
+ </div>
113
+ </DemoScreensSheet>
114
+ </PrizmaScreenShell>
115
+ );
116
+ },
117
+ );
118
+ DemoScreensConfigSheetScreen.displayName = 'DemoScreensConfigSheetScreen';
119
+
120
+ export default DemoScreensConfigSheetScreen;