Skip to content

Commit

Permalink
Merge pull request #21907 from storybookjs/tom/21649-change-react-dec…
Browse files Browse the repository at this point in the history
…orator-order

React: Don't show decorators in JSX snippets
  • Loading branch information
shilman authored Apr 5, 2023
2 parents 05cb5d5 + 55eeb05 commit fcecd47
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 2 deletions.
5 changes: 4 additions & 1 deletion code/lib/preview-api/src/modules/addons/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ function hookify<TRenderer extends Renderer>(
decorator: DecoratorFunction<TRenderer>
): DecoratorFunction<TRenderer>;
function hookify<TRenderer extends Renderer>(fn: AbstractFunction) {
return (...args: any[]) => {
const hookified = (...args: any[]) => {
const { hooks }: { hooks: HooksContext<TRenderer> } =
typeof args[0] === 'function' ? args[1] : args[0];

Expand Down Expand Up @@ -172,6 +172,9 @@ function hookify<TRenderer extends Renderer>(fn: AbstractFunction) {
hooks.currentDecoratorName = prevDecoratorName;
return result;
};

hookified.originalFn = fn;
return hookified;
}

// Counter to prevent infinite loops.
Expand Down
19 changes: 19 additions & 0 deletions code/renderers/react/src/applyDecorators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { defaultDecorateStory } from '@storybook/preview-api';
import type { LegacyStoryFn, DecoratorFunction } from '@storybook/types';

import type { ReactRenderer } from './types';
import { jsxDecorator } from './docs/jsxDecorator';

export const applyDecorators = (
storyFn: LegacyStoryFn<ReactRenderer>,
decorators: DecoratorFunction<ReactRenderer>[]
): LegacyStoryFn<ReactRenderer> => {
// @ts-expect-error originalFn is not defined on the type for decorator. This is a temporary fix
// that we will remove soon (likely) in favour of a proper concept of "inner" decorators.
const jsxIndex = decorators.findIndex((d) => d.originalFn === jsxDecorator);

const reorderedDecorators =
jsxIndex === -1 ? decorators : [...decorators.splice(jsxIndex, 1), ...decorators];

return defaultDecorateStory(storyFn, reorderedDecorators);
};
2 changes: 2 additions & 0 deletions code/renderers/react/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export const parameters = { renderer: 'react', ...docsParams };
export { decorators, argTypesEnhancers } from './docs/config';

export { render, renderToCanvas } from './render';

export { applyDecorators } from './applyDecorators';
22 changes: 21 additions & 1 deletion code/renderers/react/template/stories/decorators.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { FC } from 'react';
import React from 'react';
import React, { useContext, createContext } from 'react';
import type { StoryObj, Meta } from '@storybook/react';

const Component: FC = () => <p>Story</p>;

export default {
component: Component,
tags: ['autodocs'],
decorators: [
(Story) => (
<>
Expand All @@ -26,3 +27,22 @@ export const All: StoryObj<typeof Component> = {
),
],
};

// This story will error if `parameters.docs.source.excludeDecorators` is true:
// See https://github.com/storybookjs/storybook/issues/21900
const TestContext = createContext<boolean>(false);
export const Context: StoryObj<typeof Component> = {
// parameters: { docs: { source: { excludeDecorators: true } } },
decorators: [
(Story) => (
<TestContext.Provider value>
<Story />
</TestContext.Provider>
),
],
render: function Render(args, context) {
const value = useContext(TestContext);
if (!value) throw new Error('TestContext not set, decorator did not run!');
return <p>Story</p>;
},
};

0 comments on commit fcecd47

Please sign in to comment.