@pattern-stack/frontend-patterns 0.2.0-alpha.8 → 0.2.0-alpha.9

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 (29) hide show
  1. package/dist/atoms/components/core/Badge/Badge.d.ts +1 -1
  2. package/dist/atoms/components/data/DataTable/DataTable.d.ts +2 -2
  3. package/dist/atoms/components/data/DataTable/DataTable.d.ts.map +1 -1
  4. package/dist/atoms/components/data/DataTable/DataTable.types.d.ts +40 -2
  5. package/dist/atoms/components/data/DataTable/DataTable.types.d.ts.map +1 -1
  6. package/dist/atoms/hooks/index.d.ts +1 -0
  7. package/dist/atoms/hooks/index.d.ts.map +1 -1
  8. package/dist/atoms/hooks/useAdaptiveTable.d.ts +49 -0
  9. package/dist/atoms/hooks/useAdaptiveTable.d.ts.map +1 -0
  10. package/dist/atoms/hooks/useApi.d.ts +1 -1
  11. package/dist/atoms/hooks/useApi.d.ts.map +1 -1
  12. package/dist/atoms/hooks/useResponsiveTable.d.ts +44 -24
  13. package/dist/atoms/hooks/useResponsiveTable.d.ts.map +1 -1
  14. package/dist/atoms/shared/config/table-config.d.ts +79 -0
  15. package/dist/atoms/shared/config/table-config.d.ts.map +1 -0
  16. package/dist/atoms/shared/index.d.ts +1 -0
  17. package/dist/atoms/shared/index.d.ts.map +1 -1
  18. package/dist/atoms/utils/entity-card-mapping.d.ts +1 -1
  19. package/dist/atoms/utils/entity-card-mapping.d.ts.map +1 -1
  20. package/dist/atoms/utils/index.d.ts +1 -0
  21. package/dist/atoms/utils/index.d.ts.map +1 -1
  22. package/dist/index.es.js +917 -179
  23. package/dist/index.es.js.map +1 -1
  24. package/dist/index.js +915 -177
  25. package/dist/index.js.map +1 -1
  26. package/dist/molecules/layout/navigation-context.d.ts.map +1 -1
  27. package/dist/templates/factory.d.ts +11 -0
  28. package/dist/templates/factory.d.ts.map +1 -1
  29. package/package.json +5 -3
package/dist/index.es.js CHANGED
@@ -7,9 +7,9 @@ import { twMerge } from "tailwind-merge";
7
7
  import axios from "axios";
8
8
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
9
9
  import * as React from "react";
10
- import React__default, { useRef, useState, useEffect, useMemo, forwardRef, useCallback, useContext, createContext, useId, Component } from "react";
10
+ import React__default, { useRef, useState, useEffect, useMemo, forwardRef, useCallback, useContext, createContext, useId, Component, Suspense } from "react";
11
11
  import * as SheetPrimitive from "@radix-ui/react-dialog";
12
- import { Map as Map$1, Calculator, Brain, User, Handshake, Truck, Building, HelpCircle, Info, AlertCircle, Check, ArrowDown, ArrowUp, ArrowLeft, ArrowRight, ChevronUp, ChevronLeft, ChevronDown, ChevronRight, Music, Video, Image, Folder, File, Flag, Tag, Bookmark, Heart, Star, MapPin, Clock, Calendar, Phone, Mail, Unlock, Lock, Share, Upload, Download, Eye, Trash2, Edit, Plus, Search, Bell, Settings, Home, Layout, TrendingUp, Database, BarChart3, Users, Shield, X, Menu, Palette, Loader2, EyeOff, InfoIcon, Circle, ChevronsUpDown, AreaChart, LineChart, TrendingDown, Minus, AlertTriangle, Activity, WifiOff, CloudOff, Cloud, CheckCircle, FileX, Sun, Moon, LogOut, Square, Waves, Zap, TreePine, Sparkles, Sunset, Building2, DollarSign, ShoppingCart, Target, ExternalLink, MoreHorizontal, Filter, Edit2, Undo2, RefreshCw, FileText, History, Save, Copy, Grid3X3, Layers, XCircle, Briefcase } from "lucide-react";
12
+ import { Map as Map$1, Calculator, Brain, User, Handshake, Truck, Building, HelpCircle, Info, AlertCircle, Check, ArrowDown, ArrowUp, ArrowLeft, ArrowRight, ChevronUp, ChevronLeft, ChevronDown, ChevronRight, Music, Video, Image, Folder, File, Flag, Tag, Bookmark, Heart, Star, MapPin, Clock, Calendar, Phone, Mail, Unlock, Lock, Share, Upload, Download, Eye, Trash2, Edit, Plus, Search, Bell, Settings, Home, Layout, TrendingUp, Database, BarChart3, Users, Shield, X, Menu, Palette, Circle, Building2, Package, FileText, Loader2, EyeOff, InfoIcon, ChevronsUpDown, AreaChart, LineChart, TrendingDown, Minus, AlertTriangle, Activity, WifiOff, CloudOff, Cloud, CheckCircle, FileX, Sun, Moon, LogOut, Square, Waves, Zap, TreePine, Sparkles, Sunset, DollarSign, ShoppingCart, Target, ExternalLink, MoreHorizontal, Filter, Edit2, Undo2, RefreshCw, History, Save, Copy, Grid3X3, Layers, XCircle, Briefcase } from "lucide-react";
13
13
  import * as LabelPrimitive from "@radix-ui/react-label";
14
14
  import { cva } from "class-variance-authority";
15
15
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
@@ -136,6 +136,141 @@ const RESPONSIVE_CHART_HEIGHTS = {
136
136
  secondary: DASHBOARD_CHART_HEIGHTS.medium
137
137
  }
138
138
  };
139
+ const COLUMN_WIDTHS = {
140
+ // Text
141
+ text: 180,
142
+ password: 120,
143
+ // Numbers
144
+ number: 80,
145
+ money: 100,
146
+ percent: 70,
147
+ // Dates
148
+ date: 100,
149
+ datetime: 140,
150
+ // Contact/Links
151
+ email: 180,
152
+ phone: 120,
153
+ url: 160,
154
+ // Visual indicators
155
+ status: 90,
156
+ badge: 90,
157
+ boolean: 60,
158
+ rating: 80,
159
+ color: 60,
160
+ // Entity references
161
+ entity: 140,
162
+ user: 140,
163
+ // Special
164
+ image: 60,
165
+ file: 100,
166
+ json: 200
167
+ };
168
+ const COMPACT_COLUMN_WIDTHS = {
169
+ text: 120,
170
+ // With truncation
171
+ money: 60,
172
+ // $2.5k format
173
+ date: 55,
174
+ // "Dec 5" or "Tu"
175
+ datetime: 65,
176
+ // "5m ago"
177
+ email: 100,
178
+ // Truncated
179
+ phone: 80,
180
+ url: 80,
181
+ entity: 100,
182
+ user: 80,
183
+ json: 80
184
+ };
185
+ const COMPACT_FORMATTERS = {
186
+ money: "compactCurrency",
187
+ // $2,456.99 → $2.5k
188
+ date: "shortDate",
189
+ // 2024-01-15 → Dec 5
190
+ datetime: "relative",
191
+ // 2024-01-15T10:30 → 5m ago
192
+ text: "truncate",
193
+ // Long customer name → Long cust...
194
+ email: "truncate",
195
+ url: "domain",
196
+ // https://example.com/path → example.com
197
+ number: "compact"
198
+ // 1234567 → 1.2M
199
+ };
200
+ const COMPACT_LABELS = {
201
+ // Common field names → short versions
202
+ customer: "Cust",
203
+ description: "Desc",
204
+ quantity: "Qty",
205
+ amount: "Amt",
206
+ total: "Tot",
207
+ priority: "Pri",
208
+ status: "Stat",
209
+ created_at: "Created",
210
+ updated_at: "Updated",
211
+ email: "Email",
212
+ phone: "Ph",
213
+ category: "Cat",
214
+ // Time fields
215
+ time: "Time",
216
+ timeAgo: "Time",
217
+ timestamp: "Time",
218
+ // ID fields
219
+ order_id: "#",
220
+ id: "#",
221
+ transaction_id: "Txn"
222
+ };
223
+ const TABLE_BREAKPOINTS = {
224
+ /** Below this width (px), always use cards */
225
+ minForTable: 400,
226
+ /** Buffer (px) to add when calculating if columns fit */
227
+ widthBuffer: 50,
228
+ /** Minimum columns to show in compact mode */
229
+ minCompactColumns: 3,
230
+ /** Maximum columns in compact mode */
231
+ maxCompactColumns: 6
232
+ };
233
+ const IMPORTANCE_VISIBILITY = {
234
+ full: ["primary", "secondary", "tertiary", "critical", "high", "medium", "low", "minimal"],
235
+ compact: ["primary", "secondary", "critical", "high", "medium"],
236
+ cards: ["primary", "critical", "high"]
237
+ };
238
+ function getColumnWidth(type, mode = "full") {
239
+ if (mode === "compact" && type in COMPACT_COLUMN_WIDTHS) {
240
+ return COMPACT_COLUMN_WIDTHS[type];
241
+ }
242
+ return COLUMN_WIDTHS[type] ?? COLUMN_WIDTHS.text;
243
+ }
244
+ function calculateTableWidth(columns, mode = "full") {
245
+ return columns.reduce((sum, col) => sum + getColumnWidth(col.type, mode), 0);
246
+ }
247
+ function getCompactLabel(fieldName, originalLabel) {
248
+ const normalized = fieldName.toLowerCase();
249
+ return COMPACT_LABELS[normalized] ?? originalLabel;
250
+ }
251
+ function getCompactFormatter(type) {
252
+ return COMPACT_FORMATTERS[type];
253
+ }
254
+ function determineTableMode(containerWidth, columns) {
255
+ const { minForTable, widthBuffer } = TABLE_BREAKPOINTS;
256
+ if (containerWidth < minForTable) {
257
+ return "cards";
258
+ }
259
+ const fullWidth = calculateTableWidth(columns, "full");
260
+ const compactColumns = columns.filter(
261
+ (col) => IMPORTANCE_VISIBILITY.compact.includes(
262
+ col.importance ?? "medium"
263
+ )
264
+ );
265
+ const compactWidth = calculateTableWidth(compactColumns, "compact");
266
+ if (fullWidth + widthBuffer <= containerWidth) {
267
+ return "full";
268
+ }
269
+ if (compactWidth + widthBuffer <= containerWidth) {
270
+ return "compact";
271
+ }
272
+ return "cards";
273
+ }
139
274
  const breakpoints = {
140
275
  "2xs": 400,
141
276
  xs: 500,
@@ -2009,6 +2144,498 @@ function renderField(value, fieldName, fieldType, breakpoint, item, customRender
2009
2144
  function cn(...inputs) {
2010
2145
  return twMerge(clsx(inputs));
2011
2146
  }
2147
+ const IconBadge = ({
2148
+ children,
2149
+ icon,
2150
+ variant = "category",
2151
+ category = 1,
2152
+ status = "neutral",
2153
+ size = "md",
2154
+ interactive = false,
2155
+ onClick,
2156
+ className,
2157
+ tooltip
2158
+ }) => {
2159
+ const currentSize = useResponsiveValue(size);
2160
+ const sizeConfig = responsiveScales.components.iconBadge[currentSize];
2161
+ const sizeClasses2 = {
2162
+ xs: `${(sizeConfig == null ? void 0 : sizeConfig.size) || "w-6 h-6"} ${(sizeConfig == null ? void 0 : sizeConfig.text) || "text-[10px]"} ${(sizeConfig == null ? void 0 : sizeConfig.rounded) || "rounded-md"}`,
2163
+ sm: "w-8 h-8 text-xs rounded-lg",
2164
+ md: "w-10 h-10 text-sm rounded-xl",
2165
+ lg: "w-12 h-12 text-base rounded-xl"
2166
+ };
2167
+ const baseClasses = cn(
2168
+ "inline-flex items-center justify-center font-bold shadow-md",
2169
+ sizeClasses2[currentSize],
2170
+ interactive && [
2171
+ "cursor-pointer",
2172
+ getAnimationClasses({
2173
+ ...animationPresets.dataBadge,
2174
+ size: currentSize === "lg" ? "lg" : currentSize === "sm" || currentSize === "xs" ? "sm" : "md"
2175
+ })
2176
+ ],
2177
+ className
2178
+ );
2179
+ const gradientClasses = variant === "category" ? `bg-gradient-to-br from-category-${category} to-category-${Math.min(category + 1, 8)}` : variant === "status" ? `bg-gradient-to-br from-status-${status} to-status-${status}` : "bg-gradient-to-br from-category-1 to-category-2";
2180
+ const badge = /* @__PURE__ */ jsxs(
2181
+ "div",
2182
+ {
2183
+ className: cn(baseClasses, gradientClasses, "animate-fade-in"),
2184
+ onClick,
2185
+ role: interactive ? "button" : void 0,
2186
+ tabIndex: interactive ? 0 : void 0,
2187
+ onKeyDown: interactive ? (e) => {
2188
+ if (e.key === "Enter" || e.key === " ") {
2189
+ e.preventDefault();
2190
+ onClick == null ? void 0 : onClick();
2191
+ }
2192
+ } : void 0,
2193
+ "data-component-name": "IconBadge",
2194
+ children: [
2195
+ icon && /* @__PURE__ */ jsx("span", { className: "text-primary-foreground drop-shadow", children: icon }),
2196
+ children && !icon && /* @__PURE__ */ jsx("span", { className: "text-primary-foreground font-bold", children })
2197
+ ]
2198
+ }
2199
+ );
2200
+ if (tooltip) {
2201
+ return /* @__PURE__ */ jsx(Tooltip, { content: tooltip, position: "top", size: "sm", children: badge });
2202
+ }
2203
+ return badge;
2204
+ };
2205
+ const valueColorMap = {
2206
+ success: "text-green-600",
2207
+ error: "text-red-600",
2208
+ warning: "text-yellow-600",
2209
+ info: "text-blue-600",
2210
+ neutral: "text-muted-foreground",
2211
+ default: "text-foreground"
2212
+ };
2213
+ function ListCard({
2214
+ icon,
2215
+ title,
2216
+ subtitle,
2217
+ metadata,
2218
+ value,
2219
+ badge,
2220
+ onClick,
2221
+ className,
2222
+ children
2223
+ }) {
2224
+ return /* @__PURE__ */ jsxs(
2225
+ "div",
2226
+ {
2227
+ className: cn(
2228
+ "flex items-start gap-3 p-3 rounded-lg border border-border transition-colors",
2229
+ onClick && "hover:bg-muted/50 cursor-pointer",
2230
+ className
2231
+ ),
2232
+ onClick,
2233
+ children: [
2234
+ icon && /* @__PURE__ */ jsx(
2235
+ IconBadge,
2236
+ {
2237
+ variant: icon.variant || "category",
2238
+ category: icon.variant === "category" ? icon.category || 1 : void 0,
2239
+ status: icon.variant === "status" ? icon.status || "neutral" : void 0,
2240
+ size: icon.size || "sm",
2241
+ icon: icon.icon,
2242
+ tooltip: icon.tooltip
2243
+ }
2244
+ ),
2245
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2246
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
2247
+ /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
2248
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-medium text-foreground truncate", children: title }),
2249
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: subtitle }),
2250
+ metadata && metadata.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 mt-1", children: metadata.map((item, index) => /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: item }, index)) })
2251
+ ] }),
2252
+ (value || badge) && /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
2253
+ value && /* @__PURE__ */ jsx(
2254
+ "p",
2255
+ {
2256
+ className: cn(
2257
+ "text-sm font-semibold",
2258
+ value.variant && valueColorMap[value.variant],
2259
+ value.className
2260
+ ),
2261
+ children: value.text
2262
+ }
2263
+ ),
2264
+ badge && /* @__PURE__ */ jsx(
2265
+ DataBadge,
2266
+ {
2267
+ variant: badge.variant,
2268
+ status: badge.variant === "status" ? badge.status : void 0,
2269
+ category: badge.variant === "category" ? badge.category : void 0,
2270
+ size: badge.size || "sm",
2271
+ icon: badge.icon,
2272
+ className: "mt-1",
2273
+ children: badge.text
2274
+ }
2275
+ )
2276
+ ] })
2277
+ ] }),
2278
+ children
2279
+ ] })
2280
+ ]
2281
+ }
2282
+ );
2283
+ }
2284
+ const STATUS_COLOR_MAP = {
2285
+ // Success states
2286
+ active: "success",
2287
+ completed: "success",
2288
+ approved: "success",
2289
+ paid: "success",
2290
+ delivered: "success",
2291
+ resolved: "success",
2292
+ closed: "success",
2293
+ // Warning states
2294
+ pending: "warning",
2295
+ processing: "warning",
2296
+ review: "warning",
2297
+ draft: "warning",
2298
+ waiting: "warning",
2299
+ // Error states
2300
+ failed: "error",
2301
+ rejected: "error",
2302
+ cancelled: "error",
2303
+ overdue: "error",
2304
+ blocked: "error",
2305
+ // Info states
2306
+ new: "info",
2307
+ open: "info",
2308
+ in_progress: "info",
2309
+ scheduled: "info",
2310
+ // Neutral (default)
2311
+ inactive: "neutral",
2312
+ archived: "neutral",
2313
+ unknown: "neutral"
2314
+ };
2315
+ function getStatusColor(value) {
2316
+ if (typeof value !== "string") return "neutral";
2317
+ const normalized = value.toLowerCase().replace(/[_-]/g, "_");
2318
+ return STATUS_COLOR_MAP[normalized] ?? "neutral";
2319
+ }
2320
+ const CATEGORY_MAP = {
2321
+ account: 1,
2322
+ customer: 1,
2323
+ client: 1,
2324
+ user: 2,
2325
+ contact: 2,
2326
+ person: 2,
2327
+ order: 3,
2328
+ sale: 3,
2329
+ transaction: 3,
2330
+ product: 4,
2331
+ item: 4,
2332
+ inventory: 4,
2333
+ task: 5,
2334
+ activity: 5,
2335
+ event: 5,
2336
+ file: 6,
2337
+ document: 6,
2338
+ report: 6,
2339
+ tag: 7,
2340
+ category: 7,
2341
+ label: 7,
2342
+ default: 8
2343
+ };
2344
+ function getCategoryForEntity(entityType) {
2345
+ if (!entityType) return 8;
2346
+ const normalized = entityType.toLowerCase();
2347
+ for (const [key, value] of Object.entries(CATEGORY_MAP)) {
2348
+ if (normalized.includes(key)) return value;
2349
+ }
2350
+ return 8;
2351
+ }
2352
+ function getIconForEntity(entityType) {
2353
+ if (!entityType) return /* @__PURE__ */ jsx(Circle, { className: "w-4 h-4" });
2354
+ const normalized = entityType.toLowerCase();
2355
+ if (normalized.includes("account") || normalized.includes("customer") || normalized.includes("client")) {
2356
+ return /* @__PURE__ */ jsx(Building2, { className: "w-4 h-4" });
2357
+ }
2358
+ if (normalized.includes("user") || normalized.includes("contact") || normalized.includes("person")) {
2359
+ return /* @__PURE__ */ jsx(User, { className: "w-4 h-4" });
2360
+ }
2361
+ if (normalized.includes("product") || normalized.includes("item")) {
2362
+ return /* @__PURE__ */ jsx(Package, { className: "w-4 h-4" });
2363
+ }
2364
+ if (normalized.includes("file") || normalized.includes("document")) {
2365
+ return /* @__PURE__ */ jsx(FileText, { className: "w-4 h-4" });
2366
+ }
2367
+ if (normalized.includes("tag") || normalized.includes("category")) {
2368
+ return /* @__PURE__ */ jsx(Tag, { className: "w-4 h-4" });
2369
+ }
2370
+ return /* @__PURE__ */ jsx(Circle, { className: "w-4 h-4" });
2371
+ }
2372
+ function normalizeImportance(importance) {
2373
+ switch (importance) {
2374
+ case "critical":
2375
+ case "high":
2376
+ case "primary":
2377
+ return "primary";
2378
+ case "medium":
2379
+ case "secondary":
2380
+ return "secondary";
2381
+ default:
2382
+ return "tertiary";
2383
+ }
2384
+ }
2385
+ function isPrimaryImportance(importance) {
2386
+ return normalizeImportance(importance) === "primary";
2387
+ }
2388
+ function formatValueForCard(value, type, format) {
2389
+ if (value === null || value === void 0) return "—";
2390
+ switch (type) {
2391
+ case "money": {
2392
+ const num = Number(value);
2393
+ const currency = (format == null ? void 0 : format.currency) ?? "USD";
2394
+ if (num >= 1e6) {
2395
+ return new Intl.NumberFormat("en-US", {
2396
+ style: "currency",
2397
+ currency,
2398
+ notation: "compact",
2399
+ maximumFractionDigits: 1
2400
+ }).format(num);
2401
+ }
2402
+ if (num >= 1e3) {
2403
+ return new Intl.NumberFormat("en-US", {
2404
+ style: "currency",
2405
+ currency,
2406
+ notation: "compact",
2407
+ maximumFractionDigits: 1
2408
+ }).format(num);
2409
+ }
2410
+ return new Intl.NumberFormat("en-US", {
2411
+ style: "currency",
2412
+ currency,
2413
+ maximumFractionDigits: 0
2414
+ }).format(num);
2415
+ }
2416
+ case "percent": {
2417
+ const num = Number(value);
2418
+ return `${num.toFixed(0)}%`;
2419
+ }
2420
+ case "number": {
2421
+ const num = Number(value);
2422
+ if (num >= 1e6) return `${(num / 1e6).toFixed(1)}M`;
2423
+ if (num >= 1e3) return `${(num / 1e3).toFixed(1)}K`;
2424
+ return String(num);
2425
+ }
2426
+ case "date":
2427
+ case "datetime": {
2428
+ const date = new Date(String(value));
2429
+ if (isNaN(date.getTime())) return String(value);
2430
+ return date.toLocaleDateString("en-US", {
2431
+ month: "short",
2432
+ day: "numeric"
2433
+ });
2434
+ }
2435
+ case "boolean":
2436
+ return value ? "Yes" : "No";
2437
+ default:
2438
+ return String(value);
2439
+ }
2440
+ }
2441
+ function autoDetectMapping(columns) {
2442
+ var _a, _b, _c, _d, _e, _f;
2443
+ const primaryCols = columns.filter((c) => isPrimaryImportance(c.importance));
2444
+ const titleField = ((_a = primaryCols.find((c) => ["text", "entity", "user"].includes(c.type))) == null ? void 0 : _a.field) ?? ((_b = primaryCols[0]) == null ? void 0 : _b.field) ?? ((_c = columns[0]) == null ? void 0 : _c.field);
2445
+ const valueField = (_d = primaryCols.find((c) => c.type === "money")) == null ? void 0 : _d.field;
2446
+ const statusField = (_e = primaryCols.find(
2447
+ (c) => c.type === "status" || c.type === "badge"
2448
+ )) == null ? void 0 : _e.field;
2449
+ const usedForMain = new Set([titleField, valueField, statusField].filter(Boolean));
2450
+ const remainingPrimary = primaryCols.filter((c) => !usedForMain.has(c.field));
2451
+ const subtitleField = (_f = remainingPrimary[0]) == null ? void 0 : _f.field;
2452
+ const usedFields = new Set(
2453
+ [titleField, valueField, statusField, subtitleField].filter(Boolean)
2454
+ );
2455
+ const metadataFields = primaryCols.filter((c) => !usedFields.has(c.field)).slice(0, 3).map((c) => c.field);
2456
+ return {
2457
+ titleField: titleField ?? "id",
2458
+ subtitleField,
2459
+ valueField,
2460
+ statusField,
2461
+ metadataFields,
2462
+ iconConfig: void 0
2463
+ };
2464
+ }
2465
+ function entityToListCardProps(item, columns, mapping, entityType) {
2466
+ const autoMapping = autoDetectMapping(columns);
2467
+ const effectiveMapping = { ...autoMapping, ...mapping };
2468
+ const {
2469
+ titleField,
2470
+ subtitleField,
2471
+ valueField,
2472
+ statusField,
2473
+ metadataFields,
2474
+ iconConfig
2475
+ } = effectiveMapping;
2476
+ const getColumn = (field) => field ? columns.find((c) => c.field === field) : void 0;
2477
+ const title = item[titleField] != null ? String(item[titleField]) : "—";
2478
+ const subtitle = subtitleField && item[subtitleField] != null ? String(item[subtitleField]) : void 0;
2479
+ let value;
2480
+ if (valueField && item[valueField] != null) {
2481
+ const valueCol = getColumn(valueField);
2482
+ const formatted = formatValueForCard(
2483
+ item[valueField],
2484
+ (valueCol == null ? void 0 : valueCol.type) ?? "text",
2485
+ valueCol == null ? void 0 : valueCol.format
2486
+ );
2487
+ value = {
2488
+ text: formatted,
2489
+ variant: "success"
2490
+ // Money typically green
2491
+ };
2492
+ }
2493
+ let badge;
2494
+ if (statusField && item[statusField] != null) {
2495
+ const statusValue = String(item[statusField]);
2496
+ badge = {
2497
+ text: statusValue,
2498
+ variant: "status",
2499
+ status: getStatusColor(statusValue),
2500
+ size: "sm"
2501
+ };
2502
+ }
2503
+ const metadata = metadataFields == null ? void 0 : metadataFields.map((field) => {
2504
+ const col = getColumn(field);
2505
+ if (!col || item[field] == null) return null;
2506
+ return formatValueForCard(item[field], col.type, col.format);
2507
+ }).filter((v) => v !== null);
2508
+ let icon;
2509
+ if (iconConfig) {
2510
+ const iconValue = iconConfig.field ? item[iconConfig.field] : void 0;
2511
+ if (iconConfig.variant === "status" && iconValue) {
2512
+ icon = {
2513
+ icon: iconConfig.icon ?? getIconForEntity(entityType),
2514
+ variant: "status",
2515
+ status: getStatusColor(iconValue),
2516
+ size: "sm"
2517
+ };
2518
+ } else {
2519
+ icon = {
2520
+ icon: iconConfig.icon ?? getIconForEntity(entityType),
2521
+ variant: "category",
2522
+ category: getCategoryForEntity(entityType),
2523
+ size: "sm"
2524
+ };
2525
+ }
2526
+ } else {
2527
+ icon = {
2528
+ icon: getIconForEntity(entityType),
2529
+ variant: "category",
2530
+ category: getCategoryForEntity(entityType),
2531
+ size: "sm"
2532
+ };
2533
+ }
2534
+ return {
2535
+ icon,
2536
+ title,
2537
+ subtitle,
2538
+ metadata,
2539
+ value,
2540
+ badge
2541
+ };
2542
+ }
2543
+ const HEADER_ABBREVIATIONS = {
2544
+ customer: "Cust",
2545
+ account: "Acct",
2546
+ amount: "Amt",
2547
+ quantity: "Qty",
2548
+ priority: "Pri",
2549
+ status: "Status",
2550
+ created: "Created",
2551
+ updated: "Updated",
2552
+ description: "Desc",
2553
+ total: "Total",
2554
+ items: "Items",
2555
+ number: "#",
2556
+ date: "Date",
2557
+ time: "Time"
2558
+ };
2559
+ function abbreviateHeader(label) {
2560
+ const lower = label.toLowerCase();
2561
+ for (const [key, abbrev] of Object.entries(HEADER_ABBREVIATIONS)) {
2562
+ if (lower.includes(key)) return abbrev;
2563
+ }
2564
+ if (label.length > 8) return label.slice(0, 6) + "…";
2565
+ return label;
2566
+ }
2567
+ function generateCompactColumns(columns, options = {}) {
2568
+ const {
2569
+ maxColumns = 5,
2570
+ abbreviateHeaders = true,
2571
+ requiredFields = [],
2572
+ excludeFields = []
2573
+ } = options;
2574
+ const excludeSet = new Set(excludeFields);
2575
+ const requiredSet = new Set(requiredFields);
2576
+ const filteredColumns = columns.filter((col) => {
2577
+ if (excludeSet.has(col.field)) return false;
2578
+ return true;
2579
+ });
2580
+ const required = filteredColumns.filter((c) => requiredSet.has(c.field));
2581
+ const primary = filteredColumns.filter(
2582
+ (c) => !requiredSet.has(c.field) && normalizeImportance(c.importance) === "primary"
2583
+ );
2584
+ const secondary = filteredColumns.filter(
2585
+ (c) => !requiredSet.has(c.field) && normalizeImportance(c.importance) === "secondary"
2586
+ );
2587
+ const selectedColumns = [...required, ...primary, ...secondary].slice(
2588
+ 0,
2589
+ maxColumns
2590
+ );
2591
+ return selectedColumns.map((col) => ({
2592
+ key: col.field,
2593
+ header: abbreviateHeaders ? abbreviateHeader(col.label) : col.label,
2594
+ sortable: col.sortable,
2595
+ type: col.type,
2596
+ format: col.format,
2597
+ // Compact widths
2598
+ width: getCompactWidth(col.type)
2599
+ }));
2600
+ }
2601
+ function getCompactWidth(type) {
2602
+ switch (type) {
2603
+ case "money":
2604
+ return "70px";
2605
+ case "number":
2606
+ case "percent":
2607
+ return "50px";
2608
+ case "status":
2609
+ case "badge":
2610
+ return "80px";
2611
+ case "date":
2612
+ return "70px";
2613
+ case "datetime":
2614
+ return "90px";
2615
+ case "boolean":
2616
+ return "50px";
2617
+ default:
2618
+ return "120px";
2619
+ }
2620
+ }
2621
+ function createMobileCardRenderer(columns, mapping, entityType) {
2622
+ return ({ data, onItemClick }) => /* @__PURE__ */ jsx("div", { className: "space-y-2", children: data.map((item, index) => {
2623
+ const cardProps = entityToListCardProps(
2624
+ item,
2625
+ columns,
2626
+ mapping,
2627
+ entityType
2628
+ );
2629
+ return /* @__PURE__ */ jsx(
2630
+ ListCard,
2631
+ {
2632
+ ...cardProps,
2633
+ onClick: onItemClick ? () => onItemClick(item) : void 0
2634
+ },
2635
+ item.id ?? index
2636
+ );
2637
+ }) });
2638
+ }
2012
2639
  let globalAuthService = null;
2013
2640
  function setGlobalAuthService(authService) {
2014
2641
  globalAuthService = authService;
@@ -2174,10 +2801,10 @@ function useApiMutation(mutationFn, options) {
2174
2801
  const queryClient = useQueryClient();
2175
2802
  return useMutation({
2176
2803
  mutationFn,
2177
- onSuccess: (data, variables, context) => {
2804
+ onSuccess: (...args) => {
2178
2805
  var _a;
2179
- queryClient.invalidateQueries();
2180
- (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data, variables, context);
2806
+ void queryClient.invalidateQueries({});
2807
+ (_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, ...args);
2181
2808
  },
2182
2809
  ...options
2183
2810
  });
@@ -2252,43 +2879,87 @@ function useFieldMetadata({
2252
2879
  }
2253
2880
  function useResponsiveTable(options = {}) {
2254
2881
  const {
2882
+ columns,
2255
2883
  initialView = "full",
2256
2884
  autoSwitch = true,
2257
- minWidthForCompact = 400,
2885
+ minWidthForCompact = TABLE_BREAKPOINTS.minForTable,
2258
2886
  debounceMs = 100,
2259
2887
  onViewChange
2260
2888
  } = options;
2261
2889
  const [viewMode, setViewModeState] = useState(initialView);
2262
2890
  const [isAutoSwitching, setIsAutoSwitching] = useState(autoSwitch);
2891
+ const [containerWidth, setContainerWidth] = useState(0);
2263
2892
  const [overflowState, setOverflowState] = useState({
2264
2893
  fullOverflows: false,
2265
2894
  compactOverflows: false
2266
2895
  });
2896
+ const containerRef = useRef(null);
2267
2897
  const fullTableRef = useRef(null);
2268
2898
  const compactTableRef = useRef(null);
2269
2899
  const debounceTimerRef = useRef(null);
2270
2900
  const isTransitioningRef = useRef(false);
2901
+ const compactColumns = useCallback(() => {
2902
+ if (!columns) return null;
2903
+ const validImportance = IMPORTANCE_VISIBILITY.compact;
2904
+ const filtered = columns.filter(
2905
+ (col) => validImportance.includes(col.importance ?? "medium")
2906
+ );
2907
+ const limited = filtered.slice(0, TABLE_BREAKPOINTS.maxCompactColumns);
2908
+ return limited.map((col) => ({
2909
+ ...col,
2910
+ label: getCompactLabel(col.field, col.label)
2911
+ }));
2912
+ }, [columns])();
2913
+ const calculatedWidths = useCallback(() => {
2914
+ if (!columns) {
2915
+ return { full: 0, compact: 0, container: containerWidth };
2916
+ }
2917
+ const fullWidth = calculateTableWidth(
2918
+ columns.map((c) => ({ type: c.type })),
2919
+ "full"
2920
+ );
2921
+ const compactCols = compactColumns ?? [];
2922
+ const compactWidth = calculateTableWidth(
2923
+ compactCols.map((c) => ({ type: c.type })),
2924
+ "compact"
2925
+ );
2926
+ return {
2927
+ full: fullWidth,
2928
+ compact: compactWidth,
2929
+ container: containerWidth
2930
+ };
2931
+ }, [columns, compactColumns, containerWidth])();
2271
2932
  const hasOverflow = useCallback((element) => {
2272
2933
  if (!element) return false;
2273
2934
  return element.scrollWidth > element.clientWidth + 2;
2274
2935
  }, []);
2275
2936
  const determineView = useCallback(() => {
2276
- var _a, _b, _c, _d;
2277
- const containerWidth = ((_b = (_a = fullTableRef.current) == null ? void 0 : _a.parentElement) == null ? void 0 : _b.clientWidth) || ((_d = (_c = compactTableRef.current) == null ? void 0 : _c.parentElement) == null ? void 0 : _d.clientWidth) || window.innerWidth;
2278
- if (containerWidth < minWidthForCompact) {
2937
+ var _a, _b, _c, _d, _e;
2938
+ if (columns && containerWidth > 0) {
2939
+ const { full, compact } = calculatedWidths;
2940
+ const buffer = TABLE_BREAKPOINTS.widthBuffer;
2941
+ if (containerWidth < minWidthForCompact) {
2942
+ return "cards";
2943
+ }
2944
+ if (full + buffer <= containerWidth) {
2945
+ return "full";
2946
+ }
2947
+ if (compact + buffer <= containerWidth) {
2948
+ return "compact";
2949
+ }
2950
+ return "cards";
2951
+ }
2952
+ const width = ((_a = containerRef.current) == null ? void 0 : _a.clientWidth) || ((_c = (_b = fullTableRef.current) == null ? void 0 : _b.parentElement) == null ? void 0 : _c.clientWidth) || ((_e = (_d = compactTableRef.current) == null ? void 0 : _d.parentElement) == null ? void 0 : _e.clientWidth) || window.innerWidth;
2953
+ if (width < minWidthForCompact) {
2279
2954
  return "cards";
2280
2955
  }
2281
2956
  const fullOverflows = hasOverflow(fullTableRef.current);
2282
2957
  const compactOverflows = hasOverflow(compactTableRef.current);
2283
2958
  setOverflowState({ fullOverflows, compactOverflows });
2284
- if (!fullOverflows) {
2285
- return "full";
2286
- }
2287
- if (!compactOverflows) {
2288
- return "compact";
2289
- }
2959
+ if (!fullOverflows) return "full";
2960
+ if (!compactOverflows) return "compact";
2290
2961
  return "cards";
2291
- }, [hasOverflow, minWidthForCompact]);
2962
+ }, [columns, containerWidth, calculatedWidths, minWidthForCompact, hasOverflow]);
2292
2963
  const checkAndUpdate = useCallback(() => {
2293
2964
  if (!isAutoSwitching || isTransitioningRef.current) return;
2294
2965
  if (debounceTimerRef.current) {
@@ -2320,42 +2991,49 @@ function useResponsiveTable(options = {}) {
2320
2991
  useEffect(() => {
2321
2992
  var _a, _b;
2322
2993
  if (!isAutoSwitching) return;
2323
- const initialCheckTimer = setTimeout(checkAndUpdate, 50);
2994
+ const updateContainerWidth = () => {
2995
+ var _a2;
2996
+ const ref = containerRef.current || ((_a2 = fullTableRef.current) == null ? void 0 : _a2.parentElement);
2997
+ if (ref) {
2998
+ setContainerWidth(ref.clientWidth);
2999
+ }
3000
+ };
3001
+ const initialTimer = setTimeout(updateContainerWidth, 50);
2324
3002
  const resizeObserver = new ResizeObserver(() => {
3003
+ updateContainerWidth();
2325
3004
  checkAndUpdate();
2326
3005
  });
2327
- if (fullTableRef.current) {
2328
- resizeObserver.observe(fullTableRef.current);
3006
+ const observeTarget = containerRef.current || ((_a = fullTableRef.current) == null ? void 0 : _a.parentElement) || ((_b = compactTableRef.current) == null ? void 0 : _b.parentElement);
3007
+ if (observeTarget) {
3008
+ resizeObserver.observe(observeTarget);
2329
3009
  }
2330
- if (compactTableRef.current) {
2331
- resizeObserver.observe(compactTableRef.current);
2332
- }
2333
- const parent = ((_a = fullTableRef.current) == null ? void 0 : _a.parentElement) || ((_b = compactTableRef.current) == null ? void 0 : _b.parentElement);
2334
- if (parent) {
2335
- resizeObserver.observe(parent);
3010
+ if (!columns) {
3011
+ if (fullTableRef.current) resizeObserver.observe(fullTableRef.current);
3012
+ if (compactTableRef.current) resizeObserver.observe(compactTableRef.current);
2336
3013
  }
2337
3014
  window.addEventListener("resize", checkAndUpdate);
2338
3015
  return () => {
2339
- clearTimeout(initialCheckTimer);
2340
- if (debounceTimerRef.current) {
2341
- clearTimeout(debounceTimerRef.current);
2342
- }
3016
+ clearTimeout(initialTimer);
3017
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
2343
3018
  resizeObserver.disconnect();
2344
3019
  window.removeEventListener("resize", checkAndUpdate);
2345
3020
  };
2346
- }, [isAutoSwitching, checkAndUpdate]);
3021
+ }, [isAutoSwitching, columns, checkAndUpdate]);
2347
3022
  useEffect(() => {
2348
3023
  if (!isAutoSwitching) return;
2349
3024
  const timer = setTimeout(checkAndUpdate, 100);
2350
3025
  return () => clearTimeout(timer);
2351
- }, [viewMode, isAutoSwitching, checkAndUpdate]);
3026
+ }, [viewMode, containerWidth, isAutoSwitching, checkAndUpdate]);
2352
3027
  return {
2353
3028
  viewMode,
2354
3029
  setViewMode,
2355
3030
  enableAutoSwitch,
2356
3031
  isAutoSwitching,
3032
+ containerRef,
2357
3033
  fullTableRef,
2358
3034
  compactTableRef,
3035
+ compactColumns,
3036
+ calculatedWidths,
2359
3037
  overflowState
2360
3038
  };
2361
3039
  }
@@ -2374,6 +3052,154 @@ function useOverflowDetection(ref) {
2374
3052
  }, [ref]);
2375
3053
  return hasOverflow;
2376
3054
  }
3055
+ const IMPORTANCE_PRIORITY = {
3056
+ minimal: 0,
3057
+ low: 1,
3058
+ tertiary: 2,
3059
+ medium: 3,
3060
+ secondary: 4,
3061
+ high: 5,
3062
+ critical: 6,
3063
+ primary: 7
3064
+ };
3065
+ function getColumnModeWidth(col, mode) {
3066
+ if (mode === "hidden") return 0;
3067
+ return getColumnWidth(col.type, mode === "compact" ? "compact" : "full");
3068
+ }
3069
+ function calculateAdaptiveWidth(columns, modes) {
3070
+ return columns.reduce((sum, col) => sum + getColumnModeWidth(col, modes[col.field] ?? "full"), 0);
3071
+ }
3072
+ function calculateColumnModes(columns, containerWidth, protectedColumns, minColumnsVisible) {
3073
+ const buffer = TABLE_BREAKPOINTS.widthBuffer;
3074
+ const sortedByImportance = [...columns].sort((a, b) => {
3075
+ const priorityA = IMPORTANCE_PRIORITY[a.importance ?? "tertiary"];
3076
+ const priorityB = IMPORTANCE_PRIORITY[b.importance ?? "tertiary"];
3077
+ return priorityA - priorityB;
3078
+ });
3079
+ const modes = {};
3080
+ columns.forEach((col) => modes[col.field] = "full");
3081
+ let currentWidth = calculateAdaptiveWidth(columns, modes);
3082
+ if (currentWidth + buffer <= containerWidth) {
3083
+ return { modes, degradationLevel: 0 };
3084
+ }
3085
+ let degradationLevel = 1;
3086
+ for (const col of sortedByImportance) {
3087
+ if (protectedColumns.has(col.field)) continue;
3088
+ const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
3089
+ if (priority > 2) break;
3090
+ modes[col.field] = "compact";
3091
+ currentWidth = calculateAdaptiveWidth(columns, modes);
3092
+ if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
3093
+ }
3094
+ degradationLevel = 2;
3095
+ for (const col of sortedByImportance) {
3096
+ if (protectedColumns.has(col.field)) continue;
3097
+ const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
3098
+ if (priority <= 2) continue;
3099
+ if (priority > 4) break;
3100
+ modes[col.field] = "compact";
3101
+ currentWidth = calculateAdaptiveWidth(columns, modes);
3102
+ if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
3103
+ }
3104
+ degradationLevel = 3;
3105
+ let visibleCount = columns.length;
3106
+ for (const col of sortedByImportance) {
3107
+ const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
3108
+ if (priority > 2) break;
3109
+ if (visibleCount <= minColumnsVisible) break;
3110
+ modes[col.field] = "hidden";
3111
+ visibleCount--;
3112
+ currentWidth = calculateAdaptiveWidth(columns, modes);
3113
+ if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
3114
+ }
3115
+ degradationLevel = 4;
3116
+ for (const col of sortedByImportance) {
3117
+ const priority = IMPORTANCE_PRIORITY[col.importance ?? "tertiary"];
3118
+ if (priority <= 2) continue;
3119
+ if (priority > 4) break;
3120
+ if (visibleCount <= minColumnsVisible) break;
3121
+ modes[col.field] = "hidden";
3122
+ visibleCount--;
3123
+ currentWidth = calculateAdaptiveWidth(columns, modes);
3124
+ if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
3125
+ }
3126
+ degradationLevel = 5;
3127
+ for (const col of sortedByImportance) {
3128
+ if (modes[col.field] === "hidden") continue;
3129
+ modes[col.field] = "compact";
3130
+ currentWidth = calculateAdaptiveWidth(columns, modes);
3131
+ if (currentWidth + buffer <= containerWidth) return { modes, degradationLevel };
3132
+ }
3133
+ return { modes, degradationLevel: 6 };
3134
+ }
3135
+ function useAdaptiveTable(options) {
3136
+ const {
3137
+ columns,
3138
+ protectedColumns = [],
3139
+ minColumnsVisible = 2,
3140
+ minWidthForTable = TABLE_BREAKPOINTS.minForTable,
3141
+ debounceMs = 100,
3142
+ onModeChange
3143
+ } = options;
3144
+ const containerRef = useRef(null);
3145
+ const [containerWidth, setContainerWidth] = useState(0);
3146
+ const debounceTimerRef = useRef(null);
3147
+ const protectedSet = useMemo(() => new Set(protectedColumns), [protectedColumns]);
3148
+ const { modes: columnModes, degradationLevel } = useMemo(() => {
3149
+ if (containerWidth === 0) {
3150
+ const modes = {};
3151
+ columns.forEach((col) => modes[col.field] = "full");
3152
+ return { modes, degradationLevel: 0 };
3153
+ }
3154
+ return calculateColumnModes(columns, containerWidth, protectedSet, minColumnsVisible);
3155
+ }, [columns, containerWidth, protectedSet, minColumnsVisible]);
3156
+ const visibleColumns = useMemo(() => {
3157
+ return columns.filter((col) => columnModes[col.field] !== "hidden").map(
3158
+ (col) => columnModes[col.field] === "compact" ? { ...col, label: getCompactLabel(col.field, col.label) } : col
3159
+ );
3160
+ }, [columns, columnModes]);
3161
+ const calculatedWidth = useMemo(
3162
+ () => calculateAdaptiveWidth(columns, columnModes),
3163
+ [columns, columnModes]
3164
+ );
3165
+ const viewMode = useMemo(() => {
3166
+ if (containerWidth > 0 && containerWidth < minWidthForTable) return "cards";
3167
+ if (visibleColumns.length < minColumnsVisible) return "cards";
3168
+ return "table";
3169
+ }, [containerWidth, minWidthForTable, visibleColumns.length, minColumnsVisible]);
3170
+ useEffect(() => {
3171
+ const updateWidth = () => {
3172
+ if (containerRef.current) setContainerWidth(containerRef.current.clientWidth);
3173
+ };
3174
+ const initialTimer = setTimeout(updateWidth, 50);
3175
+ const resizeObserver = new ResizeObserver(() => {
3176
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
3177
+ debounceTimerRef.current = setTimeout(updateWidth, debounceMs);
3178
+ });
3179
+ if (containerRef.current) resizeObserver.observe(containerRef.current);
3180
+ return () => {
3181
+ clearTimeout(initialTimer);
3182
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
3183
+ resizeObserver.disconnect();
3184
+ };
3185
+ }, [debounceMs]);
3186
+ const prevModesRef = useRef(columnModes);
3187
+ useEffect(() => {
3188
+ if (onModeChange && columnModes !== prevModesRef.current) {
3189
+ onModeChange(columnModes);
3190
+ prevModesRef.current = columnModes;
3191
+ }
3192
+ }, [columnModes, onModeChange]);
3193
+ return {
3194
+ containerRef,
3195
+ columnModes,
3196
+ visibleColumns,
3197
+ viewMode,
3198
+ calculatedWidth,
3199
+ containerWidth,
3200
+ degradationLevel
3201
+ };
3202
+ }
2377
3203
  function useEntityData(entity, options = {}) {
2378
3204
  var _a, _b, _c;
2379
3205
  const {
@@ -4256,8 +5082,9 @@ function normalizeColumn(col) {
4256
5082
  return col;
4257
5083
  }
4258
5084
  function DataTable({
4259
- data,
4260
- columns,
5085
+ data: dataProp,
5086
+ columns: columnsProp,
5087
+ query,
4261
5088
  searchPlaceholder = "Search...",
4262
5089
  pageSize = 10,
4263
5090
  showPagination = true,
@@ -4266,12 +5093,12 @@ function DataTable({
4266
5093
  emptyMessage = "No data available",
4267
5094
  className = "",
4268
5095
  hover = false,
4269
- isLoading = false,
5096
+ isLoading: isLoadingProp = false,
4270
5097
  loadingItemCount = 5,
4271
5098
  responsive = true,
4272
5099
  renderMobileCard,
4273
5100
  ui,
4274
- error = null,
5101
+ error: errorProp = null,
4275
5102
  errorTitle,
4276
5103
  errorRetry,
4277
5104
  selectable = false,
@@ -4286,6 +5113,10 @@ function DataTable({
4286
5113
  const [currentPage, setCurrentPage] = useState(1);
4287
5114
  const currentBreakpoint = useBreakpoint();
4288
5115
  const isMobile = currentBreakpoint === "xs" || currentBreakpoint === "2xs" || currentBreakpoint === "sm";
5116
+ const data = dataProp ?? (query == null ? void 0 : query.data) ?? [];
5117
+ const columns = columnsProp ?? (query == null ? void 0 : query.columns) ?? [];
5118
+ const isLoading = isLoadingProp || (query == null ? void 0 : query.isLoading) || (query == null ? void 0 : query.isLoadingMetadata) || false;
5119
+ const error = errorProp ?? (query == null ? void 0 : query.error) ?? (query == null ? void 0 : query.metadataError) ?? null;
4289
5120
  const normalizedColumns = useMemo(
4290
5121
  () => columns.map((col) => normalizeColumn(col)),
4291
5122
  [columns]
@@ -4672,64 +5503,6 @@ const TableHead = TableHead$1;
4672
5503
  const TableHeader = TableHeader$1;
4673
5504
  const TableRow = TableRow$1;
4674
5505
  const TableFooter = TableFooter$1;
4675
- const IconBadge = ({
4676
- children,
4677
- icon,
4678
- variant = "category",
4679
- category = 1,
4680
- status = "neutral",
4681
- size = "md",
4682
- interactive = false,
4683
- onClick,
4684
- className,
4685
- tooltip
4686
- }) => {
4687
- const currentSize = useResponsiveValue(size);
4688
- const sizeConfig = responsiveScales.components.iconBadge[currentSize];
4689
- const sizeClasses2 = {
4690
- xs: `${(sizeConfig == null ? void 0 : sizeConfig.size) || "w-6 h-6"} ${(sizeConfig == null ? void 0 : sizeConfig.text) || "text-[10px]"} ${(sizeConfig == null ? void 0 : sizeConfig.rounded) || "rounded-md"}`,
4691
- sm: "w-8 h-8 text-xs rounded-lg",
4692
- md: "w-10 h-10 text-sm rounded-xl",
4693
- lg: "w-12 h-12 text-base rounded-xl"
4694
- };
4695
- const baseClasses = cn(
4696
- "inline-flex items-center justify-center font-bold shadow-md",
4697
- sizeClasses2[currentSize],
4698
- interactive && [
4699
- "cursor-pointer",
4700
- getAnimationClasses({
4701
- ...animationPresets.dataBadge,
4702
- size: currentSize === "lg" ? "lg" : currentSize === "sm" || currentSize === "xs" ? "sm" : "md"
4703
- })
4704
- ],
4705
- className
4706
- );
4707
- const gradientClasses = variant === "category" ? `bg-gradient-to-br from-category-${category} to-category-${Math.min(category + 1, 8)}` : variant === "status" ? `bg-gradient-to-br from-status-${status} to-status-${status}` : "bg-gradient-to-br from-category-1 to-category-2";
4708
- const badge = /* @__PURE__ */ jsxs(
4709
- "div",
4710
- {
4711
- className: cn(baseClasses, gradientClasses, "animate-fade-in"),
4712
- onClick,
4713
- role: interactive ? "button" : void 0,
4714
- tabIndex: interactive ? 0 : void 0,
4715
- onKeyDown: interactive ? (e) => {
4716
- if (e.key === "Enter" || e.key === " ") {
4717
- e.preventDefault();
4718
- onClick == null ? void 0 : onClick();
4719
- }
4720
- } : void 0,
4721
- "data-component-name": "IconBadge",
4722
- children: [
4723
- icon && /* @__PURE__ */ jsx("span", { className: "text-primary-foreground drop-shadow", children: icon }),
4724
- children && !icon && /* @__PURE__ */ jsx("span", { className: "text-primary-foreground font-bold", children })
4725
- ]
4726
- }
4727
- );
4728
- if (tooltip) {
4729
- return /* @__PURE__ */ jsx(Tooltip, { content: tooltip, position: "top", size: "sm", children: badge });
4730
- }
4731
- return badge;
4732
- };
4733
5506
  const Chart = ({
4734
5507
  title,
4735
5508
  subtitle,
@@ -5492,85 +6265,6 @@ const ProgressBar = ({
5492
6265
  )
5493
6266
  ] });
5494
6267
  };
5495
- const valueColorMap = {
5496
- success: "text-green-600",
5497
- error: "text-red-600",
5498
- warning: "text-yellow-600",
5499
- info: "text-blue-600",
5500
- neutral: "text-muted-foreground",
5501
- default: "text-foreground"
5502
- };
5503
- function ListCard({
5504
- icon,
5505
- title,
5506
- subtitle,
5507
- metadata,
5508
- value,
5509
- badge,
5510
- onClick,
5511
- className,
5512
- children
5513
- }) {
5514
- return /* @__PURE__ */ jsxs(
5515
- "div",
5516
- {
5517
- className: cn(
5518
- "flex items-start gap-3 p-3 rounded-lg border border-border transition-colors",
5519
- onClick && "hover:bg-muted/50 cursor-pointer",
5520
- className
5521
- ),
5522
- onClick,
5523
- children: [
5524
- icon && /* @__PURE__ */ jsx(
5525
- IconBadge,
5526
- {
5527
- variant: icon.variant || "category",
5528
- category: icon.variant === "category" ? icon.category || 1 : void 0,
5529
- status: icon.variant === "status" ? icon.status || "neutral" : void 0,
5530
- size: icon.size || "sm",
5531
- icon: icon.icon,
5532
- tooltip: icon.tooltip
5533
- }
5534
- ),
5535
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
5536
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
5537
- /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
5538
- /* @__PURE__ */ jsx("h4", { className: "text-sm font-medium text-foreground truncate", children: title }),
5539
- subtitle && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: subtitle }),
5540
- metadata && metadata.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 mt-1", children: metadata.map((item, index) => /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: item }, index)) })
5541
- ] }),
5542
- (value || badge) && /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
5543
- value && /* @__PURE__ */ jsx(
5544
- "p",
5545
- {
5546
- className: cn(
5547
- "text-sm font-semibold",
5548
- value.variant && valueColorMap[value.variant],
5549
- value.className
5550
- ),
5551
- children: value.text
5552
- }
5553
- ),
5554
- badge && /* @__PURE__ */ jsx(
5555
- DataBadge,
5556
- {
5557
- variant: badge.variant,
5558
- status: badge.variant === "status" ? badge.status : void 0,
5559
- category: badge.variant === "category" ? badge.category : void 0,
5560
- size: badge.size || "sm",
5561
- icon: badge.icon,
5562
- className: "mt-1",
5563
- children: badge.text
5564
- }
5565
- )
5566
- ] })
5567
- ] }),
5568
- children
5569
- ] })
5570
- ]
5571
- }
5572
- );
5573
- }
5574
6268
  const TruncatedText = ({
5575
6269
  text,
5576
6270
  className,
@@ -8891,6 +9585,13 @@ const defaultShowcaseNavigation = [
8891
9585
  path: "/admin/dashboard",
8892
9586
  category: 2
8893
9587
  },
9588
+ {
9589
+ value: "admin-dashboard-v2",
9590
+ label: "Admin Dashboard V2",
9591
+ icon: "Shield",
9592
+ path: "/admin/dashboard-v2",
9593
+ category: 2
9594
+ },
8894
9595
  {
8895
9596
  value: "admin-users",
8896
9597
  label: "User Management",
@@ -9161,7 +9862,6 @@ const Sidebar = ({ className }) => {
9161
9862
  );
9162
9863
  };
9163
9864
  const AppHeader = ({ className }) => {
9164
- const isTrialMode = false;
9165
9865
  return /* @__PURE__ */ jsx(
9166
9866
  "header",
9167
9867
  {
@@ -9174,7 +9874,7 @@ const AppHeader = ({ className }) => {
9174
9874
  children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-7xl px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs("div", { className: "flex h-16 items-center justify-between", children: [
9175
9875
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
9176
9876
  /* @__PURE__ */ jsx("h1", { className: "text-xl font-bold text-foreground", children: "Frontend Template" }),
9177
- isTrialMode
9877
+ /* @__PURE__ */ jsx(DataBadge, { variant: "status", status: "info", display: "icon-text", children: "Trial Mode" })
9178
9878
  ] }),
9179
9879
  /* @__PURE__ */ jsx("div", { className: "flex-1 max-w-2xl mx-8", children: /* @__PURE__ */ jsx(
9180
9880
  GlobalSearch,
@@ -13958,18 +14658,41 @@ function createReactApp(config) {
13958
14658
  enableRouting = true,
13959
14659
  auth,
13960
14660
  navigation,
13961
- customProviders = []
14661
+ customProviders = [],
14662
+ persistQueryCache = false,
14663
+ queryCacheKey = "PATTERN_STACK_QUERY_CACHE"
13962
14664
  } = appConfig;
13963
14665
  const queryClient = new QueryClient({
13964
14666
  defaultOptions: {
13965
14667
  queries: {
13966
14668
  retry: 1,
13967
14669
  refetchOnWindowFocus: false,
13968
- staleTime: 5 * 60 * 1e3
14670
+ staleTime: 5 * 60 * 1e3,
13969
14671
  // 5 minutes
14672
+ // Keep data longer when persistence is enabled
14673
+ gcTime: persistQueryCache ? 1e3 * 60 * 60 * 24 : 1e3 * 60 * 5
13970
14674
  }
13971
14675
  }
13972
14676
  });
14677
+ if (persistQueryCache && typeof window !== "undefined") {
14678
+ import("@tanstack/react-query-persist-client").then(({ persistQueryClient }) => {
14679
+ import("@tanstack/query-sync-storage-persister").then(({ createSyncStoragePersister }) => {
14680
+ const persister = createSyncStoragePersister({
14681
+ storage: window.localStorage,
14682
+ key: queryCacheKey
14683
+ });
14684
+ persistQueryClient({
14685
+ queryClient,
14686
+ persister,
14687
+ maxAge: 1e3 * 60 * 60 * 24
14688
+ // 24 hours
14689
+ });
14690
+ console.info("[app] Query cache persistence enabled");
14691
+ });
14692
+ }).catch((err) => {
14693
+ console.warn("[app] Query persistence not available:", err.message);
14694
+ });
14695
+ }
13973
14696
  const routes = [];
13974
14697
  const DefaultHome = () => /* @__PURE__ */ jsx(DashboardTemplate, { title, description, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center min-h-[400px] text-center", children: [
13975
14698
  /* @__PURE__ */ jsxs("h1", { className: "text-4xl font-bold text-foreground mb-4", children: [
@@ -13988,7 +14711,7 @@ function createReactApp(config) {
13988
14711
  ] }) });
13989
14712
  const createProviderTree = (children) => {
13990
14713
  let tree = children;
13991
- customProviders.reverse().forEach((Provider) => {
14714
+ [...customProviders].reverse().forEach((Provider) => {
13992
14715
  tree = /* @__PURE__ */ jsx(Provider, { children: tree }, Provider.name);
13993
14716
  });
13994
14717
  if (enableRouting) {
@@ -14031,10 +14754,10 @@ function createReactApp(config) {
14031
14754
  }
14032
14755
  return component;
14033
14756
  };
14034
- const AppContent = () => /* @__PURE__ */ jsx(Routes, { children: /* @__PURE__ */ jsxs(Route, { path: "/", element: /* @__PURE__ */ jsx(AppLayout, {}), children: [
14757
+ const AppContent = () => /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center min-h-screen", children: "Loading..." }), children: /* @__PURE__ */ jsx(Routes, { children: /* @__PURE__ */ jsxs(Route, { path: "/", element: /* @__PURE__ */ jsx(AppLayout, {}), children: [
14035
14758
  /* @__PURE__ */ jsx(Route, { index: true, element: wrapWithProtection("/", /* @__PURE__ */ jsx(DefaultHome, {})) }),
14036
14759
  routes.map(({ path, component }, index) => /* @__PURE__ */ jsx(Route, { path, element: wrapWithProtection(path, component) }, index))
14037
- ] }) });
14760
+ ] }) }) });
14038
14761
  return createProviderTree(/* @__PURE__ */ jsx(AppContent, {}));
14039
14762
  },
14040
14763
  mount(elementId = "root") {
@@ -17230,6 +17953,10 @@ export {
17230
17953
  Breadcrumb,
17231
17954
  BulkSelectionBar,
17232
17955
  Button,
17956
+ COLUMN_WIDTHS,
17957
+ COMPACT_COLUMN_WIDTHS,
17958
+ COMPACT_FORMATTERS,
17959
+ COMPACT_LABELS,
17233
17960
  Card,
17234
17961
  CardContent,
17235
17962
  CardDescription,
@@ -17288,6 +18015,7 @@ export {
17288
18015
  FormField,
17289
18016
  FormGroup,
17290
18017
  GlobalSearch,
18018
+ IMPORTANCE_VISIBILITY,
17291
18019
  Icon,
17292
18020
  IconBadge,
17293
18021
  Input,
@@ -17343,6 +18071,7 @@ export {
17343
18071
  StatCard,
17344
18072
  StyleGuide,
17345
18073
  Switch,
18074
+ TABLE_BREAKPOINTS,
17346
18075
  Table,
17347
18076
  TableBody,
17348
18077
  TableCaption,
@@ -17365,19 +18094,27 @@ export {
17365
18094
  animationPresets,
17366
18095
  apiClient,
17367
18096
  breakpoints,
18097
+ calculateTableWidth,
17368
18098
  cn,
17369
18099
  createAPIDataTemplate,
17370
18100
  createApiClient,
18101
+ createMobileCardRenderer,
17371
18102
  createReactApp,
17372
18103
  createSimpleApp,
17373
18104
  defaultFieldRenderers,
17374
18105
  detectBulkOperationType,
17375
18106
  detectUIConfig,
18107
+ determineTableMode,
18108
+ entityToListCardProps,
17376
18109
  env,
17377
18110
  formatNumberWithTooltip,
17378
18111
  generateBulkOperationName,
18112
+ generateCompactColumns,
17379
18113
  getAnimationClasses,
17380
18114
  getChartHeight,
18115
+ getColumnWidth,
18116
+ getCompactFormatter,
18117
+ getCompactLabel,
17381
18118
  getContainerHeightClass,
17382
18119
  getCurrentBreakpoint,
17383
18120
  getFieldType,
@@ -17396,6 +18133,7 @@ export {
17396
18133
  responsiveScales,
17397
18134
  setGlobalAuthService,
17398
18135
  tooltipContent,
18136
+ useAdaptiveTable,
17399
18137
  useApiMutation,
17400
18138
  useApiQuery,
17401
18139
  useAuth,