UNPKG

@sanity/table

Version:

Table schema type and input component for Sanity Studio

530 lines (529 loc) 18.9 kB
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