@incodetech/prizma-core-screens 0.2.24 → 0.2.26

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.
@@ -1,12 +1,17 @@
1
- import React, { forwardRef } from 'react';
1
+ import React, { forwardRef, useEffect, useId, useState } from 'react';
2
+ import { PrizmaSegmentedControl } from '@incodetech/prizma-core-web/segmented-control';
2
3
  import { PrizmaSignaturePad } from '@incodetech/prizma-core-web/signature-pad';
4
+ import { PrizmaSignaturePreview } from '@incodetech/prizma-core-web/signature-preview';
5
+ import { PrizmaTextField } from '@incodetech/prizma-core-web/text-field';
3
6
  import { PrizmaFormScreen, type PrizmaFormScreenProps } from './FormScreen';
4
7
  import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
5
8
  import type {
6
9
  ElectronicSignatureDrawState,
10
+ ElectronicSignatureMethod,
7
11
  ElectronicSignatureStrings,
8
12
  } from './ElectronicSignatureStrings';
9
13
  import './ScreenLayout.css';
14
+ import './ElectronicSignatureLayout.css';
10
15
 
11
16
  export interface ElectronicSignatureDrawScreenProps
12
17
  extends Omit<
@@ -23,8 +28,22 @@ export interface ElectronicSignatureDrawScreenProps
23
28
  > {
24
29
  /** Module copy — this screen reads the `draw` slice. */
25
30
  strings: ElectronicSignatureStrings;
26
- /** Which purple section to render: `draw` (empty) or `signed`. Default `draw`. */
31
+ /**
32
+ * Which pose to render: `draw` (empty pad), `signed` (ink on the pad) or
33
+ * `type` (type mode, `typedName` in the field). Default `draw`.
34
+ */
27
35
  state?: ElectronicSignatureDrawState;
36
+ /**
37
+ * Draw or Type, when the host owns it. Left out, the screen keeps its own,
38
+ * starting from `state`. Only read when `strings.type` is supplied.
39
+ */
40
+ method?: ElectronicSignatureMethod;
41
+ /** Called when the person switches between Draw and Type. */
42
+ onMethodChange?: (method: ElectronicSignatureMethod) => void;
43
+ /** The typed name, when the host owns it. Left out, the screen keeps its own. */
44
+ typedName?: string;
45
+ /** Called on every change to the typed name. */
46
+ onTypedNameChange?: (name: string) => void;
28
47
  /**
29
48
  * Core's own extension point for the drawing engine
30
49
  * (`PrizmaSignaturePad.onCanvasReady`: "consumers wire their drawing engine
@@ -79,6 +98,10 @@ export const ElectronicSignatureDrawScreen = forwardRef<
79
98
  {
80
99
  strings,
81
100
  state = 'draw',
101
+ method: methodProp,
102
+ onMethodChange,
103
+ typedName: typedNameProp,
104
+ onTypedNameChange,
82
105
  onCanvasReady,
83
106
  screenId = `electronic-signature-${state}`,
84
107
  overrides,
@@ -88,16 +111,129 @@ export const ElectronicSignatureDrawScreen = forwardRef<
88
111
  ref,
89
112
  ) => {
90
113
  const signed = state === 'signed';
114
+ const alt = strings.type;
115
+
116
+ // Draw / Type: controlled when the host passes `method` / `typedName`,
117
+ // otherwise the screen holds them, starting from the pose.
118
+ const [ownMethod, setOwnMethod] = useState<ElectronicSignatureMethod>(
119
+ state === 'type' ? 'type' : 'draw',
120
+ );
121
+ const [ownName, setOwnName] = useState(state === 'type' ? typedNameProp ?? '' : '');
122
+ useEffect(() => {
123
+ setOwnMethod(state === 'type' ? 'type' : 'draw');
124
+ }, [state]);
125
+ const method: ElectronicSignatureMethod = alt ? methodProp ?? ownMethod : 'draw';
126
+ const name = typedNameProp ?? ownName;
127
+ const typing = method === 'type';
128
+ const [padKey, setPadKey] = useState(0);
129
+ const panelId = useId();
130
+
131
+ const setName = (next: string) => {
132
+ if (typedNameProp === undefined) setOwnName(next);
133
+ onTypedNameChange?.(next);
134
+ };
135
+ // Switching clears what the other mode held, the Document Electronic
136
+ // Signature rule (Elena, 2026-11-12), so Done only turns on for the
137
+ // signature on screen. A fresh pad is a remount of Core's pad.
138
+ const switchMethod = (next: ElectronicSignatureMethod) => {
139
+ if (next === method) return;
140
+ setPadKey((k) => k + 1);
141
+ setName('');
142
+ if (methodProp === undefined) setOwnMethod(next);
143
+ onMethodChange?.(next);
144
+ };
145
+
146
+ const ready = typing ? name.trim().length > 1 : signed;
147
+ const title = typing && alt ? alt.title : strings.draw.title;
148
+ const subtitle = typing && alt ? alt.subtitle : strings.draw.subtitle;
149
+
150
+ const pad = (ghost: boolean) => (
151
+ <PrizmaSignaturePad
152
+ key={ghost ? 'ghost' : padKey}
153
+ isFilled={ghost ? false : signed}
154
+ /* Full-signature sub-type, not the initials one. */
155
+ isInitials={false}
156
+ placeholder={strings.draw.placeholder}
157
+ canvasLabel={strings.draw.canvasLabel}
158
+ clearLabel={strings.draw.clearLabel}
159
+ /* Clearing the canvas is a different flow from submitting it, so it
160
+ emits its own event rather than collapsing into the CTA
161
+ (DEVIATIONS #PI-10). */
162
+ onClear={ghost ? undefined : () => onAction?.({ type: 'secondary', screenId })}
163
+ onCanvasReady={ghost ? undefined : onCanvasReady}
164
+ />
165
+ );
166
+
167
+ // No `type` copy: the pad-only screen the module shipped with.
168
+ const middle = !alt ? (
169
+ pad(false)
170
+ ) : (
171
+ <div className="electronic-signature-method">
172
+ <PrizmaSegmentedControl
173
+ aria-label={alt.methodLabel}
174
+ value={method}
175
+ onValueChange={(v: string) => switchMethod(v === 'type' ? 'type' : 'draw')}
176
+ options={[
177
+ { value: 'draw', label: alt.drawLabel, controls: !typing ? panelId : undefined },
178
+ { value: 'type', label: alt.typeLabel, controls: typing ? panelId : undefined },
179
+ ]}
180
+ />
181
+ {!typing ? (
182
+ <div id={panelId} role="tabpanel" aria-label={alt.drawLabel} className="electronic-signature-method__body">
183
+ {pad(false)}
184
+ </div>
185
+ ) : (
186
+ <div
187
+ id={panelId}
188
+ role="tabpanel"
189
+ aria-label={alt.typeLabel}
190
+ className="electronic-signature-method__body electronic-signature-method__body--type"
191
+ >
192
+ {/* An inert copy of the pad holds the Draw height, so the CTA does
193
+ not jump when the mode switches. Inert, not just hidden: its
194
+ Clear canvas button must stay out of focus and hit-testing. */}
195
+ <div className="electronic-signature-method__floor" aria-hidden="true" {...{ inert: '' }}>
196
+ {pad(true)}
197
+ </div>
198
+ <div className="electronic-signature-method__type">
199
+ {/* Set up for a name: the phone offers the person's own,
200
+ capitalises each word, does not autocorrect, Return submits. */}
201
+ <PrizmaTextField
202
+ label={alt.nameLabel}
203
+ value={name}
204
+ onValueChange={setName}
205
+ autoComplete="name"
206
+ autoCapitalize="words"
207
+ autoCorrect="off"
208
+ spellCheck={false}
209
+ enterKeyHint="done"
210
+ onKeyDown={(e) => {
211
+ if (e.key === 'Enter' && ready) {
212
+ e.preventDefault();
213
+ onAction?.({ type: 'cta', screenId });
214
+ }
215
+ }}
216
+ />
217
+ <PrizmaSignaturePreview
218
+ label={alt.previewLabel}
219
+ name={name}
220
+ placeholder={alt.previewPlaceholder}
221
+ />
222
+ </div>
223
+ </div>
224
+ )}
225
+ </div>
226
+ );
91
227
 
92
228
  return (
93
229
  <PrizmaFormScreen
94
230
  ref={ref}
95
- title={strings.draw.title}
96
- subtitle={strings.draw.subtitle}
231
+ title={title}
232
+ subtitle={subtitle}
97
233
  ctaLabel={strings.draw.ctaLabel}
98
234
  /* `eSign.draw` draws `Done` on Button/Primary/Surface/Disabled — there
99
- is nothing to submit until the canvas has ink. */
100
- ctaDisabled={!signed}
235
+ is nothing to submit until the canvas has ink, or a name is typed. */
236
+ ctaDisabled={!ready}
101
237
  verifiedLabel={strings.verifiedLabel}
102
238
  navLabel={strings.navLabel}
103
239
  screenId={screenId}
@@ -105,19 +241,7 @@ export const ElectronicSignatureDrawScreen = forwardRef<
105
241
  onAction={onAction}
106
242
  {...shell}
107
243
  >
108
- <PrizmaSignaturePad
109
- isFilled={signed}
110
- /* Full-signature sub-type, not the initials one. */
111
- isInitials={false}
112
- placeholder={strings.draw.placeholder}
113
- canvasLabel={strings.draw.canvasLabel}
114
- clearLabel={strings.draw.clearLabel}
115
- /* Clearing the canvas is a different flow from submitting it, so it
116
- emits its own event rather than collapsing into the CTA
117
- (DEVIATIONS #PI-10). */
118
- onClear={() => onAction?.({ type: 'secondary', screenId })}
119
- onCanvasReady={onCanvasReady}
120
- />
244
+ {middle}
121
245
  </PrizmaFormScreen>
122
246
  );
123
247
  },
@@ -84,3 +84,35 @@
84
84
  letter-spacing: var(--prizma-headline-h5-letter-spacing);
85
85
  color: var(--prizma-text-body-800-primary);
86
86
  }
87
+
88
+ /* ── Draw / Type (`strings.type` supplied) ───────────────────────────────────
89
+ * Core's Segmented control over the mode's body, the same composition as
90
+ * Document Electronic Signature's sheet (`.document-signature-sheet-body`):
91
+ * Spacing/8 between the control and the body, and between field and preview.
92
+ * Type mode keeps the Draw body's height: an inert copy of Core's pad shares
93
+ * the grid cell with the field + preview, so the CTA does not jump. */
94
+ .electronic-signature-method,
95
+ .electronic-signature-method__body,
96
+ .electronic-signature-method__type {
97
+ display: flex;
98
+ flex-direction: column;
99
+ gap: var(--prizma-spacing-8);
100
+ }
101
+
102
+ .electronic-signature-method__body--type {
103
+ display: grid;
104
+ }
105
+
106
+ .electronic-signature-method__body--type > * {
107
+ grid-area: 1 / 1;
108
+ min-width: 0;
109
+ }
110
+
111
+ .electronic-signature-method__floor {
112
+ visibility: hidden;
113
+ pointer-events: none;
114
+ }
115
+
116
+ .electronic-signature-method__type {
117
+ align-self: start;
118
+ }
@@ -15,7 +15,10 @@
15
15
  * placeholder visible, both actions inert) and `eSign.signed` (ink on the
16
16
  * canvas, Clear live, Done live). One screen, one Figma-drawn axis.
17
17
  */
18
- export type ElectronicSignatureDrawState = 'draw' | 'signed';
18
+ export type ElectronicSignatureDrawState = 'draw' | 'signed' | 'type';
19
+
20
+ /** How the person signs: drawing on the pad, or typing their name. */
21
+ export type ElectronicSignatureMethod = 'draw' | 'type';
19
22
 
20
23
  export interface ElectronicSignatureStrings {
21
24
  /** "verified by" attribution copy for the footer tag. */
@@ -49,6 +52,30 @@ export interface ElectronicSignatureStrings {
49
52
  ctaLabel: string;
50
53
  };
51
54
 
55
+ /**
56
+ * Draw / Type — the accessible alternative to the pad (Elena, 2026-11-13,
57
+ * the same switch as Document Electronic Signature's sheet). Optional: a
58
+ * host that leaves it out keeps the pad-only screen it shipped with.
59
+ */
60
+ type?: {
61
+ /** Accessible name for the Draw / Type Segmented control — "Signature method". */
62
+ methodLabel: string;
63
+ /** Segmented control, the draw option — "Draw". */
64
+ drawLabel: string;
65
+ /** Segmented control, the type option — "Type". */
66
+ typeLabel: string;
67
+ /** H2 in type mode — "Type your name". */
68
+ title: string;
69
+ /** H5 in type mode — "Use your full name". */
70
+ subtitle: string;
71
+ /** Field label — "Full name". */
72
+ nameLabel: string;
73
+ /** Core's Signature preview label, under the field — "Preview". */
74
+ previewLabel: string;
75
+ /** Signature preview while the field is empty — "Your signature". */
76
+ previewPlaceholder: string;
77
+ };
78
+
52
79
  /** `eSign.success` — the verdict, reported with no action. */
53
80
  success: {
54
81
  /** H2 — "Signed successfully!". */
@@ -154,7 +154,6 @@ export const FaceCaptureCapturingScreen = forwardRef<
154
154
  extendTime && offer ? (
155
155
  <PrizmaSnackbar
156
156
  state="neutral"
157
- isMultiline
158
157
  // Assertive on purpose — see the live-region note in this file's
159
158
  // header. The component default here would be `status`.
160
159
  role="alert"
@@ -228,7 +228,6 @@ export const IdCaptureStageScreen = forwardRef<HTMLDivElement, IdCaptureStageScr
228
228
  (extendTime && offer ? (
229
229
  <PrizmaSnackbar
230
230
  state="neutral"
231
- isMultiline
232
231
  // Assertive on purpose — a polite region can queue behind the
233
232
  // stage's own state announcements and be read out after the 20 s
234
233
  // has already run out. FaceCaptureCapturingScreen's header has the
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ // from the `read-and-sign-in-one-screen` exploration
1
2
  // @incodetech/prizma-core-screens — barrel.
2
3
  //
3
4
  // Foundation: shell, nav, capture overlay, and the seven screen archetypes
@@ -394,11 +395,27 @@ export { CurpResultScreen, type CurpResultScreenProps } from './CurpResultScreen
394
395
 
395
396
  // ── Electronic Signature (wave 3) ────────────────────────────────────────────────
396
397
  // Purple sections of the Electronic Signature Figma file (kUsDigsC8Mq1WobTewF0R6, page 5:13191).
397
- export { type ElectronicSignatureDrawState, type ElectronicSignatureStrings } from './ElectronicSignatureStrings';
398
+ export {
399
+ type ElectronicSignatureDrawState,
400
+ type ElectronicSignatureMethod,
401
+ type ElectronicSignatureStrings,
402
+ } from './ElectronicSignatureStrings';
398
403
  export { ElectronicSignatureDrawScreen, type ElectronicSignatureDrawScreenProps } from './ElectronicSignatureDrawScreen';
399
404
  export { ElectronicSignatureErrorScreen, type ElectronicSignatureErrorScreenProps } from './ElectronicSignatureErrorScreen';
400
405
  export { ElectronicSignatureReviewScreen, type ElectronicSignatureReviewScreenProps } from './ElectronicSignatureReviewScreen';
401
406
  export { ElectronicSignatureSuccessScreen, type ElectronicSignatureSuccessScreenProps } from './ElectronicSignatureSuccessScreen';
407
+ // Document Electronic Signature: from the `read-and-sign-in-one-screen` exploration.
408
+ export {
409
+ documentSignatureResultStrings,
410
+ type DocumentSignatureState,
411
+ type DocumentSignatureStrings,
412
+ } from './DocumentSignatureStrings';
413
+ export {
414
+ DocumentSignatureReviewScreen,
415
+ type DocumentSignatureDocument,
416
+ type DocumentSignatureReviewScreenProps,
417
+ type DocumentSignatureSignature,
418
+ } from './DocumentSignatureReviewScreen';
402
419
 
403
420
  // ── Qualified Signature (wave 3) ────────────────────────────────────────────────
404
421
  // Purple sections of the Qualified Signature Figma file (XO9YGKlEsGUyag8CGbSUsi, page 6086:28669).
package/src/styles.css CHANGED
@@ -18,6 +18,7 @@
18
18
  @import './DemoScreensLayout.css';
19
19
  @import './DigitalIdProvidersLayout.css';
20
20
  @import './DocumentCaptureLayout.css';
21
+ @import './DocumentSignatureLayout.css';
21
22
  @import './EkycLayout.css';
22
23
  @import './ElectronicSignatureLayout.css';
23
24
  @import './FaceCaptureLayout.css';