@elvix.is/sdk 0.5.3 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/react.d.ts +92 -36
  2. package/dist/react.js +1027 -314
  3. package/package.json +2 -2
package/dist/react.js CHANGED
@@ -1,11 +1,33 @@
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
+
1
14
  // src/react/elvix-card.tsx
15
+ import { jsx, jsxs } from "react/jsx-runtime";
2
16
  function ElvixCard({
3
17
  title,
4
18
  footer,
5
19
  className = "",
6
- children
20
+ style,
21
+ children,
22
+ width,
23
+ height,
24
+ minWidth,
25
+ maxWidth,
26
+ minHeight,
27
+ maxHeight
7
28
  }) {
8
- return /* @__PURE__ */ React.createElement(
29
+ const sized = sizeStyle({ width, height, minWidth, maxWidth, minHeight, maxHeight });
30
+ return /* @__PURE__ */ jsxs(
9
31
  "div",
10
32
  {
11
33
  className: `elvix-card ${className}`.trim(),
@@ -17,35 +39,39 @@ function ElvixCard({
17
39
  display: "flex",
18
40
  flexDirection: "column",
19
41
  maxWidth: "440px",
20
- width: "100%"
21
- }
22
- },
23
- title && /* @__PURE__ */ React.createElement(
24
- "div",
25
- {
26
- style: {
27
- padding: "20px 24px 0",
28
- fontSize: "16px",
29
- fontWeight: 600,
30
- color: "var(--elvix-primary-strong, #5d4dff)"
31
- }
42
+ width: "100%",
43
+ ...style,
44
+ ...sized
32
45
  },
33
- title
34
- ),
35
- /* @__PURE__ */ React.createElement("div", { style: { padding: "16px 24px", flex: 1 } }, children),
36
- footer && /* @__PURE__ */ React.createElement(
37
- "div",
38
- {
39
- style: {
40
- padding: "12px 24px",
41
- borderTop: "1px solid var(--elvix-primary-12, rgba(93,77,255,0.12))",
42
- background: "rgba(0,0,0,0.02)",
43
- fontSize: "12px",
44
- color: "rgba(0,0,0,0.55)"
45
- }
46
- },
47
- footer
48
- )
46
+ children: [
47
+ title && /* @__PURE__ */ jsx(
48
+ "div",
49
+ {
50
+ style: {
51
+ padding: "20px 24px 0",
52
+ fontSize: "16px",
53
+ fontWeight: 600,
54
+ color: "var(--elvix-primary-strong, #5d4dff)"
55
+ },
56
+ children: title
57
+ }
58
+ ),
59
+ /* @__PURE__ */ jsx("div", { style: { padding: "16px 24px", flex: 1 }, children }),
60
+ footer && /* @__PURE__ */ jsx(
61
+ "div",
62
+ {
63
+ style: {
64
+ padding: "12px 24px",
65
+ borderTop: "1px solid var(--elvix-primary-12, rgba(93,77,255,0.12))",
66
+ background: "rgba(0,0,0,0.02)",
67
+ fontSize: "12px",
68
+ color: "rgba(0,0,0,0.55)"
69
+ },
70
+ children: footer
71
+ }
72
+ )
73
+ ]
74
+ }
49
75
  );
50
76
  }
51
77
 
@@ -57,6 +83,7 @@ import {
57
83
  useMemo,
58
84
  useState
59
85
  } from "react";
86
+ import { jsx as jsx2 } from "react/jsx-runtime";
60
87
  var ELVIX_DEFAULT_BRAND = {
61
88
  light: { primary: "#5d4dff", on: "#ffffff" },
62
89
  dark: { primary: "#8e7dff", on: "#0a0a0b" }
@@ -140,15 +167,15 @@ function ElvixProvider({
140
167
  appError,
141
168
  resolvedTheme: effectiveTheme
142
169
  };
143
- return /* @__PURE__ */ React.createElement(ElvixContext.Provider, { value }, /* @__PURE__ */ React.createElement(
170
+ return /* @__PURE__ */ jsx2(ElvixContext.Provider, { value, children: /* @__PURE__ */ jsx2(
144
171
  "div",
145
172
  {
146
173
  "data-elvix-theme": effectiveTheme,
147
174
  style: cssVars,
148
- className: (effectiveTheme === "dark" ? "dark " : "") + "elvix-sdk-root " + className
149
- },
150
- children
151
- ));
175
+ className: (effectiveTheme === "dark" ? "dark " : "") + "elvix-sdk-root " + className,
176
+ children
177
+ }
178
+ ) });
152
179
  }
153
180
  function appBrand(app) {
154
181
  if (!app?.brandColor) return null;
@@ -246,12 +273,20 @@ function isSameOrigin(baseUrl) {
246
273
  }
247
274
 
248
275
  // src/react/elvix-sign-in.tsx
276
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
249
277
  function ElvixSignIn({
250
278
  onResult,
251
279
  redirectAfterSignIn,
252
280
  copy: copyProp,
253
- className = ""
281
+ className = "",
282
+ width,
283
+ height,
284
+ minWidth,
285
+ maxWidth,
286
+ minHeight,
287
+ maxHeight
254
288
  }) {
289
+ const sized = sizeStyle({ width, height, minWidth, maxWidth, minHeight, maxHeight });
255
290
  const ctx = useElvixContext();
256
291
  const app = useElvixApp();
257
292
  const copy = resolveCopy(app?.strings, copyProp);
@@ -336,67 +371,549 @@ function ElvixSignIn({
336
371
  }
337
372
  const card = `elvix-card ${className}`.trim();
338
373
  if (step === "done") {
339
- return /* @__PURE__ */ React.createElement("div", { className: card, "data-elvix-pane": "done" }, /* @__PURE__ */ React.createElement("p", null, copy.signedInText));
374
+ return /* @__PURE__ */ jsx3("div", { className: card, style: sized, "data-elvix-pane": "done", children: /* @__PURE__ */ jsx3("p", { children: copy.signedInText }) });
340
375
  }
341
- return /* @__PURE__ */ React.createElement("div", { className: card, "data-elvix-pane": step }, /* @__PURE__ */ React.createElement("h2", { className: "elvix-h" }, title), copy.subtitle && /* @__PURE__ */ React.createElement("p", { className: "elvix-muted elvix-subtitle" }, copy.subtitle), step === "identify" && /* @__PURE__ */ React.createElement(React.Fragment, null, app?.methodGoogle && /* @__PURE__ */ React.createElement(
342
- "button",
343
- {
344
- type: "button",
345
- onClick: startGoogle,
346
- disabled: busy,
347
- className: "elvix-btn elvix-btn-google",
348
- "data-elvix-method": "google"
349
- },
350
- copy.googleButton
351
- ), app?.methodEmailOtp && /* @__PURE__ */ React.createElement("form", { onSubmit: startOtp, "data-elvix-method": "email_otp", className: "elvix-otp-form" }, /* @__PURE__ */ React.createElement(
352
- "input",
353
- {
354
- type: "email",
355
- value: email,
356
- onChange: (ev) => setEmail(ev.target.value),
357
- placeholder: copy.emailPlaceholder,
358
- required: true,
359
- disabled: busy,
360
- className: "elvix-input"
361
- }
362
- ), /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary" }, busy ? copy.sendingLabel : copy.sendCodeButton))), step === "code" && /* @__PURE__ */ React.createElement("form", { onSubmit: verifyOtp, className: "elvix-otp-form" }, /* @__PURE__ */ React.createElement("p", { className: "elvix-muted" }, fillCopy(copy.codeSentSubtitle ?? "", { email })), /* @__PURE__ */ React.createElement(
363
- "input",
364
- {
365
- type: "text",
366
- inputMode: "numeric",
367
- pattern: "[0-9]*",
368
- maxLength: 6,
369
- value: code,
370
- onChange: (ev) => setCode(ev.target.value.replace(/\D/g, "")),
371
- placeholder: copy.codePlaceholder,
372
- required: true,
373
- disabled: busy,
374
- className: "elvix-input"
375
- }
376
- ), /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary" }, busy ? copy.verifyingLabel : submitLabel)), error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error));
376
+ return /* @__PURE__ */ jsxs2("div", { className: card, style: sized, "data-elvix-pane": step, children: [
377
+ /* @__PURE__ */ jsx3("h2", { className: "elvix-h", children: title }),
378
+ copy.subtitle && /* @__PURE__ */ jsx3("p", { className: "elvix-muted elvix-subtitle", children: copy.subtitle }),
379
+ step === "identify" && /* @__PURE__ */ jsxs2(Fragment, { children: [
380
+ app?.methodGoogle && /* @__PURE__ */ jsx3(
381
+ "button",
382
+ {
383
+ type: "button",
384
+ onClick: startGoogle,
385
+ disabled: busy,
386
+ className: "elvix-btn elvix-btn-google",
387
+ "data-elvix-method": "google",
388
+ children: copy.googleButton
389
+ }
390
+ ),
391
+ app?.methodEmailOtp && /* @__PURE__ */ jsxs2("form", { onSubmit: startOtp, "data-elvix-method": "email_otp", className: "elvix-otp-form", children: [
392
+ /* @__PURE__ */ jsx3(
393
+ "input",
394
+ {
395
+ type: "email",
396
+ value: email,
397
+ onChange: (ev) => setEmail(ev.target.value),
398
+ placeholder: copy.emailPlaceholder,
399
+ required: true,
400
+ disabled: busy,
401
+ className: "elvix-input"
402
+ }
403
+ ),
404
+ /* @__PURE__ */ jsx3("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? copy.sendingLabel : copy.sendCodeButton })
405
+ ] })
406
+ ] }),
407
+ step === "code" && /* @__PURE__ */ jsxs2("form", { onSubmit: verifyOtp, className: "elvix-otp-form", children: [
408
+ /* @__PURE__ */ jsx3("p", { className: "elvix-muted", children: fillCopy(copy.codeSentSubtitle ?? "", { email }) }),
409
+ /* @__PURE__ */ jsx3(
410
+ "input",
411
+ {
412
+ type: "text",
413
+ inputMode: "numeric",
414
+ pattern: "[0-9]*",
415
+ maxLength: 6,
416
+ value: code,
417
+ onChange: (ev) => setCode(ev.target.value.replace(/\D/g, "")),
418
+ placeholder: copy.codePlaceholder,
419
+ required: true,
420
+ disabled: busy,
421
+ className: "elvix-input"
422
+ }
423
+ ),
424
+ /* @__PURE__ */ jsx3("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? copy.verifyingLabel : submitLabel })
425
+ ] }),
426
+ error && /* @__PURE__ */ jsx3("p", { role: "alert", className: "elvix-error", children: error })
427
+ ] });
377
428
  }
378
429
 
379
- // src/react/elvix-sign-in-button.tsx
380
- import { useState as useState3 } from "react";
430
+ // src/react/elvix-sign-in-form.tsx
431
+ import { useMemo as useMemo2, useState as useState3 } from "react";
381
432
 
382
433
  // src/react/elvix-shield.tsx
434
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
383
435
  function ElvixShield({
384
436
  size,
385
437
  fill,
386
438
  accent
387
439
  }) {
388
- return /* @__PURE__ */ React.createElement("svg", { width: size, height: size, viewBox: "2 2 20 20", "aria-hidden": true, style: { display: "block" } }, /* @__PURE__ */ React.createElement(
389
- "path",
440
+ return /* @__PURE__ */ jsxs3("svg", { width: size, height: size, viewBox: "2 2 20 20", "aria-hidden": true, style: { display: "block" }, children: [
441
+ /* @__PURE__ */ jsx4(
442
+ "path",
443
+ {
444
+ fill,
445
+ fillRule: "evenodd",
446
+ 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"
447
+ }
448
+ ),
449
+ /* @__PURE__ */ jsx4("circle", { cx: "19.5", cy: "4.5", r: "2.4", fill: accent })
450
+ ] });
451
+ }
452
+
453
+ // src/react/elvix-secured-badge.tsx
454
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
455
+ var ELVIX_URL = "https://elvix.is";
456
+ var SIZE = {
457
+ sm: { height: 28, padX: 10, font: 11.5, icon: 14, gap: 6 },
458
+ md: { height: 32, padX: 12, font: 12.5, icon: 16, gap: 7 },
459
+ lg: { height: 36, padX: 14, font: 13, icon: 18, gap: 8 }
460
+ };
461
+ var TONE = {
462
+ white: {
463
+ light: { bg: "#ffffff", border: "#e4e4e7", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" },
464
+ dark: { bg: "#ffffff", border: "transparent", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" }
465
+ },
466
+ dark: {
467
+ light: { bg: "#0a0a0b", border: "rgba(0,0,0,0.1)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" },
468
+ dark: { bg: "#0a0a0b", border: "rgba(255,255,255,0.1)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" }
469
+ },
470
+ outline: {
471
+ light: { bg: "transparent", border: "rgba(0,0,0,0.15)", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" },
472
+ dark: { bg: "transparent", border: "rgba(142,125,255,0.4)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" }
473
+ }
474
+ };
475
+ function ElvixSecuredBadge({
476
+ variant = "white",
477
+ size = "md",
478
+ theme = "dark",
479
+ accentColor = "#8e7dff",
480
+ href = ELVIX_URL,
481
+ className = "",
482
+ width,
483
+ height,
484
+ minWidth,
485
+ maxWidth,
486
+ minHeight,
487
+ maxHeight
488
+ }) {
489
+ const s = SIZE[size];
490
+ const t = TONE[variant][theme];
491
+ const style = {
492
+ display: "inline-flex",
493
+ alignItems: "center",
494
+ gap: s.gap,
495
+ height: s.height,
496
+ paddingLeft: s.padX,
497
+ paddingRight: s.padX,
498
+ fontSize: s.font,
499
+ fontWeight: 500,
500
+ borderRadius: 9999,
501
+ background: t.bg,
502
+ border: `1px solid ${t.border}`,
503
+ color: t.brand,
504
+ textDecoration: "none",
505
+ userSelect: "none",
506
+ lineHeight: 1,
507
+ // Dimensional overrides win over the size preset above.
508
+ ...sizeStyle({ width, height, minWidth, maxWidth, minHeight, maxHeight })
509
+ };
510
+ return /* @__PURE__ */ jsxs4(
511
+ "a",
390
512
  {
391
- fill,
392
- fillRule: "evenodd",
393
- 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"
513
+ href,
514
+ target: "_blank",
515
+ rel: "noopener noreferrer",
516
+ className,
517
+ style,
518
+ "data-elvix-secured-badge": "",
519
+ children: [
520
+ /* @__PURE__ */ jsx5(ElvixShield, { size: s.icon, fill: t.shield, accent: accentColor }),
521
+ /* @__PURE__ */ jsxs4("span", { style: { display: "inline-flex", alignItems: "baseline", gap: 4 }, children: [
522
+ /* @__PURE__ */ jsx5("span", { style: { color: t.lead }, children: "Secured by" }),
523
+ /* @__PURE__ */ jsx5("span", { style: { color: t.brand, fontWeight: 600 }, children: "elvix" })
524
+ ] })
525
+ ]
526
+ }
527
+ );
528
+ }
529
+
530
+ // src/react/elvix-sign-in-form.tsx
531
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
532
+ function GoogleG({ size = 18 }) {
533
+ return /* @__PURE__ */ jsxs5("svg", { width: size, height: size, viewBox: "0 0 18 18", "aria-hidden": true, style: { display: "block" }, children: [
534
+ /* @__PURE__ */ jsx6(
535
+ "path",
536
+ {
537
+ fill: "#4285F4",
538
+ 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"
539
+ }
540
+ ),
541
+ /* @__PURE__ */ jsx6(
542
+ "path",
543
+ {
544
+ fill: "#34A853",
545
+ 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"
546
+ }
547
+ ),
548
+ /* @__PURE__ */ jsx6(
549
+ "path",
550
+ {
551
+ fill: "#FBBC05",
552
+ 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"
553
+ }
554
+ ),
555
+ /* @__PURE__ */ jsx6(
556
+ "path",
557
+ {
558
+ fill: "#EA4335",
559
+ 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"
560
+ }
561
+ )
562
+ ] });
563
+ }
564
+ function ElvixSignInForm({
565
+ onResult,
566
+ redirectAfterSignIn,
567
+ copy: copyProp,
568
+ className = "",
569
+ minWidth,
570
+ maxWidth,
571
+ minHeight,
572
+ maxHeight,
573
+ width,
574
+ height
575
+ }) {
576
+ const ctx = useElvixContext();
577
+ const app = useElvixApp();
578
+ const copy = resolveCopy(app?.strings, copyProp);
579
+ const [step, setStep] = useState3("identify");
580
+ const [email, setEmail] = useState3("");
581
+ const [code, setCode] = useState3("");
582
+ const [challengeId, setChallengeId] = useState3(null);
583
+ const [busy, setBusy] = useState3(false);
584
+ const [error, setError] = useState3(null);
585
+ const brand = app?.brandColor || "#6c5ce7";
586
+ const onBrand = app?.onBrandColor || "#fff";
587
+ const appName = app?.appName ?? "your app";
588
+ const verb = app?.signInVerb === "login" ? "Log in" : "Sign in";
589
+ const defaultTitle = app?.appName ? `${verb} to ${app.appName}` : verb;
590
+ const title = copy.title ? fillCopy(copy.title, { app: app?.appName ?? "" }) : defaultTitle;
591
+ const submitLabel = copy.submitButton ?? verb;
592
+ const showGoogle = Boolean(app?.methodGoogle);
593
+ const showEmail = Boolean(app?.methodEmailOtp);
594
+ const showDivider = showGoogle && showEmail;
595
+ const logoSrc = app?.iconUrl || app?.logoUrl || null;
596
+ const privacyUrl = app?.privacyPolicyUrl || null;
597
+ const termsUrl = app?.termsOfServiceUrl || null;
598
+ const hasLegal = Boolean(privacyUrl || termsUrl);
599
+ const cardStyle = useMemo2(
600
+ () => ({
601
+ boxSizing: "border-box",
602
+ // Defaults first; the shared sizeStyle() overrides only the keys the host set,
603
+ // so the form keeps its width "100%" / maxWidth 400 defaults when unsized.
604
+ width: "100%",
605
+ maxWidth: 400,
606
+ ...sizeStyle({ width, height, minWidth, maxWidth, minHeight, maxHeight }),
607
+ margin: "0 auto",
608
+ display: "flex",
609
+ flexDirection: "column",
610
+ gap: 18,
611
+ background: "#fff",
612
+ color: "#18181b",
613
+ border: "1px solid rgba(0,0,0,0.08)",
614
+ borderRadius: 16,
615
+ boxShadow: "0 1px 2px rgba(0,0,0,0.04), 0 12px 32px -12px rgba(0,0,0,0.18)",
616
+ padding: 28,
617
+ fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif",
618
+ textAlign: "center"
619
+ }),
620
+ [width, maxWidth, minWidth, height, minHeight, maxHeight]
621
+ );
622
+ function fail(error2, message) {
623
+ setError(message ?? error2);
624
+ onResult?.({ ok: false, error: error2, message });
625
+ }
626
+ async function startGoogle() {
627
+ if (!ctx.clientId) return fail("missing_client_id", "ElvixProvider needs a clientId.");
628
+ window.location.assign(
629
+ `${ctx.baseUrl}/api/auth/google/start?intent=app&clientId=${encodeURIComponent(ctx.clientId)}`
630
+ );
631
+ }
632
+ async function startOtp(e) {
633
+ e.preventDefault();
634
+ if (!email.trim()) return fail("invalid_input", copy.errorEnterEmail);
635
+ setBusy(true);
636
+ setError(null);
637
+ try {
638
+ const res = await fetch(`${ctx.baseUrl}/api/auth/otp/start`, {
639
+ method: "POST",
640
+ headers: { "content-type": "application/json" },
641
+ credentials: isSameOrigin(ctx.baseUrl) ? "include" : "omit",
642
+ body: JSON.stringify({
643
+ email: email.trim(),
644
+ intent: "app",
645
+ clientId: ctx.clientId
646
+ })
647
+ });
648
+ const body = await res.json();
649
+ if (!res.ok || !body.success || !body.data?.challengeId) {
650
+ return fail(body.errorMessage ?? "otp_start_failed");
651
+ }
652
+ setChallengeId(body.data.challengeId);
653
+ setStep("code");
654
+ } catch (e2) {
655
+ fail("network", e2 instanceof Error ? e2.message : void 0);
656
+ } finally {
657
+ setBusy(false);
394
658
  }
395
- ), /* @__PURE__ */ React.createElement("circle", { cx: "19.5", cy: "4.5", r: "2.4", fill: accent }));
659
+ }
660
+ async function verifyOtp(e) {
661
+ e.preventDefault();
662
+ if (!challengeId) return;
663
+ if (code.trim().length !== 6) return fail("invalid_input", copy.errorEnterCode);
664
+ setBusy(true);
665
+ setError(null);
666
+ try {
667
+ const res = await fetch(`${ctx.baseUrl}/api/auth/otp/verify`, {
668
+ method: "POST",
669
+ headers: { "content-type": "application/json" },
670
+ credentials: isSameOrigin(ctx.baseUrl) ? "include" : "omit",
671
+ body: JSON.stringify({ challengeId, code: code.trim() })
672
+ });
673
+ const body = await res.json();
674
+ if (!res.ok || !body.success) {
675
+ return fail(body.errorMessage ?? "otp_verify_failed");
676
+ }
677
+ if (body.data?.token) setElvixToken(body.data.token);
678
+ setStep("done");
679
+ onResult?.({
680
+ ok: true,
681
+ method: "email_otp",
682
+ redirect: body.data?.redirect ?? redirectAfterSignIn,
683
+ token: body.data?.token
684
+ });
685
+ } catch (e2) {
686
+ fail("network", e2 instanceof Error ? e2.message : void 0);
687
+ } finally {
688
+ setBusy(false);
689
+ }
690
+ }
691
+ const labelStyle = {
692
+ display: "block",
693
+ textAlign: "left",
694
+ fontSize: 12.5,
695
+ fontWeight: 500,
696
+ color: "#52525b",
697
+ marginBottom: 6
698
+ };
699
+ const inputStyle = {
700
+ boxSizing: "border-box",
701
+ width: "100%",
702
+ height: 44,
703
+ padding: "0 14px",
704
+ borderRadius: 10,
705
+ border: "1px solid rgba(0,0,0,0.14)",
706
+ background: "#fff",
707
+ color: "#18181b",
708
+ fontSize: 14,
709
+ outline: "none"
710
+ };
711
+ const primaryBtnStyle = {
712
+ boxSizing: "border-box",
713
+ width: "100%",
714
+ height: 44,
715
+ marginTop: 10,
716
+ border: "1px solid rgba(0,0,0,0.08)",
717
+ borderRadius: 10,
718
+ background: brand,
719
+ color: onBrand,
720
+ fontSize: 14,
721
+ fontWeight: 600,
722
+ cursor: busy ? "not-allowed" : "pointer",
723
+ opacity: busy ? 0.65 : 1,
724
+ backgroundImage: "linear-gradient(to bottom, rgba(255,255,255,0.12), rgba(255,255,255,0) 40%)",
725
+ 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)"
726
+ };
727
+ const googleBtnStyle = {
728
+ boxSizing: "border-box",
729
+ width: "100%",
730
+ height: 44,
731
+ display: "inline-flex",
732
+ alignItems: "center",
733
+ justifyContent: "center",
734
+ gap: 10,
735
+ border: "1px solid rgba(0,0,0,0.14)",
736
+ borderRadius: 10,
737
+ background: "#fff",
738
+ color: "#18181b",
739
+ fontSize: 14,
740
+ fontWeight: 500,
741
+ cursor: busy ? "not-allowed" : "pointer",
742
+ opacity: busy ? 0.65 : 1
743
+ };
744
+ const tileTint = hexToRgba(brand, 0.12);
745
+ const root = `${className}`.trim() || void 0;
746
+ return /* @__PURE__ */ jsxs5("div", { className: root, style: cardStyle, "data-elvix-pane": step, children: [
747
+ /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
748
+ /* @__PURE__ */ jsx6(
749
+ "div",
750
+ {
751
+ style: {
752
+ width: 52,
753
+ height: 52,
754
+ borderRadius: 14,
755
+ display: "grid",
756
+ placeItems: "center",
757
+ overflow: "hidden",
758
+ background: logoSrc ? "#fff" : tileTint,
759
+ border: "1px solid rgba(0,0,0,0.08)"
760
+ },
761
+ children: logoSrc ? (
762
+ // biome-ignore lint/a11y/useAltText: alt is set
763
+ /* @__PURE__ */ jsx6(
764
+ "img",
765
+ {
766
+ src: logoSrc,
767
+ alt: appName,
768
+ style: { width: "100%", height: "100%", objectFit: "cover" }
769
+ }
770
+ )
771
+ ) : /* @__PURE__ */ jsx6("span", { style: { fontSize: 22, fontWeight: 700, color: brand }, children: appName.charAt(0).toUpperCase() || "?" })
772
+ }
773
+ ),
774
+ /* @__PURE__ */ jsxs5("div", { children: [
775
+ /* @__PURE__ */ jsx6("h2", { style: { margin: 0, fontSize: 19, fontWeight: 600, letterSpacing: "-0.01em" }, children: step === "code" ? "Check your inbox" : title }),
776
+ step !== "done" && /* @__PURE__ */ jsx6("p", { style: { margin: "4px 0 0", fontSize: 13, color: "#71717a" }, children: step === "code" ? fillCopy(copy.codeSentSubtitle ?? "", { email }) : copy.subtitle })
777
+ ] })
778
+ ] }),
779
+ step === "done" && /* @__PURE__ */ jsx6("p", { style: { margin: 0, fontSize: 14, color: "#18181b" }, children: copy.signedInText }),
780
+ step === "identify" && /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: 14 }, children: [
781
+ showGoogle && /* @__PURE__ */ jsxs5(
782
+ "button",
783
+ {
784
+ type: "button",
785
+ onClick: startGoogle,
786
+ disabled: busy,
787
+ style: googleBtnStyle,
788
+ "data-elvix-method": "google",
789
+ children: [
790
+ /* @__PURE__ */ jsx6(GoogleG, {}),
791
+ /* @__PURE__ */ jsx6("span", { children: copy.googleButton })
792
+ ]
793
+ }
794
+ ),
795
+ showDivider && /* @__PURE__ */ jsxs5(
796
+ "div",
797
+ {
798
+ "aria-hidden": true,
799
+ style: { display: "flex", alignItems: "center", gap: 12, color: "#a1a1aa" },
800
+ children: [
801
+ /* @__PURE__ */ jsx6("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.08)" } }),
802
+ /* @__PURE__ */ jsx6("span", { style: { fontSize: 11, fontWeight: 600, letterSpacing: "0.08em" }, children: "OR" }),
803
+ /* @__PURE__ */ jsx6("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.08)" } })
804
+ ]
805
+ }
806
+ ),
807
+ showEmail && /* @__PURE__ */ jsxs5("form", { onSubmit: startOtp, "data-elvix-method": "email_otp", children: [
808
+ /* @__PURE__ */ jsx6("label", { htmlFor: "elvix-email", style: labelStyle, children: "Email" }),
809
+ /* @__PURE__ */ jsx6(
810
+ "input",
811
+ {
812
+ id: "elvix-email",
813
+ type: "email",
814
+ value: email,
815
+ onChange: (ev) => setEmail(ev.target.value),
816
+ placeholder: copy.emailPlaceholder,
817
+ required: true,
818
+ disabled: busy,
819
+ autoComplete: "email",
820
+ style: inputStyle
821
+ }
822
+ ),
823
+ /* @__PURE__ */ jsx6("button", { type: "submit", disabled: busy, style: primaryBtnStyle, children: busy ? copy.sendingLabel : copy.sendCodeButton })
824
+ ] })
825
+ ] }),
826
+ step === "code" && /* @__PURE__ */ jsxs5("form", { onSubmit: verifyOtp, children: [
827
+ /* @__PURE__ */ jsx6("label", { htmlFor: "elvix-code", style: labelStyle, children: "Verification code" }),
828
+ /* @__PURE__ */ jsx6(
829
+ "input",
830
+ {
831
+ id: "elvix-code",
832
+ type: "text",
833
+ inputMode: "numeric",
834
+ pattern: "[0-9]*",
835
+ maxLength: 6,
836
+ value: code,
837
+ onChange: (ev) => setCode(ev.target.value.replace(/\D/g, "")),
838
+ placeholder: copy.codePlaceholder,
839
+ required: true,
840
+ disabled: busy,
841
+ autoComplete: "one-time-code",
842
+ autoFocus: true,
843
+ style: { ...inputStyle, letterSpacing: "0.3em", textAlign: "center", fontSize: 18 }
844
+ }
845
+ ),
846
+ /* @__PURE__ */ jsx6("button", { type: "submit", disabled: busy, style: primaryBtnStyle, children: busy ? copy.verifyingLabel : submitLabel }),
847
+ /* @__PURE__ */ jsx6(
848
+ "button",
849
+ {
850
+ type: "button",
851
+ onClick: () => {
852
+ setStep("identify");
853
+ setCode("");
854
+ setError(null);
855
+ },
856
+ disabled: busy,
857
+ style: {
858
+ marginTop: 12,
859
+ background: "none",
860
+ border: "none",
861
+ color: "#71717a",
862
+ fontSize: 12.5,
863
+ cursor: busy ? "not-allowed" : "pointer"
864
+ },
865
+ children: "Use a different email"
866
+ }
867
+ )
868
+ ] }),
869
+ error && /* @__PURE__ */ jsx6("p", { role: "alert", style: { margin: 0, fontSize: 12.5, color: "#dc2626" }, children: error }),
870
+ hasLegal && step !== "done" && /* @__PURE__ */ jsxs5("p", { style: { margin: 0, fontSize: 11.5, lineHeight: 1.5, color: "#a1a1aa" }, children: [
871
+ "By continuing, you agree to ",
872
+ appName,
873
+ "'s",
874
+ " ",
875
+ termsUrl && /* @__PURE__ */ jsx6(
876
+ "a",
877
+ {
878
+ href: termsUrl,
879
+ target: "_blank",
880
+ rel: "noopener noreferrer",
881
+ style: { color: "#71717a", textDecoration: "underline" },
882
+ children: "Terms of Service"
883
+ }
884
+ ),
885
+ termsUrl && privacyUrl && " \xB7 ",
886
+ privacyUrl && /* @__PURE__ */ jsx6(
887
+ "a",
888
+ {
889
+ href: privacyUrl,
890
+ target: "_blank",
891
+ rel: "noopener noreferrer",
892
+ style: { color: "#71717a", textDecoration: "underline" },
893
+ children: "Privacy Policy"
894
+ }
895
+ )
896
+ ] }),
897
+ /* @__PURE__ */ jsx6("div", { style: { display: "flex", justifyContent: "center", paddingTop: 2 }, children: /* @__PURE__ */ jsx6(ElvixSecuredBadge, { variant: "outline", theme: "light", size: "sm", accentColor: brand }) })
898
+ ] });
899
+ }
900
+ function hexToRgba(hex, alpha) {
901
+ const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
902
+ if (!m) return hex;
903
+ let h = m[1];
904
+ if (h.length === 3)
905
+ h = h.split("").map((c) => c + c).join("");
906
+ const n = Number.parseInt(h, 16);
907
+ const r = n >> 16 & 255;
908
+ const g = n >> 8 & 255;
909
+ const b = n & 255;
910
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
396
911
  }
397
912
 
398
913
  // src/react/elvix-sign-in-button.tsx
399
- var ELVIX_URL = "https://elvix.is";
914
+ import { useState as useState4 } from "react";
915
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
916
+ var ELVIX_URL2 = "https://elvix.is";
400
917
  var PRESET_LABEL = {
401
918
  "sign-in-with-elvix": "Sign in with elvix",
402
919
  "continue-with-elvix": "Continue with elvix",
@@ -435,7 +952,7 @@ function shieldColor(variant, theme) {
435
952
  }
436
953
  function ElvixSignInButton({
437
954
  clientId,
438
- baseUrl = ELVIX_URL,
955
+ baseUrl = ELVIX_URL2,
439
956
  returnUrl,
440
957
  type = "standard",
441
958
  variant = "filled",
@@ -448,9 +965,16 @@ function ElvixSignInButton({
448
965
  href,
449
966
  mode = "redirect",
450
967
  onClick,
451
- onResult
968
+ onResult,
969
+ width,
970
+ height,
971
+ minWidth,
972
+ maxWidth,
973
+ minHeight,
974
+ maxHeight
452
975
  }) {
453
- const [embedOpen, setEmbedOpen] = useState3(false);
976
+ const sized = sizeStyle({ width, height, minWidth, maxWidth, minHeight, maxHeight });
977
+ const [embedOpen, setEmbedOpen] = useState4(false);
454
978
  const isIcon = type === "icon";
455
979
  const resolvedLabel = label ?? PRESET_LABEL[preset];
456
980
  const tone = variantTone(variant, theme);
@@ -471,31 +995,39 @@ function ElvixSignInButton({
471
995
  border: tone.border,
472
996
  boxShadow: tone.shadow,
473
997
  transition: "background 0.15s, border-color 0.15s",
474
- ...isIcon ? { height: SIZE_ICON[size], width: SIZE_ICON[size] } : { height: std.height, paddingLeft: std.padX, paddingRight: std.padX, gap: std.gap }
998
+ ...isIcon ? { height: SIZE_ICON[size], width: SIZE_ICON[size] } : { height: std.height, paddingLeft: std.padX, paddingRight: std.padX, gap: std.gap },
999
+ // Dimensional overrides win over the size preset above.
1000
+ ...sized
475
1001
  };
476
- const content = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ElvixShield, { size: ICON_SIZE[size], fill: shieldColor(variant, theme), accent: "#8e7dff" }), isIcon ? null : /* @__PURE__ */ React.createElement("span", null, resolvedLabel));
1002
+ const content = /* @__PURE__ */ jsxs6(Fragment2, { children: [
1003
+ /* @__PURE__ */ jsx7(ElvixShield, { size: ICON_SIZE[size], fill: shieldColor(variant, theme), accent: "#8e7dff" }),
1004
+ isIcon ? null : /* @__PURE__ */ jsx7("span", { children: resolvedLabel })
1005
+ ] });
477
1006
  if (mode === "callback") {
478
- return /* @__PURE__ */ React.createElement("button", { type: "button", onClick, className, style, "aria-label": isIcon ? resolvedLabel : void 0 }, content);
1007
+ return /* @__PURE__ */ jsx7("button", { type: "button", onClick, className, style, "aria-label": isIcon ? resolvedLabel : void 0, children: content });
479
1008
  }
480
1009
  if (mode === "embed") {
481
- return /* @__PURE__ */ React.createElement("div", { "data-elvix-signin-button-embed": "" }, !embedOpen && /* @__PURE__ */ React.createElement(
482
- "button",
483
- {
484
- type: "button",
485
- onClick: () => setEmbedOpen(true),
486
- className,
487
- style,
488
- "aria-label": isIcon ? resolvedLabel : void 0
489
- },
490
- content
491
- ), embedOpen && /* @__PURE__ */ React.createElement(
492
- ElvixSignIn,
493
- {
494
- onResult: (r) => {
495
- onResult?.(r);
1010
+ return /* @__PURE__ */ jsxs6("div", { "data-elvix-signin-button-embed": "", style: sized, children: [
1011
+ !embedOpen && /* @__PURE__ */ jsx7(
1012
+ "button",
1013
+ {
1014
+ type: "button",
1015
+ onClick: () => setEmbedOpen(true),
1016
+ className,
1017
+ style,
1018
+ "aria-label": isIcon ? resolvedLabel : void 0,
1019
+ children: content
496
1020
  }
497
- }
498
- ));
1021
+ ),
1022
+ embedOpen && /* @__PURE__ */ jsx7(
1023
+ ElvixSignIn,
1024
+ {
1025
+ onResult: (r) => {
1026
+ onResult?.(r);
1027
+ }
1028
+ }
1029
+ )
1030
+ ] });
499
1031
  }
500
1032
  const destination = (() => {
501
1033
  if (href) return href;
@@ -504,80 +1036,17 @@ function ElvixSignInButton({
504
1036
  const sep = base.includes("?") ? "&" : "?";
505
1037
  return `${base}${sep}return=${encodeURIComponent(returnUrl)}`;
506
1038
  })();
507
- return /* @__PURE__ */ React.createElement("a", { href: destination, className, style, "aria-label": isIcon ? resolvedLabel : void 0 }, content);
508
- }
509
-
510
- // src/react/elvix-secured-badge.tsx
511
- var ELVIX_URL2 = "https://elvix.is";
512
- var SIZE = {
513
- sm: { height: 28, padX: 10, font: 11.5, icon: 14, gap: 6 },
514
- md: { height: 32, padX: 12, font: 12.5, icon: 16, gap: 7 },
515
- lg: { height: 36, padX: 14, font: 13, icon: 18, gap: 8 }
516
- };
517
- var TONE = {
518
- white: {
519
- light: { bg: "#ffffff", border: "#e4e4e7", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" },
520
- dark: { bg: "#ffffff", border: "transparent", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" }
521
- },
522
- dark: {
523
- light: { bg: "#0a0a0b", border: "rgba(0,0,0,0.1)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" },
524
- dark: { bg: "#0a0a0b", border: "rgba(255,255,255,0.1)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" }
525
- },
526
- outline: {
527
- light: { bg: "transparent", border: "rgba(0,0,0,0.15)", lead: "#71717a", brand: "#0a0a0b", shield: "#0a0a0b" },
528
- dark: { bg: "transparent", border: "rgba(142,125,255,0.4)", lead: "#d4d4d8", brand: "#ffffff", shield: "#ffffff" }
529
- }
530
- };
531
- function ElvixSecuredBadge({
532
- variant = "white",
533
- size = "md",
534
- theme = "dark",
535
- accentColor = "#8e7dff",
536
- href = ELVIX_URL2,
537
- className = ""
538
- }) {
539
- const s = SIZE[size];
540
- const t = TONE[variant][theme];
541
- const style = {
542
- display: "inline-flex",
543
- alignItems: "center",
544
- gap: s.gap,
545
- height: s.height,
546
- paddingLeft: s.padX,
547
- paddingRight: s.padX,
548
- fontSize: s.font,
549
- fontWeight: 500,
550
- borderRadius: 9999,
551
- background: t.bg,
552
- border: `1px solid ${t.border}`,
553
- color: t.brand,
554
- textDecoration: "none",
555
- userSelect: "none",
556
- lineHeight: 1
557
- };
558
- return /* @__PURE__ */ React.createElement(
559
- "a",
560
- {
561
- href,
562
- target: "_blank",
563
- rel: "noopener noreferrer",
564
- className,
565
- style,
566
- "data-elvix-secured-badge": ""
567
- },
568
- /* @__PURE__ */ React.createElement(ElvixShield, { size: s.icon, fill: t.shield, accent: accentColor }),
569
- /* @__PURE__ */ React.createElement("span", { style: { display: "inline-flex", alignItems: "baseline", gap: 4 } }, /* @__PURE__ */ React.createElement("span", { style: { color: t.lead } }, "Secured by"), /* @__PURE__ */ React.createElement("span", { style: { color: t.brand, fontWeight: 600 } }, "elvix"))
570
- );
1039
+ return /* @__PURE__ */ jsx7("a", { href: destination, className, style, "aria-label": isIcon ? resolvedLabel : void 0, children: content });
571
1040
  }
572
1041
 
573
1042
  // src/react/hooks.ts
574
- import { useCallback, useEffect as useEffect2, useState as useState4 } from "react";
1043
+ import { useCallback, useEffect as useEffect2, useState as useState5 } from "react";
575
1044
  var POLL_MS = 7e3;
576
1045
  function useUserList(kind, opts) {
577
1046
  const { applicationId, baseUrl = "", pollMs = POLL_MS } = opts;
578
- const [slugs, setSlugs] = useState4([]);
579
- const [loading, setLoading] = useState4(true);
580
- const [error, setError] = useState4(null);
1047
+ const [slugs, setSlugs] = useState5([]);
1048
+ const [loading, setLoading] = useState5(true);
1049
+ const [error, setError] = useState5(null);
581
1050
  const refresh = useCallback(async () => {
582
1051
  setError(null);
583
1052
  try {
@@ -644,7 +1113,7 @@ function ElvixLifecycleWatcher({
644
1113
  }
645
1114
 
646
1115
  // src/react/elvix-username.tsx
647
- import { useState as useState5 } from "react";
1116
+ import { useState as useState6 } from "react";
648
1117
 
649
1118
  // src/react/lib.ts
650
1119
  async function appPost(opts, path, body) {
@@ -702,14 +1171,22 @@ async function appDelete(opts, path) {
702
1171
  }
703
1172
 
704
1173
  // src/react/elvix-username.tsx
1174
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
705
1175
  function ElvixUsername({
706
- onResult
1176
+ onResult,
1177
+ width,
1178
+ height,
1179
+ minWidth,
1180
+ maxWidth,
1181
+ minHeight,
1182
+ maxHeight
707
1183
  }) {
1184
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
708
1185
  const ctx = useElvixContext();
709
- const [value, setValue] = useState5("");
710
- const [busy, setBusy] = useState5(false);
711
- const [error, setError] = useState5(null);
712
- const [done, setDone] = useState5(null);
1186
+ const [value, setValue] = useState6("");
1187
+ const [busy, setBusy] = useState6(false);
1188
+ const [error, setError] = useState6(null);
1189
+ const [done, setDone] = useState6(null);
713
1190
  async function submit(e) {
714
1191
  e.preventDefault();
715
1192
  if (!ctx.app) return;
@@ -729,32 +1206,51 @@ function ElvixUsername({
729
1206
  onResult?.(result);
730
1207
  }
731
1208
  if (done) {
732
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Username saved" }, /* @__PURE__ */ React.createElement("p", null, "You are now ", /* @__PURE__ */ React.createElement("strong", null, "@", done), "."));
1209
+ return /* @__PURE__ */ jsx8(ElvixCard, { title: "Username saved", ...sizeProps, children: /* @__PURE__ */ jsxs7("p", { children: [
1210
+ "You are now ",
1211
+ /* @__PURE__ */ jsxs7("strong", { children: [
1212
+ "@",
1213
+ done
1214
+ ] }),
1215
+ "."
1216
+ ] }) });
733
1217
  }
734
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Choose a username" }, /* @__PURE__ */ React.createElement("form", { onSubmit: submit, className: "elvix-form" }, /* @__PURE__ */ React.createElement(
735
- "input",
736
- {
737
- type: "text",
738
- value,
739
- onChange: (e) => setValue(e.target.value.toLowerCase()),
740
- placeholder: "alice",
741
- pattern: "[a-z][a-z0-9._]{2,28}[a-z0-9]",
742
- required: true,
743
- disabled: busy,
744
- className: "elvix-input"
745
- }
746
- ), /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy || value.length < 4, className: "elvix-btn elvix-btn-primary" }, busy ? "Saving\u2026" : "Claim"), error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error)));
1218
+ return /* @__PURE__ */ jsx8(ElvixCard, { title: "Choose a username", ...sizeProps, children: /* @__PURE__ */ jsxs7("form", { onSubmit: submit, className: "elvix-form", children: [
1219
+ /* @__PURE__ */ jsx8(
1220
+ "input",
1221
+ {
1222
+ type: "text",
1223
+ value,
1224
+ onChange: (e) => setValue(e.target.value.toLowerCase()),
1225
+ placeholder: "alice",
1226
+ pattern: "[a-z][a-z0-9._]{2,28}[a-z0-9]",
1227
+ required: true,
1228
+ disabled: busy,
1229
+ className: "elvix-input"
1230
+ }
1231
+ ),
1232
+ /* @__PURE__ */ jsx8("button", { type: "submit", disabled: busy || value.length < 4, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Claim" }),
1233
+ error && /* @__PURE__ */ jsx8("p", { role: "alert", className: "elvix-error", children: error })
1234
+ ] }) });
747
1235
  }
748
1236
 
749
1237
  // src/react/elvix-avatar.tsx
750
- import { useState as useState6 } from "react";
1238
+ import { useState as useState7 } from "react";
1239
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
751
1240
  function ElvixAvatar({
752
- onResult
1241
+ onResult,
1242
+ width,
1243
+ height,
1244
+ minWidth,
1245
+ maxWidth,
1246
+ minHeight,
1247
+ maxHeight
753
1248
  }) {
1249
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
754
1250
  const ctx = useElvixContext();
755
- const [busy, setBusy] = useState6(false);
756
- const [error, setError] = useState6(null);
757
- const [preview, setPreview] = useState6(null);
1251
+ const [busy, setBusy] = useState7(false);
1252
+ const [error, setError] = useState7(null);
1253
+ const [preview, setPreview] = useState7(null);
758
1254
  async function onFile(e) {
759
1255
  const file = e.target.files?.[0];
760
1256
  if (!file || !ctx.app) return;
@@ -777,25 +1273,38 @@ function ElvixAvatar({
777
1273
  if (!result.ok) setError(result.error);
778
1274
  onResult?.(result);
779
1275
  }
780
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Avatar" }, preview && /* @__PURE__ */ React.createElement(
781
- "img",
782
- {
783
- src: preview,
784
- alt: "avatar preview",
785
- style: { width: 96, height: 96, borderRadius: "50%", objectFit: "cover", marginBottom: 12 }
786
- }
787
- ), /* @__PURE__ */ React.createElement("input", { type: "file", accept: "image/png,image/jpeg,image/webp", onChange: onFile, disabled: busy }), busy && /* @__PURE__ */ React.createElement("p", null, "Uploading\u2026"), error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error));
1276
+ return /* @__PURE__ */ jsxs8(ElvixCard, { title: "Avatar", ...sizeProps, children: [
1277
+ preview && /* @__PURE__ */ jsx9(
1278
+ "img",
1279
+ {
1280
+ src: preview,
1281
+ alt: "avatar preview",
1282
+ style: { width: 96, height: 96, borderRadius: "50%", objectFit: "cover", marginBottom: 12 }
1283
+ }
1284
+ ),
1285
+ /* @__PURE__ */ jsx9("input", { type: "file", accept: "image/png,image/jpeg,image/webp", onChange: onFile, disabled: busy }),
1286
+ busy && /* @__PURE__ */ jsx9("p", { children: "Uploading\u2026" }),
1287
+ error && /* @__PURE__ */ jsx9("p", { role: "alert", className: "elvix-error", children: error })
1288
+ ] });
788
1289
  }
789
1290
 
790
1291
  // src/react/elvix-banner.tsx
791
- import { useState as useState7 } from "react";
1292
+ import { useState as useState8 } from "react";
1293
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
792
1294
  function ElvixBanner({
793
- onResult
1295
+ onResult,
1296
+ width,
1297
+ height,
1298
+ minWidth,
1299
+ maxWidth,
1300
+ minHeight,
1301
+ maxHeight
794
1302
  }) {
1303
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
795
1304
  const ctx = useElvixContext();
796
- const [busy, setBusy] = useState7(false);
797
- const [error, setError] = useState7(null);
798
- const [preview, setPreview] = useState7(null);
1305
+ const [busy, setBusy] = useState8(false);
1306
+ const [error, setError] = useState8(null);
1307
+ const [preview, setPreview] = useState8(null);
799
1308
  async function onFile(e) {
800
1309
  const file = e.target.files?.[0];
801
1310
  if (!file || !ctx.app) return;
@@ -818,29 +1327,42 @@ function ElvixBanner({
818
1327
  if (!result.ok) setError(result.error);
819
1328
  onResult?.(result);
820
1329
  }
821
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Banner" }, preview && /* @__PURE__ */ React.createElement(
822
- "img",
823
- {
824
- src: preview,
825
- alt: "banner preview",
826
- style: { width: "100%", aspectRatio: "16/9", objectFit: "cover", borderRadius: 10, marginBottom: 12 }
827
- }
828
- ), /* @__PURE__ */ React.createElement("input", { type: "file", accept: "image/png,image/jpeg,image/webp", onChange: onFile, disabled: busy }), busy && /* @__PURE__ */ React.createElement("p", null, "Uploading\u2026"), error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error));
1330
+ return /* @__PURE__ */ jsxs9(ElvixCard, { title: "Banner", ...sizeProps, children: [
1331
+ preview && /* @__PURE__ */ jsx10(
1332
+ "img",
1333
+ {
1334
+ src: preview,
1335
+ alt: "banner preview",
1336
+ style: { width: "100%", aspectRatio: "16/9", objectFit: "cover", borderRadius: 10, marginBottom: 12 }
1337
+ }
1338
+ ),
1339
+ /* @__PURE__ */ jsx10("input", { type: "file", accept: "image/png,image/jpeg,image/webp", onChange: onFile, disabled: busy }),
1340
+ busy && /* @__PURE__ */ jsx10("p", { children: "Uploading\u2026" }),
1341
+ error && /* @__PURE__ */ jsx10("p", { role: "alert", className: "elvix-error", children: error })
1342
+ ] });
829
1343
  }
830
1344
 
831
1345
  // src/react/elvix-identity-form.tsx
832
- import { useState as useState8 } from "react";
1346
+ import { useState as useState9 } from "react";
1347
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
833
1348
  function ElvixIdentityForm({
834
1349
  initialName = "",
835
1350
  initialBio = "",
836
- onResult
1351
+ onResult,
1352
+ width,
1353
+ height,
1354
+ minWidth,
1355
+ maxWidth,
1356
+ minHeight,
1357
+ maxHeight
837
1358
  }) {
1359
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
838
1360
  const ctx = useElvixContext();
839
- const [name, setName] = useState8(initialName);
840
- const [bio, setBio] = useState8(initialBio);
841
- const [busy, setBusy] = useState8(false);
842
- const [error, setError] = useState8(null);
843
- const [saved, setSaved] = useState8(false);
1361
+ const [name, setName] = useState9(initialName);
1362
+ const [bio, setBio] = useState9(initialBio);
1363
+ const [busy, setBusy] = useState9(false);
1364
+ const [error, setError] = useState9(null);
1365
+ const [saved, setSaved] = useState9(false);
844
1366
  async function submit(e) {
845
1367
  e.preventDefault();
846
1368
  if (!ctx.app) return;
@@ -856,22 +1378,42 @@ function ElvixIdentityForm({
856
1378
  else setSaved(true);
857
1379
  onResult?.(result);
858
1380
  }
859
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Identity" }, /* @__PURE__ */ React.createElement("form", { onSubmit: submit, className: "elvix-form" }, /* @__PURE__ */ React.createElement("label", null, "Name", /* @__PURE__ */ React.createElement("input", { value: name, onChange: (e) => setName(e.target.value), maxLength: 80, disabled: busy, className: "elvix-input" })), /* @__PURE__ */ React.createElement("label", null, "Bio", /* @__PURE__ */ React.createElement("textarea", { value: bio, onChange: (e) => setBio(e.target.value), maxLength: 500, rows: 3, disabled: busy, className: "elvix-input" })), /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary" }, busy ? "Saving\u2026" : "Save"), saved && /* @__PURE__ */ React.createElement("p", { className: "elvix-muted" }, "Saved."), error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error)));
1381
+ return /* @__PURE__ */ jsx11(ElvixCard, { title: "Identity", ...sizeProps, children: /* @__PURE__ */ jsxs10("form", { onSubmit: submit, className: "elvix-form", children: [
1382
+ /* @__PURE__ */ jsxs10("label", { children: [
1383
+ "Name",
1384
+ /* @__PURE__ */ jsx11("input", { value: name, onChange: (e) => setName(e.target.value), maxLength: 80, disabled: busy, className: "elvix-input" })
1385
+ ] }),
1386
+ /* @__PURE__ */ jsxs10("label", { children: [
1387
+ "Bio",
1388
+ /* @__PURE__ */ jsx11("textarea", { value: bio, onChange: (e) => setBio(e.target.value), maxLength: 500, rows: 3, disabled: busy, className: "elvix-input" })
1389
+ ] }),
1390
+ /* @__PURE__ */ jsx11("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" }),
1391
+ saved && /* @__PURE__ */ jsx11("p", { className: "elvix-muted", children: "Saved." }),
1392
+ error && /* @__PURE__ */ jsx11("p", { role: "alert", className: "elvix-error", children: error })
1393
+ ] }) });
860
1394
  }
861
1395
 
862
1396
  // src/react/elvix-region.tsx
863
- import { useState as useState9 } from "react";
1397
+ import { useState as useState10 } from "react";
1398
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
864
1399
  function ElvixRegion({
865
1400
  initialCountry = "",
866
1401
  initialTimezone = "",
867
- onResult
1402
+ onResult,
1403
+ width,
1404
+ height,
1405
+ minWidth,
1406
+ maxWidth,
1407
+ minHeight,
1408
+ maxHeight
868
1409
  }) {
1410
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
869
1411
  const ctx = useElvixContext();
870
- const [country, setCountry] = useState9(initialCountry);
871
- const [timezone, setTimezone] = useState9(initialTimezone);
872
- const [busy, setBusy] = useState9(false);
873
- const [error, setError] = useState9(null);
874
- const [saved, setSaved] = useState9(false);
1412
+ const [country, setCountry] = useState10(initialCountry);
1413
+ const [timezone, setTimezone] = useState10(initialTimezone);
1414
+ const [busy, setBusy] = useState10(false);
1415
+ const [error, setError] = useState10(null);
1416
+ const [saved, setSaved] = useState10(false);
875
1417
  async function submit(e) {
876
1418
  e.preventDefault();
877
1419
  if (!ctx.app) return;
@@ -887,20 +1429,40 @@ function ElvixRegion({
887
1429
  else setSaved(true);
888
1430
  onResult?.(result);
889
1431
  }
890
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Region" }, /* @__PURE__ */ React.createElement("form", { onSubmit: submit, className: "elvix-form" }, /* @__PURE__ */ React.createElement("label", null, "Country (ISO-2)", /* @__PURE__ */ React.createElement("input", { value: country, onChange: (e) => setCountry(e.target.value.toUpperCase()), maxLength: 2, pattern: "[A-Z]{2}", disabled: busy, className: "elvix-input" })), /* @__PURE__ */ React.createElement("label", null, "Timezone", /* @__PURE__ */ React.createElement("input", { value: timezone, onChange: (e) => setTimezone(e.target.value), placeholder: "Europe/Berlin", disabled: busy, className: "elvix-input" })), /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary" }, busy ? "Saving\u2026" : "Save"), saved && /* @__PURE__ */ React.createElement("p", { className: "elvix-muted" }, "Saved."), error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error)));
1432
+ return /* @__PURE__ */ jsx12(ElvixCard, { title: "Region", ...sizeProps, children: /* @__PURE__ */ jsxs11("form", { onSubmit: submit, className: "elvix-form", children: [
1433
+ /* @__PURE__ */ jsxs11("label", { children: [
1434
+ "Country (ISO-2)",
1435
+ /* @__PURE__ */ jsx12("input", { value: country, onChange: (e) => setCountry(e.target.value.toUpperCase()), maxLength: 2, pattern: "[A-Z]{2}", disabled: busy, className: "elvix-input" })
1436
+ ] }),
1437
+ /* @__PURE__ */ jsxs11("label", { children: [
1438
+ "Timezone",
1439
+ /* @__PURE__ */ jsx12("input", { value: timezone, onChange: (e) => setTimezone(e.target.value), placeholder: "Europe/Berlin", disabled: busy, className: "elvix-input" })
1440
+ ] }),
1441
+ /* @__PURE__ */ jsx12("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" }),
1442
+ saved && /* @__PURE__ */ jsx12("p", { className: "elvix-muted", children: "Saved." }),
1443
+ error && /* @__PURE__ */ jsx12("p", { role: "alert", className: "elvix-error", children: error })
1444
+ ] }) });
891
1445
  }
892
1446
 
893
1447
  // src/react/elvix-languages.tsx
894
- import { useState as useState10 } from "react";
1448
+ import { useState as useState11 } from "react";
1449
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
895
1450
  function ElvixLanguages({
896
1451
  initial = [],
897
- onResult
1452
+ onResult,
1453
+ width,
1454
+ height,
1455
+ minWidth,
1456
+ maxWidth,
1457
+ minHeight,
1458
+ maxHeight
898
1459
  }) {
1460
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
899
1461
  const ctx = useElvixContext();
900
- const [raw, setRaw] = useState10(initial.join(", "));
901
- const [busy, setBusy] = useState10(false);
902
- const [error, setError] = useState10(null);
903
- const [saved, setSaved] = useState10(false);
1462
+ const [raw, setRaw] = useState11(initial.join(", "));
1463
+ const [busy, setBusy] = useState11(false);
1464
+ const [error, setError] = useState11(null);
1465
+ const [saved, setSaved] = useState11(false);
904
1466
  async function submit(e) {
905
1467
  e.preventDefault();
906
1468
  if (!ctx.app) return;
@@ -917,18 +1479,34 @@ function ElvixLanguages({
917
1479
  else setSaved(true);
918
1480
  onResult?.(result);
919
1481
  }
920
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Languages" }, /* @__PURE__ */ React.createElement("form", { onSubmit: submit, className: "elvix-form" }, /* @__PURE__ */ React.createElement("label", null, "Preferred languages (comma-separated BCP-47 tags)", /* @__PURE__ */ React.createElement("input", { value: raw, onChange: (e) => setRaw(e.target.value), placeholder: "en-GB, de-DE", disabled: busy, className: "elvix-input" })), /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary" }, busy ? "Saving\u2026" : "Save"), saved && /* @__PURE__ */ React.createElement("p", { className: "elvix-muted" }, "Saved."), error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error)));
1482
+ return /* @__PURE__ */ jsx13(ElvixCard, { title: "Languages", ...sizeProps, children: /* @__PURE__ */ jsxs12("form", { onSubmit: submit, className: "elvix-form", children: [
1483
+ /* @__PURE__ */ jsxs12("label", { children: [
1484
+ "Preferred languages (comma-separated BCP-47 tags)",
1485
+ /* @__PURE__ */ jsx13("input", { value: raw, onChange: (e) => setRaw(e.target.value), placeholder: "en-GB, de-DE", disabled: busy, className: "elvix-input" })
1486
+ ] }),
1487
+ /* @__PURE__ */ jsx13("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" }),
1488
+ saved && /* @__PURE__ */ jsx13("p", { className: "elvix-muted", children: "Saved." }),
1489
+ error && /* @__PURE__ */ jsx13("p", { role: "alert", className: "elvix-error", children: error })
1490
+ ] }) });
921
1491
  }
922
1492
 
923
1493
  // src/react/elvix-sessions.tsx
924
- import { useEffect as useEffect4, useState as useState11 } from "react";
1494
+ import { useEffect as useEffect4, useState as useState12 } from "react";
1495
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
925
1496
  function ElvixSessions({
926
- onResult
1497
+ onResult,
1498
+ width,
1499
+ height,
1500
+ minWidth,
1501
+ maxWidth,
1502
+ minHeight,
1503
+ maxHeight
927
1504
  }) {
1505
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
928
1506
  const ctx = useElvixContext();
929
- const [rows, setRows] = useState11(null);
930
- const [error, setError] = useState11(null);
931
- const [busy, setBusy] = useState11(false);
1507
+ const [rows, setRows] = useState12(null);
1508
+ const [error, setError] = useState12(null);
1509
+ const [busy, setBusy] = useState12(false);
932
1510
  useEffect4(() => {
933
1511
  if (!ctx.app) return;
934
1512
  fetch(`${ctx.baseUrl}/api/account/apps/${ctx.app.applicationId}/sessions`, {
@@ -949,18 +1527,43 @@ function ElvixSessions({
949
1527
  if (result.ok) setRows((prev) => prev?.filter((s) => s.id !== id) ?? null);
950
1528
  onResult?.(result);
951
1529
  }
952
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Active sessions" }, error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error), !rows && !error && /* @__PURE__ */ React.createElement("p", null, "Loading\u2026"), rows && /* @__PURE__ */ React.createElement("ul", { style: { listStyle: "none", padding: 0, margin: 0 } }, rows.map((s) => /* @__PURE__ */ React.createElement("li", { key: s.id, style: { padding: "10px 0", borderBottom: "1px solid rgba(0,0,0,0.06)" } }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", justifyContent: "space-between", gap: 12 } }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { style: { fontSize: 13, fontWeight: 500 } }, s.device, s.current && /* @__PURE__ */ React.createElement("span", { style: { marginLeft: 8, color: "var(--elvix-primary-strong)", fontSize: 11 } }, "\xB7 this device")), /* @__PURE__ */ React.createElement("div", { style: { fontSize: 11, color: "rgba(0,0,0,0.55)" } }, s.country ?? "\u2014", " \xB7 since ", new Date(s.createdAt).toLocaleDateString())), !s.current && /* @__PURE__ */ React.createElement("button", { type: "button", disabled: busy, onClick: () => revoke(s.id), className: "elvix-btn elvix-btn-ghost" }, "Revoke"))))));
1530
+ return /* @__PURE__ */ jsxs13(ElvixCard, { title: "Active sessions", ...sizeProps, children: [
1531
+ error && /* @__PURE__ */ jsx14("p", { role: "alert", className: "elvix-error", children: error }),
1532
+ !rows && !error && /* @__PURE__ */ jsx14("p", { children: "Loading\u2026" }),
1533
+ 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: [
1534
+ /* @__PURE__ */ jsxs13("div", { children: [
1535
+ /* @__PURE__ */ jsxs13("div", { style: { fontSize: 13, fontWeight: 500 }, children: [
1536
+ s.device,
1537
+ s.current && /* @__PURE__ */ jsx14("span", { style: { marginLeft: 8, color: "var(--elvix-primary-strong)", fontSize: 11 }, children: "\xB7 this device" })
1538
+ ] }),
1539
+ /* @__PURE__ */ jsxs13("div", { style: { fontSize: 11, color: "rgba(0,0,0,0.55)" }, children: [
1540
+ s.country ?? "\u2014",
1541
+ " \xB7 since ",
1542
+ new Date(s.createdAt).toLocaleDateString()
1543
+ ] })
1544
+ ] }),
1545
+ !s.current && /* @__PURE__ */ jsx14("button", { type: "button", disabled: busy, onClick: () => revoke(s.id), className: "elvix-btn elvix-btn-ghost", children: "Revoke" })
1546
+ ] }) }, s.id)) })
1547
+ ] });
953
1548
  }
954
1549
 
955
1550
  // src/react/elvix-export.tsx
956
- import { useState as useState12 } from "react";
1551
+ import { useState as useState13 } from "react";
1552
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
957
1553
  function ElvixExport({
958
- onResult
1554
+ onResult,
1555
+ width,
1556
+ height,
1557
+ minWidth,
1558
+ maxWidth,
1559
+ minHeight,
1560
+ maxHeight
959
1561
  }) {
1562
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
960
1563
  const ctx = useElvixContext();
961
- const [busy, setBusy] = useState12(false);
962
- const [done, setDone] = useState12(false);
963
- const [error, setError] = useState12(null);
1564
+ const [busy, setBusy] = useState13(false);
1565
+ const [done, setDone] = useState13(false);
1566
+ const [error, setError] = useState13(null);
964
1567
  async function start() {
965
1568
  if (!ctx.app) return;
966
1569
  setBusy(true);
@@ -975,20 +1578,32 @@ function ElvixExport({
975
1578
  else setDone(true);
976
1579
  onResult?.(result);
977
1580
  }
978
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Export my data" }, /* @__PURE__ */ React.createElement("p", { style: { fontSize: 13, color: "rgba(0,0,0,0.6)" } }, "Request a zip of every record we hold for you in this app. Delivery by email; single-use download link valid for 24h."), done ? /* @__PURE__ */ React.createElement("p", { className: "elvix-muted" }, "Request queued. Check your email.") : /* @__PURE__ */ React.createElement("button", { type: "button", onClick: start, disabled: busy, className: "elvix-btn elvix-btn-primary" }, busy ? "Queuing\u2026" : "Request export"), error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error));
1581
+ return /* @__PURE__ */ jsxs14(ElvixCard, { title: "Export my data", ...sizeProps, children: [
1582
+ /* @__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." }),
1583
+ 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" }),
1584
+ error && /* @__PURE__ */ jsx15("p", { role: "alert", className: "elvix-error", children: error })
1585
+ ] });
979
1586
  }
980
1587
 
981
1588
  // src/react/elvix-deactivate.tsx
982
- import { useState as useState13 } from "react";
1589
+ import { useState as useState14 } from "react";
1590
+ import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
983
1591
  function ElvixDeactivate({
984
- onResult
1592
+ onResult,
1593
+ width,
1594
+ height,
1595
+ minWidth,
1596
+ maxWidth,
1597
+ minHeight,
1598
+ maxHeight
985
1599
  }) {
1600
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
986
1601
  const ctx = useElvixContext();
987
- const [pane, setPane] = useState13("warn");
988
- const [challengeId, setChallengeId] = useState13(null);
989
- const [code, setCode] = useState13("");
990
- const [busy, setBusy] = useState13(false);
991
- const [error, setError] = useState13(null);
1602
+ const [pane, setPane] = useState14("warn");
1603
+ const [challengeId, setChallengeId] = useState14(null);
1604
+ const [code, setCode] = useState14("");
1605
+ const [busy, setBusy] = useState14(false);
1606
+ const [error, setError] = useState14(null);
992
1607
  async function startChallenge() {
993
1608
  if (!ctx.app) return;
994
1609
  setBusy(true);
@@ -1026,35 +1641,54 @@ function ElvixDeactivate({
1026
1641
  onResult?.(result);
1027
1642
  }
1028
1643
  if (pane === "done") {
1029
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Deactivated" }, /* @__PURE__ */ React.createElement("p", null, "Your access has been paused. Sign in again to restore it."));
1644
+ return /* @__PURE__ */ jsx16(ElvixCard, { title: "Deactivated", ...sizeProps, children: /* @__PURE__ */ jsx16("p", { children: "Your access has been paused. Sign in again to restore it." }) });
1030
1645
  }
1031
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Deactivate account" }, pane === "warn" && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("p", { style: { fontSize: 13, color: "rgba(0,0,0,0.6)" } }, "Pause your membership. You can restore it any time by signing in again. No data is deleted."), /* @__PURE__ */ React.createElement("button", { type: "button", onClick: startChallenge, disabled: busy, className: "elvix-btn elvix-btn-danger" }, busy ? "Sending\u2026" : "Send code")), pane === "otp" && /* @__PURE__ */ React.createElement("form", { onSubmit: confirm, className: "elvix-form" }, /* @__PURE__ */ React.createElement("p", { className: "elvix-muted" }, "We sent a 6-digit code to your email."), /* @__PURE__ */ React.createElement(
1032
- "input",
1033
- {
1034
- type: "text",
1035
- inputMode: "numeric",
1036
- pattern: "[0-9]*",
1037
- maxLength: 6,
1038
- value: code,
1039
- onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
1040
- required: true,
1041
- disabled: busy,
1042
- className: "elvix-input"
1043
- }
1044
- ), /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy || code.length !== 6, className: "elvix-btn elvix-btn-danger" }, busy ? "Deactivating\u2026" : "Confirm")), error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error));
1646
+ return /* @__PURE__ */ jsxs15(ElvixCard, { title: "Deactivate account", ...sizeProps, children: [
1647
+ pane === "warn" && /* @__PURE__ */ jsxs15(Fragment3, { children: [
1648
+ /* @__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." }),
1649
+ /* @__PURE__ */ jsx16("button", { type: "button", onClick: startChallenge, disabled: busy, className: "elvix-btn elvix-btn-danger", children: busy ? "Sending\u2026" : "Send code" })
1650
+ ] }),
1651
+ pane === "otp" && /* @__PURE__ */ jsxs15("form", { onSubmit: confirm, className: "elvix-form", children: [
1652
+ /* @__PURE__ */ jsx16("p", { className: "elvix-muted", children: "We sent a 6-digit code to your email." }),
1653
+ /* @__PURE__ */ jsx16(
1654
+ "input",
1655
+ {
1656
+ type: "text",
1657
+ inputMode: "numeric",
1658
+ pattern: "[0-9]*",
1659
+ maxLength: 6,
1660
+ value: code,
1661
+ onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
1662
+ required: true,
1663
+ disabled: busy,
1664
+ className: "elvix-input"
1665
+ }
1666
+ ),
1667
+ /* @__PURE__ */ jsx16("button", { type: "submit", disabled: busy || code.length !== 6, className: "elvix-btn elvix-btn-danger", children: busy ? "Deactivating\u2026" : "Confirm" })
1668
+ ] }),
1669
+ error && /* @__PURE__ */ jsx16("p", { role: "alert", className: "elvix-error", children: error })
1670
+ ] });
1045
1671
  }
1046
1672
 
1047
1673
  // src/react/elvix-leave.tsx
1048
- import { useState as useState14 } from "react";
1674
+ import { useState as useState15 } from "react";
1675
+ import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
1049
1676
  function ElvixLeave({
1050
- onResult
1677
+ onResult,
1678
+ width,
1679
+ height,
1680
+ minWidth,
1681
+ maxWidth,
1682
+ minHeight,
1683
+ maxHeight
1051
1684
  }) {
1685
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
1052
1686
  const ctx = useElvixContext();
1053
- const [pane, setPane] = useState14("warn");
1054
- const [challengeId, setChallengeId] = useState14(null);
1055
- const [code, setCode] = useState14("");
1056
- const [busy, setBusy] = useState14(false);
1057
- const [error, setError] = useState14(null);
1687
+ const [pane, setPane] = useState15("warn");
1688
+ const [challengeId, setChallengeId] = useState15(null);
1689
+ const [code, setCode] = useState15("");
1690
+ const [busy, setBusy] = useState15(false);
1691
+ const [error, setError] = useState15(null);
1058
1692
  async function startChallenge() {
1059
1693
  if (!ctx.app) return;
1060
1694
  setBusy(true);
@@ -1092,35 +1726,54 @@ function ElvixLeave({
1092
1726
  onResult?.(result);
1093
1727
  }
1094
1728
  if (pane === "done") {
1095
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "You've left" }, /* @__PURE__ */ React.createElement("p", null, "You've left this app. Your data is archived; sign in again to rejoin."));
1729
+ 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." }) });
1096
1730
  }
1097
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Leave this app" }, pane === "warn" && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("p", { style: { fontSize: 13, color: "rgba(0,0,0,0.6)" } }, "Remove yourself from this app. Audit trail is preserved; you can sign back in any time to rejoin."), /* @__PURE__ */ React.createElement("button", { type: "button", onClick: startChallenge, disabled: busy, className: "elvix-btn elvix-btn-danger" }, busy ? "Sending\u2026" : "Send code")), pane === "otp" && /* @__PURE__ */ React.createElement("form", { onSubmit: confirm, className: "elvix-form" }, /* @__PURE__ */ React.createElement("p", { className: "elvix-muted" }, "We sent a 6-digit code to your email."), /* @__PURE__ */ React.createElement(
1098
- "input",
1099
- {
1100
- type: "text",
1101
- inputMode: "numeric",
1102
- pattern: "[0-9]*",
1103
- maxLength: 6,
1104
- value: code,
1105
- onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
1106
- required: true,
1107
- disabled: busy,
1108
- className: "elvix-input"
1109
- }
1110
- ), /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy || code.length !== 6, className: "elvix-btn elvix-btn-danger" }, busy ? "Leaving\u2026" : "Confirm leave")), error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error));
1731
+ return /* @__PURE__ */ jsxs16(ElvixCard, { title: "Leave this app", ...sizeProps, children: [
1732
+ pane === "warn" && /* @__PURE__ */ jsxs16(Fragment4, { children: [
1733
+ /* @__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." }),
1734
+ /* @__PURE__ */ jsx17("button", { type: "button", onClick: startChallenge, disabled: busy, className: "elvix-btn elvix-btn-danger", children: busy ? "Sending\u2026" : "Send code" })
1735
+ ] }),
1736
+ pane === "otp" && /* @__PURE__ */ jsxs16("form", { onSubmit: confirm, className: "elvix-form", children: [
1737
+ /* @__PURE__ */ jsx17("p", { className: "elvix-muted", children: "We sent a 6-digit code to your email." }),
1738
+ /* @__PURE__ */ jsx17(
1739
+ "input",
1740
+ {
1741
+ type: "text",
1742
+ inputMode: "numeric",
1743
+ pattern: "[0-9]*",
1744
+ maxLength: 6,
1745
+ value: code,
1746
+ onChange: (e) => setCode(e.target.value.replace(/\D/g, "")),
1747
+ required: true,
1748
+ disabled: busy,
1749
+ className: "elvix-input"
1750
+ }
1751
+ ),
1752
+ /* @__PURE__ */ jsx17("button", { type: "submit", disabled: busy || code.length !== 6, className: "elvix-btn elvix-btn-danger", children: busy ? "Leaving\u2026" : "Confirm leave" })
1753
+ ] }),
1754
+ error && /* @__PURE__ */ jsx17("p", { role: "alert", className: "elvix-error", children: error })
1755
+ ] });
1111
1756
  }
1112
1757
 
1113
1758
  // src/react/elvix-address-book.tsx
1114
- import { useEffect as useEffect5, useState as useState15 } from "react";
1759
+ import { useEffect as useEffect5, useState as useState16 } from "react";
1760
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
1115
1761
  function ElvixAddressBook({
1116
- onResult
1762
+ onResult,
1763
+ width,
1764
+ height,
1765
+ minWidth,
1766
+ maxWidth,
1767
+ minHeight,
1768
+ maxHeight
1117
1769
  }) {
1770
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
1118
1771
  const ctx = useElvixContext();
1119
- const [rows, setRows] = useState15(null);
1120
- const [error, setError] = useState15(null);
1121
- const [busy, setBusy] = useState15(false);
1122
- const [adding, setAdding] = useState15(false);
1123
- const [form, setForm] = useState15({
1772
+ const [rows, setRows] = useState16(null);
1773
+ const [error, setError] = useState16(null);
1774
+ const [busy, setBusy] = useState16(false);
1775
+ const [adding, setAdding] = useState16(false);
1776
+ const [form, setForm] = useState16({
1124
1777
  label: "Home",
1125
1778
  line1: "",
1126
1779
  postalCode: "",
@@ -1169,20 +1822,57 @@ function ElvixAddressBook({
1169
1822
  if (result.ok) setRows((prev) => prev?.filter((a) => a.id !== id) ?? null);
1170
1823
  onResult?.(result);
1171
1824
  }
1172
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Addresses" }, error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error), !rows && !error && /* @__PURE__ */ React.createElement("p", null, "Loading\u2026"), rows && rows.length === 0 && /* @__PURE__ */ React.createElement("p", { className: "elvix-muted" }, "No addresses yet."), rows?.map((a) => /* @__PURE__ */ React.createElement("div", { key: a.id, style: { padding: "8px 0", borderBottom: "1px solid rgba(0,0,0,0.06)", display: "flex", justifyContent: "space-between", gap: 12 } }, /* @__PURE__ */ React.createElement("div", { style: { fontSize: 13 } }, /* @__PURE__ */ React.createElement("div", { style: { fontWeight: 500 } }, a.label), /* @__PURE__ */ React.createElement("div", { style: { color: "rgba(0,0,0,0.55)" } }, a.line1, a.line2 ? `, ${a.line2}` : "", ", ", a.postalCode, " ", a.city, ", ", a.country)), /* @__PURE__ */ React.createElement("button", { type: "button", disabled: busy, onClick: () => remove(a.id), className: "elvix-btn elvix-btn-ghost" }, "Remove"))), !adding && /* @__PURE__ */ React.createElement("button", { type: "button", onClick: () => setAdding(true), className: "elvix-btn elvix-btn-primary", style: { marginTop: 12 } }, "Add address"), adding && /* @__PURE__ */ React.createElement("form", { onSubmit: add, className: "elvix-form", style: { marginTop: 12 } }, /* @__PURE__ */ React.createElement("input", { value: form.label, onChange: (e) => setForm({ ...form, label: e.target.value }), placeholder: "Label", className: "elvix-input" }), /* @__PURE__ */ React.createElement("input", { value: form.line1, onChange: (e) => setForm({ ...form, line1: e.target.value }), placeholder: "Street", required: true, className: "elvix-input" }), /* @__PURE__ */ React.createElement("input", { value: form.postalCode, onChange: (e) => setForm({ ...form, postalCode: e.target.value }), placeholder: "Postal code", required: true, className: "elvix-input" }), /* @__PURE__ */ React.createElement("input", { value: form.city, onChange: (e) => setForm({ ...form, city: e.target.value }), placeholder: "City", required: true, className: "elvix-input" }), /* @__PURE__ */ React.createElement("input", { value: form.country, onChange: (e) => setForm({ ...form, country: e.target.value.toUpperCase() }), placeholder: "Country (ISO-2)", maxLength: 2, required: true, className: "elvix-input" }), /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary" }, busy ? "Saving\u2026" : "Save")));
1825
+ return /* @__PURE__ */ jsxs17(ElvixCard, { title: "Addresses", ...sizeProps, children: [
1826
+ error && /* @__PURE__ */ jsx18("p", { role: "alert", className: "elvix-error", children: error }),
1827
+ !rows && !error && /* @__PURE__ */ jsx18("p", { children: "Loading\u2026" }),
1828
+ rows && rows.length === 0 && /* @__PURE__ */ jsx18("p", { className: "elvix-muted", children: "No addresses yet." }),
1829
+ 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: [
1830
+ /* @__PURE__ */ jsxs17("div", { style: { fontSize: 13 }, children: [
1831
+ /* @__PURE__ */ jsx18("div", { style: { fontWeight: 500 }, children: a.label }),
1832
+ /* @__PURE__ */ jsxs17("div", { style: { color: "rgba(0,0,0,0.55)" }, children: [
1833
+ a.line1,
1834
+ a.line2 ? `, ${a.line2}` : "",
1835
+ ", ",
1836
+ a.postalCode,
1837
+ " ",
1838
+ a.city,
1839
+ ", ",
1840
+ a.country
1841
+ ] })
1842
+ ] }),
1843
+ /* @__PURE__ */ jsx18("button", { type: "button", disabled: busy, onClick: () => remove(a.id), className: "elvix-btn elvix-btn-ghost", children: "Remove" })
1844
+ ] }, a.id)),
1845
+ !adding && /* @__PURE__ */ jsx18("button", { type: "button", onClick: () => setAdding(true), className: "elvix-btn elvix-btn-primary", style: { marginTop: 12 }, children: "Add address" }),
1846
+ adding && /* @__PURE__ */ jsxs17("form", { onSubmit: add, className: "elvix-form", style: { marginTop: 12 }, children: [
1847
+ /* @__PURE__ */ jsx18("input", { value: form.label, onChange: (e) => setForm({ ...form, label: e.target.value }), placeholder: "Label", className: "elvix-input" }),
1848
+ /* @__PURE__ */ jsx18("input", { value: form.line1, onChange: (e) => setForm({ ...form, line1: e.target.value }), placeholder: "Street", required: true, className: "elvix-input" }),
1849
+ /* @__PURE__ */ jsx18("input", { value: form.postalCode, onChange: (e) => setForm({ ...form, postalCode: e.target.value }), placeholder: "Postal code", required: true, className: "elvix-input" }),
1850
+ /* @__PURE__ */ jsx18("input", { value: form.city, onChange: (e) => setForm({ ...form, city: e.target.value }), placeholder: "City", required: true, className: "elvix-input" }),
1851
+ /* @__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" }),
1852
+ /* @__PURE__ */ jsx18("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" })
1853
+ ] })
1854
+ ] });
1173
1855
  }
1174
1856
 
1175
1857
  // src/react/elvix-legal-entities.tsx
1176
- import { useEffect as useEffect6, useState as useState16 } from "react";
1858
+ import { useEffect as useEffect6, useState as useState17 } from "react";
1859
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
1177
1860
  function ElvixLegalEntities({
1178
- onResult
1861
+ onResult,
1862
+ width,
1863
+ height,
1864
+ minWidth,
1865
+ maxWidth,
1866
+ minHeight,
1867
+ maxHeight
1179
1868
  }) {
1869
+ const sizeProps = { width, height, minWidth, maxWidth, minHeight, maxHeight };
1180
1870
  const ctx = useElvixContext();
1181
- const [rows, setRows] = useState16(null);
1182
- const [error, setError] = useState16(null);
1183
- const [busy, setBusy] = useState16(false);
1184
- const [adding, setAdding] = useState16(false);
1185
- const [form, setForm] = useState16({
1871
+ const [rows, setRows] = useState17(null);
1872
+ const [error, setError] = useState17(null);
1873
+ const [busy, setBusy] = useState17(false);
1874
+ const [adding, setAdding] = useState17(false);
1875
+ const [form, setForm] = useState17({
1186
1876
  legalName: "",
1187
1877
  taxId: "",
1188
1878
  country: ""
@@ -1229,7 +1919,29 @@ function ElvixLegalEntities({
1229
1919
  if (result.ok) setRows((prev) => prev?.filter((a) => a.id !== id) ?? null);
1230
1920
  onResult?.(result);
1231
1921
  }
1232
- return /* @__PURE__ */ React.createElement(ElvixCard, { title: "Legal entities" }, error && /* @__PURE__ */ React.createElement("p", { role: "alert", className: "elvix-error" }, error), !rows && !error && /* @__PURE__ */ React.createElement("p", null, "Loading\u2026"), rows && rows.length === 0 && /* @__PURE__ */ React.createElement("p", { className: "elvix-muted" }, "No legal entities yet."), rows?.map((e) => /* @__PURE__ */ React.createElement("div", { key: e.id, style: { padding: "8px 0", borderBottom: "1px solid rgba(0,0,0,0.06)", display: "flex", justifyContent: "space-between", gap: 12 } }, /* @__PURE__ */ React.createElement("div", { style: { fontSize: 13 } }, /* @__PURE__ */ React.createElement("div", { style: { fontWeight: 500 } }, e.legalName), /* @__PURE__ */ React.createElement("div", { style: { color: "rgba(0,0,0,0.55)" } }, e.taxId, " \xB7 ", e.country)), /* @__PURE__ */ React.createElement("button", { type: "button", disabled: busy, onClick: () => remove(e.id), className: "elvix-btn elvix-btn-ghost" }, "Remove"))), !adding && /* @__PURE__ */ React.createElement("button", { type: "button", onClick: () => setAdding(true), className: "elvix-btn elvix-btn-primary", style: { marginTop: 12 } }, "Add entity"), adding && /* @__PURE__ */ React.createElement("form", { onSubmit: add, className: "elvix-form", style: { marginTop: 12 } }, /* @__PURE__ */ React.createElement("input", { value: form.legalName, onChange: (e) => setForm({ ...form, legalName: e.target.value }), placeholder: "Legal name", required: true, className: "elvix-input" }), /* @__PURE__ */ React.createElement("input", { value: form.taxId, onChange: (e) => setForm({ ...form, taxId: e.target.value }), placeholder: "Tax / VAT ID", required: true, className: "elvix-input" }), /* @__PURE__ */ React.createElement("input", { value: form.country, onChange: (e) => setForm({ ...form, country: e.target.value.toUpperCase() }), placeholder: "Country (ISO-2)", maxLength: 2, required: true, className: "elvix-input" }), /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary" }, busy ? "Saving\u2026" : "Save")));
1922
+ return /* @__PURE__ */ jsxs18(ElvixCard, { title: "Legal entities", ...sizeProps, children: [
1923
+ error && /* @__PURE__ */ jsx19("p", { role: "alert", className: "elvix-error", children: error }),
1924
+ !rows && !error && /* @__PURE__ */ jsx19("p", { children: "Loading\u2026" }),
1925
+ rows && rows.length === 0 && /* @__PURE__ */ jsx19("p", { className: "elvix-muted", children: "No legal entities yet." }),
1926
+ 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: [
1927
+ /* @__PURE__ */ jsxs18("div", { style: { fontSize: 13 }, children: [
1928
+ /* @__PURE__ */ jsx19("div", { style: { fontWeight: 500 }, children: e.legalName }),
1929
+ /* @__PURE__ */ jsxs18("div", { style: { color: "rgba(0,0,0,0.55)" }, children: [
1930
+ e.taxId,
1931
+ " \xB7 ",
1932
+ e.country
1933
+ ] })
1934
+ ] }),
1935
+ /* @__PURE__ */ jsx19("button", { type: "button", disabled: busy, onClick: () => remove(e.id), className: "elvix-btn elvix-btn-ghost", children: "Remove" })
1936
+ ] }, e.id)),
1937
+ !adding && /* @__PURE__ */ jsx19("button", { type: "button", onClick: () => setAdding(true), className: "elvix-btn elvix-btn-primary", style: { marginTop: 12 }, children: "Add entity" }),
1938
+ adding && /* @__PURE__ */ jsxs18("form", { onSubmit: add, className: "elvix-form", style: { marginTop: 12 }, children: [
1939
+ /* @__PURE__ */ jsx19("input", { value: form.legalName, onChange: (e) => setForm({ ...form, legalName: e.target.value }), placeholder: "Legal name", required: true, className: "elvix-input" }),
1940
+ /* @__PURE__ */ jsx19("input", { value: form.taxId, onChange: (e) => setForm({ ...form, taxId: e.target.value }), placeholder: "Tax / VAT ID", required: true, className: "elvix-input" }),
1941
+ /* @__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" }),
1942
+ /* @__PURE__ */ jsx19("button", { type: "submit", disabled: busy, className: "elvix-btn elvix-btn-primary", children: busy ? "Saving\u2026" : "Save" })
1943
+ ] })
1944
+ ] });
1233
1945
  }
1234
1946
  export {
1235
1947
  DEFAULT_COPY,
@@ -1250,6 +1962,7 @@ export {
1250
1962
  ElvixSessions,
1251
1963
  ElvixSignIn,
1252
1964
  ElvixSignInButton,
1965
+ ElvixSignInForm,
1253
1966
  ElvixUsername,
1254
1967
  getElvixToken,
1255
1968
  setElvixToken,