UNPKG

@wordpress/block-editor

Version:
213 lines (194 loc) 7.02 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import { createElement, Fragment } from "@wordpress/element"; /** * External dependencies */ import classnames from 'classnames'; import tinycolor from 'tinycolor2'; /** * WordPress dependencies */ import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks'; import { SVG } from '@wordpress/components'; import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose'; import { addFilter } from '@wordpress/hooks'; /** * Internal dependencies */ import { BlockControls, __experimentalDuotoneControl as DuotoneControl, __experimentalUseEditorFeature as useEditorFeature } from '../components'; /** * Convert a list of colors to an object of R, G, and B values. * * @param {string[]} colors Array of RBG color strings. * * @return {Object} R, G, and B values. */ export function getValuesFromColors(colors = []) { const values = { r: [], g: [], b: [] }; colors.forEach(color => { // Access values directly to skip extra rounding that tinycolor.toRgb() does. const tcolor = tinycolor(color); values.r.push(tcolor._r / 255); values.g.push(tcolor._g / 255); values.b.push(tcolor._b / 255); }); return values; } /** * Values for the SVG `feComponentTransfer`. * * @typedef Values {Object} * @property {number[]} r Red values. * @property {number[]} g Green values. * @property {number[]} b Blue values. */ /** * 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 {Values} props.values R, G, and B values to filter with. * @return {WPElement} Duotone element. */ function DuotoneFilter({ selector, id, values }) { const stylesheet = ` ${selector} { filter: url( #${id} ); } `; return createElement(Fragment, null, createElement(SVG, { xmlnsXlink: "http://www.w3.org/1999/xlink", viewBox: "0 0 0 0", width: "0", height: "0", focusable: "false", role: "none", style: { visibility: 'hidden', position: 'absolute', left: '-9999px', overflow: 'hidden' } }, createElement("defs", null, createElement("filter", { id: id }, createElement("feColorMatrix", { type: "matrix" // Use perceptual brightness to convert to grayscale. // prettier-ignore , values: ".299 .587 .114 0 0 .299 .587 .114 0 0 .299 .587 .114 0 0 0 0 0 1 0" }), createElement("feComponentTransfer", { // Use sRGB instead of linearRGB to be consistent with how CSS gradients work. colorInterpolationFilters: "sRGB" }, createElement("feFuncR", { type: "table", tableValues: values.r.join(' ') }), createElement("feFuncG", { type: "table", tableValues: values.g.join(' ') }), createElement("feFuncB", { type: "table", tableValues: values.b.join(' ') }))))), createElement("style", { dangerouslySetInnerHTML: { __html: stylesheet } })); } function DuotonePanel({ attributes, setAttributes }) { var _style$color; const style = attributes === null || attributes === void 0 ? void 0 : attributes.style; const duotone = style === null || style === void 0 ? void 0 : (_style$color = style.color) === null || _style$color === void 0 ? void 0 : _style$color.duotone; const duotonePalette = useEditorFeature('color.duotone'); const colorPalette = useEditorFeature('color.palette'); return createElement(BlockControls, { group: "block" }, createElement(DuotoneControl, { duotonePalette: duotonePalette, colorPalette: colorPalette, value: duotone, onChange: newDuotone => { const newStyle = { ...style, color: { ...(style === null || style === void 0 ? void 0 : style.color), duotone: newDuotone } }; setAttributes({ style: newStyle }); } })); } /** * 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) { if (!hasBlockSupport(settings, 'color.__experimentalDuotone')) { 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 = createHigherOrderComponent(BlockEdit => props => { const hasDuotoneSupport = hasBlockSupport(props.name, 'color.__experimentalDuotone'); return createElement(Fragment, null, createElement(BlockEdit, props), hasDuotoneSupport && createElement(DuotonePanel, props)); }, 'withDuotoneControls'); /** * Override the default block element to include duotone styles. * * @param {Function} BlockListBlock Original component * @return {Function} Wrapped component */ const withDuotoneStyles = createHigherOrderComponent(BlockListBlock => props => { var _props$attributes, _props$attributes$sty, _props$attributes$sty2; const duotoneSupport = getBlockSupport(props.name, 'color.__experimentalDuotone'); const values = props === null || props === void 0 ? void 0 : (_props$attributes = props.attributes) === null || _props$attributes === void 0 ? void 0 : (_props$attributes$sty = _props$attributes.style) === null || _props$attributes$sty === void 0 ? void 0 : (_props$attributes$sty2 = _props$attributes$sty.color) === null || _props$attributes$sty2 === void 0 ? void 0 : _props$attributes$sty2.duotone; if (!duotoneSupport || !values) { return createElement(BlockListBlock, props); } const id = `wp-duotone-filter-${useInstanceId(BlockListBlock)}`; const selectors = duotoneSupport.split(','); const selectorsScoped = selectors.map(selector => `.${id} ${selector.trim()}`); const selectorsGroup = selectorsScoped.join(', '); const className = classnames(props === null || props === void 0 ? void 0 : props.classname, id); return createElement(Fragment, null, createElement(DuotoneFilter, { selector: selectorsGroup, id: id, values: getValuesFromColors(values) }), createElement(BlockListBlock, _extends({}, props, { className: className }))); }, 'withDuotoneStyles'); addFilter('blocks.registerBlockType', 'core/editor/duotone/add-attributes', addDuotoneAttributes); addFilter('editor.BlockEdit', 'core/editor/duotone/with-editor-controls', withDuotoneControls); addFilter('editor.BlockListBlock', 'core/editor/duotone/with-styles', withDuotoneStyles); //# sourceMappingURL=duotone.js.map