@hexdspace/react 0.1.9 → 0.1.11

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.
@@ -81,20 +81,6 @@
81
81
  }
82
82
 
83
83
  @layer components {
84
- .card {
85
- background: var(--surface-2);
86
- border: 1px solid color-mix(in oklab, var(--border), transparent 80%);
87
- border-radius: var(--radius-card);
88
- box-shadow: var(--shadow-elevated);
89
- }
90
-
91
- .popover {
92
- background: var(--surface-3);
93
- border: 1px solid color-mix(in oklab, var(--border), transparent 40%);
94
- border-radius: var(--radius-card);
95
- box-shadow: var(--shadow-popover);
96
- }
97
-
98
84
  .shell {
99
85
  background: var(--surface-1);
100
86
  border-radius: var(--radius-shell);
@@ -107,10 +93,11 @@
107
93
  box-shadow: var(--shadow-elevated);
108
94
  }
109
95
 
110
- .inset {
111
- background: var(--surface-1);
96
+ .card {
97
+ background: var(--surface-2);
98
+ border: 1px solid color-mix(in oklab, var(--border), transparent 80%);
112
99
  border-radius: var(--radius-card);
113
- box-shadow: inset 0 1px 0 color-mix(in oklab, var(--border), transparent 60%);
100
+ box-shadow: var(--shadow-elevated);
114
101
  }
115
102
 
116
103
  .chip {
@@ -156,10 +143,58 @@
156
143
  }
157
144
  }
158
145
 
159
- .brand-gradient {
160
- background: linear-gradient(90deg, var(--brand-strong) 0%, var(--brand) 30%);
161
- -webkit-background-clip: text;
162
- -webkit-text-fill-color: transparent;
146
+ @keyframes dialog-overlay-in {
147
+ from {
148
+ opacity: 0;
149
+ }
150
+ to {
151
+ opacity: 1;
152
+ }
153
+ }
154
+
155
+ @keyframes dialog-overlay-out {
156
+ from {
157
+ opacity: 1;
158
+ }
159
+ to {
160
+ opacity: 0;
161
+ }
162
+ }
163
+
164
+ @keyframes dialog-fade-in {
165
+ from {
166
+ opacity: 0;
167
+ }
168
+ to {
169
+ opacity: 1;
170
+ }
171
+ }
172
+
173
+ @keyframes dialog-fade-out {
174
+ from {
175
+ opacity: 1;
176
+ }
177
+ to {
178
+ opacity: 0;
179
+ }
180
+ }
181
+
182
+ @keyframes dialog-surface-in {
183
+ from {
184
+ transform: translateY(0.75rem);
185
+ }
186
+ to {
187
+ transform: translateY(0);
188
+ }
189
+ }
190
+
191
+ @keyframes dialog-surface-out {
192
+ from {
193
+ transform: translateY(0);
194
+ }
195
+ to {
196
+ transform: translateY(0.75rem);
197
+ }
163
198
  }
164
199
 
165
200
  :root .prose code {
package/dist/index.d.ts CHANGED
@@ -155,8 +155,8 @@ type UIFail = ResultError<string> & {
155
155
  };
156
156
  type UIResult<T> = UIOk<T> | UIFail;
157
157
  declare const ui: {
158
- success: <T>(value: T, ...effects: Instruction[]) => UIResult<T>;
159
- failure: (error: string, ...effects: Instruction[]) => UIResult<never>;
158
+ success: <T>(value: T, ...effects: Instruction[]) => UIOk<T>;
159
+ failure: (error: string, ...effects: Instruction[]) => UIFail;
160
160
  };
161
161
 
162
162
  type OptimisticSnapshot = {
@@ -409,6 +409,163 @@ interface ButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>
409
409
  }
410
410
  declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
411
411
 
412
+ type ConfirmPayload = {
413
+ title: string;
414
+ message?: string;
415
+ confirmText?: string;
416
+ cancelText?: string;
417
+ variant?: React__default.ComponentProps<typeof Button>['variant'];
418
+ danger?: boolean;
419
+ children?: React__default.ReactNode;
420
+ };
421
+ interface ConfirmDialogProps {
422
+ id: string;
423
+ payload?: ConfirmPayload;
424
+ onResolve?: (result?: unknown) => void;
425
+ }
426
+ declare const ConfirmDialog: React__default.FC<ConfirmDialogProps>;
427
+
428
+ interface CustomDialogPayload {
429
+ children?: React__default.ReactNode;
430
+ }
431
+ interface CustomDialogProps {
432
+ id: string;
433
+ payload?: CustomDialogPayload;
434
+ onResolve?: (result?: unknown) => void;
435
+ }
436
+ declare const CustomDialog: React__default.FC<CustomDialogProps>;
437
+
438
+ interface InfoPayload {
439
+ title: string;
440
+ children?: React__default.ReactNode;
441
+ confirmText?: string;
442
+ }
443
+ interface InfoDialogProps {
444
+ id: string;
445
+ payload?: InfoPayload;
446
+ onResolve?: (result?: unknown) => void;
447
+ }
448
+ declare const InfoDialog: React__default.FC<InfoDialogProps>;
449
+
450
+ declare function registerDefaultDialogs(): void;
451
+ type DefaultDialogPayloads = {
452
+ custom: CustomDialogPayload;
453
+ confirm: ConfirmPayload;
454
+ info: InfoPayload;
455
+ };
456
+ type DefaultDialogTemplateKey = keyof DefaultDialogPayloads;
457
+ declare const DefaultDialogTemplateKeys: ["custom", "confirm", "info"];
458
+
459
+ type DialogTemplate<TPayload = unknown> = React__default.ComponentType<{
460
+ id: string;
461
+ payload?: TPayload;
462
+ onResolve?: (result?: unknown) => void;
463
+ }>;
464
+ declare function registerDialogTemplate<TPayload>(key: string, component: DialogTemplate<TPayload>): void;
465
+ declare function unregisterDialogTemplate(key: string): void;
466
+ declare function getDialogTemplate<K extends DefaultDialogTemplateKey>(key: K): DialogTemplate<DefaultDialogPayloads[K]> | undefined;
467
+ declare function getDialogTemplate<TPayload = unknown>(key: string): DialogTemplate<TPayload> | undefined;
468
+
469
+ declare const DialogHost: React.FC;
470
+
471
+ interface DialogOptions {
472
+ modal: boolean;
473
+ dismissible: boolean;
474
+ zIndex: number;
475
+ }
476
+ interface DialogInstance {
477
+ id: string;
478
+ templateKey: string;
479
+ payload: unknown;
480
+ options: DialogOptions;
481
+ }
482
+
483
+ type OpenDialogCommand = {
484
+ templateKey: string;
485
+ payload?: unknown;
486
+ options?: DialogOptions;
487
+ };
488
+ interface OpenDialog {
489
+ execute<T = unknown>(cmd: OpenDialogCommand): Promise<T | undefined>;
490
+ }
491
+
492
+ declare function useDialog(): {
493
+ open: (cmd: Parameters<(<T>(cmd: OpenDialogCommand) => Promise<T | undefined>)>[0]) => Promise<unknown>;
494
+ resolve: (id: string, result?: unknown) => void;
495
+ dismiss: (id: string) => void;
496
+ closeTop: () => void;
497
+ };
498
+
499
+ interface CloseTopDialog {
500
+ execute(): void;
501
+ }
502
+
503
+ interface DismissDialog {
504
+ execute(id: string): void;
505
+ }
506
+
507
+ interface ResolveDialog {
508
+ execute(id: string, result?: unknown): void;
509
+ }
510
+
511
+ type DialogState = {
512
+ stack: DialogInstance[];
513
+ };
514
+
515
+ interface DialogRegistry {
516
+ getState(): DialogState;
517
+ subscribe(cb: (s: DialogState) => void): () => void;
518
+ push(instance: DialogInstance): void;
519
+ remove(id: string): void;
520
+ findById(id: string): DialogInstance | undefined;
521
+ createDeferred(id: string): {
522
+ promise: Promise<unknown>;
523
+ resolve: (v?: unknown) => void;
524
+ reject: (r?: unknown) => void;
525
+ };
526
+ takeDeferred(id: string): {
527
+ resolve: (v?: unknown) => void;
528
+ reject: (r?: unknown) => void;
529
+ } | undefined;
530
+ getTop(): DialogInstance | undefined;
531
+ }
532
+
533
+ declare class DialogController {
534
+ private readonly registry;
535
+ private readonly open;
536
+ private readonly resolve;
537
+ private readonly dismiss;
538
+ private readonly closeTop;
539
+ constructor(registry: DialogRegistry, open: OpenDialog, resolve: ResolveDialog, dismiss: DismissDialog, closeTop: CloseTopDialog);
540
+ handleOpen<T>(cmd: OpenDialogCommand): Promise<T | undefined>;
541
+ handleResolve(id: string, result?: unknown): void;
542
+ handleDismiss(id: string): void;
543
+ handleCloseTop(): void;
544
+ handleGetRegistry(): DialogRegistry;
545
+ }
546
+ declare const dialogController: DialogController;
547
+
548
+ declare const dialogPanelVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
549
+ declare function DialogContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): react_jsx_runtime.JSX.Element;
550
+ interface DialogProps<TPayload = unknown> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'>, VariantProps<typeof dialogPanelVariants> {
551
+ id: string;
552
+ template: DialogTemplate<TPayload>;
553
+ payload: TPayload;
554
+ trigger?: React.ReactElement;
555
+ modal?: boolean;
556
+ dismissible?: boolean;
557
+ zIndex?: number;
558
+ maxWidthPx?: number;
559
+ onDismiss?: () => void;
560
+ onResolve?: (result?: unknown) => void;
561
+ onOpenChange?: (open: boolean) => void;
562
+ showClose?: boolean;
563
+ closeLabel?: string;
564
+ open?: boolean;
565
+ defaultOpen?: boolean;
566
+ }
567
+ declare function Dialog<TPayload>({ id, template, payload, trigger, modal, dismissible, zIndex, maxWidthPx, onDismiss, onResolve, onOpenChange, showClose, closeLabel, open, defaultOpen, className, style, ...props }: DialogProps<TPayload>): react_jsx_runtime.JSX.Element;
568
+
412
569
  type ControlLikeProps = {
413
570
  id?: string;
414
571
  disabled?: boolean;
@@ -468,4 +625,15 @@ interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement
468
625
  }
469
626
  declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
470
627
 
471
- export { AuthController, AuthControllerCtx, type AuthControllerDeps, AuthControllerProvider, AuthDispatchCtx, AuthProvider, type AuthState, AuthStateCtx, Button, type ButtonProps, type CacheInstruction, type CustomInstruction, DEFAULT_NOTIFICATION_CHANNEL, type ErrorResponse, Field, type FieldProps, type GenericResponse, type HttpClient, HttpError, type HttpMethod, type HttpResponse, Input, type InputProps, type Instruction, type InstructionContext, MockAuthHttpClient, MockHttpClient, type MutationFn, type Notification, type NotificationAction, NotificationHost, type NotificationInstruction, type NotificationVariant, NotifierController, type OnSuccessFn, type OptimisticSnapshot, type OptimisticUpdateFn, RedirectIfAuthed, type RedirectIfAuthedProps, type RequestConfig, RequireAuth, type RequireAuthProps, type ResolvedToastTheme, type ResponsiveMutation, Skeleton, type SkeletonProps, Textarea, type TextareaProps, type ToastActionTheme, type ToastTheme, type ToastTransition, type ToastifyCSSVars, type UIFail, type UIOk, type UIResult, type User, authController, controllerFactory, createAuthController, httpClient as fetchHttpClient, notifierController, resolveToastTheme, ui, useAuth, useAuthActions, useAuthController, useAuthDispatch, useAuthedUser, useResponsiveMutation };
628
+ type Props = {
629
+ children: React.ReactElement;
630
+ content: React.ReactNode;
631
+ delayMs?: number;
632
+ side?: 'top' | 'right' | 'bottom' | 'left';
633
+ sideOffset?: number;
634
+ maxWidthPx?: number;
635
+ preserveWhitespace?: boolean;
636
+ };
637
+ declare function Tooltip({ children, content, delayMs, side, sideOffset, maxWidthPx, preserveWhitespace, }: Props): react_jsx_runtime.JSX.Element;
638
+
639
+ export { AuthController, AuthControllerCtx, type AuthControllerDeps, AuthControllerProvider, AuthDispatchCtx, AuthProvider, type AuthState, AuthStateCtx, Button, type ButtonProps, type CacheInstruction, ConfirmDialog, type ConfirmDialogProps, type ConfirmPayload, CustomDialog, type CustomDialogPayload, type CustomDialogProps, type CustomInstruction, DEFAULT_NOTIFICATION_CHANNEL, type DefaultDialogPayloads, type DefaultDialogTemplateKey, DefaultDialogTemplateKeys, Dialog, DialogContent, DialogController, DialogHost, type DialogInstance, type DialogOptions, type DialogProps, type DialogTemplate, type ErrorResponse, Field, type FieldProps, type GenericResponse, type HttpClient, HttpError, type HttpMethod, type HttpResponse, InfoDialog, type InfoDialogProps, type InfoPayload, Input, type InputProps, type Instruction, type InstructionContext, MockAuthHttpClient, MockHttpClient, type MutationFn, type Notification, type NotificationAction, NotificationHost, type NotificationInstruction, type NotificationVariant, NotifierController, type OnSuccessFn, type OptimisticSnapshot, type OptimisticUpdateFn, RedirectIfAuthed, type RedirectIfAuthedProps, type RequestConfig, RequireAuth, type RequireAuthProps, type ResolvedToastTheme, type ResponsiveMutation, Skeleton, type SkeletonProps, Textarea, type TextareaProps, type ToastActionTheme, type ToastTheme, type ToastTransition, type ToastifyCSSVars, Tooltip, type UIFail, type UIOk, type UIResult, type User, authController, controllerFactory, createAuthController, dialogController, httpClient as fetchHttpClient, getDialogTemplate, notifierController, registerDefaultDialogs, registerDialogTemplate, resolveToastTheme, ui, unregisterDialogTemplate, useAuth, useAuthActions, useAuthController, useAuthDispatch, useAuthedUser, useDialog, useResponsiveMutation };
package/dist/index.js CHANGED
@@ -1026,7 +1026,7 @@ var MockAuthHttpClient = class extends MockHttpClient {
1026
1026
  }
1027
1027
  registerAuthRoutes() {
1028
1028
  this.register("GET", "/auth/me", async () => {
1029
- await new Promise((resolve) => setTimeout(resolve, this.delayMs));
1029
+ await new Promise((resolve2) => setTimeout(resolve2, this.delayMs));
1030
1030
  if (this.fixtures.meError) {
1031
1031
  throw this.fixtures.meError;
1032
1032
  }
@@ -1036,7 +1036,7 @@ var MockAuthHttpClient = class extends MockHttpClient {
1036
1036
  throw unauthorized();
1037
1037
  });
1038
1038
  this.register("POST", "/auth/login", async (payload) => {
1039
- await new Promise((resolve) => setTimeout(resolve, this.delayMs));
1039
+ await new Promise((resolve2) => setTimeout(resolve2, this.delayMs));
1040
1040
  if (this.fixtures.loginError) {
1041
1041
  throw this.fixtures.loginError;
1042
1042
  }
@@ -1048,14 +1048,14 @@ var MockAuthHttpClient = class extends MockHttpClient {
1048
1048
  return httpResponse({ message: "Logged in" });
1049
1049
  });
1050
1050
  this.register("POST", "/auth/register", async () => {
1051
- await new Promise((resolve) => setTimeout(resolve, this.delayMs));
1051
+ await new Promise((resolve2) => setTimeout(resolve2, this.delayMs));
1052
1052
  if (this.fixtures.registerError) {
1053
1053
  throw this.fixtures.registerError;
1054
1054
  }
1055
1055
  return httpResponse({ message: "Registered" });
1056
1056
  });
1057
1057
  this.register("POST", "/auth/logout", async () => {
1058
- await new Promise((resolve) => setTimeout(resolve, this.delayMs));
1058
+ await new Promise((resolve2) => setTimeout(resolve2, this.delayMs));
1059
1059
  if (this.fixtures.logoutError) {
1060
1060
  throw this.fixtures.logoutError;
1061
1061
  }
@@ -1065,6 +1065,9 @@ var MockAuthHttpClient = class extends MockHttpClient {
1065
1065
  }
1066
1066
  };
1067
1067
 
1068
+ // src/ui/components/dialog/dialog-variant/ConfirmDialog.tsx
1069
+ import { Dialog as DialogPrimitive2 } from "radix-ui";
1070
+
1068
1071
  // src/ui/components/Button.tsx
1069
1072
  import { cva } from "class-variance-authority";
1070
1073
  import { Slot } from "radix-ui";
@@ -1537,14 +1540,419 @@ var Button = React.forwardRef(
1537
1540
  );
1538
1541
  Button.displayName = "Button";
1539
1542
 
1540
- // src/ui/components/Field.tsx
1543
+ // src/ui/components/dialog/Dialog.tsx
1544
+ import { cva as cva2 } from "class-variance-authority";
1545
+ import { XIcon } from "lucide-react";
1546
+ import { Dialog as DialogPrimitive } from "radix-ui";
1547
+ import * as React2 from "react";
1548
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1549
+ var dialogPanelVariants = cva2(
1550
+ cn(
1551
+ "fixed left-1/2 top-1/2",
1552
+ "-translate-x-1/2 -translate-y-1/2",
1553
+ "w-[min(92vw,var(--dialog-width))]",
1554
+ "pointer-events-auto",
1555
+ "data-[state=open]:animate-[dialog-fade-in_var(--motion-med)_cubic-bezier(0.16,1,0.3,1)]",
1556
+ "data-[state=closed]:animate-[dialog-fade-out_var(--motion-fast)_cubic-bezier(0.4,0,1,1)]",
1557
+ "motion-reduce:animate-none",
1558
+ "data-[state=closed]:pointer-events-none"
1559
+ )
1560
+ );
1561
+ var dialogOverlayClass = cn(
1562
+ "fixed inset-0 bg-[color:var(--overlay)]",
1563
+ "data-[state=open]:animate-[dialog-overlay-in_var(--motion-med)_cubic-bezier(0.16,1,0.3,1)]",
1564
+ "data-[state=closed]:animate-[dialog-overlay-out_var(--motion-fast)_cubic-bezier(0.4,0,1,1)]",
1565
+ "motion-reduce:animate-none",
1566
+ "data-[state=closed]:pointer-events-none"
1567
+ );
1568
+ function DialogContent({ className, ...props }) {
1569
+ return /* @__PURE__ */ jsx7("div", { className: cn("DialogContent p-6", className), ...props });
1570
+ }
1571
+ function AutoHeight({ children }) {
1572
+ const ref = React2.useRef(null);
1573
+ const [height, setHeight] = React2.useState("auto");
1574
+ React2.useLayoutEffect(() => {
1575
+ const el = ref.current;
1576
+ if (!el) return;
1577
+ const dpr = Math.max(1, Math.round(window.devicePixelRatio || 1));
1578
+ let raf = 0;
1579
+ const ro = new ResizeObserver((entries) => {
1580
+ const entry = entries[0];
1581
+ const raw = entry.borderBoxSize?.[0]?.blockSize ?? entry.contentRect.height;
1582
+ const snapped = Math.round(raw * dpr) / dpr;
1583
+ raf = requestAnimationFrame(() => {
1584
+ setHeight((prev) => {
1585
+ const prevNum = prev === "auto" ? -1 : prev;
1586
+ if (prevNum < 0 || Math.abs(snapped - prevNum) >= 2) return snapped;
1587
+ return prev;
1588
+ });
1589
+ });
1590
+ });
1591
+ ro.observe(el);
1592
+ return () => {
1593
+ ro.disconnect();
1594
+ cancelAnimationFrame(raf);
1595
+ };
1596
+ }, []);
1597
+ return /* @__PURE__ */ jsx7(
1598
+ "div",
1599
+ {
1600
+ className: "transition-[height] duration-(--motion-med) ease",
1601
+ style: { height: height === "auto" ? "auto" : height, overflow: "hidden", willChange: "height" },
1602
+ children: /* @__PURE__ */ jsx7("div", { ref, style: { boxSizing: "border-box" }, children })
1603
+ }
1604
+ );
1605
+ }
1606
+ function Dialog({
1607
+ id,
1608
+ template,
1609
+ payload,
1610
+ trigger,
1611
+ modal = true,
1612
+ dismissible = true,
1613
+ zIndex = 0,
1614
+ maxWidthPx = 800,
1615
+ onDismiss,
1616
+ onResolve,
1617
+ onOpenChange,
1618
+ showClose = true,
1619
+ closeLabel = "Close dialog",
1620
+ open: open2,
1621
+ defaultOpen,
1622
+ className,
1623
+ style,
1624
+ ...props
1625
+ }) {
1626
+ const fallbackId = React2.useId();
1627
+ const resolvedRef = React2.useRef(false);
1628
+ const Template = template;
1629
+ const handleOpenChange = (nextOpen) => {
1630
+ onOpenChange?.(nextOpen);
1631
+ if (nextOpen) {
1632
+ resolvedRef.current = false;
1633
+ return;
1634
+ }
1635
+ if (resolvedRef.current) {
1636
+ resolvedRef.current = false;
1637
+ return;
1638
+ }
1639
+ onDismiss?.();
1640
+ };
1641
+ const handleResolve = React2.useCallback(
1642
+ (result) => {
1643
+ resolvedRef.current = true;
1644
+ onResolve?.(result);
1645
+ },
1646
+ [onResolve]
1647
+ );
1648
+ return /* @__PURE__ */ jsxs3(DialogPrimitive.Root, { open: open2, defaultOpen, onOpenChange: handleOpenChange, modal, children: [
1649
+ trigger ? /* @__PURE__ */ jsx7(DialogPrimitive.Trigger, { asChild: true, children: trigger }) : null,
1650
+ /* @__PURE__ */ jsxs3(DialogPrimitive.Portal, { children: [
1651
+ modal ? /* @__PURE__ */ jsx7(
1652
+ DialogPrimitive.Overlay,
1653
+ {
1654
+ className: cn("DialogOverlay", dialogOverlayClass),
1655
+ style: { zIndex: zIndex - 1 }
1656
+ }
1657
+ ) : null,
1658
+ /* @__PURE__ */ jsx7(
1659
+ DialogPrimitive.Content,
1660
+ {
1661
+ className: cn(
1662
+ "DialogContent",
1663
+ dialogPanelVariants(),
1664
+ "data-[state=open]:[&_.dialog-surface]:animate-[dialog-surface-in_var(--motion-med)_cubic-bezier(0.16,1,0.3,1)]",
1665
+ "data-[state=closed]:[&_.dialog-surface]:animate-[dialog-surface-out_var(--motion-fast)_cubic-bezier(0.4,0,1,1)]",
1666
+ "motion-reduce:[&_.dialog-surface]:animate-none",
1667
+ className
1668
+ ),
1669
+ style: {
1670
+ ...style,
1671
+ zIndex,
1672
+ "--dialog-width": `${maxWidthPx}px`
1673
+ },
1674
+ onInteractOutside: (event) => {
1675
+ if (!dismissible) event.preventDefault();
1676
+ },
1677
+ onEscapeKeyDown: (event) => {
1678
+ if (!dismissible) event.preventDefault();
1679
+ },
1680
+ ...props,
1681
+ children: /* @__PURE__ */ jsxs3("div", { className: "dialog-surface relative shell overflow-hidden", children: [
1682
+ showClose ? /* @__PURE__ */ jsx7(DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx7(
1683
+ Button,
1684
+ {
1685
+ variant: "ghost",
1686
+ size: "icon",
1687
+ leftIcon: /* @__PURE__ */ jsx7(XIcon, { className: "w-5 h-5" }),
1688
+ className: "absolute right-2 top-2 z-10 rounded-full",
1689
+ "aria-label": closeLabel
1690
+ }
1691
+ ) }) : null,
1692
+ /* @__PURE__ */ jsx7(AutoHeight, { children: /* @__PURE__ */ jsx7(Template, { id: id ?? fallbackId, payload, onResolve: handleResolve }) })
1693
+ ] })
1694
+ }
1695
+ )
1696
+ ] })
1697
+ ] });
1698
+ }
1699
+
1700
+ // src/ui/components/dialog/dialog-variant/ConfirmDialog.tsx
1701
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1702
+ var ConfirmDialog = (props) => {
1703
+ const p = props.payload ?? { title: "Are you sure?" };
1704
+ const confirmVariant = p.variant ?? (p.danger ? "danger" : "secondary");
1705
+ return /* @__PURE__ */ jsxs4(DialogContent, { children: [
1706
+ /* @__PURE__ */ jsx8("h3", { className: "text-lg font-semibold", children: p.title }),
1707
+ p.children && p.children,
1708
+ p.message ? /* @__PURE__ */ jsx8("p", { className: "mt-2 text-sm opacity-80", children: p.message }) : null,
1709
+ /* @__PURE__ */ jsxs4("div", { className: "mt-5 flex items-center justify-end gap-4", children: [
1710
+ /* @__PURE__ */ jsx8(DialogPrimitive2.Close, { asChild: true, children: /* @__PURE__ */ jsx8(Button, { variant: "secondary", children: p.cancelText ?? "Cancel" }) }),
1711
+ /* @__PURE__ */ jsx8(DialogPrimitive2.Close, { asChild: true, children: /* @__PURE__ */ jsx8(Button, { variant: confirmVariant, onClick: () => props.onResolve?.({ confirmed: true }), children: p.confirmText ?? "Confirm" }) })
1712
+ ] })
1713
+ ] });
1714
+ };
1715
+
1716
+ // src/ui/components/dialog/dialog-variant/CustomDialog.tsx
1717
+ import { jsx as jsx9 } from "react/jsx-runtime";
1718
+ var CustomDialog = (props) => {
1719
+ const p = props.payload ?? { children: /* @__PURE__ */ jsx9("div", { children: "Empty custom dialog" }) };
1720
+ return /* @__PURE__ */ jsx9(DialogContent, { children: p.children });
1721
+ };
1722
+
1723
+ // src/ui/components/dialog/dialog-variant/InfoDialog.tsx
1724
+ import { Dialog as DialogPrimitive3 } from "radix-ui";
1725
+ import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
1726
+ var InfoDialog = (props) => {
1727
+ const p = props.payload ?? { title: "Information" };
1728
+ return /* @__PURE__ */ jsxs5(DialogContent, { children: [
1729
+ /* @__PURE__ */ jsx10("h3", { className: "text-lg font-semibold", children: p.title }),
1730
+ p.children,
1731
+ /* @__PURE__ */ jsx10("div", { className: "mt-5 flex items-center justify-end gap-4", children: /* @__PURE__ */ jsx10(DialogPrimitive3.Close, { asChild: true, children: /* @__PURE__ */ jsx10(Button, { variant: "secondary", children: p.confirmText || "Dismiss" }) }) })
1732
+ ] });
1733
+ };
1734
+
1735
+ // src/feature/dialog/infra/web/react/DialogTemplate.tsx
1736
+ var templates = /* @__PURE__ */ new Map();
1737
+ function registerDialogTemplate(key, component) {
1738
+ templates.set(key, component);
1739
+ }
1740
+ function unregisterDialogTemplate(key) {
1741
+ templates.delete(key);
1742
+ }
1743
+ function getDialogTemplate(key) {
1744
+ return templates.get(key);
1745
+ }
1746
+
1747
+ // src/feature/dialog/infra/web/react/bootstrap-dialogs.ts
1748
+ function registerDefaultDialogs() {
1749
+ registerDialogTemplate("custom", CustomDialog);
1750
+ registerDialogTemplate("confirm", ConfirmDialog);
1751
+ registerDialogTemplate("info", InfoDialog);
1752
+ }
1753
+ var DefaultDialogTemplateKeys = ["custom", "confirm", "info"];
1754
+
1755
+ // src/feature/dialog/infra/web/react/DialogHost.tsx
1541
1756
  import * as React3 from "react";
1542
1757
 
1758
+ // src/feature/dialog/application/use-case/close-top-dialog-use-case.ts
1759
+ var CloseTopUseCase = class {
1760
+ constructor(reg) {
1761
+ this.reg = reg;
1762
+ }
1763
+ execute() {
1764
+ const top = this.reg.getTop();
1765
+ if (!top) return;
1766
+ this.reg.takeDeferred(top.id)?.resolve(void 0);
1767
+ this.reg.remove(top.id);
1768
+ }
1769
+ };
1770
+
1771
+ // src/feature/dialog/application/use-case/dismiss-dialog-use-case.ts
1772
+ var DismissDialogUseCase = class {
1773
+ constructor(reg) {
1774
+ this.reg = reg;
1775
+ }
1776
+ execute(id) {
1777
+ this.reg.takeDeferred(id)?.resolve(void 0);
1778
+ this.reg.remove(id);
1779
+ }
1780
+ };
1781
+
1782
+ // src/feature/dialog/application/use-case/open-dialog-use-case.ts
1783
+ import { v4 as uuid } from "uuid";
1784
+ var OpenDialogUseCase = class {
1785
+ constructor(reg) {
1786
+ this.reg = reg;
1787
+ }
1788
+ async execute(cmd) {
1789
+ const id = uuid();
1790
+ const options = cmd.options ?? getDefaultOptions();
1791
+ if (!options.zIndex) {
1792
+ options.zIndex = 2e3;
1793
+ }
1794
+ this.reg.push({
1795
+ id,
1796
+ templateKey: cmd.templateKey,
1797
+ payload: cmd.payload ?? {},
1798
+ options
1799
+ });
1800
+ const { promise } = this.reg.createDeferred(id);
1801
+ const result = await promise;
1802
+ return result;
1803
+ }
1804
+ };
1805
+ function getDefaultOptions() {
1806
+ return {
1807
+ modal: true,
1808
+ dismissible: true,
1809
+ zIndex: 2500
1810
+ };
1811
+ }
1812
+
1813
+ // src/feature/dialog/application/use-case/resolve-dialog-use-case.ts
1814
+ var ResolveDialogUseCase = class {
1815
+ constructor(reg) {
1816
+ this.reg = reg;
1817
+ }
1818
+ execute(id, result) {
1819
+ this.reg.takeDeferred(id)?.resolve(result);
1820
+ this.reg.remove(id);
1821
+ }
1822
+ };
1823
+
1824
+ // src/feature/dialog/infra/provider/in-memory-dialog-registry.ts
1825
+ var InMemoryDialogRegistry = class {
1826
+ state = { stack: [] };
1827
+ subs = /* @__PURE__ */ new Set();
1828
+ deferred = /* @__PURE__ */ new Map();
1829
+ getState() {
1830
+ return this.state;
1831
+ }
1832
+ subscribe(cb) {
1833
+ this.subs.add(cb);
1834
+ cb(this.state);
1835
+ return () => this.subs.delete(cb);
1836
+ }
1837
+ emit() {
1838
+ for (const cb of this.subs) cb(this.state);
1839
+ }
1840
+ push(instance) {
1841
+ this.state = { stack: [...this.state.stack, instance] };
1842
+ this.emit();
1843
+ }
1844
+ remove(id) {
1845
+ this.state = { stack: this.state.stack.filter((d) => d.id !== id) };
1846
+ this.emit();
1847
+ }
1848
+ findById(id) {
1849
+ return this.state.stack.find((d) => d.id === id);
1850
+ }
1851
+ getTop() {
1852
+ const s = this.state.stack;
1853
+ return s.length ? s[s.length - 1] : void 0;
1854
+ }
1855
+ createDeferred(id) {
1856
+ let resolve2;
1857
+ let reject;
1858
+ const promise = new Promise((res, rej) => {
1859
+ resolve2 = res;
1860
+ reject = rej;
1861
+ });
1862
+ this.deferred.set(id, { resolve: resolve2, reject });
1863
+ return { promise, resolve: resolve2, reject };
1864
+ }
1865
+ takeDeferred(id) {
1866
+ const d = this.deferred.get(id);
1867
+ this.deferred.delete(id);
1868
+ return d;
1869
+ }
1870
+ };
1871
+
1872
+ // src/feature/dialog/infra/controller/dialog-controller.ts
1873
+ var DialogController = class {
1874
+ constructor(registry2, open2, resolve2, dismiss2, closeTop2) {
1875
+ this.registry = registry2;
1876
+ this.open = open2;
1877
+ this.resolve = resolve2;
1878
+ this.dismiss = dismiss2;
1879
+ this.closeTop = closeTop2;
1880
+ }
1881
+ handleOpen(cmd) {
1882
+ return this.open.execute(cmd);
1883
+ }
1884
+ handleResolve(id, result) {
1885
+ return this.resolve.execute(id, result);
1886
+ }
1887
+ handleDismiss(id) {
1888
+ return this.dismiss.execute(id);
1889
+ }
1890
+ handleCloseTop() {
1891
+ return this.closeTop.execute();
1892
+ }
1893
+ handleGetRegistry() {
1894
+ return this.registry;
1895
+ }
1896
+ };
1897
+ var registry = new InMemoryDialogRegistry();
1898
+ var open = new OpenDialogUseCase(registry);
1899
+ var resolve = new ResolveDialogUseCase(registry);
1900
+ var dismiss = new DismissDialogUseCase(registry);
1901
+ var closeTop = new CloseTopUseCase(registry);
1902
+ var dialogController = new DialogController(registry, open, resolve, dismiss, closeTop);
1903
+
1904
+ // src/feature/dialog/infra/web/react/DialogHost.tsx
1905
+ import { Fragment as Fragment2, jsx as jsx11 } from "react/jsx-runtime";
1906
+ var DialogHost = () => {
1907
+ const [state, setState] = React3.useState(dialogController.handleGetRegistry().getState());
1908
+ React3.useEffect(() => dialogController.handleGetRegistry().subscribe(setState), []);
1909
+ return /* @__PURE__ */ jsx11(Fragment2, { children: state.stack.map((dialog, index) => {
1910
+ const template = getDialogTemplate(dialog.templateKey);
1911
+ if (!template) {
1912
+ console.error(`Missing dialog template: ${dialog.templateKey}`);
1913
+ return null;
1914
+ }
1915
+ return /* @__PURE__ */ jsx11(
1916
+ Dialog,
1917
+ {
1918
+ id: dialog.id,
1919
+ template,
1920
+ payload: dialog.payload,
1921
+ modal: dialog.options.modal,
1922
+ dismissible: dialog.options.dismissible,
1923
+ zIndex: dialog.options.zIndex + index,
1924
+ defaultOpen: true,
1925
+ onResolve: (result) => dialogController.handleResolve(dialog.id, result),
1926
+ onDismiss: () => dialogController.handleDismiss(dialog.id)
1927
+ },
1928
+ dialog.id
1929
+ );
1930
+ }) });
1931
+ };
1932
+
1933
+ // src/feature/dialog/infra/web/react/useDialog.tsx
1934
+ import { useMemo as useMemo3 } from "react";
1935
+ function useDialog() {
1936
+ const c = dialogController;
1937
+ return useMemo3(
1938
+ () => ({
1939
+ open: (cmd) => c.handleOpen(cmd),
1940
+ resolve: (id, result) => c.handleResolve(id, result),
1941
+ dismiss: (id) => c.handleDismiss(id),
1942
+ closeTop: () => c.handleCloseTop()
1943
+ }),
1944
+ [c]
1945
+ );
1946
+ }
1947
+
1948
+ // src/ui/components/Field.tsx
1949
+ import * as React5 from "react";
1950
+
1543
1951
  // 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(
1952
+ import * as React4 from "react";
1953
+ import { jsx as jsx12 } from "react/jsx-runtime";
1954
+ var Label = React4.forwardRef(
1955
+ ({ className, htmlFor, children, ...props }, ref) => /* @__PURE__ */ jsx12(
1548
1956
  "label",
1549
1957
  {
1550
1958
  ref,
@@ -1558,9 +1966,9 @@ var Label = React2.forwardRef(
1558
1966
  Label.displayName = "Label";
1559
1967
 
1560
1968
  // src/ui/components/Field.tsx
1561
- import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
1969
+ import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
1562
1970
  function Field({ label, hint, error, required, disabled, id, children, className, ...props }) {
1563
- const reactId = React3.useId();
1971
+ const reactId = React5.useId();
1564
1972
  const controlId = id ?? `field-${reactId}`;
1565
1973
  const hintId = hint ? `${controlId}-hint` : void 0;
1566
1974
  const errorId = error ? `${controlId}-error` : void 0;
@@ -1570,31 +1978,31 @@ function Field({ label, hint, error, required, disabled, id, children, className
1570
1978
  const ariaDescribedBy = describedByParts.length ? describedByParts.join(" ") : void 0;
1571
1979
  const resolvedDisabled = disabled ?? children.props.disabled;
1572
1980
  const resolvedRequired = required ?? children.props.required;
1573
- const control = React3.cloneElement(children, {
1981
+ const control = React5.cloneElement(children, {
1574
1982
  id: controlId,
1575
1983
  disabled: resolvedDisabled,
1576
1984
  required: resolvedRequired,
1577
1985
  invalid,
1578
1986
  "aria-describedby": ariaDescribedBy
1579
1987
  });
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: [
1988
+ return /* @__PURE__ */ jsxs6("div", { className: cn("grid gap-1.5", className), ...props, children: [
1989
+ label ? /* @__PURE__ */ jsx13("div", { className: "flex items-center justify-between gap-3", children: /* @__PURE__ */ jsxs6(Label, { htmlFor: controlId, children: [
1582
1990
  label,
1583
- resolvedRequired ? /* @__PURE__ */ jsxs3("span", { "aria-hidden": "true", className: "text-(--muted)", children: [
1991
+ resolvedRequired ? /* @__PURE__ */ jsxs6("span", { "aria-hidden": "true", className: "text-(--muted)", children: [
1584
1992
  " ",
1585
1993
  "*"
1586
1994
  ] }) : null
1587
1995
  ] }) }) : null,
1588
1996
  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
1997
+ error ? /* @__PURE__ */ jsx13("p", { id: errorId, className: "text-xs leading-5 text-(--danger-contrast)", role: "alert", children: error }) : null,
1998
+ hint ? /* @__PURE__ */ jsx13("p", { id: hintId, className: "text-xs leading-5 text-(--muted)", children: hint }) : null
1591
1999
  ] });
1592
2000
  }
1593
2001
 
1594
2002
  // 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";
2003
+ import { cva as cva3 } from "class-variance-authority";
2004
+ import * as React6 from "react";
2005
+ import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
1598
2006
  var controlShellBase = cn(
1599
2007
  "relative inline-flex items-center gap-2",
1600
2008
  "rounded-[var(--radius-input)]",
@@ -1611,7 +2019,7 @@ var controlShellBase = cn(
1611
2019
  "data-[disabled]:border-[color:var(--disabled-border)]",
1612
2020
  "data-[disabled]:cursor-not-allowed"
1613
2021
  );
1614
- var controlShellVariants = cva2(controlShellBase, {
2022
+ var controlShellVariants = cva3(controlShellBase, {
1615
2023
  variants: {
1616
2024
  variant: {
1617
2025
  surface: cn("bg-[color:var(--surface-2)]", "hover:bg-[color:var(--surface-hover)]"),
@@ -1649,7 +2057,7 @@ var slotBase = cn(
1649
2057
  "data-[disabled]:text-[color:var(--disabled-fg)]"
1650
2058
  );
1651
2059
  var slotReserve = "min-w-[var(--input-slot-size)]";
1652
- var Input = React4.forwardRef(
2060
+ var Input = React6.forwardRef(
1653
2061
  ({
1654
2062
  variant,
1655
2063
  size,
@@ -1667,14 +2075,14 @@ var Input = React4.forwardRef(
1667
2075
  const isDisabled = Boolean(disabled);
1668
2076
  const showLeftSlot = Boolean(leftSlot || reserveLeftSlot);
1669
2077
  const showRightSlot = Boolean(rightSlot || reserveRightSlot);
1670
- return /* @__PURE__ */ jsxs4(
2078
+ return /* @__PURE__ */ jsxs7(
1671
2079
  "div",
1672
2080
  {
1673
2081
  className: cn(controlShellVariants({ variant, size, fullWidth }), className),
1674
2082
  "data-invalid": invalid ? "" : void 0,
1675
2083
  "data-disabled": isDisabled ? "" : void 0,
1676
2084
  children: [
1677
- showLeftSlot ? /* @__PURE__ */ jsx9(
2085
+ showLeftSlot ? /* @__PURE__ */ jsx14(
1678
2086
  "span",
1679
2087
  {
1680
2088
  className: cn(slotBase, reserveLeftSlot && slotReserve),
@@ -1682,7 +2090,7 @@ var Input = React4.forwardRef(
1682
2090
  children: leftSlot
1683
2091
  }
1684
2092
  ) : null,
1685
- /* @__PURE__ */ jsx9(
2093
+ /* @__PURE__ */ jsx14(
1686
2094
  "input",
1687
2095
  {
1688
2096
  ref,
@@ -1692,7 +2100,7 @@ var Input = React4.forwardRef(
1692
2100
  ...props
1693
2101
  }
1694
2102
  ),
1695
- showRightSlot ? /* @__PURE__ */ jsx9(
2103
+ showRightSlot ? /* @__PURE__ */ jsx14(
1696
2104
  "span",
1697
2105
  {
1698
2106
  className: cn(slotBase, reserveRightSlot && slotReserve),
@@ -1708,9 +2116,9 @@ var Input = React4.forwardRef(
1708
2116
  Input.displayName = "Input";
1709
2117
 
1710
2118
  // 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";
2119
+ import { cva as cva4 } from "class-variance-authority";
2120
+ import * as React7 from "react";
2121
+ import { jsx as jsx15 } from "react/jsx-runtime";
1714
2122
  var skeletonBase = cn(
1715
2123
  "relative isolate inline-flex overflow-hidden",
1716
2124
  "bg-[color:color-mix(in_oklab,var(--surface-2),var(--border)_25%)]",
@@ -1723,7 +2131,7 @@ var shimmerEffect = cn(
1723
2131
  "before:[background-size:200%_100%]",
1724
2132
  "before:animate-[skeleton-shimmer_1.6s_linear_infinite] motion-reduce:before:animate-none"
1725
2133
  );
1726
- var skeletonVariants = cva3(skeletonBase, {
2134
+ var skeletonVariants = cva4(skeletonBase, {
1727
2135
  variants: {
1728
2136
  variant: {
1729
2137
  surface: "",
@@ -1764,10 +2172,10 @@ var skeletonVariants = cva3(skeletonBase, {
1764
2172
  preset: "none"
1765
2173
  }
1766
2174
  });
1767
- var Skeleton = React5.forwardRef(
2175
+ var Skeleton = React7.forwardRef(
1768
2176
  ({ variant, size, radius, fullWidth, animation, preset, animate, className, ...props }, ref) => {
1769
2177
  const resolvedAnimation = animation ?? (animate === false ? "none" : animate ? "pulse" : void 0);
1770
- return /* @__PURE__ */ jsx10(
2178
+ return /* @__PURE__ */ jsx15(
1771
2179
  "div",
1772
2180
  {
1773
2181
  ref,
@@ -1790,9 +2198,9 @@ var Skeleton = React5.forwardRef(
1790
2198
  Skeleton.displayName = "Skeleton";
1791
2199
 
1792
2200
  // 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";
2201
+ import { cva as cva5 } from "class-variance-authority";
2202
+ import * as React8 from "react";
2203
+ import { jsx as jsx16 } from "react/jsx-runtime";
1796
2204
  var controlShellBase2 = cn(
1797
2205
  "relative inline-flex w-full",
1798
2206
  "rounded-[var(--radius-input)]",
@@ -1809,7 +2217,7 @@ var controlShellBase2 = cn(
1809
2217
  "data-[disabled]:border-[color:var(--disabled-border)]",
1810
2218
  "data-[disabled]:cursor-not-allowed"
1811
2219
  );
1812
- var textareaShellVariants = cva4(controlShellBase2, {
2220
+ var textareaShellVariants = cva5(controlShellBase2, {
1813
2221
  variants: {
1814
2222
  variant: {
1815
2223
  surface: cn("bg-[color:var(--surface-2)]", "hover:bg-[color:var(--surface-hover)]"),
@@ -1854,7 +2262,7 @@ function mergeRefs(...refs) {
1854
2262
  }
1855
2263
  };
1856
2264
  }
1857
- var Textarea = React6.forwardRef(
2265
+ var Textarea = React8.forwardRef(
1858
2266
  ({
1859
2267
  variant,
1860
2268
  size,
@@ -1871,8 +2279,8 @@ var Textarea = React6.forwardRef(
1871
2279
  ...props
1872
2280
  }, ref) => {
1873
2281
  const isDisabled = Boolean(disabled);
1874
- const innerRef = React6.useRef(null);
1875
- const resize = React6.useCallback(() => {
2282
+ const innerRef = React8.useRef(null);
2283
+ const resize = React8.useCallback(() => {
1876
2284
  if (!autoResize) return;
1877
2285
  const el = innerRef.current;
1878
2286
  if (!el) return;
@@ -1884,16 +2292,16 @@ var Textarea = React6.forwardRef(
1884
2292
  resize();
1885
2293
  onInput?.(e);
1886
2294
  };
1887
- React6.useLayoutEffect(() => {
2295
+ React8.useLayoutEffect(() => {
1888
2296
  resize();
1889
2297
  }, [resize, value]);
1890
- return /* @__PURE__ */ jsx11(
2298
+ return /* @__PURE__ */ jsx16(
1891
2299
  "div",
1892
2300
  {
1893
2301
  className: cn(textareaShellVariants({ variant, size, fullWidth }), className),
1894
2302
  "data-invalid": invalid ? "" : void 0,
1895
2303
  "data-disabled": isDisabled ? "" : void 0,
1896
- children: /* @__PURE__ */ jsx11(
2304
+ children: /* @__PURE__ */ jsx16(
1897
2305
  "textarea",
1898
2306
  {
1899
2307
  ref: mergeRefs(innerRef, ref),
@@ -1915,6 +2323,54 @@ var Textarea = React6.forwardRef(
1915
2323
  }
1916
2324
  );
1917
2325
  Textarea.displayName = "Textarea";
2326
+
2327
+ // src/ui/components/Tooltip.tsx
2328
+ import { Tooltip as TooltipPrimitive } from "radix-ui";
2329
+ import { jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
2330
+ var tooltipContentBase = cn(
2331
+ "panel shadow-none px-4 py-2.5 text-xs z-5000 select-none",
2332
+ "origin-center will-change-[transform,opacity]",
2333
+ "[--tooltip-x:0px] [--tooltip-y:4px]",
2334
+ "data-[side=bottom]:[--tooltip-y:-4px]",
2335
+ "data-[side=left]:[--tooltip-x:4px] data-[side=left]:[--tooltip-y:0px]",
2336
+ "data-[side=right]:[--tooltip-x:-4px] data-[side=right]:[--tooltip-y:0px]",
2337
+ "data-[state=delayed-open]:animate-[tooltip-in_140ms_ease-out]",
2338
+ "data-[state=instant-open]:animate-[tooltip-in_140ms_ease-out]",
2339
+ "data-[state=closed]:animate-[tooltip-out_120ms_ease-in]",
2340
+ "motion-reduce:animate-none"
2341
+ );
2342
+ function Tooltip({
2343
+ children,
2344
+ content,
2345
+ delayMs = 300,
2346
+ side = "top",
2347
+ sideOffset = 12,
2348
+ maxWidthPx = 240,
2349
+ preserveWhitespace = false
2350
+ }) {
2351
+ return /* @__PURE__ */ jsx17(TooltipPrimitive.Provider, { delayDuration: delayMs, children: /* @__PURE__ */ jsxs8(TooltipPrimitive.Root, { children: [
2352
+ /* @__PURE__ */ jsx17(TooltipPrimitive.Trigger, { asChild: true, children }),
2353
+ /* @__PURE__ */ jsx17(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs8(
2354
+ TooltipPrimitive.Content,
2355
+ {
2356
+ side,
2357
+ sideOffset,
2358
+ className: tooltipContentBase,
2359
+ style: {
2360
+ width: "max-content",
2361
+ maxWidth: `min(${maxWidthPx}px, 90vw)`,
2362
+ whiteSpace: preserveWhitespace ? "pre-line" : "normal",
2363
+ overflowWrap: "break-word",
2364
+ hyphens: "auto"
2365
+ },
2366
+ children: [
2367
+ content,
2368
+ /* @__PURE__ */ jsx17(TooltipPrimitive.Arrow, { style: { fill: "var(--surface-2)" } })
2369
+ ]
2370
+ }
2371
+ ) })
2372
+ ] }) });
2373
+ }
1918
2374
  export {
1919
2375
  AuthController,
1920
2376
  AuthControllerCtx,
@@ -1923,9 +2379,17 @@ export {
1923
2379
  AuthProvider,
1924
2380
  AuthStateCtx,
1925
2381
  Button,
2382
+ ConfirmDialog,
2383
+ CustomDialog,
1926
2384
  DEFAULT_NOTIFICATION_CHANNEL,
2385
+ DefaultDialogTemplateKeys,
2386
+ Dialog,
2387
+ DialogContent,
2388
+ DialogController,
2389
+ DialogHost,
1927
2390
  Field,
1928
2391
  HttpError,
2392
+ InfoDialog,
1929
2393
  Input,
1930
2394
  MockAuthHttpClient,
1931
2395
  MockHttpClient,
@@ -1935,17 +2399,24 @@ export {
1935
2399
  RequireAuth,
1936
2400
  Skeleton,
1937
2401
  Textarea,
2402
+ Tooltip,
1938
2403
  authController,
1939
2404
  controllerFactory,
1940
2405
  createAuthController,
2406
+ dialogController,
1941
2407
  httpClient as fetchHttpClient,
2408
+ getDialogTemplate,
1942
2409
  notifierController,
2410
+ registerDefaultDialogs,
2411
+ registerDialogTemplate,
1943
2412
  resolveToastTheme,
1944
2413
  ui,
2414
+ unregisterDialogTemplate,
1945
2415
  useAuth,
1946
2416
  useAuthActions,
1947
2417
  useAuthController,
1948
2418
  useAuthDispatch,
1949
2419
  useAuthedUser,
2420
+ useDialog,
1950
2421
  useResponsiveMutation
1951
2422
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hexdspace/react",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -71,6 +71,8 @@
71
71
  "build": "tsup src/index.ts --dts --format esm --clean && pnpm run build:css",
72
72
  "build:css": "mkdir -p dist/css && cp -R src/ui/theme/css/* dist/css/",
73
73
  "test": "vitest",
74
+ "test:unit": "vitest --project unit",
75
+ "test:storybook": "vitest --project storybook",
74
76
  "storybook": "storybook dev -p 6006",
75
77
  "build-storybook": "storybook build"
76
78
  }