@stackframe/dashboard-ui-components 2.8.76

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 (169) hide show
  1. package/LICENSE +5 -0
  2. package/dist/chunk-BE-pF4vm.js +34 -0
  3. package/dist/components/alert.d.ts +22 -0
  4. package/dist/components/alert.d.ts.map +1 -0
  5. package/dist/components/alert.js +75 -0
  6. package/dist/components/alert.js.map +1 -0
  7. package/dist/components/badge.d.ts +24 -0
  8. package/dist/components/badge.d.ts.map +1 -0
  9. package/dist/components/badge.js +59 -0
  10. package/dist/components/badge.js.map +1 -0
  11. package/dist/components/button.d.ts +32 -0
  12. package/dist/components/button.d.ts.map +1 -0
  13. package/dist/components/button.js +68 -0
  14. package/dist/components/button.js.map +1 -0
  15. package/dist/components/card.d.ts +59 -0
  16. package/dist/components/card.d.ts.map +1 -0
  17. package/dist/components/card.js +133 -0
  18. package/dist/components/card.js.map +1 -0
  19. package/dist/components/chart-card.d.ts +21 -0
  20. package/dist/components/chart-card.d.ts.map +1 -0
  21. package/dist/components/chart-card.js +54 -0
  22. package/dist/components/chart-card.js.map +1 -0
  23. package/dist/components/chart-container.d.ts +51 -0
  24. package/dist/components/chart-container.d.ts.map +1 -0
  25. package/dist/components/chart-container.js +77 -0
  26. package/dist/components/chart-container.js.map +1 -0
  27. package/dist/components/chart-legend.d.ts +12 -0
  28. package/dist/components/chart-legend.d.ts.map +1 -0
  29. package/dist/components/chart-legend.js +41 -0
  30. package/dist/components/chart-legend.js.map +1 -0
  31. package/dist/components/chart-theme.d.ts +26 -0
  32. package/dist/components/chart-theme.d.ts.map +1 -0
  33. package/dist/components/chart-theme.js +64 -0
  34. package/dist/components/chart-theme.js.map +1 -0
  35. package/dist/components/chart-tooltip.d.ts +41 -0
  36. package/dist/components/chart-tooltip.d.ts.map +1 -0
  37. package/dist/components/chart-tooltip.js +89 -0
  38. package/dist/components/chart-tooltip.js.map +1 -0
  39. package/dist/components/cursor-blast-effect.d.ts +27 -0
  40. package/dist/components/cursor-blast-effect.d.ts.map +1 -0
  41. package/dist/components/cursor-blast-effect.js +243 -0
  42. package/dist/components/cursor-blast-effect.js.map +1 -0
  43. package/dist/components/edit-mode.d.ts +12 -0
  44. package/dist/components/edit-mode.d.ts.map +1 -0
  45. package/dist/components/edit-mode.js +23 -0
  46. package/dist/components/edit-mode.js.map +1 -0
  47. package/dist/components/empty-state.d.ts +21 -0
  48. package/dist/components/empty-state.d.ts.map +1 -0
  49. package/dist/components/empty-state.js +37 -0
  50. package/dist/components/empty-state.js.map +1 -0
  51. package/dist/components/input.d.ts +18 -0
  52. package/dist/components/input.d.ts.map +1 -0
  53. package/dist/components/input.js +53 -0
  54. package/dist/components/input.js.map +1 -0
  55. package/dist/components/metric-card.d.ts +31 -0
  56. package/dist/components/metric-card.d.ts.map +1 -0
  57. package/dist/components/metric-card.js +88 -0
  58. package/dist/components/metric-card.js.map +1 -0
  59. package/dist/components/pill-toggle.d.ts +33 -0
  60. package/dist/components/pill-toggle.d.ts.map +1 -0
  61. package/dist/components/pill-toggle.js +86 -0
  62. package/dist/components/pill-toggle.js.map +1 -0
  63. package/dist/components/progress-bar.d.ts +25 -0
  64. package/dist/components/progress-bar.d.ts.map +1 -0
  65. package/dist/components/progress-bar.js +44 -0
  66. package/dist/components/progress-bar.js.map +1 -0
  67. package/dist/components/separator.d.ts +14 -0
  68. package/dist/components/separator.d.ts.map +1 -0
  69. package/dist/components/separator.js +20 -0
  70. package/dist/components/separator.js.map +1 -0
  71. package/dist/components/skeleton.d.ts +12 -0
  72. package/dist/components/skeleton.d.ts.map +1 -0
  73. package/dist/components/skeleton.js +18 -0
  74. package/dist/components/skeleton.js.map +1 -0
  75. package/dist/components/table.d.ts +24 -0
  76. package/dist/components/table.d.ts.map +1 -0
  77. package/dist/components/table.js +59 -0
  78. package/dist/components/table.js.map +1 -0
  79. package/dist/components/tabs.d.ts +34 -0
  80. package/dist/components/tabs.d.ts.map +1 -0
  81. package/dist/components/tabs.js +100 -0
  82. package/dist/components/tabs.js.map +1 -0
  83. package/dist/dashboard-ui-components.global.js +15232 -0
  84. package/dist/dashboard-ui-components.global.js.map +7 -0
  85. package/dist/esm/components/alert.d.ts +22 -0
  86. package/dist/esm/components/alert.d.ts.map +1 -0
  87. package/dist/esm/components/alert.js +73 -0
  88. package/dist/esm/components/alert.js.map +1 -0
  89. package/dist/esm/components/badge.d.ts +24 -0
  90. package/dist/esm/components/badge.d.ts.map +1 -0
  91. package/dist/esm/components/badge.js +57 -0
  92. package/dist/esm/components/badge.js.map +1 -0
  93. package/dist/esm/components/button.d.ts +32 -0
  94. package/dist/esm/components/button.d.ts.map +1 -0
  95. package/dist/esm/components/button.js +65 -0
  96. package/dist/esm/components/button.js.map +1 -0
  97. package/dist/esm/components/card.d.ts +59 -0
  98. package/dist/esm/components/card.d.ts.map +1 -0
  99. package/dist/esm/components/card.js +127 -0
  100. package/dist/esm/components/card.js.map +1 -0
  101. package/dist/esm/components/chart-card.d.ts +21 -0
  102. package/dist/esm/components/chart-card.d.ts.map +1 -0
  103. package/dist/esm/components/chart-card.js +51 -0
  104. package/dist/esm/components/chart-card.js.map +1 -0
  105. package/dist/esm/components/chart-container.d.ts +51 -0
  106. package/dist/esm/components/chart-container.d.ts.map +1 -0
  107. package/dist/esm/components/chart-container.js +70 -0
  108. package/dist/esm/components/chart-container.js.map +1 -0
  109. package/dist/esm/components/chart-legend.d.ts +12 -0
  110. package/dist/esm/components/chart-legend.d.ts.map +1 -0
  111. package/dist/esm/components/chart-legend.js +36 -0
  112. package/dist/esm/components/chart-legend.js.map +1 -0
  113. package/dist/esm/components/chart-theme.d.ts +26 -0
  114. package/dist/esm/components/chart-theme.d.ts.map +1 -0
  115. package/dist/esm/components/chart-theme.js +59 -0
  116. package/dist/esm/components/chart-theme.js.map +1 -0
  117. package/dist/esm/components/chart-tooltip.d.ts +41 -0
  118. package/dist/esm/components/chart-tooltip.d.ts.map +1 -0
  119. package/dist/esm/components/chart-tooltip.js +84 -0
  120. package/dist/esm/components/chart-tooltip.js.map +1 -0
  121. package/dist/esm/components/cursor-blast-effect.d.ts +27 -0
  122. package/dist/esm/components/cursor-blast-effect.d.ts.map +1 -0
  123. package/dist/esm/components/cursor-blast-effect.js +241 -0
  124. package/dist/esm/components/cursor-blast-effect.js.map +1 -0
  125. package/dist/esm/components/edit-mode.d.ts +12 -0
  126. package/dist/esm/components/edit-mode.d.ts.map +1 -0
  127. package/dist/esm/components/edit-mode.js +20 -0
  128. package/dist/esm/components/edit-mode.js.map +1 -0
  129. package/dist/esm/components/empty-state.d.ts +21 -0
  130. package/dist/esm/components/empty-state.d.ts.map +1 -0
  131. package/dist/esm/components/empty-state.js +34 -0
  132. package/dist/esm/components/empty-state.js.map +1 -0
  133. package/dist/esm/components/input.d.ts +18 -0
  134. package/dist/esm/components/input.d.ts.map +1 -0
  135. package/dist/esm/components/input.js +50 -0
  136. package/dist/esm/components/input.js.map +1 -0
  137. package/dist/esm/components/metric-card.d.ts +31 -0
  138. package/dist/esm/components/metric-card.d.ts.map +1 -0
  139. package/dist/esm/components/metric-card.js +85 -0
  140. package/dist/esm/components/metric-card.js.map +1 -0
  141. package/dist/esm/components/pill-toggle.d.ts +33 -0
  142. package/dist/esm/components/pill-toggle.d.ts.map +1 -0
  143. package/dist/esm/components/pill-toggle.js +84 -0
  144. package/dist/esm/components/pill-toggle.js.map +1 -0
  145. package/dist/esm/components/progress-bar.d.ts +25 -0
  146. package/dist/esm/components/progress-bar.d.ts.map +1 -0
  147. package/dist/esm/components/progress-bar.js +42 -0
  148. package/dist/esm/components/progress-bar.js.map +1 -0
  149. package/dist/esm/components/separator.d.ts +14 -0
  150. package/dist/esm/components/separator.d.ts.map +1 -0
  151. package/dist/esm/components/separator.js +18 -0
  152. package/dist/esm/components/separator.js.map +1 -0
  153. package/dist/esm/components/skeleton.d.ts +12 -0
  154. package/dist/esm/components/skeleton.d.ts.map +1 -0
  155. package/dist/esm/components/skeleton.js +16 -0
  156. package/dist/esm/components/skeleton.js.map +1 -0
  157. package/dist/esm/components/table.d.ts +24 -0
  158. package/dist/esm/components/table.d.ts.map +1 -0
  159. package/dist/esm/components/table.js +51 -0
  160. package/dist/esm/components/table.js.map +1 -0
  161. package/dist/esm/components/tabs.d.ts +34 -0
  162. package/dist/esm/components/tabs.d.ts.map +1 -0
  163. package/dist/esm/components/tabs.js +98 -0
  164. package/dist/esm/components/tabs.js.map +1 -0
  165. package/dist/esm/index.d.ts +21 -0
  166. package/dist/esm/index.js +22 -0
  167. package/dist/index.d.ts +21 -0
  168. package/dist/index.js +245 -0
  169. package/package.json +71 -0
@@ -0,0 +1,241 @@
1
+ "use client";
2
+
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { useEffect, useRef, useState } from "react";
5
+ import { createPortal } from "react-dom";
6
+
7
+ //#region src/components/cursor-blast-effect.tsx
8
+ const DEFAULT_BLAST_LIFETIME_MS = 720;
9
+ const DEFAULT_MAX_ACTIVE_BLASTS = 18;
10
+ /** Minimum rapid clicks in the time window to count as a rage click */
11
+ const DEFAULT_RAGE_CLICK_THRESHOLD = 3;
12
+ /** Time window (ms) in which clicks must occur to be considered rage clicking */
13
+ const DEFAULT_RAGE_CLICK_WINDOW_MS = 600;
14
+ /** Max distance (px) between clicks to still count as same-spot rage clicking */
15
+ const DEFAULT_RAGE_CLICK_RADIUS_PX = 60;
16
+ function CursorBlastEffect({ blastLifetimeMs = DEFAULT_BLAST_LIFETIME_MS, maxActiveBlasts = DEFAULT_MAX_ACTIVE_BLASTS, rageClickThreshold = DEFAULT_RAGE_CLICK_THRESHOLD, rageClickWindowMs = DEFAULT_RAGE_CLICK_WINDOW_MS, rageClickRadiusPx = DEFAULT_RAGE_CLICK_RADIUS_PX, containerRef } = {}) {
17
+ const [blasts, setBlasts] = useState([]);
18
+ const [mounted, setMounted] = useState(false);
19
+ const idCounterRef = useRef(0);
20
+ const timeoutIdsRef = useRef(/* @__PURE__ */ new Map());
21
+ const recentClicksRef = useRef([]);
22
+ const configRef = useRef({
23
+ blastLifetimeMs,
24
+ maxActiveBlasts,
25
+ rageClickThreshold,
26
+ rageClickWindowMs,
27
+ rageClickRadiusPx
28
+ });
29
+ configRef.current = {
30
+ blastLifetimeMs,
31
+ maxActiveBlasts,
32
+ rageClickThreshold,
33
+ rageClickWindowMs,
34
+ rageClickRadiusPx
35
+ };
36
+ useEffect(() => {
37
+ setMounted(true);
38
+ }, []);
39
+ useEffect(() => {
40
+ const removeBlast = (id) => {
41
+ setBlasts((prev) => prev.filter((blast) => blast.id !== id));
42
+ const timeoutId = timeoutIdsRef.current.get(id);
43
+ if (timeoutId !== void 0) {
44
+ window.clearTimeout(timeoutId);
45
+ timeoutIdsRef.current.delete(id);
46
+ }
47
+ };
48
+ const spawnBlast = (x, y) => {
49
+ const cfg = configRef.current;
50
+ const nextId = idCounterRef.current;
51
+ idCounterRef.current += 1;
52
+ const nextBlast = {
53
+ id: nextId,
54
+ x,
55
+ y,
56
+ size: 44 + Math.random() * 20,
57
+ hue: 185 + Math.random() * 35
58
+ };
59
+ setBlasts((prev) => {
60
+ const next = [...prev, nextBlast];
61
+ if (next.length <= cfg.maxActiveBlasts) return next;
62
+ return next.slice(next.length - cfg.maxActiveBlasts);
63
+ });
64
+ const timeoutId = window.setTimeout(() => removeBlast(nextId), cfg.blastLifetimeMs);
65
+ timeoutIdsRef.current.set(nextId, timeoutId);
66
+ };
67
+ const onClick = (event) => {
68
+ const cfg = configRef.current;
69
+ const now = performance.now();
70
+ let x;
71
+ let y;
72
+ if (containerRef?.current) {
73
+ const rect = containerRef.current.getBoundingClientRect();
74
+ x = event.clientX - rect.left;
75
+ y = event.clientY - rect.top;
76
+ } else {
77
+ x = event.clientX;
78
+ y = event.clientY;
79
+ }
80
+ recentClicksRef.current = recentClicksRef.current.filter((click) => now - click.time < cfg.rageClickWindowMs);
81
+ recentClicksRef.current.push({
82
+ time: now,
83
+ x,
84
+ y
85
+ });
86
+ if (recentClicksRef.current.filter((click) => {
87
+ const dx = click.x - x;
88
+ const dy = click.y - y;
89
+ return Math.sqrt(dx * dx + dy * dy) <= cfg.rageClickRadiusPx;
90
+ }).length >= cfg.rageClickThreshold) spawnBlast(x, y);
91
+ };
92
+ const target = containerRef?.current ?? window;
93
+ const timeoutIds = timeoutIdsRef.current;
94
+ target.addEventListener("click", onClick);
95
+ return () => {
96
+ target.removeEventListener("click", onClick);
97
+ for (const timeoutId of timeoutIds.values()) window.clearTimeout(timeoutId);
98
+ timeoutIds.clear();
99
+ };
100
+ }, [containerRef]);
101
+ if (!mounted) return null;
102
+ const blastElements = /* @__PURE__ */ jsxs(Fragment, { children: [blasts.map((blast) => /* @__PURE__ */ jsxs("div", {
103
+ style: {
104
+ position: "absolute",
105
+ left: blast.x,
106
+ top: blast.y,
107
+ width: blast.size,
108
+ height: blast.size,
109
+ transform: "translate(-50%, -50%)",
110
+ willChange: "transform, opacity",
111
+ filter: `hue-rotate(${blast.hue}deg)`
112
+ },
113
+ children: [
114
+ /* @__PURE__ */ jsx("span", { className: "cursor-blast-ring" }),
115
+ /* @__PURE__ */ jsx("span", { className: "cursor-blast-core" }),
116
+ Array.from({ length: 10 }).map((_, index) => {
117
+ return /* @__PURE__ */ jsx("span", {
118
+ className: "cursor-blast-shard-wrap",
119
+ style: {
120
+ transform: `translate(-50%, -50%) rotate(${360 / 10 * index}deg)`,
121
+ animationDelay: `${index * 16}ms`
122
+ },
123
+ children: /* @__PURE__ */ jsx("span", { className: "cursor-blast-shard" })
124
+ }, `${blast.id}-${index}`);
125
+ })
126
+ ]
127
+ }, blast.id)), /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: `
128
+ .cursor-blast-ring {
129
+ position: absolute;
130
+ inset: 0;
131
+ border-radius: 999px;
132
+ border: 2px solid hsl(197 98% 67% / 0.9);
133
+ box-shadow:
134
+ 0 0 22px hsl(191 100% 72% / 0.6),
135
+ inset 0 0 12px hsl(204 100% 77% / 0.65);
136
+ animation: blast-ring 560ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
137
+ }
138
+
139
+ .cursor-blast-core {
140
+ position: absolute;
141
+ left: 50%;
142
+ top: 50%;
143
+ width: 10px;
144
+ height: 10px;
145
+ border-radius: 999px;
146
+ transform: translate(-50%, -50%);
147
+ background: hsl(196 100% 85%);
148
+ box-shadow:
149
+ 0 0 26px hsl(193 100% 72% / 0.9),
150
+ 0 0 10px hsl(201 100% 85% / 0.9);
151
+ animation: blast-core 420ms ease-out forwards;
152
+ }
153
+
154
+ .cursor-blast-shard-wrap {
155
+ position: absolute;
156
+ left: 50%;
157
+ top: 50%;
158
+ width: 0;
159
+ height: 0;
160
+ }
161
+
162
+ .cursor-blast-shard {
163
+ position: absolute;
164
+ left: 0;
165
+ top: -1.5px;
166
+ width: 12px;
167
+ height: 3px;
168
+ border-radius: 999px;
169
+ background: linear-gradient(90deg, hsl(190 100% 84%), hsl(197 98% 67%));
170
+ box-shadow: 0 0 12px hsl(195 100% 70% / 0.8);
171
+ animation: blast-shard 680ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
172
+ }
173
+
174
+ @keyframes blast-ring {
175
+ 0% {
176
+ transform: scale(0.2);
177
+ opacity: 0.95;
178
+ }
179
+ 100% {
180
+ transform: scale(1.6);
181
+ opacity: 0;
182
+ }
183
+ }
184
+
185
+ @keyframes blast-core {
186
+ 0% {
187
+ transform: translate(-50%, -50%) scale(0.5);
188
+ opacity: 1;
189
+ }
190
+ 100% {
191
+ transform: translate(-50%, -50%) scale(2.2);
192
+ opacity: 0;
193
+ }
194
+ }
195
+
196
+ @keyframes blast-shard {
197
+ 0% {
198
+ transform: translateX(0) scaleX(0.7);
199
+ opacity: 1;
200
+ }
201
+ 100% {
202
+ transform: translateX(46px) scaleX(1.1);
203
+ opacity: 0;
204
+ }
205
+ }
206
+
207
+ @media (prefers-reduced-motion: reduce) {
208
+ .cursor-blast-ring,
209
+ .cursor-blast-core,
210
+ .cursor-blast-shard {
211
+ animation-duration: 1ms;
212
+ }
213
+ }
214
+ ` } })] });
215
+ if (containerRef) return /* @__PURE__ */ jsx("div", {
216
+ "aria-hidden": true,
217
+ style: {
218
+ position: "absolute",
219
+ inset: 0,
220
+ zIndex: 2147483647,
221
+ pointerEvents: "none",
222
+ overflow: "hidden",
223
+ borderRadius: "inherit"
224
+ },
225
+ children: blastElements
226
+ });
227
+ return createPortal(/* @__PURE__ */ jsx("div", {
228
+ "aria-hidden": true,
229
+ style: {
230
+ position: "fixed",
231
+ inset: 0,
232
+ zIndex: 2147483647,
233
+ pointerEvents: "none"
234
+ },
235
+ children: blastElements
236
+ }), document.body);
237
+ }
238
+
239
+ //#endregion
240
+ export { CursorBlastEffect };
241
+ //# sourceMappingURL=cursor-blast-effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-blast-effect.js","names":[],"sources":["../../../src/components/cursor-blast-effect.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\ntype Blast = {\n id: number,\n x: number,\n y: number,\n size: number,\n hue: number,\n};\n\nconst DEFAULT_BLAST_LIFETIME_MS = 720;\nconst DEFAULT_MAX_ACTIVE_BLASTS = 18;\n\n/** Minimum rapid clicks in the time window to count as a rage click */\nconst DEFAULT_RAGE_CLICK_THRESHOLD = 3;\n/** Time window (ms) in which clicks must occur to be considered rage clicking */\nconst DEFAULT_RAGE_CLICK_WINDOW_MS = 600;\n/** Max distance (px) between clicks to still count as same-spot rage clicking */\nconst DEFAULT_RAGE_CLICK_RADIUS_PX = 60;\n\ntype RecentClick = {\n time: number,\n x: number,\n y: number,\n};\n\nexport type CursorBlastEffectProps = {\n /** Lifetime of each blast animation in ms. Default: 720 */\n blastLifetimeMs?: number,\n /** Maximum number of concurrent active blasts. Default: 18 */\n maxActiveBlasts?: number,\n /** Minimum rapid clicks in the time window to trigger a blast. Default: 3 */\n rageClickThreshold?: number,\n /** Time window (ms) for counting rage clicks. Default: 600 */\n rageClickWindowMs?: number,\n /** Max distance (px) between clicks to count as same-spot rage clicking. Default: 60 */\n rageClickRadiusPx?: number,\n /**\n * When provided, the blast effect is scoped to this container element.\n * Clicks are only detected within the container and blasts are positioned\n * relative to the container rather than the viewport.\n */\n containerRef?: React.RefObject<HTMLElement | null>,\n};\n\nexport function CursorBlastEffect({\n blastLifetimeMs = DEFAULT_BLAST_LIFETIME_MS,\n maxActiveBlasts = DEFAULT_MAX_ACTIVE_BLASTS,\n rageClickThreshold = DEFAULT_RAGE_CLICK_THRESHOLD,\n rageClickWindowMs = DEFAULT_RAGE_CLICK_WINDOW_MS,\n rageClickRadiusPx = DEFAULT_RAGE_CLICK_RADIUS_PX,\n containerRef,\n}: CursorBlastEffectProps = {}) {\n const [blasts, setBlasts] = useState<Blast[]>([]);\n const [mounted, setMounted] = useState(false);\n const idCounterRef = useRef(0);\n const timeoutIdsRef = useRef<Map<number, number>>(new Map());\n const recentClicksRef = useRef<RecentClick[]>([]);\n\n // Store latest config in refs so the effect callback always reads current values\n const configRef = useRef({\n blastLifetimeMs,\n maxActiveBlasts,\n rageClickThreshold,\n rageClickWindowMs,\n rageClickRadiusPx,\n });\n configRef.current = {\n blastLifetimeMs,\n maxActiveBlasts,\n rageClickThreshold,\n rageClickWindowMs,\n rageClickRadiusPx,\n };\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n const removeBlast = (id: number) => {\n setBlasts((prev) => prev.filter((blast) => blast.id !== id));\n const timeoutId = timeoutIdsRef.current.get(id);\n if (timeoutId !== undefined) {\n window.clearTimeout(timeoutId);\n timeoutIdsRef.current.delete(id);\n }\n };\n\n const spawnBlast = (x: number, y: number) => {\n const cfg = configRef.current;\n const nextId = idCounterRef.current;\n idCounterRef.current += 1;\n\n const nextBlast: Blast = {\n id: nextId,\n x,\n y,\n size: 44 + Math.random() * 20,\n hue: 185 + Math.random() * 35,\n };\n\n setBlasts((prev) => {\n const next = [...prev, nextBlast];\n if (next.length <= cfg.maxActiveBlasts) {\n return next;\n }\n return next.slice(next.length - cfg.maxActiveBlasts);\n });\n\n const timeoutId = window.setTimeout(() => removeBlast(nextId), cfg.blastLifetimeMs);\n timeoutIdsRef.current.set(nextId, timeoutId);\n };\n\n const onClick = (event: MouseEvent) => {\n const cfg = configRef.current;\n const now = performance.now();\n\n let x: number;\n let y: number;\n\n if (containerRef?.current) {\n const rect = containerRef.current.getBoundingClientRect();\n x = event.clientX - rect.left;\n y = event.clientY - rect.top;\n } else {\n x = event.clientX;\n y = event.clientY;\n }\n\n // Prune clicks outside the time window\n recentClicksRef.current = recentClicksRef.current.filter(\n (click) => now - click.time < cfg.rageClickWindowMs,\n );\n\n recentClicksRef.current.push({ time: now, x, y });\n\n // Count how many recent clicks are within the radius of the current click\n const nearbyCount = recentClicksRef.current.filter((click) => {\n const dx = click.x - x;\n const dy = click.y - y;\n return Math.sqrt(dx * dx + dy * dy) <= cfg.rageClickRadiusPx;\n }).length;\n\n if (nearbyCount >= cfg.rageClickThreshold) {\n spawnBlast(x, y);\n }\n };\n\n const target = containerRef?.current ?? window;\n const timeoutIds = timeoutIdsRef.current;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- EventTarget union requires cast\n (target as EventTarget).addEventListener(\"click\", onClick as EventListener);\n return () => {\n (target as EventTarget).removeEventListener(\"click\", onClick as EventListener);\n for (const timeoutId of timeoutIds.values()) {\n window.clearTimeout(timeoutId);\n }\n timeoutIds.clear();\n };\n }, [containerRef]);\n\n if (!mounted) {\n return null;\n }\n\n const blastElements = (\n <>\n {blasts.map((blast) => (\n <div\n key={blast.id}\n style={{\n position: \"absolute\",\n left: blast.x,\n top: blast.y,\n width: blast.size,\n height: blast.size,\n transform: \"translate(-50%, -50%)\",\n willChange: \"transform, opacity\",\n filter: `hue-rotate(${blast.hue}deg)`,\n }}\n >\n <span className=\"cursor-blast-ring\" />\n <span className=\"cursor-blast-core\" />\n {Array.from({ length: 10 }).map((_, index) => {\n const angle = (360 / 10) * index;\n return (\n <span\n key={`${blast.id}-${index}`}\n className=\"cursor-blast-shard-wrap\"\n style={{\n transform: `translate(-50%, -50%) rotate(${angle}deg)`,\n animationDelay: `${index * 16}ms`,\n }}\n >\n <span className=\"cursor-blast-shard\" />\n </span>\n );\n })}\n </div>\n ))}\n <style dangerouslySetInnerHTML={{ __html: `\n .cursor-blast-ring {\n position: absolute;\n inset: 0;\n border-radius: 999px;\n border: 2px solid hsl(197 98% 67% / 0.9);\n box-shadow:\n 0 0 22px hsl(191 100% 72% / 0.6),\n inset 0 0 12px hsl(204 100% 77% / 0.65);\n animation: blast-ring 560ms cubic-bezier(0.16, 1, 0.3, 1) forwards;\n }\n\n .cursor-blast-core {\n position: absolute;\n left: 50%;\n top: 50%;\n width: 10px;\n height: 10px;\n border-radius: 999px;\n transform: translate(-50%, -50%);\n background: hsl(196 100% 85%);\n box-shadow:\n 0 0 26px hsl(193 100% 72% / 0.9),\n 0 0 10px hsl(201 100% 85% / 0.9);\n animation: blast-core 420ms ease-out forwards;\n }\n\n .cursor-blast-shard-wrap {\n position: absolute;\n left: 50%;\n top: 50%;\n width: 0;\n height: 0;\n }\n\n .cursor-blast-shard {\n position: absolute;\n left: 0;\n top: -1.5px;\n width: 12px;\n height: 3px;\n border-radius: 999px;\n background: linear-gradient(90deg, hsl(190 100% 84%), hsl(197 98% 67%));\n box-shadow: 0 0 12px hsl(195 100% 70% / 0.8);\n animation: blast-shard 680ms cubic-bezier(0.22, 1, 0.36, 1) forwards;\n }\n\n @keyframes blast-ring {\n 0% {\n transform: scale(0.2);\n opacity: 0.95;\n }\n 100% {\n transform: scale(1.6);\n opacity: 0;\n }\n }\n\n @keyframes blast-core {\n 0% {\n transform: translate(-50%, -50%) scale(0.5);\n opacity: 1;\n }\n 100% {\n transform: translate(-50%, -50%) scale(2.2);\n opacity: 0;\n }\n }\n\n @keyframes blast-shard {\n 0% {\n transform: translateX(0) scaleX(0.7);\n opacity: 1;\n }\n 100% {\n transform: translateX(46px) scaleX(1.1);\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .cursor-blast-ring,\n .cursor-blast-core,\n .cursor-blast-shard {\n animation-duration: 1ms;\n }\n }\n ` }} />\n </>\n );\n\n // When scoped to a container, render inline (the container must have position: relative)\n if (containerRef) {\n return (\n <div\n aria-hidden\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 2147483647,\n pointerEvents: \"none\",\n overflow: \"hidden\",\n borderRadius: \"inherit\",\n }}\n >\n {blastElements}\n </div>\n );\n }\n\n // Default: portal to body with fixed positioning (original behaviour)\n return createPortal(\n <div\n aria-hidden\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n pointerEvents: \"none\",\n }}\n >\n {blastElements}\n </div>,\n document.body,\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+
3
+ //#region src/components/edit-mode.d.ts
4
+ declare function DesignEditMode({
5
+ children
6
+ }: {
7
+ children: React.ReactNode;
8
+ }): react_jsx_runtime0.JSX.Element;
9
+ declare function useDesignEditMode(): boolean;
10
+ //#endregion
11
+ export { DesignEditMode, useDesignEditMode };
12
+ //# sourceMappingURL=edit-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-mode.d.ts","names":[],"sources":["../../../src/components/edit-mode.tsx"],"mappings":";;;iBAMgB,cAAA,CAAA;EAAiB;AAAA;EAAc,QAAA,EAAU,KAAA,CAAM,SAAA;AAAA,IAAW,kBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAQ1D,iBAAA,CAAA"}
@@ -0,0 +1,20 @@
1
+ "use client";
2
+
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { createContext, useContext } from "react";
5
+
6
+ //#region src/components/edit-mode.tsx
7
+ const DesignEditModeContext = createContext(false);
8
+ function DesignEditMode({ children }) {
9
+ return /* @__PURE__ */ jsx(DesignEditModeContext.Provider, {
10
+ value: true,
11
+ children
12
+ });
13
+ }
14
+ function useDesignEditMode() {
15
+ return useContext(DesignEditModeContext);
16
+ }
17
+
18
+ //#endregion
19
+ export { DesignEditMode, useDesignEditMode };
20
+ //# sourceMappingURL=edit-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-mode.js","names":[],"sources":["../../../src/components/edit-mode.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext } from \"react\";\n\nconst DesignEditModeContext = createContext(false);\n\nexport function DesignEditMode({ children }: { children: React.ReactNode }) {\n return (\n <DesignEditModeContext.Provider value={true}>\n {children}\n </DesignEditModeContext.Provider>\n );\n}\n\nexport function useDesignEditMode(): boolean {\n return useContext(DesignEditModeContext);\n}\n"],"mappings":";;;;;;AAIA,MAAM,wBAAwB,cAAc,MAAM;AAElD,SAAgB,eAAe,EAAE,YAA2C;AAC1E,QACE,oBAAC,sBAAsB;EAAS,OAAO;EACpC;GAC8B;;AAIrC,SAAgB,oBAA6B;AAC3C,QAAO,WAAW,sBAAsB"}
@@ -0,0 +1,21 @@
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+ import React from "react";
3
+
4
+ //#region src/components/empty-state.d.ts
5
+ type DesignEmptyStateProps = {
6
+ icon?: React.ElementType;
7
+ title?: string;
8
+ description?: string;
9
+ children?: React.ReactNode;
10
+ className?: string;
11
+ };
12
+ declare function DesignEmptyState({
13
+ icon: Icon,
14
+ title,
15
+ description,
16
+ children,
17
+ className
18
+ }: DesignEmptyStateProps): react_jsx_runtime0.JSX.Element;
19
+ //#endregion
20
+ export { DesignEmptyState, DesignEmptyStateProps };
21
+ //# sourceMappingURL=empty-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-state.d.ts","names":[],"sources":["../../../src/components/empty-state.tsx"],"mappings":";;;;KAKY,qBAAA;EACV,IAAA,GAAO,KAAA,CAAM,WAAA;EACb,KAAA;EACA,WAAA;EACA,QAAA,GAAW,KAAA,CAAM,SAAA;EACjB,SAAA;AAAA;AAAA,iBAGc,gBAAA,CAAA;EACd,IAAA,EAAM,IAAA;EACN,KAAA;EACA,WAAA;EACA,QAAA;EACA;AAAA,GACC,qBAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -0,0 +1,34 @@
1
+ "use client";
2
+
3
+ import { cn } from "@stackframe/stack-ui";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import React from "react";
6
+
7
+ //#region src/components/empty-state.tsx
8
+ function DesignEmptyState({ icon: Icon, title = "No data available", description, children, className }) {
9
+ return /* @__PURE__ */ jsxs("div", {
10
+ className: cn("flex flex-col items-center justify-center py-12 px-6 text-center", className),
11
+ children: [
12
+ Icon && /* @__PURE__ */ jsx("div", {
13
+ className: "mb-4",
14
+ children: /* @__PURE__ */ jsx(Icon, { className: "h-10 w-10 text-muted-foreground/30" })
15
+ }),
16
+ /* @__PURE__ */ jsx("h3", {
17
+ className: "text-sm font-medium text-foreground",
18
+ children: title
19
+ }),
20
+ description && /* @__PURE__ */ jsx("p", {
21
+ className: "mt-1 text-xs text-muted-foreground max-w-[280px]",
22
+ children: description
23
+ }),
24
+ children && /* @__PURE__ */ jsx("div", {
25
+ className: "mt-4",
26
+ children
27
+ })
28
+ ]
29
+ });
30
+ }
31
+
32
+ //#endregion
33
+ export { DesignEmptyState };
34
+ //# sourceMappingURL=empty-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-state.js","names":[],"sources":["../../../src/components/empty-state.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@stackframe/stack-ui\";\nimport React from \"react\";\n\nexport type DesignEmptyStateProps = {\n icon?: React.ElementType,\n title?: string,\n description?: string,\n children?: React.ReactNode,\n className?: string,\n};\n\nexport function DesignEmptyState({\n icon: Icon,\n title = \"No data available\",\n description,\n children,\n className,\n}: DesignEmptyStateProps) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center py-12 px-6 text-center\",\n className\n )}\n >\n {Icon && (\n <div className=\"mb-4\">\n <Icon className=\"h-10 w-10 text-muted-foreground/30\" />\n </div>\n )}\n <h3 className=\"text-sm font-medium text-foreground\">\n {title}\n </h3>\n {description && (\n <p className=\"mt-1 text-xs text-muted-foreground max-w-[280px]\">\n {description}\n </p>\n )}\n {children && (\n <div className=\"mt-4\">\n {children}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,iBAAiB,EAC/B,MAAM,MACN,QAAQ,qBACR,aACA,UACA,aACwB;AACxB,QACE,qBAAC;EACC,WAAW,GACT,oEACA,UACD;;GAEA,QACC,oBAAC;IAAI,WAAU;cACb,oBAAC,QAAK,WAAU,uCAAuC;KACnD;GAER,oBAAC;IAAG,WAAU;cACX;KACE;GACJ,eACC,oBAAC;IAAE,WAAU;cACV;KACC;GAEL,YACC,oBAAC;IAAI,WAAU;IACZ;KACG;;GAEJ"}
@@ -0,0 +1,18 @@
1
+ import React from "react";
2
+
3
+ //#region src/components/input.d.ts
4
+ type DesignInputProps = {
5
+ prefixItem?: React.ReactNode;
6
+ leadingIcon?: React.ReactNode;
7
+ size?: "sm" | "md" | "lg";
8
+ } & Omit<React.InputHTMLAttributes<HTMLInputElement>, "size">;
9
+ declare const DesignInput: React.FC<{
10
+ prefixItem?: React.ReactNode;
11
+ leadingIcon?: React.ReactNode;
12
+ size?: "sm" | "md" | "lg";
13
+ } & Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> & {
14
+ ref?: React.Ref<HTMLInputElement> | undefined;
15
+ }>;
16
+ //#endregion
17
+ export { DesignInput, DesignInputProps };
18
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","names":[],"sources":["../../../src/components/input.tsx"],"mappings":";;;KAOY,gBAAA;EACV,UAAA,GAAa,KAAA,CAAM,SAAA;EACnB,WAAA,GAAc,KAAA,CAAM,SAAA;EACpB,IAAA;AAAA,IACE,IAAA,CAAK,KAAA,CAAM,mBAAA,CAAoB,gBAAA;AAAA,cAEtB,WAAA,EAAW,KAAA,CAAA,EAAA;eALT,KAAA,CAAM,SAAA;gBACL,KAAA,CAAM,SAAA"}
@@ -0,0 +1,50 @@
1
+ "use client";
2
+
3
+ import { cn } from "@stackframe/stack-ui";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { forwardRefIfNeeded } from "@stackframe/stack-shared/dist/utils/react";
6
+ import React from "react";
7
+
8
+ //#region src/components/input.tsx
9
+ const DesignInput = forwardRefIfNeeded(({ className, type, prefixItem, leadingIcon, size = "md", ...props }, ref) => {
10
+ const sizeClasses = size === "sm" ? "h-7 px-2 text-xs" : size === "lg" ? "h-10 px-4 text-sm" : "h-9 px-3 text-sm";
11
+ const baseClasses = cn("stack-scope flex w-full rounded-xl border border-black/[0.08] dark:border-white/[0.06] bg-white/80 dark:bg-foreground/[0.03] shadow-sm ring-1 ring-black/[0.08] dark:ring-white/[0.06]", "file:border-0 file:bg-transparent file:text-sm file:font-medium", "placeholder:text-muted-foreground/50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-foreground/[0.1]", "disabled:cursor-not-allowed disabled:opacity-50", "transition-all duration-150 hover:transition-none hover:bg-white dark:hover:bg-foreground/[0.06]", sizeClasses);
12
+ if (prefixItem) return /* @__PURE__ */ jsxs("div", {
13
+ className: "flex flex-row items-center flex-1 rounded-xl border border-black/[0.08] dark:border-white/[0.06] bg-white/80 dark:bg-foreground/[0.03] shadow-sm ring-1 ring-black/[0.08] dark:ring-white/[0.06] overflow-hidden transition-all duration-150 hover:transition-none hover:bg-white dark:hover:bg-foreground/[0.06] focus-within:ring-1 focus-within:ring-foreground/[0.1]",
14
+ children: [/* @__PURE__ */ jsx("div", {
15
+ className: cn("flex self-stretch items-center justify-center select-none text-muted-foreground/70 border-r border-black/[0.06] dark:border-white/[0.06] bg-black/[0.03] dark:bg-white/[0.02]", size === "sm" ? "px-2.5 text-xs" : size === "lg" ? "px-3.5 text-sm" : "px-3 text-sm"),
16
+ children: prefixItem
17
+ }), /* @__PURE__ */ jsx("input", {
18
+ type,
19
+ className: cn("stack-scope flex w-full bg-transparent", "file:border-0 file:bg-transparent file:text-sm file:font-medium", "placeholder:text-muted-foreground/50 focus-visible:outline-none", "disabled:cursor-not-allowed disabled:opacity-50", sizeClasses, "rounded-none border-0 shadow-none ring-0 focus-visible:ring-0", className),
20
+ ref,
21
+ ...props
22
+ })]
23
+ });
24
+ if (leadingIcon) return /* @__PURE__ */ jsxs("div", {
25
+ className: "relative flex flex-row items-center flex-1",
26
+ children: [/* @__PURE__ */ jsx("div", {
27
+ className: "pointer-events-none absolute left-2.5 flex items-center text-muted-foreground",
28
+ children: leadingIcon
29
+ }), /* @__PURE__ */ jsx("input", {
30
+ type,
31
+ className: cn(baseClasses, "pl-8", className),
32
+ ref,
33
+ ...props
34
+ })]
35
+ });
36
+ return /* @__PURE__ */ jsx("div", {
37
+ className: "flex flex-row items-center flex-1",
38
+ children: /* @__PURE__ */ jsx("input", {
39
+ type,
40
+ className: cn(baseClasses, className),
41
+ ref,
42
+ ...props
43
+ })
44
+ });
45
+ });
46
+ DesignInput.displayName = "DesignInput";
47
+
48
+ //#endregion
49
+ export { DesignInput };
50
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","names":[],"sources":["../../../src/components/input.tsx"],"sourcesContent":["\"use client\";\n\nimport { forwardRefIfNeeded } from \"@stackframe/stack-shared/dist/utils/react\";\nimport React from \"react\";\n\nimport { cn } from \"@stackframe/stack-ui\";\n\nexport type DesignInputProps = {\n prefixItem?: React.ReactNode,\n leadingIcon?: React.ReactNode,\n size?: \"sm\" | \"md\" | \"lg\",\n} & Omit<React.InputHTMLAttributes<HTMLInputElement>, \"size\">;\n\nexport const DesignInput = forwardRefIfNeeded<HTMLInputElement, DesignInputProps>(\n ({ className, type, prefixItem, leadingIcon, size = \"md\", ...props }, ref) => {\n const sizeClasses = size === \"sm\"\n ? \"h-7 px-2 text-xs\"\n : size === \"lg\"\n ? \"h-10 px-4 text-sm\"\n : \"h-9 px-3 text-sm\";\n const baseClasses = cn(\n \"stack-scope flex w-full rounded-xl border border-black/[0.08] dark:border-white/[0.06] bg-white/80 dark:bg-foreground/[0.03] shadow-sm ring-1 ring-black/[0.08] dark:ring-white/[0.06]\",\n \"file:border-0 file:bg-transparent file:text-sm file:font-medium\",\n \"placeholder:text-muted-foreground/50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-foreground/[0.1]\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n \"transition-all duration-150 hover:transition-none hover:bg-white dark:hover:bg-foreground/[0.06]\",\n sizeClasses\n );\n\n if (prefixItem) {\n return (\n <div className=\"flex flex-row items-center flex-1 rounded-xl border border-black/[0.08] dark:border-white/[0.06] bg-white/80 dark:bg-foreground/[0.03] shadow-sm ring-1 ring-black/[0.08] dark:ring-white/[0.06] overflow-hidden transition-all duration-150 hover:transition-none hover:bg-white dark:hover:bg-foreground/[0.06] focus-within:ring-1 focus-within:ring-foreground/[0.1]\">\n <div className={cn(\n \"flex self-stretch items-center justify-center select-none text-muted-foreground/70 border-r border-black/[0.06] dark:border-white/[0.06] bg-black/[0.03] dark:bg-white/[0.02]\",\n size === \"sm\" ? \"px-2.5 text-xs\" : size === \"lg\" ? \"px-3.5 text-sm\" : \"px-3 text-sm\"\n )}>\n {prefixItem}\n </div>\n <input\n type={type}\n className={cn(\n \"stack-scope flex w-full bg-transparent\",\n \"file:border-0 file:bg-transparent file:text-sm file:font-medium\",\n \"placeholder:text-muted-foreground/50 focus-visible:outline-none\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n sizeClasses,\n \"rounded-none border-0 shadow-none ring-0 focus-visible:ring-0\",\n className\n )}\n ref={ref}\n {...props}\n />\n </div>\n );\n }\n\n if (leadingIcon) {\n return (\n <div className=\"relative flex flex-row items-center flex-1\">\n <div className=\"pointer-events-none absolute left-2.5 flex items-center text-muted-foreground\">\n {leadingIcon}\n </div>\n <input\n type={type}\n className={cn(baseClasses, \"pl-8\", className)}\n ref={ref}\n {...props}\n />\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-row items-center flex-1\">\n <input\n type={type}\n className={cn(baseClasses, className)}\n ref={ref}\n {...props}\n />\n </div>\n );\n }\n);\nDesignInput.displayName = \"DesignInput\";\n"],"mappings":";;;;;;;;AAaA,MAAa,cAAc,oBACxB,EAAE,WAAW,MAAM,YAAY,aAAa,OAAO,MAAM,GAAG,SAAS,QAAQ;CAC5E,MAAM,cAAc,SAAS,OACzB,qBACA,SAAS,OACP,sBACA;CACN,MAAM,cAAc,GAClB,0LACA,mEACA,4HACA,mDACA,oGACA,YACD;AAED,KAAI,WACF,QACE,qBAAC;EAAI,WAAU;aACb,oBAAC;GAAI,WAAW,GACd,iLACA,SAAS,OAAO,mBAAmB,SAAS,OAAO,mBAAmB,eACvE;aACE;IACG,EACN,oBAAC;GACO;GACN,WAAW,GACT,0CACA,mEACA,mEACA,mDACA,aACA,iEACA,UACD;GACI;GACL,GAAI;IACJ;GACE;AAIV,KAAI,YACF,QACE,qBAAC;EAAI,WAAU;aACb,oBAAC;GAAI,WAAU;aACZ;IACG,EACN,oBAAC;GACO;GACN,WAAW,GAAG,aAAa,QAAQ,UAAU;GACxC;GACL,GAAI;IACJ;GACE;AAIV,QACE,oBAAC;EAAI,WAAU;YACb,oBAAC;GACO;GACN,WAAW,GAAG,aAAa,UAAU;GAChC;GACL,GAAI;IACJ;GACE;EAGX;AACD,YAAY,cAAc"}
@@ -0,0 +1,31 @@
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+ import React from "react";
3
+
4
+ //#region src/components/metric-card.d.ts
5
+ type DesignMetricCardGradient = "blue" | "cyan" | "purple" | "green" | "orange" | "default";
6
+ type DesignMetricCardTrend = {
7
+ value: number;
8
+ direction: "up" | "down";
9
+ label?: string;
10
+ };
11
+ type DesignMetricCardProps = {
12
+ label: string;
13
+ value: string | number;
14
+ description?: string;
15
+ trend?: DesignMetricCardTrend;
16
+ icon?: React.ElementType;
17
+ gradient?: DesignMetricCardGradient;
18
+ } & Omit<React.ComponentProps<"div">, "children">;
19
+ declare function DesignMetricCard({
20
+ label,
21
+ value,
22
+ description,
23
+ trend,
24
+ icon: Icon,
25
+ gradient,
26
+ className,
27
+ ...props
28
+ }: DesignMetricCardProps): react_jsx_runtime0.JSX.Element;
29
+ //#endregion
30
+ export { DesignMetricCard, DesignMetricCardProps, DesignMetricCardTrend };
31
+ //# sourceMappingURL=metric-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metric-card.d.ts","names":[],"sources":["../../../src/components/metric-card.tsx"],"mappings":";;;;KAKK,wBAAA;AAAA,KAWO,qBAAA;EACV,KAAA;EACA,SAAA;EACA,KAAA;AAAA;AAAA,KAGU,qBAAA;EACV,KAAA;EACA,KAAA;EACA,WAAA;EACA,KAAA,GAAQ,qBAAA;EACR,IAAA,GAAO,KAAA,CAAM,WAAA;EACb,QAAA,GAAW,wBAAA;AAAA,IACT,IAAA,CAAK,KAAA,CAAM,cAAA;AAAA,iBAEC,gBAAA,CAAA;EACd,KAAA;EACA,KAAA;EACA,WAAA;EACA,KAAA;EACA,IAAA,EAAM,IAAA;EACN,QAAA;EACA,SAAA;EAAA,GACG;AAAA,GACF,qBAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -0,0 +1,85 @@
1
+ "use client";
2
+
3
+ import { cn } from "@stackframe/stack-ui";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import React from "react";
6
+
7
+ //#region src/components/metric-card.tsx
8
+ const hoverTintClasses = new Map([
9
+ ["blue", "group-hover:bg-blue-500/[0.03]"],
10
+ ["cyan", "group-hover:bg-cyan-500/[0.03]"],
11
+ ["purple", "group-hover:bg-purple-500/[0.03]"],
12
+ ["green", "group-hover:bg-emerald-500/[0.03]"],
13
+ ["orange", "group-hover:bg-orange-500/[0.03]"],
14
+ ["default", "group-hover:bg-slate-500/[0.02]"]
15
+ ]);
16
+ function DesignMetricCard({ label, value, description, trend, icon: Icon, gradient = "default", className, ...props }) {
17
+ const hoverTintClass = hoverTintClasses.get(gradient) ?? "group-hover:bg-slate-500/[0.02]";
18
+ return /* @__PURE__ */ jsxs("div", {
19
+ className: cn("group relative rounded-2xl bg-white/90 dark:bg-background/60 backdrop-blur-xl transition-all duration-150 hover:transition-none overflow-hidden", "ring-1 ring-black/[0.06] hover:ring-black/[0.1] dark:ring-white/[0.06] dark:hover:ring-white/[0.1]", "shadow-sm hover:shadow-md", className),
20
+ ...props,
21
+ children: [
22
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-br from-foreground/[0.04] dark:from-foreground/[0.02] to-transparent pointer-events-none rounded-2xl" }),
23
+ /* @__PURE__ */ jsx("div", { className: cn("absolute inset-0 transition-colors duration-150 group-hover:transition-none pointer-events-none rounded-2xl", hoverTintClass) }),
24
+ /* @__PURE__ */ jsx("div", {
25
+ className: "relative p-5",
26
+ children: /* @__PURE__ */ jsx("div", {
27
+ className: "flex items-start justify-between gap-3",
28
+ children: /* @__PURE__ */ jsxs("div", {
29
+ className: "flex-1 min-w-0",
30
+ children: [
31
+ /* @__PURE__ */ jsxs("div", {
32
+ className: "flex items-center gap-2",
33
+ children: [Icon && /* @__PURE__ */ jsx("div", {
34
+ className: "p-1.5 rounded-lg bg-foreground/[0.06] dark:bg-foreground/[0.04]",
35
+ children: /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5 text-foreground/70 dark:text-muted-foreground" })
36
+ }), /* @__PURE__ */ jsx("span", {
37
+ className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider",
38
+ children: label
39
+ })]
40
+ }),
41
+ /* @__PURE__ */ jsxs("div", {
42
+ className: "mt-3 flex items-baseline gap-2",
43
+ children: [/* @__PURE__ */ jsx("span", {
44
+ className: "text-3xl font-bold tabular-nums text-foreground",
45
+ children: typeof value === "number" ? value.toLocaleString() : value
46
+ }), trend && /* @__PURE__ */ jsxs("span", {
47
+ className: cn("inline-flex items-center gap-0.5 text-xs font-medium", trend.direction === "up" ? "text-emerald-600 dark:text-emerald-400" : "text-red-600 dark:text-red-400"),
48
+ children: [
49
+ /* @__PURE__ */ jsx("svg", {
50
+ className: cn("h-3 w-3", trend.direction === "down" && "rotate-180"),
51
+ viewBox: "0 0 12 12",
52
+ fill: "none",
53
+ xmlns: "http://www.w3.org/2000/svg",
54
+ children: /* @__PURE__ */ jsx("path", {
55
+ d: "M6 2.5V9.5M6 2.5L3 5.5M6 2.5L9 5.5",
56
+ stroke: "currentColor",
57
+ strokeWidth: "1.5",
58
+ strokeLinecap: "round",
59
+ strokeLinejoin: "round"
60
+ })
61
+ }),
62
+ trend.value,
63
+ "%",
64
+ trend.label && /* @__PURE__ */ jsx("span", {
65
+ className: "text-muted-foreground ml-0.5",
66
+ children: trend.label
67
+ })
68
+ ]
69
+ })]
70
+ }),
71
+ description && /* @__PURE__ */ jsx("p", {
72
+ className: "mt-1 text-xs text-muted-foreground",
73
+ children: description
74
+ })
75
+ ]
76
+ })
77
+ })
78
+ })
79
+ ]
80
+ });
81
+ }
82
+
83
+ //#endregion
84
+ export { DesignMetricCard };
85
+ //# sourceMappingURL=metric-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metric-card.js","names":[],"sources":["../../../src/components/metric-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@stackframe/stack-ui\";\nimport React from \"react\";\n\ntype DesignMetricCardGradient = \"blue\" | \"cyan\" | \"purple\" | \"green\" | \"orange\" | \"default\";\n\nconst hoverTintClasses = new Map<DesignMetricCardGradient, string>([\n [\"blue\", \"group-hover:bg-blue-500/[0.03]\"],\n [\"cyan\", \"group-hover:bg-cyan-500/[0.03]\"],\n [\"purple\", \"group-hover:bg-purple-500/[0.03]\"],\n [\"green\", \"group-hover:bg-emerald-500/[0.03]\"],\n [\"orange\", \"group-hover:bg-orange-500/[0.03]\"],\n [\"default\", \"group-hover:bg-slate-500/[0.02]\"],\n]);\n\nexport type DesignMetricCardTrend = {\n value: number,\n direction: \"up\" | \"down\",\n label?: string,\n};\n\nexport type DesignMetricCardProps = {\n label: string,\n value: string | number,\n description?: string,\n trend?: DesignMetricCardTrend,\n icon?: React.ElementType,\n gradient?: DesignMetricCardGradient,\n} & Omit<React.ComponentProps<\"div\">, \"children\">;\n\nexport function DesignMetricCard({\n label,\n value,\n description,\n trend,\n icon: Icon,\n gradient = \"default\",\n className,\n ...props\n}: DesignMetricCardProps) {\n const hoverTintClass = hoverTintClasses.get(gradient) ?? \"group-hover:bg-slate-500/[0.02]\";\n\n return (\n <div\n className={cn(\n \"group relative rounded-2xl bg-white/90 dark:bg-background/60 backdrop-blur-xl transition-all duration-150 hover:transition-none overflow-hidden\",\n \"ring-1 ring-black/[0.06] hover:ring-black/[0.1] dark:ring-white/[0.06] dark:hover:ring-white/[0.1]\",\n \"shadow-sm hover:shadow-md\",\n className\n )}\n {...props}\n >\n <div className=\"absolute inset-0 bg-gradient-to-br from-foreground/[0.04] dark:from-foreground/[0.02] to-transparent pointer-events-none rounded-2xl\" />\n <div\n className={cn(\n \"absolute inset-0 transition-colors duration-150 group-hover:transition-none pointer-events-none rounded-2xl\",\n hoverTintClass\n )}\n />\n <div className=\"relative p-5\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n {Icon && (\n <div className=\"p-1.5 rounded-lg bg-foreground/[0.06] dark:bg-foreground/[0.04]\">\n <Icon className=\"h-3.5 w-3.5 text-foreground/70 dark:text-muted-foreground\" />\n </div>\n )}\n <span className=\"text-xs font-semibold text-muted-foreground uppercase tracking-wider\">\n {label}\n </span>\n </div>\n <div className=\"mt-3 flex items-baseline gap-2\">\n <span className=\"text-3xl font-bold tabular-nums text-foreground\">\n {typeof value === \"number\" ? value.toLocaleString() : value}\n </span>\n {trend && (\n <span\n className={cn(\n \"inline-flex items-center gap-0.5 text-xs font-medium\",\n trend.direction === \"up\"\n ? \"text-emerald-600 dark:text-emerald-400\"\n : \"text-red-600 dark:text-red-400\"\n )}\n >\n <svg\n className={cn(\"h-3 w-3\", trend.direction === \"down\" && \"rotate-180\")}\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 2.5V9.5M6 2.5L3 5.5M6 2.5L9 5.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n {trend.value}%\n {trend.label && (\n <span className=\"text-muted-foreground ml-0.5\">{trend.label}</span>\n )}\n </span>\n )}\n </div>\n {description && (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAOA,MAAM,mBAAmB,IAAI,IAAsC;CACjE,CAAC,QAAQ,iCAAiC;CAC1C,CAAC,QAAQ,iCAAiC;CAC1C,CAAC,UAAU,mCAAmC;CAC9C,CAAC,SAAS,oCAAoC;CAC9C,CAAC,UAAU,mCAAmC;CAC9C,CAAC,WAAW,kCAAkC;CAC/C,CAAC;AAiBF,SAAgB,iBAAiB,EAC/B,OACA,OACA,aACA,OACA,MAAM,MACN,WAAW,WACX,WACA,GAAG,SACqB;CACxB,MAAM,iBAAiB,iBAAiB,IAAI,SAAS,IAAI;AAEzD,QACE,qBAAC;EACC,WAAW,GACT,mJACA,sGACA,6BACA,UACD;EACD,GAAI;;GAEJ,oBAAC,SAAI,WAAU,yIAAyI;GACxJ,oBAAC,SACC,WAAW,GACT,+GACA,eACD,GACD;GACF,oBAAC;IAAI,WAAU;cACb,oBAAC;KAAI,WAAU;eACb,qBAAC;MAAI,WAAU;;OACb,qBAAC;QAAI,WAAU;mBACZ,QACC,oBAAC;SAAI,WAAU;mBACb,oBAAC,QAAK,WAAU,8DAA8D;UAC1E,EAER,oBAAC;SAAK,WAAU;mBACb;UACI;SACH;OACN,qBAAC;QAAI,WAAU;mBACb,oBAAC;SAAK,WAAU;mBACb,OAAO,UAAU,WAAW,MAAM,gBAAgB,GAAG;UACjD,EACN,SACC,qBAAC;SACC,WAAW,GACT,wDACA,MAAM,cAAc,OAChB,2CACA,iCACL;;UAED,oBAAC;WACC,WAAW,GAAG,WAAW,MAAM,cAAc,UAAU,aAAa;WACpE,SAAQ;WACR,MAAK;WACL,OAAM;qBAEN,oBAAC;YACC,GAAE;YACF,QAAO;YACP,aAAY;YACZ,eAAc;YACd,gBAAe;aACf;YACE;UACL,MAAM;UAAM;UACZ,MAAM,SACL,oBAAC;WAAK,WAAU;qBAAgC,MAAM;YAAa;;UAEhE;SAEL;OACL,eACC,oBAAC;QAAE,WAAU;kBACV;SACC;;OAEF;MACF;KACF;;GACF"}
@@ -0,0 +1,33 @@
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+
3
+ //#region src/components/pill-toggle.d.ts
4
+ type DesignPillToggleSize = "sm" | "md" | "lg";
5
+ type DesignPillToggleGradient = "blue" | "cyan" | "purple" | "green" | "orange" | "default";
6
+ type DesignPillToggleOption = {
7
+ id: string;
8
+ label: string;
9
+ icon?: React.ElementType;
10
+ };
11
+ type DesignPillToggleProps = {
12
+ options: DesignPillToggleOption[];
13
+ selected: string;
14
+ onSelect: (id: string) => void | Promise<void>;
15
+ size?: DesignPillToggleSize;
16
+ glassmorphic?: boolean;
17
+ gradient?: DesignPillToggleGradient; /** When false, hides labels and shows a tooltip on hover instead. Defaults to true. */
18
+ showLabels?: boolean;
19
+ className?: string;
20
+ };
21
+ declare function DesignPillToggle({
22
+ options,
23
+ selected,
24
+ onSelect,
25
+ size,
26
+ glassmorphic: glassmorphicProp,
27
+ gradient,
28
+ showLabels,
29
+ className
30
+ }: DesignPillToggleProps): react_jsx_runtime0.JSX.Element;
31
+ //#endregion
32
+ export { DesignPillToggle, DesignPillToggleOption, DesignPillToggleProps };
33
+ //# sourceMappingURL=pill-toggle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pill-toggle.d.ts","names":[],"sources":["../../../src/components/pill-toggle.tsx"],"mappings":";;;KAQK,oBAAA;AAAA,KACA,wBAAA;AAAA,KAEO,sBAAA;EACV,EAAA;EACA,KAAA;EACA,IAAA,GAAO,KAAA,CAAM,WAAA;AAAA;AAAA,KAGH,qBAAA;EACV,OAAA,EAAS,sBAAA;EACT,QAAA;EACA,QAAA,GAAW,EAAA,oBAAsB,OAAA;EACjC,IAAA,GAAO,oBAAA;EACP,YAAA;EACA,QAAA,GAAW,wBAAA,EAZqB;EAchC,UAAA;EACA,SAAA;AAAA;AAAA,iBA+Bc,gBAAA,CAAA;EACd,OAAA;EACA,QAAA;EACA,QAAA;EACA,IAAA;EACA,YAAA,EAAc,gBAAA;EACd,QAAA;EACA,UAAA;EACA;AAAA,GACC,qBAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA"}