@pos-360/horizon 0.23.0 → 0.25.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.
@@ -117,6 +117,159 @@ var Dashboard = forwardRef(
117
117
  }
118
118
  );
119
119
  Dashboard.displayName = "Dashboard";
120
+ var TrendBadge = ({ trend, size }) => {
121
+ const Icon = trend.direction === "up" ? TrendingUp : trend.direction === "down" ? TrendingDown : Minus;
122
+ const iconSize = size === "sm" ? "w-3 h-3" : "w-3.5 h-3.5";
123
+ return /* @__PURE__ */ jsxs(
124
+ "div",
125
+ {
126
+ className: cn(
127
+ "inline-flex items-center gap-1 px-2 py-0.5 rounded-hz-full font-medium",
128
+ size === "sm" && "text-xs",
129
+ size === "md" && "text-xs",
130
+ size === "lg" && "text-sm",
131
+ trend.direction === "up" && "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400",
132
+ trend.direction === "down" && "bg-rose-100 text-rose-700 dark:bg-rose-900/30 dark:text-rose-400",
133
+ trend.direction === "neutral" && "bg-gray-100 text-gray-600 dark:bg-neutral-800 dark:text-gray-400"
134
+ ),
135
+ children: [
136
+ /* @__PURE__ */ jsx(Icon, { className: iconSize }),
137
+ /* @__PURE__ */ jsx("span", { children: trend.value === null ? "N/A" : `${Math.abs(trend.value).toFixed(1)}%` })
138
+ ]
139
+ }
140
+ );
141
+ };
142
+ var StatDisplay = forwardRef(
143
+ ({ data, size = "md", className }, ref) => {
144
+ const { value, label, trend, prefix = "", suffix = "" } = data;
145
+ const formattedValue = useMemo(() => {
146
+ if (typeof value === "number") {
147
+ return value.toLocaleString("en-US", {
148
+ minimumFractionDigits: 0,
149
+ maximumFractionDigits: 2
150
+ });
151
+ }
152
+ return value;
153
+ }, [value]);
154
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex flex-col", className), children: [
155
+ /* @__PURE__ */ jsx(
156
+ Text,
157
+ {
158
+ as: "span",
159
+ size: "xs",
160
+ color: "muted",
161
+ className: "uppercase tracking-wide",
162
+ children: label
163
+ }
164
+ ),
165
+ /* @__PURE__ */ jsxs(
166
+ "span",
167
+ {
168
+ className: cn(
169
+ "font-bold text-gray-900 dark:text-gray-100 mt-0.5 font-mono",
170
+ size === "sm" && "text-lg",
171
+ size === "md" && "text-xl",
172
+ size === "lg" && "text-2xl"
173
+ ),
174
+ children: [
175
+ prefix,
176
+ formattedValue,
177
+ suffix
178
+ ]
179
+ }
180
+ ),
181
+ trend && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-1", children: [
182
+ /* @__PURE__ */ jsx(TrendBadge, { trend, size }),
183
+ trend.label && /* @__PURE__ */ jsx(Text, { as: "span", size: "xs", color: "muted", children: trend.label })
184
+ ] })
185
+ ] });
186
+ }
187
+ );
188
+ StatDisplay.displayName = "StatDisplay";
189
+ var KPI_CARD_ROWS = {
190
+ /** A single standard KpiCard (~80px) */
191
+ standard: 2,
192
+ /** The featured/hero variant (~110px) */
193
+ featured: 3,
194
+ /**
195
+ * A KpiCardGroup with one featured card + one row of supporting cards (~250px).
196
+ * Add 2 for each additional row of supporting cards.
197
+ */
198
+ group: 6
199
+ };
200
+ var LARGE_PANEL_HEADER_ROWS = 1;
201
+ function KpiCardGroup({
202
+ cards,
203
+ featured,
204
+ columns = 4,
205
+ gap = 4,
206
+ className
207
+ }) {
208
+ const colClass = {
209
+ 2: "grid-cols-2",
210
+ 3: "grid-cols-3",
211
+ 4: "grid-cols-2 md:grid-cols-4",
212
+ 5: "grid-cols-2 md:grid-cols-5"
213
+ };
214
+ const gapClass = `gap-${gap}`;
215
+ const featuredCard = featured ? cards.find((c) => c.id === featured) : null;
216
+ const supportingCards = featured ? cards.filter((c) => c.id !== featured) : cards;
217
+ const supportingCols = Math.min(supportingCards.length, columns);
218
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", gapClass, className), children: [
219
+ featuredCard && /* @__PURE__ */ jsx(KpiCard, { ...featuredCard, featured: true }),
220
+ supportingCards.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("grid", colClass[supportingCols], gapClass), children: supportingCards.map((card) => /* @__PURE__ */ jsx(KpiCard, { ...card, featured: false }, card.id)) })
221
+ ] });
222
+ }
223
+ function KpiCard({
224
+ label,
225
+ value,
226
+ prefix,
227
+ suffix,
228
+ trend,
229
+ size = "md",
230
+ featured = false,
231
+ className
232
+ }) {
233
+ const formattedValue = useMemo(() => {
234
+ if (typeof value === "number") {
235
+ return value.toLocaleString("en-US", { minimumFractionDigits: 0, maximumFractionDigits: 2 });
236
+ }
237
+ return value;
238
+ }, [value]);
239
+ if (featured) {
240
+ const Icon = trend?.direction === "up" ? TrendingUp : trend?.direction === "down" ? TrendingDown : Minus;
241
+ return /* @__PURE__ */ jsxs("div", { className: cn("p-4", className), children: [
242
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wide text-blue-500 dark:text-blue-400", children: label }),
243
+ /* @__PURE__ */ jsxs("p", { className: "text-4xl font-bold text-gray-900 dark:text-gray-100 mt-1 font-mono leading-none", children: [
244
+ prefix,
245
+ formattedValue,
246
+ suffix
247
+ ] }),
248
+ trend && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-2", children: [
249
+ /* @__PURE__ */ jsxs("span", { className: cn(
250
+ "inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium",
251
+ trend.direction === "up" && "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400",
252
+ trend.direction === "down" && "bg-rose-100 text-rose-700 dark:bg-rose-900/30 dark:text-rose-400",
253
+ trend.direction === "neutral" && "bg-gray-100 text-gray-600 dark:bg-neutral-800 dark:text-gray-400"
254
+ ), children: [
255
+ /* @__PURE__ */ jsx(Icon, { className: "w-3 h-3" }),
256
+ trend.value === null ? "N/A" : `${Math.abs(trend.value).toFixed(1)}%`
257
+ ] }),
258
+ trend.label && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: trend.label })
259
+ ] })
260
+ ] });
261
+ }
262
+ return /* @__PURE__ */ jsx("div", { className: cn(
263
+ "bg-white dark:bg-neutral-900 border border-gray-100 dark:border-neutral-800 rounded-lg p-4",
264
+ className
265
+ ), children: /* @__PURE__ */ jsx(
266
+ StatDisplay,
267
+ {
268
+ data: { label, value, prefix, suffix, trend },
269
+ size
270
+ }
271
+ ) });
272
+ }
120
273
  var breakpoints2 = {
121
274
  sm: 640,
122
275
  md: 768,
@@ -191,78 +344,6 @@ var DashboardPanel = forwardRef(
191
344
  }
192
345
  );
193
346
  DashboardPanel.displayName = "DashboardPanel";
194
- var TrendBadge = ({ trend, size }) => {
195
- const Icon = trend.direction === "up" ? TrendingUp : trend.direction === "down" ? TrendingDown : Minus;
196
- const iconSize = size === "sm" ? "w-3 h-3" : "w-3.5 h-3.5";
197
- return /* @__PURE__ */ jsxs(
198
- "div",
199
- {
200
- className: cn(
201
- "inline-flex items-center gap-1 px-2 py-0.5 rounded-hz-full font-medium",
202
- size === "sm" && "text-xs",
203
- size === "md" && "text-xs",
204
- size === "lg" && "text-sm",
205
- trend.direction === "up" && "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400",
206
- trend.direction === "down" && "bg-rose-100 text-rose-700 dark:bg-rose-900/30 dark:text-rose-400",
207
- trend.direction === "neutral" && "bg-gray-100 text-gray-600 dark:bg-neutral-800 dark:text-gray-400"
208
- ),
209
- children: [
210
- /* @__PURE__ */ jsx(Icon, { className: iconSize }),
211
- /* @__PURE__ */ jsxs("span", { children: [
212
- Math.abs(trend.value).toFixed(1),
213
- "%"
214
- ] })
215
- ]
216
- }
217
- );
218
- };
219
- var StatDisplay = forwardRef(
220
- ({ data, size = "md", className }, ref) => {
221
- const { value, label, trend, prefix = "", suffix = "" } = data;
222
- const formattedValue = useMemo(() => {
223
- if (typeof value === "number") {
224
- return value.toLocaleString("en-US", {
225
- minimumFractionDigits: 0,
226
- maximumFractionDigits: 2
227
- });
228
- }
229
- return value;
230
- }, [value]);
231
- return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex flex-col", className), children: [
232
- /* @__PURE__ */ jsx(
233
- Text,
234
- {
235
- as: "span",
236
- size: "xs",
237
- color: "muted",
238
- className: "uppercase tracking-wide",
239
- children: label
240
- }
241
- ),
242
- /* @__PURE__ */ jsxs(
243
- "span",
244
- {
245
- className: cn(
246
- "font-bold text-gray-900 dark:text-gray-100 mt-0.5",
247
- size === "sm" && "text-lg",
248
- size === "md" && "text-xl",
249
- size === "lg" && "text-2xl"
250
- ),
251
- children: [
252
- prefix,
253
- formattedValue,
254
- suffix
255
- ]
256
- }
257
- ),
258
- trend && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-1", children: [
259
- /* @__PURE__ */ jsx(TrendBadge, { trend, size }),
260
- trend.label && /* @__PURE__ */ jsx(Text, { as: "span", size: "xs", color: "muted", children: trend.label })
261
- ] })
262
- ] });
263
- }
264
- );
265
- StatDisplay.displayName = "StatDisplay";
266
347
  var defaultColors = [
267
348
  "#3b82f6",
268
349
  // blue-500
@@ -891,10 +972,7 @@ var TrendIndicator = ({ trend }) => {
891
972
  ),
892
973
  children: [
893
974
  /* @__PURE__ */ jsx(Icon, { className: "w-4 h-4" }),
894
- /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold", children: [
895
- Math.abs(trend.value).toFixed(1),
896
- "%"
897
- ] })
975
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: trend.value === null ? "N/A" : `${Math.abs(trend.value).toFixed(1)}%` })
898
976
  ]
899
977
  }
900
978
  );
@@ -2619,6 +2697,6 @@ var SideNavFooter = forwardRef(
2619
2697
  );
2620
2698
  SideNavFooter.displayName = "SideNavFooter";
2621
2699
 
2622
- export { AnimatedButton, ChartRenderer, CompactPanel, Dashboard, DashboardPanel, Input, LargePanel, MediumPanel, SideNav, SideNavFooter, SideNavHeader, SideNavItem, SideNavSection, StatDisplay, TableRenderer, TemplateSelector, TextButton, Toast, useDashboardContext, useSideNavContext };
2623
- //# sourceMappingURL=chunk-3TY2CM2C.mjs.map
2624
- //# sourceMappingURL=chunk-3TY2CM2C.mjs.map
2700
+ export { AnimatedButton, ChartRenderer, CompactPanel, Dashboard, DashboardPanel, Input, KPI_CARD_ROWS, KpiCard, KpiCardGroup, LARGE_PANEL_HEADER_ROWS, LargePanel, MediumPanel, SideNav, SideNavFooter, SideNavHeader, SideNavItem, SideNavSection, StatDisplay, TableRenderer, TemplateSelector, TextButton, Toast, useDashboardContext, useSideNavContext };
2701
+ //# sourceMappingURL=chunk-BFDGIY6V.mjs.map
2702
+ //# sourceMappingURL=chunk-BFDGIY6V.mjs.map