@justanarthur/modo-ui 0.0.0-stage → 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 (172) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSE.beui +21 -0
  3. package/LICENSE.fluid-functionalism +21 -0
  4. package/LICENSE.motion-primitives +21 -0
  5. package/LICENSE.sileo +21 -0
  6. package/README.md +608 -2
  7. package/dist/base.css +994 -0
  8. package/dist/blocks/sidebar-app/index.d.ts +34 -0
  9. package/dist/blocks/sidebar-app/index.js +34 -0
  10. package/dist/components/badge/index.d.ts +59 -0
  11. package/dist/components/badge/index.js +18 -0
  12. package/dist/components/button/index.d.ts +59 -0
  13. package/dist/components/button/index.js +16 -0
  14. package/dist/components/card/index.d.ts +141 -0
  15. package/dist/components/card/index.js +44 -0
  16. package/dist/components/inputs/checkbox-group/index.d.ts +50 -0
  17. package/dist/components/inputs/checkbox-group/index.js +23 -0
  18. package/dist/components/inputs/color-picker/index.d.ts +137 -0
  19. package/dist/components/inputs/color-picker/index.js +37 -0
  20. package/dist/components/inputs/combobox/index.d.ts +161 -0
  21. package/dist/components/inputs/combobox/index.js +41 -0
  22. package/dist/components/inputs/date-time/calendar/index.d.ts +45 -0
  23. package/dist/components/inputs/date-time/calendar/index.js +20 -0
  24. package/dist/components/inputs/date-time/date-picker/index.d.ts +82 -0
  25. package/dist/components/inputs/date-time/date-picker/index.js +34 -0
  26. package/dist/components/inputs/date-time/date-range-picker/index.d.ts +64 -0
  27. package/dist/components/inputs/date-time/date-range-picker/index.js +33 -0
  28. package/dist/components/inputs/date-time/duration-picker/index.d.ts +57 -0
  29. package/dist/components/inputs/date-time/duration-picker/index.js +33 -0
  30. package/dist/components/inputs/date-time/month-picker/index.d.ts +57 -0
  31. package/dist/components/inputs/date-time/month-picker/index.js +32 -0
  32. package/dist/components/inputs/date-time/time-picker/index.d.ts +59 -0
  33. package/dist/components/inputs/date-time/time-picker/index.js +33 -0
  34. package/dist/components/inputs/input/index.d.ts +84 -0
  35. package/dist/components/inputs/input/index.js +20 -0
  36. package/dist/components/inputs/input-copy/index.d.ts +44 -0
  37. package/dist/components/inputs/input-copy/index.js +18 -0
  38. package/dist/components/inputs/input-message/index.d.ts +125 -0
  39. package/dist/components/inputs/input-message/index.js +27 -0
  40. package/dist/components/inputs/radio-group/index.d.ts +58 -0
  41. package/dist/components/inputs/radio-group/index.js +22 -0
  42. package/dist/components/inputs/search/index.d.ts +83 -0
  43. package/dist/components/inputs/search/index.js +28 -0
  44. package/dist/components/inputs/select/index.d.ts +105 -0
  45. package/dist/components/inputs/select/index.js +37 -0
  46. package/dist/components/inputs/slider/index.d.ts +108 -0
  47. package/dist/components/inputs/slider/index.js +16 -0
  48. package/dist/components/inputs/switch/index.d.ts +43 -0
  49. package/dist/components/inputs/switch/index.js +16 -0
  50. package/dist/components/navigation/accordion/index.d.ts +117 -0
  51. package/dist/components/navigation/accordion/index.js +30 -0
  52. package/dist/components/navigation/sidebar/index.d.ts +388 -0
  53. package/dist/components/navigation/sidebar/index.js +101 -0
  54. package/dist/components/navigation/tabs/index.d.ts +70 -0
  55. package/dist/components/navigation/tabs/index.js +25 -0
  56. package/dist/components/navigation/tabs-subtle/index.d.ts +73 -0
  57. package/dist/components/navigation/tabs-subtle/index.js +23 -0
  58. package/dist/components/overlays/alert-dialog/index.d.ts +67 -0
  59. package/dist/components/overlays/alert-dialog/index.js +24 -0
  60. package/dist/components/overlays/command/index.d.ts +121 -0
  61. package/dist/components/overlays/command/index.js +39 -0
  62. package/dist/components/overlays/context-menu/index.d.ts +97 -0
  63. package/dist/components/overlays/context-menu/index.js +32 -0
  64. package/dist/components/overlays/dialog/index.d.ts +130 -0
  65. package/dist/components/overlays/dialog/index.js +39 -0
  66. package/dist/components/overlays/dropdown/index.d.ts +222 -0
  67. package/dist/components/overlays/dropdown/index.js +47 -0
  68. package/dist/components/overlays/popover/index.d.ts +87 -0
  69. package/dist/components/overlays/popover/index.js +28 -0
  70. package/dist/components/overlays/preview-card/index.d.ts +75 -0
  71. package/dist/components/overlays/preview-card/index.js +21 -0
  72. package/dist/components/overlays/sheet/index.d.ts +67 -0
  73. package/dist/components/overlays/sheet/index.js +26 -0
  74. package/dist/components/overlays/toast/index.d.ts +107 -0
  75. package/dist/components/overlays/toast/index.js +23 -0
  76. package/dist/components/overlays/tooltip/index.d.ts +75 -0
  77. package/dist/components/overlays/tooltip/index.js +19 -0
  78. package/dist/components/table/index.d.ts +44 -0
  79. package/dist/components/table/index.js +28 -0
  80. package/dist/components/thinking-indicator/index.d.ts +32 -0
  81. package/dist/components/thinking-indicator/index.js +15 -0
  82. package/dist/index.d.ts +3926 -0
  83. package/dist/index.js +513 -0
  84. package/dist/preset.d.ts +104 -0
  85. package/dist/preset.js +124 -0
  86. package/dist/primitives/code/index.d.ts +23 -0
  87. package/dist/primitives/code/index.js +12 -0
  88. package/dist/primitives/craft/index.d.ts +31 -0
  89. package/dist/primitives/craft/index.js +13 -0
  90. package/dist/primitives/fluid-hover/index.d.ts +233 -0
  91. package/dist/primitives/fluid-hover/index.js +27 -0
  92. package/dist/primitives/morph/index.d.ts +127 -0
  93. package/dist/primitives/morph/index.js +21 -0
  94. package/dist/primitives/motion/index.d.ts +115 -0
  95. package/dist/primitives/motion/index.js +20 -0
  96. package/dist/primitives/scroll-area/index.d.ts +41 -0
  97. package/dist/primitives/scroll-area/index.js +13 -0
  98. package/dist/primitives/sizes/index.d.ts +128 -0
  99. package/dist/primitives/sizes/index.js +22 -0
  100. package/dist/primitives/surface/index.d.ts +69 -0
  101. package/dist/primitives/surface/index.js +18 -0
  102. package/dist/shared/components-0f0as45n.js +17 -0
  103. package/dist/shared/components-40j34hdb.js +986 -0
  104. package/dist/shared/components-4hh0gm0v.js +292 -0
  105. package/dist/shared/components-4xxddc44.js +15 -0
  106. package/dist/shared/components-4xxtggzp.js +110 -0
  107. package/dist/shared/components-54nf2x99.js +293 -0
  108. package/dist/shared/components-5pkcfprd.js +232 -0
  109. package/dist/shared/components-5vxtcp88.js +9 -0
  110. package/dist/shared/components-5zry9te1.js +152 -0
  111. package/dist/shared/components-61ckf42z.js +220 -0
  112. package/dist/shared/components-6hzwfmfd.js +58 -0
  113. package/dist/shared/components-6phwsry6.js +361 -0
  114. package/dist/shared/components-6t6nr33r.js +86 -0
  115. package/dist/shared/components-6y1th6k4.js +111 -0
  116. package/dist/shared/components-74c20v2f.js +32 -0
  117. package/dist/shared/components-7cqq1sqy.js +193 -0
  118. package/dist/shared/components-7gv95yfy.js +496 -0
  119. package/dist/shared/components-7nww01w4.js +375 -0
  120. package/dist/shared/components-7zp99w5d.js +62 -0
  121. package/dist/shared/components-8hk9ve3r.js +1200 -0
  122. package/dist/shared/components-8hzbsfbd.js +123 -0
  123. package/dist/shared/components-9p8s8n5q.js +171 -0
  124. package/dist/shared/components-aaq3yk4f.js +304 -0
  125. package/dist/shared/components-bf2d9k02.js +484 -0
  126. package/dist/shared/components-bkvb6nem.js +63 -0
  127. package/dist/shared/components-brnzrp2t.js +262 -0
  128. package/dist/shared/components-csxz9f52.js +42 -0
  129. package/dist/shared/components-de8xsm9y.js +22 -0
  130. package/dist/shared/components-dg0w8g5p.js +26 -0
  131. package/dist/shared/components-dphg9gjr.js +42 -0
  132. package/dist/shared/components-e46kf6cp.js +298 -0
  133. package/dist/shared/components-ed7cmssr.js +105 -0
  134. package/dist/shared/components-ess3ch6w.js +137 -0
  135. package/dist/shared/components-gjfrycb5.js +984 -0
  136. package/dist/shared/components-gndm6am4.js +128 -0
  137. package/dist/shared/components-hjkrv00c.js +191 -0
  138. package/dist/shared/components-hzfp4tjb.js +270 -0
  139. package/dist/shared/components-j65qt1mq.js +719 -0
  140. package/dist/shared/components-jw16snbn.js +19 -0
  141. package/dist/shared/components-jxgznftn.js +146 -0
  142. package/dist/shared/components-kf2ehztc.js +216 -0
  143. package/dist/shared/components-kpbcms10.js +9 -0
  144. package/dist/shared/components-m5br529r.js +141 -0
  145. package/dist/shared/components-nn6xezy2.js +1828 -0
  146. package/dist/shared/components-nnnd2xef.js +9 -0
  147. package/dist/shared/components-p2vmyfe1.js +345 -0
  148. package/dist/shared/components-peg09pzs.js +79 -0
  149. package/dist/shared/components-r22vtgqc.js +45 -0
  150. package/dist/shared/components-r2gke5p6.js +1759 -0
  151. package/dist/shared/components-r43mqnd6.js +160 -0
  152. package/dist/shared/components-r4jt6hgd.js +58 -0
  153. package/dist/shared/components-rc63qsy6.js +159 -0
  154. package/dist/shared/components-s3yfvfkr.js +149 -0
  155. package/dist/shared/components-s5pkbjx1.js +445 -0
  156. package/dist/shared/components-tad5h7ta.js +346 -0
  157. package/dist/shared/components-taxmgbnh.js +120 -0
  158. package/dist/shared/components-tm88ghva.js +215 -0
  159. package/dist/shared/components-v7es8aan.js +144 -0
  160. package/dist/shared/components-vb033rns.js +28 -0
  161. package/dist/shared/components-vc1k7yv2.js +30 -0
  162. package/dist/shared/components-vktws5r6.js +667 -0
  163. package/dist/shared/components-x2xyckd5.js +198 -0
  164. package/dist/shared/components-x3rz4cyn.js +61 -0
  165. package/dist/shared/components-xszag63d.js +141 -0
  166. package/dist/shared/components-y3cqdrgy.js +291 -0
  167. package/dist/shared/components-zvb11ker.js +288 -0
  168. package/dist/shared/components-zx2hr57f.js +124 -0
  169. package/dist/styles.css +1949 -0
  170. package/dist/tailwind.css +219 -0
  171. package/dist/tokens.css +345 -0
  172. package/package.json +102 -3
@@ -0,0 +1,123 @@
1
+ import {
2
+ SizeProvider
3
+ } from "./components-vb033rns.js";
4
+ import {
5
+ FluidHoverHighlight
6
+ } from "./components-r22vtgqc.js";
7
+ import {
8
+ useFluidHover,
9
+ useRegisterFluidHoverItem
10
+ } from "./components-e46kf6cp.js";
11
+ import {
12
+ useSize
13
+ } from "./components-x3rz4cyn.js";
14
+ import {
15
+ cn
16
+ } from "./components-0f0as45n.js";
17
+
18
+ // components/table/index.tsx
19
+ import {
20
+ createContext,
21
+ forwardRef,
22
+ useContext,
23
+ useMemo,
24
+ useRef
25
+ } from "react";
26
+ import { jsx, jsxs } from "react/jsx-runtime";
27
+ var TableContext = createContext(null);
28
+ var Table = forwardRef(({ children, size, className, ...props }, ref) => {
29
+ const containerRef = useRef(null);
30
+ const sizeClasses = useSize(size);
31
+ const hover = useFluidHover(containerRef);
32
+ const { activeIndex, handlers, registerItem } = hover;
33
+ const contextValue = useMemo(() => ({ registerItem, activeIndex }), [registerItem, activeIndex]);
34
+ const table = /* @__PURE__ */ jsx(TableContext.Provider, {
35
+ value: contextValue,
36
+ children: /* @__PURE__ */ jsxs("div", {
37
+ ref: containerRef,
38
+ className: "relative",
39
+ onMouseEnter: handlers.onMouseEnter,
40
+ onMouseMove: handlers.onMouseMove,
41
+ onMouseLeave: handlers.onMouseLeave,
42
+ onClick: handlers.onClick,
43
+ children: [
44
+ /* @__PURE__ */ jsx(FluidHoverHighlight, {
45
+ hover
46
+ }),
47
+ /* @__PURE__ */ jsx("table", {
48
+ ref,
49
+ className: cn("w-full border-collapse", sizeClasses.text, className),
50
+ ...props,
51
+ children
52
+ })
53
+ ]
54
+ })
55
+ });
56
+ return size ? /* @__PURE__ */ jsx(SizeProvider, {
57
+ size,
58
+ children: table
59
+ }) : table;
60
+ });
61
+ Table.displayName = "Table";
62
+ var TableHeader = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", {
63
+ ref,
64
+ className: cn("", className),
65
+ ...props
66
+ }));
67
+ TableHeader.displayName = "TableHeader";
68
+ var TableBody = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("tbody", {
69
+ ref,
70
+ className: cn("", className),
71
+ ...props
72
+ }));
73
+ TableBody.displayName = "TableBody";
74
+ var TableRow = forwardRef(({ index, className, style, ...props }, ref) => {
75
+ const internalRef = useRef(null);
76
+ const ctx = useContext(TableContext);
77
+ useRegisterFluidHoverItem(ctx?.registerItem, index, internalRef);
78
+ const isBodyRow = index !== undefined;
79
+ const activeIdx = ctx?.activeIndex ?? null;
80
+ const hideBorder = activeIdx !== null && (isBodyRow && (index === activeIdx || index === activeIdx - 1) || !isBodyRow && activeIdx === 0);
81
+ return /* @__PURE__ */ jsx("tr", {
82
+ ref: (node) => {
83
+ internalRef.current = node;
84
+ if (typeof ref === "function")
85
+ ref(node);
86
+ else if (ref)
87
+ ref.current = node;
88
+ },
89
+ "data-fluid-hover-index": index,
90
+ className: cn("group/row relative z-10 border-b transition-[border-color] duration-fast", hideBorder ? "border-transparent" : "border-accent/40", isBodyRow && activeIdx === index && "is-active", isBodyRow ? "weight-normal" : "weight-semibold", className),
91
+ style,
92
+ ...props
93
+ });
94
+ });
95
+ TableRow.displayName = "TableRow";
96
+ var TableHead = forwardRef(({ className, ...props }, ref) => {
97
+ const sizeClasses = useSize();
98
+ return /* @__PURE__ */ jsx("th", {
99
+ ref,
100
+ className: cn("text-left text-foreground", sizeClasses.variant === "compact" ? "px-2.5 py-[5px]" : "px-3 py-2", className),
101
+ ...props
102
+ });
103
+ });
104
+ TableHead.displayName = "TableHead";
105
+ var TableCell = forwardRef(({ className, ...props }, ref) => {
106
+ const sizeClasses = useSize();
107
+ return /* @__PURE__ */ jsx("td", {
108
+ ref,
109
+ className: cn("text-muted-foreground transition-colors duration-fast group-[.is-active]/row:text-foreground", sizeClasses.variant === "compact" ? "px-2.5 py-[5px]" : "px-3 py-2", className),
110
+ ...props
111
+ });
112
+ });
113
+ TableCell.displayName = "TableCell";
114
+ Object.assign(Table, {
115
+ Header: TableHeader,
116
+ Body: TableBody,
117
+ Row: TableRow,
118
+ Head: TableHead,
119
+ Cell: TableCell
120
+ });
121
+ var table_default = Table;
122
+
123
+ export { Table, TableHeader, TableBody, TableRow, TableHead, TableCell, table_default };
@@ -0,0 +1,171 @@
1
+ import {
2
+ useShape
3
+ } from "./components-7zp99w5d.js";
4
+ import {
5
+ useReduceMotion
6
+ } from "./components-nnnd2xef.js";
7
+ import {
8
+ spring
9
+ } from "./components-vc1k7yv2.js";
10
+ import {
11
+ useSizeVariant
12
+ } from "./components-x3rz4cyn.js";
13
+ import {
14
+ cn
15
+ } from "./components-0f0as45n.js";
16
+
17
+ // components/badge/index.tsx
18
+ import { cva } from "class-variance-authority";
19
+ import { AnimatePresence, animate, motion } from "motion/react";
20
+ import { forwardRef, useLayoutEffect, useRef } from "react";
21
+ import { jsx, jsxs } from "react/jsx-runtime";
22
+ var badgeColors = {
23
+ gray: "var(--badge-gray)",
24
+ red: "var(--badge-red)",
25
+ orange: "var(--badge-orange)",
26
+ amber: "var(--badge-amber)",
27
+ yellow: "var(--badge-yellow)",
28
+ lime: "var(--badge-lime)",
29
+ green: "var(--badge-green)",
30
+ emerald: "var(--badge-emerald)",
31
+ teal: "var(--badge-teal)",
32
+ cyan: "var(--badge-cyan)",
33
+ blue: "var(--badge-blue)",
34
+ indigo: "var(--badge-indigo)",
35
+ violet: "var(--badge-violet)",
36
+ purple: "var(--badge-purple)",
37
+ fuchsia: "var(--badge-fuchsia)",
38
+ pink: "var(--badge-pink)",
39
+ rose: "var(--badge-rose)"
40
+ };
41
+ var badgeVariants = cva("inline-flex items-center weight-medium whitespace-nowrap", {
42
+ variants: {
43
+ variant: {
44
+ solid: "",
45
+ dot: "border border-border text-foreground"
46
+ },
47
+ size: {
48
+ default: "h-6 px-2.5 text-caption gap-1.5",
49
+ compact: "h-5 px-2 text-caption-compact gap-1"
50
+ }
51
+ },
52
+ defaultVariants: {
53
+ variant: "solid",
54
+ size: "default"
55
+ }
56
+ });
57
+ var legacySizeAliases = {
58
+ sm: "compact",
59
+ md: "default",
60
+ lg: "default"
61
+ };
62
+ var { exit: _exit, ...enter } = spring.moderate;
63
+ function textOf(node) {
64
+ const parts = Array.isArray(node) ? node : [node];
65
+ if (parts.every((part) => typeof part === "string" || typeof part === "number"))
66
+ return parts.join("");
67
+ }
68
+ function useWidthMorph(change) {
69
+ const content = useRef(null);
70
+ const rest = useRef(0);
71
+ const live = useRef(null);
72
+ const reduced = useReduceMotion();
73
+ useLayoutEffect(() => {
74
+ const el = content.current;
75
+ if (!el)
76
+ return;
77
+ const observer = new ResizeObserver(() => {
78
+ if (live.current === null)
79
+ rest.current = el.offsetWidth;
80
+ });
81
+ observer.observe(el);
82
+ return () => observer.disconnect();
83
+ }, []);
84
+ useLayoutEffect(() => {
85
+ const el = content.current;
86
+ const from = live.current ?? rest.current;
87
+ if (!el || !from)
88
+ return;
89
+ el.style.width = "";
90
+ const to = el.offsetWidth;
91
+ rest.current = to;
92
+ live.current = null;
93
+ if (reduced || from === to)
94
+ return;
95
+ const write = (width) => {
96
+ live.current = width;
97
+ el.style.width = `${width}px`;
98
+ };
99
+ write(from);
100
+ const controls = animate(from, to, {
101
+ ...enter,
102
+ onUpdate: write,
103
+ onComplete: () => {
104
+ live.current = null;
105
+ el.style.width = "";
106
+ }
107
+ });
108
+ return () => controls.stop();
109
+ }, [change, reduced]);
110
+ return content;
111
+ }
112
+ var Badge = forwardRef(({ className, variant = "solid", size: sizeProp, color = "gray", children, style, ...props }, ref) => {
113
+ const shape = useShape();
114
+ const contextSize = useSizeVariant();
115
+ const size = sizeProp ? legacySizeAliases[sizeProp] ?? sizeProp : contextSize === "compact" ? "compact" : "default";
116
+ const colorValue = badgeColors[color];
117
+ const isSolid = variant === "solid";
118
+ const dotSize = size === "compact" ? 6 : 7;
119
+ const colorStyle = isSolid ? color === "gray" ? { backgroundColor: "var(--accent)", color: "var(--foreground)" } : {
120
+ color: "var(--foreground)",
121
+ backgroundColor: `color-mix(in srgb, ${colorValue} 15%, var(--background))`
122
+ } : {};
123
+ const dotColor = color === "gray" ? "var(--muted-foreground)" : colorValue;
124
+ const label = textOf(children);
125
+ const content = useWidthMorph(`${variant} ${size} ${label}`);
126
+ return /* @__PURE__ */ jsx("span", {
127
+ ref,
128
+ className: cn(badgeVariants({ variant, size }), shape.item, "transition-[background-color] duration-moderate", className),
129
+ style: { ...colorStyle, ...style },
130
+ ...props,
131
+ children: /* @__PURE__ */ jsxs("span", {
132
+ ref: content,
133
+ className: "relative inline-flex min-w-0 items-center gap-[inherit] overflow-x-clip",
134
+ children: [
135
+ /* @__PURE__ */ jsx(AnimatePresence, {
136
+ mode: "popLayout",
137
+ initial: false,
138
+ children: !isSolid && /* @__PURE__ */ jsx(motion.span, {
139
+ className: "shrink-0 rounded-full transition-[background-color] duration-moderate",
140
+ style: {
141
+ width: dotSize,
142
+ height: dotSize,
143
+ backgroundColor: dotColor
144
+ },
145
+ initial: { opacity: 0, scale: 0 },
146
+ animate: { opacity: 1, scale: 1 },
147
+ exit: { opacity: 0, scale: 0, transition: spring.moderate.exit },
148
+ transition: enter
149
+ }, "dot")
150
+ }),
151
+ /* @__PURE__ */ jsx(AnimatePresence, {
152
+ mode: "popLayout",
153
+ initial: false,
154
+ children: /* @__PURE__ */ jsx(motion.span, {
155
+ layout: "position",
156
+ className: "[text-box:trim-both_cap_alphabetic]",
157
+ initial: { opacity: 0, filter: "blur(4px)" },
158
+ animate: { opacity: 1, filter: "blur(0px)", transitionEnd: { filter: "none" } },
159
+ exit: { opacity: 0, filter: "blur(4px)", transition: spring.moderate.exit },
160
+ transition: enter,
161
+ children
162
+ }, label ?? "label")
163
+ })
164
+ ]
165
+ })
166
+ });
167
+ });
168
+ Badge.displayName = "Badge";
169
+ var badge_default = Badge;
170
+
171
+ export { badgeColors, badgeVariants, Badge, badge_default };
@@ -0,0 +1,304 @@
1
+ import {
2
+ SizeProvider
3
+ } from "./components-vb033rns.js";
4
+ import {
5
+ useFluidHover
6
+ } from "./components-e46kf6cp.js";
7
+ import {
8
+ useShape
9
+ } from "./components-7zp99w5d.js";
10
+ import {
11
+ useControllableState
12
+ } from "./components-dg0w8g5p.js";
13
+ import {
14
+ GooIndicator
15
+ } from "./components-kf2ehztc.js";
16
+ import {
17
+ spring
18
+ } from "./components-vc1k7yv2.js";
19
+ import {
20
+ useSize
21
+ } from "./components-x3rz4cyn.js";
22
+ import {
23
+ cn
24
+ } from "./components-0f0as45n.js";
25
+
26
+ // components/navigation/tabs-subtle/index.tsx
27
+ import { Tabs } from "@base-ui/react/tabs";
28
+ import { AnimatePresence, motion } from "motion/react";
29
+ import {
30
+ Children,
31
+ createContext,
32
+ forwardRef,
33
+ isValidElement,
34
+ useCallback,
35
+ useContext,
36
+ useEffect,
37
+ useId,
38
+ useRef,
39
+ useState
40
+ } from "react";
41
+ import { jsx, jsxs } from "react/jsx-runtime";
42
+ var TabsSubtleContext = createContext(null);
43
+ var isPanel = (child) => isValidElement(child) && child.type === TabsSubtlePanel;
44
+ function useTabsSubtle() {
45
+ const ctx = useContext(TabsSubtleContext);
46
+ if (!ctx)
47
+ throw new Error("useTabsSubtle must be used within a TabsSubtle");
48
+ return ctx;
49
+ }
50
+ var TabsSubtle = forwardRef(({
51
+ children,
52
+ selectedIndex: selectedIndexProp,
53
+ defaultSelectedIndex = 0,
54
+ onSelect: onSelectProp,
55
+ idPrefix,
56
+ activeLabel = false,
57
+ size,
58
+ className,
59
+ ...props
60
+ }, ref) => {
61
+ const [selectedIndex, onSelect] = useControllableState(selectedIndexProp, defaultSelectedIndex, onSelectProp);
62
+ const childList = Children.toArray(children);
63
+ const panels = childList.filter(isPanel);
64
+ const tabs = childList.filter((child) => !isPanel(child));
65
+ const generatedIdPrefix = useId();
66
+ const resolvedIdPrefix = idPrefix ?? (panels.length > 0 ? generatedIdPrefix : undefined);
67
+ const containerRef = useRef(null);
68
+ const isMouseInside = useRef(false);
69
+ const shape = useShape();
70
+ const {
71
+ activeIndex: hoveredIndex,
72
+ setActiveIndex: setHoveredIndex,
73
+ itemRects: tabRects,
74
+ handlers,
75
+ registerItem,
76
+ measureItems: measureTabs
77
+ } = useFluidHover(containerRef, { axis: "x" });
78
+ const tabElementsRef = useRef(new Map);
79
+ const registerTab = useCallback((index, element) => {
80
+ registerItem(index, element);
81
+ if (element) {
82
+ tabElementsRef.current.set(index, element);
83
+ } else {
84
+ tabElementsRef.current.delete(index);
85
+ }
86
+ }, [registerItem]);
87
+ useEffect(() => {
88
+ measureTabs();
89
+ }, [measureTabs, children]);
90
+ useEffect(() => {
91
+ const elements = tabElementsRef.current;
92
+ if (elements.size === 0)
93
+ return;
94
+ const ro = new ResizeObserver(() => measureTabs());
95
+ elements.forEach((el) => ro.observe(el));
96
+ return () => ro.disconnect();
97
+ }, [measureTabs, children]);
98
+ const handleMouseMove = useCallback((e) => {
99
+ isMouseInside.current = true;
100
+ handlers.onMouseMove(e);
101
+ }, [handlers]);
102
+ const handleMouseLeave = useCallback(() => {
103
+ isMouseInside.current = false;
104
+ handlers.onMouseLeave();
105
+ }, [handlers]);
106
+ const [focusedIndex, setFocusedIndex] = useState(null);
107
+ const selectedRect = tabRects[selectedIndex];
108
+ const hoverRect = hoveredIndex !== null ? tabRects[hoveredIndex] : null;
109
+ const focusRect = focusedIndex !== null ? tabRects[focusedIndex] : null;
110
+ const isHoveringSelected = hoveredIndex === selectedIndex;
111
+ const isHovering = hoveredIndex !== null && !isHoveringSelected;
112
+ const root = /* @__PURE__ */ jsxs(TabsSubtleContext.Provider, {
113
+ value: {
114
+ registerTab,
115
+ hoveredIndex,
116
+ selectedIndex,
117
+ idPrefix: resolvedIdPrefix,
118
+ activeLabel
119
+ },
120
+ children: [
121
+ /* @__PURE__ */ jsx(Tabs.Root, {
122
+ value: selectedIndex,
123
+ onValueChange: (value) => {
124
+ if (typeof value === "number")
125
+ onSelect(value);
126
+ },
127
+ render: /* @__PURE__ */ jsxs(Tabs.List, {
128
+ activateOnFocus: false,
129
+ ref: (node) => {
130
+ containerRef.current = node;
131
+ if (typeof ref === "function")
132
+ ref(node);
133
+ else if (ref)
134
+ ref.current = node;
135
+ },
136
+ onMouseMove: handleMouseMove,
137
+ onMouseLeave: handleMouseLeave,
138
+ onFocus: (e) => {
139
+ const indexAttr = e.target.closest("[data-fluid-hover-index]")?.getAttribute("data-fluid-hover-index");
140
+ if (indexAttr != null) {
141
+ const idx = Number(indexAttr);
142
+ setHoveredIndex(idx);
143
+ setFocusedIndex(e.target.matches(":focus-visible") ? idx : null);
144
+ }
145
+ },
146
+ onBlur: (e) => {
147
+ if (containerRef.current?.contains(e.relatedTarget))
148
+ return;
149
+ setFocusedIndex(null);
150
+ if (isMouseInside.current)
151
+ return;
152
+ setHoveredIndex(null);
153
+ },
154
+ className: cn("relative flex items-center select-none overflow-x-auto max-w-[calc(100%_+_8px)] scrollbar-hide -mx-1 px-1 -my-1 py-1", className),
155
+ ...props,
156
+ children: [
157
+ selectedRect && /* @__PURE__ */ jsx(GooIndicator, {
158
+ rect: selectedRect,
159
+ className: cn("bg-active", shape.bg),
160
+ opacity: isHovering ? 0.8 : 1
161
+ }),
162
+ selectedRect && /* @__PURE__ */ jsx(GooIndicator, {
163
+ rect: isHovering && hoverRect ? hoverRect : selectedRect,
164
+ className: cn("bg-active", shape.bg),
165
+ transition: spring.fast,
166
+ opacity: isHovering ? 0.4 : 0
167
+ }),
168
+ /* @__PURE__ */ jsx(AnimatePresence, {
169
+ children: focusRect && /* @__PURE__ */ jsx(motion.div, {
170
+ className: cn("absolute pointer-events-none z-20 border border-focus-ring", shape.focusRing),
171
+ initial: false,
172
+ animate: {
173
+ left: focusRect.left - 2,
174
+ top: focusRect.top - 2,
175
+ width: focusRect.width + 4,
176
+ height: focusRect.height + 4
177
+ },
178
+ exit: { opacity: 0, transition: spring.fast.exit },
179
+ transition: {
180
+ ...spring.fast,
181
+ opacity: { duration: spring.fast.duration }
182
+ }
183
+ })
184
+ }),
185
+ tabs
186
+ ]
187
+ })
188
+ }),
189
+ panels
190
+ ]
191
+ });
192
+ return size ? /* @__PURE__ */ jsx(SizeProvider, {
193
+ size,
194
+ children: root
195
+ }) : root;
196
+ });
197
+ TabsSubtle.displayName = "TabsSubtle";
198
+ var TabsSubtleItem = forwardRef(({ icon: Icon, label, index, className, ...props }, ref) => {
199
+ const internalRef = useRef(null);
200
+ const [labelWidth, setLabelWidth] = useState(null);
201
+ const labelRoRef = useRef(null);
202
+ const measureLabel = useCallback((el) => {
203
+ labelRoRef.current?.disconnect();
204
+ labelRoRef.current = null;
205
+ if (!el)
206
+ return;
207
+ const update = () => setLabelWidth(el.offsetWidth);
208
+ update();
209
+ labelRoRef.current = new ResizeObserver(update);
210
+ labelRoRef.current.observe(el);
211
+ }, []);
212
+ const shape = useShape();
213
+ const sizeClasses = useSize();
214
+ const { registerTab, hoveredIndex, selectedIndex, idPrefix, activeLabel } = useTabsSubtle();
215
+ useEffect(() => {
216
+ registerTab(index, internalRef.current);
217
+ return () => registerTab(index, null);
218
+ }, [index, registerTab]);
219
+ const isSelected = selectedIndex === index;
220
+ const isActive = hoveredIndex === index || isSelected;
221
+ const collapseLabel = activeLabel && !!Icon;
222
+ const showLabel = !collapseLabel || isSelected;
223
+ const labelContent = /* @__PURE__ */ jsxs("span", {
224
+ ref: measureLabel,
225
+ className: cn("inline-grid whitespace-nowrap", sizeClasses.text),
226
+ children: [
227
+ /* @__PURE__ */ jsx("span", {
228
+ className: "col-start-1 row-start-1 invisible [text-box:trim-both_cap_alphabetic] weight-semibold",
229
+ "aria-hidden": "true",
230
+ children: label
231
+ }),
232
+ /* @__PURE__ */ jsx("span", {
233
+ className: cn("col-start-1 row-start-1 transition-[color,font-variation-settings] duration-fast [text-box:trim-both_cap_alphabetic]", isActive ? "text-foreground" : "text-muted-foreground", isSelected ? "weight-semibold" : "weight-normal"),
234
+ children: label
235
+ })
236
+ ]
237
+ });
238
+ return /* @__PURE__ */ jsxs(Tabs.Tab, {
239
+ ref: (node) => {
240
+ const button = node;
241
+ internalRef.current = button;
242
+ if (typeof ref === "function")
243
+ ref(button);
244
+ else if (ref)
245
+ ref.current = button;
246
+ },
247
+ value: index,
248
+ "data-fluid-hover-index": index,
249
+ id: idPrefix ? `${idPrefix}-tab-${index}` : undefined,
250
+ "aria-controls": idPrefix ? `${idPrefix}-panel-${index}` : undefined,
251
+ "aria-label": collapseLabel && !showLabel ? label : undefined,
252
+ className: cn("relative z-10 flex items-center cursor-pointer bg-transparent border-none outline-none", sizeClasses.control, sizeClasses.px, !collapseLabel && sizeClasses.gap, shape.bg, className),
253
+ ...props,
254
+ children: [
255
+ Icon && /* @__PURE__ */ jsx(Icon, {
256
+ size: sizeClasses.icon,
257
+ strokeWidth: isActive ? 2 : 1.5,
258
+ className: cn("shrink-0 transition-[color,stroke-width] duration-fast", isActive ? "text-foreground" : "text-muted-foreground")
259
+ }),
260
+ collapseLabel ? /* @__PURE__ */ jsx(AnimatePresence, {
261
+ initial: false,
262
+ children: showLabel && /* @__PURE__ */ jsx(motion.span, {
263
+ className: "overflow-hidden",
264
+ style: labelWidth == null ? { width: "auto" } : undefined,
265
+ initial: { width: 0, opacity: 0, marginLeft: 0 },
266
+ animate: {
267
+ ...labelWidth != null ? { width: labelWidth } : null,
268
+ opacity: 1,
269
+ marginLeft: sizeClasses.variant === "compact" ? 6 : 8
270
+ },
271
+ exit: { width: 0, opacity: 0, marginLeft: 0 },
272
+ transition: {
273
+ ...spring.fast,
274
+ opacity: { duration: spring.fast.exit.duration }
275
+ },
276
+ children: labelContent
277
+ }, "label")
278
+ }) : labelContent
279
+ ]
280
+ });
281
+ });
282
+ TabsSubtleItem.displayName = "TabsSubtleItem";
283
+ var TabsSubtlePanel = forwardRef(({ index, selectedIndex, idPrefix, children, className, ...props }, ref) => {
284
+ const ctx = useContext(TabsSubtleContext);
285
+ const resolvedSelectedIndex = selectedIndex ?? ctx?.selectedIndex ?? -1;
286
+ const resolvedIdPrefix = idPrefix ?? ctx?.idPrefix;
287
+ const isSelected = resolvedSelectedIndex === index;
288
+ return /* @__PURE__ */ jsx("div", {
289
+ ref,
290
+ id: resolvedIdPrefix ? `${resolvedIdPrefix}-panel-${index}` : undefined,
291
+ role: "tabpanel",
292
+ "aria-labelledby": resolvedIdPrefix ? `${resolvedIdPrefix}-tab-${index}` : undefined,
293
+ hidden: !isSelected,
294
+ tabIndex: -1,
295
+ className: cn("outline-none", className),
296
+ ...props,
297
+ children: isSelected && children
298
+ });
299
+ });
300
+ TabsSubtlePanel.displayName = "TabsSubtlePanel";
301
+ Object.assign(TabsSubtle, { Item: TabsSubtleItem, Panel: TabsSubtlePanel });
302
+ var tabs_subtle_default = TabsSubtle;
303
+
304
+ export { TabsSubtle, TabsSubtleItem, TabsSubtlePanel, tabs_subtle_default };