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

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,362 +2052,6 @@ 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
- }
2411
2055
  let globalAuthService = null;
2412
2056
  function setGlobalAuthService(authService) {
2413
2057
  globalAuthService = authService;
@@ -17766,17 +17410,14 @@ exports.breakpoints = breakpoints;
17766
17410
  exports.cn = cn;
17767
17411
  exports.createAPIDataTemplate = createAPIDataTemplate;
17768
17412
  exports.createApiClient = createApiClient;
17769
- exports.createMobileCardRenderer = createMobileCardRenderer;
17770
17413
  exports.createReactApp = createReactApp;
17771
17414
  exports.createSimpleApp = createSimpleApp;
17772
17415
  exports.defaultFieldRenderers = defaultFieldRenderers;
17773
17416
  exports.detectBulkOperationType = detectBulkOperationType;
17774
17417
  exports.detectUIConfig = detectUIConfig;
17775
- exports.entityToListCardProps = entityToListCardProps;
17776
17418
  exports.env = env;
17777
17419
  exports.formatNumberWithTooltip = formatNumberWithTooltip;
17778
17420
  exports.generateBulkOperationName = generateBulkOperationName;
17779
- exports.generateCompactColumns = generateCompactColumns;
17780
17421
  exports.getAnimationClasses = getAnimationClasses;
17781
17422
  exports.getChartHeight = getChartHeight;
17782
17423
  exports.getContainerHeightClass = getContainerHeightClass;