From 8d288e5177b2f19bab902c064aa5734fc02c8f79 Mon Sep 17 00:00:00 2001 From: Jorge Date: Tue, 22 Dec 2020 22:38:15 +0000 Subject: [PATCH] Move font size component into gutenberg repository. --- package-lock.json | 1 + packages/components/package.json | 1 + .../components/src/font-size-picker/index.js | 2 +- .../next/font-size-control-select.js | 101 +++++++++++++ .../next/font-size-control-slider.js | 58 ++++++++ .../next/font-size-control-styles.js | 11 ++ .../next/font-size-control-utils.js | 99 +++++++++++++ .../next/font-size-control.js | 79 ++++++++++ .../{next.js => next/index.js} | 8 +- .../next/use-font-size-control.js | 137 ++++++++++++++++++ 10 files changed, 490 insertions(+), 7 deletions(-) create mode 100755 packages/components/src/font-size-picker/next/font-size-control-select.js create mode 100755 packages/components/src/font-size-picker/next/font-size-control-slider.js create mode 100755 packages/components/src/font-size-picker/next/font-size-control-styles.js create mode 100755 packages/components/src/font-size-picker/next/font-size-control-utils.js create mode 100755 packages/components/src/font-size-picker/next/font-size-control.js rename packages/components/src/font-size-picker/{next.js => next/index.js} (79%) create mode 100755 packages/components/src/font-size-picker/next/use-font-size-control.js diff --git a/package-lock.json b/package-lock.json index 89f30f573ed8a5..899acefba1c091 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11819,6 +11819,7 @@ "@wordpress/rich-text": "file:packages/rich-text", "@wordpress/warning": "file:packages/warning", "@wp-g2/components": "^0.0.117", + "@wp-g2/context": "^0.0.117", "@wp-g2/styles": "^0.0.117", "@wp-g2/substate": "^0.0.117", "@wp-g2/utils": "^0.0.117", diff --git a/packages/components/package.json b/packages/components/package.json index 81e1f7f4249f1f..6611fee7ed5438 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -46,6 +46,7 @@ "@wordpress/rich-text": "file:../rich-text", "@wordpress/warning": "file:../warning", "@wp-g2/components": "^0.0.117", + "@wp-g2/context": "^0.0.117", "@wp-g2/styles": "^0.0.117", "@wp-g2/substate": "^0.0.117", "@wp-g2/utils": "^0.0.117", diff --git a/packages/components/src/font-size-picker/index.js b/packages/components/src/font-size-picker/index.js index e5987684459c3c..21de09fc89487f 100644 --- a/packages/components/src/font-size-picker/index.js +++ b/packages/components/src/font-size-picker/index.js @@ -18,7 +18,7 @@ import Button from '../button'; import RangeControl from '../range-control'; import CustomSelectControl from '../custom-select-control'; import VisuallyHidden from '../visually-hidden'; -import { withNextComponent } from './next'; +import { withNextComponent } from './next/'; const DEFAULT_FONT_SIZE = 'default'; const CUSTOM_FONT_SIZE = 'custom'; diff --git a/packages/components/src/font-size-picker/next/font-size-control-select.js b/packages/components/src/font-size-picker/next/font-size-control-select.js new file mode 100755 index 00000000000000..8df1cc5413de69 --- /dev/null +++ b/packages/components/src/font-size-picker/next/font-size-control-select.js @@ -0,0 +1,101 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { useCallback } from '@wordpress/element'; +/** + * External dependencies + */ +import { contextConnect, useContextSystem } from '@wp-g2/context'; +import { noop } from '@wp-g2/utils'; +import { + Grid, + TextInput, + SelectDropdown, + FormGroup, + Button, + View, +} from '@wp-g2/components'; + +/** + * Internal dependencies + */ +import { getSelectTemplateColumns } from './font-size-control-utils'; + +function FontSizeControlSelect( props, forwardedRef ) { + const { + customLabel, + disabled, + inputValue, + isDefaultValue, + label, + max, + min, + onChange = noop, + onInputChange = noop, + onReset = noop, + options = [], + size, + value, + withNumberInput, + withSelect, + ...otherProps + } = useContextSystem( props, 'FontSizeControlSelect' ); + + const templateColumns = getSelectTemplateColumns( withNumberInput ); + const subControlsTemplateColumns = withNumberInput ? '1fr 1fr' : '1fr'; + + const renderItem = useCallback( + ( { name, style } ) => { name }, + [] + ); + + return ( + + { withSelect && ( + + + + ) } + + { withNumberInput && ( + + + + ) } + + + + + + ); +} + +export default contextConnect( FontSizeControlSelect, 'FontSizeControlSelect' ); diff --git a/packages/components/src/font-size-picker/next/font-size-control-slider.js b/packages/components/src/font-size-picker/next/font-size-control-slider.js new file mode 100755 index 00000000000000..3c6a2aa0235590 --- /dev/null +++ b/packages/components/src/font-size-picker/next/font-size-control-slider.js @@ -0,0 +1,58 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +/** + * External dependencies + */ +import { noop } from '@wp-g2/utils'; + +/** + * Internal dependencies + */ +import { + ControlLabel, + Grid, + Slider, + TextInput, + VStack, +} from '@wp-g2/components'; +import { getSliderTemplateColumns } from './font-size-control-utils'; + +function FontSizeControlSlider( props ) { + const { + label = __( 'Custom size' ), + disabled, + min, + max, + onChange = noop, + size, + value, + withSlider, + } = props; + + if ( ! withSlider ) return null; + + const templateColumns = getSliderTemplateColumns(); + + const controlProps = { + disabled, + min, + max, + onChange, + size, + value, + }; + + return ( + + { label } + + + + + + ); +} + +export default FontSizeControlSlider; diff --git a/packages/components/src/font-size-picker/next/font-size-control-styles.js b/packages/components/src/font-size-picker/next/font-size-control-styles.js new file mode 100755 index 00000000000000..b4c34f8aa338e5 --- /dev/null +++ b/packages/components/src/font-size-picker/next/font-size-control-styles.js @@ -0,0 +1,11 @@ +/** + * External dependencies + */ +import { css } from '@wp-g2/styles'; + +export const FontSizeControl = css` + appearance: none; + border: none; + margin: 0; + padding: 0; +`; diff --git a/packages/components/src/font-size-picker/next/font-size-control-utils.js b/packages/components/src/font-size-picker/next/font-size-control-utils.js new file mode 100755 index 00000000000000..83e805d2ea4b08 --- /dev/null +++ b/packages/components/src/font-size-picker/next/font-size-control-utils.js @@ -0,0 +1,99 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +/** + * External dependencies + */ +import { ui } from '@wp-g2/styles'; +import { createUnitValue, is, parseUnitValue } from '@wp-g2/utils'; + +const DEFAULT_FONT_SIZE = 'default'; +const CUSTOM_FONT_SIZE = 'custom'; +const MAX_FONT_SIZE_DISPLAY = '25px'; +const ASIDE_CONTROL_WIDTH = 70; + +export function hasUnit( value ) { + const [ , unit ] = parseUnitValue( value ); + return !! unit; +} + +function getFontSize( values = [], value ) { + return values.find( ( item ) => item.size === value ); +} + +function isCustomValue( values = [], value ) { + const item = getFontSize( values, value ); + return !! item; +} + +export function isCustomSelectedItem( selectedItem ) { + return selectedItem?.key === CUSTOM_FONT_SIZE; +} + +export function getSelectValueFromFontSize( fontSizes, value ) { + if ( ! value ) return DEFAULT_FONT_SIZE; + + const fontSize = getFontSize( fontSizes, value ); + return fontSize ? fontSize.slug : CUSTOM_FONT_SIZE; +} + +export function getSelectOptions( { disableCustomFontSizes, options, value } ) { + if ( disableCustomFontSizes && ! options.length ) return null; + + options = [ + { slug: DEFAULT_FONT_SIZE, name: __( 'Default' ), size: undefined }, + ...options, + ]; + + if ( ! isCustomValue( options, value ) && ! disableCustomFontSizes ) { + options.push( { slug: CUSTOM_FONT_SIZE, name: __( 'Custom' ) } ); + } + + return options.map( ( option ) => { + const fontSize = is.number( option.size ) + ? createUnitValue( option.size, 'px' ) + : option.size; + + return { + key: option.slug, + name: option.name, + size: option.size, + style: { + fontSize: `min( ${ fontSize }, ${ MAX_FONT_SIZE_DISPLAY } )`, + }, + }; + } ); +} + +export function getInputValue( fontSizes = [], value ) { + const hasUnits = hasUnit( value || fontSizes[ 0 ]?.size ); + + let noUnitsValue; + if ( ! hasUnits ) { + noUnitsValue = value; + } else { + noUnitsValue = parseInt( value ); + } + + const isPixelValue = + is.number( value ) || ( is.string( value ) && value.endsWith( 'px' ) ); + + const inputValue = ( isPixelValue && noUnitsValue ) || ''; + + return inputValue; +} + +export function getSelectTemplateColumns( withNumberInput ) { + return withNumberInput + ? `minmax(0, 1fr) minmax(auto, ${ ui.value.px( + ASIDE_CONTROL_WIDTH * 2 + ) })` + : `minmax(0, 2fr) minmax(auto, ${ ui.value.px( + ASIDE_CONTROL_WIDTH + ) })`; +} + +export function getSliderTemplateColumns() { + return `2fr minmax(auto, ${ ui.value.px( ASIDE_CONTROL_WIDTH ) })`; +} diff --git a/packages/components/src/font-size-picker/next/font-size-control.js b/packages/components/src/font-size-picker/next/font-size-control.js new file mode 100755 index 00000000000000..013b0a2fd859ff --- /dev/null +++ b/packages/components/src/font-size-picker/next/font-size-control.js @@ -0,0 +1,79 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +/** + * External dependencies + */ +import { contextConnect } from '@wp-g2/context'; +import { View, VisuallyHidden, VStack } from '@wp-g2/components'; + +/** + * Internal dependencies + */ +import FontSizeControlSelect from './font-size-control-select'; +import FontSizeControlSlider from './font-size-control-slider'; +import { useFontSizeControl } from './use-font-size-control'; + +function FontSizeControl( props, forwardedRef ) { + const { + customLabel = __( 'Custom' ), + disabled, + label, + max, + min, + options, + inputValue, + isDefaultValue, + value, + onChange, + onReset, + onInputChange, + selectDropdownProps, + size, + withSlider, + withNumberInput, + withSelect, + ...otherProps + } = useFontSizeControl( props ); + + if ( ! options ) return null; + + return ( + + { label } + + + + + + ); +} + +export default contextConnect( FontSizeControl, 'FontSizeControl' ); diff --git a/packages/components/src/font-size-picker/next.js b/packages/components/src/font-size-picker/next/index.js similarity index 79% rename from packages/components/src/font-size-picker/next.js rename to packages/components/src/font-size-picker/next/index.js index 6d7e487e020f8e..0532b82e229289 100644 --- a/packages/components/src/font-size-picker/next.js +++ b/packages/components/src/font-size-picker/next/index.js @@ -1,12 +1,8 @@ -/** - * External dependencies - */ -import { FontSizeControl } from '@wp-g2/components'; - /** * Internal dependencies */ -import { __unstableWithNext as withNext } from '../__next/context'; +import { __unstableWithNext as withNext } from '../../__next/context'; +import FontSizeControl from './font-size-control'; const FontSizePicker = process.env.COMPONENT_SYSTEM_PHASE === 1 diff --git a/packages/components/src/font-size-picker/next/use-font-size-control.js b/packages/components/src/font-size-picker/next/use-font-size-control.js new file mode 100755 index 00000000000000..30bb2cde1b971e --- /dev/null +++ b/packages/components/src/font-size-picker/next/use-font-size-control.js @@ -0,0 +1,137 @@ +/** + * External dependencies + */ +import { useContextSystem } from '@wp-g2/context'; +import { cx } from '@wp-g2/styles'; +import { createUnitValue, is, noop } from '@wp-g2/utils'; + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { useCallback } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import * as styles from './font-size-control-styles'; +import { + getInputValue, + getSelectOptions, + getSelectValueFromFontSize, + hasUnit, + isCustomSelectedItem, +} from './font-size-control-utils'; + +export function useFontSizeControl( props ) { + const { + className, + customLabel = __( 'Custom' ), + disableCustomFontSizes, + disabled = false, + fontSizes = [], + isPreviewable, + label = __( 'Font size' ), + max = 100, + maxWidth, + min = 1, + minWidth, + onChange = noop, + onClose, + onOpen, + placeholder, + renderItem, + size, + value, + withSlider = false, + ...otherProps + } = useContextSystem( props ); + + const hasUnits = hasUnit( value || fontSizes[ 0 ]?.size ); + + const options = getSelectOptions( { + options: fontSizes, + disableCustomFontSizes, + value, + } ); + + const handleOnReset = useCallback( () => { + onChange( undefined ); + }, [ onChange ] ); + + const handleOnChange = useCallback( + ( { selectedItem } ) => { + if ( isCustomSelectedItem( selectedItem ) ) return; + + if ( hasUnits ) { + onChange( selectedItem.size ); + } else if ( is.defined( selectedItem.size ) ) { + onChange( Number( selectedItem.size ) ); + } else { + handleOnReset(); + } + }, + [ handleOnReset, hasUnits, onChange ] + ); + + const handleOnInputChange = useCallback( + ( next ) => { + if ( ! next && next !== 0 ) { + handleOnReset(); + return; + } + if ( hasUnits ) { + onChange( createUnitValue( next, 'px' ) ); + } else { + onChange( Number( next ) ); + } + }, + [ handleOnReset, hasUnits, onChange ] + ); + + const inputValue = getInputValue( fontSizes, value ); + + const selectedFontSizeSlug = getSelectValueFromFontSize( fontSizes, value ); + const currentValue = options.find( + ( option ) => option.key === selectedFontSizeSlug + ); + + const isDefaultValue = ! is.defined( value ); + + const classes = cx( styles.FontSizeControl, className ); + + const withSelect = fontSizes.length > 0; + const withNumberInput = ! withSlider && ! disableCustomFontSizes; + + const selectDropdownProps = { + isPreviewable, + maxWidth, + minWidth, + onClose, + onOpen, + placeholder, + renderItem, + }; + + return { + ...otherProps, + className: classes, + customLabel, + disabled, + inputValue, + isDefaultValue, + label, + max, + min, + onChange: handleOnChange, + onInputChange: handleOnInputChange, + onReset: handleOnReset, + options, + selectDropdownProps, + size, + value: currentValue, + withNumberInput, + withSelect, + withSlider, + }; +}