@lablup/ui-common 0.1.0-alpha.2 → 0.1.0-alpha.20

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 (71) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/components/BaseCard/BaseCard.css +1 -1
  3. package/dist/assets/components/Button/Button.css +1 -1
  4. package/dist/assets/components/DataTable/DataTable.css +1 -1
  5. package/dist/assets/components/Drawer/Drawer.css +1 -1
  6. package/dist/assets/components/EmptyState/EmptyState.css +1 -1
  7. package/dist/assets/components/ErrorState/ErrorState.css +1 -1
  8. package/dist/assets/components/PageHeader/PageHeader.css +1 -1
  9. package/dist/assets/components/Select/Select.css +1 -0
  10. package/dist/assets/components/StatCard/StatCard.css +1 -1
  11. package/dist/assets/components/Tabs/Tabs.css +1 -1
  12. package/dist/assets/components/Tooltip/Tooltip.css +1 -1
  13. package/dist/components/DataTable/DataTable.d.ts +30 -6
  14. package/dist/components/DataTable/DataTable2.js +85 -92
  15. package/dist/components/DataTable/DataTable2.js.map +1 -1
  16. package/dist/components/Drawer/Drawer.d.ts +12 -1
  17. package/dist/components/Drawer/Drawer2.js +69 -51
  18. package/dist/components/Drawer/Drawer2.js.map +1 -1
  19. package/dist/components/EmptyState/EmptyState.d.ts +10 -3
  20. package/dist/components/EmptyState/EmptyState2.js +31 -48
  21. package/dist/components/EmptyState/EmptyState2.js.map +1 -1
  22. package/dist/components/EmptyState/index.d.ts +6 -1
  23. package/dist/components/ErrorState/ErrorState.d.ts +17 -4
  24. package/dist/components/ErrorState/ErrorState2.js +20 -23
  25. package/dist/components/ErrorState/ErrorState2.js.map +1 -1
  26. package/dist/components/ErrorState/index.d.ts +1 -1
  27. package/dist/components/PageHeader/PageHeader.d.ts +14 -1
  28. package/dist/components/PageHeader/PageHeader2.js +40 -24
  29. package/dist/components/PageHeader/PageHeader2.js.map +1 -1
  30. package/dist/components/Select/Select.d.ts +38 -0
  31. package/dist/components/Select/Select2.js +313 -0
  32. package/dist/components/Select/Select2.js.map +1 -0
  33. package/dist/components/Select/index.d.ts +2 -0
  34. package/dist/components/Select/index.js +2 -0
  35. package/dist/components/Skeleton/Skeleton.d.ts +11 -1
  36. package/dist/components/Skeleton/Skeleton2.js +8 -6
  37. package/dist/components/Skeleton/Skeleton2.js.map +1 -1
  38. package/dist/components/Skeleton/SkeletonCard.d.ts +3 -1
  39. package/dist/components/Skeleton/SkeletonCard2.js +13 -3
  40. package/dist/components/Skeleton/SkeletonCard2.js.map +1 -1
  41. package/dist/components/Skeleton/SkeletonChart2.js +5 -0
  42. package/dist/components/Skeleton/SkeletonChart2.js.map +1 -1
  43. package/dist/components/Skeleton/SkeletonRow.d.ts +3 -1
  44. package/dist/components/Skeleton/SkeletonRow2.js +9 -3
  45. package/dist/components/Skeleton/SkeletonRow2.js.map +1 -1
  46. package/dist/components/Skeleton/SkeletonText.d.ts +3 -1
  47. package/dist/components/Skeleton/SkeletonText2.js +7 -5
  48. package/dist/components/Skeleton/SkeletonText2.js.map +1 -1
  49. package/dist/components/StatCard/StatCard.d.ts +10 -1
  50. package/dist/components/StatCard/StatCard2.js +30 -30
  51. package/dist/components/StatCard/StatCard2.js.map +1 -1
  52. package/dist/components/Tabs/Tabs.d.ts +10 -23
  53. package/dist/components/Tabs/Tabs2.js +127 -146
  54. package/dist/components/Tabs/Tabs2.js.map +1 -1
  55. package/dist/components/Tabs/index.d.ts +2 -2
  56. package/dist/components/Tabs/index.js +2 -3
  57. package/dist/components/Tooltip/Tooltip.d.ts +15 -1
  58. package/dist/components/Tooltip/Tooltip2.js +77 -47
  59. package/dist/components/Tooltip/Tooltip2.js.map +1 -1
  60. package/dist/index.d.ts +1 -0
  61. package/dist/index.js +6 -6
  62. package/dist/styles/base.css +101 -10
  63. package/dist/styles/themes/orange-dark.css +3 -0
  64. package/dist/styles/themes/orange-light.css +6 -1
  65. package/package.json +1 -1
  66. package/dist/components/EmptyState/illustrations.d.ts +0 -51
  67. package/dist/components/EmptyState/illustrations.js +0 -571
  68. package/dist/components/EmptyState/illustrations.js.map +0 -1
  69. package/dist/components/Tabs/tabTags.d.ts +0 -9
  70. package/dist/components/Tabs/tabTags.js +0 -11
  71. package/dist/components/Tabs/tabTags.js.map +0 -1
@@ -2,29 +2,33 @@ import { Skeleton as e } from "./Skeleton2.js";
2
2
  /* empty css */
3
3
  import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
4
4
  //#region src/components/Skeleton/SkeletonCard.tsx
5
- function i({ variant: i = "default", className: a = "", testId: o }) {
6
- let s = [
5
+ function i({ variant: i = "default", className: a = "", testId: o, loadingLabel: s }) {
6
+ let c = [
7
7
  "skeleton-card",
8
8
  `skeleton-card--${i}`,
9
9
  a
10
10
  ].filter(Boolean).join(" ");
11
11
  return /* @__PURE__ */ n("div", {
12
- className: s,
12
+ className: c,
13
13
  "data-testid": o,
14
14
  role: "status",
15
15
  "aria-busy": "true",
16
+ "aria-label": s ?? "Loading",
16
17
  children: i === "stat" ? /* @__PURE__ */ n(t, { children: /* @__PURE__ */ r("div", {
17
18
  className: "skeleton-card__header",
18
19
  children: [/* @__PURE__ */ n(e, {
20
+ decorative: !0,
19
21
  width: "48px",
20
22
  height: "48px",
21
23
  variant: "circle"
22
24
  }), /* @__PURE__ */ r("div", {
23
25
  className: "skeleton-card__header-text",
24
26
  children: [/* @__PURE__ */ n(e, {
27
+ decorative: !0,
25
28
  width: "60%",
26
29
  height: "16px"
27
30
  }), /* @__PURE__ */ n(e, {
31
+ decorative: !0,
28
32
  width: "40%",
29
33
  height: "24px"
30
34
  })]
@@ -33,6 +37,7 @@ function i({ variant: i = "default", className: a = "", testId: o }) {
33
37
  /* @__PURE__ */ n("div", {
34
38
  className: "skeleton-card__header",
35
39
  children: /* @__PURE__ */ n(e, {
40
+ decorative: !0,
36
41
  width: "70%",
37
42
  height: "20px"
38
43
  })
@@ -41,14 +46,17 @@ function i({ variant: i = "default", className: a = "", testId: o }) {
41
46
  className: "skeleton-card__content",
42
47
  children: [
43
48
  /* @__PURE__ */ n(e, {
49
+ decorative: !0,
44
50
  width: "100%",
45
51
  height: "16px"
46
52
  }),
47
53
  /* @__PURE__ */ n(e, {
54
+ decorative: !0,
48
55
  width: "90%",
49
56
  height: "16px"
50
57
  }),
51
58
  /* @__PURE__ */ n(e, {
59
+ decorative: !0,
52
60
  width: "80%",
53
61
  height: "16px"
54
62
  })
@@ -57,9 +65,11 @@ function i({ variant: i = "default", className: a = "", testId: o }) {
57
65
  i !== "compact" && /* @__PURE__ */ r("div", {
58
66
  className: "skeleton-card__footer",
59
67
  children: [/* @__PURE__ */ n(e, {
68
+ decorative: !0,
60
69
  width: "80px",
61
70
  height: "32px"
62
71
  }), /* @__PURE__ */ n(e, {
72
+ decorative: !0,
63
73
  width: "80px",
64
74
  height: "32px"
65
75
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"SkeletonCard2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonCard.tsx"],"sourcesContent":["/**\n * SkeletonCard Component\n *\n * Skeleton placeholder for card components (model cards, stat cards, etc.).\n * Mimics the structure of a typical card with header, content, and footer areas.\n *\n * @example\n * // Basic usage\n * <SkeletonCard />\n *\n * @example\n * // Compact variant\n * <SkeletonCard variant=\"compact\" />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonCard.css\";\n\nexport interface SkeletonCardProps {\n /** Card size variant */\n variant?: \"default\" | \"compact\" | \"stat\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n}\n\n/**\n * SkeletonCard provides a loading placeholder for card components.\n *\n * Variants:\n * - default: Full card with header, content, and footer\n * - compact: Smaller card with reduced padding\n * - stat: Statistics card layout\n */\nexport function SkeletonCard({\n variant = \"default\",\n className = \"\",\n testId,\n}: SkeletonCardProps) {\n const classNames = [\"skeleton-card\", `skeleton-card--${variant}`, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div className={classNames} data-testid={testId} role=\"status\" aria-busy=\"true\">\n {variant === \"stat\" ? (\n <>\n <div className=\"skeleton-card__header\">\n <Skeleton width=\"48px\" height=\"48px\" variant=\"circle\" />\n <div className=\"skeleton-card__header-text\">\n <Skeleton width=\"60%\" height=\"16px\" />\n <Skeleton width=\"40%\" height=\"24px\" />\n </div>\n </div>\n </>\n ) : (\n <>\n <div className=\"skeleton-card__header\">\n <Skeleton width=\"70%\" height=\"20px\" />\n </div>\n <div className=\"skeleton-card__content\">\n <Skeleton width=\"100%\" height=\"16px\" />\n <Skeleton width=\"90%\" height=\"16px\" />\n <Skeleton width=\"80%\" height=\"16px\" />\n </div>\n {variant !== \"compact\" && (\n <div className=\"skeleton-card__footer\">\n <Skeleton width=\"80px\" height=\"32px\" />\n <Skeleton width=\"80px\" height=\"32px\" />\n </div>\n )}\n </>\n )}\n </div>\n );\n}\n\nexport default SkeletonCard;\n"],"mappings":";;;;AAmCA,SAAgB,EAAa,EAC3B,aAAU,WACV,eAAY,IACZ,aACoB;CACpB,IAAM,IAAa;EAAC;EAAiB,kBAAkB;EAAW;CAAS,CAAC,CACzE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,OAAD;EAAK,WAAW;EAAY,eAAa;EAAQ,MAAK;EAAS,aAAU;EACtE,UAAA,MAAY,SACX,kBAAA,GAAA,EAAA,UACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,GAAD;IAAU,OAAM;IAAO,QAAO;IAAO,SAAQ;GAAU,CAAA,GACvD,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,OAAM;KAAM,QAAO;IAAQ,CAAA,GACrC,kBAAC,GAAD;KAAU,OAAM;KAAM,QAAO;IAAQ,CAAA,CAClC;GACF,CAAA,CAAA;EACL,CAAA,EAAA,CAAA,IAEF,kBAAA,GAAA,EAAA,UAAA;GACE,kBAAC,OAAD;IAAK,WAAU;IACb,UAAA,kBAAC,GAAD;KAAU,OAAM;KAAM,QAAO;IAAQ,CAAA;GAClC,CAAA;GACL,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,GAAD;MAAU,OAAM;MAAO,QAAO;KAAQ,CAAA;KACtC,kBAAC,GAAD;MAAU,OAAM;MAAM,QAAO;KAAQ,CAAA;KACrC,kBAAC,GAAD;MAAU,OAAM;MAAM,QAAO;KAAQ,CAAA;IAClC;;GACJ,MAAY,aACX,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,OAAM;KAAO,QAAO;IAAQ,CAAA,GACtC,kBAAC,GAAD;KAAU,OAAM;KAAO,QAAO;IAAQ,CAAA,CACnC;;EAEP,EAAA,CAAA;CAED,CAAA;AAET"}
1
+ {"version":3,"file":"SkeletonCard2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonCard.tsx"],"sourcesContent":["/**\n * SkeletonCard Component\n *\n * Skeleton placeholder for card components (model cards, stat cards, etc.).\n * Mimics the structure of a typical card with header, content, and footer areas.\n *\n * @example\n * // Basic usage\n * <SkeletonCard />\n *\n * @example\n * // Compact variant\n * <SkeletonCard variant=\"compact\" />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonCard.css\";\n\nexport interface SkeletonCardProps {\n /** Card size variant */\n variant?: \"default\" | \"compact\" | \"stat\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible name announced for the placeholder as a whole. Defaults to \"Loading\". */\n loadingLabel?: string;\n}\n\n/**\n * SkeletonCard provides a loading placeholder for card components.\n *\n * Variants:\n * - default: Full card with header, content, and footer\n * - compact: Smaller card with reduced padding\n * - stat: Statistics card layout\n */\nexport function SkeletonCard({\n variant = \"default\",\n className = \"\",\n testId,\n loadingLabel,\n}: SkeletonCardProps) {\n const classNames = [\"skeleton-card\", `skeleton-card--${variant}`, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n className={classNames}\n data-testid={testId}\n role=\"status\"\n aria-busy=\"true\"\n aria-label={loadingLabel ?? \"Loading\"}\n >\n {variant === \"stat\" ? (\n <>\n <div className=\"skeleton-card__header\">\n <Skeleton decorative width=\"48px\" height=\"48px\" variant=\"circle\" />\n <div className=\"skeleton-card__header-text\">\n <Skeleton decorative width=\"60%\" height=\"16px\" />\n <Skeleton decorative width=\"40%\" height=\"24px\" />\n </div>\n </div>\n </>\n ) : (\n <>\n <div className=\"skeleton-card__header\">\n <Skeleton decorative width=\"70%\" height=\"20px\" />\n </div>\n <div className=\"skeleton-card__content\">\n <Skeleton decorative width=\"100%\" height=\"16px\" />\n <Skeleton decorative width=\"90%\" height=\"16px\" />\n <Skeleton decorative width=\"80%\" height=\"16px\" />\n </div>\n {variant !== \"compact\" && (\n <div className=\"skeleton-card__footer\">\n <Skeleton decorative width=\"80px\" height=\"32px\" />\n <Skeleton decorative width=\"80px\" height=\"32px\" />\n </div>\n )}\n </>\n )}\n </div>\n );\n}\n\nexport default SkeletonCard;\n"],"mappings":";;;;AAqCA,SAAgB,EAAa,EAC3B,aAAU,WACV,eAAY,IACZ,WACA,mBACoB;CACpB,IAAM,IAAa;EAAC;EAAiB,kBAAkB;EAAW;CAAS,CAAC,CACzE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,OAAD;EACE,WAAW;EACX,eAAa;EACb,MAAK;EACL,aAAU;EACV,cAAY,KAAgB;EAE3B,UAAA,MAAY,SACX,kBAAA,GAAA,EAAA,UACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,GAAD;IAAU,YAAA;IAAW,OAAM;IAAO,QAAO;IAAO,SAAQ;GAAU,CAAA,GAClE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAM,QAAO;IAAQ,CAAA,GAChD,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAM,QAAO;IAAQ,CAAA,CAC7C;GACF,CAAA,CAAA;EACL,CAAA,EAAA,CAAA,IAEF,kBAAA,GAAA,EAAA,UAAA;GACE,kBAAC,OAAD;IAAK,WAAU;IACb,UAAA,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAM,QAAO;IAAQ,CAAA;GAC7C,CAAA;GACL,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,GAAD;MAAU,YAAA;MAAW,OAAM;MAAO,QAAO;KAAQ,CAAA;KACjD,kBAAC,GAAD;MAAU,YAAA;MAAW,OAAM;MAAM,QAAO;KAAQ,CAAA;KAChD,kBAAC,GAAD;MAAU,YAAA;MAAW,OAAM;MAAM,QAAO;KAAQ,CAAA;IAC7C;;GACJ,MAAY,aACX,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;IAAQ,CAAA,GACjD,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;IAAQ,CAAA,CAC9C;;EAEP,EAAA,CAAA;CAED,CAAA;AAET"}
@@ -18,6 +18,7 @@ function r({ variant: r = "bar", height: i = "300px", className: a = "", testId:
18
18
  children: r === "pie" ? /* @__PURE__ */ n("div", {
19
19
  className: "skeleton-chart__pie",
20
20
  children: [/* @__PURE__ */ t(e, {
21
+ decorative: !0,
21
22
  width: "100%",
22
23
  height: "100%",
23
24
  variant: "circle"
@@ -26,10 +27,12 @@ function r({ variant: r = "bar", height: i = "300px", className: a = "", testId:
26
27
  children: Array.from({ length: 4 }).map((r, i) => /* @__PURE__ */ n("div", {
27
28
  className: "skeleton-chart__legend-item",
28
29
  children: [/* @__PURE__ */ t(e, {
30
+ decorative: !0,
29
31
  width: "16px",
30
32
  height: "16px",
31
33
  variant: "circle"
32
34
  }), /* @__PURE__ */ t(e, {
35
+ decorative: !0,
33
36
  width: "80px",
34
37
  height: "14px"
35
38
  })]
@@ -47,6 +50,7 @@ function r({ variant: r = "bar", height: i = "300px", className: a = "", testId:
47
50
  85,
48
51
  65
49
52
  ].map((n, r) => /* @__PURE__ */ t(e, {
53
+ decorative: !0,
50
54
  width: "100%",
51
55
  height: `${String(n)}%`,
52
56
  className: "skeleton-chart__bar"
@@ -54,6 +58,7 @@ function r({ variant: r = "bar", height: i = "300px", className: a = "", testId:
54
58
  }) : /* @__PURE__ */ t("div", {
55
59
  className: "skeleton-chart__line",
56
60
  children: /* @__PURE__ */ t(e, {
61
+ decorative: !0,
57
62
  width: "100%",
58
63
  height: "100%"
59
64
  })
@@ -1 +1 @@
1
- {"version":3,"file":"SkeletonChart2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonChart.tsx"],"sourcesContent":["/**\n * SkeletonChart Component\n *\n * Skeleton placeholder for chart components.\n * Shows a simplified chart-like shape with bars or circular elements.\n *\n * @example\n * // Bar chart skeleton\n * <SkeletonChart variant=\"bar\" />\n *\n * @example\n * // Pie chart skeleton\n * <SkeletonChart variant=\"pie\" />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonChart.css\";\n\nexport interface SkeletonChartProps {\n /** Chart type variant */\n variant?: \"bar\" | \"line\" | \"pie\" | \"area\";\n /** Chart height */\n height?: string;\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible label announced while the chart is loading. Default: \"Loading chart\" */\n loadingLabel?: string;\n}\n\n/**\n * SkeletonChart provides a loading placeholder for chart components.\n *\n * Variants:\n * - bar: Vertical bars of varying heights\n * - line: Line graph placeholder\n * - pie: Circular chart placeholder\n * - area: Area chart placeholder\n */\nexport function SkeletonChart({\n variant = \"bar\",\n height = \"300px\",\n className = \"\",\n testId,\n loadingLabel = \"Loading chart\",\n}: SkeletonChartProps) {\n const classNames = [\"skeleton-chart\", `skeleton-chart--${variant}`, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n className={classNames}\n style={{ height }}\n data-testid={testId}\n role=\"status\"\n aria-busy=\"true\"\n aria-label={loadingLabel}\n >\n {variant === \"pie\" ? (\n <div className=\"skeleton-chart__pie\">\n <Skeleton width=\"100%\" height=\"100%\" variant=\"circle\" />\n <div className=\"skeleton-chart__legend\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"skeleton-chart__legend-item\">\n <Skeleton width=\"16px\" height=\"16px\" variant=\"circle\" />\n <Skeleton width=\"80px\" height=\"14px\" />\n </div>\n ))}\n </div>\n </div>\n ) : variant === \"bar\" ? (\n <div className=\"skeleton-chart__bars\">\n {[60, 80, 45, 90, 70, 55, 85, 65].map((barHeight, i) => (\n <Skeleton\n key={i}\n width=\"100%\"\n height={`${String(barHeight)}%`}\n className=\"skeleton-chart__bar\"\n />\n ))}\n </div>\n ) : (\n <div className=\"skeleton-chart__line\">\n <Skeleton width=\"100%\" height=\"100%\" />\n </div>\n )}\n </div>\n );\n}\n\nexport default SkeletonChart;\n"],"mappings":";;;;AAwCA,SAAgB,EAAc,EAC5B,aAAU,OACV,YAAS,SACT,eAAY,IACZ,WACA,kBAAe,mBACM;CACrB,IAAM,IAAa;EAAC;EAAkB,mBAAmB;EAAW;CAAS,CAAC,CAC3E,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,OAAD;EACE,WAAW;EACX,OAAO,EAAE,UAAO;EAChB,eAAa;EACb,MAAK;EACL,aAAU;EACV,cAAY;EAEX,UAAA,MAAY,QACX,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,GAAD;IAAU,OAAM;IAAO,QAAO;IAAO,SAAQ;GAAU,CAAA,GACvD,kBAAC,OAAD;IAAK,WAAU;IACZ,UAAA,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,MACjC,kBAAC,OAAD;KAAa,WAAU;KAAvB,UAAA,CACE,kBAAC,GAAD;MAAU,OAAM;MAAO,QAAO;MAAO,SAAQ;KAAU,CAAA,GACvD,kBAAC,GAAD;MAAU,OAAM;MAAO,QAAO;KAAQ,CAAA,CACnC;IAHK,GAAA,CAGL,CACN;GACE,CAAA,CACF;EACH,CAAA,IAAA,MAAY,QACd,kBAAC,OAAD;GAAK,WAAU;GACZ,UAAA;IAAC;IAAI;IAAI;IAAI;IAAI;IAAI;IAAI;IAAI;GAAE,CAAC,CAAC,KAAK,GAAW,MAChD,kBAAC,GAAD;IAEE,OAAM;IACN,QAAQ,GAAG,OAAO,CAAS,EAAE;IAC7B,WAAU;GACX,GAJM,CAIN,CACF;EACE,CAAA,IAEL,kBAAC,OAAD;GAAK,WAAU;GACb,UAAA,kBAAC,GAAD;IAAU,OAAM;IAAO,QAAO;GAAQ,CAAA;EACnC,CAAA;CAEJ,CAAA;AAET"}
1
+ {"version":3,"file":"SkeletonChart2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonChart.tsx"],"sourcesContent":["/**\n * SkeletonChart Component\n *\n * Skeleton placeholder for chart components.\n * Shows a simplified chart-like shape with bars or circular elements.\n *\n * @example\n * // Bar chart skeleton\n * <SkeletonChart variant=\"bar\" />\n *\n * @example\n * // Pie chart skeleton\n * <SkeletonChart variant=\"pie\" />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonChart.css\";\n\nexport interface SkeletonChartProps {\n /** Chart type variant */\n variant?: \"bar\" | \"line\" | \"pie\" | \"area\";\n /** Chart height */\n height?: string;\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible label announced while the chart is loading. Default: \"Loading chart\" */\n loadingLabel?: string;\n}\n\n/**\n * SkeletonChart provides a loading placeholder for chart components.\n *\n * Variants:\n * - bar: Vertical bars of varying heights\n * - line: Line graph placeholder\n * - pie: Circular chart placeholder\n * - area: Area chart placeholder\n */\nexport function SkeletonChart({\n variant = \"bar\",\n height = \"300px\",\n className = \"\",\n testId,\n loadingLabel = \"Loading chart\",\n}: SkeletonChartProps) {\n const classNames = [\"skeleton-chart\", `skeleton-chart--${variant}`, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n className={classNames}\n style={{ height }}\n data-testid={testId}\n role=\"status\"\n aria-busy=\"true\"\n aria-label={loadingLabel}\n >\n {variant === \"pie\" ? (\n <div className=\"skeleton-chart__pie\">\n <Skeleton decorative width=\"100%\" height=\"100%\" variant=\"circle\" />\n <div className=\"skeleton-chart__legend\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"skeleton-chart__legend-item\">\n <Skeleton decorative width=\"16px\" height=\"16px\" variant=\"circle\" />\n <Skeleton decorative width=\"80px\" height=\"14px\" />\n </div>\n ))}\n </div>\n </div>\n ) : variant === \"bar\" ? (\n <div className=\"skeleton-chart__bars\">\n {[60, 80, 45, 90, 70, 55, 85, 65].map((barHeight, i) => (\n <Skeleton\n decorative\n key={i}\n width=\"100%\"\n height={`${String(barHeight)}%`}\n className=\"skeleton-chart__bar\"\n />\n ))}\n </div>\n ) : (\n <div className=\"skeleton-chart__line\">\n <Skeleton decorative width=\"100%\" height=\"100%\" />\n </div>\n )}\n </div>\n );\n}\n\nexport default SkeletonChart;\n"],"mappings":";;;;AAwCA,SAAgB,EAAc,EAC5B,aAAU,OACV,YAAS,SACT,eAAY,IACZ,WACA,kBAAe,mBACM;CACrB,IAAM,IAAa;EAAC;EAAkB,mBAAmB;EAAW;CAAS,CAAC,CAC3E,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,OAAD;EACE,WAAW;EACX,OAAO,EAAE,UAAO;EAChB,eAAa;EACb,MAAK;EACL,aAAU;EACV,cAAY;EAEX,UAAA,MAAY,QACX,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,GAAD;IAAU,YAAA;IAAW,OAAM;IAAO,QAAO;IAAO,SAAQ;GAAU,CAAA,GAClE,kBAAC,OAAD;IAAK,WAAU;IACZ,UAAA,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,MACjC,kBAAC,OAAD;KAAa,WAAU;KAAvB,UAAA,CACE,kBAAC,GAAD;MAAU,YAAA;MAAW,OAAM;MAAO,QAAO;MAAO,SAAQ;KAAU,CAAA,GAClE,kBAAC,GAAD;MAAU,YAAA;MAAW,OAAM;MAAO,QAAO;KAAQ,CAAA,CAC9C;IAHK,GAAA,CAGL,CACN;GACE,CAAA,CACF;EACH,CAAA,IAAA,MAAY,QACd,kBAAC,OAAD;GAAK,WAAU;GACZ,UAAA;IAAC;IAAI;IAAI;IAAI;IAAI;IAAI;IAAI;IAAI;GAAE,CAAC,CAAC,KAAK,GAAW,MAChD,kBAAC,GAAD;IACE,YAAA;IAEA,OAAM;IACN,QAAQ,GAAG,OAAO,CAAS,EAAE;IAC7B,WAAU;GACX,GAJM,CAIN,CACF;EACE,CAAA,IAEL,kBAAC,OAAD;GAAK,WAAU;GACb,UAAA,kBAAC,GAAD;IAAU,YAAA;IAAW,OAAM;IAAO,QAAO;GAAQ,CAAA;EAC9C,CAAA;CAEJ,CAAA;AAET"}
@@ -9,6 +9,8 @@ export interface SkeletonRowProps {
9
9
  className?: string;
10
10
  /** Test ID for testing */
11
11
  testId?: string;
12
+ /** Accessible name announced for the placeholder as a whole. Defaults to "Loading". */
13
+ loadingLabel?: string;
12
14
  }
13
15
  /**
14
16
  * SkeletonRow provides a loading placeholder for list/table rows.
@@ -18,5 +20,5 @@ export interface SkeletonRowProps {
18
20
  * - Optional action buttons
19
21
  * - Multiple rows for lists
20
22
  */
21
- export declare function SkeletonRow({ showAvatar, showActions, count, className, testId, }: SkeletonRowProps): import("react").JSX.Element;
23
+ export declare function SkeletonRow({ showAvatar, showActions, count, className, testId, loadingLabel, }: SkeletonRowProps): import("react").JSX.Element;
22
24
  export default SkeletonRow;
@@ -2,17 +2,19 @@ import { Skeleton as e } from "./Skeleton2.js";
2
2
  /* empty css */
3
3
  import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
4
4
  //#region src/components/Skeleton/SkeletonRow.tsx
5
- function i({ showAvatar: i = !1, showActions: a = !1, count: o = 1, className: s = "", testId: c }) {
6
- let l = Array.from({ length: o });
7
- return /* @__PURE__ */ n(t, { children: l.map((t, o) => /* @__PURE__ */ r("div", {
5
+ function i({ showAvatar: i = !1, showActions: a = !1, count: o = 1, className: s = "", testId: c, loadingLabel: l }) {
6
+ let u = Array.from({ length: o });
7
+ return /* @__PURE__ */ n(t, { children: u.map((t, o) => /* @__PURE__ */ r("div", {
8
8
  className: `skeleton-row ${s}`,
9
9
  "data-testid": c ? `${c}-${String(o)}` : void 0,
10
10
  role: "status",
11
11
  "aria-busy": "true",
12
+ "aria-label": l ?? "Loading",
12
13
  children: [
13
14
  i && /* @__PURE__ */ n("div", {
14
15
  className: "skeleton-row__avatar",
15
16
  children: /* @__PURE__ */ n(e, {
17
+ decorative: !0,
16
18
  width: "40px",
17
19
  height: "40px",
18
20
  variant: "circle"
@@ -21,9 +23,11 @@ function i({ showAvatar: i = !1, showActions: a = !1, count: o = 1, className: s
21
23
  /* @__PURE__ */ r("div", {
22
24
  className: "skeleton-row__content",
23
25
  children: [/* @__PURE__ */ n(e, {
26
+ decorative: !0,
24
27
  width: "25%",
25
28
  height: "14px"
26
29
  }), /* @__PURE__ */ n(e, {
30
+ decorative: !0,
27
31
  width: "100%",
28
32
  height: "16px"
29
33
  })]
@@ -31,9 +35,11 @@ function i({ showAvatar: i = !1, showActions: a = !1, count: o = 1, className: s
31
35
  a && /* @__PURE__ */ r("div", {
32
36
  className: "skeleton-row__actions",
33
37
  children: [/* @__PURE__ */ n(e, {
38
+ decorative: !0,
34
39
  width: "32px",
35
40
  height: "32px"
36
41
  }), /* @__PURE__ */ n(e, {
42
+ decorative: !0,
37
43
  width: "32px",
38
44
  height: "32px"
39
45
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"SkeletonRow2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonRow.tsx"],"sourcesContent":["/**\n * SkeletonRow Component\n *\n * Skeleton placeholder for list rows and table rows.\n * Mimics the structure of a log entry or table row.\n *\n * @example\n * // Basic usage\n * <SkeletonRow />\n *\n * @example\n * // With avatar\n * <SkeletonRow showAvatar />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonRow.css\";\n\nexport interface SkeletonRowProps {\n /** Show avatar/icon on the left */\n showAvatar?: boolean;\n /** Show action buttons on the right */\n showActions?: boolean;\n /** Number of rows to display */\n count?: number;\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n}\n\n/**\n * SkeletonRow provides a loading placeholder for list/table rows.\n *\n * Features:\n * - Optional avatar/icon\n * - Optional action buttons\n * - Multiple rows for lists\n */\nexport function SkeletonRow({\n showAvatar = false,\n showActions = false,\n count = 1,\n className = \"\",\n testId,\n}: SkeletonRowProps) {\n const rows = Array.from({ length: count });\n\n return (\n <>\n {rows.map((_, index) => (\n <div\n key={index}\n className={`skeleton-row ${className}`}\n data-testid={testId ? `${testId}-${String(index)}` : undefined}\n role=\"status\"\n aria-busy=\"true\"\n >\n {showAvatar && (\n <div className=\"skeleton-row__avatar\">\n <Skeleton width=\"40px\" height=\"40px\" variant=\"circle\" />\n </div>\n )}\n <div className=\"skeleton-row__content\">\n <Skeleton width=\"25%\" height=\"14px\" />\n <Skeleton width=\"100%\" height=\"16px\" />\n </div>\n {showActions && (\n <div className=\"skeleton-row__actions\">\n <Skeleton width=\"32px\" height=\"32px\" />\n <Skeleton width=\"32px\" height=\"32px\" />\n </div>\n )}\n </div>\n ))}\n </>\n );\n}\n\nexport default SkeletonRow;\n"],"mappings":";;;;AAuCA,SAAgB,EAAY,EAC1B,gBAAa,IACb,iBAAc,IACd,WAAQ,GACR,eAAY,IACZ,aACmB;CACnB,IAAM,IAAO,MAAM,KAAK,EAAE,QAAQ,EAAM,CAAC;CAEzC,OACE,kBAAA,GAAA,EAAA,UACG,EAAK,KAAK,GAAG,MACZ,kBAAC,OAAD;EAEE,WAAW,gBAAgB;EAC3B,eAAa,IAAS,GAAG,EAAO,GAAG,OAAO,CAAK,MAAM,KAAA;EACrD,MAAK;EACL,aAAU;EALZ,UAAA;GAOG,KACC,kBAAC,OAAD;IAAK,WAAU;IACb,UAAA,kBAAC,GAAD;KAAU,OAAM;KAAO,QAAO;KAAO,SAAQ;IAAU,CAAA;GACpD,CAAA;GAEP,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,OAAM;KAAM,QAAO;IAAQ,CAAA,GACrC,kBAAC,GAAD;KAAU,OAAM;KAAO,QAAO;IAAQ,CAAA,CACnC;;GACJ,KACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,OAAM;KAAO,QAAO;IAAQ,CAAA,GACtC,kBAAC,GAAD;KAAU,OAAM;KAAO,QAAO;IAAQ,CAAA,CACnC;;EAEJ;CArBE,GAAA,CAqBF,CACN,EACD,CAAA;AAEN"}
1
+ {"version":3,"file":"SkeletonRow2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonRow.tsx"],"sourcesContent":["/**\n * SkeletonRow Component\n *\n * Skeleton placeholder for list rows and table rows.\n * Mimics the structure of a log entry or table row.\n *\n * @example\n * // Basic usage\n * <SkeletonRow />\n *\n * @example\n * // With avatar\n * <SkeletonRow showAvatar />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonRow.css\";\n\nexport interface SkeletonRowProps {\n /** Show avatar/icon on the left */\n showAvatar?: boolean;\n /** Show action buttons on the right */\n showActions?: boolean;\n /** Number of rows to display */\n count?: number;\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible name announced for the placeholder as a whole. Defaults to \"Loading\". */\n loadingLabel?: string;\n}\n\n/**\n * SkeletonRow provides a loading placeholder for list/table rows.\n *\n * Features:\n * - Optional avatar/icon\n * - Optional action buttons\n * - Multiple rows for lists\n */\nexport function SkeletonRow({\n showAvatar = false,\n showActions = false,\n count = 1,\n className = \"\",\n testId,\n loadingLabel,\n}: SkeletonRowProps) {\n const rows = Array.from({ length: count });\n\n return (\n <>\n {rows.map((_, index) => (\n <div\n key={index}\n className={`skeleton-row ${className}`}\n data-testid={testId ? `${testId}-${String(index)}` : undefined}\n role=\"status\"\n aria-busy=\"true\"\n aria-label={loadingLabel ?? \"Loading\"}\n >\n {showAvatar && (\n <div className=\"skeleton-row__avatar\">\n <Skeleton decorative width=\"40px\" height=\"40px\" variant=\"circle\" />\n </div>\n )}\n <div className=\"skeleton-row__content\">\n <Skeleton decorative width=\"25%\" height=\"14px\" />\n <Skeleton decorative width=\"100%\" height=\"16px\" />\n </div>\n {showActions && (\n <div className=\"skeleton-row__actions\">\n <Skeleton decorative width=\"32px\" height=\"32px\" />\n <Skeleton decorative width=\"32px\" height=\"32px\" />\n </div>\n )}\n </div>\n ))}\n </>\n );\n}\n\nexport default SkeletonRow;\n"],"mappings":";;;;AAyCA,SAAgB,EAAY,EAC1B,gBAAa,IACb,iBAAc,IACd,WAAQ,GACR,eAAY,IACZ,WACA,mBACmB;CACnB,IAAM,IAAO,MAAM,KAAK,EAAE,QAAQ,EAAM,CAAC;CAEzC,OACE,kBAAA,GAAA,EAAA,UACG,EAAK,KAAK,GAAG,MACZ,kBAAC,OAAD;EAEE,WAAW,gBAAgB;EAC3B,eAAa,IAAS,GAAG,EAAO,GAAG,OAAO,CAAK,MAAM,KAAA;EACrD,MAAK;EACL,aAAU;EACV,cAAY,KAAgB;EAN9B,UAAA;GAQG,KACC,kBAAC,OAAD;IAAK,WAAU;IACb,UAAA,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;KAAO,SAAQ;IAAU,CAAA;GAC/D,CAAA;GAEP,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAM,QAAO;IAAQ,CAAA,GAChD,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;IAAQ,CAAA,CAC9C;;GACJ,KACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;IAAQ,CAAA,GACjD,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;IAAQ,CAAA,CAC9C;;EAEJ;CAtBE,GAAA,CAsBF,CACN,EACD,CAAA;AAEN"}
@@ -7,6 +7,8 @@ export interface SkeletonTextProps {
7
7
  className?: string;
8
8
  /** Test ID for testing */
9
9
  testId?: string;
10
+ /** Accessible name announced for the placeholder as a whole. Defaults to "Loading". */
11
+ loadingLabel?: string;
10
12
  }
11
13
  /**
12
14
  * SkeletonText provides a loading placeholder for text content.
@@ -16,5 +18,5 @@ export interface SkeletonTextProps {
16
18
  * - Configurable line spacing
17
19
  * - Accessible via aria-busy
18
20
  */
19
- export declare function SkeletonText({ lines, spacing, className, testId, }: SkeletonTextProps): import("react").JSX.Element;
21
+ export declare function SkeletonText({ lines, spacing, className, testId, loadingLabel, }: SkeletonTextProps): import("react").JSX.Element;
20
22
  export default SkeletonText;
@@ -2,18 +2,20 @@ import { Skeleton as e } from "./Skeleton2.js";
2
2
  /* empty css */
3
3
  import { jsx as t } from "react/jsx-runtime";
4
4
  //#region src/components/Skeleton/SkeletonText.tsx
5
- function n({ lines: n = 3, spacing: r = "normal", className: i = "", testId: a }) {
6
- let o = [
5
+ function n({ lines: n = 3, spacing: r = "normal", className: i = "", testId: a, loadingLabel: o }) {
6
+ let s = [
7
7
  "skeleton-text",
8
8
  `skeleton-text--${r}`,
9
9
  i
10
- ].filter(Boolean).join(" "), s = Array.from({ length: n }, (e, t) => t === n - 1 ? "60%" : t % 2 == 0 ? "100%" : "95%");
10
+ ].filter(Boolean).join(" "), c = Array.from({ length: n }, (e, t) => t === n - 1 ? "60%" : t % 2 == 0 ? "100%" : "95%");
11
11
  return /* @__PURE__ */ t("div", {
12
- className: o,
12
+ className: s,
13
13
  "data-testid": a,
14
14
  role: "status",
15
15
  "aria-busy": "true",
16
- children: s.map((n, r) => /* @__PURE__ */ t(e, {
16
+ "aria-label": o ?? "Loading",
17
+ children: c.map((n, r) => /* @__PURE__ */ t(e, {
18
+ decorative: !0,
17
19
  width: n,
18
20
  height: "1em",
19
21
  variant: "text"
@@ -1 +1 @@
1
- {"version":3,"file":"SkeletonText2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonText.tsx"],"sourcesContent":["/**\n * SkeletonText Component\n *\n * Skeleton placeholder for text content.\n * Provides multiple lines with varying widths for natural appearance.\n *\n * @example\n * // Basic usage (3 lines)\n * <SkeletonText />\n *\n * @example\n * // Custom number of lines\n * <SkeletonText lines={5} />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonText.css\";\n\nexport interface SkeletonTextProps {\n /** Number of text lines to display */\n lines?: number;\n /** Spacing between lines */\n spacing?: \"compact\" | \"normal\" | \"relaxed\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n}\n\n/**\n * SkeletonText provides a loading placeholder for text content.\n *\n * Features:\n * - Multiple lines with varying widths\n * - Configurable line spacing\n * - Accessible via aria-busy\n */\nexport function SkeletonText({\n lines = 3,\n spacing = \"normal\",\n className = \"\",\n testId,\n}: SkeletonTextProps) {\n const classNames = [\"skeleton-text\", `skeleton-text--${spacing}`, className]\n .filter(Boolean)\n .join(\" \");\n\n // Generate varying widths for natural appearance\n const widths = Array.from({ length: lines }, (_, i) => {\n if (i === lines - 1) {\n // Last line is shorter\n return \"60%\";\n }\n // Alternate between full and slightly shorter widths\n return i % 2 === 0 ? \"100%\" : \"95%\";\n });\n\n return (\n <div className={classNames} data-testid={testId} role=\"status\" aria-busy=\"true\">\n {widths.map((width, index) => (\n <Skeleton key={index} width={width} height=\"1em\" variant=\"text\" />\n ))}\n </div>\n );\n}\n\nexport default SkeletonText;\n"],"mappings":";;;;AAqCA,SAAgB,EAAa,EAC3B,WAAQ,GACR,aAAU,UACV,eAAY,IACZ,aACoB;CACpB,IAAM,IAAa;EAAC;EAAiB,kBAAkB;EAAW;CAAS,CAAC,CACzE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,GAGL,IAAS,MAAM,KAAK,EAAE,QAAQ,EAAM,IAAI,GAAG,MAC3C,MAAM,IAAQ,IAET,QAGF,IAAI,KAAM,IAAI,SAAS,KAC/B;CAED,OACE,kBAAC,OAAD;EAAK,WAAW;EAAY,eAAa;EAAQ,MAAK;EAAS,aAAU;EACtE,UAAA,EAAO,KAAK,GAAO,MAClB,kBAAC,GAAD;GAA6B;GAAO,QAAO;GAAM,SAAQ;EAAQ,GAAlD,CAAkD,CAClE;CACE,CAAA;AAET"}
1
+ {"version":3,"file":"SkeletonText2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonText.tsx"],"sourcesContent":["/**\n * SkeletonText Component\n *\n * Skeleton placeholder for text content.\n * Provides multiple lines with varying widths for natural appearance.\n *\n * @example\n * // Basic usage (3 lines)\n * <SkeletonText />\n *\n * @example\n * // Custom number of lines\n * <SkeletonText lines={5} />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonText.css\";\n\nexport interface SkeletonTextProps {\n /** Number of text lines to display */\n lines?: number;\n /** Spacing between lines */\n spacing?: \"compact\" | \"normal\" | \"relaxed\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible name announced for the placeholder as a whole. Defaults to \"Loading\". */\n loadingLabel?: string;\n}\n\n/**\n * SkeletonText provides a loading placeholder for text content.\n *\n * Features:\n * - Multiple lines with varying widths\n * - Configurable line spacing\n * - Accessible via aria-busy\n */\nexport function SkeletonText({\n lines = 3,\n spacing = \"normal\",\n className = \"\",\n testId,\n loadingLabel,\n}: SkeletonTextProps) {\n const classNames = [\"skeleton-text\", `skeleton-text--${spacing}`, className]\n .filter(Boolean)\n .join(\" \");\n\n // Generate varying widths for natural appearance\n const widths = Array.from({ length: lines }, (_, i) => {\n if (i === lines - 1) {\n // Last line is shorter\n return \"60%\";\n }\n // Alternate between full and slightly shorter widths\n return i % 2 === 0 ? \"100%\" : \"95%\";\n });\n\n return (\n <div\n className={classNames}\n data-testid={testId}\n role=\"status\"\n aria-busy=\"true\"\n aria-label={loadingLabel ?? \"Loading\"}\n >\n {widths.map((width, index) => (\n <Skeleton decorative key={index} width={width} height=\"1em\" variant=\"text\" />\n ))}\n </div>\n );\n}\n\nexport default SkeletonText;\n"],"mappings":";;;;AAuCA,SAAgB,EAAa,EAC3B,WAAQ,GACR,aAAU,UACV,eAAY,IACZ,WACA,mBACoB;CACpB,IAAM,IAAa;EAAC;EAAiB,kBAAkB;EAAW;CAAS,CAAC,CACzE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,GAGL,IAAS,MAAM,KAAK,EAAE,QAAQ,EAAM,IAAI,GAAG,MAC3C,MAAM,IAAQ,IAET,QAGF,IAAI,KAAM,IAAI,SAAS,KAC/B;CAED,OACE,kBAAC,OAAD;EACE,WAAW;EACX,eAAa;EACb,MAAK;EACL,aAAU;EACV,cAAY,KAAgB;EAE3B,UAAA,EAAO,KAAK,GAAO,MAClB,kBAAC,GAAD;GAAU,YAAA;GAA8B;GAAO,QAAO;GAAM,SAAQ;EAAQ,GAAlD,CAAkD,CAC7E;CACE,CAAA;AAET"}
@@ -13,6 +13,15 @@ export interface StatCardTrend {
13
13
  export interface StatCardProps {
14
14
  /** Short label rendered above the value (UPPERCASE styled) */
15
15
  label: string;
16
+ /**
17
+ * Rendered in place of `label` when the label is not plain text: a glossary
18
+ * term carrying its definition, a unit badge, an info affordance.
19
+ *
20
+ * `label` stays required and stays the accessible name, so the name is a
21
+ * string the consumer wrote rather than whatever text happens to fall out of
22
+ * a node. Pass the same words in both.
23
+ */
24
+ labelNode?: ReactNode;
16
25
  /** Primary metric value (number is coerced to localised string) */
17
26
  value: string | number;
18
27
  /** Optional suffix appended to the value (e.g. "/ 4", "GB") */
@@ -54,6 +63,6 @@ export interface StatCardProps {
54
63
  /** Visual weight. Default: "default" */
55
64
  emphasis?: StatCardEmphasis;
56
65
  }
57
- declare function StatCardComponent({ label, value, valueSuffix, hint, icon, tone, trend, onClick, loading, ariaLabel, className, testId, format, animate, sparkline, emphasis, }: StatCardProps): JSX.Element;
66
+ declare function StatCardComponent({ label, labelNode, value, valueSuffix, hint, icon, tone, trend, onClick, loading, ariaLabel, className, testId, format, animate, sparkline, emphasis, }: StatCardProps): JSX.Element;
58
67
  export declare const StatCard: import('react').MemoExoticComponent<typeof StatCardComponent>;
59
68
  export {};
@@ -30,76 +30,76 @@ var d = {
30
30
  function f(e, t) {
31
31
  return typeof e == "number" ? t ? t(e) : e.toLocaleString() : e;
32
32
  }
33
- function p({ label: r, value: i, valueSuffix: a, hint: o, icon: l, tone: p = "default", trend: m, onClick: h, loading: g = !1, ariaLabel: _, className: v = "", testId: y, format: b, animate: x = !1, sparkline: S, emphasis: C = "default" }) {
34
- let w = n(), T = typeof i == "number", E = x && T && !g && !w, D = u(T ? i : 0, E), O = f(T && E ? D : i, b), k = _ ?? (g ? r : `${r}: ${f(i, b)}${a ?? ""}`), A = [
33
+ function p({ label: r, labelNode: i, value: a, valueSuffix: o, hint: l, icon: p, tone: m = "default", trend: h, onClick: g, loading: _ = !1, ariaLabel: v, className: y = "", testId: b, format: x, animate: S = !1, sparkline: C, emphasis: w = "default" }) {
34
+ let T = n(), E = typeof a == "number", D = S && E && !_ && !T, O = u(E ? a : 0, D), k = f(E && D ? O : a, x), A = v ?? (_ ? r : `${r}: ${f(a, x)}${o ?? ""}`), j = [
35
35
  "stat-card",
36
36
  "corner-accent",
37
- `stat-card--tone-${p}`,
38
- C === "default" ? "" : `stat-card--${C}`,
39
- v
37
+ `stat-card--tone-${m}`,
38
+ w === "default" ? "" : `stat-card--${w}`,
39
+ y
40
40
  ].filter(Boolean).join(" ");
41
41
  return /* @__PURE__ */ c(e, {
42
- className: A,
43
- onClick: h,
44
- role: h ? void 0 : "group",
45
- ariaLabel: k,
46
- testId: y,
42
+ className: j,
43
+ onClick: g,
44
+ role: g ? void 0 : "group",
45
+ ariaLabel: A,
46
+ testId: b,
47
47
  children: [
48
48
  /* @__PURE__ */ c("div", {
49
49
  className: "stat-card__header",
50
50
  children: [/* @__PURE__ */ s("span", {
51
51
  className: "stat-card__label",
52
- children: r
53
- }), l && /* @__PURE__ */ s("span", {
52
+ children: i ?? r
53
+ }), p && /* @__PURE__ */ s("span", {
54
54
  className: "stat-card__icon",
55
55
  "aria-hidden": "true",
56
- children: l
56
+ children: p
57
57
  })]
58
58
  }),
59
59
  /* @__PURE__ */ c("div", {
60
60
  className: "stat-card__body",
61
- children: [g ? /* @__PURE__ */ s(t, {
61
+ children: [_ ? /* @__PURE__ */ s(t, {
62
62
  width: "60%",
63
63
  height: "2rem"
64
- }) : S ? /* @__PURE__ */ c("span", {
64
+ }) : C ? /* @__PURE__ */ c("span", {
65
65
  className: "stat-card__value-line",
66
66
  children: [/* @__PURE__ */ c("span", {
67
67
  className: "stat-card__value-row",
68
68
  children: [/* @__PURE__ */ s("span", {
69
69
  className: "stat-card__value",
70
- children: O
71
- }), a && /* @__PURE__ */ s("span", {
70
+ children: k
71
+ }), o && /* @__PURE__ */ s("span", {
72
72
  className: "stat-card__value-suffix",
73
- children: a
73
+ children: o
74
74
  })]
75
75
  }), /* @__PURE__ */ s("span", {
76
76
  className: "stat-card__sparkline",
77
- children: S
77
+ children: C
78
78
  })]
79
79
  }) : /* @__PURE__ */ c("span", {
80
80
  className: "stat-card__value-row",
81
81
  children: [/* @__PURE__ */ s("span", {
82
82
  className: "stat-card__value",
83
- children: O
84
- }), a && /* @__PURE__ */ s("span", {
83
+ children: k
84
+ }), o && /* @__PURE__ */ s("span", {
85
85
  className: "stat-card__value-suffix",
86
- children: a
86
+ children: o
87
87
  })]
88
- }), m && !g && /* @__PURE__ */ c("span", {
89
- className: `stat-card__trend stat-card__trend--${m.direction}`,
90
- "aria-label": m.ariaLabel ?? m.label,
88
+ }), h && !_ && /* @__PURE__ */ c("span", {
89
+ className: `stat-card__trend stat-card__trend--${h.direction}`,
90
+ "aria-label": h.ariaLabel ?? h.label,
91
91
  children: [/* @__PURE__ */ s("span", {
92
92
  "aria-hidden": "true",
93
- children: d[m.direction]
94
- }), /* @__PURE__ */ s("span", { children: m.label })]
93
+ children: d[h.direction]
94
+ }), /* @__PURE__ */ s("span", { children: h.label })]
95
95
  })]
96
96
  }),
97
- o != null && /* @__PURE__ */ s("div", {
97
+ l != null && /* @__PURE__ */ s("div", {
98
98
  className: "stat-card__hint",
99
- children: g ? /* @__PURE__ */ s(t, {
99
+ children: _ ? /* @__PURE__ */ s(t, {
100
100
  width: "80%",
101
101
  height: "0.85rem"
102
- }) : o
102
+ }) : l
103
103
  })
104
104
  ]
105
105
  });
@@ -1 +1 @@
1
- {"version":3,"file":"StatCard2.js","names":[],"sources":["../../../src/components/StatCard/StatCard.tsx"],"sourcesContent":["/**\n * StatCard Component\n *\n * Compact metric card for dashboards. Renders a label, a large numeric\n * value (with optional unit/suffix), and optional icon, hint, trend, or\n * accent tone. Wraps `BaseCard` so it inherits hover/focus/click affordances\n * and design tokens consistently with the rest of the common library.\n *\n * Designed for cross-page reuse: Squad dashboard, Statistics page, Cowork\n * dashboard, etc.\n */\n\nimport { memo, useEffect, useRef, useState, type ReactNode, type JSX } from \"react\";\nimport { usePrefersReducedMotion } from \"../../hooks/usePrefersReducedMotion\";\nimport { BaseCard } from \"../BaseCard\";\nimport { Skeleton } from \"../Skeleton\";\nimport \"./StatCard.css\";\n\nexport type StatCardEmphasis = \"compact\" | \"default\" | \"prominent\";\n\nexport type StatCardTone = \"default\" | \"success\" | \"warning\" | \"danger\" | \"info\";\n\nexport type StatCardTrendDirection = \"up\" | \"down\" | \"flat\";\n\nexport interface StatCardTrend {\n /** Direction indicator (up / down / flat) */\n direction: StatCardTrendDirection;\n /** Human-readable delta label (e.g. \"+12%\", \"-3\", \"0\") */\n label: string;\n /** Optional ARIA description for screen readers */\n ariaLabel?: string;\n}\n\nexport interface StatCardProps {\n /** Short label rendered above the value (UPPERCASE styled) */\n label: string;\n /** Primary metric value (number is coerced to localised string) */\n value: string | number;\n /** Optional suffix appended to the value (e.g. \"/ 4\", \"GB\") */\n valueSuffix?: string;\n /** Optional helper line under the value (e.g. context, secondary metric) */\n hint?: ReactNode;\n /** Optional leading icon node, rendered inside an accent badge */\n icon?: ReactNode;\n /** Visual tone, mirrors Badge variants. Default: \"default\" */\n tone?: StatCardTone;\n /** Optional trend indicator under the value */\n trend?: StatCardTrend;\n /** Click handler. Renders the card as keyboard-accessible button. */\n onClick?: () => void;\n /** Render skeletons instead of value/label content while loading */\n loading?: boolean;\n /** Optional aria label override (defaults to label + value) */\n ariaLabel?: string;\n /** Extra class name applied to the root */\n className?: string;\n /** Test id for unit tests */\n testId?: string;\n /**\n * Formatter for numeric values (e.g. abbreviate to \"1.2K\", append \"%\").\n * Defaults to `toLocaleString`. Ignored when `value` is a string.\n */\n format?: (value: number) => string;\n /**\n * Count up to a numeric value on mount and on change. Off by default so\n * existing consumers render the final value immediately; opt in for\n * dashboard hero metrics. Suppressed under `prefers-reduced-motion`.\n */\n animate?: boolean;\n /**\n * Optional trailing visual on the value line (e.g. a sparkline). Kept as a\n * slot so the card does not depend on any particular chart component.\n */\n sparkline?: ReactNode;\n /** Visual weight. Default: \"default\" */\n emphasis?: StatCardEmphasis;\n}\n\nconst ANIMATION_DURATION_MS = 800;\n\n/**\n * Counts from the previous value to `target` with an ease-out-cubic curve.\n * When `enabled` is false the target is returned directly and no animation\n * frame is ever scheduled.\n */\nfunction useAnimatedValue(target: number, enabled: boolean): number {\n const [displayValue, setDisplayValue] = useState(enabled ? 0 : target);\n const previousValue = useRef(enabled ? 0 : target);\n const frameRef = useRef<number | null>(null);\n\n useEffect(() => {\n if (!enabled) {\n previousValue.current = target;\n setDisplayValue(target);\n return;\n }\n\n const startValue = previousValue.current;\n const startTime = performance.now();\n\n const step = (now: number): void => {\n const progress = Math.min((now - startTime) / ANIMATION_DURATION_MS, 1);\n const eased = 1 - Math.pow(1 - progress, 3);\n setDisplayValue(Math.round(startValue + (target - startValue) * eased));\n\n if (progress < 1) {\n frameRef.current = requestAnimationFrame(step);\n } else {\n previousValue.current = target;\n }\n };\n\n frameRef.current = requestAnimationFrame(step);\n\n return () => {\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n }\n };\n }, [target, enabled]);\n\n return enabled ? displayValue : target;\n}\n\nconst TREND_GLYPH: Record<StatCardTrendDirection, string> = {\n up: \"▲\",\n down: \"▼\",\n flat: \"•\",\n};\n\nfunction formatValue(\n value: string | number,\n format?: (value: number) => string,\n): string {\n if (typeof value === \"number\") {\n return format ? format(value) : value.toLocaleString();\n }\n return value;\n}\n\nfunction StatCardComponent({\n label,\n value,\n valueSuffix,\n hint,\n icon,\n tone = \"default\",\n trend,\n onClick,\n loading = false,\n ariaLabel,\n className = \"\",\n testId,\n format,\n animate = false,\n sparkline,\n emphasis = \"default\",\n}: StatCardProps): JSX.Element {\n const prefersReducedMotion = usePrefersReducedMotion();\n const isNumeric = typeof value === \"number\";\n const shouldAnimate = animate && isNumeric && !loading && !prefersReducedMotion;\n const animatedValue = useAnimatedValue(isNumeric ? value : 0, shouldAnimate);\n\n const displayValue = formatValue(\n isNumeric && shouldAnimate ? animatedValue : value,\n format,\n );\n\n // The aria-label always describes the settled value, never an in-flight\n // animation frame, so assistive tech is not read a counting-up number.\n const composedAriaLabel =\n ariaLabel ??\n (loading ? label : `${label}: ${formatValue(value, format)}${valueSuffix ?? \"\"}`);\n\n const rootClass = [\n \"stat-card\",\n \"corner-accent\",\n `stat-card--tone-${tone}`,\n emphasis !== \"default\" ? `stat-card--${emphasis}` : \"\",\n className,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <BaseCard\n className={rootClass}\n onClick={onClick}\n role={onClick ? undefined : \"group\"}\n ariaLabel={composedAriaLabel}\n testId={testId}\n >\n <div className=\"stat-card__header\">\n <span className=\"stat-card__label\">{label}</span>\n {icon && (\n <span className=\"stat-card__icon\" aria-hidden=\"true\">\n {icon}\n </span>\n )}\n </div>\n\n <div className=\"stat-card__body\">\n {loading ? (\n <Skeleton width=\"60%\" height=\"2rem\" />\n ) : sparkline ? (\n // Only wrap when a sparkline is present, so cards without one keep\n // the exact DOM they had before the slot existed.\n <span className=\"stat-card__value-line\">\n <span className=\"stat-card__value-row\">\n <span className=\"stat-card__value\">{displayValue}</span>\n {valueSuffix && (\n <span className=\"stat-card__value-suffix\">{valueSuffix}</span>\n )}\n </span>\n <span className=\"stat-card__sparkline\">{sparkline}</span>\n </span>\n ) : (\n <span className=\"stat-card__value-row\">\n <span className=\"stat-card__value\">{displayValue}</span>\n {valueSuffix && (\n <span className=\"stat-card__value-suffix\">{valueSuffix}</span>\n )}\n </span>\n )}\n\n {trend && !loading && (\n <span\n className={`stat-card__trend stat-card__trend--${trend.direction}`}\n aria-label={trend.ariaLabel ?? trend.label}\n >\n <span aria-hidden=\"true\">{TREND_GLYPH[trend.direction]}</span>\n <span>{trend.label}</span>\n </span>\n )}\n </div>\n\n {hint !== undefined && hint !== null && (\n <div className=\"stat-card__hint\">\n {loading ? <Skeleton width=\"80%\" height=\"0.85rem\" /> : hint}\n </div>\n )}\n </BaseCard>\n );\n}\n\nexport const StatCard = memo(StatCardComponent);\n"],"mappings":"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"}
1
+ {"version":3,"file":"StatCard2.js","names":[],"sources":["../../../src/components/StatCard/StatCard.tsx"],"sourcesContent":["/**\n * StatCard Component\n *\n * Compact metric card for dashboards. Renders a label, a large numeric\n * value (with optional unit/suffix), and optional icon, hint, trend, or\n * accent tone. The label can be a node (`labelNode`) while the accessible name\n * stays the plain `label` string. Wraps `BaseCard` so it inherits hover/focus/click affordances\n * and design tokens consistently with the rest of the common library.\n *\n * Designed for cross-page reuse: Squad dashboard, Statistics page, Cowork\n * dashboard, etc.\n */\n\nimport { memo, useEffect, useRef, useState, type ReactNode, type JSX } from \"react\";\nimport { usePrefersReducedMotion } from \"../../hooks/usePrefersReducedMotion\";\nimport { BaseCard } from \"../BaseCard\";\nimport { Skeleton } from \"../Skeleton\";\nimport \"./StatCard.css\";\n\nexport type StatCardEmphasis = \"compact\" | \"default\" | \"prominent\";\n\nexport type StatCardTone = \"default\" | \"success\" | \"warning\" | \"danger\" | \"info\";\n\nexport type StatCardTrendDirection = \"up\" | \"down\" | \"flat\";\n\nexport interface StatCardTrend {\n /** Direction indicator (up / down / flat) */\n direction: StatCardTrendDirection;\n /** Human-readable delta label (e.g. \"+12%\", \"-3\", \"0\") */\n label: string;\n /** Optional ARIA description for screen readers */\n ariaLabel?: string;\n}\n\nexport interface StatCardProps {\n /** Short label rendered above the value (UPPERCASE styled) */\n label: string;\n /**\n * Rendered in place of `label` when the label is not plain text: a glossary\n * term carrying its definition, a unit badge, an info affordance.\n *\n * `label` stays required and stays the accessible name, so the name is a\n * string the consumer wrote rather than whatever text happens to fall out of\n * a node. Pass the same words in both.\n */\n labelNode?: ReactNode;\n /** Primary metric value (number is coerced to localised string) */\n value: string | number;\n /** Optional suffix appended to the value (e.g. \"/ 4\", \"GB\") */\n valueSuffix?: string;\n /** Optional helper line under the value (e.g. context, secondary metric) */\n hint?: ReactNode;\n /** Optional leading icon node, rendered inside an accent badge */\n icon?: ReactNode;\n /** Visual tone, mirrors Badge variants. Default: \"default\" */\n tone?: StatCardTone;\n /** Optional trend indicator under the value */\n trend?: StatCardTrend;\n /** Click handler. Renders the card as keyboard-accessible button. */\n onClick?: () => void;\n /** Render skeletons instead of value/label content while loading */\n loading?: boolean;\n /** Optional aria label override (defaults to label + value) */\n ariaLabel?: string;\n /** Extra class name applied to the root */\n className?: string;\n /** Test id for unit tests */\n testId?: string;\n /**\n * Formatter for numeric values (e.g. abbreviate to \"1.2K\", append \"%\").\n * Defaults to `toLocaleString`. Ignored when `value` is a string.\n */\n format?: (value: number) => string;\n /**\n * Count up to a numeric value on mount and on change. Off by default so\n * existing consumers render the final value immediately; opt in for\n * dashboard hero metrics. Suppressed under `prefers-reduced-motion`.\n */\n animate?: boolean;\n /**\n * Optional trailing visual on the value line (e.g. a sparkline). Kept as a\n * slot so the card does not depend on any particular chart component.\n */\n sparkline?: ReactNode;\n /** Visual weight. Default: \"default\" */\n emphasis?: StatCardEmphasis;\n}\n\nconst ANIMATION_DURATION_MS = 800;\n\n/**\n * Counts from the previous value to `target` with an ease-out-cubic curve.\n * When `enabled` is false the target is returned directly and no animation\n * frame is ever scheduled.\n */\nfunction useAnimatedValue(target: number, enabled: boolean): number {\n const [displayValue, setDisplayValue] = useState(enabled ? 0 : target);\n const previousValue = useRef(enabled ? 0 : target);\n const frameRef = useRef<number | null>(null);\n\n useEffect(() => {\n if (!enabled) {\n previousValue.current = target;\n setDisplayValue(target);\n return;\n }\n\n const startValue = previousValue.current;\n const startTime = performance.now();\n\n const step = (now: number): void => {\n const progress = Math.min((now - startTime) / ANIMATION_DURATION_MS, 1);\n const eased = 1 - Math.pow(1 - progress, 3);\n setDisplayValue(Math.round(startValue + (target - startValue) * eased));\n\n if (progress < 1) {\n frameRef.current = requestAnimationFrame(step);\n } else {\n previousValue.current = target;\n }\n };\n\n frameRef.current = requestAnimationFrame(step);\n\n return () => {\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n }\n };\n }, [target, enabled]);\n\n return enabled ? displayValue : target;\n}\n\nconst TREND_GLYPH: Record<StatCardTrendDirection, string> = {\n up: \"▲\",\n down: \"▼\",\n flat: \"•\",\n};\n\nfunction formatValue(\n value: string | number,\n format?: (value: number) => string,\n): string {\n if (typeof value === \"number\") {\n return format ? format(value) : value.toLocaleString();\n }\n return value;\n}\n\nfunction StatCardComponent({\n label,\n labelNode,\n value,\n valueSuffix,\n hint,\n icon,\n tone = \"default\",\n trend,\n onClick,\n loading = false,\n ariaLabel,\n className = \"\",\n testId,\n format,\n animate = false,\n sparkline,\n emphasis = \"default\",\n}: StatCardProps): JSX.Element {\n const prefersReducedMotion = usePrefersReducedMotion();\n const isNumeric = typeof value === \"number\";\n const shouldAnimate = animate && isNumeric && !loading && !prefersReducedMotion;\n const animatedValue = useAnimatedValue(isNumeric ? value : 0, shouldAnimate);\n\n const displayValue = formatValue(\n isNumeric && shouldAnimate ? animatedValue : value,\n format,\n );\n\n // The aria-label always describes the settled value, never an in-flight\n // animation frame, so assistive tech is not read a counting-up number.\n const composedAriaLabel =\n ariaLabel ??\n (loading ? label : `${label}: ${formatValue(value, format)}${valueSuffix ?? \"\"}`);\n\n const rootClass = [\n \"stat-card\",\n \"corner-accent\",\n `stat-card--tone-${tone}`,\n emphasis !== \"default\" ? `stat-card--${emphasis}` : \"\",\n className,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <BaseCard\n className={rootClass}\n onClick={onClick}\n role={onClick ? undefined : \"group\"}\n ariaLabel={composedAriaLabel}\n testId={testId}\n >\n <div className=\"stat-card__header\">\n <span className=\"stat-card__label\">{labelNode ?? label}</span>\n {icon && (\n <span className=\"stat-card__icon\" aria-hidden=\"true\">\n {icon}\n </span>\n )}\n </div>\n\n <div className=\"stat-card__body\">\n {loading ? (\n <Skeleton width=\"60%\" height=\"2rem\" />\n ) : sparkline ? (\n // Only wrap when a sparkline is present, so cards without one keep\n // the exact DOM they had before the slot existed.\n <span className=\"stat-card__value-line\">\n <span className=\"stat-card__value-row\">\n <span className=\"stat-card__value\">{displayValue}</span>\n {valueSuffix && (\n <span className=\"stat-card__value-suffix\">{valueSuffix}</span>\n )}\n </span>\n <span className=\"stat-card__sparkline\">{sparkline}</span>\n </span>\n ) : (\n <span className=\"stat-card__value-row\">\n <span className=\"stat-card__value\">{displayValue}</span>\n {valueSuffix && (\n <span className=\"stat-card__value-suffix\">{valueSuffix}</span>\n )}\n </span>\n )}\n\n {trend && !loading && (\n <span\n className={`stat-card__trend stat-card__trend--${trend.direction}`}\n aria-label={trend.ariaLabel ?? trend.label}\n >\n <span aria-hidden=\"true\">{TREND_GLYPH[trend.direction]}</span>\n <span>{trend.label}</span>\n </span>\n )}\n </div>\n\n {hint !== undefined && hint !== null && (\n <div className=\"stat-card__hint\">\n {loading ? <Skeleton width=\"80%\" height=\"0.85rem\" /> : hint}\n </div>\n )}\n </BaseCard>\n );\n}\n\nexport const StatCard = memo(StatCardComponent);\n"],"mappings":";;;;;;;AAwFA,IAAM,IAAwB;AAO9B,SAAS,EAAiB,GAAgB,GAA0B;CAClE,IAAM,CAAC,GAAc,KAAmB,EAAS,IAAU,IAAI,CAAM,GAC/D,IAAgB,EAAO,IAAU,IAAI,CAAM,GAC3C,IAAW,EAAsB,IAAI;CAiC3C,OA/BA,QAAgB;EACd,IAAI,CAAC,GAAS;GAEZ,AADA,EAAc,UAAU,GACxB,EAAgB,CAAM;GACtB;EACF;EAEA,IAAM,IAAa,EAAc,SAC3B,IAAY,YAAY,IAAI,GAE5B,KAAQ,MAAsB;GAClC,IAAM,IAAW,KAAK,KAAK,IAAM,KAAa,GAAuB,CAAC,GAChE,IAAQ,KAAa,IAAI,MAAU;GAGzC,AAFA,EAAgB,KAAK,MAAM,KAAc,IAAS,KAAc,CAAK,CAAC,GAElE,IAAW,IACb,EAAS,UAAU,sBAAsB,CAAI,IAE7C,EAAc,UAAU;EAE5B;EAIA,OAFA,EAAS,UAAU,sBAAsB,CAAI,SAEhC;GACX,AAAI,EAAS,YAAY,QACvB,qBAAqB,EAAS,OAAO;EAEzC;CACF,GAAG,CAAC,GAAQ,CAAO,CAAC,GAEb,IAAU,IAAe;AAClC;AAEA,IAAM,IAAsD;CAC1D,IAAI;CACJ,MAAM;CACN,MAAM;AACR;AAEA,SAAS,EACP,GACA,GACQ;CAIR,OAHI,OAAO,KAAU,WACZ,IAAS,EAAO,CAAK,IAAI,EAAM,eAAe,IAEhD;AACT;AAEA,SAAS,EAAkB,EACzB,UACA,cACA,UACA,gBACA,SACA,SACA,UAAO,WACP,UACA,YACA,aAAU,IACV,cACA,eAAY,IACZ,WACA,WACA,aAAU,IACV,cACA,cAAW,aACkB;CAC7B,IAAM,IAAuB,EAAwB,GAC/C,IAAY,OAAO,KAAU,UAC7B,IAAgB,KAAW,KAAa,CAAC,KAAW,CAAC,GACrD,IAAgB,EAAiB,IAAY,IAAQ,GAAG,CAAa,GAErE,IAAe,EACnB,KAAa,IAAgB,IAAgB,GAC7C,CACF,GAIM,IACJ,MACC,IAAU,IAAQ,GAAG,EAAM,IAAI,EAAY,GAAO,CAAM,IAAI,KAAe,OAExE,IAAY;EAChB;EACA;EACA,mBAAmB;EACnB,MAAa,YAAuC,KAA3B,cAAc;EACvC;CACF,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,GAAD;EACE,WAAW;EACF;EACT,MAAM,IAAU,KAAA,IAAY;EAC5B,WAAW;EACH;EALV,UAAA;GAOE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,QAAD;KAAM,WAAU;KAAoB,UAAA,KAAa;IAAY,CAAA,GAC5D,KACC,kBAAC,QAAD;KAAM,WAAU;KAAkB,eAAY;KAC3C,UAAA;IACG,CAAA,CAEL;;GAEL,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,IACC,kBAAC,GAAD;KAAU,OAAM;KAAM,QAAO;IAAQ,CAAA,IACnC,IAGF,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACE,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA,CACE,kBAAC,QAAD;OAAM,WAAU;OAAoB,UAAA;MAAmB,CAAA,GACtD,KACC,kBAAC,QAAD;OAAM,WAAU;OAA2B,UAAA;MAAkB,CAAA,CAE3D;KACN,CAAA,GAAA,kBAAC,QAAD;MAAM,WAAU;MAAwB,UAAA;KAAgB,CAAA,CACpD;IAEN,CAAA,IAAA,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACE,kBAAC,QAAD;MAAM,WAAU;MAAoB,UAAA;KAAmB,CAAA,GACtD,KACC,kBAAC,QAAD;MAAM,WAAU;MAA2B,UAAA;KAAkB,CAAA,CAE3D;IAGP,CAAA,GAAA,KAAS,CAAC,KACT,kBAAC,QAAD;KACE,WAAW,sCAAsC,EAAM;KACvD,cAAY,EAAM,aAAa,EAAM;KAFvC,UAAA,CAIE,kBAAC,QAAD;MAAM,eAAY;MAAQ,UAAA,EAAY,EAAM;KAAiB,CAAA,GAC7D,kBAAC,QAAD,EAAA,UAAO,EAAM,MAAY,CAAA,CACrB;IAEL,CAAA,CAAA;;GAEJ,KAA+B,QAC9B,kBAAC,OAAD;IAAK,WAAU;IACZ,UAAA,IAAU,kBAAC,GAAD;KAAU,OAAM;KAAM,QAAO;IAAW,CAAA,IAAI;GACpD,CAAA;EAEC;;AAEd;AAEA,IAAa,IAAW,EAAK,CAAiB"}
@@ -1,26 +1,18 @@
1
1
  import { ReactNode } from 'react';
2
- import { TabTagType, TabTagLabels } from './tabTags';
3
- export type { TabTagType, TabTagLabels } from './tabTags';
4
- export { TAG_CONFIG } from './tabTags';
5
2
  export interface TabItem {
6
3
  id: string;
7
4
  label: string;
8
5
  content: ReactNode;
9
6
  /**
10
- * Show a "Required" badge next to the tab label.
11
- * @deprecated Use `tag="required"` instead. Kept for backward compatibility.
12
- */
13
- required?: boolean;
14
- /**
15
- * Guide tag displayed after the tab label as a small badge.
16
- * When set, takes precedence over the `required` boolean.
17
- */
18
- tag?: TabTagType;
19
- /**
20
- * Optional extra trailing node rendered next to the tab label (e.g. a
21
- * count badge). Distinct from `tag` (which uses a fixed preset). Use this
22
- * when migrating segmented controls that rendered their own inline count
23
- * pill alongside the label.
7
+ * Trailing node rendered next to the tab label: a count pill, a status
8
+ * badge, whatever the consumer's vocabulary calls for.
9
+ *
10
+ * This used to sit beside a `tag` prop that took one of four fixed names,
11
+ * required / recommended / beta / experimental, and rendered a Badge for
12
+ * it. Those are one product's guide vocabulary, and the arrangement had
13
+ * already split across the boundary: the badge variant lived here while the
14
+ * label text had to be passed in from the consumer's locale bundle. A
15
+ * consumer that wants that badge renders it here, and owns both halves.
24
16
  */
25
17
  labelExtra?: ReactNode;
26
18
  /**
@@ -98,10 +90,5 @@ export interface TabsProps {
98
90
  scrollLeftLabel?: string;
99
91
  /** Accessible label for the right scroll-arrow button. Default: "Scroll right" */
100
92
  scrollRightLabel?: string;
101
- /**
102
- * English defaults for every guide-tag badge label (required / recommended
103
- * / beta / experimental). Override individual entries to translate them.
104
- */
105
- tagLabels?: TabTagLabels;
106
93
  }
107
- export declare function Tabs({ tabs, groups, defaultTab, activeTab: controlledTab, onTabChange, className, panelClassName, ariaLabel, showOverflowControls, showGroupLabels, overflowMode: explicitOverflowMode, variant, fillContainer, renderPanel, moreTabsLabel, selectTabLabel, scrollLeftLabel, scrollRightLabel, tagLabels, }: TabsProps): import("react").JSX.Element;
94
+ export declare function Tabs({ tabs, groups, defaultTab, activeTab: controlledTab, onTabChange, className, panelClassName, ariaLabel, showOverflowControls, showGroupLabels, overflowMode: explicitOverflowMode, variant, fillContainer, renderPanel, moreTabsLabel, selectTabLabel, scrollLeftLabel, scrollRightLabel, }: TabsProps): import("react").JSX.Element;