@wordpress/block-library
Version:
Block library for the WordPress editor.
515 lines (493 loc) • 15.6 kB
JavaScript
"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