Skip to content

Commit

Permalink
Add DimensionControl component (#16791)
Browse files Browse the repository at this point in the history
* Adds initial component

Note this is copied wholescale from original PR #16730

* Remove redunant files. Refactors tests.

* Updates docs

* Checks callbacks are functions prior to calling

* Adds temp testing example usage of component to Group Block

* Updates to allow sizes as an (optionaly) prop dependency

* Update default value label

* Removes unnecessary InstanceId HOC usage

Addresses #16791 (comment)

* Remove unused abbreviation in size table

* Revert "Adds temp testing example usage of component to Group Block"

This reverts commit 6f9f3bf.

* Remove arbitrary size value from sizes list

This is not required as we cannot know how the dimensions component will be used. Therefore sticking with relative values via the slugs is safer. These can be mapped on a case by case basis as required.

* Remove icon label for a11y reasons

Addresses #16791 (comment)

* Update component docs for consistency, spelling and grammar

* Tweak docblock formats

* Update test snapshots to match new default value

* Update API from onSpacingChange to more agnostic onChange

Addresses #16791 (comment)

* Update tests to cover onChange handler renamed

* Update currentSize prop to value for consistency with other components

* Removes onReset in favour of onChange with undefined for consistency

Adddresses #16791 (comment)

* Move component to @wordpress/components package

* Remove invalid font sizes style import

Accidentally included from rebase.

* Deps update due to rebase

* Remove unneeded doc blocks

* Remove usage suggestion which was not helpful

* Update readme docs to match current API

Addresses #16791 (comment)

* Export as experimental component

Addresses #16791 (comment)

* Revert "Deps update due to rebase"

This reverts commit 95d00f3.

Addresses #16791 (comment)
  • Loading branch information
getdave authored Oct 28, 2019
1 parent 567216f commit 4f2e7f2
Show file tree
Hide file tree
Showing 9 changed files with 562 additions and 0 deletions.
6 changes: 6 additions & 0 deletions docs/manifest-devhub.json
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,12 @@
"markdown_source": "../packages/components/src/date-time/README.md",
"parent": "components"
},
{
"title": "DimensionControl",
"slug": "dimension-control",
"markdown_source": "../packages/components/src/dimension-control/README.md",
"parent": "components"
},
{
"title": "Disabled",
"slug": "disabled",
Expand Down
120 changes: 120 additions & 0 deletions packages/components/src/dimension-control/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
DimensionControl
=============================

`DimensionControl` is a component designed to provide a UI to control spacing and/or dimensions.

## Usage

In a block's `edit` implementation, render a `<DimensionControl />` component.


```jsx
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import {
DimensionControl,
} from '@wordpress/block-editor';

registerBlockType( 'my-plugin/my-block', {
// ...

attributes: {
// other attributes here
// ...

paddingSize: {
type: 'string',
},
},

edit( { attributes, setAttributes, clientId } ) {

const { paddingSize } = attributes;


const updateSpacing = ( dimension, size, device = '' ) => {
setAttributes( {
[ `${ dimension }${ device }` ]: size,
} );
};

return (
<DimensionControl
label={ __( 'Padding' ) }
icon={ 'desktop' }
onChange={ partialRight( updateSpacing, 'paddingSize' ) }
value={ paddingSize }
/>
);
}
} );
```

_Note:_ it is recommended to partially apply the value of the Block attribute to be updated (eg: `paddingSize`, `marginSize`...etc) to your callback functions. This avoids the need to unnecessarily couple the component to the Block attribute schema.

_Note:_ by default, if you do not provide an initial `value` prop for the current dimension value, then no value will be selected (ie: there is no default dimension set).

## Props

### `label`
* **Type:** `String`
* **Default:** `undefined`
* **Required:** Yes

The human readable label for the control.

### `value`
* **Type:** `String`
* **Default:** `''`
* **Required:** No

The current value of the dimension UI control. If provided the UI with automatically select the value.

### `sizes`
* **Type:** `Array`
* **Default:** See `packages/block-editor/src/components/dimension-control/sizes.js`
* **Required:** No

An optional array of size objects in the following shape:

```
[
{
name: __( 'Small' ),
slug: 'small',
},
{
name: __( 'Medium' ),
slug: 'small',
},
// ...etc
]
```

By default a set of relative sizes (`small`, `medium`...etc) are provided. See `packages/block-editor/src/components/dimension-control/sizes.js`.

### `icon`
* **Type:** `String`
* **Default:** `undefined`
* **Required:** No

An optional dashicon to display before to the control label.

### `onChange`
* **Type:** `Function`
* **Default:** `undefined`
* **Required:** No
* **Arguments:**:
- `size` - a string representing the selected size (eg: `medium`)

A callback which is triggered when a spacing size value changes (is selected/clicked).


### `className`
* **Type:** `String`
* **Default:** `''`
* **Required:** No

A string of classes to be added to the control component.


76 changes: 76 additions & 0 deletions packages/components/src/dimension-control/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* External dependencies
*/
import classnames from 'classnames';
import { isFunction } from 'lodash';

/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
import {
Icon,
SelectControl,
} from '../';
import { __ } from '@wordpress/i18n';

import {
Fragment,
} from '@wordpress/element';

/**
* Internal dependencies
*/
import sizesTable, { findSizeBySlug } from './sizes';

export function DimensionControl( props ) {
const { label, value, sizes = sizesTable, icon, onChange, className = '' } = props;

const onChangeSpacingSize = ( val ) => {
const theSize = findSizeBySlug( sizes, val );

if ( ! theSize || value === theSize.slug ) {
onChange( undefined );
} else if ( isFunction( onChange ) ) {
onChange( theSize.slug );
}
};

const formatSizesAsOptions = ( theSizes ) => {
const options = theSizes.map( ( { name, slug } ) => ( {
label: name,
value: slug,
} ) );

return [ {
label: __( 'Default' ),
value: '',
} ].concat( options );
};

const selectLabel = (
<Fragment>
{ icon && (
<Icon
icon={ icon }
/>
) }
{ label }
</Fragment>
);

return (
<SelectControl
className={ classnames( className, 'block-editor-dimension-control' ) }
label={ selectLabel }
hideLabelFromVision={ false }
value={ value }
onChange={ onChangeSpacingSize }
options={ formatSizesAsOptions( sizes ) }
/>
);
}

export default DimensionControl;
45 changes: 45 additions & 0 deletions packages/components/src/dimension-control/sizes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Sizes
*
* defines the sizes used in dimension controls
* all hardcoded `size` values are based on the value of
* the Sass variable `$block-padding` from
* `packages/block-editor/src/components/dimension-control/sizes.js`.
*/

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Finds the correct size object from the provided sizes
* table by size slug (eg: `medium`)
*
* @param {Array} sizes containing objects for each size definition
* @param {string} slug a string representation of the size (eg: `medium`)
* @return {Object} the matching size definition
*/
export const findSizeBySlug = ( sizes, slug ) => sizes.find( ( size ) => slug === size.slug );

export default [
{
name: __( 'None' ),
slug: 'none',
},
{
name: __( 'Small' ),
slug: 'small',
},
{
name: __( 'Medium' ),
slug: 'medium',
},
{
name: __( 'Large' ),
slug: 'large',
}, {
name: __( 'Extra Large' ),
slug: 'xlarge',
},
];
22 changes: 22 additions & 0 deletions packages/components/src/dimension-control/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.block-editor-dimension-control {

.components-base-control__field {
display: flex;
align-items: center;
}

.components-base-control__label {
display: flex;
align-items: center;
margin-right: 1em;
margin-bottom: 0;

.dashicon {
margin-right: 0.5em;
}
}

&.is-manual .components-base-control__label {
width: 10em;
}
}
Loading

0 comments on commit 4f2e7f2

Please sign in to comment.