From 9664a9ceaf012cd49b349c88c18603680081ba92 Mon Sep 17 00:00:00 2001 From: Saad Date: Sun, 28 Apr 2024 09:17:15 +0600 Subject: [PATCH 1/2] added SizeControl component --- .../src/components/size-control/README.md | 64 ++++++ .../src/components/size-control/index.js | 210 ++++++++++++++++++ .../size-control/stories/index.story.js | 21 ++ .../src/components/size-control/style.scss | 5 + 4 files changed, 300 insertions(+) create mode 100644 packages/block-editor/src/components/size-control/README.md create mode 100644 packages/block-editor/src/components/size-control/index.js create mode 100644 packages/block-editor/src/components/size-control/stories/index.story.js create mode 100644 packages/block-editor/src/components/size-control/style.scss diff --git a/packages/block-editor/src/components/size-control/README.md b/packages/block-editor/src/components/size-control/README.md new file mode 100644 index 00000000000000..38aaf51ae7b762 --- /dev/null +++ b/packages/block-editor/src/components/size-control/README.md @@ -0,0 +1,64 @@ +# Size Control + +The `SizeControl` component adds a linked unit control and slider component for controlling the size of something within the block editor. It supports passing a label & rangeConfig, and is used for controlling the minimum size dimensions of Group blocks. + +_Note:_ It is worth noting that the minimum size option is an opt-in feature. Themes need to declare support for it before it'll be available, and a convenient way to do that is via opting in to the [appearanceTools](/docs/how-to-guides/themes/global-settings-and-styles.md#opt-in-into-ui-controls) UI controls. + +## Development guidelines + +### Usage + +Renders the markup for size control component, to be used in the block inspector. + +```jsx +import { useState } from 'react'; +import { SizeControl } from '@wordpress/block-editor'; + +const MyLineSizeControl = () => ( + const [ value, setValue ] = useState(); + +); +``` + +### Props + +#### `value` + +- **Type:** `String` or `Number` or `Undefined` + +The value of the current size. + +#### `onChange` + +- **Type:** `Function` + +A callback function that handles the application of the size value. + +#### `label` + +- **Type:** `String` +- **Default:** `'Size'` + +A label for the size control. This is useful when using the size control for a feature that is controlled in the same way as size, but requires a different label. For example, "Minimum size". + +#### `rangeConfig` + +- **Type:** `Object` +- **Default:** `{}` + +An object of the shape `{[key: units]:{min?: number; step?: number; max?: number}}` for overriding the min, max & step values. + +#### `adaptiveRange` + +- **Type:** `boolean` +- **Default:** `false` + +This is to set the behavior when the value is out of it's specified range. When true, the min/max will adapt to the value. + +## Related components + +Block Editor components are components that can be used to compose the UI of your block editor. Thus, they can only be used under a [`BlockEditorProvider`](https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/provider/README.md) in the components tree. diff --git a/packages/block-editor/src/components/size-control/index.js b/packages/block-editor/src/components/size-control/index.js new file mode 100644 index 00000000000000..59e54f465e94f8 --- /dev/null +++ b/packages/block-editor/src/components/size-control/index.js @@ -0,0 +1,210 @@ +/** + * WordPress dependencies + */ +import { useMemo } from '@wordpress/element'; +import { + BaseControl, + RangeControl, + Flex, + FlexItem, + __experimentalSpacer as Spacer, + __experimentalUseCustomUnits as useCustomUnits, + __experimentalUnitControl as UnitControl, + __experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue, +} from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import { useSettings } from '../use-settings'; + +const RANGE_CONTROL_CUSTOM_SETTINGS = { + px: { max: 1000, step: 1 }, + '%': { max: 100, step: 1 }, + vw: { max: 100, step: 1 }, + vh: { max: 100, step: 1 }, + em: { max: 50, step: 0.1 }, + rem: { max: 50, step: 0.1 }, + svw: { max: 100, step: 1 }, + lvw: { max: 100, step: 1 }, + dvw: { max: 100, step: 1 }, + svh: { max: 100, step: 1 }, + lvh: { max: 100, step: 1 }, + dvh: { max: 100, step: 1 }, + vi: { max: 100, step: 1 }, + svi: { max: 100, step: 1 }, + lvi: { max: 100, step: 1 }, + dvi: { max: 100, step: 1 }, + vb: { max: 100, step: 1 }, + svb: { max: 100, step: 1 }, + lvb: { max: 100, step: 1 }, + dvb: { max: 100, step: 1 }, + vmin: { max: 100, step: 1 }, + svmin: { max: 100, step: 1 }, + lvmin: { max: 100, step: 1 }, + dvmin: { max: 100, step: 1 }, + vmax: { max: 100, step: 1 }, + svmax: { max: 100, step: 1 }, + lvmax: { max: 100, step: 1 }, + dvmax: { max: 100, step: 1 }, +}; + +/** + * SizeControl renders a linked unit control and range control for setting the size of anyting. + * + * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/height-control/README.md + * + * @param {Object} props + * @param {?string} props.label A label for the control. + * @param {( value: string ) => void } props.onChange Called when the height changes. + * @param {string} props.value The current height value. + * @param {?boolean} props.adaptiveRange Whether the min/max should adapt to the value + * @param { + * { + * [Key in keyof typeof RANGE_CONTROL_CUSTOM_SETTINGS]?: { + * min?: number; + * max: number; + * step: number; + * } + * } + * } props.rangeConfig The current height value. + * + * @return {Component} The component to be rendered. + */ +export default function SizeControl( { + label = __( 'Size' ), + onChange, + value, + adaptiveRange = false, + rangeConfig = {} +} ) { + const customRangeValue = parseFloat( value ); + + const [ availableUnits ] = useSettings( 'spacing.units' ); + const units = useCustomUnits( { + availableUnits: availableUnits || [ + '%', + 'px', + 'em', + 'rem', + 'vh', + 'vw', + ], + } ); + + const selectedUnit = + useMemo( + () => parseQuantityAndUnitFromRawValue( value ), + [ value ] + )[ 1 ] || + units[ 0 ]?.value || + 'px'; + + const handleSliderChange = ( next ) => { + onChange( [ next, selectedUnit ].join( '' ) ); + }; + + const handleUnitChange = ( newUnit ) => { + // Attempt to smooth over differences between currentUnit and newUnit. + // This should slightly improve the experience of switching between unit types. + const [ currentValue, currentUnit ] = + parseQuantityAndUnitFromRawValue( value ); + + if ( [ 'em', 'rem' ].includes( newUnit ) && currentUnit === 'px' ) { + // Convert pixel value to an approximate of the new unit, assuming a root size of 16px. + onChange( ( currentValue / 16 ).toFixed( 2 ) + newUnit ); + } else if ( + [ 'em', 'rem' ].includes( currentUnit ) && + newUnit === 'px' + ) { + // Convert to pixel value assuming a root size of 16px. + onChange( Math.round( currentValue * 16 ) + newUnit ); + } else if ( + [ + '%', + 'vw', + 'svw', + 'lvw', + 'dvw', + 'vh', + 'svh', + 'lvh', + 'dvh', + 'vi', + 'svi', + 'lvi', + 'dvi', + 'vb', + 'svb', + 'lvb', + 'dvb', + 'vmin', + 'svmin', + 'lvmin', + 'dvmin', + 'vmax', + 'svmax', + 'lvmax', + 'dvmax', + ].includes( newUnit ) && + currentValue > 100 + ) { + // When converting to `%` or viewport-relative units, cap the new value at 100. + onChange( 100 + newUnit ); + } + }; + + const customConfig = rangeConfig[ selectedUnit ]; + const defaultConfig = RANGE_CONTROL_CUSTOM_SETTINGS[ selectedUnit ]; + + let minVal = customConfig?.min ?? defaultConfig?.min ?? 0; + let maxVal = customConfig?.max ?? defaultConfig?.max ?? 100; + const stepVal = customConfig?.step ?? defaultConfig?.step ?? 0.1; + + if (adaptiveRange) { + minVal = Math.min(minVal, customRangeValue); + maxVal = Math.max(maxVal, customRangeValue); + } + + return ( +
+ + { label } + + + + + + + + + + + +
+ ); +} diff --git a/packages/block-editor/src/components/size-control/stories/index.story.js b/packages/block-editor/src/components/size-control/stories/index.story.js new file mode 100644 index 00000000000000..be284b5047fdb9 --- /dev/null +++ b/packages/block-editor/src/components/size-control/stories/index.story.js @@ -0,0 +1,21 @@ +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import SizeControl from '../'; + +export default { + component: SizeControl, + title: 'BlockEditor/SizeControl', +}; + +const Template = ( props ) => { + const [ value, setValue ] = useState(); + return ; +}; + +export const Default = Template.bind( {} ); diff --git a/packages/block-editor/src/components/size-control/style.scss b/packages/block-editor/src/components/size-control/style.scss new file mode 100644 index 00000000000000..add0866835f767 --- /dev/null +++ b/packages/block-editor/src/components/size-control/style.scss @@ -0,0 +1,5 @@ +.block-editor-height-control { + border: 0; + margin: 0; + padding: 0; +} From 55074f39644986a2c80f665e6b490f27b540fe8a Mon Sep 17 00:00:00 2001 From: Saad Date: Sun, 28 Apr 2024 09:17:30 +0600 Subject: [PATCH 2/2] updated the HeightControl --- .../src/components/height-control/index.js | 165 +----------------- .../src/components/height-control/style.scss | 5 - 2 files changed, 2 insertions(+), 168 deletions(-) delete mode 100644 packages/block-editor/src/components/height-control/style.scss diff --git a/packages/block-editor/src/components/height-control/index.js b/packages/block-editor/src/components/height-control/index.js index 23738378b69983..ad81dfd34edc95 100644 --- a/packages/block-editor/src/components/height-control/index.js +++ b/packages/block-editor/src/components/height-control/index.js @@ -1,54 +1,8 @@ -/** - * WordPress dependencies - */ -import { useMemo } from '@wordpress/element'; -import { - BaseControl, - RangeControl, - Flex, - FlexItem, - __experimentalSpacer as Spacer, - __experimentalUseCustomUnits as useCustomUnits, - __experimentalUnitControl as UnitControl, - __experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue, -} from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import { useSettings } from '../use-settings'; - -const RANGE_CONTROL_CUSTOM_SETTINGS = { - px: { max: 1000, step: 1 }, - '%': { max: 100, step: 1 }, - vw: { max: 100, step: 1 }, - vh: { max: 100, step: 1 }, - em: { max: 50, step: 0.1 }, - rem: { max: 50, step: 0.1 }, - svw: { max: 100, step: 1 }, - lvw: { max: 100, step: 1 }, - dvw: { max: 100, step: 1 }, - svh: { max: 100, step: 1 }, - lvh: { max: 100, step: 1 }, - dvh: { max: 100, step: 1 }, - vi: { max: 100, step: 1 }, - svi: { max: 100, step: 1 }, - lvi: { max: 100, step: 1 }, - dvi: { max: 100, step: 1 }, - vb: { max: 100, step: 1 }, - svb: { max: 100, step: 1 }, - lvb: { max: 100, step: 1 }, - dvb: { max: 100, step: 1 }, - vmin: { max: 100, step: 1 }, - svmin: { max: 100, step: 1 }, - lvmin: { max: 100, step: 1 }, - dvmin: { max: 100, step: 1 }, - vmax: { max: 100, step: 1 }, - svmax: { max: 100, step: 1 }, - lvmax: { max: 100, step: 1 }, - dvmax: { max: 100, step: 1 }, -}; +import SizeControl from '../size-control'; /** * HeightControl renders a linked unit control and range control for adjusting the height of a block. @@ -67,122 +21,7 @@ export default function HeightControl( { onChange, value, } ) { - const customRangeValue = parseFloat( value ); - - const [ availableUnits ] = useSettings( 'spacing.units' ); - const units = useCustomUnits( { - availableUnits: availableUnits || [ - '%', - 'px', - 'em', - 'rem', - 'vh', - 'vw', - ], - } ); - - const selectedUnit = - useMemo( - () => parseQuantityAndUnitFromRawValue( value ), - [ value ] - )[ 1 ] || - units[ 0 ]?.value || - 'px'; - - const handleSliderChange = ( next ) => { - onChange( [ next, selectedUnit ].join( '' ) ); - }; - - const handleUnitChange = ( newUnit ) => { - // Attempt to smooth over differences between currentUnit and newUnit. - // This should slightly improve the experience of switching between unit types. - const [ currentValue, currentUnit ] = - parseQuantityAndUnitFromRawValue( value ); - - if ( [ 'em', 'rem' ].includes( newUnit ) && currentUnit === 'px' ) { - // Convert pixel value to an approximate of the new unit, assuming a root size of 16px. - onChange( ( currentValue / 16 ).toFixed( 2 ) + newUnit ); - } else if ( - [ 'em', 'rem' ].includes( currentUnit ) && - newUnit === 'px' - ) { - // Convert to pixel value assuming a root size of 16px. - onChange( Math.round( currentValue * 16 ) + newUnit ); - } else if ( - [ - '%', - 'vw', - 'svw', - 'lvw', - 'dvw', - 'vh', - 'svh', - 'lvh', - 'dvh', - 'vi', - 'svi', - 'lvi', - 'dvi', - 'vb', - 'svb', - 'lvb', - 'dvb', - 'vmin', - 'svmin', - 'lvmin', - 'dvmin', - 'vmax', - 'svmax', - 'lvmax', - 'dvmax', - ].includes( newUnit ) && - currentValue > 100 - ) { - // When converting to `%` or viewport-relative units, cap the new value at 100. - onChange( 100 + newUnit ); - } - }; - return ( -
- - { label } - - - - - - - - - - - -
+ ); } diff --git a/packages/block-editor/src/components/height-control/style.scss b/packages/block-editor/src/components/height-control/style.scss deleted file mode 100644 index add0866835f767..00000000000000 --- a/packages/block-editor/src/components/height-control/style.scss +++ /dev/null @@ -1,5 +0,0 @@ -.block-editor-height-control { - border: 0; - margin: 0; - padding: 0; -}