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

FIX zoom in docs #10801

Merged
merged 17 commits into from
May 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions addons/docs/src/blocks/Story.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React, { FunctionComponent, ReactNode } from 'react';
import React, { FunctionComponent, ReactNode, ComponentProps } from 'react';
import { MDXProvider } from '@mdx-js/react';
import { resetComponents } from '@storybook/components/html';
import { Story as PureStory, StoryProps as PureStoryProps } from '@storybook/components';
import { Story as PureStory } from '@storybook/components';
import { toId, storyNameFromExport } from '@storybook/csf';
import { CURRENT_SELECTION } from './types';

import { DocsContext, DocsContextProps } from './DocsContext';

export const storyBlockIdFromId = (storyId: string) => `story--${storyId}`;

type PureStoryProps = ComponentProps<typeof PureStory>;

interface CommonProps {
height?: string;
inline?: boolean;
Expand Down Expand Up @@ -48,14 +50,13 @@ export const getStoryProps = (props: StoryProps, context: DocsContextProps): Pur
const { name } = props as StoryDefProps;
const inputId = id === CURRENT_SELECTION ? context.id : id;
const previewId = inputId || lookupStoryId(name, context);
const data = context.storyStore.fromId(previewId) || {};

const { height, inline } = props;
const data = context.storyStore.fromId(previewId);
const { framework = null } = (data && data.parameters) || {};

const docsParam = (data && data.parameters && data.parameters.docs) || {};
const { parameters = {}, docs = {} } = data;
const { framework = null } = parameters;

if (docsParam.disable) {
if (docs.disable) {
return null;
}

Expand All @@ -64,8 +65,8 @@ export const getStoryProps = (props: StoryProps, context: DocsContextProps): Pur
inlineStories = inferInlineStories(framework),
iframeHeight = undefined,
prepareForInline = undefined,
} = docsParam;
const { storyFn = undefined, name: storyName = undefined } = data || {};
} = docs;
const { storyFn = undefined, name: storyName = undefined } = data;

const storyIsInline = typeof inline === 'boolean' ? inline : inlineStories;
if (storyIsInline && !prepareForInline && framework !== 'react') {
Expand All @@ -75,6 +76,7 @@ export const getStoryProps = (props: StoryProps, context: DocsContextProps): Pur
}

return {
parameters,
inline: storyIsInline,
id: previewId,
storyFn: prepareForInline && storyFn ? () => prepareForInline(storyFn) : storyFn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ import { Meta, DocsContainer } from '@storybook/addon-docs/blocks';
}}
/>

<Story name='dummy'><div>some content</div></Story>
<Story name='dummy' parameters={{ layout: 'fullscreen' }}><div>some content</div></Story>
3 changes: 3 additions & 0 deletions examples/official-storybook/stories/addon-docs/mdx.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import markdown from './markdown.stories.mdx';
export default {
title: 'Addons/Docs/mdx-in-story',
decorators: [(storyFn) => <DocsContainer context={{}}>{storyFn()}</DocsContainer>],
parameters: {
layout: 'fullscreen',
},
};

// This renders the contents of the docs panel into story content
Expand Down
26 changes: 23 additions & 3 deletions examples/official-storybook/stories/core/layout.stories.mdx
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
import { Meta, Preview, Story } from '@storybook/addon-docs/blocks';
import { Button } from '@storybook/react/demo';

<Meta
title="Core/Layout MDX"
component={Button}
id="core-layout-mdx"
decorators={[storyFn => <div style={{ backgroundColor: 'yellow' }}>{storyFn()}</div>]}
decorators={[(storyFn) => <div style={{ backgroundColor: 'yellow' }}>{storyFn()}</div>]}
/>

# Selected
# Layout parameter

<Preview>
This tests Storybook's built-in `layout` parameter, both as its applied in the canvas, and also how it's handled by the `Preview` block in `addon-docs`.

## Default

<Preview withToolbar>
<Story name="defaultValue">
<Button>Hello world</Button>
</Story>
</Preview>

## Padded

<Preview withToolbar>
<Story name="padded" parameters={{ layout: 'padded' }}>
<Button>Hello world</Button>
</Story>
</Preview>

## Fullscreen

<Preview withToolbar>
<Story name="fullscreen" parameters={{ layout: 'fullscreen' }}>
<Button>Hello world</Button>
</Story>
</Preview>

## Centered

<Preview withToolbar>
<Story name="centered" parameters={{ layout: 'centered' }}>
<Button>Hello world</Button>
</Story>
Expand Down
2 changes: 1 addition & 1 deletion examples/official-storybook/stories/hooks.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { useEffect, useRef, useState } from '@storybook/client-api';

export default {
title: 'Hooks',
title: 'Core/Hooks',
};

export const Checkbox = () => {
Expand Down
3 changes: 3 additions & 0 deletions lib/components/src/blocks/DocsPage.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import * as descriptionStories from './Description.stories';
export default {
title: 'Docs/DocsPage',
component: DocsWrapper,
parameters: {
layout: 'fullscreen',
},
decorators: [
(storyFn) => (
<DocsWrapper>
Expand Down
26 changes: 26 additions & 0 deletions lib/components/src/blocks/Preview.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,29 @@ export const withToolbarMulti = () => (
<Story inline storyFn={buttonFn} title="story2" />
</Preview>
);

export const withFullscreenSingle = () => (
<Preview withToolbar>
<Story inline storyFn={buttonFn} title="story1" parameters={{ layout: 'fullscreen' }} />
</Preview>
);

export const withFullscreenMulti = () => (
<Preview withToolbar>
<Story inline storyFn={buttonFn} title="story1" parameters={{ layout: 'fullscreen' }} />
<Story inline storyFn={buttonFn} title="story2" parameters={{ layout: 'fullscreen' }} />
</Preview>
);

export const withCenteredSingle = () => (
<Preview withToolbar>
<Story inline storyFn={buttonFn} title="story1" parameters={{ layout: 'centered' }} />
</Preview>
);

export const withCenteredMulti = () => (
<Preview withToolbar>
<Story inline storyFn={buttonFn} title="story1" parameters={{ layout: 'centered' }} />
<Story inline storyFn={buttonFn} title="story2" parameters={{ layout: 'centered' }} />
</Preview>
);
138 changes: 87 additions & 51 deletions lib/components/src/blocks/Preview.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { Children, FunctionComponent, ReactElement, ReactNode, useState } from 'react';
import { styled } from '@storybook/theming';
import { darken } from 'polished';
import { logger } from '@storybook/client-logger';
import { styled } from '@storybook/theming';

import { getBlockBackgroundStyle } from './BlockBackgroundStyles';
import { Source, SourceProps } from './Source';
import { ActionBar, ActionItem } from '../ActionBar/ActionBar';
import { Toolbar } from './Toolbar';
import { ZoomContext } from './ZoomContext';

export interface PreviewProps {
isColumn?: boolean;
Expand All @@ -17,20 +17,54 @@ export interface PreviewProps {
className?: string;
}

const ChildrenContainer = styled.div<PreviewProps>(({ isColumn, columns }) => ({
display: 'flex',
position: 'relative',
flexWrap: 'wrap',
padding: '10px 20px 30px 20px',
overflow: 'auto',
flexDirection: isColumn ? 'column' : 'row',

'> *': {
flex: columns ? `1 1 calc(100%/${columns} - 20px)` : `1 1 0%`,
marginTop: 20,
maxWidth: '100%',
},
}));
type layout = 'padded' | 'fullscreen' | 'centered';

const ChildrenContainer = styled.div<PreviewProps & { zoom: number; layout: layout }>(
({ isColumn, columns }) => ({
display: isColumn || !columns ? 'block' : 'flex',
position: 'relative',
flexWrap: 'wrap',
overflow: 'auto',
flexDirection: isColumn ? 'column' : 'row',

'& > *': isColumn
? {
width: '100%',
display: 'block',
}
: {
maxWidth: '100%',
display: 'inline-block',
},
}),
({ layout = 'padded' }) =>
layout === 'centered' || layout === 'padded'
? {
padding: '30px 20px',
margin: -10,
'& > *': {
border: '10px solid transparent!important',
},
}
: {},
({ layout = 'padded' }) =>
layout === 'centered'
? {
display: 'flex',
justifyContent: 'center',
justifyItems: 'center',
alignContent: 'center',
alignItems: 'center',
}
: {},
({ zoom = 1 }) => ({
'> *': {
zoom: 1 / zoom,
},
}),
({ columns }) =>
columns && columns > 1 ? { '> *': { minWidth: `calc(100% / ${columns} - 20px)` } } : {}
);

const StyledSource = styled(Source)<{}>(({ theme }) => ({
margin: 0,
Expand Down Expand Up @@ -107,23 +141,6 @@ function getStoryId(children: ReactNode) {
return null;
}

const Relative = styled.div({
position: 'relative',
});

const Scale = styled.div<{ scale: number }>(
{
position: 'relative',
},
({ scale }) =>
scale
? {
transform: `scale(${1 / scale})`,
transformOrigin: 'top left',
}
: {}
);

const PositionedToolbar = styled(Toolbar)({
position: 'absolute',
top: 0,
Expand All @@ -132,6 +149,23 @@ const PositionedToolbar = styled(Toolbar)({
height: 40,
});

const Relative = styled.div({
overflow: 'hidden',
position: 'relative',
});

const getLayout = (children: ReactElement[]) => {
Copy link
Member

Choose a reason for hiding this comment

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

AFAICT this uses the first story layout if there are multiple stories with different layouts, or padded if there are non-story children. WDYT about using the story layout if all children are stories and their layouts match, and padded layout in any other case. Seems a little simpler and more predictable?

return children.reduce((result, c) => {
if (result) {
return result;
}
if (typeof c === 'string' || typeof c === 'number') {
return 'padded';
}
return (c.props && c.props.parameters && c.props.parameters.layout) || 'padded';
}, undefined);
};

/**
* A preview component for showing one or more component `Story`
* items. The preview also shows the source for the component
Expand All @@ -150,19 +184,18 @@ const Preview: FunctionComponent<PreviewProps> = ({
const [expanded, setExpanded] = useState(isExpanded);
const { source, actionItem } = getSource(withSource, expanded, setExpanded);
const [scale, setScale] = useState(1);
const previewClasses = className ? `${className} sbdocs sbdocs-preview` : 'sbdocs sbdocs-preview';
const previewClasses = [className].concat(['sbdocs', 'sbdocs-preview']);

// @ts-ignore
const layout = getLayout(Children.count(children) === 1 ? [children] : children);

if (withToolbar && Array.isArray(children)) {
logger.warn('Cannot use toolbar with multiple preview children, disabling');
}
const showToolbar = withToolbar && !Array.isArray(children);
return (
<PreviewContainer
{...{ withSource, withToolbar: showToolbar }}
{...{ withSource, withToolbar }}
{...props}
className={previewClasses}
className={previewClasses.join(' ')}
ndelangen marked this conversation as resolved.
Show resolved Hide resolved
>
{showToolbar && (
{withToolbar && (
<PositionedToolbar
border
zoom={(z) => setScale(scale * z)}
Expand All @@ -171,16 +204,19 @@ const Preview: FunctionComponent<PreviewProps> = ({
baseUrl="./iframe.html"
/>
)}
<Relative>
<ChildrenContainer isColumn={isColumn} columns={columns}>
{Array.isArray(children) ? (
children.map((child, i) => <div key={i.toString()}>{child}</div>)
) : (
<Scale scale={scale}>{children}</Scale>
)}
</ChildrenContainer>
{withSource && <ActionBar actionItems={[actionItem]} />}
</Relative>
<ZoomContext.Provider value={{ scale }}>
<Relative>
<ChildrenContainer isColumn={isColumn} columns={columns} zoom={scale} layout={layout}>
{Array.isArray(children) ? (
// eslint-disable-next-line react/no-array-index-key
children.map((child, i) => <div key={i}>{child}</div>)
) : (
<div>{children}</div>
)}
</ChildrenContainer>
{withSource && <ActionBar actionItems={[actionItem]} />}
</Relative>
</ZoomContext.Provider>
{withSource && source}
</PreviewContainer>
);
Expand Down
Loading