@teton/smith-ui 0.2.179 → 0.2.181

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.
package/dist/card.d.ts CHANGED
@@ -23,6 +23,29 @@ export declare function Panel({ icon: Icon, title, theme, count, actions, bodyCl
23
23
  className?: string;
24
24
  children: ReactNode;
25
25
  }): import("react/jsx-runtime").JSX.Element;
26
+ declare const ALERT_TONES: {
27
+ red: {
28
+ accent: string;
29
+ chip: string;
30
+ };
31
+ amber: {
32
+ accent: string;
33
+ chip: string;
34
+ };
35
+ };
36
+ export type AlertTone = keyof typeof ALERT_TONES;
37
+ /**
38
+ * Attention banner for a problem the page wants to lead with: colored left
39
+ * accent, headline plus severity chip, one line of detail, optional action on
40
+ * the right. Callers render it conditionally — it has no "all clear" state.
41
+ */
42
+ export declare function AlertBanner({ tone, title, severity, action, children, }: {
43
+ tone?: AlertTone;
44
+ title: ReactNode;
45
+ severity?: string;
46
+ action?: ReactNode;
47
+ children: ReactNode;
48
+ }): import("react/jsx-runtime").JSX.Element;
26
49
  /**
27
50
  * Card with a colored, titled header bar — for grouped lists.
28
51
  * Right side shows a count pill (when `count` is set) and/or `actions`.
@@ -53,3 +76,4 @@ export declare function ViewAllFooter({ to, count, noun, }: {
53
76
  count: number;
54
77
  noun?: string;
55
78
  }): import("react/jsx-runtime").JSX.Element;
79
+ export {};
package/dist/detail.d.ts CHANGED
@@ -14,9 +14,11 @@ export interface TabItem {
14
14
  state?: unknown;
15
15
  }
16
16
  /** Underlined tab bar used across the device detail subpages. The active tab
17
- * renders as static text; the rest are router links. */
18
- export declare function TabNav({ items }: {
17
+ * renders as static text; the rest are router links. `actions` renders on the
18
+ * right of the bar, for controls that belong to the active tab's content. */
19
+ export declare function TabNav({ items, actions, }: {
19
20
  items: TabItem[];
21
+ actions?: ReactNode;
20
22
  }): import("react/jsx-runtime").JSX.Element;
21
23
  export interface SideNavItem {
22
24
  label: string;
@@ -0,0 +1,33 @@
1
+ import { ReactNode } from 'react';
2
+ import { ButtonSize, ButtonTone, ButtonVariant } from './button';
3
+ export interface DropdownItem {
4
+ label: ReactNode;
5
+ /** Secondary line under the label — good for the detail a tooltip carried. */
6
+ description?: ReactNode;
7
+ icon?: ReactNode;
8
+ /** Tints the icon with the tone the action would have as a standalone button. */
9
+ tone?: ButtonTone;
10
+ onClick?: () => void;
11
+ /** Leaves the menu open after selecting — for items that swap to an
12
+ * in-place confirmation (e.g. "Copied!") instead of navigating away. */
13
+ keepOpen?: boolean;
14
+ /** Renders the item as an external link instead of a button. */
15
+ href?: string;
16
+ target?: string;
17
+ disabled?: boolean;
18
+ }
19
+ /**
20
+ * A button that opens a menu of actions — for collapsing a row of related
21
+ * buttons into one control. Closes on outside click, Escape, or item select.
22
+ */
23
+ export declare function DropdownMenu({ label, items, icon, variant, tone, size, align, className, }: {
24
+ label: ReactNode;
25
+ items: DropdownItem[];
26
+ icon?: ReactNode;
27
+ variant?: ButtonVariant;
28
+ tone?: ButtonTone;
29
+ size?: ButtonSize;
30
+ /** Which edge of the trigger the menu is anchored to. */
31
+ align?: "left" | "right";
32
+ className?: string;
33
+ }): import("react/jsx-runtime").JSX.Element;
package/dist/index.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  export { BADGE_COLORS, Badge, type BadgeVariant, LabelChip } from './badge';
2
2
  export { Button, type ButtonSize, type ButtonTone, type ButtonVariant, } from './button';
3
- export { Card, ListRow, Panel, SectionCard, ViewAllFooter } from './card';
3
+ export { AlertBanner, type AlertTone, Card, ListRow, Panel, SectionCard, ViewAllFooter, } from './card';
4
4
  export { CountryFlag } from './country-flag';
5
5
  export { BackLink, InfoRow, SideNav, type SideNavItem, type TabItem, TabNav, } from './detail';
6
+ export { type DropdownItem, DropdownMenu } from './dropdown';
6
7
  export { PageContainer } from './page-container';
7
8
  export { SearchInput } from './search-input';
8
9
  export { StatCard } from './stat-card';
10
+ export { StateTimeline, type TimelineLane, type TimelineSpan, type TimelineTone, UptimeBars, type UptimeBucket, } from './state-timeline';
9
11
  export { type IconComponent, SECTION_THEMES, type SectionTheme, type SectionThemeName, } from './theme';
10
12
  export { Toast, type ToastState } from './toast';
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { jsx as r, jsxs as l, Fragment as u } from "react/jsx-runtime";
2
- import { X as h, Loader2 as w, ArrowLeft as $, Search as E, Check as S } from "lucide-react";
3
- import { Link as b } from "react-router";
4
- import { useRef as k, useEffect as L } from "react";
5
- const T = {
1
+ import { jsx as e, jsxs as s, Fragment as v } from "react/jsx-runtime";
2
+ import { X as w, Loader2 as j, ArrowLeft as D, ChevronDown as O, Search as R, Check as B } from "lucide-react";
3
+ import { Link as f } from "react-router";
4
+ import { useState as M, useRef as _, useEffect as A } from "react";
5
+ const I = {
6
6
  gray: "bg-gray-100 text-gray-700",
7
7
  blue: "bg-blue-100 text-blue-700",
8
8
  green: "bg-green-100 text-green-700",
@@ -11,69 +11,69 @@ const T = {
11
11
  purple: "bg-purple-100 text-purple-700",
12
12
  orange: "bg-orange-100 text-orange-700"
13
13
  };
14
- function D({
15
- variant: t = "gray",
16
- pill: e = !1,
14
+ function J({
15
+ variant: r = "gray",
16
+ pill: t = !1,
17
17
  className: n = "",
18
- children: o
18
+ children: a
19
19
  }) {
20
- return /* @__PURE__ */ r(
20
+ return /* @__PURE__ */ e(
21
21
  "span",
22
22
  {
23
- className: `px-1.5 py-0.5 text-xs font-medium ${e ? "rounded-full" : "rounded"} ${T[t]} ${n}`,
24
- children: o
23
+ className: `px-1.5 py-0.5 text-xs font-medium ${t ? "rounded-full" : "rounded"} ${I[r]} ${n}`,
24
+ children: a
25
25
  }
26
26
  );
27
27
  }
28
- function P({
29
- name: t,
30
- value: e,
28
+ function Q({
29
+ name: r,
30
+ value: t,
31
31
  onClick: n,
32
- onRemove: o,
33
- active: a = !1,
34
- title: g
32
+ onRemove: a,
33
+ active: o = !1,
34
+ title: m
35
35
  }) {
36
- const s = /* @__PURE__ */ l(u, { children: [
37
- /* @__PURE__ */ r(
36
+ const l = /* @__PURE__ */ s(v, { children: [
37
+ /* @__PURE__ */ e(
38
38
  "span",
39
39
  {
40
- className: `px-2 py-1 font-medium ${a ? "text-blue-700 bg-blue-100" : "text-gray-500 bg-gray-50"}`,
41
- children: t
40
+ className: `px-2 py-1 font-medium ${o ? "text-blue-700 bg-blue-100" : "text-gray-500 bg-gray-50"}`,
41
+ children: r
42
42
  }
43
43
  ),
44
- e !== void 0 && e !== "" && /* @__PURE__ */ r(
44
+ t !== void 0 && t !== "" && /* @__PURE__ */ e(
45
45
  "span",
46
46
  {
47
- className: `px-2 py-1 font-mono border-l ${a ? "text-blue-700 bg-blue-100 border-blue-200" : "text-gray-900 bg-white border-gray-200"}`,
48
- children: e
47
+ className: `px-2 py-1 font-mono border-l ${o ? "text-blue-700 bg-blue-100 border-blue-200" : "text-gray-900 bg-white border-gray-200"}`,
48
+ children: t
49
49
  }
50
50
  )
51
- ] }), d = `inline-flex items-center overflow-hidden rounded-md border text-xs ${a ? "border-blue-300" : "border-gray-200"}`;
52
- return o ? /* @__PURE__ */ l("span", { className: d, children: [
53
- s,
54
- /* @__PURE__ */ r(
51
+ ] }), d = `inline-flex items-center overflow-hidden rounded-md border text-xs ${o ? "border-blue-300" : "border-gray-200"}`;
52
+ return a ? /* @__PURE__ */ s("span", { className: d, children: [
53
+ l,
54
+ /* @__PURE__ */ e(
55
55
  "button",
56
56
  {
57
57
  type: "button",
58
- onClick: o,
59
- title: g,
60
- "aria-label": `Remove ${e !== void 0 ? `${t}=${e}` : t}`,
61
- className: `flex items-center px-1.5 py-1 border-l cursor-pointer transition-colors ${a ? "bg-blue-100 border-blue-200 text-blue-500 hover:bg-blue-200 hover:text-blue-700" : "border-gray-200 text-gray-400 hover:bg-gray-100 hover:text-gray-600"}`,
62
- children: /* @__PURE__ */ r(h, { className: "w-3 h-3" })
58
+ onClick: a,
59
+ title: m,
60
+ "aria-label": `Remove ${t !== void 0 ? `${r}=${t}` : r}`,
61
+ className: `flex items-center px-1.5 py-1 border-l cursor-pointer transition-colors ${o ? "bg-blue-100 border-blue-200 text-blue-500 hover:bg-blue-200 hover:text-blue-700" : "border-gray-200 text-gray-400 hover:bg-gray-100 hover:text-gray-600"}`,
62
+ children: /* @__PURE__ */ e(w, { className: "w-3 h-3" })
63
63
  }
64
64
  )
65
- ] }) : n ? /* @__PURE__ */ r(
65
+ ] }) : n ? /* @__PURE__ */ e(
66
66
  "button",
67
67
  {
68
68
  type: "button",
69
69
  onClick: n,
70
- title: g,
71
- className: `${d} cursor-pointer transition-colors ${a ? "" : "hover:border-gray-300"}`,
72
- children: s
70
+ title: m,
71
+ className: `${d} cursor-pointer transition-colors ${o ? "" : "hover:border-gray-300"}`,
72
+ children: l
73
73
  }
74
- ) : /* @__PURE__ */ r("span", { className: d, children: s });
74
+ ) : /* @__PURE__ */ e("span", { className: d, children: l });
75
75
  }
76
- const C = {
76
+ const K = {
77
77
  solid: {
78
78
  blue: "bg-blue-600 text-white hover:bg-blue-700",
79
79
  purple: "bg-purple-600 text-white hover:bg-purple-700",
@@ -98,129 +98,158 @@ const C = {
98
98
  orange: "text-orange-600 hover:bg-orange-50",
99
99
  gray: "text-gray-600 hover:bg-gray-100"
100
100
  }
101
- }, j = {
101
+ }, P = {
102
102
  sm: "px-2.5 py-1.5 text-xs gap-1.5",
103
103
  md: "px-3 py-2 text-sm gap-2"
104
- }, A = {
104
+ }, U = {
105
105
  solid: "shadow-sm hover:shadow-md",
106
106
  soft: "shadow-sm hover:shadow",
107
107
  ghost: ""
108
108
  };
109
- function U({
110
- variant: t = "soft",
111
- tone: e = "blue",
109
+ function X({
110
+ variant: r = "soft",
111
+ tone: t = "blue",
112
112
  size: n = "md",
113
- icon: o,
114
- loading: a = !1,
115
- disabled: g = !1,
116
- type: s = "button",
113
+ icon: a,
114
+ loading: o = !1,
115
+ disabled: m = !1,
116
+ type: l = "button",
117
117
  title: d,
118
- onClick: i,
119
- to: c,
120
- href: m,
121
- target: f,
122
- className: v = "",
123
- children: N
118
+ onClick: p,
119
+ to: g,
120
+ href: h,
121
+ target: i,
122
+ className: b = "",
123
+ children: c
124
124
  }) {
125
- const p = `inline-flex items-center justify-center font-medium rounded-lg transition-colors duration-100 cursor-pointer active:scale-[.98] ${j[n]} ${A[t]} ${C[t][e]} ${v}`, x = /* @__PURE__ */ l(u, { children: [
126
- a ? /* @__PURE__ */ r(w, { className: "w-4 h-4 animate-spin" }) : o,
127
- N
125
+ const u = `inline-flex items-center justify-center font-medium rounded-lg transition-colors duration-100 cursor-pointer active:scale-[.98] ${P[n]} ${U[r]} ${K[r][t]} ${b}`, x = /* @__PURE__ */ s(v, { children: [
126
+ o ? /* @__PURE__ */ e(j, { className: "w-4 h-4 animate-spin" }) : a,
127
+ c
128
128
  ] });
129
- return c ? /* @__PURE__ */ r(b, { to: c, className: p, title: d, children: x }) : m ? /* @__PURE__ */ r(
129
+ return g ? /* @__PURE__ */ e(f, { to: g, className: u, title: d, children: x }) : h ? /* @__PURE__ */ e(
130
130
  "a",
131
131
  {
132
- href: m,
133
- target: f,
134
- rel: f === "_blank" ? "noopener noreferrer" : void 0,
135
- className: p,
132
+ href: h,
133
+ target: i,
134
+ rel: i === "_blank" ? "noopener noreferrer" : void 0,
135
+ className: u,
136
136
  title: d,
137
137
  children: x
138
138
  }
139
- ) : /* @__PURE__ */ r(
139
+ ) : /* @__PURE__ */ e(
140
140
  "button",
141
141
  {
142
- type: s,
143
- onClick: i,
144
- disabled: g || a,
142
+ type: l,
143
+ onClick: p,
144
+ disabled: m || o,
145
145
  title: d,
146
- className: `${p} disabled:opacity-50 disabled:cursor-not-allowed`,
146
+ className: `${u} disabled:opacity-50 disabled:cursor-not-allowed`,
147
147
  children: x
148
148
  }
149
149
  );
150
150
  }
151
- function y({
152
- className: t = "",
153
- children: e
151
+ function $({
152
+ className: r = "",
153
+ children: t
154
154
  }) {
155
- return /* @__PURE__ */ r(
155
+ return /* @__PURE__ */ e(
156
156
  "div",
157
157
  {
158
- className: `bg-white rounded-xl border border-gray-200/80 shadow-sm ${t}`,
159
- children: e
158
+ className: `bg-white rounded-xl border border-gray-200/80 shadow-sm ${r}`,
159
+ children: t
160
160
  }
161
161
  );
162
162
  }
163
- function V({
164
- icon: t,
165
- title: e,
163
+ function W({
164
+ icon: r,
165
+ title: t,
166
166
  theme: n,
167
- count: o,
168
- actions: a,
169
- bodyClassName: g = "p-5",
170
- className: s = "",
167
+ count: a,
168
+ actions: o,
169
+ bodyClassName: m = "p-5",
170
+ className: l = "",
171
171
  children: d
172
172
  }) {
173
- return /* @__PURE__ */ l(y, { className: `overflow-hidden ${s}`, children: [
174
- /* @__PURE__ */ l(
173
+ return /* @__PURE__ */ s($, { className: `overflow-hidden ${l}`, children: [
174
+ /* @__PURE__ */ s(
175
175
  "div",
176
176
  {
177
177
  className: `px-4 py-3 flex items-center justify-between border-b border-black/5 ${n.header}`,
178
178
  children: [
179
- /* @__PURE__ */ l("h4", { className: "text-sm font-semibold flex items-center", children: [
180
- t && /* @__PURE__ */ r(t, { className: "w-4 h-4 mr-2" }),
181
- e
179
+ /* @__PURE__ */ s("h4", { className: "text-sm font-semibold flex items-center", children: [
180
+ r && /* @__PURE__ */ e(r, { className: "w-4 h-4 mr-2" }),
181
+ t
182
182
  ] }),
183
- (a || o !== void 0) && /* @__PURE__ */ l("div", { className: "flex items-center gap-2", children: [
184
- a,
185
- o !== void 0 && /* @__PURE__ */ r(
183
+ (o || a !== void 0) && /* @__PURE__ */ s("div", { className: "flex items-center gap-2", children: [
184
+ o,
185
+ a !== void 0 && /* @__PURE__ */ e(
186
186
  "span",
187
187
  {
188
188
  className: `text-xs font-semibold px-2 py-0.5 rounded-full ${n.badge}`,
189
- children: o
189
+ children: a
190
190
  }
191
191
  )
192
192
  ] })
193
193
  ]
194
194
  }
195
195
  ),
196
- /* @__PURE__ */ r("div", { className: g, children: d })
196
+ /* @__PURE__ */ e("div", { className: m, children: d })
197
197
  ] });
198
198
  }
199
- function X({
200
- icon: t,
201
- title: e,
199
+ const z = {
200
+ red: { accent: "border-l-red-500", chip: "bg-red-50 text-red-600" },
201
+ amber: { accent: "border-l-amber-500", chip: "bg-amber-50 text-amber-700" }
202
+ };
203
+ function ee({
204
+ tone: r = "red",
205
+ title: t,
206
+ severity: n,
207
+ action: a,
208
+ children: o
209
+ }) {
210
+ const { accent: m, chip: l } = z[r];
211
+ return /* @__PURE__ */ e($, { className: `border-l-4 ${m} px-5 py-4`, children: /* @__PURE__ */ s("div", { className: "flex items-start justify-between gap-4", children: [
212
+ /* @__PURE__ */ s("div", { className: "min-w-0 flex-1", children: [
213
+ /* @__PURE__ */ s("div", { className: "flex items-center gap-2.5 flex-wrap", children: [
214
+ /* @__PURE__ */ e("h4", { className: "text-base font-semibold text-gray-900", children: t }),
215
+ n && /* @__PURE__ */ e(
216
+ "span",
217
+ {
218
+ className: `text-[11px] font-bold uppercase tracking-wide px-1.5 py-0.5 rounded ${l}`,
219
+ children: n
220
+ }
221
+ )
222
+ ] }),
223
+ /* @__PURE__ */ e("div", { className: "mt-1 text-sm text-gray-600", children: o })
224
+ ] }),
225
+ a && /* @__PURE__ */ e("div", { className: "shrink-0 text-sm", children: a })
226
+ ] }) });
227
+ }
228
+ function re({
229
+ icon: r,
230
+ title: t,
202
231
  count: n,
203
- theme: o,
204
- actions: a,
205
- footer: g,
206
- children: s
232
+ theme: a,
233
+ actions: o,
234
+ footer: m,
235
+ children: l
207
236
  }) {
208
- return /* @__PURE__ */ l(y, { className: "overflow-hidden flex flex-col", children: [
209
- /* @__PURE__ */ l(
237
+ return /* @__PURE__ */ s($, { className: "overflow-hidden flex flex-col", children: [
238
+ /* @__PURE__ */ s(
210
239
  "div",
211
240
  {
212
- className: `px-4 py-3 flex items-center justify-between border-b border-black/5 ${o.header}`,
241
+ className: `px-4 py-3 flex items-center justify-between border-b border-black/5 ${a.header}`,
213
242
  children: [
214
- /* @__PURE__ */ l("h4", { className: "text-sm font-semibold flex items-center", children: [
215
- t && /* @__PURE__ */ r(t, { className: "w-4 h-4 mr-2" }),
216
- e
243
+ /* @__PURE__ */ s("h4", { className: "text-sm font-semibold flex items-center", children: [
244
+ r && /* @__PURE__ */ e(r, { className: "w-4 h-4 mr-2" }),
245
+ t
217
246
  ] }),
218
- /* @__PURE__ */ l("div", { className: "flex items-center gap-2", children: [
219
- a,
220
- n !== void 0 && /* @__PURE__ */ r(
247
+ /* @__PURE__ */ s("div", { className: "flex items-center gap-2", children: [
248
+ o,
249
+ n !== void 0 && /* @__PURE__ */ e(
221
250
  "span",
222
251
  {
223
- className: `text-xs font-semibold px-2 py-0.5 rounded-full ${o.badge}`,
252
+ className: `text-xs font-semibold px-2 py-0.5 rounded-full ${a.badge}`,
224
253
  children: n
225
254
  }
226
255
  )
@@ -228,41 +257,41 @@ function X({
228
257
  ]
229
258
  }
230
259
  ),
231
- /* @__PURE__ */ r("div", { className: "divide-y divide-gray-100", children: s }),
232
- g
260
+ /* @__PURE__ */ e("div", { className: "divide-y divide-gray-100", children: l }),
261
+ m
233
262
  ] });
234
263
  }
235
- function F({
236
- to: t,
237
- onClick: e,
264
+ function te({
265
+ to: r,
266
+ onClick: t,
238
267
  hover: n = "hover:bg-gray-50",
239
- className: o = "",
240
- children: a
268
+ className: a = "",
269
+ children: o
241
270
  }) {
242
- const s = `flex items-center justify-between px-4 py-3 transition-colors ${n} ${!!(t || e) ? "cursor-pointer" : ""} ${o}`;
243
- return t ? /* @__PURE__ */ r(b, { to: t, className: s, children: a }) : e ? /* @__PURE__ */ r(
271
+ const l = `flex items-center justify-between px-4 py-3 transition-colors ${n} ${!!(r || t) ? "cursor-pointer" : ""} ${a}`;
272
+ return r ? /* @__PURE__ */ e(f, { to: r, className: l, children: o }) : t ? /* @__PURE__ */ e(
244
273
  "button",
245
274
  {
246
275
  type: "button",
247
- onClick: e,
248
- className: `w-full text-left ${s}`,
249
- children: a
276
+ onClick: t,
277
+ className: `w-full text-left ${l}`,
278
+ children: o
250
279
  }
251
- ) : /* @__PURE__ */ r("div", { className: s, children: a });
280
+ ) : /* @__PURE__ */ e("div", { className: l, children: o });
252
281
  }
253
- function Y({
254
- to: t,
255
- count: e,
282
+ function ne({
283
+ to: r,
284
+ count: t,
256
285
  noun: n = "items"
257
286
  }) {
258
- return /* @__PURE__ */ l(
259
- b,
287
+ return /* @__PURE__ */ s(
288
+ f,
260
289
  {
261
- to: t,
290
+ to: r,
262
291
  className: "block px-4 py-2.5 text-sm font-medium text-blue-600 hover:text-blue-700 hover:bg-gray-50 transition-colors",
263
292
  children: [
264
293
  "View all ",
265
- e,
294
+ t,
266
295
  " ",
267
296
  n,
268
297
  " →"
@@ -270,16 +299,16 @@ function Y({
270
299
  }
271
300
  );
272
301
  }
273
- const R = (t) => `https://flagicons.lipis.dev/flags/4x3/${t.toLowerCase()}.svg`;
274
- function z({
275
- countryCode: t,
276
- country: e
302
+ const F = (r) => `https://flagicons.lipis.dev/flags/4x3/${r.toLowerCase()}.svg`;
303
+ function ae({
304
+ countryCode: r,
305
+ country: t
277
306
  }) {
278
- return t ? /* @__PURE__ */ r(
307
+ return r ? /* @__PURE__ */ e(
279
308
  "img",
280
309
  {
281
- src: R(t),
282
- alt: e || "Country flag",
310
+ src: F(r),
311
+ alt: t || "Country flag",
283
312
  className: "w-4 h-3 flex-shrink-0 rounded-sm ring-1 ring-black/5",
284
313
  onError: (n) => {
285
314
  n.target.style.display = "none";
@@ -287,107 +316,211 @@ function z({
287
316
  }
288
317
  ) : null;
289
318
  }
290
- function G({
291
- to: t,
292
- onClick: e,
319
+ function oe({
320
+ to: r,
321
+ onClick: t,
293
322
  children: n
294
323
  }) {
295
- const o = "inline-flex items-center gap-2 text-sm font-medium text-gray-600 hover:text-gray-900 transition-colors cursor-pointer", a = /* @__PURE__ */ l(u, { children: [
296
- /* @__PURE__ */ r($, { className: "w-4 h-4" }),
297
- /* @__PURE__ */ r("span", { children: n })
324
+ const a = "inline-flex items-center gap-2 text-sm font-medium text-gray-600 hover:text-gray-900 transition-colors cursor-pointer", o = /* @__PURE__ */ s(v, { children: [
325
+ /* @__PURE__ */ e(D, { className: "w-4 h-4" }),
326
+ /* @__PURE__ */ e("span", { children: n })
298
327
  ] });
299
- return t ? /* @__PURE__ */ r(b, { to: t, className: o, children: a }) : /* @__PURE__ */ r("button", { type: "button", onClick: e, className: o, children: a });
328
+ return r ? /* @__PURE__ */ e(f, { to: r, className: a, children: o }) : /* @__PURE__ */ e("button", { type: "button", onClick: t, className: a, children: o });
300
329
  }
301
- function H({ items: t }) {
302
- return /* @__PURE__ */ r("div", { className: "border-b border-gray-200", children: /* @__PURE__ */ r("nav", { className: "-mb-px flex space-x-8", children: t.map((e) => {
303
- const n = e.active ? "py-2 px-1 border-b-2 border-blue-500 text-blue-600 font-medium text-sm" : "py-2 px-1 border-b-2 border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 font-medium text-sm transition-colors cursor-pointer";
304
- return e.to && !e.active ? /* @__PURE__ */ r(
305
- b,
306
- {
307
- to: e.to,
308
- state: e.state,
309
- className: n,
310
- children: e.label
311
- },
312
- e.label
313
- ) : /* @__PURE__ */ r("span", { className: n, children: e.label }, e.label);
314
- }) }) });
330
+ function se({
331
+ items: r,
332
+ actions: t
333
+ }) {
334
+ return /* @__PURE__ */ s("div", { className: "border-b border-gray-200 flex items-end justify-between gap-4", children: [
335
+ /* @__PURE__ */ e("nav", { className: "-mb-px flex space-x-8", children: r.map((n) => {
336
+ const a = n.active ? "py-2 px-1 border-b-2 border-blue-500 text-blue-600 font-medium text-sm" : "py-2 px-1 border-b-2 border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 font-medium text-sm transition-colors cursor-pointer";
337
+ return n.to && !n.active ? /* @__PURE__ */ e(
338
+ f,
339
+ {
340
+ to: n.to,
341
+ state: n.state,
342
+ className: a,
343
+ children: n.label
344
+ },
345
+ n.label
346
+ ) : /* @__PURE__ */ e("span", { className: a, children: n.label }, n.label);
347
+ }) }),
348
+ t && /* @__PURE__ */ e("div", { className: "flex items-center gap-2 pb-1.5", children: t })
349
+ ] });
315
350
  }
316
- function M({ items: t }) {
317
- return /* @__PURE__ */ r("nav", { className: "space-y-1", children: t.map((e) => {
318
- const n = e.icon, o = `group/side relative flex items-center gap-3 h-10 rounded-md px-3 text-sm transition-all duration-200 cursor-pointer ${e.active ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-600 hover:bg-gray-100 hover:text-gray-900"}`, a = /* @__PURE__ */ l(u, { children: [
319
- /* @__PURE__ */ r(
351
+ function le({ items: r }) {
352
+ return /* @__PURE__ */ e("nav", { className: "space-y-1", children: r.map((t) => {
353
+ const n = t.icon, a = `group/side relative flex items-center gap-3 h-10 rounded-md px-3 text-sm transition-all duration-200 cursor-pointer ${t.active ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-600 hover:bg-gray-100 hover:text-gray-900"}`, o = /* @__PURE__ */ s(v, { children: [
354
+ /* @__PURE__ */ e(
320
355
  "span",
321
356
  {
322
- className: `absolute left-0 top-1.5 bottom-1.5 w-[3px] rounded-r-full bg-blue-600 transition-all duration-300 ease-out ${e.active ? "opacity-100 scale-y-100" : "opacity-0 scale-y-0"}`
357
+ className: `absolute left-0 top-1.5 bottom-1.5 w-[3px] rounded-r-full bg-blue-600 transition-all duration-300 ease-out ${t.active ? "opacity-100 scale-y-100" : "opacity-0 scale-y-0"}`
323
358
  }
324
359
  ),
325
- n && /* @__PURE__ */ r(n, { className: "w-[18px] h-[18px] shrink-0 transition-transform duration-200 group-hover/side:scale-110" }),
326
- /* @__PURE__ */ r("span", { className: "truncate", children: e.label })
360
+ n && /* @__PURE__ */ e(n, { className: "w-[18px] h-[18px] shrink-0 transition-transform duration-200 group-hover/side:scale-110" }),
361
+ /* @__PURE__ */ e("span", { className: "truncate", children: t.label })
327
362
  ] });
328
- return e.active ? /* @__PURE__ */ r("span", { className: o, "aria-current": "page", children: a }, e.to) : /* @__PURE__ */ r(b, { to: e.to, className: o, children: a }, e.to);
363
+ return t.active ? /* @__PURE__ */ e("span", { className: a, "aria-current": "page", children: o }, t.to) : /* @__PURE__ */ e(f, { to: t.to, className: a, children: o }, t.to);
329
364
  }) });
330
365
  }
331
- function Z({
332
- label: t,
333
- icon: e,
366
+ function ie({
367
+ label: r,
368
+ icon: t,
334
369
  iconClassName: n = "text-gray-400",
335
- children: o
370
+ children: a
336
371
  }) {
337
- return /* @__PURE__ */ l("div", { className: "flex items-center justify-between gap-4", children: [
338
- /* @__PURE__ */ l("span", { className: "text-gray-700 flex items-center flex-shrink-0", children: [
339
- e && /* @__PURE__ */ r(e, { className: `w-4 h-4 mr-2 ${n}` }),
340
- t
372
+ return /* @__PURE__ */ s("div", { className: "flex items-center justify-between gap-4", children: [
373
+ /* @__PURE__ */ s("span", { className: "text-gray-700 flex items-center flex-shrink-0", children: [
374
+ t && /* @__PURE__ */ e(t, { className: `w-4 h-4 mr-2 ${n}` }),
375
+ r
341
376
  ] }),
342
- /* @__PURE__ */ r("span", { className: "text-sm text-gray-900 text-right min-w-0", children: o })
377
+ /* @__PURE__ */ e("span", { className: "text-sm text-gray-900 text-right min-w-0", children: a })
343
378
  ] });
344
379
  }
345
- function q({
346
- className: t = "space-y-6",
347
- children: e
380
+ const V = {
381
+ blue: "text-blue-600",
382
+ purple: "text-purple-600",
383
+ red: "text-red-600",
384
+ green: "text-green-600",
385
+ orange: "text-orange-600",
386
+ gray: "text-gray-500"
387
+ }, L = "w-full flex items-start gap-3 px-3 py-2 text-left transition-colors hover:bg-gray-50 cursor-pointer";
388
+ function de({
389
+ label: r,
390
+ items: t,
391
+ icon: n,
392
+ variant: a = "soft",
393
+ tone: o = "gray",
394
+ size: m = "md",
395
+ align: l = "right",
396
+ className: d = ""
348
397
  }) {
349
- return /* @__PURE__ */ r(
398
+ const [p, g] = M(!1), h = _(null);
399
+ return A(() => {
400
+ if (!p) return;
401
+ const i = (c) => {
402
+ var u;
403
+ (u = h.current) != null && u.contains(c.target) || g(!1);
404
+ }, b = (c) => {
405
+ c.key === "Escape" && g(!1);
406
+ };
407
+ return document.addEventListener("mousedown", i), document.addEventListener("keydown", b), () => {
408
+ document.removeEventListener("mousedown", i), document.removeEventListener("keydown", b);
409
+ };
410
+ }, [p]), /* @__PURE__ */ s("div", { className: `relative ${d}`, ref: h, children: [
411
+ /* @__PURE__ */ s(
412
+ X,
413
+ {
414
+ variant: a,
415
+ tone: o,
416
+ size: m,
417
+ icon: n,
418
+ onClick: () => g((i) => !i),
419
+ children: [
420
+ r,
421
+ /* @__PURE__ */ e(
422
+ O,
423
+ {
424
+ className: `w-4 h-4 transition-transform duration-200 ${p ? "rotate-180" : ""}`
425
+ }
426
+ )
427
+ ]
428
+ }
429
+ ),
430
+ p && /* @__PURE__ */ e(
431
+ "div",
432
+ {
433
+ className: `absolute ${l === "right" ? "right-0" : "left-0"} mt-2 w-64 py-1 bg-white rounded-lg shadow-lg border border-gray-200 z-50 animate-dropdown-in`,
434
+ children: t.map((i, b) => {
435
+ const c = V[i.tone ?? "gray"], u = /* @__PURE__ */ s(v, { children: [
436
+ i.icon && /* @__PURE__ */ e(
437
+ "span",
438
+ {
439
+ className: `flex items-center gap-1 mt-0.5 flex-shrink-0 ${c}`,
440
+ children: i.icon
441
+ }
442
+ ),
443
+ /* @__PURE__ */ s("span", { className: "min-w-0", children: [
444
+ /* @__PURE__ */ e("span", { className: "block text-sm font-medium text-gray-900", children: i.label }),
445
+ i.description && /* @__PURE__ */ e("span", { className: "block text-xs text-gray-500 mt-0.5 break-all", children: i.description })
446
+ ] })
447
+ ] });
448
+ return i.href ? /* @__PURE__ */ e(
449
+ "a",
450
+ {
451
+ href: i.href,
452
+ target: i.target,
453
+ rel: i.target === "_blank" ? "noopener noreferrer" : void 0,
454
+ className: L,
455
+ onClick: () => g(!1),
456
+ children: u
457
+ },
458
+ b
459
+ ) : /* @__PURE__ */ e(
460
+ "button",
461
+ {
462
+ type: "button",
463
+ disabled: i.disabled,
464
+ onClick: () => {
465
+ var x;
466
+ i.keepOpen || g(!1), (x = i.onClick) == null || x.call(i);
467
+ },
468
+ className: `${L} disabled:opacity-50 disabled:cursor-not-allowed`,
469
+ children: u
470
+ },
471
+ b
472
+ );
473
+ })
474
+ }
475
+ )
476
+ ] });
477
+ }
478
+ function ce({
479
+ className: r = "space-y-6",
480
+ children: t
481
+ }) {
482
+ return /* @__PURE__ */ e(
350
483
  "div",
351
484
  {
352
- className: `flex-1 overflow-y-auto px-4 sm:px-6 lg:px-8 py-6 ${t}`,
353
- children: e
485
+ className: `flex-1 overflow-y-auto px-4 sm:px-6 lg:px-8 py-6 ${r}`,
486
+ children: t
354
487
  }
355
488
  );
356
489
  }
357
- function J({
358
- value: t,
359
- onChange: e,
490
+ function ge({
491
+ value: r,
492
+ onChange: t,
360
493
  placeholder: n = "Search...",
361
- className: o = "w-full",
362
- slashToFocus: a = !1
494
+ className: a = "w-full",
495
+ slashToFocus: o = !1
363
496
  }) {
364
- const g = k(null);
365
- return L(() => {
366
- if (!a) return;
367
- function s(d) {
368
- var c;
497
+ const m = _(null);
498
+ return A(() => {
499
+ if (!o) return;
500
+ function l(d) {
501
+ var g;
369
502
  if (d.key !== "/" || d.ctrlKey || d.metaKey || d.altKey) return;
370
- const i = d.target;
371
- i.tagName === "INPUT" || i.tagName === "TEXTAREA" || i.tagName === "SELECT" || i.isContentEditable || (d.preventDefault(), (c = g.current) == null || c.focus());
503
+ const p = d.target;
504
+ p.tagName === "INPUT" || p.tagName === "TEXTAREA" || p.tagName === "SELECT" || p.isContentEditable || (d.preventDefault(), (g = m.current) == null || g.focus());
372
505
  }
373
- return document.addEventListener("keydown", s), () => document.removeEventListener("keydown", s);
374
- }, [a]), /* @__PURE__ */ l("div", { className: `relative ${o}`, children: [
375
- /* @__PURE__ */ r(E, { className: "absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-4 h-4 pointer-events-none" }),
376
- /* @__PURE__ */ r(
506
+ return document.addEventListener("keydown", l), () => document.removeEventListener("keydown", l);
507
+ }, [o]), /* @__PURE__ */ s("div", { className: `relative ${a}`, children: [
508
+ /* @__PURE__ */ e(R, { className: "absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-4 h-4 pointer-events-none" }),
509
+ /* @__PURE__ */ e(
377
510
  "input",
378
511
  {
379
- ref: g,
512
+ ref: m,
380
513
  type: "text",
381
- value: t,
382
- onChange: (s) => e(s.target.value),
514
+ value: r,
515
+ onChange: (l) => t(l.target.value),
383
516
  placeholder: n,
384
517
  className: "w-full pl-10 pr-10 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm text-gray-900 placeholder-gray-400"
385
518
  }
386
519
  ),
387
- a && !t && /* @__PURE__ */ r("kbd", { className: "absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 text-xs border border-gray-300 rounded px-1 py-0.5 font-mono leading-none pointer-events-none", children: "/" })
520
+ o && !r && /* @__PURE__ */ e("kbd", { className: "absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 text-xs border border-gray-300 rounded px-1 py-0.5 font-mono leading-none pointer-events-none", children: "/" })
388
521
  ] });
389
522
  }
390
- const B = {
523
+ const H = {
391
524
  neutral: { badge: "bg-gray-100", icon: "text-gray-400" },
392
525
  green: { badge: "bg-green-100", icon: "text-green-600" },
393
526
  blue: { badge: "bg-blue-100", icon: "text-blue-600" },
@@ -395,28 +528,163 @@ const B = {
395
528
  red: { badge: "bg-red-100", icon: "text-red-600" },
396
529
  purple: { badge: "bg-purple-100", icon: "text-purple-600" }
397
530
  };
398
- function Q({
399
- icon: t,
400
- label: e,
531
+ function be({
532
+ icon: r,
533
+ label: t,
401
534
  value: n,
402
- tone: o = "neutral"
535
+ tone: a = "neutral"
403
536
  }) {
404
- const a = B[o];
405
- return /* @__PURE__ */ l("div", { className: "flex items-center gap-4", children: [
406
- /* @__PURE__ */ r(
537
+ const o = H[a];
538
+ return /* @__PURE__ */ s("div", { className: "flex items-center gap-4", children: [
539
+ /* @__PURE__ */ e(
407
540
  "div",
408
541
  {
409
- className: `flex h-12 w-12 items-center justify-center rounded-xl ${a.badge}`,
410
- children: /* @__PURE__ */ r(t, { className: `w-6 h-6 ${a.icon}` })
542
+ className: `flex h-12 w-12 items-center justify-center rounded-xl ${o.badge}`,
543
+ children: /* @__PURE__ */ e(r, { className: `w-6 h-6 ${o.icon}` })
411
544
  }
412
545
  ),
413
- /* @__PURE__ */ l("div", { children: [
414
- /* @__PURE__ */ r("p", { className: "text-sm font-medium text-gray-500", children: e }),
415
- /* @__PURE__ */ r("p", { className: "text-3xl font-bold text-gray-900 tabular-nums", children: n })
546
+ /* @__PURE__ */ s("div", { children: [
547
+ /* @__PURE__ */ e("p", { className: "text-sm font-medium text-gray-500", children: t }),
548
+ /* @__PURE__ */ e("p", { className: "text-3xl font-bold text-gray-900 tabular-nums", children: n })
416
549
  ] })
417
550
  ] });
418
551
  }
419
- const W = {
552
+ const S = {
553
+ ok: "bg-green-500",
554
+ down: "bg-red-500",
555
+ unknown: "bg-gray-300"
556
+ }, C = (r) => `${(r * 100).toFixed(4)}%`;
557
+ function ue({
558
+ from: r,
559
+ to: t,
560
+ spans: n,
561
+ buckets: a = 48,
562
+ height: o = "1.75rem",
563
+ renderTooltip: m
564
+ }) {
565
+ const [l, d] = M(null), p = r.getTime(), g = t.getTime() - p;
566
+ if (!(g > 0)) return null;
567
+ const h = g / a, i = Array.from({ length: a }, (c, u) => {
568
+ const x = p + u * h, N = x + h;
569
+ let y = 0;
570
+ for (const T of n) {
571
+ const k = Math.max(T.start.getTime(), x), E = Math.min(T.end.getTime(), N);
572
+ E > k && (y += E - k);
573
+ }
574
+ return {
575
+ start: new Date(x),
576
+ end: new Date(N),
577
+ downMs: y,
578
+ ratio: 1 - y / h
579
+ };
580
+ });
581
+ return /* @__PURE__ */ s("div", { className: "relative", children: [
582
+ l !== null && m && /* @__PURE__ */ e(
583
+ "div",
584
+ {
585
+ className: "pointer-events-none absolute bottom-full z-10 mb-2 whitespace-nowrap rounded-md bg-gray-900 px-2 py-1.5 text-[11px] leading-tight text-white shadow-lg",
586
+ style: ((c) => {
587
+ const u = (c + 0.5) / a;
588
+ return u < 0.15 ? { left: 0 } : u > 0.85 ? { right: 0 } : { left: `${u * 100}%`, transform: "translateX(-50%)" };
589
+ })(l),
590
+ children: m(i[l])
591
+ }
592
+ ),
593
+ /* @__PURE__ */ e(
594
+ "div",
595
+ {
596
+ className: "flex items-stretch gap-[2px]",
597
+ style: { height: o },
598
+ onMouseLeave: () => d(null),
599
+ children: i.map((c, u) => /* @__PURE__ */ e(
600
+ "div",
601
+ {
602
+ onMouseEnter: () => d(u),
603
+ className: `relative min-w-[2px] flex-1 cursor-pointer overflow-hidden rounded-[2px] bg-emerald-500 transition-opacity ${l === u ? "opacity-60" : ""}`,
604
+ children: c.downMs > 0 && /* @__PURE__ */ e(
605
+ "div",
606
+ {
607
+ className: "absolute inset-x-0 bottom-0 bg-red-500",
608
+ style: { height: `max(3px, ${(1 - c.ratio) * 100}%)` }
609
+ }
610
+ )
611
+ },
612
+ c.start.getTime()
613
+ ))
614
+ }
615
+ )
616
+ ] });
617
+ }
618
+ function me({
619
+ from: r,
620
+ to: t,
621
+ lanes: n,
622
+ baseline: a = "ok",
623
+ ticks: o = 5,
624
+ formatTick: m = (g) => g.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }),
625
+ labelWidth: l = "8rem",
626
+ rowHeight: d = "1.25rem",
627
+ emptyLabel: p = "No data"
628
+ }) {
629
+ const g = r.getTime(), h = t.getTime() - g;
630
+ if (!(h > 0) || n.length === 0)
631
+ return /* @__PURE__ */ e("div", { className: "py-8 text-center text-sm text-gray-500", children: p });
632
+ const i = Array.from(
633
+ { length: Math.max(2, o) },
634
+ (b, c) => new Date(g + h * c / (Math.max(2, o) - 1))
635
+ );
636
+ return /* @__PURE__ */ s("div", { className: "space-y-1.5", children: [
637
+ n.map((b) => /* @__PURE__ */ s("div", { className: "flex items-center gap-3", children: [
638
+ /* @__PURE__ */ e(
639
+ "div",
640
+ {
641
+ className: "shrink-0 truncate font-mono text-xs text-gray-600",
642
+ style: { width: l },
643
+ title: b.name,
644
+ children: b.label ?? b.name
645
+ }
646
+ ),
647
+ /* @__PURE__ */ e(
648
+ "div",
649
+ {
650
+ className: `relative flex-1 overflow-hidden rounded-sm ${S[a]}`,
651
+ style: { height: d },
652
+ children: b.spans.map((c) => {
653
+ const u = Math.max(c.start.getTime(), g), x = Math.min(c.end.getTime(), g + h);
654
+ if (x <= u) return null;
655
+ const N = (u - g) / h, y = (x - u) / h;
656
+ return /* @__PURE__ */ e(
657
+ "div",
658
+ {
659
+ className: `absolute inset-y-0 ${S[c.tone]}`,
660
+ style: {
661
+ left: C(N),
662
+ width: `max(2px, ${C(y)})`
663
+ },
664
+ title: c.label
665
+ },
666
+ `${c.start.getTime()}-${c.end.getTime()}`
667
+ );
668
+ })
669
+ }
670
+ ),
671
+ b.trailing !== void 0 && /* @__PURE__ */ e("div", { className: "w-16 shrink-0 text-right font-mono text-xs tabular-nums text-gray-600", children: b.trailing })
672
+ ] }, b.name)),
673
+ /* @__PURE__ */ e(
674
+ "div",
675
+ {
676
+ className: "flex justify-between pt-1 text-[11px] tabular-nums text-gray-400",
677
+ style: {
678
+ marginLeft: l,
679
+ paddingLeft: "0.75rem",
680
+ marginRight: n.some((b) => b.trailing !== void 0) ? "4rem" : void 0
681
+ },
682
+ children: i.map((b) => /* @__PURE__ */ e("span", { children: m(b) }, b.getTime()))
683
+ }
684
+ )
685
+ ] });
686
+ }
687
+ const pe = {
420
688
  blue: {
421
689
  header: "bg-blue-50 text-blue-800",
422
690
  hover: "hover:bg-blue-50",
@@ -458,24 +726,24 @@ const W = {
458
726
  badge: "bg-gray-200 text-gray-700"
459
727
  }
460
728
  };
461
- function ee({
462
- toast: t,
463
- onClose: e
729
+ function he({
730
+ toast: r,
731
+ onClose: t
464
732
  }) {
465
- return t ? /* @__PURE__ */ r(
733
+ return r ? /* @__PURE__ */ e(
466
734
  "div",
467
735
  {
468
- className: `fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg border transition-all duration-300 ease-in-out ${t.type === "success" ? "bg-green-50 text-green-800 border-green-200" : "bg-red-50 text-red-800 border-red-200"}`,
469
- children: /* @__PURE__ */ l("div", { className: "flex items-center space-x-2", children: [
470
- t.type === "success" ? /* @__PURE__ */ r(S, { className: "w-5 h-5 text-green-600" }) : /* @__PURE__ */ r(h, { className: "w-5 h-5 text-red-600" }),
471
- /* @__PURE__ */ r("span", { className: "text-sm font-medium", children: t.message }),
472
- /* @__PURE__ */ r(
736
+ className: `fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg border transition-all duration-300 ease-in-out ${r.type === "success" ? "bg-green-50 text-green-800 border-green-200" : "bg-red-50 text-red-800 border-red-200"}`,
737
+ children: /* @__PURE__ */ s("div", { className: "flex items-center space-x-2", children: [
738
+ r.type === "success" ? /* @__PURE__ */ e(B, { className: "w-5 h-5 text-green-600" }) : /* @__PURE__ */ e(w, { className: "w-5 h-5 text-red-600" }),
739
+ /* @__PURE__ */ e("span", { className: "text-sm font-medium", children: r.message }),
740
+ /* @__PURE__ */ e(
473
741
  "button",
474
742
  {
475
743
  type: "button",
476
- onClick: e,
744
+ onClick: t,
477
745
  className: "ml-2 text-gray-400 hover:text-gray-600 cursor-pointer",
478
- children: /* @__PURE__ */ r(h, { className: "w-4 h-4" })
746
+ children: /* @__PURE__ */ e(w, { className: "w-4 h-4" })
479
747
  }
480
748
  )
481
749
  ] })
@@ -483,23 +751,27 @@ function ee({
483
751
  ) : null;
484
752
  }
485
753
  export {
486
- T as BADGE_COLORS,
487
- G as BackLink,
488
- D as Badge,
489
- U as Button,
490
- y as Card,
491
- z as CountryFlag,
492
- Z as InfoRow,
493
- P as LabelChip,
494
- F as ListRow,
495
- q as PageContainer,
496
- V as Panel,
497
- W as SECTION_THEMES,
498
- J as SearchInput,
499
- X as SectionCard,
500
- M as SideNav,
501
- Q as StatCard,
502
- H as TabNav,
503
- ee as Toast,
504
- Y as ViewAllFooter
754
+ ee as AlertBanner,
755
+ I as BADGE_COLORS,
756
+ oe as BackLink,
757
+ J as Badge,
758
+ X as Button,
759
+ $ as Card,
760
+ ae as CountryFlag,
761
+ de as DropdownMenu,
762
+ ie as InfoRow,
763
+ Q as LabelChip,
764
+ te as ListRow,
765
+ ce as PageContainer,
766
+ W as Panel,
767
+ pe as SECTION_THEMES,
768
+ ge as SearchInput,
769
+ re as SectionCard,
770
+ le as SideNav,
771
+ be as StatCard,
772
+ me as StateTimeline,
773
+ se as TabNav,
774
+ he as Toast,
775
+ ue as UptimeBars,
776
+ ne as ViewAllFooter
505
777
  };
@@ -0,0 +1,67 @@
1
+ import { ReactNode } from 'react';
2
+ /** A contiguous stretch of one state within a lane, in absolute time. */
3
+ export interface TimelineSpan {
4
+ start: Date;
5
+ /** Exclusive. Use the window end for a span that is still open. */
6
+ end: Date;
7
+ tone: TimelineTone;
8
+ /** Shown in the browser tooltip on hover. */
9
+ label?: string;
10
+ }
11
+ export interface TimelineLane {
12
+ /** Stable identity for the lane; also the default row label. */
13
+ name: string;
14
+ label?: ReactNode;
15
+ /** Spans that interrupt the lane's baseline. Order does not matter. */
16
+ spans: TimelineSpan[];
17
+ /** Trailing text on the right of the row, e.g. an uptime percentage. */
18
+ trailing?: ReactNode;
19
+ }
20
+ export type TimelineTone = "ok" | "down" | "unknown";
21
+ export interface UptimeBucket {
22
+ start: Date;
23
+ end: Date;
24
+ /** Downtime inside this bucket, in ms. */
25
+ downMs: number;
26
+ /** Fraction of the bucket spent up, 0..1. */
27
+ ratio: number;
28
+ }
29
+ /**
30
+ * Status-page style availability bars: the window is split into equal buckets,
31
+ * each drawn green with a red portion sized to the downtime inside it.
32
+ *
33
+ * The proportion is the point — colouring a whole bucket red for a 30-second
34
+ * blip makes a flapping device look permanently offline. A red sliver reads as
35
+ * "briefly down", a full red bar as "down the whole time", with no intermediate
36
+ * colour whose meaning has to be guessed.
37
+ */
38
+ export declare function UptimeBars({ from, to, spans, buckets, height, renderTooltip, }: {
39
+ from: Date;
40
+ to: Date;
41
+ /** Down intervals in absolute time; clipped to the window. */
42
+ spans: TimelineSpan[];
43
+ buckets?: number;
44
+ height?: string;
45
+ /** Hover card contents for a bucket. No tooltip is shown when omitted. */
46
+ renderTooltip?: (bucket: UptimeBucket) => ReactNode;
47
+ }): import("react/jsx-runtime").JSX.Element | null;
48
+ /**
49
+ * Horizontal state timeline: one lane per series, spans drawn as coloured bands
50
+ * against a baseline.
51
+ *
52
+ * Positions are percentages of the window rather than pixels, so the chart is
53
+ * fluid and needs no measurement pass or charting library. Spans are clipped to
54
+ * `[from, to]`, which lets callers pass raw intervals that start before or end
55
+ * after the window.
56
+ */
57
+ export declare function StateTimeline({ from, to, lanes, baseline, ticks, formatTick, labelWidth, rowHeight, emptyLabel, }: {
58
+ from: Date;
59
+ to: Date;
60
+ lanes: TimelineLane[];
61
+ baseline?: TimelineTone;
62
+ ticks?: number;
63
+ formatTick?: (date: Date) => string;
64
+ labelWidth?: string;
65
+ rowHeight?: string;
66
+ emptyLabel?: string;
67
+ }): import("react/jsx-runtime").JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teton/smith-ui",
3
- "version": "0.2.179",
3
+ "version": "0.2.181",
4
4
  "description": "Smith dashboard design-system primitives (React + Tailwind CSS v4).",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {