UNPKG

@blocktion/json-to-table

Version:

A powerful, modular React component for converting JSON data to navigable tables with advanced features like automatic column detection, theming, and sub-table navigation. Part of the Blocktion SaaS project ecosystem.

161 lines (160 loc) 7.67 kB
import { jsx as _jsx } from "react/jsx-runtime"; import { ObjectUtils } from "../../utils/objectUtils"; import { ArrayAnalyzer } from "../../utils/arrayUtils"; import { NavigableCell } from "../Cells/NavigableCell"; export const TableCell = ({ column, row, onNavigateToSubTable, onCellClick, enableNavigation, showRowNumbers, customRenderers = {}, }) => { const value = ObjectUtils.getNestedValue(row, column.cleanKey); const handleCellClick = () => { onCellClick?.(value, column, row); }; const handleNavigate = () => { const valueIsArray = Array.isArray(value); const valueIsObject = !!value && typeof value === "object" && !Array.isArray(value); // Check if this is navigable based on type or navigation metadata let isNavigable = valueIsArray || valueIsObject; // For root table columns, don't rely on column.isNavigable since it's based on primary type // Instead, analyze each individual value if (!isNavigable && column.columnType.isNavigable) { // This is a root table column that was marked as navigable due to mixed types // Check if THIS specific value is navigable isNavigable = valueIsArray || valueIsObject; } // Special check for mixed array items if (!isNavigable && column.cleanKey === "value" && row && typeof row === "object") { const rowObj = row; if ("_navigationInfo" in rowObj) { const navInfo = rowObj._navigationInfo; isNavigable = navInfo.isNavigable; } } if (!enableNavigation || !isNavigable) return; let title; if (valueIsArray || column.columnType.isArray) { const arrayContentType = column.columnType.arrayContentType || (Array.isArray(value) ? ArrayAnalyzer.analyzeContent(value).type : "primitives"); title = ArrayAnalyzer.getNavigationTitle(value, arrayContentType); } else if (valueIsObject || column.columnType.isObject) { title = `${column.displayName} (Object)`; } else { title = `${column.displayName} (Value)`; } onNavigateToSubTable(column.cleanKey, value, title); }; const formatValue = (val) => { if (val === null || val === undefined) return ""; if (typeof val === "string") { return val.length > 30 ? val.substring(0, 27) + "..." : val; } if (typeof val === "object" && val !== null) { const jsonStr = JSON.stringify(val); return jsonStr.length > 30 ? jsonStr.substring(0, 27) + "..." : jsonStr; } return String(val); }; // Custom renderer if (column.renderer) { return (_jsx("td", { className: "px-6 py-4 text-body-sm text-obsidian align-top max-w-xs", style: { width: showRowNumbers ? "auto" : column.width || "auto", }, onClick: handleCellClick, children: column.renderer(value, row) })); } // Custom renderer from props if (customRenderers[column.cleanKey]) { return (_jsx("td", { className: "px-6 py-4 text-body-sm text-obsidian align-top max-w-xs", style: { width: showRowNumbers ? "auto" : column.width || "auto", }, onClick: handleCellClick, children: customRenderers[column.cleanKey](value, row) })); } // Navigable cell (runtime check as well, so arrays/objects parsed at runtime are navigable) const valueIsArray = Array.isArray(value); const valueIsObject = !!value && typeof value === "object" && !Array.isArray(value); // Check if this is navigable based on type or navigation metadata let isNavigableNow = enableNavigation && (valueIsArray || valueIsObject); // For root table columns, don't rely on column.isNavigable since it's based on primary type // Instead, analyze each individual value if (!isNavigableNow && column.columnType.isNavigable) { // This is a root table column that was marked as navigable due to mixed types // Check if THIS specific value is navigable isNavigableNow = enableNavigation && (valueIsArray || valueIsObject); } // Special check for mixed array items if (!isNavigableNow && column.cleanKey === "value" && row && typeof row === "object") { const rowObj = row; if ("_navigationInfo" in rowObj) { const navInfo = rowObj._navigationInfo; isNavigableNow = enableNavigation && navInfo.isNavigable; } } if (isNavigableNow && value) { let displayText; let type; if (valueIsArray || column.columnType.isArray) { const arrayContentType = column.columnType.arrayContentType || (Array.isArray(value) ? ArrayAnalyzer.analyzeContent(value).type : "primitives"); // Show count-based text for all arrays displayText = ArrayAnalyzer.getArrayDisplayText(value); type = "array"; } else if (valueIsObject || column.columnType.isObject) { displayText = "Object"; type = "object"; } else { // Special handling for mixed array items if (column.cleanKey === "value" && row && typeof row === "object") { const rowObj = row; if ("_navigationInfo" in rowObj) { // This is a mixed array item with navigation metadata const navInfo = rowObj._navigationInfo; if (navInfo.isNavigable) { if (navInfo.type === "array") { // Show count-based text for all arrays displayText = ArrayAnalyzer.getArrayDisplayText(value); type = "array"; } else if (navInfo.type === "object") { displayText = "Object"; type = "object"; } else { displayText = formatValue(value); type = "object"; } } else { // Not navigable - show the value directly displayText = formatValue(value); type = "object"; } } else { displayText = formatValue(value); type = "object"; } } else { displayText = formatValue(value); type = "object"; } } return (_jsx("td", { className: "px-6 py-4 text-body-sm text-obsidian align-top max-w-xs", style: { width: showRowNumbers ? "auto" : column.width || "auto", }, onClick: handleCellClick, children: _jsx(NavigableCell, { value: value, displayText: displayText, onNavigate: handleNavigate, type: type }) })); } // Regular cell return (_jsx("td", { className: "px-6 py-4 text-body-sm text-obsidian align-top max-w-xs", style: { width: column.width }, onClick: handleCellClick, children: _jsx("span", { className: `truncate block ${value === null || value === undefined ? "text-jet-grey" : "text-obsidian"}`, title: typeof value === "string" ? value : undefined, children: formatValue(value) }) })); };