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

UI: Docs loading state (WIP) #16666

Merged
merged 23 commits into from
Nov 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b0f9bce
Add loading stories to various docs components
tmeasday Nov 1, 2021
bc3928e
Add `DocsPage` and `Source` loading stories
tmeasday Nov 1, 2021
f5c3af1
Add `Loader` to Story loading state
MichaelArestad Nov 3, 2021
2ea5cfe
Added basic loading state for ArgsTable
MichaelArestad Nov 4, 2021
677eb86
Add Loader to Preview Loading state
MichaelArestad Nov 4, 2021
08840c6
Merge remote-tracking branch 'origin/next' into docs-loading-state
tmeasday Nov 5, 2021
1524408
Insta-load all the stories that are in the current story's CSF file i…
tmeasday Nov 5, 2021
28cc7bd
Add `IconButtonSkeleton`
tmeasday Nov 5, 2021
f1ae090
Add stories + special handling for story/docs loading
tmeasday Nov 9, 2021
b09fa6e
Show "Loading..." while switching between async stories
tmeasday Nov 1, 2021
3f27619
Hooked up preparing story/docs views
tmeasday Nov 9, 2021
90d7978
Wrote HTML and CSS for loading states and improved ArgsTable loading …
MichaelArestad Nov 9, 2021
49c92e1
Added styling for IconButtonSkeleton
MichaelArestad Nov 9, 2021
e7a2cea
Remove unused component
MichaelArestad Nov 9, 2021
ec0f60d
Added styles for SourceSkeleton
MichaelArestad Nov 9, 2021
db4d01a
Finessed Source loading state
MichaelArestad Nov 9, 2021
de6e5d6
Further refinement of Source
MichaelArestad Nov 9, 2021
b99370b
Show nicer loading state for modernInlineRender
tmeasday Nov 10, 2021
67d6af1
Try a "loading props" pattern for loading state
tmeasday Nov 11, 2021
2f1a732
Ensure we clear loading state if story is unchanged
tmeasday Nov 11, 2021
200d4fe
Clean up tests for changing preparing state
tmeasday Nov 11, 2021
5a35319
Cleanup a little bit; use old skeleton for now
tmeasday Nov 11, 2021
100401b
Merge branch 'next' into docs-loading-state-v1
shilman Nov 12, 2021
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
4 changes: 1 addition & 3 deletions addons/docs/src/blocks/ArgsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,7 @@ export const StoryTable: FC<
const story = useStory(storyId, context);
// eslint-disable-next-line prefer-const
let [args, updateArgs, resetArgs] = useArgs(storyId, context);
if (!story) {
return <div>Loading...</div>;
}
if (!story) return <PureArgsTable isLoading />;

const argTypes = filterArgTypes(story.argTypes, include, exclude);

Expand Down
5 changes: 4 additions & 1 deletion addons/docs/src/blocks/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
resetComponents,
Preview as PurePreview,
PreviewProps as PurePreviewProps,
PreviewSkeleton,
} from '@storybook/components';
import { DocsContext, DocsContextProps } from './DocsContext';
import { SourceContext, SourceContextProps } from './SourceContainer';
Expand Down Expand Up @@ -71,7 +72,9 @@ export const Canvas: FC<CanvasProps> = (props) => {
const { isLoading, previewProps } = getPreviewProps(props, docsContext, sourceContext);
const { children } = props;

return isLoading ? null : (
if (isLoading) return <PreviewSkeleton />;

return (
<MDXProvider components={resetComponents}>
<PurePreview {...previewProps}>{children}</PurePreview>
</MDXProvider>
Expand Down
18 changes: 11 additions & 7 deletions addons/docs/src/blocks/Story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import React, {
useContext,
useRef,
useEffect,
useState,
} from 'react';
import { MDXProvider } from '@mdx-js/react';
import global from 'global';
import { resetComponents, Story as PureStory } from '@storybook/components';
import { resetComponents, Story as PureStory, StorySkeleton } from '@storybook/components';
import { StoryId, toId, storyNameFromExport, StoryAnnotations, AnyFramework } from '@storybook/csf';
import { Story as StoryType } from '@storybook/store';
import { addons } from '@storybook/addons';
Expand Down Expand Up @@ -113,13 +114,14 @@ export const getStoryProps = <TFramework extends AnyFramework>(
const Story: FunctionComponent<StoryProps> = (props) => {
const context = useContext(DocsContext);
const channel = addons.getChannel();
const ref = useRef();
const storyRef = useRef();
const storyId = getStoryId(props, context);
const story = useStory(storyId, context);
const [showLoader, setShowLoader] = useState(true);

useEffect(() => {
let cleanup: () => void;
if (story && ref.current) {
if (story && storyRef.current) {
const { componentId, id, title, name } = story;
const renderContext = {
componentId,
Expand All @@ -136,14 +138,15 @@ const Story: FunctionComponent<StoryProps> = (props) => {
cleanup = context.renderStoryToElement({
story,
renderContext,
element: ref.current as HTMLElement,
element: storyRef.current as HTMLElement,
});
setShowLoader(false);
}
return () => cleanup && cleanup();
}, [story]);

if (!story) {
return <div>Loading...</div>;
return <StorySkeleton />;
}

// If we are rendering a old-style inline Story via `PureStory` below, we want to emit
Expand All @@ -158,7 +161,7 @@ const Story: FunctionComponent<StoryProps> = (props) => {

if (global?.FEATURES?.modernInlineRender) {
// We do this so React doesn't complain when we replace the span in a secondary render
const htmlContents = `<span data-is-loading-indicator="true">loading story...</span>`;
const htmlContents = `<span></span>`;

// FIXME: height/style/etc. lifted from PureStory
const { height } = storyProps;
Expand All @@ -168,8 +171,9 @@ const Story: FunctionComponent<StoryProps> = (props) => {
{height ? (
<style>{`#story--${story.id} { min-height: ${height}; transform: translateZ(0); overflow: auto }`}</style>
) : null}
{showLoader && <StorySkeleton />}
<div
ref={ref}
ref={storyRef}
data-name={story.name}
dangerouslySetInnerHTML={{ __html: htmlContents }}
/>
Expand Down
7 changes: 6 additions & 1 deletion addons/docs/src/blocks/useStory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ export function useStories<TFramework extends AnyFramework = AnyFramework>(
storyIds: StoryId[],
context: DocsContextProps<TFramework>
): (Story<TFramework> | void)[] {
const [storiesById, setStories] = useState({} as Record<StoryId, Story<TFramework>>);
const initialStoriesById = context.componentStories().reduce((acc, story) => {
acc[story.id] = story;
return acc;
}, {} as Record<StoryId, Story<TFramework>>);

const [storiesById, setStories] = useState(initialStoriesById as typeof initialStoriesById);

useEffect(() => {
Promise.all(
Expand Down
6 changes: 4 additions & 2 deletions lib/components/src/bar/button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';

import { IconButton } from './button';
import { IconButton, IconButtonSkeleton } from './button';
import { Icons } from '../icon/icon';

export default {
component: IconButton,
title: 'Basics/IconButton',
};

/* eslint-disable-next-line no-underscore-dangle */
export const Loading = () => <IconButtonSkeleton />;

// eslint-disable-next-line no-underscore-dangle
export const _IconButton = () => (
<IconButton>
<Icons icon="bookmark" />
Expand Down
17 changes: 17 additions & 0 deletions lib/components/src/bar/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,20 @@ export const IconButton = styled(ButtonOrLink, { shouldForwardProp: isPropValid
}
);
IconButton.displayName = 'IconButton';

const IconPlaceholder = styled.div(({ theme }) => ({
width: 14,
height: 14,
backgroundColor: theme.appBorderColor,
animation: `${theme.animation.glow} 1.5s ease-in-out infinite`,
}));

const IconButtonSkeletonWrapper = styled.div(() => ({
padding: 5,
}));

export const IconButtonSkeleton = () => (
<IconButtonSkeletonWrapper>
<IconPlaceholder />
</IconButtonSkeletonWrapper>
);
2 changes: 2 additions & 0 deletions lib/components/src/blocks/ArgsTable/ArgRow.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const Template = (args) => <ArgRow {...args} />;
const baseArgs = {
updateArgs: action('updateArgs'),
};
export const Loading = Template.bind({});
Loading.args = { isLoading: true };

export const String = Template.bind({});
String.args = {
Expand Down
17 changes: 15 additions & 2 deletions lib/components/src/blocks/ArgsTable/ArgRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ArgValue } from './ArgValue';
import { ArgControl, ArgControlProps } from './ArgControl';
import { codeCommon } from '../../typography/shared';

export interface ArgRowProps {
interface ArgRowData {
row: ArgType;
arg: any;
updateArgs?: (args: Args) => void;
Expand All @@ -17,6 +17,17 @@ export interface ArgRowProps {
initialExpandedArgs?: boolean;
}

interface ArgRowLoading {
isLoading: true;
}

export const argRowLoadingData: ArgRowData = {
row: { name: 'loading', description: 'loading' },
arg: 0,
};

export type ArgRowProps = ArgRowData | ArgRowLoading;

const Name = styled.span({ fontWeight: 'bold' });

const Required = styled.span(({ theme }) => ({
Expand Down Expand Up @@ -73,7 +84,9 @@ const StyledTd = styled.td<{ expandable: boolean }>(({ theme, expandable }) => (
}));

export const ArgRow: FC<ArgRowProps> = (props) => {
const { row, updateArgs, compact, expandable, initialExpandedArgs } = props;
// const isLoading = 'isLoading' in props;
const { row, updateArgs, compact, expandable, initialExpandedArgs } =
'row' in props ? props : argRowLoadingData;
const { name, description } = row;
const table = (row.table || {}) as TableAnnotation;
const type = table.type || row.type;
Expand Down
2 changes: 2 additions & 0 deletions lib/components/src/blocks/ArgsTable/ArgsTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const longEnumType = ArgRow.LongEnum.args.row;

const Template = (args) => <ArgsTable {...args} />;

export const Loading = Template.bind({});
Loading.args = { isLoading: true };
export const Normal = Template.bind({});
Normal.args = {
rows: {
Expand Down
Loading