@wordpress/block-editor
Version:
350 lines (294 loc) • 12.7 kB
JavaScript
;
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