@machinemetrics/mm-react-components 0.2.3-13 → 0.2.3-15

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 (39) hide show
  1. package/README.md +31 -1
  2. package/agent-docs/agent-documentation-reference.md +114 -0
  3. package/agent-docs/ai-agent-guide.md +5 -1
  4. package/agent-docs/ai-agent-init-guide.md +5 -1
  5. package/dist/README.md +31 -1
  6. package/dist/components/ui/hero-metric-card/HeroMetricCard.d.ts +4 -0
  7. package/dist/components/ui/hero-metric-card/HeroMetricCard.d.ts.map +1 -0
  8. package/dist/components/ui/hero-metric-card/HeroMetricCardItem.d.ts +4 -0
  9. package/dist/components/ui/hero-metric-card/HeroMetricCardItem.d.ts.map +1 -0
  10. package/dist/components/ui/hero-metric-card/constants.d.ts +13 -0
  11. package/dist/components/ui/hero-metric-card/constants.d.ts.map +1 -0
  12. package/dist/components/ui/hero-metric-card/grid.d.ts +4 -0
  13. package/dist/components/ui/hero-metric-card/grid.d.ts.map +1 -0
  14. package/dist/components/ui/hero-metric-card/hooks.d.ts +6 -0
  15. package/dist/components/ui/hero-metric-card/hooks.d.ts.map +1 -0
  16. package/dist/components/ui/hero-metric-card/index.d.ts +5 -0
  17. package/dist/components/ui/hero-metric-card/index.d.ts.map +1 -0
  18. package/dist/components/ui/hero-metric-card/parsing.d.ts +11 -0
  19. package/dist/components/ui/hero-metric-card/parsing.d.ts.map +1 -0
  20. package/dist/components/ui/hero-metric-card/refs.d.ts +3 -0
  21. package/dist/components/ui/hero-metric-card/refs.d.ts.map +1 -0
  22. package/dist/components/ui/hero-metric-card/trend.d.ts +4 -0
  23. package/dist/components/ui/hero-metric-card/trend.d.ts.map +1 -0
  24. package/dist/components/ui/hero-metric-card/types.d.ts +60 -0
  25. package/dist/components/ui/hero-metric-card/types.d.ts.map +1 -0
  26. package/dist/components/ui/hero-metric-card/utils.d.ts +10 -0
  27. package/dist/components/ui/hero-metric-card/utils.d.ts.map +1 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/lib/mm-react-components.css +1 -1
  31. package/dist/mm-react-components.es.js +461 -2
  32. package/dist/mm-react-components.es.js.map +1 -1
  33. package/dist/mm-react-components.umd.js +10 -10
  34. package/dist/mm-react-components.umd.js.map +1 -1
  35. package/dist/preview/HeroMetricCardPreview.d.ts +2 -0
  36. package/dist/preview/HeroMetricCardPreview.d.ts.map +1 -0
  37. package/dist/scripts/chakra-to-shadcn-migrator/chakra-to-shadcn.config.json +130 -65
  38. package/dist/themes/carbide.css +23 -3
  39. package/package.json +1 -1
@@ -17592,7 +17592,7 @@ function LabeledSlider({
17592
17592
  },
17593
17593
  [onValueChange]
17594
17594
  );
17595
- const renderValue = React.useMemo(() => {
17595
+ const renderValue2 = React.useMemo(() => {
17596
17596
  if (formatValue) return formatValue(displayValue);
17597
17597
  return displayValue.length === 1 ? displayValue[0] : `${displayValue[0]} - ${displayValue[1]}`;
17598
17598
  }, [displayValue, formatValue]);
@@ -17636,7 +17636,7 @@ function LabeledSlider({
17636
17636
  {
17637
17637
  "data-slot": "slider-value",
17638
17638
  className: "text-sm text-muted-foreground tabular-nums whitespace-nowrap",
17639
- children: renderValue
17639
+ children: renderValue2
17640
17640
  }
17641
17641
  )
17642
17642
  ]
@@ -43619,6 +43619,463 @@ function BreadcrumbEllipsis({
43619
43619
  }
43620
43620
  );
43621
43621
  }
43622
+ const HERO_METRIC_CONSTANTS = {
43623
+ MIN_ITEM_WIDTH: 160,
43624
+ MIN_ITEMS: 1,
43625
+ MAX_ITEMS: 6,
43626
+ WRAPPED_GAP_DEFAULT: "gap-4",
43627
+ UNWRAPPED_GAP: "gap-0",
43628
+ PADDING_INTERACTIVE: "px-3",
43629
+ PADDING_STATIC: "px-6",
43630
+ CONTAINER_PADDING_Y: "py-4",
43631
+ CONTAINER_PADDING_X: "px-0"
43632
+ };
43633
+ const GRID_COLS_MAP = {
43634
+ 1: "grid-cols-1",
43635
+ 2: "grid-cols-2",
43636
+ 3: "grid-cols-3",
43637
+ 4: "grid-cols-4",
43638
+ 5: "grid-cols-5",
43639
+ 6: "grid-cols-6"
43640
+ };
43641
+ function parseNumeric(input) {
43642
+ if (input === null || input === void 0) return void 0;
43643
+ if (typeof input !== "string" && typeof input !== "number") return void 0;
43644
+ const n = parseFloat(String(input).replace(/[^0-9.-]/g, ""));
43645
+ return Number.isFinite(n) ? n : void 0;
43646
+ }
43647
+ function parsePercent(value) {
43648
+ return parseNumeric(value);
43649
+ }
43650
+ function parseCount(value) {
43651
+ return parseNumeric(value);
43652
+ }
43653
+ function parseMinutes(value, unit) {
43654
+ if (value === null || value === void 0) return void 0;
43655
+ if (typeof value === "number") {
43656
+ if (!Number.isFinite(value)) return void 0;
43657
+ if (unit && /h/i.test(unit)) return value * 60;
43658
+ return value;
43659
+ }
43660
+ if (typeof value !== "string") return void 0;
43661
+ const s2 = value;
43662
+ const hm = /(\d+)\s*h(?:\s*(\d+)\s*m)?/i.exec(s2);
43663
+ if (hm) {
43664
+ const h = parseInt(hm[1] ?? "0", 10);
43665
+ const m = parseInt(hm[2] ?? "0", 10);
43666
+ return h * 60 + m;
43667
+ }
43668
+ const mOnly = /(\d+)\s*m/i.exec(s2);
43669
+ if (mOnly) return parseInt(mOnly[1] ?? "0", 10);
43670
+ const n = parseFloat(s2);
43671
+ if (Number.isFinite(n)) {
43672
+ if (/h/i.test(s2) || unit && /h/i.test(unit)) return n * 60;
43673
+ return n;
43674
+ }
43675
+ return void 0;
43676
+ }
43677
+ function formatDuration(mins) {
43678
+ const h = Math.floor(mins / 60);
43679
+ const m = Math.round(mins % 60);
43680
+ if (h > 0) return `${h}h ${m}m`;
43681
+ const s2 = Math.round((mins - m) * 60);
43682
+ return `${m}m ${s2}s`;
43683
+ }
43684
+ function getNumericForKind(value, unit, kind) {
43685
+ if (kind === "percent") return parsePercent(value);
43686
+ if (kind === "duration-minutes") return parseMinutes(value, unit);
43687
+ return parseCount(value);
43688
+ }
43689
+ function getColorIntent(direction, higherIsBetter) {
43690
+ if (direction === "neutral") return "neutral";
43691
+ if (direction === "up") return higherIsBetter ? "success" : "destructive";
43692
+ return higherIsBetter ? "destructive" : "success";
43693
+ }
43694
+ function getTrendText(kind, absDiff, relativePercent) {
43695
+ if (kind === "percent")
43696
+ return `${Math.abs(absDiff).toFixed(1)}% (${relativePercent}pp)`;
43697
+ if (kind === "duration-minutes")
43698
+ return `${formatDuration(Math.abs(absDiff))} (${relativePercent}%)`;
43699
+ return `${Math.abs(absDiff).toFixed(1)} (${relativePercent}%)`;
43700
+ }
43701
+ function computeTrend(value, unit, trendComparisonValue, higherIsBetter = true, numericValue) {
43702
+ if (!trendComparisonValue || typeof trendComparisonValue.value !== "number")
43703
+ return void 0;
43704
+ const currentNumeric = typeof numericValue === "number" ? numericValue : getNumericForKind(value, unit, trendComparisonValue.kind);
43705
+ if (currentNumeric === void 0) return void 0;
43706
+ const absoluteDifference = currentNumeric - trendComparisonValue.value;
43707
+ let direction;
43708
+ if (absoluteDifference > 0) direction = "up";
43709
+ else if (absoluteDifference < 0) direction = "down";
43710
+ else direction = "neutral";
43711
+ const colorIntent = getColorIntent(direction, higherIsBetter);
43712
+ const relativePercent = Math.abs(
43713
+ absoluteDifference / Math.max(1e-6, trendComparisonValue.value) * 100
43714
+ ).toFixed(1);
43715
+ const text2 = getTrendText(
43716
+ trendComparisonValue.kind,
43717
+ Math.abs(absoluteDifference),
43718
+ relativePercent
43719
+ );
43720
+ return { direction, text: text2, colorIntent };
43721
+ }
43722
+ function getGridColsClass(n) {
43723
+ if (!n) return void 0;
43724
+ return GRID_COLS_MAP[n];
43725
+ }
43726
+ function resolveGridClasses(columns) {
43727
+ if (!columns) {
43728
+ return "[grid-template-columns:repeat(auto-fit,minmax(10rem,1fr))]";
43729
+ }
43730
+ if (typeof columns === "number") {
43731
+ return getGridColsClass(columns) ?? "grid-cols-1";
43732
+ }
43733
+ const base = getGridColsClass(columns.base) ?? "grid-cols-1";
43734
+ const md = columns.md ? `md:${getGridColsClass(columns.md)}` : "";
43735
+ const lg = columns.lg ? `lg:${getGridColsClass(columns.lg)}` : "";
43736
+ return cn$1(base, md, lg);
43737
+ }
43738
+ function mergeRefs(...refs) {
43739
+ return (node) => {
43740
+ refs.forEach((ref) => {
43741
+ if (!ref) return;
43742
+ if (typeof ref === "function") {
43743
+ ref(node);
43744
+ } else {
43745
+ ref.current = node;
43746
+ }
43747
+ });
43748
+ };
43749
+ }
43750
+ function formatNumber(value) {
43751
+ if (typeof value === "number") return value.toLocaleString();
43752
+ return value;
43753
+ }
43754
+ const renderLabel = (label, tooltip) => {
43755
+ const labelElement = /* @__PURE__ */ jsxRuntimeExports.jsx(
43756
+ "span",
43757
+ {
43758
+ className: cn$1(
43759
+ "mmc-hero-metric-card__label",
43760
+ "text-xs font-normal text-foreground",
43761
+ tooltip && "mmc-underline-dashed hover:text-foreground"
43762
+ ),
43763
+ "data-slot": "metric-label",
43764
+ children: label
43765
+ }
43766
+ );
43767
+ if (!tooltip) return labelElement;
43768
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip$1, { children: [
43769
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-block cursor-help", children: labelElement }) }),
43770
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: tooltip })
43771
+ ] });
43772
+ };
43773
+ const renderValue = (value, unit, icon, loading) => {
43774
+ const formatDisplayValue = () => {
43775
+ if (value === null || value === void 0) return "—";
43776
+ if (typeof value === "number") return formatNumber(value);
43777
+ return value;
43778
+ };
43779
+ const content = loading ? /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-9 w-28" }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "inline-flex items-baseline gap-0", children: [
43780
+ icon && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mmc-hero-metric-card__icon", "data-slot": "metric-icon", children: icon }),
43781
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-foreground", children: formatDisplayValue() }),
43782
+ unit && /* @__PURE__ */ jsxRuntimeExports.jsx(
43783
+ "span",
43784
+ {
43785
+ className: "mmc-hero-metric-card__unit text-foreground text-xl font-medium",
43786
+ "data-slot": "metric-unit",
43787
+ children: unit
43788
+ }
43789
+ )
43790
+ ] });
43791
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
43792
+ "div",
43793
+ {
43794
+ className: "mmc-hero-metric-card__value text-xl font-medium text-foreground",
43795
+ "data-slot": "metric-value",
43796
+ children: content
43797
+ }
43798
+ );
43799
+ };
43800
+ const renderCaption = (caption, loading) => {
43801
+ if (!caption) return null;
43802
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
43803
+ "div",
43804
+ {
43805
+ className: "mmc-hero-metric-card__caption text-xs font-normal text-foreground",
43806
+ "data-slot": "metric-caption",
43807
+ children: loading ? /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-32" }) : caption
43808
+ }
43809
+ );
43810
+ };
43811
+ const getTrendContent = (computedTrend, loading) => {
43812
+ if (!computedTrend) return null;
43813
+ if (loading) return /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "h-3.5 w-16" });
43814
+ if (computedTrend.colorIntent === "neutral") {
43815
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground", children: "—" });
43816
+ }
43817
+ const trendColorClass = computedTrend.colorIntent === "success" ? "text-[var(--success-foreground,theme(colors.green.600))]" : "text-[var(--destructive-foreground,theme(colors.red.600))]";
43818
+ const ArrowIcon = computedTrend.direction === "up" ? ArrowUp : ArrowDown;
43819
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
43820
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowIcon, { className: cn$1("h-3.5 w-3.5", trendColorClass) }),
43821
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: trendColorClass, children: String(computedTrend.text).replace(/^[-+]/, "") })
43822
+ ] });
43823
+ };
43824
+ const getInnerContainerClasses = (interactive, variant, dataState) => {
43825
+ return cn$1(
43826
+ interactive && cn$1(
43827
+ "px-3 py-2",
43828
+ "transition-colors",
43829
+ "rounded-lg",
43830
+ dataState !== "active" && "hover:bg-accent"
43831
+ ),
43832
+ variant === "filter" && dataState === "active" && "bg-[var(--primary-subtle)] ring-2 ring-primary",
43833
+ variant === "filter" && dataState === "unfocused" && "opacity-60"
43834
+ );
43835
+ };
43836
+ const HeroMetricCardItem = React.forwardRef(
43837
+ ({
43838
+ label,
43839
+ value,
43840
+ unit,
43841
+ caption,
43842
+ tooltip,
43843
+ icon,
43844
+ loading,
43845
+ className,
43846
+ interactive = false,
43847
+ pressed = false,
43848
+ onActivate,
43849
+ onClick,
43850
+ trendComparisonValue,
43851
+ higherIsBetter = true,
43852
+ "data-variant": variant,
43853
+ "data-state": dataState,
43854
+ ...rest
43855
+ }, ref) => {
43856
+ const isInteractiveVariant = variant === "button" || variant === "filter";
43857
+ const outerContainer = cn$1(
43858
+ "mmc-hero-metric-card__item",
43859
+ isInteractiveVariant ? HERO_METRIC_CONSTANTS.PADDING_INTERACTIVE : HERO_METRIC_CONSTANTS.PADDING_STATIC,
43860
+ "items-start text-left",
43861
+ className
43862
+ );
43863
+ const innerContainer = getInnerContainerClasses(
43864
+ interactive,
43865
+ variant,
43866
+ dataState
43867
+ );
43868
+ const computedTrend = computeTrend(
43869
+ value,
43870
+ unit,
43871
+ trendComparisonValue,
43872
+ higherIsBetter,
43873
+ rest.numericValue
43874
+ );
43875
+ const trendContent = getTrendContent(computedTrend, loading);
43876
+ const trend = trendContent ? /* @__PURE__ */ jsxRuntimeExports.jsx(
43877
+ "div",
43878
+ {
43879
+ className: "mmc-hero-metric-card__trend text-xs font-normal inline-flex items-center gap-0.5",
43880
+ "data-slot": "metric-trend",
43881
+ children: trendContent
43882
+ }
43883
+ ) : null;
43884
+ const body = /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1.5", children: [
43885
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pb-0.5", children: renderLabel(label, tooltip) }),
43886
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
43887
+ renderValue(value, unit, icon, loading),
43888
+ trend,
43889
+ renderCaption(caption, loading)
43890
+ ] })
43891
+ ] });
43892
+ if (interactive) {
43893
+ const handleClick = variant === "button" && onClick ? onClick : onActivate;
43894
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
43895
+ "button",
43896
+ {
43897
+ ref,
43898
+ type: "button",
43899
+ className: cn$1(outerContainer, "focus-visible:outline-none"),
43900
+ onClick: handleClick,
43901
+ "aria-pressed": variant === "filter" ? pressed : void 0,
43902
+ "data-slot": "metric-item",
43903
+ "data-variant": variant,
43904
+ "data-state": dataState,
43905
+ ...rest,
43906
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: innerContainer, children: body })
43907
+ }
43908
+ );
43909
+ }
43910
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
43911
+ "div",
43912
+ {
43913
+ ref,
43914
+ className: outerContainer,
43915
+ "data-slot": "metric-item",
43916
+ ...rest,
43917
+ children: body
43918
+ }
43919
+ );
43920
+ }
43921
+ );
43922
+ HeroMetricCardItem.displayName = "HeroMetricCardItem";
43923
+ function useWrappedDetection(itemCount, containerRef, children) {
43924
+ const [hasWrapped, setHasWrapped] = React.useState(false);
43925
+ React.useEffect(() => {
43926
+ if (!containerRef.current) return;
43927
+ const observer = new ResizeObserver(() => {
43928
+ if (!containerRef.current) return;
43929
+ const count2 = itemCount || React.Children.count(children);
43930
+ if (count2 === 0) return;
43931
+ const containerWidth = containerRef.current.offsetWidth;
43932
+ const totalMinWidth = count2 * HERO_METRIC_CONSTANTS.MIN_ITEM_WIDTH;
43933
+ setHasWrapped(containerWidth < totalMinWidth);
43934
+ });
43935
+ observer.observe(containerRef.current);
43936
+ return () => observer.disconnect();
43937
+ }, [itemCount, containerRef, children]);
43938
+ return hasWrapped;
43939
+ }
43940
+ function getItemProps(_idx, itemId, _itemCount, mode, activeId, handleItemActivate) {
43941
+ const isFilter = mode === "filter";
43942
+ const isButton = mode === "button";
43943
+ const isActive = isFilter && activeId === itemId;
43944
+ let dataState;
43945
+ if (isFilter) {
43946
+ if (isActive) {
43947
+ dataState = "active";
43948
+ } else if (activeId) {
43949
+ dataState = "unfocused";
43950
+ } else {
43951
+ dataState = "default";
43952
+ }
43953
+ }
43954
+ return {
43955
+ "data-variant": mode,
43956
+ "data-state": dataState,
43957
+ onActivate: isFilter ? () => handleItemActivate(itemId) : void 0,
43958
+ interactive: isFilter || isButton,
43959
+ pressed: isFilter ? isActive : false
43960
+ };
43961
+ }
43962
+ const HeroMetricCard = React.forwardRef(
43963
+ ({
43964
+ children,
43965
+ items,
43966
+ mode = "static",
43967
+ activeId: controlledActiveId,
43968
+ defaultActiveId = null,
43969
+ onActiveChange,
43970
+ columns,
43971
+ showTrends: _showTrends = true,
43972
+ loading = false,
43973
+ className,
43974
+ "data-testid": dataTestId = "hero-metric-card",
43975
+ ...rest
43976
+ }, ref) => {
43977
+ const isFilter = mode === "filter";
43978
+ const [uncontrolledActive, setUncontrolledActive] = React.useState(defaultActiveId ?? null);
43979
+ const activeId = controlledActiveId ?? uncontrolledActive;
43980
+ const containerRef = React.useRef(null);
43981
+ const itemCount = items?.length ?? React.Children.count(children);
43982
+ const hasWrapped = useWrappedDetection(itemCount, containerRef, children);
43983
+ const handleItemActivate = (id) => {
43984
+ if (isFilter) {
43985
+ const next = activeId === id ? null : id;
43986
+ if (controlledActiveId === void 0) setUncontrolledActive(next);
43987
+ onActiveChange?.(next);
43988
+ }
43989
+ };
43990
+ const renderFromItems = (src) => {
43991
+ const normalized = src.slice(0, HERO_METRIC_CONSTANTS.MAX_ITEMS);
43992
+ if (normalized.length < HERO_METRIC_CONSTANTS.MIN_ITEMS) {
43993
+ return null;
43994
+ }
43995
+ return normalized.map((it, idx) => {
43996
+ const itemId = it.id ?? String(idx);
43997
+ const itemProps = getItemProps(
43998
+ idx,
43999
+ itemId,
44000
+ normalized.length,
44001
+ mode,
44002
+ activeId,
44003
+ handleItemActivate
44004
+ );
44005
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
44006
+ HeroMetricCardItem,
44007
+ {
44008
+ ...it,
44009
+ trendComparisonValue: _showTrends ? it.trendComparisonValue : void 0,
44010
+ loading,
44011
+ ...itemProps
44012
+ },
44013
+ itemId
44014
+ );
44015
+ });
44016
+ };
44017
+ const renderFromChildren = (nodes) => {
44018
+ const arr = React.Children.toArray(nodes).slice(
44019
+ 0,
44020
+ HERO_METRIC_CONSTANTS.MAX_ITEMS
44021
+ );
44022
+ if (arr.length < HERO_METRIC_CONSTANTS.MIN_ITEMS) {
44023
+ return null;
44024
+ }
44025
+ return arr.map((child, idx) => {
44026
+ if (React.isValidElement(child) && child.type === HeroMetricCardItem) {
44027
+ const childProps = child.props;
44028
+ const itemId = childProps.id ?? String(idx);
44029
+ const itemProps = getItemProps(
44030
+ idx,
44031
+ itemId,
44032
+ arr.length,
44033
+ mode,
44034
+ activeId,
44035
+ handleItemActivate
44036
+ );
44037
+ const nextProps = {
44038
+ loading,
44039
+ ...itemProps,
44040
+ trendComparisonValue: _showTrends ? childProps.trendComparisonValue : void 0
44041
+ };
44042
+ return React.cloneElement(child, nextProps);
44043
+ }
44044
+ return child;
44045
+ });
44046
+ };
44047
+ const content = items ? renderFromItems(items) : renderFromChildren(children);
44048
+ const mergedRef = mergeRefs(containerRef, ref);
44049
+ const gapClass = hasWrapped ? HERO_METRIC_CONSTANTS.WRAPPED_GAP_DEFAULT : HERO_METRIC_CONSTANTS.UNWRAPPED_GAP;
44050
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
44051
+ "div",
44052
+ {
44053
+ ref: mergedRef,
44054
+ className: cn$1(
44055
+ "mmc-hero-metric-card",
44056
+ // Card container carries border/rounded, not items
44057
+ "rounded-lg border border-[var(--border-input)] bg-card",
44058
+ // Grid layout inside card
44059
+ "grid",
44060
+ resolveGridClasses(columns),
44061
+ // Use gaps when wrapped, no gaps when single-row with borders
44062
+ gapClass,
44063
+ // Static: 16px top/bottom, 0px left/right
44064
+ HERO_METRIC_CONSTANTS.CONTAINER_PADDING_Y,
44065
+ HERO_METRIC_CONSTANTS.CONTAINER_PADDING_X,
44066
+ className
44067
+ ),
44068
+ "data-slot": "hero-metric-card",
44069
+ "data-mode": mode,
44070
+ "data-wrapped": hasWrapped ? "true" : "false",
44071
+ "data-testid": dataTestId,
44072
+ ...rest,
44073
+ children: content
44074
+ }
44075
+ );
44076
+ }
44077
+ );
44078
+ HeroMetricCard.displayName = "HeroMetricCard";
43622
44079
  export {
43623
44080
  Accordion,
43624
44081
  AccordionContent,
@@ -43717,6 +44174,8 @@ export {
43717
44174
  FormItem,
43718
44175
  FormLabel,
43719
44176
  FormMessage,
44177
+ HeroMetricCard,
44178
+ HeroMetricCardItem,
43720
44179
  Input,
43721
44180
  Label$2 as Label,
43722
44181
  LabeledSlider,