@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.
106 lines (105 loc) • 5.81 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { ObjectUtils } from "../../utils/objectUtils";
import { useTheme } from "../../styles/theme-provider";
import { TableBody as StyledTableBody, TableRow, TableCell as StyledTableCell, } from "../../styles/styled-components";
import { CellRenderer } from "../Cells/CellRenderer";
import { RowActions } from "../Editing/RowActions";
import { EditableCell } from "../Editing/EditableCell";
export const TableBody = ({ data, columns, onRowClick, onCellClick, onNavigateToSubTable, enableNavigation, showRowNumbers, customRenderers = {},
// Editing props
editState, setEditState, onDeleteRow, onAddRow, onUpdateField, onDeleteField, onAddField, validateField, options, }) => {
const { theme } = useTheme();
const isEditingEnabled = options?.enableEditing || false;
const isRowDeletionEnabled = options?.enableRowDeletion || false;
const isFieldEditingEnabled = options?.enableFieldEditing || false;
const isInlineEditingEnabled = options?.enableInlineEditing || false;
const handleRowSelect = (rowIndex, selected) => {
if (!setEditState)
return;
setEditState((prev) => {
const newSelectedRows = new Set(prev.selectedRows);
if (selected) {
newSelectedRows.add(rowIndex);
}
else {
newSelectedRows.delete(rowIndex);
}
return { ...prev, selectedRows: newSelectedRows };
});
};
const handleStartEdit = (rowIndex, field) => {
if (!setEditState)
return;
setEditState((prev) => ({
...prev,
isEditing: true,
editingRow: rowIndex,
editingField: field,
}));
};
// Removed handleRowDoubleClick - editing should only be triggered by cell double-click
const handleSaveEdit = (rowIndex, field, value) => {
if (!onUpdateField)
return;
onUpdateField(rowIndex, field, value);
if (setEditState) {
setEditState((prev) => ({
...prev,
isEditing: false,
editingRow: null,
editingField: null,
}));
}
};
const handleCancelEdit = () => {
if (!setEditState)
return;
setEditState((prev) => ({
...prev,
isEditing: false,
editingRow: null,
editingField: null,
}));
};
const handleDeleteRow = (rowIndex) => {
if (!onDeleteRow)
return;
onDeleteRow(rowIndex);
};
return (_jsx(StyledTableBody, { children: data.map((row, index) => {
const isRowSelected = editState?.selectedRows.has(index) || false;
const isRowEditing = editState?.isEditing && editState.editingRow === index;
const isFieldEditing = isRowEditing && editState?.editingField;
return (_jsxs(TableRow, { hoverable: !!onRowClick, onClick: () => onRowClick?.(row, index), className: isEditingEnabled ? "group" : "", style: {
backgroundColor: isRowSelected ? "#e3f2fd" : undefined,
}, children: [isEditingEnabled && (_jsx(StyledTableCell, { style: {
width: "120px",
minWidth: "120px",
textAlign: "center",
}, children: _jsx(RowActions, { rowIndex: index, row: row, isSelected: isRowSelected, onDelete: () => handleDeleteRow(index), onSelect: (selected) => handleRowSelect(index, selected), enableDeletion: isRowDeletionEnabled || false }) })), showRowNumbers && (_jsx(StyledTableCell, { style: {
width: "50px",
minWidth: "50px",
maxWidth: "50px",
textAlign: "center",
color: theme.colors.text.muted,
fontSize: theme.typography.fontSize.sm,
fontWeight: theme.typography.fontWeight.medium,
boxSizing: "border-box",
}, children: index + 1 })), columns.map((column) => {
const value = ObjectUtils.getNestedValue(row, column.cleanKey);
const isFieldBeingEdited = isFieldEditing && editState?.editingField === column.cleanKey;
const validationError = validateField
? validateField(column.cleanKey, value, row).error
: null;
// Show EditableCell only if a specific field is being edited
if (isInlineEditingEnabled && isFieldBeingEdited) {
return (_jsx(StyledTableCell, { children: _jsx(EditableCell, { value: value, column: column, rowIndex: index, isEditing: true, onStartEdit: () => handleStartEdit(index, column.cleanKey), onSaveEdit: (newValue) => handleSaveEdit(index, column.cleanKey, newValue), onCancelEdit: handleCancelEdit, validationError: validationError || undefined }) }, column.key));
}
return (_jsx(CellRenderer, { column: column, row: row, value: value, onNavigateToSubTable: (path, value, title) => onNavigateToSubTable(path, value, title, index), onCellClick: onCellClick, onCellDoubleClick: (value, column, row) => {
if (isInlineEditingEnabled) {
handleStartEdit(index, column.cleanKey);
}
}, enableNavigation: enableNavigation, customRenderers: customRenderers, rowIndex: index }, column.key));
})] }, index));
}) }));
};