UNPKG

@wordpress/block-editor

Version:
350 lines (294 loc) 12.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getColorsFromDuotonePreset = getColorsFromDuotonePreset; exports.getDuotonePresetFromColors = getDuotonePresetFromColors; var _element = require("@wordpress/element"); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _classnames = _interopRequireDefault(require("classnames")); var _colord = require("colord"); var _names = _interopRequireDefault(require("colord/plugins/names")); var _blocks = require("@wordpress/blocks"); var _compose = require("@wordpress/compose"); var _hooks = require("@wordpress/hooks"); var _components = require("../components"); var _blockList = _interopRequireDefault(require("../components/block-list")); var _duotone = require("../components/duotone"); var _getBlockCssSelector = require("../components/global-styles/get-block-css-selector"); var _utils = require("../components/global-styles/utils"); var _utils2 = require("./utils"); var _filtersPanel = _interopRequireDefault(require("../components/global-styles/filters-panel")); var _blockEditingMode = require("../components/block-editing-mode"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ const EMPTY_ARRAY = []; (0, _colord.extend)([_names.default]); /** * SVG and stylesheet needed for rendering the duotone filter. * * @param {Object} props Duotone props. * @param {string} props.selector Selector to apply the filter to. * @param {string} props.id Unique id for this duotone filter. * @param {string[]|"unset"} props.colors Array of RGB color strings ordered from dark to light. * * @return {WPElement} Duotone element. */ function InlineDuotone({ selector, id, colors }) { if (colors === 'unset') { return (0, _element.createElement)(_duotone.__unstableDuotoneUnsetStylesheet, { selector: selector }); } return (0, _element.createElement)(_element.Fragment, null, (0, _element.createElement)(_duotone.__unstableDuotoneFilter, { id: id, colors: colors }), (0, _element.createElement)(_duotone.__unstableDuotoneStylesheet, { id: id, selector: selector })); } function useMultiOriginPresets({ presetSetting, defaultSetting }) { const disableDefault = !(0, _components.useSetting)(defaultSetting); const userPresets = (0, _components.useSetting)(`${presetSetting}.custom`) || EMPTY_ARRAY; const themePresets = (0, _components.useSetting)(`${presetSetting}.theme`) || EMPTY_ARRAY; const defaultPresets = (0, _components.useSetting)(`${presetSetting}.default`) || EMPTY_ARRAY; return (0, _element.useMemo)(() => [...userPresets, ...themePresets, ...(disableDefault ? EMPTY_ARRAY : defaultPresets)], [disableDefault, userPresets, themePresets, defaultPresets]); } function getColorsFromDuotonePreset(duotone, duotonePalette) { if (!duotone) { return; } const preset = duotonePalette?.find(({ slug }) => { return duotone === `var:preset|duotone|${slug}`; }); return preset ? preset.colors : undefined; } function getDuotonePresetFromColors(colors, duotonePalette) { if (!colors || !Array.isArray(colors)) { return; } const preset = duotonePalette?.find(duotonePreset => { return duotonePreset?.colors?.every((val, index) => val === colors[index]); }); return preset ? `var:preset|duotone|${preset.slug}` : undefined; } function DuotonePanel({ attributes, setAttributes, name }) { const style = attributes?.style; const duotoneStyle = style?.color?.duotone; const settings = (0, _utils2.useBlockSettings)(name); const duotonePalette = useMultiOriginPresets({ presetSetting: 'color.duotone', defaultSetting: 'color.defaultDuotone' }); const colorPalette = useMultiOriginPresets({ presetSetting: 'color.palette', defaultSetting: 'color.defaultPalette' }); const disableCustomColors = !(0, _components.useSetting)('color.custom'); const disableCustomDuotone = !(0, _components.useSetting)('color.customDuotone') || colorPalette?.length === 0 && disableCustomColors; if (duotonePalette?.length === 0 && disableCustomDuotone) { return null; } const duotonePresetOrColors = !Array.isArray(duotoneStyle) ? getColorsFromDuotonePreset(duotoneStyle, duotonePalette) : duotoneStyle; return (0, _element.createElement)(_element.Fragment, null, (0, _element.createElement)(_components.InspectorControls, { group: "filter" }, (0, _element.createElement)(_filtersPanel.default, { value: { filter: { duotone: duotonePresetOrColors } }, onChange: newDuotone => { const newStyle = { ...style, color: { ...newDuotone?.filter } }; setAttributes({ style: newStyle }); }, settings: settings })), (0, _element.createElement)(_components.BlockControls, { group: "block", __experimentalShareWithChildBlocks: true }, (0, _element.createElement)(_components.__experimentalDuotoneControl, { duotonePalette: duotonePalette, colorPalette: colorPalette, disableCustomDuotone: disableCustomDuotone, disableCustomColors: disableCustomColors, value: duotonePresetOrColors, onChange: newDuotone => { const maybePreset = getDuotonePresetFromColors(newDuotone, duotonePalette); const newStyle = { ...style, color: { ...style?.color, duotone: maybePreset !== null && maybePreset !== void 0 ? maybePreset : newDuotone // use preset or fallback to custom colors. } }; setAttributes({ style: newStyle }); }, settings: settings }))); } /** * Filters registered block settings, extending attributes to include * the `duotone` attribute. * * @param {Object} settings Original block settings. * * @return {Object} Filtered block settings. */ function addDuotoneAttributes(settings) { // Previous `color.__experimentalDuotone` support flag is migrated via // block_type_metadata_settings filter in `lib/block-supports/duotone.php`. if (!(0, _blocks.hasBlockSupport)(settings, 'filter.duotone')) { return settings; } // Allow blocks to specify their own attribute definition with default // values if needed. if (!settings.attributes.style) { Object.assign(settings.attributes, { style: { type: 'object' } }); } return settings; } /** * Override the default edit UI to include toolbar controls for duotone if the * block supports duotone. * * @param {Function} BlockEdit Original component. * * @return {Function} Wrapped component. */ const withDuotoneControls = (0, _compose.createHigherOrderComponent)(BlockEdit => props => { // Previous `color.__experimentalDuotone` support flag is migrated via // block_type_metadata_settings filter in `lib/block-supports/duotone.php`. const hasDuotoneSupport = (0, _blocks.hasBlockSupport)(props.name, 'filter.duotone'); const blockEditingMode = (0, _blockEditingMode.useBlockEditingMode)(); // CAUTION: code added before this line will be executed // for all blocks, not just those that support duotone. Code added // above this line should be carefully evaluated for its impact on // performance. return (0, _element.createElement)(_element.Fragment, null, hasDuotoneSupport && blockEditingMode === 'default' && (0, _element.createElement)(DuotonePanel, props), (0, _element.createElement)(BlockEdit, props)); }, 'withDuotoneControls'); function DuotoneStyles({ id: filterId, selector: duotoneSelector, attribute: duotoneAttr }) { const element = (0, _element.useContext)(_blockList.default.__unstableElementContext); const duotonePalette = useMultiOriginPresets({ presetSetting: 'color.duotone', defaultSetting: 'color.defaultDuotone' }); // Possible values for duotone attribute: // 1. Array of colors - e.g. ['#000000', '#ffffff']. // 2. Variable for an existing Duotone preset - e.g. 'var:preset|duotone|green-blue' or 'var(--wp--preset--duotone--green-blue)'' // 3. A CSS string - e.g. 'unset' to remove globally applied duotone. const isCustom = Array.isArray(duotoneAttr); const duotonePreset = isCustom ? undefined : getColorsFromDuotonePreset(duotoneAttr, duotonePalette); const isPreset = typeof duotoneAttr === 'string' && duotonePreset; const isCSS = typeof duotoneAttr === 'string' && !isPreset; // Match the structure of WP_Duotone_Gutenberg::render_duotone_support() in PHP. let colors = null; if (isPreset) { // Array of colors. colors = duotonePreset; } else if (isCSS) { // CSS filter property string (e.g. 'unset'). colors = duotoneAttr; } else if (isCustom) { // Array of colors. colors = duotoneAttr; } // Build the CSS selectors to which the filter will be applied. const selectors = duotoneSelector.split(','); const selectorsScoped = selectors.map(selectorPart => { // Extra .editor-styles-wrapper specificity is needed in the editor // since we're not using inline styles to apply the filter. We need to // override duotone applied by global styles and theme.json. // Assuming the selector part is a subclass selector (not a tag name) // so we can prepend the filter id class. If we want to support elements // such as `img` or namespaces, we'll need to add a case for that here. return `.editor-styles-wrapper .${filterId}${selectorPart.trim()}`; }); const selector = selectorsScoped.join(', '); const isValidFilter = Array.isArray(colors) || colors === 'unset'; return element && isValidFilter && (0, _element.createPortal)((0, _element.createElement)(InlineDuotone, { selector: selector, id: filterId, colors: colors }), element); } /** * Override the default block element to include duotone styles. * * @param {Function} BlockListBlock Original component. * * @return {Function} Wrapped component. */ const withDuotoneStyles = (0, _compose.createHigherOrderComponent)(BlockListBlock => props => { const id = (0, _compose.useInstanceId)(BlockListBlock); const selector = (0, _element.useMemo)(() => { const blockType = (0, _blocks.getBlockType)(props.name); if (blockType) { // Backwards compatibility for `supports.color.__experimentalDuotone` // is provided via the `block_type_metadata_settings` filter. If // `supports.filter.duotone` has not been set and the // experimental property has been, the experimental property // value is copied into `supports.filter.duotone`. const duotoneSupport = (0, _blocks.getBlockSupport)(blockType, 'filter.duotone', false); if (!duotoneSupport) { return null; } // If the experimental duotone support was set, that value is // to be treated as a selector and requires scoping. const experimentalDuotone = (0, _blocks.getBlockSupport)(blockType, 'color.__experimentalDuotone', false); if (experimentalDuotone) { const rootSelector = (0, _getBlockCssSelector.getBlockCSSSelector)(blockType); return typeof experimentalDuotone === 'string' ? (0, _utils.scopeSelector)(rootSelector, experimentalDuotone) : rootSelector; } // Regular filter.duotone support uses filter.duotone selectors with fallbacks. return (0, _getBlockCssSelector.getBlockCSSSelector)(blockType, 'filter.duotone', { fallback: true }); } }, [props.name]); const attribute = props?.attributes?.style?.color?.duotone; const filterClass = `wp-duotone-${id}`; const shouldRender = selector && attribute; const className = shouldRender ? (0, _classnames.default)(props?.className, filterClass) : props?.className; // CAUTION: code added before this line will be executed // for all blocks, not just those that support duotone. Code added // above this line should be carefully evaluated for its impact on // performance. return (0, _element.createElement)(_element.Fragment, null, shouldRender && (0, _element.createElement)(DuotoneStyles, { id: filterClass, selector: selector, attribute: attribute }), (0, _element.createElement)(BlockListBlock, (0, _extends2.default)({}, props, { className: className }))); }, 'withDuotoneStyles'); (0, _hooks.addFilter)('blocks.registerBlockType', 'core/editor/duotone/add-attributes', addDuotoneAttributes); (0, _hooks.addFilter)('editor.BlockEdit', 'core/editor/duotone/with-editor-controls', withDuotoneControls); (0, _hooks.addFilter)('editor.BlockListBlock', 'core/editor/duotone/with-styles', withDuotoneStyles); //# sourceMappingURL=duotone.js.map