@poly-x/react 0.1.0-alpha.7 → 0.1.0-alpha.9
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 +146 -55
- package/dist/index.d.cts +9 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.mjs +146 -55
- package/dist/styles.css +64 -0
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -360,8 +360,11 @@ const DEFAULT_LABELS$2 = {
|
|
|
360
360
|
emailPlaceholder: "you@company.com",
|
|
361
361
|
passwordLabel: "Password",
|
|
362
362
|
passwordPlaceholder: "••••••••",
|
|
363
|
+
showPassword: "Show password",
|
|
364
|
+
hidePassword: "Hide password",
|
|
363
365
|
submit: "Sign in",
|
|
364
366
|
submitting: "Signing in…",
|
|
367
|
+
forgotPassword: "Forgot password?",
|
|
365
368
|
chooseWorkspace: "Choose a workspace",
|
|
366
369
|
chooseWorkspaceSubheading: "You have access to more than one workspace.",
|
|
367
370
|
securedBy: "Secured by PolyX",
|
|
@@ -379,6 +382,77 @@ const DEFAULT_LABELS$2 = {
|
|
|
379
382
|
};
|
|
380
383
|
/** Mirrors poly-auth's own floor (Joi: min 6). */
|
|
381
384
|
const MIN_PASSWORD_LENGTH = 6;
|
|
385
|
+
function EyeIcon() {
|
|
386
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
387
|
+
viewBox: "0 0 24 24",
|
|
388
|
+
fill: "none",
|
|
389
|
+
stroke: "currentColor",
|
|
390
|
+
strokeWidth: "2",
|
|
391
|
+
strokeLinecap: "round",
|
|
392
|
+
strokeLinejoin: "round",
|
|
393
|
+
"aria-hidden": "true",
|
|
394
|
+
focusable: "false",
|
|
395
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
396
|
+
cx: "12",
|
|
397
|
+
cy: "12",
|
|
398
|
+
r: "3"
|
|
399
|
+
})]
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
function EyeOffIcon() {
|
|
403
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
404
|
+
viewBox: "0 0 24 24",
|
|
405
|
+
fill: "none",
|
|
406
|
+
stroke: "currentColor",
|
|
407
|
+
strokeWidth: "2",
|
|
408
|
+
strokeLinecap: "round",
|
|
409
|
+
strokeLinejoin: "round",
|
|
410
|
+
"aria-hidden": "true",
|
|
411
|
+
focusable: "false",
|
|
412
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M9.88 4.24A9.1 9.1 0 0 1 12 4c6.5 0 10 7 10 7a13.2 13.2 0 0 1-1.67 2.68M6.61 6.61A13.5 13.5 0 0 0 2 12s3.5 7 10 7a9.7 9.7 0 0 0 5.39-1.61" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
|
|
413
|
+
x1: "2",
|
|
414
|
+
y1: "2",
|
|
415
|
+
x2: "22",
|
|
416
|
+
y2: "22"
|
|
417
|
+
})]
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
/** A password input with an accessible show/hide reveal toggle (own visibility state). */
|
|
421
|
+
function PasswordField(props) {
|
|
422
|
+
const [visible, setVisible] = (0, react.useState)(false);
|
|
423
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
424
|
+
className: "polyx-signin__field",
|
|
425
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
426
|
+
className: "polyx-signin__label",
|
|
427
|
+
htmlFor: props.id,
|
|
428
|
+
children: props.label
|
|
429
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
430
|
+
className: "polyx-signin__input-wrap",
|
|
431
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
432
|
+
id: props.id,
|
|
433
|
+
className: "polyx-signin__input polyx-signin__input--has-reveal",
|
|
434
|
+
type: visible ? "text" : "password",
|
|
435
|
+
name: props.name,
|
|
436
|
+
autoComplete: props.autoComplete,
|
|
437
|
+
placeholder: props.placeholder,
|
|
438
|
+
required: true,
|
|
439
|
+
minLength: props.minLength,
|
|
440
|
+
value: props.value,
|
|
441
|
+
disabled: props.disabled,
|
|
442
|
+
onChange: (event) => props.onChange(event.target.value)
|
|
443
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
444
|
+
type: "button",
|
|
445
|
+
className: "polyx-signin__reveal",
|
|
446
|
+
"aria-pressed": visible,
|
|
447
|
+
"aria-label": visible ? props.hideLabel : props.showLabel,
|
|
448
|
+
title: visible ? props.hideLabel : props.showLabel,
|
|
449
|
+
disabled: props.disabled,
|
|
450
|
+
onClick: () => setVisible((value) => !value),
|
|
451
|
+
children: visible ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EyeOffIcon, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EyeIcon, {})
|
|
452
|
+
})]
|
|
453
|
+
})]
|
|
454
|
+
});
|
|
455
|
+
}
|
|
382
456
|
/**
|
|
383
457
|
* The embedded, Clerk-style sign-in form (D2b). Renders email/password inside the
|
|
384
458
|
* consuming app and POSTs to the SDK's BFF (`@poly-x/next` `authenticate`), which
|
|
@@ -404,6 +478,29 @@ function SignIn(props) {
|
|
|
404
478
|
const [tenants, setTenants] = (0, react.useState)(null);
|
|
405
479
|
const [submitting, setSubmitting] = (0, react.useState)(false);
|
|
406
480
|
const [error, setError] = (0, react.useState)(null);
|
|
481
|
+
const polyx = (0, react.useContext)(PolyXContext);
|
|
482
|
+
const [branding, setBranding] = (0, react.useState)({});
|
|
483
|
+
(0, react.useEffect)(() => {
|
|
484
|
+
if (!polyx) return;
|
|
485
|
+
let active = true;
|
|
486
|
+
polyx.authClient.fetchBranding(props.organizationCode ? { organizationCode: props.organizationCode } : {}).then((tokens) => {
|
|
487
|
+
if (active) setBranding(tokens);
|
|
488
|
+
});
|
|
489
|
+
return () => {
|
|
490
|
+
active = false;
|
|
491
|
+
};
|
|
492
|
+
}, [polyx, props.organizationCode]);
|
|
493
|
+
const brandingStyle = {};
|
|
494
|
+
if (branding.primaryColor) brandingStyle["--polyx-brand"] = branding.primaryColor;
|
|
495
|
+
if (branding.backgroundColor) {
|
|
496
|
+
brandingStyle["--polyx-bg"] = branding.backgroundColor;
|
|
497
|
+
brandingStyle["--polyx-page-bg"] = branding.backgroundColor;
|
|
498
|
+
}
|
|
499
|
+
const brandingLogo = props.logo ?? (branding.logoUrl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
500
|
+
className: "polyx-signin__brand-logo",
|
|
501
|
+
src: branding.logoUrl,
|
|
502
|
+
alt: branding.displayName ?? ""
|
|
503
|
+
}) : void 0);
|
|
407
504
|
/**
|
|
408
505
|
* One round-trip to the BFF. `tenantId` picks a workspace; `passwords` completes
|
|
409
506
|
* the temp-password flow (the BFF re-verifies the temporary password, sets the
|
|
@@ -473,8 +570,7 @@ function SignIn(props) {
|
|
|
473
570
|
} });
|
|
474
571
|
}
|
|
475
572
|
const picking = tenants !== null;
|
|
476
|
-
const
|
|
477
|
-
const showHeaderLogo = Boolean(props.logo) && !hasPanel;
|
|
573
|
+
const showHeaderLogo = Boolean(brandingLogo) && !(variant === "page");
|
|
478
574
|
const rootClass = [
|
|
479
575
|
"polyx-signin",
|
|
480
576
|
`polyx-signin--${variant}`,
|
|
@@ -500,7 +596,7 @@ function SignIn(props) {
|
|
|
500
596
|
children: [
|
|
501
597
|
showHeaderLogo ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
502
598
|
className: "polyx-signin__logo",
|
|
503
|
-
children:
|
|
599
|
+
children: brandingLogo
|
|
504
600
|
}) : null,
|
|
505
601
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
506
602
|
className: "polyx-signin__heading",
|
|
@@ -545,41 +641,31 @@ function SignIn(props) {
|
|
|
545
641
|
className: "polyx-signin__form",
|
|
546
642
|
onSubmit: onSetPasswordSubmit,
|
|
547
643
|
children: [
|
|
548
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
minLength: MIN_PASSWORD_LENGTH,
|
|
561
|
-
value: newPassword,
|
|
562
|
-
disabled: submitting,
|
|
563
|
-
onChange: (event) => setNewPassword(event.target.value)
|
|
564
|
-
})]
|
|
644
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PasswordField, {
|
|
645
|
+
id: "polyx-signin-new-password",
|
|
646
|
+
label: labels.newPasswordLabel,
|
|
647
|
+
name: "newPassword",
|
|
648
|
+
autoComplete: "new-password",
|
|
649
|
+
placeholder: labels.passwordPlaceholder,
|
|
650
|
+
minLength: MIN_PASSWORD_LENGTH,
|
|
651
|
+
value: newPassword,
|
|
652
|
+
disabled: submitting,
|
|
653
|
+
onChange: setNewPassword,
|
|
654
|
+
showLabel: labels.showPassword,
|
|
655
|
+
hideLabel: labels.hidePassword
|
|
565
656
|
}),
|
|
566
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
minLength: MIN_PASSWORD_LENGTH,
|
|
579
|
-
value: confirmPassword,
|
|
580
|
-
disabled: submitting,
|
|
581
|
-
onChange: (event) => setConfirmPassword(event.target.value)
|
|
582
|
-
})]
|
|
657
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PasswordField, {
|
|
658
|
+
id: "polyx-signin-confirm-password",
|
|
659
|
+
label: labels.confirmPasswordLabel,
|
|
660
|
+
name: "confirmPassword",
|
|
661
|
+
autoComplete: "new-password",
|
|
662
|
+
placeholder: labels.passwordPlaceholder,
|
|
663
|
+
minLength: MIN_PASSWORD_LENGTH,
|
|
664
|
+
value: confirmPassword,
|
|
665
|
+
disabled: submitting,
|
|
666
|
+
onChange: setConfirmPassword,
|
|
667
|
+
showLabel: labels.showPassword,
|
|
668
|
+
hideLabel: labels.hidePassword
|
|
583
669
|
}),
|
|
584
670
|
errorNode,
|
|
585
671
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -615,23 +701,26 @@ function SignIn(props) {
|
|
|
615
701
|
onChange: (event) => setEmail(event.target.value)
|
|
616
702
|
})]
|
|
617
703
|
}),
|
|
618
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
required: true,
|
|
630
|
-
value: password,
|
|
631
|
-
disabled: submitting,
|
|
632
|
-
onChange: (event) => setPassword(event.target.value)
|
|
633
|
-
})]
|
|
704
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PasswordField, {
|
|
705
|
+
id: "polyx-signin-password",
|
|
706
|
+
label: labels.passwordLabel,
|
|
707
|
+
name: "password",
|
|
708
|
+
autoComplete: "current-password",
|
|
709
|
+
placeholder: labels.passwordPlaceholder,
|
|
710
|
+
value: password,
|
|
711
|
+
disabled: submitting,
|
|
712
|
+
onChange: setPassword,
|
|
713
|
+
showLabel: labels.showPassword,
|
|
714
|
+
hideLabel: labels.hidePassword
|
|
634
715
|
}),
|
|
716
|
+
props.forgotPasswordUrl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
717
|
+
className: "polyx-signin__forgot",
|
|
718
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
719
|
+
className: "polyx-signin__link",
|
|
720
|
+
href: props.forgotPasswordUrl,
|
|
721
|
+
children: labels.forgotPassword
|
|
722
|
+
})
|
|
723
|
+
}) : null,
|
|
635
724
|
errorNode,
|
|
636
725
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
637
726
|
type: "submit",
|
|
@@ -647,11 +736,12 @@ function SignIn(props) {
|
|
|
647
736
|
if (variant === "page") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
648
737
|
className: rootClass,
|
|
649
738
|
"data-polyx-signin": step,
|
|
739
|
+
style: brandingStyle,
|
|
650
740
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("aside", {
|
|
651
741
|
className: "polyx-signin__panel",
|
|
652
|
-
children: props.panel ?? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
742
|
+
children: props.panel ?? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [brandingLogo ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
653
743
|
className: "polyx-signin__panel-logo",
|
|
654
|
-
children:
|
|
744
|
+
children: brandingLogo
|
|
655
745
|
}) : null, labels.tagline ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
656
746
|
className: "polyx-signin__tagline",
|
|
657
747
|
children: labels.tagline
|
|
@@ -664,6 +754,7 @@ function SignIn(props) {
|
|
|
664
754
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
665
755
|
className: rootClass,
|
|
666
756
|
"data-polyx-signin": step,
|
|
757
|
+
style: brandingStyle,
|
|
667
758
|
children: card
|
|
668
759
|
});
|
|
669
760
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -201,8 +201,12 @@ interface SignInLabels {
|
|
|
201
201
|
emailPlaceholder: string;
|
|
202
202
|
passwordLabel: string;
|
|
203
203
|
passwordPlaceholder: string;
|
|
204
|
+
/** Reveal-toggle a11y labels (aria-label / tooltip on the show-hide button). */
|
|
205
|
+
showPassword: string;
|
|
206
|
+
hidePassword: string;
|
|
204
207
|
submit: string;
|
|
205
208
|
submitting: string;
|
|
209
|
+
forgotPassword: string;
|
|
206
210
|
chooseWorkspace: string;
|
|
207
211
|
chooseWorkspaceSubheading: string;
|
|
208
212
|
securedBy: string;
|
|
@@ -235,6 +239,11 @@ interface SignInProps {
|
|
|
235
239
|
panel?: ReactNode;
|
|
236
240
|
/** BFF endpoint backed by `createAuthHandlers().authenticate`. Default `/api/polyx/authenticate`. */
|
|
237
241
|
action?: string;
|
|
242
|
+
/**
|
|
243
|
+
* URL of your reset flow (where `<ForgotPassword/>` lives). When set, a
|
|
244
|
+
* "Forgot password?" link appears under the password field. Omit to hide it.
|
|
245
|
+
*/
|
|
246
|
+
forgotPasswordUrl?: string;
|
|
238
247
|
/** Where to send the browser after success. Overrides the server's default redirect. */
|
|
239
248
|
afterSignInPath?: string;
|
|
240
249
|
/** Pre-scope the login to a single organization (skips org discovery). */
|
package/dist/index.d.mts
CHANGED
|
@@ -201,8 +201,12 @@ interface SignInLabels {
|
|
|
201
201
|
emailPlaceholder: string;
|
|
202
202
|
passwordLabel: string;
|
|
203
203
|
passwordPlaceholder: string;
|
|
204
|
+
/** Reveal-toggle a11y labels (aria-label / tooltip on the show-hide button). */
|
|
205
|
+
showPassword: string;
|
|
206
|
+
hidePassword: string;
|
|
204
207
|
submit: string;
|
|
205
208
|
submitting: string;
|
|
209
|
+
forgotPassword: string;
|
|
206
210
|
chooseWorkspace: string;
|
|
207
211
|
chooseWorkspaceSubheading: string;
|
|
208
212
|
securedBy: string;
|
|
@@ -235,6 +239,11 @@ interface SignInProps {
|
|
|
235
239
|
panel?: ReactNode;
|
|
236
240
|
/** BFF endpoint backed by `createAuthHandlers().authenticate`. Default `/api/polyx/authenticate`. */
|
|
237
241
|
action?: string;
|
|
242
|
+
/**
|
|
243
|
+
* URL of your reset flow (where `<ForgotPassword/>` lives). When set, a
|
|
244
|
+
* "Forgot password?" link appears under the password field. Omit to hide it.
|
|
245
|
+
*/
|
|
246
|
+
forgotPasswordUrl?: string;
|
|
238
247
|
/** Where to send the browser after success. Overrides the server's default redirect. */
|
|
239
248
|
afterSignInPath?: string;
|
|
240
249
|
/** Pre-scope the login to a single organization (skips org discovery). */
|
package/dist/index.mjs
CHANGED
|
@@ -359,8 +359,11 @@ const DEFAULT_LABELS$2 = {
|
|
|
359
359
|
emailPlaceholder: "you@company.com",
|
|
360
360
|
passwordLabel: "Password",
|
|
361
361
|
passwordPlaceholder: "••••••••",
|
|
362
|
+
showPassword: "Show password",
|
|
363
|
+
hidePassword: "Hide password",
|
|
362
364
|
submit: "Sign in",
|
|
363
365
|
submitting: "Signing in…",
|
|
366
|
+
forgotPassword: "Forgot password?",
|
|
364
367
|
chooseWorkspace: "Choose a workspace",
|
|
365
368
|
chooseWorkspaceSubheading: "You have access to more than one workspace.",
|
|
366
369
|
securedBy: "Secured by PolyX",
|
|
@@ -378,6 +381,77 @@ const DEFAULT_LABELS$2 = {
|
|
|
378
381
|
};
|
|
379
382
|
/** Mirrors poly-auth's own floor (Joi: min 6). */
|
|
380
383
|
const MIN_PASSWORD_LENGTH = 6;
|
|
384
|
+
function EyeIcon() {
|
|
385
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
386
|
+
viewBox: "0 0 24 24",
|
|
387
|
+
fill: "none",
|
|
388
|
+
stroke: "currentColor",
|
|
389
|
+
strokeWidth: "2",
|
|
390
|
+
strokeLinecap: "round",
|
|
391
|
+
strokeLinejoin: "round",
|
|
392
|
+
"aria-hidden": "true",
|
|
393
|
+
focusable: "false",
|
|
394
|
+
children: [/* @__PURE__ */ jsx("path", { d: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z" }), /* @__PURE__ */ jsx("circle", {
|
|
395
|
+
cx: "12",
|
|
396
|
+
cy: "12",
|
|
397
|
+
r: "3"
|
|
398
|
+
})]
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
function EyeOffIcon() {
|
|
402
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
403
|
+
viewBox: "0 0 24 24",
|
|
404
|
+
fill: "none",
|
|
405
|
+
stroke: "currentColor",
|
|
406
|
+
strokeWidth: "2",
|
|
407
|
+
strokeLinecap: "round",
|
|
408
|
+
strokeLinejoin: "round",
|
|
409
|
+
"aria-hidden": "true",
|
|
410
|
+
focusable: "false",
|
|
411
|
+
children: [/* @__PURE__ */ jsx("path", { d: "M9.88 4.24A9.1 9.1 0 0 1 12 4c6.5 0 10 7 10 7a13.2 13.2 0 0 1-1.67 2.68M6.61 6.61A13.5 13.5 0 0 0 2 12s3.5 7 10 7a9.7 9.7 0 0 0 5.39-1.61" }), /* @__PURE__ */ jsx("line", {
|
|
412
|
+
x1: "2",
|
|
413
|
+
y1: "2",
|
|
414
|
+
x2: "22",
|
|
415
|
+
y2: "22"
|
|
416
|
+
})]
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
/** A password input with an accessible show/hide reveal toggle (own visibility state). */
|
|
420
|
+
function PasswordField(props) {
|
|
421
|
+
const [visible, setVisible] = useState(false);
|
|
422
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
423
|
+
className: "polyx-signin__field",
|
|
424
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
425
|
+
className: "polyx-signin__label",
|
|
426
|
+
htmlFor: props.id,
|
|
427
|
+
children: props.label
|
|
428
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
429
|
+
className: "polyx-signin__input-wrap",
|
|
430
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
431
|
+
id: props.id,
|
|
432
|
+
className: "polyx-signin__input polyx-signin__input--has-reveal",
|
|
433
|
+
type: visible ? "text" : "password",
|
|
434
|
+
name: props.name,
|
|
435
|
+
autoComplete: props.autoComplete,
|
|
436
|
+
placeholder: props.placeholder,
|
|
437
|
+
required: true,
|
|
438
|
+
minLength: props.minLength,
|
|
439
|
+
value: props.value,
|
|
440
|
+
disabled: props.disabled,
|
|
441
|
+
onChange: (event) => props.onChange(event.target.value)
|
|
442
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
443
|
+
type: "button",
|
|
444
|
+
className: "polyx-signin__reveal",
|
|
445
|
+
"aria-pressed": visible,
|
|
446
|
+
"aria-label": visible ? props.hideLabel : props.showLabel,
|
|
447
|
+
title: visible ? props.hideLabel : props.showLabel,
|
|
448
|
+
disabled: props.disabled,
|
|
449
|
+
onClick: () => setVisible((value) => !value),
|
|
450
|
+
children: visible ? /* @__PURE__ */ jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsx(EyeIcon, {})
|
|
451
|
+
})]
|
|
452
|
+
})]
|
|
453
|
+
});
|
|
454
|
+
}
|
|
381
455
|
/**
|
|
382
456
|
* The embedded, Clerk-style sign-in form (D2b). Renders email/password inside the
|
|
383
457
|
* consuming app and POSTs to the SDK's BFF (`@poly-x/next` `authenticate`), which
|
|
@@ -403,6 +477,29 @@ function SignIn(props) {
|
|
|
403
477
|
const [tenants, setTenants] = useState(null);
|
|
404
478
|
const [submitting, setSubmitting] = useState(false);
|
|
405
479
|
const [error, setError] = useState(null);
|
|
480
|
+
const polyx = useContext(PolyXContext);
|
|
481
|
+
const [branding, setBranding] = useState({});
|
|
482
|
+
useEffect(() => {
|
|
483
|
+
if (!polyx) return;
|
|
484
|
+
let active = true;
|
|
485
|
+
polyx.authClient.fetchBranding(props.organizationCode ? { organizationCode: props.organizationCode } : {}).then((tokens) => {
|
|
486
|
+
if (active) setBranding(tokens);
|
|
487
|
+
});
|
|
488
|
+
return () => {
|
|
489
|
+
active = false;
|
|
490
|
+
};
|
|
491
|
+
}, [polyx, props.organizationCode]);
|
|
492
|
+
const brandingStyle = {};
|
|
493
|
+
if (branding.primaryColor) brandingStyle["--polyx-brand"] = branding.primaryColor;
|
|
494
|
+
if (branding.backgroundColor) {
|
|
495
|
+
brandingStyle["--polyx-bg"] = branding.backgroundColor;
|
|
496
|
+
brandingStyle["--polyx-page-bg"] = branding.backgroundColor;
|
|
497
|
+
}
|
|
498
|
+
const brandingLogo = props.logo ?? (branding.logoUrl ? /* @__PURE__ */ jsx("img", {
|
|
499
|
+
className: "polyx-signin__brand-logo",
|
|
500
|
+
src: branding.logoUrl,
|
|
501
|
+
alt: branding.displayName ?? ""
|
|
502
|
+
}) : void 0);
|
|
406
503
|
/**
|
|
407
504
|
* One round-trip to the BFF. `tenantId` picks a workspace; `passwords` completes
|
|
408
505
|
* the temp-password flow (the BFF re-verifies the temporary password, sets the
|
|
@@ -472,8 +569,7 @@ function SignIn(props) {
|
|
|
472
569
|
} });
|
|
473
570
|
}
|
|
474
571
|
const picking = tenants !== null;
|
|
475
|
-
const
|
|
476
|
-
const showHeaderLogo = Boolean(props.logo) && !hasPanel;
|
|
572
|
+
const showHeaderLogo = Boolean(brandingLogo) && !(variant === "page");
|
|
477
573
|
const rootClass = [
|
|
478
574
|
"polyx-signin",
|
|
479
575
|
`polyx-signin--${variant}`,
|
|
@@ -499,7 +595,7 @@ function SignIn(props) {
|
|
|
499
595
|
children: [
|
|
500
596
|
showHeaderLogo ? /* @__PURE__ */ jsx("div", {
|
|
501
597
|
className: "polyx-signin__logo",
|
|
502
|
-
children:
|
|
598
|
+
children: brandingLogo
|
|
503
599
|
}) : null,
|
|
504
600
|
/* @__PURE__ */ jsx("h1", {
|
|
505
601
|
className: "polyx-signin__heading",
|
|
@@ -544,41 +640,31 @@ function SignIn(props) {
|
|
|
544
640
|
className: "polyx-signin__form",
|
|
545
641
|
onSubmit: onSetPasswordSubmit,
|
|
546
642
|
children: [
|
|
547
|
-
/* @__PURE__ */
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
minLength: MIN_PASSWORD_LENGTH,
|
|
560
|
-
value: newPassword,
|
|
561
|
-
disabled: submitting,
|
|
562
|
-
onChange: (event) => setNewPassword(event.target.value)
|
|
563
|
-
})]
|
|
643
|
+
/* @__PURE__ */ jsx(PasswordField, {
|
|
644
|
+
id: "polyx-signin-new-password",
|
|
645
|
+
label: labels.newPasswordLabel,
|
|
646
|
+
name: "newPassword",
|
|
647
|
+
autoComplete: "new-password",
|
|
648
|
+
placeholder: labels.passwordPlaceholder,
|
|
649
|
+
minLength: MIN_PASSWORD_LENGTH,
|
|
650
|
+
value: newPassword,
|
|
651
|
+
disabled: submitting,
|
|
652
|
+
onChange: setNewPassword,
|
|
653
|
+
showLabel: labels.showPassword,
|
|
654
|
+
hideLabel: labels.hidePassword
|
|
564
655
|
}),
|
|
565
|
-
/* @__PURE__ */
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
minLength: MIN_PASSWORD_LENGTH,
|
|
578
|
-
value: confirmPassword,
|
|
579
|
-
disabled: submitting,
|
|
580
|
-
onChange: (event) => setConfirmPassword(event.target.value)
|
|
581
|
-
})]
|
|
656
|
+
/* @__PURE__ */ jsx(PasswordField, {
|
|
657
|
+
id: "polyx-signin-confirm-password",
|
|
658
|
+
label: labels.confirmPasswordLabel,
|
|
659
|
+
name: "confirmPassword",
|
|
660
|
+
autoComplete: "new-password",
|
|
661
|
+
placeholder: labels.passwordPlaceholder,
|
|
662
|
+
minLength: MIN_PASSWORD_LENGTH,
|
|
663
|
+
value: confirmPassword,
|
|
664
|
+
disabled: submitting,
|
|
665
|
+
onChange: setConfirmPassword,
|
|
666
|
+
showLabel: labels.showPassword,
|
|
667
|
+
hideLabel: labels.hidePassword
|
|
582
668
|
}),
|
|
583
669
|
errorNode,
|
|
584
670
|
/* @__PURE__ */ jsx("button", {
|
|
@@ -614,23 +700,26 @@ function SignIn(props) {
|
|
|
614
700
|
onChange: (event) => setEmail(event.target.value)
|
|
615
701
|
})]
|
|
616
702
|
}),
|
|
617
|
-
/* @__PURE__ */
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
required: true,
|
|
629
|
-
value: password,
|
|
630
|
-
disabled: submitting,
|
|
631
|
-
onChange: (event) => setPassword(event.target.value)
|
|
632
|
-
})]
|
|
703
|
+
/* @__PURE__ */ jsx(PasswordField, {
|
|
704
|
+
id: "polyx-signin-password",
|
|
705
|
+
label: labels.passwordLabel,
|
|
706
|
+
name: "password",
|
|
707
|
+
autoComplete: "current-password",
|
|
708
|
+
placeholder: labels.passwordPlaceholder,
|
|
709
|
+
value: password,
|
|
710
|
+
disabled: submitting,
|
|
711
|
+
onChange: setPassword,
|
|
712
|
+
showLabel: labels.showPassword,
|
|
713
|
+
hideLabel: labels.hidePassword
|
|
633
714
|
}),
|
|
715
|
+
props.forgotPasswordUrl ? /* @__PURE__ */ jsx("div", {
|
|
716
|
+
className: "polyx-signin__forgot",
|
|
717
|
+
children: /* @__PURE__ */ jsx("a", {
|
|
718
|
+
className: "polyx-signin__link",
|
|
719
|
+
href: props.forgotPasswordUrl,
|
|
720
|
+
children: labels.forgotPassword
|
|
721
|
+
})
|
|
722
|
+
}) : null,
|
|
634
723
|
errorNode,
|
|
635
724
|
/* @__PURE__ */ jsx("button", {
|
|
636
725
|
type: "submit",
|
|
@@ -646,11 +735,12 @@ function SignIn(props) {
|
|
|
646
735
|
if (variant === "page") return /* @__PURE__ */ jsxs("div", {
|
|
647
736
|
className: rootClass,
|
|
648
737
|
"data-polyx-signin": step,
|
|
738
|
+
style: brandingStyle,
|
|
649
739
|
children: [/* @__PURE__ */ jsx("aside", {
|
|
650
740
|
className: "polyx-signin__panel",
|
|
651
|
-
children: props.panel ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
741
|
+
children: props.panel ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [brandingLogo ? /* @__PURE__ */ jsx("div", {
|
|
652
742
|
className: "polyx-signin__panel-logo",
|
|
653
|
-
children:
|
|
743
|
+
children: brandingLogo
|
|
654
744
|
}) : null, labels.tagline ? /* @__PURE__ */ jsx("p", {
|
|
655
745
|
className: "polyx-signin__tagline",
|
|
656
746
|
children: labels.tagline
|
|
@@ -663,6 +753,7 @@ function SignIn(props) {
|
|
|
663
753
|
return /* @__PURE__ */ jsx("div", {
|
|
664
754
|
className: rootClass,
|
|
665
755
|
"data-polyx-signin": step,
|
|
756
|
+
style: brandingStyle,
|
|
666
757
|
children: card
|
|
667
758
|
});
|
|
668
759
|
}
|
package/dist/styles.css
CHANGED
|
@@ -208,6 +208,13 @@
|
|
|
208
208
|
margin-bottom: 0.75rem;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
/* Branding logo fetched from the app's tokens (FR-BRND). */
|
|
212
|
+
.polyx-signin__brand-logo {
|
|
213
|
+
max-height: 2.25rem;
|
|
214
|
+
width: auto;
|
|
215
|
+
object-fit: contain;
|
|
216
|
+
}
|
|
217
|
+
|
|
211
218
|
.polyx-signin__heading {
|
|
212
219
|
margin: 0;
|
|
213
220
|
font-size: 1.375rem;
|
|
@@ -270,6 +277,56 @@
|
|
|
270
277
|
cursor: not-allowed;
|
|
271
278
|
}
|
|
272
279
|
|
|
280
|
+
/* --- Password reveal toggle --------------------------------------------- */
|
|
281
|
+
|
|
282
|
+
.polyx-signin__input-wrap {
|
|
283
|
+
position: relative;
|
|
284
|
+
display: flex;
|
|
285
|
+
align-items: center;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/* Leave room for the reveal button so masked text never slides under it. */
|
|
289
|
+
.polyx-signin__input--has-reveal {
|
|
290
|
+
padding-right: 2.75rem;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.polyx-signin__reveal {
|
|
294
|
+
position: absolute;
|
|
295
|
+
right: 0.25rem;
|
|
296
|
+
display: inline-flex;
|
|
297
|
+
align-items: center;
|
|
298
|
+
justify-content: center;
|
|
299
|
+
width: 2rem;
|
|
300
|
+
height: 2rem;
|
|
301
|
+
padding: 0;
|
|
302
|
+
color: var(--polyx-muted-fg);
|
|
303
|
+
background: transparent;
|
|
304
|
+
border: none;
|
|
305
|
+
border-radius: var(--polyx-radius-sm);
|
|
306
|
+
cursor: pointer;
|
|
307
|
+
transition: color 0.15s ease, box-shadow 0.15s ease;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.polyx-signin__reveal:hover:not(:disabled) {
|
|
311
|
+
color: var(--polyx-fg);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.polyx-signin__reveal:focus-visible {
|
|
315
|
+
outline: none;
|
|
316
|
+
color: var(--polyx-fg);
|
|
317
|
+
box-shadow: 0 0 0 3px var(--polyx-ring);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.polyx-signin__reveal:disabled {
|
|
321
|
+
cursor: not-allowed;
|
|
322
|
+
opacity: 0.6;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.polyx-signin__reveal svg {
|
|
326
|
+
width: 1.125rem;
|
|
327
|
+
height: 1.125rem;
|
|
328
|
+
}
|
|
329
|
+
|
|
273
330
|
/* --- Buttons ------------------------------------------------------------- */
|
|
274
331
|
|
|
275
332
|
.polyx-signin__submit,
|
|
@@ -339,6 +396,13 @@
|
|
|
339
396
|
opacity: 0.85;
|
|
340
397
|
}
|
|
341
398
|
|
|
399
|
+
/* "Forgot password?" link under the sign-in password field. */
|
|
400
|
+
.polyx-signin__forgot {
|
|
401
|
+
display: flex;
|
|
402
|
+
justify-content: flex-end;
|
|
403
|
+
margin-top: -0.5rem;
|
|
404
|
+
}
|
|
405
|
+
|
|
342
406
|
/* --- Recovery confirmation states (ForgotPassword / ResetPassword) ------- */
|
|
343
407
|
|
|
344
408
|
.polyx-signin__header--center {
|
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.9",
|
|
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.9"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"react": ">=18",
|