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

Displaying imported HTML in Storysource #8297

Closed
danhead opened this issue Oct 4, 2019 · 30 comments
Closed

Displaying imported HTML in Storysource #8297

danhead opened this issue Oct 4, 2019 · 30 comments

Comments

@danhead
Copy link

danhead commented Oct 4, 2019

Support request summary

I would like to be able to display imported HTML in the Storysource panel, rather than the contents of the .stories.js file.

Steps to reproduce

  1. Create a new package and create/amend the two files below:

html/button.html:

<button>Hello world</button>

stories/index.stories.js:

import button from '../html/button.html';

export default {
  title: 'Demo',
};

export const Button = () => button;
  1. Set up Storysource addon as per package README

.storybook/addons.js

import '@storybook/addon-storysource/register';

.storybook/webpack.config.js

module.exports = function({ config }) {
  config.module.rules.push({
    test: /\.stories\.jsx?$/,
    loaders: [require.resolve('@storybook/source-loader')],
    enforce: 'pre',
  });

  return config;
};

Please specify which version of Storybook and optionally any affected addons that you're running

  • @babel/core@7.6.2
  • @storybook/addon-storysource@5.2.1
  • @storybook/html@5.2.1
  • babel-loader@8.0.6

Expected result

I would like the Storysource panel to display the contents of html/button.html

Actual result

Storysource panel shows contents of stories/index.stories.js

image

Any advice on how to achieve this is greatly appreciated.

Thanks!

@danhead
Copy link
Author

danhead commented Oct 17, 2019

Just a quick follow up to this, in older versions of @storybook/html (v5.1.9) I used to do this with success:

.storybook/config.js

import { withStorySource } from '@storybook/addon-storysource';
addDecorator((storyFn, context) => {
  const source = storyFn()
  return withStorySource(source)(storyFn, context)
})

However with @storybook/html@5.2.x upwards I get the following error with this technique:

storybook_ui_dll.js:2 TypeError: Cannot read property 'source' of undefined
    at StoryPanel._this.listener (main.8e749501743145db6330.bundle.js:9344)
    at storybook_ui_dll.js:2
    at Array.forEach (<anonymous>)
    at t.value (storybook_ui_dll.js:2)
    at PostmsgTransport.<anonymous> (storybook_ui_dll.js:2)
    at PostmsgTransport.handler (main.8e749501743145db6330.bundle.js:10423)
    at PostmsgTransport.handleEvent (main.8e749501743145db6330.bundle.js:1051

@danhead
Copy link
Author

danhead commented Oct 17, 2019

I believe this is the change that has introduced the issue: https://github.com/storybookjs/storybook/pull/7272/files#diff-904dad7f92c7bbfac64aca74960bbf33

@shilman
Copy link
Member

shilman commented Oct 18, 2019

@libetl do you have any time to look at @danhead 's error above?

storybook_ui_dll.js:2 TypeError: Cannot read property 'source' of undefined
at StoryPanel._this.listener (main.8e749501743145db6330.bundle.js:9344)
at storybook_ui_dll.js:2
at Array.forEach ()
at t.value (storybook_ui_dll.js:2)
at PostmsgTransport. (storybook_ui_dll.js:2)
at PostmsgTransport.handler (main.8e749501743145db6330.bundle.js:10423)
at PostmsgTransport.handleEvent (main.8e749501743145db6330.bundle.js:1051

@stale stale bot added the inactive label Nov 8, 2019
@stale stale bot closed this as completed Dec 8, 2019
@shilman shilman added the todo label Dec 9, 2019
@storybookjs storybookjs deleted a comment from stale bot Dec 9, 2019
@storybookjs storybookjs deleted a comment from stale bot Dec 9, 2019
@LeeBurton
Copy link

LeeBurton commented Jan 16, 2020

@shilman You added a "TODO" label but didn't re-open the issue. It still appears to have problems, which appear to be related to the changes mentioned by @danhead:

https://github.com/storybookjs/storybook/pull/7272/files#diff-904dad7f92c7bbfac64aca74960bbf33

I am trying to use the following:

.addDecorator(withStorySource('my test source'))

(to overwrite the source inserted automatically by register) but nothing changes in the Storysource panel.

I debugged the "storybook/source-loader/set" event parameters, and the source added by register has the following event parameters:

edition: {source: '...', …}, story: {…}, location: {…}

but the events triggered by "withStorysource" have the following event parameters:

source: "my test source", currentLocation: undefined, locationsMap: {…}

I guess that setStorySource() needs updating to work with the new format?

@LeeBurton
Copy link

LeeBurton commented Jan 20, 2020

@shilman @igor-dv @libetl

I created a pull request with a fix for the issue I described above:

https://github.com/storybookjs/storybook/pull/9561

If you try to use withStorySource(source) in addDecorator, and the '@storybook/source-loader' is added to the storybook webpack config, with "injectDecorator" set to true, the story decorators are executed first, then overwritten by the decorators injected by the webpack loader... is this expected behaviour? I would expect the injected decorator to load first, followed by the global stories decorator, followed by story-specific changes...

If this is the expected behaviour, how can I override it so that I can overwrite the storysource in specific stories?

@atanasster
Copy link
Member

@LeeBurton thanks for taking the time to file this pull request.

For 6+, storybook is moving away from addDecorator: #9506 and I just filed a refactor of source-loader here: #9547

Would you like us to work together on adapting your use case to use parameters instead of addDecorator with the new code base?

@shilman ?

@atanasster
Copy link
Member

@LeeBurton
Copy link

LeeBurton commented Jan 20, 2020

We are using the HTML version to include web components, rather than React, so I guess that we are a little limited with what we can do in the stories.

It would be useful if I could somehow set a parameter within the stories, then access that parameter within a global decorator to emit an event to update the source panel.

Currently, the only solution I have found is to emit the event in the stories. This also solves the problem that the Webpack loader injected decorator story source is overwriting the story decorator source (but only with my pull request changes, otherwise the wrong parameters are provided to emit().

This is causing me real difficulties on my client’s project, and I’m struggling to make progress after trying various solutions for a week 😳

When is version 6 scheduled to be released?

@LeeBurton
Copy link

Plus, this should also be tagged as a bug, I guess.

@atanasster
Copy link
Member

@LeeBurton - did you check the example, it does not use events at all and this makes it to also work for the docs tab (the source-loader events were only working for the StorySource panel):

import button from './button.html';

 export default {
   title: 'Addons/Source loader',
 };

 export const Button = () => button;
 Button.story = {
   parameters: {
     storySource: {
       source: button,
     },
   },
 };

@LeeBurton
Copy link

I’ll explain a little more about what I’m trying to achieve, as I’m not sure how this helps with my problem.

The story uses a template string with our custom elements, such as:

<my-grid title=“my title” rows=3> </my-grid>

and I am then populating it with data by setting the “data” attribute.

So I need to document our grid component HTML code, but also the necessary code populating various attributes, including the example JSON data.

The grid component includes pagination. When a paging button is clicked, the next page of data is fetched from the backend API and used to update the “data” attribute. I need to show the developers how the data is changing when events such as paging occurs.

@atanasster
Copy link
Member

Thanks @LeeBurton I think we can have a 'dynamic' storySource parameter - ie a function that will be called at runtime, so you can entirely customize what source code to display for the developers.

@shilman - any thoughts?

@shilman
Copy link
Member

shilman commented Jan 21, 2020

@atanasster @LeeBurton Parameters cascade, so global parameters can be overridden at a story level, just as you have done in your comment above @atanasster . I don't think we need to do anything special to support user configuration. Maybe just better documentation on how to do it.

@LeeBurton
Copy link

  1. withSource(...) doesn’t work when the source loader is used in webpack. It injects a decorator which overwrites the value set by the withSource decorator. The same goes for storySource added to a story’s parameters...

  2. How can parameters be updated dynamically within a story?

@shilman
Copy link
Member

shilman commented Jan 21, 2020

you can create separate stories for each state that you want to show. in the future we may try to support more interaction scenarios, but we have our hands pretty full with doing a great job of simply showing every state. you can also link between stories with addon-links to fake interactivity.

@LeeBurton
Copy link

I greatly appreciate the hard work you guys are doing, but any assistance in achieving my goals would be greatly appreciated. My client is a government department responsible for building web components that various other government departments can use, and we are trying to convince them that Storybook is the best choice for documenting their components for developers in the other departments. If we cannot make progress quickly, they may start looking at other options.

For this particular component, I have a story that uses knobs, and interactions.

I need to be able to show documentation for the current story HTML with the attributes set (which I could get from storyFn() in a decorator) and also include JavaScript code. I am also listening to events within the story, by getting the element in useEffect() using document.querySelector() and then adding event listeners. when the listeners fire, I want to be able to update the documentation. Although, it seems a bit messy having to implement it like this... Are there better ways without cluttering the stories?

Is it not currently possible to update a parameter in stories (that I can access in a decorator)?

@shilman
Copy link
Member

shilman commented Jan 21, 2020

As far as I know it's not possible to update parameters dynamically this way.

@atanasster and @ndelangen have been working on powerful addon APIs (shared state hooks) that could make sharing state between stories & addons much easier. It might be fairly easy to implement your use case using that shared state hook, and not have to deal with the entirety of storysource for that purpose.

@atanasster
Copy link
Member

@LeeBurton as michael mentioned, its not possible to modify parameters dynamically.
However we can add a dynamic property source that would allow you to do pretty much the same thing. The best thing would be if you can join and test the upcoming sb6 alphas and give us feedback on the discord channel until me make it work as best as we can for your use case.

@LeeBurton
Copy link

Okay, thanks. Unfortunately, I’m too much under pressure with my client’s project at the moment. If I have more time later, I’d love to help. When is v.6.0 release planned?

When will my bug fix pull request likely be merged to fix the storySource event parameters to the correct format? Currently my workaround won’t work without these changes merged...

@LeeBurton
Copy link

@LeeBurton - did you check the example, it does not use events at all and this makes it to also work for the docs tab (the source-loader events were only working for the StorySource panel):

import button from './button.html';

 export default {
   title: 'Addons/Source loader',
 };

 export const Button = () => button;
 Button.story = {
   parameters: {
     storySource: {
       source: button,
     },
   },
 };

@atanasster When I set the storySource.source parameter, it does nothing. It just says “Loading source...” 😳

@atanasster
Copy link
Member

@LeeBurton - are you trying the PR, its not yet merged.

If yes, please try the html-kitchen sink example https://github.com/storybookjs/storybook/pull/9547/files#diff-f9e4c1787dc63502454a68f7ff88245c

@LeeBurton
Copy link

LeeBurton commented Jan 22, 2020

@atanasster I don’t understand what you mean by “are you trying the PR”... which PR? The one you just included?

When are your changes likely to be merged and available?

@atanasster
Copy link
Member

@LeeBurton - yes i meant the listed PR from above.

That PR is meant for 6.0 and @shilman would know about the merging, but i think he is currently very busy with the 5.3 updates.

@shilman
Copy link
Member

shilman commented Jan 23, 2020

I can probably merge/release an alpha today, but I want to do another review & test it first. Juggling a lot.

@lmcmill
Copy link

lmcmill commented Jan 28, 2020

storySource.source - still seems to have no effect, when can we expect this to work?

@shilman
Copy link
Member

shilman commented Jan 29, 2020

Will release this in 6.0-alpha on Thu at earliest, Sat at latest. Currently in a remote area with poor network connection, and unfortunately the release process requires a good connection. Thanks for your patience.

@juniovitorino
Copy link

@LeeBurton - did you check the example, it does not use events at all and this makes it to also work for the docs tab (the source-loader events were only working for the StorySource panel):

import button from './button.html';

 export default {
   title: 'Addons/Source loader',
 };

 export const Button = () => button;
 Button.story = {
   parameters: {
     storySource: {
       source: button,
     },
   },
 };

This works great, now could someone say how write a storydocs for a example like that?

@shilman
Copy link
Member

shilman commented Jun 14, 2020

@juniovitorino like this?

import button from './button.html';

 export default {
   title: 'Addons/Source loader',
 };

 export const Button = () => button;
 Button.story = {
   parameters: {
     storyDescription: 'some description here',
     storySource: {
       source: button,
     },
   },
 };

@radum
Copy link

radum commented Aug 26, 2020

@shilman Am I right that the correct format now is

import button from './button.html';

 export default {
   title: 'Addons/Source loader',
 };

 export const Button = () => button;
 Button.parameters = {
   storyDescription: 'some description here',
   storySource: {
     source: button,
   },
};

Also is this documented anywhere?

@shilman
Copy link
Member

shilman commented Jun 8, 2023

We’re cleaning house! Storybook has changed a lot since this issue was created and we don’t know if it’s still valid. Please open a new issue referencing this one if:

@shilman shilman closed this as not planned Won't fix, can't repro, duplicate, stale Jun 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants