@poly-x/react 0.1.0-alpha.2 → 0.1.0-alpha.3

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 CHANGED
@@ -353,11 +353,16 @@ function Protected({ children, fallback = null, loading = null }) {
353
353
  //#endregion
354
354
  //#region src/components/sign-in.tsx
355
355
  const DEFAULT_LABELS = {
356
+ heading: "Sign in",
357
+ subheading: "Enter your credentials to continue.",
356
358
  emailLabel: "Email",
359
+ emailPlaceholder: "you@company.com",
357
360
  passwordLabel: "Password",
361
+ passwordPlaceholder: "••••••••",
358
362
  submit: "Sign in",
359
363
  submitting: "Signing in…",
360
364
  chooseWorkspace: "Choose a workspace",
365
+ chooseWorkspaceSubheading: "You have access to more than one workspace.",
361
366
  invalidCredentials: "Invalid email or password.",
362
367
  noAccess: "You don't have access to this application.",
363
368
  passwordChangeRequired: "You must reset your password before you can sign in.",
@@ -369,9 +374,13 @@ const DEFAULT_LABELS = {
369
374
  * runs the credential authorize server-side and seals an httpOnly session — no
370
375
  * redirect to a hosted PolyX login page, no tokens or credentials in the browser
371
376
  * after submit. Handles the workspace picker (select_tenant) inline.
377
+ *
378
+ * Ships styled: `import "@poly-x/react/styles.css"` once, then theme it by
379
+ * overriding the `--polyx-*` custom properties on any ancestor.
372
380
  */
373
381
  function SignIn(props) {
374
382
  const action = props.action ?? "/api/polyx/authenticate";
383
+ const variant = props.variant ?? "card";
375
384
  const labels = {
376
385
  ...DEFAULT_LABELS,
377
386
  ...props.labels
@@ -426,73 +435,100 @@ function SignIn(props) {
426
435
  event.preventDefault();
427
436
  authenticate();
428
437
  }
429
- if (tenants) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
430
- className: props.className,
431
- "data-polyx-signin": "select-tenant",
438
+ const rootClass = [
439
+ "polyx-signin",
440
+ `polyx-signin--${variant}`,
441
+ props.className
442
+ ].filter(Boolean).join(" ");
443
+ const picking = tenants !== null;
444
+ const header = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
445
+ className: "polyx-signin__header",
432
446
  children: [
433
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
447
+ props.logo ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
448
+ className: "polyx-signin__logo",
449
+ children: props.logo
450
+ }) : null,
451
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
434
452
  className: "polyx-signin__heading",
435
- children: labels.chooseWorkspace
436
- }),
437
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
438
- className: "polyx-signin__tenants",
439
- children: tenants.map((tenant) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
440
- type: "button",
441
- className: "polyx-signin__tenant",
442
- disabled: submitting,
443
- onClick: () => void authenticate(tenant.tenantId),
444
- children: tenant.name ?? tenant.slug ?? tenant.organizationCode ?? tenant.tenantId
445
- }) }, tenant.tenantId))
453
+ children: picking ? labels.chooseWorkspace : labels.heading
446
454
  }),
447
- error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
448
- role: "alert",
449
- className: "polyx-signin__error",
450
- children: error
451
- }) : null
452
- ]
453
- });
454
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
455
- className: props.className,
456
- "data-polyx-signin": "credentials",
457
- onSubmit,
458
- children: [
459
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
460
- className: "polyx-signin__field",
461
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: labels.emailLabel }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
462
- type: "email",
463
- name: "email",
464
- autoComplete: "username",
465
- required: true,
466
- value: email,
467
- disabled: submitting,
468
- onChange: (event) => setEmail(event.target.value)
469
- })]
470
- }),
471
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
472
- className: "polyx-signin__field",
473
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: labels.passwordLabel }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
474
- type: "password",
475
- name: "password",
476
- autoComplete: "current-password",
477
- required: true,
478
- value: password,
479
- disabled: submitting,
480
- onChange: (event) => setPassword(event.target.value)
481
- })]
482
- }),
483
- error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
484
- role: "alert",
485
- className: "polyx-signin__error",
486
- children: error
487
- }) : null,
488
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
489
- type: "submit",
490
- className: "polyx-signin__submit",
491
- disabled: submitting,
492
- children: submitting ? labels.submitting : labels.submit
455
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
456
+ className: "polyx-signin__subheading",
457
+ children: picking ? labels.chooseWorkspaceSubheading : labels.subheading
493
458
  })
494
459
  ]
495
460
  });
461
+ const errorNode = error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
462
+ role: "alert",
463
+ className: "polyx-signin__error",
464
+ children: error
465
+ }) : null;
466
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
467
+ className: rootClass,
468
+ "data-polyx-signin": picking ? "select-tenant" : "credentials",
469
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
470
+ className: "polyx-signin__card",
471
+ children: [header, picking ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
472
+ className: "polyx-signin__form",
473
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
474
+ className: "polyx-signin__tenants",
475
+ children: tenants.map((tenant) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
476
+ type: "button",
477
+ className: "polyx-signin__tenant",
478
+ disabled: submitting,
479
+ onClick: () => void authenticate(tenant.tenantId),
480
+ children: tenant.name ?? tenant.slug ?? tenant.organizationCode ?? tenant.tenantId
481
+ }) }, tenant.tenantId))
482
+ }), errorNode]
483
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
484
+ className: "polyx-signin__form",
485
+ onSubmit,
486
+ children: [
487
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
488
+ className: "polyx-signin__field",
489
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
490
+ className: "polyx-signin__label",
491
+ children: labels.emailLabel
492
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
493
+ className: "polyx-signin__input",
494
+ type: "email",
495
+ name: "email",
496
+ autoComplete: "username",
497
+ placeholder: labels.emailPlaceholder,
498
+ required: true,
499
+ value: email,
500
+ disabled: submitting,
501
+ onChange: (event) => setEmail(event.target.value)
502
+ })]
503
+ }),
504
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
505
+ className: "polyx-signin__field",
506
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
507
+ className: "polyx-signin__label",
508
+ children: labels.passwordLabel
509
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
510
+ className: "polyx-signin__input",
511
+ type: "password",
512
+ name: "password",
513
+ autoComplete: "current-password",
514
+ placeholder: labels.passwordPlaceholder,
515
+ required: true,
516
+ value: password,
517
+ disabled: submitting,
518
+ onChange: (event) => setPassword(event.target.value)
519
+ })]
520
+ }),
521
+ errorNode,
522
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
523
+ type: "submit",
524
+ className: "polyx-signin__submit",
525
+ disabled: submitting,
526
+ children: submitting ? labels.submitting : labels.submit
527
+ })
528
+ ]
529
+ })]
530
+ })
531
+ });
496
532
  }
497
533
  //#endregion
498
534
  //#region src/components/auth-callback.tsx
package/dist/index.d.cts CHANGED
@@ -193,24 +193,38 @@ declare function Protected({
193
193
  //#region src/components/sign-in.d.ts
194
194
  /** Every user-facing string, overridable for i18n / white-labelling. */
195
195
  interface SignInLabels {
196
+ heading: string;
197
+ subheading: string;
196
198
  emailLabel: string;
199
+ emailPlaceholder: string;
197
200
  passwordLabel: string;
201
+ passwordPlaceholder: string;
198
202
  submit: string;
199
203
  submitting: string;
200
204
  chooseWorkspace: string;
205
+ chooseWorkspaceSubheading: string;
201
206
  invalidCredentials: string;
202
207
  noAccess: string;
203
208
  passwordChangeRequired: string;
204
209
  genericError: string;
205
210
  }
211
+ /**
212
+ * `card` renders just the card — drop it into your own layout.
213
+ * `page` owns the viewport — a centered card on a full-bleed background.
214
+ */
215
+ type SignInVariant = "card" | "page";
206
216
  interface SignInProps {
217
+ /** Layout preset. Default `card`. */
218
+ variant?: SignInVariant;
207
219
  /** BFF endpoint backed by `createAuthHandlers().authenticate`. Default `/api/polyx/authenticate`. */
208
220
  action?: string;
209
221
  /** Where to send the browser after success. Overrides the server's default redirect. */
210
222
  afterSignInPath?: string;
211
223
  /** Pre-scope the login to a single organization (skips org discovery). */
212
224
  organizationCode?: string;
213
- /** Applied to the root `<form>` / picker container style via your own CSS. */
225
+ /** Rendered above the headingyour wordmark or logo. */
226
+ logo?: ReactNode;
227
+ /** Appended to the root element's class list, for escape-hatch styling. */
214
228
  className?: string;
215
229
  labels?: Partial<SignInLabels>;
216
230
  /** Fired when the backend requires the user to set a new password before continuing. */
@@ -222,6 +236,9 @@ interface SignInProps {
222
236
  * runs the credential authorize server-side and seals an httpOnly session — no
223
237
  * redirect to a hosted PolyX login page, no tokens or credentials in the browser
224
238
  * after submit. Handles the workspace picker (select_tenant) inline.
239
+ *
240
+ * Ships styled: `import "@poly-x/react/styles.css"` once, then theme it by
241
+ * overriding the `--polyx-*` custom properties on any ancestor.
225
242
  */
226
243
  declare function SignIn(props: SignInProps): ReactNode;
227
244
  //#endregion
@@ -243,4 +260,4 @@ declare function AuthCallback({
243
260
  declare const PACKAGE_NAME = "@poly-x/react";
244
261
  declare const version = "0.0.0";
245
262
  //#endregion
246
- 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 UseAuth, WebLocksLock, WindowBrowserBridge, createLoginController, useAuth, useAuthCallback, useSession, useUser, version };
263
+ 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 };
package/dist/index.d.mts CHANGED
@@ -193,24 +193,38 @@ declare function Protected({
193
193
  //#region src/components/sign-in.d.ts
194
194
  /** Every user-facing string, overridable for i18n / white-labelling. */
195
195
  interface SignInLabels {
196
+ heading: string;
197
+ subheading: string;
196
198
  emailLabel: string;
199
+ emailPlaceholder: string;
197
200
  passwordLabel: string;
201
+ passwordPlaceholder: string;
198
202
  submit: string;
199
203
  submitting: string;
200
204
  chooseWorkspace: string;
205
+ chooseWorkspaceSubheading: string;
201
206
  invalidCredentials: string;
202
207
  noAccess: string;
203
208
  passwordChangeRequired: string;
204
209
  genericError: string;
205
210
  }
211
+ /**
212
+ * `card` renders just the card — drop it into your own layout.
213
+ * `page` owns the viewport — a centered card on a full-bleed background.
214
+ */
215
+ type SignInVariant = "card" | "page";
206
216
  interface SignInProps {
217
+ /** Layout preset. Default `card`. */
218
+ variant?: SignInVariant;
207
219
  /** BFF endpoint backed by `createAuthHandlers().authenticate`. Default `/api/polyx/authenticate`. */
208
220
  action?: string;
209
221
  /** Where to send the browser after success. Overrides the server's default redirect. */
210
222
  afterSignInPath?: string;
211
223
  /** Pre-scope the login to a single organization (skips org discovery). */
212
224
  organizationCode?: string;
213
- /** Applied to the root `<form>` / picker container style via your own CSS. */
225
+ /** Rendered above the headingyour wordmark or logo. */
226
+ logo?: ReactNode;
227
+ /** Appended to the root element's class list, for escape-hatch styling. */
214
228
  className?: string;
215
229
  labels?: Partial<SignInLabels>;
216
230
  /** Fired when the backend requires the user to set a new password before continuing. */
@@ -222,6 +236,9 @@ interface SignInProps {
222
236
  * runs the credential authorize server-side and seals an httpOnly session — no
223
237
  * redirect to a hosted PolyX login page, no tokens or credentials in the browser
224
238
  * after submit. Handles the workspace picker (select_tenant) inline.
239
+ *
240
+ * Ships styled: `import "@poly-x/react/styles.css"` once, then theme it by
241
+ * overriding the `--polyx-*` custom properties on any ancestor.
225
242
  */
226
243
  declare function SignIn(props: SignInProps): ReactNode;
227
244
  //#endregion
@@ -243,4 +260,4 @@ declare function AuthCallback({
243
260
  declare const PACKAGE_NAME = "@poly-x/react";
244
261
  declare const version = "0.0.0";
245
262
  //#endregion
246
- 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 UseAuth, WebLocksLock, WindowBrowserBridge, createLoginController, useAuth, useAuthCallback, useSession, useUser, version };
263
+ 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 };
package/dist/index.mjs CHANGED
@@ -352,11 +352,16 @@ function Protected({ children, fallback = null, loading = null }) {
352
352
  //#endregion
353
353
  //#region src/components/sign-in.tsx
354
354
  const DEFAULT_LABELS = {
355
+ heading: "Sign in",
356
+ subheading: "Enter your credentials to continue.",
355
357
  emailLabel: "Email",
358
+ emailPlaceholder: "you@company.com",
356
359
  passwordLabel: "Password",
360
+ passwordPlaceholder: "••••••••",
357
361
  submit: "Sign in",
358
362
  submitting: "Signing in…",
359
363
  chooseWorkspace: "Choose a workspace",
364
+ chooseWorkspaceSubheading: "You have access to more than one workspace.",
360
365
  invalidCredentials: "Invalid email or password.",
361
366
  noAccess: "You don't have access to this application.",
362
367
  passwordChangeRequired: "You must reset your password before you can sign in.",
@@ -368,9 +373,13 @@ const DEFAULT_LABELS = {
368
373
  * runs the credential authorize server-side and seals an httpOnly session — no
369
374
  * redirect to a hosted PolyX login page, no tokens or credentials in the browser
370
375
  * after submit. Handles the workspace picker (select_tenant) inline.
376
+ *
377
+ * Ships styled: `import "@poly-x/react/styles.css"` once, then theme it by
378
+ * overriding the `--polyx-*` custom properties on any ancestor.
371
379
  */
372
380
  function SignIn(props) {
373
381
  const action = props.action ?? "/api/polyx/authenticate";
382
+ const variant = props.variant ?? "card";
374
383
  const labels = {
375
384
  ...DEFAULT_LABELS,
376
385
  ...props.labels
@@ -425,73 +434,100 @@ function SignIn(props) {
425
434
  event.preventDefault();
426
435
  authenticate();
427
436
  }
428
- if (tenants) return /* @__PURE__ */ jsxs("div", {
429
- className: props.className,
430
- "data-polyx-signin": "select-tenant",
437
+ const rootClass = [
438
+ "polyx-signin",
439
+ `polyx-signin--${variant}`,
440
+ props.className
441
+ ].filter(Boolean).join(" ");
442
+ const picking = tenants !== null;
443
+ const header = /* @__PURE__ */ jsxs("div", {
444
+ className: "polyx-signin__header",
431
445
  children: [
432
- /* @__PURE__ */ jsx("p", {
446
+ props.logo ? /* @__PURE__ */ jsx("div", {
447
+ className: "polyx-signin__logo",
448
+ children: props.logo
449
+ }) : null,
450
+ /* @__PURE__ */ jsx("h1", {
433
451
  className: "polyx-signin__heading",
434
- children: labels.chooseWorkspace
435
- }),
436
- /* @__PURE__ */ jsx("ul", {
437
- className: "polyx-signin__tenants",
438
- children: tenants.map((tenant) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("button", {
439
- type: "button",
440
- className: "polyx-signin__tenant",
441
- disabled: submitting,
442
- onClick: () => void authenticate(tenant.tenantId),
443
- children: tenant.name ?? tenant.slug ?? tenant.organizationCode ?? tenant.tenantId
444
- }) }, tenant.tenantId))
452
+ children: picking ? labels.chooseWorkspace : labels.heading
445
453
  }),
446
- error ? /* @__PURE__ */ jsx("p", {
447
- role: "alert",
448
- className: "polyx-signin__error",
449
- children: error
450
- }) : null
451
- ]
452
- });
453
- return /* @__PURE__ */ jsxs("form", {
454
- className: props.className,
455
- "data-polyx-signin": "credentials",
456
- onSubmit,
457
- children: [
458
- /* @__PURE__ */ jsxs("label", {
459
- className: "polyx-signin__field",
460
- children: [/* @__PURE__ */ jsx("span", { children: labels.emailLabel }), /* @__PURE__ */ jsx("input", {
461
- type: "email",
462
- name: "email",
463
- autoComplete: "username",
464
- required: true,
465
- value: email,
466
- disabled: submitting,
467
- onChange: (event) => setEmail(event.target.value)
468
- })]
469
- }),
470
- /* @__PURE__ */ jsxs("label", {
471
- className: "polyx-signin__field",
472
- children: [/* @__PURE__ */ jsx("span", { children: labels.passwordLabel }), /* @__PURE__ */ jsx("input", {
473
- type: "password",
474
- name: "password",
475
- autoComplete: "current-password",
476
- required: true,
477
- value: password,
478
- disabled: submitting,
479
- onChange: (event) => setPassword(event.target.value)
480
- })]
481
- }),
482
- error ? /* @__PURE__ */ jsx("p", {
483
- role: "alert",
484
- className: "polyx-signin__error",
485
- children: error
486
- }) : null,
487
- /* @__PURE__ */ jsx("button", {
488
- type: "submit",
489
- className: "polyx-signin__submit",
490
- disabled: submitting,
491
- children: submitting ? labels.submitting : labels.submit
454
+ /* @__PURE__ */ jsx("p", {
455
+ className: "polyx-signin__subheading",
456
+ children: picking ? labels.chooseWorkspaceSubheading : labels.subheading
492
457
  })
493
458
  ]
494
459
  });
460
+ const errorNode = error ? /* @__PURE__ */ jsx("p", {
461
+ role: "alert",
462
+ className: "polyx-signin__error",
463
+ children: error
464
+ }) : null;
465
+ return /* @__PURE__ */ jsx("div", {
466
+ className: rootClass,
467
+ "data-polyx-signin": picking ? "select-tenant" : "credentials",
468
+ children: /* @__PURE__ */ jsxs("div", {
469
+ className: "polyx-signin__card",
470
+ children: [header, picking ? /* @__PURE__ */ jsxs("div", {
471
+ className: "polyx-signin__form",
472
+ children: [/* @__PURE__ */ jsx("ul", {
473
+ className: "polyx-signin__tenants",
474
+ children: tenants.map((tenant) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("button", {
475
+ type: "button",
476
+ className: "polyx-signin__tenant",
477
+ disabled: submitting,
478
+ onClick: () => void authenticate(tenant.tenantId),
479
+ children: tenant.name ?? tenant.slug ?? tenant.organizationCode ?? tenant.tenantId
480
+ }) }, tenant.tenantId))
481
+ }), errorNode]
482
+ }) : /* @__PURE__ */ jsxs("form", {
483
+ className: "polyx-signin__form",
484
+ onSubmit,
485
+ children: [
486
+ /* @__PURE__ */ jsxs("label", {
487
+ className: "polyx-signin__field",
488
+ children: [/* @__PURE__ */ jsx("span", {
489
+ className: "polyx-signin__label",
490
+ children: labels.emailLabel
491
+ }), /* @__PURE__ */ jsx("input", {
492
+ className: "polyx-signin__input",
493
+ type: "email",
494
+ name: "email",
495
+ autoComplete: "username",
496
+ placeholder: labels.emailPlaceholder,
497
+ required: true,
498
+ value: email,
499
+ disabled: submitting,
500
+ onChange: (event) => setEmail(event.target.value)
501
+ })]
502
+ }),
503
+ /* @__PURE__ */ jsxs("label", {
504
+ className: "polyx-signin__field",
505
+ children: [/* @__PURE__ */ jsx("span", {
506
+ className: "polyx-signin__label",
507
+ children: labels.passwordLabel
508
+ }), /* @__PURE__ */ jsx("input", {
509
+ className: "polyx-signin__input",
510
+ type: "password",
511
+ name: "password",
512
+ autoComplete: "current-password",
513
+ placeholder: labels.passwordPlaceholder,
514
+ required: true,
515
+ value: password,
516
+ disabled: submitting,
517
+ onChange: (event) => setPassword(event.target.value)
518
+ })]
519
+ }),
520
+ errorNode,
521
+ /* @__PURE__ */ jsx("button", {
522
+ type: "submit",
523
+ className: "polyx-signin__submit",
524
+ disabled: submitting,
525
+ children: submitting ? labels.submitting : labels.submit
526
+ })
527
+ ]
528
+ })]
529
+ })
530
+ });
495
531
  }
496
532
  //#endregion
497
533
  //#region src/components/auth-callback.tsx
@@ -0,0 +1,274 @@
1
+ /**
2
+ * @poly-x/react — default component styles.
3
+ *
4
+ * Import once, near the root of your app:
5
+ * import "@poly-x/react/styles.css"; // or "@poly-x/next/styles.css"
6
+ *
7
+ * The SDK is a guest in your app: every rule is scoped under a `.polyx-*` class,
8
+ * there are no global element selectors, and nothing here leaks into your own
9
+ * markup. To theme it, override the custom properties below on any ancestor
10
+ * (`:root`, a wrapper div, …) — that is the supported theming surface. Dark mode
11
+ * follows the OS by default and defers to an explicit `.dark` / `[data-theme]`
12
+ * on a host ancestor when one is present.
13
+ */
14
+
15
+ .polyx-signin {
16
+ /* Colors */
17
+ --polyx-brand: #4f46e5;
18
+ --polyx-brand-hover: #4338ca;
19
+ --polyx-brand-fg: #ffffff;
20
+ --polyx-bg: #ffffff;
21
+ --polyx-fg: #18181b;
22
+ --polyx-muted-fg: #71717a;
23
+ --polyx-border: #e4e4e7;
24
+ --polyx-input-bg: #ffffff;
25
+ --polyx-ring: #a5b4fc;
26
+ --polyx-danger: #dc2626;
27
+ --polyx-danger-bg: #fef2f2;
28
+ --polyx-page-bg: #fafafa;
29
+
30
+ /* Shape + type */
31
+ --polyx-radius: 0.75rem;
32
+ --polyx-radius-sm: 0.5rem;
33
+ --polyx-font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
34
+ --polyx-shadow: 0 1px 3px rgb(0 0 0 / 0.06), 0 10px 30px rgb(0 0 0 / 0.07);
35
+
36
+ font-family: var(--polyx-font);
37
+ color: var(--polyx-fg);
38
+ -webkit-font-smoothing: antialiased;
39
+ }
40
+
41
+ /* Scoped box model — applies only inside our own subtree. */
42
+ .polyx-signin,
43
+ .polyx-signin *,
44
+ .polyx-signin *::before,
45
+ .polyx-signin *::after {
46
+ box-sizing: border-box;
47
+ }
48
+
49
+ /* Dark: follow the OS… */
50
+ @media (prefers-color-scheme: dark) {
51
+ .polyx-signin {
52
+ --polyx-brand: #6366f1;
53
+ --polyx-brand-hover: #818cf8;
54
+ --polyx-bg: #18181b;
55
+ --polyx-fg: #fafafa;
56
+ --polyx-muted-fg: #a1a1aa;
57
+ --polyx-border: #3f3f46;
58
+ --polyx-input-bg: #27272a;
59
+ --polyx-ring: #4f46e5;
60
+ --polyx-danger: #f87171;
61
+ --polyx-danger-bg: #2a1616;
62
+ --polyx-page-bg: #09090b;
63
+ --polyx-shadow: 0 1px 3px rgb(0 0 0 / 0.4), 0 10px 30px rgb(0 0 0 / 0.35);
64
+ }
65
+ }
66
+
67
+ /* …but an explicit host theme wins over the OS preference (`:where` keeps
68
+ specificity at 0 so these stay as easy to override as the base rule). */
69
+ :where(.dark, [data-theme="dark"]) .polyx-signin {
70
+ --polyx-brand: #6366f1;
71
+ --polyx-brand-hover: #818cf8;
72
+ --polyx-bg: #18181b;
73
+ --polyx-fg: #fafafa;
74
+ --polyx-muted-fg: #a1a1aa;
75
+ --polyx-border: #3f3f46;
76
+ --polyx-input-bg: #27272a;
77
+ --polyx-ring: #4f46e5;
78
+ --polyx-danger: #f87171;
79
+ --polyx-danger-bg: #2a1616;
80
+ --polyx-page-bg: #09090b;
81
+ --polyx-shadow: 0 1px 3px rgb(0 0 0 / 0.4), 0 10px 30px rgb(0 0 0 / 0.35);
82
+ }
83
+
84
+ :where(.light, [data-theme="light"]) .polyx-signin {
85
+ --polyx-brand: #4f46e5;
86
+ --polyx-brand-hover: #4338ca;
87
+ --polyx-bg: #ffffff;
88
+ --polyx-fg: #18181b;
89
+ --polyx-muted-fg: #71717a;
90
+ --polyx-border: #e4e4e7;
91
+ --polyx-input-bg: #ffffff;
92
+ --polyx-ring: #a5b4fc;
93
+ --polyx-danger: #dc2626;
94
+ --polyx-danger-bg: #fef2f2;
95
+ --polyx-page-bg: #fafafa;
96
+ --polyx-shadow: 0 1px 3px rgb(0 0 0 / 0.06), 0 10px 30px rgb(0 0 0 / 0.07);
97
+ }
98
+
99
+ /* --- Variants ------------------------------------------------------------ */
100
+
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
+ /* `card`: just the card — drop it anywhere in your own layout. */
111
+ .polyx-signin--card {
112
+ display: block;
113
+ }
114
+
115
+ .polyx-signin__card {
116
+ width: 100%;
117
+ max-width: 24rem;
118
+ margin-inline: auto;
119
+ padding: 2rem;
120
+ background: var(--polyx-bg);
121
+ border: 1px solid var(--polyx-border);
122
+ border-radius: var(--polyx-radius);
123
+ box-shadow: var(--polyx-shadow);
124
+ }
125
+
126
+ /* --- Header -------------------------------------------------------------- */
127
+
128
+ .polyx-signin__header {
129
+ display: flex;
130
+ flex-direction: column;
131
+ gap: 0.375rem;
132
+ margin-bottom: 1.75rem;
133
+ }
134
+
135
+ .polyx-signin__logo {
136
+ display: flex;
137
+ margin-bottom: 0.75rem;
138
+ }
139
+
140
+ .polyx-signin__heading {
141
+ margin: 0;
142
+ font-size: 1.375rem;
143
+ font-weight: 600;
144
+ letter-spacing: -0.01em;
145
+ color: var(--polyx-fg);
146
+ }
147
+
148
+ .polyx-signin__subheading {
149
+ margin: 0;
150
+ font-size: 0.875rem;
151
+ color: var(--polyx-muted-fg);
152
+ }
153
+
154
+ /* --- Form ---------------------------------------------------------------- */
155
+
156
+ .polyx-signin__form {
157
+ display: flex;
158
+ flex-direction: column;
159
+ gap: 1.125rem;
160
+ }
161
+
162
+ .polyx-signin__field {
163
+ display: flex;
164
+ flex-direction: column;
165
+ gap: 0.4375rem;
166
+ }
167
+
168
+ .polyx-signin__label {
169
+ font-size: 0.875rem;
170
+ font-weight: 500;
171
+ color: var(--polyx-fg);
172
+ }
173
+
174
+ .polyx-signin__input {
175
+ width: 100%;
176
+ height: 2.5rem;
177
+ padding: 0 0.75rem;
178
+ font: inherit;
179
+ font-size: 0.875rem;
180
+ color: var(--polyx-fg);
181
+ background: var(--polyx-input-bg);
182
+ border: 1px solid var(--polyx-border);
183
+ border-radius: var(--polyx-radius-sm);
184
+ outline: none;
185
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
186
+ }
187
+
188
+ .polyx-signin__input::placeholder {
189
+ color: var(--polyx-muted-fg);
190
+ }
191
+
192
+ .polyx-signin__input:focus-visible {
193
+ border-color: var(--polyx-brand);
194
+ box-shadow: 0 0 0 3px var(--polyx-ring);
195
+ }
196
+
197
+ .polyx-signin__input:disabled {
198
+ opacity: 0.6;
199
+ cursor: not-allowed;
200
+ }
201
+
202
+ /* --- Buttons ------------------------------------------------------------- */
203
+
204
+ .polyx-signin__submit,
205
+ .polyx-signin__tenant {
206
+ display: inline-flex;
207
+ align-items: center;
208
+ justify-content: center;
209
+ width: 100%;
210
+ min-height: 2.5rem;
211
+ padding: 0 1rem;
212
+ font: inherit;
213
+ font-size: 0.875rem;
214
+ font-weight: 500;
215
+ color: var(--polyx-brand-fg);
216
+ background: var(--polyx-brand);
217
+ border: 1px solid transparent;
218
+ border-radius: var(--polyx-radius-sm);
219
+ cursor: pointer;
220
+ transition: background-color 0.15s ease;
221
+ }
222
+
223
+ .polyx-signin__submit:hover:not(:disabled),
224
+ .polyx-signin__tenant:hover:not(:disabled) {
225
+ background: var(--polyx-brand-hover);
226
+ }
227
+
228
+ .polyx-signin__submit:focus-visible,
229
+ .polyx-signin__tenant:focus-visible {
230
+ outline: none;
231
+ box-shadow: 0 0 0 3px var(--polyx-ring);
232
+ }
233
+
234
+ .polyx-signin__submit:disabled,
235
+ .polyx-signin__tenant:disabled {
236
+ opacity: 0.6;
237
+ cursor: not-allowed;
238
+ }
239
+
240
+ /* --- Error --------------------------------------------------------------- */
241
+
242
+ .polyx-signin__error {
243
+ margin: 0;
244
+ padding: 0.625rem 0.75rem;
245
+ font-size: 0.8125rem;
246
+ color: var(--polyx-danger);
247
+ background: var(--polyx-danger-bg);
248
+ border: 1px solid color-mix(in srgb, var(--polyx-danger) 30%, transparent);
249
+ border-radius: var(--polyx-radius-sm);
250
+ }
251
+
252
+ /* --- Workspace picker ---------------------------------------------------- */
253
+
254
+ .polyx-signin__tenants {
255
+ display: flex;
256
+ flex-direction: column;
257
+ gap: 0.625rem;
258
+ margin: 0;
259
+ padding: 0;
260
+ list-style: none;
261
+ }
262
+
263
+ /* The picker's buttons read as choices, not as the primary CTA. */
264
+ .polyx-signin__tenant {
265
+ justify-content: flex-start;
266
+ color: var(--polyx-fg);
267
+ background: var(--polyx-input-bg);
268
+ border-color: var(--polyx-border);
269
+ }
270
+
271
+ .polyx-signin__tenant:hover:not(:disabled) {
272
+ background: var(--polyx-input-bg);
273
+ border-color: var(--polyx-brand);
274
+ }
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@poly-x/react",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.3",
4
4
  "description": "PolyX SDK for React SPAs - provider, hooks, drop-in auth UI",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
- "sideEffects": false,
7
+ "sideEffects": [
8
+ "**/*.css"
9
+ ],
8
10
  "files": [
9
11
  "dist"
10
12
  ],
@@ -18,13 +20,14 @@
18
20
  "types": "./dist/index.d.cts",
19
21
  "default": "./dist/index.cjs"
20
22
  }
21
- }
23
+ },
24
+ "./styles.css": "./dist/styles.css"
22
25
  },
23
26
  "main": "./dist/index.cjs",
24
27
  "module": "./dist/index.mjs",
25
28
  "types": "./dist/index.d.cts",
26
29
  "dependencies": {
27
- "@poly-x/core": "0.1.0-alpha.2"
30
+ "@poly-x/core": "0.1.0-alpha.3"
28
31
  },
29
32
  "peerDependencies": {
30
33
  "react": ">=18",
@@ -51,7 +54,7 @@
51
54
  "react-dom": "^19.2.7"
52
55
  },
53
56
  "scripts": {
54
- "build": "tsdown",
57
+ "build": "tsdown && node scripts/copy-styles.mjs",
55
58
  "test": "vitest run",
56
59
  "lint": "eslint src"
57
60
  }