-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
Conversation
@@ -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", |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) => { |
There was a problem hiding this comment.
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!
There was a problem hiding this 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.
code/renderers/vue3/template/stories_vue3-vite-default-ts/ReactiveDecorators.stories.ts
Outdated
Show resolved
Hide resolved
code/renderers/vue3/template/stories_vue3-vite-default-ts/ReactiveDecorators.stories.ts
Outdated
Show resolved
Hide resolved
// Normalize the functional component, and make sure inheritAttrs is set to false | ||
const normalizedStory = { ...normalizeFunctionalComponent(story), inheritAttrs: false }; |
There was a problem hiding this comment.
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,
*/ | ||
return (context: StoryContext<VueRenderer>) => { | ||
const story = currentDecoratedStory(context); | ||
if (!storyResult) storyResult = accuDecoratedStoryFn(context); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 callprepare()
on it?
we don't need to prepare it because the previous one is already prepared we just return it
There was a problem hiding this comment.
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
}
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this 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.
@tmeasday @kasperpeulen what are the next steps in this PR? |
Closes #22945
What I did
How to test
Checklist
MIGRATION.MD
Maintainers
make sure to add the
ci:merged
orci:daily
GH label to it.["cleanup", "BREAKING CHANGE", "feature request", "bug", "documentation", "maintenance", "dependencies", "other"]