mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-12 06:42:59 +00:00
throw out @zitadel/react @zitadel/next
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["zitadel"],
|
||||
};
|
||||
@@ -1,48 +0,0 @@
|
||||
{
|
||||
"name": "@zitadel/next",
|
||||
"version": "0.0.0",
|
||||
"sideEffects": false,
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist/**"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"test": "pnpm test:unit",
|
||||
"test:watch": "pnpm test:unit:watch",
|
||||
"test:unit": "vitest",
|
||||
"test:unit:watch": "vitest --watch",
|
||||
"dev": "tsup --watch",
|
||||
"lint": "eslint \"src/**/*.ts*\"",
|
||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@zitadel/node": "workspace:*",
|
||||
"@zitadel/react": "workspace:*",
|
||||
"@zitadel/client": "workspace:*",
|
||||
"@zitadel/proto": "workspace:*",
|
||||
"next": "^14.2.5",
|
||||
"react": "^18.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "^14.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.3.3",
|
||||
"@zitadel/tsconfig": "workspace:*",
|
||||
"eslint-config-zitadel": "workspace:*",
|
||||
"postcss": "8.4.41",
|
||||
"tailwindcss": "3.4.9",
|
||||
"zitadel-tailwind-config": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// If you want to use other PostCSS plugins, see the following:
|
||||
// https://tailwindcss.com/docs/using-with-preprocessors
|
||||
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
export type ZitadelNextProps = {
|
||||
dark: boolean;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export function ZitadelNextProvider({ dark, children }: ZitadelNextProps) {
|
||||
return <div className={`${dark ? "ztdl-dark" : "ztdl-light"} `}>{children}</div>;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
// import "./styles.css";
|
||||
|
||||
export { ZitadelNextProvider, type ZitadelNextProps } from "./components/ZitadelNextProvider";
|
||||
export * from "./utils/cookies";
|
||||
export { loadMostRecentSession } from "./utils/session";
|
||||
@@ -1,3 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -1,256 +0,0 @@
|
||||
"use server";
|
||||
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export type Cookie = {
|
||||
id: string;
|
||||
token: string;
|
||||
loginName: string;
|
||||
organization?: string;
|
||||
creationDate: string;
|
||||
expirationDate: string;
|
||||
changeDate: string;
|
||||
authRequestId?: string; // if its linked to an OIDC flow
|
||||
};
|
||||
|
||||
type SessionCookie<T> = Cookie & T;
|
||||
|
||||
function setSessionHttpOnlyCookie<T>(sessions: SessionCookie<T>[]) {
|
||||
const cookiesList = cookies();
|
||||
// @ts-ignore
|
||||
return cookiesList.set({
|
||||
name: "sessions",
|
||||
value: JSON.stringify(sessions),
|
||||
httpOnly: true,
|
||||
path: "/",
|
||||
});
|
||||
}
|
||||
|
||||
export async function addSessionToCookie<T>(session: SessionCookie<T>, cleanup: boolean = false): Promise<any> {
|
||||
const cookiesList = cookies();
|
||||
const stringifiedCookie = cookiesList.get("sessions");
|
||||
|
||||
let currentSessions: SessionCookie<T>[] = stringifiedCookie?.value ? JSON.parse(stringifiedCookie?.value) : [];
|
||||
|
||||
const index = currentSessions.findIndex((s) => s.loginName === session.loginName);
|
||||
|
||||
if (index > -1) {
|
||||
currentSessions[index] = session;
|
||||
} else {
|
||||
currentSessions = [...currentSessions, session];
|
||||
}
|
||||
|
||||
if (cleanup) {
|
||||
const now = new Date();
|
||||
const filteredSessions = currentSessions.filter((session) =>
|
||||
session.expirationDate ? new Date(session.expirationDate) > now : true,
|
||||
);
|
||||
return setSessionHttpOnlyCookie(filteredSessions);
|
||||
} else {
|
||||
return setSessionHttpOnlyCookie(currentSessions);
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateSessionCookie<T>(id: string, session: SessionCookie<T>, cleanup: boolean = false): Promise<any> {
|
||||
const cookiesList = cookies();
|
||||
const stringifiedCookie = cookiesList.get("sessions");
|
||||
|
||||
const sessions: SessionCookie<T>[] = stringifiedCookie?.value ? JSON.parse(stringifiedCookie?.value) : [session];
|
||||
|
||||
const foundIndex = sessions.findIndex((session) => session.id === id);
|
||||
|
||||
if (foundIndex > -1) {
|
||||
sessions[foundIndex] = session;
|
||||
if (cleanup) {
|
||||
const now = new Date();
|
||||
const filteredSessions = sessions.filter((session) =>
|
||||
session.expirationDate ? new Date(session.expirationDate) > now : true,
|
||||
);
|
||||
return setSessionHttpOnlyCookie(filteredSessions);
|
||||
} else {
|
||||
return setSessionHttpOnlyCookie(sessions);
|
||||
}
|
||||
} else {
|
||||
throw "updateSessionCookie<T>: session id now found";
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeSessionFromCookie<T>(session: SessionCookie<T>, cleanup: boolean = false): Promise<any> {
|
||||
const cookiesList = cookies();
|
||||
const stringifiedCookie = cookiesList.get("sessions");
|
||||
|
||||
const sessions: SessionCookie<T>[] = stringifiedCookie?.value ? JSON.parse(stringifiedCookie?.value) : [session];
|
||||
|
||||
const reducedSessions = sessions.filter((s) => s.id !== session.id);
|
||||
if (cleanup) {
|
||||
const now = new Date();
|
||||
const filteredSessions = reducedSessions.filter((session) =>
|
||||
session.expirationDate ? new Date(session.expirationDate) > now : true,
|
||||
);
|
||||
return setSessionHttpOnlyCookie(filteredSessions);
|
||||
} else {
|
||||
return setSessionHttpOnlyCookie(reducedSessions);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getMostRecentSessionCookie<T>(): Promise<any> {
|
||||
const cookiesList = cookies();
|
||||
const stringifiedCookie = cookiesList.get("sessions");
|
||||
|
||||
if (stringifiedCookie?.value) {
|
||||
const sessions: SessionCookie<T>[] = JSON.parse(stringifiedCookie?.value);
|
||||
|
||||
const latest = sessions.reduce((prev, current) => {
|
||||
return new Date(prev.changeDate).getTime() > new Date(current.changeDate).getTime() ? prev : current;
|
||||
});
|
||||
|
||||
return latest;
|
||||
} else {
|
||||
return Promise.reject("no session cookie found");
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSessionCookieById<T>({
|
||||
sessionId,
|
||||
organization,
|
||||
}: {
|
||||
sessionId: string;
|
||||
organization?: string;
|
||||
}): Promise<SessionCookie<T>> {
|
||||
const cookiesList = cookies();
|
||||
const stringifiedCookie = cookiesList.get("sessions");
|
||||
|
||||
if (stringifiedCookie?.value) {
|
||||
const sessions: SessionCookie<T>[] = JSON.parse(stringifiedCookie?.value);
|
||||
|
||||
const found = sessions.find((s) =>
|
||||
organization ? s.organization === organization && s.id === sessionId : s.id === sessionId,
|
||||
);
|
||||
if (found) {
|
||||
return found;
|
||||
} else {
|
||||
return Promise.reject();
|
||||
}
|
||||
} else {
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSessionCookieByLoginName<T>({
|
||||
loginName,
|
||||
organization,
|
||||
}: {
|
||||
loginName?: string;
|
||||
organization?: string;
|
||||
}): Promise<SessionCookie<T>> {
|
||||
const cookiesList = cookies();
|
||||
const stringifiedCookie = cookiesList.get("sessions");
|
||||
|
||||
if (stringifiedCookie?.value) {
|
||||
const sessions: SessionCookie<T>[] = JSON.parse(stringifiedCookie?.value);
|
||||
const found = sessions.find((s) =>
|
||||
organization ? s.organization === organization && s.loginName === loginName : s.loginName === loginName,
|
||||
);
|
||||
if (found) {
|
||||
return found;
|
||||
} else {
|
||||
return Promise.reject("no cookie found with loginName: " + loginName);
|
||||
}
|
||||
} else {
|
||||
return Promise.reject("no session cookie found");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param cleanup when true, removes all expired sessions, default true
|
||||
* @returns Session Cookies
|
||||
*/
|
||||
export async function getAllSessionCookieIds<T>(cleanup: boolean = false): Promise<any> {
|
||||
const cookiesList = cookies();
|
||||
const stringifiedCookie = cookiesList.get("sessions");
|
||||
|
||||
if (stringifiedCookie?.value) {
|
||||
const sessions: SessionCookie<T>[] = JSON.parse(stringifiedCookie?.value);
|
||||
|
||||
if (cleanup) {
|
||||
const now = new Date();
|
||||
return sessions
|
||||
.filter((session) => (session.expirationDate ? new Date(session.expirationDate) > now : true))
|
||||
.map((session) => session.id);
|
||||
} else {
|
||||
return sessions.map((session) => session.id);
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param cleanup when true, removes all expired sessions, default true
|
||||
* @returns Session Cookies
|
||||
*/
|
||||
export async function getAllSessions<T>(cleanup: boolean = false): Promise<SessionCookie<T>[]> {
|
||||
const cookiesList = cookies();
|
||||
const stringifiedCookie = cookiesList.get("sessions");
|
||||
|
||||
if (stringifiedCookie?.value) {
|
||||
const sessions: SessionCookie<T>[] = JSON.parse(stringifiedCookie?.value);
|
||||
|
||||
if (cleanup) {
|
||||
const now = new Date();
|
||||
return sessions.filter((session) => (session.expirationDate ? new Date(session.expirationDate) > now : true));
|
||||
} else {
|
||||
return sessions;
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns most recent session filtered by optinal loginName
|
||||
* @param loginName optional loginName to filter cookies, if non provided, returns most recent session
|
||||
* @param organization optional organization to filter cookies
|
||||
* @returns most recent session
|
||||
*/
|
||||
export async function getMostRecentCookieWithLoginname<T>({
|
||||
loginName,
|
||||
organization,
|
||||
}: {
|
||||
loginName?: string;
|
||||
organization?: string;
|
||||
}): Promise<any> {
|
||||
const cookiesList = cookies();
|
||||
const stringifiedCookie = cookiesList.get("sessions");
|
||||
|
||||
if (stringifiedCookie?.value) {
|
||||
const sessions: SessionCookie<T>[] = JSON.parse(stringifiedCookie?.value);
|
||||
let filtered = sessions.filter((cookie) => {
|
||||
return !!loginName ? cookie.loginName === loginName : true;
|
||||
});
|
||||
|
||||
if (organization) {
|
||||
filtered = filtered.filter((cookie) => {
|
||||
return cookie.organization === organization;
|
||||
});
|
||||
}
|
||||
|
||||
const latest =
|
||||
filtered && filtered.length
|
||||
? filtered.reduce((prev, current) => {
|
||||
return new Date(prev.changeDate).getTime() > new Date(current.changeDate).getTime() ? prev : current;
|
||||
})
|
||||
: undefined;
|
||||
|
||||
if (latest) {
|
||||
return latest;
|
||||
} else {
|
||||
console.error("sessions", sessions, loginName, organization);
|
||||
return Promise.reject("Could not get the context or retrieve a session");
|
||||
}
|
||||
} else {
|
||||
return Promise.reject("Could not read session cookie");
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
|
||||
import { GetSessionResponse } from "@zitadel/proto/zitadel/session/v2/session_service_pb";
|
||||
import { getMostRecentCookieWithLoginname } from "./cookies";
|
||||
|
||||
export async function loadMostRecentSession(
|
||||
sessionService: any, // TODO: SessionServiceClient,
|
||||
sessionParams: { loginName?: string; organization?: string },
|
||||
): Promise<Session | undefined> {
|
||||
const recent = await getMostRecentCookieWithLoginname({
|
||||
loginName: sessionParams.loginName,
|
||||
organization: sessionParams.organization,
|
||||
});
|
||||
return sessionService
|
||||
.getSession({ sessionId: recent.id, sessionToken: recent.token }, {})
|
||||
.then((resp: GetSessionResponse) => resp.session);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
const sharedConfig = require("zitadel-tailwind-config/tailwind.config.mjs");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
presets: [sharedConfig],
|
||||
prefix: "ztdl-next-",
|
||||
darkMode: "class",
|
||||
content: [`src/**/*.{js,ts,jsx,tsx}`],
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"extends": "@zitadel/tsconfig/react-library.json",
|
||||
"include": ["."],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { defineConfig, Options } from "tsup";
|
||||
|
||||
export default defineConfig((options: Options) => ({
|
||||
treeshake: true,
|
||||
splitting: true,
|
||||
publicDir: true,
|
||||
entry: ["src/**/*.tsx"],
|
||||
format: ["esm"],
|
||||
dts: true,
|
||||
minify: true,
|
||||
clean: true,
|
||||
external: ["react"],
|
||||
...options,
|
||||
}));
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": ["//"],
|
||||
"tasks": {
|
||||
"build": {
|
||||
"outputs": ["dist/**"],
|
||||
"dependsOn": ["@zitadel/client#build", "@zitadel/react#build"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["zitadel"],
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
# How to use
|
||||
|
||||
### Install
|
||||
|
||||
```sh
|
||||
npm install @zitadel/react
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
yarn add @zitadel/react
|
||||
```
|
||||
|
||||
### Import styles file
|
||||
|
||||
To get the styles, import them in `_app.tsx` or global styling file
|
||||
|
||||
```
|
||||
import "@zitadel/react/styles.css";
|
||||
```
|
||||
|
||||
### Setup Dark mode
|
||||
|
||||
to set dark theme, wrap your components in a `ui-dark` class.
|
||||
|
||||
### Use components
|
||||
|
||||
```tsx
|
||||
import { SignInWithGoogle } from "@zitadel/react";
|
||||
|
||||
export default function IdentityProviders() {
|
||||
return (
|
||||
<div className="py-4">
|
||||
<SignInWithGoogle />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
@@ -1,48 +0,0 @@
|
||||
{
|
||||
"name": "@zitadel/react",
|
||||
"version": "0.0.0",
|
||||
"types": "./dist/index.d.ts",
|
||||
"sideEffects": [
|
||||
"**/*.css"
|
||||
],
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs"
|
||||
},
|
||||
"./styles.css": "./dist/index.css",
|
||||
"./assets/*": "./dist/assets/*"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"test": "pnpm test:unit",
|
||||
"test:watch": "pnpm test:unit:watch",
|
||||
"test:unit": "vitest",
|
||||
"test:unit:watch": "vitest --watch",
|
||||
"dev": "tsup --watch",
|
||||
"lint": "eslint \"src/**/*.ts*\"",
|
||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
|
||||
"copy-files": "cp -R ./src/public/ ./dist/"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^6.4.5",
|
||||
"@testing-library/react": "^16.0.0",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@zitadel/tsconfig": "workspace:*",
|
||||
"autoprefixer": "10.4.20",
|
||||
"eslint-config-zitadel": "workspace:*",
|
||||
"jsdom": "^24.0.0",
|
||||
"postcss": "8.4.41",
|
||||
"sass": "^1.77.1",
|
||||
"tailwindcss": "3.4.9",
|
||||
"zitadel-tailwind-config": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// If you want to use other PostCSS plugins, see the following:
|
||||
// https://tailwindcss.com/docs/using-with-preprocessors
|
||||
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
import { ButtonHTMLAttributes, DetailedHTMLProps } from "react";
|
||||
|
||||
export type SignInWithIdentityProviderProps = DetailedHTMLProps<
|
||||
ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
HTMLButtonElement
|
||||
> & {
|
||||
name?: string;
|
||||
e2e?: string;
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode, forwardRef } from "react";
|
||||
import { SignInWithIdentityProviderProps } from "./SignInWith";
|
||||
import { IdpButtonClasses } from "./classes";
|
||||
|
||||
export const SignInWithAzureAD = forwardRef<HTMLButtonElement, SignInWithIdentityProviderProps>(
|
||||
({ children, className = "", name = "", ...props }, ref): ReactNode => (
|
||||
<button type="button" ref={ref} className={`${IdpButtonClasses} ${className}`} {...props}>
|
||||
<div className="ztdl-h-12 ztdl-p-[10px] ztdl-w-12 ztdl-flex ztdl-items-center ztdl-justify-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21" className="w-full h-full">
|
||||
<path fill="#f25022" d="M1 1H10V10H1z"></path>
|
||||
<path fill="#00a4ef" d="M1 11H10V20H1z"></path>
|
||||
<path fill="#7fba00" d="M11 1H20V10H11z"></path>
|
||||
<path fill="#ffb900" d="M11 11H20V20H11z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
{children ? children : <span className="ztdl-ml-4">{name ? name : "Sign in with AzureAD"}</span>}
|
||||
</button>
|
||||
),
|
||||
);
|
||||
|
||||
SignInWithAzureAD.displayName = "SignInWithAzureAD";
|
||||
@@ -1,47 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode, forwardRef } from "react";
|
||||
import { SignInWithIdentityProviderProps } from "./SignInWith";
|
||||
import { IdpButtonClasses } from "./classes";
|
||||
|
||||
export const SignInWithGithub = forwardRef<HTMLButtonElement, SignInWithIdentityProviderProps>(
|
||||
({ children, className = "", name = "", ...props }, ref): ReactNode => (
|
||||
<button type="button" ref={ref} className={`${IdpButtonClasses} ${className}`} {...props}>
|
||||
<div className="ztdl-h-8 ztdl-w-8 ztdl-mx-2 flex items-center justify-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1024"
|
||||
height="1024"
|
||||
fill="none"
|
||||
viewBox="0 0 1024 1024"
|
||||
className="hidden dark:ztdl-block"
|
||||
>
|
||||
<path
|
||||
fill="#fafafa"
|
||||
fillRule="evenodd"
|
||||
d="M512 0C229.12 0 0 229.12 0 512c0 226.56 146.56 417.92 350.08 485.76 25.6 4.48 35.2-10.88 35.2-24.32 0-12.16-.64-52.48-.64-95.36-128.64 23.68-161.92-31.36-172.16-60.16-5.76-14.72-30.72-60.16-52.48-72.32-17.92-9.6-43.52-33.28-.64-33.92 40.32-.64 69.12 37.12 78.72 52.48 46.08 77.44 119.68 55.68 149.12 42.24 4.48-33.28 17.92-55.68 32.64-68.48-113.92-12.8-232.96-56.96-232.96-252.8 0-55.68 19.84-101.76 52.48-137.6-5.12-12.8-23.04-65.28 5.12-135.68 0 0 42.88-13.44 140.8 52.48 40.96-11.52 84.48-17.28 128-17.28 43.52 0 87.04 5.76 128 17.28 97.92-66.56 140.8-52.48 140.8-52.48 28.16 70.4 10.24 122.88 5.12 135.68 32.64 35.84 52.48 81.28 52.48 137.6 0 196.48-119.68 240-233.6 252.8 18.56 16 34.56 46.72 34.56 94.72 0 68.48-.64 123.52-.64 140.8 0 13.44 9.6 29.44 35.2 24.32C877.44 929.92 1024 737.92 1024 512 1024 229.12 794.88 0 512 0z"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1024"
|
||||
height="1024"
|
||||
fill="none"
|
||||
viewBox="0 0 1024 1024"
|
||||
className="ztdl-block dark:ztdl-hidden"
|
||||
>
|
||||
<path
|
||||
fill="#1B1F23"
|
||||
fillRule="evenodd"
|
||||
d="M512 0C229.12 0 0 229.12 0 512c0 226.56 146.56 417.92 350.08 485.76 25.6 4.48 35.2-10.88 35.2-24.32 0-12.16-.64-52.48-.64-95.36-128.64 23.68-161.92-31.36-172.16-60.16-5.76-14.72-30.72-60.16-52.48-72.32-17.92-9.6-43.52-33.28-.64-33.92 40.32-.64 69.12 37.12 78.72 52.48 46.08 77.44 119.68 55.68 149.12 42.24 4.48-33.28 17.92-55.68 32.64-68.48-113.92-12.8-232.96-56.96-232.96-252.8 0-55.68 19.84-101.76 52.48-137.6-5.12-12.8-23.04-65.28 5.12-135.68 0 0 42.88-13.44 140.8 52.48 40.96-11.52 84.48-17.28 128-17.28 43.52 0 87.04 5.76 128 17.28 97.92-66.56 140.8-52.48 140.8-52.48 28.16 70.4 10.24 122.88 5.12 135.68 32.64 35.84 52.48 81.28 52.48 137.6 0 196.48-119.68 240-233.6 252.8 18.56 16 34.56 46.72 34.56 94.72 0 68.48-.64 123.52-.64 140.8 0 13.44 9.6 29.44 35.2 24.32C877.44 929.92 1024 737.92 1024 512 1024 229.12 794.88 0 512 0z"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
{children ? children : <span className="ztdl-ml-4">{name ? name : "Sign in with GitHub"}</span>}
|
||||
</button>
|
||||
),
|
||||
);
|
||||
|
||||
SignInWithGithub.displayName = "SignInWithGithub";
|
||||
@@ -1,25 +0,0 @@
|
||||
import { afterEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { cleanup, render, screen } from "@testing-library/react";
|
||||
import { SignInWithGitlab } from "./SignInWithGitlab";
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe("<SignInWithGitlab />", () => {
|
||||
test("renders without crashing", () => {
|
||||
const { container } = render(<SignInWithGitlab />);
|
||||
expect(container.firstChild).toBeDefined();
|
||||
});
|
||||
|
||||
test("displays the default text", () => {
|
||||
render(<SignInWithGitlab />);
|
||||
const signInText = screen.getByText(/Sign in with Gitlab/i);
|
||||
expect(signInText).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("displays the given text", () => {
|
||||
render(<SignInWithGitlab name={"Gitlab"} />);
|
||||
const signInText = screen.getByText(/Gitlab/i);
|
||||
expect(signInText).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
import { ReactNode, forwardRef } from "react";
|
||||
import { SignInWithIdentityProviderProps } from "./SignInWith";
|
||||
import { IdpButtonClasses } from "./classes";
|
||||
|
||||
export const SignInWithGitlab = forwardRef<HTMLButtonElement, SignInWithIdentityProviderProps>(
|
||||
({ children, className = "", name = "", ...props }, ref): ReactNode => (
|
||||
<button type="button" ref={ref} className={`${IdpButtonClasses} ${className}`} {...props}>
|
||||
<div className="ztdl-h-12 ztdl-w-12 flex items-center justify-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width={25} height={24} fill="none">
|
||||
<path
|
||||
fill="#e24329"
|
||||
d="m24.507 9.5-.034-.09L21.082.562a.896.896 0 0 0-1.694.091l-2.29 7.01H7.825L5.535.653a.898.898 0 0 0-1.694-.09L.451 9.411.416 9.5a6.297 6.297 0 0 0 2.09 7.278l.012.01.03.022 5.16 3.867 2.56 1.935 1.554 1.176a1.051 1.051 0 0 0 1.268 0l1.555-1.176 2.56-1.935 5.197-3.89.014-.01A6.297 6.297 0 0 0 24.507 9.5z"
|
||||
/>
|
||||
<path
|
||||
fill="#fc6d26"
|
||||
d="m24.507 9.5-.034-.09a11.44 11.44 0 0 0-4.56 2.051l-7.447 5.632 4.742 3.584 5.197-3.89.014-.01A6.297 6.297 0 0 0 24.507 9.5z"
|
||||
/>
|
||||
<path
|
||||
fill="#fca326"
|
||||
d="m7.707 20.677 2.56 1.935 1.555 1.176a1.051 1.051 0 0 0 1.268 0l1.555-1.176 2.56-1.935-4.743-3.584-4.755 3.584z"
|
||||
/>
|
||||
<path
|
||||
fill="#fc6d26"
|
||||
d="M5.01 11.461a11.43 11.43 0 0 0-4.56-2.05L.416 9.5a6.297 6.297 0 0 0 2.09 7.278l.012.01.03.022 5.16 3.867 4.745-3.584-7.444-5.632z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
{children ? children : <span className="ztdl-ml-4">{name ? name : "Sign in with GitLab"}</span>}
|
||||
</button>
|
||||
),
|
||||
);
|
||||
|
||||
SignInWithGitlab.displayName = "SignInWithGitlab";
|
||||
@@ -1,25 +0,0 @@
|
||||
import { afterEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { cleanup, render, screen } from "@testing-library/react";
|
||||
import { SignInWithGoogle } from "./SignInWithGoogle";
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe("<SignInWithGoogle />", () => {
|
||||
test("renders without crashing", () => {
|
||||
const { container } = render(<SignInWithGoogle />);
|
||||
expect(container.firstChild).toBeDefined();
|
||||
});
|
||||
|
||||
test("displays the default text", () => {
|
||||
render(<SignInWithGoogle />);
|
||||
const signInText = screen.getByText(/Sign in with Google/i);
|
||||
expect(signInText).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("displays the given text", () => {
|
||||
render(<SignInWithGoogle name={"Google"} />);
|
||||
const signInText = screen.getByText(/Google/i);
|
||||
expect(signInText).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,46 +0,0 @@
|
||||
import { ReactNode, forwardRef } from "react";
|
||||
import { SignInWithIdentityProviderProps } from "./SignInWith";
|
||||
import { IdpButtonClasses } from "./classes";
|
||||
|
||||
export const SignInWithGoogle = forwardRef<HTMLButtonElement, SignInWithIdentityProviderProps>(
|
||||
({ children, className = "", name = "", ...props }, ref): ReactNode => (
|
||||
<button type="button" ref={ref} className={`${IdpButtonClasses} ${className}`} {...props}>
|
||||
<div className="ztdl-h-12 ztdl-w-12 ztdl-flex ztdl-items-center ztdl-justify-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlSpace="preserve" id="Capa_1" viewBox="0 0 150 150">
|
||||
<style>
|
||||
{
|
||||
".st0{fill:#1a73e8}.st1{fill:#ea4335}.st2{fill:#4285f4}.st3{fill:#fbbc04}.st4{fill:#34a853}.st5{fill:#4caf50}.st6{fill:#1e88e5}.st7{fill:#e53935}.st8{fill:#c62828}.st9{fill:#fbc02d}.st10{fill:#1565c0}.st11{fill:#2e7d32}.st16{clip-path:url(#SVGID_2_)}.st17{fill:#188038}.st18,.st19{opacity:.2;fill:#fff;enable-background:new}.st19{opacity:.3;fill:#0d652d}.st20{clip-path:url(#SVGID_4_)}.st21{opacity:.3;fill:url(#_45_shadow_1_);enable-background:new}.st22{clip-path:url(#SVGID_6_)}.st23{fill:#fa7b17}.st24,.st25,.st26{opacity:.3;fill:#174ea6;enable-background:new}.st25,.st26{fill:#a50e0e}.st26{fill:#e37400}.st27{fill:url(#Finish_mask_1_)}.st28{fill:#fff}.st29{fill:#0c9d58}.st30,.st31{opacity:.2;fill:#004d40;enable-background:new}.st31{fill:#3e2723}.st32{fill:#ffc107}.st33{fill:#1a237e;enable-background:new}.st33,.st34{opacity:.2}.st35{fill:#1a237e}.st36{fill:url(#SVGID_7_)}.st37{fill:#fbbc05}.st38{clip-path:url(#SVGID_9_);fill:#e53935}.st39{clip-path:url(#SVGID_11_);fill:#fbc02d}.st40{clip-path:url(#SVGID_13_);fill:#e53935}.st41{clip-path:url(#SVGID_15_);fill:#fbc02d}"
|
||||
}
|
||||
</style>
|
||||
<path
|
||||
d="M120 76.1c0-3.1-.3-6.3-.8-9.3H75.9v17.7h24.8c-1 5.7-4.3 10.7-9.2 13.9l14.8 11.5C115 101.8 120 90 120 76.1z"
|
||||
style={{
|
||||
fill: "#4280ef",
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M75.9 120.9c12.4 0 22.8-4.1 30.4-11.1L91.5 98.4c-4.1 2.8-9.4 4.4-15.6 4.4-12 0-22.1-8.1-25.8-18.9L34.9 95.6c7.8 15.5 23.6 25.3 41 25.3z"
|
||||
style={{
|
||||
fill: "#34a353",
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M50.1 83.8c-1.9-5.7-1.9-11.9 0-17.6L34.9 54.4c-6.5 13-6.5 28.3 0 41.2l15.2-11.8z"
|
||||
style={{
|
||||
fill: "#f6b704",
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M75.9 47.3c6.5-.1 12.9 2.4 17.6 6.9L106.6 41c-8.3-7.8-19.3-12-30.7-11.9-17.4 0-33.2 9.8-41 25.3l15.2 11.8c3.7-10.9 13.8-18.9 25.8-18.9z"
|
||||
style={{
|
||||
fill: "#e54335",
|
||||
}}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
{children ? children : <span className="ztdl-ml-4">{name ? name : "Sign in with Google"}</span>}
|
||||
</button>
|
||||
),
|
||||
);
|
||||
|
||||
SignInWithGoogle.displayName = "SignInWithGoogle";
|
||||
@@ -1,17 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface SignInWithIDPProps {
|
||||
children?: React.ReactNode;
|
||||
orgId?: string;
|
||||
}
|
||||
|
||||
export function SignInWithIDP(props: SignInWithIDPProps) {
|
||||
return (
|
||||
<div className="ztdl-flex ztdl-flex-row border ztdl-border-divider-light dark:ztdl-border-divider-dark rounded-md px-4 text-sm">
|
||||
<div></div>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
SignInWithIDP.displayName = "SignInWithIDP";
|
||||
@@ -1,8 +0,0 @@
|
||||
export type ZitadelReactProps = {
|
||||
dark: boolean;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export function ZitadelReactProvider({ dark, children }: ZitadelReactProps) {
|
||||
return <div className={`${dark ? "ztdl-dark" : "ztdl-light"} `}>{children}</div>;
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
export const IdpButtonClasses =
|
||||
"transition-all ztdl-w-full ztdl-cursor-pointer ztdl-flex ztdl-flex-row ztdl-items-center bg-background-light-400 text-text-light-500 dark:bg-background-dark-500 dark:text-text-dark-500 border border-divider-light hover:border-black dark:border-divider-dark hover:dark:border-white focus:border-primary-light-500 focus:dark:border-primary-dark-500 outline-none rounded-md px-4 text-sm";
|
||||
@@ -1,13 +0,0 @@
|
||||
import "./styles.css";
|
||||
|
||||
export { SignInWithGoogle } from "./components/SignInWithGoogle";
|
||||
|
||||
export { SignInWithGitlab } from "./components/SignInWithGitlab";
|
||||
|
||||
export { SignInWithAzureAD } from "./components/SignInWithAzureAD";
|
||||
|
||||
export { SignInWithGithub } from "./components/SignInWithGithub";
|
||||
|
||||
export { ZitadelReactProvider, type ZitadelReactProps } from "./components/ZitadelReactProvider";
|
||||
|
||||
export { SignInWithIDP, type SignInWithIDPProps } from "./components/SignInWithIDP";
|
||||
@@ -1,3 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -1,9 +0,0 @@
|
||||
const sharedConfig = require("zitadel-tailwind-config/tailwind.config.mjs");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
presets: [sharedConfig],
|
||||
prefix: "ztdl-",
|
||||
darkMode: "class",
|
||||
content: [`src/**/*.{js,ts,jsx,tsx}`],
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": "@zitadel/tsconfig/react-library.json",
|
||||
"include": ["."],
|
||||
"exclude": ["dist", "build", "node_modules"],
|
||||
"compilerOptions": {
|
||||
"types": ["@testing-library/jest-dom"]
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { defineConfig, Options } from "tsup";
|
||||
|
||||
export default defineConfig((options: Options) => ({
|
||||
entry: ["src/index.tsx"],
|
||||
format: ["esm", "cjs"],
|
||||
dts: true,
|
||||
external: ["react"],
|
||||
...options,
|
||||
}));
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"//"
|
||||
],
|
||||
"tasks": {
|
||||
"build": {
|
||||
"outputs": [
|
||||
"dist/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
import react from "@vitejs/plugin-react";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
test: {
|
||||
include: ['src/**/*.test.ts', 'src/**/*.test.tsx'],
|
||||
environment: "jsdom",
|
||||
setupFiles: ["@testing-library/jest-dom/vitest"],
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user