UNPKG

@wordpress/block-editor

Version:
311 lines (298 loc) 12.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; exports.getColorsFromDuotonePreset = getColorsFromDuotonePreset; exports.getDuotonePresetFromColors = getDuotonePresetFromColors; 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 _element = require("@wordpress/element"); var _components = require("../components"); var _utils = require("../components/duotone/utils"); var _getBlockCssSelector = require("../components/global-styles/get-block-css-selector"); var _utils2 = require("../components/global-styles/utils"); var _utils3 = require("./utils"); var _filtersPanel = _interopRequireDefault(require("../components/global-styles/filters-panel")); var _blockEditingMode = require("../components/block-editing-mode"); var _useBlockRefs = require("../components/block-list/use-block-props/use-block-refs"); var _jsxRuntime = require("react/jsx-runtime"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ const EMPTY_ARRAY = []; // Safari does not always update the duotone filter when the duotone colors // are changed. This browser check is later used to force a re-render of the block // element to ensure the duotone filter is updated. The check is included at the // root of this file as it only needs to be run once per page load. const isSafari = window?.navigator.userAgent && window.navigator.userAgent.includes('Safari') && !window.navigator.userAgent.includes('Chrome') && !window.navigator.userAgent.includes('Chromium'); (0, _colord.extend)([_names.default]); function useMultiOriginPresets({ presetSetting, defaultSetting }) { const [enableDefault, userPresets, themePresets, defaultPresets] = (0, _components.useSettings)(defaultSetting, `${presetSetting}.custom`, `${presetSetting}.theme`, `${presetSetting}.default`); return (0, _element.useMemo)(() => [...(userPresets || EMPTY_ARRAY), ...(themePresets || EMPTY_ARRAY), ...(enableDefault && defaultPresets || EMPTY_ARRAY)], [enableDefault, 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 DuotonePanelPure({ style, setAttributes, name }) { const duotoneStyle = style?.color?.duotone; const settings = (0, _utils3.useBlockSettings)(name); const blockEditingMode = (0, _blockEditingMode.useBlockEditingMode)(); const duotonePalette = useMultiOriginPresets({ presetSetting: 'color.duotone', defaultSetting: 'color.defaultDuotone' }); const colorPalette = useMultiOriginPresets({ presetSetting: 'color.palette', defaultSetting: 'color.defaultPalette' }); const [enableCustomColors, enableCustomDuotone] = (0, _components.useSettings)('color.custom', 'color.customDuotone'); const disableCustomColors = !enableCustomColors; const disableCustomDuotone = !enableCustomDuotone || colorPalette?.length === 0 && disableCustomColors; if (duotonePalette?.length === 0 && disableCustomDuotone) { return null; } if (blockEditingMode !== 'default') { return null; } const duotonePresetOrColors = !Array.isArray(duotoneStyle) ? getColorsFromDuotonePreset(duotoneStyle, duotonePalette) : duotoneStyle; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.InspectorControls, { group: "filter", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_filtersPanel.default, { value: { filter: { duotone: duotonePresetOrColors } }, onChange: newDuotone => { const newStyle = { ...style, color: { ...newDuotone?.filter } }; setAttributes({ style: newStyle }); }, settings: settings }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.BlockControls, { group: "block", __experimentalShareWithChildBlocks: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_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 }) })] }); } var _default = exports.default = { shareWithChildBlocks: true, edit: DuotonePanelPure, useBlockProps, attributeKeys: ['style'], hasSupport(name) { return (0, _blocks.hasBlockSupport)(name, 'filter.duotone'); } }; /** * 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; } function useDuotoneStyles({ clientId, id: filterId, selector: duotoneSelector, attribute: duotoneAttr }) { 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 => { // 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 `.${filterId}${selectorPart.trim()}`; }); const selector = selectorsScoped.join(', '); const isValidFilter = Array.isArray(colors) || colors === 'unset'; (0, _utils3.usePrivateStyleOverride)(isValidFilter ? { css: colors !== 'unset' ? (0, _utils.getDuotoneStylesheet)(selector, filterId) : (0, _utils.getDuotoneUnsetStylesheet)(selector), __unstableType: 'presets' } : undefined); (0, _utils3.usePrivateStyleOverride)(isValidFilter ? { assets: colors !== 'unset' ? (0, _utils.getDuotoneFilter)(filterId, colors) : '', __unstableType: 'svgs' } : undefined); const blockElement = (0, _useBlockRefs.useBlockElement)(clientId); (0, _element.useEffect)(() => { if (!isValidFilter) { return; } // Safari does not always update the duotone filter when the duotone // colors are changed. When using Safari, force the block element to be // repainted by the browser to ensure any changes are reflected // visually. This logic matches that used on the site frontend in // `block-supports/duotone.php`. if (blockElement && isSafari) { const display = blockElement.style.display; // Switch to `inline-block` to force a repaint. In the editor, // `inline-block` is used instead of `none` to ensure that scroll // position is not affected, as `none` results in the editor // scrolling to the top of the block. blockElement.style.setProperty('display', 'inline-block'); // Simply accessing el.offsetHeight flushes layout and style changes // in WebKit without having to wait for setTimeout. // eslint-disable-next-line no-unused-expressions blockElement.offsetHeight; blockElement.style.setProperty('display', display); } // `colors` must be a dependency so this effect runs when the colors // change in Safari. }, [isValidFilter, blockElement, colors]); } // Used for generating the instance ID const DUOTONE_BLOCK_PROPS_REFERENCE = {}; function useBlockProps({ clientId, name, style }) { const id = (0, _compose.useInstanceId)(DUOTONE_BLOCK_PROPS_REFERENCE); const selector = (0, _element.useMemo)(() => { const blockType = (0, _blocks.getBlockType)(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, _utils2.scopeSelector)(rootSelector, experimentalDuotone) : rootSelector; } // Regular filter.duotone support uses filter.duotone selectors with fallbacks. return (0, _getBlockCssSelector.getBlockCSSSelector)(blockType, 'filter.duotone', { fallback: true }); } }, [name]); const attribute = style?.color?.duotone; const filterClass = `wp-duotone-${id}`; const shouldRender = selector && attribute; useDuotoneStyles({ clientId, id: filterClass, selector, attribute }); return { className: shouldRender ? filterClass : '' }; } (0, _hooks.addFilter)('blocks.registerBlockType', 'core/editor/duotone/add-attributes', addDuotoneAttributes); //# sourceMappingURL=duotone.js.map