@wordpress/block-editor
Version:
270 lines (240 loc) • 8.93 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.__experimentalImageURLInputUI = void 0;
var _element = require("@wordpress/element");
var _i18n = require("@wordpress/i18n");
var _components = require("@wordpress/components");
var _icons = require("@wordpress/icons");
var _index = _interopRequireDefault(require("./index"));
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
const LINK_DESTINATION_NONE = 'none';
const LINK_DESTINATION_CUSTOM = 'custom';
const LINK_DESTINATION_MEDIA = 'media';
const LINK_DESTINATION_ATTACHMENT = 'attachment';
const NEW_TAB_REL = ['noreferrer', 'noopener'];
const icon = (0, _element.createElement)(_components.SVG, {
viewBox: "0 0 24 24",
xmlns: "http://www.w3.org/2000/svg"
}, (0, _element.createElement)(_components.Path, {
d: "M0,0h24v24H0V0z",
fill: "none"
}), (0, _element.createElement)(_components.Path, {
d: "m19 5v14h-14v-14h14m0-2h-14c-1.1 0-2 0.9-2 2v14c0 1.1 0.9 2 2 2h14c1.1 0 2-0.9 2-2v-14c0-1.1-0.9-2-2-2z"
}), (0, _element.createElement)(_components.Path, {
d: "m14.14 11.86l-3 3.87-2.14-2.59-3 3.86h12l-3.86-5.14z"
}));
const ImageURLInputUI = ({
linkDestination,
onChangeUrl,
url,
mediaType = 'image',
mediaUrl,
mediaLink,
linkTarget,
linkClass,
rel
}) => {
const [isOpen, setIsOpen] = (0, _element.useState)(false); // Use internal state instead of a ref to make sure that the component
// re-renders when the popover's anchor updates.
const [popoverAnchor, setPopoverAnchor] = (0, _element.useState)(null);
const openLinkUI = (0, _element.useCallback)(() => {
setIsOpen(true);
});
const [isEditingLink, setIsEditingLink] = (0, _element.useState)(false);
const [urlInput, setUrlInput] = (0, _element.useState)(null);
const autocompleteRef = (0, _element.useRef)(null);
const startEditLink = (0, _element.useCallback)(() => {
if (linkDestination === LINK_DESTINATION_MEDIA || linkDestination === LINK_DESTINATION_ATTACHMENT) {
setUrlInput('');
}
setIsEditingLink(true);
});
const stopEditLink = (0, _element.useCallback)(() => {
setIsEditingLink(false);
});
const closeLinkUI = (0, _element.useCallback)(() => {
setUrlInput(null);
stopEditLink();
setIsOpen(false);
});
const getUpdatedLinkTargetSettings = value => {
const newLinkTarget = value ? '_blank' : undefined;
let updatedRel;
if (newLinkTarget) {
const rels = (rel !== null && rel !== void 0 ? rel : '').split(' ');
NEW_TAB_REL.forEach(relVal => {
if (!rels.includes(relVal)) {
rels.push(relVal);
}
});
updatedRel = rels.join(' ');
} else {
const rels = (rel !== null && rel !== void 0 ? rel : '').split(' ').filter(relVal => NEW_TAB_REL.includes(relVal) === false);
updatedRel = rels.length ? rels.join(' ') : undefined;
}
return {
linkTarget: newLinkTarget,
rel: updatedRel
};
};
const onFocusOutside = (0, _element.useCallback)(() => {
return event => {
// The autocomplete suggestions list renders in a separate popover (in a portal),
// so onFocusOutside fails to detect that a click on a suggestion occurred in the
// LinkContainer. Detect clicks on autocomplete suggestions using a ref here, and
// return to avoid the popover being closed.
const autocompleteElement = autocompleteRef.current;
if (autocompleteElement && autocompleteElement.contains(event.target)) {
return;
}
setIsOpen(false);
setUrlInput(null);
stopEditLink();
};
});
const onSubmitLinkChange = (0, _element.useCallback)(() => {
return event => {
if (urlInput) {
// It is possible the entered URL actually matches a named link destination.
// This check will ensure our link destination is correct.
const selectedDestination = getLinkDestinations().find(destination => destination.url === urlInput)?.linkDestination || LINK_DESTINATION_CUSTOM;
onChangeUrl({
href: urlInput,
linkDestination: selectedDestination
});
}
stopEditLink();
setUrlInput(null);
event.preventDefault();
};
});
const onLinkRemove = (0, _element.useCallback)(() => {
onChangeUrl({
linkDestination: LINK_DESTINATION_NONE,
href: ''
});
});
const getLinkDestinations = () => {
const linkDestinations = [{
linkDestination: LINK_DESTINATION_MEDIA,
title: (0, _i18n.__)('Media File'),
url: mediaType === 'image' ? mediaUrl : undefined,
icon
}];
if (mediaType === 'image' && mediaLink) {
linkDestinations.push({
linkDestination: LINK_DESTINATION_ATTACHMENT,
title: (0, _i18n.__)('Attachment Page'),
url: mediaType === 'image' ? mediaLink : undefined,
icon: (0, _element.createElement)(_components.SVG, {
viewBox: "0 0 24 24",
xmlns: "http://www.w3.org/2000/svg"
}, (0, _element.createElement)(_components.Path, {
d: "M0 0h24v24H0V0z",
fill: "none"
}), (0, _element.createElement)(_components.Path, {
d: "M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zM6 20V4h7v5h5v11H6z"
}))
});
}
return linkDestinations;
};
const onSetHref = value => {
const linkDestinations = getLinkDestinations();
let linkDestinationInput;
if (!value) {
linkDestinationInput = LINK_DESTINATION_NONE;
} else {
linkDestinationInput = (linkDestinations.find(destination => {
return destination.url === value;
}) || {
linkDestination: LINK_DESTINATION_CUSTOM
}).linkDestination;
}
onChangeUrl({
linkDestination: linkDestinationInput,
href: value
});
};
const onSetNewTab = value => {
const updatedLinkTarget = getUpdatedLinkTargetSettings(value);
onChangeUrl(updatedLinkTarget);
};
const onSetLinkRel = value => {
onChangeUrl({
rel: value
});
};
const onSetLinkClass = value => {
onChangeUrl({
linkClass: value
});
};
const advancedOptions = (0, _element.createElement)(_components.__experimentalVStack, {
spacing: "3"
}, (0, _element.createElement)(_components.ToggleControl, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Open in new tab'),
onChange: onSetNewTab,
checked: linkTarget === '_blank'
}), (0, _element.createElement)(_components.TextControl, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Link rel'),
value: rel !== null && rel !== void 0 ? rel : '',
onChange: onSetLinkRel
}), (0, _element.createElement)(_components.TextControl, {
__nextHasNoMarginBottom: true,
label: (0, _i18n.__)('Link CSS Class'),
value: linkClass || '',
onChange: onSetLinkClass
}));
const linkEditorValue = urlInput !== null ? urlInput : url;
const urlLabel = (getLinkDestinations().find(destination => destination.linkDestination === linkDestination) || {}).title;
return (0, _element.createElement)(_element.Fragment, null, (0, _element.createElement)(_components.ToolbarButton, {
icon: _icons.link,
className: "components-toolbar__control",
label: url ? (0, _i18n.__)('Edit link') : (0, _i18n.__)('Insert link'),
"aria-expanded": isOpen,
onClick: openLinkUI,
ref: setPopoverAnchor
}), isOpen && (0, _element.createElement)(_index.default, {
anchor: popoverAnchor,
onFocusOutside: onFocusOutside(),
onClose: closeLinkUI,
renderSettings: () => advancedOptions,
additionalControls: !linkEditorValue && (0, _element.createElement)(_components.NavigableMenu, null, getLinkDestinations().map(link => (0, _element.createElement)(_components.MenuItem, {
key: link.linkDestination,
icon: link.icon,
onClick: () => {
setUrlInput(null);
onSetHref(link.url);
stopEditLink();
}
}, link.title)))
}, (!url || isEditingLink) && (0, _element.createElement)(_index.default.LinkEditor, {
className: "block-editor-format-toolbar__link-container-content",
value: linkEditorValue,
onChangeInputValue: setUrlInput,
onSubmit: onSubmitLinkChange(),
autocompleteRef: autocompleteRef
}), url && !isEditingLink && (0, _element.createElement)(_element.Fragment, null, (0, _element.createElement)(_index.default.LinkViewer, {
className: "block-editor-format-toolbar__link-container-content",
url: url,
onEditLinkClick: startEditLink,
urlLabel: urlLabel
}), (0, _element.createElement)(_components.Button, {
icon: _icons.close,
label: (0, _i18n.__)('Remove link'),
onClick: onLinkRemove
}))));
};
exports.__experimentalImageURLInputUI = ImageURLInputUI;
//# sourceMappingURL=image-url-input-ui.js.map