addons/backgrounds/src/decorators/withGrid.ts
import dedent from 'ts-dedent';
import deprecate from 'util-deprecate';
import { useMemo, useEffect } from '@storybook/addons';
import { AnyFramework, PartialStoryFn as StoryFunction, StoryContext } from '@storybook/csf';
import { clearStyles, addGridStyle } from '../helpers';
import { PARAM_KEY as BACKGROUNDS_PARAM_KEY } from '../constants';
const deprecatedCellSizeWarning = deprecate(
() => {},
dedent`
Backgrounds Addon: The cell size parameter has been changed.
- parameters.grid.cellSize should now be parameters.backgrounds.grid.cellSize
See https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-grid-parameter
`
);
export const withGrid = (
StoryFn: StoryFunction<AnyFramework>,
context: StoryContext<AnyFramework>
) => {
const { globals, parameters } = context;
const gridParameters = parameters[BACKGROUNDS_PARAM_KEY].grid;
const isActive = globals[BACKGROUNDS_PARAM_KEY]?.grid === true && gridParameters.disable !== true;
const { cellAmount, cellSize, opacity } = gridParameters;
const isInDocs = context.viewMode === 'docs';
let gridSize: number;
if (parameters.grid?.cellSize) {
gridSize = parameters.grid.cellSize;
deprecatedCellSizeWarning();
} else {
gridSize = cellSize;
}
const isLayoutPadded = parameters.layout === undefined || parameters.layout === 'padded';
// 16px offset in the grid to account for padded layout
const defaultOffset = isLayoutPadded ? 16 : 0;
const offsetX = gridParameters.offsetX ?? (isInDocs ? 20 : defaultOffset);
const offsetY = gridParameters.offsetY ?? (isInDocs ? 20 : defaultOffset);
const gridStyles = useMemo(() => {
const selector =
context.viewMode === 'docs' ? `#anchor--${context.id} .docs-story` : '.sb-show-main';
const backgroundSize = [
`${gridSize * cellAmount}px ${gridSize * cellAmount}px`,
`${gridSize * cellAmount}px ${gridSize * cellAmount}px`,
`${gridSize}px ${gridSize}px`,
`${gridSize}px ${gridSize}px`,
].join(', ');
return `
${selector} {
background-size: ${backgroundSize} !important;
background-position: ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px !important;
background-blend-mode: difference !important;
background-image: linear-gradient(rgba(130, 130, 130, ${opacity}) 1px, transparent 1px),
linear-gradient(90deg, rgba(130, 130, 130, ${opacity}) 1px, transparent 1px),
linear-gradient(rgba(130, 130, 130, ${opacity / 2}) 1px, transparent 1px),
linear-gradient(90deg, rgba(130, 130, 130, ${
opacity / 2
}) 1px, transparent 1px) !important;
}
`;
}, [gridSize]);
useEffect(() => {
const selectorId =
context.viewMode === 'docs'
? `addon-backgrounds-grid-docs-${context.id}`
: `addon-backgrounds-grid`;
if (!isActive) {
clearStyles(selectorId);
return;
}
addGridStyle(selectorId, gridStyles);
}, [isActive, gridStyles, context]);
return StoryFn();
};