Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add formatting options to the Table block inspector sidebar #7035

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core-blocks/table/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
td,
th {
padding: 0.5em;
border: 1px solid currentColor;
border: 1px solid #444;
}

td[data-mce-selected="1"],
Expand Down
18 changes: 11 additions & 7 deletions core-blocks/table/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import classnames from 'classnames';
import { Fragment } from '@wordpress/element';
import { getPhrasingContentSchema } from '@wordpress/blocks';
import {
BlockControls,
BlockAlignmentToolbar,
RichText,
InspectorControls,
} from '@wordpress/editor';

import {
BaseControl,
PanelBody,
ToggleControl,
} from '@wordpress/components';
Expand Down Expand Up @@ -119,19 +119,23 @@ export const settings = {

return (
<Fragment>
<BlockControls>
<BlockAlignmentToolbar
value={ attributes.align }
onChange={ updateAlignment }
/>
</BlockControls>
<InspectorControls>
<PanelBody title={ __( 'Table Settings' ) } className="blocks-table-settings">
<ToggleControl
label={ __( 'Fixed width table cells' ) }
checked={ !! hasFixedLayout }
onChange={ toggleFixedLayout }
/>
<BaseControl
label={ __( 'Alignment' ) }
id="inspector-block-alignment"
className="components-block-alignment"
>
<BlockAlignmentToolbar
value={ attributes.align }
onChange={ updateAlignment }
/>
</BaseControl>
</PanelBody>
</InspectorControls>
<TableBlock
Expand Down
5 changes: 4 additions & 1 deletion core-blocks/table/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
td,
th {
padding: 0.5em;
border: 1px solid currentColor;
border: 1px solid #444;
}

// Fixed layout toggle
&.has-fixed-layout tbody {
table-layout: fixed;
}
}
.edit-post-sidebar .components-block-alignment .components-toolbar {
margin-bottom: 0;
}
220 changes: 214 additions & 6 deletions core-blocks/table/table-block.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
/**
* External dependencies
*/
import { find, parseInt, isEmpty } from 'lodash';
import tinycolor from 'tinycolor2';

/**
* WordPress dependencies
*/
import { Component, Fragment } from '@wordpress/element';
import { Toolbar, DropdownMenu } from '@wordpress/components';
import {
Toolbar,
DropdownMenu,
FontSizePicker,
PanelBody,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import {
AlignmentToolbar,
BlockControls,
RichText,
ContrastChecker,
InspectorControls,
PanelColor,
} from '@wordpress/editor';

/**
* Internal dependencies
*/
import { domToFormat } from '../../editor/components/rich-text/format';

function isTableSelected( editor ) {
return editor.dom.getParent(
editor.selection.getStart( true ),
Expand Down Expand Up @@ -70,27 +90,175 @@ const TABLE_CONTROLS = [
},
];

const FONT_SIZES = [
{
name: 'small',
shortName: 'S',
size: 14,
},
{
name: 'regular',
shortName: 'M',
size: 16,
},
{
name: 'large',
shortName: 'L',
size: 36,
},
{
name: 'larger',
shortName: 'XL',
size: 48,
},
];

export default class TableBlock extends Component {
constructor() {
super();
super( ...arguments );
this.handleSetup = this.handleSetup.bind( this );
this.getFontSize = this.getFontSize.bind( this );
this.setFontSize = this.setFontSize.bind( this );
this.setBorderColor = this.setBorderColor.bind( this );
this.updateTableCellStyle = this.updateTableCellStyle.bind( this );
this.state = {
editor: null,
};
}

handleSetup( editor, isSelected ) {
handleSetup( editor ) {
const { isSelected } = this.props;

// select the end of the first table cell
editor.on( 'init', () => {
if ( isSelected ) {
selectFirstCell( editor );
}
} );

// Update the alignment toolbar, font size, text and background color
// value for the current table cell.
editor.on( 'nodechange', ( { selectionChange, parents } ) => {
if ( document.activeElement !== editor.getBody() ) {
return;
}

if ( selectionChange ) {
const selectedCell = find( parents, ( node ) => node.tagName === 'TD' || node.tagName === 'TH' );
const {
textAlign,
borderColor,
fontSize,
color,
backgroundColor,
} = selectedCell ? selectedCell.style : {};

this.setFontSize( parseInt( fontSize ) );
this.setState( {
textAlign,
color: color ? tinycolor( color ).toHexString() : null,
backgroundColor: backgroundColor ? tinycolor( backgroundColor ).toHexString() : null,
borderColor: borderColor ? tinycolor( borderColor ).toHexString() : null,
} );
}
} );

this.setState( { editor } );
}

// Get the correct font size value using the font size data stored
// in state.
getFontSize() {
const { customFontSize, fontSize } = this.state;

if ( fontSize ) {
const fontSizeObj = find( FONT_SIZES, { name: fontSize } );
if ( fontSizeObj ) {
return fontSizeObj.size;
}
}

if ( customFontSize ) {
return customFontSize;
}
}

/**
* Save the correct font size value in state. If the font size is a
* defined in the `FONT_SIZES` constant, save the name of the font
* size instead.
*
* @param {number} fontSizeValue The numeric font size value.
*/
setFontSize( fontSizeValue ) {
const thresholdFontSize = find( FONT_SIZES, { size: fontSizeValue } );

if ( thresholdFontSize ) {
this.setState( {
fontSize: thresholdFontSize.name,
customFontSize: undefined,
} );
return;
}

this.setState( {
fontSize: undefined,
customFontSize: fontSizeValue,
} );
}

/**
* Sets the specified CSS property of the current table cell.
*
* @param {string} property The CSS property name (camelcased).
* @param {(string|number)} value The value to set.
* @param {boolean} updateStateValue Whether to update the property value stored in state.
*/
updateTableCellStyle( property, value, updateStateValue = true ) {
const { editor } = this.state;
const { onChange } = this.props;
const currentNode = editor.selection.getNode();
const tableCell = editor.dom.getParent( currentNode, ( parentNode ) => parentNode.tagName === 'TD' || parentNode.tagName === 'TH' );

if ( tableCell ) {
// If `propertyValue` is undefined, set `propertyValue` to an empty
// string in order to update both the CSS property on the current
// table cell and the current state value.
const propertyValue = value ? value : '';
editor.dom.setStyle( tableCell, property, propertyValue );
const content = domToFormat( editor.getBody().childNodes || [], 'element', editor );
onChange( content );

if ( updateStateValue ) {
this.setState( { [ property ]: propertyValue } );
}
}
}

/**
* Set the border color for each table cell.
*
* @param {string} nextBorderColor The next border color value to set.
*/
setBorderColor( nextBorderColor ) {
const { onChange } = this.props;
const { editor } = this.state;
const cells = editor.dom.select( 'td,th' );

if ( ! isEmpty( cells ) ) {
const borderColor = nextBorderColor ? nextBorderColor : '';
editor.dom.setStyle( cells, 'border-color', borderColor );
const content = domToFormat( editor.getBody().childNodes || [], 'element', editor );
onChange( content );

this.setState( { borderColor: nextBorderColor } );
}
}

render() {
const { content, onChange, className, isSelected } = this.props;
const { content, onChange, className } = this.props;
const { textAlign, color, backgroundColor, borderColor, editor } = this.state;
const fontSize = this.getFontSize();

return (
<Fragment>
Expand All @@ -102,7 +270,8 @@ export default class TableBlock extends Component {
plugins: ( settings.plugins || [] ).concat( 'table' ),
table_tab_navigation: false,
} ) }
onSetup={ ( editor ) => this.handleSetup( editor, isSelected ) }
style={ borderColor ? { borderColor } : null }
onSetup={ ( currentEditor ) => this.handleSetup( currentEditor ) }
onChange={ onChange }
value={ content }
/>
Expand All @@ -114,11 +283,50 @@ export default class TableBlock extends Component {
controls={
TABLE_CONTROLS.map( ( control ) => ( {
...control,
onClick: () => control.onClick( this.state.editor ),
onClick: () => control.onClick( editor ),
} ) ) }
/>
</Toolbar>
<AlignmentToolbar
value={ textAlign }
onChange={ ( nextAlign ) => this.updateTableCellStyle( 'textAlign', nextAlign ) }
/>
</BlockControls>
<InspectorControls>
<PanelColor
colorValue={ borderColor }
initialOpen={ false }
title={ __( 'Border Color' ) }
onChange={ this.setBorderColor }
/>
<PanelBody title={ __( 'Text Size' ) } className="blocks-font-size">
<FontSizePicker
fontSizes={ FONT_SIZES }
value={ fontSize }
onChange={ ( nextFontSize ) => {
this.updateTableCellStyle( 'fontSize', nextFontSize, false );
this.setFontSize( nextFontSize );
} }
/>
</PanelBody>
<PanelColor
colorValue={ color }
initialOpen={ false }
title={ __( 'Text Color' ) }
onChange={ ( nextTextColor ) => this.updateTableCellStyle( 'color', nextTextColor ) }
/>
<ContrastChecker
textColor={ color }
backgroundColor={ backgroundColor }
isLargeText={ fontSize >= 18 }
/>
<PanelColor
colorValue={ backgroundColor }
initialOpen={ false }
title={ __( 'Background Color' ) }
onChange={ ( nextBackgroundColor ) => this.updateTableCellStyle( 'backgroundColor', nextBackgroundColor ) }
/>
</InspectorControls>
</Fragment>
);
}
Expand Down