@alfadocs/ui-kit 0.32.1 → 0.32.2

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.
@@ -1,9 +1,9 @@
1
1
  import { jsxs as z, jsx as i } from "react/jsx-runtime";
2
- import { forwardRef as Q, useId as X, useCallback as L, useRef as Z, useMemo as tt } from "react";
2
+ import { forwardRef as X, useId as Z, useCallback as O, useRef as tt, useMemo as et } from "react";
3
3
  import { c as V } from "./index-D2ZczOXr.js";
4
- import { useTranslation as U } from "react-i18next";
5
- import { u as et } from "./use-count-up-BLLetaZ8.js";
6
- const O = V("ds:flex ds:flex-col ds:h-full", {
4
+ import { useTranslation as B } from "react-i18next";
5
+ import { u as st } from "./use-count-up-BLLetaZ8.js";
6
+ const P = V("ds:flex ds:flex-col ds:h-full", {
7
7
  variants: {
8
8
  variant: {
9
9
  default: "ds:gap-[var(--spacing-xs)]",
@@ -48,7 +48,7 @@ const O = V("ds:flex ds:flex-col ds:h-full", {
48
48
  size: "md",
49
49
  align: "start"
50
50
  }
51
- }), P = V("type-metric ds:text-[var(--foreground)]", {
51
+ }), U = V("type-metric", {
52
52
  variants: {
53
53
  size: {
54
54
  sm: "ds:[--type-metric-size:var(--font-size-xl)]",
@@ -60,6 +60,22 @@ const O = V("ds:flex ds:flex-col ds:h-full", {
60
60
  outlined: "",
61
61
  elevated: "",
62
62
  compact: ""
63
+ },
64
+ // Colour of the headline metric value. Defaults to `--foreground`
65
+ // (the existing render). `primary` / `accent` are the brand intents
66
+ // — use for hero / marketing stats where the number IS the visual
67
+ // marker. `success` / `destructive` / `info` / `warning` map to the
68
+ // semantic tokens for KPI tiles that want to signal status via the
69
+ // value colour itself (e.g. revenue green, debt red). The trend
70
+ // chevron and the label colour are independent of this prop.
71
+ intent: {
72
+ foreground: "ds:text-[var(--foreground)]",
73
+ primary: "ds:text-[var(--primary)]",
74
+ accent: "ds:text-[var(--accent)]",
75
+ success: "ds:text-[var(--success)]",
76
+ destructive: "ds:text-[var(--destructive)]",
77
+ info: "ds:text-[var(--info)]",
78
+ warning: "ds:text-[var(--warning)]"
63
79
  }
64
80
  },
65
81
  compoundVariants: [
@@ -81,9 +97,10 @@ const O = V("ds:flex ds:flex-col ds:h-full", {
81
97
  ],
82
98
  defaultVariants: {
83
99
  size: "md",
84
- variant: "default"
100
+ variant: "default",
101
+ intent: "foreground"
85
102
  }
86
- }), st = V(
103
+ }), rt = V(
87
104
  "ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)] type-label",
88
105
  {
89
106
  variants: {
@@ -97,76 +114,77 @@ const O = V("ds:flex ds:flex-col ds:h-full", {
97
114
  trend: "flat"
98
115
  }
99
116
  }
100
- ), rt = { up: "↑", down: "↓", flat: "→" }, at = {
117
+ ), at = { up: "↑", down: "↓", flat: "→" }, nt = {
101
118
  up: "stat.trend.up",
102
119
  down: "stat.trend.down",
103
120
  flat: "stat.trend.flat"
104
121
  };
105
- function nt({
122
+ function it({
106
123
  trend: d,
107
124
  delta: t,
108
125
  deltaFormat: c = "decimal",
109
126
  locale: a
110
127
  }) {
111
- const { t: e, i18n: l } = U(), o = typeof t == "string" ? t : new Intl.NumberFormat(a ?? l.language, {
128
+ const { t: e, i18n: o } = B(), l = typeof t == "string" ? t : new Intl.NumberFormat(a ?? o.language, {
112
129
  style: c === "percent" ? "percent" : "decimal"
113
130
  }).format(c === "percent" ? t / 100 : t);
114
- return /* @__PURE__ */ z("span", { className: st({ trend: d }), children: [
115
- /* @__PURE__ */ i("span", { "aria-hidden": "true", children: rt[d] }),
116
- /* @__PURE__ */ i("span", { className: "ds:sr-only", children: e(at[d]) }),
117
- o
131
+ return /* @__PURE__ */ z("span", { className: rt({ trend: d }), children: [
132
+ /* @__PURE__ */ i("span", { "aria-hidden": "true", children: at[d] }),
133
+ /* @__PURE__ */ i("span", { className: "ds:sr-only", children: e(nt[d]) }),
134
+ l
118
135
  ] });
119
136
  }
120
- function it(d, t) {
137
+ function dt(d, t) {
121
138
  const c = d.trim();
122
139
  if (c === "") return null;
123
140
  let a = "", e = c;
124
141
  e.startsWith("+") ? (a = "+", e = e.slice(1).trimStart()) : (e.startsWith("-") || e.startsWith("−")) && (a = "-", e = e.slice(1).trimStart());
125
- let l = "";
126
- const o = e.match(/[KMB]$/i);
127
- o && (l = o[0], e = e.slice(0, -1).trimEnd());
128
- let m = "", u = ".";
142
+ let o = "";
143
+ const l = e.match(/[KMB]$/i);
144
+ l && (o = l[0], e = e.slice(0, -1).trimEnd());
145
+ let u = "", m = ".";
129
146
  try {
130
- const b = new Intl.NumberFormat(t).formatToParts(12345.6);
131
- for (const n of b)
132
- n.type === "group" ? m = n.value : n.type === "decimal" && (u = n.value);
147
+ const x = new Intl.NumberFormat(t).formatToParts(12345.6);
148
+ for (const n of x)
149
+ n.type === "group" ? u = n.value : n.type === "decimal" && (m = n.value);
133
150
  } catch {
134
151
  }
135
152
  const g = e.match(/^(\d+)\.(\d+)$/);
136
- if (g && !(g[2].length === 3 && m === ".")) {
153
+ if (g && !(g[2].length === 3 && u === ".")) {
137
154
  const n = Number.parseFloat(e);
138
155
  if (Number.isFinite(n))
139
- return { target: n, sign: a, suffix: l };
156
+ return { target: n, sign: a, suffix: o };
140
157
  }
141
158
  let s = e;
142
- m !== "" && (s = s.split(m).join("")), u !== "." && (s = s.split(u).join(".")), s = s.replace(/[\s\u00A0\u202F]/g, "");
159
+ u !== "" && (s = s.split(u).join("")), m !== "." && (s = s.split(m).join(".")), s = s.replace(/[\s\u00A0\u202F]/g, "");
143
160
  const v = Number.parseFloat(s);
144
- return Number.isFinite(v) ? { target: v, sign: a, suffix: l } : null;
161
+ return Number.isFinite(v) ? { target: v, sign: a, suffix: o } : null;
145
162
  }
146
- const dt = Q(
163
+ const ct = X(
147
164
  ({
148
165
  label: d,
149
166
  value: t,
150
167
  format: c,
151
168
  currency: a,
152
169
  locale: e,
153
- trend: l,
154
- delta: o,
155
- deltaFormat: m = "decimal",
156
- icon: u,
170
+ trend: o,
171
+ delta: l,
172
+ deltaFormat: u = "decimal",
173
+ icon: m,
157
174
  loading: g = !1,
158
175
  animate: s = !1,
159
176
  animateOnEveryView: v = !1,
160
- animateDurationMs: b = 1600,
177
+ animateDurationMs: x = 1600,
161
178
  animateLocale: n,
162
- animateSeparators: h,
163
- variant: x = "default",
179
+ animateSeparators: b,
180
+ variant: h = "default",
164
181
  size: y = "md",
165
182
  align: I = "start",
166
- className: M,
167
- ...j
168
- }, k) => {
169
- const { i18n: B } = U(), R = X(), f = e ?? B.language, K = L(() => {
183
+ intent: M = "foreground",
184
+ className: j,
185
+ ...k
186
+ }, R) => {
187
+ const { i18n: K } = B(), T = Z(), f = e ?? K.language, Y = O(() => {
170
188
  if (typeof t == "string") return t;
171
189
  switch (c) {
172
190
  case "currency":
@@ -186,10 +204,10 @@ const dt = Q(
186
204
  return new Intl.NumberFormat(f).format(t);
187
205
  }
188
206
  }, [t, c, f, a])(), N = n ?? f;
189
- Z(!1);
190
- const r = tt(() => s ? typeof t == "number" ? Number.isFinite(t) ? { target: t, sign: "", suffix: "" } : null : it(t, N) : null, [s, t, N]), Y = s && r !== null, _ = (r == null ? void 0 : r.target) ?? 0, F = (r == null ? void 0 : r.sign) ?? "", T = (r == null ? void 0 : r.suffix) ?? "", q = L(
207
+ tt(!1);
208
+ const r = et(() => s ? typeof t == "number" ? Number.isFinite(t) ? { target: t, sign: "", suffix: "" } : null : dt(t, N) : null, [s, t, N]), _ = s && r !== null, q = (r == null ? void 0 : r.target) ?? 0, F = (r == null ? void 0 : r.sign) ?? "", $ = (r == null ? void 0 : r.suffix) ?? "", H = O(
191
209
  (w) => {
192
- const C = (() => {
210
+ const E = (() => {
193
211
  try {
194
212
  return new Intl.NumberFormat(N, {
195
213
  useGrouping: !0
@@ -199,46 +217,46 @@ const dt = Q(
199
217
  }
200
218
  })();
201
219
  let p;
202
- if (C)
203
- if (h) {
204
- const W = Math.abs(w), A = Math.trunc(W), D = W - A, H = h.thousand ?? "", S = String(A).replace(
220
+ if (E)
221
+ if (b) {
222
+ const A = Math.abs(w), D = Math.trunc(A), G = A - D, J = b.thousand ?? "", S = String(D).replace(
205
223
  /\B(?=(\d{3})+(?!\d))/g,
206
- H
224
+ J
207
225
  );
208
- if (D === 0)
226
+ if (G === 0)
209
227
  p = S;
210
228
  else {
211
- const G = D.toFixed(6).replace(/0+$/, "").slice(2), J = h.decimal ?? ".";
212
- p = G ? S + J + G : S;
229
+ const L = G.toFixed(6).replace(/0+$/, "").slice(2), Q = b.decimal ?? ".";
230
+ p = L ? S + Q + L : S;
213
231
  }
214
232
  } else
215
- p = C.format(Math.abs(w));
233
+ p = E.format(Math.abs(w));
216
234
  else
217
235
  p = String(Math.abs(w));
218
- let E = F;
219
- return F === "" && w < 0 && (E = "-"), `${E}${p}${T}`;
236
+ let W = F;
237
+ return F === "" && w < 0 && (W = "-"), `${W}${p}${$}`;
220
238
  },
221
- [N, h, F, T]
222
- ), $ = et({
223
- to: _,
239
+ [N, b, F, $]
240
+ ), C = st({
241
+ to: q,
224
242
  from: 0,
225
- durationMs: b,
243
+ durationMs: x,
226
244
  startOnVisible: !0,
227
245
  retriggerOnReEntry: v,
228
246
  // `formatter` is the only path we use — it owns both the locale
229
247
  // formatting and the sign/suffix re-application.
230
- formatter: q
248
+ formatter: H
231
249
  });
232
250
  return g ? /* @__PURE__ */ z(
233
251
  "div",
234
252
  {
235
- ref: k,
253
+ ref: R,
236
254
  role: "group",
237
255
  "aria-busy": "true",
238
256
  "aria-label": d,
239
257
  "data-component": "stat",
240
- className: O({ variant: x, size: y, align: I, className: M }),
241
- ...j,
258
+ className: P({ variant: h, size: y, align: I, className: j }),
259
+ ...k,
242
260
  children: [
243
261
  /* @__PURE__ */ i("div", { className: "ds:h-[var(--skeleton-label-h)] ds:w-[var(--skeleton-label-w)] ds:animate-pulse ds:rounded-[var(--radius-sm)] ds:bg-[var(--muted)]" }),
244
262
  /* @__PURE__ */ i("div", { className: "ds:h-[var(--skeleton-value-h)] ds:w-[var(--skeleton-value-w)] ds:animate-pulse ds:rounded-[var(--radius-sm)] ds:bg-[var(--muted)]" })
@@ -247,15 +265,15 @@ const dt = Q(
247
265
  ) : /* @__PURE__ */ z(
248
266
  "div",
249
267
  {
250
- ref: k,
268
+ ref: R,
251
269
  role: "group",
252
- "aria-labelledby": R,
270
+ "aria-labelledby": T,
253
271
  "data-component": "stat",
254
- className: O({ variant: x, size: y, align: I, className: M }),
255
- ...j,
272
+ className: P({ variant: h, size: y, align: I, className: j }),
273
+ ...k,
256
274
  children: [
257
275
  /* @__PURE__ */ z("span", { className: "ds:inline-flex ds:items-center", children: [
258
- u && /* @__PURE__ */ i(
276
+ m && /* @__PURE__ */ i(
259
277
  "span",
260
278
  {
261
279
  "aria-hidden": "true",
@@ -268,19 +286,19 @@ const dt = Q(
268
286
  "ds:text-[color:var(--accent)]",
269
287
  "ds:forced-colors:text-[CanvasText]"
270
288
  ].join(" "),
271
- children: u
289
+ children: m
272
290
  }
273
291
  ),
274
292
  /* @__PURE__ */ i(
275
293
  "span",
276
294
  {
277
- id: R,
295
+ id: T,
278
296
  className: "type-label ds:text-[var(--muted-foreground)]",
279
297
  children: d
280
298
  }
281
299
  )
282
300
  ] }),
283
- Y ? (
301
+ _ ? (
284
302
  // The animated number is wrapped in an `aria-live="off"` span
285
303
  // so screen readers don't announce every interpolated frame.
286
304
  // The `role="group"` ancestor (with `aria-labelledby` pointing
@@ -289,19 +307,19 @@ const dt = Q(
289
307
  /* @__PURE__ */ i(
290
308
  "span",
291
309
  {
292
- ref: $.ref,
310
+ ref: C.ref,
293
311
  "aria-live": "off",
294
- className: P({ size: y, variant: x }),
295
- children: $.value
312
+ className: U({ size: y, variant: h, intent: M }),
313
+ children: C.value
296
314
  }
297
315
  )
298
- ) : /* @__PURE__ */ i("span", { className: P({ size: y, variant: x }), children: K }),
299
- l != null && o != null && /* @__PURE__ */ i(
300
- nt,
316
+ ) : /* @__PURE__ */ i("span", { className: U({ size: y, variant: h, intent: M }), children: Y }),
317
+ o != null && l != null && /* @__PURE__ */ i(
318
+ it,
301
319
  {
302
- trend: l,
303
- delta: o,
304
- deltaFormat: m,
320
+ trend: o,
321
+ delta: l,
322
+ deltaFormat: u,
305
323
  locale: e
306
324
  }
307
325
  )
@@ -310,8 +328,8 @@ const dt = Q(
310
328
  );
311
329
  }
312
330
  );
313
- dt.displayName = "Stat";
331
+ ct.displayName = "Stat";
314
332
  export {
315
- dt as S
333
+ ct as S
316
334
  };
317
- //# sourceMappingURL=stat-EC2Papj7.js.map
335
+ //# sourceMappingURL=stat-DhAA5ltU.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "packageVersion": "0.32.1",
3
+ "packageVersion": "0.32.2",
4
4
  "components": [
5
5
  {
6
6
  "kind": "component",
@@ -1,4 +1,4 @@
1
- import { S as o } from "../../_chunks/stat-EC2Papj7.js";
1
+ import { S as o } from "../../_chunks/stat-DhAA5ltU.js";
2
2
  export {
3
3
  o as Stat
4
4
  };
@@ -24,6 +24,15 @@ export interface StatProps extends HTMLAttributes<HTMLDivElement>, VariantProps<
24
24
  deltaFormat?: 'decimal' | 'percent';
25
25
  /** Optional leading icon rendered at the start of the label row. */
26
26
  icon?: ReactNode;
27
+ /**
28
+ * Colour of the headline value. Defaults to `foreground`. Brand
29
+ * intents (`primary`, `accent`) are for hero / marketing stats where
30
+ * the number is the visual marker. Semantic intents
31
+ * (`success`, `destructive`, `info`, `warning`) signal status via
32
+ * the value colour itself — e.g. revenue green, debt red on KPI
33
+ * tiles. Trend chevron and label colour are independent.
34
+ */
35
+ intent?: 'foreground' | 'primary' | 'accent' | 'success' | 'destructive' | 'info' | 'warning';
27
36
  /** Renders animated skeleton placeholders instead of content. */
28
37
  loading?: boolean;
29
38
  /**
package/dist/index.js CHANGED
@@ -60,7 +60,7 @@ import { M as vr } from "./_chunks/map-view-knHSNLoe.js";
60
60
  import { R as Wr } from "./_chunks/rating-BRD7O74e.js";
61
61
  import { S as Ur } from "./_chunks/skeleton-CZbwyJAA.js";
62
62
  import { S as Yr, s as jr, u as zr } from "./_chunks/sparkline-DEROcSl0.js";
63
- import { S as Qr } from "./_chunks/stat-EC2Papj7.js";
63
+ import { S as Qr } from "./_chunks/stat-DhAA5ltU.js";
64
64
  import { T as Xr } from "./_chunks/tag-CyoaEmf_.js";
65
65
  import { T as $r, t as ao } from "./_chunks/timeline-DQa5Tyz4.js";
66
66
  import { T as ro } from "./_chunks/timestamp-BV2lC-wV.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfadocs/ui-kit",
3
- "version": "0.32.1",
3
+ "version": "0.32.2",
4
4
  "type": "module",
5
5
  "description": "AlfaDocs shared design system — tokens, components, patterns, and translations for platform, booking, and alfascribe.",
6
6
  "license": "BUSL-1.1",