@firebase-oss/ui-angular 0.0.1 → 0.0.2-exp.6bf0c31
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 +13 -1
- package/dist/README.md +13 -1
- package/dist/fesm2022/firebase-oss-ui-angular.mjs +1983 -591
- package/dist/fesm2022/firebase-oss-ui-angular.mjs.map +1 -1
- package/dist/index.d.ts +473 -100
- package/package.json +6 -4
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, HostBinding, Component, computed, InjectionToken, inject, makeEnvironmentProviders, signal, effect,
|
|
3
|
-
import { getBehavior, getTranslation, createSignInAuthFormSchema, createSignUpAuthFormSchema, createForgotPasswordAuthFormSchema, createEmailLinkAuthFormSchema, createPhoneAuthNumberFormSchema, createPhoneAuthVerifyFormSchema, createMultiFactorPhoneAuthNumberFormSchema, createMultiFactorPhoneAuthVerifyFormSchema, createMultiFactorTotpAuthNumberFormSchema, createMultiFactorTotpAuthVerifyFormSchema, sendSignInLinkToEmail, FirebaseUIError, completeEmailLinkSignIn, sendPasswordResetEmail, verifyPhoneNumber, signInWithMultiFactorAssertion,
|
|
4
|
-
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { input, HostBinding, Component, computed, InjectionToken, Optional, inject, makeEnvironmentProviders, signal, effect, PLATFORM_ID, EventEmitter, Output, viewChild, model, output, isDevMode } from '@angular/core';
|
|
3
|
+
import { getBehavior, getTranslation, createSignInAuthFormSchema, createSignUpAuthFormSchema, createForgotPasswordAuthFormSchema, createEmailLinkAuthFormSchema, createPhoneAuthNumberFormSchema, createPhoneAuthVerifyFormSchema, createMultiFactorPhoneAuthNumberFormSchema, createMultiFactorPhoneAuthAssertionFormSchema, createMultiFactorPhoneAuthVerifyFormSchema, createMultiFactorTotpAuthNumberFormSchema, createMultiFactorTotpAuthVerifyFormSchema, sendSignInLinkToEmail, FirebaseUIError, completeEmailLinkSignIn, sendPasswordResetEmail, verifyPhoneNumber, signInWithMultiFactorAssertion, formatPhoneNumber, enrollWithMultiFactorAssertion, generateTotpSecret, generateTotpQrCode, countryData, confirmPhoneNumber, signInWithEmailAndPassword, hasBehavior, createUserWithEmailAndPassword, signInWithProvider, registerFramework } from '@firebase-oss/ui-core';
|
|
4
|
+
import { isPlatformBrowser, CommonModule } from '@angular/common';
|
|
5
5
|
import { injectField, injectForm, injectStore, TanStackField, TanStackAppField } from '@tanstack/angular-form';
|
|
6
6
|
import { buttonVariant } from '@firebase-oss/ui-styles';
|
|
7
7
|
import { FirebaseApps } from '@angular/fire/app';
|
|
8
|
-
import {
|
|
8
|
+
import { Auth, authState, GoogleAuthProvider, FacebookAuthProvider, OAuthProvider, TwitterAuthProvider, GithubAuthProvider } from '@angular/fire/auth';
|
|
9
|
+
import { PhoneAuthProvider, PhoneMultiFactorGenerator, TotpMultiFactorGenerator, multiFactor, FactorId } from 'firebase/auth';
|
|
9
10
|
import * as i1 from '@angular/forms';
|
|
10
11
|
import { FormsModule } from '@angular/forms';
|
|
11
|
-
import { GoogleAuthProvider, FacebookAuthProvider, OAuthProvider, TwitterAuthProvider, GithubAuthProvider } from '@angular/fire/auth';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Copyright 2025 Google LLC
|
|
@@ -25,7 +25,11 @@ import { GoogleAuthProvider, FacebookAuthProvider, OAuthProvider, TwitterAuthPro
|
|
|
25
25
|
* See the License for the specific language governing permissions and
|
|
26
26
|
* limitations under the License.
|
|
27
27
|
*/
|
|
28
|
+
/**
|
|
29
|
+
* A customizable button component with multiple variants.
|
|
30
|
+
*/
|
|
28
31
|
class ButtonComponent {
|
|
32
|
+
/** The visual variant of the button. */
|
|
29
33
|
variant = input(...(ngDevMode ? [undefined, { debugName: "variant" }] : []));
|
|
30
34
|
get getButtonClasses() {
|
|
31
35
|
return buttonVariant({ variant: this.variant() });
|
|
@@ -45,16 +49,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
45
49
|
args: ["class"]
|
|
46
50
|
}] } });
|
|
47
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Copyright 2025 Google LLC
|
|
54
|
+
*
|
|
55
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
56
|
+
* you may not use this file except in compliance with the License.
|
|
57
|
+
* You may obtain a copy of the License at
|
|
58
|
+
*
|
|
59
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
60
|
+
*
|
|
61
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
62
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
63
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
64
|
+
* See the License for the specific language governing permissions and
|
|
65
|
+
* limitations under the License.
|
|
66
|
+
*/
|
|
67
|
+
/**
|
|
68
|
+
* A component that displays form field metadata, such as validation errors.
|
|
69
|
+
*/
|
|
48
70
|
class FormMetadataComponent {
|
|
71
|
+
/** The form field API instance. */
|
|
49
72
|
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
50
73
|
errors = computed(() => this.field()
|
|
51
74
|
.state.meta.errors.map((error) => error.message)
|
|
52
75
|
.join(", "), ...(ngDevMode ? [{ debugName: "errors" }] : []));
|
|
53
76
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: FormMetadataComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
54
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: FormMetadataComponent, isStandalone: true, selector: "fui-form-metadata", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
77
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: FormMetadataComponent, isStandalone: true, selector: "fui-form-metadata", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null } }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
55
78
|
@if (field().state.meta.isTouched && errors().length > 0) {
|
|
56
79
|
<div>
|
|
57
|
-
<div role="alert" aria-live="polite" class="fui-
|
|
80
|
+
<div role="alert" aria-live="polite" class="fui-error">
|
|
58
81
|
{{ errors() }}
|
|
59
82
|
</div>
|
|
60
83
|
</div>
|
|
@@ -66,10 +89,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
66
89
|
args: [{
|
|
67
90
|
selector: "fui-form-metadata",
|
|
68
91
|
standalone: true,
|
|
92
|
+
host: {
|
|
93
|
+
style: "display: block;",
|
|
94
|
+
},
|
|
69
95
|
template: `
|
|
70
96
|
@if (field().state.meta.isTouched && errors().length > 0) {
|
|
71
97
|
<div>
|
|
72
|
-
<div role="alert" aria-live="polite" class="fui-
|
|
98
|
+
<div role="alert" aria-live="polite" class="fui-error">
|
|
73
99
|
{{ errors() }}
|
|
74
100
|
</div>
|
|
75
101
|
</div>
|
|
@@ -77,17 +103,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
77
103
|
`,
|
|
78
104
|
}]
|
|
79
105
|
}], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
|
|
106
|
+
/**
|
|
107
|
+
* A form input component with label, description, and validation support.
|
|
108
|
+
*/
|
|
80
109
|
class FormInputComponent {
|
|
81
110
|
field = injectField();
|
|
111
|
+
/** The label text for the input field. */
|
|
82
112
|
label = input.required(...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
113
|
+
/** The input type (e.g., "text", "email", "password"). */
|
|
83
114
|
type = input("text", ...(ngDevMode ? [{ debugName: "type" }] : []));
|
|
115
|
+
/** Optional description text displayed below the label. */
|
|
116
|
+
description = input(...(ngDevMode ? [undefined, { debugName: "description" }] : []));
|
|
84
117
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: FormInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
85
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
118
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: FormInputComponent, isStandalone: true, selector: "fui-form-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
86
119
|
<label [for]="field.api.name">
|
|
87
120
|
<div data-input-label>
|
|
88
121
|
<div>{{ label() }}</div>
|
|
89
122
|
<div><ng-content select="input-action" /></div>
|
|
90
123
|
</div>
|
|
124
|
+
@if (description()) {
|
|
125
|
+
<div data-input-description>{{ description() }}</div>
|
|
126
|
+
}
|
|
91
127
|
<div data-input-group>
|
|
92
128
|
<ng-content select="input-before" />
|
|
93
129
|
<input
|
|
@@ -111,12 +147,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
111
147
|
selector: "fui-form-input",
|
|
112
148
|
standalone: true,
|
|
113
149
|
imports: [FormMetadataComponent],
|
|
150
|
+
host: {
|
|
151
|
+
style: "display: block;",
|
|
152
|
+
},
|
|
114
153
|
template: `
|
|
115
154
|
<label [for]="field.api.name">
|
|
116
155
|
<div data-input-label>
|
|
117
156
|
<div>{{ label() }}</div>
|
|
118
157
|
<div><ng-content select="input-action" /></div>
|
|
119
158
|
</div>
|
|
159
|
+
@if (description()) {
|
|
160
|
+
<div data-input-description>{{ description() }}</div>
|
|
161
|
+
}
|
|
120
162
|
<div data-input-group>
|
|
121
163
|
<ng-content select="input-before" />
|
|
122
164
|
<input
|
|
@@ -134,7 +176,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
134
176
|
</label>
|
|
135
177
|
`,
|
|
136
178
|
}]
|
|
137
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }] } });
|
|
179
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
|
|
180
|
+
/**
|
|
181
|
+
* A button component for form actions (e.g., "Forgot Password?" link).
|
|
182
|
+
*/
|
|
138
183
|
class FormActionComponent {
|
|
139
184
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: FormActionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
140
185
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: FormActionComponent, isStandalone: true, selector: "button[fui-form-action]", host: { attributes: { "type": "button" }, classAttribute: "fui-form__action" }, ngImport: i0, template: `<ng-content></ng-content> `, isInline: true });
|
|
@@ -151,12 +196,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
151
196
|
template: `<ng-content></ng-content> `,
|
|
152
197
|
}]
|
|
153
198
|
}] });
|
|
199
|
+
/**
|
|
200
|
+
* A submit button component for forms.
|
|
201
|
+
*
|
|
202
|
+
* Automatically disables when the form is submitting.
|
|
203
|
+
*/
|
|
154
204
|
class FormSubmitComponent {
|
|
205
|
+
/** Optional additional CSS classes. */
|
|
155
206
|
class = input(...(ngDevMode ? [undefined, { debugName: "class" }] : []));
|
|
207
|
+
/** The form state for tracking submission status. */
|
|
156
208
|
state = input.required(...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
157
209
|
isSubmitting = computed(() => this.state().isSubmitting, ...(ngDevMode ? [{ debugName: "isSubmitting" }] : []));
|
|
158
210
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: FormSubmitComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
159
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: FormSubmitComponent, isStandalone: true, selector: "fui-form-submit", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "type": "submit" } }, ngImport: i0, template: `
|
|
211
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: FormSubmitComponent, isStandalone: true, selector: "fui-form-submit", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "type": "submit" }, styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
160
212
|
<button fui-button class="fui-form__action" [class]="class()" [disabled]="isSubmitting()">
|
|
161
213
|
<ng-content></ng-content>
|
|
162
214
|
</button>
|
|
@@ -170,6 +222,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
170
222
|
imports: [ButtonComponent],
|
|
171
223
|
host: {
|
|
172
224
|
type: "submit",
|
|
225
|
+
style: "display: block;",
|
|
173
226
|
},
|
|
174
227
|
template: `
|
|
175
228
|
<button fui-button class="fui-form__action" [class]="class()" [disabled]="isSubmitting()">
|
|
@@ -178,7 +231,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
178
231
|
`,
|
|
179
232
|
}]
|
|
180
233
|
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: true }] }] } });
|
|
234
|
+
/**
|
|
235
|
+
* A component that displays form-level error messages.
|
|
236
|
+
*
|
|
237
|
+
* Shows errors from form submission, not validation errors.
|
|
238
|
+
*/
|
|
181
239
|
class FormErrorMessageComponent {
|
|
240
|
+
/** The form state containing error information. */
|
|
182
241
|
state = input.required(...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
183
242
|
errorMessage = computed(() => {
|
|
184
243
|
const error = this.state().errorMap?.onSubmit;
|
|
@@ -189,9 +248,9 @@ class FormErrorMessageComponent {
|
|
|
189
248
|
return undefined;
|
|
190
249
|
}, ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
|
|
191
250
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: FormErrorMessageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
192
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: FormErrorMessageComponent, isStandalone: true, selector: "fui-form-error-message", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
251
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: FormErrorMessageComponent, isStandalone: true, selector: "fui-form-error-message", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: true, transformFunction: null } }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
193
252
|
@if (errorMessage()) {
|
|
194
|
-
<div class="fui-
|
|
253
|
+
<div class="fui-error">
|
|
195
254
|
{{ errorMessage() }}
|
|
196
255
|
</div>
|
|
197
256
|
}
|
|
@@ -202,9 +261,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
202
261
|
args: [{
|
|
203
262
|
selector: "fui-form-error-message",
|
|
204
263
|
standalone: true,
|
|
264
|
+
host: {
|
|
265
|
+
style: "display: block;",
|
|
266
|
+
},
|
|
205
267
|
template: `
|
|
206
268
|
@if (errorMessage()) {
|
|
207
|
-
<div class="fui-
|
|
269
|
+
<div class="fui-error">
|
|
208
270
|
{{ errorMessage() }}
|
|
209
271
|
</div>
|
|
210
272
|
}
|
|
@@ -229,12 +291,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
229
291
|
*/
|
|
230
292
|
const FIREBASE_UI_STORE = new InjectionToken("firebaseui.store");
|
|
231
293
|
const FIREBASE_UI_POLICIES = new InjectionToken("firebaseui.policies");
|
|
294
|
+
/**
|
|
295
|
+
* Provides FirebaseUI configuration for the Angular application.
|
|
296
|
+
*
|
|
297
|
+
* This function must be called in your application's providers array to enable FirebaseUI functionality.
|
|
298
|
+
*
|
|
299
|
+
* @param uiFactory - Factory function that creates a FirebaseUIStore from Firebase apps.
|
|
300
|
+
* @returns Environment providers for FirebaseUI.
|
|
301
|
+
*/
|
|
232
302
|
function provideFirebaseUI(uiFactory) {
|
|
233
303
|
const providers = [
|
|
234
304
|
// TODO: This should depend on the FirebaseAuth provider via deps,
|
|
235
305
|
// see https://github.com/angular/angularfire/blob/35e0a9859299010488852b1826e4083abe56528f/src/firestore/firestore.module.ts#L76
|
|
236
306
|
{
|
|
237
307
|
provide: FIREBASE_UI_STORE,
|
|
308
|
+
deps: [FirebaseApps, [new Optional(), Auth]],
|
|
238
309
|
useFactory: () => {
|
|
239
310
|
const apps = inject(FirebaseApps);
|
|
240
311
|
if (!apps || apps.length === 0) {
|
|
@@ -246,10 +317,23 @@ function provideFirebaseUI(uiFactory) {
|
|
|
246
317
|
];
|
|
247
318
|
return makeEnvironmentProviders(providers);
|
|
248
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* Provides policy configuration (terms of service and privacy policy URLs) for FirebaseUI components.
|
|
322
|
+
*
|
|
323
|
+
* @param factory - Factory function that returns the policy configuration.
|
|
324
|
+
* @returns Environment providers for FirebaseUI policies.
|
|
325
|
+
*/
|
|
249
326
|
function provideFirebaseUIPolicies(factory) {
|
|
250
327
|
const providers = [{ provide: FIREBASE_UI_POLICIES, useFactory: factory }];
|
|
251
328
|
return makeEnvironmentProviders(providers);
|
|
252
329
|
}
|
|
330
|
+
/**
|
|
331
|
+
* Injects the FirebaseUI store as a reactive signal.
|
|
332
|
+
*
|
|
333
|
+
* Returns a readonly signal that updates when the UI state changes.
|
|
334
|
+
*
|
|
335
|
+
* @returns A readonly signal containing the current FirebaseUI state.
|
|
336
|
+
*/
|
|
253
337
|
function injectUI() {
|
|
254
338
|
const store = inject(FIREBASE_UI_STORE);
|
|
255
339
|
const ui = signal(store.get(), ...(ngDevMode ? [{ debugName: "ui" }] : []));
|
|
@@ -258,9 +342,42 @@ function injectUI() {
|
|
|
258
342
|
});
|
|
259
343
|
return ui.asReadonly();
|
|
260
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* Injects a callback that is called when a user is authenticated.
|
|
347
|
+
*
|
|
348
|
+
* The callback is only triggered for non-anonymous users.
|
|
349
|
+
*
|
|
350
|
+
* @param onAuthenticated - Callback function called when a user is authenticated.
|
|
351
|
+
*/
|
|
352
|
+
function injectUserAuthenticated(onAuthenticated) {
|
|
353
|
+
const auth = inject(Auth);
|
|
354
|
+
const state = authState(auth);
|
|
355
|
+
effect((onCleanup) => {
|
|
356
|
+
const subscription = state.subscribe((user) => {
|
|
357
|
+
if (user && !user.isAnonymous) {
|
|
358
|
+
onAuthenticated(user);
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
onCleanup(() => {
|
|
362
|
+
subscription.unsubscribe();
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Injects a reCAPTCHA verifier for phone authentication.
|
|
368
|
+
*
|
|
369
|
+
* Automatically renders the reCAPTCHA widget in the provided element when available.
|
|
370
|
+
*
|
|
371
|
+
* @param element - Function that returns the element reference where reCAPTCHA should be rendered.
|
|
372
|
+
* @returns A computed signal containing the reCAPTCHA verifier instance, or null if not available.
|
|
373
|
+
*/
|
|
261
374
|
function injectRecaptchaVerifier(element) {
|
|
262
375
|
const ui = injectUI();
|
|
376
|
+
const platformId = inject(PLATFORM_ID);
|
|
263
377
|
const verifier = computed(() => {
|
|
378
|
+
if (!isPlatformBrowser(platformId)) {
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
264
381
|
const elementRef = element();
|
|
265
382
|
if (!elementRef) {
|
|
266
383
|
return null;
|
|
@@ -275,61 +392,151 @@ function injectRecaptchaVerifier(element) {
|
|
|
275
392
|
});
|
|
276
393
|
return verifier;
|
|
277
394
|
}
|
|
395
|
+
/**
|
|
396
|
+
* Injects a translation string as a reactive signal.
|
|
397
|
+
*
|
|
398
|
+
* The signal updates when the UI locale changes.
|
|
399
|
+
*
|
|
400
|
+
* @param category - The translation category (e.g., "labels", "errors", "prompts").
|
|
401
|
+
* @param key - The translation key within the category.
|
|
402
|
+
* @returns A computed signal containing the translated string.
|
|
403
|
+
*/
|
|
278
404
|
function injectTranslation(category, key) {
|
|
279
405
|
const ui = injectUI();
|
|
280
406
|
return computed(() => getTranslation(ui(), category, key));
|
|
281
407
|
}
|
|
408
|
+
/**
|
|
409
|
+
* Injects the sign-in authentication form schema as a reactive signal.
|
|
410
|
+
*
|
|
411
|
+
* @returns A computed signal containing the sign-in form schema.
|
|
412
|
+
*/
|
|
282
413
|
function injectSignInAuthFormSchema() {
|
|
283
414
|
const ui = injectUI();
|
|
284
415
|
return computed(() => createSignInAuthFormSchema(ui()));
|
|
285
416
|
}
|
|
417
|
+
/**
|
|
418
|
+
* Injects the sign-up authentication form schema as a reactive signal.
|
|
419
|
+
*
|
|
420
|
+
* @returns A computed signal containing the sign-up form schema.
|
|
421
|
+
*/
|
|
286
422
|
function injectSignUpAuthFormSchema() {
|
|
287
423
|
const ui = injectUI();
|
|
288
424
|
return computed(() => createSignUpAuthFormSchema(ui()));
|
|
289
425
|
}
|
|
426
|
+
/**
|
|
427
|
+
* Injects the forgot password authentication form schema as a reactive signal.
|
|
428
|
+
*
|
|
429
|
+
* @returns A computed signal containing the forgot password form schema.
|
|
430
|
+
*/
|
|
290
431
|
function injectForgotPasswordAuthFormSchema() {
|
|
291
432
|
const ui = injectUI();
|
|
292
433
|
return computed(() => createForgotPasswordAuthFormSchema(ui()));
|
|
293
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* Injects the email link authentication form schema as a reactive signal.
|
|
437
|
+
*
|
|
438
|
+
* @returns A computed signal containing the email link auth form schema.
|
|
439
|
+
*/
|
|
294
440
|
function injectEmailLinkAuthFormSchema() {
|
|
295
441
|
const ui = injectUI();
|
|
296
442
|
return computed(() => createEmailLinkAuthFormSchema(ui()));
|
|
297
443
|
}
|
|
444
|
+
/**
|
|
445
|
+
* Injects the phone authentication number form schema as a reactive signal.
|
|
446
|
+
*
|
|
447
|
+
* @returns A computed signal containing the phone auth number form schema.
|
|
448
|
+
*/
|
|
298
449
|
function injectPhoneAuthFormSchema() {
|
|
299
450
|
const ui = injectUI();
|
|
300
451
|
return computed(() => createPhoneAuthNumberFormSchema(ui()));
|
|
301
452
|
}
|
|
453
|
+
/**
|
|
454
|
+
* Injects the phone authentication verification form schema as a reactive signal.
|
|
455
|
+
*
|
|
456
|
+
* @returns A computed signal containing the phone auth verification form schema.
|
|
457
|
+
*/
|
|
302
458
|
function injectPhoneAuthVerifyFormSchema() {
|
|
303
459
|
const ui = injectUI();
|
|
304
460
|
return computed(() => createPhoneAuthVerifyFormSchema(ui()));
|
|
305
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* Injects the multi-factor phone authentication number form schema as a reactive signal.
|
|
464
|
+
*
|
|
465
|
+
* @returns A computed signal containing the MFA phone auth number form schema.
|
|
466
|
+
*/
|
|
306
467
|
function injectMultiFactorPhoneAuthNumberFormSchema() {
|
|
307
468
|
const ui = injectUI();
|
|
308
469
|
return computed(() => createMultiFactorPhoneAuthNumberFormSchema(ui()));
|
|
309
470
|
}
|
|
471
|
+
/**
|
|
472
|
+
* Injects the multi-factor phone authentication assertion form schema as a reactive signal.
|
|
473
|
+
*
|
|
474
|
+
* @returns A computed signal containing the MFA phone auth assertion form schema.
|
|
475
|
+
*/
|
|
476
|
+
function injectMultiFactorPhoneAuthAssertionFormSchema() {
|
|
477
|
+
const ui = injectUI();
|
|
478
|
+
return computed(() => createMultiFactorPhoneAuthAssertionFormSchema(ui()));
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Injects the multi-factor phone authentication verification form schema as a reactive signal.
|
|
482
|
+
*
|
|
483
|
+
* @returns A computed signal containing the MFA phone auth verification form schema.
|
|
484
|
+
*/
|
|
310
485
|
function injectMultiFactorPhoneAuthVerifyFormSchema() {
|
|
311
486
|
const ui = injectUI();
|
|
312
487
|
return computed(() => createMultiFactorPhoneAuthVerifyFormSchema(ui()));
|
|
313
488
|
}
|
|
489
|
+
/**
|
|
490
|
+
* Injects the multi-factor TOTP authentication number form schema as a reactive signal.
|
|
491
|
+
*
|
|
492
|
+
* @returns A computed signal containing the MFA TOTP auth number form schema.
|
|
493
|
+
*/
|
|
314
494
|
function injectMultiFactorTotpAuthNumberFormSchema() {
|
|
315
495
|
const ui = injectUI();
|
|
316
496
|
return computed(() => createMultiFactorTotpAuthNumberFormSchema(ui()));
|
|
317
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* Injects the multi-factor TOTP authentication verification form schema as a reactive signal.
|
|
500
|
+
*
|
|
501
|
+
* @returns A computed signal containing the MFA TOTP auth verification form schema.
|
|
502
|
+
*/
|
|
318
503
|
function injectMultiFactorTotpAuthVerifyFormSchema() {
|
|
319
504
|
const ui = injectUI();
|
|
320
505
|
return computed(() => createMultiFactorTotpAuthVerifyFormSchema(ui()));
|
|
321
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Injects the policy configuration (terms of service and privacy policy URLs).
|
|
509
|
+
*
|
|
510
|
+
* @returns The policy configuration, or null if not provided.
|
|
511
|
+
*/
|
|
322
512
|
function injectPolicies() {
|
|
323
513
|
return inject(FIREBASE_UI_POLICIES, { optional: true });
|
|
324
514
|
}
|
|
515
|
+
/**
|
|
516
|
+
* Injects the list of allowed countries for phone authentication as a reactive signal.
|
|
517
|
+
*
|
|
518
|
+
* @returns A computed signal containing the array of allowed country data.
|
|
519
|
+
*/
|
|
325
520
|
function injectCountries() {
|
|
326
521
|
const ui = injectUI();
|
|
327
522
|
return computed(() => getBehavior(ui(), "countryCodes")().allowedCountries);
|
|
328
523
|
}
|
|
524
|
+
/**
|
|
525
|
+
* Injects the default country for phone authentication as a reactive signal.
|
|
526
|
+
*
|
|
527
|
+
* @returns A computed signal containing the default country data.
|
|
528
|
+
*/
|
|
329
529
|
function injectDefaultCountry() {
|
|
330
530
|
const ui = injectUI();
|
|
331
531
|
return computed(() => getBehavior(ui(), "countryCodes")().defaultCountry);
|
|
332
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* Injects the redirect error message as a reactive signal.
|
|
535
|
+
*
|
|
536
|
+
* Returns the error message if a redirect error occurred, undefined otherwise.
|
|
537
|
+
*
|
|
538
|
+
* @returns A computed signal containing the redirect error message, or undefined if no error.
|
|
539
|
+
*/
|
|
333
540
|
function injectRedirectError() {
|
|
334
541
|
const ui = injectUI();
|
|
335
542
|
return computed(() => {
|
|
@@ -356,6 +563,11 @@ function injectRedirectError() {
|
|
|
356
563
|
* See the License for the specific language governing permissions and
|
|
357
564
|
* limitations under the License.
|
|
358
565
|
*/
|
|
566
|
+
/**
|
|
567
|
+
* A component that displays terms of service and privacy policy links.
|
|
568
|
+
*
|
|
569
|
+
* Parses the terms and privacy policy template and renders clickable links.
|
|
570
|
+
*/
|
|
359
571
|
class PoliciesComponent {
|
|
360
572
|
policies = injectPolicies();
|
|
361
573
|
termsText = injectTranslation("labels", "termsOfService");
|
|
@@ -364,6 +576,9 @@ class PoliciesComponent {
|
|
|
364
576
|
tosUrl = this.policies?.termsOfServiceUrl;
|
|
365
577
|
privacyPolicyUrl = this.policies?.privacyPolicyUrl;
|
|
366
578
|
shouldShow = computed(() => this.policies !== null, ...(ngDevMode ? [{ debugName: "shouldShow" }] : []));
|
|
579
|
+
get displayStyle() {
|
|
580
|
+
return this.shouldShow() ? "block" : "none";
|
|
581
|
+
}
|
|
367
582
|
policyParts = computed(() => {
|
|
368
583
|
if (!this.shouldShow()) {
|
|
369
584
|
return [];
|
|
@@ -394,23 +609,21 @@ class PoliciesComponent {
|
|
|
394
609
|
});
|
|
395
610
|
}, ...(ngDevMode ? [{ debugName: "policyParts" }] : []));
|
|
396
611
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: PoliciesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
397
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: PoliciesComponent, isStandalone: true, selector: "fui-policies", ngImport: i0, template: `
|
|
612
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: PoliciesComponent, isStandalone: true, selector: "fui-policies", host: { properties: { "style.display": "this.displayStyle" }, classAttribute: "fui-policies" }, ngImport: i0, template: `
|
|
398
613
|
@if (shouldShow()) {
|
|
399
|
-
|
|
400
|
-
@
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
<span>{{ part.content }}</span>
|
|
411
|
-
}
|
|
614
|
+
@for (part of policyParts(); track $index) {
|
|
615
|
+
@if (part.type === "tos") {
|
|
616
|
+
<a [attr.href]="part.url" target="_blank" rel="noopener noreferrer">
|
|
617
|
+
{{ part.text }}
|
|
618
|
+
</a>
|
|
619
|
+
} @else if (part.type === "privacy") {
|
|
620
|
+
<a [attr.href]="part.url" target="_blank" rel="noopener noreferrer">
|
|
621
|
+
{{ part.text }}
|
|
622
|
+
</a>
|
|
623
|
+
} @else {
|
|
624
|
+
<span>{{ part.content }}</span>
|
|
412
625
|
}
|
|
413
|
-
|
|
626
|
+
}
|
|
414
627
|
}
|
|
415
628
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
416
629
|
}
|
|
@@ -418,29 +631,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
418
631
|
type: Component,
|
|
419
632
|
args: [{
|
|
420
633
|
selector: "fui-policies",
|
|
634
|
+
host: {
|
|
635
|
+
class: "fui-policies",
|
|
636
|
+
},
|
|
421
637
|
standalone: true,
|
|
422
638
|
imports: [CommonModule],
|
|
423
639
|
template: `
|
|
424
640
|
@if (shouldShow()) {
|
|
425
|
-
|
|
426
|
-
@
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
<span>{{ part.content }}</span>
|
|
437
|
-
}
|
|
641
|
+
@for (part of policyParts(); track $index) {
|
|
642
|
+
@if (part.type === "tos") {
|
|
643
|
+
<a [attr.href]="part.url" target="_blank" rel="noopener noreferrer">
|
|
644
|
+
{{ part.text }}
|
|
645
|
+
</a>
|
|
646
|
+
} @else if (part.type === "privacy") {
|
|
647
|
+
<a [attr.href]="part.url" target="_blank" rel="noopener noreferrer">
|
|
648
|
+
{{ part.text }}
|
|
649
|
+
</a>
|
|
650
|
+
} @else {
|
|
651
|
+
<span>{{ part.content }}</span>
|
|
438
652
|
}
|
|
439
|
-
|
|
653
|
+
}
|
|
440
654
|
}
|
|
441
655
|
`,
|
|
442
656
|
}]
|
|
443
|
-
}]
|
|
657
|
+
}], propDecorators: { displayStyle: [{
|
|
658
|
+
type: HostBinding,
|
|
659
|
+
args: ["style.display"]
|
|
660
|
+
}] } });
|
|
444
661
|
|
|
445
662
|
/**
|
|
446
663
|
* Copyright 2025 Google LLC
|
|
@@ -457,6 +674,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
457
674
|
* See the License for the specific language governing permissions and
|
|
458
675
|
* limitations under the License.
|
|
459
676
|
*/
|
|
677
|
+
/**
|
|
678
|
+
* A form component for email link authentication.
|
|
679
|
+
*
|
|
680
|
+
* Sends a sign-in link to the user's email address and automatically completes sign-in
|
|
681
|
+
* if the user arrives via an email link.
|
|
682
|
+
*/
|
|
460
683
|
class EmailLinkAuthFormComponent {
|
|
461
684
|
ui = injectUI();
|
|
462
685
|
formSchema = injectEmailLinkAuthFormSchema();
|
|
@@ -465,8 +688,10 @@ class EmailLinkAuthFormComponent {
|
|
|
465
688
|
sendSignInLinkLabel = injectTranslation("labels", "sendSignInLink");
|
|
466
689
|
emailSentMessage = injectTranslation("messages", "signInLinkSent");
|
|
467
690
|
unknownErrorLabel = injectTranslation("errors", "unknownError");
|
|
468
|
-
|
|
469
|
-
|
|
691
|
+
/** Event emitter fired when sign-in link email is sent. */
|
|
692
|
+
emailSent = new EventEmitter();
|
|
693
|
+
/** Event emitter for successful sign-in. */
|
|
694
|
+
signIn = new EventEmitter();
|
|
470
695
|
form = injectForm({
|
|
471
696
|
defaultValues: {
|
|
472
697
|
email: "",
|
|
@@ -484,18 +709,18 @@ class EmailLinkAuthFormComponent {
|
|
|
484
709
|
this.form.update({
|
|
485
710
|
validators: {
|
|
486
711
|
onBlur: this.formSchema(),
|
|
487
|
-
onSubmit: this.formSchema(),
|
|
488
712
|
onSubmitAsync: async ({ value }) => {
|
|
489
713
|
try {
|
|
490
714
|
await sendSignInLinkToEmail(this.ui(), value.email);
|
|
491
715
|
this.emailSentState.set(true);
|
|
492
|
-
this.emailSent
|
|
716
|
+
this.emailSent.emit();
|
|
493
717
|
return;
|
|
494
718
|
}
|
|
495
719
|
catch (error) {
|
|
496
720
|
if (error instanceof FirebaseUIError) {
|
|
497
721
|
return error.message;
|
|
498
722
|
}
|
|
723
|
+
console.error(error);
|
|
499
724
|
return this.unknownErrorLabel();
|
|
500
725
|
}
|
|
501
726
|
},
|
|
@@ -506,13 +731,13 @@ class EmailLinkAuthFormComponent {
|
|
|
506
731
|
async completeSignIn() {
|
|
507
732
|
const credential = await completeEmailLinkSignIn(this.ui(), window.location.href);
|
|
508
733
|
if (credential) {
|
|
509
|
-
this.signIn
|
|
734
|
+
this.signIn.emit(credential);
|
|
510
735
|
}
|
|
511
736
|
}
|
|
512
737
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: EmailLinkAuthFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
513
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: EmailLinkAuthFormComponent, isStandalone: true, selector: "fui-email-link-auth-form", outputs: { emailSent: "emailSent", signIn: "signIn" }, ngImport: i0, template: `
|
|
738
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: EmailLinkAuthFormComponent, isStandalone: true, selector: "fui-email-link-auth-form", outputs: { emailSent: "emailSent", signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
514
739
|
@if (emailSentState()) {
|
|
515
|
-
<div class="fui-
|
|
740
|
+
<div class="fui-success">
|
|
516
741
|
{{ emailSentMessage() }}
|
|
517
742
|
</div>
|
|
518
743
|
}
|
|
@@ -533,13 +758,16 @@ class EmailLinkAuthFormComponent {
|
|
|
533
758
|
</fieldset>
|
|
534
759
|
</form>
|
|
535
760
|
}
|
|
536
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }] });
|
|
761
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type", "description"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }] });
|
|
537
762
|
}
|
|
538
763
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: EmailLinkAuthFormComponent, decorators: [{
|
|
539
764
|
type: Component,
|
|
540
765
|
args: [{
|
|
541
766
|
selector: "fui-email-link-auth-form",
|
|
542
767
|
standalone: true,
|
|
768
|
+
host: {
|
|
769
|
+
style: "display: block;",
|
|
770
|
+
},
|
|
543
771
|
imports: [
|
|
544
772
|
CommonModule,
|
|
545
773
|
TanStackField,
|
|
@@ -551,7 +779,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
551
779
|
],
|
|
552
780
|
template: `
|
|
553
781
|
@if (emailSentState()) {
|
|
554
|
-
<div class="fui-
|
|
782
|
+
<div class="fui-success">
|
|
555
783
|
{{ emailSentMessage() }}
|
|
556
784
|
</div>
|
|
557
785
|
}
|
|
@@ -574,7 +802,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
574
802
|
}
|
|
575
803
|
`,
|
|
576
804
|
}]
|
|
577
|
-
}], ctorParameters: () => [], propDecorators: { emailSent: [{
|
|
805
|
+
}], ctorParameters: () => [], propDecorators: { emailSent: [{
|
|
806
|
+
type: Output
|
|
807
|
+
}], signIn: [{
|
|
808
|
+
type: Output
|
|
809
|
+
}] } });
|
|
578
810
|
|
|
579
811
|
/**
|
|
580
812
|
* Copyright 2025 Google LLC
|
|
@@ -591,6 +823,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
591
823
|
* See the License for the specific language governing permissions and
|
|
592
824
|
* limitations under the License.
|
|
593
825
|
*/
|
|
826
|
+
/**
|
|
827
|
+
* A form component for requesting a password reset email.
|
|
828
|
+
*
|
|
829
|
+
* Displays a success message after the email is sent.
|
|
830
|
+
*/
|
|
594
831
|
class ForgotPasswordAuthFormComponent {
|
|
595
832
|
ui = injectUI();
|
|
596
833
|
formSchema = injectForgotPasswordAuthFormSchema();
|
|
@@ -600,8 +837,10 @@ class ForgotPasswordAuthFormComponent {
|
|
|
600
837
|
backToSignInLabel = injectTranslation("labels", "backToSignIn");
|
|
601
838
|
checkEmailForResetMessage = injectTranslation("messages", "checkEmailForReset");
|
|
602
839
|
unknownErrorLabel = injectTranslation("errors", "unknownError");
|
|
603
|
-
|
|
604
|
-
backToSignIn =
|
|
840
|
+
/** Event emitter for back to sign in action. */
|
|
841
|
+
backToSignIn = input(...(ngDevMode ? [undefined, { debugName: "backToSignIn" }] : []));
|
|
842
|
+
/** Event emitter fired when password reset email is sent. */
|
|
843
|
+
passwordSent = new EventEmitter();
|
|
605
844
|
form = injectForm({
|
|
606
845
|
defaultValues: {
|
|
607
846
|
email: "",
|
|
@@ -618,18 +857,18 @@ class ForgotPasswordAuthFormComponent {
|
|
|
618
857
|
this.form.update({
|
|
619
858
|
validators: {
|
|
620
859
|
onBlur: this.formSchema(),
|
|
621
|
-
onSubmit: this.formSchema(),
|
|
622
860
|
onSubmitAsync: async ({ value }) => {
|
|
623
861
|
try {
|
|
624
862
|
await sendPasswordResetEmail(this.ui(), value.email);
|
|
625
863
|
this.emailSent.set(true);
|
|
626
|
-
this.passwordSent
|
|
864
|
+
this.passwordSent.emit();
|
|
627
865
|
return;
|
|
628
866
|
}
|
|
629
867
|
catch (error) {
|
|
630
868
|
if (error instanceof FirebaseUIError) {
|
|
631
869
|
return error.message;
|
|
632
870
|
}
|
|
871
|
+
console.error(error);
|
|
633
872
|
return this.unknownErrorLabel();
|
|
634
873
|
}
|
|
635
874
|
},
|
|
@@ -638,9 +877,9 @@ class ForgotPasswordAuthFormComponent {
|
|
|
638
877
|
});
|
|
639
878
|
}
|
|
640
879
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ForgotPasswordAuthFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
641
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: ForgotPasswordAuthFormComponent, isStandalone: true, selector: "fui-forgot-password-auth-form", outputs: { passwordSent: "passwordSent",
|
|
880
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: ForgotPasswordAuthFormComponent, isStandalone: true, selector: "fui-forgot-password-auth-form", inputs: { backToSignIn: { classPropertyName: "backToSignIn", publicName: "backToSignIn", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { passwordSent: "passwordSent" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
642
881
|
@if (emailSent()) {
|
|
643
|
-
<div class="fui-
|
|
882
|
+
<div class="fui-success">
|
|
644
883
|
{{ checkEmailForResetMessage() }}
|
|
645
884
|
</div>
|
|
646
885
|
}
|
|
@@ -660,18 +899,21 @@ class ForgotPasswordAuthFormComponent {
|
|
|
660
899
|
<fui-form-error-message [state]="state()" />
|
|
661
900
|
</fieldset>
|
|
662
901
|
|
|
663
|
-
@if (backToSignIn) {
|
|
664
|
-
<button fui-form-action (click)="backToSignIn
|
|
902
|
+
@if (backToSignIn()?.observed) {
|
|
903
|
+
<button fui-form-action (click)="backToSignIn()?.emit()">{{ backToSignInLabel() }} →</button>
|
|
665
904
|
}
|
|
666
905
|
</form>
|
|
667
906
|
}
|
|
668
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }, { kind: "component", type: FormActionComponent, selector: "button[fui-form-action]" }] });
|
|
907
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type", "description"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }, { kind: "component", type: FormActionComponent, selector: "button[fui-form-action]" }] });
|
|
669
908
|
}
|
|
670
909
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ForgotPasswordAuthFormComponent, decorators: [{
|
|
671
910
|
type: Component,
|
|
672
911
|
args: [{
|
|
673
912
|
selector: "fui-forgot-password-auth-form",
|
|
674
913
|
standalone: true,
|
|
914
|
+
host: {
|
|
915
|
+
style: "display: block;",
|
|
916
|
+
},
|
|
675
917
|
imports: [
|
|
676
918
|
CommonModule,
|
|
677
919
|
TanStackField,
|
|
@@ -684,7 +926,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
684
926
|
],
|
|
685
927
|
template: `
|
|
686
928
|
@if (emailSent()) {
|
|
687
|
-
<div class="fui-
|
|
929
|
+
<div class="fui-success">
|
|
688
930
|
{{ checkEmailForResetMessage() }}
|
|
689
931
|
</div>
|
|
690
932
|
}
|
|
@@ -704,14 +946,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
704
946
|
<fui-form-error-message [state]="state()" />
|
|
705
947
|
</fieldset>
|
|
706
948
|
|
|
707
|
-
@if (backToSignIn) {
|
|
708
|
-
<button fui-form-action (click)="backToSignIn
|
|
949
|
+
@if (backToSignIn()?.observed) {
|
|
950
|
+
<button fui-form-action (click)="backToSignIn()?.emit()">{{ backToSignInLabel() }} →</button>
|
|
709
951
|
}
|
|
710
952
|
</form>
|
|
711
953
|
}
|
|
712
954
|
`,
|
|
713
955
|
}]
|
|
714
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
956
|
+
}], ctorParameters: () => [], propDecorators: { backToSignIn: [{ type: i0.Input, args: [{ isSignal: true, alias: "backToSignIn", required: false }] }], passwordSent: [{
|
|
957
|
+
type: Output
|
|
958
|
+
}] } });
|
|
715
959
|
|
|
716
960
|
/**
|
|
717
961
|
* Copyright 2025 Google LLC
|
|
@@ -727,51 +971,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
727
971
|
* See the License for the specific language governing permissions and
|
|
728
972
|
* limitations under the License.
|
|
729
973
|
*/
|
|
974
|
+
/**
|
|
975
|
+
* A form component for requesting SMS verification code during MFA assertion.
|
|
976
|
+
*/
|
|
730
977
|
class SmsMultiFactorAssertionPhoneFormComponent {
|
|
731
978
|
ui = injectUI();
|
|
732
|
-
|
|
979
|
+
/** The multi-factor info hint containing phone number details. */
|
|
733
980
|
hint = input.required(...(ngDevMode ? [{ debugName: "hint" }] : []));
|
|
734
|
-
|
|
735
|
-
|
|
981
|
+
/** Event emitter fired when verification ID is received. */
|
|
982
|
+
onSubmit = new EventEmitter();
|
|
736
983
|
sendCodeLabel = injectTranslation("labels", "sendCode");
|
|
737
|
-
unknownErrorLabel = injectTranslation("errors", "unknownError");
|
|
738
984
|
recaptchaContainer = viewChild.required("recaptchaContainer");
|
|
739
985
|
phoneNumber = computed(() => {
|
|
740
986
|
const hint = this.hint();
|
|
741
987
|
return hint.phoneNumber || "";
|
|
742
988
|
}, ...(ngDevMode ? [{ debugName: "phoneNumber" }] : []));
|
|
989
|
+
mfaSmsAssertionPrompt = computed(() => {
|
|
990
|
+
return getTranslation(this.ui(), "messages", "mfaSmsAssertionPrompt", { phoneNumber: this.phoneNumber() });
|
|
991
|
+
}, ...(ngDevMode ? [{ debugName: "mfaSmsAssertionPrompt" }] : []));
|
|
743
992
|
recaptchaVerifier = injectRecaptchaVerifier(() => this.recaptchaContainer());
|
|
744
993
|
form = injectForm({
|
|
745
|
-
defaultValues: {
|
|
746
|
-
phoneNumber: "",
|
|
747
|
-
},
|
|
994
|
+
defaultValues: {},
|
|
748
995
|
});
|
|
749
996
|
state = injectStore(this.form, (state) => state);
|
|
750
997
|
constructor() {
|
|
751
|
-
effect(() => {
|
|
752
|
-
// Set the phone number value from the hint
|
|
753
|
-
this.form.setFieldValue("phoneNumber", this.phoneNumber());
|
|
754
|
-
});
|
|
755
998
|
effect(() => {
|
|
756
999
|
this.form.update({
|
|
757
1000
|
validators: {
|
|
758
|
-
onBlur: this.formSchema(),
|
|
759
|
-
onSubmit: this.formSchema(),
|
|
760
1001
|
onSubmitAsync: async () => {
|
|
761
1002
|
try {
|
|
762
1003
|
const verifier = this.recaptchaVerifier();
|
|
763
1004
|
if (!verifier) {
|
|
764
|
-
return
|
|
1005
|
+
return "Recaptcha verifier not available";
|
|
765
1006
|
}
|
|
766
1007
|
const verificationId = await verifyPhoneNumber(this.ui(), "", verifier, undefined, this.hint());
|
|
767
1008
|
this.onSubmit.emit(verificationId);
|
|
768
1009
|
return;
|
|
769
1010
|
}
|
|
770
1011
|
catch (error) {
|
|
771
|
-
|
|
772
|
-
return error.message;
|
|
773
|
-
}
|
|
774
|
-
return this.unknownErrorLabel();
|
|
1012
|
+
return error instanceof FirebaseUIError ? error.message : String(error);
|
|
775
1013
|
}
|
|
776
1014
|
},
|
|
777
1015
|
},
|
|
@@ -792,16 +1030,14 @@ class SmsMultiFactorAssertionPhoneFormComponent {
|
|
|
792
1030
|
this.form.handleSubmit();
|
|
793
1031
|
}
|
|
794
1032
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SmsMultiFactorAssertionPhoneFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
795
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.7", type: SmsMultiFactorAssertionPhoneFormComponent, isStandalone: true, selector: "fui-sms-multi-factor-assertion-phone-form", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onSubmit: "onSubmit" }, viewQueries: [{ propertyName: "recaptchaContainer", first: true, predicate: ["recaptchaContainer"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1033
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.7", type: SmsMultiFactorAssertionPhoneFormComponent, isStandalone: true, selector: "fui-sms-multi-factor-assertion-phone-form", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onSubmit: "onSubmit" }, host: { styleAttribute: "display: block;" }, viewQueries: [{ propertyName: "recaptchaContainer", first: true, predicate: ["recaptchaContainer"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
796
1034
|
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
797
1035
|
<fieldset>
|
|
798
|
-
<
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
type="tel"
|
|
804
|
-
></fui-form-input>
|
|
1036
|
+
<label>
|
|
1037
|
+
<div data-input-description>
|
|
1038
|
+
{{ mfaSmsAssertionPrompt() }}
|
|
1039
|
+
</div>
|
|
1040
|
+
</label>
|
|
805
1041
|
</fieldset>
|
|
806
1042
|
<fieldset>
|
|
807
1043
|
<div class="fui-recaptcha-container" #recaptchaContainer></div>
|
|
@@ -813,31 +1049,25 @@ class SmsMultiFactorAssertionPhoneFormComponent {
|
|
|
813
1049
|
<fui-form-error-message [state]="state()" />
|
|
814
1050
|
</fieldset>
|
|
815
1051
|
</form>
|
|
816
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "
|
|
1052
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }] });
|
|
817
1053
|
}
|
|
818
1054
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SmsMultiFactorAssertionPhoneFormComponent, decorators: [{
|
|
819
1055
|
type: Component,
|
|
820
1056
|
args: [{
|
|
821
1057
|
selector: "fui-sms-multi-factor-assertion-phone-form",
|
|
822
1058
|
standalone: true,
|
|
823
|
-
imports: [
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
FormInputComponent,
|
|
828
|
-
FormSubmitComponent,
|
|
829
|
-
FormErrorMessageComponent,
|
|
830
|
-
],
|
|
1059
|
+
imports: [CommonModule, FormSubmitComponent, FormErrorMessageComponent],
|
|
1060
|
+
host: {
|
|
1061
|
+
style: "display: block;",
|
|
1062
|
+
},
|
|
831
1063
|
template: `
|
|
832
1064
|
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
833
1065
|
<fieldset>
|
|
834
|
-
<
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
type="tel"
|
|
840
|
-
></fui-form-input>
|
|
1066
|
+
<label>
|
|
1067
|
+
<div data-input-description>
|
|
1068
|
+
{{ mfaSmsAssertionPrompt() }}
|
|
1069
|
+
</div>
|
|
1070
|
+
</label>
|
|
841
1071
|
</fieldset>
|
|
842
1072
|
<fieldset>
|
|
843
1073
|
<div class="fui-recaptcha-container" #recaptchaContainer></div>
|
|
@@ -851,14 +1081,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
851
1081
|
</form>
|
|
852
1082
|
`,
|
|
853
1083
|
}]
|
|
854
|
-
}], ctorParameters: () => [], propDecorators: { hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: true }] }], onSubmit: [{
|
|
1084
|
+
}], ctorParameters: () => [], propDecorators: { hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: true }] }], onSubmit: [{
|
|
1085
|
+
type: Output
|
|
1086
|
+
}], recaptchaContainer: [{ type: i0.ViewChild, args: ["recaptchaContainer", { isSignal: true }] }] } });
|
|
1087
|
+
/**
|
|
1088
|
+
* A form component for verifying SMS code during MFA assertion.
|
|
1089
|
+
*/
|
|
855
1090
|
class SmsMultiFactorAssertionVerifyFormComponent {
|
|
856
1091
|
ui = injectUI();
|
|
857
1092
|
formSchema = injectMultiFactorPhoneAuthVerifyFormSchema();
|
|
1093
|
+
/** The verification ID received from the phone form. */
|
|
858
1094
|
verificationId = input.required(...(ngDevMode ? [{ debugName: "verificationId" }] : []));
|
|
859
|
-
|
|
1095
|
+
/** Event emitter for successful MFA assertion. */
|
|
1096
|
+
onSuccess = new EventEmitter();
|
|
860
1097
|
verificationCodeLabel = injectTranslation("labels", "verificationCode");
|
|
861
1098
|
verifyCodeLabel = injectTranslation("labels", "verifyCode");
|
|
1099
|
+
smsVerificationPrompt = injectTranslation("prompts", "smsVerificationPrompt");
|
|
862
1100
|
unknownErrorLabel = injectTranslation("errors", "unknownError");
|
|
863
1101
|
form = injectForm({
|
|
864
1102
|
defaultValues: {
|
|
@@ -880,15 +1118,12 @@ class SmsMultiFactorAssertionVerifyFormComponent {
|
|
|
880
1118
|
try {
|
|
881
1119
|
const credential = PhoneAuthProvider.credential(value.verificationId, value.verificationCode);
|
|
882
1120
|
const assertion = PhoneMultiFactorGenerator.assertion(credential);
|
|
883
|
-
await signInWithMultiFactorAssertion(this.ui(), assertion);
|
|
884
|
-
this.onSuccess.emit();
|
|
1121
|
+
const result = await signInWithMultiFactorAssertion(this.ui(), assertion);
|
|
1122
|
+
this.onSuccess.emit(result);
|
|
885
1123
|
return;
|
|
886
1124
|
}
|
|
887
1125
|
catch (error) {
|
|
888
|
-
|
|
889
|
-
return error.message;
|
|
890
|
-
}
|
|
891
|
-
return this.unknownErrorLabel();
|
|
1126
|
+
return error instanceof FirebaseUIError ? error.message : String(error);
|
|
892
1127
|
}
|
|
893
1128
|
},
|
|
894
1129
|
},
|
|
@@ -901,14 +1136,15 @@ class SmsMultiFactorAssertionVerifyFormComponent {
|
|
|
901
1136
|
this.form.handleSubmit();
|
|
902
1137
|
}
|
|
903
1138
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SmsMultiFactorAssertionVerifyFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
904
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: SmsMultiFactorAssertionVerifyFormComponent, isStandalone: true, selector: "fui-sms-multi-factor-assertion-verify-form", inputs: { verificationId: { classPropertyName: "verificationId", publicName: "verificationId", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onSuccess: "onSuccess" }, ngImport: i0, template: `
|
|
1139
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: SmsMultiFactorAssertionVerifyFormComponent, isStandalone: true, selector: "fui-sms-multi-factor-assertion-verify-form", inputs: { verificationId: { classPropertyName: "verificationId", publicName: "verificationId", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onSuccess: "onSuccess" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
905
1140
|
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
906
1141
|
<fieldset>
|
|
907
1142
|
<fui-form-input
|
|
908
1143
|
name="verificationCode"
|
|
909
1144
|
tanstack-app-field
|
|
910
1145
|
[tanstackField]="form"
|
|
911
|
-
label="
|
|
1146
|
+
[label]="verificationCodeLabel()"
|
|
1147
|
+
[description]="smsVerificationPrompt()"
|
|
912
1148
|
type="text"
|
|
913
1149
|
></fui-form-input>
|
|
914
1150
|
</fieldset>
|
|
@@ -919,13 +1155,16 @@ class SmsMultiFactorAssertionVerifyFormComponent {
|
|
|
919
1155
|
<fui-form-error-message [state]="state()" />
|
|
920
1156
|
</fieldset>
|
|
921
1157
|
</form>
|
|
922
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }] });
|
|
1158
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type", "description"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }] });
|
|
923
1159
|
}
|
|
924
1160
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SmsMultiFactorAssertionVerifyFormComponent, decorators: [{
|
|
925
1161
|
type: Component,
|
|
926
1162
|
args: [{
|
|
927
1163
|
selector: "fui-sms-multi-factor-assertion-verify-form",
|
|
928
1164
|
standalone: true,
|
|
1165
|
+
host: {
|
|
1166
|
+
style: "display: block;",
|
|
1167
|
+
},
|
|
929
1168
|
imports: [
|
|
930
1169
|
CommonModule,
|
|
931
1170
|
TanStackField,
|
|
@@ -941,7 +1180,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
941
1180
|
name="verificationCode"
|
|
942
1181
|
tanstack-app-field
|
|
943
1182
|
[tanstackField]="form"
|
|
944
|
-
label="
|
|
1183
|
+
[label]="verificationCodeLabel()"
|
|
1184
|
+
[description]="smsVerificationPrompt()"
|
|
945
1185
|
type="text"
|
|
946
1186
|
></fui-form-input>
|
|
947
1187
|
</fieldset>
|
|
@@ -954,21 +1194,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
954
1194
|
</form>
|
|
955
1195
|
`,
|
|
956
1196
|
}]
|
|
957
|
-
}], ctorParameters: () => [], propDecorators: { verificationId: [{ type: i0.Input, args: [{ isSignal: true, alias: "verificationId", required: true }] }], onSuccess: [{
|
|
1197
|
+
}], ctorParameters: () => [], propDecorators: { verificationId: [{ type: i0.Input, args: [{ isSignal: true, alias: "verificationId", required: true }] }], onSuccess: [{
|
|
1198
|
+
type: Output
|
|
1199
|
+
}] } });
|
|
1200
|
+
/**
|
|
1201
|
+
* A form component for SMS multi-factor authentication assertion.
|
|
1202
|
+
*
|
|
1203
|
+
* Manages the flow between requesting and verifying SMS codes for MFA.
|
|
1204
|
+
*/
|
|
958
1205
|
class SmsMultiFactorAssertionFormComponent {
|
|
1206
|
+
/** The multi-factor info hint containing phone number details. */
|
|
959
1207
|
hint = input.required(...(ngDevMode ? [{ debugName: "hint" }] : []));
|
|
960
|
-
|
|
1208
|
+
/** Event emitter for successful MFA assertion. */
|
|
1209
|
+
onSuccess = new EventEmitter();
|
|
961
1210
|
verification = signal(null, ...(ngDevMode ? [{ debugName: "verification" }] : []));
|
|
962
1211
|
handlePhoneSubmit(verificationId) {
|
|
963
1212
|
this.verification.set({ verificationId });
|
|
964
1213
|
}
|
|
965
1214
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SmsMultiFactorAssertionFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
966
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SmsMultiFactorAssertionFormComponent, isStandalone: true, selector: "fui-sms-multi-factor-assertion-form", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onSuccess: "onSuccess" }, ngImport: i0, template: `
|
|
1215
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SmsMultiFactorAssertionFormComponent, isStandalone: true, selector: "fui-sms-multi-factor-assertion-form", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onSuccess: "onSuccess" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
967
1216
|
<div class="fui-content">
|
|
968
1217
|
@if (verification()) {
|
|
969
1218
|
<fui-sms-multi-factor-assertion-verify-form
|
|
970
1219
|
[verificationId]="verification()!.verificationId"
|
|
971
|
-
(onSuccess)="onSuccess.emit()"
|
|
1220
|
+
(onSuccess)="onSuccess.emit($event)"
|
|
972
1221
|
/>
|
|
973
1222
|
} @else {
|
|
974
1223
|
<fui-sms-multi-factor-assertion-phone-form [hint]="hint()" (onSubmit)="handlePhoneSubmit($event)" />
|
|
@@ -982,12 +1231,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
982
1231
|
selector: "fui-sms-multi-factor-assertion-form",
|
|
983
1232
|
standalone: true,
|
|
984
1233
|
imports: [CommonModule, SmsMultiFactorAssertionPhoneFormComponent, SmsMultiFactorAssertionVerifyFormComponent],
|
|
1234
|
+
host: {
|
|
1235
|
+
style: "display: block;",
|
|
1236
|
+
},
|
|
985
1237
|
template: `
|
|
986
1238
|
<div class="fui-content">
|
|
987
1239
|
@if (verification()) {
|
|
988
1240
|
<fui-sms-multi-factor-assertion-verify-form
|
|
989
1241
|
[verificationId]="verification()!.verificationId"
|
|
990
|
-
(onSuccess)="onSuccess.emit()"
|
|
1242
|
+
(onSuccess)="onSuccess.emit($event)"
|
|
991
1243
|
/>
|
|
992
1244
|
} @else {
|
|
993
1245
|
<fui-sms-multi-factor-assertion-phone-form [hint]="hint()" (onSubmit)="handlePhoneSubmit($event)" />
|
|
@@ -995,7 +1247,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
995
1247
|
</div>
|
|
996
1248
|
`,
|
|
997
1249
|
}]
|
|
998
|
-
}], propDecorators: { hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: true }] }], onSuccess: [{
|
|
1250
|
+
}], propDecorators: { hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: true }] }], onSuccess: [{
|
|
1251
|
+
type: Output
|
|
1252
|
+
}] } });
|
|
999
1253
|
|
|
1000
1254
|
/**
|
|
1001
1255
|
* Copyright 2025 Google LLC
|
|
@@ -1011,14 +1265,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1011
1265
|
* See the License for the specific language governing permissions and
|
|
1012
1266
|
* limitations under the License.
|
|
1013
1267
|
*/
|
|
1268
|
+
/**
|
|
1269
|
+
* A form component for TOTP multi-factor authentication assertion.
|
|
1270
|
+
*
|
|
1271
|
+
* Allows users to enter a TOTP code from their authenticator app.
|
|
1272
|
+
*/
|
|
1014
1273
|
class TotpMultiFactorAssertionFormComponent {
|
|
1015
1274
|
ui = injectUI();
|
|
1016
1275
|
formSchema = injectMultiFactorTotpAuthVerifyFormSchema();
|
|
1276
|
+
/** The multi-factor info hint containing TOTP details. */
|
|
1017
1277
|
hint = input.required(...(ngDevMode ? [{ debugName: "hint" }] : []));
|
|
1018
|
-
|
|
1278
|
+
/** Event emitter for successful MFA assertion. */
|
|
1279
|
+
onSuccess = new EventEmitter();
|
|
1019
1280
|
verificationCodeLabel = injectTranslation("labels", "verificationCode");
|
|
1020
1281
|
verifyCodeLabel = injectTranslation("labels", "verifyCode");
|
|
1021
|
-
|
|
1282
|
+
enterVerificationCodePrompt = injectTranslation("prompts", "enterVerificationCode");
|
|
1022
1283
|
form = injectForm({
|
|
1023
1284
|
defaultValues: {
|
|
1024
1285
|
verificationCode: "",
|
|
@@ -1030,19 +1291,15 @@ class TotpMultiFactorAssertionFormComponent {
|
|
|
1030
1291
|
this.form.update({
|
|
1031
1292
|
validators: {
|
|
1032
1293
|
onBlur: this.formSchema(),
|
|
1033
|
-
onSubmit: this.formSchema(),
|
|
1034
1294
|
onSubmitAsync: async ({ value }) => {
|
|
1035
1295
|
try {
|
|
1036
1296
|
const assertion = TotpMultiFactorGenerator.assertionForSignIn(this.hint().uid, value.verificationCode);
|
|
1037
|
-
await signInWithMultiFactorAssertion(this.ui(), assertion);
|
|
1038
|
-
this.onSuccess.emit();
|
|
1297
|
+
const result = await signInWithMultiFactorAssertion(this.ui(), assertion);
|
|
1298
|
+
this.onSuccess.emit(result);
|
|
1039
1299
|
return;
|
|
1040
1300
|
}
|
|
1041
1301
|
catch (error) {
|
|
1042
|
-
|
|
1043
|
-
return error.message;
|
|
1044
|
-
}
|
|
1045
|
-
return this.unknownErrorLabel();
|
|
1302
|
+
return error instanceof FirebaseUIError ? error.message : String(error);
|
|
1046
1303
|
}
|
|
1047
1304
|
},
|
|
1048
1305
|
},
|
|
@@ -1055,14 +1312,15 @@ class TotpMultiFactorAssertionFormComponent {
|
|
|
1055
1312
|
this.form.handleSubmit();
|
|
1056
1313
|
}
|
|
1057
1314
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: TotpMultiFactorAssertionFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1058
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: TotpMultiFactorAssertionFormComponent, isStandalone: true, selector: "fui-totp-multi-factor-assertion-form", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onSuccess: "onSuccess" }, ngImport: i0, template: `
|
|
1315
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: TotpMultiFactorAssertionFormComponent, isStandalone: true, selector: "fui-totp-multi-factor-assertion-form", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onSuccess: "onSuccess" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
1059
1316
|
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
1060
1317
|
<fieldset>
|
|
1061
1318
|
<fui-form-input
|
|
1062
1319
|
name="verificationCode"
|
|
1063
1320
|
tanstack-app-field
|
|
1064
1321
|
[tanstackField]="form"
|
|
1065
|
-
label="
|
|
1322
|
+
[label]="verificationCodeLabel()"
|
|
1323
|
+
[description]="enterVerificationCodePrompt()"
|
|
1066
1324
|
type="text"
|
|
1067
1325
|
placeholder="123456"
|
|
1068
1326
|
maxlength="6"
|
|
@@ -1075,13 +1333,16 @@ class TotpMultiFactorAssertionFormComponent {
|
|
|
1075
1333
|
<fui-form-error-message [state]="state()" />
|
|
1076
1334
|
</fieldset>
|
|
1077
1335
|
</form>
|
|
1078
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }] });
|
|
1336
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type", "description"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }] });
|
|
1079
1337
|
}
|
|
1080
1338
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: TotpMultiFactorAssertionFormComponent, decorators: [{
|
|
1081
1339
|
type: Component,
|
|
1082
1340
|
args: [{
|
|
1083
1341
|
selector: "fui-totp-multi-factor-assertion-form",
|
|
1084
1342
|
standalone: true,
|
|
1343
|
+
host: {
|
|
1344
|
+
style: "display: block;",
|
|
1345
|
+
},
|
|
1085
1346
|
imports: [
|
|
1086
1347
|
CommonModule,
|
|
1087
1348
|
TanStackField,
|
|
@@ -1097,7 +1358,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1097
1358
|
name="verificationCode"
|
|
1098
1359
|
tanstack-app-field
|
|
1099
1360
|
[tanstackField]="form"
|
|
1100
|
-
label="
|
|
1361
|
+
[label]="verificationCodeLabel()"
|
|
1362
|
+
[description]="enterVerificationCodePrompt()"
|
|
1101
1363
|
type="text"
|
|
1102
1364
|
placeholder="123456"
|
|
1103
1365
|
maxlength="6"
|
|
@@ -1112,7 +1374,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1112
1374
|
</form>
|
|
1113
1375
|
`,
|
|
1114
1376
|
}]
|
|
1115
|
-
}], ctorParameters: () => [], propDecorators: { hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: true }] }], onSuccess: [{
|
|
1377
|
+
}], ctorParameters: () => [], propDecorators: { hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: true }] }], onSuccess: [{
|
|
1378
|
+
type: Output
|
|
1379
|
+
}] } });
|
|
1116
1380
|
|
|
1117
1381
|
/**
|
|
1118
1382
|
* Copyright 2025 Google LLC
|
|
@@ -1129,8 +1393,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1129
1393
|
* See the License for the specific language governing permissions and
|
|
1130
1394
|
* limitations under the License.
|
|
1131
1395
|
*/
|
|
1396
|
+
/**
|
|
1397
|
+
* A form component for multi-factor authentication assertion.
|
|
1398
|
+
*
|
|
1399
|
+
* Allows users to select and complete MFA verification using SMS or TOTP.
|
|
1400
|
+
*/
|
|
1132
1401
|
class MultiFactorAuthAssertionFormComponent {
|
|
1133
1402
|
ui = injectUI();
|
|
1403
|
+
constructor() {
|
|
1404
|
+
effect((onCleanup) => {
|
|
1405
|
+
// Cleanup the multi-factor resolver when the component unmounts.
|
|
1406
|
+
onCleanup(() => {
|
|
1407
|
+
this.ui().setMultiFactorResolver();
|
|
1408
|
+
});
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
/** Event emitter for successful MFA assertion. */
|
|
1412
|
+
onSuccess = new EventEmitter();
|
|
1134
1413
|
resolver = computed(() => {
|
|
1135
1414
|
const resolver = this.ui().multiFactorResolver;
|
|
1136
1415
|
if (!resolver) {
|
|
@@ -1139,30 +1418,31 @@ class MultiFactorAuthAssertionFormComponent {
|
|
|
1139
1418
|
return resolver;
|
|
1140
1419
|
}, ...(ngDevMode ? [{ debugName: "resolver" }] : []));
|
|
1141
1420
|
selectedHint = signal(this.resolver().hints.length === 1 ? this.resolver().hints[0] : undefined, ...(ngDevMode ? [{ debugName: "selectedHint" }] : []));
|
|
1142
|
-
phoneFactorId =
|
|
1143
|
-
totpFactorId =
|
|
1421
|
+
phoneFactorId = PhoneMultiFactorGenerator.FACTOR_ID;
|
|
1422
|
+
totpFactorId = TotpMultiFactorGenerator.FACTOR_ID;
|
|
1144
1423
|
smsVerificationLabel = injectTranslation("labels", "mfaSmsVerification");
|
|
1145
1424
|
totpVerificationLabel = injectTranslation("labels", "mfaTotpVerification");
|
|
1425
|
+
mfaAssertionFactorPrompt = injectTranslation("prompts", "mfaAssertionFactorPrompt");
|
|
1146
1426
|
selectHint(hint) {
|
|
1147
1427
|
this.selectedHint.set(hint);
|
|
1148
1428
|
}
|
|
1149
1429
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MultiFactorAuthAssertionFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1150
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: MultiFactorAuthAssertionFormComponent, isStandalone: true, selector: "fui-multi-factor-auth-assertion-form", ngImport: i0, template: `
|
|
1430
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: MultiFactorAuthAssertionFormComponent, isStandalone: true, selector: "fui-multi-factor-auth-assertion-form", outputs: { onSuccess: "onSuccess" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
1151
1431
|
<div class="fui-content">
|
|
1152
1432
|
@if (selectedHint()) {
|
|
1153
|
-
@if (selectedHint()!.factorId === phoneFactorId
|
|
1154
|
-
<fui-sms-multi-factor-assertion-form [hint]="selectedHint()!" />
|
|
1155
|
-
} @else if (selectedHint()!.factorId === totpFactorId
|
|
1156
|
-
<fui-totp-multi-factor-assertion-form [hint]="selectedHint()!" />
|
|
1433
|
+
@if (selectedHint()!.factorId === phoneFactorId) {
|
|
1434
|
+
<fui-sms-multi-factor-assertion-form [hint]="selectedHint()!" (onSuccess)="onSuccess.emit($event)" />
|
|
1435
|
+
} @else if (selectedHint()!.factorId === totpFactorId) {
|
|
1436
|
+
<fui-totp-multi-factor-assertion-form [hint]="selectedHint()!" (onSuccess)="onSuccess.emit($event)" />
|
|
1157
1437
|
}
|
|
1158
1438
|
} @else {
|
|
1159
|
-
<p>
|
|
1439
|
+
<p>{{ mfaAssertionFactorPrompt() }}</p>
|
|
1160
1440
|
@for (hint of resolver().hints; track hint.factorId) {
|
|
1161
|
-
@if (hint.factorId === totpFactorId
|
|
1441
|
+
@if (hint.factorId === totpFactorId) {
|
|
1162
1442
|
<button fui-button (click)="selectHint(hint)">
|
|
1163
1443
|
{{ totpVerificationLabel() }}
|
|
1164
1444
|
</button>
|
|
1165
|
-
} @else if (hint.factorId === phoneFactorId
|
|
1445
|
+
} @else if (hint.factorId === phoneFactorId) {
|
|
1166
1446
|
<button fui-button (click)="selectHint(hint)">
|
|
1167
1447
|
{{ smsVerificationLabel() }}
|
|
1168
1448
|
</button>
|
|
@@ -1178,22 +1458,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1178
1458
|
selector: "fui-multi-factor-auth-assertion-form",
|
|
1179
1459
|
standalone: true,
|
|
1180
1460
|
imports: [CommonModule, SmsMultiFactorAssertionFormComponent, TotpMultiFactorAssertionFormComponent, ButtonComponent],
|
|
1461
|
+
host: {
|
|
1462
|
+
style: "display: block;",
|
|
1463
|
+
},
|
|
1181
1464
|
template: `
|
|
1182
1465
|
<div class="fui-content">
|
|
1183
1466
|
@if (selectedHint()) {
|
|
1184
|
-
@if (selectedHint()!.factorId === phoneFactorId
|
|
1185
|
-
<fui-sms-multi-factor-assertion-form [hint]="selectedHint()!" />
|
|
1186
|
-
} @else if (selectedHint()!.factorId === totpFactorId
|
|
1187
|
-
<fui-totp-multi-factor-assertion-form [hint]="selectedHint()!" />
|
|
1467
|
+
@if (selectedHint()!.factorId === phoneFactorId) {
|
|
1468
|
+
<fui-sms-multi-factor-assertion-form [hint]="selectedHint()!" (onSuccess)="onSuccess.emit($event)" />
|
|
1469
|
+
} @else if (selectedHint()!.factorId === totpFactorId) {
|
|
1470
|
+
<fui-totp-multi-factor-assertion-form [hint]="selectedHint()!" (onSuccess)="onSuccess.emit($event)" />
|
|
1188
1471
|
}
|
|
1189
1472
|
} @else {
|
|
1190
|
-
<p>
|
|
1473
|
+
<p>{{ mfaAssertionFactorPrompt() }}</p>
|
|
1191
1474
|
@for (hint of resolver().hints; track hint.factorId) {
|
|
1192
|
-
@if (hint.factorId === totpFactorId
|
|
1475
|
+
@if (hint.factorId === totpFactorId) {
|
|
1193
1476
|
<button fui-button (click)="selectHint(hint)">
|
|
1194
1477
|
{{ totpVerificationLabel() }}
|
|
1195
1478
|
</button>
|
|
1196
|
-
} @else if (hint.factorId === phoneFactorId
|
|
1479
|
+
} @else if (hint.factorId === phoneFactorId) {
|
|
1197
1480
|
<button fui-button (click)="selectHint(hint)">
|
|
1198
1481
|
{{ smsVerificationLabel() }}
|
|
1199
1482
|
</button>
|
|
@@ -1203,7 +1486,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1203
1486
|
</div>
|
|
1204
1487
|
`,
|
|
1205
1488
|
}]
|
|
1206
|
-
}]
|
|
1489
|
+
}], ctorParameters: () => [], propDecorators: { onSuccess: [{
|
|
1490
|
+
type: Output
|
|
1491
|
+
}] } });
|
|
1207
1492
|
|
|
1208
1493
|
/**
|
|
1209
1494
|
* Copyright 2025 Google LLC
|
|
@@ -1220,9 +1505,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1220
1505
|
* See the License for the specific language governing permissions and
|
|
1221
1506
|
* limitations under the License.
|
|
1222
1507
|
*/
|
|
1508
|
+
/**
|
|
1509
|
+
* A country selector component for phone number input.
|
|
1510
|
+
*
|
|
1511
|
+
* Displays a dropdown with country flags, dial codes, and names for selecting a country.
|
|
1512
|
+
*/
|
|
1223
1513
|
class CountrySelectorComponent {
|
|
1224
1514
|
countries = injectCountries();
|
|
1225
1515
|
defaultCountry = injectDefaultCountry();
|
|
1516
|
+
/** The selected country code (two-way binding). */
|
|
1226
1517
|
value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
|
|
1227
1518
|
selected = computed(() => {
|
|
1228
1519
|
if (!this.value()) {
|
|
@@ -1237,7 +1528,7 @@ class CountrySelectorComponent {
|
|
|
1237
1528
|
}
|
|
1238
1529
|
}
|
|
1239
1530
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CountrySelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1240
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: CountrySelectorComponent, isStandalone: true, selector: "fui-country-selector", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, ngImport: i0, template: `
|
|
1531
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: CountrySelectorComponent, isStandalone: true, selector: "fui-country-selector", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
1241
1532
|
<div class="fui-country-selector">
|
|
1242
1533
|
<div class="fui-country-selector__wrapper">
|
|
1243
1534
|
<span class="fui-country-selector__flag">{{ selected().emoji }}</span>
|
|
@@ -1248,7 +1539,7 @@ class CountrySelectorComponent {
|
|
|
1248
1539
|
[ngModel]="selected().code"
|
|
1249
1540
|
(ngModelChange)="handleCountryChange($event)"
|
|
1250
1541
|
>
|
|
1251
|
-
@for (country of countries(); track
|
|
1542
|
+
@for (country of countries(); track $index) {
|
|
1252
1543
|
<option [value]="country.code">{{ country.dialCode }} ({{ country.name }})</option>
|
|
1253
1544
|
}
|
|
1254
1545
|
</select>
|
|
@@ -1263,6 +1554,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1263
1554
|
selector: "fui-country-selector",
|
|
1264
1555
|
standalone: true,
|
|
1265
1556
|
imports: [CommonModule, FormsModule],
|
|
1557
|
+
host: {
|
|
1558
|
+
style: "display: block;",
|
|
1559
|
+
},
|
|
1266
1560
|
template: `
|
|
1267
1561
|
<div class="fui-country-selector">
|
|
1268
1562
|
<div class="fui-country-selector__wrapper">
|
|
@@ -1274,7 +1568,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1274
1568
|
[ngModel]="selected().code"
|
|
1275
1569
|
(ngModelChange)="handleCountryChange($event)"
|
|
1276
1570
|
>
|
|
1277
|
-
@for (country of countries(); track
|
|
1571
|
+
@for (country of countries(); track $index) {
|
|
1278
1572
|
<option [value]="country.code">{{ country.dialCode }} ({{ country.name }})</option>
|
|
1279
1573
|
}
|
|
1280
1574
|
</select>
|
|
@@ -1300,42 +1594,712 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1300
1594
|
* See the License for the specific language governing permissions and
|
|
1301
1595
|
* limitations under the License.
|
|
1302
1596
|
*/
|
|
1303
|
-
|
|
1597
|
+
/**
|
|
1598
|
+
* A form component for SMS multi-factor authentication enrollment.
|
|
1599
|
+
*
|
|
1600
|
+
* Manages the flow between phone number entry and verification code entry for MFA enrollment.
|
|
1601
|
+
*/
|
|
1602
|
+
class SmsMultiFactorEnrollmentFormComponent {
|
|
1304
1603
|
ui = injectUI();
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1604
|
+
phoneFormSchema = injectMultiFactorPhoneAuthNumberFormSchema();
|
|
1605
|
+
verificationFormSchema = injectMultiFactorPhoneAuthVerifyFormSchema();
|
|
1606
|
+
defaultCountry = injectDefaultCountry();
|
|
1607
|
+
verificationId = signal(null, ...(ngDevMode ? [{ debugName: "verificationId" }] : []));
|
|
1608
|
+
country = signal(this.defaultCountry().code, ...(ngDevMode ? [{ debugName: "country" }] : []));
|
|
1609
|
+
displayName = signal("", ...(ngDevMode ? [{ debugName: "displayName" }] : []));
|
|
1610
|
+
displayNameLabel = injectTranslation("labels", "displayName");
|
|
1308
1611
|
phoneNumberLabel = injectTranslation("labels", "phoneNumber");
|
|
1309
1612
|
sendCodeLabel = injectTranslation("labels", "sendCode");
|
|
1310
|
-
|
|
1613
|
+
verificationCodeLabel = injectTranslation("labels", "verificationCode");
|
|
1614
|
+
verifyCodeLabel = injectTranslation("labels", "verifyCode");
|
|
1615
|
+
smsVerificationPrompt = injectTranslation("prompts", "smsVerificationPrompt");
|
|
1616
|
+
/** Event emitter fired when MFA enrollment is completed. */
|
|
1617
|
+
onEnrollment = new EventEmitter();
|
|
1311
1618
|
recaptchaContainer = viewChild.required("recaptchaContainer");
|
|
1312
1619
|
recaptchaVerifier = injectRecaptchaVerifier(() => this.recaptchaContainer());
|
|
1313
|
-
|
|
1620
|
+
phoneForm = injectForm({
|
|
1314
1621
|
defaultValues: {
|
|
1622
|
+
displayName: "",
|
|
1315
1623
|
phoneNumber: "",
|
|
1316
1624
|
},
|
|
1317
1625
|
});
|
|
1318
|
-
|
|
1626
|
+
verificationForm = injectForm({
|
|
1627
|
+
defaultValues: {
|
|
1628
|
+
verificationCode: "",
|
|
1629
|
+
},
|
|
1630
|
+
});
|
|
1631
|
+
phoneState = injectStore(this.phoneForm, (state) => state);
|
|
1632
|
+
verificationState = injectStore(this.verificationForm, (state) => state);
|
|
1319
1633
|
constructor() {
|
|
1634
|
+
if (!this.ui().auth.currentUser) {
|
|
1635
|
+
throw new Error("User must be authenticated to enroll with multi-factor authentication");
|
|
1636
|
+
}
|
|
1320
1637
|
effect(() => {
|
|
1321
|
-
this.
|
|
1638
|
+
this.phoneForm.update({
|
|
1322
1639
|
validators: {
|
|
1323
|
-
onBlur: this.
|
|
1324
|
-
onSubmit: this.
|
|
1640
|
+
onBlur: this.phoneFormSchema(),
|
|
1641
|
+
onSubmit: this.phoneFormSchema(),
|
|
1325
1642
|
onSubmitAsync: async ({ value }) => {
|
|
1326
|
-
const selectedCountry = countryData.find((c) => c.code === this.country());
|
|
1327
|
-
const formattedNumber = formatPhoneNumber(value.phoneNumber, selectedCountry);
|
|
1328
1643
|
try {
|
|
1329
1644
|
const verifier = this.recaptchaVerifier();
|
|
1330
1645
|
if (!verifier) {
|
|
1331
|
-
return
|
|
1646
|
+
return "Recaptcha verifier not available";
|
|
1332
1647
|
}
|
|
1333
|
-
const
|
|
1334
|
-
|
|
1648
|
+
const currentUser = this.ui().auth.currentUser;
|
|
1649
|
+
const mfaUser = multiFactor(currentUser);
|
|
1650
|
+
const formattedPhoneNumber = formatPhoneNumber(value.phoneNumber, this.defaultCountry());
|
|
1651
|
+
const verificationId = await verifyPhoneNumber(this.ui(), formattedPhoneNumber, verifier, mfaUser);
|
|
1652
|
+
this.displayName.set(value.displayName);
|
|
1653
|
+
this.verificationId.set(verificationId);
|
|
1335
1654
|
return;
|
|
1336
1655
|
}
|
|
1337
1656
|
catch (error) {
|
|
1338
|
-
|
|
1657
|
+
return error instanceof FirebaseUIError ? error.message : String(error);
|
|
1658
|
+
}
|
|
1659
|
+
},
|
|
1660
|
+
},
|
|
1661
|
+
});
|
|
1662
|
+
});
|
|
1663
|
+
effect(() => {
|
|
1664
|
+
this.verificationForm.update({
|
|
1665
|
+
validators: {
|
|
1666
|
+
onBlur: this.verificationFormSchema(),
|
|
1667
|
+
onSubmit: this.verificationFormSchema(),
|
|
1668
|
+
onSubmitAsync: async ({ value }) => {
|
|
1669
|
+
try {
|
|
1670
|
+
const credential = PhoneAuthProvider.credential(this.verificationId(), value.verificationCode);
|
|
1671
|
+
const assertion = PhoneMultiFactorGenerator.assertion(credential);
|
|
1672
|
+
await enrollWithMultiFactorAssertion(this.ui(), assertion, this.displayName());
|
|
1673
|
+
this.onEnrollment.emit();
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
catch (error) {
|
|
1677
|
+
return error instanceof FirebaseUIError ? error.message : String(error);
|
|
1678
|
+
}
|
|
1679
|
+
},
|
|
1680
|
+
},
|
|
1681
|
+
});
|
|
1682
|
+
});
|
|
1683
|
+
}
|
|
1684
|
+
async handlePhoneSubmit(event) {
|
|
1685
|
+
event.preventDefault();
|
|
1686
|
+
event.stopPropagation();
|
|
1687
|
+
this.phoneForm.handleSubmit();
|
|
1688
|
+
}
|
|
1689
|
+
async handleVerificationSubmit(event) {
|
|
1690
|
+
event.preventDefault();
|
|
1691
|
+
event.stopPropagation();
|
|
1692
|
+
this.verificationForm.handleSubmit();
|
|
1693
|
+
}
|
|
1694
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SmsMultiFactorEnrollmentFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1695
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SmsMultiFactorEnrollmentFormComponent, isStandalone: true, selector: "fui-sms-multi-factor-enrollment-form", outputs: { onEnrollment: "onEnrollment" }, host: { styleAttribute: "display: block;" }, viewQueries: [{ propertyName: "recaptchaContainer", first: true, predicate: ["recaptchaContainer"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1696
|
+
<div class="fui-form-container">
|
|
1697
|
+
@if (!verificationId()) {
|
|
1698
|
+
<form (submit)="handlePhoneSubmit($event)" class="fui-form">
|
|
1699
|
+
<fieldset>
|
|
1700
|
+
<fui-form-input
|
|
1701
|
+
name="displayName"
|
|
1702
|
+
tanstack-app-field
|
|
1703
|
+
[tanstackField]="phoneForm"
|
|
1704
|
+
[label]="displayNameLabel()"
|
|
1705
|
+
type="text"
|
|
1706
|
+
/>
|
|
1707
|
+
</fieldset>
|
|
1708
|
+
<fieldset>
|
|
1709
|
+
<fui-form-input
|
|
1710
|
+
name="phoneNumber"
|
|
1711
|
+
tanstack-app-field
|
|
1712
|
+
[tanstackField]="phoneForm"
|
|
1713
|
+
[label]="phoneNumberLabel()"
|
|
1714
|
+
type="tel"
|
|
1715
|
+
>
|
|
1716
|
+
<fui-country-selector [(value)]="country" ngProjectAs="input-before" />
|
|
1717
|
+
</fui-form-input>
|
|
1718
|
+
</fieldset>
|
|
1719
|
+
<fieldset>
|
|
1720
|
+
<div class="fui-recaptcha-container" #recaptchaContainer></div>
|
|
1721
|
+
</fieldset>
|
|
1722
|
+
<fieldset>
|
|
1723
|
+
<fui-form-submit [state]="phoneState()">
|
|
1724
|
+
{{ sendCodeLabel() }}
|
|
1725
|
+
</fui-form-submit>
|
|
1726
|
+
<fui-form-error-message [state]="phoneState()" />
|
|
1727
|
+
</fieldset>
|
|
1728
|
+
</form>
|
|
1729
|
+
} @else {
|
|
1730
|
+
<form (submit)="handleVerificationSubmit($event)" class="fui-form">
|
|
1731
|
+
<fieldset>
|
|
1732
|
+
<fui-form-input
|
|
1733
|
+
name="verificationCode"
|
|
1734
|
+
tanstack-app-field
|
|
1735
|
+
[tanstackField]="verificationForm"
|
|
1736
|
+
[label]="verificationCodeLabel()"
|
|
1737
|
+
[description]="smsVerificationPrompt()"
|
|
1738
|
+
type="text"
|
|
1739
|
+
></fui-form-input>
|
|
1740
|
+
</fieldset>
|
|
1741
|
+
<fieldset>
|
|
1742
|
+
<fui-form-submit [state]="verificationState()">
|
|
1743
|
+
{{ verifyCodeLabel() }}
|
|
1744
|
+
</fui-form-submit>
|
|
1745
|
+
<fui-form-error-message [state]="verificationState()" />
|
|
1746
|
+
</fieldset>
|
|
1747
|
+
</form>
|
|
1748
|
+
}
|
|
1749
|
+
</div>
|
|
1750
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type", "description"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }, { kind: "component", type: CountrySelectorComponent, selector: "fui-country-selector", inputs: ["value"], outputs: ["valueChange"] }] });
|
|
1751
|
+
}
|
|
1752
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SmsMultiFactorEnrollmentFormComponent, decorators: [{
|
|
1753
|
+
type: Component,
|
|
1754
|
+
args: [{
|
|
1755
|
+
selector: "fui-sms-multi-factor-enrollment-form",
|
|
1756
|
+
standalone: true,
|
|
1757
|
+
host: {
|
|
1758
|
+
style: "display: block;",
|
|
1759
|
+
},
|
|
1760
|
+
imports: [
|
|
1761
|
+
CommonModule,
|
|
1762
|
+
TanStackField,
|
|
1763
|
+
TanStackAppField,
|
|
1764
|
+
FormInputComponent,
|
|
1765
|
+
FormSubmitComponent,
|
|
1766
|
+
FormErrorMessageComponent,
|
|
1767
|
+
CountrySelectorComponent,
|
|
1768
|
+
],
|
|
1769
|
+
template: `
|
|
1770
|
+
<div class="fui-form-container">
|
|
1771
|
+
@if (!verificationId()) {
|
|
1772
|
+
<form (submit)="handlePhoneSubmit($event)" class="fui-form">
|
|
1773
|
+
<fieldset>
|
|
1774
|
+
<fui-form-input
|
|
1775
|
+
name="displayName"
|
|
1776
|
+
tanstack-app-field
|
|
1777
|
+
[tanstackField]="phoneForm"
|
|
1778
|
+
[label]="displayNameLabel()"
|
|
1779
|
+
type="text"
|
|
1780
|
+
/>
|
|
1781
|
+
</fieldset>
|
|
1782
|
+
<fieldset>
|
|
1783
|
+
<fui-form-input
|
|
1784
|
+
name="phoneNumber"
|
|
1785
|
+
tanstack-app-field
|
|
1786
|
+
[tanstackField]="phoneForm"
|
|
1787
|
+
[label]="phoneNumberLabel()"
|
|
1788
|
+
type="tel"
|
|
1789
|
+
>
|
|
1790
|
+
<fui-country-selector [(value)]="country" ngProjectAs="input-before" />
|
|
1791
|
+
</fui-form-input>
|
|
1792
|
+
</fieldset>
|
|
1793
|
+
<fieldset>
|
|
1794
|
+
<div class="fui-recaptcha-container" #recaptchaContainer></div>
|
|
1795
|
+
</fieldset>
|
|
1796
|
+
<fieldset>
|
|
1797
|
+
<fui-form-submit [state]="phoneState()">
|
|
1798
|
+
{{ sendCodeLabel() }}
|
|
1799
|
+
</fui-form-submit>
|
|
1800
|
+
<fui-form-error-message [state]="phoneState()" />
|
|
1801
|
+
</fieldset>
|
|
1802
|
+
</form>
|
|
1803
|
+
} @else {
|
|
1804
|
+
<form (submit)="handleVerificationSubmit($event)" class="fui-form">
|
|
1805
|
+
<fieldset>
|
|
1806
|
+
<fui-form-input
|
|
1807
|
+
name="verificationCode"
|
|
1808
|
+
tanstack-app-field
|
|
1809
|
+
[tanstackField]="verificationForm"
|
|
1810
|
+
[label]="verificationCodeLabel()"
|
|
1811
|
+
[description]="smsVerificationPrompt()"
|
|
1812
|
+
type="text"
|
|
1813
|
+
></fui-form-input>
|
|
1814
|
+
</fieldset>
|
|
1815
|
+
<fieldset>
|
|
1816
|
+
<fui-form-submit [state]="verificationState()">
|
|
1817
|
+
{{ verifyCodeLabel() }}
|
|
1818
|
+
</fui-form-submit>
|
|
1819
|
+
<fui-form-error-message [state]="verificationState()" />
|
|
1820
|
+
</fieldset>
|
|
1821
|
+
</form>
|
|
1822
|
+
}
|
|
1823
|
+
</div>
|
|
1824
|
+
`,
|
|
1825
|
+
}]
|
|
1826
|
+
}], ctorParameters: () => [], propDecorators: { onEnrollment: [{
|
|
1827
|
+
type: Output
|
|
1828
|
+
}], recaptchaContainer: [{ type: i0.ViewChild, args: ["recaptchaContainer", { isSignal: true }] }] } });
|
|
1829
|
+
|
|
1830
|
+
/**
|
|
1831
|
+
* Copyright 2025 Google LLC
|
|
1832
|
+
*
|
|
1833
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1834
|
+
* you may not use this file except in compliance with the License.
|
|
1835
|
+
* You may obtain a copy of the License at
|
|
1836
|
+
*
|
|
1837
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1838
|
+
*
|
|
1839
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1840
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1841
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1842
|
+
* See the License for the specific language governing permissions and
|
|
1843
|
+
* limitations under the License.
|
|
1844
|
+
*/
|
|
1845
|
+
/**
|
|
1846
|
+
* A form component for generating a TOTP secret and display name during MFA enrollment.
|
|
1847
|
+
*/
|
|
1848
|
+
class TotpMultiFactorSecretGenerationFormComponent {
|
|
1849
|
+
ui = injectUI();
|
|
1850
|
+
formSchema = injectMultiFactorTotpAuthNumberFormSchema();
|
|
1851
|
+
/** Event emitter fired when TOTP secret is generated. */
|
|
1852
|
+
onSubmit = new EventEmitter();
|
|
1853
|
+
displayNameLabel = injectTranslation("labels", "displayName");
|
|
1854
|
+
generateQrCodeLabel = injectTranslation("labels", "generateQrCode");
|
|
1855
|
+
form = injectForm({
|
|
1856
|
+
defaultValues: {
|
|
1857
|
+
displayName: "",
|
|
1858
|
+
},
|
|
1859
|
+
});
|
|
1860
|
+
state = injectStore(this.form, (state) => state);
|
|
1861
|
+
constructor() {
|
|
1862
|
+
effect(() => {
|
|
1863
|
+
this.form.update({
|
|
1864
|
+
validators: {
|
|
1865
|
+
onBlur: this.formSchema(),
|
|
1866
|
+
onSubmit: this.formSchema(),
|
|
1867
|
+
onSubmitAsync: async ({ value }) => {
|
|
1868
|
+
try {
|
|
1869
|
+
const secret = await generateTotpSecret(this.ui());
|
|
1870
|
+
this.onSubmit.emit({ secret, displayName: value.displayName });
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
catch (error) {
|
|
1874
|
+
return error instanceof FirebaseUIError ? error.message : String(error);
|
|
1875
|
+
}
|
|
1876
|
+
},
|
|
1877
|
+
},
|
|
1878
|
+
});
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
async handleSubmit(event) {
|
|
1882
|
+
event.preventDefault();
|
|
1883
|
+
event.stopPropagation();
|
|
1884
|
+
this.form.handleSubmit();
|
|
1885
|
+
}
|
|
1886
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: TotpMultiFactorSecretGenerationFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1887
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: TotpMultiFactorSecretGenerationFormComponent, isStandalone: true, selector: "fui-totp-multi-factor-secret-generation-form", outputs: { onSubmit: "onSubmit" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
1888
|
+
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
1889
|
+
<fieldset>
|
|
1890
|
+
<fui-form-input
|
|
1891
|
+
name="displayName"
|
|
1892
|
+
tanstack-app-field
|
|
1893
|
+
[tanstackField]="form"
|
|
1894
|
+
[label]="displayNameLabel()"
|
|
1895
|
+
type="text"
|
|
1896
|
+
></fui-form-input>
|
|
1897
|
+
</fieldset>
|
|
1898
|
+
<fieldset>
|
|
1899
|
+
<fui-form-submit [state]="state()">
|
|
1900
|
+
{{ generateQrCodeLabel() }}
|
|
1901
|
+
</fui-form-submit>
|
|
1902
|
+
<fui-form-error-message [state]="state()" />
|
|
1903
|
+
</fieldset>
|
|
1904
|
+
</form>
|
|
1905
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type", "description"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }] });
|
|
1906
|
+
}
|
|
1907
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: TotpMultiFactorSecretGenerationFormComponent, decorators: [{
|
|
1908
|
+
type: Component,
|
|
1909
|
+
args: [{
|
|
1910
|
+
selector: "fui-totp-multi-factor-secret-generation-form",
|
|
1911
|
+
standalone: true,
|
|
1912
|
+
host: {
|
|
1913
|
+
style: "display: block;",
|
|
1914
|
+
},
|
|
1915
|
+
imports: [
|
|
1916
|
+
CommonModule,
|
|
1917
|
+
TanStackField,
|
|
1918
|
+
TanStackAppField,
|
|
1919
|
+
FormInputComponent,
|
|
1920
|
+
FormSubmitComponent,
|
|
1921
|
+
FormErrorMessageComponent,
|
|
1922
|
+
],
|
|
1923
|
+
template: `
|
|
1924
|
+
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
1925
|
+
<fieldset>
|
|
1926
|
+
<fui-form-input
|
|
1927
|
+
name="displayName"
|
|
1928
|
+
tanstack-app-field
|
|
1929
|
+
[tanstackField]="form"
|
|
1930
|
+
[label]="displayNameLabel()"
|
|
1931
|
+
type="text"
|
|
1932
|
+
></fui-form-input>
|
|
1933
|
+
</fieldset>
|
|
1934
|
+
<fieldset>
|
|
1935
|
+
<fui-form-submit [state]="state()">
|
|
1936
|
+
{{ generateQrCodeLabel() }}
|
|
1937
|
+
</fui-form-submit>
|
|
1938
|
+
<fui-form-error-message [state]="state()" />
|
|
1939
|
+
</fieldset>
|
|
1940
|
+
</form>
|
|
1941
|
+
`,
|
|
1942
|
+
}]
|
|
1943
|
+
}], ctorParameters: () => [], propDecorators: { onSubmit: [{
|
|
1944
|
+
type: Output
|
|
1945
|
+
}] } });
|
|
1946
|
+
/**
|
|
1947
|
+
* A form component for verifying TOTP code during MFA enrollment.
|
|
1948
|
+
*
|
|
1949
|
+
* Displays a QR code and allows users to verify their authenticator app setup.
|
|
1950
|
+
*/
|
|
1951
|
+
class TotpMultiFactorVerificationFormComponent {
|
|
1952
|
+
ui = injectUI();
|
|
1953
|
+
formSchema = injectMultiFactorTotpAuthVerifyFormSchema();
|
|
1954
|
+
/** The TOTP secret generated in the previous step. */
|
|
1955
|
+
secret = input.required(...(ngDevMode ? [{ debugName: "secret" }] : []));
|
|
1956
|
+
/** The display name for the TOTP factor. */
|
|
1957
|
+
displayName = input.required(...(ngDevMode ? [{ debugName: "displayName" }] : []));
|
|
1958
|
+
/** Event emitter fired when MFA enrollment is completed. */
|
|
1959
|
+
onEnrollment = new EventEmitter();
|
|
1960
|
+
verificationCodeLabel = injectTranslation("labels", "verificationCode");
|
|
1961
|
+
verifyCodeLabel = injectTranslation("labels", "verifyCode");
|
|
1962
|
+
mfaTotpQrCodePrompt = injectTranslation("prompts", "mfaTotpQrCodePrompt");
|
|
1963
|
+
mfaTotpEnrollmentVerificationPrompt = injectTranslation("prompts", "mfaTotpEnrollmentVerificationPrompt");
|
|
1964
|
+
form = injectForm({
|
|
1965
|
+
defaultValues: {
|
|
1966
|
+
verificationCode: "",
|
|
1967
|
+
},
|
|
1968
|
+
});
|
|
1969
|
+
state = injectStore(this.form, (state) => state);
|
|
1970
|
+
qrCodeDataUrl = computed(() => {
|
|
1971
|
+
return generateTotpQrCode(this.ui(), this.secret(), this.displayName());
|
|
1972
|
+
}, ...(ngDevMode ? [{ debugName: "qrCodeDataUrl" }] : []));
|
|
1973
|
+
constructor() {
|
|
1974
|
+
effect(() => {
|
|
1975
|
+
this.form.update({
|
|
1976
|
+
validators: {
|
|
1977
|
+
onBlur: this.formSchema(),
|
|
1978
|
+
onSubmit: this.formSchema(),
|
|
1979
|
+
onSubmitAsync: async ({ value }) => {
|
|
1980
|
+
try {
|
|
1981
|
+
const assertion = TotpMultiFactorGenerator.assertionForEnrollment(this.secret(), value.verificationCode);
|
|
1982
|
+
await enrollWithMultiFactorAssertion(this.ui(), assertion, this.displayName());
|
|
1983
|
+
this.onEnrollment.emit();
|
|
1984
|
+
return;
|
|
1985
|
+
}
|
|
1986
|
+
catch (error) {
|
|
1987
|
+
return error instanceof FirebaseUIError ? error.message : String(error);
|
|
1988
|
+
}
|
|
1989
|
+
},
|
|
1990
|
+
},
|
|
1991
|
+
});
|
|
1992
|
+
});
|
|
1993
|
+
}
|
|
1994
|
+
async handleSubmit(event) {
|
|
1995
|
+
event.preventDefault();
|
|
1996
|
+
event.stopPropagation();
|
|
1997
|
+
this.form.handleSubmit();
|
|
1998
|
+
}
|
|
1999
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: TotpMultiFactorVerificationFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2000
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: TotpMultiFactorVerificationFormComponent, isStandalone: true, selector: "fui-totp-multi-factor-verification-form", inputs: { secret: { classPropertyName: "secret", publicName: "secret", isSignal: true, isRequired: true, transformFunction: null }, displayName: { classPropertyName: "displayName", publicName: "displayName", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onEnrollment: "onEnrollment" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
2001
|
+
<div class="fui-qr-code-container">
|
|
2002
|
+
<img [src]="qrCodeDataUrl()" alt="TOTP QR Code" />
|
|
2003
|
+
<code>{{ secret().secretKey.toString() }}</code>
|
|
2004
|
+
<p>{{ mfaTotpQrCodePrompt() }}</p>
|
|
2005
|
+
</div>
|
|
2006
|
+
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
2007
|
+
<fieldset>
|
|
2008
|
+
<fui-form-input
|
|
2009
|
+
name="verificationCode"
|
|
2010
|
+
tanstack-app-field
|
|
2011
|
+
[tanstackField]="form"
|
|
2012
|
+
[label]="verificationCodeLabel()"
|
|
2013
|
+
[description]="mfaTotpEnrollmentVerificationPrompt()"
|
|
2014
|
+
type="text"
|
|
2015
|
+
></fui-form-input>
|
|
2016
|
+
</fieldset>
|
|
2017
|
+
<fieldset>
|
|
2018
|
+
<fui-form-submit [state]="state()">
|
|
2019
|
+
{{ verifyCodeLabel() }}
|
|
2020
|
+
</fui-form-submit>
|
|
2021
|
+
<fui-form-error-message [state]="state()" />
|
|
2022
|
+
</fieldset>
|
|
2023
|
+
</form>
|
|
2024
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type", "description"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }] });
|
|
2025
|
+
}
|
|
2026
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: TotpMultiFactorVerificationFormComponent, decorators: [{
|
|
2027
|
+
type: Component,
|
|
2028
|
+
args: [{
|
|
2029
|
+
selector: "fui-totp-multi-factor-verification-form",
|
|
2030
|
+
standalone: true,
|
|
2031
|
+
host: {
|
|
2032
|
+
style: "display: block;",
|
|
2033
|
+
},
|
|
2034
|
+
imports: [
|
|
2035
|
+
CommonModule,
|
|
2036
|
+
TanStackField,
|
|
2037
|
+
TanStackAppField,
|
|
2038
|
+
FormInputComponent,
|
|
2039
|
+
FormSubmitComponent,
|
|
2040
|
+
FormErrorMessageComponent,
|
|
2041
|
+
],
|
|
2042
|
+
template: `
|
|
2043
|
+
<div class="fui-qr-code-container">
|
|
2044
|
+
<img [src]="qrCodeDataUrl()" alt="TOTP QR Code" />
|
|
2045
|
+
<code>{{ secret().secretKey.toString() }}</code>
|
|
2046
|
+
<p>{{ mfaTotpQrCodePrompt() }}</p>
|
|
2047
|
+
</div>
|
|
2048
|
+
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
2049
|
+
<fieldset>
|
|
2050
|
+
<fui-form-input
|
|
2051
|
+
name="verificationCode"
|
|
2052
|
+
tanstack-app-field
|
|
2053
|
+
[tanstackField]="form"
|
|
2054
|
+
[label]="verificationCodeLabel()"
|
|
2055
|
+
[description]="mfaTotpEnrollmentVerificationPrompt()"
|
|
2056
|
+
type="text"
|
|
2057
|
+
></fui-form-input>
|
|
2058
|
+
</fieldset>
|
|
2059
|
+
<fieldset>
|
|
2060
|
+
<fui-form-submit [state]="state()">
|
|
2061
|
+
{{ verifyCodeLabel() }}
|
|
2062
|
+
</fui-form-submit>
|
|
2063
|
+
<fui-form-error-message [state]="state()" />
|
|
2064
|
+
</fieldset>
|
|
2065
|
+
</form>
|
|
2066
|
+
`,
|
|
2067
|
+
}]
|
|
2068
|
+
}], ctorParameters: () => [], propDecorators: { secret: [{ type: i0.Input, args: [{ isSignal: true, alias: "secret", required: true }] }], displayName: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayName", required: true }] }], onEnrollment: [{
|
|
2069
|
+
type: Output
|
|
2070
|
+
}] } });
|
|
2071
|
+
/**
|
|
2072
|
+
* A form component for TOTP multi-factor authentication enrollment.
|
|
2073
|
+
*
|
|
2074
|
+
* Manages the flow between secret generation and verification for TOTP MFA enrollment.
|
|
2075
|
+
*/
|
|
2076
|
+
class TotpMultiFactorEnrollmentFormComponent {
|
|
2077
|
+
ui = injectUI();
|
|
2078
|
+
enrollment = signal(null, ...(ngDevMode ? [{ debugName: "enrollment" }] : []));
|
|
2079
|
+
/** Event emitter fired when MFA enrollment is completed. */
|
|
2080
|
+
onEnrollment = new EventEmitter();
|
|
2081
|
+
constructor() {
|
|
2082
|
+
if (!this.ui().auth.currentUser) {
|
|
2083
|
+
throw new Error("User must be authenticated to enroll with multi-factor authentication");
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
handleSecretGeneration(data) {
|
|
2087
|
+
this.enrollment.set(data);
|
|
2088
|
+
}
|
|
2089
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: TotpMultiFactorEnrollmentFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2090
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: TotpMultiFactorEnrollmentFormComponent, isStandalone: true, selector: "fui-totp-multi-factor-enrollment-form", outputs: { onEnrollment: "onEnrollment" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
2091
|
+
<div class="fui-form-container">
|
|
2092
|
+
@if (!enrollment()) {
|
|
2093
|
+
<fui-totp-multi-factor-secret-generation-form (onSubmit)="handleSecretGeneration($event)" />
|
|
2094
|
+
} @else {
|
|
2095
|
+
<fui-totp-multi-factor-verification-form
|
|
2096
|
+
[secret]="enrollment()!.secret"
|
|
2097
|
+
[displayName]="enrollment()!.displayName"
|
|
2098
|
+
(onEnrollment)="onEnrollment.emit()"
|
|
2099
|
+
/>
|
|
2100
|
+
}
|
|
2101
|
+
</div>
|
|
2102
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: TotpMultiFactorSecretGenerationFormComponent, selector: "fui-totp-multi-factor-secret-generation-form", outputs: ["onSubmit"] }, { kind: "component", type: TotpMultiFactorVerificationFormComponent, selector: "fui-totp-multi-factor-verification-form", inputs: ["secret", "displayName"], outputs: ["onEnrollment"] }] });
|
|
2103
|
+
}
|
|
2104
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: TotpMultiFactorEnrollmentFormComponent, decorators: [{
|
|
2105
|
+
type: Component,
|
|
2106
|
+
args: [{
|
|
2107
|
+
selector: "fui-totp-multi-factor-enrollment-form",
|
|
2108
|
+
standalone: true,
|
|
2109
|
+
imports: [CommonModule, TotpMultiFactorSecretGenerationFormComponent, TotpMultiFactorVerificationFormComponent],
|
|
2110
|
+
host: {
|
|
2111
|
+
style: "display: block;",
|
|
2112
|
+
},
|
|
2113
|
+
template: `
|
|
2114
|
+
<div class="fui-form-container">
|
|
2115
|
+
@if (!enrollment()) {
|
|
2116
|
+
<fui-totp-multi-factor-secret-generation-form (onSubmit)="handleSecretGeneration($event)" />
|
|
2117
|
+
} @else {
|
|
2118
|
+
<fui-totp-multi-factor-verification-form
|
|
2119
|
+
[secret]="enrollment()!.secret"
|
|
2120
|
+
[displayName]="enrollment()!.displayName"
|
|
2121
|
+
(onEnrollment)="onEnrollment.emit()"
|
|
2122
|
+
/>
|
|
2123
|
+
}
|
|
2124
|
+
</div>
|
|
2125
|
+
`,
|
|
2126
|
+
}]
|
|
2127
|
+
}], ctorParameters: () => [], propDecorators: { onEnrollment: [{
|
|
2128
|
+
type: Output
|
|
2129
|
+
}] } });
|
|
2130
|
+
|
|
2131
|
+
/**
|
|
2132
|
+
* Copyright 2025 Google LLC
|
|
2133
|
+
*
|
|
2134
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
2135
|
+
* you may not use this file except in compliance with the License.
|
|
2136
|
+
* You may obtain a copy of the License at
|
|
2137
|
+
*
|
|
2138
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
2139
|
+
*
|
|
2140
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
2141
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
2142
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
2143
|
+
* See the License for the specific language governing permissions and
|
|
2144
|
+
* limitations under the License.
|
|
2145
|
+
*/
|
|
2146
|
+
/**
|
|
2147
|
+
* A form component for multi-factor authentication enrollment.
|
|
2148
|
+
*
|
|
2149
|
+
* Allows users to enroll in MFA using SMS or TOTP methods.
|
|
2150
|
+
*/
|
|
2151
|
+
class MultiFactorAuthEnrollmentFormComponent {
|
|
2152
|
+
/** The available MFA factor types for enrollment. */
|
|
2153
|
+
hints = input([FactorId.TOTP, FactorId.PHONE], ...(ngDevMode ? [{ debugName: "hints" }] : []));
|
|
2154
|
+
/** Event emitter fired when MFA enrollment is completed. */
|
|
2155
|
+
onEnrollment = new EventEmitter();
|
|
2156
|
+
selectedHint = signal(undefined, ...(ngDevMode ? [{ debugName: "selectedHint" }] : []));
|
|
2157
|
+
phoneFactorId = FactorId.PHONE;
|
|
2158
|
+
totpFactorId = FactorId.TOTP;
|
|
2159
|
+
smsVerificationLabel = injectTranslation("labels", "mfaSmsVerification");
|
|
2160
|
+
totpVerificationLabel = injectTranslation("labels", "mfaTotpVerification");
|
|
2161
|
+
validatedHint = computed(() => {
|
|
2162
|
+
const hint = this.selectedHint();
|
|
2163
|
+
if (hint && hint !== this.phoneFactorId && hint !== this.totpFactorId) {
|
|
2164
|
+
throw new Error(`Unknown multi-factor enrollment type: ${hint}`);
|
|
2165
|
+
}
|
|
2166
|
+
return hint;
|
|
2167
|
+
}, ...(ngDevMode ? [{ debugName: "validatedHint" }] : []));
|
|
2168
|
+
ngOnInit() {
|
|
2169
|
+
const hints = this.hints();
|
|
2170
|
+
if (hints.length === 0) {
|
|
2171
|
+
throw new Error("MultiFactorAuthEnrollmentForm must have at least one hint");
|
|
2172
|
+
}
|
|
2173
|
+
// Auto-select single hint after component initialization
|
|
2174
|
+
if (hints.length === 1) {
|
|
2175
|
+
this.selectedHint.set(hints[0]);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
selectHint(hint) {
|
|
2179
|
+
this.selectedHint.set(hint);
|
|
2180
|
+
}
|
|
2181
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MultiFactorAuthEnrollmentFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2182
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: MultiFactorAuthEnrollmentFormComponent, isStandalone: true, selector: "fui-multi-factor-auth-enrollment-form", inputs: { hints: { classPropertyName: "hints", publicName: "hints", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onEnrollment: "onEnrollment" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
2183
|
+
<div class="fui-content">
|
|
2184
|
+
@if (validatedHint()) {
|
|
2185
|
+
@if (validatedHint() === phoneFactorId) {
|
|
2186
|
+
<fui-sms-multi-factor-enrollment-form (onEnrollment)="onEnrollment.emit()" />
|
|
2187
|
+
} @else if (validatedHint() === totpFactorId) {
|
|
2188
|
+
<fui-totp-multi-factor-enrollment-form (onEnrollment)="onEnrollment.emit()" />
|
|
2189
|
+
}
|
|
2190
|
+
} @else {
|
|
2191
|
+
@for (hint of hints(); track hint) {
|
|
2192
|
+
@if (hint === totpFactorId) {
|
|
2193
|
+
<button fui-button [variant]="'secondary'" (click)="selectHint(hint)">
|
|
2194
|
+
{{ totpVerificationLabel() }}
|
|
2195
|
+
</button>
|
|
2196
|
+
} @else if (hint === phoneFactorId) {
|
|
2197
|
+
<button fui-button [variant]="'secondary'" (click)="selectHint(hint)">
|
|
2198
|
+
{{ smsVerificationLabel() }}
|
|
2199
|
+
</button>
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
</div>
|
|
2204
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: SmsMultiFactorEnrollmentFormComponent, selector: "fui-sms-multi-factor-enrollment-form", outputs: ["onEnrollment"] }, { kind: "component", type: TotpMultiFactorEnrollmentFormComponent, selector: "fui-totp-multi-factor-enrollment-form", outputs: ["onEnrollment"] }, { kind: "component", type: ButtonComponent, selector: "button[fui-button]", inputs: ["variant"] }] });
|
|
2205
|
+
}
|
|
2206
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MultiFactorAuthEnrollmentFormComponent, decorators: [{
|
|
2207
|
+
type: Component,
|
|
2208
|
+
args: [{
|
|
2209
|
+
selector: "fui-multi-factor-auth-enrollment-form",
|
|
2210
|
+
standalone: true,
|
|
2211
|
+
host: {
|
|
2212
|
+
style: "display: block;",
|
|
2213
|
+
},
|
|
2214
|
+
imports: [
|
|
2215
|
+
CommonModule,
|
|
2216
|
+
SmsMultiFactorEnrollmentFormComponent,
|
|
2217
|
+
TotpMultiFactorEnrollmentFormComponent,
|
|
2218
|
+
ButtonComponent,
|
|
2219
|
+
],
|
|
2220
|
+
template: `
|
|
2221
|
+
<div class="fui-content">
|
|
2222
|
+
@if (validatedHint()) {
|
|
2223
|
+
@if (validatedHint() === phoneFactorId) {
|
|
2224
|
+
<fui-sms-multi-factor-enrollment-form (onEnrollment)="onEnrollment.emit()" />
|
|
2225
|
+
} @else if (validatedHint() === totpFactorId) {
|
|
2226
|
+
<fui-totp-multi-factor-enrollment-form (onEnrollment)="onEnrollment.emit()" />
|
|
2227
|
+
}
|
|
2228
|
+
} @else {
|
|
2229
|
+
@for (hint of hints(); track hint) {
|
|
2230
|
+
@if (hint === totpFactorId) {
|
|
2231
|
+
<button fui-button [variant]="'secondary'" (click)="selectHint(hint)">
|
|
2232
|
+
{{ totpVerificationLabel() }}
|
|
2233
|
+
</button>
|
|
2234
|
+
} @else if (hint === phoneFactorId) {
|
|
2235
|
+
<button fui-button [variant]="'secondary'" (click)="selectHint(hint)">
|
|
2236
|
+
{{ smsVerificationLabel() }}
|
|
2237
|
+
</button>
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
</div>
|
|
2242
|
+
`,
|
|
2243
|
+
}]
|
|
2244
|
+
}], propDecorators: { hints: [{ type: i0.Input, args: [{ isSignal: true, alias: "hints", required: false }] }], onEnrollment: [{
|
|
2245
|
+
type: Output
|
|
2246
|
+
}] } });
|
|
2247
|
+
|
|
2248
|
+
/**
|
|
2249
|
+
* Copyright 2025 Google LLC
|
|
2250
|
+
*
|
|
2251
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
2252
|
+
* you may not use this file except in compliance with the License.
|
|
2253
|
+
* You may obtain a copy of the License at
|
|
2254
|
+
*
|
|
2255
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
2256
|
+
*
|
|
2257
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
2258
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
2259
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
2260
|
+
* See the License for the specific language governing permissions and
|
|
2261
|
+
* limitations under the License.
|
|
2262
|
+
*/
|
|
2263
|
+
/**
|
|
2264
|
+
* A form component for entering a phone number and requesting a verification code.
|
|
2265
|
+
*/
|
|
2266
|
+
class PhoneNumberFormComponent {
|
|
2267
|
+
ui = injectUI();
|
|
2268
|
+
formSchema = injectPhoneAuthFormSchema();
|
|
2269
|
+
/** Event emitter fired when phone number is verified and verification ID is received. */
|
|
2270
|
+
onSubmit = new EventEmitter();
|
|
2271
|
+
/** The selected country code for phone number formatting. */
|
|
2272
|
+
country = signal(countryData[0].code, ...(ngDevMode ? [{ debugName: "country" }] : []));
|
|
2273
|
+
phoneNumberLabel = injectTranslation("labels", "phoneNumber");
|
|
2274
|
+
sendCodeLabel = injectTranslation("labels", "sendCode");
|
|
2275
|
+
unknownErrorLabel = injectTranslation("errors", "unknownError");
|
|
2276
|
+
recaptchaContainer = viewChild.required("recaptchaContainer");
|
|
2277
|
+
recaptchaVerifier = injectRecaptchaVerifier(() => this.recaptchaContainer());
|
|
2278
|
+
form = injectForm({
|
|
2279
|
+
defaultValues: {
|
|
2280
|
+
phoneNumber: "",
|
|
2281
|
+
},
|
|
2282
|
+
});
|
|
2283
|
+
state = injectStore(this.form, (state) => state);
|
|
2284
|
+
constructor() {
|
|
2285
|
+
effect(() => {
|
|
2286
|
+
this.form.update({
|
|
2287
|
+
validators: {
|
|
2288
|
+
onBlur: this.formSchema(),
|
|
2289
|
+
onSubmitAsync: async ({ value }) => {
|
|
2290
|
+
const selectedCountry = countryData.find((c) => c.code === this.country());
|
|
2291
|
+
const formattedNumber = formatPhoneNumber(value.phoneNumber, selectedCountry);
|
|
2292
|
+
try {
|
|
2293
|
+
const verifier = this.recaptchaVerifier();
|
|
2294
|
+
if (!verifier) {
|
|
2295
|
+
return this.unknownErrorLabel();
|
|
2296
|
+
}
|
|
2297
|
+
const verificationId = await verifyPhoneNumber(this.ui(), formattedNumber, verifier);
|
|
2298
|
+
this.onSubmit.emit({ verificationId, phoneNumber: formattedNumber });
|
|
2299
|
+
return;
|
|
2300
|
+
}
|
|
2301
|
+
catch (error) {
|
|
2302
|
+
if (error instanceof FirebaseUIError) {
|
|
1339
2303
|
return error.message;
|
|
1340
2304
|
}
|
|
1341
2305
|
return this.unknownErrorLabel();
|
|
@@ -1359,16 +2323,18 @@ class PhoneNumberFormComponent {
|
|
|
1359
2323
|
this.form.handleSubmit();
|
|
1360
2324
|
}
|
|
1361
2325
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: PhoneNumberFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1362
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.7", type: PhoneNumberFormComponent, isStandalone: true, selector: "fui-phone-number-form", outputs: { onSubmit: "onSubmit" }, viewQueries: [{ propertyName: "recaptchaContainer", first: true, predicate: ["recaptchaContainer"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
2326
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.7", type: PhoneNumberFormComponent, isStandalone: true, selector: "fui-phone-number-form", outputs: { onSubmit: "onSubmit" }, host: { styleAttribute: "display: block;" }, viewQueries: [{ propertyName: "recaptchaContainer", first: true, predicate: ["recaptchaContainer"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1363
2327
|
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
1364
2328
|
<fieldset>
|
|
1365
|
-
<fui-country-selector [(value)]="country"></fui-country-selector>
|
|
1366
2329
|
<fui-form-input
|
|
1367
2330
|
name="phoneNumber"
|
|
1368
2331
|
tanstack-app-field
|
|
1369
2332
|
[tanstackField]="form"
|
|
1370
|
-
label="
|
|
1371
|
-
|
|
2333
|
+
[label]="phoneNumberLabel()"
|
|
2334
|
+
type="tel"
|
|
2335
|
+
>
|
|
2336
|
+
<fui-country-selector [(value)]="country" ngProjectAs="input-before" />
|
|
2337
|
+
</fui-form-input>
|
|
1372
2338
|
</fieldset>
|
|
1373
2339
|
<fieldset>
|
|
1374
2340
|
<div class="fui-recaptcha-container" #recaptchaContainer></div>
|
|
@@ -1381,13 +2347,16 @@ class PhoneNumberFormComponent {
|
|
|
1381
2347
|
<fui-form-error-message [state]="state()" />
|
|
1382
2348
|
</fieldset>
|
|
1383
2349
|
</form>
|
|
1384
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }, { kind: "component", type: CountrySelectorComponent, selector: "fui-country-selector", inputs: ["value"], outputs: ["valueChange"] }] });
|
|
2350
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type", "description"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }, { kind: "component", type: CountrySelectorComponent, selector: "fui-country-selector", inputs: ["value"], outputs: ["valueChange"] }] });
|
|
1385
2351
|
}
|
|
1386
2352
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: PhoneNumberFormComponent, decorators: [{
|
|
1387
2353
|
type: Component,
|
|
1388
2354
|
args: [{
|
|
1389
2355
|
selector: "fui-phone-number-form",
|
|
1390
2356
|
standalone: true,
|
|
2357
|
+
host: {
|
|
2358
|
+
style: "display: block;",
|
|
2359
|
+
},
|
|
1391
2360
|
imports: [
|
|
1392
2361
|
CommonModule,
|
|
1393
2362
|
TanStackField,
|
|
@@ -1401,13 +2370,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1401
2370
|
template: `
|
|
1402
2371
|
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
1403
2372
|
<fieldset>
|
|
1404
|
-
<fui-country-selector [(value)]="country"></fui-country-selector>
|
|
1405
2373
|
<fui-form-input
|
|
1406
2374
|
name="phoneNumber"
|
|
1407
2375
|
tanstack-app-field
|
|
1408
2376
|
[tanstackField]="form"
|
|
1409
|
-
label="
|
|
1410
|
-
|
|
2377
|
+
[label]="phoneNumberLabel()"
|
|
2378
|
+
type="tel"
|
|
2379
|
+
>
|
|
2380
|
+
<fui-country-selector [(value)]="country" ngProjectAs="input-before" />
|
|
2381
|
+
</fui-form-input>
|
|
1411
2382
|
</fieldset>
|
|
1412
2383
|
<fieldset>
|
|
1413
2384
|
<div class="fui-recaptcha-container" #recaptchaContainer></div>
|
|
@@ -1422,14 +2393,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1422
2393
|
</form>
|
|
1423
2394
|
`,
|
|
1424
2395
|
}]
|
|
1425
|
-
}], ctorParameters: () => [], propDecorators: { onSubmit: [{
|
|
2396
|
+
}], ctorParameters: () => [], propDecorators: { onSubmit: [{
|
|
2397
|
+
type: Output
|
|
2398
|
+
}], recaptchaContainer: [{ type: i0.ViewChild, args: ["recaptchaContainer", { isSignal: true }] }] } });
|
|
2399
|
+
/**
|
|
2400
|
+
* A form component for entering and verifying the SMS verification code.
|
|
2401
|
+
*/
|
|
1426
2402
|
class VerificationFormComponent {
|
|
1427
2403
|
ui = injectUI();
|
|
1428
2404
|
formSchema = injectPhoneAuthVerifyFormSchema();
|
|
2405
|
+
/** The verification ID received from the phone number form. */
|
|
1429
2406
|
verificationId = input.required(...(ngDevMode ? [{ debugName: "verificationId" }] : []));
|
|
1430
|
-
|
|
2407
|
+
/** Event emitter for successful sign-in. */
|
|
2408
|
+
signIn = new EventEmitter();
|
|
1431
2409
|
verificationCodeLabel = injectTranslation("labels", "verificationCode");
|
|
1432
2410
|
verifyCodeLabel = injectTranslation("labels", "verifyCode");
|
|
2411
|
+
smsVerificationPrompt = injectTranslation("prompts", "smsVerificationPrompt");
|
|
1433
2412
|
unknownErrorLabel = injectTranslation("errors", "unknownError");
|
|
1434
2413
|
form = injectForm({
|
|
1435
2414
|
defaultValues: {
|
|
@@ -1446,7 +2425,6 @@ class VerificationFormComponent {
|
|
|
1446
2425
|
this.form.update({
|
|
1447
2426
|
validators: {
|
|
1448
2427
|
onBlur: this.formSchema(),
|
|
1449
|
-
onSubmit: this.formSchema(),
|
|
1450
2428
|
onSubmitAsync: async ({ value }) => {
|
|
1451
2429
|
try {
|
|
1452
2430
|
const credential = await confirmPhoneNumber(this.ui(), this.verificationId(), value.verificationCode);
|
|
@@ -1470,14 +2448,16 @@ class VerificationFormComponent {
|
|
|
1470
2448
|
this.form.handleSubmit();
|
|
1471
2449
|
}
|
|
1472
2450
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: VerificationFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1473
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: VerificationFormComponent, isStandalone: true, selector: "fui-verification-form", inputs: { verificationId: { classPropertyName: "verificationId", publicName: "verificationId", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { signIn: "signIn" }, ngImport: i0, template: `
|
|
2451
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: VerificationFormComponent, isStandalone: true, selector: "fui-verification-form", inputs: { verificationId: { classPropertyName: "verificationId", publicName: "verificationId", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
1474
2452
|
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
1475
2453
|
<fieldset>
|
|
1476
2454
|
<fui-form-input
|
|
1477
2455
|
name="verificationCode"
|
|
1478
2456
|
tanstack-app-field
|
|
1479
2457
|
[tanstackField]="form"
|
|
1480
|
-
label="
|
|
2458
|
+
[label]="verificationCodeLabel()"
|
|
2459
|
+
[description]="smsVerificationPrompt()"
|
|
2460
|
+
type="text"
|
|
1481
2461
|
></fui-form-input>
|
|
1482
2462
|
</fieldset>
|
|
1483
2463
|
|
|
@@ -1490,13 +2470,16 @@ class VerificationFormComponent {
|
|
|
1490
2470
|
<fui-form-error-message [state]="state()" />
|
|
1491
2471
|
</fieldset>
|
|
1492
2472
|
</form>
|
|
1493
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }] });
|
|
2473
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type", "description"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }] });
|
|
1494
2474
|
}
|
|
1495
2475
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: VerificationFormComponent, decorators: [{
|
|
1496
2476
|
type: Component,
|
|
1497
2477
|
args: [{
|
|
1498
2478
|
selector: "fui-verification-form",
|
|
1499
2479
|
standalone: true,
|
|
2480
|
+
host: {
|
|
2481
|
+
style: "display: block;",
|
|
2482
|
+
},
|
|
1500
2483
|
imports: [
|
|
1501
2484
|
CommonModule,
|
|
1502
2485
|
TanStackField,
|
|
@@ -1513,7 +2496,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1513
2496
|
name="verificationCode"
|
|
1514
2497
|
tanstack-app-field
|
|
1515
2498
|
[tanstackField]="form"
|
|
1516
|
-
label="
|
|
2499
|
+
[label]="verificationCodeLabel()"
|
|
2500
|
+
[description]="smsVerificationPrompt()"
|
|
2501
|
+
type="text"
|
|
1517
2502
|
></fui-form-input>
|
|
1518
2503
|
</fieldset>
|
|
1519
2504
|
|
|
@@ -1528,15 +2513,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1528
2513
|
</form>
|
|
1529
2514
|
`,
|
|
1530
2515
|
}]
|
|
1531
|
-
}], ctorParameters: () => [], propDecorators: { verificationId: [{ type: i0.Input, args: [{ isSignal: true, alias: "verificationId", required: true }] }], signIn: [{
|
|
2516
|
+
}], ctorParameters: () => [], propDecorators: { verificationId: [{ type: i0.Input, args: [{ isSignal: true, alias: "verificationId", required: true }] }], signIn: [{
|
|
2517
|
+
type: Output
|
|
2518
|
+
}] } });
|
|
2519
|
+
/**
|
|
2520
|
+
* A form component for phone number authentication.
|
|
2521
|
+
*
|
|
2522
|
+
* Manages the flow between phone number entry and verification code entry.
|
|
2523
|
+
*/
|
|
1532
2524
|
class PhoneAuthFormComponent {
|
|
1533
2525
|
verificationId = signal(null, ...(ngDevMode ? [{ debugName: "verificationId" }] : []));
|
|
1534
|
-
|
|
2526
|
+
/** Event emitter for successful sign-in. */
|
|
2527
|
+
signIn = new EventEmitter();
|
|
1535
2528
|
handlePhoneSubmit(data) {
|
|
1536
2529
|
this.verificationId.set(data.verificationId);
|
|
1537
2530
|
}
|
|
1538
2531
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: PhoneAuthFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1539
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: PhoneAuthFormComponent, isStandalone: true, selector: "fui-phone-auth-form", outputs: { signIn: "signIn" }, ngImport: i0, template: `
|
|
2532
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: PhoneAuthFormComponent, isStandalone: true, selector: "fui-phone-auth-form", outputs: { signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
1540
2533
|
<div class="fui-form-container">
|
|
1541
2534
|
@if (verificationId()) {
|
|
1542
2535
|
<fui-verification-form [verificationId]="verificationId()!" (signIn)="signIn.emit($event)" />
|
|
@@ -1552,6 +2545,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1552
2545
|
selector: "fui-phone-auth-form",
|
|
1553
2546
|
standalone: true,
|
|
1554
2547
|
imports: [CommonModule, PhoneNumberFormComponent, VerificationFormComponent],
|
|
2548
|
+
host: {
|
|
2549
|
+
style: "display: block;",
|
|
2550
|
+
},
|
|
1555
2551
|
template: `
|
|
1556
2552
|
<div class="fui-form-container">
|
|
1557
2553
|
@if (verificationId()) {
|
|
@@ -1562,7 +2558,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1562
2558
|
</div>
|
|
1563
2559
|
`,
|
|
1564
2560
|
}]
|
|
1565
|
-
}], propDecorators: { signIn: [{
|
|
2561
|
+
}], propDecorators: { signIn: [{
|
|
2562
|
+
type: Output
|
|
2563
|
+
}] } });
|
|
1566
2564
|
|
|
1567
2565
|
/**
|
|
1568
2566
|
* Copyright 2025 Google LLC
|
|
@@ -1579,6 +2577,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1579
2577
|
* See the License for the specific language governing permissions and
|
|
1580
2578
|
* limitations under the License.
|
|
1581
2579
|
*/
|
|
2580
|
+
/**
|
|
2581
|
+
* A form component for signing in with email and password.
|
|
2582
|
+
*/
|
|
1582
2583
|
class SignInAuthFormComponent {
|
|
1583
2584
|
ui = injectUI();
|
|
1584
2585
|
formSchema = injectSignInAuthFormSchema();
|
|
@@ -1589,9 +2590,12 @@ class SignInAuthFormComponent {
|
|
|
1589
2590
|
noAccountLabel = injectTranslation("prompts", "noAccount");
|
|
1590
2591
|
signUpLabel = injectTranslation("labels", "signUp");
|
|
1591
2592
|
unknownErrorLabel = injectTranslation("errors", "unknownError");
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
2593
|
+
/** Event emitter for forgot password action. */
|
|
2594
|
+
forgotPassword = input(...(ngDevMode ? [undefined, { debugName: "forgotPassword" }] : []));
|
|
2595
|
+
/** Event emitter for sign up action. */
|
|
2596
|
+
signUp = input(...(ngDevMode ? [undefined, { debugName: "signUp" }] : []));
|
|
2597
|
+
/** Event emitter for successful sign-in. */
|
|
2598
|
+
signIn = new EventEmitter();
|
|
1595
2599
|
form = injectForm({
|
|
1596
2600
|
defaultValues: {
|
|
1597
2601
|
email: "",
|
|
@@ -1608,19 +2612,18 @@ class SignInAuthFormComponent {
|
|
|
1608
2612
|
effect(() => {
|
|
1609
2613
|
this.form.update({
|
|
1610
2614
|
validators: {
|
|
1611
|
-
onChange: this.formSchema(),
|
|
1612
2615
|
onBlur: this.formSchema(),
|
|
1613
|
-
onSubmit: this.formSchema(),
|
|
1614
2616
|
onSubmitAsync: async ({ value }) => {
|
|
1615
2617
|
try {
|
|
1616
2618
|
const credential = await signInWithEmailAndPassword(this.ui(), value.email, value.password);
|
|
1617
|
-
this.signIn
|
|
2619
|
+
this.signIn.emit(credential);
|
|
1618
2620
|
return;
|
|
1619
2621
|
}
|
|
1620
2622
|
catch (error) {
|
|
1621
2623
|
if (error instanceof FirebaseUIError) {
|
|
1622
2624
|
return error.message;
|
|
1623
2625
|
}
|
|
2626
|
+
console.error(error);
|
|
1624
2627
|
return this.unknownErrorLabel();
|
|
1625
2628
|
}
|
|
1626
2629
|
},
|
|
@@ -1629,14 +2632,15 @@ class SignInAuthFormComponent {
|
|
|
1629
2632
|
});
|
|
1630
2633
|
}
|
|
1631
2634
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SignInAuthFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1632
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SignInAuthFormComponent, isStandalone: true, selector: "fui-sign-in-auth-form",
|
|
2635
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SignInAuthFormComponent, isStandalone: true, selector: "fui-sign-in-auth-form", inputs: { forgotPassword: { classPropertyName: "forgotPassword", publicName: "forgotPassword", isSignal: true, isRequired: false, transformFunction: null }, signUp: { classPropertyName: "signUp", publicName: "signUp", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
1633
2636
|
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
1634
2637
|
<fieldset>
|
|
1635
2638
|
<fui-form-input
|
|
1636
2639
|
name="email"
|
|
1637
2640
|
tanstack-app-field
|
|
1638
2641
|
[tanstackField]="form"
|
|
1639
|
-
label="
|
|
2642
|
+
[label]="emailLabel()"
|
|
2643
|
+
type="email"
|
|
1640
2644
|
></fui-form-input>
|
|
1641
2645
|
</fieldset>
|
|
1642
2646
|
<fieldset>
|
|
@@ -1644,11 +2648,11 @@ class SignInAuthFormComponent {
|
|
|
1644
2648
|
name="password"
|
|
1645
2649
|
tanstack-app-field
|
|
1646
2650
|
[tanstackField]="form"
|
|
1647
|
-
label="
|
|
2651
|
+
[label]="passwordLabel()"
|
|
1648
2652
|
type="password"
|
|
1649
2653
|
>
|
|
1650
|
-
@if (forgotPassword) {
|
|
1651
|
-
<button ngProjectAs="input-action" fui-form-action (click)="forgotPassword
|
|
2654
|
+
@if (forgotPassword()?.observed) {
|
|
2655
|
+
<button ngProjectAs="input-action" fui-form-action (click)="forgotPassword()?.emit()">
|
|
1652
2656
|
{{ forgotPasswordLabel() }}
|
|
1653
2657
|
</button>
|
|
1654
2658
|
}
|
|
@@ -1664,17 +2668,20 @@ class SignInAuthFormComponent {
|
|
|
1664
2668
|
<fui-form-error-message [state]="state()" />
|
|
1665
2669
|
</fieldset>
|
|
1666
2670
|
|
|
1667
|
-
@if (signUp) {
|
|
1668
|
-
<button fui-form-action (click)="signUp
|
|
2671
|
+
@if (signUp()?.observed) {
|
|
2672
|
+
<button fui-form-action (click)="signUp()?.emit()">{{ noAccountLabel() }} {{ signUpLabel() }}</button>
|
|
1669
2673
|
}
|
|
1670
2674
|
</form>
|
|
1671
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }, { kind: "component", type: FormActionComponent, selector: "button[fui-form-action]" }] });
|
|
2675
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type", "description"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }, { kind: "component", type: FormActionComponent, selector: "button[fui-form-action]" }] });
|
|
1672
2676
|
}
|
|
1673
2677
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SignInAuthFormComponent, decorators: [{
|
|
1674
2678
|
type: Component,
|
|
1675
2679
|
args: [{
|
|
1676
2680
|
selector: "fui-sign-in-auth-form",
|
|
1677
2681
|
standalone: true,
|
|
2682
|
+
host: {
|
|
2683
|
+
style: "display: block;",
|
|
2684
|
+
},
|
|
1678
2685
|
imports: [
|
|
1679
2686
|
CommonModule,
|
|
1680
2687
|
TanStackField,
|
|
@@ -1692,7 +2699,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1692
2699
|
name="email"
|
|
1693
2700
|
tanstack-app-field
|
|
1694
2701
|
[tanstackField]="form"
|
|
1695
|
-
label="
|
|
2702
|
+
[label]="emailLabel()"
|
|
2703
|
+
type="email"
|
|
1696
2704
|
></fui-form-input>
|
|
1697
2705
|
</fieldset>
|
|
1698
2706
|
<fieldset>
|
|
@@ -1700,11 +2708,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1700
2708
|
name="password"
|
|
1701
2709
|
tanstack-app-field
|
|
1702
2710
|
[tanstackField]="form"
|
|
1703
|
-
label="
|
|
2711
|
+
[label]="passwordLabel()"
|
|
1704
2712
|
type="password"
|
|
1705
2713
|
>
|
|
1706
|
-
@if (forgotPassword) {
|
|
1707
|
-
<button ngProjectAs="input-action" fui-form-action (click)="forgotPassword
|
|
2714
|
+
@if (forgotPassword()?.observed) {
|
|
2715
|
+
<button ngProjectAs="input-action" fui-form-action (click)="forgotPassword()?.emit()">
|
|
1708
2716
|
{{ forgotPasswordLabel() }}
|
|
1709
2717
|
</button>
|
|
1710
2718
|
}
|
|
@@ -1720,13 +2728,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1720
2728
|
<fui-form-error-message [state]="state()" />
|
|
1721
2729
|
</fieldset>
|
|
1722
2730
|
|
|
1723
|
-
@if (signUp) {
|
|
1724
|
-
<button fui-form-action (click)="signUp
|
|
2731
|
+
@if (signUp()?.observed) {
|
|
2732
|
+
<button fui-form-action (click)="signUp()?.emit()">{{ noAccountLabel() }} {{ signUpLabel() }}</button>
|
|
1725
2733
|
}
|
|
1726
2734
|
</form>
|
|
1727
2735
|
`,
|
|
1728
2736
|
}]
|
|
1729
|
-
}], ctorParameters: () => [], propDecorators: { forgotPassword: [{ type: i0.
|
|
2737
|
+
}], ctorParameters: () => [], propDecorators: { forgotPassword: [{ type: i0.Input, args: [{ isSignal: true, alias: "forgotPassword", required: false }] }], signUp: [{ type: i0.Input, args: [{ isSignal: true, alias: "signUp", required: false }] }], signIn: [{
|
|
2738
|
+
type: Output
|
|
2739
|
+
}] } });
|
|
1730
2740
|
|
|
1731
2741
|
/**
|
|
1732
2742
|
* Copyright 2025 Google LLC
|
|
@@ -1743,6 +2753,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1743
2753
|
* See the License for the specific language governing permissions and
|
|
1744
2754
|
* limitations under the License.
|
|
1745
2755
|
*/
|
|
2756
|
+
/**
|
|
2757
|
+
* A form component for signing up with email and password.
|
|
2758
|
+
*
|
|
2759
|
+
* Optionally includes a display name field if the requireDisplayName behavior is enabled.
|
|
2760
|
+
*/
|
|
1746
2761
|
class SignUpAuthFormComponent {
|
|
1747
2762
|
ui = injectUI();
|
|
1748
2763
|
formSchema = injectSignUpAuthFormSchema();
|
|
@@ -1756,8 +2771,10 @@ class SignUpAuthFormComponent {
|
|
|
1756
2771
|
haveAccountLabel = injectTranslation("prompts", "haveAccount");
|
|
1757
2772
|
signInLabel = injectTranslation("labels", "signIn");
|
|
1758
2773
|
unknownErrorLabel = injectTranslation("errors", "unknownError");
|
|
1759
|
-
|
|
1760
|
-
signIn =
|
|
2774
|
+
/** Event emitter for sign in action. */
|
|
2775
|
+
signIn = input(...(ngDevMode ? [undefined, { debugName: "signIn" }] : []));
|
|
2776
|
+
/** Event emitter for successful sign-up. */
|
|
2777
|
+
signUp = new EventEmitter();
|
|
1761
2778
|
form = injectForm({
|
|
1762
2779
|
defaultValues: {
|
|
1763
2780
|
email: "",
|
|
@@ -1776,17 +2793,17 @@ class SignUpAuthFormComponent {
|
|
|
1776
2793
|
this.form.update({
|
|
1777
2794
|
validators: {
|
|
1778
2795
|
onBlur: this.formSchema(),
|
|
1779
|
-
onSubmit: this.formSchema(),
|
|
1780
2796
|
onSubmitAsync: async ({ value }) => {
|
|
1781
2797
|
try {
|
|
1782
2798
|
const credential = await createUserWithEmailAndPassword(this.ui(), value.email, value.password, value.displayName);
|
|
1783
|
-
this.signUp
|
|
2799
|
+
this.signUp.emit(credential);
|
|
1784
2800
|
return;
|
|
1785
2801
|
}
|
|
1786
2802
|
catch (error) {
|
|
1787
2803
|
if (error instanceof FirebaseUIError) {
|
|
1788
2804
|
return error.message;
|
|
1789
2805
|
}
|
|
2806
|
+
console.error(error);
|
|
1790
2807
|
return this.unknownErrorLabel();
|
|
1791
2808
|
}
|
|
1792
2809
|
},
|
|
@@ -1795,27 +2812,22 @@ class SignUpAuthFormComponent {
|
|
|
1795
2812
|
});
|
|
1796
2813
|
}
|
|
1797
2814
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SignUpAuthFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1798
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SignUpAuthFormComponent, isStandalone: true, selector: "fui-sign-up-auth-form", outputs: { signUp: "signUp",
|
|
2815
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SignUpAuthFormComponent, isStandalone: true, selector: "fui-sign-up-auth-form", inputs: { signIn: { classPropertyName: "signIn", publicName: "signIn", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { signUp: "signUp" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
1799
2816
|
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
1800
2817
|
@if (requireDisplayNameField()) {
|
|
1801
2818
|
<fieldset>
|
|
1802
|
-
<fui-form-input
|
|
1803
|
-
name="displayName"
|
|
1804
|
-
tanstack-app-field
|
|
1805
|
-
[tanstackField]="form"
|
|
1806
|
-
label="{{ displayNameLabel() }}"
|
|
1807
|
-
/>
|
|
2819
|
+
<fui-form-input name="displayName" tanstack-app-field [tanstackField]="form" [label]="displayNameLabel()" />
|
|
1808
2820
|
</fieldset>
|
|
1809
2821
|
}
|
|
1810
2822
|
<fieldset>
|
|
1811
|
-
<fui-form-input name="email" tanstack-app-field [tanstackField]="form" label="
|
|
2823
|
+
<fui-form-input name="email" tanstack-app-field [tanstackField]="form" [label]="emailLabel()" type="email" />
|
|
1812
2824
|
</fieldset>
|
|
1813
2825
|
<fieldset>
|
|
1814
2826
|
<fui-form-input
|
|
1815
2827
|
name="password"
|
|
1816
2828
|
tanstack-app-field
|
|
1817
2829
|
[tanstackField]="form"
|
|
1818
|
-
label="
|
|
2830
|
+
[label]="passwordLabel()"
|
|
1819
2831
|
type="password"
|
|
1820
2832
|
/>
|
|
1821
2833
|
</fieldset>
|
|
@@ -1827,16 +2839,20 @@ class SignUpAuthFormComponent {
|
|
|
1827
2839
|
<fui-form-error-message [state]="state()" />
|
|
1828
2840
|
</fieldset>
|
|
1829
2841
|
|
|
1830
|
-
@if (signIn) {
|
|
1831
|
-
<button fui-form-action (click)="signIn
|
|
2842
|
+
@if (signIn()?.observed) {
|
|
2843
|
+
<button fui-form-action (click)="signIn()?.emit()">{{ haveAccountLabel() }} {{ signInLabel() }}</button>
|
|
1832
2844
|
}
|
|
1833
2845
|
</form>
|
|
1834
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }, { kind: "component", type: FormActionComponent, selector: "button[fui-form-action]" }] });
|
|
2846
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TanStackField, selector: "[tanstackField]", inputs: ["name", "defaultValue", "asyncDebounceMs", "asyncAlways", "tanstackField", "validators", "listeners", "defaultMeta", "mode", "disableErrorFlat"], exportAs: ["field"] }, { kind: "directive", type: TanStackAppField, selector: "[tanstack-app-field]" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: FormInputComponent, selector: "fui-form-input", inputs: ["label", "type", "description"] }, { kind: "component", type: FormSubmitComponent, selector: "fui-form-submit", inputs: ["class", "state"] }, { kind: "component", type: FormErrorMessageComponent, selector: "fui-form-error-message", inputs: ["state"] }, { kind: "component", type: FormActionComponent, selector: "button[fui-form-action]" }] });
|
|
1835
2847
|
}
|
|
1836
2848
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SignUpAuthFormComponent, decorators: [{
|
|
1837
2849
|
type: Component,
|
|
1838
2850
|
args: [{
|
|
1839
2851
|
selector: "fui-sign-up-auth-form",
|
|
2852
|
+
standalone: true,
|
|
2853
|
+
host: {
|
|
2854
|
+
style: "display: block;",
|
|
2855
|
+
},
|
|
1840
2856
|
imports: [
|
|
1841
2857
|
CommonModule,
|
|
1842
2858
|
TanStackField,
|
|
@@ -1851,23 +2867,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1851
2867
|
<form (submit)="handleSubmit($event)" class="fui-form">
|
|
1852
2868
|
@if (requireDisplayNameField()) {
|
|
1853
2869
|
<fieldset>
|
|
1854
|
-
<fui-form-input
|
|
1855
|
-
name="displayName"
|
|
1856
|
-
tanstack-app-field
|
|
1857
|
-
[tanstackField]="form"
|
|
1858
|
-
label="{{ displayNameLabel() }}"
|
|
1859
|
-
/>
|
|
2870
|
+
<fui-form-input name="displayName" tanstack-app-field [tanstackField]="form" [label]="displayNameLabel()" />
|
|
1860
2871
|
</fieldset>
|
|
1861
2872
|
}
|
|
1862
2873
|
<fieldset>
|
|
1863
|
-
<fui-form-input name="email" tanstack-app-field [tanstackField]="form" label="
|
|
2874
|
+
<fui-form-input name="email" tanstack-app-field [tanstackField]="form" [label]="emailLabel()" type="email" />
|
|
1864
2875
|
</fieldset>
|
|
1865
2876
|
<fieldset>
|
|
1866
2877
|
<fui-form-input
|
|
1867
2878
|
name="password"
|
|
1868
2879
|
tanstack-app-field
|
|
1869
2880
|
[tanstackField]="form"
|
|
1870
|
-
label="
|
|
2881
|
+
[label]="passwordLabel()"
|
|
1871
2882
|
type="password"
|
|
1872
2883
|
/>
|
|
1873
2884
|
</fieldset>
|
|
@@ -1879,14 +2890,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1879
2890
|
<fui-form-error-message [state]="state()" />
|
|
1880
2891
|
</fieldset>
|
|
1881
2892
|
|
|
1882
|
-
@if (signIn) {
|
|
1883
|
-
<button fui-form-action (click)="signIn
|
|
2893
|
+
@if (signIn()?.observed) {
|
|
2894
|
+
<button fui-form-action (click)="signIn()?.emit()">{{ haveAccountLabel() }} {{ signInLabel() }}</button>
|
|
1884
2895
|
}
|
|
1885
2896
|
</form>
|
|
1886
2897
|
`,
|
|
1887
|
-
standalone: true,
|
|
1888
2898
|
}]
|
|
1889
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
2899
|
+
}], ctorParameters: () => [], propDecorators: { signIn: [{ type: i0.Input, args: [{ isSignal: true, alias: "signIn", required: false }] }], signUp: [{
|
|
2900
|
+
type: Output
|
|
2901
|
+
}] } });
|
|
1890
2902
|
|
|
1891
2903
|
/**
|
|
1892
2904
|
* Copyright 2025 Google LLC
|
|
@@ -1903,15 +2915,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1903
2915
|
* See the License for the specific language governing permissions and
|
|
1904
2916
|
* limitations under the License.
|
|
1905
2917
|
*/
|
|
2918
|
+
/**
|
|
2919
|
+
* A generic OAuth button component for signing in with any OAuth provider.
|
|
2920
|
+
*/
|
|
1906
2921
|
class OAuthButtonComponent {
|
|
1907
2922
|
ui = injectUI();
|
|
1908
|
-
|
|
2923
|
+
/** The OAuth provider to use for sign-in. */
|
|
1909
2924
|
provider = input.required(...(ngDevMode ? [{ debugName: "provider" }] : []));
|
|
1910
|
-
|
|
2925
|
+
/** Whether to use themed styling. */
|
|
2926
|
+
themed = input(...(ngDevMode ? [undefined, { debugName: "themed" }] : []));
|
|
2927
|
+
error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
2928
|
+
/** Event emitter for successful sign-in. */
|
|
2929
|
+
signIn = output();
|
|
2930
|
+
buttonVariant = computed(() => {
|
|
2931
|
+
return this.themed() ? "primary" : "secondary";
|
|
2932
|
+
}, ...(ngDevMode ? [{ debugName: "buttonVariant" }] : []));
|
|
1911
2933
|
async handleOAuthSignIn() {
|
|
1912
|
-
this.error.set(
|
|
2934
|
+
this.error.set(null);
|
|
1913
2935
|
try {
|
|
1914
|
-
await signInWithProvider(this.ui(), this.provider());
|
|
2936
|
+
const credential = await signInWithProvider(this.ui(), this.provider());
|
|
2937
|
+
this.signIn.emit(credential);
|
|
1915
2938
|
}
|
|
1916
2939
|
catch (error) {
|
|
1917
2940
|
if (error instanceof FirebaseUIError) {
|
|
@@ -1919,16 +2942,18 @@ class OAuthButtonComponent {
|
|
|
1919
2942
|
return;
|
|
1920
2943
|
}
|
|
1921
2944
|
console.error(error);
|
|
1922
|
-
this.error.set(this.
|
|
2945
|
+
this.error.set(getTranslation(this.ui(), "errors", "unknownError"));
|
|
1923
2946
|
}
|
|
1924
2947
|
}
|
|
1925
2948
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: OAuthButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1926
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: OAuthButtonComponent, isStandalone: true, selector: "fui-oauth-button", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
2949
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: OAuthButtonComponent, isStandalone: true, selector: "fui-oauth-button", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: true, transformFunction: null }, themed: { classPropertyName: "themed", publicName: "themed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
1927
2950
|
<div>
|
|
1928
2951
|
<button
|
|
1929
2952
|
fui-button
|
|
1930
2953
|
type="button"
|
|
1931
2954
|
(click)="handleOAuthSignIn()"
|
|
2955
|
+
[variant]="buttonVariant()"
|
|
2956
|
+
[attr.data-themed]="themed()"
|
|
1932
2957
|
[disabled]="ui().state !== 'idle'"
|
|
1933
2958
|
[attr.data-provider]="provider().providerId"
|
|
1934
2959
|
class="fui-provider__button"
|
|
@@ -1937,7 +2962,7 @@ class OAuthButtonComponent {
|
|
|
1937
2962
|
</button>
|
|
1938
2963
|
|
|
1939
2964
|
@if (error()) {
|
|
1940
|
-
<div class="fui-
|
|
2965
|
+
<div class="fui-error">{{ error() }}</div>
|
|
1941
2966
|
}
|
|
1942
2967
|
</div>
|
|
1943
2968
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ButtonComponent, selector: "button[fui-button]", inputs: ["variant"] }] });
|
|
@@ -1948,12 +2973,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1948
2973
|
selector: "fui-oauth-button",
|
|
1949
2974
|
standalone: true,
|
|
1950
2975
|
imports: [CommonModule, ButtonComponent],
|
|
2976
|
+
host: {
|
|
2977
|
+
style: "display: block;",
|
|
2978
|
+
},
|
|
1951
2979
|
template: `
|
|
1952
2980
|
<div>
|
|
1953
2981
|
<button
|
|
1954
2982
|
fui-button
|
|
1955
2983
|
type="button"
|
|
1956
2984
|
(click)="handleOAuthSignIn()"
|
|
2985
|
+
[variant]="buttonVariant()"
|
|
2986
|
+
[attr.data-themed]="themed()"
|
|
1957
2987
|
[disabled]="ui().state !== 'idle'"
|
|
1958
2988
|
[attr.data-provider]="provider().providerId"
|
|
1959
2989
|
class="fui-provider__button"
|
|
@@ -1962,12 +2992,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
1962
2992
|
</button>
|
|
1963
2993
|
|
|
1964
2994
|
@if (error()) {
|
|
1965
|
-
<div class="fui-
|
|
2995
|
+
<div class="fui-error">{{ error() }}</div>
|
|
1966
2996
|
}
|
|
1967
2997
|
</div>
|
|
1968
2998
|
`,
|
|
1969
2999
|
}]
|
|
1970
|
-
}], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: true }] }] } });
|
|
3000
|
+
}], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: true }] }], themed: [{ type: i0.Input, args: [{ isSignal: true, alias: "themed", required: false }] }], signIn: [{ type: i0.Output, args: ["signIn"] }] } });
|
|
1971
3001
|
|
|
1972
3002
|
/**
|
|
1973
3003
|
* Copyright 2025 Google LLC
|
|
@@ -2054,21 +3084,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2054
3084
|
* See the License for the specific language governing permissions and
|
|
2055
3085
|
* limitations under the License.
|
|
2056
3086
|
*/
|
|
3087
|
+
/**
|
|
3088
|
+
* A button component for signing in with Google.
|
|
3089
|
+
*/
|
|
2057
3090
|
class GoogleSignInButtonComponent {
|
|
2058
3091
|
ui = injectUI();
|
|
2059
3092
|
signInWithGoogleLabel = injectTranslation("labels", "signInWithGoogle");
|
|
3093
|
+
/** Whether to use themed styling. */
|
|
3094
|
+
themed = input(false, ...(ngDevMode ? [{ debugName: "themed" }] : []));
|
|
3095
|
+
/** Event emitter for successful sign-in. */
|
|
3096
|
+
signIn = output();
|
|
2060
3097
|
defaultProvider = new GoogleAuthProvider();
|
|
3098
|
+
/** Optional custom OAuth provider configuration. */
|
|
2061
3099
|
provider = input(...(ngDevMode ? [undefined, { debugName: "provider" }] : []));
|
|
2062
3100
|
get googleProvider() {
|
|
2063
3101
|
return this.provider() || this.defaultProvider;
|
|
2064
3102
|
}
|
|
2065
3103
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: GoogleSignInButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2066
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: GoogleSignInButtonComponent, isStandalone: true, selector: "fui-google-sign-in-button", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2067
|
-
<fui-oauth-button [provider]="googleProvider">
|
|
3104
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: GoogleSignInButtonComponent, isStandalone: true, selector: "fui-google-sign-in-button", inputs: { themed: { classPropertyName: "themed", publicName: "themed", isSignal: true, isRequired: false, transformFunction: null }, provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
3105
|
+
<fui-oauth-button [provider]="googleProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2068
3106
|
<fui-google-logo />
|
|
2069
3107
|
<span>{{ signInWithGoogleLabel() }}</span>
|
|
2070
3108
|
</fui-oauth-button>
|
|
2071
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider"] }, { kind: "component", type: GoogleLogoComponent, selector: "fui-google-logo", inputs: ["width", "height", "className"] }] });
|
|
3109
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider", "themed"], outputs: ["signIn"] }, { kind: "component", type: GoogleLogoComponent, selector: "fui-google-logo", inputs: ["width", "height", "className"] }] });
|
|
2072
3110
|
}
|
|
2073
3111
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: GoogleSignInButtonComponent, decorators: [{
|
|
2074
3112
|
type: Component,
|
|
@@ -2076,14 +3114,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2076
3114
|
selector: "fui-google-sign-in-button",
|
|
2077
3115
|
standalone: true,
|
|
2078
3116
|
imports: [CommonModule, OAuthButtonComponent, GoogleLogoComponent],
|
|
3117
|
+
host: {
|
|
3118
|
+
style: "display: block;",
|
|
3119
|
+
},
|
|
2079
3120
|
template: `
|
|
2080
|
-
<fui-oauth-button [provider]="googleProvider">
|
|
3121
|
+
<fui-oauth-button [provider]="googleProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2081
3122
|
<fui-google-logo />
|
|
2082
3123
|
<span>{{ signInWithGoogleLabel() }}</span>
|
|
2083
3124
|
</fui-oauth-button>
|
|
2084
3125
|
`,
|
|
2085
3126
|
}]
|
|
2086
|
-
}], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
3127
|
+
}], propDecorators: { themed: [{ type: i0.Input, args: [{ isSignal: true, alias: "themed", required: false }] }], signIn: [{ type: i0.Output, args: ["signIn"] }], provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
2087
3128
|
|
|
2088
3129
|
/**
|
|
2089
3130
|
* Copyright 2025 Google LLC
|
|
@@ -2107,7 +3148,7 @@ class FacebookLogoComponent {
|
|
|
2107
3148
|
className = input("", ...(ngDevMode ? [{ debugName: "className" }] : []));
|
|
2108
3149
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: FacebookLogoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2109
3150
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: FacebookLogoComponent, isStandalone: true, selector: "fui-facebook-logo", inputs: { width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2110
|
-
|
|
3151
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" class="fui-provider__icon">
|
|
2111
3152
|
<path
|
|
2112
3153
|
fill="currentColor"
|
|
2113
3154
|
d="M25,3C12.85,3,3,12.85,3,25c0,11.03,8.125,20.137,18.712,21.728V30.831h-5.443v-5.783h5.443v-3.848 c0-6.371,3.104-9.168,8.399-9.168c2.536,0,3.877,0.188,4.512,0.274v5.048h-3.612c-2.248,0-3.033,2.131-3.033,4.533v3.161h6.588 l-0.894,5.783h-5.694v15.944C38.716,45.318,47,36.137,47,25C47,12.85,37.15,3,25,3z"
|
|
@@ -2121,7 +3162,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2121
3162
|
selector: "fui-facebook-logo",
|
|
2122
3163
|
standalone: true,
|
|
2123
3164
|
template: `
|
|
2124
|
-
|
|
3165
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" class="fui-provider__icon">
|
|
2125
3166
|
<path
|
|
2126
3167
|
fill="currentColor"
|
|
2127
3168
|
d="M25,3C12.85,3,3,12.85,3,25c0,11.03,8.125,20.137,18.712,21.728V30.831h-5.443v-5.783h5.443v-3.848 c0-6.371,3.104-9.168,8.399-9.168c2.536,0,3.877,0.188,4.512,0.274v5.048h-3.612c-2.248,0-3.033,2.131-3.033,4.533v3.161h6.588 l-0.894,5.783h-5.694v15.944C38.716,45.318,47,36.137,47,25C47,12.85,37.15,3,25,3z"
|
|
@@ -2146,21 +3187,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2146
3187
|
* See the License for the specific language governing permissions and
|
|
2147
3188
|
* limitations under the License.
|
|
2148
3189
|
*/
|
|
3190
|
+
/**
|
|
3191
|
+
* A button component for signing in with Facebook.
|
|
3192
|
+
*/
|
|
2149
3193
|
class FacebookSignInButtonComponent {
|
|
2150
3194
|
ui = injectUI();
|
|
2151
3195
|
signInWithFacebookLabel = injectTranslation("labels", "signInWithFacebook");
|
|
3196
|
+
/** Whether to use themed styling. */
|
|
3197
|
+
themed = input(false, ...(ngDevMode ? [{ debugName: "themed" }] : []));
|
|
3198
|
+
/** Event emitter for successful sign-in. */
|
|
3199
|
+
signIn = output();
|
|
2152
3200
|
defaultProvider = new FacebookAuthProvider();
|
|
3201
|
+
/** Optional custom OAuth provider configuration. */
|
|
2153
3202
|
provider = input(...(ngDevMode ? [undefined, { debugName: "provider" }] : []));
|
|
2154
3203
|
get facebookProvider() {
|
|
2155
3204
|
return this.provider() || this.defaultProvider;
|
|
2156
3205
|
}
|
|
2157
3206
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: FacebookSignInButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2158
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: FacebookSignInButtonComponent, isStandalone: true, selector: "fui-facebook-sign-in-button", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2159
|
-
<fui-oauth-button [provider]="facebookProvider">
|
|
3207
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: FacebookSignInButtonComponent, isStandalone: true, selector: "fui-facebook-sign-in-button", inputs: { themed: { classPropertyName: "themed", publicName: "themed", isSignal: true, isRequired: false, transformFunction: null }, provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
3208
|
+
<fui-oauth-button [provider]="facebookProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2160
3209
|
<fui-facebook-logo />
|
|
2161
3210
|
<span>{{ signInWithFacebookLabel() }}</span>
|
|
2162
3211
|
</fui-oauth-button>
|
|
2163
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider"] }, { kind: "component", type: FacebookLogoComponent, selector: "fui-facebook-logo", inputs: ["width", "height", "className"] }] });
|
|
3212
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider", "themed"], outputs: ["signIn"] }, { kind: "component", type: FacebookLogoComponent, selector: "fui-facebook-logo", inputs: ["width", "height", "className"] }] });
|
|
2164
3213
|
}
|
|
2165
3214
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: FacebookSignInButtonComponent, decorators: [{
|
|
2166
3215
|
type: Component,
|
|
@@ -2168,14 +3217,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2168
3217
|
selector: "fui-facebook-sign-in-button",
|
|
2169
3218
|
standalone: true,
|
|
2170
3219
|
imports: [CommonModule, OAuthButtonComponent, FacebookLogoComponent],
|
|
3220
|
+
host: {
|
|
3221
|
+
style: "display: block;",
|
|
3222
|
+
},
|
|
2171
3223
|
template: `
|
|
2172
|
-
<fui-oauth-button [provider]="facebookProvider">
|
|
3224
|
+
<fui-oauth-button [provider]="facebookProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2173
3225
|
<fui-facebook-logo />
|
|
2174
3226
|
<span>{{ signInWithFacebookLabel() }}</span>
|
|
2175
3227
|
</fui-oauth-button>
|
|
2176
3228
|
`,
|
|
2177
3229
|
}]
|
|
2178
|
-
}], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
3230
|
+
}], propDecorators: { themed: [{ type: i0.Input, args: [{ isSignal: true, alias: "themed", required: false }] }], signIn: [{ type: i0.Output, args: ["signIn"] }], provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
2179
3231
|
|
|
2180
3232
|
/**
|
|
2181
3233
|
* Copyright 2025 Google LLC
|
|
@@ -2238,21 +3290,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2238
3290
|
* See the License for the specific language governing permissions and
|
|
2239
3291
|
* limitations under the License.
|
|
2240
3292
|
*/
|
|
3293
|
+
/**
|
|
3294
|
+
* A button component for signing in with Apple.
|
|
3295
|
+
*/
|
|
2241
3296
|
class AppleSignInButtonComponent {
|
|
2242
3297
|
ui = injectUI();
|
|
2243
3298
|
signInWithAppleLabel = injectTranslation("labels", "signInWithApple");
|
|
3299
|
+
/** Whether to use themed styling. */
|
|
3300
|
+
themed = input(false, ...(ngDevMode ? [{ debugName: "themed" }] : []));
|
|
3301
|
+
/** Event emitter for successful sign-in. */
|
|
3302
|
+
signIn = output();
|
|
2244
3303
|
defaultProvider = new OAuthProvider("apple.com");
|
|
3304
|
+
/** Optional custom OAuth provider configuration. */
|
|
2245
3305
|
provider = input(...(ngDevMode ? [undefined, { debugName: "provider" }] : []));
|
|
2246
3306
|
get appleProvider() {
|
|
2247
3307
|
return this.provider() || this.defaultProvider;
|
|
2248
3308
|
}
|
|
2249
3309
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: AppleSignInButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2250
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: AppleSignInButtonComponent, isStandalone: true, selector: "fui-apple-sign-in-button", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2251
|
-
<fui-oauth-button [provider]="appleProvider">
|
|
3310
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: AppleSignInButtonComponent, isStandalone: true, selector: "fui-apple-sign-in-button", inputs: { themed: { classPropertyName: "themed", publicName: "themed", isSignal: true, isRequired: false, transformFunction: null }, provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
3311
|
+
<fui-oauth-button [provider]="appleProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2252
3312
|
<fui-apple-logo />
|
|
2253
3313
|
<span>{{ signInWithAppleLabel() }}</span>
|
|
2254
3314
|
</fui-oauth-button>
|
|
2255
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider"] }, { kind: "component", type: AppleLogoComponent, selector: "fui-apple-logo", inputs: ["width", "height", "className"] }] });
|
|
3315
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider", "themed"], outputs: ["signIn"] }, { kind: "component", type: AppleLogoComponent, selector: "fui-apple-logo", inputs: ["width", "height", "className"] }] });
|
|
2256
3316
|
}
|
|
2257
3317
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: AppleSignInButtonComponent, decorators: [{
|
|
2258
3318
|
type: Component,
|
|
@@ -2260,14 +3320,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2260
3320
|
selector: "fui-apple-sign-in-button",
|
|
2261
3321
|
standalone: true,
|
|
2262
3322
|
imports: [CommonModule, OAuthButtonComponent, AppleLogoComponent],
|
|
3323
|
+
host: {
|
|
3324
|
+
style: "display: block;",
|
|
3325
|
+
},
|
|
2263
3326
|
template: `
|
|
2264
|
-
<fui-oauth-button [provider]="appleProvider">
|
|
3327
|
+
<fui-oauth-button [provider]="appleProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2265
3328
|
<fui-apple-logo />
|
|
2266
3329
|
<span>{{ signInWithAppleLabel() }}</span>
|
|
2267
3330
|
</fui-oauth-button>
|
|
2268
3331
|
`,
|
|
2269
3332
|
}]
|
|
2270
|
-
}], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
3333
|
+
}], propDecorators: { themed: [{ type: i0.Input, args: [{ isSignal: true, alias: "themed", required: false }] }], signIn: [{ type: i0.Output, args: ["signIn"] }], provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
2271
3334
|
|
|
2272
3335
|
/**
|
|
2273
3336
|
* Copyright 2025 Google LLC
|
|
@@ -2330,20 +3393,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2330
3393
|
* See the License for the specific language governing permissions and
|
|
2331
3394
|
* limitations under the License.
|
|
2332
3395
|
*/
|
|
3396
|
+
/**
|
|
3397
|
+
* A button component for signing in with Microsoft.
|
|
3398
|
+
*/
|
|
2333
3399
|
class MicrosoftSignInButtonComponent {
|
|
2334
3400
|
signInWithMicrosoftLabel = injectTranslation("labels", "signInWithMicrosoft");
|
|
3401
|
+
/** Whether to use themed styling. */
|
|
3402
|
+
themed = input(false, ...(ngDevMode ? [{ debugName: "themed" }] : []));
|
|
3403
|
+
/** Event emitter for successful sign-in. */
|
|
3404
|
+
signIn = output();
|
|
2335
3405
|
defaultProvider = new OAuthProvider("microsoft.com");
|
|
3406
|
+
/** Optional custom OAuth provider configuration. */
|
|
2336
3407
|
provider = input(...(ngDevMode ? [undefined, { debugName: "provider" }] : []));
|
|
2337
3408
|
get microsoftProvider() {
|
|
2338
3409
|
return this.provider() || this.defaultProvider;
|
|
2339
3410
|
}
|
|
2340
3411
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MicrosoftSignInButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2341
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: MicrosoftSignInButtonComponent, isStandalone: true, selector: "fui-microsoft-sign-in-button", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2342
|
-
<fui-oauth-button [provider]="microsoftProvider">
|
|
3412
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: MicrosoftSignInButtonComponent, isStandalone: true, selector: "fui-microsoft-sign-in-button", inputs: { themed: { classPropertyName: "themed", publicName: "themed", isSignal: true, isRequired: false, transformFunction: null }, provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
3413
|
+
<fui-oauth-button [provider]="microsoftProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2343
3414
|
<fui-microsoft-logo />
|
|
2344
3415
|
<span>{{ signInWithMicrosoftLabel() }}</span>
|
|
2345
3416
|
</fui-oauth-button>
|
|
2346
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider"] }, { kind: "component", type: MicrosoftLogoComponent, selector: "fui-microsoft-logo", inputs: ["width", "height", "className"] }] });
|
|
3417
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider", "themed"], outputs: ["signIn"] }, { kind: "component", type: MicrosoftLogoComponent, selector: "fui-microsoft-logo", inputs: ["width", "height", "className"] }] });
|
|
2347
3418
|
}
|
|
2348
3419
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MicrosoftSignInButtonComponent, decorators: [{
|
|
2349
3420
|
type: Component,
|
|
@@ -2351,14 +3422,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2351
3422
|
selector: "fui-microsoft-sign-in-button",
|
|
2352
3423
|
standalone: true,
|
|
2353
3424
|
imports: [CommonModule, OAuthButtonComponent, MicrosoftLogoComponent],
|
|
3425
|
+
host: {
|
|
3426
|
+
style: "display: block;",
|
|
3427
|
+
},
|
|
2354
3428
|
template: `
|
|
2355
|
-
<fui-oauth-button [provider]="microsoftProvider">
|
|
3429
|
+
<fui-oauth-button [provider]="microsoftProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2356
3430
|
<fui-microsoft-logo />
|
|
2357
3431
|
<span>{{ signInWithMicrosoftLabel() }}</span>
|
|
2358
3432
|
</fui-oauth-button>
|
|
2359
3433
|
`,
|
|
2360
3434
|
}]
|
|
2361
|
-
}], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
3435
|
+
}], propDecorators: { themed: [{ type: i0.Input, args: [{ isSignal: true, alias: "themed", required: false }] }], signIn: [{ type: i0.Output, args: ["signIn"] }], provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
2362
3436
|
|
|
2363
3437
|
/**
|
|
2364
3438
|
* Copyright 2025 Google LLC
|
|
@@ -2419,20 +3493,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2419
3493
|
* See the License for the specific language governing permissions and
|
|
2420
3494
|
* limitations under the License.
|
|
2421
3495
|
*/
|
|
3496
|
+
/**
|
|
3497
|
+
* A button component for signing in with Twitter/X.
|
|
3498
|
+
*/
|
|
2422
3499
|
class TwitterSignInButtonComponent {
|
|
2423
3500
|
signInWithTwitterLabel = injectTranslation("labels", "signInWithTwitter");
|
|
3501
|
+
/** Whether to use themed styling. */
|
|
3502
|
+
themed = input(false, ...(ngDevMode ? [{ debugName: "themed" }] : []));
|
|
3503
|
+
/** Event emitter for successful sign-in. */
|
|
3504
|
+
signIn = output();
|
|
2424
3505
|
defaultProvider = new TwitterAuthProvider();
|
|
3506
|
+
/** Optional custom OAuth provider configuration. */
|
|
2425
3507
|
provider = input(...(ngDevMode ? [undefined, { debugName: "provider" }] : []));
|
|
2426
3508
|
get twitterProvider() {
|
|
2427
3509
|
return this.provider() || this.defaultProvider;
|
|
2428
3510
|
}
|
|
2429
3511
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: TwitterSignInButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2430
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: TwitterSignInButtonComponent, isStandalone: true, selector: "fui-twitter-sign-in-button", inputs: { provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2431
|
-
<fui-oauth-button [provider]="twitterProvider">
|
|
3512
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: TwitterSignInButtonComponent, isStandalone: true, selector: "fui-twitter-sign-in-button", inputs: { themed: { classPropertyName: "themed", publicName: "themed", isSignal: true, isRequired: false, transformFunction: null }, provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
3513
|
+
<fui-oauth-button [provider]="twitterProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2432
3514
|
<fui-twitter-logo />
|
|
2433
3515
|
<span>{{ signInWithTwitterLabel() }}</span>
|
|
2434
3516
|
</fui-oauth-button>
|
|
2435
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider"] }, { kind: "component", type: TwitterLogoComponent, selector: "fui-twitter-logo", inputs: ["width", "height", "className"] }] });
|
|
3517
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider", "themed"], outputs: ["signIn"] }, { kind: "component", type: TwitterLogoComponent, selector: "fui-twitter-logo", inputs: ["width", "height", "className"] }] });
|
|
2436
3518
|
}
|
|
2437
3519
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: TwitterSignInButtonComponent, decorators: [{
|
|
2438
3520
|
type: Component,
|
|
@@ -2440,14 +3522,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2440
3522
|
selector: "fui-twitter-sign-in-button",
|
|
2441
3523
|
standalone: true,
|
|
2442
3524
|
imports: [CommonModule, OAuthButtonComponent, TwitterLogoComponent],
|
|
3525
|
+
host: {
|
|
3526
|
+
style: "display: block;",
|
|
3527
|
+
},
|
|
2443
3528
|
template: `
|
|
2444
|
-
<fui-oauth-button [provider]="twitterProvider">
|
|
3529
|
+
<fui-oauth-button [provider]="twitterProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2445
3530
|
<fui-twitter-logo />
|
|
2446
3531
|
<span>{{ signInWithTwitterLabel() }}</span>
|
|
2447
3532
|
</fui-oauth-button>
|
|
2448
3533
|
`,
|
|
2449
3534
|
}]
|
|
2450
|
-
}], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
3535
|
+
}], propDecorators: { themed: [{ type: i0.Input, args: [{ isSignal: true, alias: "themed", required: false }] }], signIn: [{ type: i0.Output, args: ["signIn"] }], provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
2451
3536
|
|
|
2452
3537
|
/**
|
|
2453
3538
|
* Copyright 2025 Google LLC
|
|
@@ -2508,35 +3593,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2508
3593
|
* See the License for the specific language governing permissions and
|
|
2509
3594
|
* limitations under the License.
|
|
2510
3595
|
*/
|
|
2511
|
-
|
|
2512
|
-
|
|
3596
|
+
/**
|
|
3597
|
+
* A button component for signing in with GitHub.
|
|
3598
|
+
*/
|
|
3599
|
+
class GitHubSignInButtonComponent {
|
|
3600
|
+
signInWithGitHubLabel = injectTranslation("labels", "signInWithGitHub");
|
|
3601
|
+
/** Whether to use themed styling. */
|
|
3602
|
+
themed = input(false, ...(ngDevMode ? [{ debugName: "themed" }] : []));
|
|
3603
|
+
/** Event emitter for successful sign-in. */
|
|
3604
|
+
signIn = output();
|
|
2513
3605
|
defaultProvider = new GithubAuthProvider();
|
|
3606
|
+
/** Optional custom OAuth provider configuration. */
|
|
2514
3607
|
provider = input(...(ngDevMode ? [undefined, { debugName: "provider" }] : []));
|
|
2515
3608
|
get githubProvider() {
|
|
2516
3609
|
return this.provider() || this.defaultProvider;
|
|
2517
3610
|
}
|
|
2518
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type:
|
|
2519
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type:
|
|
2520
|
-
<fui-oauth-button [provider]="githubProvider">
|
|
3611
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: GitHubSignInButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3612
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: GitHubSignInButtonComponent, isStandalone: true, selector: "fui-github-sign-in-button", inputs: { themed: { classPropertyName: "themed", publicName: "themed", isSignal: true, isRequired: false, transformFunction: null }, provider: { classPropertyName: "provider", publicName: "provider", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
3613
|
+
<fui-oauth-button [provider]="githubProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2521
3614
|
<fui-github-logo />
|
|
2522
|
-
<span>{{
|
|
3615
|
+
<span>{{ signInWithGitHubLabel() }}</span>
|
|
2523
3616
|
</fui-oauth-button>
|
|
2524
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider"] }, { kind: "component", type: GithubLogoComponent, selector: "fui-github-logo", inputs: ["width", "height", "className"] }] });
|
|
3617
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: OAuthButtonComponent, selector: "fui-oauth-button", inputs: ["provider", "themed"], outputs: ["signIn"] }, { kind: "component", type: GithubLogoComponent, selector: "fui-github-logo", inputs: ["width", "height", "className"] }] });
|
|
2525
3618
|
}
|
|
2526
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type:
|
|
3619
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: GitHubSignInButtonComponent, decorators: [{
|
|
2527
3620
|
type: Component,
|
|
2528
3621
|
args: [{
|
|
2529
3622
|
selector: "fui-github-sign-in-button",
|
|
2530
3623
|
standalone: true,
|
|
2531
3624
|
imports: [CommonModule, OAuthButtonComponent, GithubLogoComponent],
|
|
3625
|
+
host: {
|
|
3626
|
+
style: "display: block;",
|
|
3627
|
+
},
|
|
2532
3628
|
template: `
|
|
2533
|
-
<fui-oauth-button [provider]="githubProvider">
|
|
3629
|
+
<fui-oauth-button [provider]="githubProvider" [themed]="themed()" (signIn)="signIn.emit($event)">
|
|
2534
3630
|
<fui-github-logo />
|
|
2535
|
-
<span>{{
|
|
3631
|
+
<span>{{ signInWithGitHubLabel() }}</span>
|
|
2536
3632
|
</fui-oauth-button>
|
|
2537
3633
|
`,
|
|
2538
3634
|
}]
|
|
2539
|
-
}], propDecorators: { provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
3635
|
+
}], propDecorators: { themed: [{ type: i0.Input, args: [{ isSignal: true, alias: "themed", required: false }] }], signIn: [{ type: i0.Output, args: ["signIn"] }], provider: [{ type: i0.Input, args: [{ isSignal: true, alias: "provider", required: false }] }] } });
|
|
2540
3636
|
|
|
2541
3637
|
/**
|
|
2542
3638
|
* Copyright 2025 Google LLC
|
|
@@ -2553,13 +3649,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2553
3649
|
* See the License for the specific language governing permissions and
|
|
2554
3650
|
* limitations under the License.
|
|
2555
3651
|
*/
|
|
3652
|
+
/**
|
|
3653
|
+
* A card container component for grouping related content.
|
|
3654
|
+
*/
|
|
2556
3655
|
class CardComponent {
|
|
2557
3656
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2558
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: CardComponent, isStandalone: true, selector: "fui-card", ngImport: i0, template: `
|
|
2559
|
-
<
|
|
2560
|
-
|
|
2561
|
-
<ng-content select="fui-card-content"></ng-content>
|
|
2562
|
-
</div>
|
|
3657
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: CardComponent, isStandalone: true, selector: "fui-card", host: { styleAttribute: "display: block;", classAttribute: "fui-card" }, ngImport: i0, template: `
|
|
3658
|
+
<ng-content select="fui-card-header"></ng-content>
|
|
3659
|
+
<ng-content select="fui-card-content"></ng-content>
|
|
2563
3660
|
`, isInline: true });
|
|
2564
3661
|
}
|
|
2565
3662
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CardComponent, decorators: [{
|
|
@@ -2568,21 +3665,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2568
3665
|
selector: "fui-card",
|
|
2569
3666
|
standalone: true,
|
|
2570
3667
|
imports: [],
|
|
3668
|
+
host: {
|
|
3669
|
+
class: "fui-card",
|
|
3670
|
+
style: "display: block;",
|
|
3671
|
+
},
|
|
2571
3672
|
template: `
|
|
2572
|
-
<
|
|
2573
|
-
|
|
2574
|
-
<ng-content select="fui-card-content"></ng-content>
|
|
2575
|
-
</div>
|
|
3673
|
+
<ng-content select="fui-card-header"></ng-content>
|
|
3674
|
+
<ng-content select="fui-card-content"></ng-content>
|
|
2576
3675
|
`,
|
|
2577
3676
|
}]
|
|
2578
3677
|
}] });
|
|
3678
|
+
/**
|
|
3679
|
+
* The header section of a card.
|
|
3680
|
+
*/
|
|
2579
3681
|
class CardHeaderComponent {
|
|
2580
3682
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CardHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2581
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: CardHeaderComponent, isStandalone: true, selector: "fui-card-header", ngImport: i0, template: `
|
|
2582
|
-
<
|
|
2583
|
-
|
|
2584
|
-
<ng-content select="fui-card-subtitle"></ng-content>
|
|
2585
|
-
</div>
|
|
3683
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: CardHeaderComponent, isStandalone: true, selector: "fui-card-header", host: { styleAttribute: "display: block;", classAttribute: "fui-card__header" }, ngImport: i0, template: `
|
|
3684
|
+
<ng-content select="fui-card-title"></ng-content>
|
|
3685
|
+
<ng-content select="fui-card-subtitle"></ng-content>
|
|
2586
3686
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
2587
3687
|
}
|
|
2588
3688
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CardHeaderComponent, decorators: [{
|
|
@@ -2591,18 +3691,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2591
3691
|
selector: "fui-card-header",
|
|
2592
3692
|
standalone: true,
|
|
2593
3693
|
imports: [CommonModule],
|
|
3694
|
+
host: {
|
|
3695
|
+
class: "fui-card__header",
|
|
3696
|
+
style: "display: block;",
|
|
3697
|
+
},
|
|
2594
3698
|
template: `
|
|
2595
|
-
<
|
|
2596
|
-
|
|
2597
|
-
<ng-content select="fui-card-subtitle"></ng-content>
|
|
2598
|
-
</div>
|
|
3699
|
+
<ng-content select="fui-card-title"></ng-content>
|
|
3700
|
+
<ng-content select="fui-card-subtitle"></ng-content>
|
|
2599
3701
|
`,
|
|
2600
3702
|
}]
|
|
2601
3703
|
}] });
|
|
3704
|
+
/**
|
|
3705
|
+
* The title of a card.
|
|
3706
|
+
*/
|
|
2602
3707
|
class CardTitleComponent {
|
|
2603
3708
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CardTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2604
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: CardTitleComponent, isStandalone: true, selector: "fui-card-title", ngImport: i0, template: `
|
|
2605
|
-
<h2
|
|
3709
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: CardTitleComponent, isStandalone: true, selector: "fui-card-title", host: { styleAttribute: "display: block;", classAttribute: "fui-card__title" }, ngImport: i0, template: `
|
|
3710
|
+
<h2>
|
|
2606
3711
|
<ng-content></ng-content>
|
|
2607
3712
|
</h2>
|
|
2608
3713
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
@@ -2613,17 +3718,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2613
3718
|
selector: "fui-card-title",
|
|
2614
3719
|
standalone: true,
|
|
2615
3720
|
imports: [CommonModule],
|
|
3721
|
+
host: {
|
|
3722
|
+
class: "fui-card__title",
|
|
3723
|
+
style: "display: block;",
|
|
3724
|
+
},
|
|
2616
3725
|
template: `
|
|
2617
|
-
<h2
|
|
3726
|
+
<h2>
|
|
2618
3727
|
<ng-content></ng-content>
|
|
2619
3728
|
</h2>
|
|
2620
3729
|
`,
|
|
2621
3730
|
}]
|
|
2622
3731
|
}] });
|
|
3732
|
+
/**
|
|
3733
|
+
* The subtitle of a card.
|
|
3734
|
+
*/
|
|
2623
3735
|
class CardSubtitleComponent {
|
|
2624
3736
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CardSubtitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2625
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: CardSubtitleComponent, isStandalone: true, selector: "fui-card-subtitle", ngImport: i0, template: `
|
|
2626
|
-
<p
|
|
3737
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: CardSubtitleComponent, isStandalone: true, selector: "fui-card-subtitle", host: { styleAttribute: "display: block;", classAttribute: "fui-card__subtitle" }, ngImport: i0, template: `
|
|
3738
|
+
<p>
|
|
2627
3739
|
<ng-content></ng-content>
|
|
2628
3740
|
</p>
|
|
2629
3741
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
@@ -2634,20 +3746,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2634
3746
|
selector: "fui-card-subtitle",
|
|
2635
3747
|
standalone: true,
|
|
2636
3748
|
imports: [CommonModule],
|
|
3749
|
+
host: {
|
|
3750
|
+
class: "fui-card__subtitle",
|
|
3751
|
+
style: "display: block;",
|
|
3752
|
+
},
|
|
2637
3753
|
template: `
|
|
2638
|
-
<p
|
|
3754
|
+
<p>
|
|
2639
3755
|
<ng-content></ng-content>
|
|
2640
3756
|
</p>
|
|
2641
3757
|
`,
|
|
2642
3758
|
}]
|
|
2643
3759
|
}] });
|
|
3760
|
+
/**
|
|
3761
|
+
* The content section of a card.
|
|
3762
|
+
*/
|
|
2644
3763
|
class CardContentComponent {
|
|
2645
3764
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CardContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2646
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: CardContentComponent, isStandalone: true, selector: "fui-card-content", ngImport: i0, template: `
|
|
2647
|
-
<div class="fui-card__content">
|
|
2648
|
-
<ng-content></ng-content>
|
|
2649
|
-
</div>
|
|
2650
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
3765
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: CardContentComponent, isStandalone: true, selector: "fui-card-content", host: { styleAttribute: "display: block;", classAttribute: "fui-card__content" }, ngImport: i0, template: ` <ng-content></ng-content> `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
2651
3766
|
}
|
|
2652
3767
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CardContentComponent, decorators: [{
|
|
2653
3768
|
type: Component,
|
|
@@ -2655,13 +3770,88 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2655
3770
|
selector: "fui-card-content",
|
|
2656
3771
|
standalone: true,
|
|
2657
3772
|
imports: [CommonModule],
|
|
3773
|
+
host: {
|
|
3774
|
+
class: "fui-card__content",
|
|
3775
|
+
style: "display: block;",
|
|
3776
|
+
},
|
|
3777
|
+
template: ` <ng-content></ng-content> `,
|
|
3778
|
+
}]
|
|
3779
|
+
}] });
|
|
3780
|
+
|
|
3781
|
+
/**
|
|
3782
|
+
* Copyright 2025 Google LLC
|
|
3783
|
+
*
|
|
3784
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
3785
|
+
* you may not use this file except in compliance with the License.
|
|
3786
|
+
* You may obtain a copy of the License at
|
|
3787
|
+
*
|
|
3788
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
3789
|
+
*
|
|
3790
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
3791
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
3792
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
3793
|
+
* See the License for the specific language governing permissions and
|
|
3794
|
+
* limitations under the License.
|
|
3795
|
+
*/
|
|
3796
|
+
/**
|
|
3797
|
+
* A screen component for multi-factor authentication assertion.
|
|
3798
|
+
*
|
|
3799
|
+
* Displays the MFA assertion form for completing multi-factor verification.
|
|
3800
|
+
*/
|
|
3801
|
+
class MultiFactorAuthAssertionScreenComponent {
|
|
3802
|
+
/** Event emitter for successful MFA assertion. */
|
|
3803
|
+
onSuccess = new EventEmitter();
|
|
3804
|
+
titleText = injectTranslation("labels", "multiFactorAssertion");
|
|
3805
|
+
subtitleText = injectTranslation("prompts", "mfaAssertionPrompt");
|
|
3806
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MultiFactorAuthAssertionScreenComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3807
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: MultiFactorAuthAssertionScreenComponent, isStandalone: true, selector: "fui-multi-factor-auth-assertion-screen", outputs: { onSuccess: "onSuccess" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
3808
|
+
<div class="fui-screen">
|
|
3809
|
+
<fui-card>
|
|
3810
|
+
<fui-card-header>
|
|
3811
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
3812
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
3813
|
+
</fui-card-header>
|
|
3814
|
+
<fui-card-content>
|
|
3815
|
+
<fui-multi-factor-auth-assertion-form (onSuccess)="onSuccess.emit($event)" />
|
|
3816
|
+
</fui-card-content>
|
|
3817
|
+
</fui-card>
|
|
3818
|
+
</div>
|
|
3819
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CardComponent, selector: "fui-card" }, { kind: "component", type: CardHeaderComponent, selector: "fui-card-header" }, { kind: "component", type: CardTitleComponent, selector: "fui-card-title" }, { kind: "component", type: CardSubtitleComponent, selector: "fui-card-subtitle" }, { kind: "component", type: CardContentComponent, selector: "fui-card-content" }, { kind: "component", type: MultiFactorAuthAssertionFormComponent, selector: "fui-multi-factor-auth-assertion-form", outputs: ["onSuccess"] }] });
|
|
3820
|
+
}
|
|
3821
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MultiFactorAuthAssertionScreenComponent, decorators: [{
|
|
3822
|
+
type: Component,
|
|
3823
|
+
args: [{
|
|
3824
|
+
selector: "fui-multi-factor-auth-assertion-screen",
|
|
3825
|
+
standalone: true,
|
|
3826
|
+
host: {
|
|
3827
|
+
style: "display: block;",
|
|
3828
|
+
},
|
|
3829
|
+
imports: [
|
|
3830
|
+
CommonModule,
|
|
3831
|
+
CardComponent,
|
|
3832
|
+
CardHeaderComponent,
|
|
3833
|
+
CardTitleComponent,
|
|
3834
|
+
CardSubtitleComponent,
|
|
3835
|
+
CardContentComponent,
|
|
3836
|
+
MultiFactorAuthAssertionFormComponent,
|
|
3837
|
+
],
|
|
2658
3838
|
template: `
|
|
2659
|
-
<div class="fui-
|
|
2660
|
-
<
|
|
3839
|
+
<div class="fui-screen">
|
|
3840
|
+
<fui-card>
|
|
3841
|
+
<fui-card-header>
|
|
3842
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
3843
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
3844
|
+
</fui-card-header>
|
|
3845
|
+
<fui-card-content>
|
|
3846
|
+
<fui-multi-factor-auth-assertion-form (onSuccess)="onSuccess.emit($event)" />
|
|
3847
|
+
</fui-card-content>
|
|
3848
|
+
</fui-card>
|
|
2661
3849
|
</div>
|
|
2662
3850
|
`,
|
|
2663
3851
|
}]
|
|
2664
|
-
}]
|
|
3852
|
+
}], propDecorators: { onSuccess: [{
|
|
3853
|
+
type: Output
|
|
3854
|
+
}] } });
|
|
2665
3855
|
|
|
2666
3856
|
/**
|
|
2667
3857
|
* Copyright 2025 Google LLC
|
|
@@ -2677,12 +3867,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2677
3867
|
* See the License for the specific language governing permissions and
|
|
2678
3868
|
* limitations under the License.
|
|
2679
3869
|
*/
|
|
3870
|
+
/**
|
|
3871
|
+
* A component that displays redirect error messages.
|
|
3872
|
+
*
|
|
3873
|
+
* Shows errors that occurred during OAuth redirect flows.
|
|
3874
|
+
*/
|
|
2680
3875
|
class RedirectErrorComponent {
|
|
2681
3876
|
error = injectRedirectError();
|
|
2682
3877
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: RedirectErrorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2683
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: RedirectErrorComponent, isStandalone: true, selector: "fui-redirect-error", ngImport: i0, template: `
|
|
3878
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: RedirectErrorComponent, isStandalone: true, selector: "fui-redirect-error", host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
2684
3879
|
@if (error()) {
|
|
2685
|
-
<div class="fui-
|
|
3880
|
+
<div class="fui-error">{{ error() }}</div>
|
|
2686
3881
|
}
|
|
2687
3882
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
2688
3883
|
}
|
|
@@ -2692,9 +3887,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2692
3887
|
selector: "fui-redirect-error",
|
|
2693
3888
|
standalone: true,
|
|
2694
3889
|
imports: [CommonModule],
|
|
3890
|
+
host: {
|
|
3891
|
+
style: "display: block;",
|
|
3892
|
+
},
|
|
2695
3893
|
template: `
|
|
2696
3894
|
@if (error()) {
|
|
2697
|
-
<div class="fui-
|
|
3895
|
+
<div class="fui-error">{{ error() }}</div>
|
|
2698
3896
|
}
|
|
2699
3897
|
`,
|
|
2700
3898
|
}]
|
|
@@ -2715,33 +3913,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2715
3913
|
* See the License for the specific language governing permissions and
|
|
2716
3914
|
* limitations under the License.
|
|
2717
3915
|
*/
|
|
3916
|
+
/**
|
|
3917
|
+
* A screen component for email link authentication.
|
|
3918
|
+
*
|
|
3919
|
+
* Automatically displays the MFA assertion screen if a multi-factor resolver is present.
|
|
3920
|
+
*/
|
|
2718
3921
|
class EmailLinkAuthScreenComponent {
|
|
3922
|
+
ui = injectUI();
|
|
3923
|
+
mfaResolver = computed(() => this.ui().multiFactorResolver, ...(ngDevMode ? [{ debugName: "mfaResolver" }] : []));
|
|
2719
3924
|
titleText = injectTranslation("labels", "signIn");
|
|
2720
3925
|
subtitleText = injectTranslation("prompts", "signInToAccount");
|
|
2721
|
-
|
|
2722
|
-
|
|
3926
|
+
constructor() {
|
|
3927
|
+
injectUserAuthenticated((user) => {
|
|
3928
|
+
this.signIn.emit(user);
|
|
3929
|
+
});
|
|
3930
|
+
}
|
|
3931
|
+
/** Event emitter fired when sign-in link email is sent. */
|
|
3932
|
+
emailSent = new EventEmitter();
|
|
3933
|
+
/** Event emitter for successful sign-in. */
|
|
3934
|
+
signIn = new EventEmitter();
|
|
2723
3935
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: EmailLinkAuthScreenComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2724
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
2725
|
-
|
|
2726
|
-
<fui-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
<
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
3936
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: EmailLinkAuthScreenComponent, isStandalone: true, selector: "fui-email-link-auth-screen", outputs: { emailSent: "emailSent", signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
3937
|
+
@if (mfaResolver()) {
|
|
3938
|
+
<fui-multi-factor-auth-assertion-screen />
|
|
3939
|
+
} @else {
|
|
3940
|
+
<div class="fui-screen">
|
|
3941
|
+
<fui-card>
|
|
3942
|
+
<fui-card-header>
|
|
3943
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
3944
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
3945
|
+
</fui-card-header>
|
|
3946
|
+
<fui-card-content>
|
|
3947
|
+
<fui-email-link-auth-form (emailSent)="emailSent.emit()" (signIn)="signIn.emit($event.user)" />
|
|
3948
|
+
<ng-content></ng-content>
|
|
3949
|
+
<fui-redirect-error />
|
|
3950
|
+
</fui-card-content>
|
|
3951
|
+
</fui-card>
|
|
3952
|
+
</div>
|
|
3953
|
+
}
|
|
3954
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CardComponent, selector: "fui-card" }, { kind: "component", type: CardHeaderComponent, selector: "fui-card-header" }, { kind: "component", type: CardTitleComponent, selector: "fui-card-title" }, { kind: "component", type: CardSubtitleComponent, selector: "fui-card-subtitle" }, { kind: "component", type: CardContentComponent, selector: "fui-card-content" }, { kind: "component", type: EmailLinkAuthFormComponent, selector: "fui-email-link-auth-form", outputs: ["emailSent", "signIn"] }, { kind: "component", type: MultiFactorAuthAssertionScreenComponent, selector: "fui-multi-factor-auth-assertion-screen", outputs: ["onSuccess"] }, { kind: "component", type: RedirectErrorComponent, selector: "fui-redirect-error" }] });
|
|
2739
3955
|
}
|
|
2740
3956
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: EmailLinkAuthScreenComponent, decorators: [{
|
|
2741
3957
|
type: Component,
|
|
2742
3958
|
args: [{
|
|
2743
3959
|
selector: "fui-email-link-auth-screen",
|
|
2744
3960
|
standalone: true,
|
|
3961
|
+
host: {
|
|
3962
|
+
style: "display: block;",
|
|
3963
|
+
},
|
|
2745
3964
|
imports: [
|
|
2746
3965
|
CommonModule,
|
|
2747
3966
|
CardComponent,
|
|
@@ -2750,25 +3969,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2750
3969
|
CardSubtitleComponent,
|
|
2751
3970
|
CardContentComponent,
|
|
2752
3971
|
EmailLinkAuthFormComponent,
|
|
3972
|
+
MultiFactorAuthAssertionScreenComponent,
|
|
2753
3973
|
RedirectErrorComponent,
|
|
2754
3974
|
],
|
|
2755
3975
|
template: `
|
|
2756
|
-
|
|
2757
|
-
<fui-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
<
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
3976
|
+
@if (mfaResolver()) {
|
|
3977
|
+
<fui-multi-factor-auth-assertion-screen />
|
|
3978
|
+
} @else {
|
|
3979
|
+
<div class="fui-screen">
|
|
3980
|
+
<fui-card>
|
|
3981
|
+
<fui-card-header>
|
|
3982
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
3983
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
3984
|
+
</fui-card-header>
|
|
3985
|
+
<fui-card-content>
|
|
3986
|
+
<fui-email-link-auth-form (emailSent)="emailSent.emit()" (signIn)="signIn.emit($event.user)" />
|
|
3987
|
+
<ng-content></ng-content>
|
|
3988
|
+
<fui-redirect-error />
|
|
3989
|
+
</fui-card-content>
|
|
3990
|
+
</fui-card>
|
|
3991
|
+
</div>
|
|
3992
|
+
}
|
|
2769
3993
|
`,
|
|
2770
3994
|
}]
|
|
2771
|
-
}],
|
|
3995
|
+
}], ctorParameters: () => [], propDecorators: { emailSent: [{
|
|
3996
|
+
type: Output
|
|
3997
|
+
}], signIn: [{
|
|
3998
|
+
type: Output
|
|
3999
|
+
}] } });
|
|
2772
4000
|
|
|
2773
4001
|
/**
|
|
2774
4002
|
* Copyright 2025 Google LLC
|
|
@@ -2785,13 +4013,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2785
4013
|
* See the License for the specific language governing permissions and
|
|
2786
4014
|
* limitations under the License.
|
|
2787
4015
|
*/
|
|
4016
|
+
/**
|
|
4017
|
+
* A screen component for requesting a password reset.
|
|
4018
|
+
*/
|
|
2788
4019
|
class ForgotPasswordAuthScreenComponent {
|
|
2789
4020
|
titleText = injectTranslation("labels", "resetPassword");
|
|
2790
4021
|
subtitleText = injectTranslation("prompts", "enterEmailToReset");
|
|
2791
|
-
|
|
2792
|
-
|
|
4022
|
+
/** Event emitter fired when password reset email is sent. */
|
|
4023
|
+
passwordSent = new EventEmitter();
|
|
4024
|
+
/** Event emitter for back to sign in action. */
|
|
4025
|
+
backToSignIn = new EventEmitter();
|
|
2793
4026
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ForgotPasswordAuthScreenComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2794
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: ForgotPasswordAuthScreenComponent, isStandalone: true, selector: "fui-forgot-password-auth-screen", outputs: { passwordSent: "passwordSent", backToSignIn: "backToSignIn" }, ngImport: i0, template: `
|
|
4027
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: ForgotPasswordAuthScreenComponent, isStandalone: true, selector: "fui-forgot-password-auth-screen", outputs: { passwordSent: "passwordSent", backToSignIn: "backToSignIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
2795
4028
|
<div class="fui-screen">
|
|
2796
4029
|
<fui-card>
|
|
2797
4030
|
<fui-card-header>
|
|
@@ -2799,18 +4032,20 @@ class ForgotPasswordAuthScreenComponent {
|
|
|
2799
4032
|
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
2800
4033
|
</fui-card-header>
|
|
2801
4034
|
<fui-card-content>
|
|
2802
|
-
<fui-forgot-password-auth-form
|
|
2803
|
-
<fui-redirect-error />
|
|
4035
|
+
<fui-forgot-password-auth-form [backToSignIn]="backToSignIn" (passwordSent)="passwordSent.emit()" />
|
|
2804
4036
|
</fui-card-content>
|
|
2805
4037
|
</fui-card>
|
|
2806
4038
|
</div>
|
|
2807
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CardComponent, selector: "fui-card" }, { kind: "component", type: CardHeaderComponent, selector: "fui-card-header" }, { kind: "component", type: CardTitleComponent, selector: "fui-card-title" }, { kind: "component", type: CardSubtitleComponent, selector: "fui-card-subtitle" }, { kind: "component", type: CardContentComponent, selector: "fui-card-content" }, { kind: "component", type: ForgotPasswordAuthFormComponent, selector: "fui-forgot-password-auth-form",
|
|
4039
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CardComponent, selector: "fui-card" }, { kind: "component", type: CardHeaderComponent, selector: "fui-card-header" }, { kind: "component", type: CardTitleComponent, selector: "fui-card-title" }, { kind: "component", type: CardSubtitleComponent, selector: "fui-card-subtitle" }, { kind: "component", type: CardContentComponent, selector: "fui-card-content" }, { kind: "component", type: ForgotPasswordAuthFormComponent, selector: "fui-forgot-password-auth-form", inputs: ["backToSignIn"], outputs: ["passwordSent"] }] });
|
|
2808
4040
|
}
|
|
2809
4041
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ForgotPasswordAuthScreenComponent, decorators: [{
|
|
2810
4042
|
type: Component,
|
|
2811
4043
|
args: [{
|
|
2812
4044
|
selector: "fui-forgot-password-auth-screen",
|
|
2813
4045
|
standalone: true,
|
|
4046
|
+
host: {
|
|
4047
|
+
style: "display: block;",
|
|
4048
|
+
},
|
|
2814
4049
|
imports: [
|
|
2815
4050
|
CommonModule,
|
|
2816
4051
|
CardComponent,
|
|
@@ -2819,7 +4054,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2819
4054
|
CardSubtitleComponent,
|
|
2820
4055
|
CardContentComponent,
|
|
2821
4056
|
ForgotPasswordAuthFormComponent,
|
|
2822
|
-
RedirectErrorComponent,
|
|
2823
4057
|
],
|
|
2824
4058
|
template: `
|
|
2825
4059
|
<div class="fui-screen">
|
|
@@ -2829,14 +4063,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2829
4063
|
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
2830
4064
|
</fui-card-header>
|
|
2831
4065
|
<fui-card-content>
|
|
2832
|
-
<fui-forgot-password-auth-form
|
|
2833
|
-
<fui-redirect-error />
|
|
4066
|
+
<fui-forgot-password-auth-form [backToSignIn]="backToSignIn" (passwordSent)="passwordSent.emit()" />
|
|
2834
4067
|
</fui-card-content>
|
|
2835
4068
|
</fui-card>
|
|
2836
4069
|
</div>
|
|
2837
4070
|
`,
|
|
2838
4071
|
}]
|
|
2839
|
-
}], propDecorators: { passwordSent: [{
|
|
4072
|
+
}], propDecorators: { passwordSent: [{
|
|
4073
|
+
type: Output
|
|
4074
|
+
}], backToSignIn: [{
|
|
4075
|
+
type: Output
|
|
4076
|
+
}] } });
|
|
2840
4077
|
|
|
2841
4078
|
/**
|
|
2842
4079
|
* Copyright 2025 Google LLC
|
|
@@ -2853,76 +4090,67 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2853
4090
|
* See the License for the specific language governing permissions and
|
|
2854
4091
|
* limitations under the License.
|
|
2855
4092
|
*/
|
|
2856
|
-
class DividerComponent {
|
|
2857
|
-
label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
|
|
2858
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: DividerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2859
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: DividerComponent, isStandalone: true, selector: "fui-divider", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2860
|
-
<div class="fui-divider my-6">
|
|
2861
|
-
<div class="fui-divider__line"></div>
|
|
2862
|
-
@if (label()) {
|
|
2863
|
-
<div class="fui-divider__text">{{ label() }}</div>
|
|
2864
|
-
<div class="fui-divider__line"></div>
|
|
2865
|
-
}
|
|
2866
|
-
</div>
|
|
2867
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
2868
|
-
}
|
|
2869
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: DividerComponent, decorators: [{
|
|
2870
|
-
type: Component,
|
|
2871
|
-
args: [{
|
|
2872
|
-
selector: "fui-divider",
|
|
2873
|
-
standalone: true,
|
|
2874
|
-
imports: [CommonModule],
|
|
2875
|
-
template: `
|
|
2876
|
-
<div class="fui-divider my-6">
|
|
2877
|
-
<div class="fui-divider__line"></div>
|
|
2878
|
-
@if (label()) {
|
|
2879
|
-
<div class="fui-divider__text">{{ label() }}</div>
|
|
2880
|
-
<div class="fui-divider__line"></div>
|
|
2881
|
-
}
|
|
2882
|
-
</div>
|
|
2883
|
-
`,
|
|
2884
|
-
}]
|
|
2885
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
|
|
2886
|
-
|
|
2887
4093
|
/**
|
|
2888
|
-
*
|
|
2889
|
-
*
|
|
2890
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
2891
|
-
* you may not use this file except in compliance with the License.
|
|
2892
|
-
* You may obtain a copy of the License at
|
|
4094
|
+
* A screen component for multi-factor authentication enrollment.
|
|
2893
4095
|
*
|
|
2894
|
-
*
|
|
2895
|
-
*
|
|
2896
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
2897
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
2898
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
2899
|
-
* See the License for the specific language governing permissions and
|
|
2900
|
-
* limitations under the License.
|
|
4096
|
+
* Displays the MFA enrollment form for setting up multi-factor authentication.
|
|
2901
4097
|
*/
|
|
2902
|
-
class
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
4098
|
+
class MultiFactorAuthEnrollmentScreenComponent {
|
|
4099
|
+
/** The available MFA factor types for enrollment. */
|
|
4100
|
+
hints = input([FactorId.TOTP, FactorId.PHONE], ...(ngDevMode ? [{ debugName: "hints" }] : []));
|
|
4101
|
+
/** Event emitter fired when MFA enrollment is completed. */
|
|
4102
|
+
onEnrollment = new EventEmitter();
|
|
4103
|
+
titleText = injectTranslation("labels", "multiFactorEnrollment");
|
|
4104
|
+
subtitleText = injectTranslation("prompts", "mfaEnrollmentPrompt");
|
|
4105
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MultiFactorAuthEnrollmentScreenComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4106
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.7", type: MultiFactorAuthEnrollmentScreenComponent, isStandalone: true, selector: "fui-multi-factor-auth-enrollment-screen", inputs: { hints: { classPropertyName: "hints", publicName: "hints", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onEnrollment: "onEnrollment" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
4107
|
+
<div class="fui-screen">
|
|
4108
|
+
<fui-card>
|
|
4109
|
+
<fui-card-header>
|
|
4110
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
4111
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
4112
|
+
</fui-card-header>
|
|
4113
|
+
<fui-card-content>
|
|
4114
|
+
<fui-multi-factor-auth-enrollment-form [hints]="hints()" (onEnrollment)="onEnrollment.emit()" />
|
|
4115
|
+
</fui-card-content>
|
|
4116
|
+
</fui-card>
|
|
2909
4117
|
</div>
|
|
2910
|
-
`, isInline: true, dependencies: [{ kind: "component", type:
|
|
4118
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CardComponent, selector: "fui-card" }, { kind: "component", type: CardHeaderComponent, selector: "fui-card-header" }, { kind: "component", type: CardTitleComponent, selector: "fui-card-title" }, { kind: "component", type: CardSubtitleComponent, selector: "fui-card-subtitle" }, { kind: "component", type: CardContentComponent, selector: "fui-card-content" }, { kind: "component", type: MultiFactorAuthEnrollmentFormComponent, selector: "fui-multi-factor-auth-enrollment-form", inputs: ["hints"], outputs: ["onEnrollment"] }] });
|
|
2911
4119
|
}
|
|
2912
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type:
|
|
4120
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MultiFactorAuthEnrollmentScreenComponent, decorators: [{
|
|
2913
4121
|
type: Component,
|
|
2914
4122
|
args: [{
|
|
2915
|
-
selector: "fui-
|
|
4123
|
+
selector: "fui-multi-factor-auth-enrollment-screen",
|
|
2916
4124
|
standalone: true,
|
|
2917
|
-
|
|
4125
|
+
host: {
|
|
4126
|
+
style: "display: block;",
|
|
4127
|
+
},
|
|
4128
|
+
imports: [
|
|
4129
|
+
CommonModule,
|
|
4130
|
+
CardComponent,
|
|
4131
|
+
CardHeaderComponent,
|
|
4132
|
+
CardTitleComponent,
|
|
4133
|
+
CardSubtitleComponent,
|
|
4134
|
+
CardContentComponent,
|
|
4135
|
+
MultiFactorAuthEnrollmentFormComponent,
|
|
4136
|
+
],
|
|
2918
4137
|
template: `
|
|
2919
|
-
<
|
|
2920
|
-
|
|
2921
|
-
|
|
4138
|
+
<div class="fui-screen">
|
|
4139
|
+
<fui-card>
|
|
4140
|
+
<fui-card-header>
|
|
4141
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
4142
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
4143
|
+
</fui-card-header>
|
|
4144
|
+
<fui-card-content>
|
|
4145
|
+
<fui-multi-factor-auth-enrollment-form [hints]="hints()" (onEnrollment)="onEnrollment.emit()" />
|
|
4146
|
+
</fui-card-content>
|
|
4147
|
+
</fui-card>
|
|
2922
4148
|
</div>
|
|
2923
4149
|
`,
|
|
2924
4150
|
}]
|
|
2925
|
-
}] }
|
|
4151
|
+
}], propDecorators: { hints: [{ type: i0.Input, args: [{ isSignal: true, alias: "hints", required: false }] }], onEnrollment: [{
|
|
4152
|
+
type: Output
|
|
4153
|
+
}] } });
|
|
2926
4154
|
|
|
2927
4155
|
/**
|
|
2928
4156
|
* Copyright 2025 Google LLC
|
|
@@ -2939,39 +4167,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2939
4167
|
* See the License for the specific language governing permissions and
|
|
2940
4168
|
* limitations under the License.
|
|
2941
4169
|
*/
|
|
4170
|
+
/**
|
|
4171
|
+
* A screen component for OAuth authentication.
|
|
4172
|
+
*
|
|
4173
|
+
* Automatically displays the MFA assertion screen if a multi-factor resolver is present.
|
|
4174
|
+
* Use this screen to display OAuth sign-in buttons.
|
|
4175
|
+
*/
|
|
2942
4176
|
class OAuthScreenComponent {
|
|
2943
4177
|
ui = injectUI();
|
|
2944
4178
|
mfaResolver = computed(() => this.ui().multiFactorResolver, ...(ngDevMode ? [{ debugName: "mfaResolver" }] : []));
|
|
2945
4179
|
titleText = injectTranslation("labels", "signIn");
|
|
2946
4180
|
subtitleText = injectTranslation("prompts", "signInToAccount");
|
|
4181
|
+
constructor() {
|
|
4182
|
+
injectUserAuthenticated((user) => {
|
|
4183
|
+
this.onSignIn.emit(user);
|
|
4184
|
+
});
|
|
4185
|
+
}
|
|
4186
|
+
/** Event emitter for successful sign-in. */
|
|
4187
|
+
onSignIn = new EventEmitter();
|
|
2947
4188
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: OAuthScreenComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2948
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: OAuthScreenComponent, isStandalone: true, selector: "fui-oauth-screen", ngImport: i0, template: `
|
|
2949
|
-
|
|
2950
|
-
<fui-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
<fui-
|
|
4189
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: OAuthScreenComponent, isStandalone: true, selector: "fui-oauth-screen", outputs: { onSignIn: "onSignIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
4190
|
+
@if (mfaResolver()) {
|
|
4191
|
+
<fui-multi-factor-auth-assertion-screen />
|
|
4192
|
+
} @else {
|
|
4193
|
+
<div class="fui-screen">
|
|
4194
|
+
<fui-card>
|
|
4195
|
+
<fui-card-header>
|
|
4196
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
4197
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
4198
|
+
</fui-card-header>
|
|
4199
|
+
<fui-card-content>
|
|
4200
|
+
<div class="fui-screen__children">
|
|
2960
4201
|
<ng-content></ng-content>
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
</fui-card
|
|
2966
|
-
</
|
|
2967
|
-
|
|
2968
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CardComponent, selector: "fui-card" }, { kind: "component", type: CardHeaderComponent, selector: "fui-card-header" }, { kind: "component", type: CardTitleComponent, selector: "fui-card-title" }, { kind: "component", type: CardSubtitleComponent, selector: "fui-card-subtitle" }, { kind: "component", type: CardContentComponent, selector: "fui-card-content" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type:
|
|
4202
|
+
<fui-redirect-error />
|
|
4203
|
+
<fui-policies />
|
|
4204
|
+
</div>
|
|
4205
|
+
</fui-card-content>
|
|
4206
|
+
</fui-card>
|
|
4207
|
+
</div>
|
|
4208
|
+
}
|
|
4209
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CardComponent, selector: "fui-card" }, { kind: "component", type: CardHeaderComponent, selector: "fui-card-header" }, { kind: "component", type: CardTitleComponent, selector: "fui-card-title" }, { kind: "component", type: CardSubtitleComponent, selector: "fui-card-subtitle" }, { kind: "component", type: CardContentComponent, selector: "fui-card-content" }, { kind: "component", type: PoliciesComponent, selector: "fui-policies" }, { kind: "component", type: MultiFactorAuthAssertionScreenComponent, selector: "fui-multi-factor-auth-assertion-screen", outputs: ["onSuccess"] }, { kind: "component", type: RedirectErrorComponent, selector: "fui-redirect-error" }] });
|
|
2969
4210
|
}
|
|
2970
4211
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: OAuthScreenComponent, decorators: [{
|
|
2971
4212
|
type: Component,
|
|
2972
4213
|
args: [{
|
|
2973
4214
|
selector: "fui-oauth-screen",
|
|
2974
4215
|
standalone: true,
|
|
4216
|
+
host: {
|
|
4217
|
+
style: "display: block;",
|
|
4218
|
+
},
|
|
2975
4219
|
imports: [
|
|
2976
4220
|
CommonModule,
|
|
2977
4221
|
CardComponent,
|
|
@@ -2980,33 +4224,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2980
4224
|
CardSubtitleComponent,
|
|
2981
4225
|
CardContentComponent,
|
|
2982
4226
|
PoliciesComponent,
|
|
2983
|
-
|
|
2984
|
-
MultiFactorAuthAssertionFormComponent,
|
|
4227
|
+
MultiFactorAuthAssertionScreenComponent,
|
|
2985
4228
|
RedirectErrorComponent,
|
|
2986
4229
|
],
|
|
2987
4230
|
template: `
|
|
2988
|
-
|
|
2989
|
-
<fui-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
<fui-
|
|
4231
|
+
@if (mfaResolver()) {
|
|
4232
|
+
<fui-multi-factor-auth-assertion-screen />
|
|
4233
|
+
} @else {
|
|
4234
|
+
<div class="fui-screen">
|
|
4235
|
+
<fui-card>
|
|
4236
|
+
<fui-card-header>
|
|
4237
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
4238
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
4239
|
+
</fui-card-header>
|
|
4240
|
+
<fui-card-content>
|
|
4241
|
+
<div class="fui-screen__children">
|
|
2999
4242
|
<ng-content></ng-content>
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
</fui-card
|
|
3005
|
-
</
|
|
3006
|
-
|
|
4243
|
+
<fui-redirect-error />
|
|
4244
|
+
<fui-policies />
|
|
4245
|
+
</div>
|
|
4246
|
+
</fui-card-content>
|
|
4247
|
+
</fui-card>
|
|
4248
|
+
</div>
|
|
4249
|
+
}
|
|
3007
4250
|
`,
|
|
3008
4251
|
}]
|
|
3009
|
-
}]
|
|
4252
|
+
}], ctorParameters: () => [], propDecorators: { onSignIn: [{
|
|
4253
|
+
type: Output
|
|
4254
|
+
}] } });
|
|
3010
4255
|
|
|
3011
4256
|
/**
|
|
3012
4257
|
* Copyright 2025 Google LLC
|
|
@@ -3023,39 +4268,52 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
3023
4268
|
* See the License for the specific language governing permissions and
|
|
3024
4269
|
* limitations under the License.
|
|
3025
4270
|
*/
|
|
4271
|
+
/**
|
|
4272
|
+
* A screen component for phone number authentication.
|
|
4273
|
+
*
|
|
4274
|
+
* Automatically displays the MFA assertion screen if a multi-factor resolver is present.
|
|
4275
|
+
*/
|
|
3026
4276
|
class PhoneAuthScreenComponent {
|
|
3027
4277
|
ui = injectUI();
|
|
3028
4278
|
mfaResolver = computed(() => this.ui().multiFactorResolver, ...(ngDevMode ? [{ debugName: "mfaResolver" }] : []));
|
|
3029
4279
|
titleText = injectTranslation("labels", "signIn");
|
|
3030
4280
|
subtitleText = injectTranslation("prompts", "signInToAccount");
|
|
3031
|
-
|
|
3032
|
-
|
|
4281
|
+
constructor() {
|
|
4282
|
+
injectUserAuthenticated((user) => {
|
|
4283
|
+
this.signIn.emit(user);
|
|
4284
|
+
});
|
|
4285
|
+
}
|
|
4286
|
+
/** Event emitter for successful sign-in. */
|
|
4287
|
+
signIn = new EventEmitter();
|
|
3033
4288
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: PhoneAuthScreenComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3034
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: PhoneAuthScreenComponent, isStandalone: true, selector: "fui-phone-auth-screen",
|
|
3035
|
-
|
|
3036
|
-
<fui-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
<fui-phone-auth-form (signIn)="signIn.emit($event)" />
|
|
3046
|
-
<fui-redirect-error />
|
|
4289
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: PhoneAuthScreenComponent, isStandalone: true, selector: "fui-phone-auth-screen", outputs: { signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
4290
|
+
@if (mfaResolver()) {
|
|
4291
|
+
<fui-multi-factor-auth-assertion-screen />
|
|
4292
|
+
} @else {
|
|
4293
|
+
<div class="fui-screen">
|
|
4294
|
+
<fui-card>
|
|
4295
|
+
<fui-card-header>
|
|
4296
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
4297
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
4298
|
+
</fui-card-header>
|
|
4299
|
+
<fui-card-content>
|
|
4300
|
+
<fui-phone-auth-form (signIn)="signIn.emit($event.user)" />
|
|
3047
4301
|
<ng-content />
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
4302
|
+
<fui-redirect-error />
|
|
4303
|
+
</fui-card-content>
|
|
4304
|
+
</fui-card>
|
|
4305
|
+
</div>
|
|
4306
|
+
}
|
|
4307
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CardComponent, selector: "fui-card" }, { kind: "component", type: CardHeaderComponent, selector: "fui-card-header" }, { kind: "component", type: CardTitleComponent, selector: "fui-card-title" }, { kind: "component", type: CardSubtitleComponent, selector: "fui-card-subtitle" }, { kind: "component", type: CardContentComponent, selector: "fui-card-content" }, { kind: "component", type: PhoneAuthFormComponent, selector: "fui-phone-auth-form", outputs: ["signIn"] }, { kind: "component", type: MultiFactorAuthAssertionScreenComponent, selector: "fui-multi-factor-auth-assertion-screen", outputs: ["onSuccess"] }, { kind: "component", type: RedirectErrorComponent, selector: "fui-redirect-error" }] });
|
|
3053
4308
|
}
|
|
3054
4309
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: PhoneAuthScreenComponent, decorators: [{
|
|
3055
4310
|
type: Component,
|
|
3056
4311
|
args: [{
|
|
3057
4312
|
selector: "fui-phone-auth-screen",
|
|
3058
4313
|
standalone: true,
|
|
4314
|
+
host: {
|
|
4315
|
+
style: "display: block;",
|
|
4316
|
+
},
|
|
3059
4317
|
imports: [
|
|
3060
4318
|
CommonModule,
|
|
3061
4319
|
CardComponent,
|
|
@@ -3064,30 +4322,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
3064
4322
|
CardSubtitleComponent,
|
|
3065
4323
|
CardContentComponent,
|
|
3066
4324
|
PhoneAuthFormComponent,
|
|
3067
|
-
|
|
4325
|
+
MultiFactorAuthAssertionScreenComponent,
|
|
3068
4326
|
RedirectErrorComponent,
|
|
3069
4327
|
],
|
|
3070
4328
|
template: `
|
|
3071
|
-
|
|
3072
|
-
<fui-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
<fui-phone-auth-form (signIn)="signIn.emit($event)" />
|
|
3082
|
-
<fui-redirect-error />
|
|
4329
|
+
@if (mfaResolver()) {
|
|
4330
|
+
<fui-multi-factor-auth-assertion-screen />
|
|
4331
|
+
} @else {
|
|
4332
|
+
<div class="fui-screen">
|
|
4333
|
+
<fui-card>
|
|
4334
|
+
<fui-card-header>
|
|
4335
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
4336
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
4337
|
+
</fui-card-header>
|
|
4338
|
+
<fui-card-content>
|
|
4339
|
+
<fui-phone-auth-form (signIn)="signIn.emit($event.user)" />
|
|
3083
4340
|
<ng-content />
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
4341
|
+
<fui-redirect-error />
|
|
4342
|
+
</fui-card-content>
|
|
4343
|
+
</fui-card>
|
|
4344
|
+
</div>
|
|
4345
|
+
}
|
|
3088
4346
|
`,
|
|
3089
4347
|
}]
|
|
3090
|
-
}],
|
|
4348
|
+
}], ctorParameters: () => [], propDecorators: { signIn: [{
|
|
4349
|
+
type: Output
|
|
4350
|
+
}] } });
|
|
3091
4351
|
|
|
3092
4352
|
/**
|
|
3093
4353
|
* Copyright 2025 Google LLC
|
|
@@ -3104,44 +4364,56 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
3104
4364
|
* See the License for the specific language governing permissions and
|
|
3105
4365
|
* limitations under the License.
|
|
3106
4366
|
*/
|
|
4367
|
+
/**
|
|
4368
|
+
* A screen component for email/password sign-in.
|
|
4369
|
+
*
|
|
4370
|
+
* Automatically displays the MFA assertion screen if a multi-factor resolver is present.
|
|
4371
|
+
*/
|
|
3107
4372
|
class SignInAuthScreenComponent {
|
|
3108
4373
|
ui = injectUI();
|
|
3109
4374
|
mfaResolver = computed(() => this.ui().multiFactorResolver, ...(ngDevMode ? [{ debugName: "mfaResolver" }] : []));
|
|
3110
4375
|
titleText = injectTranslation("labels", "signIn");
|
|
3111
4376
|
subtitleText = injectTranslation("prompts", "signInToAccount");
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
4377
|
+
constructor() {
|
|
4378
|
+
injectUserAuthenticated((user) => {
|
|
4379
|
+
this.signIn.emit(user);
|
|
4380
|
+
});
|
|
4381
|
+
}
|
|
4382
|
+
/** Event emitter for forgot password action. */
|
|
4383
|
+
forgotPassword = new EventEmitter();
|
|
4384
|
+
/** Event emitter for sign up action. */
|
|
4385
|
+
signUp = new EventEmitter();
|
|
4386
|
+
/** Event emitter for successful sign-in. */
|
|
4387
|
+
signIn = new EventEmitter();
|
|
3115
4388
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SignInAuthScreenComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3116
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SignInAuthScreenComponent, isStandalone: true, selector: "fui-sign-in-auth-screen", outputs: { forgotPassword: "forgotPassword", signUp: "signUp", signIn: "signIn" }, ngImport: i0, template: `
|
|
3117
|
-
|
|
3118
|
-
<fui-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
<fui-sign-in-auth-form
|
|
3128
|
-
(forgotPassword)="forgotPassword.emit()"
|
|
3129
|
-
(signUp)="signUp.emit()"
|
|
3130
|
-
(signIn)="signIn.emit($event)"
|
|
3131
|
-
/>
|
|
3132
|
-
<fui-redirect-error />
|
|
4389
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SignInAuthScreenComponent, isStandalone: true, selector: "fui-sign-in-auth-screen", outputs: { forgotPassword: "forgotPassword", signUp: "signUp", signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
4390
|
+
@if (mfaResolver()) {
|
|
4391
|
+
<fui-multi-factor-auth-assertion-screen />
|
|
4392
|
+
} @else {
|
|
4393
|
+
<div class="fui-screen">
|
|
4394
|
+
<fui-card>
|
|
4395
|
+
<fui-card-header>
|
|
4396
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
4397
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
4398
|
+
</fui-card-header>
|
|
4399
|
+
<fui-card-content>
|
|
4400
|
+
<fui-sign-in-auth-form [forgotPassword]="forgotPassword" [signUp]="signUp" />
|
|
3133
4401
|
<ng-content />
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
4402
|
+
<fui-redirect-error />
|
|
4403
|
+
</fui-card-content>
|
|
4404
|
+
</fui-card>
|
|
4405
|
+
</div>
|
|
4406
|
+
}
|
|
4407
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CardComponent, selector: "fui-card" }, { kind: "component", type: CardHeaderComponent, selector: "fui-card-header" }, { kind: "component", type: CardTitleComponent, selector: "fui-card-title" }, { kind: "component", type: CardSubtitleComponent, selector: "fui-card-subtitle" }, { kind: "component", type: CardContentComponent, selector: "fui-card-content" }, { kind: "component", type: SignInAuthFormComponent, selector: "fui-sign-in-auth-form", inputs: ["forgotPassword", "signUp"], outputs: ["signIn"] }, { kind: "component", type: MultiFactorAuthAssertionScreenComponent, selector: "fui-multi-factor-auth-assertion-screen", outputs: ["onSuccess"] }, { kind: "component", type: RedirectErrorComponent, selector: "fui-redirect-error" }] });
|
|
3139
4408
|
}
|
|
3140
4409
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SignInAuthScreenComponent, decorators: [{
|
|
3141
4410
|
type: Component,
|
|
3142
4411
|
args: [{
|
|
3143
4412
|
selector: "fui-sign-in-auth-screen",
|
|
3144
4413
|
standalone: true,
|
|
4414
|
+
host: {
|
|
4415
|
+
style: "display: block;",
|
|
4416
|
+
},
|
|
3145
4417
|
imports: [
|
|
3146
4418
|
CommonModule,
|
|
3147
4419
|
CardComponent,
|
|
@@ -3150,34 +4422,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
3150
4422
|
CardSubtitleComponent,
|
|
3151
4423
|
CardContentComponent,
|
|
3152
4424
|
SignInAuthFormComponent,
|
|
3153
|
-
|
|
4425
|
+
MultiFactorAuthAssertionScreenComponent,
|
|
3154
4426
|
RedirectErrorComponent,
|
|
3155
4427
|
],
|
|
3156
4428
|
template: `
|
|
3157
|
-
|
|
3158
|
-
<fui-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
<fui-sign-in-auth-form
|
|
3168
|
-
(forgotPassword)="forgotPassword.emit()"
|
|
3169
|
-
(signUp)="signUp.emit()"
|
|
3170
|
-
(signIn)="signIn.emit($event)"
|
|
3171
|
-
/>
|
|
3172
|
-
<fui-redirect-error />
|
|
4429
|
+
@if (mfaResolver()) {
|
|
4430
|
+
<fui-multi-factor-auth-assertion-screen />
|
|
4431
|
+
} @else {
|
|
4432
|
+
<div class="fui-screen">
|
|
4433
|
+
<fui-card>
|
|
4434
|
+
<fui-card-header>
|
|
4435
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
4436
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
4437
|
+
</fui-card-header>
|
|
4438
|
+
<fui-card-content>
|
|
4439
|
+
<fui-sign-in-auth-form [forgotPassword]="forgotPassword" [signUp]="signUp" />
|
|
3173
4440
|
<ng-content />
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
4441
|
+
<fui-redirect-error />
|
|
4442
|
+
</fui-card-content>
|
|
4443
|
+
</fui-card>
|
|
4444
|
+
</div>
|
|
4445
|
+
}
|
|
3178
4446
|
`,
|
|
3179
4447
|
}]
|
|
3180
|
-
}],
|
|
4448
|
+
}], ctorParameters: () => [], propDecorators: { forgotPassword: [{
|
|
4449
|
+
type: Output
|
|
4450
|
+
}], signUp: [{
|
|
4451
|
+
type: Output
|
|
4452
|
+
}], signIn: [{
|
|
4453
|
+
type: Output
|
|
4454
|
+
}] } });
|
|
3181
4455
|
|
|
3182
4456
|
/**
|
|
3183
4457
|
* Copyright 2025 Google LLC
|
|
@@ -3194,39 +4468,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
3194
4468
|
* See the License for the specific language governing permissions and
|
|
3195
4469
|
* limitations under the License.
|
|
3196
4470
|
*/
|
|
4471
|
+
/**
|
|
4472
|
+
* A screen component for email/password sign-up.
|
|
4473
|
+
*
|
|
4474
|
+
* Automatically displays the MFA assertion screen if a multi-factor resolver is present.
|
|
4475
|
+
*/
|
|
3197
4476
|
class SignUpAuthScreenComponent {
|
|
3198
4477
|
ui = injectUI();
|
|
3199
4478
|
mfaResolver = computed(() => this.ui().multiFactorResolver, ...(ngDevMode ? [{ debugName: "mfaResolver" }] : []));
|
|
3200
4479
|
titleText = injectTranslation("labels", "signUp");
|
|
3201
4480
|
subtitleText = injectTranslation("prompts", "enterDetailsToCreate");
|
|
3202
|
-
|
|
3203
|
-
|
|
4481
|
+
constructor() {
|
|
4482
|
+
injectUserAuthenticated((user) => {
|
|
4483
|
+
this.signUp.emit(user);
|
|
4484
|
+
});
|
|
4485
|
+
}
|
|
4486
|
+
/** Event emitter for successful sign-up. */
|
|
4487
|
+
signUp = new EventEmitter();
|
|
4488
|
+
/** Event emitter for sign in action. */
|
|
4489
|
+
signIn = new EventEmitter();
|
|
3204
4490
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SignUpAuthScreenComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3205
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SignUpAuthScreenComponent, isStandalone: true, selector: "fui-sign-up-auth-screen", outputs: { signUp: "signUp", signIn: "signIn" }, ngImport: i0, template: `
|
|
3206
|
-
|
|
3207
|
-
<fui-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
<fui-sign-up-auth-form
|
|
3217
|
-
<fui-redirect-error />
|
|
4491
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SignUpAuthScreenComponent, isStandalone: true, selector: "fui-sign-up-auth-screen", outputs: { signUp: "signUp", signIn: "signIn" }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
4492
|
+
@if (mfaResolver()) {
|
|
4493
|
+
<fui-multi-factor-auth-assertion-screen />
|
|
4494
|
+
} @else {
|
|
4495
|
+
<div class="fui-screen">
|
|
4496
|
+
<fui-card>
|
|
4497
|
+
<fui-card-header>
|
|
4498
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
4499
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
4500
|
+
</fui-card-header>
|
|
4501
|
+
<fui-card-content>
|
|
4502
|
+
<fui-sign-up-auth-form [signIn]="signIn" (signUp)="signUp.emit($event.user)" />
|
|
3218
4503
|
<ng-content />
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
4504
|
+
<fui-redirect-error />
|
|
4505
|
+
</fui-card-content>
|
|
4506
|
+
</fui-card>
|
|
4507
|
+
</div>
|
|
4508
|
+
}
|
|
4509
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: CardComponent, selector: "fui-card" }, { kind: "component", type: CardHeaderComponent, selector: "fui-card-header" }, { kind: "component", type: CardTitleComponent, selector: "fui-card-title" }, { kind: "component", type: CardSubtitleComponent, selector: "fui-card-subtitle" }, { kind: "component", type: CardContentComponent, selector: "fui-card-content" }, { kind: "component", type: SignUpAuthFormComponent, selector: "fui-sign-up-auth-form", inputs: ["signIn"], outputs: ["signUp"] }, { kind: "component", type: MultiFactorAuthAssertionScreenComponent, selector: "fui-multi-factor-auth-assertion-screen", outputs: ["onSuccess"] }, { kind: "component", type: RedirectErrorComponent, selector: "fui-redirect-error" }] });
|
|
3224
4510
|
}
|
|
3225
4511
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SignUpAuthScreenComponent, decorators: [{
|
|
3226
4512
|
type: Component,
|
|
3227
4513
|
args: [{
|
|
3228
4514
|
selector: "fui-sign-up-auth-screen",
|
|
3229
4515
|
standalone: true,
|
|
4516
|
+
host: {
|
|
4517
|
+
style: "display: block;",
|
|
4518
|
+
},
|
|
3230
4519
|
imports: [
|
|
3231
4520
|
CommonModule,
|
|
3232
4521
|
CardComponent,
|
|
@@ -3235,30 +4524,133 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
3235
4524
|
CardSubtitleComponent,
|
|
3236
4525
|
CardContentComponent,
|
|
3237
4526
|
SignUpAuthFormComponent,
|
|
3238
|
-
|
|
4527
|
+
MultiFactorAuthAssertionScreenComponent,
|
|
3239
4528
|
RedirectErrorComponent,
|
|
3240
4529
|
],
|
|
3241
4530
|
template: `
|
|
3242
|
-
|
|
3243
|
-
<fui-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
<fui-sign-up-auth-form
|
|
3253
|
-
<fui-redirect-error />
|
|
4531
|
+
@if (mfaResolver()) {
|
|
4532
|
+
<fui-multi-factor-auth-assertion-screen />
|
|
4533
|
+
} @else {
|
|
4534
|
+
<div class="fui-screen">
|
|
4535
|
+
<fui-card>
|
|
4536
|
+
<fui-card-header>
|
|
4537
|
+
<fui-card-title>{{ titleText() }}</fui-card-title>
|
|
4538
|
+
<fui-card-subtitle>{{ subtitleText() }}</fui-card-subtitle>
|
|
4539
|
+
</fui-card-header>
|
|
4540
|
+
<fui-card-content>
|
|
4541
|
+
<fui-sign-up-auth-form [signIn]="signIn" (signUp)="signUp.emit($event.user)" />
|
|
3254
4542
|
<ng-content />
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
4543
|
+
<fui-redirect-error />
|
|
4544
|
+
</fui-card-content>
|
|
4545
|
+
</fui-card>
|
|
4546
|
+
</div>
|
|
4547
|
+
}
|
|
4548
|
+
`,
|
|
4549
|
+
}]
|
|
4550
|
+
}], ctorParameters: () => [], propDecorators: { signUp: [{
|
|
4551
|
+
type: Output
|
|
4552
|
+
}], signIn: [{
|
|
4553
|
+
type: Output
|
|
4554
|
+
}] } });
|
|
4555
|
+
|
|
4556
|
+
/**
|
|
4557
|
+
* Copyright 2025 Google LLC
|
|
4558
|
+
*
|
|
4559
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4560
|
+
* you may not use this file except in compliance with the License.
|
|
4561
|
+
* You may obtain a copy of the License at
|
|
4562
|
+
*
|
|
4563
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
4564
|
+
*
|
|
4565
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
4566
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
4567
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
4568
|
+
* See the License for the specific language governing permissions and
|
|
4569
|
+
* limitations under the License.
|
|
4570
|
+
*/
|
|
4571
|
+
/**
|
|
4572
|
+
* A divider component that can display a line or a line with text in the middle.
|
|
4573
|
+
*/
|
|
4574
|
+
class DividerComponent {
|
|
4575
|
+
/** Optional label text to display in the center of the divider. */
|
|
4576
|
+
label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
|
|
4577
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: DividerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4578
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: DividerComponent, isStandalone: true, selector: "fui-divider", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
4579
|
+
<div class="fui-divider my-6">
|
|
4580
|
+
<div class="fui-divider__line"></div>
|
|
4581
|
+
@if (label()) {
|
|
4582
|
+
<div class="fui-divider__text">{{ label() }}</div>
|
|
4583
|
+
<div class="fui-divider__line"></div>
|
|
4584
|
+
}
|
|
4585
|
+
</div>
|
|
4586
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
4587
|
+
}
|
|
4588
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: DividerComponent, decorators: [{
|
|
4589
|
+
type: Component,
|
|
4590
|
+
args: [{
|
|
4591
|
+
selector: "fui-divider",
|
|
4592
|
+
standalone: true,
|
|
4593
|
+
imports: [CommonModule],
|
|
4594
|
+
host: {
|
|
4595
|
+
style: "display: block;",
|
|
4596
|
+
},
|
|
4597
|
+
template: `
|
|
4598
|
+
<div class="fui-divider my-6">
|
|
4599
|
+
<div class="fui-divider__line"></div>
|
|
4600
|
+
@if (label()) {
|
|
4601
|
+
<div class="fui-divider__text">{{ label() }}</div>
|
|
4602
|
+
<div class="fui-divider__line"></div>
|
|
4603
|
+
}
|
|
4604
|
+
</div>
|
|
4605
|
+
`,
|
|
4606
|
+
}]
|
|
4607
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
|
|
4608
|
+
|
|
4609
|
+
/**
|
|
4610
|
+
* Copyright 2025 Google LLC
|
|
4611
|
+
*
|
|
4612
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4613
|
+
* you may not use this file except in compliance with the License.
|
|
4614
|
+
* You may obtain a copy of the License at
|
|
4615
|
+
*
|
|
4616
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
4617
|
+
*
|
|
4618
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
4619
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
4620
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
4621
|
+
* See the License for the specific language governing permissions and
|
|
4622
|
+
* limitations under the License.
|
|
4623
|
+
*/
|
|
4624
|
+
/**
|
|
4625
|
+
* A content wrapper component that displays a divider and children content.
|
|
4626
|
+
*/
|
|
4627
|
+
class ContentComponent {
|
|
4628
|
+
dividerOrLabel = injectTranslation("messages", "dividerOr");
|
|
4629
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4630
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: ContentComponent, isStandalone: true, selector: "fui-content", host: { styleAttribute: "display: block;" }, ngImport: i0, template: `
|
|
4631
|
+
<fui-divider [label]="dividerOrLabel()" />
|
|
4632
|
+
<div class="fui-screen__children">
|
|
4633
|
+
<ng-content></ng-content>
|
|
4634
|
+
</div>
|
|
4635
|
+
`, isInline: true, dependencies: [{ kind: "component", type: DividerComponent, selector: "fui-divider", inputs: ["label"] }] });
|
|
4636
|
+
}
|
|
4637
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ContentComponent, decorators: [{
|
|
4638
|
+
type: Component,
|
|
4639
|
+
args: [{
|
|
4640
|
+
selector: "fui-content",
|
|
4641
|
+
standalone: true,
|
|
4642
|
+
imports: [DividerComponent],
|
|
4643
|
+
host: {
|
|
4644
|
+
style: "display: block;",
|
|
4645
|
+
},
|
|
4646
|
+
template: `
|
|
4647
|
+
<fui-divider [label]="dividerOrLabel()" />
|
|
4648
|
+
<div class="fui-screen__children">
|
|
4649
|
+
<ng-content></ng-content>
|
|
3258
4650
|
</div>
|
|
3259
4651
|
`,
|
|
3260
4652
|
}]
|
|
3261
|
-
}]
|
|
4653
|
+
}] });
|
|
3262
4654
|
|
|
3263
4655
|
/**
|
|
3264
4656
|
* Copyright 2025 Google LLC
|
|
@@ -3284,5 +4676,5 @@ if (!isDevMode()) {
|
|
|
3284
4676
|
* Generated bundle index. Do not edit.
|
|
3285
4677
|
*/
|
|
3286
4678
|
|
|
3287
|
-
export { AppleSignInButtonComponent, ButtonComponent, CardComponent, ContentComponent, CountrySelectorComponent, DividerComponent, EmailLinkAuthFormComponent, EmailLinkAuthScreenComponent, FacebookSignInButtonComponent, ForgotPasswordAuthFormComponent, ForgotPasswordAuthScreenComponent,
|
|
4679
|
+
export { AppleSignInButtonComponent, ButtonComponent, CardComponent, CardContentComponent, CardHeaderComponent, CardSubtitleComponent, CardTitleComponent, ContentComponent, CountrySelectorComponent, DividerComponent, EmailLinkAuthFormComponent, EmailLinkAuthScreenComponent, FacebookSignInButtonComponent, ForgotPasswordAuthFormComponent, ForgotPasswordAuthScreenComponent, GitHubSignInButtonComponent, GoogleSignInButtonComponent, MicrosoftSignInButtonComponent, MultiFactorAuthAssertionFormComponent, MultiFactorAuthAssertionScreenComponent, MultiFactorAuthEnrollmentFormComponent, MultiFactorAuthEnrollmentScreenComponent, OAuthButtonComponent, OAuthScreenComponent, PhoneAuthFormComponent, PhoneAuthScreenComponent, PoliciesComponent, RedirectErrorComponent, SignInAuthFormComponent, SignInAuthScreenComponent, SignUpAuthFormComponent, SignUpAuthScreenComponent, SmsMultiFactorAssertionFormComponent, SmsMultiFactorAssertionPhoneFormComponent, SmsMultiFactorAssertionVerifyFormComponent, SmsMultiFactorEnrollmentFormComponent, TotpMultiFactorAssertionFormComponent, TotpMultiFactorEnrollmentFormComponent, TwitterSignInButtonComponent, injectCountries, injectDefaultCountry, injectEmailLinkAuthFormSchema, injectForgotPasswordAuthFormSchema, injectMultiFactorPhoneAuthAssertionFormSchema, injectMultiFactorPhoneAuthNumberFormSchema, injectMultiFactorPhoneAuthVerifyFormSchema, injectMultiFactorTotpAuthNumberFormSchema, injectMultiFactorTotpAuthVerifyFormSchema, injectPhoneAuthFormSchema, injectPhoneAuthVerifyFormSchema, injectPolicies, injectRecaptchaVerifier, injectRedirectError, injectSignInAuthFormSchema, injectSignUpAuthFormSchema, injectTranslation, injectUI, injectUserAuthenticated, provideFirebaseUI, provideFirebaseUIPolicies };
|
|
3288
4680
|
//# sourceMappingURL=firebase-oss-ui-angular.mjs.map
|