mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-05 08:01:20 +08:00
Make sure the render functions is a proper react components
This commit is contained in:
parent
5b4401b2e1
commit
69dee4cde6
@ -246,7 +246,7 @@ export interface StoryContext<TRenderer extends Renderer = Renderer, TArgs = Arg
|
||||
abortSignal: AbortSignal;
|
||||
canvasElement: TRenderer['canvasElement'];
|
||||
hooks: unknown;
|
||||
originalStoryFn: StoryFn<TRenderer>;
|
||||
originalStoryFn: ArgsStoryFn<TRenderer>;
|
||||
viewMode: ViewMode;
|
||||
step: StepFunction<TRenderer, TArgs>;
|
||||
context: this;
|
||||
|
14
code/renderers/react/src/applyDecorators.ts
Normal file
14
code/renderers/react/src/applyDecorators.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
|
||||
import type { DecoratorFunction, LegacyStoryFn } from 'storybook/internal/types';
|
||||
|
||||
import { defaultDecorateStory } from 'storybook/preview-api';
|
||||
|
||||
import type { ReactRenderer } from './types';
|
||||
|
||||
export const applyDecorators = (
|
||||
storyFn: LegacyStoryFn<ReactRenderer>,
|
||||
decorators: DecoratorFunction<ReactRenderer>[]
|
||||
): LegacyStoryFn<ReactRenderer> => {
|
||||
return defaultDecorateStory((context) => React.createElement(storyFn, context), decorators);
|
||||
};
|
@ -1,7 +1,6 @@
|
||||
import type { DecoratorFunction, LegacyStoryFn } from 'storybook/internal/types';
|
||||
|
||||
import { defaultDecorateStory } from 'storybook/preview-api';
|
||||
|
||||
import { applyDecorators as defaultDecorateStory } from '../applyDecorators';
|
||||
import type { ReactRenderer } from '../types';
|
||||
import { jsxDecorator } from './jsxDecorator';
|
||||
|
||||
|
@ -264,10 +264,7 @@ export const jsxDecorator = (
|
||||
...(context?.parameters.jsx || {}),
|
||||
} as Required<JSXOptions>;
|
||||
|
||||
// Exclude decorators from source code snippet by default
|
||||
const storyJsx = context?.parameters.docs?.source?.excludeDecorators
|
||||
? (context.originalStoryFn as ArgsStoryFn<ReactRenderer>)(context.args, context)
|
||||
: story;
|
||||
const storyJsx = context.originalStoryFn(context.args, context);
|
||||
|
||||
const sourceJsx = mdxToJsx(storyJsx);
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const parameters = { renderer: 'react' };
|
||||
export { render } from './render';
|
||||
export { renderToCanvas } from './renderToCanvas';
|
||||
export { mount } from './mount';
|
||||
export { applyDecorators } from './applyDecorators';
|
||||
|
||||
export const decorators: Decorator[] = [
|
||||
(story, context) => {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import type { FC } from 'react';
|
||||
import React, { createContext, useContext } from 'react';
|
||||
import React, { createContext, useContext, useState } from 'react';
|
||||
|
||||
import { useParameter } from 'storybook/internal/preview-api';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
@ -29,11 +31,11 @@ export const All: StoryObj<typeof Component> = {
|
||||
],
|
||||
};
|
||||
|
||||
// This story will error if `parameters.docs.source.excludeDecorators` is true:
|
||||
// This story should not error
|
||||
// See https://github.com/storybookjs/storybook/issues/21900
|
||||
const TestContext = createContext<boolean>(false);
|
||||
export const Context: StoryObj<typeof Component> = {
|
||||
// parameters: { docs: { source: { excludeDecorators: true } } },
|
||||
parameters: { docs: { source: { excludeDecorators: true } } },
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<TestContext.Provider value>
|
||||
@ -50,3 +52,29 @@ export const Context: StoryObj<typeof Component> = {
|
||||
return <p>Story</p>;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* This story demonstrates is a regression test for this issue with React hooks in Storybook
|
||||
* (https://github.com/storybookjs/storybook/issues/29189)
|
||||
*
|
||||
* Which happened when a decorator was using storybook hooks, and the render react hooks.
|
||||
*/
|
||||
export const AllowUseStateInRender: StoryObj = {
|
||||
render: () => {
|
||||
const [count, setCount] = useState(0);
|
||||
const Button = (globalThis as any).Components.Button;
|
||||
return <Button onClick={() => setCount(count + 1)} label={`Clicked ${count} times`} />;
|
||||
},
|
||||
decorators: [
|
||||
(storyFn) => {
|
||||
useParameter('docs', {});
|
||||
return storyFn();
|
||||
},
|
||||
],
|
||||
play: async ({ canvas, userEvent }) => {
|
||||
const button = await canvas.findByText('Clicked 0 times');
|
||||
await userEvent.click(button);
|
||||
await canvas.findByText('Clicked 1 times');
|
||||
},
|
||||
tags: ['!vitest'],
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user