@teton/smith-ui 0.2.178 → 0.2.180

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/index.d.ts CHANGED
@@ -6,5 +6,6 @@ export { BackLink, InfoRow, SideNav, type SideNavItem, type TabItem, TabNav, } f
6
6
  export { PageContainer } from './page-container';
7
7
  export { SearchInput } from './search-input';
8
8
  export { StatCard } from './stat-card';
9
+ export { StateTimeline, type TimelineLane, type TimelineSpan, type TimelineTone, } from './state-timeline';
9
10
  export { type IconComponent, SECTION_THEMES, type SectionTheme, type SectionThemeName, } from './theme';
10
11
  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 l, Fragment as y } from "react/jsx-runtime";
2
+ import { X as v, Loader2 as E, ArrowLeft as S, Search as L, Check as C } from "lucide-react";
3
+ import { Link as h } from "react-router";
4
+ import { useRef as j, useEffect as A } from "react";
5
+ const R = {
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({
14
+ function U({
15
15
  variant: t = "gray",
16
- pill: e = !1,
16
+ pill: r = !1,
17
17
  className: n = "",
18
18
  children: o
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}`,
23
+ className: `px-1.5 py-0.5 text-xs font-medium ${r ? "rounded-full" : "rounded"} ${R[t]} ${n}`,
24
24
  children: o
25
25
  }
26
26
  );
27
27
  }
28
- function P({
28
+ function V({
29
29
  name: t,
30
- value: e,
30
+ value: r,
31
31
  onClick: n,
32
32
  onRemove: o,
33
33
  active: a = !1,
34
34
  title: g
35
35
  }) {
36
- const s = /* @__PURE__ */ l(u, { children: [
37
- /* @__PURE__ */ r(
36
+ const s = /* @__PURE__ */ l(y, { children: [
37
+ /* @__PURE__ */ e(
38
38
  "span",
39
39
  {
40
40
  className: `px-2 py-1 font-medium ${a ? "text-blue-700 bg-blue-100" : "text-gray-500 bg-gray-50"}`,
41
41
  children: t
42
42
  }
43
43
  ),
44
- e !== void 0 && e !== "" && /* @__PURE__ */ r(
44
+ r !== void 0 && r !== "" && /* @__PURE__ */ e(
45
45
  "span",
46
46
  {
47
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
48
+ children: r
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: [
51
+ ] }), i = `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: i, children: [
53
53
  s,
54
- /* @__PURE__ */ r(
54
+ /* @__PURE__ */ e(
55
55
  "button",
56
56
  {
57
57
  type: "button",
58
58
  onClick: o,
59
59
  title: g,
60
- "aria-label": `Remove ${e !== void 0 ? `${t}=${e}` : t}`,
60
+ "aria-label": `Remove ${r !== void 0 ? `${t}=${r}` : t}`,
61
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" })
62
+ children: /* @__PURE__ */ e(v, { 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
70
  title: g,
71
- className: `${d} cursor-pointer transition-colors ${a ? "" : "hover:border-gray-300"}`,
71
+ className: `${i} cursor-pointer transition-colors ${a ? "" : "hover:border-gray-300"}`,
72
72
  children: s
73
73
  }
74
- ) : /* @__PURE__ */ r("span", { className: d, children: s });
74
+ ) : /* @__PURE__ */ e("span", { className: i, children: s });
75
75
  }
76
- const C = {
76
+ const _ = {
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,91 +98,91 @@ 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
+ }, B = {
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
+ }, M = {
105
105
  solid: "shadow-sm hover:shadow-md",
106
106
  soft: "shadow-sm hover:shadow",
107
107
  ghost: ""
108
108
  };
109
- function U({
109
+ function X({
110
110
  variant: t = "soft",
111
- tone: e = "blue",
111
+ tone: r = "blue",
112
112
  size: n = "md",
113
113
  icon: o,
114
114
  loading: a = !1,
115
115
  disabled: g = !1,
116
116
  type: s = "button",
117
- title: d,
118
- onClick: i,
117
+ title: i,
118
+ onClick: u,
119
119
  to: c,
120
120
  href: m,
121
121
  target: f,
122
- className: v = "",
123
- children: N
122
+ className: d = "",
123
+ children: b
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 x = `inline-flex items-center justify-center font-medium rounded-lg transition-colors duration-100 cursor-pointer active:scale-[.98] ${B[n]} ${M[t]} ${_[t][r]} ${d}`, p = /* @__PURE__ */ l(y, { children: [
126
+ a ? /* @__PURE__ */ e(E, { className: "w-4 h-4 animate-spin" }) : o,
127
+ b
128
128
  ] });
129
- return c ? /* @__PURE__ */ r(b, { to: c, className: p, title: d, children: x }) : m ? /* @__PURE__ */ r(
129
+ return c ? /* @__PURE__ */ e(h, { to: c, className: x, title: i, children: p }) : m ? /* @__PURE__ */ e(
130
130
  "a",
131
131
  {
132
132
  href: m,
133
133
  target: f,
134
134
  rel: f === "_blank" ? "noopener noreferrer" : void 0,
135
- className: p,
136
- title: d,
137
- children: x
135
+ className: x,
136
+ title: i,
137
+ children: p
138
138
  }
139
- ) : /* @__PURE__ */ r(
139
+ ) : /* @__PURE__ */ e(
140
140
  "button",
141
141
  {
142
142
  type: s,
143
- onClick: i,
143
+ onClick: u,
144
144
  disabled: g || a,
145
- title: d,
146
- className: `${p} disabled:opacity-50 disabled:cursor-not-allowed`,
147
- children: x
145
+ title: i,
146
+ className: `${x} disabled:opacity-50 disabled:cursor-not-allowed`,
147
+ children: p
148
148
  }
149
149
  );
150
150
  }
151
- function y({
151
+ function $({
152
152
  className: t = "",
153
- children: e
153
+ children: r
154
154
  }) {
155
- return /* @__PURE__ */ r(
155
+ return /* @__PURE__ */ e(
156
156
  "div",
157
157
  {
158
158
  className: `bg-white rounded-xl border border-gray-200/80 shadow-sm ${t}`,
159
- children: e
159
+ children: r
160
160
  }
161
161
  );
162
162
  }
163
- function V({
163
+ function Y({
164
164
  icon: t,
165
- title: e,
165
+ title: r,
166
166
  theme: n,
167
167
  count: o,
168
168
  actions: a,
169
169
  bodyClassName: g = "p-5",
170
170
  className: s = "",
171
- children: d
171
+ children: i
172
172
  }) {
173
- return /* @__PURE__ */ l(y, { className: `overflow-hidden ${s}`, children: [
173
+ return /* @__PURE__ */ l($, { className: `overflow-hidden ${s}`, children: [
174
174
  /* @__PURE__ */ l(
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
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
180
+ t && /* @__PURE__ */ e(t, { className: "w-4 h-4 mr-2" }),
181
+ r
182
182
  ] }),
183
183
  (a || o !== void 0) && /* @__PURE__ */ l("div", { className: "flex items-center gap-2", children: [
184
184
  a,
185
- o !== void 0 && /* @__PURE__ */ r(
185
+ o !== 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}`,
@@ -193,31 +193,31 @@ function V({
193
193
  ]
194
194
  }
195
195
  ),
196
- /* @__PURE__ */ r("div", { className: g, children: d })
196
+ /* @__PURE__ */ e("div", { className: g, children: i })
197
197
  ] });
198
198
  }
199
- function X({
199
+ function z({
200
200
  icon: t,
201
- title: e,
201
+ title: r,
202
202
  count: n,
203
203
  theme: o,
204
204
  actions: a,
205
205
  footer: g,
206
206
  children: s
207
207
  }) {
208
- return /* @__PURE__ */ l(y, { className: "overflow-hidden flex flex-col", children: [
208
+ return /* @__PURE__ */ l($, { className: "overflow-hidden flex flex-col", children: [
209
209
  /* @__PURE__ */ l(
210
210
  "div",
211
211
  {
212
212
  className: `px-4 py-3 flex items-center justify-between border-b border-black/5 ${o.header}`,
213
213
  children: [
214
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
215
+ t && /* @__PURE__ */ e(t, { className: "w-4 h-4 mr-2" }),
216
+ r
217
217
  ] }),
218
218
  /* @__PURE__ */ l("div", { className: "flex items-center gap-2", children: [
219
219
  a,
220
- n !== void 0 && /* @__PURE__ */ r(
220
+ n !== void 0 && /* @__PURE__ */ e(
221
221
  "span",
222
222
  {
223
223
  className: `text-xs font-semibold px-2 py-0.5 rounded-full ${o.badge}`,
@@ -228,41 +228,41 @@ function X({
228
228
  ]
229
229
  }
230
230
  ),
231
- /* @__PURE__ */ r("div", { className: "divide-y divide-gray-100", children: s }),
231
+ /* @__PURE__ */ e("div", { className: "divide-y divide-gray-100", children: s }),
232
232
  g
233
233
  ] });
234
234
  }
235
- function F({
235
+ function G({
236
236
  to: t,
237
- onClick: e,
237
+ onClick: r,
238
238
  hover: n = "hover:bg-gray-50",
239
239
  className: o = "",
240
240
  children: a
241
241
  }) {
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(
242
+ const s = `flex items-center justify-between px-4 py-3 transition-colors ${n} ${!!(t || r) ? "cursor-pointer" : ""} ${o}`;
243
+ return t ? /* @__PURE__ */ e(h, { to: t, className: s, children: a }) : r ? /* @__PURE__ */ e(
244
244
  "button",
245
245
  {
246
246
  type: "button",
247
- onClick: e,
247
+ onClick: r,
248
248
  className: `w-full text-left ${s}`,
249
249
  children: a
250
250
  }
251
- ) : /* @__PURE__ */ r("div", { className: s, children: a });
251
+ ) : /* @__PURE__ */ e("div", { className: s, children: a });
252
252
  }
253
- function Y({
253
+ function H({
254
254
  to: t,
255
- count: e,
255
+ count: r,
256
256
  noun: n = "items"
257
257
  }) {
258
258
  return /* @__PURE__ */ l(
259
- b,
259
+ h,
260
260
  {
261
261
  to: t,
262
262
  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
263
  children: [
264
264
  "View all ",
265
- e,
265
+ r,
266
266
  " ",
267
267
  n,
268
268
  " →"
@@ -270,16 +270,16 @@ function Y({
270
270
  }
271
271
  );
272
272
  }
273
- const R = (t) => `https://flagicons.lipis.dev/flags/4x3/${t.toLowerCase()}.svg`;
274
- function z({
273
+ const O = (t) => `https://flagicons.lipis.dev/flags/4x3/${t.toLowerCase()}.svg`;
274
+ function Z({
275
275
  countryCode: t,
276
- country: e
276
+ country: r
277
277
  }) {
278
- return t ? /* @__PURE__ */ r(
278
+ return t ? /* @__PURE__ */ e(
279
279
  "img",
280
280
  {
281
- src: R(t),
282
- alt: e || "Country flag",
281
+ src: O(t),
282
+ alt: r || "Country flag",
283
283
  className: "w-4 h-3 flex-shrink-0 rounded-sm ring-1 ring-black/5",
284
284
  onError: (n) => {
285
285
  n.target.style.display = "none";
@@ -287,107 +287,107 @@ function z({
287
287
  }
288
288
  ) : null;
289
289
  }
290
- function G({
290
+ function q({
291
291
  to: t,
292
- onClick: e,
292
+ onClick: r,
293
293
  children: n
294
294
  }) {
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 })
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(y, { children: [
296
+ /* @__PURE__ */ e(S, { className: "w-4 h-4" }),
297
+ /* @__PURE__ */ e("span", { children: n })
298
298
  ] });
299
- return t ? /* @__PURE__ */ r(b, { to: t, className: o, children: a }) : /* @__PURE__ */ r("button", { type: "button", onClick: e, className: o, children: a });
299
+ return t ? /* @__PURE__ */ e(h, { to: t, className: o, children: a }) : /* @__PURE__ */ e("button", { type: "button", onClick: r, className: o, children: a });
300
300
  }
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,
301
+ function J({ items: t }) {
302
+ return /* @__PURE__ */ e("div", { className: "border-b border-gray-200", children: /* @__PURE__ */ e("nav", { className: "-mb-px flex space-x-8", children: t.map((r) => {
303
+ const n = r.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 r.to && !r.active ? /* @__PURE__ */ e(
305
+ h,
306
306
  {
307
- to: e.to,
308
- state: e.state,
307
+ to: r.to,
308
+ state: r.state,
309
309
  className: n,
310
- children: e.label
310
+ children: r.label
311
311
  },
312
- e.label
313
- ) : /* @__PURE__ */ r("span", { className: n, children: e.label }, e.label);
312
+ r.label
313
+ ) : /* @__PURE__ */ e("span", { className: n, children: r.label }, r.label);
314
314
  }) }) });
315
315
  }
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(
316
+ function Q({ items: t }) {
317
+ return /* @__PURE__ */ e("nav", { className: "space-y-1", children: t.map((r) => {
318
+ const n = r.icon, o = `group/side relative flex items-center gap-3 h-10 rounded-md px-3 text-sm transition-all duration-200 cursor-pointer ${r.active ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-600 hover:bg-gray-100 hover:text-gray-900"}`, a = /* @__PURE__ */ l(y, { children: [
319
+ /* @__PURE__ */ e(
320
320
  "span",
321
321
  {
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"}`
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 ${r.active ? "opacity-100 scale-y-100" : "opacity-0 scale-y-0"}`
323
323
  }
324
324
  ),
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 })
325
+ n && /* @__PURE__ */ e(n, { className: "w-[18px] h-[18px] shrink-0 transition-transform duration-200 group-hover/side:scale-110" }),
326
+ /* @__PURE__ */ e("span", { className: "truncate", children: r.label })
327
327
  ] });
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);
328
+ return r.active ? /* @__PURE__ */ e("span", { className: o, "aria-current": "page", children: a }, r.to) : /* @__PURE__ */ e(h, { to: r.to, className: o, children: a }, r.to);
329
329
  }) });
330
330
  }
331
- function Z({
331
+ function W({
332
332
  label: t,
333
- icon: e,
333
+ icon: r,
334
334
  iconClassName: n = "text-gray-400",
335
335
  children: o
336
336
  }) {
337
337
  return /* @__PURE__ */ l("div", { className: "flex items-center justify-between gap-4", children: [
338
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}` }),
339
+ r && /* @__PURE__ */ e(r, { className: `w-4 h-4 mr-2 ${n}` }),
340
340
  t
341
341
  ] }),
342
- /* @__PURE__ */ r("span", { className: "text-sm text-gray-900 text-right min-w-0", children: o })
342
+ /* @__PURE__ */ e("span", { className: "text-sm text-gray-900 text-right min-w-0", children: o })
343
343
  ] });
344
344
  }
345
- function q({
345
+ function ee({
346
346
  className: t = "space-y-6",
347
- children: e
347
+ children: r
348
348
  }) {
349
- return /* @__PURE__ */ r(
349
+ return /* @__PURE__ */ e(
350
350
  "div",
351
351
  {
352
352
  className: `flex-1 overflow-y-auto px-4 sm:px-6 lg:px-8 py-6 ${t}`,
353
- children: e
353
+ children: r
354
354
  }
355
355
  );
356
356
  }
357
- function J({
357
+ function re({
358
358
  value: t,
359
- onChange: e,
359
+ onChange: r,
360
360
  placeholder: n = "Search...",
361
361
  className: o = "w-full",
362
362
  slashToFocus: a = !1
363
363
  }) {
364
- const g = k(null);
365
- return L(() => {
364
+ const g = j(null);
365
+ return A(() => {
366
366
  if (!a) return;
367
- function s(d) {
367
+ function s(i) {
368
368
  var c;
369
- 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());
369
+ if (i.key !== "/" || i.ctrlKey || i.metaKey || i.altKey) return;
370
+ const u = i.target;
371
+ u.tagName === "INPUT" || u.tagName === "TEXTAREA" || u.tagName === "SELECT" || u.isContentEditable || (i.preventDefault(), (c = g.current) == null || c.focus());
372
372
  }
373
373
  return document.addEventListener("keydown", s), () => document.removeEventListener("keydown", s);
374
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(
375
+ /* @__PURE__ */ e(L, { className: "absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-4 h-4 pointer-events-none" }),
376
+ /* @__PURE__ */ e(
377
377
  "input",
378
378
  {
379
379
  ref: g,
380
380
  type: "text",
381
381
  value: t,
382
- onChange: (s) => e(s.target.value),
382
+ onChange: (s) => r(s.target.value),
383
383
  placeholder: n,
384
384
  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
385
  }
386
386
  ),
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: "/" })
387
+ a && !t && /* @__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
388
  ] });
389
389
  }
390
- const B = {
390
+ const D = {
391
391
  neutral: { badge: "bg-gray-100", icon: "text-gray-400" },
392
392
  green: { badge: "bg-green-100", icon: "text-green-600" },
393
393
  blue: { badge: "bg-blue-100", icon: "text-blue-600" },
@@ -395,28 +395,102 @@ const B = {
395
395
  red: { badge: "bg-red-100", icon: "text-red-600" },
396
396
  purple: { badge: "bg-purple-100", icon: "text-purple-600" }
397
397
  };
398
- function Q({
398
+ function te({
399
399
  icon: t,
400
- label: e,
400
+ label: r,
401
401
  value: n,
402
402
  tone: o = "neutral"
403
403
  }) {
404
- const a = B[o];
404
+ const a = D[o];
405
405
  return /* @__PURE__ */ l("div", { className: "flex items-center gap-4", children: [
406
- /* @__PURE__ */ r(
406
+ /* @__PURE__ */ e(
407
407
  "div",
408
408
  {
409
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}` })
410
+ children: /* @__PURE__ */ e(t, { className: `w-6 h-6 ${a.icon}` })
411
411
  }
412
412
  ),
413
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 })
414
+ /* @__PURE__ */ e("p", { className: "text-sm font-medium text-gray-500", children: r }),
415
+ /* @__PURE__ */ e("p", { className: "text-3xl font-bold text-gray-900 tabular-nums", children: n })
416
416
  ] })
417
417
  ] });
418
418
  }
419
- const W = {
419
+ const N = {
420
+ ok: "bg-green-500",
421
+ down: "bg-red-500",
422
+ unknown: "bg-gray-300"
423
+ }, w = (t) => `${(t * 100).toFixed(4)}%`;
424
+ function ne({
425
+ from: t,
426
+ to: r,
427
+ lanes: n,
428
+ baseline: o = "ok",
429
+ ticks: a = 5,
430
+ formatTick: g = (c) => c.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }),
431
+ labelWidth: s = "8rem",
432
+ rowHeight: i = "1.25rem",
433
+ emptyLabel: u = "No data"
434
+ }) {
435
+ const c = t.getTime(), m = r.getTime() - c;
436
+ if (!(m > 0) || n.length === 0)
437
+ return /* @__PURE__ */ e("div", { className: "py-8 text-center text-sm text-gray-500", children: u });
438
+ const f = Array.from(
439
+ { length: Math.max(2, a) },
440
+ (d, b) => new Date(c + m * b / (Math.max(2, a) - 1))
441
+ );
442
+ return /* @__PURE__ */ l("div", { className: "space-y-1.5", children: [
443
+ n.map((d) => /* @__PURE__ */ l("div", { className: "flex items-center gap-3", children: [
444
+ /* @__PURE__ */ e(
445
+ "div",
446
+ {
447
+ className: "shrink-0 truncate font-mono text-xs text-gray-600",
448
+ style: { width: s },
449
+ title: d.name,
450
+ children: d.label ?? d.name
451
+ }
452
+ ),
453
+ /* @__PURE__ */ e(
454
+ "div",
455
+ {
456
+ className: `relative flex-1 overflow-hidden rounded-sm ${N[o]}`,
457
+ style: { height: i },
458
+ children: d.spans.map((b) => {
459
+ const x = Math.max(b.start.getTime(), c), p = Math.min(b.end.getTime(), c + m);
460
+ if (p <= x) return null;
461
+ const T = (x - c) / m, k = (p - x) / m;
462
+ return /* @__PURE__ */ e(
463
+ "div",
464
+ {
465
+ className: `absolute inset-y-0 ${N[b.tone]}`,
466
+ style: {
467
+ left: w(T),
468
+ width: `max(2px, ${w(k)})`
469
+ },
470
+ title: b.label
471
+ },
472
+ `${b.start.getTime()}-${b.end.getTime()}`
473
+ );
474
+ })
475
+ }
476
+ ),
477
+ d.trailing !== void 0 && /* @__PURE__ */ e("div", { className: "w-16 shrink-0 text-right font-mono text-xs tabular-nums text-gray-600", children: d.trailing })
478
+ ] }, d.name)),
479
+ /* @__PURE__ */ e(
480
+ "div",
481
+ {
482
+ className: "flex justify-between pt-1 text-[11px] tabular-nums text-gray-400",
483
+ style: {
484
+ marginLeft: s,
485
+ paddingLeft: "0.75rem",
486
+ marginRight: n.some((d) => d.trailing !== void 0) ? "4rem" : void 0
487
+ },
488
+ children: f.map((d) => /* @__PURE__ */ e("span", { children: g(d) }, d.getTime()))
489
+ }
490
+ )
491
+ ] });
492
+ }
493
+ const ae = {
420
494
  blue: {
421
495
  header: "bg-blue-50 text-blue-800",
422
496
  hover: "hover:bg-blue-50",
@@ -458,24 +532,24 @@ const W = {
458
532
  badge: "bg-gray-200 text-gray-700"
459
533
  }
460
534
  };
461
- function ee({
535
+ function oe({
462
536
  toast: t,
463
- onClose: e
537
+ onClose: r
464
538
  }) {
465
- return t ? /* @__PURE__ */ r(
539
+ return t ? /* @__PURE__ */ e(
466
540
  "div",
467
541
  {
468
542
  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
543
  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(
544
+ t.type === "success" ? /* @__PURE__ */ e(C, { className: "w-5 h-5 text-green-600" }) : /* @__PURE__ */ e(v, { className: "w-5 h-5 text-red-600" }),
545
+ /* @__PURE__ */ e("span", { className: "text-sm font-medium", children: t.message }),
546
+ /* @__PURE__ */ e(
473
547
  "button",
474
548
  {
475
549
  type: "button",
476
- onClick: e,
550
+ onClick: r,
477
551
  className: "ml-2 text-gray-400 hover:text-gray-600 cursor-pointer",
478
- children: /* @__PURE__ */ r(h, { className: "w-4 h-4" })
552
+ children: /* @__PURE__ */ e(v, { className: "w-4 h-4" })
479
553
  }
480
554
  )
481
555
  ] })
@@ -483,23 +557,24 @@ function ee({
483
557
  ) : null;
484
558
  }
485
559
  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
560
+ R as BADGE_COLORS,
561
+ q as BackLink,
562
+ U as Badge,
563
+ X as Button,
564
+ $ as Card,
565
+ Z as CountryFlag,
566
+ W as InfoRow,
567
+ V as LabelChip,
568
+ G as ListRow,
569
+ ee as PageContainer,
570
+ Y as Panel,
571
+ ae as SECTION_THEMES,
572
+ re as SearchInput,
573
+ z as SectionCard,
574
+ Q as SideNav,
575
+ te as StatCard,
576
+ ne as StateTimeline,
577
+ J as TabNav,
578
+ oe as Toast,
579
+ H as ViewAllFooter
505
580
  };
@@ -0,0 +1,40 @@
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
+ /**
22
+ * Horizontal state timeline: one lane per series, spans drawn as coloured bands
23
+ * against a baseline.
24
+ *
25
+ * Positions are percentages of the window rather than pixels, so the chart is
26
+ * fluid and needs no measurement pass or charting library. Spans are clipped to
27
+ * `[from, to]`, which lets callers pass raw intervals that start before or end
28
+ * after the window.
29
+ */
30
+ export declare function StateTimeline({ from, to, lanes, baseline, ticks, formatTick, labelWidth, rowHeight, emptyLabel, }: {
31
+ from: Date;
32
+ to: Date;
33
+ lanes: TimelineLane[];
34
+ baseline?: TimelineTone;
35
+ ticks?: number;
36
+ formatTick?: (date: Date) => string;
37
+ labelWidth?: string;
38
+ rowHeight?: string;
39
+ emptyLabel?: string;
40
+ }): 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.178",
3
+ "version": "0.2.180",
4
4
  "description": "Smith dashboard design-system primitives (React + Tailwind CSS v4).",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {