@wordpress/block-library
Version:
Block library for the WordPress editor.
369 lines (334 loc) • 14.6 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
var _styles$widthMargin, _styles$widthMargin2;
import { createElement } from "@wordpress/element";
/**
* External dependencies
*/
import { View, AccessibilityInfo } from 'react-native';
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { RichText, PlainText, useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, SelectControl, ToggleControl, Icon } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { search } from '@wordpress/icons';
import { useRef, useEffect, useState } from '@wordpress/element';
import { usePreferredColorSchemeStyle } from '@wordpress/compose';
/**
* Internal dependencies
*/
import styles from './style.scss';
/**
* Constants
*/
const MIN_BUTTON_WIDTH = 75;
const MARGINS = ((_styles$widthMargin = styles.widthMargin) === null || _styles$widthMargin === void 0 ? void 0 : _styles$widthMargin.marginLeft) + ((_styles$widthMargin2 = styles.widthMargin) === null || _styles$widthMargin2 === void 0 ? void 0 : _styles$widthMargin2.paddingLeft);
const BUTTON_OPTIONS = [{
value: 'button-inside',
label: __('Button inside')
}, {
value: 'button-outside',
label: __('Button outside')
}, {
value: 'no-button',
label: __('No button')
}];
export default function SearchEdit(_ref) {
var _style$baseColors, _style$baseColors2, _style$baseColors2$co, _style$baseColors3, _style$baseColors4, _style$baseColors4$co, _style$baseColors5, _style$baseColors5$bl, _style$baseColors5$bl2, _attributes$style, _styles$richTextButto2;
let {
onFocus,
isSelected,
attributes,
setAttributes,
className,
blockWidth,
style
} = _ref;
const [isButtonSelected, setIsButtonSelected] = useState(false);
const [isLabelSelected, setIsLabelSelected] = useState(false);
const [isPlaceholderSelected, setIsPlaceholderSelected] = useState(false);
const [isLongButton, setIsLongButton] = useState(false);
const [buttonWidth, setButtonWidth] = useState(MIN_BUTTON_WIDTH);
const [isScreenReaderEnabled, setIsScreenReaderEnabled] = useState(false);
const textInputRef = useRef(null);
const {
label,
showLabel,
buttonPosition,
buttonUseIcon,
placeholder,
buttonText
} = attributes;
/*
* Check if screenreader is enabled and save to state. This is important for
* properly creating accessibilityLabel text.
*/
useEffect(() => {
const a11yInfoChangeSubscription = AccessibilityInfo.addEventListener('screenReaderChanged', handleScreenReaderToggled);
AccessibilityInfo.isScreenReaderEnabled().then(screenReaderEnabled => {
setIsScreenReaderEnabled(screenReaderEnabled);
});
return () => {
a11yInfoChangeSubscription.remove();
};
}, []);
const handleScreenReaderToggled = screenReaderEnabled => {
setIsScreenReaderEnabled(screenReaderEnabled);
};
/*
* Called when the value of isSelected changes. Blurs the PlainText component
* used by the placeholder when this block loses focus.
*/
useEffect(() => {
if (hasTextInput() && isPlaceholderSelected && !isSelected) {
textInputRef.current.blur();
}
}, [isSelected]);
useEffect(() => {
const maxButtonWidth = Math.floor(blockWidth / 2 - MARGINS);
const tempIsLongButton = buttonWidth > maxButtonWidth; // Update this value only if it has changed to avoid flickering.
if (isLongButton !== tempIsLongButton) {
setIsLongButton(tempIsLongButton);
}
}, [blockWidth, buttonWidth]);
const hasTextInput = () => {
return textInputRef && textInputRef.current;
};
const onLayoutButton = _ref2 => {
let {
nativeEvent
} = _ref2;
const {
width
} = nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.layout;
if (width) {
setButtonWidth(width);
}
};
const getBlockClassNames = () => {
return classnames(className, 'button-inside' === buttonPosition ? 'wp-block-search__button-inside' : undefined, 'button-outside' === buttonPosition ? 'wp-block-search__button-outside' : undefined, 'no-button' === buttonPosition ? 'wp-block-search__no-button' : undefined, 'button-only' === buttonPosition ? 'wp-block-search__button-only' : undefined, !buttonUseIcon && 'no-button' !== buttonPosition ? 'wp-block-search__text-button' : undefined, buttonUseIcon && 'no-button' !== buttonPosition ? 'wp-block-search__icon-button' : undefined);
};
const getSelectedButtonPositionLabel = option => {
switch (option) {
case 'button-inside':
return __('Inside');
case 'button-outside':
return __('Outside');
case 'no-button':
return __('No button');
}
};
const blockProps = useBlockProps({
className: getBlockClassNames()
});
const controls = createElement(InspectorControls, null, createElement(PanelBody, {
title: __('Search settings')
}, createElement(ToggleControl, {
label: __('Hide search heading'),
checked: !showLabel,
onChange: () => {
setAttributes({
showLabel: !showLabel
});
}
}), createElement(SelectControl, {
label: __('Button position'),
value: getSelectedButtonPositionLabel(buttonPosition),
onChange: position => {
setAttributes({
buttonPosition: position
});
},
options: BUTTON_OPTIONS,
hideCancelButton: true
}), buttonPosition !== 'no-button' && createElement(ToggleControl, {
label: __('Use icon button'),
checked: buttonUseIcon,
onChange: () => {
setAttributes({
buttonUseIcon: !buttonUseIcon
});
}
})));
const isButtonInside = buttonPosition === 'button-inside';
const borderStyle = usePreferredColorSchemeStyle(styles.border, styles.borderDark);
const inputStyle = [!isButtonInside && borderStyle, usePreferredColorSchemeStyle(styles.plainTextInput, styles.plainTextInputDark), (style === null || style === void 0 ? void 0 : (_style$baseColors = style.baseColors) === null || _style$baseColors === void 0 ? void 0 : _style$baseColors.color) && {
color: style === null || style === void 0 ? void 0 : (_style$baseColors2 = style.baseColors) === null || _style$baseColors2 === void 0 ? void 0 : (_style$baseColors2$co = _style$baseColors2.color) === null || _style$baseColors2$co === void 0 ? void 0 : _style$baseColors2$co.text
}];
const placeholderStyle = { ...usePreferredColorSchemeStyle(styles.plainTextPlaceholder, styles.plainTextPlaceholderDark),
...((style === null || style === void 0 ? void 0 : (_style$baseColors3 = style.baseColors) === null || _style$baseColors3 === void 0 ? void 0 : _style$baseColors3.color) && {
color: style === null || style === void 0 ? void 0 : (_style$baseColors4 = style.baseColors) === null || _style$baseColors4 === void 0 ? void 0 : (_style$baseColors4$co = _style$baseColors4.color) === null || _style$baseColors4$co === void 0 ? void 0 : _style$baseColors4$co.text
})
};
const searchBarStyle = [styles.searchBarContainer, isButtonInside && borderStyle, isLongButton && {
flexDirection: 'column'
}];
/**
* If a screenreader is enabled, create a descriptive label for this field. If
* not, return a label that is used during automated UI tests.
*
* @return {string} The accessibilityLabel for the Search Button
*/
const getAccessibilityLabelForButton = () => {
if (!isScreenReaderEnabled) {
return 'search-block-button';
}
return `${__('Search button. Current button text is')} ${buttonText}`;
};
/**
* If a screenreader is enabled, create a descriptive label for this field. If
* not, return a label that is used during automated UI tests.
*
* @return {string} The accessibilityLabel for the Search Input
* placeholder field.
*/
const getAccessibilityLabelForPlaceholder = () => {
if (!isScreenReaderEnabled) {
return 'search-block-input';
}
const title = __('Search input field.');
const description = placeholder ? `${__('Current placeholder text is')} ${placeholder}` : __('No custom placeholder set');
return `${title} ${description}`;
};
/**
* If a screenreader is enabled, create a descriptive label for this field. If
* not, return a label that is used during automated UI tests.
*
* @return {string} The accessibilityLabel for the Search Label field
*/
const getAccessibilityLabelForLabel = () => {
if (!isScreenReaderEnabled) {
return 'search-block-label';
}
return `${__('Search block label. Current text is')} ${label}`;
};
const renderTextField = () => {
return createElement(View, {
style: styles.searchInputContainer,
accessible: true,
accessibilityRole: "none",
accessibilityHint: isScreenReaderEnabled ? __('Double tap to edit placeholder text') : undefined,
accessibilityLabel: getAccessibilityLabelForPlaceholder()
}, createElement(PlainText, {
ref: textInputRef,
isSelected: isPlaceholderSelected,
className: "wp-block-search__input",
style: inputStyle,
numberOfLines: 1,
ellipsizeMode: "tail" // Currently only works on ios.
,
label: null,
value: placeholder,
placeholder: placeholder ? undefined : __('Optional placeholder…'),
onChange: newVal => setAttributes({
placeholder: newVal
}),
onFocus: () => {
setIsPlaceholderSelected(true);
onFocus();
},
onBlur: () => setIsPlaceholderSelected(false),
placeholderTextColor: placeholderStyle === null || placeholderStyle === void 0 ? void 0 : placeholderStyle.color
}));
}; // To achieve proper expanding and shrinking `RichText` on Android, there is a need to set
// a `placeholder` as an empty string when `RichText` is focused,
// because `AztecView` is calculating a `minWidth` based on placeholder text.
const buttonPlaceholderText = isButtonSelected || !isButtonSelected && buttonText && buttonText !== '' ? '' : __('Add button text');
const baseButtonStyles = { ...(style === null || style === void 0 ? void 0 : (_style$baseColors5 = style.baseColors) === null || _style$baseColors5 === void 0 ? void 0 : (_style$baseColors5$bl = _style$baseColors5.blocks) === null || _style$baseColors5$bl === void 0 ? void 0 : (_style$baseColors5$bl2 = _style$baseColors5$bl['core/button']) === null || _style$baseColors5$bl2 === void 0 ? void 0 : _style$baseColors5$bl2.color),
...(attributes === null || attributes === void 0 ? void 0 : (_attributes$style = attributes.style) === null || _attributes$style === void 0 ? void 0 : _attributes$style.color),
...((style === null || style === void 0 ? void 0 : style.color) && {
text: style.color
})
};
const richTextButtonContainerStyle = [styles.buttonContainer, isLongButton && styles.buttonContainerWide, (baseButtonStyles === null || baseButtonStyles === void 0 ? void 0 : baseButtonStyles.background) && {
backgroundColor: baseButtonStyles.background,
borderWidth: 0
}, (style === null || style === void 0 ? void 0 : style.backgroundColor) && {
backgroundColor: style.backgroundColor,
borderWidth: 0
}];
const richTextButtonStyle = { ...styles.richTextButton,
...((baseButtonStyles === null || baseButtonStyles === void 0 ? void 0 : baseButtonStyles.text) && {
color: baseButtonStyles.text,
placeholderColor: baseButtonStyles.text
})
};
const iconStyles = { ...styles.icon,
...((baseButtonStyles === null || baseButtonStyles === void 0 ? void 0 : baseButtonStyles.text) && {
fill: baseButtonStyles.text
})
};
const renderButton = () => {
var _styles$richTextButto;
return createElement(View, {
style: richTextButtonContainerStyle
}, buttonUseIcon && createElement(Icon, _extends({
icon: search
}, iconStyles, {
onLayout: onLayoutButton
})), !buttonUseIcon && createElement(View, {
accessible: true,
accessibilityRole: "none",
accessibilityHint: isScreenReaderEnabled ? __('Double tap to edit button text') : undefined,
accessibilityLabel: getAccessibilityLabelForButton(),
onLayout: onLayoutButton
}, createElement(RichText, {
className: "wp-block-search__button",
identifier: "text",
tagName: "p",
style: richTextButtonStyle,
placeholder: buttonPlaceholderText,
value: buttonText,
withoutInteractiveFormatting: true,
onChange: html => setAttributes({
buttonText: html
}),
minWidth: MIN_BUTTON_WIDTH,
maxWidth: blockWidth - MARGINS,
textAlign: "center",
isSelected: isButtonSelected,
__unstableMobileNoFocusOnMount: !isSelected,
unstableOnFocus: () => {
setIsButtonSelected(true);
},
onBlur: () => {
setIsButtonSelected(false);
},
selectionColor: (_styles$richTextButto = styles.richTextButtonCursor) === null || _styles$richTextButto === void 0 ? void 0 : _styles$richTextButto.color
})));
};
return createElement(View, _extends({}, blockProps, {
style: styles.searchBlockContainer,
importantForAccessibility: isSelected ? 'yes' : 'no-hide-descendants',
accessibilityElementsHidden: isSelected ? false : true
}), isSelected && controls, showLabel && createElement(View, {
accessible: true,
accessibilityRole: "none",
accessibilityHint: isScreenReaderEnabled ? __('Double tap to edit label text') : undefined,
accessibilityLabel: getAccessibilityLabelForLabel()
}, createElement(RichText, {
className: "wp-block-search__label",
identifier: "text",
tagName: "p",
style: styles.richTextLabel,
placeholder: __('Add label…'),
withoutInteractiveFormatting: true,
value: label,
onChange: html => setAttributes({
label: html
}),
isSelected: isLabelSelected,
__unstableMobileNoFocusOnMount: !isSelected,
unstableOnFocus: () => {
setIsLabelSelected(true);
},
onBlur: () => {
setIsLabelSelected(false);
},
selectionColor: (_styles$richTextButto2 = styles.richTextButtonCursor) === null || _styles$richTextButto2 === void 0 ? void 0 : _styles$richTextButto2.color
})), ('button-inside' === buttonPosition || 'button-outside' === buttonPosition) && createElement(View, {
style: searchBarStyle
}, renderTextField(), renderButton()), 'button-only' === buttonPosition && renderButton(), 'no-button' === buttonPosition && renderTextField());
}
//# sourceMappingURL=edit.native.js.map