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 table dimension controls #9801

Closed
wants to merge 5 commits into from
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
144 changes: 135 additions & 9 deletions packages/block-library/src/table/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ import {
PanelColorSettings,
createCustomColorsHOC,
} from '@wordpress/editor';
import { __ } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import {
PanelBody,
ToggleControl,
TextControl,
SelectControl,
Button,
Toolbar,
DropdownMenu,
ResizableBox,
} from '@wordpress/components';

/**
Expand All @@ -34,6 +36,8 @@ import {
deleteRow,
insertColumn,
deleteColumn,
getStyleValue,
getStyleUnit,
} from './state';

const BACKGROUND_COLORS = [
Expand Down Expand Up @@ -67,6 +71,10 @@ export class TableEdit extends Component {

this.onCreateTable = this.onCreateTable.bind( this );
this.onChangeFixedLayout = this.onChangeFixedLayout.bind( this );
this.setWidth = this.setWidth.bind( this );
this.onChangeWidth = this.onChangeWidth.bind( this );
this.onChangeWidthUnit = this.onChangeWidthUnit.bind( this );
this.onChangeHeight = this.onChangeHeight.bind( this );
this.onChange = this.onChange.bind( this );
this.onChangeInitialColumnCount = this.onChangeInitialColumnCount.bind( this );
this.onChangeInitialRowCount = this.onChangeInitialRowCount.bind( this );
Expand All @@ -85,6 +93,7 @@ export class TableEdit extends Component {
initialRowCount: 2,
initialColumnCount: 2,
selectedCell: null,
widthUnit: getStyleUnit( this.props.attributes.width ) || '%',
};
}

Expand Down Expand Up @@ -136,6 +145,55 @@ export class TableEdit extends Component {
setAttributes( { hasFixedLayout: ! hasFixedLayout } );
}

/**
* Set the width attribute of the table.
*
* @param {string|number} rawWidth The width of the table.
* @param {string} widthUnit The width unit to use (e.g. px, %).
*/
setWidth( rawWidth, widthUnit ) {
const width = getStyleValue( rawWidth );
if ( ! width ) {
this.props.setAttributes( { width: undefined } );
} else {
this.props.setAttributes( { width: `${ width }${ widthUnit }` } );
}
}

/**
* Handle a change of the width of the table.
*
* @param {string} width The new width of the table.
* @param {string} widthUnit The width unit to use (e.g. px, %).
*/
onChangeWidth( width ) {
this.setWidth( width, this.state.widthUnit );
}

/**
* Handle a change of the width unit.
*
* @param {string} widthUnit The new width unit (e.g. px, %).
*/
onChangeWidthUnit( widthUnit ) {
this.setState( { widthUnit } );
this.setWidth( this.props.attributes.width, widthUnit );
}

/**
* Update the height of the table.
*
* @param {string} rawHeight The new height of the table.
*/
onChangeHeight( rawHeight ) {
const height = getStyleValue( rawHeight );
if ( height === undefined ) {
this.props.setAttributes( { height: undefined } );
} else {
this.props.setAttributes( { height: `${ height }px` } );
}
}

/**
* Changes the content of the currently selected cell.
*
Expand Down Expand Up @@ -366,9 +424,16 @@ export class TableEdit extends Component {
<CellTag
key={ columnIndex }
className={ cellClasses }
onClick={ ( event ) => {
// When a cell is selected, forward focus to the child contenteditable. This solves an issue where the
// user may click inside a cell, but outside of the contenteditable, resulting in nothing happening.
const contentEditable = event && event.target && event.target.querySelector( '[contenteditable=true]' );
if ( contentEditable ) {
contentEditable.focus();
}
} }
>
<RichText
className="wp-block-table__cell-content"
value={ content }
onChange={ this.onChange }
unstableOnFocus={ this.createOnFocus( cell ) }
Expand Down Expand Up @@ -397,9 +462,12 @@ export class TableEdit extends Component {
className,
backgroundColor,
setBackgroundColor,
toggleSelection,
setAttributes,
} = this.props;
const { initialRowCount, initialColumnCount } = this.state;
const { hasFixedLayout, head, body, foot } = attributes;
const { initialRowCount, initialColumnCount, widthUnit } = this.state;
const { hasFixedLayout, head, body, foot, width, height } = attributes;

const isEmpty = ! head.length && ! body.length && ! foot.length;
const Section = this.renderSection;

Expand Down Expand Up @@ -430,6 +498,9 @@ export class TableEdit extends Component {
'has-background': !! backgroundColor.color,
} );

// translators: %s: a unit of measurement for CSS (e.g. 'px' or '%')
const widthLabel = widthUnit ? sprintf( __( 'Width (%s)' ), widthUnit ) : __( 'Width' );

return (
<Fragment>
<BlockControls>
Expand All @@ -443,6 +514,39 @@ export class TableEdit extends Component {
</BlockControls>
<InspectorControls>
<PanelBody title={ __( 'Table Settings' ) } className="blocks-table-settings">
<div className="block-library-table__dimensions__row">
<TextControl
type="number"
className="block-library-table__dimensions__width"
label={ widthLabel }
value={ getStyleValue( width ) }
min={ 1 }
onChange={ this.onChangeWidth }
/>
<SelectControl
label={ __( 'Width Unit' ) }
options={ [
{
value: '%',
label: '%',
},
{
value: 'px',
label: 'px',
},
] }
value={ widthUnit }
onChange={ this.onChangeWidthUnit }
/>
</div>
<TextControl
type="number"
className="block-library-table__dimensions__height"
label={ __( 'Height (px)' ) }
value={ getStyleValue( height ) }
min={ 1 }
onChange={ this.onChangeHeight }
/>
<ToggleControl
label={ __( 'Fixed width table cells' ) }
checked={ !! hasFixedLayout }
Expand All @@ -463,11 +567,33 @@ export class TableEdit extends Component {
] }
/>
</InspectorControls>
<table className={ classes }>
<Section type="head" rows={ head } />
<Section type="body" rows={ body } />
<Section type="foot" rows={ foot } />
</table>
<ResizableBox
className="block-library-table__resizable-box"
size={ {
width,
height,
} }
enable={ {
right: true,
bottom: true,
} }
onResizeStart={ () => {
toggleSelection( false );
} }
onResizeStop={ ( event, direction, element ) => {
setAttributes( {
width: direction === 'right' ? element.style.width : width,
height: direction === 'bottom' ? element.style.height : height,
} );
toggleSelection( true );
} }
>
<table className={ classes }>
<Section type="head" rows={ head } />
<Section type="body" rows={ body } />
<Section type="foot" rows={ foot } />
</table>
</ResizableBox>
</Fragment>
);
}
Expand Down
31 changes: 23 additions & 8 deletions packages/block-library/src/table/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,13 @@
}
}


.wp-block-table {
table {
border-collapse: collapse;
width: 100%;
}
width: 100%;
height: 100%;

td,
th {
padding: 0;
padding: 0.5rem;
border: $border-width solid $black;
}

Expand All @@ -37,7 +34,25 @@
border-style: double;
}

&__cell-content {
padding: 0.5em;

}

.block-library-table__resizable-box {
// Using display table is a hack to ensure wrapping resizable box can't be resized to smaller than the content.
display: table;
min-width: $break-mobile / 2;

& .components-resizable-box__handle {
display: block;
}
}

.block-library-table__dimensions__row {
display: flex;
}

.block-library-table__dimensions__width {
flex: 1;
// Use padding since it's hard to override the margin of the base control.
padding-right: 5px;
}
11 changes: 10 additions & 1 deletion packages/block-library/src/table/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { RichText, getColorClassName } from '@wordpress/editor';
* Internal dependencies
*/
import edit from './edit';
import { getTableStyles } from './state';

const tableContentPasteSchema = {
tr: {
Expand All @@ -31,6 +32,7 @@ const tableContentPasteSchema = {

const tablePasteSchema = {
table: {
attributes: [ 'style' ],
children: {
thead: {
children: tableContentPasteSchema,
Expand Down Expand Up @@ -89,6 +91,13 @@ export const settings = {
backgroundColor: {
type: 'string',
},
width: {
type: 'string',
default: '100%',
},
height: {
type: 'string',
},
head: getTableSectionAttributeSchema( 'head' ),
body: getTableSectionAttributeSchema( 'body' ),
foot: getTableSectionAttributeSchema( 'foot' ),
Expand Down Expand Up @@ -161,7 +170,7 @@ export const settings = {
};

return (
<table className={ classes }>
<table className={ classes } style={ getTableStyles( attributes ) }>
<Section type="head" rows={ head } />
<Section type="body" rows={ body } />
<Section type="foot" rows={ foot } />
Expand Down
53 changes: 53 additions & 0 deletions packages/block-library/src/table/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,56 @@ export function deleteColumn( state, {
} ) ).filter( ( row ) => row.cells.length ),
};
}

/**
* Get the integer value of a style property.
*
* @param {?string} rawValue The style's raw value (e.g. 100%, 25px).
*
* @return {?number} The integer value (e.g. 100, 25).
*/
export function getStyleValue( rawValue ) {
const parsedValue = parseInt( rawValue, 10 );

if ( isNaN( parsedValue ) ) {
return;
}

return parsedValue;
}

/**
* Get the px or % unit from a style value.
*
* @param {?string} value The style's value (e.g. 100px, 25%).
*
* @return {?string} The unit (e.g. px, %).
*/
export function getStyleUnit( value ) {
const match = /(px|%)/i.exec( value );

if ( ! match ) {
return;
}

return match[ 1 ].toLowerCase();
}

/**
* Given the table block attributes, return the style properties.
*
* @param {?string} attributes.width The width value.
* @param {?string} attributes.height The height value.
*
* @return {?Object} The style properties.
*/
export function getTableStyles( { width, height } ) {
if ( ! width && ! height ) {
return;
}

return {
width: width && width !== '100%' ? width : undefined,
height: height ? height : undefined,
};
}
Loading