@poly-x/react 0.1.0-alpha.3 → 0.1.0-alpha.5
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 +167 -30
- package/dist/index.d.cts +20 -1
- package/dist/index.d.mts +20 -1
- package/dist/index.mjs +168 -31
- package/dist/styles.css +105 -15
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -355,6 +355,7 @@ function Protected({ children, fallback = null, loading = null }) {
|
|
|
355
355
|
const DEFAULT_LABELS = {
|
|
356
356
|
heading: "Sign in",
|
|
357
357
|
subheading: "Enter your credentials to continue.",
|
|
358
|
+
tagline: "",
|
|
358
359
|
emailLabel: "Email",
|
|
359
360
|
emailPlaceholder: "you@company.com",
|
|
360
361
|
passwordLabel: "Password",
|
|
@@ -363,11 +364,21 @@ const DEFAULT_LABELS = {
|
|
|
363
364
|
submitting: "Signing in…",
|
|
364
365
|
chooseWorkspace: "Choose a workspace",
|
|
365
366
|
chooseWorkspaceSubheading: "You have access to more than one workspace.",
|
|
367
|
+
securedBy: "Secured by PolyX",
|
|
368
|
+
setPasswordHeading: "Choose a new password",
|
|
369
|
+
setPasswordSubheading: "Your temporary password must be replaced before you continue.",
|
|
370
|
+
newPasswordLabel: "New password",
|
|
371
|
+
confirmPasswordLabel: "Confirm new password",
|
|
372
|
+
setPasswordSubmit: "Set password and sign in",
|
|
373
|
+
passwordMismatch: "Those passwords don't match.",
|
|
374
|
+
weakPassword: "Password must be at least 6 characters.",
|
|
366
375
|
invalidCredentials: "Invalid email or password.",
|
|
367
376
|
noAccess: "You don't have access to this application.",
|
|
368
377
|
passwordChangeRequired: "You must reset your password before you can sign in.",
|
|
369
378
|
genericError: "Something went wrong. Please try again."
|
|
370
379
|
};
|
|
380
|
+
/** Mirrors poly-auth's own floor (Joi: min 6). */
|
|
381
|
+
const MIN_PASSWORD_LENGTH = 6;
|
|
371
382
|
/**
|
|
372
383
|
* The embedded, Clerk-style sign-in form (D2b). Renders email/password inside the
|
|
373
384
|
* consuming app and POSTs to the SDK's BFF (`@poly-x/next` `authenticate`), which
|
|
@@ -387,10 +398,18 @@ function SignIn(props) {
|
|
|
387
398
|
};
|
|
388
399
|
const [email, setEmail] = (0, react.useState)("");
|
|
389
400
|
const [password, setPassword] = (0, react.useState)("");
|
|
401
|
+
const [newPassword, setNewPassword] = (0, react.useState)("");
|
|
402
|
+
const [confirmPassword, setConfirmPassword] = (0, react.useState)("");
|
|
403
|
+
const [mustSetPassword, setMustSetPassword] = (0, react.useState)(false);
|
|
390
404
|
const [tenants, setTenants] = (0, react.useState)(null);
|
|
391
405
|
const [submitting, setSubmitting] = (0, react.useState)(false);
|
|
392
406
|
const [error, setError] = (0, react.useState)(null);
|
|
393
|
-
|
|
407
|
+
/**
|
|
408
|
+
* One round-trip to the BFF. `tenantId` picks a workspace; `passwords` completes
|
|
409
|
+
* the temp-password flow (the BFF re-verifies the temporary password, sets the
|
|
410
|
+
* new one, and signs the user straight in).
|
|
411
|
+
*/
|
|
412
|
+
async function authenticate(options = {}) {
|
|
394
413
|
setSubmitting(true);
|
|
395
414
|
setError(null);
|
|
396
415
|
try {
|
|
@@ -401,7 +420,8 @@ function SignIn(props) {
|
|
|
401
420
|
email,
|
|
402
421
|
password,
|
|
403
422
|
organizationCode: props.organizationCode,
|
|
404
|
-
tenantId
|
|
423
|
+
tenantId: options.tenantId,
|
|
424
|
+
...options.passwords
|
|
405
425
|
})
|
|
406
426
|
})).json().catch(() => ({}));
|
|
407
427
|
switch (body.status) {
|
|
@@ -411,16 +431,22 @@ function SignIn(props) {
|
|
|
411
431
|
case "select_tenant":
|
|
412
432
|
setTenants(body.tenants ?? []);
|
|
413
433
|
return;
|
|
434
|
+
case "password_change_required":
|
|
435
|
+
setMustSetPassword(true);
|
|
436
|
+
if (body.userId) props.onPasswordChangeRequired?.(body.userId);
|
|
437
|
+
return;
|
|
438
|
+
case "password_mismatch":
|
|
439
|
+
setError(labels.passwordMismatch);
|
|
440
|
+
return;
|
|
441
|
+
case "weak_password":
|
|
442
|
+
setError(labels.weakPassword);
|
|
443
|
+
return;
|
|
414
444
|
case "invalid_credentials":
|
|
415
445
|
setError(labels.invalidCredentials);
|
|
416
446
|
return;
|
|
417
447
|
case "no_access":
|
|
418
448
|
setError(labels.noAccess);
|
|
419
449
|
return;
|
|
420
|
-
case "password_change_required":
|
|
421
|
-
setError(labels.passwordChangeRequired);
|
|
422
|
-
if (body.userId) props.onPasswordChangeRequired?.(body.userId);
|
|
423
|
-
return;
|
|
424
450
|
default:
|
|
425
451
|
setError(labels.genericError);
|
|
426
452
|
return;
|
|
@@ -435,26 +461,54 @@ function SignIn(props) {
|
|
|
435
461
|
event.preventDefault();
|
|
436
462
|
authenticate();
|
|
437
463
|
}
|
|
464
|
+
function onSetPasswordSubmit(event) {
|
|
465
|
+
event.preventDefault();
|
|
466
|
+
if (newPassword !== confirmPassword) {
|
|
467
|
+
setError(labels.passwordMismatch);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
authenticate({ passwords: {
|
|
471
|
+
newPassword,
|
|
472
|
+
confirmPassword
|
|
473
|
+
} });
|
|
474
|
+
}
|
|
475
|
+
const picking = tenants !== null;
|
|
476
|
+
const hasPanel = variant === "page";
|
|
477
|
+
const showHeaderLogo = Boolean(props.logo) && !hasPanel;
|
|
438
478
|
const rootClass = [
|
|
439
479
|
"polyx-signin",
|
|
440
480
|
`polyx-signin--${variant}`,
|
|
441
481
|
props.className
|
|
442
482
|
].filter(Boolean).join(" ");
|
|
443
|
-
const
|
|
483
|
+
const step = picking ? "select_tenant" : mustSetPassword ? "set_password" : "credentials";
|
|
484
|
+
const HEADINGS = {
|
|
485
|
+
credentials: {
|
|
486
|
+
heading: labels.heading,
|
|
487
|
+
subheading: labels.subheading
|
|
488
|
+
},
|
|
489
|
+
select_tenant: {
|
|
490
|
+
heading: labels.chooseWorkspace,
|
|
491
|
+
subheading: labels.chooseWorkspaceSubheading
|
|
492
|
+
},
|
|
493
|
+
set_password: {
|
|
494
|
+
heading: labels.setPasswordHeading,
|
|
495
|
+
subheading: labels.setPasswordSubheading
|
|
496
|
+
}
|
|
497
|
+
};
|
|
444
498
|
const header = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
445
499
|
className: "polyx-signin__header",
|
|
446
500
|
children: [
|
|
447
|
-
|
|
501
|
+
showHeaderLogo ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
448
502
|
className: "polyx-signin__logo",
|
|
449
503
|
children: props.logo
|
|
450
504
|
}) : null,
|
|
451
505
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
452
506
|
className: "polyx-signin__heading",
|
|
453
|
-
children:
|
|
507
|
+
children: HEADINGS[step].heading
|
|
454
508
|
}),
|
|
455
509
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
456
510
|
className: "polyx-signin__subheading",
|
|
457
|
-
children:
|
|
511
|
+
children: HEADINGS[step].subheading
|
|
458
512
|
})
|
|
459
513
|
]
|
|
460
514
|
});
|
|
@@ -463,24 +517,84 @@ function SignIn(props) {
|
|
|
463
517
|
className: "polyx-signin__error",
|
|
464
518
|
children: error
|
|
465
519
|
}) : null;
|
|
466
|
-
|
|
467
|
-
className:
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
520
|
+
const footer = props.showSecuredBy === false ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
521
|
+
className: "polyx-signin__footer",
|
|
522
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
523
|
+
className: "polyx-signin__shield",
|
|
524
|
+
viewBox: "0 0 16 16",
|
|
525
|
+
fill: "currentColor",
|
|
526
|
+
"aria-hidden": "true",
|
|
527
|
+
focusable: "false",
|
|
528
|
+
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" })
|
|
529
|
+
}), labels.securedBy]
|
|
530
|
+
});
|
|
531
|
+
const tenantPicker = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
532
|
+
className: "polyx-signin__form",
|
|
533
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
534
|
+
className: "polyx-signin__tenants",
|
|
535
|
+
children: (tenants ?? []).map((tenant) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
536
|
+
type: "button",
|
|
537
|
+
className: "polyx-signin__tenant",
|
|
538
|
+
disabled: submitting,
|
|
539
|
+
onClick: () => void authenticate({ tenantId: tenant.tenantId }),
|
|
540
|
+
children: tenant.name ?? tenant.slug ?? tenant.organizationCode ?? tenant.tenantId
|
|
541
|
+
}) }, tenant.tenantId))
|
|
542
|
+
}), errorNode]
|
|
543
|
+
});
|
|
544
|
+
const setPasswordForm = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
545
|
+
className: "polyx-signin__form",
|
|
546
|
+
onSubmit: onSetPasswordSubmit,
|
|
547
|
+
children: [
|
|
548
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
549
|
+
className: "polyx-signin__field",
|
|
550
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
551
|
+
className: "polyx-signin__label",
|
|
552
|
+
children: labels.newPasswordLabel
|
|
553
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
554
|
+
className: "polyx-signin__input",
|
|
555
|
+
type: "password",
|
|
556
|
+
name: "newPassword",
|
|
557
|
+
autoComplete: "new-password",
|
|
558
|
+
placeholder: labels.passwordPlaceholder,
|
|
559
|
+
required: true,
|
|
560
|
+
minLength: MIN_PASSWORD_LENGTH,
|
|
561
|
+
value: newPassword,
|
|
562
|
+
disabled: submitting,
|
|
563
|
+
onChange: (event) => setNewPassword(event.target.value)
|
|
564
|
+
})]
|
|
565
|
+
}),
|
|
566
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
567
|
+
className: "polyx-signin__field",
|
|
568
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
569
|
+
className: "polyx-signin__label",
|
|
570
|
+
children: labels.confirmPasswordLabel
|
|
571
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
572
|
+
className: "polyx-signin__input",
|
|
573
|
+
type: "password",
|
|
574
|
+
name: "confirmPassword",
|
|
575
|
+
autoComplete: "new-password",
|
|
576
|
+
placeholder: labels.passwordPlaceholder,
|
|
577
|
+
required: true,
|
|
578
|
+
minLength: MIN_PASSWORD_LENGTH,
|
|
579
|
+
value: confirmPassword,
|
|
580
|
+
disabled: submitting,
|
|
581
|
+
onChange: (event) => setConfirmPassword(event.target.value)
|
|
582
|
+
})]
|
|
583
|
+
}),
|
|
584
|
+
errorNode,
|
|
585
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
586
|
+
type: "submit",
|
|
587
|
+
className: "polyx-signin__submit",
|
|
588
|
+
disabled: submitting,
|
|
589
|
+
children: submitting ? labels.submitting : labels.setPasswordSubmit
|
|
590
|
+
})
|
|
591
|
+
]
|
|
592
|
+
});
|
|
593
|
+
const card = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
594
|
+
className: "polyx-signin__card",
|
|
595
|
+
children: [
|
|
596
|
+
header,
|
|
597
|
+
step === "select_tenant" ? tenantPicker : step === "set_password" ? setPasswordForm : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
484
598
|
className: "polyx-signin__form",
|
|
485
599
|
onSubmit,
|
|
486
600
|
children: [
|
|
@@ -526,8 +640,31 @@ function SignIn(props) {
|
|
|
526
640
|
children: submitting ? labels.submitting : labels.submit
|
|
527
641
|
})
|
|
528
642
|
]
|
|
529
|
-
})
|
|
530
|
-
|
|
643
|
+
}),
|
|
644
|
+
footer
|
|
645
|
+
]
|
|
646
|
+
});
|
|
647
|
+
if (variant === "page") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
648
|
+
className: rootClass,
|
|
649
|
+
"data-polyx-signin": step,
|
|
650
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("aside", {
|
|
651
|
+
className: "polyx-signin__panel",
|
|
652
|
+
children: props.panel ?? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [props.logo ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
653
|
+
className: "polyx-signin__panel-logo",
|
|
654
|
+
children: props.logo
|
|
655
|
+
}) : null, labels.tagline ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
656
|
+
className: "polyx-signin__tagline",
|
|
657
|
+
children: labels.tagline
|
|
658
|
+
}) : null] })
|
|
659
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
660
|
+
className: "polyx-signin__main",
|
|
661
|
+
children: card
|
|
662
|
+
})]
|
|
663
|
+
});
|
|
664
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
665
|
+
className: rootClass,
|
|
666
|
+
"data-polyx-signin": step,
|
|
667
|
+
children: card
|
|
531
668
|
});
|
|
532
669
|
}
|
|
533
670
|
//#endregion
|
package/dist/index.d.cts
CHANGED
|
@@ -195,6 +195,8 @@ declare function Protected({
|
|
|
195
195
|
interface SignInLabels {
|
|
196
196
|
heading: string;
|
|
197
197
|
subheading: string;
|
|
198
|
+
/** Headline on the `page` variant's brand panel. Empty renders a clean brand panel. */
|
|
199
|
+
tagline: string;
|
|
198
200
|
emailLabel: string;
|
|
199
201
|
emailPlaceholder: string;
|
|
200
202
|
passwordLabel: string;
|
|
@@ -203,6 +205,14 @@ interface SignInLabels {
|
|
|
203
205
|
submitting: string;
|
|
204
206
|
chooseWorkspace: string;
|
|
205
207
|
chooseWorkspaceSubheading: string;
|
|
208
|
+
securedBy: string;
|
|
209
|
+
setPasswordHeading: string;
|
|
210
|
+
setPasswordSubheading: string;
|
|
211
|
+
newPasswordLabel: string;
|
|
212
|
+
confirmPasswordLabel: string;
|
|
213
|
+
setPasswordSubmit: string;
|
|
214
|
+
passwordMismatch: string;
|
|
215
|
+
weakPassword: string;
|
|
206
216
|
invalidCredentials: string;
|
|
207
217
|
noAccess: string;
|
|
208
218
|
passwordChangeRequired: string;
|
|
@@ -210,12 +220,19 @@ interface SignInLabels {
|
|
|
210
220
|
}
|
|
211
221
|
/**
|
|
212
222
|
* `card` renders just the card — drop it into your own layout.
|
|
213
|
-
* `page` owns the viewport — a
|
|
223
|
+
* `page` owns the viewport — a split layout with a brand panel beside the form
|
|
224
|
+
* (the panel collapses away under 64rem, leaving the form on its own).
|
|
214
225
|
*/
|
|
215
226
|
type SignInVariant = "card" | "page";
|
|
216
227
|
interface SignInProps {
|
|
217
228
|
/** Layout preset. Default `card`. */
|
|
218
229
|
variant?: SignInVariant;
|
|
230
|
+
/**
|
|
231
|
+
* Content for the `page` variant's brand panel. Defaults to your `logo` plus
|
|
232
|
+
* `labels.tagline`; pass your own node to take the panel over completely.
|
|
233
|
+
* Ignored by the `card` variant.
|
|
234
|
+
*/
|
|
235
|
+
panel?: ReactNode;
|
|
219
236
|
/** BFF endpoint backed by `createAuthHandlers().authenticate`. Default `/api/polyx/authenticate`. */
|
|
220
237
|
action?: string;
|
|
221
238
|
/** Where to send the browser after success. Overrides the server's default redirect. */
|
|
@@ -224,6 +241,8 @@ interface SignInProps {
|
|
|
224
241
|
organizationCode?: string;
|
|
225
242
|
/** Rendered above the heading — your wordmark or logo. */
|
|
226
243
|
logo?: ReactNode;
|
|
244
|
+
/** Show the "Secured by PolyX" attribution under the form. Default true. */
|
|
245
|
+
showSecuredBy?: boolean;
|
|
227
246
|
/** Appended to the root element's class list, for escape-hatch styling. */
|
|
228
247
|
className?: string;
|
|
229
248
|
labels?: Partial<SignInLabels>;
|
package/dist/index.d.mts
CHANGED
|
@@ -195,6 +195,8 @@ declare function Protected({
|
|
|
195
195
|
interface SignInLabels {
|
|
196
196
|
heading: string;
|
|
197
197
|
subheading: string;
|
|
198
|
+
/** Headline on the `page` variant's brand panel. Empty renders a clean brand panel. */
|
|
199
|
+
tagline: string;
|
|
198
200
|
emailLabel: string;
|
|
199
201
|
emailPlaceholder: string;
|
|
200
202
|
passwordLabel: string;
|
|
@@ -203,6 +205,14 @@ interface SignInLabels {
|
|
|
203
205
|
submitting: string;
|
|
204
206
|
chooseWorkspace: string;
|
|
205
207
|
chooseWorkspaceSubheading: string;
|
|
208
|
+
securedBy: string;
|
|
209
|
+
setPasswordHeading: string;
|
|
210
|
+
setPasswordSubheading: string;
|
|
211
|
+
newPasswordLabel: string;
|
|
212
|
+
confirmPasswordLabel: string;
|
|
213
|
+
setPasswordSubmit: string;
|
|
214
|
+
passwordMismatch: string;
|
|
215
|
+
weakPassword: string;
|
|
206
216
|
invalidCredentials: string;
|
|
207
217
|
noAccess: string;
|
|
208
218
|
passwordChangeRequired: string;
|
|
@@ -210,12 +220,19 @@ interface SignInLabels {
|
|
|
210
220
|
}
|
|
211
221
|
/**
|
|
212
222
|
* `card` renders just the card — drop it into your own layout.
|
|
213
|
-
* `page` owns the viewport — a
|
|
223
|
+
* `page` owns the viewport — a split layout with a brand panel beside the form
|
|
224
|
+
* (the panel collapses away under 64rem, leaving the form on its own).
|
|
214
225
|
*/
|
|
215
226
|
type SignInVariant = "card" | "page";
|
|
216
227
|
interface SignInProps {
|
|
217
228
|
/** Layout preset. Default `card`. */
|
|
218
229
|
variant?: SignInVariant;
|
|
230
|
+
/**
|
|
231
|
+
* Content for the `page` variant's brand panel. Defaults to your `logo` plus
|
|
232
|
+
* `labels.tagline`; pass your own node to take the panel over completely.
|
|
233
|
+
* Ignored by the `card` variant.
|
|
234
|
+
*/
|
|
235
|
+
panel?: ReactNode;
|
|
219
236
|
/** BFF endpoint backed by `createAuthHandlers().authenticate`. Default `/api/polyx/authenticate`. */
|
|
220
237
|
action?: string;
|
|
221
238
|
/** Where to send the browser after success. Overrides the server's default redirect. */
|
|
@@ -224,6 +241,8 @@ interface SignInProps {
|
|
|
224
241
|
organizationCode?: string;
|
|
225
242
|
/** Rendered above the heading — your wordmark or logo. */
|
|
226
243
|
logo?: ReactNode;
|
|
244
|
+
/** Show the "Secured by PolyX" attribution under the form. Default true. */
|
|
245
|
+
showSecuredBy?: boolean;
|
|
227
246
|
/** Appended to the root element's class list, for escape-hatch styling. */
|
|
228
247
|
className?: string;
|
|
229
248
|
labels?: Partial<SignInLabels>;
|
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
3
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState, useSyncExternalStore } from "react";
|
|
4
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
//#region src/auth-channel.ts
|
|
6
6
|
var BroadcastAuthChannel = class {
|
|
7
7
|
supported;
|
|
@@ -354,6 +354,7 @@ function Protected({ children, fallback = null, loading = null }) {
|
|
|
354
354
|
const DEFAULT_LABELS = {
|
|
355
355
|
heading: "Sign in",
|
|
356
356
|
subheading: "Enter your credentials to continue.",
|
|
357
|
+
tagline: "",
|
|
357
358
|
emailLabel: "Email",
|
|
358
359
|
emailPlaceholder: "you@company.com",
|
|
359
360
|
passwordLabel: "Password",
|
|
@@ -362,11 +363,21 @@ const DEFAULT_LABELS = {
|
|
|
362
363
|
submitting: "Signing in…",
|
|
363
364
|
chooseWorkspace: "Choose a workspace",
|
|
364
365
|
chooseWorkspaceSubheading: "You have access to more than one workspace.",
|
|
366
|
+
securedBy: "Secured by PolyX",
|
|
367
|
+
setPasswordHeading: "Choose a new password",
|
|
368
|
+
setPasswordSubheading: "Your temporary password must be replaced before you continue.",
|
|
369
|
+
newPasswordLabel: "New password",
|
|
370
|
+
confirmPasswordLabel: "Confirm new password",
|
|
371
|
+
setPasswordSubmit: "Set password and sign in",
|
|
372
|
+
passwordMismatch: "Those passwords don't match.",
|
|
373
|
+
weakPassword: "Password must be at least 6 characters.",
|
|
365
374
|
invalidCredentials: "Invalid email or password.",
|
|
366
375
|
noAccess: "You don't have access to this application.",
|
|
367
376
|
passwordChangeRequired: "You must reset your password before you can sign in.",
|
|
368
377
|
genericError: "Something went wrong. Please try again."
|
|
369
378
|
};
|
|
379
|
+
/** Mirrors poly-auth's own floor (Joi: min 6). */
|
|
380
|
+
const MIN_PASSWORD_LENGTH = 6;
|
|
370
381
|
/**
|
|
371
382
|
* The embedded, Clerk-style sign-in form (D2b). Renders email/password inside the
|
|
372
383
|
* consuming app and POSTs to the SDK's BFF (`@poly-x/next` `authenticate`), which
|
|
@@ -386,10 +397,18 @@ function SignIn(props) {
|
|
|
386
397
|
};
|
|
387
398
|
const [email, setEmail] = useState("");
|
|
388
399
|
const [password, setPassword] = useState("");
|
|
400
|
+
const [newPassword, setNewPassword] = useState("");
|
|
401
|
+
const [confirmPassword, setConfirmPassword] = useState("");
|
|
402
|
+
const [mustSetPassword, setMustSetPassword] = useState(false);
|
|
389
403
|
const [tenants, setTenants] = useState(null);
|
|
390
404
|
const [submitting, setSubmitting] = useState(false);
|
|
391
405
|
const [error, setError] = useState(null);
|
|
392
|
-
|
|
406
|
+
/**
|
|
407
|
+
* One round-trip to the BFF. `tenantId` picks a workspace; `passwords` completes
|
|
408
|
+
* the temp-password flow (the BFF re-verifies the temporary password, sets the
|
|
409
|
+
* new one, and signs the user straight in).
|
|
410
|
+
*/
|
|
411
|
+
async function authenticate(options = {}) {
|
|
393
412
|
setSubmitting(true);
|
|
394
413
|
setError(null);
|
|
395
414
|
try {
|
|
@@ -400,7 +419,8 @@ function SignIn(props) {
|
|
|
400
419
|
email,
|
|
401
420
|
password,
|
|
402
421
|
organizationCode: props.organizationCode,
|
|
403
|
-
tenantId
|
|
422
|
+
tenantId: options.tenantId,
|
|
423
|
+
...options.passwords
|
|
404
424
|
})
|
|
405
425
|
})).json().catch(() => ({}));
|
|
406
426
|
switch (body.status) {
|
|
@@ -410,16 +430,22 @@ function SignIn(props) {
|
|
|
410
430
|
case "select_tenant":
|
|
411
431
|
setTenants(body.tenants ?? []);
|
|
412
432
|
return;
|
|
433
|
+
case "password_change_required":
|
|
434
|
+
setMustSetPassword(true);
|
|
435
|
+
if (body.userId) props.onPasswordChangeRequired?.(body.userId);
|
|
436
|
+
return;
|
|
437
|
+
case "password_mismatch":
|
|
438
|
+
setError(labels.passwordMismatch);
|
|
439
|
+
return;
|
|
440
|
+
case "weak_password":
|
|
441
|
+
setError(labels.weakPassword);
|
|
442
|
+
return;
|
|
413
443
|
case "invalid_credentials":
|
|
414
444
|
setError(labels.invalidCredentials);
|
|
415
445
|
return;
|
|
416
446
|
case "no_access":
|
|
417
447
|
setError(labels.noAccess);
|
|
418
448
|
return;
|
|
419
|
-
case "password_change_required":
|
|
420
|
-
setError(labels.passwordChangeRequired);
|
|
421
|
-
if (body.userId) props.onPasswordChangeRequired?.(body.userId);
|
|
422
|
-
return;
|
|
423
449
|
default:
|
|
424
450
|
setError(labels.genericError);
|
|
425
451
|
return;
|
|
@@ -434,26 +460,54 @@ function SignIn(props) {
|
|
|
434
460
|
event.preventDefault();
|
|
435
461
|
authenticate();
|
|
436
462
|
}
|
|
463
|
+
function onSetPasswordSubmit(event) {
|
|
464
|
+
event.preventDefault();
|
|
465
|
+
if (newPassword !== confirmPassword) {
|
|
466
|
+
setError(labels.passwordMismatch);
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
authenticate({ passwords: {
|
|
470
|
+
newPassword,
|
|
471
|
+
confirmPassword
|
|
472
|
+
} });
|
|
473
|
+
}
|
|
474
|
+
const picking = tenants !== null;
|
|
475
|
+
const hasPanel = variant === "page";
|
|
476
|
+
const showHeaderLogo = Boolean(props.logo) && !hasPanel;
|
|
437
477
|
const rootClass = [
|
|
438
478
|
"polyx-signin",
|
|
439
479
|
`polyx-signin--${variant}`,
|
|
440
480
|
props.className
|
|
441
481
|
].filter(Boolean).join(" ");
|
|
442
|
-
const
|
|
482
|
+
const step = picking ? "select_tenant" : mustSetPassword ? "set_password" : "credentials";
|
|
483
|
+
const HEADINGS = {
|
|
484
|
+
credentials: {
|
|
485
|
+
heading: labels.heading,
|
|
486
|
+
subheading: labels.subheading
|
|
487
|
+
},
|
|
488
|
+
select_tenant: {
|
|
489
|
+
heading: labels.chooseWorkspace,
|
|
490
|
+
subheading: labels.chooseWorkspaceSubheading
|
|
491
|
+
},
|
|
492
|
+
set_password: {
|
|
493
|
+
heading: labels.setPasswordHeading,
|
|
494
|
+
subheading: labels.setPasswordSubheading
|
|
495
|
+
}
|
|
496
|
+
};
|
|
443
497
|
const header = /* @__PURE__ */ jsxs("div", {
|
|
444
498
|
className: "polyx-signin__header",
|
|
445
499
|
children: [
|
|
446
|
-
|
|
500
|
+
showHeaderLogo ? /* @__PURE__ */ jsx("div", {
|
|
447
501
|
className: "polyx-signin__logo",
|
|
448
502
|
children: props.logo
|
|
449
503
|
}) : null,
|
|
450
504
|
/* @__PURE__ */ jsx("h1", {
|
|
451
505
|
className: "polyx-signin__heading",
|
|
452
|
-
children:
|
|
506
|
+
children: HEADINGS[step].heading
|
|
453
507
|
}),
|
|
454
508
|
/* @__PURE__ */ jsx("p", {
|
|
455
509
|
className: "polyx-signin__subheading",
|
|
456
|
-
children:
|
|
510
|
+
children: HEADINGS[step].subheading
|
|
457
511
|
})
|
|
458
512
|
]
|
|
459
513
|
});
|
|
@@ -462,24 +516,84 @@ function SignIn(props) {
|
|
|
462
516
|
className: "polyx-signin__error",
|
|
463
517
|
children: error
|
|
464
518
|
}) : null;
|
|
465
|
-
|
|
466
|
-
className:
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
519
|
+
const footer = props.showSecuredBy === false ? null : /* @__PURE__ */ jsxs("p", {
|
|
520
|
+
className: "polyx-signin__footer",
|
|
521
|
+
children: [/* @__PURE__ */ jsx("svg", {
|
|
522
|
+
className: "polyx-signin__shield",
|
|
523
|
+
viewBox: "0 0 16 16",
|
|
524
|
+
fill: "currentColor",
|
|
525
|
+
"aria-hidden": "true",
|
|
526
|
+
focusable: "false",
|
|
527
|
+
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" })
|
|
528
|
+
}), labels.securedBy]
|
|
529
|
+
});
|
|
530
|
+
const tenantPicker = /* @__PURE__ */ jsxs("div", {
|
|
531
|
+
className: "polyx-signin__form",
|
|
532
|
+
children: [/* @__PURE__ */ jsx("ul", {
|
|
533
|
+
className: "polyx-signin__tenants",
|
|
534
|
+
children: (tenants ?? []).map((tenant) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("button", {
|
|
535
|
+
type: "button",
|
|
536
|
+
className: "polyx-signin__tenant",
|
|
537
|
+
disabled: submitting,
|
|
538
|
+
onClick: () => void authenticate({ tenantId: tenant.tenantId }),
|
|
539
|
+
children: tenant.name ?? tenant.slug ?? tenant.organizationCode ?? tenant.tenantId
|
|
540
|
+
}) }, tenant.tenantId))
|
|
541
|
+
}), errorNode]
|
|
542
|
+
});
|
|
543
|
+
const setPasswordForm = /* @__PURE__ */ jsxs("form", {
|
|
544
|
+
className: "polyx-signin__form",
|
|
545
|
+
onSubmit: onSetPasswordSubmit,
|
|
546
|
+
children: [
|
|
547
|
+
/* @__PURE__ */ jsxs("label", {
|
|
548
|
+
className: "polyx-signin__field",
|
|
549
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
550
|
+
className: "polyx-signin__label",
|
|
551
|
+
children: labels.newPasswordLabel
|
|
552
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
553
|
+
className: "polyx-signin__input",
|
|
554
|
+
type: "password",
|
|
555
|
+
name: "newPassword",
|
|
556
|
+
autoComplete: "new-password",
|
|
557
|
+
placeholder: labels.passwordPlaceholder,
|
|
558
|
+
required: true,
|
|
559
|
+
minLength: MIN_PASSWORD_LENGTH,
|
|
560
|
+
value: newPassword,
|
|
561
|
+
disabled: submitting,
|
|
562
|
+
onChange: (event) => setNewPassword(event.target.value)
|
|
563
|
+
})]
|
|
564
|
+
}),
|
|
565
|
+
/* @__PURE__ */ jsxs("label", {
|
|
566
|
+
className: "polyx-signin__field",
|
|
567
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
568
|
+
className: "polyx-signin__label",
|
|
569
|
+
children: labels.confirmPasswordLabel
|
|
570
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
571
|
+
className: "polyx-signin__input",
|
|
572
|
+
type: "password",
|
|
573
|
+
name: "confirmPassword",
|
|
574
|
+
autoComplete: "new-password",
|
|
575
|
+
placeholder: labels.passwordPlaceholder,
|
|
576
|
+
required: true,
|
|
577
|
+
minLength: MIN_PASSWORD_LENGTH,
|
|
578
|
+
value: confirmPassword,
|
|
579
|
+
disabled: submitting,
|
|
580
|
+
onChange: (event) => setConfirmPassword(event.target.value)
|
|
581
|
+
})]
|
|
582
|
+
}),
|
|
583
|
+
errorNode,
|
|
584
|
+
/* @__PURE__ */ jsx("button", {
|
|
585
|
+
type: "submit",
|
|
586
|
+
className: "polyx-signin__submit",
|
|
587
|
+
disabled: submitting,
|
|
588
|
+
children: submitting ? labels.submitting : labels.setPasswordSubmit
|
|
589
|
+
})
|
|
590
|
+
]
|
|
591
|
+
});
|
|
592
|
+
const card = /* @__PURE__ */ jsxs("div", {
|
|
593
|
+
className: "polyx-signin__card",
|
|
594
|
+
children: [
|
|
595
|
+
header,
|
|
596
|
+
step === "select_tenant" ? tenantPicker : step === "set_password" ? setPasswordForm : /* @__PURE__ */ jsxs("form", {
|
|
483
597
|
className: "polyx-signin__form",
|
|
484
598
|
onSubmit,
|
|
485
599
|
children: [
|
|
@@ -525,8 +639,31 @@ function SignIn(props) {
|
|
|
525
639
|
children: submitting ? labels.submitting : labels.submit
|
|
526
640
|
})
|
|
527
641
|
]
|
|
528
|
-
})
|
|
529
|
-
|
|
642
|
+
}),
|
|
643
|
+
footer
|
|
644
|
+
]
|
|
645
|
+
});
|
|
646
|
+
if (variant === "page") return /* @__PURE__ */ jsxs("div", {
|
|
647
|
+
className: rootClass,
|
|
648
|
+
"data-polyx-signin": step,
|
|
649
|
+
children: [/* @__PURE__ */ jsx("aside", {
|
|
650
|
+
className: "polyx-signin__panel",
|
|
651
|
+
children: props.panel ?? /* @__PURE__ */ jsxs(Fragment, { children: [props.logo ? /* @__PURE__ */ jsx("div", {
|
|
652
|
+
className: "polyx-signin__panel-logo",
|
|
653
|
+
children: props.logo
|
|
654
|
+
}) : null, labels.tagline ? /* @__PURE__ */ jsx("p", {
|
|
655
|
+
className: "polyx-signin__tagline",
|
|
656
|
+
children: labels.tagline
|
|
657
|
+
}) : null] })
|
|
658
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
659
|
+
className: "polyx-signin__main",
|
|
660
|
+
children: card
|
|
661
|
+
})]
|
|
662
|
+
});
|
|
663
|
+
return /* @__PURE__ */ jsx("div", {
|
|
664
|
+
className: rootClass,
|
|
665
|
+
"data-polyx-signin": step,
|
|
666
|
+
children: card
|
|
530
667
|
});
|
|
531
668
|
}
|
|
532
669
|
//#endregion
|
package/dist/styles.css
CHANGED
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
--polyx-ring: #a5b4fc;
|
|
26
26
|
--polyx-danger: #dc2626;
|
|
27
27
|
--polyx-danger-bg: #fef2f2;
|
|
28
|
-
--polyx-page-bg: #
|
|
28
|
+
--polyx-page-bg: #ffffff;
|
|
29
|
+
/* The `page` variant's left panel — a quiet surface, a shade off the form side. */
|
|
30
|
+
--polyx-panel-bg: #fafafa;
|
|
31
|
+
--polyx-panel-fg: #18181b;
|
|
29
32
|
|
|
30
33
|
/* Shape + type */
|
|
31
34
|
--polyx-radius: 0.75rem;
|
|
@@ -59,7 +62,9 @@
|
|
|
59
62
|
--polyx-ring: #4f46e5;
|
|
60
63
|
--polyx-danger: #f87171;
|
|
61
64
|
--polyx-danger-bg: #2a1616;
|
|
62
|
-
--polyx-page-bg: #
|
|
65
|
+
--polyx-page-bg: #18181b;
|
|
66
|
+
--polyx-panel-bg: #09090b;
|
|
67
|
+
--polyx-panel-fg: #fafafa;
|
|
63
68
|
--polyx-shadow: 0 1px 3px rgb(0 0 0 / 0.4), 0 10px 30px rgb(0 0 0 / 0.35);
|
|
64
69
|
}
|
|
65
70
|
}
|
|
@@ -77,7 +82,9 @@
|
|
|
77
82
|
--polyx-ring: #4f46e5;
|
|
78
83
|
--polyx-danger: #f87171;
|
|
79
84
|
--polyx-danger-bg: #2a1616;
|
|
80
|
-
--polyx-page-bg: #
|
|
85
|
+
--polyx-page-bg: #18181b;
|
|
86
|
+
--polyx-panel-bg: #09090b;
|
|
87
|
+
--polyx-panel-fg: #fafafa;
|
|
81
88
|
--polyx-shadow: 0 1px 3px rgb(0 0 0 / 0.4), 0 10px 30px rgb(0 0 0 / 0.35);
|
|
82
89
|
}
|
|
83
90
|
|
|
@@ -92,21 +99,14 @@
|
|
|
92
99
|
--polyx-ring: #a5b4fc;
|
|
93
100
|
--polyx-danger: #dc2626;
|
|
94
101
|
--polyx-danger-bg: #fef2f2;
|
|
95
|
-
--polyx-page-bg: #
|
|
102
|
+
--polyx-page-bg: #ffffff;
|
|
103
|
+
--polyx-panel-bg: #fafafa;
|
|
104
|
+
--polyx-panel-fg: #18181b;
|
|
96
105
|
--polyx-shadow: 0 1px 3px rgb(0 0 0 / 0.06), 0 10px 30px rgb(0 0 0 / 0.07);
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
/* --- Variants ------------------------------------------------------------ */
|
|
100
109
|
|
|
101
|
-
/* `page`: owns the viewport — centered card on a full-bleed background. */
|
|
102
|
-
.polyx-signin--page {
|
|
103
|
-
display: grid;
|
|
104
|
-
place-items: center;
|
|
105
|
-
min-height: 100dvh;
|
|
106
|
-
padding: 1.5rem;
|
|
107
|
-
background: var(--polyx-page-bg);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
110
|
/* `card`: just the card — drop it anywhere in your own layout. */
|
|
111
111
|
.polyx-signin--card {
|
|
112
112
|
display: block;
|
|
@@ -114,15 +114,86 @@
|
|
|
114
114
|
|
|
115
115
|
.polyx-signin__card {
|
|
116
116
|
width: 100%;
|
|
117
|
-
max-width:
|
|
117
|
+
max-width: 27rem;
|
|
118
118
|
margin-inline: auto;
|
|
119
|
-
padding:
|
|
119
|
+
padding: 2.25rem;
|
|
120
120
|
background: var(--polyx-bg);
|
|
121
121
|
border: 1px solid var(--polyx-border);
|
|
122
122
|
border-radius: var(--polyx-radius);
|
|
123
123
|
box-shadow: var(--polyx-shadow);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
/**
|
|
127
|
+
* `page`: owns the viewport — a left/right split. The form sits on the right; the
|
|
128
|
+
* left is a quiet surface holding whatever the consumer gives it (a `logo`, a
|
|
129
|
+
* `tagline`, or a custom `panel`). Deliberately minimal: no gradient, no invented
|
|
130
|
+
* copy. An empty panel reads as intentional negative space, and never fights the
|
|
131
|
+
* host app's brand. Below 64rem the panel drops away entirely and the form takes
|
|
132
|
+
* the screen on its own.
|
|
133
|
+
*/
|
|
134
|
+
.polyx-signin--page {
|
|
135
|
+
display: grid;
|
|
136
|
+
grid-template-columns: 1fr;
|
|
137
|
+
min-height: 100dvh;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@media (min-width: 64rem) {
|
|
141
|
+
.polyx-signin--page {
|
|
142
|
+
grid-template-columns: 1fr 1fr;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.polyx-signin__panel {
|
|
147
|
+
display: none;
|
|
148
|
+
flex-direction: column;
|
|
149
|
+
justify-content: space-between;
|
|
150
|
+
gap: 2rem;
|
|
151
|
+
padding: 3.5rem;
|
|
152
|
+
color: var(--polyx-panel-fg);
|
|
153
|
+
background: var(--polyx-panel-bg);
|
|
154
|
+
border-right: 1px solid var(--polyx-border);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@media (min-width: 64rem) {
|
|
158
|
+
.polyx-signin__panel {
|
|
159
|
+
display: flex;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* The tagline is the panel's headline — it only earns its space on wide screens. */
|
|
164
|
+
.polyx-signin__tagline {
|
|
165
|
+
display: none;
|
|
166
|
+
margin: 0;
|
|
167
|
+
max-width: 18ch;
|
|
168
|
+
font-size: 2rem;
|
|
169
|
+
font-weight: 600;
|
|
170
|
+
line-height: 1.2;
|
|
171
|
+
letter-spacing: -0.02em;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@media (min-width: 64rem) {
|
|
175
|
+
.polyx-signin__tagline {
|
|
176
|
+
display: block;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.polyx-signin__main {
|
|
181
|
+
display: grid;
|
|
182
|
+
place-items: center;
|
|
183
|
+
padding: 2.5rem 1.5rem;
|
|
184
|
+
background: var(--polyx-page-bg);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* On the page variant the form isn't a floating card — it sits on the page itself. */
|
|
188
|
+
.polyx-signin--page .polyx-signin__card {
|
|
189
|
+
max-width: 25rem;
|
|
190
|
+
padding: 0;
|
|
191
|
+
background: transparent;
|
|
192
|
+
border: none;
|
|
193
|
+
box-shadow: none;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
126
197
|
/* --- Header -------------------------------------------------------------- */
|
|
127
198
|
|
|
128
199
|
.polyx-signin__header {
|
|
@@ -249,6 +320,25 @@
|
|
|
249
320
|
border-radius: var(--polyx-radius-sm);
|
|
250
321
|
}
|
|
251
322
|
|
|
323
|
+
/* --- Footer -------------------------------------------------------------- */
|
|
324
|
+
|
|
325
|
+
.polyx-signin__footer {
|
|
326
|
+
display: flex;
|
|
327
|
+
align-items: center;
|
|
328
|
+
justify-content: center;
|
|
329
|
+
gap: 0.375rem;
|
|
330
|
+
margin-top: 1.5rem;
|
|
331
|
+
font-size: 0.75rem;
|
|
332
|
+
color: var(--polyx-muted-fg);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.polyx-signin__shield {
|
|
336
|
+
flex: none;
|
|
337
|
+
width: 0.875rem;
|
|
338
|
+
height: 0.875rem;
|
|
339
|
+
opacity: 0.85;
|
|
340
|
+
}
|
|
341
|
+
|
|
252
342
|
/* --- Workspace picker ---------------------------------------------------- */
|
|
253
343
|
|
|
254
344
|
.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.5",
|
|
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.5"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"react": ">=18",
|