@pattern-stack/frontend-patterns 0.2.0-alpha.5 → 0.2.0-alpha.6

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/index.js CHANGED
@@ -2052,6 +2052,362 @@ function renderField(value, fieldName, fieldType, breakpoint, item, customRender
2052
2052
  function cn(...inputs) {
2053
2053
  return tailwindMerge.twMerge(clsx.clsx(inputs));
2054
2054
  }
2055
+ const STATUS_COLOR_MAP = {
2056
+ // Success states
2057
+ active: "success",
2058
+ completed: "success",
2059
+ approved: "success",
2060
+ paid: "success",
2061
+ delivered: "success",
2062
+ resolved: "success",
2063
+ closed: "success",
2064
+ // Warning states
2065
+ pending: "warning",
2066
+ processing: "warning",
2067
+ review: "warning",
2068
+ draft: "warning",
2069
+ waiting: "warning",
2070
+ // Error states
2071
+ failed: "error",
2072
+ rejected: "error",
2073
+ cancelled: "error",
2074
+ overdue: "error",
2075
+ blocked: "error",
2076
+ // Info states
2077
+ new: "info",
2078
+ open: "info",
2079
+ in_progress: "info",
2080
+ scheduled: "info",
2081
+ // Neutral (default)
2082
+ inactive: "neutral",
2083
+ archived: "neutral",
2084
+ unknown: "neutral"
2085
+ };
2086
+ function getStatusColor(value) {
2087
+ if (typeof value !== "string") return "neutral";
2088
+ const normalized = value.toLowerCase().replace(/[_-]/g, "_");
2089
+ return STATUS_COLOR_MAP[normalized] ?? "neutral";
2090
+ }
2091
+ const CATEGORY_MAP = {
2092
+ account: 1,
2093
+ customer: 1,
2094
+ client: 1,
2095
+ user: 2,
2096
+ contact: 2,
2097
+ person: 2,
2098
+ order: 3,
2099
+ sale: 3,
2100
+ transaction: 3,
2101
+ product: 4,
2102
+ item: 4,
2103
+ inventory: 4,
2104
+ task: 5,
2105
+ activity: 5,
2106
+ event: 5,
2107
+ file: 6,
2108
+ document: 6,
2109
+ report: 6,
2110
+ tag: 7,
2111
+ category: 7,
2112
+ label: 7,
2113
+ default: 8
2114
+ };
2115
+ function getCategoryForEntity(entityType) {
2116
+ if (!entityType) return 8;
2117
+ const normalized = entityType.toLowerCase();
2118
+ for (const [key, value] of Object.entries(CATEGORY_MAP)) {
2119
+ if (normalized.includes(key)) return value;
2120
+ }
2121
+ return 8;
2122
+ }
2123
+ function getIconForEntity(entityType) {
2124
+ if (!entityType) return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { className: "w-4 h-4" });
2125
+ const normalized = entityType.toLowerCase();
2126
+ if (normalized.includes("account") || normalized.includes("customer") || normalized.includes("client")) {
2127
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Building2, { className: "w-4 h-4" });
2128
+ }
2129
+ if (normalized.includes("user") || normalized.includes("contact") || normalized.includes("person")) {
2130
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "w-4 h-4" });
2131
+ }
2132
+ if (normalized.includes("product") || normalized.includes("item")) {
2133
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Package, { className: "w-4 h-4" });
2134
+ }
2135
+ if (normalized.includes("file") || normalized.includes("document")) {
2136
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "w-4 h-4" });
2137
+ }
2138
+ if (normalized.includes("tag") || normalized.includes("category")) {
2139
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tag, { className: "w-4 h-4" });
2140
+ }
2141
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { className: "w-4 h-4" });
2142
+ }
2143
+ function normalizeImportance(importance) {
2144
+ switch (importance) {
2145
+ case "critical":
2146
+ case "high":
2147
+ case "primary":
2148
+ return "primary";
2149
+ case "medium":
2150
+ case "secondary":
2151
+ return "secondary";
2152
+ default:
2153
+ return "tertiary";
2154
+ }
2155
+ }
2156
+ function isPrimaryImportance(importance) {
2157
+ return normalizeImportance(importance) === "primary";
2158
+ }
2159
+ function formatValueForCard(value, type, format) {
2160
+ if (value === null || value === void 0) return "—";
2161
+ switch (type) {
2162
+ case "money": {
2163
+ const num = Number(value);
2164
+ const currency = (format == null ? void 0 : format.currency) ?? "USD";
2165
+ if (num >= 1e6) {
2166
+ return new Intl.NumberFormat("en-US", {
2167
+ style: "currency",
2168
+ currency,
2169
+ notation: "compact",
2170
+ maximumFractionDigits: 1
2171
+ }).format(num);
2172
+ }
2173
+ if (num >= 1e3) {
2174
+ return new Intl.NumberFormat("en-US", {
2175
+ style: "currency",
2176
+ currency,
2177
+ notation: "compact",
2178
+ maximumFractionDigits: 1
2179
+ }).format(num);
2180
+ }
2181
+ return new Intl.NumberFormat("en-US", {
2182
+ style: "currency",
2183
+ currency,
2184
+ maximumFractionDigits: 0
2185
+ }).format(num);
2186
+ }
2187
+ case "percent": {
2188
+ const num = Number(value);
2189
+ return `${num.toFixed(0)}%`;
2190
+ }
2191
+ case "number": {
2192
+ const num = Number(value);
2193
+ if (num >= 1e6) return `${(num / 1e6).toFixed(1)}M`;
2194
+ if (num >= 1e3) return `${(num / 1e3).toFixed(1)}K`;
2195
+ return String(num);
2196
+ }
2197
+ case "date":
2198
+ case "datetime": {
2199
+ const date = new Date(String(value));
2200
+ if (isNaN(date.getTime())) return String(value);
2201
+ return date.toLocaleDateString("en-US", {
2202
+ month: "short",
2203
+ day: "numeric"
2204
+ });
2205
+ }
2206
+ case "boolean":
2207
+ return value ? "Yes" : "No";
2208
+ default:
2209
+ return String(value);
2210
+ }
2211
+ }
2212
+ function autoDetectMapping(columns) {
2213
+ var _a, _b, _c, _d, _e, _f;
2214
+ const primaryCols = columns.filter((c) => isPrimaryImportance(c.importance));
2215
+ 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);
2216
+ const valueField = (_d = primaryCols.find((c) => c.type === "money")) == null ? void 0 : _d.field;
2217
+ const statusField = (_e = primaryCols.find(
2218
+ (c) => c.type === "status" || c.type === "badge"
2219
+ )) == null ? void 0 : _e.field;
2220
+ const usedForMain = new Set([titleField, valueField, statusField].filter(Boolean));
2221
+ const remainingPrimary = primaryCols.filter((c) => !usedForMain.has(c.field));
2222
+ const subtitleField = (_f = remainingPrimary[0]) == null ? void 0 : _f.field;
2223
+ const usedFields = new Set(
2224
+ [titleField, valueField, statusField, subtitleField].filter(Boolean)
2225
+ );
2226
+ const metadataFields = primaryCols.filter((c) => !usedFields.has(c.field)).slice(0, 3).map((c) => c.field);
2227
+ return {
2228
+ titleField: titleField ?? "id",
2229
+ subtitleField,
2230
+ valueField,
2231
+ statusField,
2232
+ metadataFields,
2233
+ iconConfig: void 0
2234
+ };
2235
+ }
2236
+ function entityToListCardProps(item, columns, mapping, entityType) {
2237
+ const autoMapping = autoDetectMapping(columns);
2238
+ const effectiveMapping = { ...autoMapping, ...mapping };
2239
+ const {
2240
+ titleField,
2241
+ subtitleField,
2242
+ valueField,
2243
+ statusField,
2244
+ metadataFields,
2245
+ iconConfig
2246
+ } = effectiveMapping;
2247
+ const getColumn = (field) => field ? columns.find((c) => c.field === field) : void 0;
2248
+ const title = item[titleField] != null ? String(item[titleField]) : "—";
2249
+ const subtitle = subtitleField && item[subtitleField] != null ? String(item[subtitleField]) : void 0;
2250
+ let value;
2251
+ if (valueField && item[valueField] != null) {
2252
+ const valueCol = getColumn(valueField);
2253
+ const formatted = formatValueForCard(
2254
+ item[valueField],
2255
+ (valueCol == null ? void 0 : valueCol.type) ?? "text",
2256
+ valueCol == null ? void 0 : valueCol.format
2257
+ );
2258
+ value = {
2259
+ text: formatted,
2260
+ variant: "success"
2261
+ // Money typically green
2262
+ };
2263
+ }
2264
+ let badge;
2265
+ if (statusField && item[statusField] != null) {
2266
+ const statusValue = String(item[statusField]);
2267
+ badge = {
2268
+ text: statusValue,
2269
+ variant: "status",
2270
+ status: getStatusColor(statusValue),
2271
+ size: "sm"
2272
+ };
2273
+ }
2274
+ const metadata = metadataFields == null ? void 0 : metadataFields.map((field) => {
2275
+ const col = getColumn(field);
2276
+ if (!col || item[field] == null) return null;
2277
+ return formatValueForCard(item[field], col.type, col.format);
2278
+ }).filter((v) => v !== null);
2279
+ let icon;
2280
+ if (iconConfig) {
2281
+ const iconValue = iconConfig.field ? item[iconConfig.field] : void 0;
2282
+ if (iconConfig.variant === "status" && iconValue) {
2283
+ icon = {
2284
+ icon: iconConfig.icon ?? getIconForEntity(entityType),
2285
+ variant: "status",
2286
+ status: getStatusColor(iconValue),
2287
+ size: "sm"
2288
+ };
2289
+ } else {
2290
+ icon = {
2291
+ icon: iconConfig.icon ?? getIconForEntity(entityType),
2292
+ variant: "category",
2293
+ category: getCategoryForEntity(entityType),
2294
+ size: "sm"
2295
+ };
2296
+ }
2297
+ } else {
2298
+ icon = {
2299
+ icon: getIconForEntity(entityType),
2300
+ variant: "category",
2301
+ category: getCategoryForEntity(entityType),
2302
+ size: "sm"
2303
+ };
2304
+ }
2305
+ return {
2306
+ icon,
2307
+ title,
2308
+ subtitle,
2309
+ metadata,
2310
+ value,
2311
+ badge
2312
+ };
2313
+ }
2314
+ const HEADER_ABBREVIATIONS = {
2315
+ customer: "Cust",
2316
+ account: "Acct",
2317
+ amount: "Amt",
2318
+ quantity: "Qty",
2319
+ priority: "Pri",
2320
+ status: "Status",
2321
+ created: "Created",
2322
+ updated: "Updated",
2323
+ description: "Desc",
2324
+ total: "Total",
2325
+ items: "Items",
2326
+ number: "#",
2327
+ date: "Date",
2328
+ time: "Time"
2329
+ };
2330
+ function abbreviateHeader(label) {
2331
+ const lower = label.toLowerCase();
2332
+ for (const [key, abbrev] of Object.entries(HEADER_ABBREVIATIONS)) {
2333
+ if (lower.includes(key)) return abbrev;
2334
+ }
2335
+ if (label.length > 8) return label.slice(0, 6) + "…";
2336
+ return label;
2337
+ }
2338
+ function generateCompactColumns(columns, options = {}) {
2339
+ const {
2340
+ maxColumns = 5,
2341
+ abbreviateHeaders = true,
2342
+ requiredFields = [],
2343
+ excludeFields = []
2344
+ } = options;
2345
+ const excludeSet = new Set(excludeFields);
2346
+ const requiredSet = new Set(requiredFields);
2347
+ const filteredColumns = columns.filter((col) => {
2348
+ if (excludeSet.has(col.field)) return false;
2349
+ return true;
2350
+ });
2351
+ const required = filteredColumns.filter((c) => requiredSet.has(c.field));
2352
+ const primary = filteredColumns.filter(
2353
+ (c) => !requiredSet.has(c.field) && normalizeImportance(c.importance) === "primary"
2354
+ );
2355
+ const secondary = filteredColumns.filter(
2356
+ (c) => !requiredSet.has(c.field) && normalizeImportance(c.importance) === "secondary"
2357
+ );
2358
+ const selectedColumns = [...required, ...primary, ...secondary].slice(
2359
+ 0,
2360
+ maxColumns
2361
+ );
2362
+ return selectedColumns.map((col) => ({
2363
+ key: col.field,
2364
+ header: abbreviateHeaders ? abbreviateHeader(col.label) : col.label,
2365
+ sortable: col.sortable,
2366
+ type: col.type,
2367
+ format: col.format,
2368
+ // Compact widths
2369
+ width: getCompactWidth(col.type)
2370
+ }));
2371
+ }
2372
+ function getCompactWidth(type) {
2373
+ switch (type) {
2374
+ case "money":
2375
+ return "70px";
2376
+ case "number":
2377
+ case "percent":
2378
+ return "50px";
2379
+ case "status":
2380
+ case "badge":
2381
+ return "80px";
2382
+ case "date":
2383
+ return "70px";
2384
+ case "datetime":
2385
+ return "90px";
2386
+ case "boolean":
2387
+ return "50px";
2388
+ default:
2389
+ return "120px";
2390
+ }
2391
+ }
2392
+ function createMobileCardRenderer(columns, mapping, entityType) {
2393
+ const { ListCard: ListCard2 } = require("../components/data/ListCard");
2394
+ return ({ data, onItemClick }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: data.map((item, index) => {
2395
+ const cardProps = entityToListCardProps(
2396
+ item,
2397
+ columns,
2398
+ mapping,
2399
+ entityType
2400
+ );
2401
+ return /* @__PURE__ */ jsxRuntime.jsx(
2402
+ ListCard2,
2403
+ {
2404
+ ...cardProps,
2405
+ onClick: onItemClick ? () => onItemClick(item) : void 0
2406
+ },
2407
+ item.id ?? index
2408
+ );
2409
+ }) });
2410
+ }
2055
2411
  let globalAuthService = null;
2056
2412
  function setGlobalAuthService(authService) {
2057
2413
  globalAuthService = authService;
@@ -2105,6 +2461,9 @@ class ApiClient {
2105
2461
  async (error) => {
2106
2462
  var _a, _b, _c, _d;
2107
2463
  const status = (_a = error.response) == null ? void 0 : _a.status;
2464
+ if (!error.response) {
2465
+ return Promise.reject(error);
2466
+ }
2108
2467
  if (status === 401 || status === 403) {
2109
2468
  if (globalAuthService) {
2110
2469
  const tokenData = globalAuthService.getTokenData();
@@ -2122,12 +2481,12 @@ class ApiClient {
2122
2481
  const errorInfo = { status, message: (_c = (_b = error.response) == null ? void 0 : _b.data) == null ? void 0 : _c.detail };
2123
2482
  const handled = (_d = globalAuthService.onAuthError) == null ? void 0 : _d.call(globalAuthService, errorInfo);
2124
2483
  if (!handled) {
2125
- window.location.reload();
2484
+ window.location.href = "/login";
2126
2485
  }
2127
2486
  } else {
2128
2487
  localStorage.removeItem("auth_token");
2129
2488
  localStorage.removeItem("auth_user");
2130
- window.location.reload();
2489
+ window.location.href = "/login";
2131
2490
  }
2132
2491
  }
2133
2492
  return Promise.reject(error);
@@ -2502,6 +2861,61 @@ function useEntityDetail(entity, id, options = {}) {
2502
2861
  refetch
2503
2862
  };
2504
2863
  }
2864
+ function useOnlineStatus(healthEndpoint) {
2865
+ const [isOnline, setIsOnline] = React.useState(
2866
+ typeof navigator !== "undefined" ? navigator.onLine : true
2867
+ );
2868
+ const [isBackendReachable, setIsBackendReachable] = React.useState(true);
2869
+ const [lastBackendContact, setLastBackendContact] = React.useState(
2870
+ null
2871
+ );
2872
+ React.useEffect(() => {
2873
+ const handleOnline = () => setIsOnline(true);
2874
+ const handleOffline = () => {
2875
+ setIsOnline(false);
2876
+ setIsBackendReachable(false);
2877
+ };
2878
+ window.addEventListener("online", handleOnline);
2879
+ window.addEventListener("offline", handleOffline);
2880
+ return () => {
2881
+ window.removeEventListener("online", handleOnline);
2882
+ window.removeEventListener("offline", handleOffline);
2883
+ };
2884
+ }, []);
2885
+ const checkBackend = React.useCallback(async () => {
2886
+ if (!isOnline) {
2887
+ setIsBackendReachable(false);
2888
+ return false;
2889
+ }
2890
+ try {
2891
+ const endpoint = healthEndpoint || "/api/v1/health";
2892
+ const response = await fetch(endpoint, {
2893
+ method: "GET",
2894
+ cache: "no-store"
2895
+ });
2896
+ const reachable = response.ok;
2897
+ setIsBackendReachable(reachable);
2898
+ if (reachable) {
2899
+ setLastBackendContact(Date.now());
2900
+ }
2901
+ return reachable;
2902
+ } catch {
2903
+ setIsBackendReachable(false);
2904
+ return false;
2905
+ }
2906
+ }, [isOnline, healthEndpoint]);
2907
+ React.useEffect(() => {
2908
+ if (isOnline) {
2909
+ checkBackend();
2910
+ }
2911
+ }, [isOnline, checkBackend]);
2912
+ return {
2913
+ isOnline,
2914
+ isBackendReachable,
2915
+ lastBackendContact,
2916
+ checkBackend
2917
+ };
2918
+ }
2505
2919
  const buttonVariants = classVarianceAuthority.cva(
2506
2920
  "inline-flex items-center justify-center whitespace-nowrap rounded-lg text-sm font-medium ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/20 focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.98]",
2507
2921
  {
@@ -5758,6 +6172,75 @@ const ActivityFeed = ({
5758
6172
  ] }) })
5759
6173
  ] });
5760
6174
  };
6175
+ const statusConfig = {
6176
+ online: {
6177
+ icon: lucideReact.Cloud,
6178
+ label: "Online",
6179
+ color: "text-green-600 dark:text-green-400",
6180
+ bgColor: "bg-green-100 dark:bg-green-900/30"
6181
+ },
6182
+ degraded: {
6183
+ icon: lucideReact.CloudOff,
6184
+ label: "Server Offline",
6185
+ color: "text-yellow-600 dark:text-yellow-400",
6186
+ bgColor: "bg-yellow-100 dark:bg-yellow-900/30"
6187
+ },
6188
+ offline: {
6189
+ icon: lucideReact.WifiOff,
6190
+ label: "Offline",
6191
+ color: "text-red-600 dark:text-red-400",
6192
+ bgColor: "bg-red-100 dark:bg-red-900/30"
6193
+ }
6194
+ };
6195
+ function ConnectionStatus({
6196
+ healthEndpoint,
6197
+ variant = "badge",
6198
+ className,
6199
+ showWhenOnline = false
6200
+ }) {
6201
+ const { isOnline, isBackendReachable } = useOnlineStatus(healthEndpoint);
6202
+ const status = !isOnline ? "offline" : !isBackendReachable ? "degraded" : "online";
6203
+ if (status === "online" && !showWhenOnline) {
6204
+ return null;
6205
+ }
6206
+ const config = statusConfig[status];
6207
+ const Icon2 = config.icon;
6208
+ if (variant === "badge") {
6209
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6210
+ "div",
6211
+ {
6212
+ className: cn(
6213
+ "inline-flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium",
6214
+ config.bgColor,
6215
+ config.color,
6216
+ className
6217
+ ),
6218
+ children: [
6219
+ /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "h-3 w-3" }),
6220
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: config.label })
6221
+ ]
6222
+ }
6223
+ );
6224
+ }
6225
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6226
+ "div",
6227
+ {
6228
+ className: cn(
6229
+ "flex items-center gap-2 px-3 py-2 rounded-lg",
6230
+ config.bgColor,
6231
+ className
6232
+ ),
6233
+ children: [
6234
+ /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: cn("h-4 w-4", config.color) }),
6235
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
6236
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-sm font-medium", config.color), children: config.label }),
6237
+ status === "degraded" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Working with cached data" }),
6238
+ status === "offline" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Check your connection" })
6239
+ ] })
6240
+ ]
6241
+ }
6242
+ );
6243
+ }
5761
6244
  const FormField = ({
5762
6245
  label,
5763
6246
  description,
@@ -9099,7 +9582,10 @@ const AppHeader = ({ className }) => {
9099
9582
  placeholder: "Search models, tests, jobs, and components..."
9100
9583
  }
9101
9584
  ) }),
9102
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center space-x-4", children: /* @__PURE__ */ jsxRuntime.jsx(UserMenu, { category: 8 }) })
9585
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-4", children: [
9586
+ /* @__PURE__ */ jsxRuntime.jsx(ConnectionStatus, {}),
9587
+ /* @__PURE__ */ jsxRuntime.jsx(UserMenu, { category: 8 })
9588
+ ] })
9103
9589
  ] }) })
9104
9590
  }
9105
9591
  );
@@ -10452,10 +10938,12 @@ function AuthProvider({
10452
10938
  try {
10453
10939
  await authService.refreshToken();
10454
10940
  setUser(storedUser);
10455
- try {
10456
- const freshUser = await authService.getCurrentUser();
10457
- if (freshUser) setUser(freshUser);
10458
- } catch {
10941
+ if (!(config == null ? void 0 : config.offlineFirst)) {
10942
+ try {
10943
+ const freshUser = await authService.getCurrentUser();
10944
+ if (freshUser) setUser(freshUser);
10945
+ } catch {
10946
+ }
10459
10947
  }
10460
10948
  } catch {
10461
10949
  authService.clearAuth();
@@ -10465,10 +10953,12 @@ function AuthProvider({
10465
10953
  }
10466
10954
  } else {
10467
10955
  setUser(storedUser);
10468
- try {
10469
- const freshUser = await authService.getCurrentUser();
10470
- if (freshUser) setUser(freshUser);
10471
- } catch {
10956
+ if (!(config == null ? void 0 : config.offlineFirst)) {
10957
+ try {
10958
+ const freshUser = await authService.getCurrentUser();
10959
+ if (freshUser) setUser(freshUser);
10960
+ } catch {
10961
+ }
10472
10962
  }
10473
10963
  }
10474
10964
  }
@@ -17150,6 +17640,7 @@ exports.Checkbox = Checkbox;
17150
17640
  exports.ColorSwatch = ColorSwatch;
17151
17641
  exports.ComponentShowcasePage = ComponentShowcasePage;
17152
17642
  exports.ComponentShowcaseTemplate = ComponentShowcaseTemplate;
17643
+ exports.ConnectionStatus = ConnectionStatus;
17153
17644
  exports.DASHBOARD_CHART_HEIGHTS = DASHBOARD_CHART_HEIGHTS;
17154
17645
  exports.DASHBOARD_CONTAINER_HEIGHTS = DASHBOARD_CONTAINER_HEIGHTS;
17155
17646
  exports.DASHBOARD_HEIGHT_CLASSES = DASHBOARD_HEIGHT_CLASSES;
@@ -17275,14 +17766,17 @@ exports.breakpoints = breakpoints;
17275
17766
  exports.cn = cn;
17276
17767
  exports.createAPIDataTemplate = createAPIDataTemplate;
17277
17768
  exports.createApiClient = createApiClient;
17769
+ exports.createMobileCardRenderer = createMobileCardRenderer;
17278
17770
  exports.createReactApp = createReactApp;
17279
17771
  exports.createSimpleApp = createSimpleApp;
17280
17772
  exports.defaultFieldRenderers = defaultFieldRenderers;
17281
17773
  exports.detectBulkOperationType = detectBulkOperationType;
17282
17774
  exports.detectUIConfig = detectUIConfig;
17775
+ exports.entityToListCardProps = entityToListCardProps;
17283
17776
  exports.env = env;
17284
17777
  exports.formatNumberWithTooltip = formatNumberWithTooltip;
17285
17778
  exports.generateBulkOperationName = generateBulkOperationName;
17779
+ exports.generateCompactColumns = generateCompactColumns;
17286
17780
  exports.getAnimationClasses = getAnimationClasses;
17287
17781
  exports.getChartHeight = getChartHeight;
17288
17782
  exports.getContainerHeightClass = getContainerHeightClass;
@@ -17324,6 +17818,7 @@ exports.useMaxMediaQuery = useMaxMediaQuery;
17324
17818
  exports.useMediaQuery = useMediaQuery;
17325
17819
  exports.useMockAuth = useMockAuth;
17326
17820
  exports.useNavigation = useNavigation;
17821
+ exports.useOnlineStatus = useOnlineStatus;
17327
17822
  exports.useOverflowDetection = useOverflowDetection;
17328
17823
  exports.usePermissions = usePermissions;
17329
17824
  exports.useResponsiveClasses = useResponsiveClasses;