@poly-x/react 0.1.0-alpha.6 → 0.1.0-alpha.7
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.
- package/dist/index.cjs +484 -2
- package/dist/index.d.cts +96 -1
- package/dist/index.d.mts +96 -1
- package/dist/index.mjs +486 -6
- package/dist/styles.css +71 -0
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -352,7 +352,7 @@ function Protected({ children, fallback = null, loading = null }) {
|
|
|
352
352
|
}
|
|
353
353
|
//#endregion
|
|
354
354
|
//#region src/components/sign-in.tsx
|
|
355
|
-
const DEFAULT_LABELS = {
|
|
355
|
+
const DEFAULT_LABELS$2 = {
|
|
356
356
|
heading: "Sign in",
|
|
357
357
|
subheading: "Enter your credentials to continue.",
|
|
358
358
|
tagline: "",
|
|
@@ -393,7 +393,7 @@ function SignIn(props) {
|
|
|
393
393
|
const action = props.action ?? "/api/polyx/authenticate";
|
|
394
394
|
const variant = props.variant ?? "card";
|
|
395
395
|
const labels = {
|
|
396
|
-
...DEFAULT_LABELS,
|
|
396
|
+
...DEFAULT_LABELS$2,
|
|
397
397
|
...props.labels
|
|
398
398
|
};
|
|
399
399
|
const [email, setEmail] = (0, react.useState)("");
|
|
@@ -668,6 +668,486 @@ function SignIn(props) {
|
|
|
668
668
|
});
|
|
669
669
|
}
|
|
670
670
|
//#endregion
|
|
671
|
+
//#region src/components/_recovery-status.tsx
|
|
672
|
+
const ICONS = {
|
|
673
|
+
mail: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
674
|
+
viewBox: "0 0 24 24",
|
|
675
|
+
fill: "none",
|
|
676
|
+
stroke: "currentColor",
|
|
677
|
+
strokeWidth: "1.75",
|
|
678
|
+
"aria-hidden": "true",
|
|
679
|
+
focusable: "false",
|
|
680
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
681
|
+
x: "3",
|
|
682
|
+
y: "5",
|
|
683
|
+
width: "18",
|
|
684
|
+
height: "14",
|
|
685
|
+
rx: "2.5"
|
|
686
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
687
|
+
d: "m4 7 8 6 8-6",
|
|
688
|
+
strokeLinecap: "round",
|
|
689
|
+
strokeLinejoin: "round"
|
|
690
|
+
})]
|
|
691
|
+
}),
|
|
692
|
+
check: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
693
|
+
viewBox: "0 0 24 24",
|
|
694
|
+
fill: "none",
|
|
695
|
+
stroke: "currentColor",
|
|
696
|
+
strokeWidth: "2",
|
|
697
|
+
"aria-hidden": "true",
|
|
698
|
+
focusable: "false",
|
|
699
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
700
|
+
d: "m5 12.5 4.5 4.5L19 7",
|
|
701
|
+
strokeLinecap: "round",
|
|
702
|
+
strokeLinejoin: "round"
|
|
703
|
+
})
|
|
704
|
+
}),
|
|
705
|
+
warning: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
706
|
+
viewBox: "0 0 24 24",
|
|
707
|
+
fill: "none",
|
|
708
|
+
stroke: "currentColor",
|
|
709
|
+
strokeWidth: "1.75",
|
|
710
|
+
"aria-hidden": "true",
|
|
711
|
+
focusable: "false",
|
|
712
|
+
children: [
|
|
713
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
714
|
+
cx: "12",
|
|
715
|
+
cy: "12",
|
|
716
|
+
r: "9"
|
|
717
|
+
}),
|
|
718
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
719
|
+
d: "M12 7.5v5",
|
|
720
|
+
strokeLinecap: "round"
|
|
721
|
+
}),
|
|
722
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
723
|
+
cx: "12",
|
|
724
|
+
cy: "16",
|
|
725
|
+
r: "0.6",
|
|
726
|
+
fill: "currentColor",
|
|
727
|
+
stroke: "none"
|
|
728
|
+
})
|
|
729
|
+
]
|
|
730
|
+
})
|
|
731
|
+
};
|
|
732
|
+
/**
|
|
733
|
+
* A centered, icon-topped confirmation card — the shape every recovery terminal
|
|
734
|
+
* state shares (link sent, password updated, link expired). Reuses the `<SignIn/>`
|
|
735
|
+
* class anatomy so it themes from the same `--polyx-*` custom properties.
|
|
736
|
+
*/
|
|
737
|
+
function RecoveryStatus(props) {
|
|
738
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
739
|
+
className: "polyx-signin__card",
|
|
740
|
+
children: [
|
|
741
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
742
|
+
className: "polyx-signin__header polyx-signin__header--center",
|
|
743
|
+
children: [
|
|
744
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
745
|
+
className: `polyx-signin__status-icon polyx-signin__status-icon--${props.tone ?? "brand"}`,
|
|
746
|
+
children: ICONS[props.icon]
|
|
747
|
+
}),
|
|
748
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
749
|
+
className: "polyx-signin__heading",
|
|
750
|
+
children: props.heading
|
|
751
|
+
}),
|
|
752
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
753
|
+
className: "polyx-signin__subheading",
|
|
754
|
+
children: props.children
|
|
755
|
+
})
|
|
756
|
+
]
|
|
757
|
+
}),
|
|
758
|
+
props.actions ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
759
|
+
className: "polyx-signin__actions",
|
|
760
|
+
children: props.actions
|
|
761
|
+
}) : null,
|
|
762
|
+
props.footer
|
|
763
|
+
]
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
//#endregion
|
|
767
|
+
//#region src/components/forgot-password.tsx
|
|
768
|
+
const DEFAULT_LABELS$1 = {
|
|
769
|
+
heading: "Reset your password",
|
|
770
|
+
subheading: "Enter your email and we'll send you a reset link.",
|
|
771
|
+
emailLabel: "Email",
|
|
772
|
+
emailPlaceholder: "you@company.com",
|
|
773
|
+
submit: "Send reset link",
|
|
774
|
+
submitting: "Sending…",
|
|
775
|
+
sentHeading: "Check your email",
|
|
776
|
+
sentSubheading: "If an account exists for {email}, a password reset link is on its way. It expires in 30 minutes.",
|
|
777
|
+
differentEmail: "Use a different email",
|
|
778
|
+
backToSignIn: "Back to sign in",
|
|
779
|
+
securedBy: "Secured by PolyX",
|
|
780
|
+
genericError: "Something went wrong. Please try again."
|
|
781
|
+
};
|
|
782
|
+
/** Splits a label on `{email}` and drops the entered address in, emphasized. */
|
|
783
|
+
function withEmail(template, email) {
|
|
784
|
+
return template.split("{email}").map((chunk, index, all) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [chunk, index < all.length - 1 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
785
|
+
className: "polyx-signin__email",
|
|
786
|
+
children: email || "that address"
|
|
787
|
+
}) : null] }, index));
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* The self-service "forgot password" form (poly-x v5 / F040). Renders an email field
|
|
791
|
+
* inside the consuming app and POSTs to the SDK's BFF (`@poly-x/next` `forgotPassword`),
|
|
792
|
+
* which asks poly-auth to email a single-use reset link SERVER-SIDE. The response is
|
|
793
|
+
* always the same — no token, no account-existence signal — so after submit the form
|
|
794
|
+
* shows an identical "check your email" state whether or not the account exists.
|
|
795
|
+
*
|
|
796
|
+
* Reuses the `<SignIn/>` styling: `import "@poly-x/react/styles.css"` once, then theme
|
|
797
|
+
* via the `--polyx-*` custom properties. Target `.polyx-forgot` for form-specific tweaks.
|
|
798
|
+
*/
|
|
799
|
+
function ForgotPassword(props) {
|
|
800
|
+
const action = props.action ?? "/api/polyx/forgot-password";
|
|
801
|
+
const signInPath = props.signInPath ?? "/sign-in";
|
|
802
|
+
const labels = {
|
|
803
|
+
...DEFAULT_LABELS$1,
|
|
804
|
+
...props.labels
|
|
805
|
+
};
|
|
806
|
+
const [email, setEmail] = (0, react.useState)("");
|
|
807
|
+
const [submitting, setSubmitting] = (0, react.useState)(false);
|
|
808
|
+
const [sent, setSent] = (0, react.useState)(false);
|
|
809
|
+
const [error, setError] = (0, react.useState)(null);
|
|
810
|
+
async function onSubmit(event) {
|
|
811
|
+
event.preventDefault();
|
|
812
|
+
setSubmitting(true);
|
|
813
|
+
setError(null);
|
|
814
|
+
try {
|
|
815
|
+
if ((await (await fetch(action, {
|
|
816
|
+
method: "POST",
|
|
817
|
+
headers: { "content-type": "application/json" },
|
|
818
|
+
body: JSON.stringify({ email })
|
|
819
|
+
})).json().catch(() => ({}))).status === "accepted") {
|
|
820
|
+
setSent(true);
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
setError(labels.genericError);
|
|
824
|
+
} catch {
|
|
825
|
+
setError(labels.genericError);
|
|
826
|
+
} finally {
|
|
827
|
+
setSubmitting(false);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
const rootClass = [
|
|
831
|
+
"polyx-signin",
|
|
832
|
+
"polyx-forgot",
|
|
833
|
+
props.className
|
|
834
|
+
].filter(Boolean).join(" ");
|
|
835
|
+
const footer = props.showSecuredBy === false ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
836
|
+
className: "polyx-signin__footer",
|
|
837
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
838
|
+
className: "polyx-signin__shield",
|
|
839
|
+
viewBox: "0 0 16 16",
|
|
840
|
+
fill: "currentColor",
|
|
841
|
+
"aria-hidden": "true",
|
|
842
|
+
focusable: "false",
|
|
843
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 0.5 2 3v4.2c0 3.5 2.5 6.7 6 7.8 3.5-1.1 6-4.3 6-7.8V3L8 .5Zm2.9 5.6-3.4 3.4a.7.7 0 0 1-1 0L5.1 8.1a.7.7 0 1 1 1-1l.9.9 2.9-2.9a.7.7 0 0 1 1 1Z" })
|
|
844
|
+
}), labels.securedBy]
|
|
845
|
+
});
|
|
846
|
+
const header = (heading, subheading) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
847
|
+
className: "polyx-signin__header",
|
|
848
|
+
children: [
|
|
849
|
+
props.logo ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
850
|
+
className: "polyx-signin__logo",
|
|
851
|
+
children: props.logo
|
|
852
|
+
}) : null,
|
|
853
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
854
|
+
className: "polyx-signin__heading",
|
|
855
|
+
children: heading
|
|
856
|
+
}),
|
|
857
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
858
|
+
className: "polyx-signin__subheading",
|
|
859
|
+
children: subheading
|
|
860
|
+
})
|
|
861
|
+
]
|
|
862
|
+
});
|
|
863
|
+
if (sent) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
864
|
+
className: rootClass,
|
|
865
|
+
"data-polyx-forgot": "sent",
|
|
866
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecoveryStatus, {
|
|
867
|
+
icon: "mail",
|
|
868
|
+
heading: labels.sentHeading,
|
|
869
|
+
footer,
|
|
870
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
871
|
+
type: "button",
|
|
872
|
+
className: "polyx-signin__link",
|
|
873
|
+
onClick: () => setSent(false),
|
|
874
|
+
children: labels.differentEmail
|
|
875
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
876
|
+
className: "polyx-signin__link",
|
|
877
|
+
href: signInPath,
|
|
878
|
+
children: labels.backToSignIn
|
|
879
|
+
})] }),
|
|
880
|
+
children: withEmail(labels.sentSubheading, email)
|
|
881
|
+
})
|
|
882
|
+
});
|
|
883
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
884
|
+
className: rootClass,
|
|
885
|
+
"data-polyx-forgot": "request",
|
|
886
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
887
|
+
className: "polyx-signin__card",
|
|
888
|
+
children: [
|
|
889
|
+
header(labels.heading, labels.subheading),
|
|
890
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
891
|
+
className: "polyx-signin__form",
|
|
892
|
+
onSubmit,
|
|
893
|
+
children: [
|
|
894
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
895
|
+
className: "polyx-signin__field",
|
|
896
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
897
|
+
className: "polyx-signin__label",
|
|
898
|
+
children: labels.emailLabel
|
|
899
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
900
|
+
className: "polyx-signin__input",
|
|
901
|
+
type: "email",
|
|
902
|
+
name: "email",
|
|
903
|
+
autoComplete: "username",
|
|
904
|
+
placeholder: labels.emailPlaceholder,
|
|
905
|
+
required: true,
|
|
906
|
+
value: email,
|
|
907
|
+
disabled: submitting,
|
|
908
|
+
onChange: (event) => setEmail(event.target.value)
|
|
909
|
+
})]
|
|
910
|
+
}),
|
|
911
|
+
error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
912
|
+
role: "alert",
|
|
913
|
+
className: "polyx-signin__error",
|
|
914
|
+
children: error
|
|
915
|
+
}) : null,
|
|
916
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
917
|
+
type: "submit",
|
|
918
|
+
className: "polyx-signin__submit",
|
|
919
|
+
disabled: submitting,
|
|
920
|
+
children: submitting ? labels.submitting : labels.submit
|
|
921
|
+
})
|
|
922
|
+
]
|
|
923
|
+
}),
|
|
924
|
+
footer
|
|
925
|
+
]
|
|
926
|
+
})
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
//#endregion
|
|
930
|
+
//#region src/components/reset-password.tsx
|
|
931
|
+
const DEFAULT_LABELS = {
|
|
932
|
+
heading: "Choose a new password",
|
|
933
|
+
subheading: "Enter and confirm your new password.",
|
|
934
|
+
newPasswordLabel: "New password",
|
|
935
|
+
confirmPasswordLabel: "Confirm new password",
|
|
936
|
+
passwordPlaceholder: "••••••••",
|
|
937
|
+
submit: "Reset password",
|
|
938
|
+
submitting: "Resetting…",
|
|
939
|
+
successHeading: "Password updated",
|
|
940
|
+
successSubheading: "You can now sign in with your new password.",
|
|
941
|
+
invalidHeading: "This link is invalid or expired",
|
|
942
|
+
invalidSubheading: "Password reset links can be used once and expire quickly. Request a new one.",
|
|
943
|
+
requestNewLink: "Request a new link",
|
|
944
|
+
backToSignIn: "Back to sign in",
|
|
945
|
+
securedBy: "Secured by PolyX",
|
|
946
|
+
passwordMismatch: "Those passwords don't match.",
|
|
947
|
+
weakPassword: "Password must be at least 8 characters.",
|
|
948
|
+
genericError: "Something went wrong. Please try again."
|
|
949
|
+
};
|
|
950
|
+
/** Matches poly-auth's v5 reset floor (F040). */
|
|
951
|
+
const DEFAULT_MIN_LENGTH = 8;
|
|
952
|
+
/**
|
|
953
|
+
* The reset-completion form (poly-x v5 / F040). Reads the opaque token from the URL,
|
|
954
|
+
* collects a new password, and POSTs to the SDK's BFF (`@poly-x/next` `resetPassword`),
|
|
955
|
+
* which redeems the token single-use server-side. The token is never decoded in the
|
|
956
|
+
* browser — identity, validity, and expiry are all enforced by the backend.
|
|
957
|
+
*
|
|
958
|
+
* Reuses the `<SignIn/>` styling: `import "@poly-x/react/styles.css"` once, then theme
|
|
959
|
+
* via the `--polyx-*` custom properties. Target `.polyx-reset` for form-specific tweaks.
|
|
960
|
+
*/
|
|
961
|
+
function ResetPassword(props) {
|
|
962
|
+
const action = props.action ?? "/api/polyx/reset-password";
|
|
963
|
+
const minLength = props.minLength ?? DEFAULT_MIN_LENGTH;
|
|
964
|
+
const signInPath = props.signInPath ?? "/sign-in";
|
|
965
|
+
const forgotPasswordPath = props.forgotPasswordPath ?? "/forgot-password";
|
|
966
|
+
const labels = {
|
|
967
|
+
...DEFAULT_LABELS,
|
|
968
|
+
...props.labels
|
|
969
|
+
};
|
|
970
|
+
const [token] = (0, react.useState)(() => props.token ?? (typeof window !== "undefined" ? new URLSearchParams(window.location.search).get("token") ?? "" : ""));
|
|
971
|
+
const [newPassword, setNewPassword] = (0, react.useState)("");
|
|
972
|
+
const [confirmPassword, setConfirmPassword] = (0, react.useState)("");
|
|
973
|
+
const [submitting, setSubmitting] = (0, react.useState)(false);
|
|
974
|
+
const [error, setError] = (0, react.useState)(null);
|
|
975
|
+
const [step, setStep] = (0, react.useState)(token ? "form" : "invalid");
|
|
976
|
+
async function onSubmit(event) {
|
|
977
|
+
event.preventDefault();
|
|
978
|
+
if (newPassword !== confirmPassword) {
|
|
979
|
+
setError(labels.passwordMismatch);
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
setSubmitting(true);
|
|
983
|
+
setError(null);
|
|
984
|
+
try {
|
|
985
|
+
switch ((await (await fetch(action, {
|
|
986
|
+
method: "POST",
|
|
987
|
+
headers: { "content-type": "application/json" },
|
|
988
|
+
body: JSON.stringify({
|
|
989
|
+
token,
|
|
990
|
+
newPassword,
|
|
991
|
+
confirmPassword
|
|
992
|
+
})
|
|
993
|
+
})).json().catch(() => ({}))).status) {
|
|
994
|
+
case "success":
|
|
995
|
+
setStep("success");
|
|
996
|
+
if (props.afterResetPath) window.location.assign(props.afterResetPath);
|
|
997
|
+
return;
|
|
998
|
+
case "weak_password":
|
|
999
|
+
setError(labels.weakPassword);
|
|
1000
|
+
return;
|
|
1001
|
+
case "password_mismatch":
|
|
1002
|
+
setError(labels.passwordMismatch);
|
|
1003
|
+
return;
|
|
1004
|
+
case "invalid_or_expired":
|
|
1005
|
+
setStep("invalid");
|
|
1006
|
+
return;
|
|
1007
|
+
default:
|
|
1008
|
+
setError(labels.genericError);
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
} catch {
|
|
1012
|
+
setError(labels.genericError);
|
|
1013
|
+
} finally {
|
|
1014
|
+
setSubmitting(false);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
const rootClass = [
|
|
1018
|
+
"polyx-signin",
|
|
1019
|
+
"polyx-reset",
|
|
1020
|
+
props.className
|
|
1021
|
+
].filter(Boolean).join(" ");
|
|
1022
|
+
const footer = props.showSecuredBy === false ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1023
|
+
className: "polyx-signin__footer",
|
|
1024
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
1025
|
+
className: "polyx-signin__shield",
|
|
1026
|
+
viewBox: "0 0 16 16",
|
|
1027
|
+
fill: "currentColor",
|
|
1028
|
+
"aria-hidden": "true",
|
|
1029
|
+
focusable: "false",
|
|
1030
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 0.5 2 3v4.2c0 3.5 2.5 6.7 6 7.8 3.5-1.1 6-4.3 6-7.8V3L8 .5Zm2.9 5.6-3.4 3.4a.7.7 0 0 1-1 0L5.1 8.1a.7.7 0 1 1 1-1l.9.9 2.9-2.9a.7.7 0 0 1 1 1Z" })
|
|
1031
|
+
}), labels.securedBy]
|
|
1032
|
+
});
|
|
1033
|
+
const header = (heading, subheading) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1034
|
+
className: "polyx-signin__header",
|
|
1035
|
+
children: [
|
|
1036
|
+
props.logo ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1037
|
+
className: "polyx-signin__logo",
|
|
1038
|
+
children: props.logo
|
|
1039
|
+
}) : null,
|
|
1040
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
1041
|
+
className: "polyx-signin__heading",
|
|
1042
|
+
children: heading
|
|
1043
|
+
}),
|
|
1044
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1045
|
+
className: "polyx-signin__subheading",
|
|
1046
|
+
children: subheading
|
|
1047
|
+
})
|
|
1048
|
+
]
|
|
1049
|
+
});
|
|
1050
|
+
if (step === "success") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1051
|
+
className: rootClass,
|
|
1052
|
+
"data-polyx-reset": "success",
|
|
1053
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecoveryStatus, {
|
|
1054
|
+
icon: "check",
|
|
1055
|
+
heading: labels.successHeading,
|
|
1056
|
+
footer,
|
|
1057
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
1058
|
+
className: "polyx-signin__link",
|
|
1059
|
+
href: signInPath,
|
|
1060
|
+
children: labels.backToSignIn
|
|
1061
|
+
}),
|
|
1062
|
+
children: labels.successSubheading
|
|
1063
|
+
})
|
|
1064
|
+
});
|
|
1065
|
+
if (step === "invalid") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1066
|
+
className: rootClass,
|
|
1067
|
+
"data-polyx-reset": "invalid",
|
|
1068
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecoveryStatus, {
|
|
1069
|
+
icon: "warning",
|
|
1070
|
+
tone: "danger",
|
|
1071
|
+
heading: labels.invalidHeading,
|
|
1072
|
+
footer,
|
|
1073
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
1074
|
+
className: "polyx-signin__link",
|
|
1075
|
+
href: forgotPasswordPath,
|
|
1076
|
+
children: labels.requestNewLink
|
|
1077
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
1078
|
+
className: "polyx-signin__link",
|
|
1079
|
+
href: signInPath,
|
|
1080
|
+
children: labels.backToSignIn
|
|
1081
|
+
})] }),
|
|
1082
|
+
children: labels.invalidSubheading
|
|
1083
|
+
})
|
|
1084
|
+
});
|
|
1085
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1086
|
+
className: rootClass,
|
|
1087
|
+
"data-polyx-reset": step,
|
|
1088
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1089
|
+
className: "polyx-signin__card",
|
|
1090
|
+
children: [
|
|
1091
|
+
header(labels.heading, labels.subheading),
|
|
1092
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
1093
|
+
className: "polyx-signin__form",
|
|
1094
|
+
onSubmit,
|
|
1095
|
+
children: [
|
|
1096
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1097
|
+
className: "polyx-signin__field",
|
|
1098
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1099
|
+
className: "polyx-signin__label",
|
|
1100
|
+
children: labels.newPasswordLabel
|
|
1101
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1102
|
+
className: "polyx-signin__input",
|
|
1103
|
+
type: "password",
|
|
1104
|
+
name: "newPassword",
|
|
1105
|
+
autoComplete: "new-password",
|
|
1106
|
+
placeholder: labels.passwordPlaceholder,
|
|
1107
|
+
required: true,
|
|
1108
|
+
minLength,
|
|
1109
|
+
value: newPassword,
|
|
1110
|
+
disabled: submitting,
|
|
1111
|
+
onChange: (event) => setNewPassword(event.target.value)
|
|
1112
|
+
})]
|
|
1113
|
+
}),
|
|
1114
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1115
|
+
className: "polyx-signin__field",
|
|
1116
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1117
|
+
className: "polyx-signin__label",
|
|
1118
|
+
children: labels.confirmPasswordLabel
|
|
1119
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1120
|
+
className: "polyx-signin__input",
|
|
1121
|
+
type: "password",
|
|
1122
|
+
name: "confirmPassword",
|
|
1123
|
+
autoComplete: "new-password",
|
|
1124
|
+
placeholder: labels.passwordPlaceholder,
|
|
1125
|
+
required: true,
|
|
1126
|
+
minLength,
|
|
1127
|
+
value: confirmPassword,
|
|
1128
|
+
disabled: submitting,
|
|
1129
|
+
onChange: (event) => setConfirmPassword(event.target.value)
|
|
1130
|
+
})]
|
|
1131
|
+
}),
|
|
1132
|
+
error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1133
|
+
role: "alert",
|
|
1134
|
+
className: "polyx-signin__error",
|
|
1135
|
+
children: error
|
|
1136
|
+
}) : null,
|
|
1137
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1138
|
+
type: "submit",
|
|
1139
|
+
className: "polyx-signin__submit",
|
|
1140
|
+
disabled: submitting,
|
|
1141
|
+
children: submitting ? labels.submitting : labels.submit
|
|
1142
|
+
})
|
|
1143
|
+
]
|
|
1144
|
+
}),
|
|
1145
|
+
footer
|
|
1146
|
+
]
|
|
1147
|
+
})
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
//#endregion
|
|
671
1151
|
//#region src/components/auth-callback.tsx
|
|
672
1152
|
/** Drop on your `/auth/callback` route: completes the sign-in exchange on mount. */
|
|
673
1153
|
function AuthCallback({ children = null }) {
|
|
@@ -689,11 +1169,13 @@ const version = "0.0.0";
|
|
|
689
1169
|
exports.AuthCallback = AuthCallback;
|
|
690
1170
|
exports.BroadcastAuthChannel = BroadcastAuthChannel;
|
|
691
1171
|
exports.BroadcastChannelSessionChannel = BroadcastChannelSessionChannel;
|
|
1172
|
+
exports.ForgotPassword = ForgotPassword;
|
|
692
1173
|
exports.PACKAGE_NAME = PACKAGE_NAME;
|
|
693
1174
|
exports.PolyXContext = PolyXContext;
|
|
694
1175
|
exports.PolyXProvider = PolyXProvider;
|
|
695
1176
|
exports.PopupCancelledError = PopupCancelledError;
|
|
696
1177
|
exports.Protected = Protected;
|
|
1178
|
+
exports.ResetPassword = ResetPassword;
|
|
697
1179
|
exports.SessionStoragePkceStore = SessionStoragePkceStore;
|
|
698
1180
|
exports.SignIn = SignIn;
|
|
699
1181
|
exports.WebLocksLock = WebLocksLock;
|
package/dist/index.d.cts
CHANGED
|
@@ -261,6 +261,101 @@ interface SignInProps {
|
|
|
261
261
|
*/
|
|
262
262
|
declare function SignIn(props: SignInProps): ReactNode;
|
|
263
263
|
//#endregion
|
|
264
|
+
//#region src/components/forgot-password.d.ts
|
|
265
|
+
/** Every user-facing string, overridable for i18n / white-labelling. */
|
|
266
|
+
interface ForgotPasswordLabels {
|
|
267
|
+
heading: string;
|
|
268
|
+
subheading: string;
|
|
269
|
+
emailLabel: string;
|
|
270
|
+
emailPlaceholder: string;
|
|
271
|
+
submit: string;
|
|
272
|
+
submitting: string;
|
|
273
|
+
/** Shown after submit — always, regardless of whether the account exists. */
|
|
274
|
+
sentHeading: string;
|
|
275
|
+
/** Confirmation body. `{email}` is replaced with the entered address, emphasized. */
|
|
276
|
+
sentSubheading: string;
|
|
277
|
+
differentEmail: string;
|
|
278
|
+
backToSignIn: string;
|
|
279
|
+
securedBy: string;
|
|
280
|
+
genericError: string;
|
|
281
|
+
}
|
|
282
|
+
interface ForgotPasswordProps {
|
|
283
|
+
/** BFF endpoint backed by `createAuthHandlers().forgotPassword`. Default `/api/polyx/forgot-password`. */
|
|
284
|
+
action?: string;
|
|
285
|
+
/** Where the "back to sign in" link points. Default `/sign-in`. */
|
|
286
|
+
signInPath?: string;
|
|
287
|
+
/** Rendered above the heading — your wordmark or logo. */
|
|
288
|
+
logo?: ReactNode;
|
|
289
|
+
/** Show the "Secured by PolyX" attribution under the form. Default true. */
|
|
290
|
+
showSecuredBy?: boolean;
|
|
291
|
+
/** Appended to the root element's class list, for escape-hatch styling. */
|
|
292
|
+
className?: string;
|
|
293
|
+
labels?: Partial<ForgotPasswordLabels>;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* The self-service "forgot password" form (poly-x v5 / F040). Renders an email field
|
|
297
|
+
* inside the consuming app and POSTs to the SDK's BFF (`@poly-x/next` `forgotPassword`),
|
|
298
|
+
* which asks poly-auth to email a single-use reset link SERVER-SIDE. The response is
|
|
299
|
+
* always the same — no token, no account-existence signal — so after submit the form
|
|
300
|
+
* shows an identical "check your email" state whether or not the account exists.
|
|
301
|
+
*
|
|
302
|
+
* Reuses the `<SignIn/>` styling: `import "@poly-x/react/styles.css"` once, then theme
|
|
303
|
+
* via the `--polyx-*` custom properties. Target `.polyx-forgot` for form-specific tweaks.
|
|
304
|
+
*/
|
|
305
|
+
declare function ForgotPassword(props: ForgotPasswordProps): ReactNode;
|
|
306
|
+
//#endregion
|
|
307
|
+
//#region src/components/reset-password.d.ts
|
|
308
|
+
/** Every user-facing string, overridable for i18n / white-labelling. */
|
|
309
|
+
interface ResetPasswordLabels {
|
|
310
|
+
heading: string;
|
|
311
|
+
subheading: string;
|
|
312
|
+
newPasswordLabel: string;
|
|
313
|
+
confirmPasswordLabel: string;
|
|
314
|
+
passwordPlaceholder: string;
|
|
315
|
+
submit: string;
|
|
316
|
+
submitting: string;
|
|
317
|
+
successHeading: string;
|
|
318
|
+
successSubheading: string;
|
|
319
|
+
invalidHeading: string;
|
|
320
|
+
invalidSubheading: string;
|
|
321
|
+
requestNewLink: string;
|
|
322
|
+
backToSignIn: string;
|
|
323
|
+
securedBy: string;
|
|
324
|
+
passwordMismatch: string;
|
|
325
|
+
weakPassword: string;
|
|
326
|
+
genericError: string;
|
|
327
|
+
}
|
|
328
|
+
interface ResetPasswordProps {
|
|
329
|
+
/** BFF endpoint backed by `createAuthHandlers().resetPassword`. Default `/api/polyx/reset-password`. */
|
|
330
|
+
action?: string;
|
|
331
|
+
/** The opaque reset token. Defaults to `?token=` from the URL (client-side). */
|
|
332
|
+
token?: string;
|
|
333
|
+
/** Where to send the browser after a successful reset. Default `/sign-in`. */
|
|
334
|
+
afterResetPath?: string;
|
|
335
|
+
/** Where "request a new link" / "back to sign in" point. Default `/forgot-password` and `/sign-in`. */
|
|
336
|
+
forgotPasswordPath?: string;
|
|
337
|
+
signInPath?: string;
|
|
338
|
+
/** Rendered above the heading — your wordmark or logo. */
|
|
339
|
+
logo?: ReactNode;
|
|
340
|
+
/** Show the "Secured by PolyX" attribution under the form. Default true. */
|
|
341
|
+
showSecuredBy?: boolean;
|
|
342
|
+
/** Client-side minimum password length (the backend enforces the real floor). Default 8. */
|
|
343
|
+
minLength?: number;
|
|
344
|
+
/** Appended to the root element's class list, for escape-hatch styling. */
|
|
345
|
+
className?: string;
|
|
346
|
+
labels?: Partial<ResetPasswordLabels>;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* The reset-completion form (poly-x v5 / F040). Reads the opaque token from the URL,
|
|
350
|
+
* collects a new password, and POSTs to the SDK's BFF (`@poly-x/next` `resetPassword`),
|
|
351
|
+
* which redeems the token single-use server-side. The token is never decoded in the
|
|
352
|
+
* browser — identity, validity, and expiry are all enforced by the backend.
|
|
353
|
+
*
|
|
354
|
+
* Reuses the `<SignIn/>` styling: `import "@poly-x/react/styles.css"` once, then theme
|
|
355
|
+
* via the `--polyx-*` custom properties. Target `.polyx-reset` for form-specific tweaks.
|
|
356
|
+
*/
|
|
357
|
+
declare function ResetPassword(props: ResetPasswordProps): ReactNode;
|
|
358
|
+
//#endregion
|
|
264
359
|
//#region src/components/auth-callback.d.ts
|
|
265
360
|
interface AuthCallbackProps {
|
|
266
361
|
/** Rendered while the exchange completes (e.g. a spinner). */
|
|
@@ -279,4 +374,4 @@ declare function AuthCallback({
|
|
|
279
374
|
declare const PACKAGE_NAME = "@poly-x/react";
|
|
280
375
|
declare const version = "0.0.0";
|
|
281
376
|
//#endregion
|
|
282
|
-
export { AuthCallback, type AuthCallbackMessage, type AuthCallbackProps, type AuthChannel, BroadcastAuthChannel, BroadcastChannelSessionChannel, type BrowserBridge, type CallbackParams, type LoginController, type LoginControllerDeps, PACKAGE_NAME, PolyXContext, type PolyXContextValue, PolyXProvider, type PolyXProviderProps, PopupCancelledError, type PopupHandle, Protected, type ProtectedProps, SessionStoragePkceStore, SignIn, type SignInLabels, type SignInOptions, type SignInProps, type SignInVariant, type UseAuth, WebLocksLock, WindowBrowserBridge, createLoginController, useAuth, useAuthCallback, useSession, useUser, version };
|
|
377
|
+
export { AuthCallback, type AuthCallbackMessage, type AuthCallbackProps, type AuthChannel, BroadcastAuthChannel, BroadcastChannelSessionChannel, type BrowserBridge, type CallbackParams, ForgotPassword, type ForgotPasswordLabels, type ForgotPasswordProps, type LoginController, type LoginControllerDeps, PACKAGE_NAME, PolyXContext, type PolyXContextValue, PolyXProvider, type PolyXProviderProps, PopupCancelledError, type PopupHandle, Protected, type ProtectedProps, ResetPassword, type ResetPasswordLabels, type ResetPasswordProps, SessionStoragePkceStore, SignIn, type SignInLabels, type SignInOptions, type SignInProps, type SignInVariant, type UseAuth, WebLocksLock, WindowBrowserBridge, createLoginController, useAuth, useAuthCallback, useSession, useUser, version };
|
package/dist/index.d.mts
CHANGED
|
@@ -261,6 +261,101 @@ interface SignInProps {
|
|
|
261
261
|
*/
|
|
262
262
|
declare function SignIn(props: SignInProps): ReactNode;
|
|
263
263
|
//#endregion
|
|
264
|
+
//#region src/components/forgot-password.d.ts
|
|
265
|
+
/** Every user-facing string, overridable for i18n / white-labelling. */
|
|
266
|
+
interface ForgotPasswordLabels {
|
|
267
|
+
heading: string;
|
|
268
|
+
subheading: string;
|
|
269
|
+
emailLabel: string;
|
|
270
|
+
emailPlaceholder: string;
|
|
271
|
+
submit: string;
|
|
272
|
+
submitting: string;
|
|
273
|
+
/** Shown after submit — always, regardless of whether the account exists. */
|
|
274
|
+
sentHeading: string;
|
|
275
|
+
/** Confirmation body. `{email}` is replaced with the entered address, emphasized. */
|
|
276
|
+
sentSubheading: string;
|
|
277
|
+
differentEmail: string;
|
|
278
|
+
backToSignIn: string;
|
|
279
|
+
securedBy: string;
|
|
280
|
+
genericError: string;
|
|
281
|
+
}
|
|
282
|
+
interface ForgotPasswordProps {
|
|
283
|
+
/** BFF endpoint backed by `createAuthHandlers().forgotPassword`. Default `/api/polyx/forgot-password`. */
|
|
284
|
+
action?: string;
|
|
285
|
+
/** Where the "back to sign in" link points. Default `/sign-in`. */
|
|
286
|
+
signInPath?: string;
|
|
287
|
+
/** Rendered above the heading — your wordmark or logo. */
|
|
288
|
+
logo?: ReactNode;
|
|
289
|
+
/** Show the "Secured by PolyX" attribution under the form. Default true. */
|
|
290
|
+
showSecuredBy?: boolean;
|
|
291
|
+
/** Appended to the root element's class list, for escape-hatch styling. */
|
|
292
|
+
className?: string;
|
|
293
|
+
labels?: Partial<ForgotPasswordLabels>;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* The self-service "forgot password" form (poly-x v5 / F040). Renders an email field
|
|
297
|
+
* inside the consuming app and POSTs to the SDK's BFF (`@poly-x/next` `forgotPassword`),
|
|
298
|
+
* which asks poly-auth to email a single-use reset link SERVER-SIDE. The response is
|
|
299
|
+
* always the same — no token, no account-existence signal — so after submit the form
|
|
300
|
+
* shows an identical "check your email" state whether or not the account exists.
|
|
301
|
+
*
|
|
302
|
+
* Reuses the `<SignIn/>` styling: `import "@poly-x/react/styles.css"` once, then theme
|
|
303
|
+
* via the `--polyx-*` custom properties. Target `.polyx-forgot` for form-specific tweaks.
|
|
304
|
+
*/
|
|
305
|
+
declare function ForgotPassword(props: ForgotPasswordProps): ReactNode;
|
|
306
|
+
//#endregion
|
|
307
|
+
//#region src/components/reset-password.d.ts
|
|
308
|
+
/** Every user-facing string, overridable for i18n / white-labelling. */
|
|
309
|
+
interface ResetPasswordLabels {
|
|
310
|
+
heading: string;
|
|
311
|
+
subheading: string;
|
|
312
|
+
newPasswordLabel: string;
|
|
313
|
+
confirmPasswordLabel: string;
|
|
314
|
+
passwordPlaceholder: string;
|
|
315
|
+
submit: string;
|
|
316
|
+
submitting: string;
|
|
317
|
+
successHeading: string;
|
|
318
|
+
successSubheading: string;
|
|
319
|
+
invalidHeading: string;
|
|
320
|
+
invalidSubheading: string;
|
|
321
|
+
requestNewLink: string;
|
|
322
|
+
backToSignIn: string;
|
|
323
|
+
securedBy: string;
|
|
324
|
+
passwordMismatch: string;
|
|
325
|
+
weakPassword: string;
|
|
326
|
+
genericError: string;
|
|
327
|
+
}
|
|
328
|
+
interface ResetPasswordProps {
|
|
329
|
+
/** BFF endpoint backed by `createAuthHandlers().resetPassword`. Default `/api/polyx/reset-password`. */
|
|
330
|
+
action?: string;
|
|
331
|
+
/** The opaque reset token. Defaults to `?token=` from the URL (client-side). */
|
|
332
|
+
token?: string;
|
|
333
|
+
/** Where to send the browser after a successful reset. Default `/sign-in`. */
|
|
334
|
+
afterResetPath?: string;
|
|
335
|
+
/** Where "request a new link" / "back to sign in" point. Default `/forgot-password` and `/sign-in`. */
|
|
336
|
+
forgotPasswordPath?: string;
|
|
337
|
+
signInPath?: string;
|
|
338
|
+
/** Rendered above the heading — your wordmark or logo. */
|
|
339
|
+
logo?: ReactNode;
|
|
340
|
+
/** Show the "Secured by PolyX" attribution under the form. Default true. */
|
|
341
|
+
showSecuredBy?: boolean;
|
|
342
|
+
/** Client-side minimum password length (the backend enforces the real floor). Default 8. */
|
|
343
|
+
minLength?: number;
|
|
344
|
+
/** Appended to the root element's class list, for escape-hatch styling. */
|
|
345
|
+
className?: string;
|
|
346
|
+
labels?: Partial<ResetPasswordLabels>;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* The reset-completion form (poly-x v5 / F040). Reads the opaque token from the URL,
|
|
350
|
+
* collects a new password, and POSTs to the SDK's BFF (`@poly-x/next` `resetPassword`),
|
|
351
|
+
* which redeems the token single-use server-side. The token is never decoded in the
|
|
352
|
+
* browser — identity, validity, and expiry are all enforced by the backend.
|
|
353
|
+
*
|
|
354
|
+
* Reuses the `<SignIn/>` styling: `import "@poly-x/react/styles.css"` once, then theme
|
|
355
|
+
* via the `--polyx-*` custom properties. Target `.polyx-reset` for form-specific tweaks.
|
|
356
|
+
*/
|
|
357
|
+
declare function ResetPassword(props: ResetPasswordProps): ReactNode;
|
|
358
|
+
//#endregion
|
|
264
359
|
//#region src/components/auth-callback.d.ts
|
|
265
360
|
interface AuthCallbackProps {
|
|
266
361
|
/** Rendered while the exchange completes (e.g. a spinner). */
|
|
@@ -279,4 +374,4 @@ declare function AuthCallback({
|
|
|
279
374
|
declare const PACKAGE_NAME = "@poly-x/react";
|
|
280
375
|
declare const version = "0.0.0";
|
|
281
376
|
//#endregion
|
|
282
|
-
export { AuthCallback, type AuthCallbackMessage, type AuthCallbackProps, type AuthChannel, BroadcastAuthChannel, BroadcastChannelSessionChannel, type BrowserBridge, type CallbackParams, type LoginController, type LoginControllerDeps, PACKAGE_NAME, PolyXContext, type PolyXContextValue, PolyXProvider, type PolyXProviderProps, PopupCancelledError, type PopupHandle, Protected, type ProtectedProps, SessionStoragePkceStore, SignIn, type SignInLabels, type SignInOptions, type SignInProps, type SignInVariant, type UseAuth, WebLocksLock, WindowBrowserBridge, createLoginController, useAuth, useAuthCallback, useSession, useUser, version };
|
|
377
|
+
export { AuthCallback, type AuthCallbackMessage, type AuthCallbackProps, type AuthChannel, BroadcastAuthChannel, BroadcastChannelSessionChannel, type BrowserBridge, type CallbackParams, ForgotPassword, type ForgotPasswordLabels, type ForgotPasswordProps, type LoginController, type LoginControllerDeps, PACKAGE_NAME, PolyXContext, type PolyXContextValue, PolyXProvider, type PolyXProviderProps, PopupCancelledError, type PopupHandle, Protected, type ProtectedProps, ResetPassword, type ResetPasswordLabels, type ResetPasswordProps, SessionStoragePkceStore, SignIn, type SignInLabels, type SignInOptions, type SignInProps, type SignInVariant, type UseAuth, WebLocksLock, WindowBrowserBridge, createLoginController, useAuth, useAuthCallback, useSession, useUser, version };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { AuthClient, FetchTransport, InMemoryLock, InMemoryPkceStore, InMemorySessionChannel, InMemorySessionStore, createSessionEngine, generatePkce, randomState, resolveConfig } from "@poly-x/core";
|
|
3
|
-
import { createContext, useCallback, useContext, useEffect, useMemo, useState, useSyncExternalStore } from "react";
|
|
4
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Fragment, createContext, useCallback, useContext, useEffect, useMemo, useState, useSyncExternalStore } from "react";
|
|
4
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
//#region src/auth-channel.ts
|
|
6
6
|
var BroadcastAuthChannel = class {
|
|
7
7
|
supported;
|
|
@@ -351,7 +351,7 @@ function Protected({ children, fallback = null, loading = null }) {
|
|
|
351
351
|
}
|
|
352
352
|
//#endregion
|
|
353
353
|
//#region src/components/sign-in.tsx
|
|
354
|
-
const DEFAULT_LABELS = {
|
|
354
|
+
const DEFAULT_LABELS$2 = {
|
|
355
355
|
heading: "Sign in",
|
|
356
356
|
subheading: "Enter your credentials to continue.",
|
|
357
357
|
tagline: "",
|
|
@@ -392,7 +392,7 @@ function SignIn(props) {
|
|
|
392
392
|
const action = props.action ?? "/api/polyx/authenticate";
|
|
393
393
|
const variant = props.variant ?? "card";
|
|
394
394
|
const labels = {
|
|
395
|
-
...DEFAULT_LABELS,
|
|
395
|
+
...DEFAULT_LABELS$2,
|
|
396
396
|
...props.labels
|
|
397
397
|
};
|
|
398
398
|
const [email, setEmail] = useState("");
|
|
@@ -648,7 +648,7 @@ function SignIn(props) {
|
|
|
648
648
|
"data-polyx-signin": step,
|
|
649
649
|
children: [/* @__PURE__ */ jsx("aside", {
|
|
650
650
|
className: "polyx-signin__panel",
|
|
651
|
-
children: props.panel ?? /* @__PURE__ */ jsxs(Fragment, { children: [props.logo ? /* @__PURE__ */ jsx("div", {
|
|
651
|
+
children: props.panel ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [props.logo ? /* @__PURE__ */ jsx("div", {
|
|
652
652
|
className: "polyx-signin__panel-logo",
|
|
653
653
|
children: props.logo
|
|
654
654
|
}) : null, labels.tagline ? /* @__PURE__ */ jsx("p", {
|
|
@@ -667,6 +667,486 @@ function SignIn(props) {
|
|
|
667
667
|
});
|
|
668
668
|
}
|
|
669
669
|
//#endregion
|
|
670
|
+
//#region src/components/_recovery-status.tsx
|
|
671
|
+
const ICONS = {
|
|
672
|
+
mail: /* @__PURE__ */ jsxs("svg", {
|
|
673
|
+
viewBox: "0 0 24 24",
|
|
674
|
+
fill: "none",
|
|
675
|
+
stroke: "currentColor",
|
|
676
|
+
strokeWidth: "1.75",
|
|
677
|
+
"aria-hidden": "true",
|
|
678
|
+
focusable: "false",
|
|
679
|
+
children: [/* @__PURE__ */ jsx("rect", {
|
|
680
|
+
x: "3",
|
|
681
|
+
y: "5",
|
|
682
|
+
width: "18",
|
|
683
|
+
height: "14",
|
|
684
|
+
rx: "2.5"
|
|
685
|
+
}), /* @__PURE__ */ jsx("path", {
|
|
686
|
+
d: "m4 7 8 6 8-6",
|
|
687
|
+
strokeLinecap: "round",
|
|
688
|
+
strokeLinejoin: "round"
|
|
689
|
+
})]
|
|
690
|
+
}),
|
|
691
|
+
check: /* @__PURE__ */ jsx("svg", {
|
|
692
|
+
viewBox: "0 0 24 24",
|
|
693
|
+
fill: "none",
|
|
694
|
+
stroke: "currentColor",
|
|
695
|
+
strokeWidth: "2",
|
|
696
|
+
"aria-hidden": "true",
|
|
697
|
+
focusable: "false",
|
|
698
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
699
|
+
d: "m5 12.5 4.5 4.5L19 7",
|
|
700
|
+
strokeLinecap: "round",
|
|
701
|
+
strokeLinejoin: "round"
|
|
702
|
+
})
|
|
703
|
+
}),
|
|
704
|
+
warning: /* @__PURE__ */ jsxs("svg", {
|
|
705
|
+
viewBox: "0 0 24 24",
|
|
706
|
+
fill: "none",
|
|
707
|
+
stroke: "currentColor",
|
|
708
|
+
strokeWidth: "1.75",
|
|
709
|
+
"aria-hidden": "true",
|
|
710
|
+
focusable: "false",
|
|
711
|
+
children: [
|
|
712
|
+
/* @__PURE__ */ jsx("circle", {
|
|
713
|
+
cx: "12",
|
|
714
|
+
cy: "12",
|
|
715
|
+
r: "9"
|
|
716
|
+
}),
|
|
717
|
+
/* @__PURE__ */ jsx("path", {
|
|
718
|
+
d: "M12 7.5v5",
|
|
719
|
+
strokeLinecap: "round"
|
|
720
|
+
}),
|
|
721
|
+
/* @__PURE__ */ jsx("circle", {
|
|
722
|
+
cx: "12",
|
|
723
|
+
cy: "16",
|
|
724
|
+
r: "0.6",
|
|
725
|
+
fill: "currentColor",
|
|
726
|
+
stroke: "none"
|
|
727
|
+
})
|
|
728
|
+
]
|
|
729
|
+
})
|
|
730
|
+
};
|
|
731
|
+
/**
|
|
732
|
+
* A centered, icon-topped confirmation card — the shape every recovery terminal
|
|
733
|
+
* state shares (link sent, password updated, link expired). Reuses the `<SignIn/>`
|
|
734
|
+
* class anatomy so it themes from the same `--polyx-*` custom properties.
|
|
735
|
+
*/
|
|
736
|
+
function RecoveryStatus(props) {
|
|
737
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
738
|
+
className: "polyx-signin__card",
|
|
739
|
+
children: [
|
|
740
|
+
/* @__PURE__ */ jsxs("div", {
|
|
741
|
+
className: "polyx-signin__header polyx-signin__header--center",
|
|
742
|
+
children: [
|
|
743
|
+
/* @__PURE__ */ jsx("span", {
|
|
744
|
+
className: `polyx-signin__status-icon polyx-signin__status-icon--${props.tone ?? "brand"}`,
|
|
745
|
+
children: ICONS[props.icon]
|
|
746
|
+
}),
|
|
747
|
+
/* @__PURE__ */ jsx("h1", {
|
|
748
|
+
className: "polyx-signin__heading",
|
|
749
|
+
children: props.heading
|
|
750
|
+
}),
|
|
751
|
+
/* @__PURE__ */ jsx("p", {
|
|
752
|
+
className: "polyx-signin__subheading",
|
|
753
|
+
children: props.children
|
|
754
|
+
})
|
|
755
|
+
]
|
|
756
|
+
}),
|
|
757
|
+
props.actions ? /* @__PURE__ */ jsx("div", {
|
|
758
|
+
className: "polyx-signin__actions",
|
|
759
|
+
children: props.actions
|
|
760
|
+
}) : null,
|
|
761
|
+
props.footer
|
|
762
|
+
]
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
//#endregion
|
|
766
|
+
//#region src/components/forgot-password.tsx
|
|
767
|
+
const DEFAULT_LABELS$1 = {
|
|
768
|
+
heading: "Reset your password",
|
|
769
|
+
subheading: "Enter your email and we'll send you a reset link.",
|
|
770
|
+
emailLabel: "Email",
|
|
771
|
+
emailPlaceholder: "you@company.com",
|
|
772
|
+
submit: "Send reset link",
|
|
773
|
+
submitting: "Sending…",
|
|
774
|
+
sentHeading: "Check your email",
|
|
775
|
+
sentSubheading: "If an account exists for {email}, a password reset link is on its way. It expires in 30 minutes.",
|
|
776
|
+
differentEmail: "Use a different email",
|
|
777
|
+
backToSignIn: "Back to sign in",
|
|
778
|
+
securedBy: "Secured by PolyX",
|
|
779
|
+
genericError: "Something went wrong. Please try again."
|
|
780
|
+
};
|
|
781
|
+
/** Splits a label on `{email}` and drops the entered address in, emphasized. */
|
|
782
|
+
function withEmail(template, email) {
|
|
783
|
+
return template.split("{email}").map((chunk, index, all) => /* @__PURE__ */ jsxs(Fragment, { children: [chunk, index < all.length - 1 ? /* @__PURE__ */ jsx("span", {
|
|
784
|
+
className: "polyx-signin__email",
|
|
785
|
+
children: email || "that address"
|
|
786
|
+
}) : null] }, index));
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* The self-service "forgot password" form (poly-x v5 / F040). Renders an email field
|
|
790
|
+
* inside the consuming app and POSTs to the SDK's BFF (`@poly-x/next` `forgotPassword`),
|
|
791
|
+
* which asks poly-auth to email a single-use reset link SERVER-SIDE. The response is
|
|
792
|
+
* always the same — no token, no account-existence signal — so after submit the form
|
|
793
|
+
* shows an identical "check your email" state whether or not the account exists.
|
|
794
|
+
*
|
|
795
|
+
* Reuses the `<SignIn/>` styling: `import "@poly-x/react/styles.css"` once, then theme
|
|
796
|
+
* via the `--polyx-*` custom properties. Target `.polyx-forgot` for form-specific tweaks.
|
|
797
|
+
*/
|
|
798
|
+
function ForgotPassword(props) {
|
|
799
|
+
const action = props.action ?? "/api/polyx/forgot-password";
|
|
800
|
+
const signInPath = props.signInPath ?? "/sign-in";
|
|
801
|
+
const labels = {
|
|
802
|
+
...DEFAULT_LABELS$1,
|
|
803
|
+
...props.labels
|
|
804
|
+
};
|
|
805
|
+
const [email, setEmail] = useState("");
|
|
806
|
+
const [submitting, setSubmitting] = useState(false);
|
|
807
|
+
const [sent, setSent] = useState(false);
|
|
808
|
+
const [error, setError] = useState(null);
|
|
809
|
+
async function onSubmit(event) {
|
|
810
|
+
event.preventDefault();
|
|
811
|
+
setSubmitting(true);
|
|
812
|
+
setError(null);
|
|
813
|
+
try {
|
|
814
|
+
if ((await (await fetch(action, {
|
|
815
|
+
method: "POST",
|
|
816
|
+
headers: { "content-type": "application/json" },
|
|
817
|
+
body: JSON.stringify({ email })
|
|
818
|
+
})).json().catch(() => ({}))).status === "accepted") {
|
|
819
|
+
setSent(true);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
setError(labels.genericError);
|
|
823
|
+
} catch {
|
|
824
|
+
setError(labels.genericError);
|
|
825
|
+
} finally {
|
|
826
|
+
setSubmitting(false);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
const rootClass = [
|
|
830
|
+
"polyx-signin",
|
|
831
|
+
"polyx-forgot",
|
|
832
|
+
props.className
|
|
833
|
+
].filter(Boolean).join(" ");
|
|
834
|
+
const footer = props.showSecuredBy === false ? null : /* @__PURE__ */ jsxs("p", {
|
|
835
|
+
className: "polyx-signin__footer",
|
|
836
|
+
children: [/* @__PURE__ */ jsx("svg", {
|
|
837
|
+
className: "polyx-signin__shield",
|
|
838
|
+
viewBox: "0 0 16 16",
|
|
839
|
+
fill: "currentColor",
|
|
840
|
+
"aria-hidden": "true",
|
|
841
|
+
focusable: "false",
|
|
842
|
+
children: /* @__PURE__ */ jsx("path", { d: "M8 0.5 2 3v4.2c0 3.5 2.5 6.7 6 7.8 3.5-1.1 6-4.3 6-7.8V3L8 .5Zm2.9 5.6-3.4 3.4a.7.7 0 0 1-1 0L5.1 8.1a.7.7 0 1 1 1-1l.9.9 2.9-2.9a.7.7 0 0 1 1 1Z" })
|
|
843
|
+
}), labels.securedBy]
|
|
844
|
+
});
|
|
845
|
+
const header = (heading, subheading) => /* @__PURE__ */ jsxs("div", {
|
|
846
|
+
className: "polyx-signin__header",
|
|
847
|
+
children: [
|
|
848
|
+
props.logo ? /* @__PURE__ */ jsx("div", {
|
|
849
|
+
className: "polyx-signin__logo",
|
|
850
|
+
children: props.logo
|
|
851
|
+
}) : null,
|
|
852
|
+
/* @__PURE__ */ jsx("h1", {
|
|
853
|
+
className: "polyx-signin__heading",
|
|
854
|
+
children: heading
|
|
855
|
+
}),
|
|
856
|
+
/* @__PURE__ */ jsx("p", {
|
|
857
|
+
className: "polyx-signin__subheading",
|
|
858
|
+
children: subheading
|
|
859
|
+
})
|
|
860
|
+
]
|
|
861
|
+
});
|
|
862
|
+
if (sent) return /* @__PURE__ */ jsx("div", {
|
|
863
|
+
className: rootClass,
|
|
864
|
+
"data-polyx-forgot": "sent",
|
|
865
|
+
children: /* @__PURE__ */ jsx(RecoveryStatus, {
|
|
866
|
+
icon: "mail",
|
|
867
|
+
heading: labels.sentHeading,
|
|
868
|
+
footer,
|
|
869
|
+
actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
|
|
870
|
+
type: "button",
|
|
871
|
+
className: "polyx-signin__link",
|
|
872
|
+
onClick: () => setSent(false),
|
|
873
|
+
children: labels.differentEmail
|
|
874
|
+
}), /* @__PURE__ */ jsx("a", {
|
|
875
|
+
className: "polyx-signin__link",
|
|
876
|
+
href: signInPath,
|
|
877
|
+
children: labels.backToSignIn
|
|
878
|
+
})] }),
|
|
879
|
+
children: withEmail(labels.sentSubheading, email)
|
|
880
|
+
})
|
|
881
|
+
});
|
|
882
|
+
return /* @__PURE__ */ jsx("div", {
|
|
883
|
+
className: rootClass,
|
|
884
|
+
"data-polyx-forgot": "request",
|
|
885
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
886
|
+
className: "polyx-signin__card",
|
|
887
|
+
children: [
|
|
888
|
+
header(labels.heading, labels.subheading),
|
|
889
|
+
/* @__PURE__ */ jsxs("form", {
|
|
890
|
+
className: "polyx-signin__form",
|
|
891
|
+
onSubmit,
|
|
892
|
+
children: [
|
|
893
|
+
/* @__PURE__ */ jsxs("label", {
|
|
894
|
+
className: "polyx-signin__field",
|
|
895
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
896
|
+
className: "polyx-signin__label",
|
|
897
|
+
children: labels.emailLabel
|
|
898
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
899
|
+
className: "polyx-signin__input",
|
|
900
|
+
type: "email",
|
|
901
|
+
name: "email",
|
|
902
|
+
autoComplete: "username",
|
|
903
|
+
placeholder: labels.emailPlaceholder,
|
|
904
|
+
required: true,
|
|
905
|
+
value: email,
|
|
906
|
+
disabled: submitting,
|
|
907
|
+
onChange: (event) => setEmail(event.target.value)
|
|
908
|
+
})]
|
|
909
|
+
}),
|
|
910
|
+
error ? /* @__PURE__ */ jsx("p", {
|
|
911
|
+
role: "alert",
|
|
912
|
+
className: "polyx-signin__error",
|
|
913
|
+
children: error
|
|
914
|
+
}) : null,
|
|
915
|
+
/* @__PURE__ */ jsx("button", {
|
|
916
|
+
type: "submit",
|
|
917
|
+
className: "polyx-signin__submit",
|
|
918
|
+
disabled: submitting,
|
|
919
|
+
children: submitting ? labels.submitting : labels.submit
|
|
920
|
+
})
|
|
921
|
+
]
|
|
922
|
+
}),
|
|
923
|
+
footer
|
|
924
|
+
]
|
|
925
|
+
})
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
//#endregion
|
|
929
|
+
//#region src/components/reset-password.tsx
|
|
930
|
+
const DEFAULT_LABELS = {
|
|
931
|
+
heading: "Choose a new password",
|
|
932
|
+
subheading: "Enter and confirm your new password.",
|
|
933
|
+
newPasswordLabel: "New password",
|
|
934
|
+
confirmPasswordLabel: "Confirm new password",
|
|
935
|
+
passwordPlaceholder: "••••••••",
|
|
936
|
+
submit: "Reset password",
|
|
937
|
+
submitting: "Resetting…",
|
|
938
|
+
successHeading: "Password updated",
|
|
939
|
+
successSubheading: "You can now sign in with your new password.",
|
|
940
|
+
invalidHeading: "This link is invalid or expired",
|
|
941
|
+
invalidSubheading: "Password reset links can be used once and expire quickly. Request a new one.",
|
|
942
|
+
requestNewLink: "Request a new link",
|
|
943
|
+
backToSignIn: "Back to sign in",
|
|
944
|
+
securedBy: "Secured by PolyX",
|
|
945
|
+
passwordMismatch: "Those passwords don't match.",
|
|
946
|
+
weakPassword: "Password must be at least 8 characters.",
|
|
947
|
+
genericError: "Something went wrong. Please try again."
|
|
948
|
+
};
|
|
949
|
+
/** Matches poly-auth's v5 reset floor (F040). */
|
|
950
|
+
const DEFAULT_MIN_LENGTH = 8;
|
|
951
|
+
/**
|
|
952
|
+
* The reset-completion form (poly-x v5 / F040). Reads the opaque token from the URL,
|
|
953
|
+
* collects a new password, and POSTs to the SDK's BFF (`@poly-x/next` `resetPassword`),
|
|
954
|
+
* which redeems the token single-use server-side. The token is never decoded in the
|
|
955
|
+
* browser — identity, validity, and expiry are all enforced by the backend.
|
|
956
|
+
*
|
|
957
|
+
* Reuses the `<SignIn/>` styling: `import "@poly-x/react/styles.css"` once, then theme
|
|
958
|
+
* via the `--polyx-*` custom properties. Target `.polyx-reset` for form-specific tweaks.
|
|
959
|
+
*/
|
|
960
|
+
function ResetPassword(props) {
|
|
961
|
+
const action = props.action ?? "/api/polyx/reset-password";
|
|
962
|
+
const minLength = props.minLength ?? DEFAULT_MIN_LENGTH;
|
|
963
|
+
const signInPath = props.signInPath ?? "/sign-in";
|
|
964
|
+
const forgotPasswordPath = props.forgotPasswordPath ?? "/forgot-password";
|
|
965
|
+
const labels = {
|
|
966
|
+
...DEFAULT_LABELS,
|
|
967
|
+
...props.labels
|
|
968
|
+
};
|
|
969
|
+
const [token] = useState(() => props.token ?? (typeof window !== "undefined" ? new URLSearchParams(window.location.search).get("token") ?? "" : ""));
|
|
970
|
+
const [newPassword, setNewPassword] = useState("");
|
|
971
|
+
const [confirmPassword, setConfirmPassword] = useState("");
|
|
972
|
+
const [submitting, setSubmitting] = useState(false);
|
|
973
|
+
const [error, setError] = useState(null);
|
|
974
|
+
const [step, setStep] = useState(token ? "form" : "invalid");
|
|
975
|
+
async function onSubmit(event) {
|
|
976
|
+
event.preventDefault();
|
|
977
|
+
if (newPassword !== confirmPassword) {
|
|
978
|
+
setError(labels.passwordMismatch);
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
setSubmitting(true);
|
|
982
|
+
setError(null);
|
|
983
|
+
try {
|
|
984
|
+
switch ((await (await fetch(action, {
|
|
985
|
+
method: "POST",
|
|
986
|
+
headers: { "content-type": "application/json" },
|
|
987
|
+
body: JSON.stringify({
|
|
988
|
+
token,
|
|
989
|
+
newPassword,
|
|
990
|
+
confirmPassword
|
|
991
|
+
})
|
|
992
|
+
})).json().catch(() => ({}))).status) {
|
|
993
|
+
case "success":
|
|
994
|
+
setStep("success");
|
|
995
|
+
if (props.afterResetPath) window.location.assign(props.afterResetPath);
|
|
996
|
+
return;
|
|
997
|
+
case "weak_password":
|
|
998
|
+
setError(labels.weakPassword);
|
|
999
|
+
return;
|
|
1000
|
+
case "password_mismatch":
|
|
1001
|
+
setError(labels.passwordMismatch);
|
|
1002
|
+
return;
|
|
1003
|
+
case "invalid_or_expired":
|
|
1004
|
+
setStep("invalid");
|
|
1005
|
+
return;
|
|
1006
|
+
default:
|
|
1007
|
+
setError(labels.genericError);
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
} catch {
|
|
1011
|
+
setError(labels.genericError);
|
|
1012
|
+
} finally {
|
|
1013
|
+
setSubmitting(false);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
const rootClass = [
|
|
1017
|
+
"polyx-signin",
|
|
1018
|
+
"polyx-reset",
|
|
1019
|
+
props.className
|
|
1020
|
+
].filter(Boolean).join(" ");
|
|
1021
|
+
const footer = props.showSecuredBy === false ? null : /* @__PURE__ */ jsxs("p", {
|
|
1022
|
+
className: "polyx-signin__footer",
|
|
1023
|
+
children: [/* @__PURE__ */ jsx("svg", {
|
|
1024
|
+
className: "polyx-signin__shield",
|
|
1025
|
+
viewBox: "0 0 16 16",
|
|
1026
|
+
fill: "currentColor",
|
|
1027
|
+
"aria-hidden": "true",
|
|
1028
|
+
focusable: "false",
|
|
1029
|
+
children: /* @__PURE__ */ jsx("path", { d: "M8 0.5 2 3v4.2c0 3.5 2.5 6.7 6 7.8 3.5-1.1 6-4.3 6-7.8V3L8 .5Zm2.9 5.6-3.4 3.4a.7.7 0 0 1-1 0L5.1 8.1a.7.7 0 1 1 1-1l.9.9 2.9-2.9a.7.7 0 0 1 1 1Z" })
|
|
1030
|
+
}), labels.securedBy]
|
|
1031
|
+
});
|
|
1032
|
+
const header = (heading, subheading) => /* @__PURE__ */ jsxs("div", {
|
|
1033
|
+
className: "polyx-signin__header",
|
|
1034
|
+
children: [
|
|
1035
|
+
props.logo ? /* @__PURE__ */ jsx("div", {
|
|
1036
|
+
className: "polyx-signin__logo",
|
|
1037
|
+
children: props.logo
|
|
1038
|
+
}) : null,
|
|
1039
|
+
/* @__PURE__ */ jsx("h1", {
|
|
1040
|
+
className: "polyx-signin__heading",
|
|
1041
|
+
children: heading
|
|
1042
|
+
}),
|
|
1043
|
+
/* @__PURE__ */ jsx("p", {
|
|
1044
|
+
className: "polyx-signin__subheading",
|
|
1045
|
+
children: subheading
|
|
1046
|
+
})
|
|
1047
|
+
]
|
|
1048
|
+
});
|
|
1049
|
+
if (step === "success") return /* @__PURE__ */ jsx("div", {
|
|
1050
|
+
className: rootClass,
|
|
1051
|
+
"data-polyx-reset": "success",
|
|
1052
|
+
children: /* @__PURE__ */ jsx(RecoveryStatus, {
|
|
1053
|
+
icon: "check",
|
|
1054
|
+
heading: labels.successHeading,
|
|
1055
|
+
footer,
|
|
1056
|
+
actions: /* @__PURE__ */ jsx("a", {
|
|
1057
|
+
className: "polyx-signin__link",
|
|
1058
|
+
href: signInPath,
|
|
1059
|
+
children: labels.backToSignIn
|
|
1060
|
+
}),
|
|
1061
|
+
children: labels.successSubheading
|
|
1062
|
+
})
|
|
1063
|
+
});
|
|
1064
|
+
if (step === "invalid") return /* @__PURE__ */ jsx("div", {
|
|
1065
|
+
className: rootClass,
|
|
1066
|
+
"data-polyx-reset": "invalid",
|
|
1067
|
+
children: /* @__PURE__ */ jsx(RecoveryStatus, {
|
|
1068
|
+
icon: "warning",
|
|
1069
|
+
tone: "danger",
|
|
1070
|
+
heading: labels.invalidHeading,
|
|
1071
|
+
footer,
|
|
1072
|
+
actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("a", {
|
|
1073
|
+
className: "polyx-signin__link",
|
|
1074
|
+
href: forgotPasswordPath,
|
|
1075
|
+
children: labels.requestNewLink
|
|
1076
|
+
}), /* @__PURE__ */ jsx("a", {
|
|
1077
|
+
className: "polyx-signin__link",
|
|
1078
|
+
href: signInPath,
|
|
1079
|
+
children: labels.backToSignIn
|
|
1080
|
+
})] }),
|
|
1081
|
+
children: labels.invalidSubheading
|
|
1082
|
+
})
|
|
1083
|
+
});
|
|
1084
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1085
|
+
className: rootClass,
|
|
1086
|
+
"data-polyx-reset": step,
|
|
1087
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
1088
|
+
className: "polyx-signin__card",
|
|
1089
|
+
children: [
|
|
1090
|
+
header(labels.heading, labels.subheading),
|
|
1091
|
+
/* @__PURE__ */ jsxs("form", {
|
|
1092
|
+
className: "polyx-signin__form",
|
|
1093
|
+
onSubmit,
|
|
1094
|
+
children: [
|
|
1095
|
+
/* @__PURE__ */ jsxs("label", {
|
|
1096
|
+
className: "polyx-signin__field",
|
|
1097
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1098
|
+
className: "polyx-signin__label",
|
|
1099
|
+
children: labels.newPasswordLabel
|
|
1100
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
1101
|
+
className: "polyx-signin__input",
|
|
1102
|
+
type: "password",
|
|
1103
|
+
name: "newPassword",
|
|
1104
|
+
autoComplete: "new-password",
|
|
1105
|
+
placeholder: labels.passwordPlaceholder,
|
|
1106
|
+
required: true,
|
|
1107
|
+
minLength,
|
|
1108
|
+
value: newPassword,
|
|
1109
|
+
disabled: submitting,
|
|
1110
|
+
onChange: (event) => setNewPassword(event.target.value)
|
|
1111
|
+
})]
|
|
1112
|
+
}),
|
|
1113
|
+
/* @__PURE__ */ jsxs("label", {
|
|
1114
|
+
className: "polyx-signin__field",
|
|
1115
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1116
|
+
className: "polyx-signin__label",
|
|
1117
|
+
children: labels.confirmPasswordLabel
|
|
1118
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
1119
|
+
className: "polyx-signin__input",
|
|
1120
|
+
type: "password",
|
|
1121
|
+
name: "confirmPassword",
|
|
1122
|
+
autoComplete: "new-password",
|
|
1123
|
+
placeholder: labels.passwordPlaceholder,
|
|
1124
|
+
required: true,
|
|
1125
|
+
minLength,
|
|
1126
|
+
value: confirmPassword,
|
|
1127
|
+
disabled: submitting,
|
|
1128
|
+
onChange: (event) => setConfirmPassword(event.target.value)
|
|
1129
|
+
})]
|
|
1130
|
+
}),
|
|
1131
|
+
error ? /* @__PURE__ */ jsx("p", {
|
|
1132
|
+
role: "alert",
|
|
1133
|
+
className: "polyx-signin__error",
|
|
1134
|
+
children: error
|
|
1135
|
+
}) : null,
|
|
1136
|
+
/* @__PURE__ */ jsx("button", {
|
|
1137
|
+
type: "submit",
|
|
1138
|
+
className: "polyx-signin__submit",
|
|
1139
|
+
disabled: submitting,
|
|
1140
|
+
children: submitting ? labels.submitting : labels.submit
|
|
1141
|
+
})
|
|
1142
|
+
]
|
|
1143
|
+
}),
|
|
1144
|
+
footer
|
|
1145
|
+
]
|
|
1146
|
+
})
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
//#endregion
|
|
670
1150
|
//#region src/components/auth-callback.tsx
|
|
671
1151
|
/** Drop on your `/auth/callback` route: completes the sign-in exchange on mount. */
|
|
672
1152
|
function AuthCallback({ children = null }) {
|
|
@@ -685,4 +1165,4 @@ function AuthCallback({ children = null }) {
|
|
|
685
1165
|
const PACKAGE_NAME = "@poly-x/react";
|
|
686
1166
|
const version = "0.0.0";
|
|
687
1167
|
//#endregion
|
|
688
|
-
export { AuthCallback, BroadcastAuthChannel, BroadcastChannelSessionChannel, PACKAGE_NAME, PolyXContext, PolyXProvider, PopupCancelledError, Protected, SessionStoragePkceStore, SignIn, WebLocksLock, WindowBrowserBridge, createLoginController, useAuth, useAuthCallback, useSession, useUser, version };
|
|
1168
|
+
export { AuthCallback, BroadcastAuthChannel, BroadcastChannelSessionChannel, ForgotPassword, PACKAGE_NAME, PolyXContext, PolyXProvider, PopupCancelledError, Protected, ResetPassword, SessionStoragePkceStore, SignIn, WebLocksLock, WindowBrowserBridge, createLoginController, useAuth, useAuthCallback, useSession, useUser, version };
|
package/dist/styles.css
CHANGED
|
@@ -339,6 +339,77 @@
|
|
|
339
339
|
opacity: 0.85;
|
|
340
340
|
}
|
|
341
341
|
|
|
342
|
+
/* --- Recovery confirmation states (ForgotPassword / ResetPassword) ------- */
|
|
343
|
+
|
|
344
|
+
.polyx-signin__header--center {
|
|
345
|
+
align-items: center;
|
|
346
|
+
text-align: center;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.polyx-signin__status-icon {
|
|
350
|
+
display: inline-flex;
|
|
351
|
+
align-items: center;
|
|
352
|
+
justify-content: center;
|
|
353
|
+
width: 3rem;
|
|
354
|
+
height: 3rem;
|
|
355
|
+
margin-bottom: 0.25rem;
|
|
356
|
+
border-radius: 999px;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.polyx-signin__status-icon svg {
|
|
360
|
+
width: 1.5rem;
|
|
361
|
+
height: 1.5rem;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.polyx-signin__status-icon--brand {
|
|
365
|
+
color: var(--polyx-brand);
|
|
366
|
+
background: color-mix(in srgb, var(--polyx-brand) 12%, transparent);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.polyx-signin__status-icon--danger {
|
|
370
|
+
color: var(--polyx-danger);
|
|
371
|
+
background: var(--polyx-danger-bg);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/* The entered email, emphasized inside the confirmation copy. */
|
|
375
|
+
.polyx-signin__email {
|
|
376
|
+
color: var(--polyx-fg);
|
|
377
|
+
font-weight: 600;
|
|
378
|
+
word-break: break-all;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/* Secondary text-link actions under a confirmation screen — quieter than the CTA. */
|
|
382
|
+
.polyx-signin__actions {
|
|
383
|
+
display: flex;
|
|
384
|
+
flex-direction: column;
|
|
385
|
+
align-items: center;
|
|
386
|
+
gap: 0.75rem;
|
|
387
|
+
margin-top: 1.5rem;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.polyx-signin__link {
|
|
391
|
+
padding: 0;
|
|
392
|
+
font: inherit;
|
|
393
|
+
font-size: 0.875rem;
|
|
394
|
+
font-weight: 500;
|
|
395
|
+
color: var(--polyx-brand);
|
|
396
|
+
background: none;
|
|
397
|
+
border: none;
|
|
398
|
+
cursor: pointer;
|
|
399
|
+
text-decoration: none;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.polyx-signin__link:hover {
|
|
403
|
+
color: var(--polyx-brand-hover);
|
|
404
|
+
text-decoration: underline;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.polyx-signin__link:focus-visible {
|
|
408
|
+
outline: none;
|
|
409
|
+
border-radius: 2px;
|
|
410
|
+
box-shadow: 0 0 0 3px var(--polyx-ring);
|
|
411
|
+
}
|
|
412
|
+
|
|
342
413
|
/* --- Workspace picker ---------------------------------------------------- */
|
|
343
414
|
|
|
344
415
|
.polyx-signin__tenants {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poly-x/react",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.7",
|
|
4
4
|
"description": "PolyX SDK for React SPAs - provider, hooks, drop-in auth UI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"module": "./dist/index.mjs",
|
|
28
28
|
"types": "./dist/index.d.cts",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@poly-x/core": "0.1.0-alpha.
|
|
30
|
+
"@poly-x/core": "0.1.0-alpha.7"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"react": ">=18",
|