-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
/
Copy pathStory.tsx
112 lines (99 loc) · 2.96 KB
/
Story.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { global } from '@storybook/global';
import type { FunctionComponent } from 'react';
import React, { useRef, useEffect, useState } from 'react';
import type { DocsContextProps, PreparedStory } from '@storybook/types';
import { Loader, getStoryHref } from '@storybook/components';
import { IFrame } from './IFrame';
import { ZoomContext } from './ZoomContext';
const { PREVIEW_URL } = global;
const BASE_URL = PREVIEW_URL || 'iframe.html';
interface CommonProps {
story: PreparedStory;
inline: boolean;
}
interface InlineStoryProps extends CommonProps {
inline: true;
height?: string;
autoplay: boolean;
forceInitialArgs: boolean;
renderStoryToElement: DocsContextProps['renderStoryToElement'];
}
interface IFrameStoryProps extends CommonProps {
inline: false;
height: string;
}
export type StoryProps = InlineStoryProps | IFrameStoryProps;
const InlineStory: FunctionComponent<InlineStoryProps> = ({
story,
height,
autoplay,
forceInitialArgs,
renderStoryToElement,
}) => {
const storyRef = useRef();
const [showLoader, setShowLoader] = useState(true);
useEffect(() => {
if (!(story && storyRef.current)) {
return () => {};
}
const element = storyRef.current as HTMLElement;
const cleanup = renderStoryToElement(story, element, { autoplay, forceInitialArgs });
setShowLoader(false);
return () => {
cleanup();
};
}, [autoplay, renderStoryToElement, story]);
// We do this so React doesn't complain when we replace the span in a secondary render
const htmlContents = `<span></span>`;
return (
<>
{height ? (
<style>{`#story--${story.id} { min-height: ${height}; transform: translateZ(0); overflow: auto }`}</style>
) : null}
{showLoader && <StorySkeleton />}
<div
ref={storyRef}
data-name={story.name}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: htmlContents }}
/>
</>
);
};
const IFrameStory: FunctionComponent<IFrameStoryProps> = ({ story, height = '500px' }) => (
<div style={{ width: '100%', height }}>
<ZoomContext.Consumer>
{({ scale }) => {
return (
<IFrame
key="iframe"
id={`iframe--${story.id}`}
title={story.name}
src={getStoryHref(BASE_URL, story.id, { viewMode: 'story' })}
allowFullScreen
scale={scale}
style={{
width: '100%',
height: '100%',
border: '0 none',
}}
/>
);
}}
</ZoomContext.Consumer>
</div>
);
/**
* A story element, either rendered inline or in an iframe,
* with configurable height.
*/
const Story: FunctionComponent<StoryProps> = (props) => {
const { inline } = props;
return inline ? (
<InlineStory {...(props as InlineStoryProps)} />
) : (
<IFrameStory {...(props as IFrameStoryProps)} />
);
};
const StorySkeleton = () => <Loader />;
export { Story, StorySkeleton };