import { useMemo } from "react" import { Plus, Trash2 } from "lucide-react" import { Button } from "../ui/button" import { Input } from "../ui/input" import { cn } from "../../lib/utils" import { createEmptyTable, parseTableSlotValue, serializeTableSlotValue, type DynamicTableValue, } from "../../lib/dynamicTableValue" export type DynamicTableBuilderProps = { value: string onChange: (next: string) => void disabled?: boolean slotLabel: string slotMeta: string } function normalizeTable(table: DynamicTableValue): DynamicTableValue { const columns = table.columns.length > 0 ? table.columns.map((c, i) => c.trim() || `Column ${i + 1}`) : ["Column 1"] const colCount = columns.length const rows = table.rows.length > 0 ? table.rows.map((row) => { const cells = [...row] while (cells.length < colCount) cells.push("") return cells.slice(0, colCount) }) : [Array(colCount).fill("")] return { columns, rows } } export function DynamicTableBuilder({ value, onChange, disabled = false, slotLabel, slotMeta, }: DynamicTableBuilderProps) { const table = useMemo(() => normalizeTable(parseTableSlotValue(value)), [value]) const commit = (next: DynamicTableValue) => { onChange(serializeTableSlotValue(normalizeTable(next))) } const updateColumn = (colIndex: number, text: string) => { const columns = [...table.columns] columns[colIndex] = text commit({ columns, rows: table.rows }) } const updateCell = (rowIndex: number, colIndex: number, text: string) => { const rows = table.rows.map((r) => [...r]) rows[rowIndex][colIndex] = text commit({ columns: table.columns, rows }) } const addColumn = () => { const columns = [...table.columns, `Column ${table.columns.length + 1}`] const rows = table.rows.map((row) => [...row, ""]) commit({ columns, rows }) } const removeColumn = (colIndex: number) => { if (table.columns.length <= 1) return const columns = table.columns.filter((_, i) => i !== colIndex) const rows = table.rows.map((row) => row.filter((_, i) => i !== colIndex)) commit({ columns, rows }) } const addRow = () => { const rows = [...table.rows, Array(table.columns.length).fill("")] commit({ columns: table.columns, rows }) } const removeRow = (rowIndex: number) => { if (table.rows.length <= 1) return const rows = table.rows.filter((_, i) => i !== rowIndex) commit({ columns: table.columns, rows }) } const resetTable = () => { commit(createEmptyTable(2, 1)) } const previewColumns = table.columns.map((c, i) => c.trim() || `Column ${i + 1}`) const previewRows = table.rows.map((row) => row.map((cell, ci) => cell.trim() || ""), ) return (
Build the reference table learners will see with the question.
|
updateColumn(colIndex, e.target.value)}
placeholder={`Column ${colIndex + 1}`}
className="h-9 border-grayScale-200 bg-white text-xs font-semibold"
/>
{table.columns.length > 1 ? (
) : null}
|
))}
|
|---|---|
| updateCell(rowIndex, colIndex, e.target.value)} placeholder="Cell value" className="h-9 border-grayScale-200 bg-[#F8FAFC] text-sm" /> | ))}
Learner preview
| {col} | ))}
|---|
| {cell || —} | ))}