@elvix.is/sdk 0.5.4 → 0.5.6

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.
Files changed (3) hide show
  1. package/dist/react.d.ts +92 -34
  2. package/dist/react.js +1005 -304
  3. package/package.json +1 -1
package/dist/react.js CHANGED
@@ -1,12 +1,32 @@
1
1
  "use client";
2
+ // src/react/size.ts
3
+ function sizeStyle(p) {
4
+ const s = {};
5
+ if (p.width !== void 0) s.width = p.width;
6
+ if (p.height !== void 0) s.height = p.height;
7
+ if (p.minWidth !== void 0) s.minWidth = p.minWidth;
8
+ if (p.maxWidth !== void 0) s.maxWidth = p.maxWidth;
9
+ if (p.minHeight !== void 0) s.minHeight = p.minHeight;
10
+ if (p.maxHeight !== void 0) s.maxHeight = p.maxHeight;
11
+ return s;
12
+ }
13
+
2
14
  // src/react/elvix-card.tsx
3
15
  import { jsx, jsxs } from "react/jsx-runtime";
4
16
  function ElvixCard({
5
17
  title,
6
18
  footer,
7
19
  className = "",
8
- children
20
+ style,
21
+ children,
22
+ width,
23
+ height,
24
+ minWidth,
25
+ maxWidth,
26
+ minHeight,
27
+ maxHeight
9
28
  }) {
29
+ const sized = sizeStyle({ width, height, minWidth, maxWidth, minHeight, maxHeight });
10
30
  return /* @__PURE__ */ jsxs(
11
31
  "div",
12
32
  {
@@ -19,7 +39,9 @@ function ElvixCard({
19
39
  display: "flex",
20
40
  flexDirection: "column",
21
41
  maxWidth: "440px",
22
- width: "100%"
42
+ width: "100%",
43
+ ...style,
44
+ ...sized
23
45
  },
24
46
  children: [
25
47
  title && /* @__PURE__ */ jsx(
@@ -182,6 +204,7 @@ import { useState as useState2 } from "react";
182
204
  var DEFAULT_COPY = {
183
205
  subtitle: "Pick how you want to continue.",
184
206
  googleButton: "Continue with Google",
207
+ passkeyButton: "Continue with passkey",
185
208
  emailPlaceholder: "you@example.com",
186
209
  sendCodeButton: "Send code",
187
210
  sendingLabel: "Sending\u2026",
@@ -250,14 +273,112 @@ function isSameOrigin(baseUrl) {
250
273
  }
251
274
  }
252
275
 
276
+ // src/react/passkey.ts
277
+ function b64urlToBuf(b64url) {
278
+ const b64 = b64url.replace(/-/g, "+").replace(/_/g, "/");
279
+ const pad = b64.length % 4 === 0 ? "" : "=".repeat(4 - b64.length % 4);
280
+ const bin = atob(b64 + pad);
281
+ const bytes = new Uint8Array(bin.length);
282
+ for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
283
+ return bytes.buffer;
284
+ }
285
+ function bufToB64url(buf) {
286
+ const bytes = new Uint8Array(buf);
287
+ let bin = "";
288
+ for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
289
+ return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
290
+ }
291
+ async function runPasskeySignIn(baseUrl, clientId) {
292
+ if (!clientId) return { ok: false, error: "missing_client_id", message: "ElvixProvider needs a clientId." };
293
+ if (typeof window === "undefined" || !window.PublicKeyCredential || !navigator.credentials?.get) {
294
+ return { ok: false, error: "passkey_unsupported", message: "This browser can't use passkeys." };
295
+ }
296
+ const credentials = isSameOrigin(baseUrl) ? "include" : "omit";
297
+ let options;
298
+ try {
299
+ const res = await fetch(`${baseUrl}/api/auth/passkey/sign-in/start`, {
300
+ method: "POST",
301
+ headers: { "content-type": "application/json" },
302
+ credentials,
303
+ body: JSON.stringify({ intent: "app", clientId })
304
+ });
305
+ const body = await res.json();
306
+ if (!res.ok || !body.success || !body.data?.options) {
307
+ return { ok: false, error: body.errorMessage ?? "passkey_start_failed" };
308
+ }
309
+ options = body.data.options;
310
+ } catch (e) {
311
+ return { ok: false, error: "network", message: e instanceof Error ? e.message : void 0 };
312
+ }
313
+ let assertion;
314
+ try {
315
+ const publicKey = {
316
+ challenge: b64urlToBuf(options.challenge),
317
+ timeout: options.timeout,
318
+ rpId: options.rpId,
319
+ userVerification: options.userVerification,
320
+ allowCredentials: options.allowCredentials?.map((c) => ({
321
+ id: b64urlToBuf(c.id),
322
+ type: c.type,
323
+ transports: c.transports
324
+ }))
325
+ };
326
+ const cred = await navigator.credentials.get({ publicKey });
327
+ if (!cred) return { ok: false, error: "passkey_cancelled" };
328
+ const resp = cred.response;
329
+ assertion = {
330
+ id: cred.id,
331
+ rawId: bufToB64url(cred.rawId),
332
+ type: "public-key",
333
+ clientExtensionResults: cred.getClientExtensionResults(),
334
+ authenticatorAttachment: cred.authenticatorAttachment ?? void 0,
335
+ response: {
336
+ clientDataJSON: bufToB64url(resp.clientDataJSON),
337
+ authenticatorData: bufToB64url(resp.authenticatorData),
338
+ signature: bufToB64url(resp.signature),
339
+ userHandle: resp.userHandle ? bufToB64url(resp.userHandle) : void 0
340
+ }
341
+ };
342
+ } catch (e) {
343
+ const name = e?.name;
344
+ if (name === "NotAllowedError" || name === "AbortError") {
345
+ return { ok: false, error: "passkey_cancelled" };
346
+ }
347
+ return { ok: false, error: "passkey_failed", message: e instanceof Error ? e.message : void 0 };
348
+ }
349
+ try {
350
+ const res = await fetch(`${baseUrl}/api/auth/passkey/sign-in/finish`, {
351
+ method: "POST",
352
+ headers: { "content-type": "application/json" },
353
+ credentials,
354
+ body: JSON.stringify({ intent: "app", clientId, ...assertion })
355
+ });
356
+ const body = await res.json();
357
+ if (!res.ok || !body.success) {
358
+ return { ok: false, error: body.errorMessage ?? "passkey_verify_failed" };
359
+ }
360
+ if (body.data?.token) setElvixToken(body.data.token);
361
+ return { ok: true, redirect: body.data?.redirect, token: body.data?.token };
362
+ } catch (e) {
363
+ return { ok: false, error: "network", message: e instanceof Error ? e.message : void 0 };
364
+ }
365
+ }
366
+
253
367
  // src/react/elvix-sign-in.tsx
254
368
  import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
255
369
  function ElvixSignIn({
256
370
  onResult,
257
371
  redirectAfterSignIn,
258
372
  copy: copyProp,
259
- className = ""
373
+ className = "",
374
+ width,
375
+ height,
376
+ minWidth,
377
+ maxWidth,
378
+ minHeight,
379
+ maxHeight
260
380
  }) {
381
+ const sized = sizeStyle({ width, height, minWidth, maxWidth, minHeight, maxHeight });
261
382
  const ctx = useElvixContext();
262
383
  const app = useElvixApp();
263
384
  const copy = resolveCopy(app?.strings, copyProp);
@@ -281,6 +402,29 @@ function ElvixSignIn({
281
402
  `${ctx.baseUrl}/api/auth/google/start?intent=app&clientId=${encodeURIComponent(ctx.clientId)}`
282
403
  );
283
404
  }
405
+ async function startPasskey() {
406
+ setBusy(true);
407
+ setError(null);
408
+ try {
409
+ const result = await runPasskeySignIn(ctx.baseUrl, ctx.clientId);
410
+ if (!result.ok) {
411
+ if (result.error === "passkey_cancelled") {
412
+ onResult?.({ ok: false, error: result.error });
413
+ return;
414
+ }
415
+ return fail(result.error, result.message);
416
+ }
417
+ setStep("done");
418
+ onResult?.({
419
+ ok: true,
420
+ method: "passkey",
421
+ redirect: result.redirect ?? redirectAfterSignIn,
422
+ token: result.token
423
+ });
424
+ } finally {
425
+ setBusy(false);
426
+ }
427
+ }
284
428
  async function startOtp(e) {
285
429
  e.preventDefault();
286
430
  if (!email.trim()) return fail("invalid_input", copy.errorEnterEmail);
@@ -342,9 +486,9 @@ function ElvixSignIn({
342
486
  }
343
487
  const card = `elvix-card ${className}`.trim();
344
488
  if (step === "done") {
345
- return /* @__PURE__ */ jsx3("div", { className: card, "data-elvix-pane": "done", children: /* @__PURE__ */ jsx3("p", { children: copy.signedInText }) });
489
+ return /* @__PURE__ */ jsx3("div", { className: card, style: sized, "data-elvix-pane": "done", children: /* @__PURE__ */ jsx3("p", { children: copy.signedInText }) });
346
490
  }
347
- return /* @__PURE__ */ jsxs2("div", { className: card, "data-elvix-pane": step, children: [
491
+ return /* @__PURE__ */ jsxs2("div", { className: card, style: sized, "data-elvix-pane": step, children: [
348
492
  /* @__PURE__ */ jsx3("h2", { className: "elvix-h", children: title }),
349
493
  copy.subtitle && /* @__PURE__ */ jsx3("p", { className: "elvix-muted elvix-subtitle", children: copy.subtitle }),
350
494
  step === "identify" && /* @__PURE__ */ jsxs2(Fragment, { children: [
@@ -359,6 +503,17 @@ function ElvixSignIn({
359
503
  children: copy.googleButton
360
504
  }
361
505
  ),
506
+ app?.methodPasskey && /* @__PURE__ */ jsx3(
507
+ "button",
508
+ {
509
+ type: "button",
510
+ onClick: startPasskey,
511
+ disabled: busy,
512
+ className: "elvix-btn elvix-btn-passkey",
513
+ "data-elvix-method": "passkey",
514
+ children: copy.passkeyButton
515
+ }
516
+ ),
362
517
  app?.methodEmailOtp && /* @__PURE__ */ jsxs2("form", { onSubmit: startOtp, "data-elvix-method": "email_otp", className: "elvix-otp-form", children: [
363
518
  /* @__PURE__ */ jsx3(
364
519
  "input",
@@ -394,36 +549,557 @@ function ElvixSignIn({
394
549
  ),
395
550
  /* @__PURE__ */ jsx3("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? copy.verifyingLabel : submitLabel })
396
551
  ] }),
397
- error && /* @__PURE__ */ jsx3("p", { role: "alert", className: "elvix-error", children: error })
552
+ error && /* @__PURE__ */ jsx3("p", { role: "alert", className: "elvix-error", children: error })
553
+ ] });
554
+ }
555
+
556
+ // src/react/elvix-sign-in-form.tsx
557
+ import { useMemo as useMemo2, useState as useState3 } from "react";
558
+
559
+ // src/react/elvix-shield.tsx
560
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
561
+ function ElvixShield({
562
+ size,
563
+ fill,
564
+ accent
565
+ }) {
566
+ return /* @__PURE__ */ jsxs3("svg", { width: size, height: size, viewBox: "2 2 20 20", "aria-hidden": true, style: { display: "block" }, children: [
567
+ /* @__PURE__ */ jsx4(
568
+ "path",
569
+ {
570
+ fill,
571
+ fillRule: "evenodd",
572
+ d: "M 6 2.5 C 4.34 2.5 3 3.84 3 5.5 L 3 12.5 C 3 17.5 7 20.7 12 22 C 17 20.7 21 17.5 21 12.5 L 21 5.5 C 21 3.84 19.66 2.5 18 2.5 L 6 2.5 Z M 12 8.4 C 9.79 8.4 8 10.19 8 12.4 C 8 14.61 9.79 16.4 12 16.4 C 13.21 16.4 14.3 15.86 15.04 15 L 13.6 13.77 C 13.21 14.23 12.64 14.5 12 14.5 C 11.04 14.5 10.21 13.86 9.91 13 L 15.95 13 C 15.98 12.8 16 12.6 16 12.4 C 16 10.19 14.21 8.4 12 8.4 Z M 9.91 11.8 L 14.09 11.8 C 13.79 10.94 12.96 10.3 12 10.3 C 11.04 10.3 10.21 10.94 9.91 11.8 Z"
573
+ }
574
+ ),
575
+ /* @__PURE__ */ jsx4("circle", { cx: "19.5", cy: "4.5", r: "2.4", fill: accent })
576
+ ] });
577
+ }
578
+
579
+ // src/react/elvix-secured-badge.tsx
580
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
581
+ var ELVIX_URL = "https://elvix.is";
582
+ var SIZE = {
583
+ sm: { height: 28, padX: 10, font: 11.5, icon: 14, gap: 6 },
584
+ md: { height: 32, padX: 12, font: 12.5, icon: 16, gap: 7 },
585
+ lg: { height: 36, padX: 14, font: 13, icon: 18, gap: 8 }
586
+ };
587
+ var TONE = {
588
+ white: {
589
+ light: { bg: "#ffffff", border: "#e4e4e7", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" },
590
+ dark: { bg: "#ffffff", border: "transparent", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" }
591
+ },
592
+ dark: {
593
+ light: { bg: "#0a0a0b", border: "rgba(0,0,0,0.1)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" },
594
+ dark: { bg: "#0a0a0b", border: "rgba(255,255,255,0.1)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" }
595
+ },
596
+ outline: {
597
+ light: { bg: "transparent", border: "rgba(0,0,0,0.15)", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" },
598
+ dark: { bg: "transparent", border: "rgba(142,125,255,0.4)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" }
599
+ }
600
+ };
601
+ function ElvixSecuredBadge({
602
+ variant = "white",
603
+ size = "md",
604
+ theme = "dark",
605
+ accentColor = "#8e7dff",
606
+ href = ELVIX_URL,
607
+ className = "",
608
+ width,
609
+ height,
610
+ minWidth,
611
+ maxWidth,
612
+ minHeight,
613
+ maxHeight
614
+ }) {
615
+ const s = SIZE[size];
616
+ const t = TONE[variant][theme];
617
+ const style = {
618
+ display: "inline-flex",
619
+ alignItems: "center",
620
+ gap: s.gap,
621
+ height: s.height,
622
+ paddingLeft: s.padX,
623
+ paddingRight: s.padX,
624
+ fontSize: s.font,
625
+ fontWeight: 500,
626
+ borderRadius: 9999,
627
+ background: t.bg,
628
+ border: `1px solid ${t.border}`,
629
+ color: t.brand,
630
+ textDecoration: "none",
631
+ userSelect: "none",
632
+ lineHeight: 1,
633
+ // Dimensional overrides win over the size preset above.
634
+ ...sizeStyle({ width, height, minWidth, maxWidth, minHeight, maxHeight })
635
+ };
636
+ return /* @__PURE__ */ jsxs4(
637
+ "a",
638
+ {
639
+ href,
640
+ target: "_blank",
641
+ rel: "noopener noreferrer",
642
+ className,
643
+ style,
644
+ "data-elvix-secured-badge": "",
645
+ children: [
646
+ /* @__PURE__ */ jsx5(ElvixShield, { size: s.icon, fill: t.shield, accent: accentColor }),
647
+ /* @__PURE__ */ jsxs4("span", { style: { display: "inline-flex", alignItems: "baseline", gap: 4 }, children: [
648
+ /* @__PURE__ */ jsx5("span", { style: { color: t.lead }, children: "Secured by" }),
649
+ /* @__PURE__ */ jsx5("span", { style: { color: t.brand, fontWeight: 600 }, children: "elvix" })
650
+ ] })
651
+ ]
652
+ }
653
+ );
654
+ }
655
+
656
+ // src/react/elvix-sign-in-form.tsx
657
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
658
+ function PasskeyIcon({ size = 18 }) {
659
+ return /* @__PURE__ */ jsxs5(
660
+ "svg",
661
+ {
662
+ width: size,
663
+ height: size,
664
+ viewBox: "0 0 24 24",
665
+ fill: "none",
666
+ stroke: "currentColor",
667
+ strokeWidth: 1.8,
668
+ strokeLinecap: "round",
669
+ strokeLinejoin: "round",
670
+ "aria-hidden": true,
671
+ style: { display: "block" },
672
+ children: [
673
+ /* @__PURE__ */ jsx6("circle", { cx: "9", cy: "8", r: "4" }),
674
+ /* @__PURE__ */ jsx6("path", { d: "M4 20c0-3 2.5-5 5-5 1 0 1.9.3 2.7.8" }),
675
+ /* @__PURE__ */ jsx6("path", { d: "M17 12.5a2.5 2.5 0 1 0-2.5 2.5v5l1.2-1.2 1.3 1.2v-5a2.5 2.5 0 0 0 0-2.5Z" })
676
+ ]
677
+ }
678
+ );
679
+ }
680
+ function GoogleG({ size = 18 }) {
681
+ return /* @__PURE__ */ jsxs5("svg", { width: size, height: size, viewBox: "0 0 18 18", "aria-hidden": true, style: { display: "block" }, children: [
682
+ /* @__PURE__ */ jsx6(
683
+ "path",
684
+ {
685
+ fill: "#4285F4",
686
+ d: "M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.88 2.68-6.62Z"
687
+ }
688
+ ),
689
+ /* @__PURE__ */ jsx6(
690
+ "path",
691
+ {
692
+ fill: "#34A853",
693
+ d: "M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.8.54-1.84.86-3.04.86-2.34 0-4.32-1.58-5.03-3.7H.96v2.33A9 9 0 0 0 9 18Z"
694
+ }
695
+ ),
696
+ /* @__PURE__ */ jsx6(
697
+ "path",
698
+ {
699
+ fill: "#FBBC05",
700
+ d: "M3.97 10.72A5.4 5.4 0 0 1 3.68 9c0-.6.1-1.18.29-1.72V4.95H.96A9 9 0 0 0 0 9c0 1.45.35 2.83.96 4.05l3.01-2.33Z"
701
+ }
702
+ ),
703
+ /* @__PURE__ */ jsx6(
704
+ "path",
705
+ {
706
+ fill: "#EA4335",
707
+ d: "M9 3.58c1.32 0 2.5.45 3.44 1.35l2.58-2.59C13.46.89 11.43 0 9 0A9 9 0 0 0 .96 4.95l3.01 2.33C4.68 5.16 6.66 3.58 9 3.58Z"
708
+ }
709
+ )
710
+ ] });
711
+ }
712
+ function ElvixSignInForm({
713
+ onResult,
714
+ redirectAfterSignIn,
715
+ copy: copyProp,
716
+ className = "",
717
+ minWidth,
718
+ maxWidth,
719
+ minHeight,
720
+ maxHeight,
721
+ width,
722
+ height
723
+ }) {
724
+ const ctx = useElvixContext();
725
+ const app = useElvixApp();
726
+ const copy = resolveCopy(app?.strings, copyProp);
727
+ const [step, setStep] = useState3("identify");
728
+ const [email, setEmail] = useState3("");
729
+ const [code, setCode] = useState3("");
730
+ const [challengeId, setChallengeId] = useState3(null);
731
+ const [busy, setBusy] = useState3(false);
732
+ const [error, setError] = useState3(null);
733
+ const brand = app?.brandColor || "#6c5ce7";
734
+ const onBrand = app?.onBrandColor || "#fff";
735
+ const appName = app?.appName ?? "your app";
736
+ const verb = app?.signInVerb === "login" ? "Log in" : "Sign in";
737
+ const defaultTitle = app?.appName ? `${verb} to ${app.appName}` : verb;
738
+ const title = copy.title ? fillCopy(copy.title, { app: app?.appName ?? "" }) : defaultTitle;
739
+ const submitLabel = copy.submitButton ?? verb;
740
+ const showGoogle = Boolean(app?.methodGoogle);
741
+ const showPasskey = Boolean(app?.methodPasskey);
742
+ const showEmail = Boolean(app?.methodEmailOtp);
743
+ const showDivider = (showGoogle || showPasskey) && showEmail;
744
+ const logoSrc = app?.iconUrl || app?.logoUrl || null;
745
+ const privacyUrl = app?.privacyPolicyUrl || null;
746
+ const termsUrl = app?.termsOfServiceUrl || null;
747
+ const hasLegal = Boolean(privacyUrl || termsUrl);
748
+ const cardStyle = useMemo2(
749
+ () => ({
750
+ boxSizing: "border-box",
751
+ // Defaults first; the shared sizeStyle() overrides only the keys the host set,
752
+ // so the form keeps its width "100%" / maxWidth 400 defaults when unsized.
753
+ width: "100%",
754
+ maxWidth: 400,
755
+ ...sizeStyle({ width, height, minWidth, maxWidth, minHeight, maxHeight }),
756
+ margin: "0 auto",
757
+ display: "flex",
758
+ flexDirection: "column",
759
+ gap: 18,
760
+ background: "#fff",
761
+ color: "#18181b",
762
+ border: "1px solid rgba(0,0,0,0.08)",
763
+ borderRadius: 16,
764
+ boxShadow: "0 1px 2px rgba(0,0,0,0.04), 0 12px 32px -12px rgba(0,0,0,0.18)",
765
+ padding: 28,
766
+ fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif",
767
+ textAlign: "center"
768
+ }),
769
+ [width, maxWidth, minWidth, height, minHeight, maxHeight]
770
+ );
771
+ function fail(error2, message) {
772
+ setError(message ?? error2);
773
+ onResult?.({ ok: false, error: error2, message });
774
+ }
775
+ async function startGoogle() {
776
+ if (!ctx.clientId) return fail("missing_client_id", "ElvixProvider needs a clientId.");
777
+ window.location.assign(
778
+ `${ctx.baseUrl}/api/auth/google/start?intent=app&clientId=${encodeURIComponent(ctx.clientId)}`
779
+ );
780
+ }
781
+ async function startPasskey() {
782
+ setBusy(true);
783
+ setError(null);
784
+ try {
785
+ const result = await runPasskeySignIn(ctx.baseUrl, ctx.clientId);
786
+ if (!result.ok) {
787
+ if (result.error === "passkey_cancelled") {
788
+ onResult?.({ ok: false, error: result.error });
789
+ return;
790
+ }
791
+ return fail(result.error, result.message);
792
+ }
793
+ setStep("done");
794
+ onResult?.({
795
+ ok: true,
796
+ method: "passkey",
797
+ redirect: result.redirect ?? redirectAfterSignIn,
798
+ token: result.token
799
+ });
800
+ } finally {
801
+ setBusy(false);
802
+ }
803
+ }
804
+ async function startOtp(e) {
805
+ e.preventDefault();
806
+ if (!email.trim()) return fail("invalid_input", copy.errorEnterEmail);
807
+ setBusy(true);
808
+ setError(null);
809
+ try {
810
+ const res = await fetch(`${ctx.baseUrl}/api/auth/otp/start`, {
811
+ method: "POST",
812
+ headers: { "content-type": "application/json" },
813
+ credentials: isSameOrigin(ctx.baseUrl) ? "include" : "omit",
814
+ body: JSON.stringify({
815
+ email: email.trim(),
816
+ intent: "app",
817
+ clientId: ctx.clientId
818
+ })
819
+ });
820
+ const body = await res.json();
821
+ if (!res.ok || !body.success || !body.data?.challengeId) {
822
+ return fail(body.errorMessage ?? "otp_start_failed");
823
+ }
824
+ setChallengeId(body.data.challengeId);
825
+ setStep("code");
826
+ } catch (e2) {
827
+ fail("network", e2 instanceof Error ? e2.message : void 0);
828
+ } finally {
829
+ setBusy(false);
830
+ }
831
+ }
832
+ async function verifyOtp(e) {
833
+ e.preventDefault();
834
+ if (!challengeId) return;
835
+ if (code.trim().length !== 6) return fail("invalid_input", copy.errorEnterCode);
836
+ setBusy(true);
837
+ setError(null);
838
+ try {
839
+ const res = await fetch(`${ctx.baseUrl}/api/auth/otp/verify`, {
840
+ method: "POST",
841
+ headers: { "content-type": "application/json" },
842
+ credentials: isSameOrigin(ctx.baseUrl) ? "include" : "omit",
843
+ body: JSON.stringify({ challengeId, code: code.trim() })
844
+ });
845
+ const body = await res.json();
846
+ if (!res.ok || !body.success) {
847
+ return fail(body.errorMessage ?? "otp_verify_failed");
848
+ }
849
+ if (body.data?.token) setElvixToken(body.data.token);
850
+ setStep("done");
851
+ onResult?.({
852
+ ok: true,
853
+ method: "email_otp",
854
+ redirect: body.data?.redirect ?? redirectAfterSignIn,
855
+ token: body.data?.token
856
+ });
857
+ } catch (e2) {
858
+ fail("network", e2 instanceof Error ? e2.message : void 0);
859
+ } finally {
860
+ setBusy(false);
861
+ }
862
+ }
863
+ const labelStyle = {
864
+ display: "block",
865
+ textAlign: "left",
866
+ fontSize: 12.5,
867
+ fontWeight: 500,
868
+ color: "#52525b",
869
+ marginBottom: 6
870
+ };
871
+ const inputStyle = {
872
+ boxSizing: "border-box",
873
+ width: "100%",
874
+ height: 44,
875
+ padding: "0 14px",
876
+ borderRadius: 10,
877
+ border: "1px solid rgba(0,0,0,0.14)",
878
+ background: "#fff",
879
+ color: "#18181b",
880
+ fontSize: 14,
881
+ outline: "none"
882
+ };
883
+ const primaryBtnStyle = {
884
+ boxSizing: "border-box",
885
+ width: "100%",
886
+ height: 44,
887
+ marginTop: 10,
888
+ border: "1px solid rgba(0,0,0,0.08)",
889
+ borderRadius: 10,
890
+ background: brand,
891
+ color: onBrand,
892
+ fontSize: 14,
893
+ fontWeight: 600,
894
+ cursor: busy ? "not-allowed" : "pointer",
895
+ opacity: busy ? 0.65 : 1,
896
+ backgroundImage: "linear-gradient(to bottom, rgba(255,255,255,0.12), rgba(255,255,255,0) 40%)",
897
+ boxShadow: "0 1px 0 rgba(255,255,255,0.06) inset, 0 2px 3px -1px rgba(0,0,0,0.18), 0 0 0 1px rgba(25,28,33,0.06)"
898
+ };
899
+ const googleBtnStyle = {
900
+ boxSizing: "border-box",
901
+ width: "100%",
902
+ height: 44,
903
+ display: "inline-flex",
904
+ alignItems: "center",
905
+ justifyContent: "center",
906
+ gap: 10,
907
+ border: "1px solid rgba(0,0,0,0.14)",
908
+ borderRadius: 10,
909
+ background: "#fff",
910
+ color: "#18181b",
911
+ fontSize: 14,
912
+ fontWeight: 500,
913
+ cursor: busy ? "not-allowed" : "pointer",
914
+ opacity: busy ? 0.65 : 1
915
+ };
916
+ const tileTint = hexToRgba(brand, 0.12);
917
+ const root = `${className}`.trim() || void 0;
918
+ return /* @__PURE__ */ jsxs5("div", { className: root, style: cardStyle, "data-elvix-pane": step, children: [
919
+ /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
920
+ /* @__PURE__ */ jsx6(
921
+ "div",
922
+ {
923
+ style: {
924
+ width: 52,
925
+ height: 52,
926
+ borderRadius: 14,
927
+ display: "grid",
928
+ placeItems: "center",
929
+ overflow: "hidden",
930
+ background: logoSrc ? "#fff" : tileTint,
931
+ border: "1px solid rgba(0,0,0,0.08)"
932
+ },
933
+ children: logoSrc ? (
934
+ // biome-ignore lint/a11y/useAltText: alt is set
935
+ /* @__PURE__ */ jsx6(
936
+ "img",
937
+ {
938
+ src: logoSrc,
939
+ alt: appName,
940
+ style: { width: "100%", height: "100%", objectFit: "cover" }
941
+ }
942
+ )
943
+ ) : /* @__PURE__ */ jsx6("span", { style: { fontSize: 22, fontWeight: 700, color: brand }, children: appName.charAt(0).toUpperCase() || "?" })
944
+ }
945
+ ),
946
+ /* @__PURE__ */ jsxs5("div", { children: [
947
+ /* @__PURE__ */ jsx6("h2", { style: { margin: 0, fontSize: 19, fontWeight: 600, letterSpacing: "-0.01em" }, children: step === "code" ? "Check your inbox" : title }),
948
+ step !== "done" && /* @__PURE__ */ jsx6("p", { style: { margin: "4px 0 0", fontSize: 13, color: "#71717a" }, children: step === "code" ? fillCopy(copy.codeSentSubtitle ?? "", { email }) : copy.subtitle })
949
+ ] })
950
+ ] }),
951
+ step === "done" && /* @__PURE__ */ jsx6("p", { style: { margin: 0, fontSize: 14, color: "#18181b" }, children: copy.signedInText }),
952
+ step === "identify" && /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: 14 }, children: [
953
+ showGoogle && /* @__PURE__ */ jsxs5(
954
+ "button",
955
+ {
956
+ type: "button",
957
+ onClick: startGoogle,
958
+ disabled: busy,
959
+ style: googleBtnStyle,
960
+ "data-elvix-method": "google",
961
+ children: [
962
+ /* @__PURE__ */ jsx6(GoogleG, {}),
963
+ /* @__PURE__ */ jsx6("span", { children: copy.googleButton })
964
+ ]
965
+ }
966
+ ),
967
+ showPasskey && /* @__PURE__ */ jsxs5(
968
+ "button",
969
+ {
970
+ type: "button",
971
+ onClick: startPasskey,
972
+ disabled: busy,
973
+ style: googleBtnStyle,
974
+ "data-elvix-method": "passkey",
975
+ children: [
976
+ /* @__PURE__ */ jsx6(PasskeyIcon, {}),
977
+ /* @__PURE__ */ jsx6("span", { children: copy.passkeyButton })
978
+ ]
979
+ }
980
+ ),
981
+ showDivider && /* @__PURE__ */ jsxs5(
982
+ "div",
983
+ {
984
+ "aria-hidden": true,
985
+ style: { display: "flex", alignItems: "center", gap: 12, color: "#a1a1aa" },
986
+ children: [
987
+ /* @__PURE__ */ jsx6("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.08)" } }),
988
+ /* @__PURE__ */ jsx6("span", { style: { fontSize: 11, fontWeight: 600, letterSpacing: "0.08em" }, children: "OR" }),
989
+ /* @__PURE__ */ jsx6("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.08)" } })
990
+ ]
991
+ }
992
+ ),
993
+ showEmail && /* @__PURE__ */ jsxs5("form", { onSubmit: startOtp, "data-elvix-method": "email_otp", children: [
994
+ /* @__PURE__ */ jsx6("label", { htmlFor: "elvix-email", style: labelStyle, children: "Email" }),
995
+ /* @__PURE__ */ jsx6(
996
+ "input",
997
+ {
998
+ id: "elvix-email",
999
+ type: "email",
1000
+ value: email,
1001
+ onChange: (ev) => setEmail(ev.target.value),
1002
+ placeholder: copy.emailPlaceholder,
1003
+ required: true,
1004
+ disabled: busy,
1005
+ autoComplete: "email",
1006
+ style: inputStyle
1007
+ }
1008
+ ),
1009
+ /* @__PURE__ */ jsx6("button", { type: "submit", disabled: busy, style: primaryBtnStyle, children: busy ? copy.sendingLabel : copy.sendCodeButton })
1010
+ ] })
1011
+ ] }),
1012
+ step === "code" && /* @__PURE__ */ jsxs5("form", { onSubmit: verifyOtp, children: [
1013
+ /* @__PURE__ */ jsx6("label", { htmlFor: "elvix-code", style: labelStyle, children: "Verification code" }),
1014
+ /* @__PURE__ */ jsx6(
1015
+ "input",
1016
+ {
1017
+ id: "elvix-code",
1018
+ type: "text",
1019
+ inputMode: "numeric",
1020
+ pattern: "[0-9]*",
1021
+ maxLength: 6,
1022
+ value: code,
1023
+ onChange: (ev) => setCode(ev.target.value.replace(/\D/g, "")),
1024
+ placeholder: copy.codePlaceholder,
1025
+ required: true,
1026
+ disabled: busy,
1027
+ autoComplete: "one-time-code",
1028
+ autoFocus: true,
1029
+ style: { ...inputStyle, letterSpacing: "0.3em", textAlign: "center", fontSize: 18 }
1030
+ }
1031
+ ),
1032
+ /* @__PURE__ */ jsx6("button", { type: "submit", disabled: busy, style: primaryBtnStyle, children: busy ? copy.verifyingLabel : submitLabel }),
1033
+ /* @__PURE__ */ jsx6(
1034
+ "button",
1035
+ {
1036
+ type: "button",
1037
+ onClick: () => {
1038
+ setStep("identify");
1039
+ setCode("");
1040
+ setError(null);
1041
+ },
1042
+ disabled: busy,
1043
+ style: {
1044
+ marginTop: 12,
1045
+ background: "none",
1046
+ border: "none",
1047
+ color: "#71717a",
1048
+ fontSize: 12.5,
1049
+ cursor: busy ? "not-allowed" : "pointer"
1050
+ },
1051
+ children: "Use a different email"
1052
+ }
1053
+ )
1054
+ ] }),
1055
+ error && /* @__PURE__ */ jsx6("p", { role: "alert", style: { margin: 0, fontSize: 12.5, color: "#dc2626" }, children: error }),
1056
+ hasLegal && step !== "done" && /* @__PURE__ */ jsxs5("p", { style: { margin: 0, fontSize: 11.5, lineHeight: 1.5, color: "#a1a1aa" }, children: [
1057
+ "By continuing, you agree to ",
1058
+ appName,
1059
+ "'s",
1060
+ " ",
1061
+ termsUrl && /* @__PURE__ */ jsx6(
1062
+ "a",
1063
+ {
1064
+ href: termsUrl,
1065
+ target: "_blank",
1066
+ rel: "noopener noreferrer",
1067
+ style: { color: "#71717a", textDecoration: "underline" },
1068
+ children: "Terms of Service"
1069
+ }
1070
+ ),
1071
+ termsUrl && privacyUrl && " \xB7 ",
1072
+ privacyUrl && /* @__PURE__ */ jsx6(
1073
+ "a",
1074
+ {
1075
+ href: privacyUrl,
1076
+ target: "_blank",
1077
+ rel: "noopener noreferrer",
1078
+ style: { color: "#71717a", textDecoration: "underline" },
1079
+ children: "Privacy Policy"
1080
+ }
1081
+ )
1082
+ ] }),
1083
+ /* @__PURE__ */ jsx6("div", { style: { display: "flex", justifyContent: "center", paddingTop: 2 }, children: /* @__PURE__ */ jsx6(ElvixSecuredBadge, { variant: "outline", theme: "light", size: "sm", accentColor: brand }) })
398
1084
  ] });
399
1085
  }
400
-
401
- // src/react/elvix-sign-in-button.tsx
402
- import { useState as useState3 } from "react";
403
-
404
- // src/react/elvix-shield.tsx
405
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
406
- function ElvixShield({
407
- size,
408
- fill,
409
- accent
410
- }) {
411
- return /* @__PURE__ */ jsxs3("svg", { width: size, height: size, viewBox: "2 2 20 20", "aria-hidden": true, style: { display: "block" }, children: [
412
- /* @__PURE__ */ jsx4(
413
- "path",
414
- {
415
- fill,
416
- fillRule: "evenodd",
417
- d: "M 6 2.5 C 4.34 2.5 3 3.84 3 5.5 L 3 12.5 C 3 17.5 7 20.7 12 22 C 17 20.7 21 17.5 21 12.5 L 21 5.5 C 21 3.84 19.66 2.5 18 2.5 L 6 2.5 Z M 12 8.4 C 9.79 8.4 8 10.19 8 12.4 C 8 14.61 9.79 16.4 12 16.4 C 13.21 16.4 14.3 15.86 15.04 15 L 13.6 13.77 C 13.21 14.23 12.64 14.5 12 14.5 C 11.04 14.5 10.21 13.86 9.91 13 L 15.95 13 C 15.98 12.8 16 12.6 16 12.4 C 16 10.19 14.21 8.4 12 8.4 Z M 9.91 11.8 L 14.09 11.8 C 13.79 10.94 12.96 10.3 12 10.3 C 11.04 10.3 10.21 10.94 9.91 11.8 Z"
418
- }
419
- ),
420
- /* @__PURE__ */ jsx4("circle", { cx: "19.5", cy: "4.5", r: "2.4", fill: accent })
421
- ] });
1086
+ function hexToRgba(hex, alpha) {
1087
+ const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
1088
+ if (!m) return hex;
1089
+ let h = m[1];
1090
+ if (h.length === 3)
1091
+ h = h.split("").map((c) => c + c).join("");
1092
+ const n = Number.parseInt(h, 16);
1093
+ const r = n >> 16 & 255;
1094
+ const g = n >> 8 & 255;
1095
+ const b = n & 255;
1096
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
422
1097
  }
423
1098
 
424
1099
  // src/react/elvix-sign-in-button.tsx
425
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
426
- var ELVIX_URL = "https://elvix.is";
1100
+ import { useState as useState4 } from "react";
1101
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1102
+ var ELVIX_URL2 = "https://elvix.is";
427
1103
  var PRESET_LABEL = {
428
1104
  "sign-in-with-elvix": "Sign in with elvix",
429
1105
  "continue-with-elvix": "Continue with elvix",
@@ -462,7 +1138,7 @@ function shieldColor(variant, theme) {
462
1138
  }
463
1139
  function ElvixSignInButton({
464
1140
  clientId,
465
- baseUrl = ELVIX_URL,
1141
+ baseUrl = ELVIX_URL2,
466
1142
  returnUrl,
467
1143
  type = "standard",
468
1144
  variant = "filled",
@@ -475,9 +1151,16 @@ function ElvixSignInButton({
475
1151
  href,
476
1152
  mode = "redirect",
477
1153
  onClick,
478
- onResult
1154
+ onResult,
1155
+ width,
1156
+ height,
1157
+ minWidth,
1158
+ maxWidth,
1159
+ minHeight,
1160
+ maxHeight
479
1161
  }) {
480
- const [embedOpen, setEmbedOpen] = useState3(false);
1162
+ const sized = sizeStyle({ width, height, minWidth, maxWidth, minHeight, maxHeight });
1163
+ const [embedOpen, setEmbedOpen] = useState4(false);
481
1164
  const isIcon = type === "icon";
482
1165
  const resolvedLabel = label ?? PRESET_LABEL[preset];
483
1166
  const tone = variantTone(variant, theme);
@@ -498,18 +1181,20 @@ function ElvixSignInButton({
498
1181
  border: tone.border,
499
1182
  boxShadow: tone.shadow,
500
1183
  transition: "background 0.15s, border-color 0.15s",
501
- ...isIcon ? { height: SIZE_ICON[size], width: SIZE_ICON[size] } : { height: std.height, paddingLeft: std.padX, paddingRight: std.padX, gap: std.gap }
1184
+ ...isIcon ? { height: SIZE_ICON[size], width: SIZE_ICON[size] } : { height: std.height, paddingLeft: std.padX, paddingRight: std.padX, gap: std.gap },
1185
+ // Dimensional overrides win over the size preset above.
1186
+ ...sized
502
1187
  };
503
- const content = /* @__PURE__ */ jsxs4(Fragment2, { children: [
504
- /* @__PURE__ */ jsx5(ElvixShield, { size: ICON_SIZE[size], fill: shieldColor(variant, theme), accent: "#8e7dff" }),
505
- isIcon ? null : /* @__PURE__ */ jsx5("span", { children: resolvedLabel })
1188
+ const content = /* @__PURE__ */ jsxs6(Fragment2, { children: [
1189
+ /* @__PURE__ */ jsx7(ElvixShield, { size: ICON_SIZE[size], fill: shieldColor(variant, theme), accent: "#8e7dff" }),
1190
+ isIcon ? null : /* @__PURE__ */ jsx7("span", { children: resolvedLabel })
506
1191
  ] });
507
1192
  if (mode === "callback") {
508
- return /* @__PURE__ */ jsx5("button", { type: "button", onClick, className, style, "aria-label": isIcon ? resolvedLabel : void 0, children: content });
1193
+ return /* @__PURE__ */ jsx7("button", { type: "button", onClick, className, style, "aria-label": isIcon ? resolvedLabel : void 0, children: content });
509
1194
  }
510
1195
  if (mode === "embed") {
511
- return /* @__PURE__ */ jsxs4("div", { "data-elvix-signin-button-embed": "", children: [
512
- !embedOpen && /* @__PURE__ */ jsx5(
1196
+ return /* @__PURE__ */ jsxs6("div", { "data-elvix-signin-button-embed": "", style: sized, children: [
1197
+ !embedOpen && /* @__PURE__ */ jsx7(
513
1198
  "button",
514
1199
  {
515
1200
  type: "button",
@@ -520,7 +1205,7 @@ function ElvixSignInButton({
520
1205
  children: content
521
1206
  }
522
1207
  ),
523
- embedOpen && /* @__PURE__ */ jsx5(
1208
+ embedOpen && /* @__PURE__ */ jsx7(
524
1209
  ElvixSignIn,
525
1210
  {
526
1211
  onResult: (r) => {
@@ -537,86 +1222,17 @@ function ElvixSignInButton({
537
1222
  const sep = base.includes("?") ? "&" : "?";
538
1223
  return `${base}${sep}return=${encodeURIComponent(returnUrl)}`;
539
1224
  })();
540
- return /* @__PURE__ */ jsx5("a", { href: destination, className, style, "aria-label": isIcon ? resolvedLabel : void 0, children: content });
541
- }
542
-
543
- // src/react/elvix-secured-badge.tsx
544
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
545
- var ELVIX_URL2 = "https://elvix.is";
546
- var SIZE = {
547
- sm: { height: 28, padX: 10, font: 11.5, icon: 14, gap: 6 },
548
- md: { height: 32, padX: 12, font: 12.5, icon: 16, gap: 7 },
549
- lg: { height: 36, padX: 14, font: 13, icon: 18, gap: 8 }
550
- };
551
- var TONE = {
552
- white: {
553
- light: { bg: "#ffffff", border: "#e4e4e7", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" },
554
- dark: { bg: "#ffffff", border: "transparent", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" }
555
- },
556
- dark: {
557
- light: { bg: "#0a0a0b", border: "rgba(0,0,0,0.1)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" },
558
- dark: { bg: "#0a0a0b", border: "rgba(255,255,255,0.1)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" }
559
- },
560
- outline: {
561
- light: { bg: "transparent", border: "rgba(0,0,0,0.15)", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" },
562
- dark: { bg: "transparent", border: "rgba(142,125,255,0.4)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" }
563
- }
564
- };
565
- function ElvixSecuredBadge({
566
- variant = "white",
567
- size = "md",
568
- theme = "dark",
569
- accentColor = "#8e7dff",
570
- href = ELVIX_URL2,
571
- className = ""
572
- }) {
573
- const s = SIZE[size];
574
- const t = TONE[variant][theme];
575
- const style = {
576
- display: "inline-flex",
577
- alignItems: "center",
578
- gap: s.gap,
579
- height: s.height,
580
- paddingLeft: s.padX,
581
- paddingRight: s.padX,
582
- fontSize: s.font,
583
- fontWeight: 500,
584
- borderRadius: 9999,
585
- background: t.bg,
586
- border: `1px solid ${t.border}`,
587
- color: t.brand,
588
- textDecoration: "none",
589
- userSelect: "none",
590
- lineHeight: 1
591
- };
592
- return /* @__PURE__ */ jsxs5(
593
- "a",
594
- {
595
- href,
596
- target: "_blank",
597
- rel: "noopener noreferrer",
598
- className,
599
- style,
600
- "data-elvix-secured-badge": "",
601
- children: [
602
- /* @__PURE__ */ jsx6(ElvixShield, { size: s.icon, fill: t.shield, accent: accentColor }),
603
- /* @__PURE__ */ jsxs5("span", { style: { display: "inline-flex", alignItems: "baseline", gap: 4 }, children: [
604
- /* @__PURE__ */ jsx6("span", { style: { color: t.lead }, children: "Secured by" }),
605
- /* @__PURE__ */ jsx6("span", { style: { color: t.brand, fontWeight: 600 }, children: "elvix" })
606
- ] })
607
- ]
608
- }
609
- );
1225
+ return /* @__PURE__ */ jsx7("a", { href: destination, className, style, "aria-label": isIcon ? resolvedLabel : void 0, children: content });
610
1226
  }
611
1227
 
612
1228
  // src/react/hooks.ts
613
- import { useCallback, useEffect as useEffect2, useState as useState4 } from "react";
1229
+ import { useCallback, useEffect as useEffect2, useState as useState5 } from "react";
614
1230
  var POLL_MS = 7e3;
615
1231
  function useUserList(kind, opts) {
616
1232
  const { applicationId, baseUrl = "", pollMs = POLL_MS } = opts;
617
- const [slugs, setSlugs] = useState4([]);
618
- const [loading, setLoading] = useState4(true);
619
- const [error, setError] = useState4(null);
1233
+ const [slugs, setSlugs] = useState5([]);
1234
+ const [loading, setLoading] = useState5(true);
1235
+ const [error, setError] = useState5(null);
620
1236
  const refresh = useCallback(async () => {
621
1237
  setError(null);
622
1238
  try {
@@ -683,7 +1299,7 @@ function ElvixLifecycleWatcher({
683
1299
  }
684
1300
 
685
1301
  // src/react/elvix-username.tsx
686
- import { useState as useState5 } from "react";
1302
+ import { useState as useState6 } from "react";
687
1303
 
688
1304
  // src/react/lib.ts
689
1305
  async function appPost(opts, path, body) {
@@ -741,15 +1357,22 @@ async function appDelete(opts, path) {
741
1357
  }
742
1358
 
743
1359
  // src/react/elvix-username.tsx
744
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1360
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
745
1361
  function ElvixUsername({
746
- onResult
1362
+ onResult,
1363
+ width,
1364
+ height,
1365
+ minWidth,
1366
+ maxWidth,
1367
+ minHeight,
1368
+ maxHeight
747
1369
  }) {
1370
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
748
1371
  const ctx = useElvixContext();
749
- const [value, setValue] = useState5("");
750
- const [busy, setBusy] = useState5(false);
751
- const [error, setError] = useState5(null);
752
- const [done, setDone] = useState5(null);
1372
+ const [value, setValue] = useState6("");
1373
+ const [busy, setBusy] = useState6(false);
1374
+ const [error, setError] = useState6(null);
1375
+ const [done, setDone] = useState6(null);
753
1376
  async function submit(e) {
754
1377
  e.preventDefault();
755
1378
  if (!ctx.app) return;
@@ -769,17 +1392,17 @@ function ElvixUsername({
769
1392
  onResult?.(result);
770
1393
  }
771
1394
  if (done) {
772
- return /* @__PURE__ */ jsx7(ElvixCard, { title: "Username saved", children: /* @__PURE__ */ jsxs6("p", { children: [
1395
+ return /* @__PURE__ */ jsx8(ElvixCard, { title: "Username saved", ...sizeProps, children: /* @__PURE__ */ jsxs7("p", { children: [
773
1396
  "You are now ",
774
- /* @__PURE__ */ jsxs6("strong", { children: [
1397
+ /* @__PURE__ */ jsxs7("strong", { children: [
775
1398
  "@",
776
1399
  done
777
1400
  ] }),
778
1401
  "."
779
1402
  ] }) });
780
1403
  }
781
- return /* @__PURE__ */ jsx7(ElvixCard, { title: "Choose a username", children: /* @__PURE__ */ jsxs6("form", { onSubmit: submit, className: "elvix-form", children: [
782
- /* @__PURE__ */ jsx7(
1404
+ return /* @__PURE__ */ jsx8(ElvixCard, { title: "Choose a username", ...sizeProps, children: /* @__PURE__ */ jsxs7("form", { onSubmit: submit, className: "elvix-form", children: [
1405
+ /* @__PURE__ */ jsx8(
783
1406
  "input",
784
1407
  {
785
1408
  type: "text",
@@ -792,21 +1415,28 @@ function ElvixUsername({
792
1415
  className: "elvix-input"
793
1416
  }
794
1417
  ),
795
- /* @__PURE__ */ jsx7("button", { type: "submit", disabled: busy || value.length < 4, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Claim" }),
796
- error && /* @__PURE__ */ jsx7("p", { role: "alert", className: "elvix-error", children: error })
1418
+ /* @__PURE__ */ jsx8("button", { type: "submit", disabled: busy || value.length < 4, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Claim" }),
1419
+ error && /* @__PURE__ */ jsx8("p", { role: "alert", className: "elvix-error", children: error })
797
1420
  ] }) });
798
1421
  }
799
1422
 
800
1423
  // src/react/elvix-avatar.tsx
801
- import { useState as useState6 } from "react";
802
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1424
+ import { useState as useState7 } from "react";
1425
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
803
1426
  function ElvixAvatar({
804
- onResult
1427
+ onResult,
1428
+ width,
1429
+ height,
1430
+ minWidth,
1431
+ maxWidth,
1432
+ minHeight,
1433
+ maxHeight
805
1434
  }) {
1435
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
806
1436
  const ctx = useElvixContext();
807
- const [busy, setBusy] = useState6(false);
808
- const [error, setError] = useState6(null);
809
- const [preview, setPreview] = useState6(null);
1437
+ const [busy, setBusy] = useState7(false);
1438
+ const [error, setError] = useState7(null);
1439
+ const [preview, setPreview] = useState7(null);
810
1440
  async function onFile(e) {
811
1441
  const file = e.target.files?.[0];
812
1442
  if (!file || !ctx.app) return;
@@ -829,8 +1459,8 @@ function ElvixAvatar({
829
1459
  if (!result.ok) setError(result.error);
830
1460
  onResult?.(result);
831
1461
  }
832
- return /* @__PURE__ */ jsxs7(ElvixCard, { title: "Avatar", children: [
833
- preview && /* @__PURE__ */ jsx8(
1462
+ return /* @__PURE__ */ jsxs8(ElvixCard, { title: "Avatar", ...sizeProps, children: [
1463
+ preview && /* @__PURE__ */ jsx9(
834
1464
  "img",
835
1465
  {
836
1466
  src: preview,
@@ -838,22 +1468,29 @@ function ElvixAvatar({
838
1468
  style: { width: 96, height: 96, borderRadius: "50%", objectFit: "cover", marginBottom: 12 }
839
1469
  }
840
1470
  ),
841
- /* @__PURE__ */ jsx8("input", { type: "file", accept: "image/png,image/jpeg,image/webp", onChange: onFile, disabled: busy }),
842
- busy && /* @__PURE__ */ jsx8("p", { children: "Uploading\u2026" }),
843
- error && /* @__PURE__ */ jsx8("p", { role: "alert", className: "elvix-error", children: error })
1471
+ /* @__PURE__ */ jsx9("input", { type: "file", accept: "image/png,image/jpeg,image/webp", onChange: onFile, disabled: busy }),
1472
+ busy && /* @__PURE__ */ jsx9("p", { children: "Uploading\u2026" }),
1473
+ error && /* @__PURE__ */ jsx9("p", { role: "alert", className: "elvix-error", children: error })
844
1474
  ] });
845
1475
  }
846
1476
 
847
1477
  // src/react/elvix-banner.tsx
848
- import { useState as useState7 } from "react";
849
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1478
+ import { useState as useState8 } from "react";
1479
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
850
1480
  function ElvixBanner({
851
- onResult
1481
+ onResult,
1482
+ width,
1483
+ height,
1484
+ minWidth,
1485
+ maxWidth,
1486
+ minHeight,
1487
+ maxHeight
852
1488
  }) {
1489
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
853
1490
  const ctx = useElvixContext();
854
- const [busy, setBusy] = useState7(false);
855
- const [error, setError] = useState7(null);
856
- const [preview, setPreview] = useState7(null);
1491
+ const [busy, setBusy] = useState8(false);
1492
+ const [error, setError] = useState8(null);
1493
+ const [preview, setPreview] = useState8(null);
857
1494
  async function onFile(e) {
858
1495
  const file = e.target.files?.[0];
859
1496
  if (!file || !ctx.app) return;
@@ -876,8 +1513,8 @@ function ElvixBanner({
876
1513
  if (!result.ok) setError(result.error);
877
1514
  onResult?.(result);
878
1515
  }
879
- return /* @__PURE__ */ jsxs8(ElvixCard, { title: "Banner", children: [
880
- preview && /* @__PURE__ */ jsx9(
1516
+ return /* @__PURE__ */ jsxs9(ElvixCard, { title: "Banner", ...sizeProps, children: [
1517
+ preview && /* @__PURE__ */ jsx10(
881
1518
  "img",
882
1519
  {
883
1520
  src: preview,
@@ -885,26 +1522,33 @@ function ElvixBanner({
885
1522
  style: { width: "100%", aspectRatio: "16/9", objectFit: "cover", borderRadius: 10, marginBottom: 12 }
886
1523
  }
887
1524
  ),
888
- /* @__PURE__ */ jsx9("input", { type: "file", accept: "image/png,image/jpeg,image/webp", onChange: onFile, disabled: busy }),
889
- busy && /* @__PURE__ */ jsx9("p", { children: "Uploading\u2026" }),
890
- error && /* @__PURE__ */ jsx9("p", { role: "alert", className: "elvix-error", children: error })
1525
+ /* @__PURE__ */ jsx10("input", { type: "file", accept: "image/png,image/jpeg,image/webp", onChange: onFile, disabled: busy }),
1526
+ busy && /* @__PURE__ */ jsx10("p", { children: "Uploading\u2026" }),
1527
+ error && /* @__PURE__ */ jsx10("p", { role: "alert", className: "elvix-error", children: error })
891
1528
  ] });
892
1529
  }
893
1530
 
894
1531
  // src/react/elvix-identity-form.tsx
895
- import { useState as useState8 } from "react";
896
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1532
+ import { useState as useState9 } from "react";
1533
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
897
1534
  function ElvixIdentityForm({
898
1535
  initialName = "",
899
1536
  initialBio = "",
900
- onResult
1537
+ onResult,
1538
+ width,
1539
+ height,
1540
+ minWidth,
1541
+ maxWidth,
1542
+ minHeight,
1543
+ maxHeight
901
1544
  }) {
1545
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
902
1546
  const ctx = useElvixContext();
903
- const [name, setName] = useState8(initialName);
904
- const [bio, setBio] = useState8(initialBio);
905
- const [busy, setBusy] = useState8(false);
906
- const [error, setError] = useState8(null);
907
- const [saved, setSaved] = useState8(false);
1547
+ const [name, setName] = useState9(initialName);
1548
+ const [bio, setBio] = useState9(initialBio);
1549
+ const [busy, setBusy] = useState9(false);
1550
+ const [error, setError] = useState9(null);
1551
+ const [saved, setSaved] = useState9(false);
908
1552
  async function submit(e) {
909
1553
  e.preventDefault();
910
1554
  if (!ctx.app) return;
@@ -920,35 +1564,42 @@ function ElvixIdentityForm({
920
1564
  else setSaved(true);
921
1565
  onResult?.(result);
922
1566
  }
923
- return /* @__PURE__ */ jsx10(ElvixCard, { title: "Identity", children: /* @__PURE__ */ jsxs9("form", { onSubmit: submit, className: "elvix-form", children: [
924
- /* @__PURE__ */ jsxs9("label", { children: [
1567
+ return /* @__PURE__ */ jsx11(ElvixCard, { title: "Identity", ...sizeProps, children: /* @__PURE__ */ jsxs10("form", { onSubmit: submit, className: "elvix-form", children: [
1568
+ /* @__PURE__ */ jsxs10("label", { children: [
925
1569
  "Name",
926
- /* @__PURE__ */ jsx10("input", { value: name, onChange: (e) => setName(e.target.value), maxLength: 80, disabled: busy, className: "elvix-input" })
1570
+ /* @__PURE__ */ jsx11("input", { value: name, onChange: (e) => setName(e.target.value), maxLength: 80, disabled: busy, className: "elvix-input" })
927
1571
  ] }),
928
- /* @__PURE__ */ jsxs9("label", { children: [
1572
+ /* @__PURE__ */ jsxs10("label", { children: [
929
1573
  "Bio",
930
- /* @__PURE__ */ jsx10("textarea", { value: bio, onChange: (e) => setBio(e.target.value), maxLength: 500, rows: 3, disabled: busy, className: "elvix-input" })
1574
+ /* @__PURE__ */ jsx11("textarea", { value: bio, onChange: (e) => setBio(e.target.value), maxLength: 500, rows: 3, disabled: busy, className: "elvix-input" })
931
1575
  ] }),
932
- /* @__PURE__ */ jsx10("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" }),
933
- saved && /* @__PURE__ */ jsx10("p", { className: "elvix-muted", children: "Saved." }),
934
- error && /* @__PURE__ */ jsx10("p", { role: "alert", className: "elvix-error", children: error })
1576
+ /* @__PURE__ */ jsx11("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" }),
1577
+ saved && /* @__PURE__ */ jsx11("p", { className: "elvix-muted", children: "Saved." }),
1578
+ error && /* @__PURE__ */ jsx11("p", { role: "alert", className: "elvix-error", children: error })
935
1579
  ] }) });
936
1580
  }
937
1581
 
938
1582
  // src/react/elvix-region.tsx
939
- import { useState as useState9 } from "react";
940
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1583
+ import { useState as useState10 } from "react";
1584
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
941
1585
  function ElvixRegion({
942
1586
  initialCountry = "",
943
1587
  initialTimezone = "",
944
- onResult
1588
+ onResult,
1589
+ width,
1590
+ height,
1591
+ minWidth,
1592
+ maxWidth,
1593
+ minHeight,
1594
+ maxHeight
945
1595
  }) {
1596
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
946
1597
  const ctx = useElvixContext();
947
- const [country, setCountry] = useState9(initialCountry);
948
- const [timezone, setTimezone] = useState9(initialTimezone);
949
- const [busy, setBusy] = useState9(false);
950
- const [error, setError] = useState9(null);
951
- const [saved, setSaved] = useState9(false);
1598
+ const [country, setCountry] = useState10(initialCountry);
1599
+ const [timezone, setTimezone] = useState10(initialTimezone);
1600
+ const [busy, setBusy] = useState10(false);
1601
+ const [error, setError] = useState10(null);
1602
+ const [saved, setSaved] = useState10(false);
952
1603
  async function submit(e) {
953
1604
  e.preventDefault();
954
1605
  if (!ctx.app) return;
@@ -964,33 +1615,40 @@ function ElvixRegion({
964
1615
  else setSaved(true);
965
1616
  onResult?.(result);
966
1617
  }
967
- return /* @__PURE__ */ jsx11(ElvixCard, { title: "Region", children: /* @__PURE__ */ jsxs10("form", { onSubmit: submit, className: "elvix-form", children: [
968
- /* @__PURE__ */ jsxs10("label", { children: [
1618
+ return /* @__PURE__ */ jsx12(ElvixCard, { title: "Region", ...sizeProps, children: /* @__PURE__ */ jsxs11("form", { onSubmit: submit, className: "elvix-form", children: [
1619
+ /* @__PURE__ */ jsxs11("label", { children: [
969
1620
  "Country (ISO-2)",
970
- /* @__PURE__ */ jsx11("input", { value: country, onChange: (e) => setCountry(e.target.value.toUpperCase()), maxLength: 2, pattern: "[A-Z]{2}", disabled: busy, className: "elvix-input" })
1621
+ /* @__PURE__ */ jsx12("input", { value: country, onChange: (e) => setCountry(e.target.value.toUpperCase()), maxLength: 2, pattern: "[A-Z]{2}", disabled: busy, className: "elvix-input" })
971
1622
  ] }),
972
- /* @__PURE__ */ jsxs10("label", { children: [
1623
+ /* @__PURE__ */ jsxs11("label", { children: [
973
1624
  "Timezone",
974
- /* @__PURE__ */ jsx11("input", { value: timezone, onChange: (e) => setTimezone(e.target.value), placeholder: "Europe/Berlin", disabled: busy, className: "elvix-input" })
1625
+ /* @__PURE__ */ jsx12("input", { value: timezone, onChange: (e) => setTimezone(e.target.value), placeholder: "Europe/Berlin", disabled: busy, className: "elvix-input" })
975
1626
  ] }),
976
- /* @__PURE__ */ jsx11("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" }),
977
- saved && /* @__PURE__ */ jsx11("p", { className: "elvix-muted", children: "Saved." }),
978
- error && /* @__PURE__ */ jsx11("p", { role: "alert", className: "elvix-error", children: error })
1627
+ /* @__PURE__ */ jsx12("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" }),
1628
+ saved && /* @__PURE__ */ jsx12("p", { className: "elvix-muted", children: "Saved." }),
1629
+ error && /* @__PURE__ */ jsx12("p", { role: "alert", className: "elvix-error", children: error })
979
1630
  ] }) });
980
1631
  }
981
1632
 
982
1633
  // src/react/elvix-languages.tsx
983
- import { useState as useState10 } from "react";
984
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1634
+ import { useState as useState11 } from "react";
1635
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
985
1636
  function ElvixLanguages({
986
1637
  initial = [],
987
- onResult
1638
+ onResult,
1639
+ width,
1640
+ height,
1641
+ minWidth,
1642
+ maxWidth,
1643
+ minHeight,
1644
+ maxHeight
988
1645
  }) {
1646
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
989
1647
  const ctx = useElvixContext();
990
- const [raw, setRaw] = useState10(initial.join(", "));
991
- const [busy, setBusy] = useState10(false);
992
- const [error, setError] = useState10(null);
993
- const [saved, setSaved] = useState10(false);
1648
+ const [raw, setRaw] = useState11(initial.join(", "));
1649
+ const [busy, setBusy] = useState11(false);
1650
+ const [error, setError] = useState11(null);
1651
+ const [saved, setSaved] = useState11(false);
994
1652
  async function submit(e) {
995
1653
  e.preventDefault();
996
1654
  if (!ctx.app) return;
@@ -1007,27 +1665,34 @@ function ElvixLanguages({
1007
1665
  else setSaved(true);
1008
1666
  onResult?.(result);
1009
1667
  }
1010
- return /* @__PURE__ */ jsx12(ElvixCard, { title: "Languages", children: /* @__PURE__ */ jsxs11("form", { onSubmit: submit, className: "elvix-form", children: [
1011
- /* @__PURE__ */ jsxs11("label", { children: [
1668
+ return /* @__PURE__ */ jsx13(ElvixCard, { title: "Languages", ...sizeProps, children: /* @__PURE__ */ jsxs12("form", { onSubmit: submit, className: "elvix-form", children: [
1669
+ /* @__PURE__ */ jsxs12("label", { children: [
1012
1670
  "Preferred languages (comma-separated BCP-47 tags)",
1013
- /* @__PURE__ */ jsx12("input", { value: raw, onChange: (e) => setRaw(e.target.value), placeholder: "en-GB, de-DE", disabled: busy, className: "elvix-input" })
1671
+ /* @__PURE__ */ jsx13("input", { value: raw, onChange: (e) => setRaw(e.target.value), placeholder: "en-GB, de-DE", disabled: busy, className: "elvix-input" })
1014
1672
  ] }),
1015
- /* @__PURE__ */ jsx12("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" }),
1016
- saved && /* @__PURE__ */ jsx12("p", { className: "elvix-muted", children: "Saved." }),
1017
- error && /* @__PURE__ */ jsx12("p", { role: "alert", className: "elvix-error", children: error })
1673
+ /* @__PURE__ */ jsx13("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" }),
1674
+ saved && /* @__PURE__ */ jsx13("p", { className: "elvix-muted", children: "Saved." }),
1675
+ error && /* @__PURE__ */ jsx13("p", { role: "alert", className: "elvix-error", children: error })
1018
1676
  ] }) });
1019
1677
  }
1020
1678
 
1021
1679
  // src/react/elvix-sessions.tsx
1022
- import { useEffect as useEffect4, useState as useState11 } from "react";
1023
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1680
+ import { useEffect as useEffect4, useState as useState12 } from "react";
1681
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1024
1682
  function ElvixSessions({
1025
- onResult
1683
+ onResult,
1684
+ width,
1685
+ height,
1686
+ minWidth,
1687
+ maxWidth,
1688
+ minHeight,
1689
+ maxHeight
1026
1690
  }) {
1691
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
1027
1692
  const ctx = useElvixContext();
1028
- const [rows, setRows] = useState11(null);
1029
- const [error, setError] = useState11(null);
1030
- const [busy, setBusy] = useState11(false);
1693
+ const [rows, setRows] = useState12(null);
1694
+ const [error, setError] = useState12(null);
1695
+ const [busy, setBusy] = useState12(false);
1031
1696
  useEffect4(() => {
1032
1697
  if (!ctx.app) return;
1033
1698
  fetch(`${ctx.baseUrl}/api/account/apps/${ctx.app.applicationId}/sessions`, {
@@ -1048,36 +1713,43 @@ function ElvixSessions({
1048
1713
  if (result.ok) setRows((prev) => prev?.filter((s) => s.id !== id) ?? null);
1049
1714
  onResult?.(result);
1050
1715
  }
1051
- return /* @__PURE__ */ jsxs12(ElvixCard, { title: "Active sessions", children: [
1052
- error && /* @__PURE__ */ jsx13("p", { role: "alert", className: "elvix-error", children: error }),
1053
- !rows && !error && /* @__PURE__ */ jsx13("p", { children: "Loading\u2026" }),
1054
- rows && /* @__PURE__ */ jsx13("ul", { style: { listStyle: "none", padding: 0, margin: 0 }, children: rows.map((s) => /* @__PURE__ */ jsx13("li", { style: { padding: "10px 0", borderBottom: "1px solid rgba(0,0,0,0.06)" }, children: /* @__PURE__ */ jsxs12("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
1055
- /* @__PURE__ */ jsxs12("div", { children: [
1056
- /* @__PURE__ */ jsxs12("div", { style: { fontSize: 13, fontWeight: 500 }, children: [
1716
+ return /* @__PURE__ */ jsxs13(ElvixCard, { title: "Active sessions", ...sizeProps, children: [
1717
+ error && /* @__PURE__ */ jsx14("p", { role: "alert", className: "elvix-error", children: error }),
1718
+ !rows && !error && /* @__PURE__ */ jsx14("p", { children: "Loading\u2026" }),
1719
+ rows && /* @__PURE__ */ jsx14("ul", { style: { listStyle: "none", padding: 0, margin: 0 }, children: rows.map((s) => /* @__PURE__ */ jsx14("li", { style: { padding: "10px 0", borderBottom: "1px solid rgba(0,0,0,0.06)" }, children: /* @__PURE__ */ jsxs13("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 }, children: [
1720
+ /* @__PURE__ */ jsxs13("div", { children: [
1721
+ /* @__PURE__ */ jsxs13("div", { style: { fontSize: 13, fontWeight: 500 }, children: [
1057
1722
  s.device,
1058
- s.current && /* @__PURE__ */ jsx13("span", { style: { marginLeft: 8, color: "var(--elvix-primary-strong)", fontSize: 11 }, children: "\xB7 this device" })
1723
+ s.current && /* @__PURE__ */ jsx14("span", { style: { marginLeft: 8, color: "var(--elvix-primary-strong)", fontSize: 11 }, children: "\xB7 this device" })
1059
1724
  ] }),
1060
- /* @__PURE__ */ jsxs12("div", { style: { fontSize: 11, color: "rgba(0,0,0,0.55)" }, children: [
1725
+ /* @__PURE__ */ jsxs13("div", { style: { fontSize: 11, color: "rgba(0,0,0,0.55)" }, children: [
1061
1726
  s.country ?? "\u2014",
1062
1727
  " \xB7 since ",
1063
1728
  new Date(s.createdAt).toLocaleDateString()
1064
1729
  ] })
1065
1730
  ] }),
1066
- !s.current && /* @__PURE__ */ jsx13("button", { type: "button", disabled: busy, onClick: () => revoke(s.id), className: "elvix-btn elvix-btn-ghost", children: "Revoke" })
1731
+ !s.current && /* @__PURE__ */ jsx14("button", { type: "button", disabled: busy, onClick: () => revoke(s.id), className: "elvix-btn elvix-btn-ghost", children: "Revoke" })
1067
1732
  ] }) }, s.id)) })
1068
1733
  ] });
1069
1734
  }
1070
1735
 
1071
1736
  // src/react/elvix-export.tsx
1072
- import { useState as useState12 } from "react";
1073
- import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1737
+ import { useState as useState13 } from "react";
1738
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
1074
1739
  function ElvixExport({
1075
- onResult
1740
+ onResult,
1741
+ width,
1742
+ height,
1743
+ minWidth,
1744
+ maxWidth,
1745
+ minHeight,
1746
+ maxHeight
1076
1747
  }) {
1748
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
1077
1749
  const ctx = useElvixContext();
1078
- const [busy, setBusy] = useState12(false);
1079
- const [done, setDone] = useState12(false);
1080
- const [error, setError] = useState12(null);
1750
+ const [busy, setBusy] = useState13(false);
1751
+ const [done, setDone] = useState13(false);
1752
+ const [error, setError] = useState13(null);
1081
1753
  async function start() {
1082
1754
  if (!ctx.app) return;
1083
1755
  setBusy(true);
@@ -1092,25 +1764,32 @@ function ElvixExport({
1092
1764
  else setDone(true);
1093
1765
  onResult?.(result);
1094
1766
  }
1095
- return /* @__PURE__ */ jsxs13(ElvixCard, { title: "Export my data", children: [
1096
- /* @__PURE__ */ jsx14("p", { style: { fontSize: 13, color: "rgba(0,0,0,0.6)" }, children: "Request a zip of every record we hold for you in this app. Delivery by email; single-use download link valid for 24h." }),
1097
- done ? /* @__PURE__ */ jsx14("p", { className: "elvix-muted", children: "Request queued. Check your email." }) : /* @__PURE__ */ jsx14("button", { type: "button", onClick: start, disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Queuing\u2026" : "Request export" }),
1098
- error && /* @__PURE__ */ jsx14("p", { role: "alert", className: "elvix-error", children: error })
1767
+ return /* @__PURE__ */ jsxs14(ElvixCard, { title: "Export my data", ...sizeProps, children: [
1768
+ /* @__PURE__ */ jsx15("p", { style: { fontSize: 13, color: "rgba(0,0,0,0.6)" }, children: "Request a zip of every record we hold for you in this app. Delivery by email; single-use download link valid for 24h." }),
1769
+ done ? /* @__PURE__ */ jsx15("p", { className: "elvix-muted", children: "Request queued. Check your email." }) : /* @__PURE__ */ jsx15("button", { type: "button", onClick: start, disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Queuing\u2026" : "Request export" }),
1770
+ error && /* @__PURE__ */ jsx15("p", { role: "alert", className: "elvix-error", children: error })
1099
1771
  ] });
1100
1772
  }
1101
1773
 
1102
1774
  // src/react/elvix-deactivate.tsx
1103
- import { useState as useState13 } from "react";
1104
- import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
1775
+ import { useState as useState14 } from "react";
1776
+ import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
1105
1777
  function ElvixDeactivate({
1106
- onResult
1778
+ onResult,
1779
+ width,
1780
+ height,
1781
+ minWidth,
1782
+ maxWidth,
1783
+ minHeight,
1784
+ maxHeight
1107
1785
  }) {
1786
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
1108
1787
  const ctx = useElvixContext();
1109
- const [pane, setPane] = useState13("warn");
1110
- const [challengeId, setChallengeId] = useState13(null);
1111
- const [code, setCode] = useState13("");
1112
- const [busy, setBusy] = useState13(false);
1113
- const [error, setError] = useState13(null);
1788
+ const [pane, setPane] = useState14("warn");
1789
+ const [challengeId, setChallengeId] = useState14(null);
1790
+ const [code, setCode] = useState14("");
1791
+ const [busy, setBusy] = useState14(false);
1792
+ const [error, setError] = useState14(null);
1114
1793
  async function startChallenge() {
1115
1794
  if (!ctx.app) return;
1116
1795
  setBusy(true);
@@ -1148,16 +1827,16 @@ function ElvixDeactivate({
1148
1827
  onResult?.(result);
1149
1828
  }
1150
1829
  if (pane === "done") {
1151
- return /* @__PURE__ */ jsx15(ElvixCard, { title: "Deactivated", children: /* @__PURE__ */ jsx15("p", { children: "Your access has been paused. Sign in again to restore it." }) });
1830
+ return /* @__PURE__ */ jsx16(ElvixCard, { title: "Deactivated", ...sizeProps, children: /* @__PURE__ */ jsx16("p", { children: "Your access has been paused. Sign in again to restore it." }) });
1152
1831
  }
1153
- return /* @__PURE__ */ jsxs14(ElvixCard, { title: "Deactivate account", children: [
1154
- pane === "warn" && /* @__PURE__ */ jsxs14(Fragment3, { children: [
1155
- /* @__PURE__ */ jsx15("p", { style: { fontSize: 13, color: "rgba(0,0,0,0.6)" }, children: "Pause your membership. You can restore it any time by signing in again. No data is deleted." }),
1156
- /* @__PURE__ */ jsx15("button", { type: "button", onClick: startChallenge, disabled: busy, className: "elvix-btn elvix-btn-danger", children: busy ? "Sending\u2026" : "Send code" })
1832
+ return /* @__PURE__ */ jsxs15(ElvixCard, { title: "Deactivate account", ...sizeProps, children: [
1833
+ pane === "warn" && /* @__PURE__ */ jsxs15(Fragment3, { children: [
1834
+ /* @__PURE__ */ jsx16("p", { style: { fontSize: 13, color: "rgba(0,0,0,0.6)" }, children: "Pause your membership. You can restore it any time by signing in again. No data is deleted." }),
1835
+ /* @__PURE__ */ jsx16("button", { type: "button", onClick: startChallenge, disabled: busy, className: "elvix-btn elvix-btn-danger", children: busy ? "Sending\u2026" : "Send code" })
1157
1836
  ] }),
1158
- pane === "otp" && /* @__PURE__ */ jsxs14("form", { onSubmit: confirm, className: "elvix-form", children: [
1159
- /* @__PURE__ */ jsx15("p", { className: "elvix-muted", children: "We sent a 6-digit code to your email." }),
1160
- /* @__PURE__ */ jsx15(
1837
+ pane === "otp" && /* @__PURE__ */ jsxs15("form", { onSubmit: confirm, className: "elvix-form", children: [
1838
+ /* @__PURE__ */ jsx16("p", { className: "elvix-muted", children: "We sent a 6-digit code to your email." }),
1839
+ /* @__PURE__ */ jsx16(
1161
1840
  "input",
1162
1841
  {
1163
1842
  type: "text",
@@ -1171,24 +1850,31 @@ function ElvixDeactivate({
1171
1850
  className: "elvix-input"
1172
1851
  }
1173
1852
  ),
1174
- /* @__PURE__ */ jsx15("button", { type: "submit", disabled: busy || code.length !== 6, className: "elvix-btn elvix-btn-danger", children: busy ? "Deactivating\u2026" : "Confirm" })
1853
+ /* @__PURE__ */ jsx16("button", { type: "submit", disabled: busy || code.length !== 6, className: "elvix-btn elvix-btn-danger", children: busy ? "Deactivating\u2026" : "Confirm" })
1175
1854
  ] }),
1176
- error && /* @__PURE__ */ jsx15("p", { role: "alert", className: "elvix-error", children: error })
1855
+ error && /* @__PURE__ */ jsx16("p", { role: "alert", className: "elvix-error", children: error })
1177
1856
  ] });
1178
1857
  }
1179
1858
 
1180
1859
  // src/react/elvix-leave.tsx
1181
- import { useState as useState14 } from "react";
1182
- import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
1860
+ import { useState as useState15 } from "react";
1861
+ import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
1183
1862
  function ElvixLeave({
1184
- onResult
1863
+ onResult,
1864
+ width,
1865
+ height,
1866
+ minWidth,
1867
+ maxWidth,
1868
+ minHeight,
1869
+ maxHeight
1185
1870
  }) {
1871
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
1186
1872
  const ctx = useElvixContext();
1187
- const [pane, setPane] = useState14("warn");
1188
- const [challengeId, setChallengeId] = useState14(null);
1189
- const [code, setCode] = useState14("");
1190
- const [busy, setBusy] = useState14(false);
1191
- const [error, setError] = useState14(null);
1873
+ const [pane, setPane] = useState15("warn");
1874
+ const [challengeId, setChallengeId] = useState15(null);
1875
+ const [code, setCode] = useState15("");
1876
+ const [busy, setBusy] = useState15(false);
1877
+ const [error, setError] = useState15(null);
1192
1878
  async function startChallenge() {
1193
1879
  if (!ctx.app) return;
1194
1880
  setBusy(true);
@@ -1226,16 +1912,16 @@ function ElvixLeave({
1226
1912
  onResult?.(result);
1227
1913
  }
1228
1914
  if (pane === "done") {
1229
- return /* @__PURE__ */ jsx16(ElvixCard, { title: "You've left", children: /* @__PURE__ */ jsx16("p", { children: "You've left this app. Your data is archived; sign in again to rejoin." }) });
1915
+ return /* @__PURE__ */ jsx17(ElvixCard, { title: "You've left", ...sizeProps, children: /* @__PURE__ */ jsx17("p", { children: "You've left this app. Your data is archived; sign in again to rejoin." }) });
1230
1916
  }
1231
- return /* @__PURE__ */ jsxs15(ElvixCard, { title: "Leave this app", children: [
1232
- pane === "warn" && /* @__PURE__ */ jsxs15(Fragment4, { children: [
1233
- /* @__PURE__ */ jsx16("p", { style: { fontSize: 13, color: "rgba(0,0,0,0.6)" }, children: "Remove yourself from this app. Audit trail is preserved; you can sign back in any time to rejoin." }),
1234
- /* @__PURE__ */ jsx16("button", { type: "button", onClick: startChallenge, disabled: busy, className: "elvix-btn elvix-btn-danger", children: busy ? "Sending\u2026" : "Send code" })
1917
+ return /* @__PURE__ */ jsxs16(ElvixCard, { title: "Leave this app", ...sizeProps, children: [
1918
+ pane === "warn" && /* @__PURE__ */ jsxs16(Fragment4, { children: [
1919
+ /* @__PURE__ */ jsx17("p", { style: { fontSize: 13, color: "rgba(0,0,0,0.6)" }, children: "Remove yourself from this app. Audit trail is preserved; you can sign back in any time to rejoin." }),
1920
+ /* @__PURE__ */ jsx17("button", { type: "button", onClick: startChallenge, disabled: busy, className: "elvix-btn elvix-btn-danger", children: busy ? "Sending\u2026" : "Send code" })
1235
1921
  ] }),
1236
- pane === "otp" && /* @__PURE__ */ jsxs15("form", { onSubmit: confirm, className: "elvix-form", children: [
1237
- /* @__PURE__ */ jsx16("p", { className: "elvix-muted", children: "We sent a 6-digit code to your email." }),
1238
- /* @__PURE__ */ jsx16(
1922
+ pane === "otp" && /* @__PURE__ */ jsxs16("form", { onSubmit: confirm, className: "elvix-form", children: [
1923
+ /* @__PURE__ */ jsx17("p", { className: "elvix-muted", children: "We sent a 6-digit code to your email." }),
1924
+ /* @__PURE__ */ jsx17(
1239
1925
  "input",
1240
1926
  {
1241
1927
  type: "text",
@@ -1249,24 +1935,31 @@ function ElvixLeave({
1249
1935
  className: "elvix-input"
1250
1936
  }
1251
1937
  ),
1252
- /* @__PURE__ */ jsx16("button", { type: "submit", disabled: busy || code.length !== 6, className: "elvix-btn elvix-btn-danger", children: busy ? "Leaving\u2026" : "Confirm leave" })
1938
+ /* @__PURE__ */ jsx17("button", { type: "submit", disabled: busy || code.length !== 6, className: "elvix-btn elvix-btn-danger", children: busy ? "Leaving\u2026" : "Confirm leave" })
1253
1939
  ] }),
1254
- error && /* @__PURE__ */ jsx16("p", { role: "alert", className: "elvix-error", children: error })
1940
+ error && /* @__PURE__ */ jsx17("p", { role: "alert", className: "elvix-error", children: error })
1255
1941
  ] });
1256
1942
  }
1257
1943
 
1258
1944
  // src/react/elvix-address-book.tsx
1259
- import { useEffect as useEffect5, useState as useState15 } from "react";
1260
- import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
1945
+ import { useEffect as useEffect5, useState as useState16 } from "react";
1946
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
1261
1947
  function ElvixAddressBook({
1262
- onResult
1948
+ onResult,
1949
+ width,
1950
+ height,
1951
+ minWidth,
1952
+ maxWidth,
1953
+ minHeight,
1954
+ maxHeight
1263
1955
  }) {
1956
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
1264
1957
  const ctx = useElvixContext();
1265
- const [rows, setRows] = useState15(null);
1266
- const [error, setError] = useState15(null);
1267
- const [busy, setBusy] = useState15(false);
1268
- const [adding, setAdding] = useState15(false);
1269
- const [form, setForm] = useState15({
1958
+ const [rows, setRows] = useState16(null);
1959
+ const [error, setError] = useState16(null);
1960
+ const [busy, setBusy] = useState16(false);
1961
+ const [adding, setAdding] = useState16(false);
1962
+ const [form, setForm] = useState16({
1270
1963
  label: "Home",
1271
1964
  line1: "",
1272
1965
  postalCode: "",
@@ -1315,14 +2008,14 @@ function ElvixAddressBook({
1315
2008
  if (result.ok) setRows((prev) => prev?.filter((a) => a.id !== id) ?? null);
1316
2009
  onResult?.(result);
1317
2010
  }
1318
- return /* @__PURE__ */ jsxs16(ElvixCard, { title: "Addresses", children: [
1319
- error && /* @__PURE__ */ jsx17("p", { role: "alert", className: "elvix-error", children: error }),
1320
- !rows && !error && /* @__PURE__ */ jsx17("p", { children: "Loading\u2026" }),
1321
- rows && rows.length === 0 && /* @__PURE__ */ jsx17("p", { className: "elvix-muted", children: "No addresses yet." }),
1322
- rows?.map((a) => /* @__PURE__ */ jsxs16("div", { style: { padding: "8px 0", borderBottom: "1px solid rgba(0,0,0,0.06)", display: "flex", justifyContent: "space-between", gap: 12 }, children: [
1323
- /* @__PURE__ */ jsxs16("div", { style: { fontSize: 13 }, children: [
1324
- /* @__PURE__ */ jsx17("div", { style: { fontWeight: 500 }, children: a.label }),
1325
- /* @__PURE__ */ jsxs16("div", { style: { color: "rgba(0,0,0,0.55)" }, children: [
2011
+ return /* @__PURE__ */ jsxs17(ElvixCard, { title: "Addresses", ...sizeProps, children: [
2012
+ error && /* @__PURE__ */ jsx18("p", { role: "alert", className: "elvix-error", children: error }),
2013
+ !rows && !error && /* @__PURE__ */ jsx18("p", { children: "Loading\u2026" }),
2014
+ rows && rows.length === 0 && /* @__PURE__ */ jsx18("p", { className: "elvix-muted", children: "No addresses yet." }),
2015
+ rows?.map((a) => /* @__PURE__ */ jsxs17("div", { style: { padding: "8px 0", borderBottom: "1px solid rgba(0,0,0,0.06)", display: "flex", justifyContent: "space-between", gap: 12 }, children: [
2016
+ /* @__PURE__ */ jsxs17("div", { style: { fontSize: 13 }, children: [
2017
+ /* @__PURE__ */ jsx18("div", { style: { fontWeight: 500 }, children: a.label }),
2018
+ /* @__PURE__ */ jsxs17("div", { style: { color: "rgba(0,0,0,0.55)" }, children: [
1326
2019
  a.line1,
1327
2020
  a.line2 ? `, ${a.line2}` : "",
1328
2021
  ", ",
@@ -1333,32 +2026,39 @@ function ElvixAddressBook({
1333
2026
  a.country
1334
2027
  ] })
1335
2028
  ] }),
1336
- /* @__PURE__ */ jsx17("button", { type: "button", disabled: busy, onClick: () => remove(a.id), className: "elvix-btn elvix-btn-ghost", children: "Remove" })
2029
+ /* @__PURE__ */ jsx18("button", { type: "button", disabled: busy, onClick: () => remove(a.id), className: "elvix-btn elvix-btn-ghost", children: "Remove" })
1337
2030
  ] }, a.id)),
1338
- !adding && /* @__PURE__ */ jsx17("button", { type: "button", onClick: () => setAdding(true), className: "elvix-btn elvix-btn-primary", style: { marginTop: 12 }, children: "Add address" }),
1339
- adding && /* @__PURE__ */ jsxs16("form", { onSubmit: add, className: "elvix-form", style: { marginTop: 12 }, children: [
1340
- /* @__PURE__ */ jsx17("input", { value: form.label, onChange: (e) => setForm({ ...form, label: e.target.value }), placeholder: "Label", className: "elvix-input" }),
1341
- /* @__PURE__ */ jsx17("input", { value: form.line1, onChange: (e) => setForm({ ...form, line1: e.target.value }), placeholder: "Street", required: true, className: "elvix-input" }),
1342
- /* @__PURE__ */ jsx17("input", { value: form.postalCode, onChange: (e) => setForm({ ...form, postalCode: e.target.value }), placeholder: "Postal code", required: true, className: "elvix-input" }),
1343
- /* @__PURE__ */ jsx17("input", { value: form.city, onChange: (e) => setForm({ ...form, city: e.target.value }), placeholder: "City", required: true, className: "elvix-input" }),
1344
- /* @__PURE__ */ jsx17("input", { value: form.country, onChange: (e) => setForm({ ...form, country: e.target.value.toUpperCase() }), placeholder: "Country (ISO-2)", maxLength: 2, required: true, className: "elvix-input" }),
1345
- /* @__PURE__ */ jsx17("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" })
2031
+ !adding && /* @__PURE__ */ jsx18("button", { type: "button", onClick: () => setAdding(true), className: "elvix-btn elvix-btn-primary", style: { marginTop: 12 }, children: "Add address" }),
2032
+ adding && /* @__PURE__ */ jsxs17("form", { onSubmit: add, className: "elvix-form", style: { marginTop: 12 }, children: [
2033
+ /* @__PURE__ */ jsx18("input", { value: form.label, onChange: (e) => setForm({ ...form, label: e.target.value }), placeholder: "Label", className: "elvix-input" }),
2034
+ /* @__PURE__ */ jsx18("input", { value: form.line1, onChange: (e) => setForm({ ...form, line1: e.target.value }), placeholder: "Street", required: true, className: "elvix-input" }),
2035
+ /* @__PURE__ */ jsx18("input", { value: form.postalCode, onChange: (e) => setForm({ ...form, postalCode: e.target.value }), placeholder: "Postal code", required: true, className: "elvix-input" }),
2036
+ /* @__PURE__ */ jsx18("input", { value: form.city, onChange: (e) => setForm({ ...form, city: e.target.value }), placeholder: "City", required: true, className: "elvix-input" }),
2037
+ /* @__PURE__ */ jsx18("input", { value: form.country, onChange: (e) => setForm({ ...form, country: e.target.value.toUpperCase() }), placeholder: "Country (ISO-2)", maxLength: 2, required: true, className: "elvix-input" }),
2038
+ /* @__PURE__ */ jsx18("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" })
1346
2039
  ] })
1347
2040
  ] });
1348
2041
  }
1349
2042
 
1350
2043
  // src/react/elvix-legal-entities.tsx
1351
- import { useEffect as useEffect6, useState as useState16 } from "react";
1352
- import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
2044
+ import { useEffect as useEffect6, useState as useState17 } from "react";
2045
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
1353
2046
  function ElvixLegalEntities({
1354
- onResult
2047
+ onResult,
2048
+ width,
2049
+ height,
2050
+ minWidth,
2051
+ maxWidth,
2052
+ minHeight,
2053
+ maxHeight
1355
2054
  }) {
2055
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
1356
2056
  const ctx = useElvixContext();
1357
- const [rows, setRows] = useState16(null);
1358
- const [error, setError] = useState16(null);
1359
- const [busy, setBusy] = useState16(false);
1360
- const [adding, setAdding] = useState16(false);
1361
- const [form, setForm] = useState16({
2057
+ const [rows, setRows] = useState17(null);
2058
+ const [error, setError] = useState17(null);
2059
+ const [busy, setBusy] = useState17(false);
2060
+ const [adding, setAdding] = useState17(false);
2061
+ const [form, setForm] = useState17({
1362
2062
  legalName: "",
1363
2063
  taxId: "",
1364
2064
  country: ""
@@ -1405,27 +2105,27 @@ function ElvixLegalEntities({
1405
2105
  if (result.ok) setRows((prev) => prev?.filter((a) => a.id !== id) ?? null);
1406
2106
  onResult?.(result);
1407
2107
  }
1408
- return /* @__PURE__ */ jsxs17(ElvixCard, { title: "Legal entities", children: [
1409
- error && /* @__PURE__ */ jsx18("p", { role: "alert", className: "elvix-error", children: error }),
1410
- !rows && !error && /* @__PURE__ */ jsx18("p", { children: "Loading\u2026" }),
1411
- rows && rows.length === 0 && /* @__PURE__ */ jsx18("p", { className: "elvix-muted", children: "No legal entities yet." }),
1412
- rows?.map((e) => /* @__PURE__ */ jsxs17("div", { style: { padding: "8px 0", borderBottom: "1px solid rgba(0,0,0,0.06)", display: "flex", justifyContent: "space-between", gap: 12 }, children: [
1413
- /* @__PURE__ */ jsxs17("div", { style: { fontSize: 13 }, children: [
1414
- /* @__PURE__ */ jsx18("div", { style: { fontWeight: 500 }, children: e.legalName }),
1415
- /* @__PURE__ */ jsxs17("div", { style: { color: "rgba(0,0,0,0.55)" }, children: [
2108
+ return /* @__PURE__ */ jsxs18(ElvixCard, { title: "Legal entities", ...sizeProps, children: [
2109
+ error && /* @__PURE__ */ jsx19("p", { role: "alert", className: "elvix-error", children: error }),
2110
+ !rows && !error && /* @__PURE__ */ jsx19("p", { children: "Loading\u2026" }),
2111
+ rows && rows.length === 0 && /* @__PURE__ */ jsx19("p", { className: "elvix-muted", children: "No legal entities yet." }),
2112
+ rows?.map((e) => /* @__PURE__ */ jsxs18("div", { style: { padding: "8px 0", borderBottom: "1px solid rgba(0,0,0,0.06)", display: "flex", justifyContent: "space-between", gap: 12 }, children: [
2113
+ /* @__PURE__ */ jsxs18("div", { style: { fontSize: 13 }, children: [
2114
+ /* @__PURE__ */ jsx19("div", { style: { fontWeight: 500 }, children: e.legalName }),
2115
+ /* @__PURE__ */ jsxs18("div", { style: { color: "rgba(0,0,0,0.55)" }, children: [
1416
2116
  e.taxId,
1417
2117
  " \xB7 ",
1418
2118
  e.country
1419
2119
  ] })
1420
2120
  ] }),
1421
- /* @__PURE__ */ jsx18("button", { type: "button", disabled: busy, onClick: () => remove(e.id), className: "elvix-btn elvix-btn-ghost", children: "Remove" })
2121
+ /* @__PURE__ */ jsx19("button", { type: "button", disabled: busy, onClick: () => remove(e.id), className: "elvix-btn elvix-btn-ghost", children: "Remove" })
1422
2122
  ] }, e.id)),
1423
- !adding && /* @__PURE__ */ jsx18("button", { type: "button", onClick: () => setAdding(true), className: "elvix-btn elvix-btn-primary", style: { marginTop: 12 }, children: "Add entity" }),
1424
- adding && /* @__PURE__ */ jsxs17("form", { onSubmit: add, className: "elvix-form", style: { marginTop: 12 }, children: [
1425
- /* @__PURE__ */ jsx18("input", { value: form.legalName, onChange: (e) => setForm({ ...form, legalName: e.target.value }), placeholder: "Legal name", required: true, className: "elvix-input" }),
1426
- /* @__PURE__ */ jsx18("input", { value: form.taxId, onChange: (e) => setForm({ ...form, taxId: e.target.value }), placeholder: "Tax / VAT ID", required: true, className: "elvix-input" }),
1427
- /* @__PURE__ */ jsx18("input", { value: form.country, onChange: (e) => setForm({ ...form, country: e.target.value.toUpperCase() }), placeholder: "Country (ISO-2)", maxLength: 2, required: true, className: "elvix-input" }),
1428
- /* @__PURE__ */ jsx18("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" })
2123
+ !adding && /* @__PURE__ */ jsx19("button", { type: "button", onClick: () => setAdding(true), className: "elvix-btn elvix-btn-primary", style: { marginTop: 12 }, children: "Add entity" }),
2124
+ adding && /* @__PURE__ */ jsxs18("form", { onSubmit: add, className: "elvix-form", style: { marginTop: 12 }, children: [
2125
+ /* @__PURE__ */ jsx19("input", { value: form.legalName, onChange: (e) => setForm({ ...form, legalName: e.target.value }), placeholder: "Legal name", required: true, className: "elvix-input" }),
2126
+ /* @__PURE__ */ jsx19("input", { value: form.taxId, onChange: (e) => setForm({ ...form, taxId: e.target.value }), placeholder: "Tax / VAT ID", required: true, className: "elvix-input" }),
2127
+ /* @__PURE__ */ jsx19("input", { value: form.country, onChange: (e) => setForm({ ...form, country: e.target.value.toUpperCase() }), placeholder: "Country (ISO-2)", maxLength: 2, required: true, className: "elvix-input" }),
2128
+ /* @__PURE__ */ jsx19("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" })
1429
2129
  ] })
1430
2130
  ] });
1431
2131
  }
@@ -1448,6 +2148,7 @@ export {
1448
2148
  ElvixSessions,
1449
2149
  ElvixSignIn,
1450
2150
  ElvixSignInButton,
2151
+ ElvixSignInForm,
1451
2152
  ElvixUsername,
1452
2153
  getElvixToken,
1453
2154
  setElvixToken,