@wordpress/block-library
Version:
Block library for the WordPress editor.
360 lines (350 loc) • 13.7 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = SearchEdit;
var _reactNative = require("react-native");
var _clsx = _interopRequireDefault(require("clsx"));
var _blockEditor = require("@wordpress/block-editor");
var _components = require("@wordpress/components");
var _i18n = require("@wordpress/i18n");
var _icons = require("@wordpress/icons");
var _element = require("@wordpress/element");
var _compose = require("@wordpress/compose");
var _style = _interopRequireDefault(require("./style.scss"));
var _jsxRuntime = require("react/jsx-runtime");
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
/**
* Constants
*/const MIN_BUTTON_WIDTH = 75;
const MARGINS = _style.default.widthMargin?.marginLeft + _style.default.widthMargin?.paddingLeft;
const BUTTON_OPTIONS = [{
value: 'button-inside',
label: (0, _i18n.__)('Button inside')
}, {
value: 'button-outside',
label: (0, _i18n.__)('Button outside')
}, {
value: 'no-button',
label: (0, _i18n.__)('No button')
}];
function useIsScreenReaderEnabled() {
const [isScreenReaderEnabled, setIsScreenReaderEnabled] = (0, _element.useState)(false);
(0, _element.useEffect)(() => {
let mounted = true;
const changeListener = _reactNative.AccessibilityInfo.addEventListener('screenReaderChanged', enabled => setIsScreenReaderEnabled(enabled));
_reactNative.AccessibilityInfo.isScreenReaderEnabled().then(screenReaderEnabled => {
if (mounted && screenReaderEnabled) {
setIsScreenReaderEnabled(screenReaderEnabled);
}
});
return () => {
mounted = false;
changeListener.remove();
};
}, []);
return isScreenReaderEnabled;
}
function SearchEdit({
onFocus,
isSelected,
attributes,
setAttributes,
className,
blockWidth,
style
}) {
const [isButtonSelected, setIsButtonSelected] = (0, _element.useState)(false);
const [isLabelSelected, setIsLabelSelected] = (0, _element.useState)(false);
const [isPlaceholderSelected, setIsPlaceholderSelected] = (0, _element.useState)(false);
const [isLongButton, setIsLongButton] = (0, _element.useState)(false);
const [buttonWidth, setButtonWidth] = (0, _element.useState)(MIN_BUTTON_WIDTH);
const isScreenReaderEnabled = useIsScreenReaderEnabled();
const textInputRef = (0, _element.useRef)(null);
const {
label,
showLabel,
buttonPosition,
buttonUseIcon,
placeholder,
buttonText
} = attributes;
/*
* Called when the value of isSelected changes. Blurs the PlainText component
* used by the placeholder when this block loses focus.
*/
(0, _element.useEffect)(() => {
if (hasTextInput() && isPlaceholderSelected && !isSelected) {
textInputRef.current.blur();
}
}, [isSelected]);
(0, _element.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 = ({
nativeEvent
}) => {
const {
width
} = nativeEvent?.layout;
if (width) {
setButtonWidth(width);
}
};
const getBlockClassNames = () => {
return (0, _clsx.default)(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 (0, _i18n.__)('Inside');
case 'button-outside':
return (0, _i18n.__)('Outside');
case 'no-button':
return (0, _i18n.__)('No button');
}
};
const blockProps = (0, _blockEditor.useBlockProps)({
className: getBlockClassNames()
});
const controls = /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, {
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.PanelBody, {
title: (0, _i18n.__)('Search settings'),
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
label: (0, _i18n.__)('Hide search heading'),
checked: !showLabel,
onChange: () => {
setAttributes({
showLabel: !showLabel
});
}
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.SelectControl, {
label: (0, _i18n.__)('Button position'),
value: getSelectedButtonPositionLabel(buttonPosition),
onChange: position => {
setAttributes({
buttonPosition: position
});
},
options: BUTTON_OPTIONS,
hideCancelButton: true
}), buttonPosition !== 'no-button' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToggleControl, {
label: (0, _i18n.__)('Use icon button'),
checked: buttonUseIcon,
onChange: () => {
setAttributes({
buttonUseIcon: !buttonUseIcon
});
}
})]
})
});
const isButtonInside = buttonPosition === 'button-inside';
const borderStyle = (0, _compose.usePreferredColorSchemeStyle)(_style.default.border, _style.default.borderDark);
const inputStyle = [!isButtonInside && borderStyle, (0, _compose.usePreferredColorSchemeStyle)(_style.default.plainTextInput, _style.default.plainTextInputDark), style?.baseColors?.color && {
color: style?.baseColors?.color?.text
}];
const placeholderStyle = {
...(0, _compose.usePreferredColorSchemeStyle)(_style.default.plainTextPlaceholder, _style.default.plainTextPlaceholderDark),
...(style?.baseColors?.color && {
color: style?.baseColors?.color?.text
})
};
const searchBarStyle = [_style.default.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 `${(0, _i18n.__)('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 = (0, _i18n.__)('Search input field.');
const description = placeholder ? `${(0, _i18n.__)('Current placeholder text is')} ${placeholder}` : (0, _i18n.__)('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 `${(0, _i18n.__)('Search block label. Current text is')} ${label}`;
};
const renderTextField = () => {
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: _style.default.searchInputContainer,
accessible: true,
accessibilityRole: "none",
accessibilityHint: isScreenReaderEnabled ? (0, _i18n.__)('Double tap to edit placeholder text') : undefined,
accessibilityLabel: getAccessibilityLabelForPlaceholder(),
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.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 : (0, _i18n.__)('Optional placeholder…'),
onChange: newVal => setAttributes({
placeholder: newVal
}),
onFocus: () => {
setIsPlaceholderSelected(true);
onFocus();
},
onBlur: () => setIsPlaceholderSelected(false),
placeholderTextColor: 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 !== '' ? '' : (0, _i18n.__)('Add button text');
const baseButtonStyles = {
...style?.baseColors?.blocks?.['core/button']?.color,
...attributes?.style?.color,
...(style?.color && {
text: style.color
})
};
const richTextButtonContainerStyle = [_style.default.buttonContainer, isLongButton && _style.default.buttonContainerWide, baseButtonStyles?.background && {
backgroundColor: baseButtonStyles.background,
borderWidth: 0
}, style?.backgroundColor && {
backgroundColor: style.backgroundColor,
borderWidth: 0
}];
const richTextButtonStyle = {
..._style.default.richTextButton,
...(baseButtonStyles?.text && {
color: baseButtonStyles.text,
placeholderColor: baseButtonStyles.text
})
};
const iconStyles = {
..._style.default.icon,
...(baseButtonStyles?.text && {
fill: baseButtonStyles.text
})
};
const renderButton = () => {
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
style: richTextButtonContainerStyle,
children: [buttonUseIcon && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Icon, {
icon: _icons.search,
...iconStyles,
onLayout: onLayoutButton
}), !buttonUseIcon && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
accessible: true,
accessibilityRole: "none",
accessibilityHint: isScreenReaderEnabled ? (0, _i18n.__)('Double tap to edit button text') : undefined,
accessibilityLabel: getAccessibilityLabelForButton(),
onLayout: onLayoutButton,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.RichText, {
className: "wp-block-search__button",
identifier: "buttonText",
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: _style.default.richTextButtonCursor?.color
})
})]
});
};
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
...blockProps,
style: _style.default.searchBlockContainer,
importantForAccessibility: isSelected ? 'yes' : 'no-hide-descendants',
accessibilityElementsHidden: isSelected ? false : true,
children: [isSelected && controls, showLabel && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
accessible: true,
accessibilityRole: "none",
accessibilityHint: isScreenReaderEnabled ? (0, _i18n.__)('Double tap to edit label text') : undefined,
accessibilityLabel: getAccessibilityLabelForLabel(),
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.RichText, {
className: "wp-block-search__label",
identifier: "label",
tagName: "p",
style: _style.default.richTextLabel,
placeholder: (0, _i18n.__)('Add label…'),
withoutInteractiveFormatting: true,
value: label,
onChange: html => setAttributes({
label: html
}),
isSelected: isLabelSelected,
__unstableMobileNoFocusOnMount: !isSelected,
unstableOnFocus: () => {
setIsLabelSelected(true);
},
onBlur: () => {
setIsLabelSelected(false);
},
selectionColor: _style.default.richTextButtonCursor?.color
})
}), ('button-inside' === buttonPosition || 'button-outside' === buttonPosition) && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
style: searchBarStyle,
children: [renderTextField(), renderButton()]
}), 'button-only' === buttonPosition && renderButton(), 'no-button' === buttonPosition && renderTextField()]
});
}
//# sourceMappingURL=edit.native.js.map
;