mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-06 07:01:21 +08:00
MOVE grid functionality to background addon
This commit is contained in:
parent
0a6360789d
commit
b5b4deb7b1
@ -1,4 +1,6 @@
|
||||
export const ADDON_ID = 'storybook/background';
|
||||
export const BACKGROUND = `${ADDON_ID}/background`;
|
||||
export const GRID = `${ADDON_ID}/grid`;
|
||||
export const PARAM_KEY = 'backgrounds';
|
||||
|
||||
export const EVENTS = {
|
||||
|
42
addons/backgrounds/src/containers/GridSelector.tsx
Normal file
42
addons/backgrounds/src/containers/GridSelector.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import { useAddonState } from '@storybook/api';
|
||||
import { Global } from '@storybook/theming';
|
||||
import { Icons, IconButton } from '@storybook/components';
|
||||
|
||||
import { GRID } from '../constants';
|
||||
|
||||
const iframeId = 'storybook-preview-iframe';
|
||||
|
||||
export const GridSelector: FunctionComponent = () => {
|
||||
const [state, setState] = useAddonState<boolean>(GRID);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
key="background"
|
||||
active={state}
|
||||
title="Change the background of the preview"
|
||||
onClick={() => setState(!state)}
|
||||
>
|
||||
<Icons icon="grid" />
|
||||
{state ? (
|
||||
<Global
|
||||
styles={{
|
||||
[`#${iframeId}`]: {
|
||||
backgroundSize: '100px 100px, 100px 100px, 20px 20px, 20px 20px',
|
||||
backgroundPosition: '-1px -1px, -1px -1px, -1px -1px, -1px -1px',
|
||||
backgroundBlendMode: 'difference',
|
||||
backgroundImage: [
|
||||
'linear-gradient(rgba(130, 130, 130,0.5) 1px,transparent 1px)',
|
||||
'linear-gradient(90deg,rgb(130, 130, 130,0.5) 1px,transparent 1px)',
|
||||
'linear-gradient(rgba(130, 130, 130, 0.25) 1px,transparent 1px)',
|
||||
'linear-gradient(90deg,rgba(130, 130, 130, 0.25) 1px,transparent 1px)',
|
||||
].join(','),
|
||||
// `linear-gradient(black 1px, transparent 1px), linear-gradient(90deg, black 1px, transparent 1px), linear-gradient(rgba(0,0,0,.3) 1px, transparent 1px), linear-gradient(90deg, rgba(0,0,0,.3) 1px, transparent 1px)`,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</IconButton>
|
||||
);
|
||||
};
|
@ -1,14 +1,20 @@
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import { addons, types } from '@storybook/addons';
|
||||
|
||||
import { ADDON_ID } from './constants';
|
||||
import { ADDON_ID, BACKGROUND, GRID } from './constants';
|
||||
import { BackgroundSelector } from './containers/BackgroundSelector';
|
||||
import { GridSelector } from './containers/GridSelector';
|
||||
|
||||
addons.register(ADDON_ID, api => {
|
||||
addons.add(ADDON_ID, {
|
||||
addons.add(BACKGROUND, {
|
||||
title: 'Backgrounds',
|
||||
type: types.TOOL,
|
||||
match: ({ viewMode }) => viewMode === 'story',
|
||||
render: () => <BackgroundSelector api={api} />,
|
||||
render: () => (
|
||||
<Fragment>
|
||||
<BackgroundSelector api={api} />
|
||||
<GridSelector />
|
||||
</Fragment>
|
||||
),
|
||||
});
|
||||
});
|
||||
|
@ -1,110 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import { renderToStaticMarkup } from 'react-dom/server';
|
||||
import PropTypes from 'prop-types';
|
||||
import { styled } from '@storybook/theming';
|
||||
|
||||
const Context = React.createContext();
|
||||
|
||||
class Provider extends Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
grid: false,
|
||||
value: 'transparent',
|
||||
};
|
||||
|
||||
setValue = value => this.setState({ value });
|
||||
|
||||
setGrid = grid => this.setState({ grid });
|
||||
|
||||
render() {
|
||||
const { setValue, setGrid } = this;
|
||||
const { children } = this.props;
|
||||
const { value, grid } = this.state;
|
||||
|
||||
return (
|
||||
<Context.Provider value={{ value, setValue, grid, setGrid }}>{children}</Context.Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const { Consumer } = Context;
|
||||
|
||||
function createGridStyles(cellSize) {
|
||||
const cellSizeDoubled = cellSize * 2;
|
||||
const cellSizeSquared = cellSize ** 2;
|
||||
|
||||
const gridSVGEncoded = encodeURIComponent(
|
||||
renderToStaticMarkup(
|
||||
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="smallGrid" width={cellSize} height={cellSize} patternUnits="userSpaceOnUse">
|
||||
<path
|
||||
d={`M ${cellSize} 0 L 0 0 0 ${cellSize}`}
|
||||
fill="none"
|
||||
stroke="gray"
|
||||
strokeWidth="0.5"
|
||||
/>
|
||||
</pattern>
|
||||
<pattern
|
||||
id="grid"
|
||||
width={cellSizeSquared}
|
||||
height={cellSizeSquared}
|
||||
patternUnits="userSpaceOnUse"
|
||||
>
|
||||
<rect width={cellSizeSquared} height={cellSizeSquared} fill="url(#smallGrid)" />
|
||||
<path
|
||||
d={`M ${cellSizeSquared} 0 L 0 0 0 ${cellSizeSquared}`}
|
||||
fill="none"
|
||||
stroke="gray"
|
||||
strokeWidth="1"
|
||||
/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="url(#grid)" />
|
||||
</svg>
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
backgroundImage: `url("data:image/svg+xml,${gridSVGEncoded}")`,
|
||||
backgroundSize: `${cellSizeSquared}px ${cellSizeSquared}px, ${cellSizeSquared}px ${cellSizeSquared}px, ${cellSizeDoubled}px ${cellSizeDoubled}px, ${cellSizeDoubled}px ${cellSizeDoubled}px`,
|
||||
backgroundPosition: '-2px -2px',
|
||||
mixBlendMode: 'difference',
|
||||
};
|
||||
}
|
||||
|
||||
const Grid = styled.div(
|
||||
{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
({ theme }) => createGridStyles(theme.background.gridCellSize)
|
||||
);
|
||||
|
||||
const Background = styled.div(
|
||||
{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
minHeight: '100%',
|
||||
transition: 'background .1s linear',
|
||||
iframe: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
border: '0 none',
|
||||
},
|
||||
},
|
||||
({ theme }) => ({ background: theme.background.content })
|
||||
);
|
||||
|
||||
export { Grid, Background, Consumer as BackgroundConsumer, Provider as BackgroundProvider };
|
@ -11,7 +11,8 @@ const StyledIframe = styled.iframe({
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
border: '0 none',
|
||||
transition: 'background .3s',
|
||||
transition: 'all .3s, background-position 0s',
|
||||
backgroundPosition: '-1px -1px, -1px -1px, -1px -1px, -1px -1px',
|
||||
});
|
||||
|
||||
export class IFrame extends Component {
|
||||
|
@ -16,7 +16,6 @@ import { Toolbar } from './toolbar';
|
||||
import * as S from './components';
|
||||
|
||||
import { ZoomProvider, ZoomConsumer, Zoom } from './zoom';
|
||||
import { Grid, Background, BackgroundProvider, BackgroundConsumer } from './background';
|
||||
|
||||
import { IFrame } from './iframe';
|
||||
|
||||
@ -121,23 +120,6 @@ const getTools = memoize(10)(
|
||||
</Fragment>
|
||||
),
|
||||
},
|
||||
{
|
||||
match: p => p.viewMode === 'story',
|
||||
render: () => (
|
||||
<BackgroundConsumer>
|
||||
{({ setGrid, grid }) => (
|
||||
<IconButton
|
||||
active={!!grid}
|
||||
key="grid"
|
||||
onClick={() => setGrid(!grid)}
|
||||
title="Toggle background grid"
|
||||
>
|
||||
<Icons icon="grid" />
|
||||
</IconButton>
|
||||
)}
|
||||
</BackgroundConsumer>
|
||||
),
|
||||
},
|
||||
]);
|
||||
|
||||
const extraTools = getElementList(getElements, types.TOOLEXTRA, [
|
||||
@ -294,28 +276,26 @@ class Preview extends Component {
|
||||
);
|
||||
|
||||
return (
|
||||
<BackgroundProvider>
|
||||
<ZoomProvider>
|
||||
<Fragment>
|
||||
{id === 'main' && (
|
||||
<Helmet key="description">
|
||||
<title>{description ? `${description} ⋅ ` : ''}Storybook</title>
|
||||
</Helmet>
|
||||
)}
|
||||
<Toolbar key="toolbar" shown={options.isToolshown} border>
|
||||
<Fragment key="left">{left}</Fragment>
|
||||
<Fragment key="right">{right}</Fragment>
|
||||
</Toolbar>
|
||||
<S.FrameWrap key="frame" offset={toolbarHeight}>
|
||||
{panels.map(p => (
|
||||
<Fragment key={p.id || p.key}>
|
||||
{p.render({ active: p.match({ storyId, viewMode, location, path }) })}
|
||||
</Fragment>
|
||||
))}
|
||||
</S.FrameWrap>
|
||||
</Fragment>
|
||||
</ZoomProvider>
|
||||
</BackgroundProvider>
|
||||
<ZoomProvider>
|
||||
<Fragment>
|
||||
{id === 'main' && (
|
||||
<Helmet key="description">
|
||||
<title>{description ? `${description} ⋅ ` : ''}Storybook</title>
|
||||
</Helmet>
|
||||
)}
|
||||
<Toolbar key="toolbar" shown={options.isToolshown} border>
|
||||
<Fragment key="left">{left}</Fragment>
|
||||
<Fragment key="right">{right}</Fragment>
|
||||
</Toolbar>
|
||||
<S.FrameWrap key="frame" offset={toolbarHeight}>
|
||||
{panels.map(p => (
|
||||
<Fragment key={p.id || p.key}>
|
||||
{p.render({ active: p.match({ storyId, viewMode, location, path }) })}
|
||||
</Fragment>
|
||||
))}
|
||||
</S.FrameWrap>
|
||||
</Fragment>
|
||||
</ZoomProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user