@incodetech/prizma-core-screens 0.1.3 → 0.2.4

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 +64 -3
  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
+ }
@@ -98,12 +98,31 @@ export interface PrizmaFormScreenProps
98
98
  * eKYB, Data Sharing Consent); it is the archetype's now. DEVIATIONS #DSC-2.
99
99
  */
100
100
  scrollFields?: boolean;
101
+ /**
102
+ * Let the field stack change SHAPE on a wide screen: `PrizmaFormRow` pairs
103
+ * become two lanes and Continue + Back share a row, once the shell's own
104
+ * container is at least 600 wide (FormScreen.css). Off by default, so every
105
+ * phone screen is untouched. Exploration `ekyb-desktop`, 2026-09-24.
106
+ */
107
+ responsive?: boolean;
101
108
  navLabel?: string;
102
109
  screenId?: string;
103
110
  overrides?: PrizmaScreenOverrides;
104
111
  onAction?: PrizmaScreenActionHandler;
105
112
  }
106
113
 
114
+ /**
115
+ * Two (or one) related fields that share a row on a wide screen and stack on a
116
+ * phone — street + house number, name + surname. A plain wrapper: it carries no
117
+ * spacing of its own beyond the stack's gap, and it only does anything inside a
118
+ * `PrizmaFormScreen` with `responsive`.
119
+ */
120
+ export function PrizmaFormRow({ children, className }: { children?: ReactNode; className?: string }) {
121
+ return (
122
+ <div className={['prizma-form-screen__row', className].filter(Boolean).join(' ')}>{children}</div>
123
+ );
124
+ }
125
+
107
126
  /**
108
127
  * Archetype E — Form / Input (GUIDELINES.md §6-E).
109
128
  * Nav → title block → field stack → CTA → verified tag. Module states
@@ -127,6 +146,7 @@ export const PrizmaFormScreen = forwardRef<HTMLDivElement, PrizmaFormScreenProps
127
146
  fieldsOffset,
128
147
  fieldsGap,
129
148
  scrollFields = false,
149
+ responsive = false,
130
150
  navLabel,
131
151
  screenId,
132
152
  showHeader = true,
@@ -137,7 +157,13 @@ export const PrizmaFormScreen = forwardRef<HTMLDivElement, PrizmaFormScreenProps
137
157
  },
138
158
  ref,
139
159
  ) => (
140
- <PrizmaScreenShell ref={ref} {...shell}>
160
+ <PrizmaScreenShell
161
+ ref={ref}
162
+ {...shell}
163
+ className={[shell.className, responsive ? 'prizma-form-screen--responsive' : null]
164
+ .filter(Boolean)
165
+ .join(' ') || undefined}
166
+ >
141
167
  <PrizmaScreenNav reserved={!showHeader} logo={overrides?.logo} navLabel={navLabel} />
142
168
  <div className="prizma-screen-layout__content">
143
169
  {progress ? (
package/src/index.ts CHANGED
@@ -391,7 +391,18 @@ export {
391
391
  type EkycDetailsValues,
392
392
  type EkycLicenseValues,
393
393
  type EkycStrings,
394
+ type EkycCountryValues,
394
395
  } from './EkycStrings';
396
+ export {
397
+ EKYC_COUNTRY_CATALOG,
398
+ ekycCountryVariant,
399
+ type EkycCountryVariant,
400
+ type EkycCountryStep,
401
+ type EkycField,
402
+ type EkycFieldKey,
403
+ type EkycFieldKind,
404
+ } from './EkycCountryCatalog';
405
+ export { EkycCountryFormScreen, type EkycCountryFormScreenProps } from './EkycCountryFormScreen';
395
406
  export { EkycDetailsScreen, type EkycDetailsScreenProps } from './EkycDetailsScreen';
396
407
  export { EkycErrorScreen, type EkycErrorScreenProps } from './EkycErrorScreen';
397
408
  export { EkycLicenseScreen, type EkycLicenseScreenProps } from './EkycLicenseScreen';
@@ -553,7 +564,60 @@ export {
553
564
  export { ErrorScreensScreen, type ErrorScreensScreenProps } from './ErrorScreensScreen';
554
565
 
555
566
  // Demo screens — the end screen; the start screen is owner-owned and pending.
556
- export { type DemoScreensStrings } from './DemoScreensStrings';
567
+ export {
568
+ type DemoScreensStrings,
569
+ type DemoScreensLanguage,
570
+ type DemoScreensOption,
571
+ } from './DemoScreensStrings';
572
+ export {
573
+ DemoScreensConfigScreen,
574
+ type DemoScreensConfigScreenProps,
575
+ type DemoScreensConfigState,
576
+ } from './DemoScreensConfigScreen';
577
+ export {
578
+ DemoScreensTermsScreen,
579
+ type DemoScreensTermsScreenProps,
580
+ } from './DemoScreensTermsScreen';
581
+ export {
582
+ DemoScreensLaunchScreen,
583
+ type DemoScreensLaunchScreenProps,
584
+ } from './DemoScreensLaunchScreen';
585
+ export {
586
+ DemoScreensConfigSheetScreen,
587
+ type DemoScreensConfigSheetScreenProps,
588
+ type DemoScreensConfigSheetState,
589
+ } from './DemoScreensConfigSheetScreen';
590
+ export {
591
+ DemoScreensEditSheetScreen,
592
+ type DemoScreensEditSheetScreenProps,
593
+ type DemoScreensEditSheetState,
594
+ } from './DemoScreensEditSheetScreen';
595
+ export {
596
+ DemoScreensRedirectScreen,
597
+ type DemoScreensRedirectScreenProps,
598
+ type DemoScreensRedirectStage,
599
+ } from './DemoScreensRedirectScreen';
600
+ export {
601
+ DemoScreensSplashScreen,
602
+ type DemoScreensSplashScreenProps,
603
+ } from './DemoScreensSplashScreen';
604
+ export {
605
+ DemoScreensStartScreen,
606
+ type DemoScreensStartScreenProps,
607
+ } from './DemoScreensStartScreen';
608
+ export {
609
+ DemoScreensSettingsScreen,
610
+ type DemoScreensSettingsScreenProps,
611
+ } from './DemoScreensSettingsScreen';
612
+ export {
613
+ DemoScreensRunningScreen,
614
+ type DemoScreensRunningScreenProps,
615
+ } from './DemoScreensRunningScreen';
616
+ export {
617
+ DemoScreensResultScreen,
618
+ type DemoScreensResultScreenProps,
619
+ type DemoScreensResultStatus,
620
+ } from './DemoScreensResultScreen';
557
621
  export {
558
622
  DemoScreensEndScreen,
559
623
  type DemoScreensEndScreenProps,
package/src/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';