@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
JavaScript
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) }) }));
};