UNPKG

@wordpress/block-editor

Version:
283 lines (278 loc) 10.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.BlockBindingsPanel = void 0; var _i18n = require("@wordpress/i18n"); var _blocks = require("@wordpress/blocks"); var _components = require("@wordpress/components"); var _data = require("@wordpress/data"); var _element = require("@wordpress/element"); var _compose = require("@wordpress/compose"); var _blockBindings = require("../utils/block-bindings"); var _lockUnlock = require("../lock-unlock"); var _inspectorControls = _interopRequireDefault(require("../components/inspector-controls")); var _blockContext = _interopRequireDefault(require("../components/block-context")); var _blockEdit = require("../components/block-edit"); var _store = require("../store"); var _jsxRuntime = require("react/jsx-runtime"); /** * WordPress dependencies */ /** * Internal dependencies */ const { Menu } = (0, _lockUnlock.unlock)(_components.privateApis); const EMPTY_OBJECT = {}; const useToolsPanelDropdownMenuProps = () => { const isMobile = (0, _compose.useViewportMatch)('medium', '<'); return !isMobile ? { popoverProps: { placement: 'left-start', // For non-mobile, inner sidebar width (248px) - button width (24px) - border (1px) + padding (16px) + spacing (20px) offset: 259 } } : {}; }; function BlockBindingsPanelMenuContent({ fieldsList, attribute, binding }) { const { clientId } = (0, _blockEdit.useBlockEditContext)(); const registeredSources = (0, _blocks.getBlockBindingsSources)(); const { updateBlockBindings } = (0, _blockBindings.useBlockBindingsUtils)(); const currentKey = binding?.args?.key; const attributeType = (0, _data.useSelect)(select => { const { name: blockName } = select(_store.store).getBlock(clientId); const _attributeType = (0, _blocks.getBlockType)(blockName).attributes?.[attribute]?.type; return _attributeType === 'rich-text' ? 'string' : _attributeType; }, [clientId, attribute]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, { children: Object.entries(fieldsList).map(([name, fields], i) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_element.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(Menu.Group, { children: [Object.keys(fieldsList).length > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(Menu.GroupLabel, { children: registeredSources[name].label }), Object.entries(fields).filter(([, args]) => args?.type === attributeType).map(([key, args]) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(Menu.RadioItem, { onChange: () => updateBlockBindings({ [attribute]: { source: name, args: { key } } }), name: attribute + '-binding', value: key, checked: key === currentKey, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Menu.ItemLabel, { children: args?.label }), /*#__PURE__*/(0, _jsxRuntime.jsx)(Menu.ItemHelpText, { children: args?.value })] }, key))] }), i !== Object.keys(fieldsList).length - 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(Menu.Separator, {})] }, name)) }); } function BlockBindingsAttribute({ attribute, binding, fieldsList }) { const { source: sourceName, args } = binding || {}; const sourceProps = (0, _blocks.getBlockBindingsSource)(sourceName); const isSourceInvalid = !sourceProps; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalVStack, { className: "block-editor-bindings__item", spacing: 0, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalText, { truncate: true, children: attribute }), !!binding && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalText, { truncate: true, variant: !isSourceInvalid && 'muted', isDestructive: isSourceInvalid, children: isSourceInvalid ? (0, _i18n.__)('Invalid source') : fieldsList?.[sourceName]?.[args?.key]?.label || sourceProps?.label || sourceName })] }); } function ReadOnlyBlockBindingsPanelItems({ bindings, fieldsList }) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, { children: Object.entries(bindings).map(([attribute, binding]) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalItem, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(BlockBindingsAttribute, { attribute: attribute, binding: binding, fieldsList: fieldsList }) }, attribute)) }); } function EditableBlockBindingsPanelItems({ attributes, bindings, fieldsList }) { const { updateBlockBindings } = (0, _blockBindings.useBlockBindingsUtils)(); const isMobile = (0, _compose.useViewportMatch)('medium', '<'); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, { children: attributes.map(attribute => { const binding = bindings[attribute]; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, { hasValue: () => !!binding, label: attribute, onDeselect: () => { updateBlockBindings({ [attribute]: undefined }); }, children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(Menu, { placement: isMobile ? 'bottom-start' : 'left-start', children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Menu.TriggerButton, { render: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalItem, {}), children: /*#__PURE__*/(0, _jsxRuntime.jsx)(BlockBindingsAttribute, { attribute: attribute, binding: binding, fieldsList: fieldsList }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(Menu.Popover, { gutter: isMobile ? 8 : 36, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(BlockBindingsPanelMenuContent, { fieldsList: fieldsList, attribute: attribute, binding: binding }) })] }) }, attribute); }) }); } const BlockBindingsPanel = ({ name: blockName, metadata }) => { const blockContext = (0, _element.useContext)(_blockContext.default); const { removeAllBlockBindings } = (0, _blockBindings.useBlockBindingsUtils)(); const bindableAttributes = (0, _blockBindings.getBindableAttributes)(blockName); const dropdownMenuProps = useToolsPanelDropdownMenuProps(); // `useSelect` is used purposely here to ensure `getFieldsList` // is updated whenever there are updates in block context. // `source.getFieldsList` may also call a selector via `select`. const _fieldsList = {}; const { fieldsList, canUpdateBlockBindings } = (0, _data.useSelect)(select => { if (!bindableAttributes || bindableAttributes.length === 0) { return EMPTY_OBJECT; } const registeredSources = (0, _blocks.getBlockBindingsSources)(); Object.entries(registeredSources).forEach(([sourceName, { getFieldsList, usesContext }]) => { if (getFieldsList) { // Populate context. const context = {}; if (usesContext?.length) { for (const key of usesContext) { context[key] = blockContext[key]; } } const sourceList = getFieldsList({ select, context }); // Only add source if the list is not empty. if (Object.keys(sourceList || {}).length) { _fieldsList[sourceName] = { ...sourceList }; } } }); return { fieldsList: Object.values(_fieldsList).length > 0 ? _fieldsList : EMPTY_OBJECT, canUpdateBlockBindings: select(_store.store).getSettings().canUpdateBlockBindings }; }, [blockContext, bindableAttributes]); // Return early if there are no bindable attributes. if (!bindableAttributes || bindableAttributes.length === 0) { return null; } // Filter bindings to only show bindable attributes and remove pattern overrides. const { bindings } = metadata || {}; const filteredBindings = { ...bindings }; Object.keys(filteredBindings).forEach(key => { if (!(0, _blockBindings.canBindAttribute)(blockName, key) || filteredBindings[key].source === 'core/pattern-overrides') { delete filteredBindings[key]; } }); // Lock the UI when the user can't update bindings or there are no fields to connect to. const readOnly = !canUpdateBlockBindings || !Object.keys(fieldsList).length; if (readOnly && Object.keys(filteredBindings).length === 0) { return null; } return /*#__PURE__*/(0, _jsxRuntime.jsx)(_inspectorControls.default, { group: "bindings", children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, { label: (0, _i18n.__)('Attributes'), resetAll: () => { removeAllBlockBindings(); }, dropdownMenuProps: dropdownMenuProps, className: "block-editor-bindings__panel", children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalItemGroup, { isBordered: true, isSeparated: true, children: readOnly ? /*#__PURE__*/(0, _jsxRuntime.jsx)(ReadOnlyBlockBindingsPanelItems, { bindings: filteredBindings, fieldsList: fieldsList }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EditableBlockBindingsPanelItems, { attributes: bindableAttributes, bindings: filteredBindings, fieldsList: fieldsList }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalText, { as: "div", variant: "muted", children: /*#__PURE__*/(0, _jsxRuntime.jsx)("p", { children: (0, _i18n.__)('Attributes connected to custom fields or other dynamic data.') }) })] }) }); }; exports.BlockBindingsPanel = BlockBindingsPanel; var _default = exports.default = { edit: BlockBindingsPanel, attributeKeys: ['metadata'], hasSupport() { return true; } }; //# sourceMappingURL=block-bindings.js.map