@wordpress/block-editor
Version:
311 lines (298 loc) • 12.1 kB
JavaScript
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
;