@kerne/react 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3268 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+ var _chunk7U3QBMA7cjs = require('../chunk-7U3QBMA7.cjs');
20
+
21
+ // src/ui/AuthFlow.tsx
22
+ var _react = require('react');
23
+
24
+ // src/ui/useUrlToken.ts
25
+
26
+ function useUrlToken(param = "token", override) {
27
+ const [token, setToken] = _react.useState.call(void 0, _nullishCoalesce(override, () => ( null)));
28
+ _react.useEffect.call(void 0, () => {
29
+ if (override) {
30
+ setToken(override);
31
+ return;
32
+ }
33
+ if (typeof window === "undefined") return;
34
+ setToken(_nullishCoalesce(new URLSearchParams(window.location.search).get(param), () => ( "")));
35
+ }, [param, override]);
36
+ return token;
37
+ }
38
+
39
+ // src/ui/LoginForm.tsx
40
+
41
+
42
+ // src/ui/primitives.tsx
43
+
44
+
45
+ // src/ui/styles.ts
46
+ var STYLE_ELEMENT_ID = "kerne-ui-styles";
47
+ var DARK_TOKENS = `
48
+ --kerne-fg: #f0f1f3;
49
+ --kerne-fg-muted: #9ba2ad;
50
+ --kerne-fg-subtle: #838b96;
51
+ --kerne-border: #2a2e36;
52
+ --kerne-border-strong: #363b45;
53
+ --kerne-panel: #1b1f26;
54
+ --kerne-surface: #14171c;
55
+ --kerne-surface-raised: #2a2f38;
56
+ --kerne-track: #313743;
57
+ --kerne-primary: #f0f1f3;
58
+ --kerne-primary-fg: #16181d;
59
+ --kerne-primary-hover: #d8dade;
60
+ --kerne-accent: #91a7ff;
61
+ --kerne-danger: #f0837a;
62
+ --kerne-success: #5cbd8d;
63
+ --kerne-warning: #d9ab5e;
64
+ --kerne-shadow: 0 4px 6px -2px rgba(0,0,0,.4), 0 12px 24px -8px rgba(0,0,0,.6);
65
+ `;
66
+ var CSS = `
67
+ .kerne-root {
68
+ --kerne-fg: #16171a;
69
+ --kerne-fg-muted: #6b7280;
70
+ /* Meets 4.5:1 on white - this carries placeholders and the legal footnote,
71
+ which used to sit around 2.5:1. */
72
+ --kerne-fg-subtle: #6f7681;
73
+ --kerne-border: #e3e5e9;
74
+ --kerne-border-strong: #d6dade;
75
+ --kerne-field-bg: transparent;
76
+ --kerne-panel: #f4f5f7;
77
+ /* The ground the component sits on. Transparent so an embedded instance
78
+ inherits the host's page; set it (appearance.background) when the component
79
+ owns the viewport, so text and background can never resolve independently. */
80
+ --kerne-bg: transparent;
81
+ /* An opaque surface for the things that must not show through: the card
82
+ variant, the dropdown floating over host content, a pressed segment. */
83
+ --kerne-surface: #ffffff;
84
+ --kerne-surface-raised: #ffffff;
85
+ /* Unfilled part of a meter, and the ground of a disabled button. Distinct
86
+ from --kerne-panel, which is tuned to sit on the page: on a card the two
87
+ are nearly the same colour, so a meter drawn in panel had invisible empty
88
+ segments and read as having fewer steps than it has. */
89
+ --kerne-track: #e3e5e9;
90
+ --kerne-primary: #16171a;
91
+ --kerne-primary-fg: #ffffff;
92
+ --kerne-primary-hover: #2c2e33;
93
+ --kerne-accent: #3b5bdb;
94
+ --kerne-danger: #c0392f;
95
+ --kerne-success: #1f7a4d;
96
+ --kerne-warning: #9a6b12;
97
+ --kerne-radius: 8px;
98
+ --kerne-control-height: 44px;
99
+ --kerne-shadow: 0 4px 6px -2px rgba(0,0,0,.06), 0 12px 24px -8px rgba(0,0,0,.16);
100
+ --kerne-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
101
+
102
+ box-sizing: border-box;
103
+ font-family: var(--kerne-font);
104
+ color: var(--kerne-fg);
105
+ background: var(--kerne-bg);
106
+ -webkit-font-smoothing: antialiased;
107
+ display: flex;
108
+ justify-content: center;
109
+ width: 100%;
110
+ }
111
+ .kerne-root *, .kerne-root *::before, .kerne-root *::after { box-sizing: inherit; }
112
+
113
+ .kerne-root[data-kerne-theme="dark"] {${DARK_TOKENS}}
114
+ /* Only an explicit opt-in follows the visitor's OS. Defaulting to it meant a
115
+ light-only host got a dark form on any machine set to dark, without ever
116
+ asking for one - and with no way for the host to know it had happened. */
117
+ @media (prefers-color-scheme: dark) {
118
+ .kerne-root[data-kerne-theme="system"] {${DARK_TOKENS}}
119
+ }
120
+
121
+ .kerne-shell {
122
+ width: 100%;
123
+ max-width: 384px;
124
+ display: flex;
125
+ flex-direction: column;
126
+ }
127
+ /* Auth screens are a single column of fields; an account manager is a
128
+ navigation plus a content pane and suffocates at 384px. */
129
+ .kerne-shell[data-kerne-size="wide"] { max-width: 800px; }
130
+
131
+ .kerne-shell[data-kerne-surface="card"] {
132
+ background: var(--kerne-surface);
133
+ border: 1px solid var(--kerne-border);
134
+ border-radius: calc(var(--kerne-radius) + 6px);
135
+ box-shadow: var(--kerne-shadow);
136
+ padding: 32px 28px;
137
+ /* The card is the ground from here down, so nested surfaces stop inheriting
138
+ the page behind it. */
139
+ --kerne-bg: var(--kerne-surface);
140
+ }
141
+ @media (max-width: 480px) {
142
+ /* Full-bleed on a phone: a card with 16px of page showing on each side wastes
143
+ the only axis a login form has. */
144
+ .kerne-shell[data-kerne-surface="card"] {
145
+ border: none;
146
+ box-shadow: none;
147
+ padding: 8px 0;
148
+ background: transparent;
149
+ /* The card no longer paints, so the ground is the page again. */
150
+ --kerne-bg: transparent;
151
+ }
152
+ }
153
+
154
+ /* ---------- Tabbed account manager ---------- */
155
+ .kerne-profile { display: grid; grid-template-columns: 188px minmax(0, 1fr); gap: 40px; align-items: start; }
156
+ @media (max-width: 640px) { .kerne-profile { grid-template-columns: 1fr; gap: 20px; } }
157
+
158
+ .kerne-nav { display: flex; flex-direction: column; gap: 2px; position: sticky; top: 24px; }
159
+ @media (max-width: 640px) {
160
+ .kerne-nav {
161
+ position: static;
162
+ flex-direction: row;
163
+ overflow-x: auto;
164
+ gap: 4px;
165
+ border-bottom: 1px solid var(--kerne-border);
166
+ padding-bottom: 8px;
167
+ }
168
+ }
169
+ .kerne-nav-item {
170
+ font: inherit; font-size: 14px; text-align: left;
171
+ background: none; border: none; cursor: pointer;
172
+ padding: 8px 12px; border-radius: 6px;
173
+ color: var(--kerne-fg-muted); white-space: nowrap;
174
+ transition: background-color .12s ease, color .12s ease;
175
+ }
176
+ .kerne-nav-item:hover { color: var(--kerne-fg); }
177
+ .kerne-nav-item[aria-current="page"] { background: var(--kerne-panel); color: var(--kerne-fg); font-weight: 500; }
178
+ .kerne-nav-item:focus-visible { outline: 2px solid var(--kerne-accent); outline-offset: 2px; }
179
+
180
+ .kerne-pane { display: flex; flex-direction: column; min-width: 0; }
181
+ .kerne-pane-title { font-size: 20px; font-weight: 600; letter-spacing: -.01em; margin: 0 0 4px; }
182
+ .kerne-pane-desc { font-size: 14px; color: var(--kerne-fg-muted); margin: 0 0 8px; }
183
+
184
+ .kerne-subsection { padding: 24px 0; display: flex; flex-direction: column; gap: 16px; }
185
+ .kerne-subsection:first-of-type { padding-top: 16px; }
186
+ .kerne-subsection + .kerne-subsection { border-top: 1px solid var(--kerne-border); }
187
+ .kerne-subsection-head { display: flex; flex-direction: column; gap: 3px; }
188
+ .kerne-subsection-title { font-size: 15px; font-weight: 600; margin: 0; }
189
+ .kerne-subsection-desc { font-size: 13px; color: var(--kerne-fg-muted); margin: 0; }
190
+ /* Buttons inside a settings pane are actions, not page-wide calls to action. */
191
+ .kerne-subsection .kerne-button { width: auto; align-self: flex-start; }
192
+
193
+ /* ---------- Plan options ---------- */
194
+ .kerne-plan-list { display: flex; flex-direction: column; gap: 10px; }
195
+ .kerne-plan-option {
196
+ display: flex; justify-content: space-between; align-items: center; gap: 16px;
197
+ padding: 14px 16px; border: 1px solid var(--kerne-border); border-radius: var(--kerne-radius);
198
+ }
199
+ .kerne-plan-option[data-current="true"] { border-color: var(--kerne-fg); }
200
+ .kerne-plan-option-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
201
+ .kerne-plan-option-name { font-size: 14px; font-weight: 500; display: flex; align-items: center; gap: 8px; }
202
+ .kerne-plan-option-price { font-size: 13px; color: var(--kerne-fg-muted); font-variant-numeric: tabular-nums; }
203
+ .kerne-plan-option .kerne-button { width: auto; flex-shrink: 0; height: 36px; font-size: 13px; }
204
+
205
+ /* Segmented control for billing interval. */
206
+ .kerne-segmented { display: inline-flex; padding: 3px; gap: 2px; background: var(--kerne-panel); border-radius: var(--kerne-radius); align-self: flex-start; }
207
+ .kerne-segment {
208
+ font: inherit; font-size: 13px; border: none; background: none; cursor: pointer;
209
+ padding: 5px 12px; border-radius: calc(var(--kerne-radius) - 3px); color: var(--kerne-fg-muted);
210
+ }
211
+ .kerne-segment[aria-pressed="true"] { background: var(--kerne-surface-raised); color: var(--kerne-fg); font-weight: 500; }
212
+ .kerne-segment:focus-visible { outline: 2px solid var(--kerne-accent); outline-offset: 2px; }
213
+
214
+ /* ---------- Masthead ---------- */
215
+ .kerne-masthead {
216
+ display: flex;
217
+ flex-direction: column;
218
+ align-items: center;
219
+ gap: 16px;
220
+ text-align: center;
221
+ margin-bottom: 32px;
222
+ }
223
+ .kerne-logo { display: flex; align-items: center; justify-content: center; }
224
+ .kerne-heading { display: flex; flex-direction: column; gap: 6px; }
225
+ .kerne-title {
226
+ margin: 0;
227
+ font-size: 24px;
228
+ font-weight: 600;
229
+ letter-spacing: -.02em;
230
+ line-height: 1.2;
231
+ text-wrap: balance;
232
+ }
233
+ .kerne-subtitle { margin: 0; font-size: 14px; color: var(--kerne-fg-muted); line-height: 1.5; }
234
+
235
+ /* Moving between steps (sign-in -> sign-up -> forgot password) used to be an
236
+ instant swap: the content and the height both jumped at once, which reads
237
+ as a page reload rather than one flow. */
238
+ @keyframes kerne-step-in {
239
+ from { opacity: 0; transform: translateY(4px); }
240
+ to { opacity: 1; transform: none; }
241
+ }
242
+ .kerne-step { animation: kerne-step-in .18s ease-out; }
243
+ @media (prefers-reduced-motion: reduce) {
244
+ .kerne-step { animation: none; }
245
+ }
246
+
247
+ /* ---------- Stack ---------- */
248
+ .kerne-stack { display: flex; flex-direction: column; gap: 16px; }
249
+ .kerne-form { display: flex; flex-direction: column; gap: 12px; }
250
+ .kerne-field { display: flex; flex-direction: column; gap: 6px; }
251
+ .kerne-label { font-size: 14px; font-weight: 500; color: var(--kerne-fg); }
252
+ .kerne-label-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
253
+
254
+ /* Positioning context for the reveal toggle, which sits inside the input box. */
255
+ .kerne-control { position: relative; display: flex; }
256
+
257
+ .kerne-input {
258
+ font: inherit;
259
+ font-size: 14px;
260
+ height: var(--kerne-control-height);
261
+ color: var(--kerne-fg);
262
+ background: var(--kerne-field-bg);
263
+ border: 1px solid var(--kerne-border-strong);
264
+ border-radius: var(--kerne-radius);
265
+ padding: 0 13px;
266
+ width: 100%;
267
+ transition: border-color .12s ease, box-shadow .12s ease;
268
+ }
269
+ /* Room for the toggle, so a long password never runs underneath it. */
270
+ .kerne-input[data-kerne-reveal="true"] { padding-right: 42px; }
271
+
272
+ .kerne-reveal {
273
+ position: absolute;
274
+ top: 0; right: 0; bottom: 0;
275
+ width: 40px;
276
+ display: flex; align-items: center; justify-content: center;
277
+ background: none; border: none; padding: 0; cursor: pointer;
278
+ color: var(--kerne-fg-subtle);
279
+ border-radius: var(--kerne-radius);
280
+ transition: color .12s ease;
281
+ }
282
+ .kerne-reveal:hover:not(:disabled) { color: var(--kerne-fg); }
283
+ .kerne-reveal:disabled { cursor: not-allowed; opacity: .5; }
284
+ .kerne-reveal:focus-visible { outline: 2px solid var(--kerne-accent); outline-offset: -2px; }
285
+
286
+ .kerne-field-note { font-size: 12.5px; line-height: 1.4; color: var(--kerne-fg-muted); margin: 0; }
287
+ .kerne-field-error { font-size: 12.5px; line-height: 1.4; color: var(--kerne-danger); margin: 0; }
288
+ /* Caps Lock is a "you are about to get this wrong" signal, not background
289
+ guidance - in muted grey it sat at the same weight as a hint and got read
290
+ as one. */
291
+ .kerne-field-note[data-kerne-warn="true"] { color: var(--kerne-warning); }
292
+
293
+ /* ---------- Password rules ---------- */
294
+ /* Unmet stays at hint weight rather than turning red: nothing is wrong yet,
295
+ the user is still typing. Only the tick earns a color. */
296
+ .kerne-rules { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 3px; }
297
+ .kerne-rule {
298
+ display: flex; align-items: center; gap: 6px;
299
+ font-size: 12.5px; line-height: 1.4; color: var(--kerne-fg-muted);
300
+ }
301
+ .kerne-rule[data-met] { color: var(--kerne-success); }
302
+
303
+ /* ---------- Password strength ---------- */
304
+ .kerne-strength { display: flex; flex-direction: column; gap: 5px; }
305
+ .kerne-strength-track { display: flex; gap: 4px; }
306
+ .kerne-strength-step {
307
+ flex: 1; height: 3px; border-radius: 999px;
308
+ background: var(--kerne-track);
309
+ transition: background-color .18s ease;
310
+ }
311
+ .kerne-strength-label { font-size: 12px; color: var(--kerne-fg-muted); }
312
+ .kerne-strength[data-score="0"] .kerne-strength-step[data-on],
313
+ .kerne-strength[data-score="1"] .kerne-strength-step[data-on] { background: var(--kerne-danger); }
314
+ .kerne-strength[data-score="2"] .kerne-strength-step[data-on] { background: var(--kerne-warning); }
315
+ .kerne-strength[data-score="3"] .kerne-strength-step[data-on],
316
+ .kerne-strength[data-score="4"] .kerne-strength-step[data-on] { background: var(--kerne-success); }
317
+ @media (prefers-reduced-motion: reduce) {
318
+ .kerne-strength-step { transition: none; }
319
+ }
320
+ .kerne-input::placeholder { color: var(--kerne-fg-subtle); }
321
+ .kerne-input:hover:not(:disabled):not(:focus) { border-color: var(--kerne-fg-subtle); }
322
+ .kerne-input:focus {
323
+ outline: none;
324
+ border-color: var(--kerne-accent);
325
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--kerne-accent) 15%, transparent);
326
+ }
327
+ .kerne-input:disabled { opacity: .6; cursor: not-allowed; }
328
+ .kerne-input[aria-invalid="true"] { border-color: var(--kerne-danger); }
329
+ .kerne-input[data-kerne-code="true"] {
330
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
331
+ letter-spacing: .3em;
332
+ text-transform: uppercase;
333
+ }
334
+
335
+ /* ---------- Buttons ---------- */
336
+ .kerne-button {
337
+ font: inherit;
338
+ font-size: 14px;
339
+ font-weight: 500;
340
+ height: var(--kerne-control-height);
341
+ border-radius: var(--kerne-radius);
342
+ padding: 0 16px;
343
+ cursor: pointer;
344
+ border: 1px solid transparent;
345
+ display: inline-flex;
346
+ align-items: center;
347
+ justify-content: center;
348
+ gap: 10px;
349
+ width: 100%;
350
+ transition: background-color .12s ease, border-color .12s ease, opacity .12s ease;
351
+ }
352
+ .kerne-button:focus-visible { outline: 2px solid var(--kerne-accent); outline-offset: 2px; }
353
+ .kerne-button:disabled { opacity: .5; cursor: not-allowed; }
354
+ /* A disabled primary drops the brand entirely rather than wearing it at half
355
+ opacity: on a dark theme the light primary faded into an opaque grey slab
356
+ that read as an enabled button, and a brand colour has no business marking
357
+ an action you cannot take. Loading is excluded - it is still the real
358
+ button, just busy. */
359
+ .kerne-button-primary:disabled:not([data-kerne-loading="true"]) {
360
+ opacity: 1;
361
+ background: var(--kerne-track);
362
+ color: var(--kerne-fg-subtle);
363
+ }
364
+ /* A button mid-request is busy, not unavailable - dimming it to the disabled
365
+ opacity reads as "this stopped working". */
366
+ .kerne-button[data-kerne-loading="true"] { opacity: 1; cursor: progress; }
367
+ .kerne-button .kerne-spinner { width: 15px; height: 15px; border-width: 2px; }
368
+ .kerne-button-primary { background: var(--kerne-primary); color: var(--kerne-primary-fg); }
369
+ .kerne-button-primary:hover:not(:disabled) { background: var(--kerne-primary-hover); }
370
+ .kerne-button-outline {
371
+ background: transparent;
372
+ color: var(--kerne-fg);
373
+ border-color: var(--kerne-border-strong);
374
+ }
375
+ .kerne-button-outline:hover:not(:disabled) { background: var(--kerne-panel); }
376
+
377
+ /* Method switch - a quiet text control, not a second call to action competing
378
+ with the primary button above it. */
379
+ .kerne-switch {
380
+ font: inherit;
381
+ font-size: 14px;
382
+ width: 100%;
383
+ text-align: center;
384
+ background: none;
385
+ border: none;
386
+ padding: 4px 0;
387
+ cursor: pointer;
388
+ color: var(--kerne-fg-muted);
389
+ text-underline-offset: 4px;
390
+ transition: color .12s ease;
391
+ }
392
+ .kerne-switch:hover { color: var(--kerne-fg); text-decoration: underline; }
393
+ .kerne-switch:focus-visible { outline: 2px solid var(--kerne-accent); outline-offset: 2px; border-radius: 4px; }
394
+
395
+ .kerne-link {
396
+ font-size: inherit;
397
+ color: var(--kerne-accent);
398
+ background: none;
399
+ border: none;
400
+ padding: 0;
401
+ cursor: pointer;
402
+ font-family: inherit;
403
+ text-decoration: none;
404
+ text-underline-offset: 3px;
405
+ }
406
+ .kerne-link:hover { text-decoration: underline; }
407
+ .kerne-link:focus-visible { outline: 2px solid var(--kerne-accent); outline-offset: 2px; border-radius: 2px; }
408
+
409
+ /* ---------- Divider ---------- */
410
+ .kerne-divider {
411
+ display: flex;
412
+ align-items: center;
413
+ gap: 12px;
414
+ color: var(--kerne-fg-muted);
415
+ font-size: 11px;
416
+ text-transform: uppercase;
417
+ letter-spacing: .06em;
418
+ padding: 2px 0;
419
+ }
420
+ .kerne-divider::before, .kerne-divider::after {
421
+ content: "";
422
+ flex: 1;
423
+ height: 1px;
424
+ background: var(--kerne-border);
425
+ }
426
+
427
+ /* ---------- Panels ---------- */
428
+ .kerne-panel {
429
+ display: flex;
430
+ align-items: flex-start;
431
+ gap: 10px;
432
+ font-size: 14px;
433
+ line-height: 1.5;
434
+ padding: 12px 14px;
435
+ border-radius: var(--kerne-radius);
436
+ background: var(--kerne-panel);
437
+ color: var(--kerne-fg-muted);
438
+ }
439
+ .kerne-panel-danger { color: var(--kerne-danger); }
440
+ .kerne-panel-success { color: var(--kerne-success); }
441
+ .kerne-panel svg { flex-shrink: 0; margin-top: 1px; }
442
+ .kerne-panel strong { color: var(--kerne-fg); font-weight: 500; }
443
+
444
+ .kerne-oauth-group { display: flex; flex-direction: column; gap: 10px; }
445
+
446
+ /* A closing line under a form, e.g. "Remembered it? Back to sign in". */
447
+ .kerne-footer { font-size: 14px; color: var(--kerne-fg-muted); text-align: center; margin: 4px 0 0; }
448
+
449
+ /* ---------- Footnotes ---------- */
450
+ .kerne-legal {
451
+ font-size: 12px;
452
+ line-height: 1.5;
453
+ color: var(--kerne-fg-subtle);
454
+ text-align: center;
455
+ margin: 32px 0 0;
456
+ }
457
+ .kerne-branding {
458
+ display: flex;
459
+ align-items: center;
460
+ justify-content: center;
461
+ gap: 5px;
462
+ margin-top: 24px;
463
+ font-size: 12px;
464
+ color: var(--kerne-fg-subtle);
465
+ text-decoration: none;
466
+ }
467
+ .kerne-branding:hover { color: var(--kerne-fg-muted); }
468
+
469
+ /* Centred outcome screen for the flows that resolve on their own (magic-link
470
+ landing, email verification by link) - there is no form to show, only what
471
+ happened. */
472
+ .kerne-status { display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; padding: 8px 0; }
473
+ .kerne-status-icon { display: flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: 50%; background: var(--kerne-panel); }
474
+ .kerne-status-icon[data-tone="danger"] { color: var(--kerne-danger); }
475
+ .kerne-status-icon[data-tone="success"] { color: var(--kerne-success); }
476
+ .kerne-status-icon[data-tone="muted"] { color: var(--kerne-fg-muted); }
477
+ .kerne-status-text { font-size: 14px; color: var(--kerne-fg-muted); line-height: 1.5; margin: 0; max-width: 34ch; }
478
+
479
+ .kerne-spinner {
480
+ width: 20px; height: 20px;
481
+ border: 2px solid currentColor;
482
+ border-right-color: transparent;
483
+ border-radius: 50%;
484
+ animation: kerne-spin .6s linear infinite;
485
+ }
486
+ @keyframes kerne-spin { to { transform: rotate(360deg); } }
487
+
488
+ .kerne-button-danger {
489
+ background: transparent;
490
+ color: var(--kerne-danger);
491
+ border-color: color-mix(in srgb, var(--kerne-danger) 40%, transparent);
492
+ }
493
+ .kerne-button-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--kerne-danger) 8%, transparent); }
494
+
495
+ /* ---------- Usage meters ---------- */
496
+ .kerne-meters { display: flex; flex-direction: column; gap: 18px; }
497
+ .kerne-meter { display: flex; flex-direction: column; gap: 7px; }
498
+ .kerne-meter-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
499
+ .kerne-meter-name { font-size: 14px; font-weight: 500; }
500
+ .kerne-meter-value {
501
+ font-size: 13px;
502
+ color: var(--kerne-fg-muted);
503
+ /* Digits line up between rows instead of jittering as counts change. */
504
+ font-variant-numeric: tabular-nums;
505
+ }
506
+ .kerne-meter-track { height: 6px; border-radius: 999px; background: var(--kerne-track); overflow: hidden; }
507
+ .kerne-meter-fill { height: 100%; border-radius: 999px; background: var(--kerne-fg); transition: width .3s ease; }
508
+ .kerne-meter[data-level="warning"] .kerne-meter-fill { background: var(--kerne-warning); }
509
+ .kerne-meter[data-level="critical"] .kerne-meter-fill { background: var(--kerne-danger); }
510
+ .kerne-meter[data-level="warning"] .kerne-meter-value { color: var(--kerne-warning); }
511
+ .kerne-meter[data-level="critical"] .kerne-meter-value { color: var(--kerne-danger); }
512
+ .kerne-meter-note { font-size: 12px; color: var(--kerne-fg-subtle); margin: 0; }
513
+ @media (prefers-reduced-motion: reduce) { .kerne-meter-fill { transition: none; } }
514
+
515
+ /* ---------- Sections (profile, settings) ---------- */
516
+ .kerne-section-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
517
+ .kerne-section-title { font-size: 15px; font-weight: 600; margin: 0; }
518
+
519
+ .kerne-rows { display: flex; flex-direction: column; gap: 10px; }
520
+ .kerne-row { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; font-size: 14px; }
521
+ .kerne-row dt { color: var(--kerne-fg-muted); margin: 0; }
522
+ .kerne-row dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
523
+
524
+ .kerne-badge {
525
+ display: inline-flex;
526
+ align-items: center;
527
+ font-size: 12px;
528
+ font-weight: 500;
529
+ padding: 2px 8px;
530
+ border-radius: 999px;
531
+ background: var(--kerne-panel);
532
+ color: var(--kerne-fg-muted);
533
+ white-space: nowrap;
534
+ }
535
+ .kerne-badge[data-tone="success"] { color: var(--kerne-success); }
536
+ .kerne-badge[data-tone="warning"] { color: var(--kerne-warning); }
537
+ .kerne-badge[data-tone="danger"] { color: var(--kerne-danger); }
538
+
539
+ /* ---------- Identity ---------- */
540
+ .kerne-avatar {
541
+ width: 32px; height: 32px; border-radius: 50%;
542
+ background: var(--kerne-panel); color: var(--kerne-fg-muted);
543
+ display: flex; align-items: center; justify-content: center;
544
+ font-size: 12px; font-weight: 600; letter-spacing: .02em; flex-shrink: 0;
545
+ object-fit: cover;
546
+ }
547
+ .kerne-identity { display: flex; align-items: center; gap: 12px; }
548
+ .kerne-identity-text { display: flex; flex-direction: column; min-width: 0; }
549
+ .kerne-identity-name { font-size: 14px; font-weight: 500; }
550
+ .kerne-identity-mail { font-size: 13px; color: var(--kerne-fg-muted); overflow: hidden; text-overflow: ellipsis; }
551
+
552
+ .kerne-menu-wrap { position: relative; display: inline-flex; }
553
+ .kerne-menu-trigger {
554
+ background: none; border: none; padding: 0; cursor: pointer;
555
+ border-radius: 50%; display: inline-flex; font: inherit;
556
+ }
557
+ .kerne-menu-trigger:focus-visible { outline: 2px solid var(--kerne-accent); outline-offset: 2px; }
558
+ .kerne-menu {
559
+ position: absolute; top: calc(100% + 8px); right: 0; z-index: 50;
560
+ min-width: 240px; padding: 8px;
561
+ display: flex; flex-direction: column; gap: 2px;
562
+ /* Needs an opaque ground of its own: it floats over host content. */
563
+ background: var(--kerne-surface);
564
+ border: 1px solid var(--kerne-border);
565
+ border-radius: var(--kerne-radius);
566
+ box-shadow: var(--kerne-shadow);
567
+ }
568
+ .kerne-menu-header { padding: 8px 10px 10px; border-bottom: 1px solid var(--kerne-border); margin-bottom: 6px; }
569
+ .kerne-menu-item {
570
+ font: inherit; font-size: 14px; text-align: left;
571
+ background: none; border: none; cursor: pointer;
572
+ padding: 8px 10px; border-radius: 6px; color: var(--kerne-fg);
573
+ display: block; width: 100%; text-decoration: none;
574
+ }
575
+ .kerne-menu-item:hover { background: var(--kerne-panel); }
576
+ .kerne-menu-item:focus-visible { outline: 2px solid var(--kerne-accent); outline-offset: -2px; }
577
+ .kerne-menu-item[data-tone="danger"] { color: var(--kerne-danger); }
578
+
579
+ /* ---------- Loading ---------- */
580
+ .kerne-skeleton {
581
+ background: var(--kerne-panel);
582
+ border-radius: var(--kerne-radius);
583
+ height: var(--kerne-control-height);
584
+ animation: kerne-pulse 1.6s ease-in-out infinite;
585
+ }
586
+ @keyframes kerne-pulse { 50% { opacity: .55; } }
587
+ @media (prefers-reduced-motion: reduce) {
588
+ .kerne-skeleton { animation: none; }
589
+ .kerne-spinner { animation-duration: 2s; }
590
+ .kerne-input, .kerne-button, .kerne-switch { transition: none; }
591
+ }
592
+ `;
593
+ function ensureStylesInjected() {
594
+ if (typeof document === "undefined") return;
595
+ if (document.getElementById(STYLE_ELEMENT_ID)) return;
596
+ const style = document.createElement("style");
597
+ style.id = STYLE_ELEMENT_ID;
598
+ style.textContent = CSS;
599
+ document.head.appendChild(style);
600
+ }
601
+ function parseColor(input) {
602
+ const value = input.trim();
603
+ const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(value);
604
+ if (hex) {
605
+ const digits = hex[1].length === 3 ? hex[1].split("").map((c) => c + c).join("") : hex[1];
606
+ return [
607
+ parseInt(digits.slice(0, 2), 16),
608
+ parseInt(digits.slice(2, 4), 16),
609
+ parseInt(digits.slice(4, 6), 16)
610
+ ];
611
+ }
612
+ const rgb = /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)/i.exec(value);
613
+ if (rgb) return [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])];
614
+ return null;
615
+ }
616
+ function luminance([r, g, b]) {
617
+ const channel = (v) => {
618
+ const s = Math.min(Math.max(v, 0), 255) / 255;
619
+ return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
620
+ };
621
+ return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);
622
+ }
623
+ function toHex([r, g, b]) {
624
+ const pair = (v) => Math.round(Math.min(Math.max(v, 0), 255)).toString(16).padStart(2, "0");
625
+ return `#${pair(r)}${pair(g)}${pair(b)}`;
626
+ }
627
+ function mix(color, toward, amount) {
628
+ return color.map((c) => c + (toward - c) * amount);
629
+ }
630
+ var LABEL_CROSSOVER = 0.2;
631
+ function appearanceToStyle(appearance) {
632
+ if (!appearance) return {};
633
+ const vars = {};
634
+ if (appearance.primaryColor) {
635
+ vars["--kerne-primary"] = appearance.primaryColor;
636
+ vars["--kerne-accent"] = _nullishCoalesce(appearance.accentColor, () => ( appearance.primaryColor));
637
+ const rgb = parseColor(appearance.primaryColor);
638
+ if (rgb) {
639
+ const light = luminance(rgb) > LABEL_CROSSOVER;
640
+ vars["--kerne-primary-fg"] = _nullishCoalesce(appearance.primaryTextColor, () => ( (light ? "#16171a" : "#ffffff")));
641
+ vars["--kerne-primary-hover"] = toHex(mix(rgb, light ? 0 : 255, 0.14));
642
+ } else if (appearance.primaryTextColor) {
643
+ vars["--kerne-primary-fg"] = appearance.primaryTextColor;
644
+ }
645
+ } else {
646
+ if (appearance.accentColor) vars["--kerne-accent"] = appearance.accentColor;
647
+ if (appearance.primaryTextColor) vars["--kerne-primary-fg"] = appearance.primaryTextColor;
648
+ }
649
+ if (appearance.textColor) vars["--kerne-fg"] = appearance.textColor;
650
+ if (appearance.borderColor) vars["--kerne-border-strong"] = appearance.borderColor;
651
+ if (appearance.panelColor) vars["--kerne-panel"] = appearance.panelColor;
652
+ if (appearance.background) vars["--kerne-bg"] = appearance.background;
653
+ if (appearance.surfaceColor) {
654
+ vars["--kerne-surface"] = appearance.surfaceColor;
655
+ vars["--kerne-surface-raised"] = appearance.surfaceColor;
656
+ }
657
+ if (appearance.fontFamily) vars["--kerne-font"] = appearance.fontFamily;
658
+ if (appearance.radius) vars["--kerne-radius"] = appearance.radius;
659
+ if (appearance.controlHeight) vars["--kerne-control-height"] = appearance.controlHeight;
660
+ return vars;
661
+ }
662
+ function resolveTheme(appearance) {
663
+ return _nullishCoalesce(_optionalChain([appearance, 'optionalAccess', _ => _.theme]), () => ( "light"));
664
+ }
665
+
666
+ // src/ui/password.ts
667
+ var MIN_PASSWORD_LENGTH = 8;
668
+ var BASELINE_POLICY = {
669
+ min_length: MIN_PASSWORD_LENGTH,
670
+ require_uppercase: false,
671
+ require_number: false,
672
+ require_symbol: false
673
+ };
674
+ function resolvePolicy(config) {
675
+ return _nullishCoalesce(_optionalChain([config, 'optionalAccess', _2 => _2.password_policy]), () => ( BASELINE_POLICY));
676
+ }
677
+ function passwordRules(password, policy) {
678
+ const rules = [{ key: "min_length", met: password.length >= policy.min_length }];
679
+ if (policy.require_uppercase) {
680
+ rules.push({ key: "require_uppercase", met: /[A-Z]/.test(password) });
681
+ }
682
+ if (policy.require_number) {
683
+ rules.push({ key: "require_number", met: /\d/.test(password) });
684
+ }
685
+ if (policy.require_symbol) {
686
+ rules.push({ key: "require_symbol", met: /[^A-Za-z0-9]/.test(password) });
687
+ }
688
+ return rules;
689
+ }
690
+ function meetsPolicy(password, policy) {
691
+ return passwordRules(password, policy).every((rule) => rule.met);
692
+ }
693
+ function passwordStrength(password) {
694
+ if (password.length < MIN_PASSWORD_LENGTH) return 0;
695
+ const variety = [/[a-z]/, /[A-Z]/, /\d/, /[^A-Za-z0-9]/].filter((re) => re.test(password)).length;
696
+ let score = 1;
697
+ if (password.length >= 12) score++;
698
+ if (password.length >= 16) score++;
699
+ if (variety >= 3) score++;
700
+ return Math.min(score, 4);
701
+ }
702
+
703
+ // src/ui/primitives.tsx
704
+ var _jsxruntime = require('react/jsx-runtime');
705
+ var InsideShell = _react.createContext.call(void 0, false);
706
+ function Shell({
707
+ appearance,
708
+ className,
709
+ size = "auth",
710
+ children
711
+ }) {
712
+ ensureStylesInjected();
713
+ const nested = _react.useContext.call(void 0, InsideShell);
714
+ if (nested) {
715
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className, children });
716
+ }
717
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InsideShell.Provider, { value: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
718
+ "div",
719
+ {
720
+ className: `kerne-root${className ? ` ${className}` : ""}`,
721
+ style: appearanceToStyle(appearance),
722
+ "data-kerne-theme": resolveTheme(appearance),
723
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
724
+ "div",
725
+ {
726
+ className: "kerne-shell",
727
+ "data-kerne-size": size === "wide" ? "wide" : void 0,
728
+ "data-kerne-surface": _optionalChain([appearance, 'optionalAccess', _3 => _3.surface]) === "card" ? "card" : void 0,
729
+ children
730
+ }
731
+ )
732
+ }
733
+ ) });
734
+ }
735
+ function Subsection({
736
+ title,
737
+ description,
738
+ children
739
+ }) {
740
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { className: "kerne-subsection", children: [
741
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-subsection-head", children: [
742
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "kerne-subsection-title", children: title }),
743
+ description ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-subsection-desc", children: description }) : null
744
+ ] }),
745
+ children
746
+ ] });
747
+ }
748
+ function Masthead({
749
+ logo,
750
+ title,
751
+ subtitle
752
+ }) {
753
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-masthead", children: [
754
+ logo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-logo", children: logo }) : null,
755
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-heading", children: [
756
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { className: "kerne-title", children: title }),
757
+ subtitle ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-subtitle", children: subtitle }) : null
758
+ ] })
759
+ ] });
760
+ }
761
+ function prefersAutoFocus() {
762
+ if (typeof window === "undefined" || !window.matchMedia) return false;
763
+ return window.matchMedia("(pointer: fine)").matches;
764
+ }
765
+ function Field({
766
+ label,
767
+ type,
768
+ value,
769
+ onChange,
770
+ autoComplete,
771
+ placeholder,
772
+ disabled,
773
+ required,
774
+ invalid,
775
+ error,
776
+ action,
777
+ code,
778
+ autoFocus,
779
+ children
780
+ }) {
781
+ const id = _react.useId.call(void 0, );
782
+ const errorId = `${id}-error`;
783
+ const noteId = `${id}-note`;
784
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
785
+ const isPassword = type === "password";
786
+ const [revealed, setRevealed] = _react.useState.call(void 0, false);
787
+ const [capsLock, setCapsLock] = _react.useState.call(void 0, false);
788
+ const trackCapsLock = (e) => {
789
+ if (!isPassword) return;
790
+ setCapsLock(_nullishCoalesce(_optionalChain([e, 'access', _4 => _4.getModifierState, 'optionalCall', _5 => _5("CapsLock")]), () => ( false)));
791
+ };
792
+ const describedBy = [error ? errorId : null, children ? noteId : null].filter(Boolean).join(" ");
793
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-field", children: [
794
+ action ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-label-row", children: [
795
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { className: "kerne-label", htmlFor: id, children: label }),
796
+ action
797
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { className: "kerne-label", htmlFor: id, children: label }),
798
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-control", children: [
799
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
800
+ "input",
801
+ {
802
+ id,
803
+ className: "kerne-input",
804
+ type: isPassword && revealed ? "text" : type,
805
+ value,
806
+ onChange: (e) => onChange(e.target.value),
807
+ onKeyUp: trackCapsLock,
808
+ onBlur: () => setCapsLock(false),
809
+ autoComplete,
810
+ placeholder,
811
+ disabled,
812
+ required,
813
+ "aria-invalid": invalid || !!error || void 0,
814
+ "aria-describedby": describedBy || void 0,
815
+ "data-kerne-code": code ? "true" : void 0,
816
+ "data-kerne-reveal": isPassword ? "true" : void 0,
817
+ autoFocus: autoFocus && prefersAutoFocus()
818
+ }
819
+ ),
820
+ isPassword ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
821
+ "button",
822
+ {
823
+ type: "button",
824
+ className: "kerne-reveal",
825
+ onClick: () => setRevealed((v) => !v),
826
+ disabled,
827
+ "aria-label": revealed ? l10n.common.hidePassword : l10n.common.showPassword,
828
+ "aria-pressed": revealed,
829
+ tabIndex: -1,
830
+ children: revealed ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EyeOffIcon, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EyeIcon, {})
831
+ }
832
+ ) : null
833
+ ] }),
834
+ children ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { id: noteId, children }) : null,
835
+ capsLock ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-field-note", "data-kerne-warn": "true", role: "status", children: l10n.common.capsLockOn }) : null,
836
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-field-error", id: errorId, role: "alert", children: error }) : null
837
+ ] });
838
+ }
839
+ function EyeIcon() {
840
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
841
+ "svg",
842
+ {
843
+ width: "16",
844
+ height: "16",
845
+ viewBox: "0 0 24 24",
846
+ fill: "none",
847
+ stroke: "currentColor",
848
+ strokeWidth: "2",
849
+ "aria-hidden": "true",
850
+ children: [
851
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7-10-7-10-7z", strokeLinejoin: "round" }),
852
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "12", cy: "12", r: "3" })
853
+ ]
854
+ }
855
+ );
856
+ }
857
+ function EyeOffIcon() {
858
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
859
+ "svg",
860
+ {
861
+ width: "16",
862
+ height: "16",
863
+ viewBox: "0 0 24 24",
864
+ fill: "none",
865
+ stroke: "currentColor",
866
+ strokeWidth: "2",
867
+ "aria-hidden": "true",
868
+ children: [
869
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
870
+ "path",
871
+ {
872
+ d: "M10.6 6.2A9.9 9.9 0 0 1 12 6c6.4 0 10 7 10 7a15.7 15.7 0 0 1-3 3.7M6.2 7.4A15.6 15.6 0 0 0 2 13s3.6 7 10 7a9.7 9.7 0 0 0 4.3-1",
873
+ strokeLinecap: "round",
874
+ strokeLinejoin: "round"
875
+ }
876
+ ),
877
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "m3 3 18 18", strokeLinecap: "round" })
878
+ ]
879
+ }
880
+ );
881
+ }
882
+ function Button({
883
+ children,
884
+ variant = "primary",
885
+ disabled,
886
+ loading,
887
+ type = "submit",
888
+ onClick,
889
+ ariaLabel
890
+ }) {
891
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
892
+ "button",
893
+ {
894
+ type,
895
+ className: `kerne-button kerne-button-${variant}`,
896
+ disabled: disabled || loading,
897
+ onClick,
898
+ "aria-label": ariaLabel,
899
+ "aria-busy": loading || void 0,
900
+ "data-kerne-loading": loading ? "true" : void 0,
901
+ children: [
902
+ loading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-spinner", "aria-hidden": "true" }) : null,
903
+ children
904
+ ]
905
+ }
906
+ );
907
+ }
908
+ function PasswordStrength({
909
+ password,
910
+ policy
911
+ }) {
912
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
913
+ const resolved = _nullishCoalesce(policy, () => ( resolvePolicy(null)));
914
+ if (!meetsPolicy(password, resolved)) {
915
+ const labels2 = {
916
+ min_length: _chunk7U3QBMA7cjs.fill.call(void 0, l10n.common.passwordHint, { count: resolved.min_length }),
917
+ require_uppercase: l10n.common.passwordRequireUppercase,
918
+ require_number: l10n.common.passwordRequireNumber,
919
+ require_symbol: l10n.common.passwordRequireSymbol
920
+ };
921
+ const rules = passwordRules(password, resolved);
922
+ if (rules.length === 1) {
923
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-field-note", children: labels2[rules[0].key] });
924
+ }
925
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "ul", { className: "kerne-rules", children: rules.map((rule) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { className: "kerne-rule", "data-met": rule.met ? "true" : void 0, children: [
926
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { "aria-hidden": "true", children: rule.met ? "\u2713" : "\xB7" }),
927
+ labels2[rule.key]
928
+ ] }, rule.key)) });
929
+ }
930
+ const score = passwordStrength(password);
931
+ const labels = [
932
+ l10n.common.strengthWeak,
933
+ l10n.common.strengthWeak,
934
+ l10n.common.strengthFair,
935
+ l10n.common.strengthGood,
936
+ l10n.common.strengthStrong
937
+ ];
938
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-strength", "data-score": score, children: [
939
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-strength-track", "aria-hidden": "true", children: [1, 2, 3, 4].map((step) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
940
+ "span",
941
+ {
942
+ className: "kerne-strength-step",
943
+ "data-on": score >= step ? "true" : void 0
944
+ },
945
+ step
946
+ )) }),
947
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "kerne-strength-label", children: [
948
+ l10n.common.strengthLabel,
949
+ ": ",
950
+ labels[score]
951
+ ] })
952
+ ] });
953
+ }
954
+ function MethodSwitch({
955
+ onClick,
956
+ children
957
+ }) {
958
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "kerne-switch", onClick, children });
959
+ }
960
+ function AlertIcon() {
961
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
962
+ "svg",
963
+ {
964
+ width: "16",
965
+ height: "16",
966
+ viewBox: "0 0 24 24",
967
+ fill: "none",
968
+ stroke: "currentColor",
969
+ strokeWidth: "2",
970
+ "aria-hidden": "true",
971
+ children: [
972
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "12", cy: "12", r: "10" }),
973
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M12 8v4M12 16h.01", strokeLinecap: "round" })
974
+ ]
975
+ }
976
+ );
977
+ }
978
+ function MailIcon() {
979
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
980
+ "svg",
981
+ {
982
+ width: "16",
983
+ height: "16",
984
+ viewBox: "0 0 24 24",
985
+ fill: "none",
986
+ stroke: "currentColor",
987
+ strokeWidth: "2",
988
+ "aria-hidden": "true",
989
+ children: [
990
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "rect", { x: "2", y: "4", width: "20", height: "16", rx: "2" }),
991
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "m2 7 10 6 10-6", strokeLinecap: "round", strokeLinejoin: "round" })
992
+ ]
993
+ }
994
+ );
995
+ }
996
+ function Panel({
997
+ children,
998
+ variant = "info"
999
+ }) {
1000
+ const danger = variant === "danger";
1001
+ const icon = danger ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AlertIcon, {}) : variant === "success" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CheckIcon, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, MailIcon, {});
1002
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1003
+ "div",
1004
+ {
1005
+ className: `kerne-panel${danger ? " kerne-panel-danger" : ""}${variant === "success" ? " kerne-panel-success" : ""}`,
1006
+ ...danger ? { role: "alert" } : { role: "status", "aria-live": "polite" },
1007
+ children: [
1008
+ icon,
1009
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children })
1010
+ ]
1011
+ }
1012
+ );
1013
+ }
1014
+ function CheckIcon() {
1015
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1016
+ "svg",
1017
+ {
1018
+ width: "16",
1019
+ height: "16",
1020
+ viewBox: "0 0 24 24",
1021
+ fill: "none",
1022
+ stroke: "currentColor",
1023
+ strokeWidth: "2",
1024
+ "aria-hidden": "true",
1025
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "m5 13 4 4L19 7", strokeLinecap: "round", strokeLinejoin: "round" })
1026
+ }
1027
+ );
1028
+ }
1029
+ function Status({
1030
+ tone,
1031
+ title,
1032
+ children,
1033
+ action
1034
+ }) {
1035
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-status", ...tone === "danger" ? { role: "alert" } : {}, children: [
1036
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-status-icon", "data-tone": tone === "loading" ? "muted" : tone, children: tone === "loading" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-spinner", "aria-hidden": "true" }) : tone === "success" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CheckIcon, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AlertIcon, {}) }),
1037
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-heading", children: [
1038
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { className: "kerne-title", children: title }),
1039
+ children ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-status-text", children }) : null
1040
+ ] }),
1041
+ action
1042
+ ] });
1043
+ }
1044
+ function Divider({ label }) {
1045
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-divider", children: label });
1046
+ }
1047
+ function TextLink({
1048
+ href,
1049
+ onClick,
1050
+ children
1051
+ }) {
1052
+ if (onClick) {
1053
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "kerne-link", onClick, children });
1054
+ }
1055
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { className: "kerne-link", href: _nullishCoalesce(href, () => ( "#")), children });
1056
+ }
1057
+ var OAUTH_LABELS = {
1058
+ google: "Google",
1059
+ github: "GitHub",
1060
+ microsoft: "Microsoft",
1061
+ apple: "Apple",
1062
+ gitlab: "GitLab",
1063
+ discord: "Discord"
1064
+ };
1065
+ function OAuthIcon({ provider }) {
1066
+ const common = { width: 18, height: 18, viewBox: "0 0 24 24", "aria-hidden": true };
1067
+ switch (provider) {
1068
+ case "google":
1069
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { ...common, children: [
1070
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1071
+ "path",
1072
+ {
1073
+ fill: "#4285F4",
1074
+ d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
1075
+ }
1076
+ ),
1077
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1078
+ "path",
1079
+ {
1080
+ fill: "#34A853",
1081
+ d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
1082
+ }
1083
+ ),
1084
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1085
+ "path",
1086
+ {
1087
+ fill: "#FBBC05",
1088
+ d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
1089
+ }
1090
+ ),
1091
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1092
+ "path",
1093
+ {
1094
+ fill: "#EA4335",
1095
+ d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
1096
+ }
1097
+ )
1098
+ ] });
1099
+ case "github":
1100
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { ...common, fill: "currentColor", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.26.8-.57v-2c-3.34.72-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.09-.75.08-.73.08-.73 1.2.09 1.84 1.24 1.84 1.24 1.07 1.83 2.81 1.3 3.5 1 .1-.78.42-1.31.76-1.61-2.67-.3-5.47-1.33-5.47-5.93 0-1.31.47-2.38 1.24-3.22-.14-.3-.54-1.52.1-3.18 0 0 1-.32 3.3 1.23a11.5 11.5 0 0 1 6 0c2.28-1.55 3.29-1.23 3.29-1.23.64 1.66.24 2.88.12 3.18.77.84 1.23 1.91 1.23 3.22 0 4.61-2.8 5.63-5.48 5.92.43.37.81 1.1.81 2.22v3.29c0 .31.2.68.81.57A12 12 0 0 0 12 .3z" }) });
1101
+ case "apple":
1102
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { ...common, fill: "currentColor", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M17.05 12.75c-.03-2.6 2.12-3.85 2.22-3.91-1.21-1.77-3.09-2.01-3.76-2.04-1.6-.16-3.12.94-3.93.94-.81 0-2.06-.92-3.39-.9-1.74.03-3.35 1.01-4.25 2.57-1.81 3.14-.46 7.79 1.3 10.34.86 1.25 1.89 2.65 3.24 2.6 1.3-.05 1.79-.84 3.36-.84 1.57 0 2.01.84 3.38.81 1.4-.02 2.28-1.27 3.13-2.53.99-1.45 1.4-2.86 1.42-2.93-.03-.01-2.72-1.04-2.75-4.13zM14.5 4.9c.71-.87 1.19-2.07 1.06-3.27-1.02.04-2.26.68-3 1.55-.66.76-1.24 1.98-1.09 3.15 1.14.09 2.31-.58 3.03-1.43z" }) });
1103
+ default:
1104
+ return null;
1105
+ }
1106
+ }
1107
+ function OAuthButtons({
1108
+ providers,
1109
+ disabled,
1110
+ onSelect
1111
+ }) {
1112
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
1113
+ if (providers.length === 0) return null;
1114
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-oauth-group", children: providers.map((provider) => {
1115
+ const label = _chunk7U3QBMA7cjs.fill.call(void 0, l10n.common.continueWith, {
1116
+ provider: _nullishCoalesce(OAUTH_LABELS[provider], () => ( provider))
1117
+ });
1118
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1119
+ "button",
1120
+ {
1121
+ type: "button",
1122
+ className: "kerne-button kerne-button-outline",
1123
+ disabled,
1124
+ onClick: () => _optionalChain([onSelect, 'optionalCall', _6 => _6(provider)]),
1125
+ "aria-label": label,
1126
+ children: [
1127
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, OAuthIcon, { provider }),
1128
+ label
1129
+ ]
1130
+ },
1131
+ provider
1132
+ );
1133
+ }) });
1134
+ }
1135
+ function KerneBranding({ show }) {
1136
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
1137
+ if (!show) return null;
1138
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { className: "kerne-branding", href: "https://kerne.io", target: "_blank", rel: "noopener noreferrer", children: l10n.common.securedByKerne });
1139
+ }
1140
+ function FormSkeleton() {
1141
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
1142
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-form", "aria-busy": "true", "aria-label": l10n.common.loading, children: [
1143
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-skeleton" }),
1144
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-skeleton" })
1145
+ ] });
1146
+ }
1147
+
1148
+ // src/ui/LoginForm.tsx
1149
+
1150
+ function LoginForm({
1151
+ onSuccess,
1152
+ redirectUrl,
1153
+ magicLinkCallbackUrl,
1154
+ signUpUrl,
1155
+ onSignUpClick,
1156
+ forgotPasswordUrl,
1157
+ onForgotPasswordClick,
1158
+ onOAuthSelect,
1159
+ title,
1160
+ subtitle,
1161
+ legal,
1162
+ appearance,
1163
+ logo,
1164
+ className
1165
+ }) {
1166
+ const client = _chunk7U3QBMA7cjs.useClient.call(void 0, );
1167
+ const { login, startPasswordless } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
1168
+ const { config, isLoading: configLoading, error: configError } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
1169
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
1170
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
1171
+ const [email, setEmail] = _react.useState.call(void 0, "");
1172
+ const [password, setPassword] = _react.useState.call(void 0, "");
1173
+ const [submitting, setSubmitting] = _react.useState.call(void 0, false);
1174
+ const [error, setError] = _react.useState.call(void 0, null);
1175
+ const [linkSentTo, setLinkSentTo] = _react.useState.call(void 0, null);
1176
+ const [passwordMode, setPasswordMode] = _react.useState.call(void 0, false);
1177
+ const shell = (children) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Shell, { appearance, className, children });
1178
+ const hasOAuth = (_nullishCoalesce(_optionalChain([config, 'optionalAccess', _7 => _7.oauth_providers, 'access', _8 => _8.length]), () => ( 0))) > 0;
1179
+ const hasCredentials = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _9 => _9.enable_credentials]), () => ( false));
1180
+ const hasMagicLink = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _10 => _10.enable_magic_link]), () => ( false));
1181
+ const hasEmailMethod = hasCredentials || hasMagicLink;
1182
+ const usePassword = passwordMode || !hasMagicLink && hasCredentials;
1183
+ const handleSubmit = async (e) => {
1184
+ e.preventDefault();
1185
+ setError(null);
1186
+ setSubmitting(true);
1187
+ try {
1188
+ if (usePassword) {
1189
+ await login({ email, password });
1190
+ if (redirectUrl) {
1191
+ await client.redirectWithSession(redirectUrl);
1192
+ } else {
1193
+ _optionalChain([onSuccess, 'optionalCall', _11 => _11()]);
1194
+ }
1195
+ } else {
1196
+ await startPasswordless(email, magicLinkCallbackUrl);
1197
+ setLinkSentTo(email);
1198
+ }
1199
+ } catch (err) {
1200
+ setError(showError(err));
1201
+ setSubmitting(false);
1202
+ }
1203
+ };
1204
+ const appName = _optionalChain([config, 'optionalAccess', _12 => _12.app_name]);
1205
+ const heading = _nullishCoalesce(title, () => ( l10n.signIn.title));
1206
+ if (configLoading) {
1207
+ return shell(
1208
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1209
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading }),
1210
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormSkeleton, {})
1211
+ ] })
1212
+ );
1213
+ }
1214
+ if (configError || !config) {
1215
+ return shell(
1216
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1217
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading }),
1218
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: l10n.signIn.loadFailed })
1219
+ ] })
1220
+ );
1221
+ }
1222
+ if (!hasEmailMethod && !hasOAuth) {
1223
+ return shell(
1224
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1225
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading }),
1226
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: l10n.signIn.unavailable })
1227
+ ] })
1228
+ );
1229
+ }
1230
+ const canSignUp = config.registration_mode !== "CLOSED";
1231
+ const signUpLine = canSignUp && (signUpUrl || onSignUpClick) ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1232
+ l10n.signIn.signUpPrompt,
1233
+ " ",
1234
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TextLink, { href: signUpUrl, onClick: onSignUpClick, children: appName ? _chunk7U3QBMA7cjs.fill.call(void 0, l10n.signIn.signUpForApp, { app: appName }) : l10n.signIn.signUpLink }),
1235
+ "."
1236
+ ] }) : void 0;
1237
+ const submitLabel = submitting ? usePassword ? l10n.signIn.submitting : l10n.signIn.magicSubmitting : usePassword ? l10n.signIn.submit : l10n.signIn.magicSubmit;
1238
+ return shell(
1239
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1240
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading, subtitle: _nullishCoalesce(subtitle, () => ( signUpLine)) }),
1241
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-stack", children: [
1242
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: error }) : null,
1243
+ linkSentTo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { children: _chunk7U3QBMA7cjs.fillNode.call(void 0, l10n.signIn.linkSent, { email: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "strong", { children: linkSentTo }) }) }) : hasEmailMethod ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "kerne-form", onSubmit: handleSubmit, children: [
1244
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1245
+ Field,
1246
+ {
1247
+ label: l10n.common.email,
1248
+ type: "email",
1249
+ value: email,
1250
+ onChange: setEmail,
1251
+ autoComplete: "email",
1252
+ placeholder: l10n.common.emailPlaceholder,
1253
+ disabled: submitting,
1254
+ required: true,
1255
+ autoFocus: true
1256
+ }
1257
+ ),
1258
+ usePassword ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1259
+ Field,
1260
+ {
1261
+ label: l10n.common.password,
1262
+ type: "password",
1263
+ value: password,
1264
+ onChange: setPassword,
1265
+ autoComplete: "current-password",
1266
+ placeholder: l10n.common.passwordPlaceholder,
1267
+ disabled: submitting,
1268
+ required: true,
1269
+ action: forgotPasswordUrl || onForgotPasswordClick ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TextLink, { href: forgotPasswordUrl, onClick: onForgotPasswordClick, children: l10n.signIn.forgotPassword }) : void 0
1270
+ }
1271
+ ) : null,
1272
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { loading: submitting, disabled: !email || usePassword && !password, children: submitLabel }),
1273
+ hasCredentials && hasMagicLink ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1274
+ MethodSwitch,
1275
+ {
1276
+ onClick: () => {
1277
+ setPasswordMode((v) => !v);
1278
+ setError(null);
1279
+ },
1280
+ children: usePassword ? l10n.signIn.useMagicLink : l10n.signIn.usePassword
1281
+ }
1282
+ ) : null
1283
+ ] }) : null,
1284
+ hasOAuth && hasEmailMethod ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Divider, { label: l10n.common.or }) : null,
1285
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1286
+ OAuthButtons,
1287
+ {
1288
+ providers: config.oauth_providers,
1289
+ disabled: submitting,
1290
+ onSelect: onOAuthSelect
1291
+ }
1292
+ )
1293
+ ] }),
1294
+ legal ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-legal", children: legal }) : null,
1295
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: config.show_kerne_branding })
1296
+ ] })
1297
+ );
1298
+ }
1299
+
1300
+ // src/ui/RegisterForm.tsx
1301
+
1302
+
1303
+ function RegisterForm({
1304
+ onSuccess,
1305
+ redirectUrl,
1306
+ magicLinkCallbackUrl,
1307
+ invitationToken: invitationTokenProp,
1308
+ signInUrl,
1309
+ onSignInClick,
1310
+ onOAuthSelect,
1311
+ title,
1312
+ subtitle,
1313
+ legal,
1314
+ collectName = true,
1315
+ appearance,
1316
+ logo,
1317
+ className
1318
+ }) {
1319
+ const client = _chunk7U3QBMA7cjs.useClient.call(void 0, );
1320
+ const { register, startPasswordless } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
1321
+ const { config, isLoading: configLoading, error: configError } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
1322
+ const policy = resolvePolicy(config);
1323
+ const invitationToken = useUrlToken("token", invitationTokenProp) || void 0;
1324
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
1325
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
1326
+ const [email, setEmail] = _react.useState.call(void 0, "");
1327
+ const [password, setPassword] = _react.useState.call(void 0, "");
1328
+ const [name, setName] = _react.useState.call(void 0, "");
1329
+ const [invitationCode, setInvitationCode] = _react.useState.call(void 0, "");
1330
+ const [submitting, setSubmitting] = _react.useState.call(void 0, false);
1331
+ const [error, setError] = _react.useState.call(void 0, null);
1332
+ const [linkSentTo, setLinkSentTo] = _react.useState.call(void 0, null);
1333
+ const [passwordMode, setPasswordMode] = _react.useState.call(void 0, false);
1334
+ const shell = (children) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Shell, { appearance, className, children });
1335
+ const appName = _optionalChain([config, 'optionalAccess', _13 => _13.app_name]);
1336
+ const heading = _nullishCoalesce(title, () => ( (appName ? _chunk7U3QBMA7cjs.fill.call(void 0, l10n.signUp.titleWithApp, { app: appName }) : l10n.signUp.title)));
1337
+ const signInLine = signInUrl || onSignInClick ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1338
+ l10n.signUp.signInPrompt,
1339
+ " ",
1340
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TextLink, { href: signInUrl, onClick: onSignInClick, children: l10n.signUp.signInLink }),
1341
+ "."
1342
+ ] }) : void 0;
1343
+ if (configLoading) {
1344
+ return shell(
1345
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1346
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading }),
1347
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormSkeleton, {})
1348
+ ] })
1349
+ );
1350
+ }
1351
+ if (configError || !config) {
1352
+ return shell(
1353
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1354
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading }),
1355
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: l10n.signUp.loadFailed })
1356
+ ] })
1357
+ );
1358
+ }
1359
+ if (config.registration_mode === "CLOSED") {
1360
+ return shell(
1361
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1362
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: l10n.signUp.closedTitle, subtitle: signInLine }),
1363
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { children: _chunk7U3QBMA7cjs.fill.call(void 0, l10n.signUp.closedBody, { app: _nullishCoalesce(appName, () => ( l10n.common.thisApp)) }) }),
1364
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: config.show_kerne_branding })
1365
+ ] })
1366
+ );
1367
+ }
1368
+ const hasOAuth = config.oauth_providers.length > 0;
1369
+ const hasCredentials = config.enable_credentials;
1370
+ const hasMagicLink = config.enable_magic_link;
1371
+ const hasEmailMethod = hasCredentials || hasMagicLink;
1372
+ const usePassword = passwordMode || !hasMagicLink && hasCredentials;
1373
+ const needsCode = config.registration_mode === "INVITE_ONLY" && !invitationToken;
1374
+ const handleSubmit = async (e) => {
1375
+ e.preventDefault();
1376
+ setError(null);
1377
+ setSubmitting(true);
1378
+ try {
1379
+ if (usePassword) {
1380
+ await register({
1381
+ email,
1382
+ password,
1383
+ name: collectName && name ? name : void 0,
1384
+ invitationToken,
1385
+ invitationCode: invitationCode || void 0
1386
+ });
1387
+ if (redirectUrl) {
1388
+ await client.redirectWithSession(redirectUrl);
1389
+ } else {
1390
+ _optionalChain([onSuccess, 'optionalCall', _14 => _14()]);
1391
+ }
1392
+ } else {
1393
+ await startPasswordless(email, magicLinkCallbackUrl, {
1394
+ invitationToken,
1395
+ invitationCode: invitationCode || void 0
1396
+ });
1397
+ setLinkSentTo(email);
1398
+ }
1399
+ } catch (err) {
1400
+ setError(showError(err));
1401
+ setSubmitting(false);
1402
+ }
1403
+ };
1404
+ if (!hasEmailMethod && !hasOAuth) {
1405
+ return shell(
1406
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1407
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading }),
1408
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: l10n.signUp.unavailable })
1409
+ ] })
1410
+ );
1411
+ }
1412
+ const submitLabel = submitting ? usePassword ? l10n.signUp.submitting : l10n.signUp.magicSubmitting : usePassword ? l10n.signUp.submit : l10n.signUp.magicSubmit;
1413
+ return shell(
1414
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1415
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1416
+ Masthead,
1417
+ {
1418
+ logo,
1419
+ title: heading,
1420
+ subtitle: _nullishCoalesce(subtitle, () => ( (needsCode ? l10n.signUp.invitationNeeded : signInLine)))
1421
+ }
1422
+ ),
1423
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-stack", children: [
1424
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: error }) : null,
1425
+ linkSentTo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { children: _chunk7U3QBMA7cjs.fillNode.call(void 0, l10n.signUp.linkSent, { email: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "strong", { children: linkSentTo }) }) }) : hasEmailMethod ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "kerne-form", onSubmit: handleSubmit, children: [
1426
+ needsCode ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1427
+ Field,
1428
+ {
1429
+ label: l10n.signUp.invitationCode,
1430
+ type: "text",
1431
+ value: invitationCode,
1432
+ onChange: setInvitationCode,
1433
+ placeholder: "XXXXXX",
1434
+ autoComplete: "one-time-code",
1435
+ disabled: submitting,
1436
+ required: true,
1437
+ code: true,
1438
+ autoFocus: true
1439
+ }
1440
+ ) : null,
1441
+ collectName && usePassword ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1442
+ Field,
1443
+ {
1444
+ label: l10n.common.name,
1445
+ type: "text",
1446
+ value: name,
1447
+ onChange: setName,
1448
+ autoComplete: "name",
1449
+ placeholder: l10n.common.namePlaceholder,
1450
+ disabled: submitting
1451
+ }
1452
+ ) : null,
1453
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1454
+ Field,
1455
+ {
1456
+ label: l10n.common.email,
1457
+ type: "email",
1458
+ value: email,
1459
+ onChange: setEmail,
1460
+ autoComplete: "email",
1461
+ placeholder: l10n.common.emailPlaceholder,
1462
+ disabled: submitting,
1463
+ required: true,
1464
+ autoFocus: !needsCode
1465
+ }
1466
+ ),
1467
+ usePassword ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1468
+ Field,
1469
+ {
1470
+ label: l10n.common.password,
1471
+ type: "password",
1472
+ value: password,
1473
+ onChange: setPassword,
1474
+ autoComplete: "new-password",
1475
+ placeholder: l10n.common.passwordPlaceholder,
1476
+ disabled: submitting,
1477
+ required: true,
1478
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PasswordStrength, { password, policy })
1479
+ }
1480
+ ) : null,
1481
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1482
+ Button,
1483
+ {
1484
+ loading: submitting,
1485
+ disabled: !email || needsCode && !invitationCode || usePassword && !meetsPolicy(password, policy),
1486
+ children: submitLabel
1487
+ }
1488
+ ),
1489
+ hasCredentials && hasMagicLink ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1490
+ MethodSwitch,
1491
+ {
1492
+ onClick: () => {
1493
+ setPasswordMode((v) => !v);
1494
+ setError(null);
1495
+ },
1496
+ children: usePassword ? l10n.signUp.useMagicLink : l10n.signUp.usePassword
1497
+ }
1498
+ ) : null
1499
+ ] }) : null,
1500
+ hasOAuth && hasEmailMethod ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Divider, { label: l10n.common.or }) : null,
1501
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1502
+ OAuthButtons,
1503
+ {
1504
+ providers: config.oauth_providers,
1505
+ disabled: submitting,
1506
+ onSelect: onOAuthSelect
1507
+ }
1508
+ )
1509
+ ] }),
1510
+ legal ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-legal", children: legal }) : null,
1511
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: config.show_kerne_branding })
1512
+ ] })
1513
+ );
1514
+ }
1515
+
1516
+ // src/ui/ForgotPasswordForm.tsx
1517
+
1518
+
1519
+ function ForgotPasswordForm({
1520
+ callbackUrl,
1521
+ signInUrl,
1522
+ onSignInClick,
1523
+ onSent,
1524
+ title,
1525
+ subtitle,
1526
+ appearance,
1527
+ logo,
1528
+ className
1529
+ }) {
1530
+ const { requestPasswordReset } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
1531
+ const { config } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
1532
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
1533
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
1534
+ const [email, setEmail] = _react.useState.call(void 0, "");
1535
+ const [submitting, setSubmitting] = _react.useState.call(void 0, false);
1536
+ const [error, setError] = _react.useState.call(void 0, null);
1537
+ const [sentTo, setSentTo] = _react.useState.call(void 0, null);
1538
+ const handleSubmit = async (e) => {
1539
+ e.preventDefault();
1540
+ setError(null);
1541
+ setSubmitting(true);
1542
+ try {
1543
+ await requestPasswordReset(email, callbackUrl);
1544
+ setSentTo(email);
1545
+ _optionalChain([onSent, 'optionalCall', _15 => _15(email)]);
1546
+ } catch (err) {
1547
+ setError(showError(err));
1548
+ } finally {
1549
+ setSubmitting(false);
1550
+ }
1551
+ };
1552
+ const backLine = signInUrl || onSignInClick ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1553
+ l10n.resetPassword.rememberedPrompt,
1554
+ " ",
1555
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TextLink, { href: signInUrl, onClick: onSignInClick, children: l10n.common.backToSignIn }),
1556
+ "."
1557
+ ] }) : void 0;
1558
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1559
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1560
+ Masthead,
1561
+ {
1562
+ logo,
1563
+ title: _nullishCoalesce(title, () => ( l10n.resetPassword.requestTitle)),
1564
+ subtitle: _nullishCoalesce(subtitle, () => ( (sentTo ? backLine : l10n.resetPassword.requestSubtitle)))
1565
+ }
1566
+ ),
1567
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-stack", children: [
1568
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: error }) : null,
1569
+ sentTo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { children: _chunk7U3QBMA7cjs.fillNode.call(void 0, l10n.resetPassword.requestSent, { email: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "strong", { children: sentTo }) }) }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "kerne-form", onSubmit: handleSubmit, children: [
1570
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1571
+ Field,
1572
+ {
1573
+ label: l10n.common.email,
1574
+ type: "email",
1575
+ value: email,
1576
+ onChange: setEmail,
1577
+ autoComplete: "email",
1578
+ placeholder: l10n.common.emailPlaceholder,
1579
+ disabled: submitting,
1580
+ required: true,
1581
+ autoFocus: true
1582
+ }
1583
+ ),
1584
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { loading: submitting, disabled: !email, children: submitting ? l10n.resetPassword.requestSubmitting : l10n.resetPassword.requestSubmit }),
1585
+ backLine ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-footer", children: backLine }) : null
1586
+ ] })
1587
+ ] }),
1588
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _16 => _16.show_kerne_branding]), () => ( false)) })
1589
+ ] });
1590
+ }
1591
+
1592
+ // src/ui/ResetPasswordForm.tsx
1593
+
1594
+
1595
+ function ResetPasswordForm({
1596
+ token: tokenProp,
1597
+ signInUrl,
1598
+ onSignInClick,
1599
+ onSuccess,
1600
+ title,
1601
+ subtitle,
1602
+ appearance,
1603
+ logo,
1604
+ className
1605
+ }) {
1606
+ const { confirmPasswordReset } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
1607
+ const { config } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
1608
+ const policy = resolvePolicy(config);
1609
+ const token = useUrlToken("token", tokenProp);
1610
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
1611
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
1612
+ const [password, setPassword] = _react.useState.call(void 0, "");
1613
+ const [confirm, setConfirm] = _react.useState.call(void 0, "");
1614
+ const [submitting, setSubmitting] = _react.useState.call(void 0, false);
1615
+ const [error, setError] = _react.useState.call(void 0, null);
1616
+ const [done, setDone] = _react.useState.call(void 0, false);
1617
+ const heading = _nullishCoalesce(title, () => ( l10n.resetPassword.title));
1618
+ const mismatch = confirm.length > 0 && password !== confirm;
1619
+ const signInAction = signInUrl || onSignInClick ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1620
+ Button,
1621
+ {
1622
+ type: "button",
1623
+ onClick: _nullishCoalesce(onSignInClick, () => ( (() => {
1624
+ if (signInUrl) window.location.href = signInUrl;
1625
+ }))),
1626
+ children: l10n.signIn.submit
1627
+ }
1628
+ ) : void 0;
1629
+ const handleSubmit = async (e) => {
1630
+ e.preventDefault();
1631
+ if (mismatch || !token) return;
1632
+ setError(null);
1633
+ setSubmitting(true);
1634
+ try {
1635
+ await confirmPasswordReset(token, password);
1636
+ setDone(true);
1637
+ _optionalChain([onSuccess, 'optionalCall', _17 => _17()]);
1638
+ } catch (err) {
1639
+ setError(showError(err));
1640
+ } finally {
1641
+ setSubmitting(false);
1642
+ }
1643
+ };
1644
+ if (token === null) {
1645
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1646
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading }),
1647
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormSkeleton, {})
1648
+ ] });
1649
+ }
1650
+ if (token === "") {
1651
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1652
+ logo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-masthead", children: logo }) : null,
1653
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Status, { tone: "danger", title: l10n.resetPassword.incompleteTitle, action: signInAction, children: l10n.resetPassword.incompleteBody }),
1654
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _18 => _18.show_kerne_branding]), () => ( false)) })
1655
+ ] });
1656
+ }
1657
+ if (done) {
1658
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1659
+ logo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-masthead", children: logo }) : null,
1660
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Status, { tone: "success", title: l10n.resetPassword.doneTitle, action: signInAction, children: l10n.resetPassword.doneBody }),
1661
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _19 => _19.show_kerne_branding]), () => ( false)) })
1662
+ ] });
1663
+ }
1664
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1665
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading, subtitle: _nullishCoalesce(subtitle, () => ( l10n.resetPassword.subtitle)) }),
1666
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-stack", children: [
1667
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: error }) : null,
1668
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "kerne-form", onSubmit: handleSubmit, children: [
1669
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1670
+ Field,
1671
+ {
1672
+ label: l10n.resetPassword.newPassword,
1673
+ type: "password",
1674
+ value: password,
1675
+ onChange: setPassword,
1676
+ autoComplete: "new-password",
1677
+ placeholder: l10n.common.passwordPlaceholder,
1678
+ disabled: submitting,
1679
+ required: true,
1680
+ autoFocus: true,
1681
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PasswordStrength, { password, policy })
1682
+ }
1683
+ ),
1684
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1685
+ Field,
1686
+ {
1687
+ label: l10n.resetPassword.confirmPassword,
1688
+ type: "password",
1689
+ value: confirm,
1690
+ onChange: setConfirm,
1691
+ autoComplete: "new-password",
1692
+ placeholder: l10n.common.passwordPlaceholder,
1693
+ disabled: submitting,
1694
+ required: true,
1695
+ error: mismatch ? l10n.resetPassword.mismatch : void 0
1696
+ }
1697
+ ),
1698
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1699
+ Button,
1700
+ {
1701
+ loading: submitting,
1702
+ disabled: !meetsPolicy(password, policy) || !confirm || mismatch,
1703
+ children: submitting ? l10n.resetPassword.submitting : l10n.resetPassword.submit
1704
+ }
1705
+ ),
1706
+ signInUrl || onSignInClick ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-footer", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TextLink, { href: signInUrl, onClick: onSignInClick, children: l10n.common.backToSignIn }) }) : null
1707
+ ] })
1708
+ ] }),
1709
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _20 => _20.show_kerne_branding]), () => ( false)) })
1710
+ ] });
1711
+ }
1712
+
1713
+ // src/ui/MagicLinkCallback.tsx
1714
+
1715
+
1716
+ function MagicLinkCallback({
1717
+ token: tokenProp,
1718
+ onSuccess,
1719
+ redirectUrl,
1720
+ signInUrl,
1721
+ onSignInClick,
1722
+ appearance,
1723
+ logo,
1724
+ className
1725
+ }) {
1726
+ const client = _chunk7U3QBMA7cjs.useClient.call(void 0, );
1727
+ const { loginWithMagicLink } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
1728
+ const { config } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
1729
+ const token = useUrlToken("token", tokenProp);
1730
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
1731
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
1732
+ const [state, setState] = _react.useState.call(void 0, "pending");
1733
+ const [message, setMessage] = _react.useState.call(void 0, null);
1734
+ const consumed = _react.useRef.call(void 0, false);
1735
+ _react.useEffect.call(void 0, () => {
1736
+ if (token === null || consumed.current) return;
1737
+ if (token === "") {
1738
+ setState("failed");
1739
+ return;
1740
+ }
1741
+ consumed.current = true;
1742
+ loginWithMagicLink(token).then(async () => {
1743
+ setState("done");
1744
+ if (redirectUrl) {
1745
+ await client.redirectWithSession(redirectUrl);
1746
+ } else {
1747
+ _optionalChain([onSuccess, 'optionalCall', _21 => _21()]);
1748
+ }
1749
+ }).catch((e) => {
1750
+ setState("failed");
1751
+ setMessage(showError(e));
1752
+ });
1753
+ }, [token, loginWithMagicLink, redirectUrl, client, onSuccess]);
1754
+ const retry = signInUrl || onSignInClick ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1755
+ Button,
1756
+ {
1757
+ variant: "outline",
1758
+ type: "button",
1759
+ onClick: _nullishCoalesce(onSignInClick, () => ( (() => {
1760
+ if (signInUrl) window.location.href = signInUrl;
1761
+ }))),
1762
+ children: l10n.common.backToSignIn
1763
+ }
1764
+ ) : void 0;
1765
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1766
+ logo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-masthead", children: logo }) : null,
1767
+ state === "pending" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Status, { tone: "loading", title: l10n.magicLink.pendingTitle, children: l10n.magicLink.pendingBody }) : state === "done" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Status, { tone: "success", title: l10n.magicLink.doneTitle, children: l10n.magicLink.doneBody }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Status, { tone: "danger", title: l10n.magicLink.failedTitle, action: retry, children: _nullishCoalesce(message, () => ( l10n.magicLink.missingToken)) }),
1768
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _22 => _22.show_kerne_branding]), () => ( false)) })
1769
+ ] });
1770
+ }
1771
+
1772
+ // src/ui/VerifyEmailForm.tsx
1773
+
1774
+
1775
+ function VerifyEmailForm({
1776
+ token: tokenProp,
1777
+ callbackUrl,
1778
+ onVerified,
1779
+ title,
1780
+ subtitle,
1781
+ appearance,
1782
+ logo,
1783
+ className
1784
+ }) {
1785
+ const { verifyEmailWithCode, verifyEmailWithLink, sendVerificationEmail, refreshToken } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
1786
+ const { config } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
1787
+ const token = useUrlToken("token", tokenProp);
1788
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
1789
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
1790
+ const [code, setCode] = _react.useState.call(void 0, "");
1791
+ const [submitting, setSubmitting] = _react.useState.call(void 0, false);
1792
+ const [error, setError] = _react.useState.call(void 0, null);
1793
+ const [resent, setResent] = _react.useState.call(void 0, false);
1794
+ const [linkState, setLinkState] = _react.useState.call(void 0, "idle");
1795
+ const [verified, setVerified] = _react.useState.call(void 0, false);
1796
+ const consumed = _react.useRef.call(void 0, false);
1797
+ const heading = _nullishCoalesce(title, () => ( l10n.verifyEmail.title));
1798
+ const settle = async (needsTokenRefresh) => {
1799
+ if (needsTokenRefresh) {
1800
+ await refreshToken().catch(() => void 0);
1801
+ }
1802
+ setVerified(true);
1803
+ _optionalChain([onVerified, 'optionalCall', _23 => _23()]);
1804
+ };
1805
+ _react.useEffect.call(void 0, () => {
1806
+ if (token === null || token === "" || consumed.current) return;
1807
+ consumed.current = true;
1808
+ setLinkState("pending");
1809
+ verifyEmailWithLink(token).then(async (r) => {
1810
+ await settle(r.needsTokenRefresh);
1811
+ setLinkState("done");
1812
+ }).catch((e) => {
1813
+ setLinkState("failed");
1814
+ setError(showError(e));
1815
+ });
1816
+ }, [token, verifyEmailWithLink]);
1817
+ const handleSubmit = async (e) => {
1818
+ e.preventDefault();
1819
+ setError(null);
1820
+ setSubmitting(true);
1821
+ try {
1822
+ const r = await verifyEmailWithCode(code);
1823
+ await settle(r.needsTokenRefresh);
1824
+ } catch (err) {
1825
+ setError(showError(err));
1826
+ } finally {
1827
+ setSubmitting(false);
1828
+ }
1829
+ };
1830
+ const handleResend = async () => {
1831
+ setError(null);
1832
+ try {
1833
+ await sendVerificationEmail("code", callbackUrl);
1834
+ setResent(true);
1835
+ } catch (err) {
1836
+ setError(showError(err));
1837
+ }
1838
+ };
1839
+ if (verified) {
1840
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1841
+ logo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-masthead", children: logo }) : null,
1842
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Status, { tone: "success", title: l10n.verifyEmail.doneTitle, children: l10n.verifyEmail.doneBody }),
1843
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _24 => _24.show_kerne_branding]), () => ( false)) })
1844
+ ] });
1845
+ }
1846
+ if (linkState === "pending") {
1847
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1848
+ logo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-masthead", children: logo }) : null,
1849
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Status, { tone: "loading", title: l10n.verifyEmail.verifyingTitle, children: l10n.verifyEmail.verifyingBody })
1850
+ ] });
1851
+ }
1852
+ if (linkState === "failed") {
1853
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1854
+ logo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-masthead", children: logo }) : null,
1855
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1856
+ Status,
1857
+ {
1858
+ tone: "danger",
1859
+ title: l10n.verifyEmail.failedTitle,
1860
+ action: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "outline", type: "button", onClick: handleResend, children: l10n.verifyEmail.newCode }),
1861
+ children: error
1862
+ }
1863
+ ),
1864
+ resent ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "success", children: l10n.verifyEmail.resent }) : null,
1865
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _25 => _25.show_kerne_branding]), () => ( false)) })
1866
+ ] });
1867
+ }
1868
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1869
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading, subtitle: _nullishCoalesce(subtitle, () => ( l10n.verifyEmail.subtitle)) }),
1870
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-stack", children: [
1871
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: error }) : null,
1872
+ resent ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "success", children: l10n.verifyEmail.resent }) : null,
1873
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "kerne-form", onSubmit: handleSubmit, children: [
1874
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1875
+ Field,
1876
+ {
1877
+ label: l10n.verifyEmail.code,
1878
+ type: "text",
1879
+ value: code,
1880
+ onChange: setCode,
1881
+ autoComplete: "one-time-code",
1882
+ placeholder: "000000",
1883
+ disabled: submitting,
1884
+ required: true,
1885
+ code: true,
1886
+ autoFocus: true
1887
+ }
1888
+ ),
1889
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { loading: submitting, disabled: !code, children: submitting ? l10n.verifyEmail.submitting : l10n.verifyEmail.submit }),
1890
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, MethodSwitch, { onClick: handleResend, children: l10n.verifyEmail.resend })
1891
+ ] })
1892
+ ] }),
1893
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _26 => _26.show_kerne_branding]), () => ( false)) })
1894
+ ] });
1895
+ }
1896
+
1897
+ // src/ui/ActivateAccountForm.tsx
1898
+
1899
+
1900
+ function ActivateAccountForm({
1901
+ token: tokenProp,
1902
+ onSuccess,
1903
+ redirectUrl,
1904
+ signInUrl,
1905
+ onSignInClick,
1906
+ title,
1907
+ appearance,
1908
+ logo,
1909
+ className
1910
+ }) {
1911
+ const client = _chunk7U3QBMA7cjs.useClient.call(void 0, );
1912
+ const { getActivationContext, completeActivation } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
1913
+ const { config } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
1914
+ const policy = resolvePolicy(config);
1915
+ const token = useUrlToken("token", tokenProp);
1916
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
1917
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
1918
+ const [context, setContext] = _react.useState.call(void 0, null);
1919
+ const [loadError, setLoadError] = _react.useState.call(void 0, null);
1920
+ const [password, setPassword] = _react.useState.call(void 0, "");
1921
+ const [confirm, setConfirm] = _react.useState.call(void 0, "");
1922
+ const [submitting, setSubmitting] = _react.useState.call(void 0, false);
1923
+ const [error, setError] = _react.useState.call(void 0, null);
1924
+ const heading = _nullishCoalesce(title, () => ( l10n.activate.title));
1925
+ const mismatch = confirm.length > 0 && password !== confirm;
1926
+ _react.useEffect.call(void 0, () => {
1927
+ if (!token) return;
1928
+ let mounted = true;
1929
+ getActivationContext(token).then((c) => mounted && setContext(c)).catch((e) => mounted && setLoadError(showError(e)));
1930
+ return () => {
1931
+ mounted = false;
1932
+ };
1933
+ }, [token, getActivationContext]);
1934
+ const signInAction = signInUrl || onSignInClick ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1935
+ Button,
1936
+ {
1937
+ type: "button",
1938
+ onClick: _nullishCoalesce(onSignInClick, () => ( (() => {
1939
+ if (signInUrl) window.location.href = signInUrl;
1940
+ }))),
1941
+ children: l10n.activate.goToSignIn
1942
+ }
1943
+ ) : void 0;
1944
+ const handleSubmit = async (e) => {
1945
+ e.preventDefault();
1946
+ if (!token || mismatch) return;
1947
+ setError(null);
1948
+ setSubmitting(true);
1949
+ try {
1950
+ await completeActivation(token, _optionalChain([context, 'optionalAccess', _27 => _27.mode]) === "credentials" ? password : void 0);
1951
+ if (redirectUrl) {
1952
+ await client.redirectWithSession(redirectUrl);
1953
+ } else {
1954
+ _optionalChain([onSuccess, 'optionalCall', _28 => _28()]);
1955
+ }
1956
+ } catch (err) {
1957
+ setError(showError(err));
1958
+ setSubmitting(false);
1959
+ }
1960
+ };
1961
+ if (token === null) {
1962
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1963
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading }),
1964
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormSkeleton, {})
1965
+ ] });
1966
+ }
1967
+ if (token === "" || loadError) {
1968
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1969
+ logo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-masthead", children: logo }) : null,
1970
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Status, { tone: "danger", title: l10n.activate.failedTitle, action: signInAction, children: _nullishCoalesce(loadError, () => ( l10n.activate.missingToken)) }),
1971
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _29 => _29.show_kerne_branding]), () => ( false)) })
1972
+ ] });
1973
+ }
1974
+ if (!context) {
1975
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1976
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Masthead, { logo, title: heading }),
1977
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, FormSkeleton, {})
1978
+ ] });
1979
+ }
1980
+ const credentialsMode = context.mode === "credentials";
1981
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
1982
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1983
+ Masthead,
1984
+ {
1985
+ logo,
1986
+ title: heading,
1987
+ subtitle: _chunk7U3QBMA7cjs.fillNode.call(void 0,
1988
+ credentialsMode ? l10n.activate.credentialsSubtitle : l10n.activate.magicSubtitle,
1989
+ { email: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "strong", { children: context.email }) }
1990
+ )
1991
+ }
1992
+ ),
1993
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-stack", children: [
1994
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: error }) : null,
1995
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "kerne-form", onSubmit: handleSubmit, children: [
1996
+ credentialsMode ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1997
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1998
+ Field,
1999
+ {
2000
+ label: l10n.common.password,
2001
+ type: "password",
2002
+ value: password,
2003
+ onChange: setPassword,
2004
+ autoComplete: "new-password",
2005
+ placeholder: l10n.common.passwordPlaceholder,
2006
+ disabled: submitting,
2007
+ required: true,
2008
+ autoFocus: true,
2009
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PasswordStrength, { password, policy })
2010
+ }
2011
+ ),
2012
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2013
+ Field,
2014
+ {
2015
+ label: l10n.activate.confirmPassword,
2016
+ type: "password",
2017
+ value: confirm,
2018
+ onChange: setConfirm,
2019
+ autoComplete: "new-password",
2020
+ placeholder: l10n.common.passwordPlaceholder,
2021
+ disabled: submitting,
2022
+ required: true,
2023
+ error: mismatch ? l10n.activate.mismatch : void 0
2024
+ }
2025
+ )
2026
+ ] }) : null,
2027
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2028
+ Button,
2029
+ {
2030
+ loading: submitting,
2031
+ disabled: credentialsMode && (!meetsPolicy(password, policy) || !confirm || mismatch),
2032
+ children: submitting ? l10n.activate.submitting : l10n.activate.submit
2033
+ }
2034
+ )
2035
+ ] })
2036
+ ] }),
2037
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _30 => _30.show_kerne_branding]), () => ( false)) })
2038
+ ] });
2039
+ }
2040
+
2041
+ // src/ui/AuthFlow.tsx
2042
+
2043
+ var TOKEN_STEPS = ["reset-password", "magic-link", "activate", "verify-email"];
2044
+ function AuthFlow({
2045
+ initialStep,
2046
+ step: controlledStep,
2047
+ onStepChange,
2048
+ onSuccess,
2049
+ redirectUrl,
2050
+ magicLinkCallbackUrl,
2051
+ resetPasswordCallbackUrl,
2052
+ verificationCallbackUrl,
2053
+ allowSignUp = true,
2054
+ legal,
2055
+ appearance,
2056
+ logo,
2057
+ className
2058
+ }) {
2059
+ const { config } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
2060
+ const token = useUrlToken("token");
2061
+ const [internalStep, setInternalStep] = _react.useState.call(void 0, null);
2062
+ const go = (next) => {
2063
+ if (controlledStep === void 0) setInternalStep(next);
2064
+ _optionalChain([onStepChange, 'optionalCall', _31 => _31(next)]);
2065
+ };
2066
+ const tokenStep = token && (initialStep === void 0 || TOKEN_STEPS.includes(initialStep)) ? _nullishCoalesce(initialStep, () => ( "magic-link")) : null;
2067
+ const step = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_nullishCoalesce(controlledStep, () => ( internalStep)), () => ( tokenStep)), () => ( initialStep)), () => ( "sign-in"));
2068
+ const canSignUp = allowSignUp && _optionalChain([config, 'optionalAccess', _32 => _32.registration_mode]) !== "CLOSED";
2069
+ const shared = {
2070
+ appearance,
2071
+ logo,
2072
+ className: `kerne-step${className ? ` ${className}` : ""}`
2073
+ };
2074
+ switch (step) {
2075
+ case "sign-up":
2076
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2077
+ RegisterForm,
2078
+ {
2079
+ ...shared,
2080
+ onSuccess,
2081
+ redirectUrl,
2082
+ magicLinkCallbackUrl,
2083
+ onSignInClick: () => go("sign-in"),
2084
+ legal
2085
+ }
2086
+ );
2087
+ case "forgot-password":
2088
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2089
+ ForgotPasswordForm,
2090
+ {
2091
+ ...shared,
2092
+ callbackUrl: resetPasswordCallbackUrl,
2093
+ onSignInClick: () => go("sign-in")
2094
+ }
2095
+ );
2096
+ case "reset-password":
2097
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ResetPasswordForm, { ...shared, onSignInClick: () => go("sign-in"), onSuccess });
2098
+ case "magic-link":
2099
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2100
+ MagicLinkCallback,
2101
+ {
2102
+ ...shared,
2103
+ onSuccess,
2104
+ redirectUrl,
2105
+ onSignInClick: () => go("sign-in")
2106
+ }
2107
+ );
2108
+ case "verify-email":
2109
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, VerifyEmailForm, { ...shared, callbackUrl: verificationCallbackUrl, onVerified: onSuccess });
2110
+ case "activate":
2111
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2112
+ ActivateAccountForm,
2113
+ {
2114
+ ...shared,
2115
+ onSuccess,
2116
+ redirectUrl,
2117
+ onSignInClick: () => go("sign-in")
2118
+ }
2119
+ );
2120
+ case "sign-in":
2121
+ default:
2122
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2123
+ LoginForm,
2124
+ {
2125
+ ...shared,
2126
+ onSuccess,
2127
+ redirectUrl,
2128
+ magicLinkCallbackUrl,
2129
+ onSignUpClick: canSignUp ? () => go("sign-up") : void 0,
2130
+ onForgotPasswordClick: () => go("forgot-password"),
2131
+ legal
2132
+ }
2133
+ );
2134
+ }
2135
+ }
2136
+
2137
+ // src/ui/ChangePasswordForm.tsx
2138
+
2139
+
2140
+ function ChangePasswordForm({
2141
+ onSuccess,
2142
+ title,
2143
+ appearance,
2144
+ className
2145
+ }) {
2146
+ const { updatePassword } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
2147
+ const { config } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
2148
+ const policy = resolvePolicy(config);
2149
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
2150
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
2151
+ const heading = title === null ? null : _nullishCoalesce(title, () => ( l10n.security.submit));
2152
+ const [currentPassword, setCurrentPassword] = _react.useState.call(void 0, "");
2153
+ const [newPassword, setNewPassword] = _react.useState.call(void 0, "");
2154
+ const [confirm, setConfirm] = _react.useState.call(void 0, "");
2155
+ const [submitting, setSubmitting] = _react.useState.call(void 0, false);
2156
+ const [error, setError] = _react.useState.call(void 0, null);
2157
+ const [done, setDone] = _react.useState.call(void 0, false);
2158
+ const mismatch = confirm.length > 0 && newPassword !== confirm;
2159
+ const unchanged = newPassword.length > 0 && newPassword === currentPassword;
2160
+ const handleSubmit = async (e) => {
2161
+ e.preventDefault();
2162
+ if (mismatch || unchanged) return;
2163
+ setError(null);
2164
+ setDone(false);
2165
+ setSubmitting(true);
2166
+ try {
2167
+ await updatePassword({ currentPassword, newPassword });
2168
+ setDone(true);
2169
+ setCurrentPassword("");
2170
+ setNewPassword("");
2171
+ setConfirm("");
2172
+ _optionalChain([onSuccess, 'optionalCall', _33 => _33()]);
2173
+ } catch (err) {
2174
+ setError(showError(err));
2175
+ } finally {
2176
+ setSubmitting(false);
2177
+ }
2178
+ };
2179
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
2180
+ heading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-heading", style: { marginBottom: 20 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { className: "kerne-title", children: heading }) }) : null,
2181
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-stack", children: [
2182
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: error }) : null,
2183
+ done ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "success", children: l10n.security.changed }) : null,
2184
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "kerne-form", onSubmit: handleSubmit, children: [
2185
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2186
+ Field,
2187
+ {
2188
+ label: l10n.security.currentPassword,
2189
+ type: "password",
2190
+ value: currentPassword,
2191
+ onChange: setCurrentPassword,
2192
+ autoComplete: "current-password",
2193
+ placeholder: l10n.common.passwordPlaceholder,
2194
+ disabled: submitting,
2195
+ required: true
2196
+ }
2197
+ ),
2198
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2199
+ Field,
2200
+ {
2201
+ label: l10n.security.newPassword,
2202
+ type: "password",
2203
+ value: newPassword,
2204
+ onChange: setNewPassword,
2205
+ autoComplete: "new-password",
2206
+ placeholder: l10n.common.passwordPlaceholder,
2207
+ disabled: submitting,
2208
+ required: true,
2209
+ error: unchanged ? l10n.security.sameAsCurrent : void 0,
2210
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, PasswordStrength, { password: newPassword, policy })
2211
+ }
2212
+ ),
2213
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2214
+ Field,
2215
+ {
2216
+ label: l10n.security.confirmPassword,
2217
+ type: "password",
2218
+ value: confirm,
2219
+ onChange: setConfirm,
2220
+ autoComplete: "new-password",
2221
+ placeholder: l10n.common.passwordPlaceholder,
2222
+ disabled: submitting,
2223
+ required: true,
2224
+ error: mismatch ? l10n.security.mismatch : void 0
2225
+ }
2226
+ ),
2227
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2228
+ Button,
2229
+ {
2230
+ loading: submitting,
2231
+ disabled: !currentPassword || !meetsPolicy(newPassword, policy) || !confirm || mismatch || unchanged,
2232
+ children: submitting ? l10n.security.submitting : l10n.security.submit
2233
+ }
2234
+ )
2235
+ ] })
2236
+ ] })
2237
+ ] });
2238
+ }
2239
+
2240
+ // src/ui/WaitlistForm.tsx
2241
+
2242
+
2243
+ function WaitlistForm({
2244
+ title,
2245
+ subtitle,
2246
+ collectName = false,
2247
+ metadata,
2248
+ submitLabel,
2249
+ successMessage,
2250
+ onJoined,
2251
+ legal,
2252
+ appearance,
2253
+ logo,
2254
+ className
2255
+ }) {
2256
+ const { join } = _chunk7U3QBMA7cjs.useWaitlist.call(void 0, );
2257
+ const { config } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
2258
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
2259
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
2260
+ const [email, setEmail] = _react.useState.call(void 0, "");
2261
+ const [name, setName] = _react.useState.call(void 0, "");
2262
+ const [submitting, setSubmitting] = _react.useState.call(void 0, false);
2263
+ const [error, setError] = _react.useState.call(void 0, null);
2264
+ const [joined, setJoined] = _react.useState.call(void 0, false);
2265
+ const handleSubmit = async (e) => {
2266
+ e.preventDefault();
2267
+ setError(null);
2268
+ setSubmitting(true);
2269
+ try {
2270
+ await join({
2271
+ email,
2272
+ name: collectName && name ? name : void 0,
2273
+ metadata
2274
+ });
2275
+ setJoined(true);
2276
+ _optionalChain([onJoined, 'optionalCall', _34 => _34(email)]);
2277
+ } catch (err) {
2278
+ setError(showError(err));
2279
+ } finally {
2280
+ setSubmitting(false);
2281
+ }
2282
+ };
2283
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
2284
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2285
+ Masthead,
2286
+ {
2287
+ logo,
2288
+ title: _nullishCoalesce(title, () => ( l10n.waitlist.title)),
2289
+ subtitle: joined ? void 0 : _nullishCoalesce(subtitle, () => ( l10n.waitlist.subtitle))
2290
+ }
2291
+ ),
2292
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-stack", children: [
2293
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: error }) : null,
2294
+ joined ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "success", children: _nullishCoalesce(successMessage, () => ( l10n.waitlist.joined)) }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "kerne-form", onSubmit: handleSubmit, children: [
2295
+ collectName ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2296
+ Field,
2297
+ {
2298
+ label: l10n.common.name,
2299
+ type: "text",
2300
+ value: name,
2301
+ onChange: setName,
2302
+ autoComplete: "name",
2303
+ placeholder: l10n.common.namePlaceholder,
2304
+ disabled: submitting
2305
+ }
2306
+ ) : null,
2307
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2308
+ Field,
2309
+ {
2310
+ label: l10n.common.email,
2311
+ type: "email",
2312
+ value: email,
2313
+ onChange: setEmail,
2314
+ autoComplete: "email",
2315
+ placeholder: l10n.common.emailPlaceholder,
2316
+ disabled: submitting,
2317
+ required: true,
2318
+ autoFocus: true
2319
+ }
2320
+ ),
2321
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { loading: submitting, disabled: !email, children: submitting ? l10n.waitlist.submitting : _nullishCoalesce(submitLabel, () => ( l10n.waitlist.submit)) })
2322
+ ] })
2323
+ ] }),
2324
+ legal ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-legal", children: legal }) : null,
2325
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _35 => _35.show_kerne_branding]), () => ( false)) })
2326
+ ] });
2327
+ }
2328
+
2329
+ // src/ui/UserButton.tsx
2330
+
2331
+
2332
+ function SignOutButton({
2333
+ children,
2334
+ onSignedOut,
2335
+ redirectUrl,
2336
+ className,
2337
+ appearance
2338
+ }) {
2339
+ ensureStylesInjected();
2340
+ const { logout } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
2341
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
2342
+ const handle = () => {
2343
+ logout();
2344
+ _optionalChain([onSignedOut, 'optionalCall', _36 => _36()]);
2345
+ if (redirectUrl && typeof window !== "undefined") window.location.href = redirectUrl;
2346
+ };
2347
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2348
+ "div",
2349
+ {
2350
+ className: "kerne-root",
2351
+ style: { ...appearanceToStyle(appearance), display: "inline-flex", width: "auto" },
2352
+ "data-kerne-theme": resolveTheme(appearance),
2353
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2354
+ "button",
2355
+ {
2356
+ type: "button",
2357
+ className: `kerne-button kerne-button-outline${className ? ` ${className}` : ""}`,
2358
+ style: { width: "auto" },
2359
+ onClick: handle,
2360
+ children: _nullishCoalesce(children, () => ( l10n.account.signOut))
2361
+ }
2362
+ )
2363
+ }
2364
+ );
2365
+ }
2366
+ function UserButton({
2367
+ items = [],
2368
+ onSignedOut,
2369
+ signOutRedirectUrl,
2370
+ signedOutFallback = null,
2371
+ appearance,
2372
+ className
2373
+ }) {
2374
+ ensureStylesInjected();
2375
+ const { logout, isAuthenticated } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
2376
+ const { user, fullName, initials, email } = _chunk7U3QBMA7cjs.useUser.call(void 0, );
2377
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
2378
+ const [open, setOpen] = _react.useState.call(void 0, false);
2379
+ const wrapRef = _react.useRef.call(void 0, null);
2380
+ _react.useEffect.call(void 0, () => {
2381
+ if (!open) return;
2382
+ const onPointerDown = (e) => {
2383
+ if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
2384
+ };
2385
+ const onKeyDown = (e) => {
2386
+ if (e.key === "Escape") setOpen(false);
2387
+ };
2388
+ document.addEventListener("mousedown", onPointerDown);
2389
+ document.addEventListener("keydown", onKeyDown);
2390
+ return () => {
2391
+ document.removeEventListener("mousedown", onPointerDown);
2392
+ document.removeEventListener("keydown", onKeyDown);
2393
+ };
2394
+ }, [open]);
2395
+ if (!isAuthenticated) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: signedOutFallback });
2396
+ const handleSignOut = () => {
2397
+ setOpen(false);
2398
+ logout();
2399
+ _optionalChain([onSignedOut, 'optionalCall', _37 => _37()]);
2400
+ if (signOutRedirectUrl && typeof window !== "undefined") {
2401
+ window.location.href = signOutRedirectUrl;
2402
+ }
2403
+ };
2404
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2405
+ "div",
2406
+ {
2407
+ className: `kerne-root${className ? ` ${className}` : ""}`,
2408
+ style: { ...appearanceToStyle(appearance), display: "inline-flex", width: "auto" },
2409
+ "data-kerne-theme": resolveTheme(appearance),
2410
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-menu-wrap", ref: wrapRef, children: [
2411
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2412
+ "button",
2413
+ {
2414
+ type: "button",
2415
+ className: "kerne-menu-trigger",
2416
+ "aria-haspopup": "menu",
2417
+ "aria-expanded": open,
2418
+ "aria-label": l10n.account.menuLabel,
2419
+ onClick: () => setOpen((v) => !v),
2420
+ children: _optionalChain([user, 'optionalAccess', _38 => _38.avatar]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { className: "kerne-avatar", src: user.avatar, alt: "" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-avatar", children: initials || _optionalChain([email, 'optionalAccess', _39 => _39[0], 'optionalAccess', _40 => _40.toUpperCase, 'call', _41 => _41()]) || "?" })
2421
+ }
2422
+ ),
2423
+ open ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-menu", role: "menu", children: [
2424
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-menu-header", children: [
2425
+ fullName ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-identity-name", children: fullName }) : null,
2426
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-identity-mail", children: email })
2427
+ ] }),
2428
+ items.map(
2429
+ (item) => item.href ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { role: "menuitem", className: "kerne-menu-item", href: item.href, children: item.label }, item.label) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2430
+ "button",
2431
+ {
2432
+ type: "button",
2433
+ role: "menuitem",
2434
+ className: "kerne-menu-item",
2435
+ onClick: () => {
2436
+ setOpen(false);
2437
+ _optionalChain([item, 'access', _42 => _42.onClick, 'optionalCall', _43 => _43()]);
2438
+ },
2439
+ children: item.label
2440
+ },
2441
+ item.label
2442
+ )
2443
+ ),
2444
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2445
+ "button",
2446
+ {
2447
+ type: "button",
2448
+ role: "menuitem",
2449
+ className: "kerne-menu-item",
2450
+ "data-tone": "danger",
2451
+ onClick: handleSignOut,
2452
+ children: l10n.account.signOut
2453
+ }
2454
+ )
2455
+ ] }) : null
2456
+ ] })
2457
+ }
2458
+ );
2459
+ }
2460
+
2461
+ // src/ui/UserProfile.tsx
2462
+
2463
+
2464
+ // src/ui/profile/ProfileSection.tsx
2465
+
2466
+
2467
+ function ProfileSection({ verificationCallbackUrl, onSaved }) {
2468
+ const { updateProfile, sendVerificationEmail, getVerificationStatus } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
2469
+ const { user, fullName, initials, email } = _chunk7U3QBMA7cjs.useUser.call(void 0, );
2470
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
2471
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
2472
+ const [firstName, setFirstName] = _react.useState.call(void 0, "");
2473
+ const [lastName, setLastName] = _react.useState.call(void 0, "");
2474
+ const [saving, setSaving] = _react.useState.call(void 0, false);
2475
+ const [saved, setSaved] = _react.useState.call(void 0, false);
2476
+ const [error, setError] = _react.useState.call(void 0, null);
2477
+ const [verified, setVerified] = _react.useState.call(void 0, null);
2478
+ const [sending, setSending] = _react.useState.call(void 0, false);
2479
+ const [sent, setSent] = _react.useState.call(void 0, false);
2480
+ _react.useEffect.call(void 0, () => {
2481
+ if (!user) return;
2482
+ setFirstName(_nullishCoalesce(user.first_name, () => ( "")));
2483
+ setLastName(_nullishCoalesce(user.last_name, () => ( "")));
2484
+ }, [user]);
2485
+ _react.useEffect.call(void 0, () => {
2486
+ let mounted = true;
2487
+ getVerificationStatus().then((s) => mounted && setVerified(s.emailVerified)).catch(() => mounted && setVerified(null));
2488
+ return () => {
2489
+ mounted = false;
2490
+ };
2491
+ }, [getVerificationStatus]);
2492
+ const handleSave = async (e) => {
2493
+ e.preventDefault();
2494
+ setError(null);
2495
+ setSaved(false);
2496
+ setSaving(true);
2497
+ try {
2498
+ await updateProfile({ first_name: firstName, last_name: lastName });
2499
+ setSaved(true);
2500
+ _optionalChain([onSaved, 'optionalCall', _44 => _44()]);
2501
+ } catch (err) {
2502
+ setError(showError(err));
2503
+ } finally {
2504
+ setSaving(false);
2505
+ }
2506
+ };
2507
+ const handleResend = async () => {
2508
+ setError(null);
2509
+ setSending(true);
2510
+ try {
2511
+ await sendVerificationEmail("link", verificationCallbackUrl);
2512
+ setSent(true);
2513
+ } catch (err) {
2514
+ setError(showError(err));
2515
+ } finally {
2516
+ setSending(false);
2517
+ }
2518
+ };
2519
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2520
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Subsection, { title: l10n.profile.profileTitle, children: [
2521
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-identity", children: [
2522
+ _optionalChain([user, 'optionalAccess', _45 => _45.avatar]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { className: "kerne-avatar", src: user.avatar, alt: "" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-avatar", "aria-hidden": "true", children: initials || _optionalChain([email, 'optionalAccess', _46 => _46[0], 'optionalAccess', _47 => _47.toUpperCase, 'call', _48 => _48()]) || "?" }),
2523
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-identity-text", children: [
2524
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-identity-name", children: fullName || l10n.profile.unnamed }),
2525
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-identity-mail", children: email })
2526
+ ] })
2527
+ ] }),
2528
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: error }) : null,
2529
+ saved ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "success", children: l10n.profile.saved }) : null,
2530
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "kerne-form", onSubmit: handleSave, children: [
2531
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2532
+ Field,
2533
+ {
2534
+ label: l10n.profile.firstName,
2535
+ type: "text",
2536
+ value: firstName,
2537
+ onChange: setFirstName,
2538
+ autoComplete: "given-name",
2539
+ placeholder: l10n.profile.firstNamePlaceholder,
2540
+ disabled: saving
2541
+ }
2542
+ ),
2543
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2544
+ Field,
2545
+ {
2546
+ label: l10n.profile.lastName,
2547
+ type: "text",
2548
+ value: lastName,
2549
+ onChange: setLastName,
2550
+ autoComplete: "family-name",
2551
+ placeholder: l10n.profile.lastNamePlaceholder,
2552
+ disabled: saving
2553
+ }
2554
+ ),
2555
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { loading: saving, children: saving ? l10n.profile.saving : l10n.profile.save })
2556
+ ] })
2557
+ ] }),
2558
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2559
+ Subsection,
2560
+ {
2561
+ title: l10n.profile.emailSectionTitle,
2562
+ description: l10n.profile.emailSectionDesc,
2563
+ children: [
2564
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-plan-option", children: [
2565
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-plan-option-text", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "kerne-plan-option-name", children: [
2566
+ email,
2567
+ verified === true ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-badge", "data-tone": "success", children: l10n.profile.verified }) : verified === false ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-badge", "data-tone": "warning", children: l10n.profile.unverified }) : null
2568
+ ] }) }),
2569
+ verified === false ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "outline", type: "button", onClick: handleResend, loading: sending, children: sending ? l10n.common.sending : l10n.profile.verify }) : null
2570
+ ] }),
2571
+ sent ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "success", children: l10n.profile.verificationSent }) : null
2572
+ ]
2573
+ }
2574
+ )
2575
+ ] });
2576
+ }
2577
+
2578
+ // src/ui/profile/SecuritySection.tsx
2579
+
2580
+
2581
+ function SecuritySection({ showDeleteAccount = true, onDeleted }) {
2582
+ const { requestAccountDeletion } = _chunk7U3QBMA7cjs.useAuth.call(void 0, );
2583
+ const { config } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
2584
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
2585
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
2586
+ const [error, setError] = _react.useState.call(void 0, null);
2587
+ const [confirmingDelete, setConfirmingDelete] = _react.useState.call(void 0, false);
2588
+ const [deleting, setDeleting] = _react.useState.call(void 0, false);
2589
+ const hasPassword = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _49 => _49.enable_credentials]), () => ( true));
2590
+ const handleDelete = async () => {
2591
+ setError(null);
2592
+ setDeleting(true);
2593
+ try {
2594
+ await requestAccountDeletion();
2595
+ _optionalChain([onDeleted, 'optionalCall', _50 => _50()]);
2596
+ } catch (err) {
2597
+ setError(showError(err));
2598
+ setDeleting(false);
2599
+ }
2600
+ };
2601
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2602
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: error }) : null,
2603
+ hasPassword ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Subsection, { title: l10n.security.passwordTitle, description: l10n.security.passwordDesc, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ChangePasswordForm, { title: null }) }) : null,
2604
+ showDeleteAccount ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Subsection, { title: l10n.security.deleteTitle, description: l10n.security.deleteDesc, children: confirmingDelete ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { display: "flex", gap: 10, flexWrap: "wrap" }, children: [
2605
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "danger", type: "button", onClick: handleDelete, loading: deleting, children: deleting ? l10n.security.deleting : l10n.security.deleteConfirm }),
2606
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2607
+ Button,
2608
+ {
2609
+ variant: "outline",
2610
+ type: "button",
2611
+ onClick: () => setConfirmingDelete(false),
2612
+ disabled: deleting,
2613
+ children: l10n.common.cancel
2614
+ }
2615
+ )
2616
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "danger", type: "button", onClick: () => setConfirmingDelete(true), children: l10n.security.deleteAction }) }) : null
2617
+ ] });
2618
+ }
2619
+
2620
+ // src/ui/profile/BillingSection.tsx
2621
+
2622
+
2623
+ // src/ui/format.ts
2624
+ function humanizeFeatureKey(key) {
2625
+ const words = key.replace(/[_-]+/g, " ").trim();
2626
+ return words.charAt(0).toUpperCase() + words.slice(1);
2627
+ }
2628
+ function formatMoney(amountMinorUnits, currency) {
2629
+ try {
2630
+ return new Intl.NumberFormat(void 0, {
2631
+ style: "currency",
2632
+ currency: currency.toUpperCase(),
2633
+ // Whole amounts read better without ".00" on a pricing surface, but a
2634
+ // real fractional price must never be rounded away.
2635
+ minimumFractionDigits: amountMinorUnits % 100 === 0 ? 0 : 2
2636
+ }).format(amountMinorUnits / 100);
2637
+ } catch (e2) {
2638
+ return `${(amountMinorUnits / 100).toFixed(2)} ${currency.toUpperCase()}`;
2639
+ }
2640
+ }
2641
+ function formatNumber(value) {
2642
+ return new Intl.NumberFormat().format(value);
2643
+ }
2644
+ function formatDate(iso) {
2645
+ if (!iso) return null;
2646
+ const d = new Date(iso);
2647
+ if (Number.isNaN(d.getTime())) return null;
2648
+ return new Intl.DateTimeFormat(void 0, {
2649
+ year: "numeric",
2650
+ month: "short",
2651
+ day: "numeric"
2652
+ }).format(d);
2653
+ }
2654
+ var ENCODED_INTERVAL = /^([1-9]\d*)([DMY])$/;
2655
+ function formatInterval(interval, labels) {
2656
+ const encoded = ENCODED_INTERVAL.exec(interval);
2657
+ if (encoded) {
2658
+ const count = parseInt(encoded[1], 10);
2659
+ const unitLabel = { D: labels.intervalDay, M: labels.intervalMonth, Y: labels.intervalYear }[encoded[2]];
2660
+ return count === 1 ? unitLabel : `${count} ${unitLabel}`;
2661
+ }
2662
+ switch (interval.toLowerCase()) {
2663
+ case "month":
2664
+ case "monthly":
2665
+ return labels.intervalMonth;
2666
+ case "year":
2667
+ case "yearly":
2668
+ case "annual":
2669
+ return labels.intervalYear;
2670
+ case "week":
2671
+ case "weekly":
2672
+ return labels.intervalWeek;
2673
+ case "day":
2674
+ case "daily":
2675
+ return labels.intervalDay;
2676
+ default:
2677
+ return interval;
2678
+ }
2679
+ }
2680
+
2681
+ // src/ui/UsageMeters.tsx
2682
+
2683
+ function levelFor(ratio, overageAllowed) {
2684
+ if (overageAllowed) return ratio >= 1 ? "warning" : "normal";
2685
+ if (ratio >= 0.9) return "critical";
2686
+ if (ratio >= 0.75) return "warning";
2687
+ return "normal";
2688
+ }
2689
+ function UsageMeters({
2690
+ title,
2691
+ featureKeys,
2692
+ showUnlimited = false,
2693
+ limit: maxRows,
2694
+ labels,
2695
+ emptyState,
2696
+ appearance,
2697
+ className
2698
+ }) {
2699
+ const { entitlements, isLoading, error } = _chunk7U3QBMA7cjs.useEntitlements.call(void 0, );
2700
+ const { subscription } = _chunk7U3QBMA7cjs.useSubscription.call(void 0, );
2701
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
2702
+ const heading = title === null ? null : _nullishCoalesce(title, () => ( l10n.usage.title));
2703
+ const nameFor = (key) => {
2704
+ if (_optionalChain([labels, 'optionalAccess', _51 => _51[key]])) return labels[key];
2705
+ const fromPlan = _optionalChain([subscription, 'optionalAccess', _52 => _52.entitlements, 'access', _53 => _53.find, 'call', _54 => _54((e) => e.feature_key === key), 'optionalAccess', _55 => _55.feature_name]);
2706
+ return _nullishCoalesce(fromPlan, () => ( humanizeFeatureKey(key)));
2707
+ };
2708
+ const shell = (children) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
2709
+ heading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-section-head", style: { marginBottom: 16 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "kerne-section-title", children: heading }) }) : null,
2710
+ children
2711
+ ] });
2712
+ if (isLoading) {
2713
+ return shell(
2714
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-meters", "aria-busy": "true", "aria-label": l10n.usage.loading, children: [
2715
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-skeleton", style: { height: 34 } }),
2716
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-skeleton", style: { height: 34 } })
2717
+ ] })
2718
+ );
2719
+ }
2720
+ if (error || !entitlements) {
2721
+ return shell(/* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: l10n.usage.loadFailed }));
2722
+ }
2723
+ const metered = entitlements.entitlements.filter((e) => {
2724
+ if (e.feature_type !== "QUOTA") return false;
2725
+ if (featureKeys && !featureKeys.includes(e.feature_key)) return false;
2726
+ if (!showUnlimited && (e.limit === null || e.limit === void 0)) return false;
2727
+ return typeof e.used === "number";
2728
+ }).sort((a, b) => {
2729
+ if (featureKeys) {
2730
+ return featureKeys.indexOf(a.feature_key) - featureKeys.indexOf(b.feature_key);
2731
+ }
2732
+ const ratio = (e) => e.limit ? e.used / e.limit : -1;
2733
+ return ratio(b) - ratio(a);
2734
+ });
2735
+ const rows = maxRows ? metered.slice(0, maxRows) : metered;
2736
+ if (rows.length === 0) {
2737
+ return shell(_nullishCoalesce(emptyState, () => ( /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-meter-note", children: l10n.usage.nothingMetered }))));
2738
+ }
2739
+ return shell(
2740
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-meters", children: rows.map((e) => {
2741
+ const unlimited = e.limit === null || e.limit === void 0;
2742
+ const overageAllowed = e.overage_behavior === "ALLOW";
2743
+ const ratio = unlimited ? 0 : Math.min(e.used / e.limit, 1);
2744
+ const level = unlimited ? "normal" : levelFor(e.used / e.limit, overageAllowed);
2745
+ const over = !unlimited && e.used > e.limit;
2746
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-meter", "data-level": level, children: [
2747
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-meter-head", children: [
2748
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-meter-name", children: nameFor(e.feature_key) }),
2749
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-meter-value", children: unlimited ? _chunk7U3QBMA7cjs.fill.call(void 0, l10n.usage.used, { count: formatNumber(e.used) }) : `${formatNumber(e.used)} / ${formatNumber(e.limit)}` })
2750
+ ] }),
2751
+ !unlimited ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2752
+ "div",
2753
+ {
2754
+ className: "kerne-meter-track",
2755
+ role: "progressbar",
2756
+ "aria-valuenow": e.used,
2757
+ "aria-valuemin": 0,
2758
+ "aria-valuemax": e.limit,
2759
+ "aria-label": nameFor(e.feature_key),
2760
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-meter-fill", style: { width: `${ratio * 100}%` } })
2761
+ }
2762
+ ) : null,
2763
+ over && overageAllowed ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-meter-note", children: _chunk7U3QBMA7cjs.fill.call(void 0, l10n.usage.overage, {
2764
+ count: formatNumber(e.used - e.limit)
2765
+ }) }) : over ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-meter-note", children: l10n.usage.limitReached }) : null
2766
+ ] }, e.feature_key);
2767
+ }) })
2768
+ );
2769
+ }
2770
+
2771
+ // src/ui/SubscriptionCard.tsx
2772
+
2773
+
2774
+ var STATUS_TONES = {
2775
+ ACTIVE: "success",
2776
+ TRIALING: "success",
2777
+ PAST_DUE: "warning",
2778
+ CANCELED: void 0,
2779
+ UNPAID: "danger",
2780
+ PAUSED: "warning"
2781
+ };
2782
+ function SubscriptionCard({
2783
+ productSlug,
2784
+ title,
2785
+ portalReturnUrl,
2786
+ upgradeUrl,
2787
+ onUpgradeClick,
2788
+ hidePortalButton = false,
2789
+ appearance,
2790
+ className
2791
+ }) {
2792
+ const { subscription, isLoading, error } = _chunk7U3QBMA7cjs.useSubscription.call(void 0, productSlug);
2793
+ const { openPortal } = _chunk7U3QBMA7cjs.usePortal.call(void 0, );
2794
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
2795
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
2796
+ const heading = title === null ? null : _nullishCoalesce(title, () => ( l10n.billing.plan));
2797
+ const statusLabels = {
2798
+ ACTIVE: l10n.billing.statusActive,
2799
+ TRIALING: l10n.billing.statusTrialing,
2800
+ PAST_DUE: l10n.billing.statusPastDue,
2801
+ CANCELED: l10n.billing.statusCanceled,
2802
+ UNPAID: l10n.billing.statusUnpaid,
2803
+ PAUSED: l10n.billing.statusPaused
2804
+ };
2805
+ const [opening, setOpening] = _react.useState.call(void 0, false);
2806
+ const [portalError, setPortalError] = _react.useState.call(void 0, null);
2807
+ const handlePortal = async () => {
2808
+ setPortalError(null);
2809
+ setOpening(true);
2810
+ try {
2811
+ await openPortal(portalReturnUrl);
2812
+ } catch (e) {
2813
+ setPortalError(showError(e));
2814
+ setOpening(false);
2815
+ }
2816
+ };
2817
+ const shell = (children) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Shell, { appearance, className, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-stack", children: [
2818
+ heading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "kerne-section-title", children: heading }) : null,
2819
+ children
2820
+ ] }) });
2821
+ if (isLoading) {
2822
+ return shell(
2823
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-rows", "aria-busy": "true", "aria-label": l10n.billing.loadingPlan, children: [
2824
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-skeleton", style: { height: 20 } }),
2825
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-skeleton", style: { height: 20 } })
2826
+ ] })
2827
+ );
2828
+ }
2829
+ if (error) {
2830
+ return shell(/* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: l10n.billing.loadFailed }));
2831
+ }
2832
+ if (!subscription) {
2833
+ return shell(
2834
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2835
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-subsection-desc", children: l10n.billing.freePlan }),
2836
+ upgradeUrl || onUpgradeClick ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2837
+ Button,
2838
+ {
2839
+ type: "button",
2840
+ onClick: _nullishCoalesce(onUpgradeClick, () => ( (() => {
2841
+ if (upgradeUrl) window.location.href = upgradeUrl;
2842
+ }))),
2843
+ children: l10n.billing.seePlans
2844
+ }
2845
+ ) : null
2846
+ ] })
2847
+ );
2848
+ }
2849
+ const { plan, plan_price, status, current_period_end, trial_end, canceled_at } = subscription;
2850
+ const renews = formatDate(current_period_end);
2851
+ const trialEnds = formatDate(trial_end);
2852
+ return shell(
2853
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2854
+ portalError ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: portalError }) : null,
2855
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "dl", { className: "kerne-rows", children: [
2856
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-row", children: [
2857
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "dt", { children: l10n.billing.plan }),
2858
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "dd", { children: plan.name })
2859
+ ] }),
2860
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-row", children: [
2861
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "dt", { children: l10n.billing.price }),
2862
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "dd", { children: [
2863
+ formatMoney(plan_price.amount, plan_price.currency),
2864
+ " /",
2865
+ " ",
2866
+ formatInterval(plan_price.interval, l10n.billing)
2867
+ ] })
2868
+ ] }),
2869
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-row", children: [
2870
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "dt", { children: l10n.billing.status }),
2871
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "dd", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-badge", "data-tone": STATUS_TONES[status], children: _nullishCoalesce(statusLabels[status], () => ( status)) }) })
2872
+ ] }),
2873
+ status === "TRIALING" && trialEnds ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-row", children: [
2874
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "dt", { children: l10n.billing.trialEnds }),
2875
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "dd", { children: trialEnds })
2876
+ ] }) : renews ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-row", children: [
2877
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "dt", { children: canceled_at ? l10n.billing.ends : l10n.billing.renews }),
2878
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "dd", { children: renews })
2879
+ ] }) : null
2880
+ ] }),
2881
+ canceled_at ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { children: l10n.billing.cancelNotice }) : null,
2882
+ !hidePortalButton ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "outline", type: "button", onClick: handlePortal, loading: opening, children: opening ? l10n.billing.opening : l10n.billing.managePortal }) : null
2883
+ ] })
2884
+ );
2885
+ }
2886
+
2887
+ // src/ui/profile/BillingSection.tsx
2888
+
2889
+ function intervalsOf(plans) {
2890
+ const seen = [];
2891
+ for (const plan of plans) {
2892
+ for (const price of plan.prices) {
2893
+ if (!seen.includes(price.interval)) seen.push(price.interval);
2894
+ }
2895
+ }
2896
+ return seen;
2897
+ }
2898
+ function BillingSection({
2899
+ productSlug,
2900
+ pricingProductIdOrSlug,
2901
+ portalReturnUrl,
2902
+ checkoutSuccessUrl,
2903
+ checkoutCancelUrl,
2904
+ showPlanSwitcher = true,
2905
+ showUsage = true,
2906
+ usageFeatureKeys,
2907
+ usageLabels
2908
+ }) {
2909
+ const { subscription } = _chunk7U3QBMA7cjs.useSubscription.call(void 0, productSlug);
2910
+ const { plans, isLoading: plansLoading } = _chunk7U3QBMA7cjs.usePlans.call(void 0, pricingProductIdOrSlug);
2911
+ const { openCheckout } = _chunk7U3QBMA7cjs.useCheckout.call(void 0, );
2912
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
2913
+ const showError = _chunk7U3QBMA7cjs.useErrorResolver.call(void 0, );
2914
+ const [busy, setBusy] = _react.useState.call(void 0, null);
2915
+ const [error, setError] = _react.useState.call(void 0, null);
2916
+ const intervals = _react.useMemo.call(void 0, () => intervalsOf(plans), [plans]);
2917
+ const [interval, setInterval] = _react.useState.call(void 0, null);
2918
+ const activeInterval = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(interval, () => ( _optionalChain([subscription, 'optionalAccess', _56 => _56.plan_price, 'access', _57 => _57.interval]))), () => ( intervals[0])), () => ( null));
2919
+ const handleSwitch = async (planPriceId) => {
2920
+ setError(null);
2921
+ setBusy(planPriceId);
2922
+ try {
2923
+ await openCheckout(planPriceId, {
2924
+ successUrl: checkoutSuccessUrl,
2925
+ cancelUrl: checkoutCancelUrl
2926
+ });
2927
+ } catch (e) {
2928
+ setError(showError(e));
2929
+ setBusy(null);
2930
+ }
2931
+ };
2932
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2933
+ error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Panel, { variant: "danger", children: error }) : null,
2934
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Subsection, { title: l10n.billing.currentPlan, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2935
+ SubscriptionCard,
2936
+ {
2937
+ title: null,
2938
+ productSlug,
2939
+ portalReturnUrl
2940
+ }
2941
+ ) }),
2942
+ showUsage ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Subsection, { title: l10n.usage.title, description: l10n.usage.subtitle, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, UsageMeters, { title: null, featureKeys: usageFeatureKeys, labels: usageLabels }) }) : null,
2943
+ showPlanSwitcher ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Subsection, { title: l10n.billing.changePlan, children: plansLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2944
+ "div",
2945
+ {
2946
+ className: "kerne-skeleton",
2947
+ style: { height: 64 },
2948
+ "aria-label": l10n.billing.loadingPlans
2949
+ }
2950
+ ) : plans.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-subsection-desc", children: l10n.billing.noPlans }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2951
+ intervals.length > 1 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2952
+ "div",
2953
+ {
2954
+ className: "kerne-segmented",
2955
+ role: "group",
2956
+ "aria-label": l10n.billing.intervalGroupLabel,
2957
+ children: intervals.map((i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2958
+ "button",
2959
+ {
2960
+ type: "button",
2961
+ className: "kerne-segment",
2962
+ "aria-pressed": i === activeInterval,
2963
+ onClick: () => setInterval(i),
2964
+ children: formatInterval(i, l10n.billing)
2965
+ },
2966
+ i
2967
+ ))
2968
+ }
2969
+ ) : null,
2970
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-plan-list", children: plans.map((plan) => {
2971
+ const price = _nullishCoalesce(plan.prices.find((p) => p.interval === activeInterval), () => ( plan.prices[0]));
2972
+ const isCurrent = _optionalChain([subscription, 'optionalAccess', _58 => _58.plan, 'access', _59 => _59.slug]) === plan.slug;
2973
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2974
+ "div",
2975
+ {
2976
+ className: "kerne-plan-option",
2977
+ "data-current": isCurrent ? "true" : void 0,
2978
+ children: [
2979
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-plan-option-text", children: [
2980
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "kerne-plan-option-name", children: [
2981
+ plan.name,
2982
+ isCurrent ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-badge", children: l10n.billing.current }) : null
2983
+ ] }),
2984
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "kerne-plan-option-price", children: price ? `${formatMoney(price.amount, price.currency)} / ${formatInterval(price.interval, l10n.billing)}` : l10n.billing.notOnInterval })
2985
+ ] }),
2986
+ !isCurrent && price ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2987
+ Button,
2988
+ {
2989
+ variant: "outline",
2990
+ type: "button",
2991
+ onClick: () => handleSwitch(price.id),
2992
+ loading: busy === price.id,
2993
+ disabled: busy !== null,
2994
+ children: busy === price.id ? l10n.billing.opening : l10n.billing.switchTo
2995
+ }
2996
+ ) : null
2997
+ ]
2998
+ },
2999
+ plan.id
3000
+ );
3001
+ }) })
3002
+ ] }) }) : null
3003
+ ] });
3004
+ }
3005
+
3006
+ // src/ui/UserProfile.tsx
3007
+
3008
+ function UserProfile({
3009
+ tabs = ["profile", "security", "billing"],
3010
+ extraTabs = [],
3011
+ defaultTab,
3012
+ activeTab: controlledTab,
3013
+ onTabChange,
3014
+ showDeleteAccount = true,
3015
+ onSaved,
3016
+ onDeleted,
3017
+ productSlug,
3018
+ pricingProductIdOrSlug,
3019
+ portalReturnUrl,
3020
+ checkoutSuccessUrl,
3021
+ checkoutCancelUrl,
3022
+ showPlanSwitcher = true,
3023
+ showUsage = true,
3024
+ usageFeatureKeys,
3025
+ usageLabels,
3026
+ verificationCallbackUrl,
3027
+ appearance,
3028
+ className
3029
+ }) {
3030
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
3031
+ const builtins = {
3032
+ profile: {
3033
+ label: l10n.profile.tabProfile,
3034
+ title: l10n.profile.profileTitle,
3035
+ description: l10n.profile.profileDesc
3036
+ },
3037
+ security: {
3038
+ label: l10n.profile.tabSecurity,
3039
+ title: l10n.profile.securityTitle,
3040
+ description: l10n.profile.securityDesc
3041
+ },
3042
+ billing: {
3043
+ label: l10n.profile.tabBilling,
3044
+ title: l10n.profile.billingTitle,
3045
+ description: l10n.profile.billingDesc
3046
+ }
3047
+ };
3048
+ const allTabs = [
3049
+ ...tabs.map((id) => ({ id, ...builtins[id] })),
3050
+ ...extraTabs.map((t) => ({
3051
+ id: t.id,
3052
+ label: t.label,
3053
+ title: _nullishCoalesce(t.title, () => ( t.label)),
3054
+ description: t.description
3055
+ }))
3056
+ ];
3057
+ const [internalTab, setInternalTab] = _react.useState.call(void 0, _nullishCoalesce(_nullishCoalesce(defaultTab, () => ( _optionalChain([allTabs, 'access', _60 => _60[0], 'optionalAccess', _61 => _61.id]))), () => ( "profile")));
3058
+ const current = _nullishCoalesce(controlledTab, () => ( internalTab));
3059
+ const select = (id) => {
3060
+ if (controlledTab === void 0) setInternalTab(id);
3061
+ _optionalChain([onTabChange, 'optionalCall', _62 => _62(id)]);
3062
+ };
3063
+ const active = _nullishCoalesce(allTabs.find((t) => t.id === current), () => ( allTabs[0]));
3064
+ const renderPane = () => {
3065
+ switch (_optionalChain([active, 'optionalAccess', _63 => _63.id])) {
3066
+ case "profile":
3067
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ProfileSection, { verificationCallbackUrl, onSaved });
3068
+ case "security":
3069
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SecuritySection, { showDeleteAccount, onDeleted });
3070
+ case "billing":
3071
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3072
+ BillingSection,
3073
+ {
3074
+ productSlug,
3075
+ pricingProductIdOrSlug,
3076
+ portalReturnUrl,
3077
+ checkoutSuccessUrl,
3078
+ checkoutCancelUrl,
3079
+ showPlanSwitcher,
3080
+ showUsage,
3081
+ usageFeatureKeys,
3082
+ usageLabels
3083
+ }
3084
+ );
3085
+ default:
3086
+ return _nullishCoalesce(_optionalChain([extraTabs, 'access', _64 => _64.find, 'call', _65 => _65((t) => t.id === _optionalChain([active, 'optionalAccess', _66 => _66.id])), 'optionalAccess', _67 => _67.content]), () => ( null));
3087
+ }
3088
+ };
3089
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Shell, { appearance, className, size: "wide", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-profile", children: [
3090
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "nav", { className: "kerne-nav", "aria-label": l10n.profile.navLabel, children: allTabs.map((tab) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3091
+ "button",
3092
+ {
3093
+ type: "button",
3094
+ className: "kerne-nav-item",
3095
+ "aria-current": tab.id === _optionalChain([active, 'optionalAccess', _68 => _68.id]) ? "page" : void 0,
3096
+ onClick: () => select(tab.id),
3097
+ children: tab.label
3098
+ },
3099
+ tab.id
3100
+ )) }),
3101
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-pane", children: [
3102
+ active ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
3103
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "kerne-pane-title", children: active.title }),
3104
+ active.description ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-pane-desc", children: active.description }) : null
3105
+ ] }) : null,
3106
+ renderPane()
3107
+ ] })
3108
+ ] }) });
3109
+ }
3110
+
3111
+ // src/ui/CheckoutResult.tsx
3112
+
3113
+
3114
+ var POLL_INTERVAL_MS = 1500;
3115
+ function CheckoutResult({
3116
+ outcome = "success",
3117
+ productSlug,
3118
+ continueUrl,
3119
+ onContinue,
3120
+ pricingUrl,
3121
+ onRetry,
3122
+ onConfirmed,
3123
+ confirmTimeoutMs = 15e3,
3124
+ appearance,
3125
+ logo,
3126
+ className
3127
+ }) {
3128
+ const client = _chunk7U3QBMA7cjs.useClient.call(void 0, );
3129
+ const { config } = _chunk7U3QBMA7cjs.useAuthConfig.call(void 0, );
3130
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
3131
+ const [state, setState] = _react.useState.call(void 0, "checking");
3132
+ const confirmed = _react.useRef.call(void 0, false);
3133
+ _react.useEffect.call(void 0, () => {
3134
+ if (outcome !== "success") return;
3135
+ let stopped = false;
3136
+ const startedAt = Date.now();
3137
+ const poll = async () => {
3138
+ if (stopped || confirmed.current) return;
3139
+ try {
3140
+ const sub = await client.getSubscription(productSlug);
3141
+ if (sub && !stopped) {
3142
+ confirmed.current = true;
3143
+ setState("confirmed");
3144
+ _optionalChain([onConfirmed, 'optionalCall', _69 => _69(sub)]);
3145
+ return;
3146
+ }
3147
+ } catch (e3) {
3148
+ }
3149
+ if (stopped) return;
3150
+ if (Date.now() - startedAt >= confirmTimeoutMs) {
3151
+ setState("pending");
3152
+ return;
3153
+ }
3154
+ window.setTimeout(poll, POLL_INTERVAL_MS);
3155
+ };
3156
+ void poll();
3157
+ return () => {
3158
+ stopped = true;
3159
+ };
3160
+ }, [outcome, productSlug, client, confirmTimeoutMs, onConfirmed]);
3161
+ const go = (url, handler) => _nullishCoalesce(handler, () => ( (() => {
3162
+ if (url) window.location.href = url;
3163
+ })));
3164
+ const continueAction = continueUrl || onContinue ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { type: "button", onClick: go(continueUrl, onContinue), children: l10n.common.continue }) : void 0;
3165
+ const shell = (children) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Shell, { appearance, className, children: [
3166
+ logo ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-masthead", children: logo }) : null,
3167
+ children,
3168
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, KerneBranding, { show: _nullishCoalesce(_optionalChain([config, 'optionalAccess', _70 => _70.show_kerne_branding]), () => ( false)) })
3169
+ ] });
3170
+ if (outcome === "cancel") {
3171
+ return shell(
3172
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3173
+ Status,
3174
+ {
3175
+ tone: "danger",
3176
+ title: l10n.checkout.cancelTitle,
3177
+ action: pricingUrl || onRetry ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Button, { variant: "outline", type: "button", onClick: go(pricingUrl, onRetry), children: l10n.checkout.backToPlans }) : void 0,
3178
+ children: l10n.checkout.cancelBody
3179
+ }
3180
+ )
3181
+ );
3182
+ }
3183
+ if (state === "checking") {
3184
+ return shell(
3185
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Status, { tone: "loading", title: l10n.checkout.confirmingTitle, children: l10n.checkout.confirmingBody })
3186
+ );
3187
+ }
3188
+ if (state === "pending") {
3189
+ return shell(
3190
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Status, { tone: "success", title: l10n.checkout.pendingTitle, action: continueAction, children: l10n.checkout.pendingBody })
3191
+ );
3192
+ }
3193
+ return shell(
3194
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Status, { tone: "success", title: l10n.checkout.doneTitle, action: continueAction, children: l10n.checkout.doneBody })
3195
+ );
3196
+ }
3197
+
3198
+ // src/ui/UpgradePrompt.tsx
3199
+
3200
+ function UpgradePrompt({
3201
+ featureKey,
3202
+ requested,
3203
+ featureName,
3204
+ children,
3205
+ upgradeUrl,
3206
+ onUpgradeClick,
3207
+ upgradeLabel,
3208
+ title,
3209
+ description,
3210
+ hideWhileLoading = false,
3211
+ appearance,
3212
+ className
3213
+ }) {
3214
+ const { details, allowed, isLoading } = _chunk7U3QBMA7cjs.useAccess.call(void 0, featureKey, requested);
3215
+ const l10n = _chunk7U3QBMA7cjs.useLocalization.call(void 0, );
3216
+ if (isLoading) {
3217
+ if (hideWhileLoading) return null;
3218
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Shell, { appearance, className, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "kerne-skeleton", style: { height: 80 }, "aria-label": l10n.upgrade.checking }) });
3219
+ }
3220
+ if (allowed) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children });
3221
+ const name = _nullishCoalesce(featureName, () => ( humanizeFeatureKey(featureKey).toLowerCase()));
3222
+ const quotaExhausted = _optionalChain([details, 'optionalAccess', _71 => _71.feature_type]) === "QUOTA" && typeof details.limit === "number" && typeof details.used === "number";
3223
+ const heading = _nullishCoalesce(title, () => ( _chunk7U3QBMA7cjs.fill.call(void 0, quotaExhausted ? l10n.upgrade.quotaTitle : l10n.upgrade.featureTitle, { feature: name })));
3224
+ const body = _nullishCoalesce(description, () => ( (quotaExhausted ? _chunk7U3QBMA7cjs.fill.call(void 0, l10n.upgrade.quotaBody, {
3225
+ used: formatNumber(details.used),
3226
+ limit: formatNumber(details.limit)
3227
+ }) : _chunk7U3QBMA7cjs.fill.call(void 0, l10n.upgrade.featureBody, { feature: name }))));
3228
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Shell, { appearance, className, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-status", children: [
3229
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "kerne-heading", children: [
3230
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "kerne-section-title", style: { fontSize: 17 }, children: heading }),
3231
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "kerne-status-text", children: body })
3232
+ ] }),
3233
+ upgradeUrl || onUpgradeClick ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3234
+ Button,
3235
+ {
3236
+ type: "button",
3237
+ onClick: _nullishCoalesce(onUpgradeClick, () => ( (() => {
3238
+ if (upgradeUrl) window.location.href = upgradeUrl;
3239
+ }))),
3240
+ children: _nullishCoalesce(upgradeLabel, () => ( l10n.upgrade.action))
3241
+ }
3242
+ ) : null
3243
+ ] }) });
3244
+ }
3245
+
3246
+
3247
+
3248
+
3249
+
3250
+
3251
+
3252
+
3253
+
3254
+
3255
+
3256
+
3257
+
3258
+
3259
+
3260
+
3261
+
3262
+
3263
+
3264
+
3265
+
3266
+
3267
+
3268
+ exports.ActivateAccountForm = ActivateAccountForm; exports.AuthFlow = AuthFlow; exports.BillingSection = BillingSection; exports.ChangePasswordForm = ChangePasswordForm; exports.CheckoutResult = CheckoutResult; exports.ForgotPasswordForm = ForgotPasswordForm; exports.LoginForm = LoginForm; exports.MagicLinkCallback = MagicLinkCallback; exports.ProfileSection = ProfileSection; exports.RegisterForm = RegisterForm; exports.ResetPasswordForm = ResetPasswordForm; exports.SecuritySection = SecuritySection; exports.SignOutButton = SignOutButton; exports.SubscriptionCard = SubscriptionCard; exports.UpgradePrompt = UpgradePrompt; exports.UsageMeters = UsageMeters; exports.UserButton = UserButton; exports.UserProfile = UserProfile; exports.VerifyEmailForm = VerifyEmailForm; exports.WaitlistForm = WaitlistForm; exports.defaultLocalization = _chunk7U3QBMA7cjs.defaultLocalization; exports.useLocalization = _chunk7U3QBMA7cjs.useLocalization;