@firebase-oss/ui-shadcn 0.0.1

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.
Files changed (34) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +53 -0
  3. package/dist/bin/cli.mjs +63 -0
  4. package/dist/bin/cli.mjs.map +1 -0
  5. package/dist/registry/apple-sign-in-button.json +39 -0
  6. package/dist/registry/country-selector.json +23 -0
  7. package/dist/registry/email-link-auth-form.json +27 -0
  8. package/dist/registry/email-link-auth-screen.json +26 -0
  9. package/dist/registry/facebook-sign-in-button.json +32 -0
  10. package/dist/registry/forgot-password-auth-form.json +26 -0
  11. package/dist/registry/forgot-password-auth-screen.json +24 -0
  12. package/dist/registry/github-sign-in-button.json +39 -0
  13. package/dist/registry/google-sign-in-button.json +44 -0
  14. package/dist/registry/microsoft-sign-in-button.json +39 -0
  15. package/dist/registry/multi-factor-auth-assertion-form.json +25 -0
  16. package/dist/registry/multi-factor-auth-assertion-screen.json +24 -0
  17. package/dist/registry/multi-factor-auth-enrollment-form.json +25 -0
  18. package/dist/registry/multi-factor-auth-enrollment-screen.json +24 -0
  19. package/dist/registry/oauth-button.json +23 -0
  20. package/dist/registry/oauth-screen.json +26 -0
  21. package/dist/registry/phone-auth-form.json +27 -0
  22. package/dist/registry/phone-auth-screen.json +27 -0
  23. package/dist/registry/policies.json +20 -0
  24. package/dist/registry/redirect-error.json +20 -0
  25. package/dist/registry/sign-in-auth-form.json +26 -0
  26. package/dist/registry/sign-in-auth-screen.json +26 -0
  27. package/dist/registry/sign-up-auth-form.json +26 -0
  28. package/dist/registry/sign-up-auth-screen.json +26 -0
  29. package/dist/registry/sms-multi-factor-assertion-form.json +26 -0
  30. package/dist/registry/sms-multi-factor-enrollment-form.json +27 -0
  31. package/dist/registry/totp-multi-factor-assertion-form.json +25 -0
  32. package/dist/registry/totp-multi-factor-enrollment-form.json +26 -0
  33. package/dist/registry/twitter-sign-in-button.json +32 -0
  34. package/package.json +56 -0
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "totp-multi-factor-assertion-form",
4
+ "type": "registry:block",
5
+ "title": "TOTP Multi-Factor Assertion Form",
6
+ "description": "A form allowing users to complete TOTP-based multi-factor authentication during sign-in.",
7
+ "dependencies": [
8
+ "@firebase-oss/ui-react"
9
+ ],
10
+ "registryDependencies": [
11
+ "form",
12
+ "button",
13
+ "input-otp"
14
+ ],
15
+ "files": [
16
+ {
17
+ "path": "src/components/totp-multi-factor-assertion-form.tsx",
18
+ "content": "/**\n * Copyright 2025 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\"use client\";\n\nimport { type UserCredential, type MultiFactorInfo } from \"firebase/auth\";\nimport { FirebaseUIError, getTranslation } from \"@firebase-oss/ui-core\";\nimport {\n useMultiFactorTotpAuthVerifyFormSchema,\n useUI,\n useTotpMultiFactorAssertionFormAction,\n} from \"@firebase-oss/ui-react\";\nimport { useForm } from \"react-hook-form\";\nimport { standardSchemaResolver } from \"@hookform/resolvers/standard-schema\";\n\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/components/ui/form\";\nimport { Button } from \"@/components/ui/button\";\nimport { InputOTP, InputOTPGroup, InputOTPSlot } from \"@/components/ui/input-otp\";\n\ntype TotpMultiFactorAssertionFormProps = {\n hint: MultiFactorInfo;\n onSuccess?: (credential: UserCredential) => void;\n};\n\nexport function TotpMultiFactorAssertionForm(props: TotpMultiFactorAssertionFormProps) {\n const ui = useUI();\n const schema = useMultiFactorTotpAuthVerifyFormSchema();\n const action = useTotpMultiFactorAssertionFormAction();\n\n const form = useForm<{ verificationCode: string }>({\n resolver: standardSchemaResolver(schema),\n defaultValues: {\n verificationCode: \"\",\n },\n });\n\n const onSubmit = async (values: { verificationCode: string }) => {\n try {\n const credential = await action({ verificationCode: values.verificationCode, hint: props.hint });\n props.onSuccess?.(credential);\n } catch (error) {\n const message = error instanceof FirebaseUIError ? error.message : String(error);\n form.setError(\"root\", { message });\n }\n };\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"flex flex-col gap-y-4\">\n <FormField\n control={form.control}\n name=\"verificationCode\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>{getTranslation(ui, \"labels\", \"verificationCode\")}</FormLabel>\n <FormControl>\n <InputOTP maxLength={6} {...field}>\n <InputOTPGroup>\n <InputOTPSlot index={0} />\n <InputOTPSlot index={1} />\n <InputOTPSlot index={2} />\n <InputOTPSlot index={3} />\n <InputOTPSlot index={4} />\n <InputOTPSlot index={5} />\n </InputOTPGroup>\n </InputOTP>\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\" disabled={ui.state !== \"idle\"}>\n {getTranslation(ui, \"labels\", \"verifyCode\")}\n </Button>\n {form.formState.errors.root && <FormMessage>{form.formState.errors.root.message}</FormMessage>}\n </form>\n </Form>\n );\n}\n",
19
+ "type": "registry:component"
20
+ }
21
+ ],
22
+ "meta": {
23
+ "version": "0.0.1"
24
+ }
25
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "totp-multi-factor-enrollment-form",
4
+ "type": "registry:block",
5
+ "title": "TOTP Multi-Factor Enrollment Form",
6
+ "description": "A form allowing users to enroll TOTP-based multi-factor authentication with QR code generation.",
7
+ "dependencies": [
8
+ "@firebase-oss/ui-react"
9
+ ],
10
+ "registryDependencies": [
11
+ "form",
12
+ "input",
13
+ "button",
14
+ "input-otp"
15
+ ],
16
+ "files": [
17
+ {
18
+ "path": "src/components/totp-multi-factor-enrollment-form.tsx",
19
+ "content": "/**\n * Copyright 2025 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\"use client\";\n\nimport { useState } from \"react\";\nimport { TotpMultiFactorGenerator, type TotpSecret } from \"firebase/auth\";\nimport {\n enrollWithMultiFactorAssertion,\n FirebaseUIError,\n generateTotpQrCode,\n generateTotpSecret,\n getTranslation,\n} from \"@firebase-oss/ui-core\";\nimport {\n useMultiFactorTotpAuthNumberFormSchema,\n useMultiFactorTotpAuthVerifyFormSchema,\n useUI,\n} from \"@firebase-oss/ui-react\";\nimport { useForm } from \"react-hook-form\";\nimport { standardSchemaResolver } from \"@hookform/resolvers/standard-schema\";\n\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport { Button } from \"@/components/ui/button\";\nimport { InputOTP, InputOTPGroup, InputOTPSlot } from \"@/components/ui/input-otp\";\n\ntype TotpMultiFactorSecretGenerationFormProps = {\n onSubmit: (secret: TotpSecret, displayName: string) => void;\n};\n\nfunction TotpMultiFactorSecretGenerationForm(props: TotpMultiFactorSecretGenerationFormProps) {\n const ui = useUI();\n const schema = useMultiFactorTotpAuthNumberFormSchema();\n\n const form = useForm<{ displayName: string }>({\n resolver: standardSchemaResolver(schema),\n defaultValues: {\n displayName: \"\",\n },\n });\n\n const onSubmit = async (values: { displayName: string }) => {\n try {\n const secret = await generateTotpSecret(ui);\n props.onSubmit(secret, values.displayName);\n } catch (error) {\n const message = error instanceof FirebaseUIError ? error.message : String(error);\n form.setError(\"root\", { message });\n }\n };\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"flex flex-col gap-y-4\">\n <FormField\n control={form.control}\n name=\"displayName\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>{getTranslation(ui, \"labels\", \"displayName\")}</FormLabel>\n <FormControl>\n <Input {...field} type=\"text\" />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\" disabled={ui.state !== \"idle\"}>\n {getTranslation(ui, \"labels\", \"generateQrCode\")}\n </Button>\n {form.formState.errors.root && <FormMessage>{form.formState.errors.root.message}</FormMessage>}\n </form>\n </Form>\n );\n}\n\ntype MultiFactorEnrollmentVerifyTotpFormProps = {\n secret: TotpSecret;\n displayName: string;\n onSuccess: () => void;\n};\n\nexport function MultiFactorEnrollmentVerifyTotpForm(props: MultiFactorEnrollmentVerifyTotpFormProps) {\n const ui = useUI();\n const schema = useMultiFactorTotpAuthVerifyFormSchema();\n\n const form = useForm<{ verificationCode: string }>({\n resolver: standardSchemaResolver(schema),\n defaultValues: {\n verificationCode: \"\",\n },\n });\n\n const onSubmit = async (values: { verificationCode: string }) => {\n try {\n const assertion = TotpMultiFactorGenerator.assertionForEnrollment(props.secret, values.verificationCode);\n await enrollWithMultiFactorAssertion(ui, assertion, values.verificationCode);\n props.onSuccess();\n } catch (error) {\n const message = error instanceof FirebaseUIError ? error.message : String(error);\n form.setError(\"root\", { message });\n }\n };\n\n const qrCodeDataUrl = generateTotpQrCode(ui, props.secret, props.displayName);\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex flex-col gap-y-4 items-center justify-center\">\n <img src={qrCodeDataUrl} alt=\"TOTP QR Code\" className=\"mx-auto\" />\n <code className=\"text-xs text-muted-foreground text-center\">{props.secret.secretKey.toString()}</code>\n <p className=\"text-xs text-muted-foreground text-center\">\n {getTranslation(ui, \"prompts\", \"mfaTotpQrCodePrompt\")}\n </p>\n </div>\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"flex flex-col gap-y-4\">\n <FormField\n control={form.control}\n name=\"verificationCode\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>{getTranslation(ui, \"labels\", \"verificationCode\")}</FormLabel>\n <FormControl>\n <InputOTP maxLength={6} {...field}>\n <InputOTPGroup>\n <InputOTPSlot index={0} />\n <InputOTPSlot index={1} />\n <InputOTPSlot index={2} />\n <InputOTPSlot index={3} />\n <InputOTPSlot index={4} />\n <InputOTPSlot index={5} />\n </InputOTPGroup>\n </InputOTP>\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\" disabled={ui.state !== \"idle\"}>\n {getTranslation(ui, \"labels\", \"verifyCode\")}\n </Button>\n {form.formState.errors.root && <FormMessage>{form.formState.errors.root.message}</FormMessage>}\n </form>\n </Form>\n </div>\n );\n}\n\nexport type TotpMultiFactorEnrollmentFormProps = {\n onSuccess?: () => void;\n};\n\nexport function TotpMultiFactorEnrollmentForm(props: TotpMultiFactorEnrollmentFormProps) {\n const ui = useUI();\n\n const [enrollment, setEnrollment] = useState<{\n secret: TotpSecret;\n displayName: string;\n } | null>(null);\n\n if (!ui.auth.currentUser) {\n throw new Error(\"User must be authenticated to enroll with multi-factor authentication\");\n }\n\n if (!enrollment) {\n return (\n <TotpMultiFactorSecretGenerationForm onSubmit={(secret, displayName) => setEnrollment({ secret, displayName })} />\n );\n }\n\n return (\n <MultiFactorEnrollmentVerifyTotpForm\n {...enrollment}\n onSuccess={() => {\n props.onSuccess?.();\n }}\n />\n );\n}\n",
20
+ "type": "registry:component"
21
+ }
22
+ ],
23
+ "meta": {
24
+ "version": "0.0.1"
25
+ }
26
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "twitter-sign-in-button",
4
+ "type": "registry:block",
5
+ "title": "Twitter Sign In Button",
6
+ "description": "A button component for Twitter OAuth authentication.",
7
+ "dependencies": [
8
+ "@firebase-oss/ui-react"
9
+ ],
10
+ "registryDependencies": [
11
+ "https://firebaseopensource.com/r/oauth-button.json"
12
+ ],
13
+ "files": [
14
+ {
15
+ "path": "src/components/twitter-sign-in-button.tsx",
16
+ "content": "/**\n * Copyright 2025 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\"use client\";\n\nimport { TwitterAuthProvider } from \"firebase/auth\";\nimport { getTranslation } from \"@firebase-oss/ui-core\";\nimport { useUI, type TwitterSignInButtonProps, TwitterLogo } from \"@firebase-oss/ui-react\";\n\nimport { OAuthButton } from \"@/components/oauth-button\";\n\nexport type { TwitterSignInButtonProps };\n\nexport function TwitterSignInButton({ provider, ...props }: TwitterSignInButtonProps) {\n const ui = useUI();\n\n return (\n <OAuthButton {...props} provider={provider || new TwitterAuthProvider()}>\n <TwitterLogo />\n <span>{getTranslation(ui, \"labels\", \"signInWithTwitter\")}</span>\n </OAuthButton>\n );\n}\n",
17
+ "type": "registry:component"
18
+ }
19
+ ],
20
+ "css": {
21
+ "@layer components": {
22
+ "button[data-provider='twitter.com'][data-themed='true']": {
23
+ "--twitter-primary": "#1DA1F2",
24
+ "--primary": "var(--twitter-primary)",
25
+ "--primary-foreground": "var(--color-white)"
26
+ }
27
+ }
28
+ },
29
+ "meta": {
30
+ "version": "0.0.1"
31
+ }
32
+ }
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@firebase-oss/ui-shadcn",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "bin": "./dist/bin/cli.js",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "devDependencies": {
10
+ "@tailwindcss/vite": "^4.1.14",
11
+ "@testing-library/jest-dom": "^6.8.0",
12
+ "@testing-library/react": "^16.3.0",
13
+ "@types/node": "^24.3.1",
14
+ "@types/react": "19.1.16",
15
+ "@types/react-dom": "19.1.9",
16
+ "@types/yargs-parser": "^21.0.3",
17
+ "@vitejs/plugin-react": "^5.0.2",
18
+ "firebase": "^11.10.0",
19
+ "react": "19.1.1",
20
+ "react-dom": "19.1.1",
21
+ "shadcn": "2.9.3-canary.0",
22
+ "tailwindcss": "^4.1.13",
23
+ "tsdown": "^0.16.6",
24
+ "tsx": "^4.20.6",
25
+ "tw-animate-css": "^1.4.0",
26
+ "typescript": "^5.9.2",
27
+ "vite": "^7.1.5",
28
+ "vite-plugin-run": "^0.6.1",
29
+ "vitest": "^3.2.4",
30
+ "yargs-parser": "^22.0.0",
31
+ "@firebase-oss/ui-translations": "0.0.2"
32
+ },
33
+ "dependencies": {
34
+ "@hookform/resolvers": "^5.2.2",
35
+ "@radix-ui/react-label": "^2.1.7",
36
+ "@radix-ui/react-select": "^2.2.6",
37
+ "@radix-ui/react-separator": "^1.1.7",
38
+ "@radix-ui/react-slot": "^1.2.3",
39
+ "class-variance-authority": "^0.7.1",
40
+ "clsx": "^2.1.1",
41
+ "input-otp": "^1.4.2",
42
+ "lucide-react": "^0.544.0",
43
+ "react-hook-form": "^7.64.0",
44
+ "tailwind-merge": "^3.3.1",
45
+ "zod": "4.1.12",
46
+ "@firebase-oss/ui-core": "0.0.2",
47
+ "@firebase-oss/ui-react": "0.0.2"
48
+ },
49
+ "scripts": {
50
+ "dev": "vite",
51
+ "build": "tsdown && tsx build.ts --domain https://firebaseopensource.com",
52
+ "preview": "vite preview",
53
+ "test": "vitest run",
54
+ "publish:npm": "../../publish.sh"
55
+ }
56
+ }