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

Vue3: Fix Conditional decorators #23029

Closed
wants to merge 33 commits into from

Conversation

chakAs3
Copy link
Contributor

@chakAs3 chakAs3 commented Jun 12, 2023

Closes #22945

What I did

How to test

Checklist

  • Make sure your changes are tested (stories and/or unit, integration, or end-to-end tests)
  • Make sure to add/update documentation regarding your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Maintainers

  • If this PR should be tested against many or all sandboxes,
    make sure to add the ci:merged or ci:daily GH label to it.
  • Make sure this PR contains one of the labels below.

["cleanup", "BREAKING CHANGE", "feature request", "bug", "documentation", "maintenance", "dependencies", "other"]

@@ -52,6 +52,7 @@
"@storybook/vue3": "7.1.0-alpha.30",
"@vitejs/plugin-vue": "^4.0.0",
"magic-string": "^0.30.0",
"react": "^18.2.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please elaborate why this is needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll take it back it was a try

* @param {LegacyStoryFn<VueRenderer>} accuDecoratedStoryFn - The accumulator of the decorated story function.
* @param {DecoratorFunction<VueRenderer>} currentDecoratorFn - The current decorator function.
*/
const finalDecoratedStoryFn = decorators.reduce((accuDecoratedStoryFn, currentDecoratorFn) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ndelangen @tmeasday would you mind taking a look? Thanks!

Copy link
Contributor

@kasperpeulen kasperpeulen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

He Chakir,

Thanks for the PR. Can you make it a bit more focused on the problem? I have been trying to solve this as well. I'm sure it can be solved in a way that doesn't involve applying args twice, which we already discussed as something we don't want to do in SB7.

Comment on lines +34 to +35
// Normalize the functional component, and make sure inheritAttrs is set to false
const normalizedStory = { ...normalizeFunctionalComponent(story), inheritAttrs: false };
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this disable attribute fallthough on all the prepared stories including decorated onces,

@chakAs3 chakAs3 requested a review from kasperpeulen June 12, 2023 18:58
@chakAs3 chakAs3 mentioned this pull request Jun 12, 2023
5 tasks
*/
return (context: StoryContext<VueRenderer>) => {
const story = currentDecoratedStory(context);
if (!storyResult) storyResult = accuDecoratedStoryFn(context);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this line mean the later decorators will get called even if the earlier decorator (currentDecoratorFn) never calls the passed storyFn (defined on line 81)?

As an aside it would help me at least (maybe it's obvious to others) to explain what's happening here -- why do we return storyResult sometimes, and other times we call prepare() on it?

Copy link
Contributor Author

@chakAs3 chakAs3 Jun 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exactly @tmeasday if you don't get a deccorated Story from the decorator or the decorator did you call storyFn, we just take the last one. so we can now have decorator that returns null, so we kind of skip them.
so now we can have

(storyFn: PartialStoryFn, context: StoryContext) => context.args.condition? storyFn(): null

Copy link
Contributor Author

@chakAs3 chakAs3 Jun 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we return storyResult sometimes, and other times we call prepare() on it?

we don't need to prepare it because the previous one is already prepared we just return it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can have decorators that have just side effects and not touching the rendering Tree. by doing something like this.

(storyFn: PartialStoryFn, context: StoryContext) => {
       saveData(context.args.data)
      return null
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an aside it would help me at least (maybe it's obvious to others)

😄 I think you are the only one or at least to first one who spotted the Key change in this PR that fix the conditional decorator issue

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can have decorators that have just side effects and not touching the rendering Tree. by doing something like this.

I'm confused. So a decorator that returns null would have "no effect" on rendering, in the sense that later decorators and the story function would still render? That's inconsistent with the other frameworks, and I think the opposite of what we are trying to achieve (consistency in decorator behaviour).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no of course the children won't render since the parent not providing any story, one thing is important I'm sure you know it is rendering should happen down -> up the tree.

decorators.mov

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what I meant no effect on the parent so only if put it like last to run

decorators: [
    // conditional decorator, runs before last
    (storyFn: PartialStoryFn, context: StoryContext) => {
      return context.args.condition
        ? storyFn()
        : null;
    },
    // decorator A that uses hooks
    (storyFn: PartialStoryFn, context: StoryContext) => {
      useEffect(() => {});

      return storyFn({ args: { ...context.args, text: `WrapperA( ${context.args['text']} )` } });
    },
    // decorator B that uses hooks
    (storyFn: PartialStoryFn, context: StoryContext) => {
      useEffect(() => {});

      return storyFn({ args: { ...context.args, text: `WrapperB( ${context.args['text']} )` } });
    },
    
  ],

in this case, won't affect the rendered tree.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a repo on Stackblitz. if you want to test that fast without spawning any sandbox https://stackblitz.com/~/github.com/chakAs3/storybook-vue3-decorators

Copy link
Contributor

@kasperpeulen kasperpeulen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep this PR focused to the actual problem, fixing conditional decorators. Please revert all other changes.

You are really making changes to the core API here, as you are applying args twice, and args are now also available as props. We should not make such big changes to the public API, in a bug fix PR.

@kasperpeulen kasperpeulen removed their assignment Aug 4, 2023
@yannbf
Copy link
Member

yannbf commented Sep 19, 2023

@tmeasday @kasperpeulen what are the next steps in this PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Vue2/3: Fix conditional decorators
4 participants