@devalok/shilp-sutra 0.49.1 → 0.49.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/_chunks/badge-group.js +37 -37
  2. package/dist/_chunks/badge-group.js.map +1 -1
  3. package/dist/_chunks/chat.js +3 -12
  4. package/dist/_chunks/chat.js.map +1 -1
  5. package/dist/_chunks/primitives.js +6 -9
  6. package/dist/_chunks/primitives.js.map +1 -1
  7. package/dist/_chunks/success.js +1 -4
  8. package/dist/_chunks/success.js.map +1 -1
  9. package/dist/ai/block-renderer.js +1 -4
  10. package/dist/ai/block-renderer.js.map +1 -1
  11. package/dist/ai/command-bar.d.ts.map +1 -1
  12. package/dist/ai/command-bar.js +2 -33
  13. package/dist/ai/command-bar.js.map +1 -1
  14. package/dist/ai/conversation.js +2 -8
  15. package/dist/ai/conversation.js.map +1 -1
  16. package/dist/ai/devadoot-icon.d.ts.map +1 -1
  17. package/dist/ai/index.js +7 -38
  18. package/dist/ai/index.js.map +1 -1
  19. package/dist/composed/activity-feed.js +3 -3
  20. package/dist/composed/activity-feed.js.map +1 -1
  21. package/dist/composed/avatar-group.js +2 -2
  22. package/dist/composed/avatar-group.js.map +1 -1
  23. package/dist/composed/empty-state.d.ts.map +1 -1
  24. package/dist/composed/empty-state.js +22 -32
  25. package/dist/composed/empty-state.js.map +1 -1
  26. package/dist/composed/schedule-view.js +1 -1
  27. package/dist/composed/schedule-view.js.map +1 -1
  28. package/dist/primitives/_internal/react-dismissable-layer.d.ts.map +1 -1
  29. package/dist/primitives/_internal/react-focus-scope.d.ts.map +1 -1
  30. package/dist/shell/bottom-navbar.js +1 -1
  31. package/dist/shell/bottom-navbar.js.map +1 -1
  32. package/dist/ui/avatar.d.ts.map +1 -1
  33. package/dist/ui/avatar.js +44 -59
  34. package/dist/ui/avatar.js.map +1 -1
  35. package/dist/ui/badge.d.ts +2 -0
  36. package/dist/ui/badge.d.ts.map +1 -1
  37. package/dist/ui/button.js +4 -4
  38. package/dist/ui/button.js.map +1 -1
  39. package/dist/ui/combobox.js +1 -1
  40. package/dist/ui/combobox.js.map +1 -1
  41. package/dist/ui/dot.d.ts.map +1 -1
  42. package/dist/ui/dot.js +23 -31
  43. package/dist/ui/dot.js.map +1 -1
  44. package/dist/ui/slider.js +1 -1
  45. package/dist/ui/slider.js.map +1 -1
  46. package/dist/ui/stat-card.d.ts +2 -0
  47. package/dist/ui/stat-card.d.ts.map +1 -1
  48. package/dist/ui/stat-card.js +92 -124
  49. package/dist/ui/stat-card.js.map +1 -1
  50. package/llms.txt +1 -1
  51. package/mcp-manifest.json +1 -1
  52. package/package.json +1 -1
  53. package/skill/SKILL.md +1 -1
  54. package/skill/references/components.md +1 -1
@@ -11,10 +11,10 @@ import { useLink as d } from "../_chunks/link-context.js";
11
11
  import { StatFlash as f } from "./stat-flash.js";
12
12
  import * as p from "react";
13
13
  import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
14
- import { IconMinus as _, IconTrendingDown as v, IconTrendingUp as y } from "@tabler/icons-react";
15
- import { motion as b } from "framer-motion";
14
+ import { IconMinus as ee, IconTrendingDown as te, IconTrendingUp as _ } from "@tabler/icons-react";
15
+ import { motion as v } from "framer-motion";
16
16
  //#region src/ui/stat-card.tsx
17
- function x(e, t, n) {
17
+ function y(e, t, n) {
18
18
  let r = e.filter((e) => Number.isFinite(e));
19
19
  if (r.length < 2) return "";
20
20
  let i = Math.min(...r), a = Math.max(...r) - i || 1, o = t / (r.length - 1);
@@ -23,8 +23,8 @@ function x(e, t, n) {
23
23
  return `${t === 0 ? "M" : "L"}${r.toFixed(1)},${s.toFixed(1)}`;
24
24
  }).join(" ");
25
25
  }
26
- function S({ data: e, colorClass: t }) {
27
- let n = p.useId(), i = p.useRef(null), [a, o] = p.useState(0), s = x(e, 80, 32);
26
+ function b({ data: e, colorClass: t }) {
27
+ let n = p.useId(), i = p.useRef(null), [a, o] = p.useState(0), s = y(e, 80, 32);
28
28
  if (p.useEffect(() => {
29
29
  i.current && o(i.current.getTotalLength());
30
30
  }, [s]), !s) return null;
@@ -76,7 +76,7 @@ function S({ data: e, colorClass: t }) {
76
76
  }), a > 0 && /* @__PURE__ */ h("style", { children: `@keyframes sparkline-draw-${n.replace(/:/g, "")} { to { stroke-dashoffset: 0; } }` })]
77
77
  });
78
78
  }
79
- function C({ progress: e, label: t }) {
79
+ function x({ progress: e, label: t }) {
80
80
  let n = Math.max(0, Math.min(100, e)), r = n >= 90 ? "success" : n >= 70 ? "warning" : "accent";
81
81
  return /* @__PURE__ */ h(u.Root, {
82
82
  value: n,
@@ -87,15 +87,15 @@ function C({ progress: e, label: t }) {
87
87
  })
88
88
  });
89
89
  }
90
- var w = p.forwardRef(({ className: u, label: p, title: x, value: w, prefix: T, suffix: E, delta: D, deltaPlacement: O = "block", icon: k, loading: ee, comparisonLabel: A, secondaryLabel: j, progress: M, variant: N = "default", size: P = "md", accentStyle: F = "none", iconFill: I = "soft", flash: L, flashSpeed: R, sparkline: z, onClick: B, href: V, footer: H, ...U }, W) => {
91
- let G = d(), K = x ?? p ?? "", q = (B || V) && !U["aria-label"] ? `View ${K}` : U["aria-label"];
92
- if (ee) return /* @__PURE__ */ h(s, {
93
- ref: W,
94
- variant: N,
95
- size: P,
90
+ var S = p.forwardRef(({ className: u, label: p, title: y, value: S, prefix: C, suffix: w, delta: T, deltaPlacement: E = "block", icon: D, loading: ne, comparisonLabel: O, secondaryLabel: k, progress: A, variant: j = "default", size: M = "md", accentStyle: N = "none", reveal: P = !1, iconFill: F = "soft", flash: I, flashSpeed: L, sparkline: R, onClick: z, href: B, footer: V, ...H }, U) => {
91
+ let W = d(), G = y ?? p ?? "", K = (z || B) && !H["aria-label"] ? `View ${G}` : H["aria-label"];
92
+ if (ne) return /* @__PURE__ */ h(s, {
93
+ ref: U,
94
+ variant: j,
95
+ size: M,
96
96
  className: u,
97
97
  "aria-busy": "true",
98
- ...U,
98
+ ...H,
99
99
  children: /* @__PURE__ */ g(c, {
100
100
  className: "flex flex-col gap-ds-03",
101
101
  children: [
@@ -105,8 +105,8 @@ var w = p.forwardRef(({ className: u, label: p, title: x, value: w, prefix: T, s
105
105
  ]
106
106
  })
107
107
  });
108
- let J = D?.direction === "up" ? y : D?.direction === "down" ? v : _, Y = D?.direction === "up" ? "text-success-11" : D?.direction === "down" ? "text-error-11" : "text-surface-fg-muted", X = D?.direction === "up" ? "text-success-11" : D?.direction === "down" ? "text-error-11" : "text-accent-11", Z = D ? /* @__PURE__ */ g(b.div, {
109
- className: r("flex items-center gap-ds-02 text-ds-sm font-medium", Y),
108
+ let q = T?.direction === "up" ? _ : T?.direction === "down" ? te : ee, J = T?.direction === "up" ? "text-success-11" : T?.direction === "down" ? "text-error-11" : "text-surface-fg-muted", Y = T?.direction === "up" ? "text-success-11" : T?.direction === "down" ? "text-error-11" : "text-accent-11", X = T ? /* @__PURE__ */ g(v.div, {
109
+ className: r("flex items-center gap-ds-02 text-ds-sm font-medium", J),
110
110
  initial: {
111
111
  opacity: 0,
112
112
  y: 8
@@ -120,7 +120,7 @@ var w = p.forwardRef(({ className: u, label: p, title: x, value: w, prefix: T, s
120
120
  delay: .2
121
121
  },
122
122
  children: [
123
- /* @__PURE__ */ h(b.span, {
123
+ /* @__PURE__ */ h(v.span, {
124
124
  className: "inline-flex",
125
125
  initial: {
126
126
  opacity: .5,
@@ -132,66 +132,52 @@ var w = p.forwardRef(({ className: u, label: p, title: x, value: w, prefix: T, s
132
132
  },
133
133
  transition: t.smooth,
134
134
  children: /* @__PURE__ */ h(i, {
135
- icon: J,
135
+ icon: q,
136
136
  size: "sm"
137
137
  })
138
138
  }),
139
- /* @__PURE__ */ h("span", { children: D.value }),
140
- A && /* @__PURE__ */ h("span", {
139
+ /* @__PURE__ */ h("span", { children: T.value }),
140
+ O && /* @__PURE__ */ h("span", {
141
141
  className: "text-surface-fg-subtle font-normal",
142
- children: A
142
+ children: O
143
143
  })
144
144
  ]
145
- }) : null, te = /* @__PURE__ */ g(m, { children: [
145
+ }) : null, Z = P ? {
146
+ initial: { y: 8 },
147
+ animate: { y: 0 },
148
+ transition: t.smooth
149
+ } : { initial: !1 }, re = /* @__PURE__ */ g(m, { children: [
146
150
  /* @__PURE__ */ g("div", {
147
151
  className: "flex items-center justify-between",
148
- children: [/* @__PURE__ */ h(b.p, {
152
+ children: [/* @__PURE__ */ h(v.p, {
149
153
  className: "text-ds-md font-medium text-surface-fg-muted",
150
- initial: { opacity: 0 },
151
- animate: { opacity: 1 },
152
- transition: n.fade,
153
- children: K
154
+ ...Z,
155
+ children: G
154
156
  }), /* @__PURE__ */ g("div", {
155
157
  className: "flex items-center gap-ds-03",
156
- children: [z && z.length >= 2 && /* @__PURE__ */ h(S, {
157
- data: z,
158
- colorClass: X
159
- }), k && L ? /* @__PURE__ */ h(f, {
160
- icon: k,
161
- flash: L,
162
- fill: I,
163
- speed: R
164
- }) : k ? F === "icon" ? /* @__PURE__ */ h(b.span, {
165
- className: r("inline-flex items-center justify-center rounded-control p-ds-02", I === "solid" ? "bg-accent-9 text-accent-fg" : "bg-accent-3 text-accent-11"),
166
- initial: {
167
- opacity: 0,
168
- scale: .96
169
- },
170
- animate: {
171
- opacity: 1,
172
- scale: 1
173
- },
174
- transition: t.snappy,
158
+ children: [R && R.length >= 2 && /* @__PURE__ */ h(b, {
159
+ data: R,
160
+ colorClass: Y
161
+ }), D && I ? /* @__PURE__ */ h(f, {
162
+ icon: D,
163
+ flash: I,
164
+ fill: F,
165
+ speed: L
166
+ }) : D ? N === "icon" ? /* @__PURE__ */ h(v.span, {
167
+ className: r("inline-flex items-center justify-center rounded-control p-ds-02", F === "solid" ? "bg-accent-9 text-accent-fg" : "bg-accent-3 text-accent-11"),
168
+ ...Z,
175
169
  "aria-hidden": "true",
176
170
  children: /* @__PURE__ */ h(e, {
177
171
  size: "md",
178
- children: o(k, "md")
172
+ children: o(D, "md")
179
173
  })
180
- }) : /* @__PURE__ */ h(b.span, {
174
+ }) : /* @__PURE__ */ h(v.span, {
181
175
  className: "text-surface-fg-muted",
182
- initial: {
183
- opacity: 0,
184
- scale: .96
185
- },
186
- animate: {
187
- opacity: 1,
188
- scale: 1
189
- },
190
- transition: t.snappy,
176
+ ...Z,
191
177
  "aria-hidden": "true",
192
178
  children: /* @__PURE__ */ h(e, {
193
179
  size: "lg",
194
- children: o(k, "lg")
180
+ children: o(D, "lg")
195
181
  })
196
182
  }) : null]
197
183
  })]
@@ -199,117 +185,99 @@ var w = p.forwardRef(({ className: u, label: p, title: x, value: w, prefix: T, s
199
185
  /* @__PURE__ */ g("div", {
200
186
  className: "flex flex-col gap-ds-01",
201
187
  children: [/* @__PURE__ */ g("div", {
202
- className: r(O === "inline" && D && "flex items-baseline gap-ds-03"),
188
+ className: r(E === "inline" && T && "flex items-baseline gap-ds-03"),
203
189
  children: [/* @__PURE__ */ h("div", {
204
190
  className: "overflow-hidden",
205
- children: /* @__PURE__ */ g(b.p, {
206
- className: r("inline-block font-semibold", P === "sm" ? "text-ds-2xl" : "text-ds-3xl", F === "tint" ? "text-accent-11" : "text-surface-fg"),
207
- initial: {
208
- opacity: 0,
209
- y: "100%"
210
- },
211
- animate: {
212
- opacity: 1,
213
- y: 0
214
- },
215
- transition: t.smooth,
191
+ children: /* @__PURE__ */ g(v.p, {
192
+ className: r("inline-block font-semibold", M === "sm" ? "text-ds-2xl" : "text-ds-3xl", N === "tint" ? "text-accent-11" : "text-surface-fg"),
193
+ ...Z,
216
194
  children: [
217
- T && /* @__PURE__ */ h("span", {
218
- className: r("text-surface-fg-muted", P === "sm" ? "text-ds-md" : "text-ds-lg"),
219
- children: T
195
+ C && /* @__PURE__ */ h("span", {
196
+ className: r("text-surface-fg-muted", M === "sm" ? "text-ds-md" : "text-ds-lg"),
197
+ children: C
220
198
  }),
221
199
  /* @__PURE__ */ h("span", {
222
200
  className: "tabular-nums",
223
- children: w
201
+ children: S
224
202
  }),
225
- E && /* @__PURE__ */ h("span", {
226
- className: r("text-surface-fg-muted", P === "sm" ? "text-ds-md" : "text-ds-lg"),
227
- children: E
203
+ w && /* @__PURE__ */ h("span", {
204
+ className: r("text-surface-fg-muted", M === "sm" ? "text-ds-md" : "text-ds-lg"),
205
+ children: w
228
206
  })
229
207
  ]
230
208
  })
231
- }), O === "inline" && Z]
232
- }), j && /* @__PURE__ */ h(b.p, {
209
+ }), E === "inline" && X]
210
+ }), k && /* @__PURE__ */ h(v.p, {
233
211
  className: "text-ds-sm text-surface-fg-subtle",
234
- initial: { opacity: 0 },
235
- animate: { opacity: 1 },
236
- transition: {
237
- ...n.fade,
238
- delay: .1
239
- },
240
- children: j
212
+ ...Z,
213
+ children: k
241
214
  })]
242
215
  }),
243
- M != null && /* @__PURE__ */ h(b.div, {
244
- initial: { opacity: 0 },
245
- animate: { opacity: 1 },
246
- transition: {
247
- ...n.fade,
248
- delay: .15
249
- },
250
- children: /* @__PURE__ */ h(C, {
251
- progress: M,
252
- label: K
216
+ A != null && /* @__PURE__ */ h(v.div, {
217
+ ...Z,
218
+ children: /* @__PURE__ */ h(x, {
219
+ progress: A,
220
+ label: G
253
221
  })
254
222
  }),
255
- O === "block" && Z
256
- ] }), Q = F === "tint" ? "bg-linear-to-t from-accent-2 to-surface-raised" : void 0, $ = /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(c, {
223
+ E === "block" && X
224
+ ] }), Q = N === "tint" ? "bg-linear-to-t from-accent-2 to-surface-raised" : void 0, $ = /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(c, {
257
225
  className: "flex flex-col gap-ds-03",
258
- children: te
259
- }), H && /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h("div", {
226
+ children: re
227
+ }), V && /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h("div", {
260
228
  "aria-hidden": "true",
261
229
  className: "h-px w-full bg-surface-border-subtle"
262
230
  }), /* @__PURE__ */ h(l, {
263
231
  className: "text-ds-sm",
264
- children: /* @__PURE__ */ h(b.div, {
232
+ children: /* @__PURE__ */ h(v.div, {
265
233
  className: "w-full",
266
- initial: { opacity: 0 },
234
+ initial: !1,
267
235
  animate: { opacity: 1 },
268
236
  transition: {
269
237
  ...n.fade,
270
238
  delay: .25
271
239
  },
272
- children: H
240
+ children: V
273
241
  })
274
242
  })] })] });
275
- return V ? /* @__PURE__ */ h(G, {
276
- ref: W,
277
- href: V,
278
- onClick: B,
243
+ return B ? /* @__PURE__ */ h(W, {
244
+ ref: U,
245
+ href: B,
246
+ onClick: z,
279
247
  className: "block no-underline",
280
- "aria-label": q,
281
- ...U,
248
+ "aria-label": K,
249
+ ...H,
282
250
  children: /* @__PURE__ */ h(s, {
283
- variant: N,
284
- size: P,
251
+ variant: j,
252
+ size: M,
285
253
  interactive: !0,
286
254
  className: Q,
287
255
  children: $
288
256
  })
289
- }) : B ? /* @__PURE__ */ h(s, {
290
- ref: W,
291
- variant: N,
292
- size: P,
257
+ }) : z ? /* @__PURE__ */ h(s, {
258
+ ref: U,
259
+ variant: j,
260
+ size: M,
293
261
  interactive: !0,
294
262
  className: r(Q, u),
295
263
  role: "button",
296
264
  tabIndex: 0,
297
- "aria-label": q,
298
- onClick: B,
265
+ "aria-label": K,
266
+ onClick: z,
299
267
  onKeyDown: (e) => {
300
- (e.key === "Enter" || e.key === " ") && (e.preventDefault(), B());
268
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), z());
301
269
  },
302
- ...U,
270
+ ...H,
303
271
  children: $
304
272
  }) : /* @__PURE__ */ h(s, {
305
- ref: W,
306
- variant: N,
307
- size: P,
273
+ ref: U,
274
+ variant: j,
275
+ size: M,
308
276
  className: r(Q, u),
309
- ...U,
277
+ ...H,
310
278
  children: $
311
279
  });
312
280
  });
313
- w.displayName = "StatCard";
281
+ S.displayName = "StatCard";
314
282
  //#endregion
315
- export { w as StatCard };
283
+ export { S as StatCard };
@@ -1 +1 @@
1
- {"version":3,"file":"stat-card.js","names":[],"sources":["../../src/ui/stat-card.tsx"],"sourcesContent":["'use client'\n\nimport { IconMinus, IconTrendingDown, IconTrendingUp } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Card, CardContent, CardFooter, type CardSize } from './card'\nimport { Icon } from './icon'\nimport { IconProvider } from './icon-context'\nimport type { IconInput } from './lib/icon-input'\nimport { useLink } from './lib/link-context'\nimport { springs, tweens } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\nimport { Progress, type ProgressColor } from './progress'\nimport { Skeleton } from './skeleton'\nimport { type FlashPreset, type FlashSpec, type FlashSpeed,StatFlash } from './stat-flash'\n\n/**\n * Props for StatCard — a dashboard metric tile displaying a label, a large numeric value,\n * an optional trend delta (with directional arrow icon), and an optional header icon.\n *\n * **Surface:** delegated to `Card` via `variant` — `default` (ring-in-shadow, no border) |\n * `elevated` | `outline` (border, no shadow) | `flat`. StatCard composes `<Card>`, so the surface,\n * padding (gap model), and elevation all live in one place.\n *\n * **Accent:** `accentStyle=\"none\"` (default) is neutral; `\"icon\"` wraps `icon` in an accent chip\n * (`iconFill=\"soft\" | \"solid\"`); `\"tint\"` applies a subtle accent surface wash + accent value.\n * (Replaces the removed `accent` left-rail prop — see CHANGELOG migration.)\n *\n * **Delta direction:** `'up'` renders a green trending-up arrow, `'down'` renders a red\n * trending-down arrow, `'neutral'` renders a grey dash. The `delta.value` is a formatted\n * string (e.g. `\"+8%\"` or `\"−120\"`).\n *\n * **Loading state:** Pass `loading={true}` to render a pulse-skeleton placeholder instead of data.\n *\n * @example\n * // Revenue metric with a positive trend:\n * <StatCard\n * label=\"Monthly Revenue\"\n * value=\"$48,200\"\n * delta={{ value: \"+12%\", direction: \"up\" }}\n * icon={<IconCurrencyDollar />}\n * />\n *\n * @example\n * // Open ticket count with a downward trend (good for support queues):\n * <StatCard\n * label=\"Open Tickets\"\n * value={142}\n * delta={{ value: \"−18\", direction: \"down\" }}\n * />\n *\n * @example\n * // Loading skeleton while data is fetching:\n * <StatCard label=\"Users\" value={0} loading={isFetching} />\n *\n * @example\n * // Simple metric with no trend (stable, neutral):\n * <StatCard\n * label=\"Storage Used\"\n * value=\"4.2 GB\"\n * delta={{ value: \"No change\", direction: \"neutral\" }}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface StatCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'> {\n /** Heading text for the metric. `title` is an alias for `label`. */\n label?: string\n /** Alias for `label` — use whichever feels natural. */\n title?: string\n value: string | number\n /** Prefix before value, e.g. \"$\" */\n prefix?: string\n /** Suffix after value, e.g. \"users\" */\n suffix?: string\n delta?: {\n value: string\n direction: 'up' | 'down' | 'neutral'\n }\n /** Where the delta sits relative to the value: `block` (below — default) or `inline` (on the value's baseline, to its right). @default 'block' */\n deltaPlacement?: 'block' | 'inline'\n icon?: IconInput\n loading?: boolean\n /** Comparison period label shown after delta, e.g. \"vs last month\" */\n comparisonLabel?: string\n /** Secondary metric below main value, e.g. \"of $50,000 target\" */\n secondaryLabel?: string\n /** Progress toward a target (0-100). Renders a thin progress bar below the value. */\n progress?: number\n /** Surface variant, delegated to Card: `default` (ring-in-shadow) | `elevated` | `outline` (border, no shadow) | `flat`. @default 'default' */\n variant?: 'default' | 'elevated' | 'outline' | 'flat'\n /**\n * Tile density, delegated to Card's size axis. `sm` tightens padding to 16px and steps\n * the value down to `text-ds-2xl` — use it for dense KPI rows and narrow stat grids\n * (e.g. stat-row's 140px tiles). @default 'md'\n */\n size?: CardSize\n /** How the brand accent reads: `none` (neutral — default), `icon` (accent chip around `icon`), or `tint` (subtle accent surface wash + accent value). */\n accentStyle?: 'none' | 'icon' | 'tint'\n /** When `accentStyle=\"icon\"`: `soft` (tinted chip) or `solid` (filled accent chip). @default 'soft' */\n iconFill?: 'soft' | 'solid'\n /**\n * Opt-in entrance flash: the icon chip mounts showing a transient state (e.g. a green up-arrow)\n * then settles to `icon`. A preset (`'up' | 'down' | 'goal' | 'record' | 'alert' | 'live'`) or an\n * explicit `{ tone, icon }`. Requires `icon`; implies the icon chip. Off by default.\n */\n flash?: FlashPreset | FlashSpec\n /** Speed of the entrance flash: `fast` | `normal` | `slow`. @default 'normal' */\n flashSpeed?: FlashSpeed\n /** Sparkline data points. Renders a mini SVG line chart in the card. */\n sparkline?: number[]\n /** Make the card clickable with hover state */\n onClick?: () => void\n /** Href — makes the card a link (uses the LinkContext Link component) */\n href?: string\n /** Footer content rendered below the card body, e.g. \"View details →\" */\n footer?: React.ReactNode\n}\n\nfunction buildSparklinePath(raw: number[], width: number, height: number): string {\n const data = raw.filter((v) => Number.isFinite(v))\n if (data.length < 2) return ''\n const min = Math.min(...data)\n const max = Math.max(...data)\n const range = max - min || 1\n const stepX = width / (data.length - 1)\n return data\n .map((v, i) => {\n const x = i * stepX\n const y = height - ((v - min) / range) * height\n return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`\n })\n .join(' ')\n}\n\nfunction Sparkline({\n data,\n colorClass,\n}: {\n data: number[]\n colorClass: string\n}) {\n const id = React.useId()\n const pathRef = React.useRef<SVGPathElement>(null)\n const [pathLength, setPathLength] = React.useState(0)\n const svgWidth = 80\n const svgHeight = 32\n const path = buildSparklinePath(data, svgWidth, svgHeight)\n\n React.useEffect(() => {\n if (pathRef.current) {\n setPathLength(pathRef.current.getTotalLength())\n }\n }, [path])\n\n if (!path) return null\n\n // Build area fill path (close to bottom-right then bottom-left)\n const areaPath = `${path} L${svgWidth.toFixed(1)},${svgHeight.toFixed(1)} L0,${svgHeight.toFixed(1)} Z`\n\n return (\n <div className={cn('w-20 h-8', colorClass)} aria-hidden=\"true\">\n <svg\n viewBox={`0 0 ${svgWidth} ${svgHeight}`}\n className=\"w-full h-full overflow-visible\"\n preserveAspectRatio=\"none\"\n >\n <defs>\n <linearGradient id={`sparkline-fill-${id}`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"currentColor\" stopOpacity=\"0.1\" />\n <stop offset=\"100%\" stopColor=\"currentColor\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n <path d={areaPath} fill={`url(#sparkline-fill-${id})`} />\n <path\n ref={pathRef}\n d={path}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{\n opacity: pathLength === 0 ? 0 : 1,\n strokeDasharray: pathLength,\n strokeDashoffset: pathLength,\n animation: pathLength > 0 ? `sparkline-draw-${id.replace(/:/g, '')} 1s ease-out forwards` : 'none',\n }}\n />\n </svg>\n {pathLength > 0 && (\n <style>{`@keyframes sparkline-draw-${id.replace(/:/g, '')} { to { stroke-dashoffset: 0; } }`}</style>\n )}\n </div>\n )\n}\n\nfunction ProgressBar({ progress, label }: { progress: number; label: string }) {\n const clamped = Math.max(0, Math.min(100, progress))\n // StatCard's own thresholds (90 = success, 70 = warning) — deliberately distinct\n // from Progress's autoColor (85/60), so we pass an explicit color.\n const barColor: ProgressColor =\n clamped >= 90 ? 'success' : clamped >= 70 ? 'warning' : 'accent'\n\n return (\n <Progress.Root value={clamped} size=\"sm\">\n <Progress.Track aria-label={`${label} progress`}>\n <Progress.Indicator color={barColor} />\n </Progress.Track>\n </Progress.Root>\n )\n}\n\nconst StatCard = React.forwardRef<HTMLDivElement, StatCardProps>(\n (\n {\n className,\n label,\n title,\n value,\n prefix,\n suffix,\n delta,\n deltaPlacement = 'block',\n icon,\n loading,\n comparisonLabel,\n secondaryLabel,\n progress,\n variant = 'default',\n size = 'md',\n accentStyle = 'none',\n iconFill = 'soft',\n flash,\n flashSpeed,\n sparkline,\n onClick,\n href,\n footer,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const resolvedLabel = title ?? label ?? ''\n const isClickable = !!(onClick || href)\n const computedAriaLabel =\n isClickable && !props['aria-label'] ? `View ${resolvedLabel}` : props['aria-label']\n\n if (loading) {\n return (\n <Card ref={ref} variant={variant} size={size} className={className} aria-busy=\"true\" {...props}>\n <CardContent className=\"flex flex-col gap-ds-03\">\n <Skeleton className=\"h-ds-04 w-24 rounded-control-inner\" />\n <Skeleton className=\"h-ds-sm w-32\" />\n <Skeleton className=\"h-3 w-16 rounded-control-inner\" />\n </CardContent>\n </Card>\n )\n }\n\n const DeltaIcon =\n delta?.direction === 'up'\n ? IconTrendingUp\n : delta?.direction === 'down'\n ? IconTrendingDown\n : IconMinus\n\n const deltaColour =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-surface-fg-muted'\n\n const sparklineColor =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-accent-11'\n\n const deltaNode = delta ? (\n <motion.div\n className={cn(\n // Rhythm comes from CardContent's flex gap — no placement margins.\n 'flex items-center gap-ds-02 text-ds-sm font-medium',\n deltaColour,\n )}\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ ...springs.smooth, delay: 0.2 }}\n >\n <motion.span\n className=\"inline-flex\"\n initial={{ opacity: 0.5, scale: 1.4 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.smooth}\n >\n <Icon icon={DeltaIcon} size=\"sm\" />\n </motion.span>\n <span>{delta.value}</span>\n {comparisonLabel && (\n <span className=\"text-surface-fg-subtle font-normal\">{comparisonLabel}</span>\n )}\n </motion.div>\n ) : null\n\n const cardContent = (\n <>\n <div className=\"flex items-center justify-between\">\n <motion.p\n className=\"text-ds-md font-medium text-surface-fg-muted\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n >\n {resolvedLabel}\n </motion.p>\n <div className=\"flex items-center gap-ds-03\">\n {sparkline && sparkline.length >= 2 && (\n <Sparkline data={sparkline} colorClass={sparklineColor} />\n )}\n {icon && flash ? (\n <StatFlash icon={icon} flash={flash} fill={iconFill} speed={flashSpeed} />\n ) : icon ? (\n accentStyle === 'icon' ? (\n <motion.span\n className={cn(\n 'inline-flex items-center justify-center rounded-control p-ds-02',\n iconFill === 'solid'\n ? 'bg-accent-9 text-accent-fg'\n : 'bg-accent-3 text-accent-11',\n )}\n initial={{ opacity: 0, scale: 0.96 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.snappy}\n aria-hidden=\"true\"\n >\n <IconProvider size=\"md\">{normalizeIcon(icon, 'md')}</IconProvider>\n </motion.span>\n ) : (\n <motion.span\n className=\"text-surface-fg-muted\"\n initial={{ opacity: 0, scale: 0.96 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.snappy}\n aria-hidden=\"true\"\n >\n <IconProvider size=\"lg\">{normalizeIcon(icon, 'lg')}</IconProvider>\n </motion.span>\n )\n ) : null}\n </div>\n </div>\n <div className=\"flex flex-col gap-ds-01\">\n <div className={cn(deltaPlacement === 'inline' && delta && 'flex items-baseline gap-ds-03')}>\n <div className=\"overflow-hidden\">\n <motion.p\n className={cn(\n 'inline-block font-semibold',\n size === 'sm' ? 'text-ds-2xl' : 'text-ds-3xl',\n accentStyle === 'tint' ? 'text-accent-11' : 'text-surface-fg',\n )}\n initial={{ opacity: 0, y: '100%' }}\n animate={{ opacity: 1, y: 0 }}\n transition={springs.smooth}\n >\n {prefix && (\n <span className={cn('text-surface-fg-muted', size === 'sm' ? 'text-ds-md' : 'text-ds-lg')}>{prefix}</span>\n )}\n <span className=\"tabular-nums\">{value}</span>\n {suffix && (\n <span className={cn('text-surface-fg-muted', size === 'sm' ? 'text-ds-md' : 'text-ds-lg')}>{suffix}</span>\n )}\n </motion.p>\n </div>\n {deltaPlacement === 'inline' && deltaNode}\n </div>\n {secondaryLabel && (\n <motion.p\n className=\"text-ds-sm text-surface-fg-subtle\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.1 }}\n >\n {secondaryLabel}\n </motion.p>\n )}\n </div>\n {progress != null && (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.15 }}\n >\n <ProgressBar progress={progress} label={resolvedLabel} />\n </motion.div>\n )}\n {deltaPlacement === 'block' && deltaNode}\n </>\n )\n\n // accentStyle=\"tint\" → a subtle accent gradient wash over Card's surface.\n const tintClass =\n accentStyle === 'tint' ? 'bg-linear-to-t from-accent-2 to-surface-raised' : undefined\n // Footer sits outside CardContent behind a full-width divider (both are direct\n // children of Card, so the rule spans edge-to-edge — no inset border-t).\n const body = (\n <>\n <CardContent className=\"flex flex-col gap-ds-03\">{cardContent}</CardContent>\n {footer && (\n <>\n <div aria-hidden=\"true\" className=\"h-px w-full bg-surface-border-subtle\" />\n <CardFooter className=\"text-ds-sm\">\n <motion.div\n className=\"w-full\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.25 }}\n >\n {footer}\n </motion.div>\n </CardFooter>\n </>\n )}\n </>\n )\n\n // href → wrap Card in the framework Link (Card stays the shell; hover-lift inside).\n if (href) {\n return (\n <Link\n ref={ref as React.Ref<HTMLAnchorElement>}\n href={href}\n onClick={onClick}\n className=\"block no-underline\"\n aria-label={computedAriaLabel}\n {...(props as React.AnchorHTMLAttributes<HTMLAnchorElement>)}\n >\n <Card variant={variant} size={size} interactive className={tintClass}>\n {body}\n </Card>\n </Link>\n )\n }\n\n // onClick → interactive Card with button semantics + keyboard activation.\n if (onClick) {\n return (\n <Card\n ref={ref}\n variant={variant}\n size={size}\n interactive\n className={cn(tintClass, className)}\n role=\"button\"\n tabIndex={0}\n aria-label={computedAriaLabel}\n onClick={onClick}\n onKeyDown={(e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n onClick()\n }\n }}\n {...props}\n >\n {body}\n </Card>\n )\n }\n\n return (\n <Card ref={ref} variant={variant} size={size} className={cn(tintClass, className)} {...props}>\n {body}\n </Card>\n )\n },\n)\n\nStatCard.displayName = 'StatCard'\n\nexport { StatCard }\n"],"mappings":"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"}
1
+ {"version":3,"file":"stat-card.js","names":[],"sources":["../../src/ui/stat-card.tsx"],"sourcesContent":["'use client'\n\nimport { IconMinus, IconTrendingDown, IconTrendingUp } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Card, CardContent, CardFooter, type CardSize } from './card'\nimport { Icon } from './icon'\nimport { IconProvider } from './icon-context'\nimport type { IconInput } from './lib/icon-input'\nimport { useLink } from './lib/link-context'\nimport { springs, tweens } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\nimport { Progress, type ProgressColor } from './progress'\nimport { Skeleton } from './skeleton'\nimport { type FlashPreset, type FlashSpec, type FlashSpeed,StatFlash } from './stat-flash'\n\n/**\n * Props for StatCard — a dashboard metric tile displaying a label, a large numeric value,\n * an optional trend delta (with directional arrow icon), and an optional header icon.\n *\n * **Surface:** delegated to `Card` via `variant` — `default` (ring-in-shadow, no border) |\n * `elevated` | `outline` (border, no shadow) | `flat`. StatCard composes `<Card>`, so the surface,\n * padding (gap model), and elevation all live in one place.\n *\n * **Accent:** `accentStyle=\"none\"` (default) is neutral; `\"icon\"` wraps `icon` in an accent chip\n * (`iconFill=\"soft\" | \"solid\"`); `\"tint\"` applies a subtle accent surface wash + accent value.\n * (Replaces the removed `accent` left-rail prop — see CHANGELOG migration.)\n *\n * **Delta direction:** `'up'` renders a green trending-up arrow, `'down'` renders a red\n * trending-down arrow, `'neutral'` renders a grey dash. The `delta.value` is a formatted\n * string (e.g. `\"+8%\"` or `\"−120\"`).\n *\n * **Loading state:** Pass `loading={true}` to render a pulse-skeleton placeholder instead of data.\n *\n * @example\n * // Revenue metric with a positive trend:\n * <StatCard\n * label=\"Monthly Revenue\"\n * value=\"$48,200\"\n * delta={{ value: \"+12%\", direction: \"up\" }}\n * icon={<IconCurrencyDollar />}\n * />\n *\n * @example\n * // Open ticket count with a downward trend (good for support queues):\n * <StatCard\n * label=\"Open Tickets\"\n * value={142}\n * delta={{ value: \"−18\", direction: \"down\" }}\n * />\n *\n * @example\n * // Loading skeleton while data is fetching:\n * <StatCard label=\"Users\" value={0} loading={isFetching} />\n *\n * @example\n * // Simple metric with no trend (stable, neutral):\n * <StatCard\n * label=\"Storage Used\"\n * value=\"4.2 GB\"\n * delta={{ value: \"No change\", direction: \"neutral\" }}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface StatCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'> {\n /** Heading text for the metric. `title` is an alias for `label`. */\n label?: string\n /** Alias for `label` — use whichever feels natural. */\n title?: string\n value: string | number\n /** Prefix before value, e.g. \"$\" */\n prefix?: string\n /** Suffix after value, e.g. \"users\" */\n suffix?: string\n delta?: {\n value: string\n direction: 'up' | 'down' | 'neutral'\n }\n /** Where the delta sits relative to the value: `block` (below — default) or `inline` (on the value's baseline, to its right). @default 'block' */\n deltaPlacement?: 'block' | 'inline'\n icon?: IconInput\n loading?: boolean\n /** Comparison period label shown after delta, e.g. \"vs last month\" */\n comparisonLabel?: string\n /** Secondary metric below main value, e.g. \"of $50,000 target\" */\n secondaryLabel?: string\n /** Progress toward a target (0-100). Renders a thin progress bar below the value. */\n progress?: number\n /** Surface variant, delegated to Card: `default` (ring-in-shadow) | `elevated` | `outline` (border, no shadow) | `flat`. @default 'default' */\n variant?: 'default' | 'elevated' | 'outline' | 'flat'\n /**\n * Tile density, delegated to Card's size axis. `sm` tightens padding to 16px and steps\n * the value down to `text-ds-2xl` — use it for dense KPI rows and narrow stat grids\n * (e.g. stat-row's 140px tiles). @default 'md'\n */\n size?: CardSize\n /** How the brand accent reads: `none` (neutral — default), `icon` (accent chip around `icon`), or `tint` (subtle accent surface wash + accent value). */\n accentStyle?: 'none' | 'icon' | 'tint'\n /** Animate value/label in on mount (subtle settle; content stays visible either way, never opacity-gated). @default false */\n reveal?: boolean\n /** When `accentStyle=\"icon\"`: `soft` (tinted chip) or `solid` (filled accent chip). @default 'soft' */\n iconFill?: 'soft' | 'solid'\n /**\n * Opt-in entrance flash: the icon chip mounts showing a transient state (e.g. a green up-arrow)\n * then settles to `icon`. A preset (`'up' | 'down' | 'goal' | 'record' | 'alert' | 'live'`) or an\n * explicit `{ tone, icon }`. Requires `icon`; implies the icon chip. Off by default.\n */\n flash?: FlashPreset | FlashSpec\n /** Speed of the entrance flash: `fast` | `normal` | `slow`. @default 'normal' */\n flashSpeed?: FlashSpeed\n /** Sparkline data points. Renders a mini SVG line chart in the card. */\n sparkline?: number[]\n /** Make the card clickable with hover state */\n onClick?: () => void\n /** Href — makes the card a link (uses the LinkContext Link component) */\n href?: string\n /** Footer content rendered below the card body, e.g. \"View details →\" */\n footer?: React.ReactNode\n}\n\nfunction buildSparklinePath(raw: number[], width: number, height: number): string {\n const data = raw.filter((v) => Number.isFinite(v))\n if (data.length < 2) return ''\n const min = Math.min(...data)\n const max = Math.max(...data)\n const range = max - min || 1\n const stepX = width / (data.length - 1)\n return data\n .map((v, i) => {\n const x = i * stepX\n const y = height - ((v - min) / range) * height\n return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`\n })\n .join(' ')\n}\n\nfunction Sparkline({\n data,\n colorClass,\n}: {\n data: number[]\n colorClass: string\n}) {\n const id = React.useId()\n const pathRef = React.useRef<SVGPathElement>(null)\n const [pathLength, setPathLength] = React.useState(0)\n const svgWidth = 80\n const svgHeight = 32\n const path = buildSparklinePath(data, svgWidth, svgHeight)\n\n React.useEffect(() => {\n if (pathRef.current) {\n setPathLength(pathRef.current.getTotalLength())\n }\n }, [path])\n\n if (!path) return null\n\n // Build area fill path (close to bottom-right then bottom-left)\n const areaPath = `${path} L${svgWidth.toFixed(1)},${svgHeight.toFixed(1)} L0,${svgHeight.toFixed(1)} Z`\n\n return (\n <div className={cn('w-20 h-8', colorClass)} aria-hidden=\"true\">\n <svg\n viewBox={`0 0 ${svgWidth} ${svgHeight}`}\n className=\"w-full h-full overflow-visible\"\n preserveAspectRatio=\"none\"\n >\n <defs>\n <linearGradient id={`sparkline-fill-${id}`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"currentColor\" stopOpacity=\"0.1\" />\n <stop offset=\"100%\" stopColor=\"currentColor\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n <path d={areaPath} fill={`url(#sparkline-fill-${id})`} />\n <path\n ref={pathRef}\n d={path}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{\n opacity: pathLength === 0 ? 0 : 1,\n strokeDasharray: pathLength,\n strokeDashoffset: pathLength,\n animation: pathLength > 0 ? `sparkline-draw-${id.replace(/:/g, '')} 1s ease-out forwards` : 'none',\n }}\n />\n </svg>\n {pathLength > 0 && (\n <style>{`@keyframes sparkline-draw-${id.replace(/:/g, '')} { to { stroke-dashoffset: 0; } }`}</style>\n )}\n </div>\n )\n}\n\nfunction ProgressBar({ progress, label }: { progress: number; label: string }) {\n const clamped = Math.max(0, Math.min(100, progress))\n // StatCard's own thresholds (90 = success, 70 = warning) — deliberately distinct\n // from Progress's autoColor (85/60), so we pass an explicit color.\n const barColor: ProgressColor =\n clamped >= 90 ? 'success' : clamped >= 70 ? 'warning' : 'accent'\n\n return (\n <Progress.Root value={clamped} size=\"sm\">\n <Progress.Track aria-label={`${label} progress`}>\n <Progress.Indicator color={barColor} />\n </Progress.Track>\n </Progress.Root>\n )\n}\n\nconst StatCard = React.forwardRef<HTMLDivElement, StatCardProps>(\n (\n {\n className,\n label,\n title,\n value,\n prefix,\n suffix,\n delta,\n deltaPlacement = 'block',\n icon,\n loading,\n comparisonLabel,\n secondaryLabel,\n progress,\n variant = 'default',\n size = 'md',\n accentStyle = 'none',\n reveal = false,\n iconFill = 'soft',\n flash,\n flashSpeed,\n sparkline,\n onClick,\n href,\n footer,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const resolvedLabel = title ?? label ?? ''\n const isClickable = !!(onClick || href)\n const computedAriaLabel =\n isClickable && !props['aria-label'] ? `View ${resolvedLabel}` : props['aria-label']\n\n if (loading) {\n return (\n <Card ref={ref} variant={variant} size={size} className={className} aria-busy=\"true\" {...props}>\n <CardContent className=\"flex flex-col gap-ds-03\">\n <Skeleton className=\"h-ds-04 w-24 rounded-control-inner\" />\n <Skeleton className=\"h-ds-sm w-32\" />\n <Skeleton className=\"h-3 w-16 rounded-control-inner\" />\n </CardContent>\n </Card>\n )\n }\n\n const DeltaIcon =\n delta?.direction === 'up'\n ? IconTrendingUp\n : delta?.direction === 'down'\n ? IconTrendingDown\n : IconMinus\n\n const deltaColour =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-surface-fg-muted'\n\n const sparklineColor =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-accent-11'\n\n const deltaNode = delta ? (\n <motion.div\n className={cn(\n // Rhythm comes from CardContent's flex gap — no placement margins.\n 'flex items-center gap-ds-02 text-ds-sm font-medium',\n deltaColour,\n )}\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ ...springs.smooth, delay: 0.2 }}\n >\n <motion.span\n className=\"inline-flex\"\n initial={{ opacity: 0.5, scale: 1.4 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.smooth}\n >\n <Icon icon={DeltaIcon} size=\"sm\" />\n </motion.span>\n <span>{delta.value}</span>\n {comparisonLabel && (\n <span className=\"text-surface-fg-subtle font-normal\">{comparisonLabel}</span>\n )}\n </motion.div>\n ) : null\n\n // reveal=false → static (content-safe default). reveal=true → subtle settle; opacity NEVER gated.\n const revealProps = reveal\n ? { initial: { y: 8 }, animate: { y: 0 }, transition: springs.smooth }\n : { initial: false as const }\n\n const cardContent = (\n <>\n <div className=\"flex items-center justify-between\">\n <motion.p\n className=\"text-ds-md font-medium text-surface-fg-muted\"\n {...revealProps}\n >\n {resolvedLabel}\n </motion.p>\n <div className=\"flex items-center gap-ds-03\">\n {sparkline && sparkline.length >= 2 && (\n <Sparkline data={sparkline} colorClass={sparklineColor} />\n )}\n {icon && flash ? (\n <StatFlash icon={icon} flash={flash} fill={iconFill} speed={flashSpeed} />\n ) : icon ? (\n accentStyle === 'icon' ? (\n <motion.span\n className={cn(\n 'inline-flex items-center justify-center rounded-control p-ds-02',\n iconFill === 'solid'\n ? 'bg-accent-9 text-accent-fg'\n : 'bg-accent-3 text-accent-11',\n )}\n {...revealProps}\n aria-hidden=\"true\"\n >\n <IconProvider size=\"md\">{normalizeIcon(icon, 'md')}</IconProvider>\n </motion.span>\n ) : (\n <motion.span\n className=\"text-surface-fg-muted\"\n {...revealProps}\n aria-hidden=\"true\"\n >\n <IconProvider size=\"lg\">{normalizeIcon(icon, 'lg')}</IconProvider>\n </motion.span>\n )\n ) : null}\n </div>\n </div>\n <div className=\"flex flex-col gap-ds-01\">\n <div className={cn(deltaPlacement === 'inline' && delta && 'flex items-baseline gap-ds-03')}>\n <div className=\"overflow-hidden\">\n <motion.p\n className={cn(\n 'inline-block font-semibold',\n size === 'sm' ? 'text-ds-2xl' : 'text-ds-3xl',\n accentStyle === 'tint' ? 'text-accent-11' : 'text-surface-fg',\n )}\n {...revealProps}\n >\n {prefix && (\n <span className={cn('text-surface-fg-muted', size === 'sm' ? 'text-ds-md' : 'text-ds-lg')}>{prefix}</span>\n )}\n <span className=\"tabular-nums\">{value}</span>\n {suffix && (\n <span className={cn('text-surface-fg-muted', size === 'sm' ? 'text-ds-md' : 'text-ds-lg')}>{suffix}</span>\n )}\n </motion.p>\n </div>\n {deltaPlacement === 'inline' && deltaNode}\n </div>\n {secondaryLabel && (\n <motion.p\n className=\"text-ds-sm text-surface-fg-subtle\"\n {...revealProps}\n >\n {secondaryLabel}\n </motion.p>\n )}\n </div>\n {progress != null && (\n <motion.div\n {...revealProps}\n >\n <ProgressBar progress={progress} label={resolvedLabel} />\n </motion.div>\n )}\n {deltaPlacement === 'block' && deltaNode}\n </>\n )\n\n // accentStyle=\"tint\" → a subtle accent gradient wash over Card's surface.\n const tintClass =\n accentStyle === 'tint' ? 'bg-linear-to-t from-accent-2 to-surface-raised' : undefined\n // Footer sits outside CardContent behind a full-width divider (both are direct\n // children of Card, so the rule spans edge-to-edge — no inset border-t).\n const body = (\n <>\n <CardContent className=\"flex flex-col gap-ds-03\">{cardContent}</CardContent>\n {footer && (\n <>\n <div aria-hidden=\"true\" className=\"h-px w-full bg-surface-border-subtle\" />\n <CardFooter className=\"text-ds-sm\">\n <motion.div\n className=\"w-full\"\n initial={false}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.25 }}\n >\n {footer}\n </motion.div>\n </CardFooter>\n </>\n )}\n </>\n )\n\n // href → wrap Card in the framework Link (Card stays the shell; hover-lift inside).\n if (href) {\n return (\n <Link\n ref={ref as React.Ref<HTMLAnchorElement>}\n href={href}\n onClick={onClick}\n className=\"block no-underline\"\n aria-label={computedAriaLabel}\n {...(props as React.AnchorHTMLAttributes<HTMLAnchorElement>)}\n >\n <Card variant={variant} size={size} interactive className={tintClass}>\n {body}\n </Card>\n </Link>\n )\n }\n\n // onClick → interactive Card with button semantics + keyboard activation.\n if (onClick) {\n return (\n <Card\n ref={ref}\n variant={variant}\n size={size}\n interactive\n className={cn(tintClass, className)}\n role=\"button\"\n tabIndex={0}\n aria-label={computedAriaLabel}\n onClick={onClick}\n onKeyDown={(e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n onClick()\n }\n }}\n {...props}\n >\n {body}\n </Card>\n )\n }\n\n return (\n <Card ref={ref} variant={variant} size={size} className={cn(tintClass, className)} {...props}>\n {body}\n </Card>\n )\n },\n)\n\nStatCard.displayName = 'StatCard'\n\nexport { StatCard }\n"],"mappings":"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"}
package/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # @devalok/shilp-sutra
2
2
 
3
- > Radix UI + Tailwind 4 (CSS-first) + CVA design system for Devalok apps, v0.49.1.
3
+ > Radix UI + Tailwind 4 (CSS-first) + CVA design system for Devalok apps, v0.49.3.
4
4
  > Built on the same primitives as shadcn/ui but with DIFFERENT prop APIs — never guess from shadcn knowledge; verify every prop.
5
5
  > This file is a ROUTER: it tells you what exists and where to get details. Do not look for prop tables here — fetch them per component (MCP tool or per-component doc file below).
6
6
 
package/mcp-manifest.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "$schema": "./mcp-manifest.schema.json",
3
3
  "manifestVersion": "1.2.0",
4
4
  "package": "@devalok/shilp-sutra",
5
- "packageVersion": "0.49.1",
5
+ "packageVersion": "0.49.3",
6
6
  "components": {
7
7
  "accordion": {
8
8
  "displayName": "Accordion",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devalok/shilp-sutra",
3
- "version": "0.49.1",
3
+ "version": "0.49.3",
4
4
  "description": "Devalok Design System — accessible React components, OKLCH design tokens, and Tailwind 4 CSS-first setup. Ships with AI-agent setup recipes.",
5
5
  "license": "MIT",
6
6
  "author": "Devalok Design & Strategy Studios <shilp-sutra@devalok.in>",
package/skill/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: shilp-sutra
3
3
  description: Add, configure, and use components from Devalok's shilp-sutra design system (@devalok/shilp-sutra) — a Tailwind 4 + React 19 + CVA library with 110+ accessible components, OKLCH design tokens, framer-motion animations, and per-component RSC-safe entry points. Use this skill whenever the user mentions shilp-sutra, Devalok, the @devalok npm scope, or asks to install/add/style/theme UI in any React project that already depends on the package — even if they don't name it explicitly. Use it instead of generic shadcn/ui, MUI, or Chakra knowledge when shilp-sutra is in the project. Covers Next.js (App + Pages), Vite, Astro, Remix, TanStack Start setup playbooks; component API and variant reference; brand token customization; Server Component import patterns; and a troubleshoot tree for the thirteen most common breakages.
4
4
  license: MIT
5
5
  metadata:
6
- version: "0.49.1"
6
+ version: "0.49.3"
7
7
  author: Devalok Design & Strategy Studios
8
8
  homepage: https://github.com/devalok-design/shilp-sutra
9
9
  npm: https://www.npmjs.com/package/@devalok/shilp-sutra
@@ -2,7 +2,7 @@
2
2
 
3
3
  # @devalok/shilp-sutra
4
4
 
5
- > Radix UI + Tailwind 4 (CSS-first) + CVA design system for Devalok apps, v0.49.1.
5
+ > Radix UI + Tailwind 4 (CSS-first) + CVA design system for Devalok apps, v0.49.3.
6
6
  > Built on the same primitives as shadcn/ui but with DIFFERENT prop APIs — never guess from shadcn knowledge; verify every prop.
7
7
  > This file is a ROUTER: it tells you what exists and where to get details. Do not look for prop tables here — fetch them per component (MCP tool or per-component doc file below).
8
8