@globalpayments-private/gpds-pattern-web 0.0.0-stage → 0.1.0-pr.6.g07fbefe
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/README.md +549 -2
- package/dist/cjs/control-strategy-DhhYTbse.js +113 -0
- package/dist/cjs/gpds-pattern-web.cjs.js +24 -0
- package/dist/cjs/index-Dzm6P89U.js +1565 -0
- package/dist/cjs/index.cjs.js +180 -0
- package/dist/cjs/loader.cjs.js +12 -0
- package/dist/cjs/uds-pattern-login-card_2.cjs.entry.js +1662 -0
- package/dist/collection/collection-manifest.json +14 -0
- package/dist/collection/components/uds-pattern-login-card/slimmers/identity-memory.slimmer.js +63 -0
- package/dist/collection/components/uds-pattern-login-card/slimmers/login-workflow.slimmer.js +357 -0
- package/dist/collection/components/uds-pattern-login-card/slimmers/renderers/login-card-renderer.js +100 -0
- package/dist/collection/components/uds-pattern-login-card/slimmers/renderers/login-field-renderer.js +129 -0
- package/dist/collection/components/uds-pattern-login-card/slimmers/renderers/login-step-renderer.js +192 -0
- package/dist/collection/components/uds-pattern-login-card/slimmers/resend-throttle.slimmer.js +65 -0
- package/dist/collection/components/uds-pattern-login-card/uds-pattern-login-card.css +154 -0
- package/dist/collection/components/uds-pattern-login-card/uds-pattern-login-card.js +508 -0
- package/dist/collection/components/uds-pattern-login-card/validation/login-validation-rules.js +86 -0
- package/dist/collection/components/uds-pattern-login-card/view-model/login-card-handlers.js +1 -0
- package/dist/collection/components/uds-pattern-login-card/view-model/login-step.view-model.js +138 -0
- package/dist/collection/components/uds-pattern-login-page/uds-pattern-login-page.css +37 -0
- package/dist/collection/components/uds-pattern-login-page/uds-pattern-login-page.js +97 -0
- package/dist/collection/index.js +5 -0
- package/dist/collection/providers/auth-provider.js +28 -0
- package/dist/collection/providers/control-strategy.js +21 -0
- package/dist/collection/providers/login-config.js +4 -0
- package/dist/collection/providers/memory-auth-provider.js +133 -0
- package/dist/collection/providers/parse-auth-result.js +135 -0
- package/dist/collection/slimmer/common/log.js +14 -0
- package/dist/collection/slimmer/common/symbols.js +10 -0
- package/dist/collection/slimmer/common/types.js +2 -0
- package/dist/collection/slimmer/decorators/inject-slimmer.js +73 -0
- package/dist/collection/slimmer/decorators/map-to-component-field.js +41 -0
- package/dist/collection/slimmer/decorators/map-to-component-method.js +33 -0
- package/dist/collection/slimmer/decorators/slimmer.js +10 -0
- package/dist/collection/slimmer/index.js +5 -0
- package/dist/collection/utils/labels.js +81 -0
- package/dist/collection/utils/types.js +1 -0
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +1 -0
- package/dist/components/p-DOrg55po.js +1 -0
- package/dist/components/p-_G8A9gg0.js +1 -0
- package/dist/components/uds-pattern-login-card.d.ts +11 -0
- package/dist/components/uds-pattern-login-card.js +1 -0
- package/dist/components/uds-pattern-login-page.d.ts +11 -0
- package/dist/components/uds-pattern-login-page.js +1 -0
- package/dist/docs.d.ts +480 -0
- package/dist/docs.json +549 -0
- package/dist/esm/control-strategy-DOrg55po.js +105 -0
- package/dist/esm/gpds-pattern-web.js +20 -0
- package/dist/esm/index-DsXlLyGj.js +1537 -0
- package/dist/esm/index.js +170 -0
- package/dist/esm/loader.js +10 -0
- package/dist/esm/uds-pattern-login-card_2.entry.js +1659 -0
- package/dist/gpds-pattern-web/gpds-pattern-web.css +1 -0
- package/dist/gpds-pattern-web/gpds-pattern-web.esm.js +1 -0
- package/dist/gpds-pattern-web/index.esm.js +1 -0
- package/dist/gpds-pattern-web/p-2c97d2da.entry.js +1 -0
- package/dist/gpds-pattern-web/p-DOrg55po.js +1 -0
- package/dist/gpds-pattern-web/p-DsXlLyGj.js +3 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/types/components/uds-pattern-login-card/slimmers/identity-memory.slimmer.d.ts +21 -0
- package/dist/types/components/uds-pattern-login-card/slimmers/login-workflow.slimmer.d.ts +100 -0
- package/dist/types/components/uds-pattern-login-card/slimmers/renderers/login-card-renderer.d.ts +44 -0
- package/dist/types/components/uds-pattern-login-card/slimmers/renderers/login-field-renderer.d.ts +91 -0
- package/dist/types/components/uds-pattern-login-card/slimmers/renderers/login-step-renderer.d.ts +40 -0
- package/dist/types/components/uds-pattern-login-card/slimmers/resend-throttle.slimmer.d.ts +21 -0
- package/dist/types/components/uds-pattern-login-card/uds-pattern-login-card.d.ts +134 -0
- package/dist/types/components/uds-pattern-login-card/validation/login-validation-rules.d.ts +72 -0
- package/dist/types/components/uds-pattern-login-card/view-model/login-card-handlers.d.ts +21 -0
- package/dist/types/components/uds-pattern-login-card/view-model/login-step.view-model.d.ts +96 -0
- package/dist/types/components/uds-pattern-login-page/uds-pattern-login-page.d.ts +21 -0
- package/dist/types/components.d.ts +327 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/providers/auth-provider.d.ts +168 -0
- package/dist/types/providers/control-strategy.d.ts +144 -0
- package/dist/types/providers/login-config.d.ts +52 -0
- package/dist/types/providers/memory-auth-provider.d.ts +37 -0
- package/dist/types/providers/parse-auth-result.d.ts +8 -0
- package/dist/types/slimmer/common/log.d.ts +8 -0
- package/dist/types/slimmer/common/symbols.d.ts +10 -0
- package/dist/types/slimmer/common/types.d.ts +30 -0
- package/dist/types/slimmer/decorators/inject-slimmer.d.ts +24 -0
- package/dist/types/slimmer/decorators/map-to-component-field.d.ts +16 -0
- package/dist/types/slimmer/decorators/map-to-component-method.d.ts +11 -0
- package/dist/types/slimmer/decorators/slimmer.d.ts +10 -0
- package/dist/types/slimmer/index.d.ts +6 -0
- package/dist/types/stencil-public-runtime.d.ts +1879 -0
- package/dist/types/utils/labels.d.ts +13 -0
- package/dist/types/utils/types.d.ts +106 -0
- package/dist/types/vega.d.ts +11 -0
- package/loader/cdn.js +1 -0
- package/loader/index.cjs.js +1 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +1 -0
- package/loader/index.js +2 -0
- package/package.json +79 -4
package/dist/collection/components/uds-pattern-login-card/slimmers/renderers/login-step-renderer.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
4
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else
|
|
6
|
+
for (var i = decorators.length - 1; i >= 0; i--)
|
|
7
|
+
if (d = decorators[i])
|
|
8
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
9
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
10
|
+
};
|
|
11
|
+
import { h } from "@stencil/core";
|
|
12
|
+
import { UdsSlimmer, InjectSlimmer, MapToComponentField } from "../../../../slimmer";
|
|
13
|
+
import { LoginFieldRenderer } from "./login-field-renderer";
|
|
14
|
+
/**
|
|
15
|
+
* Renders the body of whichever step the workflow is on.
|
|
16
|
+
*
|
|
17
|
+
* ## Why a renderer slimmer
|
|
18
|
+
*
|
|
19
|
+
* This is the same Slimmer mechanism the stateful layer uses, pointed at
|
|
20
|
+
* rendering: one class, one responsibility, bound to the component by field
|
|
21
|
+
* mapping rather than by parameter passing. Vega applies the convention the
|
|
22
|
+
* same way — `slimmers/renderers/<name>-renderer.tsx`, a class ending in
|
|
23
|
+
* `Renderer`, exposing `render()` — so a reader moving between the design
|
|
24
|
+
* system and the pattern library meets one structure, not two.
|
|
25
|
+
*
|
|
26
|
+
* The gain over the plain `view/` modules this replaces is the binding. A free
|
|
27
|
+
* function has to be handed everything it needs on each call, so its signature
|
|
28
|
+
* grows with its appetite and callers thread arguments through layers that do
|
|
29
|
+
* not use them. `@MapToComponentField()` reaches the component's `viewModel`
|
|
30
|
+
* and `handlers` directly, and types them by indexing the component class, so
|
|
31
|
+
* the renderer cannot drift out of step with what the component actually
|
|
32
|
+
* exposes — rename the getter and this stops compiling.
|
|
33
|
+
*
|
|
34
|
+
* Renderers only read. Every mutation goes back through `handlers`, into the
|
|
35
|
+
* workflow slimmer, and through the control strategy's checkpoints.
|
|
36
|
+
*/
|
|
37
|
+
export class LoginStepRenderer extends UdsSlimmer {
|
|
38
|
+
constructor() {
|
|
39
|
+
super();
|
|
40
|
+
this.fields = new LoginFieldRenderer();
|
|
41
|
+
}
|
|
42
|
+
render() {
|
|
43
|
+
const vm = this.viewModel;
|
|
44
|
+
switch (vm.step) {
|
|
45
|
+
case 'identifier':
|
|
46
|
+
return this.identifierStep(vm);
|
|
47
|
+
case 'password':
|
|
48
|
+
return this.passwordStep(vm);
|
|
49
|
+
case 'mfa-method':
|
|
50
|
+
return this.mfaMethodStep(vm);
|
|
51
|
+
case 'otp':
|
|
52
|
+
return this.otpStep(vm);
|
|
53
|
+
case 'forgot-password':
|
|
54
|
+
case 'forgot-username':
|
|
55
|
+
return this.forgotStep(vm);
|
|
56
|
+
case 'reset-password':
|
|
57
|
+
return this.resetPasswordStep(vm);
|
|
58
|
+
case 'sign-up':
|
|
59
|
+
return this.signUpStep(vm);
|
|
60
|
+
default:
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
identifierStep(vm) {
|
|
65
|
+
const { copy } = vm;
|
|
66
|
+
return [
|
|
67
|
+
this.fields.textField({
|
|
68
|
+
name: 'identifier',
|
|
69
|
+
label: copy.identifierFieldLabel,
|
|
70
|
+
type: 'email',
|
|
71
|
+
autocomplete: 'username',
|
|
72
|
+
}),
|
|
73
|
+
this.fields.checkbox('rememberIdentifier', copy.rememberIdentifier),
|
|
74
|
+
this.fields.submit(copy.continue),
|
|
75
|
+
h("div", { class: "prose" }, h("p", { class: "prose__lead" }, copy.troubleSigningInPrompt), h("p", null, "Follow the steps in \u201C", this.fields.link(copy.troubleSigningIn, this.handlers.onAction('trouble-signing-in')), "\u201D."), vm.can.signUp && (h("p", null, copy.noAccountPrompt, " ", this.fields.link(copy.createAccount, this.handlers.onNavigate('sign-up'))))),
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
passwordStep(vm) {
|
|
79
|
+
const { copy, can } = vm;
|
|
80
|
+
const recovery = [];
|
|
81
|
+
if (can.reset) {
|
|
82
|
+
recovery.push(this.fields.link(copy.forgotPassword, this.handlers.onNavigate('forgot-password')));
|
|
83
|
+
}
|
|
84
|
+
if (can.username) {
|
|
85
|
+
recovery.push(this.fields.link(copy.forgotUsername, this.handlers.onNavigate('forgot-username')));
|
|
86
|
+
}
|
|
87
|
+
return [
|
|
88
|
+
// `vega-input` carries its own password reveal control, so the card no
|
|
89
|
+
// longer renders — or tracks the state for — an eye toggle of its own.
|
|
90
|
+
this.fields.textField({
|
|
91
|
+
name: 'password',
|
|
92
|
+
label: copy.passwordFieldLabel,
|
|
93
|
+
type: 'password',
|
|
94
|
+
autocomplete: 'current-password',
|
|
95
|
+
}),
|
|
96
|
+
...(recovery.length ? [h("div", { class: "inline-links" }, recovery)] : []),
|
|
97
|
+
this.fields.submit(copy.continue),
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
mfaMethodStep(vm) {
|
|
101
|
+
const { copy } = vm;
|
|
102
|
+
return [
|
|
103
|
+
this.fields.methodGroup(vm.methods, copy.mfaMethodHeading),
|
|
104
|
+
this.fields.submit(copy.continue),
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
otpStep(vm) {
|
|
108
|
+
const { copy } = vm;
|
|
109
|
+
const tail = [];
|
|
110
|
+
if (vm.methods.length > 1) {
|
|
111
|
+
tail.push(this.fields.link(copy.changeMfaMethod, this.handlers.onNavigate('mfa-method')));
|
|
112
|
+
}
|
|
113
|
+
if (vm.can.resend) {
|
|
114
|
+
tail.push(vm.isResendThrottled ? (
|
|
115
|
+
// Rendered as text rather than a disabled link: a countdown is a
|
|
116
|
+
// status, and announcing it politely is more useful than offering a
|
|
117
|
+
// dead target.
|
|
118
|
+
h("span", { class: "countdown", "aria-live": "polite" }, vm.resendCountdownText)) : (this.fields.link(copy.resendCode, this.handlers.onResend)));
|
|
119
|
+
}
|
|
120
|
+
return [
|
|
121
|
+
// `vega-input-passcode` owns the whole multi-box entry: per-character
|
|
122
|
+
// focus advance, backspace retreat, paste distribution and masking. That
|
|
123
|
+
// replaces the card's own OTP slimmer outright.
|
|
124
|
+
this.fields.passcodeField(),
|
|
125
|
+
this.fields.submit(copy.otpSubmit),
|
|
126
|
+
...(tail.length
|
|
127
|
+
? [
|
|
128
|
+
h("div", { class: "prose" }, h("p", null, copy.changeMfaMethodPrompt), h("p", { class: "inline-links" }, tail)),
|
|
129
|
+
]
|
|
130
|
+
: []),
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
forgotStep(vm) {
|
|
134
|
+
const { copy } = vm;
|
|
135
|
+
return [
|
|
136
|
+
this.fields.textField({
|
|
137
|
+
name: vm.step === 'forgot-password' ? 'identifier' : 'email',
|
|
138
|
+
label: copy.identifierFieldLabel,
|
|
139
|
+
type: 'email',
|
|
140
|
+
autocomplete: 'username',
|
|
141
|
+
}),
|
|
142
|
+
this.fields.submit(copy.continue),
|
|
143
|
+
h("p", { class: "prose" }, this.fields.link(copy.back, this.handlers.onNavigate('identifier'))),
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
resetPasswordStep(vm) {
|
|
147
|
+
const { copy } = vm;
|
|
148
|
+
return [
|
|
149
|
+
this.fields.textField({
|
|
150
|
+
name: 'password',
|
|
151
|
+
label: copy.newPasswordFieldLabel,
|
|
152
|
+
type: 'password',
|
|
153
|
+
autocomplete: 'new-password',
|
|
154
|
+
}),
|
|
155
|
+
// The pairing is checked on the field that is wrong, inside the same
|
|
156
|
+
// `vega-form` gate as every other rule — not as a pre-submit test
|
|
157
|
+
// reported through the card-level banner.
|
|
158
|
+
this.fields.textField({
|
|
159
|
+
name: 'confirmPassword',
|
|
160
|
+
label: copy.confirmPasswordFieldLabel,
|
|
161
|
+
type: 'password',
|
|
162
|
+
autocomplete: 'new-password',
|
|
163
|
+
mustMatch: 'password',
|
|
164
|
+
}),
|
|
165
|
+
this.fields.submit(copy.continue),
|
|
166
|
+
];
|
|
167
|
+
}
|
|
168
|
+
signUpStep(vm) {
|
|
169
|
+
const { copy } = vm;
|
|
170
|
+
return [
|
|
171
|
+
this.fields.textField({ name: 'firstName', label: copy.firstNameFieldLabel, autocomplete: 'given-name' }),
|
|
172
|
+
this.fields.textField({ name: 'lastName', label: copy.lastNameFieldLabel, autocomplete: 'family-name' }),
|
|
173
|
+
this.fields.textField({
|
|
174
|
+
name: 'identifier',
|
|
175
|
+
label: copy.identifierFieldLabel,
|
|
176
|
+
type: 'email',
|
|
177
|
+
autocomplete: 'email',
|
|
178
|
+
}),
|
|
179
|
+
this.fields.submit(copy.signUpSubmit),
|
|
180
|
+
h("p", { class: "prose" }, copy.haveAccountPrompt, " ", this.fields.link(copy.signIn, this.handlers.onNavigate('identifier'))),
|
|
181
|
+
];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
__decorate([
|
|
185
|
+
InjectSlimmer()
|
|
186
|
+
], LoginStepRenderer.prototype, "fields", void 0);
|
|
187
|
+
__decorate([
|
|
188
|
+
MapToComponentField()
|
|
189
|
+
], LoginStepRenderer.prototype, "viewModel", void 0);
|
|
190
|
+
__decorate([
|
|
191
|
+
MapToComponentField()
|
|
192
|
+
], LoginStepRenderer.prototype, "handlers", void 0);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
4
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else
|
|
6
|
+
for (var i = decorators.length - 1; i >= 0; i--)
|
|
7
|
+
if (d = decorators[i])
|
|
8
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
9
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
10
|
+
};
|
|
11
|
+
import { UdsSlimmer, MapToComponentField, MapToComponentMethod } from "../../../slimmer";
|
|
12
|
+
/**
|
|
13
|
+
* The resend throttle and its countdown.
|
|
14
|
+
*
|
|
15
|
+
* Small, but exactly the kind of thing that disappears into a large component
|
|
16
|
+
* and then gets subtly broken: an interval that must be cleared on disconnect,
|
|
17
|
+
* and a tick that must drive a re-render.
|
|
18
|
+
*/
|
|
19
|
+
export class ResendThrottleSlimmer extends UdsSlimmer {
|
|
20
|
+
constructor() {
|
|
21
|
+
super();
|
|
22
|
+
}
|
|
23
|
+
/** Begins a throttle window. A missing or non-positive duration clears it. */
|
|
24
|
+
start(resendAfterMs) {
|
|
25
|
+
this.stop();
|
|
26
|
+
if (!resendAfterMs || resendAfterMs <= 0) {
|
|
27
|
+
this.resendAt = undefined;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
this.resendAt = Date.now() + resendAfterMs;
|
|
31
|
+
this.nowTick = Date.now();
|
|
32
|
+
this.timer = setInterval(() => {
|
|
33
|
+
this.nowTick = Date.now();
|
|
34
|
+
if (this.resendAt !== undefined && this.nowTick >= this.resendAt) {
|
|
35
|
+
this.stop();
|
|
36
|
+
this.resendAt = undefined;
|
|
37
|
+
}
|
|
38
|
+
}, 1000);
|
|
39
|
+
}
|
|
40
|
+
stop() {
|
|
41
|
+
if (this.timer) {
|
|
42
|
+
clearInterval(this.timer);
|
|
43
|
+
this.timer = undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Seconds left on the throttle; zero when resending is allowed. */
|
|
47
|
+
get secondsRemaining() {
|
|
48
|
+
if (this.resendAt === undefined) {
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
return Math.max(0, Math.ceil((this.resendAt - this.nowTick) / 1000));
|
|
52
|
+
}
|
|
53
|
+
get canResend() {
|
|
54
|
+
return this.secondsRemaining === 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
__decorate([
|
|
58
|
+
MapToComponentField({ writable: true })
|
|
59
|
+
], ResendThrottleSlimmer.prototype, "resendAt", void 0);
|
|
60
|
+
__decorate([
|
|
61
|
+
MapToComponentField({ writable: true })
|
|
62
|
+
], ResendThrottleSlimmer.prototype, "nowTick", void 0);
|
|
63
|
+
__decorate([
|
|
64
|
+
MapToComponentMethod('disconnectedCallback')
|
|
65
|
+
], ResendThrottleSlimmer.prototype, "stop", null);
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pattern's own styling, which is now only *layout*.
|
|
3
|
+
*
|
|
4
|
+
* Every control inside the card is a Vega element, and Vega styles its own
|
|
5
|
+
* internals from the design system's tokens. What is left for the pattern is
|
|
6
|
+
* the arrangement: the card surface, the rhythm between fields, and the
|
|
7
|
+
* supporting prose. There is deliberately no rule here for an input, a button,
|
|
8
|
+
* a checkbox or an alert — re-styling those would fork guarantees the design
|
|
9
|
+
* system is accountable for.
|
|
10
|
+
*
|
|
11
|
+
* Shadow DOM also means these rules cannot reach inside a `vega-*` element even
|
|
12
|
+
* if someone tried; Vega's own custom properties are the supported route.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
:host {
|
|
16
|
+
display: block;
|
|
17
|
+
width: 100%;
|
|
18
|
+
max-width: var(--uds-pattern-login-card-max-width);
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
|
|
21
|
+
/** Maximum width of the card. */
|
|
22
|
+
--uds-pattern-login-card-max-width: 35rem;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:host *,
|
|
26
|
+
:host *::before,
|
|
27
|
+
:host *::after {
|
|
28
|
+
box-sizing: inherit;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* --- Card surface ------------------------------------------------------- */
|
|
32
|
+
|
|
33
|
+
.card {
|
|
34
|
+
padding: var(--uds-pattern-space-2xl);
|
|
35
|
+
background: var(--uds-pattern-color-surface);
|
|
36
|
+
border-radius: var(--uds-pattern-radius-lg);
|
|
37
|
+
box-shadow: var(--uds-pattern-shadow-card);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.card__heading {
|
|
41
|
+
margin: 0 0 var(--uds-pattern-space-sm);
|
|
42
|
+
font-size: var(--uds-pattern-font-size-lg);
|
|
43
|
+
font-weight: var(--uds-pattern-font-weight-bold);
|
|
44
|
+
line-height: var(--uds-pattern-line-height-md);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* The heading takes focus on a step change so the change is announced; it is
|
|
48
|
+
not interactive, so it should not look it.
|
|
49
|
+
|
|
50
|
+
There is deliberately no :focus-visible ring here. The heading is
|
|
51
|
+
tabindex="-1", so a keyboard user can never reach it themselves — the only
|
|
52
|
+
thing that ever focuses it is our own step-change call. Chromium matches
|
|
53
|
+
:focus-visible on a programmatic focus regardless of whether the last
|
|
54
|
+
interaction was a pointer, so a ring would draw a box around the heading on
|
|
55
|
+
every step change for every user, mouse included. Announcement is the whole
|
|
56
|
+
job here; the visual belongs to whichever control we focus next. */
|
|
57
|
+
.card__heading:focus,
|
|
58
|
+
.card__heading:focus-visible {
|
|
59
|
+
outline: none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.card__description {
|
|
63
|
+
margin: 0 0 var(--uds-pattern-space-lg);
|
|
64
|
+
font-size: var(--uds-pattern-font-size-sm);
|
|
65
|
+
color: var(--uds-pattern-color-text-subtle);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.card__footer {
|
|
69
|
+
margin-top: var(--uds-pattern-space-xl);
|
|
70
|
+
padding-top: var(--uds-pattern-space-xl);
|
|
71
|
+
border-top: 1px solid var(--uds-pattern-color-border);
|
|
72
|
+
font-size: var(--uds-pattern-font-size-sm);
|
|
73
|
+
color: var(--uds-pattern-color-text-subtle);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.card__footer p {
|
|
77
|
+
margin: 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* --- Rhythm ------------------------------------------------------------- */
|
|
81
|
+
|
|
82
|
+
/* `vega-form` renders `<form><slot/></form>` into its own shadow root, so the
|
|
83
|
+
controls written inside it are slotted and are laid out by that internal
|
|
84
|
+
`<form>` — not by this host. A `display: flex` here would wrap exactly one
|
|
85
|
+
flex item (the internal form), so `gap` would space nothing at all. The
|
|
86
|
+
arrangement therefore belongs to `.form__body`, which the pattern owns.
|
|
87
|
+
|
|
88
|
+
Only the form's own offset from the content above it is set here. */
|
|
89
|
+
.form {
|
|
90
|
+
margin-top: var(--uds-pattern-space-lg);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* The real layout container: a plain element in this shadow root whose real
|
|
94
|
+
children are the step's controls, so flex applies as written. Making them
|
|
95
|
+
flex items also blockifies them, which removes the inline-block line-box
|
|
96
|
+
whitespace the controls would otherwise be subject to.
|
|
97
|
+
|
|
98
|
+
The gap is measured from the approved sign-in design rather than picked: the
|
|
99
|
+
reference puts 31–32px between the input, the checkbox and the button, which
|
|
100
|
+
is `space-xl`. */
|
|
101
|
+
.form__body {
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
gap: var(--uds-pattern-space-xl);
|
|
105
|
+
align-items: stretch;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.alert {
|
|
109
|
+
display: block;
|
|
110
|
+
margin-bottom: var(--uds-pattern-space-md);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.options {
|
|
114
|
+
display: block;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* --- Supporting prose --------------------------------------------------- */
|
|
118
|
+
|
|
119
|
+
.prose {
|
|
120
|
+
margin: 0;
|
|
121
|
+
font-size: var(--uds-pattern-font-size-sm);
|
|
122
|
+
color: var(--uds-pattern-color-text-subtle);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.prose p {
|
|
126
|
+
margin: 0 0 var(--uds-pattern-space-xs);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.prose p:last-child {
|
|
130
|
+
margin-bottom: 0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.prose__lead {
|
|
134
|
+
font-weight: var(--uds-pattern-font-weight-bold);
|
|
135
|
+
color: var(--uds-pattern-color-text);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* Links sit inline within a sentence, so they must not become block boxes. */
|
|
139
|
+
.link {
|
|
140
|
+
display: inline-block;
|
|
141
|
+
vertical-align: baseline;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.inline-links {
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-wrap: wrap;
|
|
147
|
+
gap: var(--uds-pattern-space-md);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* A resend countdown is a status, not a control — it is rendered as text and
|
|
151
|
+
styled to read as the disabled sibling of the link it replaces. */
|
|
152
|
+
.countdown {
|
|
153
|
+
color: var(--uds-pattern-color-text-subtle);
|
|
154
|
+
}
|