UNPKG

@wordpress/components

Version:
285 lines (256 loc) 9.51 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import { createElement } from "@wordpress/element"; /** * External dependencies */ import { TouchableOpacity, Text, View, TextInput, I18nManager, AccessibilityInfo } from 'react-native'; import { isEmpty, get } from 'lodash'; /** * WordPress dependencies */ import { Icon } from '@wordpress/components'; import { check } from '@wordpress/icons'; import { Component } from '@wordpress/element'; import { __, _x, sprintf } from '@wordpress/i18n'; import { withPreferredColorScheme } from '@wordpress/compose'; /** * Internal dependencies */ import styles from './styles.scss'; import platformStyles from './cellStyles.scss'; import TouchableRipple from './ripple'; class BottomSheetCell extends Component { constructor(props) { super(...arguments); this.state = { isEditingValue: props.autoFocus || false, isScreenReaderEnabled: false }; this.handleScreenReaderToggled = this.handleScreenReaderToggled.bind(this); this.isCurrent = false; } componentDidUpdate(prevProps, prevState) { if (!prevState.isEditingValue && this.state.isEditingValue) { this._valueTextInput.focus(); } } componentDidMount() { this.isCurrent = true; AccessibilityInfo.addEventListener('screenReaderChanged', this.handleScreenReaderToggled); AccessibilityInfo.isScreenReaderEnabled().then(isScreenReaderEnabled => { if (this.isCurrent) { this.setState({ isScreenReaderEnabled }); } }); } componentWillUnmount() { this.isCurrent = false; AccessibilityInfo.removeEventListener('screenReaderChanged', this.handleScreenReaderToggled); } handleScreenReaderToggled(isScreenReaderEnabled) { this.setState({ isScreenReaderEnabled }); } typeToKeyboardType(type, step) { let keyboardType = `default`; if (type === `number`) { if (step && Math.abs(step) < 1) { keyboardType = `decimal-pad`; } else { keyboardType = `number-pad`; } } return keyboardType; } render() { const { accessible, accessibilityLabel, accessibilityHint, accessibilityRole, disabled = false, activeOpacity, onPress, onLongPress, label, value, valuePlaceholder = '', icon, leftAlign, labelStyle = {}, valueStyle = {}, cellContainerStyle = {}, cellRowContainerStyle = {}, onChangeValue, onSubmit, children, editable = true, isSelected = false, separatorType, style = {}, getStylesFromColorScheme, customActionButton, type, step, borderless, ...valueProps } = this.props; const showValue = value !== undefined; const isValueEditable = editable && onChangeValue !== undefined; const cellLabelStyle = getStylesFromColorScheme(styles.cellLabel, styles.cellTextDark); const cellLabelCenteredStyle = getStylesFromColorScheme(styles.cellLabelCentered, styles.cellTextDark); const cellLabelLeftAlignNoIconStyle = getStylesFromColorScheme(styles.cellLabelLeftAlignNoIcon, styles.cellTextDark); const defaultMissingIconAndValue = leftAlign ? cellLabelLeftAlignNoIconStyle : cellLabelCenteredStyle; const defaultLabelStyle = showValue || customActionButton || icon ? cellLabelStyle : defaultMissingIconAndValue; const drawSeparator = separatorType && separatorType !== 'none' || separatorStyle === undefined; const drawTopSeparator = drawSeparator && separatorType === 'topFullWidth'; const cellContainerStyles = [styles.cellContainer, cellContainerStyle]; const rowContainerStyles = [styles.cellRowContainer, cellRowContainerStyle]; const isInteractive = isValueEditable || onPress !== undefined || onLongPress !== undefined; const onCellPress = () => { if (isValueEditable) { startEditing(); } else if (onPress !== undefined) { onPress(); } }; const finishEditing = () => { this.setState({ isEditingValue: false }); }; const startEditing = () => { if (this.state.isEditingValue === false) { this.setState({ isEditingValue: true }); } }; const separatorStyle = () => { //eslint-disable-next-line @wordpress/no-unused-vars-before-return const defaultSeparatorStyle = this.props.getStylesFromColorScheme(styles.separator, styles.separatorDark); const cellSeparatorStyle = this.props.getStylesFromColorScheme(styles.cellSeparator, styles.cellSeparatorDark); const leftMarginStyle = { ...cellSeparatorStyle, ...platformStyles.separatorMarginLeft }; switch (separatorType) { case 'leftMargin': return leftMarginStyle; case 'fullWidth': case 'topFullWidth': return defaultSeparatorStyle; case 'none': return undefined; case undefined: if (showValue && icon) { return leftMarginStyle; } return defaultSeparatorStyle; } }; const getValueComponent = () => { const styleRTL = I18nManager.isRTL && styles.cellValueRTL; const cellValueStyle = this.props.getStylesFromColorScheme(styles.cellValue, styles.cellTextDark); const finalStyle = { ...cellValueStyle, ...valueStyle, ...styleRTL }; // To be able to show the `middle` ellipsizeMode on editable cells // we show the TextInput just when the user wants to edit the value, // and the Text component to display it. // We also show the TextInput to display placeholder. const shouldShowPlaceholder = isValueEditable && value === ''; return this.state.isEditingValue || shouldShowPlaceholder ? createElement(TextInput, _extends({ ref: c => this._valueTextInput = c, numberOfLines: 1, style: finalStyle, value: value, placeholder: valuePlaceholder, placeholderTextColor: '#87a6bc', onChangeText: onChangeValue, editable: isValueEditable, pointerEvents: this.state.isEditingValue ? 'auto' : 'none', onFocus: startEditing, onBlur: finishEditing, onSubmitEditing: onSubmit, keyboardType: this.typeToKeyboardType(type, step) }, valueProps)) : createElement(Text, { style: { ...cellValueStyle, ...valueStyle }, numberOfLines: 1, ellipsizeMode: 'middle' }, value); }; const getAccessibilityLabel = () => { if (accessible === false) { return; } if (accessibilityLabel || !showValue) { return accessibilityLabel || label; } return isEmpty(value) ? sprintf( /* translators: accessibility text. Empty state of a inline textinput cell. %s: The cell's title */ _x('%s. Empty', 'inline textinput cell'), label) : // Separating by ',' is necessary to make a pause on urls (non-capitalized text) sprintf( /* translators: accessibility text. Inline textinput title and value.%1: Cell title, %2: cell value. */ _x('%1$s, %2$s', 'inline textinput cell'), label, value); }; const iconStyle = getStylesFromColorScheme(styles.icon, styles.iconDark); const resetButtonStyle = getStylesFromColorScheme(styles.resetButton, styles.resetButtonDark); const containerPointerEvents = this.state.isScreenReaderEnabled && accessible ? 'none' : 'auto'; const { title, handler } = customActionButton || {}; const opacity = activeOpacity !== undefined ? activeOpacity : get(platformStyles, 'activeOpacity.opacity'); return createElement(TouchableRipple, { accessible: accessible !== undefined ? accessible : !this.state.isEditingValue, accessibilityLabel: getAccessibilityLabel(), accessibilityRole: accessibilityRole || 'button', accessibilityHint: isValueEditable ? /* translators: accessibility text */ __('Double tap to edit this value') : accessibilityHint, disabled: disabled || !isInteractive, activeOpacity: opacity, onPress: onCellPress, onLongPress: onLongPress, style: [styles.clipToBounds, style], borderless: borderless }, drawTopSeparator && createElement(View, { style: separatorStyle() }), createElement(View, { style: cellContainerStyles, pointerEvents: containerPointerEvents }, createElement(View, { style: rowContainerStyles }, createElement(View, { style: styles.cellRowContainer }, icon && createElement(View, { style: styles.cellRowContainer }, createElement(Icon, { icon: icon, size: 24, fill: iconStyle.color, isPressed: false }), createElement(View, { style: platformStyles.labelIconSeparator })), label && createElement(Text, { style: [defaultLabelStyle, labelStyle] }, label)), customActionButton && createElement(TouchableOpacity, { onPress: handler, accessibilityRole: 'button' }, createElement(Text, { style: resetButtonStyle }, title))), isSelected && createElement(Icon, { icon: check, fill: platformStyles.isSelected.color }), showValue && getValueComponent(), children), !drawTopSeparator && createElement(View, { style: separatorStyle() })); } } export default withPreferredColorScheme(BottomSheetCell); //# sourceMappingURL=cell.native.js.map