framepexls-ui-lib 1.16.0 → 2.0.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.
package/dist/StatCard.js CHANGED
@@ -36,16 +36,16 @@ var import_jsx_runtime = require("react/jsx-runtime");
36
36
  var import_framer_motion = require("framer-motion");
37
37
  var import_react = require("react");
38
38
  var import_recharts = require("recharts");
39
+ var import_Dropdown = __toESM(require("./Dropdown"));
40
+ var import_iconos = require("./iconos");
39
41
  var import_AutoSize = __toESM(require("./internal/AutoSize"));
40
42
  var import_skeleton = require("./internal/skeleton");
41
43
  function MotionNumber({ value, format }) {
42
44
  const mv = (0, import_framer_motion.useMotionValue)(value);
43
45
  const [display, setDisplay] = (0, import_react.useState)(value);
44
- const prevRef = (0, import_react.useRef)(value);
45
46
  (0, import_react.useEffect)(() => {
46
47
  const controls = (0, import_framer_motion.animate)(mv, value, { duration: 0.5, ease: "easeOut" });
47
48
  const unsub = mv.on("change", (v) => setDisplay(v));
48
- prevRef.current = value;
49
49
  return () => {
50
50
  controls.stop();
51
51
  unsub();
@@ -53,7 +53,91 @@ function MotionNumber({ value, format }) {
53
53
  }, [value]);
54
54
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: format ? format(display) : Math.round(display).toLocaleString() });
55
55
  }
56
- function StatCard({ title, value, hint, spark, loading, loadingMinDurationMs = import_skeleton.DEFAULT_SKELETON_MIN_DURATION_MS, skeleton }) {
56
+ function resolveComparisonLabel(comparison) {
57
+ if (comparison.label !== void 0) return comparison.label;
58
+ if (!comparison.period) return null;
59
+ const periodLabels = comparison.locale === "es" ? {
60
+ day: "vs \xFAltimo d\xEDa",
61
+ week: "vs \xFAltima semana",
62
+ month: "vs \xFAltimo mes",
63
+ quarter: "vs \xFAltimo trimestre",
64
+ year: "vs \xFAltimo a\xF1o"
65
+ } : {
66
+ day: "vs last day",
67
+ week: "vs last week",
68
+ month: "vs last month",
69
+ quarter: "vs last quarter",
70
+ year: "vs last year"
71
+ };
72
+ return periodLabels[comparison.period];
73
+ }
74
+ function resolveComparisonTrend(comparison) {
75
+ if (comparison.trend && comparison.trend !== "auto") return comparison.trend;
76
+ if (comparison.value > 0) return "up";
77
+ if (comparison.value < 0) return "down";
78
+ return "flat";
79
+ }
80
+ function formatComparisonValue(comparison) {
81
+ var _a, _b;
82
+ if (comparison.formatter) return comparison.formatter(comparison.value);
83
+ const absoluteValue = Math.abs(comparison.value);
84
+ const precision = (_a = comparison.precision) != null ? _a : Number.isInteger(absoluteValue) ? 0 : 1;
85
+ const formatted = absoluteValue.toLocaleString(void 0, {
86
+ minimumFractionDigits: precision,
87
+ maximumFractionDigits: precision
88
+ });
89
+ const prefix = comparison.showSign && comparison.value !== 0 ? comparison.value > 0 ? "+" : "-" : "";
90
+ return `${prefix}${formatted}${(_b = comparison.suffix) != null ? _b : "%"}`;
91
+ }
92
+ function ComparisonLine({ comparison }) {
93
+ var _a;
94
+ const trend = resolveComparisonTrend(comparison);
95
+ const positiveIsGood = (_a = comparison.positiveIsGood) != null ? _a : true;
96
+ const isPositiveTone = trend !== "flat" && (positiveIsGood ? trend === "up" : trend === "down");
97
+ const toneClass = trend === "flat" ? "text-slate-400 dark:text-slate-500" : isPositiveTone ? "text-emerald-500 dark:text-emerald-400" : "text-rose-500 dark:text-rose-400";
98
+ const label = resolveComparisonLabel(comparison);
99
+ const Icon = trend === "up" ? import_iconos.TrendUpIcon : trend === "down" ? import_iconos.TrendDownIcon : import_iconos.MinusIcon;
100
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-4 flex flex-wrap items-center gap-x-1.5 gap-y-1 text-xs", children: [
101
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: `inline-flex items-center gap-1 font-medium ${toneClass}`, children: [
102
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { "aria-hidden": true, className: "h-3.5 w-3.5" }),
103
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: formatComparisonValue(comparison) })
104
+ ] }),
105
+ label ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-slate-400 dark:text-slate-500", children: label }) : null
106
+ ] });
107
+ }
108
+ function CardMenu({ menu }) {
109
+ var _a, _b, _c, _d;
110
+ if (!menu.items.length) return null;
111
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { onClickCapture: (e) => e.stopPropagation(), onMouseDownCapture: (e) => e.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_Dropdown.default, { align: (_a = menu.align) != null ? _a : "end", children: [
112
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
113
+ import_Dropdown.default.Trigger,
114
+ {
115
+ "aria-label": (_b = menu.triggerAriaLabel) != null ? _b : "M\xE1s opciones",
116
+ className: "h-8 w-8 shrink-0 !gap-0 rounded-xl border-transparent bg-transparent p-0 text-slate-400 shadow-none hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-white/5 dark:hover:text-slate-300",
117
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_iconos.MenuPuntosVerticalIcon, { "aria-hidden": true, className: "h-4.5 w-4.5" })
118
+ }
119
+ ),
120
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_Dropdown.default.Content, { className: (_c = menu.contentClassName) != null ? _c : "w-[220px]", maxHeight: (_d = menu.maxHeight) != null ? _d : 280, children: [
121
+ menu.label ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_Dropdown.default.Label, { children: menu.label }) : null,
122
+ menu.items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
123
+ import_Dropdown.default.Item,
124
+ {
125
+ icon: item.icon,
126
+ kbd: item.kbd,
127
+ danger: item.danger,
128
+ disabled: item.disabled,
129
+ require: item.require,
130
+ hideIfUnauthorized: item.hideIfUnauthorized,
131
+ disableIfUnauthorized: item.disableIfUnauthorized,
132
+ onSelect: item.onSelect,
133
+ children: item.label
134
+ },
135
+ index
136
+ ))
137
+ ] })
138
+ ] }) });
139
+ }
140
+ function StatCard({ title, value, hint, comparison, menu, spark, loading, loadingMinDurationMs = import_skeleton.DEFAULT_SKELETON_MIN_DURATION_MS, skeleton }) {
57
141
  var _a, _b, _c, _d, _e;
58
142
  const gid = (0, import_react.useId)();
59
143
  const color = (_a = spark == null ? void 0 : spark.color) != null ? _a : "#10b981";
@@ -66,9 +150,13 @@ function StatCard({ title, value, hint, spark, loading, loadingMinDurationMs = i
66
150
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "fx-skeleton", style: { width: (_d = skeleton == null ? void 0 : skeleton.valueWidth) != null ? _d : "32%", height: 26, borderRadius: 12 } }),
67
151
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "fx-skeleton", style: { width: (_e = skeleton == null ? void 0 : skeleton.hintWidth) != null ? _e : "58%", height: 10, borderRadius: 10, opacity: 0.9 } })
68
152
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
69
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-xs font-medium text-slate-500 dark:text-slate-400", children: title }),
70
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-1 text-2xl font-semibold tracking-tight", children: isNumber ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MotionNumber, { value }) : value }),
71
- hint && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-1 text-xs text-slate-400", children: hint })
153
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [
154
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "min-w-0 text-xs font-medium text-slate-500 dark:text-slate-400", children: title }),
155
+ menu ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardMenu, { menu }) : null
156
+ ] }),
157
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-2 text-2xl font-semibold tracking-tight text-slate-900 dark:text-slate-50", children: isNumber ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MotionNumber, { value }) : value }),
158
+ comparison ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ComparisonLine, { comparison }) : null,
159
+ hint && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `${comparison ? "mt-1" : "mt-2"} text-xs text-slate-400 dark:text-slate-500`, children: hint })
72
160
  ] }) }),
73
161
  showSpark && (showLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pointer-events-none absolute inset-y-0 right-0 w-1/2 opacity-90", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "fx-skeleton h-full w-full", style: { borderRadius: 0 } }) }) : null),
74
162
  !showLoading && spark && spark.values.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_AutoSize.default, { className: "pointer-events-none absolute inset-y-0 right-0 w-1/2 opacity-90", children: ({ width, height }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
package/dist/StatCard.mjs CHANGED
@@ -1,18 +1,18 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { animate, motion, useMotionValue } from "framer-motion";
4
- import { useEffect, useId, useRef, useState } from "react";
4
+ import { useEffect, useId, useState } from "react";
5
5
  import { Area, AreaChart } from "recharts";
6
+ import Dropdown from "./Dropdown.mjs";
7
+ import { MenuPuntosVerticalIcon, MinusIcon, TrendDownIcon, TrendUpIcon } from "./iconos/index.mjs";
6
8
  import AutoSize from "./internal/AutoSize.mjs";
7
9
  import { DEFAULT_SKELETON_MIN_DURATION_MS, useMinVisible } from "./internal/skeleton.mjs";
8
10
  function MotionNumber({ value, format }) {
9
11
  const mv = useMotionValue(value);
10
12
  const [display, setDisplay] = useState(value);
11
- const prevRef = useRef(value);
12
13
  useEffect(() => {
13
14
  const controls = animate(mv, value, { duration: 0.5, ease: "easeOut" });
14
15
  const unsub = mv.on("change", (v) => setDisplay(v));
15
- prevRef.current = value;
16
16
  return () => {
17
17
  controls.stop();
18
18
  unsub();
@@ -20,7 +20,91 @@ function MotionNumber({ value, format }) {
20
20
  }, [value]);
21
21
  return /* @__PURE__ */ jsx("span", { children: format ? format(display) : Math.round(display).toLocaleString() });
22
22
  }
23
- function StatCard({ title, value, hint, spark, loading, loadingMinDurationMs = DEFAULT_SKELETON_MIN_DURATION_MS, skeleton }) {
23
+ function resolveComparisonLabel(comparison) {
24
+ if (comparison.label !== void 0) return comparison.label;
25
+ if (!comparison.period) return null;
26
+ const periodLabels = comparison.locale === "es" ? {
27
+ day: "vs \xFAltimo d\xEDa",
28
+ week: "vs \xFAltima semana",
29
+ month: "vs \xFAltimo mes",
30
+ quarter: "vs \xFAltimo trimestre",
31
+ year: "vs \xFAltimo a\xF1o"
32
+ } : {
33
+ day: "vs last day",
34
+ week: "vs last week",
35
+ month: "vs last month",
36
+ quarter: "vs last quarter",
37
+ year: "vs last year"
38
+ };
39
+ return periodLabels[comparison.period];
40
+ }
41
+ function resolveComparisonTrend(comparison) {
42
+ if (comparison.trend && comparison.trend !== "auto") return comparison.trend;
43
+ if (comparison.value > 0) return "up";
44
+ if (comparison.value < 0) return "down";
45
+ return "flat";
46
+ }
47
+ function formatComparisonValue(comparison) {
48
+ var _a, _b;
49
+ if (comparison.formatter) return comparison.formatter(comparison.value);
50
+ const absoluteValue = Math.abs(comparison.value);
51
+ const precision = (_a = comparison.precision) != null ? _a : Number.isInteger(absoluteValue) ? 0 : 1;
52
+ const formatted = absoluteValue.toLocaleString(void 0, {
53
+ minimumFractionDigits: precision,
54
+ maximumFractionDigits: precision
55
+ });
56
+ const prefix = comparison.showSign && comparison.value !== 0 ? comparison.value > 0 ? "+" : "-" : "";
57
+ return `${prefix}${formatted}${(_b = comparison.suffix) != null ? _b : "%"}`;
58
+ }
59
+ function ComparisonLine({ comparison }) {
60
+ var _a;
61
+ const trend = resolveComparisonTrend(comparison);
62
+ const positiveIsGood = (_a = comparison.positiveIsGood) != null ? _a : true;
63
+ const isPositiveTone = trend !== "flat" && (positiveIsGood ? trend === "up" : trend === "down");
64
+ const toneClass = trend === "flat" ? "text-slate-400 dark:text-slate-500" : isPositiveTone ? "text-emerald-500 dark:text-emerald-400" : "text-rose-500 dark:text-rose-400";
65
+ const label = resolveComparisonLabel(comparison);
66
+ const Icon = trend === "up" ? TrendUpIcon : trend === "down" ? TrendDownIcon : MinusIcon;
67
+ return /* @__PURE__ */ jsxs("div", { className: "mt-4 flex flex-wrap items-center gap-x-1.5 gap-y-1 text-xs", children: [
68
+ /* @__PURE__ */ jsxs("span", { className: `inline-flex items-center gap-1 font-medium ${toneClass}`, children: [
69
+ /* @__PURE__ */ jsx(Icon, { "aria-hidden": true, className: "h-3.5 w-3.5" }),
70
+ /* @__PURE__ */ jsx("span", { children: formatComparisonValue(comparison) })
71
+ ] }),
72
+ label ? /* @__PURE__ */ jsx("span", { className: "text-slate-400 dark:text-slate-500", children: label }) : null
73
+ ] });
74
+ }
75
+ function CardMenu({ menu }) {
76
+ var _a, _b, _c, _d;
77
+ if (!menu.items.length) return null;
78
+ return /* @__PURE__ */ jsx("div", { onClickCapture: (e) => e.stopPropagation(), onMouseDownCapture: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxs(Dropdown, { align: (_a = menu.align) != null ? _a : "end", children: [
79
+ /* @__PURE__ */ jsx(
80
+ Dropdown.Trigger,
81
+ {
82
+ "aria-label": (_b = menu.triggerAriaLabel) != null ? _b : "M\xE1s opciones",
83
+ className: "h-8 w-8 shrink-0 !gap-0 rounded-xl border-transparent bg-transparent p-0 text-slate-400 shadow-none hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-white/5 dark:hover:text-slate-300",
84
+ children: /* @__PURE__ */ jsx(MenuPuntosVerticalIcon, { "aria-hidden": true, className: "h-4.5 w-4.5" })
85
+ }
86
+ ),
87
+ /* @__PURE__ */ jsxs(Dropdown.Content, { className: (_c = menu.contentClassName) != null ? _c : "w-[220px]", maxHeight: (_d = menu.maxHeight) != null ? _d : 280, children: [
88
+ menu.label ? /* @__PURE__ */ jsx(Dropdown.Label, { children: menu.label }) : null,
89
+ menu.items.map((item, index) => /* @__PURE__ */ jsx(
90
+ Dropdown.Item,
91
+ {
92
+ icon: item.icon,
93
+ kbd: item.kbd,
94
+ danger: item.danger,
95
+ disabled: item.disabled,
96
+ require: item.require,
97
+ hideIfUnauthorized: item.hideIfUnauthorized,
98
+ disableIfUnauthorized: item.disableIfUnauthorized,
99
+ onSelect: item.onSelect,
100
+ children: item.label
101
+ },
102
+ index
103
+ ))
104
+ ] })
105
+ ] }) });
106
+ }
107
+ function StatCard({ title, value, hint, comparison, menu, spark, loading, loadingMinDurationMs = DEFAULT_SKELETON_MIN_DURATION_MS, skeleton }) {
24
108
  var _a, _b, _c, _d, _e;
25
109
  const gid = useId();
26
110
  const color = (_a = spark == null ? void 0 : spark.color) != null ? _a : "#10b981";
@@ -33,9 +117,13 @@ function StatCard({ title, value, hint, spark, loading, loadingMinDurationMs = D
33
117
  /* @__PURE__ */ jsx("div", { className: "fx-skeleton", style: { width: (_d = skeleton == null ? void 0 : skeleton.valueWidth) != null ? _d : "32%", height: 26, borderRadius: 12 } }),
34
118
  /* @__PURE__ */ jsx("div", { className: "fx-skeleton", style: { width: (_e = skeleton == null ? void 0 : skeleton.hintWidth) != null ? _e : "58%", height: 10, borderRadius: 10, opacity: 0.9 } })
35
119
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
36
- /* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-slate-500 dark:text-slate-400", children: title }),
37
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-2xl font-semibold tracking-tight", children: isNumber ? /* @__PURE__ */ jsx(MotionNumber, { value }) : value }),
38
- hint && /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs text-slate-400", children: hint })
120
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
121
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 text-xs font-medium text-slate-500 dark:text-slate-400", children: title }),
122
+ menu ? /* @__PURE__ */ jsx(CardMenu, { menu }) : null
123
+ ] }),
124
+ /* @__PURE__ */ jsx("div", { className: "mt-2 text-2xl font-semibold tracking-tight text-slate-900 dark:text-slate-50", children: isNumber ? /* @__PURE__ */ jsx(MotionNumber, { value }) : value }),
125
+ comparison ? /* @__PURE__ */ jsx(ComparisonLine, { comparison }) : null,
126
+ hint && /* @__PURE__ */ jsx("div", { className: `${comparison ? "mt-1" : "mt-2"} text-xs text-slate-400 dark:text-slate-500`, children: hint })
39
127
  ] }) }),
40
128
  showSpark && (showLoading ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 right-0 w-1/2 opacity-90", children: /* @__PURE__ */ jsx("div", { className: "fx-skeleton h-full w-full", style: { borderRadius: 0 } }) }) : null),
41
129
  !showLoading && spark && spark.values.length > 1 && /* @__PURE__ */ jsx(AutoSize, { className: "pointer-events-none absolute inset-y-0 right-0 w-1/2 opacity-90", children: ({ width, height }) => /* @__PURE__ */ jsxs(
package/dist/Table.js CHANGED
@@ -46,11 +46,71 @@ function useMounted() {
46
46
  import_react.default.useEffect(() => setMounted(true), []);
47
47
  return mounted;
48
48
  }
49
+ const TableColumnResizeContext = import_react.default.createContext(null);
49
50
  function cx(...a) {
50
51
  return a.filter(Boolean).join(" ");
51
52
  }
53
+ function clamp(value, min, max) {
54
+ return Math.max(min, Math.min(max, value));
55
+ }
56
+ function toNumericWidth(value) {
57
+ if (typeof value === "number" && Number.isFinite(value)) return value;
58
+ if (typeof value !== "string") return void 0;
59
+ const normalized = value.trim().toLowerCase();
60
+ if (!normalized.endsWith("px")) return void 0;
61
+ const parsed = Number.parseFloat(normalized.slice(0, -2));
62
+ return Number.isFinite(parsed) ? parsed : void 0;
63
+ }
52
64
  const Table = import_react.default.forwardRef(function Table2({ className, dense = false, children, ...rest }, ref) {
53
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-full overflow-x-auto overscroll-x-contain", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
65
+ const [widths, setWidths] = import_react.default.useState({});
66
+ const resizingRef = import_react.default.useRef(null);
67
+ const resolveWidth = import_react.default.useCallback((colKey, fallbackW, minW, maxW) => {
68
+ const current = widths[colKey];
69
+ if (typeof current !== "number") {
70
+ return fallbackW;
71
+ }
72
+ const min = typeof minW === "number" ? minW : 72;
73
+ const max = typeof maxW === "number" ? maxW : 920;
74
+ return Math.round(clamp(current, min, max));
75
+ }, [widths]);
76
+ const onGripDown = import_react.default.useCallback((colKey, e, options) => {
77
+ var _a, _b;
78
+ e.preventDefault();
79
+ e.stopPropagation();
80
+ const th = e.currentTarget.closest("th");
81
+ const measured = th == null ? void 0 : th.getBoundingClientRect().width;
82
+ const fallback = toNumericWidth(options == null ? void 0 : options.fallbackW);
83
+ const startW = typeof measured === "number" && measured > 0 ? measured : (_b = (_a = widths[colKey]) != null ? _a : fallback) != null ? _b : 140;
84
+ const min = typeof (options == null ? void 0 : options.minW) === "number" ? options.minW : Math.min(startW, 72);
85
+ const max = typeof (options == null ? void 0 : options.maxW) === "number" ? options.maxW : 920;
86
+ resizingRef.current = {
87
+ key: colKey,
88
+ startX: e.clientX,
89
+ startW,
90
+ min,
91
+ max
92
+ };
93
+ const onMove = (ev) => {
94
+ const state = resizingRef.current;
95
+ if (!state) return;
96
+ const next = clamp(state.startW + (ev.clientX - state.startX), state.min, state.max);
97
+ setWidths((prev) => ({ ...prev, [state.key]: Math.round(next) }));
98
+ };
99
+ const onUp = () => {
100
+ resizingRef.current = null;
101
+ window.removeEventListener("pointermove", onMove);
102
+ window.removeEventListener("pointerup", onUp);
103
+ window.removeEventListener("pointercancel", onUp);
104
+ };
105
+ window.addEventListener("pointermove", onMove);
106
+ window.addEventListener("pointerup", onUp);
107
+ window.addEventListener("pointercancel", onUp);
108
+ }, [widths]);
109
+ const contextValue = import_react.default.useMemo(() => ({
110
+ resolveWidth,
111
+ onGripDown
112
+ }), [onGripDown, resolveWidth]);
113
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableColumnResizeContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-full overflow-x-auto overscroll-x-contain", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
54
114
  "table",
55
115
  {
56
116
  ref,
@@ -62,7 +122,7 @@ const Table = import_react.default.forwardRef(function Table2({ className, dense
62
122
  ...rest,
63
123
  children
64
124
  }
65
- ) });
125
+ ) }) });
66
126
  });
67
127
  function Th({
68
128
  children,
@@ -76,7 +136,20 @@ function Th({
76
136
  onGripDown
77
137
  }) {
78
138
  const mounted = useMounted();
79
- const widthStyle = typeof w === "number" ? `${w}px` : typeof w === "string" ? w : void 0;
139
+ const resizeContext = import_react.default.useContext(TableColumnResizeContext);
140
+ const resolvedW = mounted && resizeContext && resizable && colKey && !onGripDown ? resizeContext.resolveWidth(colKey, w, minW, maxW) : w;
141
+ const widthStyle = typeof resolvedW === "number" ? `${resolvedW}px` : typeof resolvedW === "string" ? resolvedW : void 0;
142
+ const handleGripDown = (key, e) => {
143
+ if (onGripDown) {
144
+ onGripDown(key, e);
145
+ return;
146
+ }
147
+ resizeContext == null ? void 0 : resizeContext.onGripDown(key, e, {
148
+ fallbackW: w,
149
+ minW,
150
+ maxW
151
+ });
152
+ };
80
153
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
81
154
  "th",
82
155
  {
@@ -92,7 +165,7 @@ function Th({
92
165
  mounted && resizable && colKey && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
93
166
  "span",
94
167
  {
95
- onPointerDown: (e) => onGripDown == null ? void 0 : onGripDown(colKey, e),
168
+ onPointerDown: (e) => handleGripDown(colKey, e),
96
169
  className: "\n absolute right-0 top-0 h-full w-2 cursor-col-resize\n bg-transparent hover:bg-slate-300/40 dark:hover:bg-white/10\n after:absolute after:inset-y-0 after:left-1/2 after:w-px after:bg-slate-300/80 dark:after:bg-white/20\n ",
97
170
  style: { transform: "translateX(50%)" },
98
171
  title: "Arrastra para ajustar el ancho",
@@ -120,7 +193,20 @@ function SortTh({
120
193
  onGripDown
121
194
  }) {
122
195
  const mounted = useMounted();
123
- const widthStyle = typeof w === "number" ? `${w}px` : typeof w === "string" ? w : void 0;
196
+ const resizeContext = import_react.default.useContext(TableColumnResizeContext);
197
+ const resolvedW = mounted && resizeContext && resizable && colKey && !onGripDown ? resizeContext.resolveWidth(colKey, w, minW, maxW) : w;
198
+ const widthStyle = typeof resolvedW === "number" ? `${resolvedW}px` : typeof resolvedW === "string" ? resolvedW : void 0;
199
+ const handleGripDown = (key, e) => {
200
+ if (onGripDown) {
201
+ onGripDown(key, e);
202
+ return;
203
+ }
204
+ resizeContext == null ? void 0 : resizeContext.onGripDown(key, e, {
205
+ fallbackW: w,
206
+ minW,
207
+ maxW
208
+ });
209
+ };
124
210
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
125
211
  "th",
126
212
  {
@@ -185,7 +271,7 @@ function SortTh({
185
271
  mounted && resizable && colKey && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
186
272
  "span",
187
273
  {
188
- onPointerDown: (e) => onGripDown == null ? void 0 : onGripDown(colKey, e),
274
+ onPointerDown: (e) => handleGripDown(colKey, e),
189
275
  className: "\n absolute right-0 top-0 h-full w-2 cursor-col-resize\n bg-transparent hover:bg-slate-300/40 dark:hover:bg-white/10\n after:absolute after:inset-y-0 after:left-1/2 after:w-px after:bg-slate-300/80 dark:after:bg-white/20\n ",
190
276
  style: { transform: "translateX(50%)" },
191
277
  title: "Arrastra para ajustar el ancho",
package/dist/Table.mjs CHANGED
@@ -9,11 +9,71 @@ function useMounted() {
9
9
  React.useEffect(() => setMounted(true), []);
10
10
  return mounted;
11
11
  }
12
+ const TableColumnResizeContext = React.createContext(null);
12
13
  function cx(...a) {
13
14
  return a.filter(Boolean).join(" ");
14
15
  }
16
+ function clamp(value, min, max) {
17
+ return Math.max(min, Math.min(max, value));
18
+ }
19
+ function toNumericWidth(value) {
20
+ if (typeof value === "number" && Number.isFinite(value)) return value;
21
+ if (typeof value !== "string") return void 0;
22
+ const normalized = value.trim().toLowerCase();
23
+ if (!normalized.endsWith("px")) return void 0;
24
+ const parsed = Number.parseFloat(normalized.slice(0, -2));
25
+ return Number.isFinite(parsed) ? parsed : void 0;
26
+ }
15
27
  const Table = React.forwardRef(function Table2({ className, dense = false, children, ...rest }, ref) {
16
- return /* @__PURE__ */ jsx("div", { className: "w-full overflow-x-auto overscroll-x-contain", children: /* @__PURE__ */ jsx(
28
+ const [widths, setWidths] = React.useState({});
29
+ const resizingRef = React.useRef(null);
30
+ const resolveWidth = React.useCallback((colKey, fallbackW, minW, maxW) => {
31
+ const current = widths[colKey];
32
+ if (typeof current !== "number") {
33
+ return fallbackW;
34
+ }
35
+ const min = typeof minW === "number" ? minW : 72;
36
+ const max = typeof maxW === "number" ? maxW : 920;
37
+ return Math.round(clamp(current, min, max));
38
+ }, [widths]);
39
+ const onGripDown = React.useCallback((colKey, e, options) => {
40
+ var _a, _b;
41
+ e.preventDefault();
42
+ e.stopPropagation();
43
+ const th = e.currentTarget.closest("th");
44
+ const measured = th == null ? void 0 : th.getBoundingClientRect().width;
45
+ const fallback = toNumericWidth(options == null ? void 0 : options.fallbackW);
46
+ const startW = typeof measured === "number" && measured > 0 ? measured : (_b = (_a = widths[colKey]) != null ? _a : fallback) != null ? _b : 140;
47
+ const min = typeof (options == null ? void 0 : options.minW) === "number" ? options.minW : Math.min(startW, 72);
48
+ const max = typeof (options == null ? void 0 : options.maxW) === "number" ? options.maxW : 920;
49
+ resizingRef.current = {
50
+ key: colKey,
51
+ startX: e.clientX,
52
+ startW,
53
+ min,
54
+ max
55
+ };
56
+ const onMove = (ev) => {
57
+ const state = resizingRef.current;
58
+ if (!state) return;
59
+ const next = clamp(state.startW + (ev.clientX - state.startX), state.min, state.max);
60
+ setWidths((prev) => ({ ...prev, [state.key]: Math.round(next) }));
61
+ };
62
+ const onUp = () => {
63
+ resizingRef.current = null;
64
+ window.removeEventListener("pointermove", onMove);
65
+ window.removeEventListener("pointerup", onUp);
66
+ window.removeEventListener("pointercancel", onUp);
67
+ };
68
+ window.addEventListener("pointermove", onMove);
69
+ window.addEventListener("pointerup", onUp);
70
+ window.addEventListener("pointercancel", onUp);
71
+ }, [widths]);
72
+ const contextValue = React.useMemo(() => ({
73
+ resolveWidth,
74
+ onGripDown
75
+ }), [onGripDown, resolveWidth]);
76
+ return /* @__PURE__ */ jsx(TableColumnResizeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { className: "w-full overflow-x-auto overscroll-x-contain", children: /* @__PURE__ */ jsx(
17
77
  "table",
18
78
  {
19
79
  ref,
@@ -25,7 +85,7 @@ const Table = React.forwardRef(function Table2({ className, dense = false, child
25
85
  ...rest,
26
86
  children
27
87
  }
28
- ) });
88
+ ) }) });
29
89
  });
30
90
  function Th({
31
91
  children,
@@ -39,7 +99,20 @@ function Th({
39
99
  onGripDown
40
100
  }) {
41
101
  const mounted = useMounted();
42
- const widthStyle = typeof w === "number" ? `${w}px` : typeof w === "string" ? w : void 0;
102
+ const resizeContext = React.useContext(TableColumnResizeContext);
103
+ const resolvedW = mounted && resizeContext && resizable && colKey && !onGripDown ? resizeContext.resolveWidth(colKey, w, minW, maxW) : w;
104
+ const widthStyle = typeof resolvedW === "number" ? `${resolvedW}px` : typeof resolvedW === "string" ? resolvedW : void 0;
105
+ const handleGripDown = (key, e) => {
106
+ if (onGripDown) {
107
+ onGripDown(key, e);
108
+ return;
109
+ }
110
+ resizeContext == null ? void 0 : resizeContext.onGripDown(key, e, {
111
+ fallbackW: w,
112
+ minW,
113
+ maxW
114
+ });
115
+ };
43
116
  return /* @__PURE__ */ jsxs(
44
117
  "th",
45
118
  {
@@ -55,7 +128,7 @@ function Th({
55
128
  mounted && resizable && colKey && /* @__PURE__ */ jsx(
56
129
  "span",
57
130
  {
58
- onPointerDown: (e) => onGripDown == null ? void 0 : onGripDown(colKey, e),
131
+ onPointerDown: (e) => handleGripDown(colKey, e),
59
132
  className: "\n absolute right-0 top-0 h-full w-2 cursor-col-resize\n bg-transparent hover:bg-slate-300/40 dark:hover:bg-white/10\n after:absolute after:inset-y-0 after:left-1/2 after:w-px after:bg-slate-300/80 dark:after:bg-white/20\n ",
60
133
  style: { transform: "translateX(50%)" },
61
134
  title: "Arrastra para ajustar el ancho",
@@ -83,7 +156,20 @@ function SortTh({
83
156
  onGripDown
84
157
  }) {
85
158
  const mounted = useMounted();
86
- const widthStyle = typeof w === "number" ? `${w}px` : typeof w === "string" ? w : void 0;
159
+ const resizeContext = React.useContext(TableColumnResizeContext);
160
+ const resolvedW = mounted && resizeContext && resizable && colKey && !onGripDown ? resizeContext.resolveWidth(colKey, w, minW, maxW) : w;
161
+ const widthStyle = typeof resolvedW === "number" ? `${resolvedW}px` : typeof resolvedW === "string" ? resolvedW : void 0;
162
+ const handleGripDown = (key, e) => {
163
+ if (onGripDown) {
164
+ onGripDown(key, e);
165
+ return;
166
+ }
167
+ resizeContext == null ? void 0 : resizeContext.onGripDown(key, e, {
168
+ fallbackW: w,
169
+ minW,
170
+ maxW
171
+ });
172
+ };
87
173
  return /* @__PURE__ */ jsxs(
88
174
  "th",
89
175
  {
@@ -148,7 +234,7 @@ function SortTh({
148
234
  mounted && resizable && colKey && /* @__PURE__ */ jsx(
149
235
  "span",
150
236
  {
151
- onPointerDown: (e) => onGripDown == null ? void 0 : onGripDown(colKey, e),
237
+ onPointerDown: (e) => handleGripDown(colKey, e),
152
238
  className: "\n absolute right-0 top-0 h-full w-2 cursor-col-resize\n bg-transparent hover:bg-slate-300/40 dark:hover:bg-white/10\n after:absolute after:inset-y-0 after:left-1/2 after:w-px after:bg-slate-300/80 dark:after:bg-white/20\n ",
153
239
  style: { transform: "translateX(50%)" },
154
240
  title: "Arrastra para ajustar el ancho",
@@ -0,0 +1,7 @@
1
+ export { CtrHorizontalBar, DestinoDonut, TopImpresionesBar } from './AnalyticsCharts.mjs';
2
+ export { BarSeries, default as RechartsBarCard, RechartsBarCardProps } from './RechartsBarCard.mjs';
3
+ export { LineSeries, default as RechartsTimeSeriesCard, RechartsTimeSeriesCardProps } from './RechartsTimeSeriesCard.mjs';
4
+ export { default as RechartsDonutCard, RechartsDonutCardProps } from './RechartsDonutCard.mjs';
5
+ export { default as StatCard, StatCardComparison, StatCardComparisonPeriod, StatCardComparisonTrend, StatCardMenu, StatCardMenuItem, StatCardProps } from './StatCard.mjs';
6
+ import 'react/jsx-runtime';
7
+ import 'react';
@@ -0,0 +1,7 @@
1
+ export { CtrHorizontalBar, DestinoDonut, TopImpresionesBar } from './AnalyticsCharts.js';
2
+ export { BarSeries, default as RechartsBarCard, RechartsBarCardProps } from './RechartsBarCard.js';
3
+ export { LineSeries, default as RechartsTimeSeriesCard, RechartsTimeSeriesCardProps } from './RechartsTimeSeriesCard.js';
4
+ export { default as RechartsDonutCard, RechartsDonutCardProps } from './RechartsDonutCard.js';
5
+ export { default as StatCard, StatCardComparison, StatCardComparisonPeriod, StatCardComparisonTrend, StatCardMenu, StatCardMenuItem, StatCardProps } from './StatCard.js';
6
+ import 'react/jsx-runtime';
7
+ import 'react';
package/dist/charts.js ADDED
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var charts_exports = {};
30
+ __export(charts_exports, {
31
+ CtrHorizontalBar: () => import_AnalyticsCharts.CtrHorizontalBar,
32
+ DestinoDonut: () => import_AnalyticsCharts.DestinoDonut,
33
+ RechartsBarCard: () => import_RechartsBarCard.default,
34
+ RechartsDonutCard: () => import_RechartsDonutCard.default,
35
+ RechartsTimeSeriesCard: () => import_RechartsTimeSeriesCard.default,
36
+ StatCard: () => import_StatCard.default,
37
+ TopImpresionesBar: () => import_AnalyticsCharts.TopImpresionesBar
38
+ });
39
+ module.exports = __toCommonJS(charts_exports);
40
+ var import_AnalyticsCharts = require("./AnalyticsCharts");
41
+ var import_RechartsBarCard = __toESM(require("./RechartsBarCard"));
42
+ var import_RechartsTimeSeriesCard = __toESM(require("./RechartsTimeSeriesCard"));
43
+ var import_RechartsDonutCard = __toESM(require("./RechartsDonutCard"));
44
+ var import_StatCard = __toESM(require("./StatCard"));
45
+ // Annotate the CommonJS export names for ESM import in node:
46
+ 0 && (module.exports = {
47
+ CtrHorizontalBar,
48
+ DestinoDonut,
49
+ RechartsBarCard,
50
+ RechartsDonutCard,
51
+ RechartsTimeSeriesCard,
52
+ StatCard,
53
+ TopImpresionesBar
54
+ });
@@ -0,0 +1,14 @@
1
+ import { TopImpresionesBar, CtrHorizontalBar, DestinoDonut } from "./AnalyticsCharts.mjs";
2
+ import { default as default2 } from "./RechartsBarCard.mjs";
3
+ import { default as default3 } from "./RechartsTimeSeriesCard.mjs";
4
+ import { default as default4 } from "./RechartsDonutCard.mjs";
5
+ import { default as default5 } from "./StatCard.mjs";
6
+ export {
7
+ CtrHorizontalBar,
8
+ DestinoDonut,
9
+ default2 as RechartsBarCard,
10
+ default4 as RechartsDonutCard,
11
+ default3 as RechartsTimeSeriesCard,
12
+ default5 as StatCard,
13
+ TopImpresionesBar
14
+ };
package/dist/index.d.mts CHANGED
@@ -22,15 +22,10 @@ export { default as TableRecordButton } from './TableRecordButton.mjs';
22
22
  export { default as Pagination, PaginationProps } from './Pagination.mjs';
23
23
  export { default as InfoGrid, InfoItem } from './InfoGrid.mjs';
24
24
  export { default as ChartCard } from './ChartCard.mjs';
25
- export { CtrHorizontalBar, DestinoDonut, TopImpresionesBar } from './AnalyticsCharts.mjs';
26
- export { BarSeries, default as RechartsBarCard, RechartsBarCardProps } from './RechartsBarCard.mjs';
27
- export { LineSeries, default as RechartsTimeSeriesCard, RechartsTimeSeriesCardProps } from './RechartsTimeSeriesCard.mjs';
28
- export { default as RechartsDonutCard, RechartsDonutCardProps } from './RechartsDonutCard.mjs';
29
25
  export { default as UploadCard, UploadCardProps, UploadItem } from './UploadCard.mjs';
30
26
  export { default as MediaCard, MediaCardProps } from './MediaCard.mjs';
31
27
  export { default as MediaTile, MediaTileProps } from './MediaTile.mjs';
32
28
  export { default as MediaSelector, MediaSelectorItem, MediosAdapter } from './MediaSelector.mjs';
33
- export { default as StatCard, StatCardProps } from './StatCard.mjs';
34
29
  export { default as KpiCard, KpiCardProps } from './KpiCard.mjs';
35
30
  export { default as Badge, Tone as BadgeTone } from './Badge.mjs';
36
31
  export { default as BadgeCluster } from './BadgeCluster.mjs';