@gechiui/block-editor
Version:
275 lines (223 loc) • 10.1 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.addEditProps = addEditProps;
exports.addSaveProps = addSaveProps;
exports.getInlineStyles = getInlineStyles;
exports.withBlockControls = void 0;
var _element = require("@gechiui/element");
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _lodash = require("lodash");
var _classnames = _interopRequireDefault(require("classnames"));
var _hooks = require("@gechiui/hooks");
var _blocks = require("@gechiui/blocks");
var _compose = require("@gechiui/compose");
var _blockList = _interopRequireDefault(require("../components/block-list"));
var _border = require("./border");
var _color = require("./color");
var _typography = require("./typography");
var _dimensions = require("./dimensions");
var _useDisplayBlockControls = _interopRequireDefault(require("../components/use-display-block-controls"));
/**
* External dependencies
*/
/**
* GeChiUI dependencies
*/
/**
* Internal dependencies
*/
const styleSupportKeys = [..._typography.TYPOGRAPHY_SUPPORT_KEYS, _border.BORDER_SUPPORT_KEY, _color.COLOR_SUPPORT_KEY, _dimensions.SPACING_SUPPORT_KEY];
const hasStyleSupport = blockType => styleSupportKeys.some(key => (0, _blocks.hasBlockSupport)(blockType, key));
const VARIABLE_REFERENCE_PREFIX = 'var:';
const VARIABLE_PATH_SEPARATOR_TOKEN_ATTRIBUTE = '|';
const VARIABLE_PATH_SEPARATOR_TOKEN_STYLE = '--';
function compileStyleValue(uncompiledValue) {
if ((0, _lodash.startsWith)(uncompiledValue, VARIABLE_REFERENCE_PREFIX)) {
const variable = uncompiledValue.slice(VARIABLE_REFERENCE_PREFIX.length).split(VARIABLE_PATH_SEPARATOR_TOKEN_ATTRIBUTE).join(VARIABLE_PATH_SEPARATOR_TOKEN_STYLE);
return `var(--gc--${variable})`;
}
return uncompiledValue;
}
/**
* Returns the inline styles to add depending on the style object
*
* @param {Object} styles Styles configuration.
*
* @return {Object} Flattened CSS variables declaration.
*/
function getInlineStyles() {
let styles = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
const ignoredStyles = ['spacing.blockGap'];
const output = {};
Object.keys(_blocks.__EXPERIMENTAL_STYLE_PROPERTY).forEach(propKey => {
const path = _blocks.__EXPERIMENTAL_STYLE_PROPERTY[propKey].value;
const subPaths = _blocks.__EXPERIMENTAL_STYLE_PROPERTY[propKey].properties; // Ignore styles on elements because they are handled on the server.
if ((0, _lodash.has)(styles, path) && 'elements' !== (0, _lodash.first)(path)) {
// Checking if style value is a string allows for shorthand css
// option and backwards compatibility for border radius support.
const styleValue = (0, _lodash.get)(styles, path);
if (!!subPaths && !(0, _lodash.isString)(styleValue)) {
Object.entries(subPaths).forEach(entry => {
const [name, subPath] = entry;
const value = (0, _lodash.get)(styleValue, [subPath]);
if (value) {
output[name] = compileStyleValue(value);
}
});
} else if (!ignoredStyles.includes(path.join('.'))) {
output[propKey] = compileStyleValue((0, _lodash.get)(styles, path));
}
}
});
return output;
}
function compileElementsStyles(selector) {
let elements = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return (0, _lodash.map)(elements, (styles, element) => {
const elementStyles = getInlineStyles(styles);
if (!(0, _lodash.isEmpty)(elementStyles)) {
return [`.${selector} ${_blocks.__EXPERIMENTAL_ELEMENTS[element]}{`, ...(0, _lodash.map)(elementStyles, (value, property) => `\t${(0, _lodash.kebabCase)(property)}: ${value};`), '}'].join('\n');
}
return '';
}).join('\n');
}
/**
* Filters registered block settings, extending attributes to include `style` attribute.
*
* @param {Object} settings Original block settings.
*
* @return {Object} Filtered block settings.
*/
function addAttribute(settings) {
if (!hasStyleSupport(settings)) {
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;
}
/**
* A dictionary of paths to flag skipping block support serialization as the key,
* with values providing the style paths to be omitted from serialization.
*
* @constant
* @type {Record<string, string[]>}
*/
const skipSerializationPathsEdit = {
[`${_border.BORDER_SUPPORT_KEY}.__experimentalSkipSerialization`]: ['border'],
[`${_color.COLOR_SUPPORT_KEY}.__experimentalSkipSerialization`]: [_color.COLOR_SUPPORT_KEY],
[`${_typography.TYPOGRAPHY_SUPPORT_KEY}.__experimentalSkipSerialization`]: [_typography.TYPOGRAPHY_SUPPORT_KEY],
[`${_dimensions.SPACING_SUPPORT_KEY}.__experimentalSkipSerialization`]: ['spacing']
};
/**
* A dictionary of paths to flag skipping block support serialization as the key,
* with values providing the style paths to be omitted from serialization.
*
* Extends the Edit skip paths to enable skipping additional paths in just
* the Save component. This allows a block support to be serialized within the
* editor, while using an alternate approach, such as server-side rendering, when
* the support is saved.
*
* @constant
* @type {Record<string, string[]>}
*/
const skipSerializationPathsSave = { ...skipSerializationPathsEdit,
[`${_dimensions.SPACING_SUPPORT_KEY}`]: ['spacing.blockGap']
};
/**
* Override props assigned to save component to inject the CSS variables definition.
*
* @param {Object} props Additional props applied to save element.
* @param {Object} blockType Block type.
* @param {Object} attributes Block attributes.
* @param {?Record<string, string[]>} skipPaths An object of keys and paths to skip serialization.
*
* @return {Object} Filtered props applied to save element.
*/
function addSaveProps(props, blockType, attributes) {
let skipPaths = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : skipSerializationPathsSave;
if (!hasStyleSupport(blockType)) {
return props;
}
let {
style
} = attributes;
(0, _lodash.forEach)(skipPaths, (path, indicator) => {
if ((0, _blocks.getBlockSupport)(blockType, indicator)) {
style = (0, _lodash.omit)(style, path);
}
});
props.style = { ...getInlineStyles(style),
...props.style
};
return props;
}
/**
* Filters registered block settings to extend the block edit wrapper
* to apply the desired styles and classnames properly.
*
* @param {Object} settings Original block settings.
*
* @return {Object}.Filtered block settings.
*/
function addEditProps(settings) {
if (!hasStyleSupport(settings)) {
return settings;
}
const existingGetEditWrapperProps = settings.getEditWrapperProps;
settings.getEditWrapperProps = attributes => {
let props = {};
if (existingGetEditWrapperProps) {
props = existingGetEditWrapperProps(attributes);
}
return addSaveProps(props, settings, attributes, skipSerializationPathsEdit);
};
return settings;
}
/**
* Override the default edit UI to include new inspector controls for
* all the custom styles configs.
*
* @param {Function} BlockEdit Original component.
*
* @return {Function} Wrapped component.
*/
const withBlockControls = (0, _compose.createHigherOrderComponent)(BlockEdit => props => {
const shouldDisplayControls = (0, _useDisplayBlockControls.default)();
return (0, _element.createElement)(_element.Fragment, null, shouldDisplayControls && (0, _element.createElement)(_element.Fragment, null, (0, _element.createElement)(_color.ColorEdit, props), (0, _element.createElement)(_typography.TypographyPanel, props), (0, _element.createElement)(_border.BorderPanel, props), (0, _element.createElement)(_dimensions.DimensionsPanel, props)), (0, _element.createElement)(BlockEdit, props));
}, 'withToolbarControls');
/**
* Override the default block element to include duotone styles.
*
* @param {Function} BlockListBlock Original component
* @return {Function} Wrapped component
*/
exports.withBlockControls = withBlockControls;
const withElementsStyles = (0, _compose.createHigherOrderComponent)(BlockListBlock => props => {
var _props$attributes$sty, _props$attributes$sty2;
const elements = (_props$attributes$sty = props.attributes.style) === null || _props$attributes$sty === void 0 ? void 0 : _props$attributes$sty.elements;
const blockElementsContainerIdentifier = `gc-elements-${(0, _compose.useInstanceId)(BlockListBlock)}`;
const styles = compileElementsStyles(blockElementsContainerIdentifier, (_props$attributes$sty2 = props.attributes.style) === null || _props$attributes$sty2 === void 0 ? void 0 : _props$attributes$sty2.elements);
const element = (0, _element.useContext)(_blockList.default.__unstableElementContext);
return (0, _element.createElement)(_element.Fragment, null, elements && element && (0, _element.createPortal)((0, _element.createElement)("style", {
dangerouslySetInnerHTML: {
__html: styles
}
}), element), (0, _element.createElement)(BlockListBlock, (0, _extends2.default)({}, props, {
className: elements ? (0, _classnames.default)(props.className, blockElementsContainerIdentifier) : props.className
})));
});
(0, _hooks.addFilter)('blocks.registerBlockType', 'core/style/addAttribute', addAttribute);
(0, _hooks.addFilter)('blocks.getSaveContent.extraProps', 'core/style/addSaveProps', addSaveProps);
(0, _hooks.addFilter)('blocks.registerBlockType', 'core/style/addEditProps', addEditProps);
(0, _hooks.addFilter)('editor.BlockEdit', 'core/style/with-block-controls', withBlockControls);
(0, _hooks.addFilter)('editor.BlockListBlock', 'core/editor/with-elements-styles', withElementsStyles);
//# sourceMappingURL=style.js.map