@wordpress/block-editor
Version:
283 lines (278 loc) • 10.2 kB
JavaScript
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
;