@elizaos/ui 2.0.0-alpha.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -0
  3. package/dist/components/ui/badge.d.ts +10 -0
  4. package/dist/components/ui/badge.d.ts.map +1 -0
  5. package/dist/components/ui/badge.js +20 -0
  6. package/dist/components/ui/banner.d.ts +18 -0
  7. package/dist/components/ui/banner.d.ts.map +1 -0
  8. package/dist/components/ui/banner.js +27 -0
  9. package/dist/components/ui/button.d.ts +12 -0
  10. package/dist/components/ui/button.d.ts.map +1 -0
  11. package/dist/components/ui/button.js +33 -0
  12. package/dist/components/ui/card.d.ts +9 -0
  13. package/dist/components/ui/card.d.ts.map +1 -0
  14. package/dist/components/ui/card.js +16 -0
  15. package/dist/components/ui/chat-atoms.d.ts +26 -0
  16. package/dist/components/ui/chat-atoms.d.ts.map +1 -0
  17. package/dist/components/ui/chat-atoms.js +17 -0
  18. package/dist/components/ui/checkbox.d.ts +5 -0
  19. package/dist/components/ui/checkbox.d.ts.map +1 -0
  20. package/dist/components/ui/checkbox.js +8 -0
  21. package/dist/components/ui/confirm-delete.d.ts +12 -0
  22. package/dist/components/ui/confirm-delete.d.ts.map +1 -0
  23. package/dist/components/ui/confirm-delete.js +13 -0
  24. package/dist/components/ui/confirm-dialog.d.ts +24 -0
  25. package/dist/components/ui/confirm-dialog.d.ts.map +1 -0
  26. package/dist/components/ui/confirm-dialog.js +55 -0
  27. package/dist/components/ui/connection-status.d.ts +9 -0
  28. package/dist/components/ui/connection-status.d.ts.map +1 -0
  29. package/dist/components/ui/connection-status.js +25 -0
  30. package/dist/components/ui/copy-button.d.ts +13 -0
  31. package/dist/components/ui/copy-button.d.ts.map +1 -0
  32. package/dist/components/ui/copy-button.js +14 -0
  33. package/dist/components/ui/dialog.d.ts +20 -0
  34. package/dist/components/ui/dialog.d.ts.map +1 -0
  35. package/dist/components/ui/dialog.js +22 -0
  36. package/dist/components/ui/dropdown-menu.d.ts +28 -0
  37. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  38. package/dist/components/ui/dropdown-menu.js +35 -0
  39. package/dist/components/ui/empty-state.d.ts +13 -0
  40. package/dist/components/ui/empty-state.d.ts.map +1 -0
  41. package/dist/components/ui/empty-state.js +5 -0
  42. package/dist/components/ui/error-boundary.d.ts +18 -0
  43. package/dist/components/ui/error-boundary.d.ts.map +1 -0
  44. package/dist/components/ui/error-boundary.js +27 -0
  45. package/dist/components/ui/grid.d.ts +11 -0
  46. package/dist/components/ui/grid.d.ts.map +1 -0
  47. package/dist/components/ui/grid.js +30 -0
  48. package/dist/components/ui/input.d.ts +6 -0
  49. package/dist/components/ui/input.d.ts.map +1 -0
  50. package/dist/components/ui/input.js +8 -0
  51. package/dist/components/ui/label.d.ts +6 -0
  52. package/dist/components/ui/label.d.ts.map +1 -0
  53. package/dist/components/ui/label.js +9 -0
  54. package/dist/components/ui/popover.d.ts +7 -0
  55. package/dist/components/ui/popover.d.ts.map +1 -0
  56. package/dist/components/ui/popover.js +9 -0
  57. package/dist/components/ui/save-footer.d.ts +13 -0
  58. package/dist/components/ui/save-footer.d.ts.map +1 -0
  59. package/dist/components/ui/save-footer.js +9 -0
  60. package/dist/components/ui/search-bar.d.ts +17 -0
  61. package/dist/components/ui/search-bar.d.ts.map +1 -0
  62. package/dist/components/ui/search-bar.js +19 -0
  63. package/dist/components/ui/search-input.d.ts +11 -0
  64. package/dist/components/ui/search-input.d.ts.map +1 -0
  65. package/dist/components/ui/search-input.js +9 -0
  66. package/dist/components/ui/section-card.d.ts +15 -0
  67. package/dist/components/ui/section-card.d.ts.map +1 -0
  68. package/dist/components/ui/section-card.js +9 -0
  69. package/dist/components/ui/select.d.ts +14 -0
  70. package/dist/components/ui/select.d.ts.map +1 -0
  71. package/dist/components/ui/select.js +26 -0
  72. package/dist/components/ui/separator.d.ts +5 -0
  73. package/dist/components/ui/separator.d.ts.map +1 -0
  74. package/dist/components/ui/separator.js +7 -0
  75. package/dist/components/ui/skeleton.d.ts +17 -0
  76. package/dist/components/ui/skeleton.d.ts.map +1 -0
  77. package/dist/components/ui/skeleton.js +25 -0
  78. package/dist/components/ui/slider.d.ts +5 -0
  79. package/dist/components/ui/slider.d.ts.map +1 -0
  80. package/dist/components/ui/slider.js +7 -0
  81. package/dist/components/ui/sonner.d.ts +5 -0
  82. package/dist/components/ui/sonner.d.ts.map +1 -0
  83. package/dist/components/ui/sonner.js +15 -0
  84. package/dist/components/ui/spinner.d.ts +6 -0
  85. package/dist/components/ui/spinner.d.ts.map +1 -0
  86. package/dist/components/ui/spinner.js +8 -0
  87. package/dist/components/ui/stack.d.ts +13 -0
  88. package/dist/components/ui/stack.d.ts.map +1 -0
  89. package/dist/components/ui/stack.js +39 -0
  90. package/dist/components/ui/status-badge.d.ts +20 -0
  91. package/dist/components/ui/status-badge.d.ts.map +1 -0
  92. package/dist/components/ui/status-badge.js +41 -0
  93. package/dist/components/ui/switch.d.ts +5 -0
  94. package/dist/components/ui/switch.d.ts.map +1 -0
  95. package/dist/components/ui/switch.js +7 -0
  96. package/dist/components/ui/tabs.d.ts +8 -0
  97. package/dist/components/ui/tabs.d.ts.map +1 -0
  98. package/dist/components/ui/tabs.js +12 -0
  99. package/dist/components/ui/tag-editor.d.ts +24 -0
  100. package/dist/components/ui/tag-editor.d.ts.map +1 -0
  101. package/dist/components/ui/tag-editor.js +32 -0
  102. package/dist/components/ui/tag-input.d.ts +19 -0
  103. package/dist/components/ui/tag-input.d.ts.map +1 -0
  104. package/dist/components/ui/tag-input.js +28 -0
  105. package/dist/components/ui/textarea.d.ts +6 -0
  106. package/dist/components/ui/textarea.d.ts.map +1 -0
  107. package/dist/components/ui/textarea.js +8 -0
  108. package/dist/components/ui/themed-select.d.ts +27 -0
  109. package/dist/components/ui/themed-select.d.ts.map +1 -0
  110. package/dist/components/ui/themed-select.js +57 -0
  111. package/dist/components/ui/tooltip-extended.d.ts +76 -0
  112. package/dist/components/ui/tooltip-extended.d.ts.map +1 -0
  113. package/dist/components/ui/tooltip-extended.js +128 -0
  114. package/dist/components/ui/tooltip.d.ts +8 -0
  115. package/dist/components/ui/tooltip.d.ts.map +1 -0
  116. package/dist/components/ui/tooltip.js +10 -0
  117. package/dist/components/ui/typography.d.ts +17 -0
  118. package/dist/components/ui/typography.d.ts.map +1 -0
  119. package/dist/components/ui/typography.js +44 -0
  120. package/dist/index.d.ts +42 -0
  121. package/dist/index.d.ts.map +1 -0
  122. package/dist/index.js +43 -0
  123. package/dist/lib/button-styles.d.ts +12 -0
  124. package/dist/lib/button-styles.d.ts.map +1 -0
  125. package/dist/lib/button-styles.js +11 -0
  126. package/dist/lib/utils.d.ts +6 -0
  127. package/dist/lib/utils.d.ts.map +1 -0
  128. package/dist/lib/utils.js +8 -0
  129. package/dist/package.json +69 -0
  130. package/dist/styles/theme.css +193 -0
  131. package/package.json +94 -0
  132. package/src/styles/theme.css +193 -0
@@ -0,0 +1,20 @@
1
+ import * as React from "react";
2
+ export type StatusTone = "success" | "warning" | "danger" | "muted";
3
+ export declare function statusToneForBoolean(condition: boolean, onTone?: StatusTone, offTone?: StatusTone): StatusTone;
4
+ export interface StatusBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
5
+ label: string;
6
+ tone: StatusTone;
7
+ withDot?: boolean;
8
+ }
9
+ export declare const StatusBadge: React.ForwardRefExoticComponent<StatusBadgeProps & React.RefAttributes<HTMLSpanElement>>;
10
+ export interface StatusDotProps extends React.HTMLAttributes<HTMLSpanElement> {
11
+ status: string;
12
+ }
13
+ export declare const StatusDot: React.ForwardRefExoticComponent<StatusDotProps & React.RefAttributes<HTMLSpanElement>>;
14
+ export interface StatCardProps extends React.HTMLAttributes<HTMLDivElement> {
15
+ label: string;
16
+ value: React.ReactNode;
17
+ accent?: boolean;
18
+ }
19
+ export declare const StatCard: React.ForwardRefExoticComponent<StatCardProps & React.RefAttributes<HTMLDivElement>>;
20
+ //# sourceMappingURL=status-badge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-badge.d.ts","sourceRoot":"","sources":["../../../src/components/ui/status-badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAqBpE,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,OAAO,EAClB,MAAM,GAAE,UAAsB,EAC9B,OAAO,GAAE,UAAoB,GAC5B,UAAU,CAEZ;AAID,MAAM,WAAW,gBACf,SAAQ,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,WAAW,0FAoBvB,CAAC;AAKF,MAAM,WAAW,cAAe,SAAQ,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;IAC3E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,SAAS,wFAsBrB,CAAC;AAKF,MAAM,WAAW,aAAc,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,QAAQ,sFAuBpB,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "../../lib/utils";
4
+ const STATUS_TONE_STYLES = {
5
+ success: {
6
+ badge: "text-ok border-ok/30 bg-ok/10",
7
+ dot: "bg-ok",
8
+ },
9
+ warning: {
10
+ badge: "text-warn border-warn/30 bg-warn/10",
11
+ dot: "bg-warn",
12
+ },
13
+ danger: {
14
+ badge: "text-destructive border-destructive/30 bg-destructive/10",
15
+ dot: "bg-destructive",
16
+ },
17
+ muted: {
18
+ badge: "text-muted border-border bg-bg",
19
+ dot: "bg-muted",
20
+ },
21
+ };
22
+ export function statusToneForBoolean(condition, onTone = "success", offTone = "muted") {
23
+ return condition ? onTone : offTone;
24
+ }
25
+ export const StatusBadge = React.forwardRef(({ label, tone, withDot = false, className, ...props }, ref) => {
26
+ const styles = STATUS_TONE_STYLES[tone];
27
+ return (_jsxs("span", { ref: ref, className: cn("inline-flex items-center gap-1 rounded-sm border px-2 py-0.5 text-[10px] font-bold uppercase", styles.badge, className), ...props, children: [withDot && (_jsx("span", { className: cn("h-1.5 w-1.5 rounded-full", styles.dot) })), label] }));
28
+ });
29
+ StatusBadge.displayName = "StatusBadge";
30
+ export const StatusDot = React.forwardRef(({ status, className, ...props }, ref) => {
31
+ const tone = status === "success" || status === "completed" || status === "connected"
32
+ ? "success"
33
+ : status === "error" || status === "failed" || status === "denied"
34
+ ? "danger"
35
+ : "muted";
36
+ const styles = STATUS_TONE_STYLES[tone];
37
+ return (_jsx("span", { ref: ref, className: cn("inline-block h-2 w-2 rounded-full", styles.dot, className), ...props }));
38
+ });
39
+ StatusDot.displayName = "StatusDot";
40
+ export const StatCard = React.forwardRef(({ label, value, accent = false, className, ...props }, ref) => (_jsxs("div", { ref: ref, className: cn("flex flex-col items-center justify-center border border-border bg-bg p-3 min-w-[80px]", className), ...props, children: [_jsx("div", { className: cn("text-lg font-bold tabular-nums", accent && "text-accent"), children: value }), _jsx("div", { className: "mt-0.5 text-[10px] uppercase tracking-wide text-muted", children: label })] })));
41
+ StatCard.displayName = "StatCard";
@@ -0,0 +1,5 @@
1
+ import * as SwitchPrimitives from "@radix-ui/react-switch";
2
+ import * as React from "react";
3
+ declare const Switch: React.ForwardRefExoticComponent<Omit<SwitchPrimitives.SwitchProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
4
+ export { Switch };
5
+ //# sourceMappingURL=switch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../../src/components/ui/switch.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,gBAAgB,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,QAAA,MAAM,MAAM,8JAkBV,CAAC;AAGH,OAAO,EAAE,MAAM,EAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as SwitchPrimitives from "@radix-ui/react-switch";
3
+ import * as React from "react";
4
+ import { cn } from "../../lib/utils";
5
+ const Switch = React.forwardRef(({ className, ...props }, ref) => (_jsx(SwitchPrimitives.Root, { className: cn("peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-bg disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input", className), ...props, ref: ref, children: _jsx(SwitchPrimitives.Thumb, { className: cn("pointer-events-none block h-5 w-5 rounded-full bg-bg shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0") }) })));
6
+ Switch.displayName = SwitchPrimitives.Root.displayName;
7
+ export { Switch };
@@ -0,0 +1,8 @@
1
+ import * as TabsPrimitive from "@radix-ui/react-tabs";
2
+ import * as React from "react";
3
+ declare const Tabs: React.ForwardRefExoticComponent<TabsPrimitive.TabsProps & React.RefAttributes<HTMLDivElement>>;
4
+ declare const TabsList: React.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsListProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
5
+ declare const TabsTrigger: React.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsTriggerProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
6
+ declare const TabsContent: React.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
7
+ export { Tabs, TabsList, TabsTrigger, TabsContent };
8
+ //# sourceMappingURL=tabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../src/components/ui/tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,QAAA,MAAM,IAAI,gGAAqB,CAAC;AAEhC,QAAA,MAAM,QAAQ,uJAYZ,CAAC;AAGH,QAAA,MAAM,WAAW,gKAYf,CAAC;AAGH,QAAA,MAAM,WAAW,0JAYf,CAAC;AAGH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as TabsPrimitive from "@radix-ui/react-tabs";
3
+ import * as React from "react";
4
+ import { cn } from "../../lib/utils";
5
+ const Tabs = TabsPrimitive.Root;
6
+ const TabsList = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.List, { ref: ref, className: cn("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-fg", className), ...props })));
7
+ TabsList.displayName = TabsPrimitive.List.displayName;
8
+ const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Trigger, { ref: ref, className: cn("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-bg transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-bg data-[state=active]:text-txt data-[state=active]:shadow-sm", className), ...props })));
9
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
10
+ const TabsContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(TabsPrimitive.Content, { ref: ref, className: cn("mt-2 ring-offset-bg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", className), ...props })));
11
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
12
+ export { Tabs, TabsList, TabsTrigger, TabsContent };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * TagEditor — add/remove string tags with chip display.
3
+ *
4
+ * Fully generic; no app-context dependency. Callers pass translated labels
5
+ * via props (with English defaults so the component works out-of-the-box).
6
+ */
7
+ export interface TagEditorProps {
8
+ label: string;
9
+ items: string[];
10
+ onChange: (items: string[]) => void;
11
+ placeholder?: string;
12
+ /** Label for the Add button. Defaults to "Add". */
13
+ addLabel?: string;
14
+ /** Label for the remove button. Defaults to "×". */
15
+ removeLabel?: string;
16
+ /** Optional class for the root container. */
17
+ className?: string;
18
+ /** Optional class for the input row. */
19
+ inputRowClassName?: string;
20
+ /** Optional class for the scrollable tag list. */
21
+ listClassName?: string;
22
+ }
23
+ export declare function TagEditor({ label, items, onChange, placeholder, addLabel, removeLabel, className, inputRowClassName, listClassName, }: TagEditorProps): import("react/jsx-runtime").JSX.Element;
24
+ //# sourceMappingURL=tag-editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag-editor.d.ts","sourceRoot":"","sources":["../../../src/components/ui/tag-editor.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kDAAkD;IAClD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,KAAK,EACL,QAAQ,EACR,WAA2B,EAC3B,QAAc,EACd,WAAiB,EACjB,SAAS,EACT,iBAAiB,EACjB,aAAa,GACd,EAAE,cAAc,2CAuEhB"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * TagEditor — add/remove string tags with chip display.
4
+ *
5
+ * Fully generic; no app-context dependency. Callers pass translated labels
6
+ * via props (with English defaults so the component works out-of-the-box).
7
+ */
8
+ import { useState } from "react";
9
+ import { cn } from "../../lib/utils";
10
+ import { Button } from "./button";
11
+ import { Input } from "./input";
12
+ export function TagEditor({ label, items, onChange, placeholder = "add item...", addLabel = "+", removeLabel = "×", className, inputRowClassName, listClassName, }) {
13
+ const [inputValue, setInputValue] = useState("");
14
+ const addItem = () => {
15
+ const trimmed = inputValue.trim();
16
+ if (trimmed && !items.includes(trimmed)) {
17
+ onChange([...items, trimmed]);
18
+ }
19
+ setInputValue("");
20
+ };
21
+ const removeItem = (index) => {
22
+ const updated = [...items];
23
+ updated.splice(index, 1);
24
+ onChange(updated);
25
+ };
26
+ return (_jsxs("div", { className: cn("flex min-h-0 flex-col gap-1.5", className), children: [_jsx("span", { className: "font-semibold text-xs", children: label }), _jsxs("div", { className: cn("flex items-center gap-1.5", inputRowClassName), children: [_jsx(Input, { type: "text", value: inputValue, placeholder: placeholder, onChange: (e) => setInputValue(e.target.value), onKeyDown: (e) => {
27
+ if (e.key === "Enter") {
28
+ e.preventDefault();
29
+ addItem();
30
+ }
31
+ }, className: "h-7 px-2 border-border bg-card text-[11px] focus-visible:ring-1 focus-visible:ring-accent flex-1 min-w-0 shadow-sm" }), _jsx(Button, { variant: "ghost", size: "sm", className: "h-7 w-7 text-[14px] p-0 text-accent border-none hover:bg-transparent hover:text-accent/80 font-bold", onClick: addItem, children: addLabel })] }), _jsx("div", { className: cn("min-h-0 overflow-y-auto rounded-xl border border-border/40 bg-bg/50 p-2 backdrop-blur-sm", "flex flex-wrap content-start items-start gap-x-1.5 gap-y-1", listClassName), children: items.map((item, i) => (_jsxs("span", { className: "inline-flex items-center justify-between gap-1 px-2 py-0.5 border border-border/50 bg-black/10 rounded text-[11px] h-fit text-txt font-medium", children: [_jsx("span", { className: "truncate max-w-[200px]", title: item, children: item }), _jsx(Button, { variant: "ghost", size: "icon", className: "h-4 w-4 p-0 text-danger/80 hover:text-danger hover:bg-transparent", onClick: () => removeItem(i), children: removeLabel })] }, item))) })] }));
32
+ }
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+ export interface TagInputProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
3
+ /** Label shown above the input */
4
+ label?: string;
5
+ /** Current list of tags */
6
+ items: string[];
7
+ /** Called with the updated tag list */
8
+ onChange: (items: string[]) => void;
9
+ /** Placeholder text for the input */
10
+ placeholder?: string;
11
+ /** Maximum number of tags */
12
+ maxItems?: number;
13
+ /** Label for the explicit add button */
14
+ addLabel?: string;
15
+ /** Aria-label template for the remove button */
16
+ removeLabel?: string;
17
+ }
18
+ export declare const TagInput: React.ForwardRefExoticComponent<TagInputProps & React.RefAttributes<HTMLDivElement>>;
19
+ //# sourceMappingURL=tag-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag-input.d.ts","sourceRoot":"","sources":["../../../src/components/ui/tag-input.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,WAAW,aACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC9D,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,uCAAuC;IACvC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACpC,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,QAAQ,sFAoFpB,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { X } from "lucide-react";
3
+ import * as React from "react";
4
+ import { cn } from "../../lib/utils";
5
+ export const TagInput = React.forwardRef(({ label, items, onChange, placeholder = "Add item…", maxItems, addLabel = "Add", removeLabel = "Remove", className, ...props }, ref) => {
6
+ const [inputValue, setInputValue] = React.useState("");
7
+ const addItem = React.useCallback(() => {
8
+ const trimmed = inputValue.trim();
9
+ if (!trimmed || items.includes(trimmed))
10
+ return;
11
+ if (maxItems != null && items.length >= maxItems)
12
+ return;
13
+ onChange([...items, trimmed]);
14
+ setInputValue("");
15
+ }, [inputValue, items, onChange, maxItems]);
16
+ const removeItem = React.useCallback((index) => {
17
+ const updated = [...items];
18
+ updated.splice(index, 1);
19
+ onChange(updated);
20
+ }, [items, onChange]);
21
+ return (_jsxs("div", { ref: ref, className: cn("flex flex-col gap-1.5", className), ...props, children: [label && _jsx("span", { className: "text-xs font-semibold", children: label }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("input", { type: "text", value: inputValue, placeholder: placeholder, onChange: (e) => setInputValue(e.target.value), onKeyDown: (e) => {
22
+ if (e.key === "Enter") {
23
+ e.preventDefault();
24
+ addItem();
25
+ }
26
+ }, className: "flex-1 min-w-0 rounded-md border border-input bg-bg px-2 py-1 text-[11px] placeholder:text-muted focus-visible:outline-none focus-visible:border-ring" }), _jsx("button", { type: "button", className: "rounded-md border border-input bg-bg px-1.5 py-0.5 text-[10px] text-muted transition-colors hover:border-accent hover:text-accent", onClick: addItem, children: addLabel })] }), _jsx("div", { className: "flex flex-wrap gap-1.5 rounded-md border border-border bg-bg-accent p-1.5 min-h-[60px] content-start", children: items.map((item, i) => (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-sm border border-border bg-bg px-2 py-0.5 text-[11px]", children: [item, _jsx("button", { type: "button", className: "text-muted hover:text-destructive transition-colors", onClick: () => removeItem(i), "aria-label": `${removeLabel} ${item}`, children: _jsx(X, { className: "h-3 w-3" }) })] }, item))) })] }));
27
+ });
28
+ TagInput.displayName = "TagInput";
@@ -0,0 +1,6 @@
1
+ import * as React from "react";
2
+ export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
3
+ }
4
+ declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
5
+ export { Textarea };
6
+ //# sourceMappingURL=textarea.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../../../src/components/ui/textarea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,aACf,SAAQ,KAAK,CAAC,sBAAsB,CAAC,mBAAmB,CAAC;CAAG;AAE9D,QAAA,MAAM,QAAQ,2FAab,CAAC;AAGF,OAAO,EAAE,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "../../lib/utils";
4
+ const Textarea = React.forwardRef(({ className, ...props }, ref) => {
5
+ return (_jsx("textarea", { className: cn("flex min-h-[80px] w-full rounded-md border border-input bg-bg px-3 py-2 text-sm ring-offset-bg placeholder:text-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", className), ref: ref, ...props }));
6
+ });
7
+ Textarea.displayName = "Textarea";
8
+ export { Textarea };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * ThemedSelect — custom dropdown with grouped options.
3
+ *
4
+ * A generic, fully-controlled select component that supports grouped option
5
+ * lists and optional hint text per item. Has no dependency on any app-level
6
+ * context; all state is passed in as props.
7
+ */
8
+ export interface ThemedSelectGroup<T extends string = string> {
9
+ label: string;
10
+ items: {
11
+ id: T;
12
+ text: string;
13
+ hint?: string;
14
+ }[];
15
+ }
16
+ export interface ThemedSelectProps<T extends string = string> {
17
+ value: T | null;
18
+ groups: ThemedSelectGroup<T>[];
19
+ onChange: (id: T) => void;
20
+ placeholder?: string;
21
+ menuPlacement?: "top" | "bottom";
22
+ className?: string;
23
+ triggerClassName?: string;
24
+ menuClassName?: string;
25
+ }
26
+ export declare function ThemedSelect<T extends string>({ value, groups, onChange, placeholder, menuPlacement, className, triggerClassName, menuClassName, }: ThemedSelectProps<T>): import("react/jsx-runtime").JSX.Element;
27
+ //# sourceMappingURL=themed-select.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"themed-select.d.ts","sourceRoot":"","sources":["../../../src/components/ui/themed-select.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QAAE,EAAE,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAC1D,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAChB,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/B,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,EAC7C,KAAK,EACL,MAAM,EACN,QAAQ,EACR,WAAyB,EACzB,aAAwB,EACxB,SAAc,EACd,gBAAqB,EACrB,aAAkB,GACnB,EAAE,iBAAiB,CAAC,CAAC,CAAC,2CAwGtB"}
@@ -0,0 +1,57 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * ThemedSelect — custom dropdown with grouped options.
4
+ *
5
+ * A generic, fully-controlled select component that supports grouped option
6
+ * lists and optional hint text per item. Has no dependency on any app-level
7
+ * context; all state is passed in as props.
8
+ */
9
+ import { useEffect, useRef, useState } from "react";
10
+ import { Button } from "./button";
11
+ export function ThemedSelect({ value, groups, onChange, placeholder = "select...", menuPlacement = "bottom", className = "", triggerClassName = "", menuClassName = "", }) {
12
+ const [open, setOpen] = useState(false);
13
+ const ref = useRef(null);
14
+ // Close on outside click
15
+ useEffect(() => {
16
+ if (!open)
17
+ return;
18
+ const handler = (e) => {
19
+ if (ref.current && !ref.current.contains(e.target))
20
+ setOpen(false);
21
+ };
22
+ document.addEventListener("mousedown", handler);
23
+ return () => document.removeEventListener("mousedown", handler);
24
+ }, [open]);
25
+ // Close on Escape
26
+ useEffect(() => {
27
+ if (!open)
28
+ return;
29
+ const handler = (e) => {
30
+ if (e.key === "Escape")
31
+ setOpen(false);
32
+ };
33
+ document.addEventListener("keydown", handler);
34
+ return () => document.removeEventListener("keydown", handler);
35
+ }, [open]);
36
+ // Find current label
37
+ let currentLabel = placeholder;
38
+ for (const g of groups) {
39
+ const found = g.items.find((i) => i.id === value);
40
+ if (found) {
41
+ currentLabel = found.hint ? `${found.text} — ${found.hint}` : found.text;
42
+ break;
43
+ }
44
+ }
45
+ const menuStyle = menuPlacement === "top"
46
+ ? { bottom: "calc(100% + 0.125rem)" }
47
+ : { top: "calc(100% + 0.125rem)" };
48
+ return (_jsxs("div", { ref: ref, className: `relative min-w-0 w-full ${open ? "z-[100]" : ""} ${className}`, children: [_jsxs(Button, { type: "button", variant: "outline", size: "sm", className: `flex h-12 w-full items-center justify-between border-border bg-card px-2.5 py-1.5 text-left text-xs shadow-sm hover:border-accent focus-visible:ring-1 focus-visible:ring-accent ${triggerClassName}`, onClick: () => setOpen(!open), children: [_jsx("span", { className: "truncate", children: currentLabel }), _jsx("span", { className: `ml-2 text-[10px] text-muted transition-transform ${open ? "rotate-180" : ""}`, children: "\u25BC" })] }), open && (_jsx("div", { className: `absolute left-0 right-0 z-50 max-h-[280px] overflow-y-auto rounded-md border border-border bg-card shadow-lg ${menuClassName}`, style: menuStyle, children: groups.map((g) => (_jsxs("div", { children: [_jsx("div", { className: "px-2.5 py-1 text-[10px] font-semibold text-muted bg-bg-muted sticky top-0", children: g.label }), g.items.map((item) => {
49
+ const active = item.id === value;
50
+ return (_jsxs(Button, { variant: "ghost", size: "sm", className: `w-full justify-start text-left px-2.5 py-1.5 h-auto text-xs rounded-none ${active
51
+ ? "bg-accent text-accent-foreground"
52
+ : "text-txt hover:bg-bg-muted"}`, onClick: () => {
53
+ onChange(item.id);
54
+ setOpen(false);
55
+ }, children: [_jsx("span", { className: "font-semibold", children: item.text }), item.hint && (_jsx("span", { className: `ml-1.5 ${active ? "opacity-70" : "text-muted"}`, children: item.hint }))] }, item.id));
56
+ })] }, g.label))) }))] }));
57
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Extended tooltip components for contextual help, icon buttons, guided
3
+ * tours, and spotlight onboarding overlays.
4
+ *
5
+ * All exports here are framework-agnostic (no app context dependency).
6
+ *
7
+ * Note: The Radix-based `Tooltip` is exported from `./tooltip`. This file
8
+ * exports a custom CSS-only hover tooltip (`HoverTooltip`), `IconTooltip`,
9
+ * `Spotlight`, and `useGuidedTour`.
10
+ */
11
+ /**
12
+ * CSS-only hover tooltip that wraps any element in a `<button>` and shows
13
+ * a floating content panel on hover/focus. Supports controlled `visible`
14
+ * mode and an optional dismiss button.
15
+ *
16
+ * Use `IconTooltip` for a div-based (non-button) variant that is safe to
17
+ * wrap interactive children.
18
+ */
19
+ export interface HoverTooltipProps {
20
+ children: React.ReactNode;
21
+ content: React.ReactNode;
22
+ position?: "top" | "bottom" | "left" | "right";
23
+ delay?: number;
24
+ showArrow?: boolean;
25
+ className?: string;
26
+ visible?: boolean;
27
+ onDismiss?: () => void;
28
+ }
29
+ export declare function HoverTooltip({ children, content, position, delay, showArrow, className, visible: controlledVisible, onDismiss, }: HoverTooltipProps): import("react/jsx-runtime").JSX.Element;
30
+ /**
31
+ * Lightweight tooltip for icon buttons.
32
+ *
33
+ * Uses a `<div>` wrapper (not `<button>`) so it can safely wrap interactive
34
+ * elements like icon buttons without nesting buttons.
35
+ */
36
+ export declare function IconTooltip({ children, label, shortcut, position, }: {
37
+ children: React.ReactNode;
38
+ label: string;
39
+ shortcut?: string;
40
+ position?: "top" | "bottom";
41
+ }): import("react/jsx-runtime").JSX.Element;
42
+ export interface SpotlightProps {
43
+ target: string;
44
+ title: string;
45
+ description: string;
46
+ step: number;
47
+ totalSteps: number;
48
+ onNext: () => void;
49
+ onPrev: () => void;
50
+ onSkip: () => void;
51
+ /** Labels to override defaults. */
52
+ labels?: {
53
+ stepOf?: string;
54
+ skipTour?: string;
55
+ previous?: string;
56
+ finish?: string;
57
+ next?: string;
58
+ };
59
+ }
60
+ export declare function Spotlight({ target, title, description, step, totalSteps, onNext, onPrev, onSkip, labels, }: SpotlightProps): import("react/jsx-runtime").JSX.Element | null;
61
+ export interface TourStep {
62
+ target: string;
63
+ title: string;
64
+ description: string;
65
+ }
66
+ export declare function useGuidedTour(steps: TourStep[]): {
67
+ isActive: boolean;
68
+ currentStep: number;
69
+ step: TourStep;
70
+ start: () => void;
71
+ next: () => void;
72
+ prev: () => void;
73
+ skip: () => void;
74
+ totalSteps: number;
75
+ };
76
+ //# sourceMappingURL=tooltip-extended.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooltip-extended.d.ts","sourceRoot":"","sources":["../../../src/components/ui/tooltip-extended.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,OAAO,EACP,QAAgB,EAChB,KAAW,EACX,SAAgB,EAChB,SAAc,EACd,OAAO,EAAE,iBAAiB,EAC1B,SAAS,GACV,EAAE,iBAAiB,2CA8EnB;AAID;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,QAAgB,GACjB,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC7B,2CAuBA;AAID,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,mCAAmC;IACnC,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,wBAAgB,SAAS,CAAC,EACxB,MAAM,EACN,KAAK,EACL,WAAW,EACX,IAAI,EACJ,UAAU,EACV,MAAM,EACN,MAAM,EACN,MAAM,EACN,MAAW,GACZ,EAAE,cAAc,kDAgGhB;AAID,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE;;;;;;;;;EAmC9C"}
@@ -0,0 +1,128 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Extended tooltip components for contextual help, icon buttons, guided
4
+ * tours, and spotlight onboarding overlays.
5
+ *
6
+ * All exports here are framework-agnostic (no app context dependency).
7
+ *
8
+ * Note: The Radix-based `Tooltip` is exported from `./tooltip`. This file
9
+ * exports a custom CSS-only hover tooltip (`HoverTooltip`), `IconTooltip`,
10
+ * `Spotlight`, and `useGuidedTour`.
11
+ */
12
+ import { X } from "lucide-react";
13
+ import { useCallback, useEffect, useRef, useState } from "react";
14
+ export function HoverTooltip({ children, content, position = "top", delay = 300, showArrow = true, className = "", visible: controlledVisible, onDismiss, }) {
15
+ const [isVisible, setIsVisible] = useState(false);
16
+ const timeoutRef = useRef(null);
17
+ const containerRef = useRef(null);
18
+ const isVisibleState = controlledVisible !== undefined ? controlledVisible : isVisible;
19
+ const show = useCallback(() => {
20
+ if (timeoutRef.current)
21
+ clearTimeout(timeoutRef.current);
22
+ timeoutRef.current = setTimeout(() => setIsVisible(true), delay);
23
+ }, [delay]);
24
+ const hide = useCallback(() => {
25
+ if (timeoutRef.current)
26
+ clearTimeout(timeoutRef.current);
27
+ timeoutRef.current = setTimeout(() => setIsVisible(false), 150);
28
+ }, []);
29
+ useEffect(() => {
30
+ return () => {
31
+ if (timeoutRef.current)
32
+ clearTimeout(timeoutRef.current);
33
+ };
34
+ }, []);
35
+ const positionClasses = {
36
+ top: "bottom-full left-1/2 -translate-x-1/2 mb-2",
37
+ bottom: "top-full left-1/2 -translate-x-1/2 mt-2",
38
+ left: "right-full top-1/2 -translate-y-1/2 mr-2",
39
+ right: "left-full top-1/2 -translate-y-1/2 ml-2",
40
+ };
41
+ const arrowClasses = {
42
+ top: "top-full left-1/2 -translate-x-1/2 border-t-border border-l-transparent border-r-transparent border-b-transparent",
43
+ bottom: "bottom-full left-1/2 -translate-x-1/2 border-b-border border-l-transparent border-r-transparent border-t-transparent",
44
+ left: "left-full top-1/2 -translate-y-1/2 border-l-border border-t-transparent border-b-transparent border-r-transparent",
45
+ right: "right-full top-1/2 -translate-y-1/2 border-r-border border-t-transparent border-b-transparent border-l-transparent",
46
+ };
47
+ return (_jsxs("button", { type: "button", ref: containerRef, className: "relative inline-flex bg-transparent border-0 p-0 cursor-default", onMouseEnter: show, onMouseLeave: hide, onFocus: show, onBlur: hide, children: [children, isVisibleState && (_jsx("div", { className: `absolute z-50 ${positionClasses[position]} ${className}`, children: _jsxs("div", { className: "relative bg-bg-elevated border border-border rounded-lg shadow-xl p-3 max-w-xs", children: [onDismiss && (_jsx("button", { type: "button", onClick: onDismiss, className: "absolute top-1 right-1 p-1 text-muted hover:text-txt rounded", "aria-label": "Dismiss tooltip", children: _jsx(X, { className: "w-3 h-3" }) })), content, showArrow && (_jsx("div", { className: `absolute w-0 h-0 border-4 ${arrowClasses[position]}` }))] }) }))] }));
48
+ }
49
+ /* ── IconTooltip ─────────────────────────────────────────────────────── */
50
+ /**
51
+ * Lightweight tooltip for icon buttons.
52
+ *
53
+ * Uses a `<div>` wrapper (not `<button>`) so it can safely wrap interactive
54
+ * elements like icon buttons without nesting buttons.
55
+ */
56
+ export function IconTooltip({ children, label, shortcut, position = "top", }) {
57
+ const posClass = position === "top"
58
+ ? "bottom-full left-1/2 -translate-x-1/2 mb-2"
59
+ : "top-full left-1/2 -translate-x-1/2 mt-2";
60
+ const arrowClass = position === "top"
61
+ ? "top-full left-1/2 -translate-x-1/2 -mt-1 border-4 border-transparent border-t-bg-elevated"
62
+ : "bottom-full left-1/2 -translate-x-1/2 -mb-1 border-4 border-transparent border-b-bg-elevated";
63
+ return (_jsxs("div", { className: "relative group", children: [children, _jsxs("div", { className: `absolute ${posClass} px-2 py-1 bg-bg-elevated border border-border text-[11px] text-txt-strong rounded-md whitespace-nowrap opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50 shadow-lg pointer-events-none`, role: "tooltip", children: [_jsx("div", { className: "font-medium", children: label }), shortcut && _jsx("div", { className: "text-muted mt-0.5", children: shortcut }), _jsx("div", { className: `absolute ${arrowClass}` })] })] }));
64
+ }
65
+ export function Spotlight({ target, title, description, step, totalSteps, onNext, onPrev, onSkip, labels = {}, }) {
66
+ const [targetRect, setTargetRect] = useState(null);
67
+ useEffect(() => {
68
+ const element = document.querySelector(target);
69
+ if (element) {
70
+ const rect = element.getBoundingClientRect();
71
+ setTargetRect(rect);
72
+ }
73
+ }, [target]);
74
+ if (!targetRect)
75
+ return null;
76
+ const padding = 8;
77
+ return (_jsxs("div", { className: "fixed inset-0 z-[300] pointer-events-none", children: [_jsx("div", { className: "absolute inset-0 bg-black/60 pointer-events-auto", style: {
78
+ clipPath: `polygon(
79
+ 0% 0%,
80
+ 0% 100%,
81
+ ${targetRect.left - padding}px 100%,
82
+ ${targetRect.left - padding}px ${targetRect.top - padding}px,
83
+ ${targetRect.right + padding}px ${targetRect.top - padding}px,
84
+ ${targetRect.right + padding}px ${targetRect.bottom + padding}px,
85
+ ${targetRect.left - padding}px ${targetRect.bottom + padding}px,
86
+ ${targetRect.left - padding}px 100%,
87
+ 100% 100%,
88
+ 100% 0%
89
+ )`,
90
+ } }), _jsxs("div", { className: "absolute bg-card border border-border rounded-xl shadow-2xl p-5 max-w-sm pointer-events-auto", style: {
91
+ top: targetRect.bottom + padding + 16,
92
+ left: Math.min(targetRect.left, window.innerWidth - 340),
93
+ }, children: [_jsxs("div", { className: "flex items-center justify-between mb-3", children: [_jsxs("span", { className: "text-xs text-muted font-medium", children: [labels.stepOf ?? "Step", " ", step, " of ", totalSteps] }), _jsx("button", { type: "button", onClick: onSkip, className: "text-xs text-muted hover:text-txt", children: labels.skipTour ?? "Skip Tour" })] }), _jsx("h3", { className: "text-lg font-bold text-txt-strong mb-2", children: title }), _jsx("p", { className: "text-sm text-muted mb-4", children: description }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("button", { type: "button", onClick: onPrev, disabled: step === 1, className: "px-4 py-2 text-sm border border-border rounded-lg disabled:opacity-40 disabled:cursor-not-allowed hover:bg-bg-hover transition-colors", children: labels.previous ?? "Previous" }), _jsx("div", { className: "flex gap-1", children: Array.from({ length: totalSteps }, (_, idx) => idx).map((dotIndex) => (_jsx("div", { className: `w-2 h-2 rounded-full transition-colors ${dotIndex + 1 === step ? "bg-accent" : "bg-border"}` }, `step-dot-${dotIndex}`))) }), _jsx("button", { type: "button", onClick: onNext, className: "px-4 py-2 text-sm bg-accent text-accent-fg rounded-lg hover:opacity-90 transition-opacity", children: step === totalSteps
94
+ ? (labels.finish ?? "Finish")
95
+ : (labels.next ?? "Next") })] })] })] }));
96
+ }
97
+ export function useGuidedTour(steps) {
98
+ const [isActive, setIsActive] = useState(false);
99
+ const [currentStep, setCurrentStep] = useState(0);
100
+ const start = useCallback(() => {
101
+ setIsActive(true);
102
+ setCurrentStep(0);
103
+ }, []);
104
+ const next = useCallback(() => {
105
+ if (currentStep < steps.length - 1) {
106
+ setCurrentStep((prev) => prev + 1);
107
+ }
108
+ else {
109
+ setIsActive(false);
110
+ }
111
+ }, [currentStep, steps.length]);
112
+ const prev = useCallback(() => {
113
+ setCurrentStep((prev) => Math.max(0, prev - 1));
114
+ }, []);
115
+ const skip = useCallback(() => {
116
+ setIsActive(false);
117
+ }, []);
118
+ return {
119
+ isActive,
120
+ currentStep,
121
+ step: steps[currentStep],
122
+ start,
123
+ next,
124
+ prev,
125
+ skip,
126
+ totalSteps: steps.length,
127
+ };
128
+ }
@@ -0,0 +1,8 @@
1
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
2
+ import * as React from "react";
3
+ declare const TooltipProvider: React.FC<TooltipPrimitive.TooltipProviderProps>;
4
+ declare const Tooltip: React.FC<TooltipPrimitive.TooltipProps>;
5
+ declare const TooltipTrigger: React.ForwardRefExoticComponent<TooltipPrimitive.TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>>;
6
+ declare const TooltipContent: React.ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
7
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
8
+ //# sourceMappingURL=tooltip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../src/components/ui/tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,QAAA,MAAM,eAAe,iDAA4B,CAAC;AAElD,QAAA,MAAM,OAAO,yCAAwB,CAAC;AAEtC,QAAA,MAAM,cAAc,gHAA2B,CAAC;AAEhD,QAAA,MAAM,cAAc,gKAalB,CAAC;AAGH,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
3
+ import * as React from "react";
4
+ import { cn } from "../../lib/utils";
5
+ const TooltipProvider = TooltipPrimitive.Provider;
6
+ const Tooltip = TooltipPrimitive.Root;
7
+ const TooltipTrigger = TooltipPrimitive.Trigger;
8
+ const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (_jsx(TooltipPrimitive.Content, { ref: ref, sideOffset: sideOffset, className: cn("z-50 overflow-hidden rounded-md border border-border bg-card px-3 py-1.5 text-sm text-txt shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className), ...props })));
9
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
10
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -0,0 +1,17 @@
1
+ import { type VariantProps } from "class-variance-authority";
2
+ import * as React from "react";
3
+ declare const textVariants: (props?: ({
4
+ variant?: "default" | "small" | "muted" | "medium" | "lead" | "large" | null | undefined;
5
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
+ export interface TextProps extends React.HTMLAttributes<HTMLParagraphElement>, VariantProps<typeof textVariants> {
7
+ asChild?: boolean;
8
+ }
9
+ export declare const Text: React.ForwardRefExoticComponent<TextProps & React.RefAttributes<HTMLParagraphElement>>;
10
+ declare const headingVariants: (props?: ({
11
+ level?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | null | undefined;
12
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
13
+ export interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement>, VariantProps<typeof headingVariants> {
14
+ }
15
+ export declare const Heading: React.ForwardRefExoticComponent<HeadingProps & React.RefAttributes<HTMLHeadingElement>>;
16
+ export {};
17
+ //# sourceMappingURL=typography.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typography.d.ts","sourceRoot":"","sources":["../../../src/components/ui/typography.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,QAAA,MAAM,YAAY;;8EAchB,CAAC;AAEH,MAAM,WAAW,SACf,SAAQ,KAAK,CAAC,cAAc,CAAC,oBAAoB,CAAC,EAChD,YAAY,CAAC,OAAO,YAAY,CAAC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,IAAI,wFAWhB,CAAC;AAGF,QAAA,MAAM,eAAe;;8EAcnB,CAAC;AAEH,MAAM,WAAW,YACf,SAAQ,KAAK,CAAC,cAAc,CAAC,kBAAkB,CAAC,EAC9C,YAAY,CAAC,OAAO,eAAe,CAAC;CAAG;AAE3C,eAAO,MAAM,OAAO,yFAWnB,CAAC"}