From 23a72978bbd1c856f58e2e09d359b44b8f8c1f7a Mon Sep 17 00:00:00 2001 From: etoledom Date: Thu, 7 Feb 2019 18:51:47 +0100 Subject: [PATCH] [Mobile] UI for size image settings (#13728) * Mobile: Importing SelectControl as native picker for iOS and Android * Adding iOS version of SelectControl as UIActionSheet. * Mobile: select-cell name change * Adding Android selector control based on modal. * Fix lint issues * Fix lint issues * Updated Android selector to show as BottomSheet * Moving SelectControl to components/mobile as `Picker` * Fix lint issues * Remove mobile `modal` component import * Updated SelectCell to PickerCell * Fix lint issues * Renaming styles.scss to styles.native.scss --- .../block-library/src/image/edit.native.js | 45 +++++++++++++- .../mobile/bottom-sheet/cell.native.js | 39 +++++++----- .../mobile/bottom-sheet/index.native.js | 3 + .../mobile/bottom-sheet/picker-cell.native.js | 33 ++++++++++ .../{styles.scss => styles.native.scss} | 1 - .../components/mobile/picker/index.android.js | 62 +++++++++++++++++++ .../src/components/mobile/picker/index.ios.js | 37 +++++++++++ .../mobile/picker/styles.android.scss | 10 +++ 8 files changed, 214 insertions(+), 16 deletions(-) create mode 100644 packages/editor/src/components/mobile/bottom-sheet/picker-cell.native.js rename packages/editor/src/components/mobile/bottom-sheet/{styles.scss => styles.native.scss} (98%) create mode 100644 packages/editor/src/components/mobile/picker/index.android.js create mode 100644 packages/editor/src/components/mobile/picker/index.ios.js create mode 100644 packages/editor/src/components/mobile/picker/styles.android.scss diff --git a/packages/block-library/src/image/edit.native.js b/packages/block-library/src/image/edit.native.js index 66b35ea5ef726b..822723ce141f65 100644 --- a/packages/block-library/src/image/edit.native.js +++ b/packages/block-library/src/image/edit.native.js @@ -12,6 +12,10 @@ import { requestImageFailedRetryDialog, requestImageUploadCancelDialog, } from 'react-native-gutenberg-bridge'; +import { + map, + compact, +} from 'lodash'; /** * Internal dependencies @@ -22,6 +26,8 @@ import { __ } from '@wordpress/i18n'; import ImageSize from './image-size'; import { isURL } from '@wordpress/url'; import styles from './styles.scss'; +import { compose } from '@wordpress/compose'; +import { withSelect } from '@wordpress/data'; const MEDIA_UPLOAD_STATE_UPLOADING = 1; const MEDIA_UPLOAD_STATE_SUCCEEDED = 2; @@ -30,7 +36,7 @@ const MEDIA_UPLOAD_STATE_RESET = 4; const LINK_DESTINATION_CUSTOM = 'custom'; -export default class ImageEdit extends React.Component { +class ImageEdit extends React.Component { constructor( props ) { super( props ); @@ -47,6 +53,7 @@ export default class ImageEdit extends React.Component { this.finishMediaUploadWithSuccess = this.finishMediaUploadWithSuccess.bind( this ); this.finishMediaUploadWithFailure = this.finishMediaUploadWithFailure.bind( this ); this.updateAlt = this.updateAlt.bind( this ); + this.updateImageURL = this.updateImageURL.bind( this ); this.onSetLinkDestination = this.onSetLinkDestination.bind( this ); this.onImagePressed = this.onImagePressed.bind( this ); } @@ -136,6 +143,10 @@ export default class ImageEdit extends React.Component { this.props.setAttributes( { alt: newAlt } ); } + updateImageURL( url ) { + this.props.setAttributes( { url, width: undefined, height: undefined } ); + } + onSetLinkDestination( href ) { this.props.setAttributes( { linkDestination: LINK_DESTINATION_CUSTOM, @@ -143,6 +154,16 @@ export default class ImageEdit extends React.Component { } ); } + getImageSizeOptions() { + const { imageSizes } = this.props; + return compact( map( imageSizes, ( { label, slug } ) => { + return { + value: this.props.attributes.url + slug, //temporary url + label, + }; + } ) ); + } + render() { const { attributes, isSelected, setAttributes } = this.props; const { url, caption, height, width, alt, href } = attributes; @@ -201,6 +222,8 @@ export default class ImageEdit extends React.Component { ); + const sizeOptions = this.getImageSizeOptions(); + const getInspectorControls = () => ( + {} } // Temporary for UI implementation. + /> { + const { getEditorSettings } = select( 'core/editor' ); + const { maxWidth, isRTL, imageSizes } = getEditorSettings(); + + return { + maxWidth, + isRTL, + imageSizes, + }; + } ), +] )( ImageEdit ); diff --git a/packages/editor/src/components/mobile/bottom-sheet/cell.native.js b/packages/editor/src/components/mobile/bottom-sheet/cell.native.js index 1a24d12952256f..89970e69b45982 100644 --- a/packages/editor/src/components/mobile/bottom-sheet/cell.native.js +++ b/packages/editor/src/components/mobile/bottom-sheet/cell.native.js @@ -24,11 +24,13 @@ export default function Cell( props ) { labelStyle = {}, valueStyle = {}, onChangeValue, + children, + editable = true, ...valueProps } = props; const showValue = value !== undefined; - const isValueEditable = onChangeValue !== undefined; + const isValueEditable = editable && onChangeValue !== undefined; const defaultLabelStyle = showValue ? styles.cellLabel : styles.cellLabelCentered; const separatorStyle = showValue ? styles.cellSeparator : styles.separator; let valueTextInput; @@ -41,6 +43,26 @@ export default function Cell( props ) { } }; + const getValueComponent = () => { + return isValueEditable ? ( + valueTextInput = c } + numberOfLines={ 1 } + style={ { ...styles.cellValue, ...valueStyle } } + value={ value } + placeholder={ valuePlaceholder } + placeholderTextColor={ '#87a6bc' } + onChangeText={ onChangeValue } + editable={ isValueEditable } + { ...valueProps } + /> + ) : ( + + { value } + + ); + }; + return ( @@ -55,19 +77,8 @@ export default function Cell( props ) { { label } - { showValue && ( - valueTextInput = c } - numberOfLines={ 1 } - style={ { ...styles.cellValue, ...valueStyle } } - value={ value } - placeholder={ valuePlaceholder } - placeholderTextColor={ '#87a6bc' } - onChangeText={ onChangeValue } - editable={ isValueEditable } - { ...valueProps } - /> - ) } + { showValue && getValueComponent() } + { children } { drawSeparator && ( diff --git a/packages/editor/src/components/mobile/bottom-sheet/index.native.js b/packages/editor/src/components/mobile/bottom-sheet/index.native.js index d4754a3909dfa8..d05eb73e1c925c 100644 --- a/packages/editor/src/components/mobile/bottom-sheet/index.native.js +++ b/packages/editor/src/components/mobile/bottom-sheet/index.native.js @@ -16,6 +16,7 @@ import { Component } from '@wordpress/element'; import styles from './styles.scss'; import Button from './button'; import Cell from './cell'; +import PickerCell from './picker-cell'; class BottomSheet extends Component { constructor() { @@ -54,6 +55,7 @@ class BottomSheet extends Component { animationOutTiming={ 500 } backdropTransitionInTiming={ 500 } backdropTransitionOutTiming={ 500 } + backdropOpacity={ 0.2 } onBackdropPress={ this.props.onClose } onSwipe={ this.props.onClose } swipeDirection="down" @@ -94,5 +96,6 @@ class BottomSheet extends Component { BottomSheet.Button = Button; BottomSheet.Cell = Cell; +BottomSheet.PickerCell = PickerCell; export default BottomSheet; diff --git a/packages/editor/src/components/mobile/bottom-sheet/picker-cell.native.js b/packages/editor/src/components/mobile/bottom-sheet/picker-cell.native.js new file mode 100644 index 00000000000000..888acd3db54b22 --- /dev/null +++ b/packages/editor/src/components/mobile/bottom-sheet/picker-cell.native.js @@ -0,0 +1,33 @@ +/** + * Internal dependencies + */ +import Cell from './cell'; +import Picker from '../picker'; + +export default function PickerCell( props ) { + const { + options, + onChangeValue, + ...cellProps + } = props; + + let picker; + + const onCellPress = () => { + picker.presentPicker(); + }; + + const onChange = ( newValue ) => { + onChangeValue( newValue ); + }; + + return ( + + picker = instance } + options={ options } + onChange={ onChange } + /> + + ); +} diff --git a/packages/editor/src/components/mobile/bottom-sheet/styles.scss b/packages/editor/src/components/mobile/bottom-sheet/styles.native.scss similarity index 98% rename from packages/editor/src/components/mobile/bottom-sheet/styles.scss rename to packages/editor/src/components/mobile/bottom-sheet/styles.native.scss index 139c79d88de56b..3081519dbb08d6 100644 --- a/packages/editor/src/components/mobile/bottom-sheet/styles.scss +++ b/packages/editor/src/components/mobile/bottom-sheet/styles.native.scss @@ -17,7 +17,6 @@ background-color: $light-gray-400; height: 1px; width: 100%; - margin-bottom: 14px; } .content { diff --git a/packages/editor/src/components/mobile/picker/index.android.js b/packages/editor/src/components/mobile/picker/index.android.js new file mode 100644 index 00000000000000..8dd1d909b12812 --- /dev/null +++ b/packages/editor/src/components/mobile/picker/index.android.js @@ -0,0 +1,62 @@ +/** + * External dependencies + */ +import React from 'react'; +import { View } from 'react-native'; + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { Component } from '@wordpress/element'; +import { BottomSheet } from '@wordpress/editor'; + +export default class Picker extends Component { + constructor() { + super( ...arguments ); + this.onClose = this.onClose.bind( this ); + this.onCellPress = this.onCellPress.bind( this ); + + this.state = { + isVisible: false, + }; + } + + presentPicker() { + this.setState( { isVisible: true } ); + } + + onClose() { + this.setState( { isVisible: false } ); + } + + onCellPress( value ) { + this.props.onChange( value ); + this.onClose(); + } + + render() { + return ( + + + { this.props.options.map( ( option, index ) => + this.onCellPress( option.value ) } + /> + ) } + + + + ); + } +} diff --git a/packages/editor/src/components/mobile/picker/index.ios.js b/packages/editor/src/components/mobile/picker/index.ios.js new file mode 100644 index 00000000000000..0a0b3d8a2dd410 --- /dev/null +++ b/packages/editor/src/components/mobile/picker/index.ios.js @@ -0,0 +1,37 @@ +/** + * External dependencies + */ +import { ActionSheetIOS } from 'react-native'; + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { Component } from '@wordpress/element'; + +class Picker extends Component { + presentPicker() { + const { options, onChange } = this.props; + const labels = options.map( ( { label } ) => label ); + const fullOptions = [ __( 'Cancel' ) ].concat( labels ); + + ActionSheetIOS.showActionSheetWithOptions( { + options: fullOptions, + cancelButtonIndex: 0, + }, + ( buttonIndex ) => { + if ( buttonIndex === 0 ) { + return; + } + const selected = options[ buttonIndex - 1 ]; + onChange( selected.value ); + }, + ); + } + + render() { + return null; + } +} + +export default Picker; diff --git a/packages/editor/src/components/mobile/picker/styles.android.scss b/packages/editor/src/components/mobile/picker/styles.android.scss new file mode 100644 index 00000000000000..56579b49165353 --- /dev/null +++ b/packages/editor/src/components/mobile/picker/styles.android.scss @@ -0,0 +1,10 @@ +.cellContainer { + min-height: 48; + align-items: flex-start; +} + +.cellLabel { + font-size: 17px; + color: #2e4453; + margin-right: 12px; +}