@wordpress/components
Version:
UI components for WordPress.
272 lines (271 loc) • 9.31 kB
JavaScript
/**
* External dependencies
*/
import { Platform } from 'react-native';
import Clipboard from '@react-native-clipboard/clipboard';
/**
* WordPress dependencies
*/
import { compose } from '@wordpress/compose';
import { withSelect } from '@wordpress/data';
import { isURL, prependHTTP } from '@wordpress/url';
import { useEffect, useState, useRef, useContext, useCallback } from '@wordpress/element';
import { link, external } from '@wordpress/icons';
/**
* Internal dependencies
*/
import BottomSheet from '../bottom-sheet';
import { BottomSheetContext } from '../bottom-sheet/bottom-sheet-context';
import PanelBody from '../../panel/body';
import TextControl from '../../text-control';
import ToggleControl from '../../toggle-control';
import FooterMessageControl from '../../footer-message-control';
import PanelActions from '../../panel/actions';
import LinkRelIcon from './link-rel';
import styles from './style.scss';
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
const NEW_TAB_REL = 'noreferrer noopener';
function LinkSettings({
// Control link settings `BottomSheet` visibility
isVisible,
// Callback that is called on closing bottom sheet
onClose,
// Function called to set attributes
setAttributes,
// Callback that is called when url input field is empty
onEmptyURL,
// Object of available options along with specific, customizable properties.
// Available options keys:
// * url - uses `TextControl` component to set `attributes.url`
// * linkLabel - uses `TextControl` component to set `attributes.label`
// * openInNewTab - uses `ToggleControl` component to set `attributes.linkTarget` and `attributes.rel`
// * linkRel - uses `TextControl` component to set `attributes.rel`
// * footer - uses `FooterMessageControl` component to display message, e.g. about missing functionality
// Available properties:
// * label - control component label, e.g. `Button Link URL`
// * placeholder - control component placeholder, e.g. `Add URL`
// * autoFocus (url only) - whether url input should be focused on sheet opening
// * autoFill (url only) - whether url input should be filled with url from clipboard
// Example:
// const options = {
// url: {
// label: __( 'Button Link URL' ),
// placeholder: __( 'Add URL' ),
// autoFocus: true,
// autoFill: true,
// }
// }
options,
// Specifies whether settings should be wrapped into `BottomSheet`
withBottomSheet,
// Defines buttons which will be displayed below the all options.
// It's an array of objects with following properties:
// * label - button title
// * onPress - callback that is called on pressing button
// Example:
// const actions = [
// {
// label: __( 'Remove link' ),
// onPress: () => setAttributes({ url: '' }),
// },
// ];
actions,
// Specifies whether general `BottomSheet` is opened
editorSidebarOpened,
// Specifies whether icon should be displayed next to the label
showIcon,
onLinkCellPressed,
urlValue,
// Attributes properties
url,
label = '',
linkTarget,
rel = ''
}) {
const [urlInputValue, setUrlInputValue] = useState('');
const [labelInputValue, setLabelInputValue] = useState('');
const [linkRelInputValue, setLinkRelInputValue] = useState('');
const onCloseSettingsSheetConsumed = useRef(false);
const prevEditorSidebarOpenedRef = useRef();
const {
onHandleClosingBottomSheet
} = useContext(BottomSheetContext);
useEffect(() => {
if (onHandleClosingBottomSheet) {
onHandleClosingBottomSheet(onCloseSettingsSheet);
}
// See https://github.com/WordPress/gutenberg/pull/41166
}, [urlInputValue, labelInputValue, linkRelInputValue]);
useEffect(() => {
prevEditorSidebarOpenedRef.current = editorSidebarOpened;
});
const prevEditorSidebarOpened = prevEditorSidebarOpenedRef.current;
useEffect(() => {
if (url !== urlInputValue) {
setUrlInputValue(url || '');
}
// See https://github.com/WordPress/gutenberg/pull/41166
}, [url]);
useEffect(() => {
setLabelInputValue(label || '');
}, [label]);
useEffect(() => {
setLinkRelInputValue(rel || '');
}, [rel]);
useEffect(() => {
const isSettingSheetOpen = isVisible || editorSidebarOpened;
if (isSettingSheetOpen) {
onCloseSettingsSheetConsumed.current = false;
}
if (options.url.autoFill && isSettingSheetOpen && !url) {
getURLFromClipboard();
}
if (prevEditorSidebarOpened && !editorSidebarOpened) {
onSetAttributes();
}
// See https://github.com/WordPress/gutenberg/pull/41166
}, [editorSidebarOpened, isVisible]);
useEffect(() => {
if (!urlValue && onEmptyURL) {
onEmptyURL();
}
if (prependHTTP(urlValue) !== url) {
setAttributes({
url: prependHTTP(urlValue)
});
}
// See https://github.com/WordPress/gutenberg/pull/41166
}, [urlValue]);
const onChangeURL = useCallback(value => {
if (!value && onEmptyURL) {
onEmptyURL();
}
setUrlInputValue(value);
}, [onEmptyURL]);
const onChangeLabel = useCallback(value => {
setLabelInputValue(value);
}, []);
const onSetAttributes = useCallback(() => {
const newURL = prependHTTP(urlInputValue);
if (url !== newURL || labelInputValue !== label || linkRelInputValue !== rel) {
setAttributes({
url: newURL,
label: labelInputValue,
rel: linkRelInputValue
});
}
// See https://github.com/WordPress/gutenberg/pull/41166
}, [urlInputValue, labelInputValue, linkRelInputValue, setAttributes]);
const onCloseSettingsSheet = useCallback(() => {
if (onCloseSettingsSheetConsumed.current) {
return;
}
onCloseSettingsSheetConsumed.current = true;
onSetAttributes();
if (onClose) {
onClose();
}
}, [onClose, onSetAttributes]);
const onChangeOpenInNewTab = useCallback(value => {
const newLinkTarget = value ? '_blank' : undefined;
let updatedRel = linkRelInputValue;
if (newLinkTarget && !linkRelInputValue) {
updatedRel = NEW_TAB_REL;
} else if (!newLinkTarget && linkRelInputValue === NEW_TAB_REL) {
updatedRel = undefined;
}
setAttributes({
linkTarget: newLinkTarget,
rel: updatedRel
});
},
// See https://github.com/WordPress/gutenberg/pull/41166
[linkRelInputValue]);
const onChangeLinkRel = useCallback(value => {
setLinkRelInputValue(value);
}, []);
async function getURLFromClipboard() {
const clipboardText = await Clipboard.getString();
if (!clipboardText) {
return;
}
// Check if pasted text is URL.
if (!isURL(clipboardText)) {
return;
}
setAttributes({
url: clipboardText
});
}
function getSettings() {
return /*#__PURE__*/_jsxs(_Fragment, {
children: [options.url && (onLinkCellPressed ? /*#__PURE__*/_jsx(BottomSheet.LinkCell, {
showIcon: showIcon,
value: url,
valueMask: options.url.valueMask,
onPress: onLinkCellPressed
}) : /*#__PURE__*/_jsx(TextControl, {
icon: showIcon && link,
label: options.url.label,
value: urlInputValue,
valuePlaceholder: options.url.placeholder,
onChange: onChangeURL,
onSubmit: onCloseSettingsSheet,
autoCapitalize: "none",
autoCorrect: false
// eslint-disable-next-line jsx-a11y/no-autofocus
,
autoFocus: Platform.OS === 'ios' && options.url.autoFocus,
keyboardType: "url"
})), options.linkLabel && /*#__PURE__*/_jsx(TextControl, {
label: options.linkLabel.label,
value: labelInputValue,
valuePlaceholder: options.linkLabel.placeholder,
onChange: onChangeLabel
}), !!urlInputValue && /*#__PURE__*/_jsxs(_Fragment, {
children: [options.openInNewTab && /*#__PURE__*/_jsx(ToggleControl, {
icon: showIcon && external,
label: options.openInNewTab.label,
checked: linkTarget === '_blank',
onChange: onChangeOpenInNewTab
}), options.linkRel && /*#__PURE__*/_jsx(TextControl, {
icon: showIcon && LinkRelIcon,
label: options.linkRel.label,
value: linkRelInputValue,
valuePlaceholder: options.linkRel.placeholder,
onChange: onChangeLinkRel,
onSubmit: onCloseSettingsSheet,
autoCapitalize: "none",
autoCorrect: false,
keyboardType: "default"
})]
})]
});
}
if (!withBottomSheet) {
return getSettings();
}
return /*#__PURE__*/_jsxs(_Fragment, {
children: [/*#__PURE__*/_jsx(PanelBody, {
style: styles.linkSettingsPanel,
children: getSettings()
}), options.footer && /*#__PURE__*/_jsx(PanelBody, {
style: styles.linkSettingsPanel,
children: /*#__PURE__*/_jsx(FooterMessageControl, {
label: options.footer.label,
separatorType: options.footer.separatorType
})
}), actions && /*#__PURE__*/_jsx(PanelActions, {
actions: actions
})]
});
}
export default compose([withSelect(select => {
const {
isEditorSidebarOpened
} = select('core/edit-post');
return {
editorSidebarOpened: isEditorSidebarOpened()
};
})])(LinkSettings);
//# sourceMappingURL=index.native.js.map