UNPKG

@wordpress/block-library

Version:
515 lines (493 loc) 15.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _clsx = _interopRequireDefault(require("clsx")); var _element = require("@wordpress/element"); var _blockEditor = require("@wordpress/block-editor"); var _i18n = require("@wordpress/i18n"); var _components = require("@wordpress/components"); var _icons = require("@wordpress/icons"); var _state = require("./state"); var _caption = require("../utils/caption"); var _hooks = require("../utils/hooks"); var _jsxRuntime = require("react/jsx-runtime"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ const ALIGNMENT_CONTROLS = [{ icon: _icons.alignLeft, title: (0, _i18n.__)('Align column left'), align: 'left' }, { icon: _icons.alignCenter, title: (0, _i18n.__)('Align column center'), align: 'center' }, { icon: _icons.alignRight, title: (0, _i18n.__)('Align column right'), align: 'right' }]; const cellAriaLabel = { head: (0, _i18n.__)('Header cell text'), body: (0, _i18n.__)('Body cell text'), foot: (0, _i18n.__)('Footer cell text') }; const placeholder = { head: (0, _i18n.__)('Header label'), foot: (0, _i18n.__)('Footer label') }; function TSection({ name, ...props }) { const TagName = `t${name}`; return /*#__PURE__*/(0, _jsxRuntime.jsx)(TagName, { ...props }); } function TableEdit({ attributes, setAttributes, insertBlocksAfter, isSelected: isSingleSelected }) { const { hasFixedLayout, head, foot } = attributes; const [initialRowCount, setInitialRowCount] = (0, _element.useState)(2); const [initialColumnCount, setInitialColumnCount] = (0, _element.useState)(2); const [selectedCell, setSelectedCell] = (0, _element.useState)(); const colorProps = (0, _blockEditor.__experimentalUseColorProps)(attributes); const borderProps = (0, _blockEditor.__experimentalUseBorderProps)(attributes); const blockEditingMode = (0, _blockEditor.useBlockEditingMode)(); const tableRef = (0, _element.useRef)(); const [hasTableCreated, setHasTableCreated] = (0, _element.useState)(false); const dropdownMenuProps = (0, _hooks.useToolsPanelDropdownMenuProps)(); /** * Updates the initial column count used for table creation. * * @param {number} count New initial column count. */ function onChangeInitialColumnCount(count) { setInitialColumnCount(count); } /** * Updates the initial row count used for table creation. * * @param {number} count New initial row count. */ function onChangeInitialRowCount(count) { setInitialRowCount(count); } /** * Creates a table based on dimensions in local state. * * @param {Object} event Form submit event. */ function onCreateTable(event) { event.preventDefault(); setAttributes((0, _state.createTable)({ rowCount: parseInt(initialRowCount, 10) || 2, columnCount: parseInt(initialColumnCount, 10) || 2 })); setHasTableCreated(true); } /** * Toggles whether the table has a fixed layout or not. */ function onChangeFixedLayout() { setAttributes({ hasFixedLayout: !hasFixedLayout }); } /** * Changes the content of the currently selected cell. * * @param {Array} content A RichText content value. */ function onChange(content) { if (!selectedCell) { return; } setAttributes((0, _state.updateSelectedCell)(attributes, selectedCell, cellAttributes => ({ ...cellAttributes, content }))); } /** * Align text within the a column. * * @param {string} align The new alignment to apply to the column. */ function onChangeColumnAlignment(align) { if (!selectedCell) { return; } // Convert the cell selection to a column selection so that alignment // is applied to the entire column. const columnSelection = { type: 'column', columnIndex: selectedCell.columnIndex }; const newAttributes = (0, _state.updateSelectedCell)(attributes, columnSelection, cellAttributes => ({ ...cellAttributes, align })); setAttributes(newAttributes); } /** * Get the alignment of the currently selected cell. * * @return {string | undefined} The new alignment to apply to the column. */ function getCellAlignment() { if (!selectedCell) { return; } return (0, _state.getCellAttribute)(attributes, selectedCell, 'align'); } /** * Add or remove a `head` table section. */ function onToggleHeaderSection() { setAttributes((0, _state.toggleSection)(attributes, 'head')); } /** * Add or remove a `foot` table section. */ function onToggleFooterSection() { setAttributes((0, _state.toggleSection)(attributes, 'foot')); } /** * Inserts a row at the currently selected row index, plus `delta`. * * @param {number} delta Offset for selected row index at which to insert. */ function onInsertRow(delta) { if (!selectedCell) { return; } const { sectionName, rowIndex } = selectedCell; const newRowIndex = rowIndex + delta; setAttributes((0, _state.insertRow)(attributes, { sectionName, rowIndex: newRowIndex })); // Select the first cell of the new row. setSelectedCell({ sectionName, rowIndex: newRowIndex, columnIndex: 0, type: 'cell' }); } /** * Inserts a row before the currently selected row. */ function onInsertRowBefore() { onInsertRow(0); } /** * Inserts a row after the currently selected row. */ function onInsertRowAfter() { onInsertRow(1); } /** * Deletes the currently selected row. */ function onDeleteRow() { if (!selectedCell) { return; } const { sectionName, rowIndex } = selectedCell; setSelectedCell(); setAttributes((0, _state.deleteRow)(attributes, { sectionName, rowIndex })); } /** * Inserts a column at the currently selected column index, plus `delta`. * * @param {number} delta Offset for selected column index at which to insert. */ function onInsertColumn(delta = 0) { if (!selectedCell) { return; } const { columnIndex } = selectedCell; const newColumnIndex = columnIndex + delta; setAttributes((0, _state.insertColumn)(attributes, { columnIndex: newColumnIndex })); // Select the first cell of the new column. setSelectedCell({ rowIndex: 0, columnIndex: newColumnIndex, type: 'cell' }); } /** * Inserts a column before the currently selected column. */ function onInsertColumnBefore() { onInsertColumn(0); } /** * Inserts a column after the currently selected column. */ function onInsertColumnAfter() { onInsertColumn(1); } /** * Deletes the currently selected column. */ function onDeleteColumn() { if (!selectedCell) { return; } const { sectionName, columnIndex } = selectedCell; setSelectedCell(); setAttributes((0, _state.deleteColumn)(attributes, { sectionName, columnIndex })); } (0, _element.useEffect)(() => { if (!isSingleSelected) { setSelectedCell(); } }, [isSingleSelected]); (0, _element.useEffect)(() => { if (hasTableCreated) { tableRef?.current?.querySelector('td div[contentEditable="true"]')?.focus(); setHasTableCreated(false); } }, [hasTableCreated]); const sections = ['head', 'body', 'foot'].filter(name => !(0, _state.isEmptyTableSection)(attributes[name])); const tableControls = [{ icon: _icons.tableRowBefore, title: (0, _i18n.__)('Insert row before'), isDisabled: !selectedCell, onClick: onInsertRowBefore }, { icon: _icons.tableRowAfter, title: (0, _i18n.__)('Insert row after'), isDisabled: !selectedCell, onClick: onInsertRowAfter }, { icon: _icons.tableRowDelete, title: (0, _i18n.__)('Delete row'), isDisabled: !selectedCell, onClick: onDeleteRow }, { icon: _icons.tableColumnBefore, title: (0, _i18n.__)('Insert column before'), isDisabled: !selectedCell, onClick: onInsertColumnBefore }, { icon: _icons.tableColumnAfter, title: (0, _i18n.__)('Insert column after'), isDisabled: !selectedCell, onClick: onInsertColumnAfter }, { icon: _icons.tableColumnDelete, title: (0, _i18n.__)('Delete column'), isDisabled: !selectedCell, onClick: onDeleteColumn }]; const renderedSections = sections.map(name => /*#__PURE__*/(0, _jsxRuntime.jsx)(TSection, { name: name, children: attributes[name].map(({ cells }, rowIndex) => /*#__PURE__*/(0, _jsxRuntime.jsx)("tr", { children: cells.map(({ content, tag: CellTag, scope, align, colspan, rowspan }, columnIndex) => /*#__PURE__*/(0, _jsxRuntime.jsx)(CellTag, { scope: CellTag === 'th' ? scope : undefined, colSpan: colspan, rowSpan: rowspan, className: (0, _clsx.default)({ [`has-text-align-${align}`]: align }, 'wp-block-table__cell-content'), children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.RichText, { value: content, onChange: onChange, onFocus: () => { setSelectedCell({ sectionName: name, rowIndex, columnIndex, type: 'cell' }); }, "aria-label": cellAriaLabel[name], placeholder: placeholder[name] }) }, columnIndex)) }, rowIndex)) }, name)); const isEmpty = !sections.length; return /*#__PURE__*/(0, _jsxRuntime.jsxs)("figure", { ...(0, _blockEditor.useBlockProps)({ ref: tableRef }), children: [!isEmpty && blockEditingMode === 'default' && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockControls, { group: "block", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.AlignmentControl, { label: (0, _i18n.__)('Change column alignment'), alignmentControls: ALIGNMENT_CONTROLS, value: getCellAlignment(), onChange: nextAlign => onChangeColumnAlignment(nextAlign) }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockControls, { group: "other", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarDropdownMenu, { icon: _icons.table, label: (0, _i18n.__)('Edit table'), controls: tableControls }) })] }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, { children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, { label: (0, _i18n.__)('Settings'), resetAll: () => { setAttributes({ hasFixedLayout: true, head: [], foot: [] }); }, dropdownMenuProps: dropdownMenuProps, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => hasFixedLayout !== true, label: (0, _i18n.__)('Fixed width table cells'), onDeselect: () => setAttributes({ hasFixedLayout: true }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, { __nextHasNoMarginBottom: true, label: (0, _i18n.__)('Fixed width table cells'), checked: !!hasFixedLayout, onChange: onChangeFixedLayout }) }), !isEmpty && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => head && head.length, label: (0, _i18n.__)('Header section'), onDeselect: () => setAttributes({ head: [] }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, { __nextHasNoMarginBottom: true, label: (0, _i18n.__)('Header section'), checked: !!(head && head.length), onChange: onToggleHeaderSection }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => foot && foot.length, label: (0, _i18n.__)('Footer section'), onDeselect: () => setAttributes({ foot: [] }), isShownByDefault: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, { __nextHasNoMarginBottom: true, label: (0, _i18n.__)('Footer section'), checked: !!(foot && foot.length), onChange: onToggleFooterSection }) })] })] }) }), !isEmpty && /*#__PURE__*/(0, _jsxRuntime.jsx)("table", { className: (0, _clsx.default)(colorProps.className, borderProps.className, { 'has-fixed-layout': hasFixedLayout, // This is required in the editor only to overcome // the fact the editor rewrites individual border // widths into a shorthand format. 'has-individual-borders': (0, _components.__experimentalHasSplitBorders)(attributes?.style?.border) }), style: { ...colorProps.style, ...borderProps.style }, children: renderedSections }), isEmpty ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Placeholder, { label: (0, _i18n.__)('Table'), icon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockIcon, { icon: _icons.blockTable, showColors: true }), instructions: (0, _i18n.__)('Insert a table for sharing data.'), children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("form", { className: "blocks-table__placeholder-form", onSubmit: onCreateTable, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.TextControl, { __nextHasNoMarginBottom: true, __next40pxDefaultSize: true, type: "number", label: (0, _i18n.__)('Column count'), value: initialColumnCount, onChange: onChangeInitialColumnCount, min: "1", className: "blocks-table__placeholder-input" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.TextControl, { __nextHasNoMarginBottom: true, __next40pxDefaultSize: true, type: "number", label: (0, _i18n.__)('Row count'), value: initialRowCount, onChange: onChangeInitialRowCount, min: "1", className: "blocks-table__placeholder-input" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, { __next40pxDefaultSize: true, variant: "primary", type: "submit", children: (0, _i18n.__)('Create Table') })] }) }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_caption.Caption, { attributes: attributes, setAttributes: setAttributes, isSelected: isSingleSelected, insertBlocksAfter: insertBlocksAfter, label: (0, _i18n.__)('Table caption text'), showToolbarButton: isSingleSelected && blockEditingMode === 'default' })] }); } var _default = exports.default = TableEdit; //# sourceMappingURL=edit.js.map