From 0ba542f3df8738b8a2f1b5de5647d06f596dd218 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 11 Nov 2022 13:46:24 +0100 Subject: [PATCH 1/5] Story stories --- code/ui/blocks/src/blocks/Story.stories.tsx | 84 ++++++++++++++++++++- code/ui/blocks/src/blocks/Story.tsx | 28 +++---- 2 files changed, 94 insertions(+), 18 deletions(-) diff --git a/code/ui/blocks/src/blocks/Story.stories.tsx b/code/ui/blocks/src/blocks/Story.stories.tsx index bb09d8c635d..bd904d08d68 100644 --- a/code/ui/blocks/src/blocks/Story.stories.tsx +++ b/code/ui/blocks/src/blocks/Story.stories.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { Story as StoryComponent } from './Story'; @@ -13,8 +14,89 @@ export default meta; type Story = StoryObj; -export const BasicOf: Story = { +export const Of: Story = { args: { of: BooleanStories.Undefined, }, }; + +export const OfWithMeta: Story = { + args: { + of: BooleanStories.True, + meta: BooleanStories.default, + }, +}; + +export const Id: Story = { + args: { + id: `${process.env.BLOCKS_ONLY ? '' : 'storybook-blocks-'}controls-boolean--false`, + }, +}; + +export const Name: Story = { + args: { + name: 'True', + }, +}; + +export const Inline: Story = { + args: { + of: BooleanStories.Undefined, + inline: true, + }, + decorators: [ + (Story) => ( + <> + A border has been added to the following story to highlight its final size. +
+ +
+ + ), + ], +}; +export const InlineWithHeight: Story = { + ...Inline, + args: { + of: BooleanStories.Undefined, + inline: true, + height: '300px', + }, +}; +export const Iframe: Story = { + ...Inline, + args: { + of: BooleanStories.Undefined, + inline: false, + }, +}; +export const IframeWithHeight: Story = { + ...Inline, + args: { + of: BooleanStories.Undefined, + inline: false, + height: '300px', + }, +}; + +// export const WithPlay: Story = { +// args: { +// of: BooleanStories.Undefined, +// play: () => { +// throw new Error('This should not play automatically'); +// }, +// parameters: { docs: { autoplay: true } }, +// }, +// }; +// export const WithPlayDisabled: Story = { +// args: { +// of: BooleanStories.Undefined, +// play: () => { +// throw new Error('This should not play automatically'); +// }, +// }, +// }; + +// TODO: types suggest that can take ProjectAnnotations, but it doesn't seem to do anything with them +// Such as parameters, decorators, etc. +// they seem to be taken from the story itself, and not from the call diff --git a/code/ui/blocks/src/blocks/Story.tsx b/code/ui/blocks/src/blocks/Story.tsx index be42c12850d..0bbe8cfac8a 100644 --- a/code/ui/blocks/src/blocks/Story.tsx +++ b/code/ui/blocks/src/blocks/Story.tsx @@ -25,7 +25,6 @@ type CommonProps = StoryAnnotations & { type StoryDefProps = { name: string; - children: ReactNode; }; type StoryRefProps = { @@ -36,7 +35,6 @@ type StoryRefProps = { type StoryImportProps = { name: string; - story: ElementType; }; export type StoryProps = (StoryDefProps | StoryRefProps | StoryImportProps) & CommonProps; @@ -49,8 +47,7 @@ export const getStoryId = (props: StoryProps, context: DocsContextProps): StoryI } const { name } = props as StoryDefProps; - const inputId = id; - return inputId || context.storyIdByName(name); + return id || context.storyIdByName(name); }; export const getStoryProps = ( @@ -87,14 +84,16 @@ const Story: FC = (props) => { const [showLoader, setShowLoader] = useState(true); useEffect(() => { - let cleanup: () => void; - if (story && storyRef.current) { - const element = storyRef.current as HTMLElement; - const { autoplay } = story.parameters.docs || {}; - cleanup = context.renderStoryToElement(story, element, { autoplay }); - setShowLoader(false); + if (!(story && storyRef.current)) { + return () => {}; } - return () => cleanup && cleanup(); + const element = storyRef.current as HTMLElement; + const { autoplay } = story.parameters.docs || {}; + const cleanup = context.renderStoryToElement(story, element, { autoplay }); + setShowLoader(false); + return () => { + cleanup(); + }; }, [context, story]); if (!story) { @@ -115,7 +114,7 @@ const Story: FC = (props) => { return (
{height ? ( - + ) : null} {showLoader && }
= (props) => { ); }; -Story.defaultProps = { - children: null, - name: null, -}; - export { Story }; From 96229e6d00ef0c8345fef8727dabfc1fdfa357b1 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 11 Nov 2022 15:20:57 +0100 Subject: [PATCH 2/5] add interaction stories to Story block --- code/ui/.storybook/main.ts | 3 ++ code/ui/blocks/src/blocks/Story.stories.tsx | 27 ++++------ .../blocks/src/controls/Boolean.stories.tsx | 54 ++++++++++++++++++- code/ui/blocks/src/controls/Boolean.tsx | 10 +++- 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/code/ui/.storybook/main.ts b/code/ui/.storybook/main.ts index 0c7c19bc1c7..0a5bbf2bad8 100644 --- a/code/ui/.storybook/main.ts +++ b/code/ui/.storybook/main.ts @@ -56,6 +56,9 @@ const config: StorybookConfig = { core: { disableTelemetry: true, }, + features: { + interactionsDebugger: true, + }, viteFinal: (vite, { configType }) => ({ ...vite, plugins: [ diff --git a/code/ui/blocks/src/blocks/Story.stories.tsx b/code/ui/blocks/src/blocks/Story.stories.tsx index bd904d08d68..8ef3de1672a 100644 --- a/code/ui/blocks/src/blocks/Story.stories.tsx +++ b/code/ui/blocks/src/blocks/Story.stories.tsx @@ -79,23 +79,16 @@ export const IframeWithHeight: Story = { }, }; -// export const WithPlay: Story = { -// args: { -// of: BooleanStories.Undefined, -// play: () => { -// throw new Error('This should not play automatically'); -// }, -// parameters: { docs: { autoplay: true } }, -// }, -// }; -// export const WithPlayDisabled: Story = { -// args: { -// of: BooleanStories.Undefined, -// play: () => { -// throw new Error('This should not play automatically'); -// }, -// }, -// }; +export const WithDefaultInteractions: Story = { + args: { + of: BooleanStories.Toggling, + }, +}; +export const WithInteractionsAutoplayInStory: Story = { + args: { + of: BooleanStories.TogglingInDocs, + }, +}; // TODO: types suggest that can take ProjectAnnotations, but it doesn't seem to do anything with them // Such as parameters, decorators, etc. diff --git a/code/ui/blocks/src/controls/Boolean.stories.tsx b/code/ui/blocks/src/controls/Boolean.stories.tsx index 726ab58e9b3..82458c745a4 100644 --- a/code/ui/blocks/src/controls/Boolean.stories.tsx +++ b/code/ui/blocks/src/controls/Boolean.stories.tsx @@ -1,10 +1,20 @@ +import { expect } from '@storybook/jest'; import type { Meta, StoryObj } from '@storybook/react'; +import { within, fireEvent } from '@storybook/testing-library'; +import { addons } from '@storybook/addons'; +import { RESET_STORY_ARGS, STORY_ARGS_UPDATED } from '@storybook/core-events'; import { BooleanControl } from './Boolean'; const meta = { component: BooleanControl, tags: ['docsPage'], - parameters: { withRawArg: 'value', controls: { include: ['value'] } }, + parameters: { + withRawArg: 'value', + controls: { include: ['value'] }, + notes: 'These are notes for the Boolean control stories', + info: 'This is info for the Boolean control stories', + jsx: { useBooleanShorthandSyntax: false }, + }, args: { name: 'boolean' }, } as Meta; @@ -26,3 +36,45 @@ export const Undefined: StoryObj = { value: undefined, }, }; + +export const Toggling: StoryObj = { + args: { + value: undefined, + }, + play: async ({ canvasElement, id }) => { + const channel = addons.getChannel(); + + channel.emit(RESET_STORY_ARGS, { storyId: id }); + await new Promise((resolve) => { + channel.once(STORY_ARGS_UPDATED, resolve); + }); + + const canvas = within(canvasElement); + + // from Undefined to False + const setBooleanControl = canvas.getByText('Set boolean'); + await fireEvent.click(setBooleanControl); + + let toggle = await canvas.findByTitle('Change to true'); + expect(toggle).toBeInTheDocument(); + + // from False to True + await fireEvent.click(toggle); + toggle = await canvas.findByTitle('Change to false'); + expect(toggle).toBeInTheDocument(); + + // from True to False + await fireEvent.click(toggle); + toggle = await canvas.findByTitle('Change to true'); + expect(toggle).toBeInTheDocument(); + }, +}; + +export const TogglingInDocs: StoryObj = { + ...Toggling, + parameters: { + docs: { + autoplay: true, + }, + }, +}; diff --git a/code/ui/blocks/src/controls/Boolean.tsx b/code/ui/blocks/src/controls/Boolean.tsx index 8abec1e3490..556701febca 100644 --- a/code/ui/blocks/src/controls/Boolean.tsx +++ b/code/ui/blocks/src/controls/Boolean.tsx @@ -86,6 +86,11 @@ const Label = styled.label(({ theme }) => ({ const parse = (value: string | null): boolean => value === 'true'; export type BooleanProps = ControlProps & BooleanConfig; +/** + * # Boolean control + * Renders a switch toggle with "True" or "False". + * or if the value is `undefined`, renders a button to set the boolean. + */ export const BooleanControl: FC = ({ name, value, onChange, onBlur, onFocus }) => { const onSetFalse = useCallback(() => onChange(false), [onChange]); if (value === undefined) { @@ -95,13 +100,14 @@ export const BooleanControl: FC = ({ name, value, onChange, onBlur ); } + const controlId = getControlId(name); const parsedValue = typeof value === 'string' ? parse(value) : value; return ( -