diff --git a/.changeset/lemon-turkeys-provide.md b/.changeset/lemon-turkeys-provide.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/lemon-turkeys-provide.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.github/.cache-version b/.github/.cache-version index 90dd19ef19..d2ec00870e 100644 --- a/.github/.cache-version +++ b/.github/.cache-version @@ -1,3 +1,3 @@ # Update this file to invalidate **all** cache on GitHub actions (use sparingly) -version: v2 +version: v3 diff --git a/package-lock.json b/package-lock.json index 50806b6465..9dd06d2711 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7121,6 +7121,175 @@ "dev": true, "license": "MIT" }, + "node_modules/@radix-ui/primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz", + "integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz", + "integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz", + "integrity": "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-form": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.0.3.tgz", + "integrity": "sha512-kgE+Z/haV6fxE5WqIXj05KkaXa3OkZASoTDy25yX2EIp/x0c54rOH/vFr5nOZTg7n7T1z8bSyXmiVIFP9bbhPQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-label": "2.0.2", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz", + "integrity": "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.2.tgz", + "integrity": "sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz", + "integrity": "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz", + "integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz", + "integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@react-native/normalize-color": { "version": "2.1.0", "dev": true, @@ -8326,7 +8495,7 @@ }, "node_modules/@types/prop-types": { "version": "15.7.5", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/ps-tree": { @@ -8359,7 +8528,7 @@ }, "node_modules/@types/react": { "version": "18.2.45", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -8369,7 +8538,7 @@ }, "node_modules/@types/react-dom": { "version": "18.2.17", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/react": "*" @@ -8399,7 +8568,7 @@ }, "node_modules/@types/scheduler": { "version": "0.16.3", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/semver": { @@ -11820,6 +11989,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "devOptional": true, @@ -26801,6 +26978,14 @@ "node": ">=0.10.0" } }, + "node_modules/react-children-utilities": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-children-utilities/-/react-children-utilities-2.9.0.tgz", + "integrity": "sha512-B3enhwcibIziobkMVccLd+6uIRoiCC9OZ1nR2B5sFCTnUYoGOCqgPOWUL+IC4S8IYaaN5AeF+SS0X1wernPdZA==", + "peerDependencies": { + "react": "18 || 17 || 16 || 15" + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "dev": true, @@ -31222,6 +31407,19 @@ "dev": true, "license": "MIT" }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sync-external-store": { "version": "1.2.0", "license": "MIT", @@ -32878,16 +33076,16 @@ }, "packages/backend": { "name": "@clerk/backend", - "version": "1.0.0-alpha-v5.9", + "version": "1.0.0-alpha-v5.11", "license": "MIT", "dependencies": { - "@clerk/shared": "2.0.0-alpha-v5.6", + "@clerk/shared": "2.0.0-alpha-v5.7", "cookie": "0.5.0", "snakecase-keys": "5.4.4", "tslib": "2.4.1" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.10", + "@clerk/types": "4.0.0-alpha-v5.12", "@cloudflare/workers-types": "^3.18.0", "@types/chai": "^4.3.3", "@types/cookie": "^0.5.1", @@ -32917,12 +33115,12 @@ }, "packages/chrome-extension": { "name": "@clerk/chrome-extension", - "version": "1.0.0-alpha-v5.10", + "version": "1.0.0-alpha-v5.12", "license": "MIT", "dependencies": { - "@clerk/clerk-js": "5.0.0-alpha-v5.10", - "@clerk/clerk-react": "5.0.0-alpha-v5.10", - "@clerk/shared": "2.0.0-alpha-v5.6", + "@clerk/clerk-js": "5.0.0-alpha-v5.12", + "@clerk/clerk-react": "5.0.0-alpha-v5.12", + "@clerk/shared": "2.0.0-alpha-v5.7", "webextension-polyfill": "^0.10.0" }, "devDependencies": { @@ -32966,12 +33164,12 @@ }, "packages/clerk-js": { "name": "@clerk/clerk-js", - "version": "5.0.0-alpha-v5.10", + "version": "5.0.0-alpha-v5.12", "license": "MIT", "dependencies": { "@clerk/localizations": "2.0.0-alpha-v5.7", - "@clerk/shared": "2.0.0-alpha-v5.6", - "@clerk/types": "4.0.0-alpha-v5.10", + "@clerk/shared": "2.0.0-alpha-v5.7", + "@clerk/types": "4.0.0-alpha-v5.12", "@emotion/cache": "11.11.0", "@emotion/react": "11.11.1", "@floating-ui/react": "0.25.4", @@ -33089,12 +33287,18 @@ }, "packages/elements": { "name": "@clerk/elements", - "version": "0.0.1", + "version": "0.0.2-alpha-v5.1", "license": "MIT", "dependencies": { - "@clerk/clerk-react": "5.0.0-alpha-v5.10" + "@clerk/nextjs": "^5.0.0-alpha-v5.12", + "@radix-ui/react-form": "^0.0.3", + "@xstate/react": "^4.0.1", + "clsx": "^2.0.0", + "react-children-utilities": "^2.9.0", + "xstate": "^5.3.1" }, "devDependencies": { + "@clerk/types": "^4.0.0-alpha-v5.11", "@types/node": "^18.17.0", "@types/react": "*", "@types/react-dom": "*", @@ -33107,9 +33311,32 @@ "node": ">=18.17.0" }, "peerDependencies": { - "next": ">=10", + "next": ">=13.0.4", "react": ">=18", "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "next": { + "optional": true + } + } + }, + "packages/elements/node_modules/@xstate/react": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@xstate/react/-/react-4.0.1.tgz", + "integrity": "sha512-UB9qUC11wcaYd05wGea0mvEA3uTHikNaB4InMZfxD7MVFxzBFU+3JFkemjiN8bDdPJfDrObyP9ZPDVojq2LytA==", + "dependencies": { + "use-isomorphic-layout-effect": "^1.1.2", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "xstate": "^5.1.0" + }, + "peerDependenciesMeta": { + "xstate": { + "optional": true + } } }, "packages/elements/node_modules/tslib": { @@ -33117,6 +33344,15 @@ "dev": true, "license": "0BSD" }, + "packages/elements/node_modules/xstate": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/xstate/-/xstate-5.3.1.tgz", + "integrity": "sha512-j4lYbMKqTQ1gxS0NAhjX0JkFJ44OLqYgXV7kVSc0YpnENhPNigvrFMqpBFtfho39pgzdcmpmnmUyEUVWwYMOdA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/xstate" + } + }, "packages/eslint-config-custom": { "version": "0.0.0", "license": "MIT", @@ -33339,17 +33575,17 @@ }, "packages/expo": { "name": "@clerk/clerk-expo", - "version": "1.0.0-alpha-v5.10", + "version": "1.0.0-alpha-v5.12", "license": "MIT", "dependencies": { - "@clerk/clerk-js": "5.0.0-alpha-v5.10", - "@clerk/clerk-react": "5.0.0-alpha-v5.10", - "@clerk/shared": "2.0.0-alpha-v5.6", + "@clerk/clerk-js": "5.0.0-alpha-v5.12", + "@clerk/clerk-react": "5.0.0-alpha-v5.12", + "@clerk/shared": "2.0.0-alpha-v5.7", "base-64": "^1.0.0", "react-native-url-polyfill": "2.0.0" }, "devDependencies": { - "@clerk/types": "^4.0.0-alpha-v5.10", + "@clerk/types": "^4.0.0-alpha-v5.12", "@types/base-64": "^1.0.2", "@types/node": "^18.17.0", "@types/react": "*", @@ -33372,12 +33608,12 @@ }, "packages/fastify": { "name": "@clerk/fastify", - "version": "1.0.0-alpha-v5.11", + "version": "1.0.0-alpha-v5.13", "license": "MIT", "dependencies": { - "@clerk/backend": "1.0.0-alpha-v5.9", - "@clerk/shared": "2.0.0-alpha-v5.6", - "@clerk/types": "4.0.0-alpha-v5.10", + "@clerk/backend": "1.0.0-alpha-v5.11", + "@clerk/shared": "2.0.0-alpha-v5.7", + "@clerk/types": "4.0.0-alpha-v5.12", "cookies": "0.8.0" }, "devDependencies": { @@ -33395,17 +33631,17 @@ } }, "packages/gatsby-plugin-clerk": { - "version": "5.0.0-alpha-v5.11", + "version": "5.0.0-alpha-v5.13", "license": "MIT", "dependencies": { - "@clerk/backend": "1.0.0-alpha-v5.9", - "@clerk/clerk-react": "5.0.0-alpha-v5.10", - "@clerk/clerk-sdk-node": "5.0.0-alpha-v5.9", + "@clerk/backend": "1.0.0-alpha-v5.11", + "@clerk/clerk-react": "5.0.0-alpha-v5.12", + "@clerk/clerk-sdk-node": "5.0.0-alpha-v5.11", "cookie": "0.5.0", "tslib": "2.4.1" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.10", + "@clerk/types": "4.0.0-alpha-v5.12", "@types/cookie": "^0.5.0", "@types/node": "^18.17.0", "eslint-config-custom": "*", @@ -33428,7 +33664,7 @@ "version": "2.0.0-alpha-v5.7", "license": "MIT", "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.10", + "@clerk/types": "4.0.0-alpha-v5.12", "@types/node": "^18.17.0", "eslint-config-custom": "*", "tsup": "*", @@ -33444,16 +33680,16 @@ }, "packages/nextjs": { "name": "@clerk/nextjs", - "version": "5.0.0-alpha-v5.11", + "version": "5.0.0-alpha-v5.13", "license": "MIT", "dependencies": { - "@clerk/backend": "1.0.0-alpha-v5.9", - "@clerk/clerk-react": "5.0.0-alpha-v5.10", - "@clerk/shared": "2.0.0-alpha-v5.6", + "@clerk/backend": "1.0.0-alpha-v5.11", + "@clerk/clerk-react": "5.0.0-alpha-v5.12", + "@clerk/shared": "2.0.0-alpha-v5.7", "path-to-regexp": "6.2.1" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.10", + "@clerk/types": "4.0.0-alpha-v5.12", "@types/node": "^18.17.0", "@types/react": "*", "@types/react-dom": "*", @@ -33478,11 +33714,11 @@ }, "packages/react": { "name": "@clerk/clerk-react", - "version": "5.0.0-alpha-v5.10", + "version": "5.0.0-alpha-v5.12", "license": "MIT", "dependencies": { - "@clerk/shared": "2.0.0-alpha-v5.6", - "@clerk/types": "4.0.0-alpha-v5.10", + "@clerk/shared": "2.0.0-alpha-v5.7", + "@clerk/types": "4.0.0-alpha-v5.12", "eslint-config-custom": "*", "semver": "^7.5.4", "tslib": "2.4.1" @@ -33510,17 +33746,17 @@ }, "packages/remix": { "name": "@clerk/remix", - "version": "4.0.0-alpha-v5.11", + "version": "4.0.0-alpha-v5.13", "license": "MIT", "dependencies": { - "@clerk/backend": "1.0.0-alpha-v5.9", - "@clerk/clerk-react": "5.0.0-alpha-v5.10", - "@clerk/shared": "2.0.0-alpha-v5.6", + "@clerk/backend": "1.0.0-alpha-v5.11", + "@clerk/clerk-react": "5.0.0-alpha-v5.12", + "@clerk/shared": "2.0.0-alpha-v5.7", "cookie": "0.5.0", "tslib": "2.4.1" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.10", + "@clerk/types": "4.0.0-alpha-v5.12", "@remix-run/react": "^2.0.0", "@remix-run/server-runtime": "^2.0.0", "@types/cookie": "^0.5.0", @@ -33546,16 +33782,16 @@ }, "packages/sdk-node": { "name": "@clerk/clerk-sdk-node", - "version": "5.0.0-alpha-v5.9", + "version": "5.0.0-alpha-v5.11", "license": "MIT", "dependencies": { - "@clerk/backend": "1.0.0-alpha-v5.9", - "@clerk/shared": "2.0.0-alpha-v5.6", + "@clerk/backend": "1.0.0-alpha-v5.11", + "@clerk/shared": "2.0.0-alpha-v5.7", "camelcase-keys": "6.2.2", "snakecase-keys": "3.2.1" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.10", + "@clerk/types": "4.0.0-alpha-v5.12", "@types/express": "4.17.14", "@types/node": "^18.17.0", "eslint-config-custom": "*", @@ -33588,7 +33824,7 @@ }, "packages/shared": { "name": "@clerk/shared", - "version": "2.0.0-alpha-v5.6", + "version": "2.0.0-alpha-v5.7", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -33597,7 +33833,7 @@ "swr": "2.2.0" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.10", + "@clerk/types": "4.0.0-alpha-v5.12", "@types/glob-to-regexp": "0.4.1", "@types/js-cookie": "3.0.2", "@types/node": "^18.17.0", @@ -33635,7 +33871,7 @@ "version": "2.0.0-alpha-v5.2", "license": "MIT", "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.10", + "@clerk/types": "4.0.0-alpha-v5.12", "@types/node": "^18.17.0", "eslint-config-custom": "*", "typescript": "*" @@ -33650,7 +33886,7 @@ }, "packages/types": { "name": "@clerk/types", - "version": "4.0.0-alpha-v5.10", + "version": "4.0.0-alpha-v5.12", "license": "MIT", "dependencies": { "csstype": "3.1.1" @@ -33668,29 +33904,6 @@ "packages/types/node_modules/csstype": { "version": "3.1.1", "license": "MIT" - }, - "playground/elements/nextjs": { - "name": "elements-nextjs", - "version": "0.1.0", - "extraneous": true, - "dependencies": { - "@clerk/elements": "*", - "next": "14.0.4", - "react": "^18", - "react-dom": "^18" - }, - "devDependencies": { - "@playwright/test": "^1.40.1", - "@types/node": "^18", - "@types/react": "^18", - "@types/react-dom": "^18", - "autoprefixer": "^10.0.1", - "eslint": "^8", - "eslint-config-next": "14.0.4", - "postcss": "^8", - "tailwindcss": "^3.3.0", - "typescript": "^5" - } } } } diff --git a/packages/elements/.npmignore b/packages/elements/.npmignore new file mode 100644 index 0000000000..1e107f52e4 --- /dev/null +++ b/packages/elements/.npmignore @@ -0,0 +1 @@ +examples diff --git a/packages/elements/examples/nextjs/.env.local.example b/packages/elements/examples/nextjs/.env.local.example new file mode 100644 index 0000000000..e85051c07b --- /dev/null +++ b/packages/elements/examples/nextjs/.env.local.example @@ -0,0 +1,7 @@ +NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY= +CLERK_SECRET_KEY= + +NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in +NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up +NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/ +NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/ diff --git a/packages/elements/examples/nextjs/app/globals.css b/packages/elements/examples/nextjs/app/globals.css index fd81e88583..71f619b0a4 100644 --- a/packages/elements/examples/nextjs/app/globals.css +++ b/packages/elements/examples/nextjs/app/globals.css @@ -18,10 +18,4 @@ body { color: rgb(var(--foreground-rgb)); - background: linear-gradient( - to bottom, - transparent, - rgb(var(--background-end-rgb)) - ) - rgb(var(--background-start-rgb)); } diff --git a/packages/elements/examples/nextjs/app/layout.tsx b/packages/elements/examples/nextjs/app/layout.tsx index 20a6644f0b..09b81586a1 100644 --- a/packages/elements/examples/nextjs/app/layout.tsx +++ b/packages/elements/examples/nextjs/app/layout.tsx @@ -1,5 +1,6 @@ import './globals.css' +import { ClerkProvider } from '@clerk/nextjs' import type { Metadata } from 'next' import { Inter } from 'next/font/google' @@ -16,8 +17,14 @@ export default function RootLayout({ children: React.ReactNode }) { return ( - - {children} - + + + + {children} + + ) } diff --git a/packages/elements/examples/nextjs/app/sign-in/[[...sign-in]]/page.tsx b/packages/elements/examples/nextjs/app/sign-in/[[...sign-in]]/page.tsx index 2ee4d9c8e9..1ac26f8b07 100644 --- a/packages/elements/examples/nextjs/app/sign-in/[[...sign-in]]/page.tsx +++ b/packages/elements/examples/nextjs/app/sign-in/[[...sign-in]]/page.tsx @@ -4,13 +4,13 @@ export default function SignInPage() { return ( - Start child +

Start child

- Factor one child - +

Factor one child

+ - Factor two child +

Factor two child

diff --git a/packages/elements/examples/nextjs/middleware.ts b/packages/elements/examples/nextjs/middleware.ts new file mode 100644 index 0000000000..35c4bf4bdb --- /dev/null +++ b/packages/elements/examples/nextjs/middleware.ts @@ -0,0 +1,12 @@ +import { authMiddleware } from "@clerk/nextjs/server"; + +// Set the paths that don't require the user to be signed in +const publicPaths = ['/', /^(\/(sign-in|sign-up|app-dir|custom)\/*).*$/]; + +export default authMiddleware({ + publicRoutes: publicPaths, +}); + +export const config = { + matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'], +}; diff --git a/packages/elements/examples/nextjs/package.json b/packages/elements/examples/nextjs/package.json index d0644a465f..fd7cb5337b 100644 --- a/packages/elements/examples/nextjs/package.json +++ b/packages/elements/examples/nextjs/package.json @@ -14,6 +14,10 @@ }, "dependencies": { "@clerk/elements": "*", + "@clerk/nextjs": "file:../../nextjs", + "@clerk/shared": "file:../../shared", + "@radix-ui/react-form": "^0.0.3", + "clsx": "^2.0.0", "next": "14.0.4", "react": "^18", "react-dom": "^18" diff --git a/packages/elements/package.json b/packages/elements/package.json index 10a96886b7..da93239f88 100644 --- a/packages/elements/package.json +++ b/packages/elements/package.json @@ -58,9 +58,15 @@ "test:cache:clear": "jest --clearCache --useStderr" }, "dependencies": { - "@clerk/clerk-react": "5.0.0-alpha-v5.12" + "@clerk/nextjs": "^5.0.0-alpha-v5.12", + "@radix-ui/react-form": "^0.0.3", + "@xstate/react": "^4.0.1", + "clsx": "^2.0.0", + "react-children-utilities": "^2.9.0", + "xstate": "^5.3.1" }, "devDependencies": { + "@clerk/types": "^4.0.0-alpha-v5.11", "@types/node": "^18.17.0", "@types/react": "*", "@types/react-dom": "*", diff --git a/packages/elements/src/internals/machines/sign-in.actors.ts b/packages/elements/src/internals/machines/sign-in.actors.ts new file mode 100644 index 0000000000..e46be2306f --- /dev/null +++ b/packages/elements/src/internals/machines/sign-in.actors.ts @@ -0,0 +1,72 @@ +import type { + AttemptFirstFactorParams, + AttemptSecondFactorParams, + PrepareFirstFactorParams, + PrepareSecondFactorParams, + SignInCreateParams, + SignInResource, +} from '@clerk/types'; +import { fromPromise } from 'xstate'; + +import type { SignInResourceParams } from './sign-in.types'; + +export const createSignIn = fromPromise>( + async ({ input: { client, params } }) => { + if (!client.signIn) { + throw new Error('signIn not available'); // TODO: better error + } + + return client.signIn.create(params); + }, +); + +export const prepareFirstFactor = fromPromise>( + async ({ input: { client, params } }) => { + if (!client.signIn) { + throw new Error('signIn not available'); // TODO: better error + } + + return client.signIn.prepareFirstFactor(params); + }, +); + +export const attemptFirstFactor = fromPromise>( + async ({ input: { client, params } }) => { + if (!client.signIn) { + throw new Error('signIn not available'); // TODO: better error + } + + return client.signIn.attemptFirstFactor(params); + }, +); + +export const prepareSecondFactor = fromPromise>( + async ({ input: { client, params } }) => { + if (!client.signIn) { + throw new Error('signIn not available'); // TODO: better error + } + + return client.signIn.prepareSecondFactor(params); + }, +); + +export const attemptSecondFactor = fromPromise>( + async ({ input: { client, params } }) => { + if (!client.signIn) { + throw new Error('signIn not available'); // TODO: better error + } + + return client.signIn.attemptSecondFactor(params); + }, +); + +// TODO: Convert to Action +// export const authenticateWithRedirect = fromPromise>( +// async ({ input: { client, params } }) => { +// if (!client.signIn) { +// throw new Error('signIn not available'); +// } + +// return client.signIn.authenticateWithRedirect(params); +// }, +// ); diff --git a/packages/elements/src/internals/machines/sign-in.context.ts b/packages/elements/src/internals/machines/sign-in.context.ts new file mode 100644 index 0000000000..e3467bfa7c --- /dev/null +++ b/packages/elements/src/internals/machines/sign-in.context.ts @@ -0,0 +1,5 @@ +import { createActorContext } from '@xstate/react'; + +import { SignInMachine } from './sign-in.machine'; + +export const SignInActor = createActorContext(SignInMachine); diff --git a/packages/elements/src/internals/machines/sign-in.machine.ts b/packages/elements/src/internals/machines/sign-in.machine.ts new file mode 100644 index 0000000000..b68cf13303 --- /dev/null +++ b/packages/elements/src/internals/machines/sign-in.machine.ts @@ -0,0 +1,305 @@ +import type { ClerkAPIResponseError } from '@clerk/shared/error'; +import { isClerkAPIResponseError } from '@clerk/shared/error'; +import type { SignInResource } from '@clerk/types'; +import { assign, setup } from 'xstate'; + +import type { ClerkHostRouter } from '../router'; +import { + attemptFirstFactor, + attemptSecondFactor, + createSignIn, + prepareFirstFactor, + prepareSecondFactor, +} from './sign-in.actors'; +import type { SignInClient } from './sign-in.types'; + +export const STATES = { + Init: 'Init', + Start: 'Start', + StartAttempting: 'StartAttempting', + StartFailure: 'StartFailure', + FirstFactor: 'FirstFactor', + FirstFactorPreparing: 'FirstFactorPreparing', + FirstFactorIdle: 'FirstFactorIdle', + FirstFactorAttempting: 'FirstFactorAttempting', + FirstFactorFailure: 'FirstFactorFailure', + SecondFactor: 'SecondFactor', + SecondFactorPreparing: 'SecondFactorPreparing', + SecondFactorIdle: 'SecondFactorIdle', + SecondFactorAttempting: 'SecondFactorAttempting', + SecondFactorFailure: 'SecondFactorFailure', + Complete: 'Complete', +} as const; + +function eventHasError(value: T): value is T & { error: Error } { + // @ts-expect-error - TODO: fix + return value.error instanceof Error; +} + +export const SignInMachine = setup({ + actors: { + createSignIn, + prepareFirstFactor, + attemptFirstFactor, + prepareSecondFactor, + attemptSecondFactor, + // authenticateWithRedirect, + }, + actions: { + assignResourceToContext: assign({ + // @ts-expect-error - TODO: fix types + resource: ({ event }) => event.output, + }), + + assignErrorMessageToContext: assign({ + error: ({ context, event }) => (eventHasError(event) ? event.error : context.error), + }), + + navigateTo: ({ context }, { path }: { path: string }) => context.router.replace(path), + + clearFields: assign({ + fields: {}, + }), + }, + guards: { + hasClerkAPIError: ({ context }) => isClerkAPIResponseError(context.error), + hasClerkAPIErrorCode: ({ context }, params?: { code?: string }) => + params?.code + ? isClerkAPIResponseError(context.error) + ? Boolean(context.error.errors.find(e => e.code === params.code)) + : false + : false, + }, + types: { + context: {} as { + client: SignInClient; + router: ClerkHostRouter; + error?: Error | ClerkAPIResponseError; + resource?: SignInResource; + fields: Record; + }, + input: {} as { + client: SignInClient; + router: ClerkHostRouter; + }, + events: {} as { type: 'START' } | { type: 'SUBMIT' } | { type: 'NEXT' } | { type: 'RETRY' } | { type: 'ASSIGN' }, + }, +}).createMachine({ + context: ({ input }) => ({ + client: input.client, + router: input.router, + currentFactor: null, + fields: {}, + }), + initial: STATES.Init, + states: { + [STATES.Init]: { + always: 'Start', + }, + [STATES.Start]: { + entry: ({ context }) => console.log('Start entry: ', context), + on: { + SUBMIT: STATES.StartAttempting, + }, + }, + [STATES.StartAttempting]: { + entry: ({ context }) => console.log('StartAttempting entry: ', context), + invoke: { + id: 'createSignIn', + src: 'createSignIn', + input: ({ context }) => ({ + client: context.client, + params: { + identifier: 'tom@clerk.dev', + password: 'tom@clerk.dev', + strategy: 'password', + }, + }), + onDone: [{ actions: 'assignResourceToContext' }], + onError: { + target: STATES.StartFailure, + actions: 'assignErrorMessageToContext', + }, + }, + }, + [STATES.StartFailure]: { + entry: ({ context }) => console.log('StartFailure entry: ', context), + always: [ + { + guard: { type: 'hasClerkAPIErrorCode', params: { code: 'session_exists' } }, + actions: [ + { + type: 'navigateTo', + params: { + path: '/', + }, + }, + ], + }, + { + guard: 'hasClerkAPIError', + target: STATES.Start, + }, + { + actions: { + type: 'navigateTo', + params: { + path: '/sign-in/factor-one', + }, + }, + }, + ], + }, + [STATES.FirstFactor]: { + always: 'FirstFactorPreparing', + }, + [STATES.FirstFactorPreparing]: { + invoke: { + id: 'prepareFirstFactor', + src: 'prepareFirstFactor', + // @ts-expect-error - TODO: Implement + input: ({ context }) => ({ + client: context.client, + params: {}, + }), + onDone: { + target: STATES.FirstFactor, + actions: [ + 'assignResourceToContext', + { + type: 'navigateTo', + params: { + path: '/sign-in/factor-one', + }, + }, + ], + }, + onError: { + target: STATES.Start, + actions: ['assignErrorMessageToContext'], + }, + }, + }, + [STATES.FirstFactorIdle]: { + on: { + SUBMIT: { + // guard: ({ context }) => !!context.resource, + target: STATES.FirstFactorAttempting, + }, + }, + }, + [STATES.FirstFactorAttempting]: { + invoke: { + id: 'prepareFirstFactor', + src: 'prepareFirstFactor', + // @ts-expect-error - TODO: Implement + input: ({ context }) => ({ + client: context.client, + params: {}, + }), + onDone: { + target: STATES.FirstFactor, + actions: [ + 'assignResourceToContext', + { + type: 'navigateTo', + params: { + path: '/sign-in/factor-one', + }, + }, + ], + }, + onError: { + target: STATES.FirstFactorIdle, + actions: 'assignErrorMessageToContext', + }, + }, + }, + [STATES.FirstFactorFailure]: { + always: [ + { + guard: 'hasClerkAPIError', + target: STATES.FirstFactorIdle, + }, + { + actions: { + type: 'navigateTo', + params: { + path: '/sign-in/factor-one', + }, + }, + }, + ], + }, + [STATES.SecondFactor]: { + always: STATES.SecondFactorPreparing, + }, + [STATES.SecondFactorPreparing]: { + invoke: { + id: 'prepareSecondFactor', + src: 'prepareSecondFactor', + // @ts-expect-error - TODO: Implement + input: ({ context }) => ({ + client: context.client, + params: {}, + }), + onDone: { + target: STATES.SecondFactorIdle, + actions: ['assignResourceToContext'], + }, + onError: { + target: STATES.SecondFactorIdle, + actions: ['assignErrorMessageToContext'], + }, + }, + }, + [STATES.SecondFactorIdle]: { + on: { + RETRY: 'SecondFactorPreparing', + SUBMIT: { + // guard: ({ context }) => !!context.resource, + target: STATES.SecondFactorAttempting, + }, + }, + }, + [STATES.SecondFactorAttempting]: { + invoke: { + id: 'prepareFirstFactor', + src: 'prepareFirstFactor', + // @ts-expect-error - TODO: Implement + input: ({ context }) => ({ + client: context.client, + params: {}, + }), + onDone: { + target: STATES.SecondFactorIdle, + actions: [ + 'assignResourceToContext', + { + type: 'navigateTo', + params: { + path: '/sign-in/factor-one', + }, + }, + ], + }, + onError: { + target: STATES.SecondFactorIdle, + actions: ['assignErrorMessageToContext'], + }, + }, + [STATES.SecondFactorFailure]: { + always: [ + { + guard: 'hasClerkAPIError', + target: STATES.SecondFactorIdle, + }, + { target: STATES.Complete }, + ], + }, + }, + [STATES.Complete]: { + type: 'final', + }, + }, +}); diff --git a/packages/elements/src/internals/machines/sign-in.types.ts b/packages/elements/src/internals/machines/sign-in.types.ts new file mode 100644 index 0000000000..526335acec --- /dev/null +++ b/packages/elements/src/internals/machines/sign-in.types.ts @@ -0,0 +1,8 @@ +import type { ClientResource } from '@clerk/types'; + +export type SignInClient = ClientResource; + +export type SignInResourceParams = { + client: SignInClient; + params: T; +}; diff --git a/packages/elements/src/internals/machines/utils/inspect.ts b/packages/elements/src/internals/machines/utils/inspect.ts new file mode 100644 index 0000000000..760561db79 --- /dev/null +++ b/packages/elements/src/internals/machines/utils/inspect.ts @@ -0,0 +1,19 @@ +import type { InspectionEvent } from 'xstate'; + +export const inspect = (inspectionEvent: InspectionEvent) => { + if (inspectionEvent.type === '@xstate.actor') { + console.log(inspectionEvent.actorRef.id, inspectionEvent.actorRef); + } + + if (inspectionEvent.type === '@xstate.event') { + console.log(inspectionEvent.actorRef.id, inspectionEvent.sourceRef); + console.log(inspectionEvent.actorRef.id, inspectionEvent.actorRef); + console.log(inspectionEvent.actorRef.id, inspectionEvent.event); + } + + if (inspectionEvent.type === '@xstate.snapshot') { + console.log(inspectionEvent.actorRef.id, inspectionEvent.actorRef); + console.log(inspectionEvent.actorRef.id, inspectionEvent.event); + console.log(inspectionEvent.actorRef.id, inspectionEvent.snapshot); + } +}; diff --git a/packages/elements/src/sign-in/index.tsx b/packages/elements/src/sign-in/index.tsx index ecb9b8fe8f..ce8c432f39 100644 --- a/packages/elements/src/sign-in/index.tsx +++ b/packages/elements/src/sign-in/index.tsx @@ -1,26 +1,67 @@ 'use client'; -import { type ClerkHostRouter, useNextRouter } from '../internals/router'; + +import { useClerk } from '@clerk/nextjs'; +import { useEffect } from 'react'; + +import { SignInActor } from '../internals/machines/sign-in.context'; +import { useNextRouter } from '../internals/router'; import { Route, Router } from '../internals/router-react'; -export function SignIn({ children }: { router?: ClerkHostRouter; children: React.ReactNode }): JSX.Element { +export function SignIn({ children }: { children: React.ReactNode }): JSX.Element | null { // TODO: eventually we'll rely on the framework SDK to specify its host router, but for now we'll default to Next.js const router = useNextRouter(); + const clerk = useClerk(); + + // @ts-expect-error - clerk.clerkjs isn't typed + if (!router || !clerk?.clerkjs) { + return null; + } + + // @ts-expect-error - clerk.clerkjs isn't typed + const client = clerk.clerkjs.client; return ( - {children} + {children} ); } +export function SubmitButton() { + const ref = SignInActor.useActorRef(); + // const fields = SignInRootMachine.useSelector((state) => state.context.fields['identifier']); + // console.log(ref.getSnapshot()); + + return ( + + ); +} + +export function SignInStartInner({ children }: { children: React.ReactNode }) { + const ref = SignInActor.useActorRef(); + + useEffect(() => ref.send({ type: 'START' }), [ref]); + + return <>{children}; +} + export function SignInStart({ children }: { children: React.ReactNode }) { return ( - Start - {children} + +

Start

+ {children} + +
); } @@ -28,7 +69,7 @@ export function SignInStart({ children }: { children: React.ReactNode }) { export function SignInFactorOne({ children }: { children: React.ReactNode }) { return ( - Factor One +

Factor One

{children}
); @@ -37,7 +78,7 @@ export function SignInFactorOne({ children }: { children: React.ReactNode }) { export function SignInFactorTwo({ children }: { children: React.ReactNode }) { return ( - Factor Two +

Factor Two

{children}
);