-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Add experimental ResponsiveBlockControl component
#16790
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
Changes from 34 commits
23807cf
95bfae8
dd64a53
8116762
4ca0fc5
fe7c77d
e051305
9c6e8b2
f2d1bfc
aa1ec5f
eb5e9ba
bec9001
1907640
17eec18
c9c5e08
eb9c5f3
238d541
1af87b9
51b43a6
20a95b4
a64c2cd
9926612
d210cfe
b81e605
8605087
3ac118d
045dd49
b5bfc06
5c9841c
b2bea8c
827bb82
059b5a5
ce3be6f
195aef5
e821dc9
863783c
8ebbd2c
64e719f
e6aad72
48529f7
d72e6af
a46f406
15da1b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| /** | ||
| * External dependencies | ||
| */ | ||
| import { isFunction } from 'lodash'; | ||
|
|
||
| /** | ||
| * WordPress dependencies | ||
| */ | ||
| import { __, _x, sprintf } from '@wordpress/i18n'; | ||
|
|
||
| import { Fragment, useState, useEffect, useCallback } from '@wordpress/element'; | ||
|
|
||
| import { | ||
| ToggleControl, | ||
| } from '@wordpress/components'; | ||
|
|
||
| /** | ||
| * Internal dependencies | ||
| */ | ||
| import ResponsiveBlockControlLabel from './label'; | ||
|
|
||
| function ResponsiveBlockControl( props ) { | ||
| const { | ||
| legend, | ||
| property, | ||
| toggleLabel, | ||
| onIsResponsiveModeChange, | ||
| renderDefaultControl, | ||
| renderResponsiveControls, | ||
| responsiveControlsActive = false, | ||
| defaultLabel = { | ||
| id: 'all', | ||
| label: _x( 'All', 'Label. Used to signify a layout property (eg: margin, padding) should apply uniformly to all screensizes.' ), | ||
| }, | ||
| devices = [ | ||
| { | ||
| id: 'small', | ||
| label: __( 'Small devices' ), | ||
| }, | ||
| { | ||
| id: 'medium', | ||
| label: __( 'Medium devices' ), | ||
| }, | ||
| { | ||
| id: 'large', | ||
| label: __( 'Large devices' ), | ||
| }, | ||
| ], | ||
| } = props; | ||
|
|
||
| const [ isResponsiveMode, setIsResponsiveMode ] = useState( responsiveControlsActive ); | ||
|
||
|
|
||
| useEffect( () => { | ||
| if ( isFunction( onIsResponsiveModeChange ) ) { | ||
| onIsResponsiveModeChange( isResponsiveMode ); | ||
getdave marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| }, [ isResponsiveMode ] ); | ||
|
|
||
| const handleToggle = useCallback( ( isChecked ) => { | ||
| setIsResponsiveMode( ! isChecked ); | ||
| } ); | ||
|
|
||
| if ( ! legend || ! property || ! renderDefaultControl ) { | ||
| return null; | ||
| } | ||
|
|
||
| const toggleControlLabel = toggleLabel || sprintf( _x( 'Use the same %s on all screensizes.', 'Toggle control label. Should the property be the same across all screen sizes or unique per screen size.' ), property ); | ||
getdave marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| const toggleHelpText = _x( 'Toggle between using the same value for all screen sizes or using a unique value per screen size.', 'Toogle control help text.' ); | ||
|
|
||
| const defaultControl = renderDefaultControl( <ResponsiveBlockControlLabel property={ property } device={ defaultLabel } />, defaultLabel ); | ||
|
|
||
| const defaultResponsiveControls = () => { | ||
| return devices.map( ( device ) => ( | ||
| <Fragment key={ device.id }> | ||
| { renderDefaultControl( <ResponsiveBlockControlLabel property={ property } device={ device } />, device ) } | ||
| </Fragment> | ||
| ) ); | ||
| }; | ||
|
|
||
| return ( | ||
|
|
||
| <fieldset className="block-editor-responsive-block-control"> | ||
| <legend className="block-editor-responsive-block-control__legend">{ legend }</legend> | ||
|
|
||
| <div className="block-editor-responsive-block-control__inner"> | ||
| <ToggleControl | ||
| className="block-editor-responsive-block-control__toggle" | ||
| label={ toggleControlLabel } | ||
| checked={ ! isResponsiveMode } | ||
| onChange={ handleToggle } | ||
| help={ toggleHelpText } | ||
| /> | ||
|
|
||
getdave marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { ! isResponsiveMode && ( | ||
| <div className="block-editor-responsive-block-control__group block-editor-responsive-block-control__group--default" > | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same note here about BEM convention as at: #17846 (comment) Also:
The second point would actually enable us to simplify this implementation, where currently there is code duplication for <div className={ classnames( 'block-editor-responsive-block-control__group', { 'is-responsive': isResponsive } ) } hidden={ ! isResponsive }> |
||
| { defaultControl } | ||
| </div> | ||
| ) } | ||
|
|
||
| { isResponsiveMode && ( | ||
| <div className="block-editor-responsive-block-control__group block-editor-responsive-block-control__group--responsive" hidden={ ! isResponsiveMode }> | ||
| { ( renderResponsiveControls ? renderResponsiveControls( devices ) : defaultResponsiveControls() ) } | ||
| </div> | ||
| ) } | ||
|
|
||
| </div> | ||
| </fieldset> | ||
| ); | ||
| } | ||
|
|
||
| export default ResponsiveBlockControl; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| /** | ||
| * WordPress dependencies | ||
| */ | ||
| import { withInstanceId } from '@wordpress/compose'; | ||
| import { _x, sprintf } from '@wordpress/i18n'; | ||
| import { Fragment } from '@wordpress/element'; | ||
|
|
||
| const ResponsiveBlockControlLabel = ( { instanceId, property, device, desc } ) => { | ||
| const accessibleLabel = desc || sprintf( _x( 'Controls the %1$s property for %2$s devices.', 'Text labelling a interface as controlling a given layout property (eg: margin) for a given screen size.' ), property, device.label ); | ||
| return ( | ||
| <Fragment> | ||
| <span aria-describedby={ `rbc-desc-${ instanceId }` }> | ||
| { device.label } | ||
| </span> | ||
| <span className="screen-reader-text" id={ `rbc-desc-${ instanceId }` }>{ accessibleLabel }</span> | ||
| </Fragment> | ||
| ); | ||
| }; | ||
|
|
||
| export default withInstanceId( ResponsiveBlockControlLabel ); | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| @mixin screen-reader-text() { | ||
| border: 0; | ||
| clip: rect(1px, 1px, 1px, 1px); | ||
| clip-path: inset(50%); | ||
| height: 1px; | ||
| margin: -1px; | ||
| overflow: hidden; | ||
| padding: 0; | ||
| position: absolute; | ||
| width: 1px; | ||
| word-wrap: normal !important; | ||
| } | ||
|
|
||
| .block-editor-responsive-block-control { | ||
| margin-bottom: $block-padding*2; | ||
| border-bottom: 1px solid $light-gray-600; | ||
| padding-bottom: $block-padding; | ||
|
|
||
| &:last-child { | ||
| padding-bottom: 0; | ||
| border-bottom: 0; | ||
| } | ||
| } | ||
|
|
||
| .block-editor-responsive-block-control__legend { | ||
| margin: 0; | ||
| margin-bottom: 0.6em; | ||
| margin-left: -3px; | ||
| } | ||
|
|
||
| .block-editor-responsive-block-control__label { | ||
| font-weight: 600; | ||
| margin-bottom: 0.6em; | ||
| margin-left: -3px; // visual compensation | ||
| } | ||
|
|
||
| .block-editor-responsive-block-control__inner { | ||
| margin-left: -1px; // visual compensation | ||
| } | ||
|
|
||
| .block-editor-responsive-block-control__toggle { | ||
| margin-left: 1px; | ||
| } | ||
|
|
||
| .block-editor-responsive-block-control .components-base-control__help { | ||
| @include screen-reader-text(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| // Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any idea how this snapshot ended up minified? Makes it impossible to review changes to the component 😞
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tellthemachines It's quite likely that because the test is using a string of HTML for the snapshot, it doesn't know how to make sense of the string as markup of elements to break across lines, vs. say a React element tree. I'd agree though that it sort of defeats the purpose of a snapshot if a future maintainer is unable to assess whether changes in the snapshot are sensible. I'm not sure exactly what our current configuration will support for those snapshots, but I'd wonder if it could be using the DOM element or if we could adapt somehow for the React element to be used. Otherwise, we may ought to avoid using the snapshot altogether and instead assert directly against specific values we're expecting in the markup. |
||
|
|
||
| exports[`Basic rendering should render with required props 1`] = `"<fieldset class=\\"block-editor-responsive-block-control\\"><legend class=\\"block-editor-responsive-block-control__legend\\">Padding</legend><div class=\\"block-editor-responsive-block-control__inner\\"><div class=\\"components-base-control components-toggle-control block-editor-responsive-block-control__toggle\\"><div class=\\"components-base-control__field\\"><span class=\\"components-form-toggle is-checked\\"><input class=\\"components-form-toggle__input\\" id=\\"inspector-toggle-control-0\\" type=\\"checkbox\\" aria-describedby=\\"inspector-toggle-control-0__help\\" checked=\\"\\"><span class=\\"components-form-toggle__track\\"></span><span class=\\"components-form-toggle__thumb\\"></span><svg class=\\"components-form-toggle__on\\" width=\\"2\\" height=\\"6\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 2 6\\" role=\\"img\\" aria-hidden=\\"true\\" focusable=\\"false\\"><path d=\\"M0 0h2v6H0z\\"></path></svg></span><label for=\\"inspector-toggle-control-0\\" class=\\"components-toggle-control__label\\">Use the same padding on all screensizes.</label></div><p id=\\"inspector-toggle-control-0__help\\" class=\\"components-base-control__help\\">Toggle between using the same value for all screen sizes or using a unique value per screen size.</p></div><div class=\\"block-editor-responsive-block-control__group block-editor-responsive-block-control__group--default\\"><div class=\\"components-base-control\\"><div class=\\"components-base-control__field\\"><label class=\\"components-base-control__label\\" for=\\"inspector-select-control-0\\"><span aria-describedby=\\"rbc-desc-0\\">All</span><span class=\\"screen-reader-text\\" id=\\"rbc-desc-0\\">Controls the padding property for All devices.</span></label><select id=\\"inspector-select-control-0\\" class=\\"components-select-control__input\\"><option value=\\"\\">Please select</option><option value=\\"small\\">Small</option><option value=\\"medium\\">Medium</option><option value=\\"large\\">Large</option></select></div></div><p id=\\"all\\">All is used here for testing purposes to ensure we have access to details about the device.</p></div></div></fieldset>"`; | ||
Uh oh!
There was an error while loading. Please reload this page.