From 8c4147787b1c3a3c81c010738fe5703e3c6f3add Mon Sep 17 00:00:00 2001 From: Elliot Hesp Date: Thu, 18 Sep 2025 15:06:58 +0100 Subject: [PATCH 01/74] feat(angular): Add injectors --- packages/angular/src/lib/provider.ts | 49 ++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/packages/angular/src/lib/provider.ts b/packages/angular/src/lib/provider.ts index 49a949b1..c75be1b1 100644 --- a/packages/angular/src/lib/provider.ts +++ b/packages/angular/src/lib/provider.ts @@ -21,9 +21,11 @@ import { InjectionToken, Injectable, inject, + signal, computed, effect, + Signal, } from "@angular/core"; import { FirebaseApps } from "@angular/fire/app"; -import { type FirebaseUI as FirebaseUIType, getTranslation } from "@firebase-ui/core"; +import { createEmailLinkAuthFormSchema, createForgotPasswordAuthFormSchema, createPhoneAuthFormSchema, createSignInAuthFormSchema, createSignUpAuthFormSchema, FirebaseUIConfiguration, type FirebaseUI as FirebaseUIType, getTranslation, SignInAuthFormSchema } from "@firebase-ui/core"; import { distinctUntilChanged, map, takeUntil } from "rxjs/operators"; import { Observable, ReplaySubject } from "rxjs"; import { Store } from "nanostores"; @@ -46,7 +48,7 @@ export function provideFirebaseUI(uiFactory: (apps: FirebaseApps) => FirebaseUIT useFactory: () => { const apps = inject(FirebaseApps); if (!apps || apps.length === 0) { - return null as any; + throw new Error("No Firebase apps found"); } return uiFactory(apps); }, @@ -63,6 +65,49 @@ export function provideFirebaseUIPolicies(factory: () => PolicyConfig) { return makeEnvironmentProviders(providers); } + +// Provides a signal with a subscription to the FirebaseUIConfiguration +export function injectUI() { + const store = inject(FIREBASE_UI_STORE); + const ui = signal(store.get()); + + effect(() => { + return store.subscribe(ui.set); + }); + + return ui.asReadonly(); +} + +export function injectTranslation(category: T, key: TranslationKey) { + const ui = injectUI(); + return computed(() => getTranslation(ui(), category, key)); +} + +export function injectSignInAuthFormSchema(): Signal> { + const ui = injectUI(); + return computed(() => createSignInAuthFormSchema(ui())); +} + +export function injectSignUpAuthFormSchema(): Signal> { + const ui = injectUI(); + return computed(() => createSignUpAuthFormSchema(ui())); +} + +export function injectForgotPasswordAuthFormSchema(): Signal> { + const ui = injectUI(); + return computed(() => createForgotPasswordAuthFormSchema(ui())); +} + +export function injectEmailLinkAuthFormSchema(): Signal> { + const ui = injectUI(); + return computed(() => createEmailLinkAuthFormSchema(ui())); +} + +export function injectPhoneAuthFormSchema(): Signal> { + const ui = injectUI(); + return computed(() => createPhoneAuthFormSchema(ui())); +} + @Injectable({ providedIn: "root", }) From a9fe6890ed0f1c172b16ab87ab6d32a3ab667f52 Mon Sep 17 00:00:00 2001 From: Elliot Hesp Date: Thu, 18 Sep 2025 15:08:42 +0100 Subject: [PATCH 02/74] refactor(angular): Update sign-in-auth-form --- .../sign-in-auth-form.component.spec.ts} | 0 .../sign-in-auth-form.component.ts} | 116 ++++++------------ 2 files changed, 40 insertions(+), 76 deletions(-) rename packages/angular/src/lib/auth/forms/{email-password-form/email-password-form.component.spec.ts => sign-in-auth-form/sign-in-auth-form.component.spec.ts} (100%) rename packages/angular/src/lib/auth/forms/{email-password-form/email-password-form.component.ts => sign-in-auth-form/sign-in-auth-form.component.ts} (61%) diff --git a/packages/angular/src/lib/auth/forms/email-password-form/email-password-form.component.spec.ts b/packages/angular/src/lib/auth/forms/sign-in-auth-form/sign-in-auth-form.component.spec.ts similarity index 100% rename from packages/angular/src/lib/auth/forms/email-password-form/email-password-form.component.spec.ts rename to packages/angular/src/lib/auth/forms/sign-in-auth-form/sign-in-auth-form.component.spec.ts diff --git a/packages/angular/src/lib/auth/forms/email-password-form/email-password-form.component.ts b/packages/angular/src/lib/auth/forms/sign-in-auth-form/sign-in-auth-form.component.ts similarity index 61% rename from packages/angular/src/lib/auth/forms/email-password-form/email-password-form.component.ts rename to packages/angular/src/lib/auth/forms/sign-in-auth-form/sign-in-auth-form.component.ts index 11b5b3e0..5d8b7da9 100644 --- a/packages/angular/src/lib/auth/forms/email-password-form/email-password-form.component.ts +++ b/packages/angular/src/lib/auth/forms/sign-in-auth-form/sign-in-auth-form.component.ts @@ -14,18 +14,16 @@ * limitations under the License. */ -import { Component, inject, Input, OnInit } from "@angular/core"; +import { Component, EventEmitter, Output } from "@angular/core"; import { CommonModule } from "@angular/common"; import { injectForm, TanStackField } from "@tanstack/angular-form"; -import { FirebaseUI } from "../../../provider"; +import { injectSignInAuthFormSchema, injectTranslation, injectUI } from "../../../provider"; import { ButtonComponent } from "../../../components/button/button.component"; import { TermsAndPrivacyComponent } from "../../../components/terms-and-privacy/terms-and-privacy.component"; -import { createEmailFormSchema, EmailFormSchema, FirebaseUIConfiguration, FirebaseUIError, signInWithEmailAndPassword } from "@firebase-ui/core"; -import { firstValueFrom } from "rxjs"; -import { Router } from "@angular/router"; +import { FirebaseUIError, signInWithEmailAndPassword } from "@firebase-ui/core"; @Component({ - selector: "fui-email-password-form", + selector: "fui-sign-in-auth-form", standalone: true, imports: [CommonModule, TanStackField, ButtonComponent, TermsAndPrivacyComponent], template: ` @@ -53,10 +51,12 @@ import { Router } from "@angular/router";