Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion examples/react/src/firebase/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,10 @@
*/

export const firebaseConfig = {
// your Firebase config here
apiKey: "AIzaSyCvMftIUCD9lUQ3BzIrimfSfBbCUQYZf-I",
authDomain: "fir-ui-rework.firebaseapp.com",
projectId: "fir-ui-rework",
storageBucket: "fir-ui-rework.firebasestorage.app",
messagingSenderId: "200312857118",
appId: "1:200312857118:web:94e3f69b0e0a4a863f040f",
};
2 changes: 1 addition & 1 deletion examples/react/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
@import "@firebase-ui/styles/tailwind";

/* @import "@firebase-ui/styles/src/themes/dark.css"; */
/* @import "@firebase-ui/styles/src/themes/brutalist.css"; */
/* @import "@firebase-ui/styles/src/themes/brutalist.css"; */
17 changes: 15 additions & 2 deletions examples/react/src/screens/oauth-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,25 @@

"use client";

import { GoogleSignInButton, OAuthScreen } from "@firebase-ui/react";
import {
FacebookSignInButton,
AppleSignInButton,
GitHubSignInButton,
GoogleSignInButton,
MicrosoftSignInButton,
OAuthScreen,
TwitterSignInButton,
} from "@firebase-ui/react";

export default function OAuthScreenPage() {
return (
<OAuthScreen>
<GoogleSignInButton />
<GoogleSignInButton themed="neutral" />
<FacebookSignInButton themed />
<AppleSignInButton themed />
<GitHubSignInButton themed />
<MicrosoftSignInButton themed />
<TwitterSignInButton themed />
</OAuthScreen>
);
}
19 changes: 17 additions & 2 deletions examples/react/src/screens/sign-in-auth-screen-w-oauth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@

"use client";

import { GoogleSignInButton, SignInAuthScreen } from "@firebase-ui/react";
import {
AppleSignInButton,
GoogleSignInButton,
SignInAuthScreen,
FacebookSignInButton,
GitHubSignInButton,
MicrosoftSignInButton,
TwitterSignInButton,
} from "@firebase-ui/react";
import { useNavigate } from "react-router";

export default function SignInAuthScreenWithOAuthPage() {
Expand All @@ -27,7 +35,14 @@ export default function SignInAuthScreenWithOAuthPage() {
onForgotPasswordClick={() => navigate("/password-reset-screen")}
onRegisterClick={() => navigate("/sign-up-auth-screen")}
>
<GoogleSignInButton />
<div className="space-y-2">
<GoogleSignInButton />
<FacebookSignInButton />
<AppleSignInButton />
<GitHubSignInButton />
<MicrosoftSignInButton />
<TwitterSignInButton />
</div>
</SignInAuthScreen>
);
}
1 change: 1 addition & 0 deletions packages/core/brands/apple/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/core/brands/facebook/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/core/brands/github/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/core/brands/google/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/core/brands/line/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/core/brands/microsoft/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/core/brands/snapchat/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/core/brands/twitter/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"./brands/*": "./brands/*"
},
"files": [
"dist"
"dist",
"brands"
],
"scripts": {
"prepare": "pnpm run build",
Expand Down
6 changes: 4 additions & 2 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
],
"scripts": {
"prepare": "pnpm run build",
"build": "tsup",
"build": "tsup && pnpm run build:logos",
"build:local": "pnpm run build && pnpm pack",
"build:logos": "pnpm dlx @svgr/cli --icon --typescript --no-index --jsx-runtime automatic --out-dir src/components/logos ../core/brands",
"dev": "tsup --watch",
"lint": "eslint . --ext .ts,.tsx",
"lint:fix": "eslint . --ext .ts,.tsx --fix",
Expand Down Expand Up @@ -58,13 +59,14 @@
"@types/react-dom": "catalog:",
"@vitejs/plugin-react": "catalog:",
"firebase": "catalog:",
"nanostores": "catalog:",
"jsdom": "catalog:",
"nanostores": "catalog:",
"react": "catalog:",
"react-dom": "catalog:",
"tsup": "catalog:",
"typescript": "catalog:",
"vite": "catalog:",
"vite-plugin-svgr": "^4.5.0",
"vitest": "catalog:"
}
}
11 changes: 10 additions & 1 deletion packages/react/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,14 @@ export { PhoneAuthScreen, type PhoneAuthScreenProps } from "./screens/phone-auth
export { SignInAuthScreen, type SignInAuthScreenProps } from "./screens/sign-in-auth-screen";
export { SignUpAuthScreen, type SignUpAuthScreenProps } from "./screens/sign-up-auth-screen";

export { GoogleSignInButton, GoogleIcon, type GoogleSignInButtonProps } from "./oauth/google-sign-in-button";
export { AppleSignInButton, AppleLogo, type AppleSignInButtonProps } from "./oauth/apple-sign-in-button";
export { FacebookSignInButton, FacebookLogo, type FacebookSignInButtonProps } from "./oauth/facebook-sign-in-button";
export { GitHubSignInButton, GitHubLogo, type GitHubSignInButtonProps } from "./oauth/github-sign-in-button";
export { GoogleSignInButton, GoogleLogo, type GoogleSignInButtonProps } from "./oauth/google-sign-in-button";
export {
MicrosoftSignInButton,
MicrosoftLogo,
type MicrosoftSignInButtonProps,
} from "./oauth/microsoft-sign-in-button";
export { TwitterSignInButton, TwitterLogo, type TwitterSignInButtonProps } from "./oauth/twitter-sign-in-button";
export { OAuthButton, type OAuthButtonProps } from "./oauth/oauth-button";
186 changes: 186 additions & 0 deletions packages/react/src/auth/oauth/apple-sign-in-button.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/**
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { describe, it, expect, vi, afterEach, beforeEach } from "vitest";
import { render, screen, cleanup } from "@testing-library/react";
import { AppleLogo, AppleSignInButton } from "./apple-sign-in-button";
import { CreateFirebaseUIProvider, createMockUI } from "~/tests/utils";
import { registerLocale } from "@firebase-ui/translations";
import { OAuthProvider } from "firebase/auth";

vi.mock("firebase/auth", () => ({
OAuthProvider: class OAuthProvider {
constructor(providerId: string) {
this.providerId = providerId;
}
providerId: string;
},
}));

afterEach(() => {
cleanup();
});

describe("<AppleSignInButton />", () => {
beforeEach(() => {
vi.clearAllMocks();
});

it("renders with the correct provider", () => {
const ui = createMockUI({
locale: registerLocale("test", {
labels: {
signInWithApple: "Sign in with Apple",
},
}),
});

render(
<CreateFirebaseUIProvider ui={ui}>
<AppleSignInButton />
</CreateFirebaseUIProvider>
);

const button = screen.getByRole("button");
expect(button).toBeDefined();
expect(button.getAttribute("data-provider")).toBe("apple.com");
});

it("renders with custom provider when provided", () => {
const ui = createMockUI({
locale: registerLocale("test", {
labels: {
signInWithApple: "Sign in with Apple",
},
}),
});

const customProvider = new OAuthProvider("custom.apple.com");

render(
<CreateFirebaseUIProvider ui={ui}>
<AppleSignInButton provider={customProvider} />
</CreateFirebaseUIProvider>
);

const button = screen.getByRole("button");
expect(button).toBeDefined();
expect(button.getAttribute("data-provider")).toBe("custom.apple.com");
});

it("renders with the Apple icon", () => {
const ui = createMockUI({
locale: registerLocale("test", {
labels: {
signInWithApple: "Sign in with Apple",
},
}),
});

render(
<CreateFirebaseUIProvider ui={ui}>
<AppleSignInButton />
</CreateFirebaseUIProvider>
);

const svg = document.querySelector(".fui-provider__icon");
expect(svg).toBeDefined();
expect(svg).toHaveClass("fui-provider__icon");
expect(svg?.tagName.toLowerCase()).toBe("svg");
});

it("renders with the correct translated text", () => {
const ui = createMockUI({
locale: registerLocale("test", {
labels: {
signInWithApple: "Sign in with Apple",
},
}),
});

render(
<CreateFirebaseUIProvider ui={ui}>
<AppleSignInButton />
</CreateFirebaseUIProvider>
);

expect(screen.getByText("Sign in with Apple")).toBeDefined();
});

it("renders with different translated text for different locales", () => {
const ui = createMockUI({
locale: registerLocale("test", {
labels: {
signInWithApple: "Iniciar sesión con Apple",
},
}),
});

render(
<CreateFirebaseUIProvider ui={ui}>
<AppleSignInButton />
</CreateFirebaseUIProvider>
);

expect(screen.getByText("Iniciar sesión con Apple")).toBeDefined();
});

it("renders as a button with correct classes", () => {
const ui = createMockUI({
locale: registerLocale("test", {
labels: {
signInWithApple: "Sign in with Apple",
},
}),
});

render(
<CreateFirebaseUIProvider ui={ui}>
<AppleSignInButton />
</CreateFirebaseUIProvider>
);

const button = screen.getByRole("button");
expect(button).toHaveClass("fui-provider__button");
expect(button.getAttribute("type")).toBe("button");
});
});

describe("<AppleLogo />", () => {
it("renders as an SVG element", () => {
const { container } = render(<AppleLogo />);
const svg = container.querySelector("svg");

expect(svg).toBeDefined();
expect(svg?.tagName.toLowerCase()).toBe("svg");
});

it("has the correct CSS class", () => {
const { container } = render(<AppleLogo />);
const svg = container.querySelector("svg");

expect(svg).toHaveClass("fui-provider__icon");
});

it("forwards custom SVG props", () => {
const { container } = render(<AppleLogo data-testid="custom-svg" className="foo" width={32} />);
const svg = container.querySelector('svg[data-testid="custom-svg"]');

expect(svg).toBeDefined();
expect(svg!.getAttribute("width")).toBe("32");
expect(svg).toHaveClass("fui-provider__icon");
expect(svg).toHaveClass("foo");
});
});
Loading