@hexdspace/react 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -15,6 +15,26 @@ var ui = {
15
15
  // src/util/responsive-query/use-responsive-mutation.ts
16
16
  import { useMutation } from "@tanstack/react-query";
17
17
 
18
+ // src/feature/notifier/application/use-case/send-notification-use-case.ts
19
+ var SendNotificationUseCase = class {
20
+ constructor(bus2) {
21
+ this.bus = bus2;
22
+ }
23
+ async execute(channel, notification) {
24
+ this.bus.publish(channel, notification);
25
+ }
26
+ };
27
+
28
+ // src/feature/notifier/application/use-case/subscribe-use-case.ts
29
+ var SubscribeUseCase = class {
30
+ constructor(bus2) {
31
+ this.bus = bus2;
32
+ }
33
+ async execute(channel, observer) {
34
+ return this.bus.subscribe(channel, observer);
35
+ }
36
+ };
37
+
18
38
  // src/feature/notifier/entity/notification-bus.ts
19
39
  var NotificationBus = class {
20
40
  channels = /* @__PURE__ */ new Map();
@@ -51,26 +71,6 @@ var NotificationBus = class {
51
71
  }
52
72
  };
53
73
 
54
- // src/feature/notifier/application/use-case/send-notification-use-case.ts
55
- var SendNotificationUseCase = class {
56
- constructor(bus2) {
57
- this.bus = bus2;
58
- }
59
- async execute(channel, notification) {
60
- this.bus.publish(channel, notification);
61
- }
62
- };
63
-
64
- // src/feature/notifier/application/use-case/subscribe-use-case.ts
65
- var SubscribeUseCase = class {
66
- constructor(bus2) {
67
- this.bus = bus2;
68
- }
69
- async execute(channel, observer) {
70
- return this.bus.subscribe(channel, observer);
71
- }
72
- };
73
-
74
74
  // src/feature/notifier/infra/controllers/notifier-controller.ts
75
75
  var NotifierController = class {
76
76
  constructor(sender, subscriber) {
@@ -91,15 +91,87 @@ var notifierController = new NotifierController(sendNotification, subscribe);
91
91
 
92
92
  // src/feature/notifier/infra/web/react/NotificationHost.tsx
93
93
  import { useCallback, useEffect, useMemo as useMemo2 } from "react";
94
- import { cssTransition, Slide, toast as toast2, ToastContainer } from "react-toastify";
94
+ import {
95
+ Slide,
96
+ ToastContainer,
97
+ cssTransition,
98
+ toast as toast2
99
+ } from "react-toastify";
95
100
 
96
101
  // src/feature/notifier/entity/notification.ts
97
102
  var DEFAULT_NOTIFICATION_CHANNEL = "app.notifications";
98
103
 
104
+ // src/feature/notifier/entity/toast-theme.ts
105
+ var DEFAULT_ACTION_THEME = {
106
+ padding: "0.35rem 0.75rem",
107
+ borderRadius: "var(--radius-btn)",
108
+ background: "color-mix(in oklab, var(--brand), transparent 88%)",
109
+ hoverBackground: "color-mix(in oklab, currentColor, transparent 92%)",
110
+ focusOutline: "2px solid var(--focus)",
111
+ focusOutlineOffset: "2px",
112
+ fontWeight: 600,
113
+ transition: "background-color var(--motion-med) ease, color var(--motion-med) ease, transform var(--motion-med) ease",
114
+ focusTransform: "translateY(-1px)",
115
+ activeTransform: "translateY(0)",
116
+ marginLeft: "auto",
117
+ marginTop: "0.15rem"
118
+ };
119
+ var DEFAULT_ICON_COLORS = {
120
+ info: "var(--info)",
121
+ success: "var(--success)",
122
+ warning: "var(--warning)",
123
+ error: "var(--danger)"
124
+ };
125
+ var DEFAULT_THEME_BASE = {
126
+ lightBg: "var(--surface-3)",
127
+ lightText: "var(--text-1)",
128
+ lightProgress: "var(--brand)",
129
+ darkBg: "var(--surface-1)",
130
+ darkText: "var(--text-1)",
131
+ darkProgress: "var(--brand)",
132
+ progressInfo: "var(--info)",
133
+ progressSuccess: "var(--success)",
134
+ progressWarning: "var(--warning)",
135
+ progressError: "var(--danger)",
136
+ width: "min(24rem, calc(100vw - 2rem))",
137
+ toastRadius: "var(--radius-card)",
138
+ contentPadding: "0.5rem 0.75rem 1rem 0.5rem",
139
+ bodyColumnGap: "0.75rem",
140
+ bodyRowGap: "0.25rem"
141
+ };
142
+ function resolveToastTheme(theme) {
143
+ return {
144
+ lightBg: theme?.lightBg ?? DEFAULT_THEME_BASE.lightBg,
145
+ lightText: theme?.lightText ?? DEFAULT_THEME_BASE.lightText,
146
+ lightProgress: theme?.lightProgress ?? DEFAULT_THEME_BASE.lightProgress,
147
+ darkBg: theme?.darkBg ?? DEFAULT_THEME_BASE.darkBg,
148
+ darkText: theme?.darkText ?? DEFAULT_THEME_BASE.darkText,
149
+ darkProgress: theme?.darkProgress ?? DEFAULT_THEME_BASE.darkProgress,
150
+ progressInfo: theme?.progressInfo ?? DEFAULT_THEME_BASE.progressInfo,
151
+ progressSuccess: theme?.progressSuccess ?? DEFAULT_THEME_BASE.progressSuccess,
152
+ progressWarning: theme?.progressWarning ?? DEFAULT_THEME_BASE.progressWarning,
153
+ progressError: theme?.progressError ?? DEFAULT_THEME_BASE.progressError,
154
+ width: theme?.width ?? DEFAULT_THEME_BASE.width,
155
+ toastRadius: theme?.toastRadius ?? DEFAULT_THEME_BASE.toastRadius,
156
+ contentPadding: theme?.contentPadding ?? DEFAULT_THEME_BASE.contentPadding,
157
+ bodyColumnGap: theme?.bodyColumnGap ?? DEFAULT_THEME_BASE.bodyColumnGap,
158
+ bodyRowGap: theme?.bodyRowGap ?? DEFAULT_THEME_BASE.bodyRowGap,
159
+ transition: theme?.transition,
160
+ action: {
161
+ ...DEFAULT_ACTION_THEME,
162
+ ...theme?.action ?? {}
163
+ },
164
+ iconColors: {
165
+ ...DEFAULT_ICON_COLORS,
166
+ ...theme?.iconColors ?? {}
167
+ }
168
+ };
169
+ }
170
+
99
171
  // src/feature/notifier/infra/web/react/ToastContent.tsx
172
+ import { AlertTriangleIcon, CheckCircleIcon, InfoIcon, XCircleIcon } from "lucide-react";
100
173
  import { useMemo, useState } from "react";
101
174
  import { toast } from "react-toastify";
102
- import { AlertTriangleIcon, CheckCircleIcon, InfoIcon, XCircleIcon } from "lucide-react";
103
175
  import { jsx, jsxs } from "react/jsx-runtime";
104
176
  var DEFAULT_NOTIFICATION_VARIANT = "info";
105
177
  var TOAST_ICON_BY_VARIANT = {
@@ -120,7 +192,8 @@ var ToastContent = ({ notification, theme, mode }) => {
120
192
  const actionTextColor = theme.action.color ?? textColor;
121
193
  const actionHoverColor = theme.action.hoverColor ?? actionTextColor;
122
194
  const actionStyle = useMemo(() => {
123
- const background = isHovered ? theme.action.hoverBackground : theme.action.background;
195
+ const hoverOverlay = theme.action.hoverBackground;
196
+ const background = isHovered ? `linear-gradient(0deg, ${hoverOverlay}, ${hoverOverlay}), ${theme.action.background}` : theme.action.background;
124
197
  const color = isHovered ? actionHoverColor : actionTextColor;
125
198
  const transform = isActive ? theme.action.activeTransform : isFocused ? theme.action.focusTransform : void 0;
126
199
  return {
@@ -173,7 +246,13 @@ var ToastContent = ({ notification, theme, mode }) => {
173
246
  /* @__PURE__ */ jsx(
174
247
  Icon,
175
248
  {
176
- style: { color: iconColor, padding: "0.125rem", width: "1.25rem", height: "1.25rem", flexShrink: 0 },
249
+ style: {
250
+ color: iconColor,
251
+ padding: "0.125rem",
252
+ width: "1.25rem",
253
+ height: "1.25rem",
254
+ flexShrink: 0
255
+ },
177
256
  "aria-hidden": "true"
178
257
  }
179
258
  ),
@@ -239,74 +318,33 @@ var ToastContent = ({ notification, theme, mode }) => {
239
318
  );
240
319
  };
241
320
 
242
- // src/feature/notifier/entity/toast-theme.ts
243
- var DEFAULT_ACTION_THEME = {
244
- padding: "0.35rem 0.75rem",
245
- borderRadius: "0.5rem",
246
- background: "rgba(79, 70, 229, 0.12)",
247
- hoverBackground: "rgba(79, 70, 229, 0.2)",
248
- focusOutline: "2px solid #4338ca",
249
- focusOutlineOffset: "2px",
250
- fontWeight: 600,
251
- transition: "background-color 0.2s ease, color 0.2s ease, transform 0.2s ease",
252
- focusTransform: "translateY(-1px)",
253
- activeTransform: "translateY(0)",
254
- marginLeft: "auto",
255
- marginTop: "0.15rem"
256
- };
257
- var DEFAULT_ICON_COLORS = {
258
- info: "#2563eb",
259
- success: "#16a34a",
260
- warning: "#f59e0b",
261
- error: "#dc2626"
262
- };
263
- var DEFAULT_THEME_BASE = {
264
- lightBg: "#f8fafc",
265
- lightText: "#0f172a",
266
- lightProgress: "#4f46e5",
267
- darkBg: "#111827",
268
- darkText: "#e5e7eb",
269
- darkProgress: "#a5b4fc",
270
- progressInfo: "#60a5fa",
271
- progressSuccess: "#34d399",
272
- progressWarning: "#fbbf24",
273
- progressError: "#f87171",
274
- width: "min(24rem, calc(100vw - 2rem))",
275
- contentPadding: "0.5rem 0.75rem 1rem 0.5rem",
276
- bodyColumnGap: "0.75rem",
277
- bodyRowGap: "0.25rem"
278
- };
279
- function resolveToastTheme(theme) {
280
- return {
281
- lightBg: theme?.lightBg ?? DEFAULT_THEME_BASE.lightBg,
282
- lightText: theme?.lightText ?? DEFAULT_THEME_BASE.lightText,
283
- lightProgress: theme?.lightProgress ?? DEFAULT_THEME_BASE.lightProgress,
284
- darkBg: theme?.darkBg ?? DEFAULT_THEME_BASE.darkBg,
285
- darkText: theme?.darkText ?? DEFAULT_THEME_BASE.darkText,
286
- darkProgress: theme?.darkProgress ?? DEFAULT_THEME_BASE.darkProgress,
287
- progressInfo: theme?.progressInfo ?? DEFAULT_THEME_BASE.progressInfo,
288
- progressSuccess: theme?.progressSuccess ?? DEFAULT_THEME_BASE.progressSuccess,
289
- progressWarning: theme?.progressWarning ?? DEFAULT_THEME_BASE.progressWarning,
290
- progressError: theme?.progressError ?? DEFAULT_THEME_BASE.progressError,
291
- width: theme?.width ?? DEFAULT_THEME_BASE.width,
292
- contentPadding: theme?.contentPadding ?? DEFAULT_THEME_BASE.contentPadding,
293
- bodyColumnGap: theme?.bodyColumnGap ?? DEFAULT_THEME_BASE.bodyColumnGap,
294
- bodyRowGap: theme?.bodyRowGap ?? DEFAULT_THEME_BASE.bodyRowGap,
295
- transition: theme?.transition,
296
- action: {
297
- ...DEFAULT_ACTION_THEME,
298
- ...theme?.action ?? {}
299
- },
300
- iconColors: {
301
- ...DEFAULT_ICON_COLORS,
302
- ...theme?.iconColors ?? {}
303
- }
304
- };
305
- }
306
-
307
321
  // src/feature/notifier/infra/web/react/NotificationHost.tsx
308
322
  import { jsx as jsx2 } from "react/jsx-runtime";
309
- var NotificationHost = ({ channel = DEFAULT_NOTIFICATION_CHANNEL, isDark, theme }) => {
323
+ var ToastCloseButton = ({ closeToast, theme, ariaLabel }) => /* @__PURE__ */ jsx2(
324
+ "button",
325
+ {
326
+ type: "button",
327
+ className: `Toastify__close-button Toastify__close-button--${theme}`,
328
+ "aria-label": ariaLabel ?? "close",
329
+ onClick: (event) => {
330
+ event.stopPropagation();
331
+ closeToast(true);
332
+ },
333
+ style: { color: "var(--text-1)" },
334
+ children: /* @__PURE__ */ jsx2("svg", { "aria-hidden": "true", viewBox: "0 0 14 16", children: /* @__PURE__ */ jsx2(
335
+ "path",
336
+ {
337
+ fillRule: "evenodd",
338
+ d: "M7.71 8.23l3.75 3.75-1.48 1.48-3.75-3.75-3.75 3.75L1 11.98l3.75-3.75L1 4.48 2.48 3l3.75 3.75L9.98 3l1.48 1.48-3.75 3.75z"
339
+ }
340
+ ) })
341
+ }
342
+ );
343
+ var NotificationHost = ({
344
+ channel = DEFAULT_NOTIFICATION_CHANNEL,
345
+ isDark,
346
+ theme
347
+ }) => {
310
348
  const resolvedTheme = useMemo2(() => resolveToastTheme(theme), [theme]);
311
349
  const mode = useMemo2(() => {
312
350
  if (!isDark) {
@@ -318,27 +356,34 @@ var NotificationHost = ({ channel = DEFAULT_NOTIFICATION_CHANNEL, isDark, theme
318
356
  const config = resolvedTheme.transition;
319
357
  return config ? cssTransition(config) : Slide;
320
358
  }, [resolvedTheme.transition]);
321
- const style = useMemo2(() => ({
322
- "--toastify-color-light": resolvedTheme.lightBg,
323
- "--toastify-text-color-light": resolvedTheme.lightText,
324
- "--toastify-color-progress-light": resolvedTheme.lightProgress,
325
- "--toastify-color-dark": resolvedTheme.darkBg,
326
- "--toastify-text-color-dark": resolvedTheme.darkText,
327
- "--toastify-color-progress-dark": resolvedTheme.darkProgress,
328
- "--toastify-color-progress-info": resolvedTheme.progressInfo,
329
- "--toastify-color-progress-success": resolvedTheme.progressSuccess,
330
- "--toastify-color-progress-warning": resolvedTheme.progressWarning,
331
- "--toastify-color-progress-error": resolvedTheme.progressError,
332
- "--toastify-toast-width": resolvedTheme.width
333
- }), [resolvedTheme]);
334
- const renderToast = useCallback((notification) => {
335
- const variant = notification.variant ?? "info";
336
- toast2(/* @__PURE__ */ jsx2(ToastContent, { notification, theme: resolvedTheme, mode }), {
337
- toastId: notification.id,
338
- icon: false,
339
- type: variant
340
- });
341
- }, [mode, resolvedTheme]);
359
+ const style = useMemo2(
360
+ () => ({
361
+ "--toastify-color-light": resolvedTheme.lightBg,
362
+ "--toastify-text-color-light": resolvedTheme.lightText,
363
+ "--toastify-color-progress-light": resolvedTheme.lightProgress,
364
+ "--toastify-color-dark": resolvedTheme.darkBg,
365
+ "--toastify-text-color-dark": resolvedTheme.darkText,
366
+ "--toastify-color-progress-dark": resolvedTheme.darkProgress,
367
+ "--toastify-color-progress-info": resolvedTheme.progressInfo,
368
+ "--toastify-color-progress-success": resolvedTheme.progressSuccess,
369
+ "--toastify-color-progress-warning": resolvedTheme.progressWarning,
370
+ "--toastify-color-progress-error": resolvedTheme.progressError,
371
+ "--toastify-toast-width": resolvedTheme.width,
372
+ "--toastify-toast-bd-radius": resolvedTheme.toastRadius
373
+ }),
374
+ [resolvedTheme]
375
+ );
376
+ const renderToast = useCallback(
377
+ (notification) => {
378
+ const variant = notification.variant ?? "info";
379
+ toast2(/* @__PURE__ */ jsx2(ToastContent, { notification, theme: resolvedTheme, mode }), {
380
+ toastId: notification.id,
381
+ icon: false,
382
+ type: variant
383
+ });
384
+ },
385
+ [mode, resolvedTheme]
386
+ );
342
387
  useEffect(() => {
343
388
  let unsub;
344
389
  let disposed = false;
@@ -361,6 +406,8 @@ var NotificationHost = ({ channel = DEFAULT_NOTIFICATION_CHANNEL, isDark, theme
361
406
  ToastContainer,
362
407
  {
363
408
  style,
409
+ toastStyle: { overflow: "hidden" },
410
+ closeButton: ToastCloseButton,
364
411
  position: "bottom-right",
365
412
  transition,
366
413
  newestOnTop: true,
@@ -399,7 +446,7 @@ function useResponsiveMutation(responsiveMutation, queryClient) {
399
446
  });
400
447
  }
401
448
  var executeEffects = (effects, ctx) => {
402
- effects.forEach((effect) => {
449
+ for (const effect of effects) {
403
450
  if (effect.type === "invalidate") {
404
451
  void ctx.queryClient.invalidateQueries({ queryKey: effect.queryKey });
405
452
  } else if (effect.type === "update") {
@@ -412,7 +459,7 @@ var executeEffects = (effects, ctx) => {
412
459
  } else if (effect.type === "custom") {
413
460
  void effect.run(ctx);
414
461
  }
415
- });
462
+ }
416
463
  };
417
464
 
418
465
  // src/util/controller-factory.ts
@@ -553,13 +600,14 @@ async function refresh(httpClient2) {
553
600
  } catch (err) {
554
601
  if (err instanceof HttpError) {
555
602
  return nok(err);
556
- } else {
557
- return nok(new HttpError("Unknown error during refresh", 0, {
603
+ }
604
+ return nok(
605
+ new HttpError("Unknown error during refresh", 0, {
558
606
  name: "Error",
559
607
  message: JSON.stringify(err),
560
608
  status: 500
561
- }));
562
- }
609
+ })
610
+ );
563
611
  }
564
612
  }
565
613
  var httpClient = new AutoRefreshDecorator(new FetchHttpClient(), refresh);
@@ -604,6 +652,46 @@ var MockHttpClient = class {
604
652
  }
605
653
  };
606
654
 
655
+ // src/feature/auth/application/use-case/get-authenticated-user-use-case.ts
656
+ var GetAuthenticatedUserUseCase = class {
657
+ constructor(authProvider) {
658
+ this.authProvider = authProvider;
659
+ }
660
+ execute() {
661
+ return this.authProvider.getAuthenticatedUser();
662
+ }
663
+ };
664
+
665
+ // src/feature/auth/application/use-case/login-user-use-case.ts
666
+ var LoginUserUseCase = class {
667
+ constructor(authProvider) {
668
+ this.authProvider = authProvider;
669
+ }
670
+ execute(email, password) {
671
+ return this.authProvider.login(email, password);
672
+ }
673
+ };
674
+
675
+ // src/feature/auth/application/use-case/logout-user-use-case.ts
676
+ var LogoutUserUseCase = class {
677
+ constructor(authProvider) {
678
+ this.authProvider = authProvider;
679
+ }
680
+ execute() {
681
+ return this.authProvider.logout();
682
+ }
683
+ };
684
+
685
+ // src/feature/auth/application/use-case/register-user-use-case.ts
686
+ var RegisterUserUseCase = class {
687
+ constructor(authProvider) {
688
+ this.authProvider = authProvider;
689
+ }
690
+ execute(email, password, attributes) {
691
+ return this.authProvider.register(email, password, attributes);
692
+ }
693
+ };
694
+
607
695
  // src/feature/auth/infra/http-cookie-auth-provider.ts
608
696
  import { nok as nok2, ok as ok2 } from "@hexdspace/util";
609
697
  var HttpCookieAuthProvider = class {
@@ -617,11 +705,11 @@ var HttpCookieAuthProvider = class {
617
705
  } catch (err) {
618
706
  if (isUnauthorizedError(err)) {
619
707
  return ok2(null);
620
- } else if (err instanceof Error) {
708
+ }
709
+ if (err instanceof Error) {
621
710
  return nok2(err);
622
- } else {
623
- return nok2(new Error("Unknown error during authentication"));
624
711
  }
712
+ return nok2(new Error("Unknown error during authentication"));
625
713
  }
626
714
  }
627
715
  async login(email, password) {
@@ -633,24 +721,23 @@ var HttpCookieAuthProvider = class {
633
721
  } catch (err) {
634
722
  if (err instanceof Error) {
635
723
  return nok2(err);
636
- } else {
637
- return nok2(new Error("Unknown error during authentication"));
638
724
  }
725
+ return nok2(new Error("Unknown error during authentication"));
639
726
  }
640
727
  }
641
728
  async register(email, password, attributes) {
642
729
  try {
643
- const res = await this.httpClient.post(
644
- "/auth/register",
645
- { email, password, ...attributes ?? {} }
646
- );
730
+ const res = await this.httpClient.post("/auth/register", {
731
+ email,
732
+ password,
733
+ ...attributes ?? {}
734
+ });
647
735
  return ok2(res.data);
648
736
  } catch (err) {
649
737
  if (err instanceof Error) {
650
738
  return nok2(err);
651
- } else {
652
- return nok2(new Error("Unknown error during authentication"));
653
739
  }
740
+ return nok2(new Error("Unknown error during authentication"));
654
741
  }
655
742
  }
656
743
  async logout() {
@@ -660,9 +747,8 @@ var HttpCookieAuthProvider = class {
660
747
  } catch (err) {
661
748
  if (err instanceof Error) {
662
749
  return nok2(err);
663
- } else {
664
- return nok2(new Error("Unknown error during logout"));
665
750
  }
751
+ return nok2(new Error("Unknown error during logout"));
666
752
  }
667
753
  }
668
754
  };
@@ -670,46 +756,6 @@ function isUnauthorizedError(error) {
670
756
  return error instanceof HttpError && error.status === 401;
671
757
  }
672
758
 
673
- // src/feature/auth/application/use-case/login-user-use-case.ts
674
- var LoginUserUseCase = class {
675
- constructor(authProvider) {
676
- this.authProvider = authProvider;
677
- }
678
- execute(email, password) {
679
- return this.authProvider.login(email, password);
680
- }
681
- };
682
-
683
- // src/feature/auth/application/use-case/logout-user-use-case.ts
684
- var LogoutUserUseCase = class {
685
- constructor(authProvider) {
686
- this.authProvider = authProvider;
687
- }
688
- execute() {
689
- return this.authProvider.logout();
690
- }
691
- };
692
-
693
- // src/feature/auth/application/use-case/register-user-use-case.ts
694
- var RegisterUserUseCase = class {
695
- constructor(authProvider) {
696
- this.authProvider = authProvider;
697
- }
698
- execute(email, password, attributes) {
699
- return this.authProvider.register(email, password, attributes);
700
- }
701
- };
702
-
703
- // src/feature/auth/application/use-case/get-authenticated-user-use-case.ts
704
- var GetAuthenticatedUserUseCase = class {
705
- constructor(authProvider) {
706
- this.authProvider = authProvider;
707
- }
708
- execute() {
709
- return this.authProvider.getAuthenticatedUser();
710
- }
711
- };
712
-
713
759
  // src/feature/auth/interface/controller/auth-controller.ts
714
760
  var AuthController = class {
715
761
  constructor(loginUser, logoutUser, registerUser, getAuthenticatedUser) {
@@ -732,12 +778,7 @@ var AuthController = class {
732
778
  }
733
779
  };
734
780
  var createAuthController = controllerFactory(
735
- (deps) => new AuthController(
736
- deps.loginUser,
737
- deps.logoutUser,
738
- deps.registerUser,
739
- deps.getAuthenticatedUser
740
- ),
781
+ (deps) => new AuthController(deps.loginUser, deps.logoutUser, deps.registerUser, deps.getAuthenticatedUser),
741
782
  (overrides) => {
742
783
  const httpClient2 = overrides.httpClient ?? httpClient;
743
784
  const authProvider = overrides.authProvider ?? new HttpCookieAuthProvider(httpClient2);
@@ -759,24 +800,6 @@ import { useContext as useContext2 } from "react";
759
800
  // src/feature/auth/interface/web/react/AuthProvider.tsx
760
801
  import { createContext as createContext2, useEffect as useEffect2, useReducer } from "react";
761
802
 
762
- // src/feature/auth/interface/web/react/state/auth-reducer.ts
763
- function authStateReducer(_state, action) {
764
- switch (action.type) {
765
- case "REQUEST":
766
- return { status: "loading" };
767
- case "SUCCESS":
768
- return { status: "unauthenticated", message: action.message };
769
- case "FAILED":
770
- return { status: "error", error: action.error };
771
- case "LOGOUT":
772
- return { status: "unauthenticated" };
773
- case "COMPLETE":
774
- return { status: "authenticated", user: action.user };
775
- default:
776
- throw new Error(`Unknown state: ${JSON.stringify(action)}`);
777
- }
778
- }
779
-
780
803
  // src/feature/auth/interface/web/react/hook/useAuthController.tsx
781
804
  import { useContext } from "react";
782
805
 
@@ -797,6 +820,24 @@ function useAuthController() {
797
820
  return authController2;
798
821
  }
799
822
 
823
+ // src/feature/auth/interface/web/react/state/auth-reducer.ts
824
+ function authStateReducer(_state, action) {
825
+ switch (action.type) {
826
+ case "REQUEST":
827
+ return { status: "loading" };
828
+ case "SUCCESS":
829
+ return { status: "unauthenticated", message: action.message };
830
+ case "FAILED":
831
+ return { status: "error", error: action.error };
832
+ case "LOGOUT":
833
+ return { status: "unauthenticated" };
834
+ case "COMPLETE":
835
+ return { status: "authenticated", user: action.user };
836
+ default:
837
+ throw new Error(`Unknown state: ${JSON.stringify(action)}`);
838
+ }
839
+ }
840
+
800
841
  // src/feature/auth/interface/web/react/AuthProvider.tsx
801
842
  import { jsx as jsx4 } from "react/jsx-runtime";
802
843
  var AuthStateCtx = createContext2(null);
@@ -820,7 +861,7 @@ function AuthProvider({ children }) {
820
861
  }
821
862
  };
822
863
  void fetchActiveUser();
823
- }, [dispatch, authController2]);
864
+ }, [authController2]);
824
865
  return /* @__PURE__ */ jsx4(AuthDispatchCtx.Provider, { value: dispatch, children: /* @__PURE__ */ jsx4(AuthStateCtx.Provider, { value: state, children }) });
825
866
  }
826
867
 
@@ -850,21 +891,27 @@ function useAuthDispatch() {
850
891
  function useAuthActions() {
851
892
  const dispatch = useAuthDispatch();
852
893
  const authController2 = useAuthController();
853
- const login = useCallback2(async (email, password) => {
854
- dispatch({ type: "REQUEST" });
855
- const res = await authController2.login(email, password);
856
- dispatchLoginResult(res, dispatch);
857
- return res;
858
- }, [dispatch, authController2]);
894
+ const login = useCallback2(
895
+ async (email, password) => {
896
+ dispatch({ type: "REQUEST" });
897
+ const res = await authController2.login(email, password);
898
+ dispatchLoginResult(res, dispatch);
899
+ return res;
900
+ },
901
+ [dispatch, authController2]
902
+ );
859
903
  const logout = useCallback2(() => {
860
904
  authController2.logout().then(() => dispatch({ type: "LOGOUT" }));
861
905
  }, [dispatch, authController2]);
862
- const register = useCallback2(async (email, password, attributes) => {
863
- dispatch({ type: "REQUEST" });
864
- const res = await authController2.register(email, password, attributes);
865
- dispatchRegisterResult(res, dispatch);
866
- return res;
867
- }, [dispatch, authController2]);
906
+ const register = useCallback2(
907
+ async (email, password, attributes) => {
908
+ dispatch({ type: "REQUEST" });
909
+ const res = await authController2.register(email, password, attributes);
910
+ dispatchRegisterResult(res, dispatch);
911
+ return res;
912
+ },
913
+ [dispatch, authController2]
914
+ );
868
915
  return { login, logout, register };
869
916
  }
870
917
  function dispatchLoginResult(res, dispatch) {
@@ -897,42 +944,9 @@ function useAuthedUser() {
897
944
  return auth.user;
898
945
  }
899
946
 
900
- // src/feature/auth/interface/web/react/AuthFormInputField.tsx
901
- import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
902
- var inputLabelStyles = {
903
- display: "block",
904
- fontSize: "small",
905
- fontWeight: "bolder",
906
- marginBottom: "4px"
907
- };
908
- var inputFieldStyles = {
909
- display: "block",
910
- width: "100%",
911
- padding: "0.5rem 0.75rem"
912
- };
913
- var AuthFormInputField = ({ id, label, type, value, onChange, placeholder, className }) => {
914
- return /* @__PURE__ */ jsxs2("div", { children: [
915
- /* @__PURE__ */ jsx5("label", { htmlFor: id, style: inputLabelStyles, children: label }),
916
- /* @__PURE__ */ jsx5(
917
- "input",
918
- {
919
- id,
920
- name: id,
921
- type,
922
- required: true,
923
- value,
924
- onChange,
925
- className,
926
- placeholder,
927
- style: inputFieldStyles
928
- }
929
- )
930
- ] });
931
- };
932
-
933
947
  // src/feature/auth/interface/web/react/auth-route-guards.tsx
934
948
  import { Navigate, Outlet, useLocation } from "react-router-dom";
935
- import { Fragment, jsx as jsx6 } from "react/jsx-runtime";
949
+ import { Fragment, jsx as jsx5 } from "react/jsx-runtime";
936
950
  function RequireAuth({
937
951
  guarded,
938
952
  loadingPlaceholder,
@@ -943,18 +957,18 @@ function RequireAuth({
943
957
  const auth = useAuth();
944
958
  const location = useLocation();
945
959
  if (auth.status === "loading") {
946
- return /* @__PURE__ */ jsx6(Fragment, { children: loadingPlaceholder ?? null });
960
+ return /* @__PURE__ */ jsx5(Fragment, { children: loadingPlaceholder ?? null });
947
961
  }
948
962
  if (auth.status === "error") {
949
- return /* @__PURE__ */ jsx6(Fragment, { children: errorPlaceholder ?? null });
963
+ return /* @__PURE__ */ jsx5(Fragment, { children: errorPlaceholder ?? null });
950
964
  }
951
965
  if (auth.status === "unauthenticated") {
952
966
  if (unauthenticatedRedirectTo) {
953
- return /* @__PURE__ */ jsx6(Navigate, { to: unauthenticatedRedirectTo, replace: true, state: { from: location } });
967
+ return /* @__PURE__ */ jsx5(Navigate, { to: unauthenticatedRedirectTo, replace: true, state: { from: location } });
954
968
  }
955
- return /* @__PURE__ */ jsx6(Fragment, { children: unauthenticatedPlaceholder ?? null });
969
+ return /* @__PURE__ */ jsx5(Fragment, { children: unauthenticatedPlaceholder ?? null });
956
970
  }
957
- return guarded ? /* @__PURE__ */ jsx6(Fragment, { children: guarded }) : /* @__PURE__ */ jsx6(Outlet, {});
971
+ return guarded ? /* @__PURE__ */ jsx5(Fragment, { children: guarded }) : /* @__PURE__ */ jsx5(Outlet, {});
958
972
  }
959
973
  function RedirectIfAuthed({
960
974
  redirectTo,
@@ -965,18 +979,18 @@ function RedirectIfAuthed({
965
979
  }) {
966
980
  const auth = useAuth();
967
981
  if (auth.status === "loading") {
968
- return /* @__PURE__ */ jsx6(Fragment, { children: loadingPlaceholder ?? null });
982
+ return /* @__PURE__ */ jsx5(Fragment, { children: loadingPlaceholder ?? null });
969
983
  }
970
984
  if (auth.status === "error") {
971
- return /* @__PURE__ */ jsx6(Fragment, { children: errorPlaceholder ?? loadingPlaceholder ?? null });
985
+ return /* @__PURE__ */ jsx5(Fragment, { children: errorPlaceholder ?? loadingPlaceholder ?? null });
972
986
  }
973
987
  if (auth.status === "authenticated") {
974
988
  if (redirectTo) {
975
- return /* @__PURE__ */ jsx6(Navigate, { to: redirectTo, replace: true });
989
+ return /* @__PURE__ */ jsx5(Navigate, { to: redirectTo, replace: true });
976
990
  }
977
- return /* @__PURE__ */ jsx6(Fragment, { children: authenticatedPlaceholder ?? null });
991
+ return /* @__PURE__ */ jsx5(Fragment, { children: authenticatedPlaceholder ?? null });
978
992
  }
979
- return nonAuthedPlaceholder ? /* @__PURE__ */ jsx6(Fragment, { children: nonAuthedPlaceholder }) : /* @__PURE__ */ jsx6(Outlet, {});
993
+ return nonAuthedPlaceholder ? /* @__PURE__ */ jsx5(Fragment, { children: nonAuthedPlaceholder }) : /* @__PURE__ */ jsx5(Outlet, {});
980
994
  }
981
995
 
982
996
  // src/feature/auth/infra/mock-auth-http-client.ts
@@ -1052,9 +1066,9 @@ var MockAuthHttpClient = class extends MockHttpClient {
1052
1066
  };
1053
1067
 
1054
1068
  // src/ui/components/Button.tsx
1055
- import * as React3 from "react";
1056
- import { Slot } from "radix-ui";
1057
1069
  import { cva } from "class-variance-authority";
1070
+ import { Slot } from "radix-ui";
1071
+ import * as React from "react";
1058
1072
 
1059
1073
  // src/ui/utils/cn.ts
1060
1074
  import { clsx } from "clsx";
@@ -1064,23 +1078,22 @@ function cn(...inputs) {
1064
1078
  }
1065
1079
 
1066
1080
  // src/ui/components/Button.tsx
1067
- import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1081
+ import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
1068
1082
  var buttonBase = cn(
1069
1083
  "relative isolate inline-flex items-center justify-center gap-2 leading-none text-sm font-medium select-none cursor-pointer",
1070
1084
  "rounded-[var(--radius-btn)]",
1071
- "transition-[background-color,color,box-shadow,transform] duration-150 ease",
1085
+ "transition-[background-color,color,box-shadow,transform] duration-[var(--motion-med)] ease",
1072
1086
  "focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--focus)]",
1073
1087
  "[--state-hover:color-mix(in_oklab,currentColor,transparent_92%)]",
1074
1088
  "[--state-active:color-mix(in_oklab,currentColor,transparent_86%)]",
1075
- "after:content-[''] after:absolute after:inset-0 after:rounded-[inherit] after:bg-[color:var(--state-hover)] after:opacity-0 after:pointer-events-none after:transition-opacity after:duration-100 after:ease",
1076
- "hover:after:opacity-100 active:after:bg-[color:var(--state-active)] active:after:opacity-100",
1077
- "disabled:opacity-50 disabled:pointer-events-none disabled:cursor-not-allowed"
1089
+ "after:content-[''] after:absolute after:inset-0 after:rounded-[inherit] after:bg-[color:var(--state-hover)] after:opacity-0 after:pointer-events-none after:transition-opacity after:duration-[var(--motion-fast)] after:ease",
1090
+ "hover:after:opacity-100 active:after:bg-[color:var(--state-active)] active:after:opacity-100"
1078
1091
  );
1079
1092
  var flatChrome = cn();
1080
1093
  var pushChrome = cn(
1081
1094
  "border-b-[3px]",
1082
1095
  "transition-all",
1083
- "duration-100",
1096
+ "duration-[var(--motion-fast)]",
1084
1097
  "ease-out",
1085
1098
  "shadow-[0_2px_4px_rgba(0,0,0,0.28),0_8px_16px_rgba(0,0,0,0.14)]",
1086
1099
  "hover:shadow-[0_3px_6px_rgba(0,0,0,0.30),0_12px_22px_rgba(0,0,0,0.18)]",
@@ -1091,18 +1104,14 @@ var softChrome = cn(
1091
1104
  "font-thin",
1092
1105
  "border",
1093
1106
  "border-[color:color-mix(in_oklab,var(--border),transparent_80%)]",
1094
- "shadow-[0_0_8px_2px_rgba(255,255,255,0.35)_inset,0_3px_8px_rgba(0,0,0,0.14)]"
1107
+ "shadow-[0_0_2px_1px_rgba(255,255,255,0.35)_inset,0_2px_4px_rgba(0,0,0,0.14)]"
1095
1108
  );
1096
1109
  var insetChrome = cn(
1097
1110
  "border",
1098
1111
  "border-[color:color-mix(in_oklab,var(--border),transparent_35%)]",
1099
1112
  "shadow-[inset_0_2px_6px_rgba(0,0,0,0.18)]"
1100
1113
  );
1101
- var glassChrome = cn(
1102
- "backdrop-blur-[6px]",
1103
- "border",
1104
- "shadow-[0_8px_18px_rgba(0,0,0,0.12)]"
1105
- );
1114
+ var glassChrome = cn("backdrop-blur-[2px]", "border", "shadow-[0_8px_18px_rgba(0,0,0,0.12)]");
1106
1115
  var glowChrome = cn(
1107
1116
  "border",
1108
1117
  "shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_40%),0_6px_16px_color-mix(in_oklab,var(--border),transparent_70%)]",
@@ -1118,8 +1127,8 @@ var hairlineChrome = cn(
1118
1127
  var buttonVariants = cva(buttonBase, {
1119
1128
  variants: {
1120
1129
  variant: {
1121
- primary: "bg-[color:var(--brand)] text-[color:var(--text-inverted)]",
1122
- accent: "bg-[color:var(--accent)] text-[color:var(--text-inverted)]",
1130
+ primary: "bg-[color:var(--brand)]",
1131
+ accent: "bg-[color:var(--accent)]",
1123
1132
  secondary: "border border-[color:var(--border)] bg-[color:var(--surface-2)]",
1124
1133
  outline: "bg-transparent border border-[color:var(--border)] shadow-none",
1125
1134
  ghost: "bg-transparent shadow-none",
@@ -1151,60 +1160,299 @@ var buttonVariants = cva(buttonBase, {
1151
1160
  { variant: "link", className: "border-0" },
1152
1161
  { chrome: "soft", className: "text-[color:var(--text-1)]" },
1153
1162
  { chrome: "glass", className: "text-[color:var(--text-1)]" },
1154
- { chrome: "push", variant: "primary", className: "border-b-[color:var(--brand-90)]" },
1155
- { chrome: "push", variant: "accent", className: "border-b-[color:var(--accent-90)]" },
1156
- { chrome: "push", variant: "secondary", className: "border-b-[color:color-mix(in oklab, var(--border), transparent 50%)]" },
1157
- { chrome: "push", variant: "outline", className: "border-b-[color:color-mix(in oklab, var(--border), transparent 50%)]" },
1163
+ { chrome: "push", variant: "primary", className: "border-b-[color:var(--brand-strong)]" },
1164
+ { chrome: "push", variant: "accent", className: "border-b-[color:var(--accent-strong)]" },
1165
+ {
1166
+ chrome: "push",
1167
+ variant: "secondary",
1168
+ className: "border-b-[color:color-mix(in_oklab,var(--border),transparent 50%)]"
1169
+ },
1170
+ {
1171
+ chrome: "push",
1172
+ variant: "outline",
1173
+ className: "border-b-[color:color-mix(in_oklab,var(--border),transparent 50%)]"
1174
+ },
1158
1175
  { chrome: "push", variant: "ghost", className: "border-b-transparent shadow-none" },
1159
1176
  { chrome: "push", variant: "success", className: "border-b-[color:var(--success-80)]" },
1160
1177
  { chrome: "push", variant: "info", className: "border-b-[color:var(--info-80)]" },
1161
1178
  { chrome: "push", variant: "warning", className: "border-b-[color:var(--warning-80)]" },
1162
1179
  { chrome: "push", variant: "danger", className: "border-b-[color:var(--danger-80)]" },
1163
1180
  { chrome: "push", variant: "link", className: "border-b-0 shadow-none" },
1164
- { chrome: "soft", variant: "primary", className: cn("bg-[color:color-mix(in_oklab,var(--brand),transparent_70%)]", "border-[color:color-mix(in_oklab,var(--brand),transparent_85%)]", "shadow-[0_0_8px_2px_rgba(255,255,255,0.2)_inset,0_3px_8px_color-mix(in_oklab,var(--brand),transparent_70%)]") },
1165
- { chrome: "soft", variant: "accent", className: cn("bg-[color:color-mix(in_oklab,var(--accent),transparent_70%)]", "border-[color:color-mix(in_oklab,var(--accent),transparent_85%)]", "shadow-[0_0_8px_2px_rgba(255,255,255,0.2)_inset,0_3px_8px_color-mix(in_oklab,var(--accent),transparent_70%)]") },
1166
- { chrome: "soft", variant: "secondary", className: cn("bg-[color:color-mix(in_oklab,var(--surface-2),transparent_25%)]", "border-[color:color-mix(in_oklab,var(--border),transparent_45%)]", "shadow-[0_0_8px_2px_rgba(255,255,255,0.1)_inset,0_3px_8px_color-mix(in_oklab,var(--border),transparent_70%)]") },
1167
- { chrome: "soft", variant: "outline", className: cn("border-[color:color-mix(in_oklab,var(--border),transparent_45%)]", "shadow-[0_0_8px_2px_rgba(255,255,255,0.1)_inset,0_3px_8px_color-mix(in_oklab,var(--border),transparent_70%)]") },
1168
- { chrome: "soft", variant: "ghost", className: "shadow-[0_3px_8px_color-mix(in_oklab,var(--border),transparent_75%)]" },
1169
- { chrome: "soft", variant: "success", className: cn("bg-[color:color-mix(in_oklab,var(--success),transparent_70%)]", "border-[color:color-mix(in_oklab,var(--success),transparent_75%)]", "shadow-[0_0_8px_2px_rgba(255,255,255,0.2)_inset,0_3px_8px_color-mix(in_oklab,var(--success),transparent_70%)]") },
1170
- { chrome: "soft", variant: "info", className: cn("bg-[color:color-mix(in_oklab,var(--info),transparent_70%)]", "border-[color:color-mix(in_oklab,var(--info),transparent_75%)]", "shadow-[0_0_8px_2px_rgba(255,255,255,0.2)_inset,0_3px_8px_color-mix(in_oklab,var(--info),transparent_70%)]") },
1171
- { chrome: "soft", variant: "warning", className: cn("bg-[color:color-mix(in_oklab,var(--warning),transparent_70%)]", "border-[color:color-mix(in_oklab,var(--warning),transparent_75%)]", "shadow-[0_0_8px_2px_rgba(255,255,255,0.2)_inset,0_3px_8px_color-mix(in_oklab,var(--warning),transparent_70%)]") },
1172
- { chrome: "soft", variant: "danger", className: cn("bg-[color:color-mix(in_oklab,var(--danger),transparent_70%)]", "border-[color:color-mix(in_oklab,var(--danger),transparent_75%)]", "shadow-[0_0_8px_2px_rgba(255,255,255,0.2)_inset,0_3px_8px_color-mix(in_oklab,var(--danger),transparent_70%)]") },
1173
- { chrome: "soft", variant: "link", className: cn("text-[color:var(--link)]", "shadow-[0_3px_8px_color-mix(in_oklab,var(--link),transparent_75%)]") },
1174
- { chrome: "glass", variant: "primary", className: cn("bg-[color:color-mix(in_oklab,var(--brand),transparent_65%)]", "border-[color:var(--brand)]") },
1175
- { chrome: "glass", variant: "accent", className: cn("bg-[color:color-mix(in_oklab,var(--accent),transparent_65%)]", "border-[color:var(--accent)]") },
1176
- { chrome: "glass", variant: "secondary", className: cn("bg-[color:color-mix(in_oklab,var(--surface-2),transparent_35%)]", "border-[color:color-mix(in_oklab,var(--border),transparent_70%)]") },
1181
+ {
1182
+ chrome: "soft",
1183
+ variant: "primary",
1184
+ className: cn(
1185
+ "bg-[color:color-mix(in_oklab,var(--brand),transparent_70%)]",
1186
+ "border-[color:color-mix(in_oklab,var(--brand),transparent_85%)]",
1187
+ "shadow-[0_0_2px_1px_rgba(255,255,255,0.2)_inset,0_2px_4px_color-mix(in_oklab,var(--brand),transparent_70%)]"
1188
+ )
1189
+ },
1190
+ {
1191
+ chrome: "soft",
1192
+ variant: "accent",
1193
+ className: cn(
1194
+ "bg-[color:color-mix(in_oklab,var(--accent),transparent_70%)]",
1195
+ "border-[color:color-mix(in_oklab,var(--accent),transparent_85%)]",
1196
+ "shadow-[0_0_2px_1px_rgba(255,255,255,0.2)_inset,0_2px_4px_color-mix(in_oklab,var(--accent),transparent_70%)]"
1197
+ )
1198
+ },
1199
+ {
1200
+ chrome: "soft",
1201
+ variant: "secondary",
1202
+ className: cn(
1203
+ "bg-[color:color-mix(in_oklab,var(--surface-2),transparent_25%)]",
1204
+ "border-[color:color-mix(in_oklab,var(--border),transparent_45%)]",
1205
+ "shadow-[0_0_2px_1px_rgba(255,255,255,0.1)_inset,0_2px_4px_color-mix(in_oklab,var(--border),transparent_70%)]"
1206
+ )
1207
+ },
1208
+ {
1209
+ chrome: "soft",
1210
+ variant: "outline",
1211
+ className: cn(
1212
+ "border-[color:color-mix(in_oklab,var(--border),transparent_45%)]",
1213
+ "shadow-[0_0_2px_1px_rgba(255,255,255,0.1)_inset,0_2px_4px_color-mix(in_oklab,var(--border),transparent_70%)]"
1214
+ )
1215
+ },
1216
+ {
1217
+ chrome: "soft",
1218
+ variant: "ghost",
1219
+ className: "shadow-[0_2px_4px_color-mix(in_oklab,var(--border),transparent_75%)]"
1220
+ },
1221
+ {
1222
+ chrome: "soft",
1223
+ variant: "success",
1224
+ className: cn(
1225
+ "bg-[color:color-mix(in_oklab,var(--success),transparent_70%)]",
1226
+ "border-[color:color-mix(in_oklab,var(--success),transparent_75%)]",
1227
+ "shadow-[0_0_2px_1px_rgba(255,255,255,0.2)_inset,0_2px_4px_color-mix(in_oklab,var(--success),transparent_70%)]"
1228
+ )
1229
+ },
1230
+ {
1231
+ chrome: "soft",
1232
+ variant: "info",
1233
+ className: cn(
1234
+ "bg-[color:color-mix(in_oklab,var(--info),transparent_70%)]",
1235
+ "border-[color:color-mix(in_oklab,var(--info),transparent_75%)]",
1236
+ "shadow-[0_0_2px_1px_rgba(255,255,255,0.2)_inset,0_2px_4px_color-mix(in_oklab,var(--info),transparent_70%)]"
1237
+ )
1238
+ },
1239
+ {
1240
+ chrome: "soft",
1241
+ variant: "warning",
1242
+ className: cn(
1243
+ "bg-[color:color-mix(in_oklab,var(--warning),transparent_70%)]",
1244
+ "border-[color:color-mix(in_oklab,var(--warning),transparent_75%)]",
1245
+ "shadow-[0_0_2px_1px_rgba(255,255,255,0.2)_inset,0_2px_4px_color-mix(in_oklab,var(--warning),transparent_70%)]"
1246
+ )
1247
+ },
1248
+ {
1249
+ chrome: "soft",
1250
+ variant: "danger",
1251
+ className: cn(
1252
+ "bg-[color:color-mix(in_oklab,var(--danger),transparent_70%)]",
1253
+ "border-[color:color-mix(in_oklab,var(--danger),transparent_75%)]",
1254
+ "shadow-[0_0_2px_1px_rgba(255,255,255,0.2)_inset,0_2px_4px_color-mix(in_oklab,var(--danger),transparent_70%)]"
1255
+ )
1256
+ },
1257
+ {
1258
+ chrome: "soft",
1259
+ variant: "link",
1260
+ className: cn(
1261
+ "text-[color:var(--link)]",
1262
+ "shadow-[0_2px_4px_color-mix(in_oklab,var(--link),transparent_75%)]"
1263
+ )
1264
+ },
1265
+ {
1266
+ chrome: "glass",
1267
+ variant: "primary",
1268
+ className: cn("bg-[color:color-mix(in_oklab,var(--brand),transparent_65%)]", "border-[color:var(--brand)]")
1269
+ },
1270
+ {
1271
+ chrome: "glass",
1272
+ variant: "accent",
1273
+ className: cn(
1274
+ "bg-[color:color-mix(in_oklab,var(--accent),transparent_65%)]",
1275
+ "border-[color:var(--accent)]"
1276
+ )
1277
+ },
1278
+ {
1279
+ chrome: "glass",
1280
+ variant: "secondary",
1281
+ className: cn(
1282
+ "bg-[color:color-mix(in_oklab,var(--surface-2),transparent_35%)]",
1283
+ "border-[color:color-mix(in_oklab,var(--border),transparent_70%)]"
1284
+ )
1285
+ },
1177
1286
  { chrome: "glass", variant: "outline", className: "" },
1178
1287
  { chrome: "glass", variant: "ghost", className: "" },
1179
- { chrome: "glass", variant: "success", className: cn("bg-[color:color-mix(in_oklab,var(--success),transparent_65%)]", "border-[color:var(--success)]") },
1180
- { chrome: "glass", variant: "info", className: cn("bg-[color:color-mix(in_oklab,var(--info),transparent_65%)]", "border-[color:var(--info)]") },
1181
- { chrome: "glass", variant: "warning", className: cn("bg-[color:color-mix(in_oklab,var(--warning),transparent_65%)]", "border-[color:var(--warning)]") },
1182
- { chrome: "glass", variant: "danger", className: cn("bg-[color:color-mix(in_oklab,var(--danger),transparent_65%)]", "border-[color:var(--danger)]") },
1288
+ {
1289
+ chrome: "glass",
1290
+ variant: "success",
1291
+ className: cn(
1292
+ "bg-[color:color-mix(in_oklab,var(--success),transparent_65%)]",
1293
+ "border-[color:var(--success)]"
1294
+ )
1295
+ },
1296
+ {
1297
+ chrome: "glass",
1298
+ variant: "info",
1299
+ className: cn("bg-[color:color-mix(in_oklab,var(--info),transparent_65%)]", "border-[color:var(--info)]")
1300
+ },
1301
+ {
1302
+ chrome: "glass",
1303
+ variant: "warning",
1304
+ className: cn(
1305
+ "bg-[color:color-mix(in_oklab,var(--warning),transparent_65%)]",
1306
+ "border-[color:var(--warning)]"
1307
+ )
1308
+ },
1309
+ {
1310
+ chrome: "glass",
1311
+ variant: "danger",
1312
+ className: cn(
1313
+ "bg-[color:color-mix(in_oklab,var(--danger),transparent_65%)]",
1314
+ "border-[color:var(--danger)]"
1315
+ )
1316
+ },
1183
1317
  { chrome: "glass", variant: "link", className: "text-[color:var(--link)]" },
1184
- { chrome: "glow", variant: "primary", className: cn("border-[color:var(--brand)]", "shadow-[0_0_0_1px_color-mix(in_oklab,var(--brand),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--brand),transparent_55%)]", "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--brand),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--brand),transparent_40%)]", "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--brand),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--brand),transparent_70%)]", "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--brand),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--brand),transparent_55%)]") },
1185
- { chrome: "glow", variant: "accent", className: cn("border-[color:var(--accent)]", "shadow-[0_0_0_1px_color-mix(in_oklab,var(--accent),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--accent),transparent_55%)]", "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--accent),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--accent),transparent_40%)]", "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--accent),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--accent),transparent_70%)]", "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--accent),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--accent),transparent_55%)]") },
1186
- { chrome: "glow", variant: "secondary", className: cn("border-[color:color-mix(in_oklab,var(--border),transparent_20%)]", "shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--border),transparent_60%)]", "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_15%),0_14px_34px_color-mix(in_oklab,var(--border),transparent_45%)]", "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--border),transparent_75%)]", "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_20%),0_12px_30px_color-mix(in_oklab,var(--border),transparent_60%)]") },
1187
- { chrome: "glow", variant: "outline", className: cn("border-[color:color-mix(in_oklab,var(--border),transparent_20%)]", "shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--border),transparent_60%)]", "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_15%),0_14px_34px_color-mix(in_oklab,var(--border),transparent_45%)]", "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--border),transparent_75%)]", "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_20%),0_12px_30px_color-mix(in_oklab,var(--border),transparent_60%)]") },
1318
+ {
1319
+ chrome: "glow",
1320
+ variant: "primary",
1321
+ className: cn(
1322
+ "border-[color:var(--brand)]",
1323
+ "shadow-[0_0_0_1px_color-mix(in_oklab,var(--brand),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--brand),transparent_55%)]",
1324
+ "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--brand),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--brand),transparent_40%)]",
1325
+ "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--brand),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--brand),transparent_70%)]",
1326
+ "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--brand),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--brand),transparent_55%)]"
1327
+ )
1328
+ },
1329
+ {
1330
+ chrome: "glow",
1331
+ variant: "accent",
1332
+ className: cn(
1333
+ "border-[color:var(--accent)]",
1334
+ "shadow-[0_0_0_1px_color-mix(in_oklab,var(--accent),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--accent),transparent_55%)]",
1335
+ "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--accent),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--accent),transparent_40%)]",
1336
+ "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--accent),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--accent),transparent_70%)]",
1337
+ "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--accent),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--accent),transparent_55%)]"
1338
+ )
1339
+ },
1340
+ {
1341
+ chrome: "glow",
1342
+ variant: "secondary",
1343
+ className: cn(
1344
+ "border-[color:color-mix(in_oklab,var(--border),transparent_20%)]",
1345
+ "shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--border),transparent_60%)]",
1346
+ "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_15%),0_14px_34px_color-mix(in_oklab,var(--border),transparent_45%)]",
1347
+ "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--border),transparent_75%)]",
1348
+ "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_20%),0_12px_30px_color-mix(in_oklab,var(--border),transparent_60%)]"
1349
+ )
1350
+ },
1351
+ {
1352
+ chrome: "glow",
1353
+ variant: "outline",
1354
+ className: cn(
1355
+ "border-[color:color-mix(in_oklab,var(--border),transparent_20%)]",
1356
+ "shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--border),transparent_60%)]",
1357
+ "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_15%),0_14px_34px_color-mix(in_oklab,var(--border),transparent_45%)]",
1358
+ "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--border),transparent_75%)]",
1359
+ "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--border),transparent_20%),0_12px_30px_color-mix(in_oklab,var(--border),transparent_60%)]"
1360
+ )
1361
+ },
1188
1362
  { chrome: "glow", variant: "ghost", className: "shadow-none border-transparent" },
1189
- { chrome: "glow", variant: "success", className: cn("border-[color:var(--success)]", "shadow-[0_0_0_1px_color-mix(in_oklab,var(--success),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--success),transparent_55%)]", "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--success),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--success),transparent_40%)]", "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--success),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--success),transparent_70%)]", "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--success),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--success),transparent_55%)]") },
1190
- { chrome: "glow", variant: "info", className: cn("border-[color:var(--info)]", "shadow-[0_0_0_1px_color-mix(in_oklab,var(--info),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--info),transparent_55%)]", "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--info),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--info),transparent_40%)]", "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--info),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--info),transparent_70%)]", "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--info),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--info),transparent_55%)]") },
1191
- { chrome: "glow", variant: "warning", className: cn("border-[color:var(--warning)]", "shadow-[0_0_0_1px_color-mix(in_oklab,var(--warning),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--warning),transparent_55%)]", "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--warning),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--warning),transparent_40%)]", "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--warning),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--warning),transparent_70%)]", "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--warning),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--warning),transparent_55%)]") },
1192
- { chrome: "glow", variant: "danger", className: cn("border-[color:var(--danger)]", "shadow-[0_0_0_1px_color-mix(in_oklab,var(--danger),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--danger),transparent_55%)]", "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--danger),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--danger),transparent_40%)]", "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--danger),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--danger),transparent_70%)]", "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--danger),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--danger),transparent_55%)]") },
1363
+ {
1364
+ chrome: "glow",
1365
+ variant: "success",
1366
+ className: cn(
1367
+ "border-[color:var(--success)]",
1368
+ "shadow-[0_0_0_1px_color-mix(in_oklab,var(--success),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--success),transparent_55%)]",
1369
+ "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--success),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--success),transparent_40%)]",
1370
+ "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--success),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--success),transparent_70%)]",
1371
+ "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--success),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--success),transparent_55%)]"
1372
+ )
1373
+ },
1374
+ {
1375
+ chrome: "glow",
1376
+ variant: "info",
1377
+ className: cn(
1378
+ "border-[color:var(--info)]",
1379
+ "shadow-[0_0_0_1px_color-mix(in_oklab,var(--info),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--info),transparent_55%)]",
1380
+ "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--info),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--info),transparent_40%)]",
1381
+ "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--info),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--info),transparent_70%)]",
1382
+ "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--info),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--info),transparent_55%)]"
1383
+ )
1384
+ },
1385
+ {
1386
+ chrome: "glow",
1387
+ variant: "warning",
1388
+ className: cn(
1389
+ "border-[color:var(--warning)]",
1390
+ "shadow-[0_0_0_1px_color-mix(in_oklab,var(--warning),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--warning),transparent_55%)]",
1391
+ "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--warning),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--warning),transparent_40%)]",
1392
+ "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--warning),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--warning),transparent_70%)]",
1393
+ "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--warning),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--warning),transparent_55%)]"
1394
+ )
1395
+ },
1396
+ {
1397
+ chrome: "glow",
1398
+ variant: "danger",
1399
+ className: cn(
1400
+ "border-[color:var(--danger)]",
1401
+ "shadow-[0_0_0_1px_color-mix(in_oklab,var(--danger),transparent_20%),0_10px_26px_color-mix(in_oklab,var(--danger),transparent_55%)]",
1402
+ "hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--danger),transparent_10%),0_14px_34px_color-mix(in_oklab,var(--danger),transparent_40%)]",
1403
+ "dark:shadow-[0_0_0_1px_color-mix(in_oklab,var(--danger),transparent_30%),0_8px_22px_color-mix(in_oklab,var(--danger),transparent_70%)]",
1404
+ "dark:hover:shadow-[0_0_0_1px_color-mix(in_oklab,var(--danger),transparent_15%),0_12px_30px_color-mix(in_oklab,var(--danger),transparent_55%)]"
1405
+ )
1406
+ },
1193
1407
  { chrome: "glow", variant: "link", className: "text-[color:var(--link)] shadow-none border-transparent" },
1194
- { chrome: "hairline", variant: "primary", className: "border-[color:color-mix(in_oklab,var(--brand),transparent_20%)] text-[color:var(--brand)]" },
1195
- { chrome: "hairline", variant: "accent", className: "border-[color:color-mix(in_oklab,var(--accent),transparent_20%)] text-[color:var(--accent)]" },
1196
- { chrome: "hairline", variant: "secondary", className: "border-[color:color-mix(in_oklab,var(--border),transparent_20%)] text-[color:var(--text-1)]" },
1197
- { chrome: "hairline", variant: "outline", className: "border-[color:color-mix(in_oklab,var(--border),transparent_20%)] text-[color:var(--text-1)]" },
1408
+ {
1409
+ chrome: "hairline",
1410
+ variant: "primary",
1411
+ className: "border-[color:color-mix(in_oklab,var(--brand-contrast),transparent_20%)] text-[color:var(--brand-contrast)]"
1412
+ },
1413
+ {
1414
+ chrome: "hairline",
1415
+ variant: "accent",
1416
+ className: "border-[color:color-mix(in_oklab,var(--accent-contrast),transparent_20%)] text-[color:var(--accent-contrast)]"
1417
+ },
1418
+ {
1419
+ chrome: "hairline",
1420
+ variant: "secondary",
1421
+ className: "border-[color:color-mix(in_oklab,var(--border),transparent_20%)] text-[color:var(--text-1)]"
1422
+ },
1423
+ {
1424
+ chrome: "hairline",
1425
+ variant: "outline",
1426
+ className: "border-[color:color-mix(in_oklab,var(--border),transparent_20%)] text-[color:var(--text-1)]"
1427
+ },
1198
1428
  { chrome: "hairline", variant: "ghost", className: "border-transparent text-[color:var(--text-1)]" },
1199
- { chrome: "hairline", variant: "success", className: "border-[color:color-mix(in_oklab,var(--success),transparent_20%)] text-[color:var(--success)]" },
1200
- { chrome: "hairline", variant: "info", className: "border-[color:color-mix(in_oklab,var(--info),transparent_20%)] text-[color:var(--info)]" },
1201
- { chrome: "hairline", variant: "warning", className: "border-[color:color-mix(in_oklab,var(--warning),transparent_20%)] text-[color:var(--warning)]" },
1202
- { chrome: "hairline", variant: "danger", className: "border-[color:color-mix(in_oklab,var(--danger),transparent_20%)] text-[color:var(--danger)]" },
1429
+ {
1430
+ chrome: "hairline",
1431
+ variant: "success",
1432
+ className: "border-[color:color-mix(in_oklab,var(--success),transparent_20%)] text-[color:var(--success-contrast)]"
1433
+ },
1434
+ {
1435
+ chrome: "hairline",
1436
+ variant: "info",
1437
+ className: "border-[color:color-mix(in_oklab,var(--info),transparent_20%)] text-[color:var(--info-contrast)]"
1438
+ },
1439
+ {
1440
+ chrome: "hairline",
1441
+ variant: "warning",
1442
+ className: "border-[color:color-mix(in_oklab,var(--warning),transparent_20%)] text-[color:var(--warning-contrast)]"
1443
+ },
1444
+ {
1445
+ chrome: "hairline",
1446
+ variant: "danger",
1447
+ className: "border-[color:color-mix(in_oklab,var(--danger),transparent_20%)] text-[color:var(--danger-contrast)]"
1448
+ },
1203
1449
  { chrome: "hairline", variant: "link", className: "text-[color:var(--link)] border-transparent" }
1204
1450
  ],
1205
1451
  defaultVariants: { variant: "primary", size: "md", chrome: "flat", fullWidth: false }
1206
1452
  });
1207
- var Button = React3.forwardRef(
1453
+ var iconSlotBase = cn("inline-flex items-center justify-center", "shrink-0");
1454
+ var iconSlotReserve = "min-w-4 min-h-4";
1455
+ var Button = React.forwardRef(
1208
1456
  ({
1209
1457
  asChild = false,
1210
1458
  variant,
@@ -1216,6 +1464,8 @@ var Button = React3.forwardRef(
1216
1464
  disabled,
1217
1465
  leftIcon,
1218
1466
  rightIcon,
1467
+ reserveLeftIcon,
1468
+ reserveRightIcon,
1219
1469
  children,
1220
1470
  onClick,
1221
1471
  type,
@@ -1227,19 +1477,19 @@ var Button = React3.forwardRef(
1227
1477
  isDisabled && "opacity-50 pointer-events-none cursor-not-allowed",
1228
1478
  className
1229
1479
  );
1230
- const content = /* @__PURE__ */ jsxs3(Fragment2, { children: [
1231
- loading ? /* @__PURE__ */ jsx7(
1232
- "span",
1233
- {
1234
- "aria-hidden": "true",
1235
- className: "inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent"
1236
- }
1237
- ) : leftIcon,
1238
- children,
1239
- rightIcon
1240
- ] });
1480
+ const showLeftSlot = Boolean(loading || leftIcon || reserveLeftIcon);
1481
+ const showRightSlot = Boolean(rightIcon || reserveRightIcon);
1482
+ const spinner = /* @__PURE__ */ jsx6(
1483
+ "span",
1484
+ {
1485
+ "aria-hidden": "true",
1486
+ className: "inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent"
1487
+ }
1488
+ );
1489
+ const leftSlot = showLeftSlot ? /* @__PURE__ */ jsx6("span", { className: cn(iconSlotBase, reserveLeftIcon && iconSlotReserve), children: loading ? spinner : leftIcon }) : null;
1490
+ const rightSlot = showRightSlot ? /* @__PURE__ */ jsx6("span", { className: cn(iconSlotBase, reserveRightIcon && iconSlotReserve), children: rightIcon }) : null;
1241
1491
  if (asChild) {
1242
- return /* @__PURE__ */ jsx7(
1492
+ return /* @__PURE__ */ jsxs2(
1243
1493
  Slot.Root,
1244
1494
  {
1245
1495
  ref,
@@ -1257,11 +1507,15 @@ var Button = React3.forwardRef(
1257
1507
  onClick?.(e);
1258
1508
  },
1259
1509
  ...props,
1260
- children: content
1510
+ children: [
1511
+ leftSlot,
1512
+ /* @__PURE__ */ jsx6(Slot.Slottable, { children }),
1513
+ rightSlot
1514
+ ]
1261
1515
  }
1262
1516
  );
1263
1517
  }
1264
- return /* @__PURE__ */ jsx7(
1518
+ return /* @__PURE__ */ jsxs2(
1265
1519
  "button",
1266
1520
  {
1267
1521
  ref,
@@ -1272,29 +1526,415 @@ var Button = React3.forwardRef(
1272
1526
  "data-loading": loading ? "" : void 0,
1273
1527
  onClick,
1274
1528
  ...props,
1275
- children: content
1529
+ children: [
1530
+ leftSlot,
1531
+ children,
1532
+ rightSlot
1533
+ ]
1276
1534
  }
1277
1535
  );
1278
1536
  }
1279
1537
  );
1280
1538
  Button.displayName = "Button";
1539
+
1540
+ // src/ui/components/Field.tsx
1541
+ import * as React3 from "react";
1542
+
1543
+ // src/ui/components/Label.tsx
1544
+ import * as React2 from "react";
1545
+ import { jsx as jsx7 } from "react/jsx-runtime";
1546
+ var Label = React2.forwardRef(
1547
+ ({ className, htmlFor, children, ...props }, ref) => /* @__PURE__ */ jsx7(
1548
+ "label",
1549
+ {
1550
+ ref,
1551
+ htmlFor,
1552
+ className: cn("inline-flex items-center gap-2 text-sm font-medium text-(--text-1)", className),
1553
+ ...props,
1554
+ children
1555
+ }
1556
+ )
1557
+ );
1558
+ Label.displayName = "Label";
1559
+
1560
+ // src/ui/components/Field.tsx
1561
+ import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
1562
+ function Field({ label, hint, error, required, disabled, id, children, className, ...props }) {
1563
+ const reactId = React3.useId();
1564
+ const controlId = id ?? `field-${reactId}`;
1565
+ const hintId = hint ? `${controlId}-hint` : void 0;
1566
+ const errorId = error ? `${controlId}-error` : void 0;
1567
+ const childInvalid = Boolean(children.props.invalid);
1568
+ const invalid = Boolean(error) || childInvalid;
1569
+ const describedByParts = [children.props["aria-describedby"], errorId, hintId].filter(Boolean);
1570
+ const ariaDescribedBy = describedByParts.length ? describedByParts.join(" ") : void 0;
1571
+ const resolvedDisabled = disabled ?? children.props.disabled;
1572
+ const resolvedRequired = required ?? children.props.required;
1573
+ const control = React3.cloneElement(children, {
1574
+ id: controlId,
1575
+ disabled: resolvedDisabled,
1576
+ required: resolvedRequired,
1577
+ invalid,
1578
+ "aria-describedby": ariaDescribedBy
1579
+ });
1580
+ return /* @__PURE__ */ jsxs3("div", { className: cn("grid gap-1.5", className), ...props, children: [
1581
+ label ? /* @__PURE__ */ jsx8("div", { className: "flex items-center justify-between gap-3", children: /* @__PURE__ */ jsxs3(Label, { htmlFor: controlId, children: [
1582
+ label,
1583
+ resolvedRequired ? /* @__PURE__ */ jsxs3("span", { "aria-hidden": "true", className: "text-(--muted)", children: [
1584
+ " ",
1585
+ "*"
1586
+ ] }) : null
1587
+ ] }) }) : null,
1588
+ control,
1589
+ error ? /* @__PURE__ */ jsx8("p", { id: errorId, className: "text-xs leading-5 text-(--danger-contrast)", role: "alert", children: error }) : null,
1590
+ hint ? /* @__PURE__ */ jsx8("p", { id: hintId, className: "text-xs leading-5 text-(--muted)", children: hint }) : null
1591
+ ] });
1592
+ }
1593
+
1594
+ // src/ui/components/Input.tsx
1595
+ import { cva as cva2 } from "class-variance-authority";
1596
+ import * as React4 from "react";
1597
+ import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
1598
+ var controlShellBase = cn(
1599
+ "relative inline-flex items-center gap-2",
1600
+ "rounded-[var(--radius-input)]",
1601
+ "border border-[color:color-mix(in_oklab,var(--border),transparent_55%)]",
1602
+ "text-[color:var(--text-1)]",
1603
+ "transition-[background-color,border-color,box-shadow] duration-[var(--motion-med)] ease",
1604
+ "[--control-focus:var(--focus)]",
1605
+ "focus-within:shadow-[0_0_0_3px_color-mix(in_oklab,var(--control-focus),transparent_60%)]",
1606
+ "focus-within:border-[color:var(--control-focus)]",
1607
+ "data-[invalid]:[--control-focus:var(--danger)]",
1608
+ "data-[invalid]:border-[color:color-mix(in_oklab,var(--danger),transparent_20%)]",
1609
+ "data-[disabled]:bg-[color:var(--disabled-bg)]",
1610
+ "data-[disabled]:text-[color:var(--disabled-fg)]",
1611
+ "data-[disabled]:border-[color:var(--disabled-border)]",
1612
+ "data-[disabled]:cursor-not-allowed"
1613
+ );
1614
+ var controlShellVariants = cva2(controlShellBase, {
1615
+ variants: {
1616
+ variant: {
1617
+ surface: cn("bg-[color:var(--surface-2)]", "hover:bg-[color:var(--surface-hover)]"),
1618
+ outline: cn(
1619
+ "bg-transparent",
1620
+ "hover:bg-[color:color-mix(in_oklab,var(--surface-2),transparent_40%)]",
1621
+ "border-[color:color-mix(in_oklab,var(--border),transparent_35%)]"
1622
+ ),
1623
+ ghost: cn(
1624
+ "bg-transparent",
1625
+ "border-[color:transparent]",
1626
+ "hover:bg-[color:color-mix(in_oklab,var(--surface-2),transparent_55%)]",
1627
+ "focus-within:border-[color:color-mix(in_oklab,var(--border),transparent_35%)]"
1628
+ )
1629
+ },
1630
+ size: {
1631
+ sm: "h-8 px-3 text-sm [--input-slot-size:2rem]",
1632
+ md: "h-10 px-3.5 text-sm [--input-slot-size:2.5rem]",
1633
+ lg: "h-11 px-4 text-base [--input-slot-size:2.75rem]"
1634
+ },
1635
+ fullWidth: { true: "w-full", false: "w-auto" }
1636
+ },
1637
+ defaultVariants: { variant: "surface", size: "md", fullWidth: false }
1638
+ });
1639
+ var inputBase = cn(
1640
+ "min-w-0 flex-1 bg-transparent",
1641
+ "outline-none border-0 ring-0",
1642
+ "placeholder:text-[color:color-mix(in_oklab,var(--muted),transparent_20%)]",
1643
+ "disabled:cursor-not-allowed",
1644
+ "read-only:cursor-default"
1645
+ );
1646
+ var slotBase = cn(
1647
+ "inline-flex items-center justify-center",
1648
+ "text-[color:var(--muted)]",
1649
+ "data-[disabled]:text-[color:var(--disabled-fg)]"
1650
+ );
1651
+ var slotReserve = "min-w-[var(--input-slot-size)]";
1652
+ var Input = React4.forwardRef(
1653
+ ({
1654
+ variant,
1655
+ size,
1656
+ fullWidth,
1657
+ invalid,
1658
+ leftSlot,
1659
+ rightSlot,
1660
+ reserveLeftSlot,
1661
+ reserveRightSlot,
1662
+ className,
1663
+ inputClassName,
1664
+ disabled,
1665
+ ...props
1666
+ }, ref) => {
1667
+ const isDisabled = Boolean(disabled);
1668
+ const showLeftSlot = Boolean(leftSlot || reserveLeftSlot);
1669
+ const showRightSlot = Boolean(rightSlot || reserveRightSlot);
1670
+ return /* @__PURE__ */ jsxs4(
1671
+ "div",
1672
+ {
1673
+ className: cn(controlShellVariants({ variant, size, fullWidth }), className),
1674
+ "data-invalid": invalid ? "" : void 0,
1675
+ "data-disabled": isDisabled ? "" : void 0,
1676
+ children: [
1677
+ showLeftSlot ? /* @__PURE__ */ jsx9(
1678
+ "span",
1679
+ {
1680
+ className: cn(slotBase, reserveLeftSlot && slotReserve),
1681
+ "data-disabled": isDisabled ? "" : void 0,
1682
+ children: leftSlot
1683
+ }
1684
+ ) : null,
1685
+ /* @__PURE__ */ jsx9(
1686
+ "input",
1687
+ {
1688
+ ref,
1689
+ disabled: isDisabled,
1690
+ "aria-invalid": invalid || void 0,
1691
+ className: cn(inputBase, inputClassName),
1692
+ ...props
1693
+ }
1694
+ ),
1695
+ showRightSlot ? /* @__PURE__ */ jsx9(
1696
+ "span",
1697
+ {
1698
+ className: cn(slotBase, reserveRightSlot && slotReserve),
1699
+ "data-disabled": isDisabled ? "" : void 0,
1700
+ children: rightSlot
1701
+ }
1702
+ ) : null
1703
+ ]
1704
+ }
1705
+ );
1706
+ }
1707
+ );
1708
+ Input.displayName = "Input";
1709
+
1710
+ // src/ui/components/Skeleton.tsx
1711
+ import { cva as cva3 } from "class-variance-authority";
1712
+ import * as React5 from "react";
1713
+ import { jsx as jsx10 } from "react/jsx-runtime";
1714
+ var skeletonBase = cn(
1715
+ "relative isolate inline-flex overflow-hidden",
1716
+ "bg-[color:color-mix(in_oklab,var(--surface-2),var(--border)_25%)]",
1717
+ "text-transparent select-none",
1718
+ "[--skeleton-shimmer:color-mix(in_oklab,var(--surface-1),white_35%)]"
1719
+ );
1720
+ var shimmerEffect = cn(
1721
+ "before:content-[''] before:absolute before:inset-0",
1722
+ "before:bg-[linear-gradient(110deg,transparent_0%,color-mix(in_oklab,var(--skeleton-shimmer),transparent_100%)_25%,color-mix(in_oklab,var(--skeleton-shimmer),transparent_55%)_50%,color-mix(in_oklab,var(--skeleton-shimmer),transparent_100%)_75%,transparent_100%)]",
1723
+ "before:[background-size:200%_100%]",
1724
+ "before:animate-[skeleton-shimmer_1.6s_linear_infinite] motion-reduce:before:animate-none"
1725
+ );
1726
+ var skeletonVariants = cva3(skeletonBase, {
1727
+ variants: {
1728
+ variant: {
1729
+ surface: "",
1730
+ outline: cn("bg-transparent", "border border-[color:color-mix(in_oklab,var(--border),transparent_65%)]")
1731
+ },
1732
+ size: {
1733
+ sm: "h-3",
1734
+ md: "h-4",
1735
+ lg: "h-5"
1736
+ },
1737
+ radius: {
1738
+ none: "rounded-[var(--shape-radius-0)]",
1739
+ sm: "rounded-[var(--shape-radius-10)]",
1740
+ md: "rounded-[var(--radius-input)]",
1741
+ lg: "rounded-[var(--radius-card)]",
1742
+ full: "rounded-full"
1743
+ },
1744
+ fullWidth: { true: "w-full", false: "w-auto" },
1745
+ animation: {
1746
+ none: "",
1747
+ pulse: "animate-pulse motion-reduce:animate-none",
1748
+ shimmer: shimmerEffect
1749
+ },
1750
+ preset: {
1751
+ none: "",
1752
+ avatar: "h-12 w-12 rounded-full",
1753
+ title: "h-6 w-2/3",
1754
+ button: "h-10 w-28 rounded-[var(--radius-btn)]",
1755
+ card: "h-40 w-full rounded-[var(--radius-card)]"
1756
+ }
1757
+ },
1758
+ defaultVariants: {
1759
+ variant: "surface",
1760
+ size: "md",
1761
+ radius: "md",
1762
+ fullWidth: true,
1763
+ animation: "shimmer",
1764
+ preset: "none"
1765
+ }
1766
+ });
1767
+ var Skeleton = React5.forwardRef(
1768
+ ({ variant, size, radius, fullWidth, animation, preset, animate, className, ...props }, ref) => {
1769
+ const resolvedAnimation = animation ?? (animate === false ? "none" : animate ? "pulse" : void 0);
1770
+ return /* @__PURE__ */ jsx10(
1771
+ "div",
1772
+ {
1773
+ ref,
1774
+ className: cn(
1775
+ skeletonVariants({
1776
+ variant,
1777
+ size,
1778
+ radius,
1779
+ fullWidth,
1780
+ animation: resolvedAnimation,
1781
+ preset
1782
+ }),
1783
+ className
1784
+ ),
1785
+ ...props
1786
+ }
1787
+ );
1788
+ }
1789
+ );
1790
+ Skeleton.displayName = "Skeleton";
1791
+
1792
+ // src/ui/components/Textarea.tsx
1793
+ import { cva as cva4 } from "class-variance-authority";
1794
+ import * as React6 from "react";
1795
+ import { jsx as jsx11 } from "react/jsx-runtime";
1796
+ var controlShellBase2 = cn(
1797
+ "relative inline-flex w-full",
1798
+ "rounded-[var(--radius-input)]",
1799
+ "border border-[color:color-mix(in_oklab,var(--border),transparent_55%)]",
1800
+ "text-[color:var(--text-1)]",
1801
+ "transition-[background-color,border-color,box-shadow] duration-[var(--motion-med)] ease",
1802
+ "[--control-focus:var(--focus)]",
1803
+ "focus-within:shadow-[0_0_0_3px_color-mix(in_oklab,var(--control-focus),transparent_60%)]",
1804
+ "focus-within:border-[color:var(--control-focus)]",
1805
+ "data-[invalid]:[--control-focus:var(--danger)]",
1806
+ "data-[invalid]:border-[color:color-mix(in_oklab,var(--danger),transparent_20%)]",
1807
+ "data-[disabled]:bg-[color:var(--disabled-bg)]",
1808
+ "data-[disabled]:text-[color:var(--disabled-fg)]",
1809
+ "data-[disabled]:border-[color:var(--disabled-border)]",
1810
+ "data-[disabled]:cursor-not-allowed"
1811
+ );
1812
+ var textareaShellVariants = cva4(controlShellBase2, {
1813
+ variants: {
1814
+ variant: {
1815
+ surface: cn("bg-[color:var(--surface-2)]", "hover:bg-[color:var(--surface-hover)]"),
1816
+ outline: cn(
1817
+ "bg-transparent",
1818
+ "hover:bg-[color:color-mix(in_oklab,var(--surface-2),transparent_40%)]",
1819
+ "border-[color:color-mix(in_oklab,var(--border),transparent_35%)]"
1820
+ ),
1821
+ ghost: cn(
1822
+ "bg-transparent",
1823
+ "border-[color:transparent]",
1824
+ "hover:bg-[color:color-mix(in_oklab,var(--surface-2),transparent_55%)]",
1825
+ "focus-within:border-[color:color-mix(in_oklab,var(--border),transparent_35%)]"
1826
+ )
1827
+ },
1828
+ size: {
1829
+ sm: "p-3 text-sm",
1830
+ md: "p-3.5 text-sm",
1831
+ lg: "p-4 text-base"
1832
+ },
1833
+ fullWidth: { true: "w-full", false: "w-auto" }
1834
+ },
1835
+ defaultVariants: { variant: "surface", size: "md", fullWidth: true }
1836
+ });
1837
+ var textareaBase = cn(
1838
+ "min-w-0 w-full bg-transparent",
1839
+ "outline-none border-0 ring-0",
1840
+ "resize-y",
1841
+ "placeholder:text-[color:color-mix(in_oklab,var(--muted),transparent_20%)]",
1842
+ "disabled:cursor-not-allowed",
1843
+ "read-only:cursor-default"
1844
+ );
1845
+ function mergeRefs(...refs) {
1846
+ return (node) => {
1847
+ for (const ref of refs) {
1848
+ if (!ref) continue;
1849
+ if (typeof ref === "function") {
1850
+ ref(node);
1851
+ } else {
1852
+ ref.current = node;
1853
+ }
1854
+ }
1855
+ };
1856
+ }
1857
+ var Textarea = React6.forwardRef(
1858
+ ({
1859
+ variant,
1860
+ size,
1861
+ fullWidth,
1862
+ invalid,
1863
+ className,
1864
+ textareaClassName,
1865
+ disabled,
1866
+ autoResize,
1867
+ maxHeightPx,
1868
+ onInput,
1869
+ rows = 4,
1870
+ value,
1871
+ ...props
1872
+ }, ref) => {
1873
+ const isDisabled = Boolean(disabled);
1874
+ const innerRef = React6.useRef(null);
1875
+ const resize = React6.useCallback(() => {
1876
+ if (!autoResize) return;
1877
+ const el = innerRef.current;
1878
+ if (!el) return;
1879
+ el.style.height = "auto";
1880
+ const next = el.scrollHeight;
1881
+ el.style.height = maxHeightPx ? `${Math.min(next, maxHeightPx)}px` : `${next}px`;
1882
+ }, [autoResize, maxHeightPx]);
1883
+ const handleInput = (e) => {
1884
+ resize();
1885
+ onInput?.(e);
1886
+ };
1887
+ React6.useLayoutEffect(() => {
1888
+ resize();
1889
+ }, [resize, value]);
1890
+ return /* @__PURE__ */ jsx11(
1891
+ "div",
1892
+ {
1893
+ className: cn(textareaShellVariants({ variant, size, fullWidth }), className),
1894
+ "data-invalid": invalid ? "" : void 0,
1895
+ "data-disabled": isDisabled ? "" : void 0,
1896
+ children: /* @__PURE__ */ jsx11(
1897
+ "textarea",
1898
+ {
1899
+ ref: mergeRefs(innerRef, ref),
1900
+ disabled: isDisabled,
1901
+ "aria-invalid": invalid || void 0,
1902
+ className: cn(
1903
+ textareaBase,
1904
+ autoResize ? "resize-none overflow-hidden" : "resize-y",
1905
+ textareaClassName
1906
+ ),
1907
+ rows,
1908
+ onInput: handleInput,
1909
+ value,
1910
+ ...props
1911
+ }
1912
+ )
1913
+ }
1914
+ );
1915
+ }
1916
+ );
1917
+ Textarea.displayName = "Textarea";
1281
1918
  export {
1282
1919
  AuthController,
1283
1920
  AuthControllerCtx,
1284
1921
  AuthControllerProvider,
1285
1922
  AuthDispatchCtx,
1286
- AuthFormInputField,
1287
1923
  AuthProvider,
1288
1924
  AuthStateCtx,
1289
1925
  Button,
1290
1926
  DEFAULT_NOTIFICATION_CHANNEL,
1927
+ Field,
1291
1928
  HttpError,
1929
+ Input,
1292
1930
  MockAuthHttpClient,
1293
1931
  MockHttpClient,
1294
1932
  NotificationHost,
1295
1933
  NotifierController,
1296
1934
  RedirectIfAuthed,
1297
1935
  RequireAuth,
1936
+ Skeleton,
1937
+ Textarea,
1298
1938
  authController,
1299
1939
  controllerFactory,
1300
1940
  createAuthController,