UNPKG

@wordpress/components

Version:
205 lines (184 loc) 6.63 kB
import { createElement } from "@wordpress/element"; /** * External dependencies */ import { TextInput, Text, View, TouchableOpacity, Platform, useColorScheme, Keyboard } from 'react-native'; /** * WordPress dependencies */ import { useState, useRef, useMemo, useEffect } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { Button, Gridicons } from '@wordpress/components'; import { Icon, cancelCircleFilled as cancelCircleFilledIcon, arrowLeft as arrowLeftIcon, close as closeIcon } from '@wordpress/icons'; /** * Internal dependencies */ import allStyles from './style.scss'; import platformStyles from './platform-style.scss'; // Merge platform specific styles with the default styles. const baseStyles = { ...allStyles }; for (const selector in platformStyles) { baseStyles[selector] = { ...baseStyles[selector], ...platformStyles[selector] }; } function selectModifiedStyles(styles, modifier) { const modifierMatcher = new RegExp(`--${modifier}$`); const modifierSelectors = Object.keys(styles).filter(selector => selector.match(modifierMatcher)); return modifierSelectors.reduce((modifiedStyles, modifierSelector) => { const blockElementSelector = modifierSelector.split('--')[0]; modifiedStyles[blockElementSelector] = styles[modifierSelector]; return modifiedStyles; }, {}); } function mergeStyles(styles, updateStyles, selectors) { selectors.forEach(selector => { styles[selector] = { ...styles[selector], ...updateStyles[selector] }; }); return styles; } function SearchControl(_ref) { let { value, onChange, placeholder = __('Search blocks') } = _ref; const [isActive, setIsActive] = useState(false); const [currentStyles, setCurrentStyles] = useState(baseStyles); const isDark = useColorScheme() === 'dark'; const inputRef = useRef(); const onCancelTimer = useRef(); const isIOS = Platform.OS === 'ios'; const darkStyles = useMemo(() => { return selectModifiedStyles(baseStyles, 'dark'); }, []); const activeStyles = useMemo(() => { return selectModifiedStyles(baseStyles, 'active'); }, []); const activeDarkStyles = useMemo(() => { return selectModifiedStyles(baseStyles, 'active-dark'); }, []); useEffect(() => { let futureStyles = { ...baseStyles }; function mergeFutureStyles(modifiedStyles, shouldUseConditions) { const shouldUseModified = shouldUseConditions.every(should => should); const updatedStyles = shouldUseModified ? modifiedStyles : futureStyles; const selectors = Object.keys(modifiedStyles); futureStyles = mergeStyles(futureStyles, updatedStyles, selectors); } mergeFutureStyles(activeStyles, [isActive]); mergeFutureStyles(darkStyles, [isDark]); mergeFutureStyles(activeDarkStyles, [isActive, isDark]); setCurrentStyles(futureStyles); // Disable reason: deferring this refactor to the native team. // see https://github.com/WordPress/gutenberg/pull/41166 // eslint-disable-next-line react-hooks/exhaustive-deps }, [isActive, isDark]); useEffect(() => { const keyboardHideSubscription = Keyboard.addListener('keyboardDidHide', () => { if (!isIOS) { onCancel(); } }); return () => { clearTimeout(onCancelTimer.current); keyboardHideSubscription.remove(); }; // Disable reason: deferring this refactor to the native team. // see https://github.com/WordPress/gutenberg/pull/41166 // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const { 'search-control__container': containerStyle, 'search-control__inner-container': innerContainerStyle, 'search-control__input-container': inputContainerStyle, 'search-control__form-input': formInputStyle, 'search-control__form-input-placeholder': placeholderStyle, 'search-control__input-button': inputButtonStyle, 'search-control__input-button-left': inputButtonLeftStyle, 'search-control__input-button-right': inputButtonRightStyle, 'search-control__cancel-button': cancelButtonStyle, 'search-control__cancel-button-text': cancelButtonTextStyle, 'search-control__icon': iconStyle, 'search-control__right-icon': rightIconStyle } = currentStyles; function clearInput() { onChange(''); } function onCancel() { onCancelTimer.current = setTimeout(() => { inputRef.current.blur(); clearInput(); setIsActive(false); }, 0); } function renderLeftButton() { const button = !isIOS && isActive ? createElement(Button, { label: __('Cancel search'), icon: arrowLeftIcon, onClick: onCancel, style: iconStyle }) : createElement(Icon, { icon: Gridicons.search, fill: iconStyle === null || iconStyle === void 0 ? void 0 : iconStyle.color }); return createElement(View, { style: [inputButtonStyle, inputButtonLeftStyle] }, button); } function renderRightButton() { let button; // Add a View element to properly center the input placeholder via flexbox. if (isIOS && !isActive) { button = createElement(View, null); } if (!!value) { button = createElement(Button, { label: __('Clear search'), icon: isIOS ? cancelCircleFilledIcon : closeIcon, onClick: clearInput, style: [iconStyle, rightIconStyle] }); } return createElement(View, { style: [inputButtonStyle, inputButtonRightStyle] }, button); } function renderCancel() { if (!isIOS) { return null; } return createElement(View, { style: cancelButtonStyle }, createElement(Text, { onPress: onCancel, style: cancelButtonTextStyle, accessible: true, accessibilityRole: 'button', accessibilityLabel: __('Cancel search'), accessibilityHint: __('Cancel search') }, __('Cancel'))); } return createElement(TouchableOpacity, { style: containerStyle, onPress: () => { setIsActive(true); inputRef.current.focus(); }, activeOpacity: 1 }, createElement(View, { style: innerContainerStyle }, createElement(View, { style: inputContainerStyle }, renderLeftButton(), createElement(TextInput, { ref: inputRef, style: formInputStyle, placeholderTextColor: placeholderStyle === null || placeholderStyle === void 0 ? void 0 : placeholderStyle.color, onChangeText: onChange, onFocus: () => setIsActive(true), value: value, placeholder: placeholder }), renderRightButton()), isActive && renderCancel())); } export default SearchControl; //# sourceMappingURL=index.native.js.map