UNPKG

@wordpress/block-library

Version:
377 lines (371 loc) 13.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _clsx = _interopRequireDefault(require("clsx")); var _constants = require("./constants"); var _getUpdatedLinkAttributes = require("./get-updated-link-attributes"); var _removeAnchorTag = _interopRequireDefault(require("../utils/remove-anchor-tag")); var _hooks = require("../utils/hooks"); var _lockUnlock = require("../lock-unlock"); var _i18n = require("@wordpress/i18n"); var _element = require("@wordpress/element"); var _components = require("@wordpress/components"); var _blockEditor = require("@wordpress/block-editor"); var _keycodes = require("@wordpress/keycodes"); var _icons = require("@wordpress/icons"); var _blocks = require("@wordpress/blocks"); var _compose = require("@wordpress/compose"); var _data = require("@wordpress/data"); var _jsxRuntime = require("react/jsx-runtime"); /** * External dependencies */ /** * Internal dependencies */ /** * WordPress dependencies */ const { HTMLElementControl } = (0, _lockUnlock.unlock)(_blockEditor.privateApis); const LINK_SETTINGS = [..._blockEditor.LinkControl.DEFAULT_LINK_SETTINGS, { id: 'nofollow', title: (0, _i18n.__)('Mark as nofollow') }]; function useEnter(props) { const { replaceBlocks, selectionChange } = (0, _data.useDispatch)(_blockEditor.store); const { getBlock, getBlockRootClientId, getBlockIndex } = (0, _data.useSelect)(_blockEditor.store); const propsRef = (0, _element.useRef)(props); propsRef.current = props; return (0, _compose.useRefEffect)(element => { function onKeyDown(event) { if (event.defaultPrevented || event.keyCode !== _keycodes.ENTER) { return; } const { content, clientId } = propsRef.current; if (content.length) { return; } event.preventDefault(); const topParentListBlock = getBlock(getBlockRootClientId(clientId)); const blockIndex = getBlockIndex(clientId); const head = (0, _blocks.cloneBlock)({ ...topParentListBlock, innerBlocks: topParentListBlock.innerBlocks.slice(0, blockIndex) }); const middle = (0, _blocks.createBlock)((0, _blocks.getDefaultBlockName)()); const after = topParentListBlock.innerBlocks.slice(blockIndex + 1); const tail = after.length ? [(0, _blocks.cloneBlock)({ ...topParentListBlock, innerBlocks: after })] : []; replaceBlocks(topParentListBlock.clientId, [head, middle, ...tail], 1); // We manually change the selection here because we are replacing // a different block than the selected one. selectionChange(middle.clientId); } element.addEventListener('keydown', onKeyDown); return () => { element.removeEventListener('keydown', onKeyDown); }; }, []); } function WidthPanel({ selectedWidth, setAttributes }) { const dropdownMenuProps = (0, _hooks.useToolsPanelDropdownMenuProps)(); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanel, { label: (0, _i18n.__)('Settings'), resetAll: () => setAttributes({ width: undefined }), dropdownMenuProps: dropdownMenuProps, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { label: (0, _i18n.__)('Width'), isShownByDefault: true, hasValue: () => !!selectedWidth, onDeselect: () => setAttributes({ width: undefined }), __nextHasNoMarginBottom: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToggleGroupControl, { label: (0, _i18n.__)('Width'), value: selectedWidth, onChange: newWidth => setAttributes({ width: newWidth }), isBlock: true, __next40pxDefaultSize: true, __nextHasNoMarginBottom: true, children: [25, 50, 75, 100].map(widthValue => { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToggleGroupControlOption, { value: widthValue, label: (0, _i18n.sprintf)(/* translators: Percentage value. */ (0, _i18n.__)('%d%%'), widthValue) }, widthValue); }) }) }) }); } function ButtonEdit(props) { const { attributes, setAttributes, className, isSelected, onReplace, mergeBlocks, clientId, context } = props; const { tagName, textAlign, linkTarget, placeholder, rel, style, text, url, width, metadata } = attributes; const TagName = tagName || 'a'; function onKeyDown(event) { if (_keycodes.isKeyboardEvent.primary(event, 'k')) { startEditing(event); } else if (_keycodes.isKeyboardEvent.primaryShift(event, 'k')) { unlink(); richTextRef.current?.focus(); } } // 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 borderProps = (0, _blockEditor.__experimentalUseBorderProps)(attributes); const colorProps = (0, _blockEditor.__experimentalUseColorProps)(attributes); const spacingProps = (0, _blockEditor.__experimentalGetSpacingClassesAndStyles)(attributes); const shadowProps = (0, _blockEditor.__experimentalGetShadowClassesAndStyles)(attributes); const ref = (0, _element.useRef)(); const richTextRef = (0, _element.useRef)(); const blockProps = (0, _blockEditor.useBlockProps)({ ref: (0, _compose.useMergeRefs)([setPopoverAnchor, ref]), onKeyDown }); const blockEditingMode = (0, _blockEditor.useBlockEditingMode)(); const [isEditingURL, setIsEditingURL] = (0, _element.useState)(false); const isURLSet = !!url; const opensInNewTab = linkTarget === _constants.NEW_TAB_TARGET; const nofollow = !!rel?.includes(_constants.NOFOLLOW_REL); const isLinkTag = 'a' === TagName; const { createPageEntity, userCanCreatePages, lockUrlControls = false } = (0, _data.useSelect)(select => { if (!isSelected) { return {}; } const _settings = select(_blockEditor.store).getSettings(); const blockBindingsSource = (0, _blocks.getBlockBindingsSource)(metadata?.bindings?.url?.source); return { createPageEntity: _settings.__experimentalCreatePageEntity, userCanCreatePages: _settings.__experimentalUserCanCreatePages, lockUrlControls: !!metadata?.bindings?.url && !blockBindingsSource?.canUserEditValue?.({ select, context, args: metadata?.bindings?.url?.args }) }; }, [context, isSelected, metadata?.bindings?.url]); async function handleCreate(pageTitle) { const page = await createPageEntity({ title: pageTitle, status: 'draft' }); return { id: page.id, type: page.type, title: page.title.rendered, url: page.link, kind: 'post-type' }; } function createButtonText(searchTerm) { return (0, _element.createInterpolateElement)((0, _i18n.sprintf)(/* translators: %s: search term. */ (0, _i18n.__)('Create page: <mark>%s</mark>'), searchTerm), { mark: /*#__PURE__*/(0, _jsxRuntime.jsx)("mark", {}) }); } function startEditing(event) { event.preventDefault(); setIsEditingURL(true); } function unlink() { setAttributes({ url: undefined, linkTarget: undefined, rel: undefined }); setIsEditingURL(false); } (0, _element.useEffect)(() => { if (!isSelected) { setIsEditingURL(false); } }, [isSelected]); // Memoize link value to avoid overriding the LinkControl's internal state. // This is a temporary fix. See https://github.com/WordPress/gutenberg/issues/51256. const linkValue = (0, _element.useMemo)(() => ({ url, opensInNewTab, nofollow }), [url, opensInNewTab, nofollow]); const useEnterRef = useEnter({ content: text, clientId }); const mergedRef = (0, _compose.useMergeRefs)([useEnterRef, richTextRef]); const [fluidTypographySettings, layout] = (0, _blockEditor.useSettings)('typography.fluid', 'layout'); const typographyProps = (0, _blockEditor.getTypographyClassesAndStyles)(attributes, { typography: { fluid: fluidTypographySettings }, layout: { wideSize: layout?.wideSize } }); const hasNonContentControls = blockEditingMode === 'default'; const hasBlockControls = hasNonContentControls || isLinkTag && !lockUrlControls; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", { ...blockProps, className: (0, _clsx.default)(blockProps.className, { [`has-custom-width wp-block-button__width-${width}`]: width }), children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.RichText, { ref: mergedRef, "aria-label": (0, _i18n.__)('Button text'), placeholder: placeholder || (0, _i18n.__)('Add text…'), value: text, onChange: value => setAttributes({ text: (0, _removeAnchorTag.default)(value) }), withoutInteractiveFormatting: true, className: (0, _clsx.default)(className, 'wp-block-button__link', colorProps.className, borderProps.className, typographyProps.className, { [`has-text-align-${textAlign}`]: textAlign, // For backwards compatibility add style that isn't // provided via block support. 'no-border-radius': style?.border?.radius === 0, [`has-custom-font-size`]: blockProps.style.fontSize }, (0, _blockEditor.__experimentalGetElementClassName)('button')), style: { ...borderProps.style, ...colorProps.style, ...spacingProps.style, ...shadowProps.style, ...typographyProps.style, writingMode: undefined }, onReplace: onReplace, onMerge: mergeBlocks, identifier: "text" }) }), hasBlockControls && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_blockEditor.BlockControls, { group: "block", children: [hasNonContentControls && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.AlignmentControl, { value: textAlign, onChange: nextAlign => { setAttributes({ textAlign: nextAlign }); } }), isLinkTag && !lockUrlControls && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarButton, { name: "link", icon: !isURLSet ? _icons.link : _icons.linkOff, title: !isURLSet ? (0, _i18n.__)('Link') : (0, _i18n.__)('Unlink'), shortcut: !isURLSet ? _keycodes.displayShortcut.primary('k') : _keycodes.displayShortcut.primaryShift('k'), onClick: !isURLSet ? startEditing : unlink, isActive: isURLSet })] }), isLinkTag && isSelected && (isEditingURL || isURLSet) && !lockUrlControls && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Popover, { placement: "bottom", onClose: () => { setIsEditingURL(false); richTextRef.current?.focus(); }, anchor: popoverAnchor, focusOnMount: isEditingURL ? 'firstElement' : false, __unstableSlotName: "__unstable-block-tools-after", shift: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.LinkControl, { value: linkValue, onChange: ({ url: newURL, opensInNewTab: newOpensInNewTab, nofollow: newNofollow }) => setAttributes((0, _getUpdatedLinkAttributes.getUpdatedLinkAttributes)({ rel, url: newURL, opensInNewTab: newOpensInNewTab, nofollow: newNofollow })), onRemove: () => { unlink(); richTextRef.current?.focus(); }, forceIsEditingLink: isEditingURL, settings: LINK_SETTINGS, createSuggestion: createPageEntity && handleCreate, withCreateSuggestion: userCanCreatePages, createSuggestionButtonText: createButtonText }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(WidthPanel, { selectedWidth: width, setAttributes: setAttributes }) }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_blockEditor.InspectorControls, { group: "advanced", children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(HTMLElementControl, { tagName: tagName, onChange: value => setAttributes({ tagName: value }), options: [{ label: (0, _i18n.__)('Default (<a>)'), value: 'a' }, { label: '<button>', value: 'button' }] }), isLinkTag && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.TextControl, { __next40pxDefaultSize: true, __nextHasNoMarginBottom: true, label: (0, _i18n.__)('Link rel'), value: rel || '', onChange: newRel => setAttributes({ rel: newRel }) })] })] }); } var _default = exports.default = ButtonEdit; //# sourceMappingURL=edit.js.map