@lablup/ui-common 0.1.0-alpha.0

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 (148) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +10 -0
  3. package/README.md +145 -0
  4. package/dist/assets/components/Badge/Badge.css +1 -0
  5. package/dist/assets/components/BaseCard/BaseCard.css +1 -0
  6. package/dist/assets/components/Button/Button.css +1 -0
  7. package/dist/assets/components/DataTable/DataTable.css +1 -0
  8. package/dist/assets/components/Drawer/Drawer.css +1 -0
  9. package/dist/assets/components/EmptyState/EmptyState.css +1 -0
  10. package/dist/assets/components/ErrorState/ErrorState.css +1 -0
  11. package/dist/assets/components/PageHeader/PageHeader.css +1 -0
  12. package/dist/assets/components/PageLayout/PageLayout.css +1 -0
  13. package/dist/assets/components/ProgressBar/ProgressBar.css +1 -0
  14. package/dist/assets/components/Skeleton/Skeleton.css +1 -0
  15. package/dist/assets/components/Skeleton/SkeletonCard.css +1 -0
  16. package/dist/assets/components/Skeleton/SkeletonChart.css +1 -0
  17. package/dist/assets/components/Skeleton/SkeletonRow.css +1 -0
  18. package/dist/assets/components/Skeleton/SkeletonText.css +1 -0
  19. package/dist/assets/components/SmoothHeight/SmoothHeight.css +1 -0
  20. package/dist/assets/components/StatCard/StatCard.css +1 -0
  21. package/dist/assets/components/StatusTag/StatusTag.css +1 -0
  22. package/dist/assets/components/Tabs/Tabs.css +1 -0
  23. package/dist/assets/components/Tooltip/Tooltip.css +1 -0
  24. package/dist/components/Badge/Badge.d.ts +7 -0
  25. package/dist/components/Badge/Badge2.js +19 -0
  26. package/dist/components/Badge/Badge2.js.map +1 -0
  27. package/dist/components/Badge/index.d.ts +2 -0
  28. package/dist/components/Badge/index.js +2 -0
  29. package/dist/components/BaseCard/BaseCard.d.ts +57 -0
  30. package/dist/components/BaseCard/BaseCard2.js +36 -0
  31. package/dist/components/BaseCard/BaseCard2.js.map +1 -0
  32. package/dist/components/BaseCard/index.d.ts +2 -0
  33. package/dist/components/BaseCard/index.js +2 -0
  34. package/dist/components/Button/Button.d.ts +54 -0
  35. package/dist/components/Button/Button2.js +74 -0
  36. package/dist/components/Button/Button2.js.map +1 -0
  37. package/dist/components/Button/index.d.ts +5 -0
  38. package/dist/components/Button/index.js +2 -0
  39. package/dist/components/DataTable/DataTable.d.ts +133 -0
  40. package/dist/components/DataTable/DataTable2.js +276 -0
  41. package/dist/components/DataTable/DataTable2.js.map +1 -0
  42. package/dist/components/DataTable/index.d.ts +2 -0
  43. package/dist/components/DataTable/index.js +2 -0
  44. package/dist/components/Drawer/Drawer.d.ts +25 -0
  45. package/dist/components/Drawer/Drawer2.js +106 -0
  46. package/dist/components/Drawer/Drawer2.js.map +1 -0
  47. package/dist/components/Drawer/index.d.ts +2 -0
  48. package/dist/components/Drawer/index.js +2 -0
  49. package/dist/components/EmptyState/EmptyState.d.ts +45 -0
  50. package/dist/components/EmptyState/EmptyState.example.d.ts +8 -0
  51. package/dist/components/EmptyState/EmptyState2.js +78 -0
  52. package/dist/components/EmptyState/EmptyState2.js.map +1 -0
  53. package/dist/components/EmptyState/illustrations.d.ts +51 -0
  54. package/dist/components/EmptyState/illustrations.js +571 -0
  55. package/dist/components/EmptyState/illustrations.js.map +1 -0
  56. package/dist/components/EmptyState/index.d.ts +5 -0
  57. package/dist/components/EmptyState/index.js +2 -0
  58. package/dist/components/ErrorState/ErrorState.d.ts +25 -0
  59. package/dist/components/ErrorState/ErrorState.example.d.ts +46 -0
  60. package/dist/components/ErrorState/ErrorState2.js +58 -0
  61. package/dist/components/ErrorState/ErrorState2.js.map +1 -0
  62. package/dist/components/ErrorState/index.d.ts +5 -0
  63. package/dist/components/ErrorState/index.js +2 -0
  64. package/dist/components/PageHeader/PageHeader.d.ts +18 -0
  65. package/dist/components/PageHeader/PageHeader2.js +42 -0
  66. package/dist/components/PageHeader/PageHeader2.js.map +1 -0
  67. package/dist/components/PageHeader/index.d.ts +2 -0
  68. package/dist/components/PageHeader/index.js +2 -0
  69. package/dist/components/PageLayout/PageLayout.d.ts +11 -0
  70. package/dist/components/PageLayout/PageLayout2.js +19 -0
  71. package/dist/components/PageLayout/PageLayout2.js.map +1 -0
  72. package/dist/components/PageLayout/index.d.ts +2 -0
  73. package/dist/components/PageLayout/index.js +2 -0
  74. package/dist/components/ProgressBar/ProgressBar.d.ts +22 -0
  75. package/dist/components/ProgressBar/ProgressBar2.js +36 -0
  76. package/dist/components/ProgressBar/ProgressBar2.js.map +1 -0
  77. package/dist/components/ProgressBar/index.d.ts +2 -0
  78. package/dist/components/ProgressBar/index.js +2 -0
  79. package/dist/components/Skeleton/Skeleton.d.ts +25 -0
  80. package/dist/components/Skeleton/Skeleton2.js +26 -0
  81. package/dist/components/Skeleton/Skeleton2.js.map +1 -0
  82. package/dist/components/Skeleton/SkeletonCard.d.ts +18 -0
  83. package/dist/components/Skeleton/SkeletonCard2.js +73 -0
  84. package/dist/components/Skeleton/SkeletonCard2.js.map +1 -0
  85. package/dist/components/Skeleton/SkeletonChart.d.ts +23 -0
  86. package/dist/components/Skeleton/SkeletonChart2.js +66 -0
  87. package/dist/components/Skeleton/SkeletonChart2.js.map +1 -0
  88. package/dist/components/Skeleton/SkeletonRow.d.ts +22 -0
  89. package/dist/components/Skeleton/SkeletonRow2.js +47 -0
  90. package/dist/components/Skeleton/SkeletonRow2.js.map +1 -0
  91. package/dist/components/Skeleton/SkeletonText.d.ts +20 -0
  92. package/dist/components/Skeleton/SkeletonText2.js +26 -0
  93. package/dist/components/Skeleton/SkeletonText2.js.map +1 -0
  94. package/dist/components/Skeleton/index.d.ts +15 -0
  95. package/dist/components/Skeleton/index.js +6 -0
  96. package/dist/components/SmoothHeight/SmoothHeight.d.ts +9 -0
  97. package/dist/components/SmoothHeight/SmoothHeight2.js +38 -0
  98. package/dist/components/SmoothHeight/SmoothHeight2.js.map +1 -0
  99. package/dist/components/SmoothHeight/index.d.ts +2 -0
  100. package/dist/components/SmoothHeight/index.js +2 -0
  101. package/dist/components/StatCard/StatCard.d.ts +59 -0
  102. package/dist/components/StatCard/StatCard2.js +111 -0
  103. package/dist/components/StatCard/StatCard2.js.map +1 -0
  104. package/dist/components/StatCard/formatters.d.ts +12 -0
  105. package/dist/components/StatCard/formatters.js +8 -0
  106. package/dist/components/StatCard/formatters.js.map +1 -0
  107. package/dist/components/StatCard/index.d.ts +3 -0
  108. package/dist/components/StatCard/index.js +3 -0
  109. package/dist/components/StatusTag/StatusTag.d.ts +38 -0
  110. package/dist/components/StatusTag/StatusTag2.js +44 -0
  111. package/dist/components/StatusTag/StatusTag2.js.map +1 -0
  112. package/dist/components/StatusTag/index.d.ts +2 -0
  113. package/dist/components/StatusTag/index.js +2 -0
  114. package/dist/components/Tabs/Tabs.d.ts +107 -0
  115. package/dist/components/Tabs/Tabs2.js +430 -0
  116. package/dist/components/Tabs/Tabs2.js.map +1 -0
  117. package/dist/components/Tabs/index.d.ts +2 -0
  118. package/dist/components/Tabs/index.js +3 -0
  119. package/dist/components/Tabs/tabTags.d.ts +9 -0
  120. package/dist/components/Tabs/tabTags.js +11 -0
  121. package/dist/components/Tabs/tabTags.js.map +1 -0
  122. package/dist/components/Tooltip/Tooltip.d.ts +16 -0
  123. package/dist/components/Tooltip/Tooltip2.js +67 -0
  124. package/dist/components/Tooltip/Tooltip2.js.map +1 -0
  125. package/dist/components/Tooltip/index.d.ts +2 -0
  126. package/dist/components/Tooltip/index.js +2 -0
  127. package/dist/hooks/index.d.ts +1 -0
  128. package/dist/hooks/index.js +2 -0
  129. package/dist/hooks/usePrefersReducedMotion.d.ts +12 -0
  130. package/dist/hooks/usePrefersReducedMotion.js +22 -0
  131. package/dist/hooks/usePrefersReducedMotion.js.map +1 -0
  132. package/dist/icons/AlertCircleIcon.d.ts +11 -0
  133. package/dist/icons/AlertCircleIcon.js +26 -0
  134. package/dist/icons/AlertCircleIcon.js.map +1 -0
  135. package/dist/index.d.ts +29 -0
  136. package/dist/index.js +24 -0
  137. package/dist/styles/base.css +169 -0
  138. package/dist/styles/themes/bliss-dark.css +123 -0
  139. package/dist/styles/themes/bliss-light.css +123 -0
  140. package/dist/styles/themes/glass-dark.css +124 -0
  141. package/dist/styles/themes/glass-light.css +125 -0
  142. package/dist/styles/themes/orange-dark.css +70 -0
  143. package/dist/styles/themes/orange-light.css +70 -0
  144. package/dist/styles/themes/reverie-dark.css +104 -0
  145. package/dist/styles/themes/reverie-light.css +104 -0
  146. package/dist/styles/themes/stained-dark.css +80 -0
  147. package/dist/styles/themes/stained-light.css +80 -0
  148. package/package.json +87 -0
@@ -0,0 +1,66 @@
1
+ import { Skeleton as e } from "./Skeleton2.js";
2
+ /* empty css */
3
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
4
+ //#region src/components/Skeleton/SkeletonChart.tsx
5
+ function r({ variant: r = "bar", height: i = "300px", className: a = "", testId: o, loadingLabel: s = "Loading chart" }) {
6
+ let c = [
7
+ "skeleton-chart",
8
+ `skeleton-chart--${r}`,
9
+ a
10
+ ].filter(Boolean).join(" ");
11
+ return /* @__PURE__ */ t("div", {
12
+ className: c,
13
+ style: { height: i },
14
+ "data-testid": o,
15
+ role: "status",
16
+ "aria-busy": "true",
17
+ "aria-label": s,
18
+ children: r === "pie" ? /* @__PURE__ */ n("div", {
19
+ className: "skeleton-chart__pie",
20
+ children: [/* @__PURE__ */ t(e, {
21
+ width: "100%",
22
+ height: "100%",
23
+ variant: "circle"
24
+ }), /* @__PURE__ */ t("div", {
25
+ className: "skeleton-chart__legend",
26
+ children: Array.from({ length: 4 }).map((r, i) => /* @__PURE__ */ n("div", {
27
+ className: "skeleton-chart__legend-item",
28
+ children: [/* @__PURE__ */ t(e, {
29
+ width: "16px",
30
+ height: "16px",
31
+ variant: "circle"
32
+ }), /* @__PURE__ */ t(e, {
33
+ width: "80px",
34
+ height: "14px"
35
+ })]
36
+ }, i))
37
+ })]
38
+ }) : r === "bar" ? /* @__PURE__ */ t("div", {
39
+ className: "skeleton-chart__bars",
40
+ children: [
41
+ 60,
42
+ 80,
43
+ 45,
44
+ 90,
45
+ 70,
46
+ 55,
47
+ 85,
48
+ 65
49
+ ].map((n, r) => /* @__PURE__ */ t(e, {
50
+ width: "100%",
51
+ height: `${String(n)}%`,
52
+ className: "skeleton-chart__bar"
53
+ }, r))
54
+ }) : /* @__PURE__ */ t("div", {
55
+ className: "skeleton-chart__line",
56
+ children: /* @__PURE__ */ t(e, {
57
+ width: "100%",
58
+ height: "100%"
59
+ })
60
+ })
61
+ });
62
+ }
63
+ //#endregion
64
+ export { r as SkeletonChart, r as default };
65
+
66
+ //# sourceMappingURL=SkeletonChart2.js.map
@@ -0,0 +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"}
@@ -0,0 +1,22 @@
1
+ export interface SkeletonRowProps {
2
+ /** Show avatar/icon on the left */
3
+ showAvatar?: boolean;
4
+ /** Show action buttons on the right */
5
+ showActions?: boolean;
6
+ /** Number of rows to display */
7
+ count?: number;
8
+ /** Additional CSS class names */
9
+ className?: string;
10
+ /** Test ID for testing */
11
+ testId?: string;
12
+ }
13
+ /**
14
+ * SkeletonRow provides a loading placeholder for list/table rows.
15
+ *
16
+ * Features:
17
+ * - Optional avatar/icon
18
+ * - Optional action buttons
19
+ * - Multiple rows for lists
20
+ */
21
+ export declare function SkeletonRow({ showAvatar, showActions, count, className, testId, }: SkeletonRowProps): import("react").JSX.Element;
22
+ export default SkeletonRow;
@@ -0,0 +1,47 @@
1
+ import { Skeleton as e } from "./Skeleton2.js";
2
+ /* empty css */
3
+ import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
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", {
8
+ className: `skeleton-row ${s}`,
9
+ "data-testid": c ? `${c}-${String(o)}` : void 0,
10
+ role: "status",
11
+ "aria-busy": "true",
12
+ children: [
13
+ i && /* @__PURE__ */ n("div", {
14
+ className: "skeleton-row__avatar",
15
+ children: /* @__PURE__ */ n(e, {
16
+ width: "40px",
17
+ height: "40px",
18
+ variant: "circle"
19
+ })
20
+ }),
21
+ /* @__PURE__ */ r("div", {
22
+ className: "skeleton-row__content",
23
+ children: [/* @__PURE__ */ n(e, {
24
+ width: "25%",
25
+ height: "14px"
26
+ }), /* @__PURE__ */ n(e, {
27
+ width: "100%",
28
+ height: "16px"
29
+ })]
30
+ }),
31
+ a && /* @__PURE__ */ r("div", {
32
+ className: "skeleton-row__actions",
33
+ children: [/* @__PURE__ */ n(e, {
34
+ width: "32px",
35
+ height: "32px"
36
+ }), /* @__PURE__ */ n(e, {
37
+ width: "32px",
38
+ height: "32px"
39
+ })]
40
+ })
41
+ ]
42
+ }, o)) });
43
+ }
44
+ //#endregion
45
+ export { i as SkeletonRow, i as default };
46
+
47
+ //# sourceMappingURL=SkeletonRow2.js.map
@@ -0,0 +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"}
@@ -0,0 +1,20 @@
1
+ export interface SkeletonTextProps {
2
+ /** Number of text lines to display */
3
+ lines?: number;
4
+ /** Spacing between lines */
5
+ spacing?: "compact" | "normal" | "relaxed";
6
+ /** Additional CSS class names */
7
+ className?: string;
8
+ /** Test ID for testing */
9
+ testId?: string;
10
+ }
11
+ /**
12
+ * SkeletonText provides a loading placeholder for text content.
13
+ *
14
+ * Features:
15
+ * - Multiple lines with varying widths
16
+ * - Configurable line spacing
17
+ * - Accessible via aria-busy
18
+ */
19
+ export declare function SkeletonText({ lines, spacing, className, testId, }: SkeletonTextProps): import("react").JSX.Element;
20
+ export default SkeletonText;
@@ -0,0 +1,26 @@
1
+ import { Skeleton as e } from "./Skeleton2.js";
2
+ /* empty css */
3
+ import { jsx as t } from "react/jsx-runtime";
4
+ //#region src/components/Skeleton/SkeletonText.tsx
5
+ function n({ lines: n = 3, spacing: r = "normal", className: i = "", testId: a }) {
6
+ let o = [
7
+ "skeleton-text",
8
+ `skeleton-text--${r}`,
9
+ i
10
+ ].filter(Boolean).join(" "), s = Array.from({ length: n }, (e, t) => t === n - 1 ? "60%" : t % 2 == 0 ? "100%" : "95%");
11
+ return /* @__PURE__ */ t("div", {
12
+ className: o,
13
+ "data-testid": a,
14
+ role: "status",
15
+ "aria-busy": "true",
16
+ children: s.map((n, r) => /* @__PURE__ */ t(e, {
17
+ width: n,
18
+ height: "1em",
19
+ variant: "text"
20
+ }, r))
21
+ });
22
+ }
23
+ //#endregion
24
+ export { n as SkeletonText, n as default };
25
+
26
+ //# sourceMappingURL=SkeletonText2.js.map
@@ -0,0 +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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Skeleton Components
3
+ *
4
+ * Loading state components with shimmer animations.
5
+ */
6
+ export { Skeleton } from './Skeleton';
7
+ export type { SkeletonProps } from './Skeleton';
8
+ export { SkeletonCard } from './SkeletonCard';
9
+ export type { SkeletonCardProps } from './SkeletonCard';
10
+ export { SkeletonText } from './SkeletonText';
11
+ export type { SkeletonTextProps } from './SkeletonText';
12
+ export { SkeletonChart } from './SkeletonChart';
13
+ export type { SkeletonChartProps } from './SkeletonChart';
14
+ export { SkeletonRow } from './SkeletonRow';
15
+ export type { SkeletonRowProps } from './SkeletonRow';
@@ -0,0 +1,6 @@
1
+ import { Skeleton as e } from "./Skeleton2.js";
2
+ import { SkeletonCard as t } from "./SkeletonCard2.js";
3
+ import { SkeletonText as n } from "./SkeletonText2.js";
4
+ import { SkeletonChart as r } from "./SkeletonChart2.js";
5
+ import { SkeletonRow as i } from "./SkeletonRow2.js";
6
+ export { e as Skeleton, t as SkeletonCard, r as SkeletonChart, i as SkeletonRow, n as SkeletonText };
@@ -0,0 +1,9 @@
1
+ import { ReactNode } from 'react';
2
+ export interface SmoothHeightProps {
3
+ /** Whether height changes should currently be animated */
4
+ active: boolean;
5
+ children: ReactNode;
6
+ /** Additional class for the outer wrapper */
7
+ className?: string;
8
+ }
9
+ export declare function SmoothHeight({ active, children, className }: SmoothHeightProps): import("react").JSX.Element;
@@ -0,0 +1,38 @@
1
+ /* empty css */
2
+ import { useLayoutEffect as e, useRef as t } from "react";
3
+ import { jsx as n } from "react/jsx-runtime";
4
+ //#region src/components/SmoothHeight/SmoothHeight.tsx
5
+ var r = 250;
6
+ function i({ active: i, children: a, className: o }) {
7
+ let s = t(null), c = t(null), l = t(null);
8
+ return e(() => {
9
+ let e = s.current, t = c.current;
10
+ if (!e || !t || typeof ResizeObserver > "u") return;
11
+ if (!i) return l.current = window.setTimeout(() => {
12
+ e.style.height = "", l.current = null;
13
+ }, r), () => {
14
+ l.current !== null && (window.clearTimeout(l.current), l.current = null);
15
+ };
16
+ l.current !== null && (window.clearTimeout(l.current), l.current = null);
17
+ let n = () => {
18
+ e.style.height = `${t.offsetHeight.toFixed(0)}px`;
19
+ };
20
+ n();
21
+ let a = new ResizeObserver(n);
22
+ return a.observe(t), () => {
23
+ a.disconnect();
24
+ };
25
+ }, [i]), /* @__PURE__ */ n("div", {
26
+ ref: s,
27
+ className: `smooth-height${i ? " smooth-height--active" : ""}${o ? ` ${o}` : ""}`,
28
+ children: /* @__PURE__ */ n("div", {
29
+ ref: c,
30
+ className: "smooth-height__content",
31
+ children: a
32
+ })
33
+ });
34
+ }
35
+ //#endregion
36
+ export { i as SmoothHeight };
37
+
38
+ //# sourceMappingURL=SmoothHeight2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmoothHeight2.js","names":[],"sources":["../../../src/components/SmoothHeight/SmoothHeight.tsx"],"sourcesContent":["/**\n * SmoothHeight Component\n *\n * Animates a container's height toward its content's natural height, so\n * content that grows in discrete jumps (streaming text wrapping onto new\n * lines) expands smoothly instead of snapping one line at a time.\n *\n * While `active`, the inner content is measured with a ResizeObserver and\n * the outer wrapper gets an explicit pixel height with a CSS height\n * transition. CSS cannot transition to `height: auto` (and the\n * `interpolate-size` opt-in is not available in WebKit), so the explicit\n * measurement is what makes the animation possible cross-platform.\n *\n * The very first activation does not animate: the wrapper goes from\n * `auto` to a pixel height, which CSS treats as non-interpolable and\n * applies instantly. Only subsequent pixel-to-pixel growth animates.\n *\n * When `active` turns off, the pixel height is kept just long enough for\n * the in-flight transition to settle, then released back to `auto` so\n * later reflows (window resizing, images loading) are unaffected.\n *\n * Degrades gracefully: without ResizeObserver (test environments), it\n * renders plain pass-through wrappers with auto height.\n */\n\nimport { useLayoutEffect, useRef, type ReactNode } from \"react\";\nimport \"./SmoothHeight.css\";\n\nexport interface SmoothHeightProps {\n /** Whether height changes should currently be animated */\n active: boolean;\n children: ReactNode;\n /** Additional class for the outer wrapper */\n className?: string;\n}\n\n/**\n * Delay before releasing the explicit height after deactivation, covering\n * the height transition duration (--token-motionDurationMid = 0.2s).\n */\nconst RELEASE_DELAY_MS = 250;\n\nexport function SmoothHeight({ active, children, className }: SmoothHeightProps) {\n const outerRef = useRef<HTMLDivElement>(null);\n const innerRef = useRef<HTMLDivElement>(null);\n const releaseTimerRef = useRef<number | null>(null);\n\n useLayoutEffect(() => {\n const outer = outerRef.current;\n const inner = innerRef.current;\n if (!outer || !inner) return;\n if (typeof ResizeObserver === \"undefined\") return;\n\n if (!active) {\n // Keep the last pixel height while the in-flight transition\n // settles, then release to auto.\n releaseTimerRef.current = window.setTimeout(() => {\n outer.style.height = \"\";\n releaseTimerRef.current = null;\n }, RELEASE_DELAY_MS);\n return () => {\n if (releaseTimerRef.current !== null) {\n window.clearTimeout(releaseTimerRef.current);\n releaseTimerRef.current = null;\n }\n };\n }\n\n // (Re)activated: cancel any pending release and track the content.\n if (releaseTimerRef.current !== null) {\n window.clearTimeout(releaseTimerRef.current);\n releaseTimerRef.current = null;\n }\n\n const measure = () => {\n outer.style.height = `${inner.offsetHeight.toFixed(0)}px`;\n };\n measure();\n\n const observer = new ResizeObserver(measure);\n observer.observe(inner);\n return () => {\n observer.disconnect();\n };\n }, [active]);\n\n return (\n <div\n ref={outerRef}\n className={`smooth-height${active ? \" smooth-height--active\" : \"\"}${className ? ` ${className}` : \"\"}`}\n >\n <div ref={innerRef} className=\"smooth-height__content\">\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;AAwCA,IAAM,IAAmB;AAEzB,SAAgB,EAAa,EAAE,WAAQ,aAAU,gBAAgC;CAC/E,IAAM,IAAW,EAAuB,IAAI,GACtC,IAAW,EAAuB,IAAI,GACtC,IAAkB,EAAsB,IAAI;CAyClD,OAvCA,QAAsB;EACpB,IAAM,IAAQ,EAAS,SACjB,IAAQ,EAAS;EAEvB,IADI,CAAC,KAAS,CAAC,KACX,OAAO,iBAAmB,KAAa;EAE3C,IAAI,CAAC,GAOH,OAJA,EAAgB,UAAU,OAAO,iBAAiB;GAEhD,AADA,EAAM,MAAM,SAAS,IACrB,EAAgB,UAAU;EAC5B,GAAG,CAAgB,SACN;GACX,AAAI,EAAgB,YAAY,SAC9B,OAAO,aAAa,EAAgB,OAAO,GAC3C,EAAgB,UAAU;EAE9B;EAIF,AAAI,EAAgB,YAAY,SAC9B,OAAO,aAAa,EAAgB,OAAO,GAC3C,EAAgB,UAAU;EAG5B,IAAM,UAAgB;GACpB,EAAM,MAAM,SAAS,GAAG,EAAM,aAAa,QAAQ,CAAC,EAAE;EACxD;EACA,EAAQ;EAER,IAAM,IAAW,IAAI,eAAe,CAAO;EAE3C,OADA,EAAS,QAAQ,CAAK,SACT;GACX,EAAS,WAAW;EACtB;CACF,GAAG,CAAC,CAAM,CAAC,GAGT,kBAAC,OAAD;EACE,KAAK;EACL,WAAW,gBAAgB,IAAS,2BAA2B,KAAK,IAAY,IAAI,MAAc;EAElG,UAAA,kBAAC,OAAD;GAAK,KAAK;GAAU,WAAU;GAC3B;EACE,CAAA;CACF,CAAA;AAET"}
@@ -0,0 +1,2 @@
1
+ export { SmoothHeight } from './SmoothHeight';
2
+ export type { SmoothHeightProps } from './SmoothHeight';
@@ -0,0 +1,2 @@
1
+ import { SmoothHeight as e } from "./SmoothHeight2.js";
2
+ export { e as SmoothHeight };
@@ -0,0 +1,59 @@
1
+ import { ReactNode, JSX } from 'react';
2
+ export type StatCardEmphasis = "compact" | "default" | "prominent";
3
+ export type StatCardTone = "default" | "success" | "warning" | "danger" | "info";
4
+ export type StatCardTrendDirection = "up" | "down" | "flat";
5
+ export interface StatCardTrend {
6
+ /** Direction indicator (up / down / flat) */
7
+ direction: StatCardTrendDirection;
8
+ /** Human-readable delta label (e.g. "+12%", "-3", "0") */
9
+ label: string;
10
+ /** Optional ARIA description for screen readers */
11
+ ariaLabel?: string;
12
+ }
13
+ export interface StatCardProps {
14
+ /** Short label rendered above the value (UPPERCASE styled) */
15
+ label: string;
16
+ /** Primary metric value (number is coerced to localised string) */
17
+ value: string | number;
18
+ /** Optional suffix appended to the value (e.g. "/ 4", "GB") */
19
+ valueSuffix?: string;
20
+ /** Optional helper line under the value (e.g. context, secondary metric) */
21
+ hint?: ReactNode;
22
+ /** Optional leading icon node, rendered inside an accent badge */
23
+ icon?: ReactNode;
24
+ /** Visual tone, mirrors Badge variants. Default: "default" */
25
+ tone?: StatCardTone;
26
+ /** Optional trend indicator under the value */
27
+ trend?: StatCardTrend;
28
+ /** Click handler. Renders the card as keyboard-accessible button. */
29
+ onClick?: () => void;
30
+ /** Render skeletons instead of value/label content while loading */
31
+ loading?: boolean;
32
+ /** Optional aria label override (defaults to label + value) */
33
+ ariaLabel?: string;
34
+ /** Extra class name applied to the root */
35
+ className?: string;
36
+ /** Test id for unit tests */
37
+ testId?: string;
38
+ /**
39
+ * Formatter for numeric values (e.g. abbreviate to "1.2K", append "%").
40
+ * Defaults to `toLocaleString`. Ignored when `value` is a string.
41
+ */
42
+ format?: (value: number) => string;
43
+ /**
44
+ * Count up to a numeric value on mount and on change. Off by default so
45
+ * existing consumers render the final value immediately; opt in for
46
+ * dashboard hero metrics. Suppressed under `prefers-reduced-motion`.
47
+ */
48
+ animate?: boolean;
49
+ /**
50
+ * Optional trailing visual on the value line (e.g. a sparkline). Kept as a
51
+ * slot so the card does not depend on any particular chart component.
52
+ */
53
+ sparkline?: ReactNode;
54
+ /** Visual weight. Default: "default" */
55
+ emphasis?: StatCardEmphasis;
56
+ }
57
+ declare function StatCardComponent({ label, value, valueSuffix, hint, icon, tone, trend, onClick, loading, ariaLabel, className, testId, format, animate, sparkline, emphasis, }: StatCardProps): JSX.Element;
58
+ export declare const StatCard: import('react').MemoExoticComponent<typeof StatCardComponent>;
59
+ export {};
@@ -0,0 +1,111 @@
1
+ import { BaseCard as e } from "../BaseCard/BaseCard2.js";
2
+ import { Skeleton as t } from "../Skeleton/Skeleton2.js";
3
+ import { usePrefersReducedMotion as n } from "../../hooks/usePrefersReducedMotion.js";
4
+ /* empty css */
5
+ import { memo as r, useEffect as i, useRef as a, useState as o } from "react";
6
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
7
+ //#region src/components/StatCard/StatCard.tsx
8
+ var l = 800;
9
+ function u(e, t) {
10
+ let [n, r] = o(t ? 0 : e), s = a(t ? 0 : e), c = a(null);
11
+ return i(() => {
12
+ if (!t) {
13
+ s.current = e, r(e);
14
+ return;
15
+ }
16
+ let n = s.current, i = performance.now(), a = (t) => {
17
+ let o = Math.min((t - i) / l, 1), u = 1 - (1 - o) ** 3;
18
+ r(Math.round(n + (e - n) * u)), o < 1 ? c.current = requestAnimationFrame(a) : s.current = e;
19
+ };
20
+ return c.current = requestAnimationFrame(a), () => {
21
+ c.current !== null && cancelAnimationFrame(c.current);
22
+ };
23
+ }, [e, t]), t ? n : e;
24
+ }
25
+ var d = {
26
+ up: "▲",
27
+ down: "▼",
28
+ flat: "•"
29
+ };
30
+ function f(e, t) {
31
+ return typeof e == "number" ? t ? t(e) : e.toLocaleString() : e;
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 = [
35
+ "stat-card",
36
+ "corner-accent",
37
+ `stat-card--tone-${p}`,
38
+ C === "default" ? "" : `stat-card--${C}`,
39
+ v
40
+ ].filter(Boolean).join(" ");
41
+ return /* @__PURE__ */ c(e, {
42
+ className: A,
43
+ onClick: h,
44
+ role: h ? void 0 : "group",
45
+ ariaLabel: k,
46
+ testId: y,
47
+ children: [
48
+ /* @__PURE__ */ c("div", {
49
+ className: "stat-card__header",
50
+ children: [/* @__PURE__ */ s("span", {
51
+ className: "stat-card__label",
52
+ children: r
53
+ }), l && /* @__PURE__ */ s("span", {
54
+ className: "stat-card__icon",
55
+ "aria-hidden": "true",
56
+ children: l
57
+ })]
58
+ }),
59
+ /* @__PURE__ */ c("div", {
60
+ className: "stat-card__body",
61
+ children: [g ? /* @__PURE__ */ s(t, {
62
+ width: "60%",
63
+ height: "2rem"
64
+ }) : S ? /* @__PURE__ */ c("span", {
65
+ className: "stat-card__value-line",
66
+ children: [/* @__PURE__ */ c("span", {
67
+ className: "stat-card__value-row",
68
+ children: [/* @__PURE__ */ s("span", {
69
+ className: "stat-card__value",
70
+ children: O
71
+ }), a && /* @__PURE__ */ s("span", {
72
+ className: "stat-card__value-suffix",
73
+ children: a
74
+ })]
75
+ }), /* @__PURE__ */ s("span", {
76
+ className: "stat-card__sparkline",
77
+ children: S
78
+ })]
79
+ }) : /* @__PURE__ */ c("span", {
80
+ className: "stat-card__value-row",
81
+ children: [/* @__PURE__ */ s("span", {
82
+ className: "stat-card__value",
83
+ children: O
84
+ }), a && /* @__PURE__ */ s("span", {
85
+ className: "stat-card__value-suffix",
86
+ children: a
87
+ })]
88
+ }), m && !g && /* @__PURE__ */ c("span", {
89
+ className: `stat-card__trend stat-card__trend--${m.direction}`,
90
+ "aria-label": m.ariaLabel ?? m.label,
91
+ children: [/* @__PURE__ */ s("span", {
92
+ "aria-hidden": "true",
93
+ children: d[m.direction]
94
+ }), /* @__PURE__ */ s("span", { children: m.label })]
95
+ })]
96
+ }),
97
+ o != null && /* @__PURE__ */ s("div", {
98
+ className: "stat-card__hint",
99
+ children: g ? /* @__PURE__ */ s(t, {
100
+ width: "80%",
101
+ height: "0.85rem"
102
+ }) : o
103
+ })
104
+ ]
105
+ });
106
+ }
107
+ var m = r(p);
108
+ //#endregion
109
+ export { m as StatCard };
110
+
111
+ //# sourceMappingURL=StatCard2.js.map
@@ -0,0 +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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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Value formatters for StatCard.
3
+ *
4
+ * Kept out of StatCard.tsx so that file only exports components, which is what
5
+ * the react-refresh lint rule requires for fast refresh to work.
6
+ */
7
+ /**
8
+ * Abbreviates large counts ("1.2M", "3.4K") and falls back to locale grouping
9
+ * below 1000. Pass explicitly via StatCard's `format` prop; the card's own
10
+ * default is plain `toLocaleString` so existing consumers are unaffected.
11
+ */
12
+ export declare function formatCompactNumber(value: number): string;
@@ -0,0 +1,8 @@
1
+ //#region src/components/StatCard/formatters.ts
2
+ function e(e) {
3
+ return e >= 1e6 ? `${(e / 1e6).toFixed(1)}M` : e >= 1e3 ? `${(e / 1e3).toFixed(1)}K` : e.toLocaleString();
4
+ }
5
+ //#endregion
6
+ export { e as formatCompactNumber };
7
+
8
+ //# sourceMappingURL=formatters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.js","names":[],"sources":["../../../src/components/StatCard/formatters.ts"],"sourcesContent":["/**\n * Value formatters for StatCard.\n *\n * Kept out of StatCard.tsx so that file only exports components, which is what\n * the react-refresh lint rule requires for fast refresh to work.\n */\n\n/**\n * Abbreviates large counts (\"1.2M\", \"3.4K\") and falls back to locale grouping\n * below 1000. Pass explicitly via StatCard's `format` prop; the card's own\n * default is plain `toLocaleString` so existing consumers are unaffected.\n */\nexport function formatCompactNumber(value: number): string {\n if (value >= 1_000_000) {\n return `${(value / 1_000_000).toFixed(1)}M`;\n }\n if (value >= 1_000) {\n return `${(value / 1_000).toFixed(1)}K`;\n }\n return value.toLocaleString();\n}\n"],"mappings":";AAYA,SAAgB,EAAoB,GAAuB;CAOzD,OANI,KAAS,MACJ,IAAI,IAAQ,IAAA,CAAW,QAAQ,CAAC,EAAE,KAEvC,KAAS,MACJ,IAAI,IAAQ,IAAA,CAAO,QAAQ,CAAC,EAAE,KAEhC,EAAM,eAAe;AAC9B"}
@@ -0,0 +1,3 @@
1
+ export { StatCard } from './StatCard';
2
+ export { formatCompactNumber } from './formatters';
3
+ export type { StatCardProps, StatCardEmphasis, StatCardTone, StatCardTrend, StatCardTrendDirection, } from './StatCard';
@@ -0,0 +1,3 @@
1
+ import { StatCard as e } from "./StatCard2.js";
2
+ import { formatCompactNumber as t } from "./formatters.js";
3
+ export { e as StatCard, t as formatCompactNumber };
@@ -0,0 +1,38 @@
1
+ import { BadgeProps } from '../Badge';
2
+ /**
3
+ * Canonical lifecycle state surface accepted by {@link StatusTag}.
4
+ *
5
+ * The names are deliberately broad so domain types can map onto them:
6
+ * - SessionState `"starting"` → `"preparing"`
7
+ * - SessionState `"running"` (healthy) → `"running"`
8
+ * - SessionState `"idle"` → `"idle"`
9
+ * - SessionState `"busy"` → `"busy"`
10
+ * - SessionState `"stopping"` → `"stopping"`
11
+ * - SessionState `"terminated"` → `"terminated"`
12
+ * - SessionState `"error"` → `"error"`
13
+ */
14
+ export type StatusKind = "running" | "preparing" | "idle" | "busy" | "stopping" | "terminated" | "error";
15
+ export interface StatusTagProps {
16
+ /** Canonical lifecycle state. Drives color and indicator behavior. */
17
+ state: StatusKind;
18
+ /** Display label. Callers are responsible for i18n at the call site. */
19
+ label: string;
20
+ /** Override the underlying Badge size. Defaults to `"small"`. */
21
+ size?: BadgeProps["size"];
22
+ /**
23
+ * When `true`, render a small pulsing dot before the label to
24
+ * communicate that the state is in motion. Defaults to a sensible
25
+ * choice based on `state` (transient states pulse, terminal ones
26
+ * don't).
27
+ */
28
+ pulse?: boolean;
29
+ /** Extra class names appended to the root span. */
30
+ className?: string;
31
+ }
32
+ declare function StatusTagComponent({ state, label, size, pulse, className, }: StatusTagProps): import("react").JSX.Element;
33
+ /**
34
+ * Memoized to avoid re-rendering rows that didn't change. The component
35
+ * is a pure function of its props.
36
+ */
37
+ export declare const StatusTag: import('react').MemoExoticComponent<typeof StatusTagComponent>;
38
+ export default StatusTag;
@@ -0,0 +1,44 @@
1
+ import { Badge as e } from "../Badge/Badge2.js";
2
+ /* empty css */
3
+ import { memo as t } from "react";
4
+ import { jsx as n, jsxs as r } from "react/jsx-runtime";
5
+ //#region src/components/StatusTag/StatusTag.tsx
6
+ function i(e) {
7
+ switch (e) {
8
+ case "running": return "success";
9
+ case "preparing": return "info";
10
+ case "idle": return "default";
11
+ case "busy": return "primary";
12
+ case "stopping": return "warning";
13
+ case "terminated": return "default";
14
+ case "error": return "danger";
15
+ }
16
+ }
17
+ function a(e) {
18
+ return e === "preparing" || e === "stopping" || e === "busy";
19
+ }
20
+ function o({ state: t, label: o, size: s = "small", pulse: c, className: l = "" }) {
21
+ let u = c ?? a(t), d = [
22
+ "status-tag",
23
+ `status-tag--${t}`,
24
+ l
25
+ ].filter(Boolean).join(" ");
26
+ return /* @__PURE__ */ r(e, {
27
+ variant: i(t),
28
+ size: s,
29
+ className: d,
30
+ children: [u && /* @__PURE__ */ n("span", {
31
+ className: "status-tag__indicator",
32
+ "aria-hidden": "true",
33
+ "data-testid": "status-tag-indicator"
34
+ }), /* @__PURE__ */ n("span", {
35
+ className: "status-tag__label",
36
+ children: o
37
+ })]
38
+ });
39
+ }
40
+ var s = t(o);
41
+ //#endregion
42
+ export { s as StatusTag, s as default };
43
+
44
+ //# sourceMappingURL=StatusTag2.js.map