@incodetech/prizma-core-screens 0.2.22 → 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.
- package/dist/DemoScreensConfigSheetScreen.js +1 -1
- package/dist/DocumentSignatureLayout.css +160 -0
- package/dist/DocumentSignatureReviewScreen.d.ts +88 -0
- package/dist/DocumentSignatureReviewScreen.js +274 -0
- package/dist/DocumentSignatureStrings.d.ts +82 -0
- package/dist/DocumentSignatureStrings.js +39 -0
- package/dist/ElectronicSignatureDrawScreen.d.ts +17 -2
- package/dist/ElectronicSignatureDrawScreen.js +60 -12
- package/dist/ElectronicSignatureLayout.css +32 -0
- package/dist/ElectronicSignatureStrings.d.ts +26 -1
- package/dist/FaceCaptureCapturingScreen.js +1 -1
- package/dist/IdCaptureStageScreen.js +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4 -0
- package/dist/styles.css +1 -0
- package/package.json +9 -3
- package/src/DemoScreensConfigSheetScreen.tsx +1 -1
- package/src/DocumentSignatureLayout.css +160 -0
- package/src/DocumentSignatureReviewScreen.tsx +517 -0
- package/src/DocumentSignatureStrings.ts +122 -0
- package/src/ElectronicSignatureDrawScreen.tsx +143 -19
- package/src/ElectronicSignatureLayout.css +32 -0
- package/src/ElectronicSignatureStrings.ts +28 -1
- package/src/FaceCaptureCapturingScreen.tsx +0 -1
- package/src/IdCaptureStageScreen.tsx +0 -1
- package/src/index.ts +18 -1
- package/src/styles.css +1 -0
|
@@ -27,7 +27,7 @@ export const DemoScreensConfigSheetScreen = forwardRef(({ strings, state = 'defa
|
|
|
27
27
|
const s = strings.configSheet;
|
|
28
28
|
const options = [{ value: s.flowValue, label: s.flowValue }, ...s.flows];
|
|
29
29
|
const value = state === 'selected' ? s.flowSelected : s.flowValue;
|
|
30
|
-
return (_jsxs(PrizmaScreenShell, { ref: ref, "data-screen-id": screenId, ...shell, children: [state === 'saved' ? (_jsx("div", { className: "demo-screens-toast", children: _jsx(PrizmaSnackbar, { state: "success", contentResizing: "fill",
|
|
30
|
+
return (_jsxs(PrizmaScreenShell, { ref: ref, "data-screen-id": screenId, ...shell, children: [state === 'saved' ? (_jsx("div", { className: "demo-screens-toast", children: _jsx(PrizmaSnackbar, { state: "success", contentResizing: "fill", children: s.savedSnackbar }) })) : null, _jsxs(DemoScreensSheet, { ariaLabel: s.title, children: [_jsx("div", { className: "demo-screens-sheet__nav", children: _jsx(PrizmaNavigation, { showIncodeLogo: false, showRightIcon: true, closeLabel: s.closeLabel, onRightIconClick: () => onAction?.({ type: 'help', screenId }), "aria-label": s.title }) }), _jsx("div", { className: "demo-screens-sheet__title", children: _jsx(PrizmaTitle, { variant: "left", title: s.title, showSubtitle: true, subtitle: s.subtitle }) }), _jsxs("div", { className: "demo-screens-sheet__fields", children: [_jsx(PrizmaDropdown, { label: s.flowLabel, options: options, value: value, showRequiredMarker: false, searchable: true, searchPlaceholder: s.searchPlaceholder, clearSearchLabel: s.clearSearchLabel, forceOpen: state === 'flowOpen' }), _jsxs("div", { className: "demo-screens-sheet__lines", children: [_jsx("p", { className: "demo-screens-sheet__line", children: s.clientIdLine }), _jsx("p", { className: "demo-screens-sheet__line", children: s.environmentLine })] })] }), _jsxs("div", { className: "demo-screens-sheet__band", children: [_jsx(PrizmaButton, { variant: "primary", size: "L", disabled: state !== 'selected', onClick: () => onAction?.({ type: 'cta', screenId }), children: s.saveLabel }), _jsx(PrizmaButton, { variant: "tertiary-link", size: "L", onClick: () => onAction?.({ type: 'tertiary', screenId }), children: s.editLinkLabel }), _jsx("p", { className: "demo-screens-build", children: s.buildLabel })] })] })] }));
|
|
31
31
|
});
|
|
32
32
|
DemoScreensConfigSheetScreen.displayName = 'DemoScreensConfigSheetScreen';
|
|
33
33
|
export default DemoScreensConfigSheetScreen;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/* from the `read-and-sign-in-one-screen` exploration
|
|
2
|
+
*
|
|
3
|
+
* Document Electronic Signature — layout glue only. No archetype value is
|
|
4
|
+
* redeclared (the gutters, the title block, the CTA band and the tag stay the
|
|
5
|
+
* foundation's) and nothing here draws a component: the viewer frame is
|
|
6
|
+
* Electronic Signature's `.electronic-signature-document`, the Stepper,
|
|
7
|
+
* Scroll pill, Segmented control, pad, field, Signature preview and sheet are
|
|
8
|
+
* Core's. Every value is a --prizma-*
|
|
9
|
+
* token. Ported from Option B (`read-and-sign.css`) of the exploration.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/* The viewer fills what the Stepper leaves. Electronic Signature's frame
|
|
13
|
+
carries a Spacing/16 bottom margin for its List screen; in the Form
|
|
14
|
+
archetype the field stack closes at Spacing/16 instead, so it is released
|
|
15
|
+
here and the stack takes it (the same gap, the same token). */
|
|
16
|
+
.document-signature-screen .prizma-form-screen__fields {
|
|
17
|
+
margin-bottom: var(--prizma-spacing-16);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.document-signature-screen .prizma-form-screen__fields > :not(.document-signature-viewer) {
|
|
21
|
+
flex-shrink: 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.document-signature-viewer.electronic-signature-document {
|
|
25
|
+
flex: 1 1 auto;
|
|
26
|
+
min-height: 0;
|
|
27
|
+
margin-bottom: 0;
|
|
28
|
+
/* The sections' offset parent, so the screen reads where each document is
|
|
29
|
+
in layout pixels, whatever transform a spec card scales the frame with. */
|
|
30
|
+
position: relative;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* One document: its title, then the host's prose. No divider between
|
|
34
|
+
documents: the count is the Stepper's caption. Electronic Signature's frame already spaces its direct
|
|
35
|
+
children; a section spaces its own. */
|
|
36
|
+
.document-signature-doc {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
gap: var(--prizma-spacing-12);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.document-signature-doc + .document-signature-doc {
|
|
43
|
+
margin-top: var(--prizma-spacing-24);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.document-signature-doc > * {
|
|
47
|
+
margin: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* A document's title is a step above its section headings: Headline/H4 on the
|
|
51
|
+
frame's own Text/Body/800. */
|
|
52
|
+
.electronic-signature-document .document-signature-doc__title {
|
|
53
|
+
font-size: var(--prizma-headline-h4-font-size);
|
|
54
|
+
line-height: var(--prizma-headline-h4-line-height);
|
|
55
|
+
font-weight: var(--prizma-headline-h4-font-weight);
|
|
56
|
+
letter-spacing: var(--prizma-headline-h4-letter-spacing);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* The sheet body: Core's Segmented control (Draw / Type), then the mode's
|
|
60
|
+
body. Spacing/8 between them, and between the field and the preview, the
|
|
61
|
+
exploration's own gap (`.rs-b-sheet`). */
|
|
62
|
+
.document-signature-sheet-body,
|
|
63
|
+
.document-signature-sheet-mode,
|
|
64
|
+
.document-signature-sheet-mode__type {
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
gap: var(--prizma-spacing-8);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Type mode keeps the Draw body's height: an invisible copy of Core's pad and
|
|
71
|
+
the field + preview share one grid cell, so the cell is as tall as the taller
|
|
72
|
+
of the two and the sheet does not jump when the mode switches. */
|
|
73
|
+
.document-signature-sheet-mode--type {
|
|
74
|
+
display: grid;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.document-signature-sheet-mode--type > * {
|
|
78
|
+
grid-area: 1 / 1;
|
|
79
|
+
min-width: 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.document-signature-sheet-mode__floor {
|
|
83
|
+
visibility: hidden;
|
|
84
|
+
pointer-events: none;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.document-signature-sheet-mode__type {
|
|
88
|
+
align-self: start;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* ── Short panels: the sheet stops under the status bar ──────────────────────
|
|
92
|
+
* The signing sheet is 652 tall (Draw, and Type keeps that height). On the
|
|
93
|
+
* Galaxy Z Fold 8 cover (416 x 657) it rose to 5px from the top, over the
|
|
94
|
+
* status bar (measured 2026-11-13); on every other frame Core Lab offers it
|
|
95
|
+
* clears with room (iPhone Duo closed 26, open 17, Fold main 164, the 844
|
|
96
|
+
* reference 192). Under the 720 short-panel line the panel stops at the status
|
|
97
|
+
* bar plus Spacing/24, the Demo screens sheet's own top, and the one element
|
|
98
|
+
* that gives ground is the pad's drawing area (step 1 of the order of
|
|
99
|
+
* concessions: it is space, not task information), 256 to 190 on the Fold
|
|
100
|
+
* cover. The title, the consent, Draw / Type, Clear canvas, Confirm and
|
|
101
|
+
* continue and Core's 34 safe area keep their size. Type keeps the field and
|
|
102
|
+
* the preview whole: only the invisible Draw floor gives way. Outside the
|
|
103
|
+
* query not one declaration exists, so the reference is untouched. */
|
|
104
|
+
@container pcs-screen (max-height: 720px) {
|
|
105
|
+
.document-signature-screen .prizma-screen-layout__sheet-panel {
|
|
106
|
+
max-height: calc(100% - var(--pcs-status-bar, 47px) - var(--prizma-spacing-24));
|
|
107
|
+
display: flex;
|
|
108
|
+
flex-direction: column;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.document-signature-screen .prizma-screen-layout__sheet-panel .prizma-bottom-sheet,
|
|
112
|
+
.document-signature-screen .prizma-screen-layout__sheet-panel .prizma-bottom-sheet__content,
|
|
113
|
+
.document-signature-screen .prizma-screen-layout__sheet-panel .prizma-bottom-sheet__body,
|
|
114
|
+
.document-signature-screen .document-signature-sheet-body,
|
|
115
|
+
.document-signature-screen .document-signature-sheet-mode,
|
|
116
|
+
.document-signature-screen .document-signature-sheet-mode .prizma-signature-pad,
|
|
117
|
+
.document-signature-screen .document-signature-sheet-mode .prizma-signature-pad__canvas-wrapper {
|
|
118
|
+
flex: 0 1 auto;
|
|
119
|
+
min-height: 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.document-signature-screen .prizma-screen-layout__sheet-panel .prizma-bottom-sheet__body {
|
|
123
|
+
display: flex;
|
|
124
|
+
flex-direction: column;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.document-signature-screen .prizma-bottom-sheet__content > :not(.prizma-bottom-sheet__body),
|
|
128
|
+
.document-signature-screen .document-signature-sheet-body > :not(.document-signature-sheet-mode) {
|
|
129
|
+
flex-shrink: 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* The grid cell may be shorter than the invisible Draw copy it holds. */
|
|
133
|
+
.document-signature-screen .document-signature-sheet-mode--type {
|
|
134
|
+
grid-template-rows: minmax(0, auto);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* ── The sheet's motion (2026-11-13) ─────────────────────────────────────────
|
|
139
|
+
Interactive only (`--moving` is set when the screen is live; static spec
|
|
140
|
+
cards stay still, as ScreenLayout's sheet rules intend). Core's Sheet/Motion
|
|
141
|
+
tokens and Core's own keyframes (`prizma-sheet-scrim-in/out`,
|
|
142
|
+
`prizma-sheet-slide-in/out` in bottom-sheet.css), as Core's presenter does: the scrim fades
|
|
143
|
+
in and the panel rises on Enter + Decelerate, and both leave on Exit +
|
|
144
|
+
Accelerate. Nothing moves under reduced motion. */
|
|
145
|
+
.document-signature-sheet-scrim--moving {
|
|
146
|
+
animation: prizma-sheet-scrim-in var(--prizma-sheet-motion-enter-duration) var(--prizma-sheet-motion-enter-easing) both;
|
|
147
|
+
}
|
|
148
|
+
.document-signature-sheet-panel--moving {
|
|
149
|
+
animation: prizma-sheet-slide-in var(--prizma-sheet-motion-enter-duration) var(--prizma-sheet-motion-enter-easing) both;
|
|
150
|
+
}
|
|
151
|
+
.document-signature-sheet-scrim--moving.is-closing {
|
|
152
|
+
animation: prizma-sheet-scrim-out var(--prizma-sheet-motion-exit-duration) var(--prizma-sheet-motion-exit-easing) both;
|
|
153
|
+
}
|
|
154
|
+
.document-signature-sheet-panel--moving.is-closing {
|
|
155
|
+
animation: prizma-sheet-slide-out var(--prizma-sheet-motion-exit-duration) var(--prizma-sheet-motion-exit-easing) both;
|
|
156
|
+
}
|
|
157
|
+
@media (prefers-reduced-motion: reduce) {
|
|
158
|
+
.document-signature-sheet-scrim--moving,
|
|
159
|
+
.document-signature-sheet-panel--moving { animation: none; }
|
|
160
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
import { type PrizmaFormScreenProps } from './FormScreen';
|
|
3
|
+
import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
|
|
4
|
+
import type { DocumentSignatureState, DocumentSignatureStrings } from './DocumentSignatureStrings';
|
|
5
|
+
import './ScreenLayout.css';
|
|
6
|
+
import './ElectronicSignatureLayout.css';
|
|
7
|
+
import './DocumentSignatureLayout.css';
|
|
8
|
+
/** One document to read and sign. Runtime DATA the host supplies, never copy
|
|
9
|
+
* the design system owns (the same slot contract as Electronic Signature's
|
|
10
|
+
* `document`). `content` is plain `<h4>` / `<p>` markup: the viewer's frame
|
|
11
|
+
* supplies the typography. */
|
|
12
|
+
export interface DocumentSignatureDocument {
|
|
13
|
+
title: string;
|
|
14
|
+
content: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/** What the person signed with, reported on Confirm and continue. */
|
|
17
|
+
export type DocumentSignatureSignature = {
|
|
18
|
+
method: 'draw';
|
|
19
|
+
} | {
|
|
20
|
+
method: 'type';
|
|
21
|
+
name: string;
|
|
22
|
+
};
|
|
23
|
+
export interface DocumentSignatureReviewScreenProps extends Omit<PrizmaFormScreenProps, 'progress' | 'title' | 'subtitle' | 'ctaLabel' | 'ctaDisabled' | 'ctaLoading' | 'ctaLoadingLabel' | 'linkLabel' | 'linkDisabled' | 'linkContent' | 'verifiedLabel' | 'navLabel' | 'children' | 'fieldsOffset' | 'fieldsGap' | 'scrollFields' | 'fieldsAlign' | 'overlay'> {
|
|
24
|
+
/** Module copy. */
|
|
25
|
+
strings: DocumentSignatureStrings;
|
|
26
|
+
/** Every document to sign, in reading order. One or more. */
|
|
27
|
+
documents: DocumentSignatureDocument[];
|
|
28
|
+
/** The pose to draw (and, when `interactive`, the pose to start from). */
|
|
29
|
+
state?: DocumentSignatureState;
|
|
30
|
+
/** The name in the field for `state="type"`. */
|
|
31
|
+
typedName?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Run the screen: the Stepper follows the scroll, the Scroll pill moves the
|
|
34
|
+
* viewer on, reaching the end of the last document turns Sign on AND opens
|
|
35
|
+
* the sheet (once), Sign reopens it after a dismiss, the Draw / Type switch
|
|
36
|
+
* clears the other mode, and Confirm and continue reports the signature. Off (the default), every pose is fixed by
|
|
37
|
+
* `state`, so a spec card always renders the same frame.
|
|
38
|
+
*/
|
|
39
|
+
interactive?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* `PrizmaSignaturePad.onCanvasReady`: the host's drawing engine, Core's
|
|
42
|
+
* documented division of labour (the pad ships the chrome, not the ink). For
|
|
43
|
+
* `state="drawn"` a spec host paints a specimen stroke here.
|
|
44
|
+
*/
|
|
45
|
+
onCanvasReady?: (canvas: HTMLCanvasElement) => void;
|
|
46
|
+
/** Confirm and continue was pressed with a signature on the sheet. */
|
|
47
|
+
onSignatureConfirm?: (signature: DocumentSignatureSignature) => void;
|
|
48
|
+
screenId?: string;
|
|
49
|
+
overrides?: PrizmaScreenOverrides;
|
|
50
|
+
/** Emits `cta` on Confirm and continue. Sign is handled inside the screen. */
|
|
51
|
+
onAction?: PrizmaScreenActionHandler;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Document Electronic Signature — read every document and sign them once, on
|
|
55
|
+
* ONE screen. Option B of the `read-and-sign-in-one-screen` exploration,
|
|
56
|
+
* decided with the owner (Elena, 2026-11-12), built on the Form archetype
|
|
57
|
+
* (GUIDELINES.md §6-E, `PrizmaFormScreen`).
|
|
58
|
+
*
|
|
59
|
+
* Core only, used as shipped:
|
|
60
|
+
*
|
|
61
|
+
* - `PrizmaFormScreen`: logo nav, "Review and sign", the Sign CTA (disabled
|
|
62
|
+
* until the reader reaches the end of the last document: consent needs
|
|
63
|
+
* proof the documents were read) and the verified tag.
|
|
64
|
+
* - `PrizmaStepper`, one segment per document, following the one being read,
|
|
65
|
+
* `Completed` once everything is read, with its `caption` ("Document 1 of
|
|
66
|
+
* 2", then "All documents read") naming the bar.
|
|
67
|
+
* - Every document in ONE scrolling viewer, Electronic Signature's own frame
|
|
68
|
+
* (`.electronic-signature-document`), one after the other with no divider:
|
|
69
|
+
* the count lives on the Stepper. One document: no Stepper.
|
|
70
|
+
* - `PrizmaScrollPill` ("Scroll to sign") in its `PrizmaScrollPillDock`, the
|
|
71
|
+
* viewer's last child, while there is reading left. A tap scrolls about 80%
|
|
72
|
+
* of the viewer; it unmounts once the end is reached.
|
|
73
|
+
* - `PrizmaBottomSheetContent` (dialog), "Add your signature": the consent as
|
|
74
|
+
* its subtitle; the body opens with `PrizmaSegmentedControl` (Draw / Type),
|
|
75
|
+
* then `PrizmaSignaturePad`, or `PrizmaTextField` with
|
|
76
|
+
* `PrizmaSignaturePreview` under it; its Button group holds only Confirm
|
|
77
|
+
* and continue, bottom bar on.
|
|
78
|
+
*
|
|
79
|
+
* The sheet rides the archetype's `overlay` slot (scrim + panel from
|
|
80
|
+
* `ScreenLayout.css`, the Reusability / Biometric Consent contract), not
|
|
81
|
+
* `PrizmaBottomSheet`'s presenter: the presenter portals to `document.body`,
|
|
82
|
+
* which escapes the 390 x 844 frame a spec card and a prototype draw in.
|
|
83
|
+
*
|
|
84
|
+
* Nothing new: the only module CSS is layout glue on Core tokens
|
|
85
|
+
* (`DocumentSignatureLayout.css`).
|
|
86
|
+
*/
|
|
87
|
+
export declare const DocumentSignatureReviewScreen: React.ForwardRefExoticComponent<DocumentSignatureReviewScreenProps & React.RefAttributes<HTMLDivElement>>;
|
|
88
|
+
export default DocumentSignatureReviewScreen;
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
// from the `read-and-sign-in-one-screen` exploration
|
|
4
|
+
import { forwardRef, useCallback, useEffect, useId, useLayoutEffect, useRef, useState, } from 'react';
|
|
5
|
+
import { PrizmaBottomSheetContent } from '@incodetech/prizma-core-web/bottom-sheet';
|
|
6
|
+
import { PrizmaScrollPill, PrizmaScrollPillDock } from '@incodetech/prizma-core-web/scroll-pill';
|
|
7
|
+
import { PrizmaSegmentedControl } from '@incodetech/prizma-core-web/segmented-control';
|
|
8
|
+
import { PrizmaSignaturePad } from '@incodetech/prizma-core-web/signature-pad';
|
|
9
|
+
import { PrizmaSignaturePreview } from '@incodetech/prizma-core-web/signature-preview';
|
|
10
|
+
import { PrizmaStepper, } from '@incodetech/prizma-core-web/stepper';
|
|
11
|
+
import { PrizmaTextField } from '@incodetech/prizma-core-web/text-field';
|
|
12
|
+
import { PrizmaFormScreen } from './FormScreen';
|
|
13
|
+
import './ScreenLayout.css';
|
|
14
|
+
import './ElectronicSignatureLayout.css';
|
|
15
|
+
import './DocumentSignatureLayout.css';
|
|
16
|
+
const POSE = {
|
|
17
|
+
start: { at: 'start', sheet: null },
|
|
18
|
+
second: { at: 'second', sheet: null },
|
|
19
|
+
end: { at: 'end', sheet: null },
|
|
20
|
+
draw: { at: 'end', sheet: 'draw' },
|
|
21
|
+
drawn: { at: 'end', sheet: 'draw' },
|
|
22
|
+
type: { at: 'end', sheet: 'type' },
|
|
23
|
+
};
|
|
24
|
+
/** Core's Stepper is authored for 2 to 7 segments. */
|
|
25
|
+
const MAX_STEPS = 7;
|
|
26
|
+
/** One tap on the Scroll pill: about a page, never straight to the end
|
|
27
|
+
* (Core's documented action for the pill, `ScrollPill.tsx`). */
|
|
28
|
+
const PILL_STEP = 0.8;
|
|
29
|
+
const count = (template, current, total) => template.replace('{{current}}', String(current)).replace('{{total}}', String(total));
|
|
30
|
+
/**
|
|
31
|
+
* Document Electronic Signature — read every document and sign them once, on
|
|
32
|
+
* ONE screen. Option B of the `read-and-sign-in-one-screen` exploration,
|
|
33
|
+
* decided with the owner (Elena, 2026-11-12), built on the Form archetype
|
|
34
|
+
* (GUIDELINES.md §6-E, `PrizmaFormScreen`).
|
|
35
|
+
*
|
|
36
|
+
* Core only, used as shipped:
|
|
37
|
+
*
|
|
38
|
+
* - `PrizmaFormScreen`: logo nav, "Review and sign", the Sign CTA (disabled
|
|
39
|
+
* until the reader reaches the end of the last document: consent needs
|
|
40
|
+
* proof the documents were read) and the verified tag.
|
|
41
|
+
* - `PrizmaStepper`, one segment per document, following the one being read,
|
|
42
|
+
* `Completed` once everything is read, with its `caption` ("Document 1 of
|
|
43
|
+
* 2", then "All documents read") naming the bar.
|
|
44
|
+
* - Every document in ONE scrolling viewer, Electronic Signature's own frame
|
|
45
|
+
* (`.electronic-signature-document`), one after the other with no divider:
|
|
46
|
+
* the count lives on the Stepper. One document: no Stepper.
|
|
47
|
+
* - `PrizmaScrollPill` ("Scroll to sign") in its `PrizmaScrollPillDock`, the
|
|
48
|
+
* viewer's last child, while there is reading left. A tap scrolls about 80%
|
|
49
|
+
* of the viewer; it unmounts once the end is reached.
|
|
50
|
+
* - `PrizmaBottomSheetContent` (dialog), "Add your signature": the consent as
|
|
51
|
+
* its subtitle; the body opens with `PrizmaSegmentedControl` (Draw / Type),
|
|
52
|
+
* then `PrizmaSignaturePad`, or `PrizmaTextField` with
|
|
53
|
+
* `PrizmaSignaturePreview` under it; its Button group holds only Confirm
|
|
54
|
+
* and continue, bottom bar on.
|
|
55
|
+
*
|
|
56
|
+
* The sheet rides the archetype's `overlay` slot (scrim + panel from
|
|
57
|
+
* `ScreenLayout.css`, the Reusability / Biometric Consent contract), not
|
|
58
|
+
* `PrizmaBottomSheet`'s presenter: the presenter portals to `document.body`,
|
|
59
|
+
* which escapes the 390 x 844 frame a spec card and a prototype draw in.
|
|
60
|
+
*
|
|
61
|
+
* Nothing new: the only module CSS is layout glue on Core tokens
|
|
62
|
+
* (`DocumentSignatureLayout.css`).
|
|
63
|
+
*/
|
|
64
|
+
export const DocumentSignatureReviewScreen = forwardRef(({ strings, documents, state = 'start', typedName = '', interactive = false, onCanvasReady, onSignatureConfirm, screenId = 'document-electronic-signature-review', overrides, onAction, className, ...shell }, ref) => {
|
|
65
|
+
const pose = POSE[state];
|
|
66
|
+
const total = documents.length;
|
|
67
|
+
const many = total > 1;
|
|
68
|
+
const { review, sign } = strings;
|
|
69
|
+
const [read, setRead] = useState(pose.at === 'end');
|
|
70
|
+
const [current, setCurrent] = useState(pose.at === 'start' ? 1 : Math.min(2, total));
|
|
71
|
+
const [sheet, setSheet] = useState(pose.sheet);
|
|
72
|
+
// Motion (Elena, 2026-11-13: "refinar el motion cuando llego abajo y
|
|
73
|
+
// aparece el pop up"). Interactive only; a static spec card never moves.
|
|
74
|
+
// `closing` keeps the sheet mounted while it slides out. Every duration is
|
|
75
|
+
// read from Core's Sheet/Motion tokens, never typed here.
|
|
76
|
+
const [closing, setClosing] = useState(false);
|
|
77
|
+
const sheetMs = (which) => {
|
|
78
|
+
if (typeof window === 'undefined')
|
|
79
|
+
return 0;
|
|
80
|
+
if (window.matchMedia?.('(prefers-reduced-motion: reduce)').matches)
|
|
81
|
+
return 0;
|
|
82
|
+
const v = getComputedStyle(document.documentElement).getPropertyValue(`--prizma-sheet-motion-${which}-duration`).trim();
|
|
83
|
+
const n = parseFloat(v);
|
|
84
|
+
return Number.isFinite(n) ? (v.endsWith('ms') ? n : n * 1000) : 0;
|
|
85
|
+
};
|
|
86
|
+
const [mode, setMode] = useState(pose.sheet === 'type' ? 'type' : 'draw');
|
|
87
|
+
const [inked, setInked] = useState(state === 'drawn');
|
|
88
|
+
const [name, setName] = useState(state === 'type' ? typedName : '');
|
|
89
|
+
const [padKey, setPadKey] = useState(0);
|
|
90
|
+
const viewer = useRef(null);
|
|
91
|
+
const panel = useRef(null);
|
|
92
|
+
const panelId = useId();
|
|
93
|
+
// A new pose from the host restarts the screen from it.
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
setRead(pose.at === 'end');
|
|
96
|
+
setCurrent(pose.at === 'start' ? 1 : pose.at === 'second' ? Math.min(2, total) : total);
|
|
97
|
+
setSheet(pose.sheet);
|
|
98
|
+
setMode(pose.sheet === 'type' ? 'type' : 'draw');
|
|
99
|
+
setInked(state === 'drawn');
|
|
100
|
+
setName(state === 'type' ? typedName : '');
|
|
101
|
+
}, [state, typedName, total, pose.at, pose.sheet]);
|
|
102
|
+
// Which document is being read (the one crossing the top third of the
|
|
103
|
+
// viewer), and whether the end of the last one was reached. Offsets, not
|
|
104
|
+
// bounding boxes: a spec card scales the frame with a CSS transform, and
|
|
105
|
+
// the viewer is the sections' offset parent (DocumentSignatureLayout.css).
|
|
106
|
+
const measure = useCallback(() => {
|
|
107
|
+
const v = viewer.current;
|
|
108
|
+
// A viewer that has not laid out yet reads as "already at the end" and
|
|
109
|
+
// would unlock Sign before anything was read.
|
|
110
|
+
if (!v || !interactive || v.clientHeight < 40)
|
|
111
|
+
return;
|
|
112
|
+
let at = 1;
|
|
113
|
+
v.querySelectorAll('[data-doc]').forEach((d, i) => {
|
|
114
|
+
if (d.offsetTop - v.scrollTop <= v.clientHeight * 0.3)
|
|
115
|
+
at = i + 1;
|
|
116
|
+
});
|
|
117
|
+
setCurrent(at);
|
|
118
|
+
if (v.scrollTop + v.clientHeight >= v.scrollHeight - 2) {
|
|
119
|
+
// Reaching the end opens the sheet by itself, once (Elena,
|
|
120
|
+
// 2026-11-12); Sign reopens it after a dismiss.
|
|
121
|
+
// A beat first, one Sheet/Motion/Enter long: the scroll settles and
|
|
122
|
+
// the Stepper's "All documents read" lands before the sheet rises, so
|
|
123
|
+
// the two changes read one after the other instead of at once.
|
|
124
|
+
setRead((was) => {
|
|
125
|
+
if (!was)
|
|
126
|
+
window.setTimeout(() => setSheet((cur) => cur ?? mode), sheetMs('enter'));
|
|
127
|
+
return true;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}, [interactive, mode]);
|
|
131
|
+
// Place the viewer for the pose: the top, the start of document 2, or the end.
|
|
132
|
+
useLayoutEffect(() => {
|
|
133
|
+
const v = viewer.current;
|
|
134
|
+
if (!v)
|
|
135
|
+
return;
|
|
136
|
+
if (pose.at === 'end')
|
|
137
|
+
v.scrollTop = v.scrollHeight;
|
|
138
|
+
else if (pose.at === 'second') {
|
|
139
|
+
const d2 = v.querySelector('[data-doc="2"]');
|
|
140
|
+
v.scrollTop = d2 ? d2.offsetTop : 0;
|
|
141
|
+
}
|
|
142
|
+
else
|
|
143
|
+
v.scrollTop = 0;
|
|
144
|
+
}, [pose.at, total]);
|
|
145
|
+
// Measure again once the viewer has its real height.
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
const v = viewer.current;
|
|
148
|
+
if (!v || !interactive || typeof ResizeObserver === 'undefined')
|
|
149
|
+
return;
|
|
150
|
+
const ro = new ResizeObserver(() => measure());
|
|
151
|
+
ro.observe(v);
|
|
152
|
+
return () => ro.disconnect();
|
|
153
|
+
}, [interactive, measure]);
|
|
154
|
+
// Focus moves into the sheet when it opens (it is a modal dialog).
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
if (interactive && sheet)
|
|
157
|
+
panel.current?.focus();
|
|
158
|
+
}, [interactive, sheet]);
|
|
159
|
+
const ready = mode === 'draw' ? inked : name.trim().length > 1;
|
|
160
|
+
// Sign reopens it the same way the end of the documents opens it (Elena,
|
|
161
|
+
// 2026-11-13): the same Sheet/Motion/Enter beat, then the same rise.
|
|
162
|
+
const openSheet = () => {
|
|
163
|
+
if (!interactive || !read)
|
|
164
|
+
return;
|
|
165
|
+
window.setTimeout(() => setSheet((cur) => cur ?? mode), sheetMs('enter'));
|
|
166
|
+
};
|
|
167
|
+
// Close with Core's exit curve: the sheet slides down, then unmounts.
|
|
168
|
+
const close = () => {
|
|
169
|
+
const ms = sheetMs('exit');
|
|
170
|
+
if (!ms) {
|
|
171
|
+
setSheet(null);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
setClosing(true);
|
|
175
|
+
window.setTimeout(() => {
|
|
176
|
+
setSheet(null);
|
|
177
|
+
setClosing(false);
|
|
178
|
+
}, ms);
|
|
179
|
+
};
|
|
180
|
+
const dismiss = () => {
|
|
181
|
+
if (!interactive)
|
|
182
|
+
return;
|
|
183
|
+
close();
|
|
184
|
+
viewer.current?.focus();
|
|
185
|
+
};
|
|
186
|
+
const confirm = () => {
|
|
187
|
+
if (!ready)
|
|
188
|
+
return;
|
|
189
|
+
onSignatureConfirm?.(mode === 'draw' ? { method: 'draw' } : { method: 'type', name: name.trim() });
|
|
190
|
+
onAction?.({ type: 'cta', screenId });
|
|
191
|
+
if (interactive)
|
|
192
|
+
close();
|
|
193
|
+
};
|
|
194
|
+
// Switching modes clears what the other mode held (Elena, 2026-11-12:
|
|
195
|
+
// "clear on switch"), so Confirm only turns on for the signature on screen.
|
|
196
|
+
const switchMode = (next) => {
|
|
197
|
+
if (!interactive || next === mode)
|
|
198
|
+
return;
|
|
199
|
+
setPadKey((k) => k + 1);
|
|
200
|
+
setInked(false);
|
|
201
|
+
setName('');
|
|
202
|
+
setMode(next);
|
|
203
|
+
setSheet(next);
|
|
204
|
+
};
|
|
205
|
+
const clear = () => {
|
|
206
|
+
if (!interactive)
|
|
207
|
+
return;
|
|
208
|
+
setPadKey((k) => k + 1);
|
|
209
|
+
setInked(false);
|
|
210
|
+
};
|
|
211
|
+
// The pill moves the reader on by about a page. Reaching the end stays a
|
|
212
|
+
// scroll, so the viewer's own onScroll unlocks Sign, not the pill.
|
|
213
|
+
const scrollOn = () => {
|
|
214
|
+
const v = viewer.current;
|
|
215
|
+
if (!interactive || !v)
|
|
216
|
+
return;
|
|
217
|
+
const still = typeof window !== 'undefined' &&
|
|
218
|
+
window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
|
|
219
|
+
v.scrollBy({ top: v.clientHeight * PILL_STEP, behavior: still ? 'auto' : 'smooth' });
|
|
220
|
+
};
|
|
221
|
+
const stepperState = read
|
|
222
|
+
? 'Completed'
|
|
223
|
+
: current <= 1
|
|
224
|
+
? 'Start'
|
|
225
|
+
: Math.min(current, MAX_STEPS);
|
|
226
|
+
const pad = (ghost) => (_jsx(PrizmaSignaturePad, { isFilled: ghost ? false : inked, isInitials: false, placeholder: sign.placeholder, canvasLabel: sign.canvasLabel, clearLabel: sign.clearLabel, onClear: ghost ? undefined : clear, onCanvasReady: ghost ? undefined : onCanvasReady }, ghost ? 'ghost' : padKey));
|
|
227
|
+
// The Type body keeps at least the Draw body's height, so the sheet does
|
|
228
|
+
// not jump when the mode switches (Elena, 2026-11-12). The exploration
|
|
229
|
+
// measured the Draw body in JS; here an invisible copy of the pad shares the
|
|
230
|
+
// Type body's grid cell, so the floor holds on a static spec card too.
|
|
231
|
+
// Layout glue, not a component: `visibility: hidden` keeps it out of the
|
|
232
|
+
// tab order and the accessibility tree.
|
|
233
|
+
const modeBody = mode === 'draw' ? (
|
|
234
|
+
// The first pointerdown on the canvas is ink: Core's pad flips its own
|
|
235
|
+
// Clear on it but reports nothing, so the screen hears it bubble up.
|
|
236
|
+
_jsx("div", { id: panelId, role: "tabpanel", "aria-label": sign.drawLabel, className: "document-signature-sheet-mode", onPointerDown: interactive ? () => setInked(true) : undefined, children: pad(false) })) : (_jsxs("div", { id: panelId, role: "tabpanel", "aria-label": sign.typeLabel, className: "document-signature-sheet-mode document-signature-sheet-mode--type", children: [_jsx("div", { className: "document-signature-sheet-mode__floor", "aria-hidden": "true", inert: '', children: pad(true) }), _jsxs("div", { className: "document-signature-sheet-mode__type", children: [_jsx(PrizmaTextField, { label: sign.nameLabel, ...(interactive ? { value: name, onValueChange: setName } : { defaultValue: name }), autoComplete: "name", autoCapitalize: "words", autoCorrect: "off", spellCheck: false, enterKeyHint: "done", onKeyDown: (e) => {
|
|
237
|
+
if (e.key === 'Enter' && ready) {
|
|
238
|
+
e.preventDefault();
|
|
239
|
+
confirm();
|
|
240
|
+
}
|
|
241
|
+
} }, interactive ? 'live' : `static-${name}`), _jsx(PrizmaSignaturePreview, { label: sign.previewLabel, name: name, placeholder: sign.previewPlaceholder })] })] }));
|
|
242
|
+
// Draw / Type sits right under the consent, at the top of the body, where
|
|
243
|
+
// the exploration's final Option B put it (it replaced the Secondary
|
|
244
|
+
// "Type your name instead / Draw instead" button).
|
|
245
|
+
const body = (_jsxs("div", { className: "document-signature-sheet-body", children: [_jsx(PrizmaSegmentedControl, { "aria-label": sign.methodLabel, value: mode, onValueChange: (v) => switchMode(v === 'type' ? 'type' : 'draw'), options: [
|
|
246
|
+
{ value: 'draw', label: sign.drawLabel, controls: mode === 'draw' ? panelId : undefined },
|
|
247
|
+
{ value: 'type', label: sign.typeLabel, controls: mode === 'type' ? panelId : undefined },
|
|
248
|
+
] }), modeBody] }));
|
|
249
|
+
const overlay = sheet ? (_jsxs(_Fragment, { children: [_jsx("div", { className: `prizma-screen-layout__sheet-scrim${interactive ? ' document-signature-sheet-scrim--moving' : ''}${closing ? ' is-closing' : ''}`, "aria-hidden": "true", onClick: dismiss }), _jsx("div", { className: `prizma-screen-layout__sheet-panel${interactive ? ' document-signature-sheet-panel--moving' : ''}${closing ? ' is-closing' : ''}`, children: _jsx(PrizmaBottomSheetContent, { ref: panel, variant: "dialog", title: sign.title, subtitle: sign.consent, body: body, showBottomBar: true, onKeyDown: (e) => {
|
|
250
|
+
if (e.key === 'Escape')
|
|
251
|
+
dismiss();
|
|
252
|
+
}, buttonGroupProps: {
|
|
253
|
+
orientation: 'vertical-v1',
|
|
254
|
+
showPrimary: true,
|
|
255
|
+
showSecondary: false,
|
|
256
|
+
showTertiary: false,
|
|
257
|
+
primaryLabel: sign.confirmLabel,
|
|
258
|
+
primaryDisabled: !ready,
|
|
259
|
+
onPrimaryClick: confirm,
|
|
260
|
+
} }) })] })) : undefined;
|
|
261
|
+
return (_jsxs(PrizmaFormScreen, { ref: ref, ...shell, className: ['document-signature-screen', className].filter(Boolean).join(' '), title: review.title, fieldsOffset: "12", ctaLabel: review.ctaLabel, ctaDisabled: !read, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides,
|
|
262
|
+
// Sign is a step inside this screen, not the module's result: it opens
|
|
263
|
+
// the sheet and reports nothing. Under the sheet's scrim it is inert.
|
|
264
|
+
onAction: (a) => {
|
|
265
|
+
if (a.type === 'cta' && !sheet)
|
|
266
|
+
openSheet();
|
|
267
|
+
}, overlay: overlay, children: [many ? (_jsx(PrizmaStepper, { steps: Math.min(total, MAX_STEPS), currentState: stepperState, showIcons: false,
|
|
268
|
+
// The caption also names the progressbar (Core wires
|
|
269
|
+
// aria-labelledby when there is no aria-label), so the count is
|
|
270
|
+
// announced once.
|
|
271
|
+
caption: read ? review.completedLabel : count(review.documentCount, current, total), completedValueText: review.completedLabel })) : null, _jsxs("div", { ref: viewer, onScroll: interactive ? measure : undefined, className: "electronic-signature-document document-signature-viewer", role: "region", "aria-label": review.documentsLabel, tabIndex: 0, children: [documents.map((d, i) => (_jsxs("section", { "data-doc": i + 1, className: "document-signature-doc", children: [_jsx("h4", { className: "document-signature-doc__title", children: d.title }), d.content] }, `${i}-${d.title}`))), read ? null : (_jsx(PrizmaScrollPillDock, { children: _jsx(PrizmaScrollPill, { label: review.scrollLabel, onClick: scrollOn }) }))] })] }));
|
|
272
|
+
});
|
|
273
|
+
DocumentSignatureReviewScreen.displayName = 'DocumentSignatureReviewScreen';
|
|
274
|
+
export default DocumentSignatureReviewScreen;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { ElectronicSignatureStrings } from './ElectronicSignatureStrings';
|
|
2
|
+
/**
|
|
3
|
+
* The poses the review screen draws, deterministic from props:
|
|
4
|
+
*
|
|
5
|
+
* - `start` reading document 1, Sign disabled.
|
|
6
|
+
* - `second` document 2 reached in the same scroll, Stepper on 2.
|
|
7
|
+
* - `end` every document read, Stepper `Completed`, Sign live.
|
|
8
|
+
* - `draw` the sheet over the read screen, empty pad, Confirm disabled.
|
|
9
|
+
* - `drawn` the sheet with a signature on the pad, Confirm live.
|
|
10
|
+
* - `type` the sheet in type mode; `typedName` fills the field.
|
|
11
|
+
*/
|
|
12
|
+
export type DocumentSignatureState = 'start' | 'second' | 'end' | 'draw' | 'drawn' | 'type';
|
|
13
|
+
export interface DocumentSignatureStrings {
|
|
14
|
+
/** "verified by" attribution copy for the footer tag. */
|
|
15
|
+
verifiedLabel: string;
|
|
16
|
+
/** Accessible name for the logo row. */
|
|
17
|
+
navLabel: string;
|
|
18
|
+
/** The review screen: every document in one scrolling viewer. */
|
|
19
|
+
review: {
|
|
20
|
+
/** H2 — "Review and sign". */
|
|
21
|
+
title: string;
|
|
22
|
+
/** Accessible name for the scrolling viewer — "Documents to sign". */
|
|
23
|
+
documentsLabel: string;
|
|
24
|
+
/**
|
|
25
|
+
* The Stepper's caption while reading, which also names its progressbar —
|
|
26
|
+
* "Document {{current}} of {{total}}". Both placeholders are replaced by
|
|
27
|
+
* the screen.
|
|
28
|
+
*/
|
|
29
|
+
documentCount: string;
|
|
30
|
+
/**
|
|
31
|
+
* The Stepper's caption and `aria-valuetext` once every document is read —
|
|
32
|
+
* "All documents read".
|
|
33
|
+
*/
|
|
34
|
+
completedLabel: string;
|
|
35
|
+
/**
|
|
36
|
+
* Core's Scroll pill over the viewer while there is reading left —
|
|
37
|
+
* "Scroll to sign". A tap scrolls about 80% of the viewer.
|
|
38
|
+
*/
|
|
39
|
+
scrollLabel: string;
|
|
40
|
+
/** Primary CTA — "Sign". Disabled until the end of the last document. */
|
|
41
|
+
ctaLabel: string;
|
|
42
|
+
};
|
|
43
|
+
/** The signing sheet (Core's Bottom sheet, dialog variant). */
|
|
44
|
+
sign: {
|
|
45
|
+
/** Sheet title, the same in both modes — "Add your signature". */
|
|
46
|
+
title: string;
|
|
47
|
+
/** Accessible name for the Draw / Type Segmented control — "Signature method". */
|
|
48
|
+
methodLabel: string;
|
|
49
|
+
/** Segmented control, the draw option — "Draw". */
|
|
50
|
+
drawLabel: string;
|
|
51
|
+
/** Segmented control, the type option — "Type". */
|
|
52
|
+
typeLabel: string;
|
|
53
|
+
/** Sheet subtitle, the consent — "By confirming, you accept and sign the documents electronically." */
|
|
54
|
+
consent: string;
|
|
55
|
+
/** Pad placeholder — "Sign here". */
|
|
56
|
+
placeholder: string;
|
|
57
|
+
/** Accessible name for the drawing canvas — "Signature capture area". */
|
|
58
|
+
canvasLabel: string;
|
|
59
|
+
/** Core's Clear-canvas link — "Clear canvas". */
|
|
60
|
+
clearLabel: string;
|
|
61
|
+
/** Type mode field label — "Full name". */
|
|
62
|
+
nameLabel: string;
|
|
63
|
+
/** Core's Signature preview label, under the field — "Preview". */
|
|
64
|
+
previewLabel: string;
|
|
65
|
+
/** Signature preview while the field is empty — "Your signature". */
|
|
66
|
+
previewPlaceholder: string;
|
|
67
|
+
/** The only button — "Confirm and continue". */
|
|
68
|
+
confirmLabel: string;
|
|
69
|
+
};
|
|
70
|
+
/** The signed verdict, drawn by the shipped `ElectronicSignatureSuccessScreen`. */
|
|
71
|
+
success: ElectronicSignatureStrings['success'];
|
|
72
|
+
/** The failure verdict, drawn by the shipped `ElectronicSignatureErrorScreen`. */
|
|
73
|
+
error: ElectronicSignatureStrings['error'];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The verdict screens are Electronic Signature's own, reused as shipped
|
|
77
|
+
* (`ElectronicSignatureSuccessScreen`, `ElectronicSignatureErrorScreen`). They
|
|
78
|
+
* take that module's strings object and read only its `success` / `error`
|
|
79
|
+
* slices plus the two chrome labels; this maps the rest from this module's copy
|
|
80
|
+
* so nothing is left blank and no second copy of a sentence is kept.
|
|
81
|
+
*/
|
|
82
|
+
export declare function documentSignatureResultStrings(strings: DocumentSignatureStrings): ElectronicSignatureStrings;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// from the `read-and-sign-in-one-screen` exploration
|
|
2
|
+
//
|
|
3
|
+
// Document Electronic Signature — the module's whole copy surface.
|
|
4
|
+
//
|
|
5
|
+
// Every string the review-and-sign screen renders lives here, so the screen
|
|
6
|
+
// carries no hardcoded English and a host translates the module by supplying
|
|
7
|
+
// one object (README rule 3, the same contract as `ElectronicSignatureStrings`).
|
|
8
|
+
//
|
|
9
|
+
// Source: the `read-and-sign-in-one-screen` exploration, Option B, decided with
|
|
10
|
+
// the owner (Elena, 2026-11-12). No Figma file yet and no SDK release, so no
|
|
11
|
+
// i18n namespace either: the demo passes the English.
|
|
12
|
+
/**
|
|
13
|
+
* The verdict screens are Electronic Signature's own, reused as shipped
|
|
14
|
+
* (`ElectronicSignatureSuccessScreen`, `ElectronicSignatureErrorScreen`). They
|
|
15
|
+
* take that module's strings object and read only its `success` / `error`
|
|
16
|
+
* slices plus the two chrome labels; this maps the rest from this module's copy
|
|
17
|
+
* so nothing is left blank and no second copy of a sentence is kept.
|
|
18
|
+
*/
|
|
19
|
+
export function documentSignatureResultStrings(strings) {
|
|
20
|
+
return {
|
|
21
|
+
verifiedLabel: strings.verifiedLabel,
|
|
22
|
+
navLabel: strings.navLabel,
|
|
23
|
+
review: {
|
|
24
|
+
title: strings.review.title,
|
|
25
|
+
documentLabel: strings.review.documentsLabel,
|
|
26
|
+
ctaLabel: strings.review.ctaLabel,
|
|
27
|
+
},
|
|
28
|
+
draw: {
|
|
29
|
+
title: strings.sign.title,
|
|
30
|
+
subtitle: strings.sign.consent,
|
|
31
|
+
placeholder: strings.sign.placeholder,
|
|
32
|
+
canvasLabel: strings.sign.canvasLabel,
|
|
33
|
+
clearLabel: strings.sign.clearLabel,
|
|
34
|
+
ctaLabel: strings.sign.confirmLabel,
|
|
35
|
+
},
|
|
36
|
+
success: strings.success,
|
|
37
|
+
error: strings.error,
|
|
38
|
+
};
|
|
39
|
+
}
|