Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BlockStyleWrapper aware of block themes #6445

Merged
merged 11 commits into from
Oct 29, 2024
12 changes: 12 additions & 0 deletions packages/types/src/blocks/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,15 @@ export interface BlockEditProps {
errors: Record<string, Array<string>>;
blocksErrors: Record<string, Record<string, Array<string>>>;
}

export type StyleDefinition =
| {
name: string;
label: string;
style: Record<`--${string}`, string>;
}
| {
name: string;
label: string;
style: undefined;
};
3 changes: 3 additions & 0 deletions packages/types/src/config/Blocks.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import type { Content } from '../content';
import type { BlockViewProps, BlockEditProps } from '../blocks';
import type { IntlShape } from 'react-intl';
import { User } from '../services';
import { StyleDefinition } from '../blocks';

export interface BlocksConfig {
blocksConfig: BlocksConfigData;
groupBlocksOrder: { id: string; title: string };
requiredBlocks: string[];
initialBlocks: Record<string, string[]> | Record<string, object[]>;
initialBlocksFocus: Record<string, string>;
themes: StyleDefinition[];
widths: StyleDefinition[];
}

export interface BlocksConfigData {
Expand Down
1 change: 1 addition & 0 deletions packages/volto/news/6445.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Enhance the `buildStyleObjectFromData` helper. @sneridagh
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const EditBlockWrapper = (props) => {
data,
classNames,
});
const style = buildStyleObjectFromData(data.styles);
const style = buildStyleObjectFromData(data);

// We need to merge the StyleWrapper styles with the draggable props from b-D&D
const styleMergedWithDragProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const StyleWrapper = (props) => {
classNames,
});

style = buildStyleObjectFromData(data.styles);
style = buildStyleObjectFromData(data);

const rewrittenChildren = React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
Expand Down
106 changes: 73 additions & 33 deletions packages/volto/src/helpers/Blocks/Blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -629,51 +629,91 @@ export const styleDataToStyleObject = (key, value, prefix = '') => {
* Generate styles object from data
*
* @function buildStyleObjectFromData
* @param {Object} obj A style wrapper object data
* @param {Object} data A block data object
* @param {string} prefix The prefix (could be dragged from a recursive call, initially empty)
* @return {Object} The style object ready to be passed as prop
*/
export const buildStyleObjectFromData = (obj = {}, prefix = '') => {
export const buildStyleObjectFromData = (data = {}, prefix = '') => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could easily make it non-breaking by making it accept either obj or data

Copy link
Member Author

@sneridagh sneridagh Oct 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, I had to detect that we have a full block by testing if @type is present. Take a look now.

// style wrapper object has the form:
// const styles = {
// color: 'red',
// '--background-color': '#AABBCC',
// }
// Returns: {'--background-color: '#AABBCC'}

return Object.fromEntries(
Object.entries(obj)
.filter(([k, v]) => k.startsWith('--') || isObject(v))
.reduce(
(acc, [k, v]) => [
...acc,
// Kept for easy debugging
// ...(() => {
// if (isObject(v)) {
// return Object.entries(
// buildStyleObjectFromData(
// v,
// `${k.endsWith(':noprefix') ? '' : `${prefix}${k}--`}`,
// ),
// );
// }
// return [styleDataToStyleObject(k, v, prefix)];
// })(),
...(isObject(v)
? Object.entries(
buildStyleObjectFromData(
v,
`${k.endsWith(':noprefix') ? '' : `${prefix}${k}--`}`, // We don't add a prefix if the key ends with the marker suffix
),
)
: [styleDataToStyleObject(k, v, prefix)]),
],
[],
)
.filter((v) => !!v),
);
function recursiveBuildStyleObjectFromData(obj, prefix) {
return Object.fromEntries(
Object.entries(obj)
.filter(([k, v]) => k.startsWith('--') || isObject(v))
.reduce(
(acc, [k, v]) => [
...acc,
// Kept for easy debugging
// ...(() => {
// if (isObject(v)) {
// return Object.entries(
// buildStyleObjectFromData(
// v,
// `${k.endsWith(':noprefix') ? '' : `${prefix}${k}--`}`,
// ),
// );
// }
// return [styleDataToStyleObject(k, v, prefix)];
// })(),
...(isObject(v)
? Object.entries(
recursiveBuildStyleObjectFromData(
v,
`${k.endsWith(':noprefix') ? '' : `${prefix}${k}--`}`, // We don't add a prefix if the key ends with the marker suffix
),
)
: [styleDataToStyleObject(k, v, prefix)]),
],
[],
)
.filter((v) => !!v),
);
}

// If the block has a `@type`, it's a full data block object
// Then apply the style enhancers
if (data['@type']) {
const styleObj = data.styles || {};
const stylesFromCSSproperties = recursiveBuildStyleObjectFromData(
styleObj,
prefix,
);

let stylesFromObjectStyleEnhancers = {};
const enhancers = config.getUtilities({
type: 'styleWrapperStyleObjectEnhancer',
});

enhancers.forEach(({ method }) => {
stylesFromObjectStyleEnhancers = {
...stylesFromObjectStyleEnhancers,
...method(data),
};
});

return { ...stylesFromCSSproperties, ...stylesFromObjectStyleEnhancers };
} else {
return recursiveBuildStyleObjectFromData(data, prefix);
}
};

/**
* Find a matching style by name given a style definition
*
* @function findStyleByName
* @param {Object} styleDefinitions An object with the style definitions
* @param {string} name The name of the style to find
* @return {Object} The style object of the matching name
*/
export function findStyleByName(styleDefinitions, name) {
return styleDefinitions.find((color) => color.name === name)?.style;
}

/**
* Return previous/next blocks given the content object and the current block id
*
Expand Down
Loading
Loading