UNPKG

@wordpress/block-editor

Version:
265 lines (252 loc) 8.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.canBindAttribute = canBindAttribute; exports.canBindBlock = canBindBlock; exports.getBindableAttributes = getBindableAttributes; exports.hasPatternOverridesDefaultBinding = hasPatternOverridesDefaultBinding; exports.replacePatternOverridesDefaultBinding = replacePatternOverridesDefaultBinding; exports.useBlockBindingsUtils = useBlockBindingsUtils; var _data = require("@wordpress/data"); var _store = require("../store"); var _blockEdit = require("../components/block-edit"); /** * WordPress dependencies */ /** * Internal dependencies */ const DEFAULT_ATTRIBUTE = '__default'; const PATTERN_OVERRIDES_SOURCE = 'core/pattern-overrides'; const BLOCK_BINDINGS_ALLOWED_BLOCKS = { 'core/paragraph': ['content'], 'core/heading': ['content'], 'core/image': ['id', 'url', 'title', 'alt'], 'core/button': ['url', 'text', 'linkTarget', 'rel'] }; /** * Checks if the given object is empty. * * @param {?Object} object The object to check. * * @return {boolean} Whether the object is empty. */ function isObjectEmpty(object) { return !object || Object.keys(object).length === 0; } /** * Based on the given block name, checks if it is possible to bind the block. * * @param {string} blockName The name of the block. * * @return {boolean} Whether it is possible to bind the block to sources. */ function canBindBlock(blockName) { return blockName in BLOCK_BINDINGS_ALLOWED_BLOCKS; } /** * Based on the given block name and attribute name, checks if it is possible to bind the block attribute. * * @param {string} blockName The name of the block. * @param {string} attributeName The name of attribute. * * @return {boolean} Whether it is possible to bind the block attribute. */ function canBindAttribute(blockName, attributeName) { return canBindBlock(blockName) && BLOCK_BINDINGS_ALLOWED_BLOCKS[blockName].includes(attributeName); } /** * Gets the bindable attributes for a given block. * * @param {string} blockName The name of the block. * * @return {string[]} The bindable attributes for the block. */ function getBindableAttributes(blockName) { return BLOCK_BINDINGS_ALLOWED_BLOCKS[blockName]; } /** * Checks if the block has the `__default` binding for pattern overrides. * * @param {?Record<string, object>} bindings A block's bindings from the metadata attribute. * * @return {boolean} Whether the block has the `__default` binding for pattern overrides. */ function hasPatternOverridesDefaultBinding(bindings) { return bindings?.[DEFAULT_ATTRIBUTE]?.source === PATTERN_OVERRIDES_SOURCE; } /** * Returns the bindings with the `__default` binding for pattern overrides * replaced with the full-set of supported attributes. e.g.: * * - bindings passed in: `{ __default: { source: 'core/pattern-overrides' } }` * - bindings returned: `{ content: { source: 'core/pattern-overrides' } }` * * @param {string} blockName The block name (e.g. 'core/paragraph'). * @param {?Record<string, object>} bindings A block's bindings from the metadata attribute. * * @return {Object} The bindings with default replaced for pattern overrides. */ function replacePatternOverridesDefaultBinding(blockName, bindings) { // The `__default` binding currently only works for pattern overrides. if (hasPatternOverridesDefaultBinding(bindings)) { const supportedAttributes = BLOCK_BINDINGS_ALLOWED_BLOCKS[blockName]; const bindingsWithDefaults = {}; for (const attributeName of supportedAttributes) { // If the block has mixed binding sources, retain any non pattern override bindings. const bindingSource = bindings[attributeName] ? bindings[attributeName] : { source: PATTERN_OVERRIDES_SOURCE }; bindingsWithDefaults[attributeName] = bindingSource; } return bindingsWithDefaults; } return bindings; } /** * Contains utils to update the block `bindings` metadata. * * @typedef {Object} WPBlockBindingsUtils * * @property {Function} updateBlockBindings Updates the value of the bindings connected to block attributes. * @property {Function} removeAllBlockBindings Removes the bindings property of the `metadata` attribute. */ /** * Retrieves the existing utils needed to update the block `bindings` metadata. * They can be used to create, modify, or remove connections from the existing block attributes. * * It contains the following utils: * - `updateBlockBindings`: Updates the value of the bindings connected to block attributes. It can be used to remove a specific binding by setting the value to `undefined`. * - `removeAllBlockBindings`: Removes the bindings property of the `metadata` attribute. * * @since 6.7.0 Introduced in WordPress core. * * @param {?string} clientId Optional block client ID. If not set, it will use the current block client ID from the context. * * @return {?WPBlockBindingsUtils} Object containing the block bindings utils. * * @example * ```js * import { useBlockBindingsUtils } from '@wordpress/block-editor' * const { updateBlockBindings, removeAllBlockBindings } = useBlockBindingsUtils(); * * // Update url and alt attributes. * updateBlockBindings( { * url: { * source: 'core/post-meta', * args: { * key: 'url_custom_field', * }, * }, * alt: { * source: 'core/post-meta', * args: { * key: 'text_custom_field', * }, * }, * } ); * * // Remove binding from url attribute. * updateBlockBindings( { url: undefined } ); * * // Remove bindings from all attributes. * removeAllBlockBindings(); * ``` */ function useBlockBindingsUtils(clientId) { const { clientId: contextClientId } = (0, _blockEdit.useBlockEditContext)(); const blockClientId = clientId || contextClientId; const { updateBlockAttributes } = (0, _data.useDispatch)(_store.store); const { getBlockAttributes } = (0, _data.useRegistry)().select(_store.store); /** * Updates the value of the bindings connected to block attributes. * It removes the binding when the new value is `undefined`. * * @param {Object} bindings Bindings including the attributes to update and the new object. * @param {string} bindings.source The source name to connect to. * @param {Object} [bindings.args] Object containing the arguments needed by the source. * * @example * ```js * import { useBlockBindingsUtils } from '@wordpress/block-editor' * * const { updateBlockBindings } = useBlockBindingsUtils(); * updateBlockBindings( { * url: { * source: 'core/post-meta', * args: { * key: 'url_custom_field', * }, * }, * alt: { * source: 'core/post-meta', * args: { * key: 'text_custom_field', * }, * } * } ); * ``` */ const updateBlockBindings = bindings => { const { metadata: { bindings: currentBindings, ...metadata } = {} } = getBlockAttributes(blockClientId); const newBindings = { ...currentBindings }; Object.entries(bindings).forEach(([attribute, binding]) => { if (!binding && newBindings[attribute]) { delete newBindings[attribute]; return; } newBindings[attribute] = binding; }); const newMetadata = { ...metadata, bindings: newBindings }; if (isObjectEmpty(newMetadata.bindings)) { delete newMetadata.bindings; } updateBlockAttributes(blockClientId, { metadata: isObjectEmpty(newMetadata) ? undefined : newMetadata }); }; /** * Removes the bindings property of the `metadata` attribute. * * @example * ```js * import { useBlockBindingsUtils } from '@wordpress/block-editor' * * const { removeAllBlockBindings } = useBlockBindingsUtils(); * removeAllBlockBindings(); * ``` */ const removeAllBlockBindings = () => { const { metadata: { bindings, ...metadata } = {} } = getBlockAttributes(blockClientId); updateBlockAttributes(blockClientId, { metadata: isObjectEmpty(metadata) ? undefined : metadata }); }; return { updateBlockBindings, removeAllBlockBindings }; } //# sourceMappingURL=block-bindings.js.map