@sanity/table
Version:
Table schema type and input component for Sanity Studio
530 lines (529 loc) • 18.9 kB
JavaScript
import { definePlugin, defineType, set, unset } from "sanity";
import { c } from "react/compiler-runtime";
import { AddIcon } from "@sanity/icons/Add";
import { Box, Button, Card, Dialog, Flex, Grid, Inline, Label, Menu, MenuButton, MenuDivider, MenuItem, Text, TextInput } from "@sanity/ui";
import { uuid } from "@sanity/uuid";
import { useState } from "react";
import { RemoveIcon } from "@sanity/icons/Remove";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { ControlsIcon } from "@sanity/icons/Controls";
import { WarningOutlineIcon } from "@sanity/icons/WarningOutline";
const TableInput = (props) => {
let $ = c(20), { rows, updateCell, removeRow, removeColumn } = props, t0;
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = { width: "100%" }, $[0] = t0) : t0 = $[0];
let t1;
if ($[1] !== removeRow || $[2] !== rows || $[3] !== updateCell) {
let t2;
$[5] !== removeRow || $[6] !== updateCell ? (t2 = (row, rowIndex) => /* @__PURE__ */ jsxs("tr", { children: [row.cells.map((cell, cellIndex) => /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(TextInput, {
fontSize: 1,
padding: 3,
value: cell,
onChange: (e) => updateCell(e, rowIndex, cellIndex)
}) }, `${row._key}-${cellIndex}`)), /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Box, {
marginLeft: 1,
style: { textAlign: "center" },
children: /* @__PURE__ */ jsx(Button, {
icon: RemoveIcon,
padding: 2,
onClick: () => removeRow(rowIndex),
mode: "bleed"
})
}) }, `${row._key}-remove`)] }, row._key), $[5] = removeRow, $[6] = updateCell, $[7] = t2) : t2 = $[7], t1 = rows.map(t2), $[1] = removeRow, $[2] = rows, $[3] = updateCell, $[4] = t1;
} else t1 = $[4];
let t2;
$[8] === rows[0]?.cells ? t2 = $[9] : (t2 = rows[0]?.cells || [], $[8] = rows[0]?.cells, $[9] = t2);
let t3;
if ($[10] !== removeColumn || $[11] !== t2) {
let t4;
$[13] === removeColumn ? t4 = $[14] : (t4 = (_, i) => /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(Box, {
marginTop: 1,
style: { textAlign: "center" },
children: /* @__PURE__ */ jsx(Button, {
icon: RemoveIcon,
padding: 2,
onClick: () => removeColumn(i),
mode: "bleed"
})
}) }, i), $[13] = removeColumn, $[14] = t4), t3 = t2.map(t4), $[10] = removeColumn, $[11] = t2, $[12] = t3;
} else t3 = $[12];
let t4;
$[15] === t3 ? t4 = $[16] : (t4 = /* @__PURE__ */ jsx("tr", { children: t3 }), $[15] = t3, $[16] = t4);
let t5;
return $[17] !== t1 || $[18] !== t4 ? (t5 = /* @__PURE__ */ jsx("table", {
style: t0,
children: /* @__PURE__ */ jsxs("tbody", { children: [t1, t4] })
}), $[17] = t1, $[18] = t4, $[19] = t5) : t5 = $[19], t5;
}, TableMenu = (props) => {
let $ = c(49), { id, remove: handleRemove } = props, [dialog, setDialog] = useState(null), [count, setCount] = useState(""), t0;
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = (e) => {
setCount(e.currentTarget.value);
}, $[0] = t0) : t0 = $[0];
let updateCount = t0, t1;
$[1] === props ? t1 = $[2] : (t1 = () => {
setDialog({
type: "rows",
callback: (c) => props.addRows(c)
}), setCount("");
}, $[1] = props, $[2] = t1);
let addRows = t1, t2;
$[3] === props ? t2 = $[4] : (t2 = () => {
setDialog({
type: "rows",
callback: (index) => props.addRowAt(index)
}), setCount("");
}, $[3] = props, $[4] = t2);
let addRowAt = t2, t3;
$[5] === props ? t3 = $[6] : (t3 = () => {
setDialog({
type: "columns",
callback: (c_0) => props.addColumns(c_0)
}), setCount("");
}, $[5] = props, $[6] = t3);
let addColumns = t3, t4;
$[7] === props ? t4 = $[8] : (t4 = () => {
setDialog({
type: "columns",
callback: (index_0) => props.addColumnAt(index_0)
}), setCount("");
}, $[7] = props, $[8] = t4);
let addColumnsAt = t4, parsedCount, t5;
$[9] === count ? (parsedCount = $[10], t5 = $[11]) : (parsedCount = Number.parseInt(count, 10), t5 = Number.isInteger(parsedCount) && parsedCount >= 0 && parsedCount < 100, $[9] = count, $[10] = parsedCount, $[11] = t5);
let isValidCount = t5, t6;
$[12] !== dialog || $[13] !== isValidCount || $[14] !== parsedCount ? (t6 = () => {
isValidCount && (setDialog(null), dialog?.callback(parsedCount), setCount(""));
}, $[12] = dialog, $[13] = isValidCount, $[14] = parsedCount, $[15] = t6) : t6 = $[15];
let onConfirm = t6, t7;
$[16] !== count || $[17] !== dialog || $[18] !== id || $[19] !== isValidCount || $[20] !== onConfirm ? (t7 = dialog && /* @__PURE__ */ jsx(Dialog, {
header: `Add ${dialog.type}`,
id: `${id}-dialog-add`,
onClose: () => {
setDialog(null), setCount("");
},
zOffset: 1e3,
children: /* @__PURE__ */ jsxs(Card, {
padding: 4,
children: [/* @__PURE__ */ jsx(TextInput, {
style: { textAlign: "left" },
fontSize: 2,
padding: 3,
type: "number",
value: count,
onChange: updateCount,
customValidity: count !== "" && !isValidCount ? "Enter a whole number from 0 to 99" : void 0
}), /* @__PURE__ */ jsx(Box, {
marginTop: 4,
children: /* @__PURE__ */ jsxs(Inline, {
gap: 1,
style: { textAlign: "right" },
children: [/* @__PURE__ */ jsx(Button, {
text: "Cancel",
mode: "ghost",
onClick: () => {
setDialog(null), setCount("");
}
}), /* @__PURE__ */ jsx(Button, {
text: "Confirm",
tone: "critical",
onClick: onConfirm,
disabled: !isValidCount
})]
})
})]
})
}), $[16] = count, $[17] = dialog, $[18] = id, $[19] = isValidCount, $[20] = onConfirm, $[21] = t7) : t7 = $[21];
let t8;
$[22] === Symbol.for("react.memo_cache_sentinel") ? (t8 = /* @__PURE__ */ jsx(Button, {
icon: ControlsIcon,
fontSize: 1,
padding: 2,
mode: "ghost"
}), $[22] = t8) : t8 = $[22];
let t9 = `${id}-menu-button`, t10;
$[23] === addRows ? t10 = $[24] : (t10 = /* @__PURE__ */ jsx(MenuItem, {
icon: AddIcon,
fontSize: 1,
text: "Add Row(s)",
onClick: addRows
}), $[23] = addRows, $[24] = t10);
let t11;
$[25] === addRowAt ? t11 = $[26] : (t11 = /* @__PURE__ */ jsx(MenuItem, {
icon: AddIcon,
fontSize: 1,
text: "Add Row At Index",
onClick: addRowAt
}), $[25] = addRowAt, $[26] = t11);
let t12;
$[27] === addColumns ? t12 = $[28] : (t12 = /* @__PURE__ */ jsx(MenuItem, {
icon: AddIcon,
fontSize: 1,
text: "Add Column(s)",
onClick: addColumns
}), $[27] = addColumns, $[28] = t12);
let t13;
$[29] === addColumnsAt ? t13 = $[30] : (t13 = /* @__PURE__ */ jsx(MenuItem, {
icon: AddIcon,
fontSize: 1,
text: "Add Column At Index",
onClick: addColumnsAt
}), $[29] = addColumnsAt, $[30] = t13);
let t14;
$[31] === Symbol.for("react.memo_cache_sentinel") ? (t14 = /* @__PURE__ */ jsx(MenuDivider, {}), $[31] = t14) : t14 = $[31];
let t15;
$[32] === handleRemove ? t15 = $[33] : (t15 = /* @__PURE__ */ jsx(MenuItem, {
icon: WarningOutlineIcon,
fontSize: 1,
text: "Remove",
tone: "critical",
onClick: handleRemove
}), $[32] = handleRemove, $[33] = t15);
let t16;
$[34] !== t10 || $[35] !== t11 || $[36] !== t12 || $[37] !== t13 || $[38] !== t15 ? (t16 = /* @__PURE__ */ jsxs(Menu, { children: [
t10,
t11,
t12,
t13,
t14,
t15
] }), $[34] = t10, $[35] = t11, $[36] = t12, $[37] = t13, $[38] = t15, $[39] = t16) : t16 = $[39];
let t17;
$[40] === props.placement ? t17 = $[41] : (t17 = { placement: props.placement }, $[40] = props.placement, $[41] = t17);
let t18;
$[42] !== t16 || $[43] !== t17 || $[44] !== t9 ? (t18 = /* @__PURE__ */ jsx(MenuButton, {
button: t8,
id: t9,
menu: t16,
popover: t17
}), $[42] = t16, $[43] = t17, $[44] = t9, $[45] = t18) : t18 = $[45];
let t19;
return $[46] !== t18 || $[47] !== t7 ? (t19 = /* @__PURE__ */ jsxs(Fragment, { children: [t7, t18] }), $[46] = t18, $[47] = t7, $[48] = t19) : t19 = $[48], t19;
}, deepClone = globalThis.structuredClone ?? ((data) => JSON.parse(JSON.stringify(data))), TableComponent = (props) => {
let $ = c(66), { id, rowType: t0, value, onChange } = props, rowType = t0 === void 0 ? "tableRow" : t0, [dialog, setDialog] = useState(null), t1;
$[0] === onChange ? t1 = $[1] : (t1 = (v) => onChange(set(v)), $[0] = onChange, $[1] = t1);
let updateValue = t1, t2;
$[2] === onChange ? t2 = $[3] : (t2 = () => onChange(unset()), $[2] = onChange, $[3] = t2);
let resetValue = t2, t3;
$[4] !== rowType || $[5] !== updateValue || $[6] !== value ? (t3 = () => {
let newValue = { rows: [{
_type: rowType,
_key: uuid(),
cells: ["", ""]
}, {
_type: rowType,
_key: uuid(),
cells: ["", ""]
}] };
return updateValue({
...value,
...newValue
});
}, $[4] = rowType, $[5] = updateValue, $[6] = value, $[7] = t3) : t3 = $[7];
let createTable = t3, confirmRemoveTable;
if ($[8] !== resetValue) {
confirmRemoveTable = () => {
setDialog({
type: "table",
callback: removeTable
});
};
let removeTable = () => {
resetValue(), setDialog(null);
};
$[8] = resetValue, $[9] = confirmRemoveTable;
} else confirmRemoveTable = $[9];
let t4;
$[10] !== rowType || $[11] !== updateValue || $[12] !== value ? (t4 = (t5) => {
let count = t5 === void 0 ? 1 : t5;
if (!value?.rows) return;
let newRows = deepClone(value.rows), columnCount = value.rows[0]?.cells.length ?? 0;
for (let i = 0; i < count; i++) newRows.push({
_type: rowType,
_key: uuid(),
cells: Array(columnCount).fill("")
});
return updateValue({
...value,
rows: newRows
});
}, $[10] = rowType, $[11] = updateValue, $[12] = value, $[13] = t4) : t4 = $[13];
let addRows = t4, t5;
$[14] !== rowType || $[15] !== updateValue || $[16] !== value ? (t5 = (t6) => {
let index = t6 === void 0 ? 0 : t6;
if (!value?.rows) return;
let newRows_0 = deepClone(value.rows), columnCount_0 = value.rows[0]?.cells.length ?? 0;
return newRows_0.splice(index, 0, {
_type: rowType,
_key: uuid(),
cells: Array(columnCount_0).fill("")
}), updateValue({
...value,
rows: newRows_0
});
}, $[14] = rowType, $[15] = updateValue, $[16] = value, $[17] = t5) : t5 = $[17];
let addRowAt = t5, t6;
$[18] !== updateValue || $[19] !== value ? (t6 = (index_0) => {
if (!value?.rows) return;
let newRows_1 = deepClone(value.rows);
newRows_1.splice(index_0, 1), updateValue({
...value,
rows: newRows_1
}), setDialog(null);
}, $[18] = updateValue, $[19] = value, $[20] = t6) : t6 = $[20];
let removeRow = t6, t7;
$[21] !== confirmRemoveTable || $[22] !== removeRow || $[23] !== value ? (t7 = (index_1) => {
if (value?.rows) return value.rows.length <= 1 ? confirmRemoveTable() : setDialog({
type: "row",
callback: () => removeRow(index_1)
});
}, $[21] = confirmRemoveTable, $[22] = removeRow, $[23] = value, $[24] = t7) : t7 = $[24];
let confirmRemoveRow = t7, addColumnAt, addColumns, confirmRemoveColumn;
if ($[25] !== confirmRemoveTable || $[26] !== updateValue || $[27] !== value) {
confirmRemoveColumn = (index_2) => {
if (value?.rows) return (value.rows[0]?.cells.length ?? 0) <= 1 ? confirmRemoveTable() : setDialog({
type: "column",
callback: () => removeColumn(index_2)
});
};
let t8;
$[31] !== updateValue || $[32] !== value ? (t8 = (count_0) => {
if (!value?.rows) return;
let newRows_2 = deepClone(value.rows);
return newRows_2.forEach((row) => {
for (let j = 0; j < count_0; j++) row.cells.push("");
}), updateValue({
...value,
rows: newRows_2
});
}, $[31] = updateValue, $[32] = value, $[33] = t8) : t8 = $[33], addColumns = t8;
let t9;
$[34] !== updateValue || $[35] !== value ? (t9 = (index_3) => {
if (!value?.rows) return;
let newRows_3 = deepClone(value.rows);
return newRows_3.forEach((row_0) => {
row_0.cells.splice(index_3, 0, "");
}), updateValue({
...value,
rows: newRows_3
});
}, $[34] = updateValue, $[35] = value, $[36] = t9) : t9 = $[36], addColumnAt = t9;
let removeColumn = (index_4) => {
if (!value?.rows) return;
let newRows_4 = deepClone(value.rows);
newRows_4.forEach((row_1) => {
row_1.cells.splice(index_4, 1);
}), updateValue({
...value,
rows: newRows_4
}), setDialog(null);
};
$[25] = confirmRemoveTable, $[26] = updateValue, $[27] = value, $[28] = addColumnAt, $[29] = addColumns, $[30] = confirmRemoveColumn;
} else addColumnAt = $[28], addColumns = $[29], confirmRemoveColumn = $[30];
let t8;
$[37] !== updateValue || $[38] !== value ? (t8 = (e, rowIndex, cellIndex) => {
if (!value?.rows) return;
let newRows_5 = deepClone(value.rows), row_2 = newRows_5[rowIndex];
if (row_2) return row_2.cells[cellIndex] = e.currentTarget.value, updateValue({
...value,
rows: newRows_5
});
}, $[37] = updateValue, $[38] = value, $[39] = t8) : t8 = $[39];
let updateCell = t8, t9;
$[40] !== dialog || $[41] !== id ? (t9 = dialog && /* @__PURE__ */ jsx(Dialog, {
header: `Remove ${dialog.type}`,
id: `${id}-dialog-remove`,
onClose: () => setDialog(null),
zOffset: 1e3,
children: /* @__PURE__ */ jsxs(Card, {
padding: 4,
children: [/* @__PURE__ */ jsxs(Text, { children: [
"Are you sure you want to remove this ",
dialog.type,
"?"
] }), /* @__PURE__ */ jsx(Box, {
marginTop: 4,
children: /* @__PURE__ */ jsxs(Inline, {
gap: 1,
style: { textAlign: "right" },
children: [/* @__PURE__ */ jsx(Button, {
text: "Cancel",
mode: "ghost",
onClick: () => setDialog(null)
}), /* @__PURE__ */ jsx(Button, {
text: "Confirm",
tone: "critical",
onClick: () => dialog.callback()
})]
})
})]
})
}), $[40] = dialog, $[41] = id, $[42] = t9) : t9 = $[42];
let t10;
$[43] !== addColumnAt || $[44] !== addColumns || $[45] !== addRowAt || $[46] !== addRows || $[47] !== confirmRemoveTable || $[48] !== id || $[49] !== value?.rows?.length ? (t10 = value?.rows?.length ? /* @__PURE__ */ jsxs(Inline, {
gap: 1,
children: [
/* @__PURE__ */ jsx(Button, {
fontSize: 1,
padding: 2,
icon: AddIcon,
text: "Add row",
mode: "ghost",
onClick: () => addRows(1)
}),
/* @__PURE__ */ jsx(Button, {
fontSize: 1,
padding: 2,
icon: AddIcon,
text: "Add column",
mode: "ghost",
onClick: () => addColumns(1)
}),
/* @__PURE__ */ jsx(TableMenu, {
id,
addColumns,
addColumnAt,
addRows,
addRowAt,
remove: confirmRemoveTable,
placement: "left"
})
]
}) : null, $[43] = addColumnAt, $[44] = addColumns, $[45] = addRowAt, $[46] = addRows, $[47] = confirmRemoveTable, $[48] = id, $[49] = value?.rows?.length, $[50] = t10) : t10 = $[50];
let t11;
$[51] === t10 ? t11 = $[52] : (t11 = /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Flex, {
justify: "flex-end",
children: t10
}) }), $[51] = t10, $[52] = t11);
let t12;
$[53] !== confirmRemoveColumn || $[54] !== confirmRemoveRow || $[55] !== updateCell || $[56] !== value ? (t12 = value?.rows?.length ? /* @__PURE__ */ jsx(TableInput, {
rows: value.rows,
removeRow: confirmRemoveRow,
removeColumn: confirmRemoveColumn,
updateCell
}) : null, $[53] = confirmRemoveColumn, $[54] = confirmRemoveRow, $[55] = updateCell, $[56] = value, $[57] = t12) : t12 = $[57];
let t13;
$[58] !== createTable || $[59] !== value ? (t13 = !value || !value?.rows?.length ? /* @__PURE__ */ jsx(Inline, {
gap: 1,
children: /* @__PURE__ */ jsx(Button, {
fontSize: 1,
padding: 3,
icon: AddIcon,
text: "Create Table",
tone: "primary",
mode: "ghost",
onClick: createTable
})
}) : null, $[58] = createTable, $[59] = value, $[60] = t13) : t13 = $[60];
let t14;
return $[61] !== t11 || $[62] !== t12 || $[63] !== t13 || $[64] !== t9 ? (t14 = /* @__PURE__ */ jsxs("div", { children: [
t9,
t11,
t12,
t13
] }), $[61] = t11, $[62] = t12, $[63] = t13, $[64] = t9, $[65] = t14) : t14 = $[65], t14;
};
function createTableComponent(rowType) {
return function(props) {
return /* @__PURE__ */ jsx(TableComponent, {
...props,
rowType
});
};
}
function TableIcon() {
let $ = c(1), t0;
return $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("svg", {
width: "1em",
height: "1em",
viewBox: "0 0 25 25",
fill: "none",
stroke: "currentColor",
strokeWidth: "1.2",
children: /* @__PURE__ */ jsx("path", { d: "M3 3h18v18H3zM21 9H3M21 15H3M12 3v18" })
}), $[0] = t0) : t0 = $[0], t0;
}
const Table = (t0) => {
let $ = c(5), { rows } = t0, numCols = rows[0]?.cells.length ?? 0, t1;
$[0] === rows ? t1 = $[1] : (t1 = rows.map(_temp), $[0] = rows, $[1] = t1);
let t2;
return $[2] !== numCols || $[3] !== t1 ? (t2 = /* @__PURE__ */ jsx(Grid, {
gridTemplateColumns: numCols,
padding: 2,
children: t1
}), $[2] = numCols, $[3] = t1, $[4] = t2) : t2 = $[4], t2;
}, TablePreview = (props) => {
let $ = c(10), { schemaType, rows: t0, title } = props, t1;
$[0] === t0 ? t1 = $[1] : (t1 = t0 === void 0 ? [] : t0, $[0] = t0, $[1] = t1);
let rows = t1, previewTitle = schemaType?.title ?? (typeof title == "string" ? title : "Title missing"), t2;
$[2] === Symbol.for("react.memo_cache_sentinel") ? (t2 = /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(Label, {
size: 4,
children: /* @__PURE__ */ jsx(TableIcon, {})
}) }), $[2] = t2) : t2 = $[2];
let t3;
$[3] === previewTitle ? t3 = $[4] : (t3 = /* @__PURE__ */ jsx(Box, {
padding: 3,
children: /* @__PURE__ */ jsxs(Inline, {
gap: 3,
children: [t2, /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(Text, { children: previewTitle }) })]
})
}), $[3] = previewTitle, $[4] = t3);
let t4;
$[5] === rows ? t4 = $[6] : (t4 = /* @__PURE__ */ jsx(Box, {
padding: 2,
children: rows.length === 0 ? /* @__PURE__ */ jsx(Label, {
muted: !0,
children: "Empty Table"
}) : /* @__PURE__ */ jsx(Table, { rows })
}), $[5] = rows, $[6] = t4);
let t5;
return $[7] !== t3 || $[8] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Fragment, { children: [t3, t4] }), $[7] = t3, $[8] = t4, $[9] = t5) : t5 = $[9], t5;
};
function _temp(row) {
return row.cells.map((cell, i) => /* @__PURE__ */ jsx(Card, {
padding: 2,
style: { outline: "1px solid #DFE2E9" },
children: /* @__PURE__ */ jsx(Text, {
textOverflow: "ellipsis",
children: cell
})
}, row._key + i));
}
const table = definePlugin((config) => {
let tableRowSchema = defineType({
title: "Table Row",
name: config?.rowType || "tableRow",
type: "object",
fields: [{
name: "cells",
type: "array",
of: [{ type: "string" }]
}]
});
return {
name: "table",
schema: { types: [tableRowSchema, defineType({
title: "Table",
name: "table",
type: "object",
fields: [{
name: "rows",
type: "array",
of: [{ type: tableRowSchema.name }]
}],
components: {
input: createTableComponent(tableRowSchema.name),
preview: TablePreview
},
preview: {
select: {
rows: "rows",
title: "title"
},
prepare: ({ title, rows = [] }) => ({
title,
rows
})
}
})] }
};
});
export { TableComponent, TablePreview, table };
//# sourceMappingURL=index.js.map