@danieljoffe/shared-ui 0.0.1 → 0.1.0

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 (54) hide show
  1. package/dist/index.js +110 -5358
  2. package/dist/lib/Alert.js +72 -0
  3. package/dist/lib/AspectRatio.js +31 -0
  4. package/dist/lib/Avatar.js +47 -0
  5. package/dist/lib/Badge.js +43 -0
  6. package/dist/lib/Breadcrumb.js +28 -0
  7. package/dist/lib/Button.js +82 -0
  8. package/dist/lib/CTACard.js +31 -0
  9. package/dist/lib/Card.js +91 -0
  10. package/dist/lib/Checkbox.js +75 -0
  11. package/dist/lib/Container.js +35 -0
  12. package/dist/lib/Divider.js +48 -0
  13. package/dist/lib/Dropdown.js +158 -0
  14. package/dist/lib/FormFieldError.js +8 -0
  15. package/dist/lib/Grid.js +67 -0
  16. package/dist/lib/GridBg.js +31 -0
  17. package/dist/lib/Heading.js +40 -0
  18. package/dist/lib/Input.js +55 -0
  19. package/dist/lib/Kbd.js +19 -0
  20. package/dist/lib/Loading.js +44 -0
  21. package/dist/lib/Modal.js +119 -0
  22. package/dist/lib/PageContainer.js +35 -0
  23. package/dist/lib/PageLayout.js +25 -0
  24. package/dist/lib/Pagination.js +111 -0
  25. package/dist/lib/ProgressBar.js +68 -0
  26. package/dist/lib/Section.js +58 -0
  27. package/dist/lib/SectionLabel.js +19 -0
  28. package/dist/lib/Select.js +67 -0
  29. package/dist/lib/Sidebar.js +97 -0
  30. package/dist/lib/Skeleton.js +63 -0
  31. package/dist/lib/Spacer.js +17 -0
  32. package/dist/lib/Spinner.js +39 -0
  33. package/dist/lib/Stack.js +59 -0
  34. package/dist/lib/StatsCard.js +79 -0
  35. package/dist/lib/StructuredData.js +15 -0
  36. package/dist/lib/Switch.js +69 -0
  37. package/dist/lib/Table.js +91 -0
  38. package/dist/lib/Tabs.js +101 -0
  39. package/dist/lib/Text.js +48 -0
  40. package/dist/lib/Textarea.js +50 -0
  41. package/dist/lib/ThemeProvider.js +54 -0
  42. package/dist/lib/ThemeToggle.js +29 -0
  43. package/dist/lib/Toast.js +95 -0
  44. package/dist/lib/Tooltip.js +70 -0
  45. package/dist/lib/index.js +112 -0
  46. package/dist/lib/styles/formStyles.js +24 -0
  47. package/dist/lib/styles/semanticVariants.js +27 -0
  48. package/dist/lib/types.js +1 -0
  49. package/dist/lib/utils/ErrorBoundary.js +17 -0
  50. package/dist/lib/utils/ModalErrorBoundary.js +17 -0
  51. package/dist/lib/utils/cn.js +8 -0
  52. package/dist/lib/utils/index.js +10 -0
  53. package/dist/lib/utils/validateProps.js +7 -0
  54. package/package.json +7 -4
@@ -0,0 +1,69 @@
1
+ import { jsxs as d, jsx as n } from "react/jsx-runtime";
2
+ import { useId as b } from "react";
3
+ import { DISABLED as x, FOCUS_RING_OFFSET as v, FOCUS_RING as g } from "./styles/formStyles.js";
4
+ import { Text as I } from "./Text.js";
5
+ import { cn as o } from "./utils/cn.js";
6
+ function F({
7
+ checked: e,
8
+ onChange: c,
9
+ label: t,
10
+ error: r,
11
+ disabled: a = !1,
12
+ className: m,
13
+ id: f,
14
+ ref: u
15
+ }) {
16
+ const p = b(), i = f || p, s = t ? `${i}-label` : void 0, l = r ? `${i}-error` : void 0;
17
+ return /* @__PURE__ */ d("div", { children: [
18
+ /* @__PURE__ */ d("div", { className: "flex items-center gap-2", children: [
19
+ /* @__PURE__ */ n(
20
+ "button",
21
+ {
22
+ ref: u,
23
+ type: "button",
24
+ role: "switch",
25
+ id: i,
26
+ "aria-checked": e,
27
+ "aria-invalid": r ? "true" : void 0,
28
+ "aria-labelledby": s,
29
+ "aria-describedby": l,
30
+ disabled: a,
31
+ onClick: () => c(!e),
32
+ className: o(
33
+ "relative inline-flex h-6 w-11 items-center rounded-full transition-colors motion-reduce:transition-none",
34
+ g,
35
+ v,
36
+ x,
37
+ e ? "bg-brand-500" : "bg-border-strong",
38
+ r && "ring-1 ring-error",
39
+ m
40
+ ),
41
+ children: /* @__PURE__ */ n(
42
+ "span",
43
+ {
44
+ className: o(
45
+ "inline-block h-4 w-4 transform rounded-full bg-surface transition-transform motion-reduce:transition-none",
46
+ e ? "translate-x-6" : "translate-x-1"
47
+ )
48
+ }
49
+ )
50
+ }
51
+ ),
52
+ t && /* @__PURE__ */ n(
53
+ "span",
54
+ {
55
+ id: s,
56
+ className: o(
57
+ "text-text-primary select-none",
58
+ a && "opacity-50 cursor-not-allowed"
59
+ ),
60
+ children: t
61
+ }
62
+ )
63
+ ] }),
64
+ r && /* @__PURE__ */ n(I, { variant: "error", id: l, className: "mt-1.5", role: "alert", children: r })
65
+ ] });
66
+ }
67
+ export {
68
+ F as Switch
69
+ };
@@ -0,0 +1,91 @@
1
+ "use client";
2
+ import { jsx as t, jsxs as f } from "react/jsx-runtime";
3
+ import { Text as y } from "./Text.js";
4
+ import { cn as n } from "./utils/cn.js";
5
+ function D({
6
+ columns: s,
7
+ data: l,
8
+ onRowClick: r,
9
+ striped: x = !1,
10
+ className: h,
11
+ caption: i,
12
+ ariaLabel: m,
13
+ rowKey: o,
14
+ getRowAriaLabel: c
15
+ }) {
16
+ const b = {
17
+ left: "text-left",
18
+ center: "text-center",
19
+ right: "text-right"
20
+ }, p = (e, d) => {
21
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), r?.(d));
22
+ };
23
+ return /* @__PURE__ */ t(
24
+ "div",
25
+ {
26
+ className: n(
27
+ "w-full overflow-x-auto border border-border rounded-xl",
28
+ h
29
+ ),
30
+ children: /* @__PURE__ */ f(
31
+ "table",
32
+ {
33
+ className: "w-full text-sm",
34
+ "aria-label": i ? void 0 : m,
35
+ children: [
36
+ i && /* @__PURE__ */ t("caption", { className: "px-4 py-3 text-left text-sm font-medium text-text-secondary", children: i }),
37
+ /* @__PURE__ */ t("thead", { children: /* @__PURE__ */ t("tr", { className: "border-b border-border bg-surface-secondary", children: s.map((e) => /* @__PURE__ */ t(
38
+ "th",
39
+ {
40
+ scope: "col",
41
+ className: n(
42
+ "px-4 py-3 font-medium text-text-secondary",
43
+ b[e.align || "left"]
44
+ ),
45
+ style: e.width ? { width: e.width } : void 0,
46
+ children: e.header
47
+ },
48
+ e.key
49
+ )) }) }),
50
+ /* @__PURE__ */ f("tbody", { children: [
51
+ l.map((e, d) => {
52
+ const u = o ? o(e) : d;
53
+ return /* @__PURE__ */ t(
54
+ "tr",
55
+ {
56
+ onClick: r ? () => r(e) : void 0,
57
+ onKeyDown: r ? (a) => p(a, e) : void 0,
58
+ tabIndex: r ? 0 : void 0,
59
+ role: r ? "button" : void 0,
60
+ "aria-label": r && c ? c(e) : void 0,
61
+ className: n(
62
+ "border-b border-border last:border-b-0 transition-colors",
63
+ r && "cursor-pointer hover:bg-surface-secondary focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-accent",
64
+ x && d % 2 === 1 && "bg-surface-secondary"
65
+ ),
66
+ children: s.map((a) => /* @__PURE__ */ t(
67
+ "td",
68
+ {
69
+ className: n(
70
+ "px-4 py-3 text-text-primary",
71
+ b[a.align || "left"]
72
+ ),
73
+ children: a.render ? a.render(e) : e[a.key]
74
+ },
75
+ a.key
76
+ ))
77
+ },
78
+ u
79
+ );
80
+ }),
81
+ l.length === 0 && /* @__PURE__ */ t("tr", { children: /* @__PURE__ */ t("td", { colSpan: s.length, className: "px-4 py-12 text-center", children: /* @__PURE__ */ t(y, { variant: "caption", as: "span", children: "No data available" }) }) })
82
+ ] })
83
+ ]
84
+ }
85
+ )
86
+ }
87
+ );
88
+ }
89
+ export {
90
+ D as Table
91
+ };
@@ -0,0 +1,101 @@
1
+ "use client";
2
+ import { jsxs as k, jsx as s } from "react/jsx-runtime";
3
+ import { useState as T, useId as N, useCallback as c } from "react";
4
+ import { cn as i } from "./utils/cn.js";
5
+ function D({
6
+ tabs: r,
7
+ defaultTab: h,
8
+ onChange: m,
9
+ className: p,
10
+ variant: a = "underline",
11
+ ref: g
12
+ }) {
13
+ const v = r[0], [n, y] = T(h ?? v?.id ?? ""), o = N(), u = c(
14
+ (e) => {
15
+ y(e), m?.(e);
16
+ },
17
+ [m]
18
+ ), w = r.find((e) => e.id === n)?.content, l = c(
19
+ (e) => `${o}-tab-${e}`,
20
+ [o]
21
+ ), x = c(
22
+ (e) => `${o}-panel-${e}`,
23
+ [o]
24
+ ), I = c(
25
+ (e, f) => {
26
+ const b = r.findIndex((d) => d.id === f);
27
+ let t = null;
28
+ switch (e.key) {
29
+ case "ArrowRight":
30
+ t = (b + 1) % r.length;
31
+ break;
32
+ case "ArrowLeft":
33
+ t = (b - 1 + r.length) % r.length;
34
+ break;
35
+ case "Home":
36
+ t = 0;
37
+ break;
38
+ case "End":
39
+ t = r.length - 1;
40
+ break;
41
+ }
42
+ if (t !== null) {
43
+ const d = r[t];
44
+ if (!d) return;
45
+ e.preventDefault(), u(d.id), document.getElementById(l(d.id))?.focus();
46
+ }
47
+ },
48
+ [r, u, l]
49
+ );
50
+ return r.length === 0 ? null : /* @__PURE__ */ k("div", { ref: g, className: i("w-full", p), children: [
51
+ /* @__PURE__ */ s("div", { className: a === "underline" ? "border-b border-border" : "", children: /* @__PURE__ */ s(
52
+ "div",
53
+ {
54
+ role: "tablist",
55
+ className: i(
56
+ "flex flex-wrap",
57
+ a === "underline" ? "gap-1" : "gap-1 p-1 bg-surface-tertiary rounded-lg"
58
+ ),
59
+ children: r.map((e) => /* @__PURE__ */ s(
60
+ "button",
61
+ {
62
+ id: l(e.id),
63
+ role: "tab",
64
+ "aria-selected": n === e.id,
65
+ "aria-controls": x(e.id),
66
+ tabIndex: n === e.id ? 0 : -1,
67
+ onClick: () => u(e.id),
68
+ onKeyDown: (f) => I(f, e.id),
69
+ className: i(
70
+ "px-4 py-2.5 transition-colors focus-visible:outline-none",
71
+ "focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2",
72
+ a === "underline" ? i(
73
+ "border-b-2",
74
+ n === e.id ? "border-brand-500 text-brand-500" : "border-transparent text-text-secondary hover:text-text-primary hover:border-border-secondary"
75
+ ) : i(
76
+ "rounded-md text-sm font-medium",
77
+ n === e.id ? "bg-surface text-text-primary shadow-sm" : "text-text-secondary hover:text-text-primary"
78
+ )
79
+ ),
80
+ children: e.label
81
+ },
82
+ e.id
83
+ ))
84
+ }
85
+ ) }),
86
+ /* @__PURE__ */ s(
87
+ "div",
88
+ {
89
+ id: x(n),
90
+ role: "tabpanel",
91
+ tabIndex: 0,
92
+ "aria-labelledby": l(n),
93
+ className: "mt-4",
94
+ children: w
95
+ }
96
+ )
97
+ ] });
98
+ }
99
+ export {
100
+ D as Tabs
101
+ };
@@ -0,0 +1,48 @@
1
+ import { jsx as i } from "react/jsx-runtime";
2
+ import { cn as n } from "./utils/cn.js";
3
+ import "react";
4
+ const d = {
5
+ body: "text-sm text-text-secondary leading-relaxed",
6
+ bodyLg: "text-base text-text-secondary leading-relaxed",
7
+ subtitle: "text-lg text-text-secondary leading-relaxed",
8
+ cardDescription: "text-sm text-text-secondary leading-relaxed",
9
+ detail: "text-xs text-text-secondary",
10
+ label: "text-xs font-semibold uppercase tracking-wider text-text-tertiary",
11
+ meta: "text-xs text-text-tertiary",
12
+ caption: "text-sm text-text-tertiary",
13
+ helper: "text-sm text-text-tertiary",
14
+ error: "text-sm text-error"
15
+ }, l = {
16
+ body: "p",
17
+ bodyLg: "p",
18
+ subtitle: "p",
19
+ cardDescription: "p",
20
+ detail: "p",
21
+ label: "span",
22
+ meta: "span",
23
+ caption: "p",
24
+ helper: "p",
25
+ error: "p"
26
+ };
27
+ function y({
28
+ as: e,
29
+ variant: t,
30
+ className: r,
31
+ children: x,
32
+ ref: a,
33
+ ...s
34
+ }) {
35
+ const o = e ?? l[t];
36
+ return /* @__PURE__ */ i(
37
+ o,
38
+ {
39
+ ref: a,
40
+ className: n(d[t], r),
41
+ ...s,
42
+ children: x
43
+ }
44
+ );
45
+ }
46
+ export {
47
+ y as Text
48
+ };
@@ -0,0 +1,50 @@
1
+ import { jsxs as n, jsx as t } from "react/jsx-runtime";
2
+ import { FORM_LABEL as L, REQUIRED_MARK as p, DISABLED as v, FIELD_PLACEHOLDER as f, FIELD_PADDING as R, BASE_FIELD as h, FIELD_ERROR as F, FIELD_SUCCESS as N } from "./styles/formStyles.js";
3
+ import { Text as o } from "./Text.js";
4
+ import { cn as S } from "./utils/cn.js";
5
+ import "react";
6
+ function g({
7
+ label: s,
8
+ error: e,
9
+ helperText: i,
10
+ success: l,
11
+ className: m,
12
+ id: E,
13
+ required: r,
14
+ ref: D,
15
+ ...I
16
+ }) {
17
+ const a = E || s?.toLowerCase().replace(/\s+/g, "-"), c = e ? `${a}-error` : void 0, d = i && !e ? `${a}-helper` : void 0;
18
+ return /* @__PURE__ */ n("div", { className: "w-full", children: [
19
+ s && /* @__PURE__ */ n("label", { htmlFor: a, className: L, children: [
20
+ s,
21
+ r && /* @__PURE__ */ t("span", { className: p, children: "*" })
22
+ ] }),
23
+ /* @__PURE__ */ t(
24
+ "textarea",
25
+ {
26
+ ref: D,
27
+ id: a,
28
+ "aria-invalid": e ? "true" : void 0,
29
+ "aria-required": r || void 0,
30
+ "aria-describedby": c || d,
31
+ required: r,
32
+ className: S(
33
+ h,
34
+ R,
35
+ f,
36
+ "resize-vertical",
37
+ v,
38
+ e ? F : l ? N : "",
39
+ m
40
+ ),
41
+ ...I
42
+ }
43
+ ),
44
+ e && /* @__PURE__ */ t(o, { variant: "error", id: c, className: "mt-1.5", role: "alert", children: e }),
45
+ i && !e && /* @__PURE__ */ t(o, { variant: "helper", id: d, className: "mt-1.5", children: i })
46
+ ] });
47
+ }
48
+ export {
49
+ g as Textarea
50
+ };
@@ -0,0 +1,54 @@
1
+ "use client";
2
+ import { jsx as T } from "react/jsx-runtime";
3
+ import { createContext as v, useState as h, useEffect as n, useMemo as l, useCallback as f, useContext as w } from "react";
4
+ const g = v({
5
+ theme: "system",
6
+ resolvedTheme: "light",
7
+ isDarkMode: !1,
8
+ setTheme: () => {
9
+ },
10
+ toggleDarkMode: () => {
11
+ }
12
+ });
13
+ function x() {
14
+ return w(g);
15
+ }
16
+ const k = "theme";
17
+ function E() {
18
+ return typeof window > "u" ? !1 : window.matchMedia("(prefers-color-scheme: dark)").matches;
19
+ }
20
+ function p() {
21
+ if (typeof window > "u") return "system";
22
+ const t = localStorage.getItem(k);
23
+ return t === "light" || t === "dark" || t === "system" ? t : "system";
24
+ }
25
+ function C({ children: t }) {
26
+ const [s, a] = h("system"), [m, c] = h(!1);
27
+ n(() => {
28
+ queueMicrotask(() => {
29
+ a(p()), c(E());
30
+ });
31
+ }, []), n(() => {
32
+ const r = window.matchMedia("(prefers-color-scheme: dark)"), u = (M) => {
33
+ c(M.matches);
34
+ };
35
+ return r.addEventListener("change", u), () => r.removeEventListener("change", u);
36
+ }, []);
37
+ const e = l(() => s === "system" ? m : s === "dark", [s, m]), d = e ? "dark" : "light";
38
+ n(() => {
39
+ document.documentElement.classList.toggle("dark", e);
40
+ }, [e]);
41
+ const o = f((r) => {
42
+ a(r), localStorage.setItem(k, r);
43
+ }, []), i = f(() => {
44
+ o(e ? "light" : "dark");
45
+ }, [e, o]), y = l(
46
+ () => ({ theme: s, resolvedTheme: d, isDarkMode: e, setTheme: o, toggleDarkMode: i }),
47
+ [s, d, e, o, i]
48
+ );
49
+ return /* @__PURE__ */ T(g.Provider, { value: y, children: t });
50
+ }
51
+ export {
52
+ C as ThemeProvider,
53
+ x as useTheme
54
+ };
@@ -0,0 +1,29 @@
1
+ "use client";
2
+ import { jsx as t } from "react/jsx-runtime";
3
+ import { Sun as s, Moon as a, Monitor as m } from "lucide-react";
4
+ import { useTheme as c } from "./ThemeProvider.js";
5
+ import { cn as l } from "./utils/cn.js";
6
+ function f() {
7
+ const { theme: o, setTheme: r } = c();
8
+ return /* @__PURE__ */ t("div", { className: "inline-flex items-center gap-0.5 p-0.5 bg-surface-tertiary rounded-lg", children: [
9
+ { value: "light", icon: s, label: "Light" },
10
+ { value: "dark", icon: a, label: "Dark" },
11
+ { value: "system", icon: m, label: "System" }
12
+ ].map(({ value: e, icon: n, label: i }) => /* @__PURE__ */ t(
13
+ "button",
14
+ {
15
+ onClick: () => r(e),
16
+ title: i,
17
+ "aria-pressed": o === e,
18
+ className: l(
19
+ "p-1.5 rounded-md transition-all duration-150 cursor-pointer motion-reduce:transition-none",
20
+ o === e ? "bg-surface text-text-primary shadow-xs" : "text-text-tertiary hover:text-text-secondary"
21
+ ),
22
+ children: /* @__PURE__ */ t(n, { className: "h-4 w-4" })
23
+ },
24
+ e
25
+ )) });
26
+ }
27
+ export {
28
+ f as ThemeToggle
29
+ };
@@ -0,0 +1,95 @@
1
+ "use client";
2
+ import { jsxs as p, jsx as o } from "react/jsx-runtime";
3
+ import { XCircle as C, AlertTriangle as w, CheckCircle as D, Info as N, X as S } from "lucide-react";
4
+ import { createContext as b, useState as v, useCallback as i, useContext as I, useRef as d, useEffect as M } from "react";
5
+ import { Heading as E } from "./Heading.js";
6
+ import { DISMISS_BUTTON as k } from "./styles/formStyles.js";
7
+ import { SEMANTIC_TEXT as R } from "./styles/semanticVariants.js";
8
+ import { Text as _ } from "./Text.js";
9
+ import { cn as f } from "./utils/cn.js";
10
+ const g = b({ toast: () => {
11
+ } });
12
+ function y() {
13
+ return I(g);
14
+ }
15
+ const A = {
16
+ info: N,
17
+ success: D,
18
+ warning: w,
19
+ error: C
20
+ }, U = R, X = 4e3;
21
+ let j = 0;
22
+ function B({
23
+ toast: t,
24
+ onDismiss: a
25
+ }) {
26
+ const c = t.duration ?? X, r = d(null), l = d(c), e = d(Date.now()), [n, s] = v(!1), h = t.variant === "error" || t.variant === "warning", x = A[t.variant], m = i(() => {
27
+ s(!0), setTimeout(() => a(t.id), 150);
28
+ }, [a, t.id]), u = i(() => {
29
+ e.current = Date.now(), r.current = setTimeout(() => {
30
+ m();
31
+ }, l.current);
32
+ }, [m]), T = i(() => {
33
+ r.current && (clearTimeout(r.current), r.current = null, l.current -= Date.now() - e.current);
34
+ }, []);
35
+ return M(() => (u(), () => {
36
+ r.current && clearTimeout(r.current);
37
+ }), [u]), // eslint-disable-next-line jsx-a11y/no-static-element-interactions -- hover/focus pause timer, not user interaction
38
+ /* @__PURE__ */ p(
39
+ "div",
40
+ {
41
+ role: h ? "alert" : "status",
42
+ "aria-atomic": "true",
43
+ onMouseEnter: T,
44
+ onMouseLeave: u,
45
+ onFocus: T,
46
+ onBlur: u,
47
+ className: f(
48
+ "flex items-start gap-3 p-4 bg-surface-elevated border border-border",
49
+ "rounded-lg shadow-lg motion-reduce:animate-none",
50
+ n ? "animate-slide-out-down" : "animate-slide-up"
51
+ ),
52
+ children: [
53
+ /* @__PURE__ */ o(x, { className: f("h-5 w-5 shrink-0", U[t.variant]) }),
54
+ /* @__PURE__ */ p("div", { className: "flex-1 min-w-0", children: [
55
+ /* @__PURE__ */ o(E, { variant: "cardTitle", as: "p", children: t.title }),
56
+ t.description && /* @__PURE__ */ o(_, { variant: "meta", className: "mt-0.5", children: t.description })
57
+ ] }),
58
+ /* @__PURE__ */ o(
59
+ "button",
60
+ {
61
+ onClick: () => m(),
62
+ "aria-label": "Dismiss notification",
63
+ className: f("p-0.5 cursor-pointer", k),
64
+ children: /* @__PURE__ */ o(S, { className: "h-4 w-4" })
65
+ }
66
+ )
67
+ ]
68
+ }
69
+ );
70
+ }
71
+ function G({ children: t }) {
72
+ const [a, c] = v([]), r = i((e) => {
73
+ const n = `toast-${++j}`;
74
+ c((s) => [...s, { ...e, id: n }]);
75
+ }, []), l = i(
76
+ (e) => c((n) => n.filter((s) => s.id !== e)),
77
+ []
78
+ );
79
+ return /* @__PURE__ */ p(g.Provider, { value: { toast: r }, children: [
80
+ t,
81
+ /* @__PURE__ */ o(
82
+ "div",
83
+ {
84
+ "aria-live": "polite",
85
+ "aria-atomic": "true",
86
+ className: "fixed bottom-4 right-4 z-[100] flex flex-col gap-2 max-w-sm",
87
+ children: a.map((e) => /* @__PURE__ */ o(B, { toast: e, onDismiss: l }, e.id))
88
+ }
89
+ )
90
+ ] });
91
+ }
92
+ export {
93
+ G as ToastProvider,
94
+ y as useToast
95
+ };
@@ -0,0 +1,70 @@
1
+ "use client";
2
+ import { jsxs as x, jsx as c } from "react/jsx-runtime";
3
+ import { useState as v, useRef as T, useId as w, useCallback as r, useEffect as E, isValidElement as g, cloneElement as k } from "react";
4
+ import { cn as u } from "./utils/cn.js";
5
+ const I = {
6
+ top: "bottom-full left-1/2 -translate-x-1/2 mb-2",
7
+ bottom: "top-full left-1/2 -translate-x-1/2 mt-2",
8
+ left: "right-full top-1/2 -translate-y-1/2 mr-2",
9
+ right: "left-full top-1/2 -translate-y-1/2 ml-2"
10
+ };
11
+ function K({
12
+ content: p,
13
+ children: o,
14
+ position: d = "top",
15
+ delay: n = 200,
16
+ className: m,
17
+ ref: f
18
+ }) {
19
+ const [i, l] = v(!1), e = T(null), s = w(), a = r(() => {
20
+ e.current = setTimeout(() => {
21
+ l(!0);
22
+ }, n);
23
+ }, [n]), t = r(() => {
24
+ e.current && (clearTimeout(e.current), e.current = null), l(!1);
25
+ }, []), b = r(
26
+ (h) => {
27
+ h.key === "Escape" && t();
28
+ },
29
+ [t]
30
+ );
31
+ E(() => () => {
32
+ e.current && clearTimeout(e.current);
33
+ }, []);
34
+ const y = g(o) ? k(o, {
35
+ "aria-describedby": s
36
+ }) : o;
37
+ return /* @__PURE__ */ x("div", { ref: f, className: u("relative inline-block", m), children: [
38
+ /* @__PURE__ */ c(
39
+ "div",
40
+ {
41
+ onMouseEnter: a,
42
+ onMouseLeave: t,
43
+ onFocus: a,
44
+ onBlur: t,
45
+ onKeyDown: b,
46
+ role: "presentation",
47
+ children: y
48
+ }
49
+ ),
50
+ /* @__PURE__ */ c(
51
+ "div",
52
+ {
53
+ id: s,
54
+ role: "tooltip",
55
+ "aria-hidden": !i,
56
+ className: u(
57
+ "absolute z-50 px-3 py-1.5 bg-surface-elevated border",
58
+ "border-border-secondary rounded-md text-sm text-text-primary",
59
+ "whitespace-nowrap pointer-events-none transition-opacity duration-150",
60
+ I[d],
61
+ i ? "opacity-100" : "opacity-0"
62
+ ),
63
+ children: p
64
+ }
65
+ )
66
+ ] });
67
+ }
68
+ export {
69
+ K as Tooltip
70
+ };