@almadar/ui 4.19.3 → 4.21.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.
@@ -3951,7 +3951,7 @@ var init_RangeSlider = __esm({
3951
3951
  action,
3952
3952
  actionPayload,
3953
3953
  onChange,
3954
- formatValue: formatValue5,
3954
+ formatValue: formatValue4,
3955
3955
  ...props
3956
3956
  }, ref) => {
3957
3957
  const [isDragging, setIsDragging] = React113.useState(false);
@@ -3960,7 +3960,7 @@ var init_RangeSlider = __esm({
3960
3960
  const eventBus = useSafeEventBus();
3961
3961
  const percentage = max !== min ? (value - min) / (max - min) * 100 : 0;
3962
3962
  const bufferedPercentage = buffered !== void 0 ? Math.min(buffered, 100) : void 0;
3963
- const displayValue = formatValue5 ? formatValue5(value) : String(value);
3963
+ const displayValue = formatValue4 ? formatValue4(value) : String(value);
3964
3964
  const handleChange = React113.useCallback(
3965
3965
  (e) => {
3966
3966
  const newValue = Number(e.target.value);
@@ -16859,6 +16859,7 @@ var init_Tabs = __esm({
16859
16859
  defaultActiveTab,
16860
16860
  activeTab: controlledActiveTab,
16861
16861
  onTabChange,
16862
+ tabChangeEvent,
16862
16863
  variant = "default",
16863
16864
  orientation = "horizontal",
16864
16865
  className
@@ -16881,6 +16882,9 @@ var init_Tabs = __esm({
16881
16882
  setInternalActiveTab(tabId);
16882
16883
  }
16883
16884
  onTabChange?.(tabId);
16885
+ if (tabChangeEvent) {
16886
+ eventBus.emit(`UI:${tabChangeEvent}`, { tabId });
16887
+ }
16884
16888
  if (tabEvent) {
16885
16889
  eventBus.emit(`UI:${tabEvent}`, { tabId });
16886
16890
  }
@@ -16961,7 +16965,7 @@ var init_Tabs = __esm({
16961
16965
  isActive ? variant === "pills" ? "text-primary-foreground font-bold" : "text-foreground font-bold" : "text-muted-foreground hover:text-foreground"
16962
16966
  ),
16963
16967
  children: [
16964
- item.icon && /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: item.icon, size: "sm" }),
16968
+ item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: item.icon, size: "sm" }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: item.icon, size: "sm" })),
16965
16969
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: isActive ? "semibold" : "normal", className: "!text-inherit", children: item.label }),
16966
16970
  item.badge !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", children: item.badge })
16967
16971
  ]
@@ -23907,25 +23911,24 @@ var init_Lightbox = __esm({
23907
23911
  Lightbox.displayName = "Lightbox";
23908
23912
  }
23909
23913
  });
23910
- function formatValue3(value, format, max) {
23914
+ function formatNumber(value, format) {
23911
23915
  if (value == null) return "0";
23912
23916
  const v = typeof value === "number" ? value : value;
23913
- let formatted;
23914
23917
  switch (format) {
23915
23918
  case "currency":
23916
- formatted = typeof v === "number" ? `$${v.toFixed(2)}` : String(v);
23917
- break;
23919
+ return typeof v === "number" ? `$${v.toFixed(2)}` : String(v);
23918
23920
  case "percent":
23919
- formatted = typeof v === "number" ? `${Math.round(v)}%` : String(v);
23920
- break;
23921
+ return typeof v === "number" ? `${Math.round(v)}%` : String(v);
23921
23922
  case "number":
23922
- formatted = typeof v === "number" ? v.toLocaleString() : String(v);
23923
- break;
23923
+ return typeof v === "number" ? v.toLocaleString() : String(v);
23924
23924
  default:
23925
- formatted = String(v);
23925
+ return String(v);
23926
23926
  }
23927
- if (max != null) return `${formatted} / ${max}`;
23928
- return formatted;
23927
+ }
23928
+ function composeDisplayValue(value, format, max, prefix, suffix) {
23929
+ const formatted = formatNumber(value, format);
23930
+ const withMax = max != null && max > 0 ? `${formatted} / ${max}` : formatted;
23931
+ return `${prefix ?? ""}${withMax}${suffix ?? ""}`;
23929
23932
  }
23930
23933
  var variantColor, StatDisplay;
23931
23934
  var init_StatDisplay = __esm({
@@ -23949,6 +23952,10 @@ var init_StatDisplay = __esm({
23949
23952
  label,
23950
23953
  value,
23951
23954
  max,
23955
+ target,
23956
+ trend,
23957
+ prefix,
23958
+ suffix,
23952
23959
  icon: iconProp,
23953
23960
  iconBg = "bg-muted",
23954
23961
  iconColor = "text-foreground",
@@ -23964,7 +23971,13 @@ var init_StatDisplay = __esm({
23964
23971
  const iconSizes2 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
23965
23972
  const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
23966
23973
  const padSizes = { sm: "p-3", md: "p-4", lg: "p-6" };
23967
- const displayValue = formatValue3(value, format, max);
23974
+ const displayValue = composeDisplayValue(value, format, max, prefix, suffix);
23975
+ const numericValue = typeof value === "number" ? value : Number(value);
23976
+ const showTarget = typeof target === "number" && target > 0 && Number.isFinite(numericValue);
23977
+ const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
23978
+ const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
23979
+ const trendUp = showTrend && trend > 0;
23980
+ const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${Math.abs(trend)}` : "";
23968
23981
  if (error) {
23969
23982
  return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "error", children: error.message }) });
23970
23983
  }
@@ -23979,13 +23992,31 @@ var init_StatDisplay = __esm({
23979
23992
  ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes2[size], iconColor) }),
23980
23993
  typeof iconProp !== "string" && iconProp,
23981
23994
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: label }),
23982
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue })
23995
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
23996
+ showTrend && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: cn("font-semibold", trendUp ? "text-success" : "text-error"), children: trendLabel })
23983
23997
  ] });
23984
23998
  }
23985
23999
  return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", justify: "between", children: [
23986
- /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1", children: [
24000
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
23987
24001
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "overline", color: "secondary", children: label }),
23988
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue })
24002
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "end", children: [
24003
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
24004
+ showTrend && /* @__PURE__ */ jsxRuntime.jsx(
24005
+ Typography,
24006
+ {
24007
+ variant: "caption",
24008
+ className: cn("font-semibold pb-1", trendUp ? "text-success" : "text-error"),
24009
+ children: trendLabel
24010
+ }
24011
+ )
24012
+ ] }),
24013
+ showTarget && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
24014
+ Box,
24015
+ {
24016
+ className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
24017
+ style: { width: `${targetPct}%` }
24018
+ }
24019
+ ) })
23989
24020
  ] }),
23990
24021
  (ResolvedIcon || typeof iconProp !== "string" && iconProp) && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-3 rounded-md", iconBg), children: ResolvedIcon ? /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes2[size], iconColor) }) : iconProp })
23991
24022
  ] }) });
@@ -30008,7 +30039,7 @@ function getStatusStyle(fieldName, value) {
30008
30039
  if (val.includes("low")) return STATUS_STYLES2.low;
30009
30040
  return STATUS_STYLES2.default;
30010
30041
  }
30011
- function formatValue4(value, fieldName) {
30042
+ function formatValue3(value, fieldName) {
30012
30043
  if (typeof value === "number") {
30013
30044
  if (fieldName.toLowerCase().includes("progress") || fieldName.toLowerCase().includes("percent")) {
30014
30045
  return `${value}%`;
@@ -30384,7 +30415,7 @@ var init_List = __esm({
30384
30415
  className: "flex items-center gap-2 text-muted-foreground group-hover:text-foreground transition-colors",
30385
30416
  children: [
30386
30417
  /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Calendar, { className: "w-3.5 h-3.5" }),
30387
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", children: formatValue4(value, field) })
30418
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", children: formatValue3(value, field) })
30388
30419
  ]
30389
30420
  },
30390
30421
  field
@@ -30403,7 +30434,7 @@ var init_List = __esm({
30403
30434
  formatFieldLabel2(field),
30404
30435
  ":"
30405
30436
  ] }),
30406
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", className: "text-foreground", children: formatValue4(value, field) })
30437
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", className: "text-foreground", children: formatValue3(value, field) })
30407
30438
  ]
30408
30439
  },
30409
30440
  field
@@ -38229,7 +38260,6 @@ function getSlotContentRenderer2() {
38229
38260
  }
38230
38261
  function makeLambdaFn(argName, lambdaBody, callerKey) {
38231
38262
  return (item, index) => {
38232
- console.log(`[lambda-triage:${callerKey}#${index}]`, JSON.stringify(item));
38233
38263
  const resolvedBody = resolveLambdaBindings(lambdaBody, argName, item);
38234
38264
  if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody)) {
38235
38265
  return null;
@@ -3906,7 +3906,7 @@ var init_RangeSlider = __esm({
3906
3906
  action,
3907
3907
  actionPayload,
3908
3908
  onChange,
3909
- formatValue: formatValue5,
3909
+ formatValue: formatValue4,
3910
3910
  ...props
3911
3911
  }, ref) => {
3912
3912
  const [isDragging, setIsDragging] = useState(false);
@@ -3915,7 +3915,7 @@ var init_RangeSlider = __esm({
3915
3915
  const eventBus = useSafeEventBus();
3916
3916
  const percentage = max !== min ? (value - min) / (max - min) * 100 : 0;
3917
3917
  const bufferedPercentage = buffered !== void 0 ? Math.min(buffered, 100) : void 0;
3918
- const displayValue = formatValue5 ? formatValue5(value) : String(value);
3918
+ const displayValue = formatValue4 ? formatValue4(value) : String(value);
3919
3919
  const handleChange = useCallback(
3920
3920
  (e) => {
3921
3921
  const newValue = Number(e.target.value);
@@ -16814,6 +16814,7 @@ var init_Tabs = __esm({
16814
16814
  defaultActiveTab,
16815
16815
  activeTab: controlledActiveTab,
16816
16816
  onTabChange,
16817
+ tabChangeEvent,
16817
16818
  variant = "default",
16818
16819
  orientation = "horizontal",
16819
16820
  className
@@ -16836,6 +16837,9 @@ var init_Tabs = __esm({
16836
16837
  setInternalActiveTab(tabId);
16837
16838
  }
16838
16839
  onTabChange?.(tabId);
16840
+ if (tabChangeEvent) {
16841
+ eventBus.emit(`UI:${tabChangeEvent}`, { tabId });
16842
+ }
16839
16843
  if (tabEvent) {
16840
16844
  eventBus.emit(`UI:${tabEvent}`, { tabId });
16841
16845
  }
@@ -16916,7 +16920,7 @@ var init_Tabs = __esm({
16916
16920
  isActive ? variant === "pills" ? "text-primary-foreground font-bold" : "text-foreground font-bold" : "text-muted-foreground hover:text-foreground"
16917
16921
  ),
16918
16922
  children: [
16919
- item.icon && /* @__PURE__ */ jsx(Icon, { icon: item.icon, size: "sm" }),
16923
+ item.icon && (typeof item.icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: item.icon, size: "sm" }) : /* @__PURE__ */ jsx(Icon, { icon: item.icon, size: "sm" })),
16920
16924
  /* @__PURE__ */ jsx(Typography, { variant: "small", weight: isActive ? "semibold" : "normal", className: "!text-inherit", children: item.label }),
16921
16925
  item.badge !== void 0 && /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: item.badge })
16922
16926
  ]
@@ -23862,25 +23866,24 @@ var init_Lightbox = __esm({
23862
23866
  Lightbox.displayName = "Lightbox";
23863
23867
  }
23864
23868
  });
23865
- function formatValue3(value, format, max) {
23869
+ function formatNumber(value, format) {
23866
23870
  if (value == null) return "0";
23867
23871
  const v = typeof value === "number" ? value : value;
23868
- let formatted;
23869
23872
  switch (format) {
23870
23873
  case "currency":
23871
- formatted = typeof v === "number" ? `$${v.toFixed(2)}` : String(v);
23872
- break;
23874
+ return typeof v === "number" ? `$${v.toFixed(2)}` : String(v);
23873
23875
  case "percent":
23874
- formatted = typeof v === "number" ? `${Math.round(v)}%` : String(v);
23875
- break;
23876
+ return typeof v === "number" ? `${Math.round(v)}%` : String(v);
23876
23877
  case "number":
23877
- formatted = typeof v === "number" ? v.toLocaleString() : String(v);
23878
- break;
23878
+ return typeof v === "number" ? v.toLocaleString() : String(v);
23879
23879
  default:
23880
- formatted = String(v);
23880
+ return String(v);
23881
23881
  }
23882
- if (max != null) return `${formatted} / ${max}`;
23883
- return formatted;
23882
+ }
23883
+ function composeDisplayValue(value, format, max, prefix, suffix) {
23884
+ const formatted = formatNumber(value, format);
23885
+ const withMax = max != null && max > 0 ? `${formatted} / ${max}` : formatted;
23886
+ return `${prefix ?? ""}${withMax}${suffix ?? ""}`;
23884
23887
  }
23885
23888
  var variantColor, StatDisplay;
23886
23889
  var init_StatDisplay = __esm({
@@ -23904,6 +23907,10 @@ var init_StatDisplay = __esm({
23904
23907
  label,
23905
23908
  value,
23906
23909
  max,
23910
+ target,
23911
+ trend,
23912
+ prefix,
23913
+ suffix,
23907
23914
  icon: iconProp,
23908
23915
  iconBg = "bg-muted",
23909
23916
  iconColor = "text-foreground",
@@ -23919,7 +23926,13 @@ var init_StatDisplay = __esm({
23919
23926
  const iconSizes2 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
23920
23927
  const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
23921
23928
  const padSizes = { sm: "p-3", md: "p-4", lg: "p-6" };
23922
- const displayValue = formatValue3(value, format, max);
23929
+ const displayValue = composeDisplayValue(value, format, max, prefix, suffix);
23930
+ const numericValue = typeof value === "number" ? value : Number(value);
23931
+ const showTarget = typeof target === "number" && target > 0 && Number.isFinite(numericValue);
23932
+ const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
23933
+ const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
23934
+ const trendUp = showTrend && trend > 0;
23935
+ const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${Math.abs(trend)}` : "";
23923
23936
  if (error) {
23924
23937
  return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "error", children: error.message }) });
23925
23938
  }
@@ -23934,13 +23947,31 @@ var init_StatDisplay = __esm({
23934
23947
  ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes2[size], iconColor) }),
23935
23948
  typeof iconProp !== "string" && iconProp,
23936
23949
  /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
23937
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue })
23950
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
23951
+ showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendUp ? "text-success" : "text-error"), children: trendLabel })
23938
23952
  ] });
23939
23953
  }
23940
23954
  return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
23941
- /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1", children: [
23955
+ /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
23942
23956
  /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
23943
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue })
23957
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
23958
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
23959
+ showTrend && /* @__PURE__ */ jsx(
23960
+ Typography,
23961
+ {
23962
+ variant: "caption",
23963
+ className: cn("font-semibold pb-1", trendUp ? "text-success" : "text-error"),
23964
+ children: trendLabel
23965
+ }
23966
+ )
23967
+ ] }),
23968
+ showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
23969
+ Box,
23970
+ {
23971
+ className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
23972
+ style: { width: `${targetPct}%` }
23973
+ }
23974
+ ) })
23944
23975
  ] }),
23945
23976
  (ResolvedIcon || typeof iconProp !== "string" && iconProp) && /* @__PURE__ */ jsx(Box, { className: cn("p-3 rounded-md", iconBg), children: ResolvedIcon ? /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes2[size], iconColor) }) : iconProp })
23946
23977
  ] }) });
@@ -29963,7 +29994,7 @@ function getStatusStyle(fieldName, value) {
29963
29994
  if (val.includes("low")) return STATUS_STYLES2.low;
29964
29995
  return STATUS_STYLES2.default;
29965
29996
  }
29966
- function formatValue4(value, fieldName) {
29997
+ function formatValue3(value, fieldName) {
29967
29998
  if (typeof value === "number") {
29968
29999
  if (fieldName.toLowerCase().includes("progress") || fieldName.toLowerCase().includes("percent")) {
29969
30000
  return `${value}%`;
@@ -30339,7 +30370,7 @@ var init_List = __esm({
30339
30370
  className: "flex items-center gap-2 text-muted-foreground group-hover:text-foreground transition-colors",
30340
30371
  children: [
30341
30372
  /* @__PURE__ */ jsx(Calendar, { className: "w-3.5 h-3.5" }),
30342
- /* @__PURE__ */ jsx(Typography, { as: "span", children: formatValue4(value, field) })
30373
+ /* @__PURE__ */ jsx(Typography, { as: "span", children: formatValue3(value, field) })
30343
30374
  ]
30344
30375
  },
30345
30376
  field
@@ -30358,7 +30389,7 @@ var init_List = __esm({
30358
30389
  formatFieldLabel2(field),
30359
30390
  ":"
30360
30391
  ] }),
30361
- /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-foreground", children: formatValue4(value, field) })
30392
+ /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-foreground", children: formatValue3(value, field) })
30362
30393
  ]
30363
30394
  },
30364
30395
  field
@@ -38184,7 +38215,6 @@ function getSlotContentRenderer2() {
38184
38215
  }
38185
38216
  function makeLambdaFn(argName, lambdaBody, callerKey) {
38186
38217
  return (item, index) => {
38187
- console.log(`[lambda-triage:${callerKey}#${index}]`, JSON.stringify(item));
38188
38218
  const resolvedBody = resolveLambdaBindings(lambdaBody, argName, item);
38189
38219
  if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody)) {
38190
38220
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "4.19.3",
3
+ "version": "4.21.0",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "main": "./dist/components/index.js",