storybookjs / storybook

Storybook is the industry standard workshop for building, documenting, and testing UI components in isolation
https://storybook.js.org
MIT License
84.61k stars 9.31k forks source link

Addon-docs: Resize iframe to fit content #8112

Open bmayen opened 5 years ago

bmayen commented 5 years ago

Is your feature request related to a problem? Please describe. Sometimes the component being displayed in Docs is only a few px tall, yet the iframe defaults to 500px. When you have a lot of these stories stacked, there is a lot of empty space.

Describe the solution you'd like After iframe loads, have it resize to fit the content

Describe alternatives you've considered Can set styles to manually override the iframe height per-story, but this is difficult/tedious to maintain

Aaron-Pool commented 5 years ago

@bmayen what framework are you using? I'm assuming it isn't react?

If that's correct, see here (particularly read the documentation added in the PR about inline rendering): https://github.com/storybookjs/storybook/pull/7929

bmayen commented 5 years ago

Correct, I'm using Angular. So, sounds like while you've done some amazing work for Vue, Angular is still stuck with fixed size iframes for now.

bmayen commented 5 years ago

Agreed that wrapping Angular components in Angular Elements seems like the logical next step for prepareForInline. I have some experience with that so I may be able to contribute here if I can find some time. Thanks for pointing me in the right direction.

bmayen commented 5 years ago

@shilman, once prepareForInline functionality is merged, do you have any thoughts on where support for angular should live? I could open a PR to add an Angular Elements wrapper for this.

Aaron-Pool commented 5 years ago

@bmayen it's possible that @shilman may have different ideas, but based on the current PR it would logically exist in the addon-docs/preset/angular folder.

bmayen commented 5 years ago

Going to close this and open a new issue to track Angular prepareForInline support.

bmayen commented 5 years ago

https://github.com/storybookjs/storybook/issues/8153

shilman commented 5 years ago

I think there are two separate issues. Apparently there are libraries to automatically resize iframes on based on content, and we should support that IN ADDITION TO supporting inline rendering support for angular. Reopening! 😄

herman-rogers commented 5 years ago

Is there a PR open for the automatic resize of iframes for angular? Happy to help contribute.

shilman commented 5 years ago

@herman-rogers that would be awesome! it would need to happen in the storybook UI, which is written in React. Are you ok with that?

herman-rogers commented 5 years ago

@shilman yea that works for me, I've used react pretty extensively.

dawidurbanski commented 4 years ago

Since Angular is not mentioned in the title of this issue, I'm not going to open another one.

I've just tried a basic, pristine installation of storybook for HTML and storybook docs. It's extremely annoying to have 500px height on each component preview iframe.

Not sure how much of work is this, but I think it should also support a plain HTML templates.

Screenshot:

localhost_6006__path=_docs_demo--heading(Laptop with MDPI screen)

shilman commented 4 years ago

@dawidurbanski yeah, this is not angular specific. it's about automatically detecting the size of the contents of an iframe, no matter what its contents are. any interest in taking this on?

dawidurbanski commented 4 years ago

@shilman Yes, I'll play around with it and share my thoughts and eventually raise a PR with POC. No promises though.

yuriyward commented 4 years ago

Any updates? I would say that it is really important feature..

shilman commented 4 years ago

@victorward any interest in contributing it?

dawidurbanski commented 4 years ago

@victorward @shilman

I made a simple POC to add this feature but it's not ideal.

First of all, it allows now to set iframeHeight to auto in storybook preview.js parameters. If specified otherwise or not set at all it works as before (defaults to 500px) so it's backwards compatible.

Screen from the html-kitchen-sink:

localhost_9007__path=_docs_addons-a11y--default(Laptop with MDPI screen) (1)

There are two problems though:

  1. It's not working well for delayed iframe content loading:
Screenshot 2020-06-21 at 2 42 10 AM
  1. It's not working well with the Addons/Centered feature (but imho it's the addon fault):
Screenshot 2020-06-21 at 2 42 23 AM

It's because it uses fixed positioning and therefore messing with the computed contents height:

Screenshot 2020-06-21 at 2 42 50 AM

I'm looking into fixing the first one, the second one is in my opinion just a matter of documenting this behaviour (saying autoHeight is not compatible with centered addon) or fixing this addon separately.

I'm gonna push the PR as soon as I'm done with it.

shilman commented 4 years ago

@dawidurbanski That's awesome!!! I agree that the centered addon isn't a problem: we're deprecating it in 6.0: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#removed-addon-centered

As for the delayed rendering, there is probably a Storybook event like Events.STORY_RENDERED you can listen to in order to trigger the code. This will be even more important in 6.1 when we introduce proper asynchronous stories. https://github.com/storybookjs/storybook/pull/11012

dawidurbanski commented 4 years ago

@shamin Well, using any api related events would be very difficult in this case I think (but I might be wrong).

First of all I don't think STORY_RENDERED is aware of async code execution inside stories. It just fires on simple story render regardless of async execution status.

Second problem is that currently docs addon is not using any component in the render method so I don't have any way to pass api down:

addons.register(ADDON_ID, api => {
  addons.add(PANEL_ID, {
    type: types.TAB,
    title: 'Docs',
    route: ({ storyId }) => `/docs/${storyId}`,
    match: ({ viewMode }) => viewMode === 'docs',
    render: () => null,
  });
});

Adding such component is beyond my understanding of how storybook internals work unfortunately. Also I don't think it would help.

I also believe that the only way to make it work is so the story itself is sending an info about the asnyc code completion status.

The solution in my opinion is to force stories using async code (and still wanting to get autoHeight feature) to inform parent renderer window about async code completion by emitting native CustomEvent that can be handled in the Iframe.tsx.

So it could look like this (on an example of delayed render story from html-kitchen-sink):

import { document, parent, setTimeout, CustomEvent } from 'global';
...

export const Story = () => {
  const div = document.createElement('div');
  setTimeout(() => {
    div.innerHTML = `<button>This button has a delayed render of 1s</button>`;
    parent.document.dispatchEvent(new CustomEvent('iframeUpdated'));
  }, 1000);
  return div;
};
Story.story = { name: 'Delayed render' };

This way I can handle updating iframe height in the right moment

Screenshot 2020-06-21 at 4 58 16 AM

Let me know if it's a viable solution, or should I dig deeper into it. Thanks.

kubijo commented 4 years ago

One that this possible touches on & that I am currently trying to figure out is a case when you render modals in docs tab. When it's in inline mode, all tabs seem to have all modals rendered at the same time. When I disable the inline mode to render components in iframes, it does render them, but doesn't update when changing args & the modals are too small (ideally I'd like to set a minHeight for the modal on a per-story basis.

shilman commented 4 years ago

@kubijo we'll hopefully get a fix for the iframe args updating here https://github.com/storybookjs/storybook/issues/11908

github-actions[bot] commented 4 years ago

Automention: Hey @patricklafrance, you've been tagged! Can you give a hand here?

guaiamum commented 3 years ago

Hey @shilman , @ghengeveld , do we have any news on this? I'm really confused, as the docs suggest this is already possible, I just don't understand how!

Screenshot 2021-07-29 at 13 54 53

I'm happy to lend a hand on the PR to be able to set the height of the iframe in the docsPage, like this:

parameters: {
    docs: {
      inlineStories: false,
      iframe: {
        height: '750px'
      }
    },
shilman commented 3 years ago

@guaiamum you can set the height already using the docs.iframeHeight parameter. This issue is about making the iframes AUTOMATICALLY resize to fit the content, which is unimplemented.

ghengeveld commented 3 years ago

For context: I've recently been working on dynamically changing an iframe's height based on the story canvas height for the purpose of embedding, by implementing Provider Height Resizing. This can serve as the basis for dynamic canvas height in Docs as we well.

guaiamum commented 3 years ago

@guaiamum you can set the height already using the docs.iframeHeight parameter. This issue is about making the iframes AUTOMATICALLY resize to fit the content, which is unimplemented.

Thanks! I did not find that in the docs, did I miss it or would be a good idea to add it right next to the line I highlighted?

drik98 commented 2 years ago

I would really appreciate if you add docs.iframeHeight to the docs.

On the documentation for DocsPage it says

But using an iframe has disadvantages. For example, you have to set the height of iframe stories explicitly,

But then it does not say how and the only way to find out is too find a semi related github issue which mentions it.

jordanwoodroffe commented 2 years ago

Still not fixed, bump

mayankav commented 2 years ago

update on this? @shilman

shilman commented 2 years ago

cc @jreinhold

JReinhold commented 2 years ago

So in summary there are two issues being discussed here:

  1. parameters.docs.iframeHeight is undocumented, which is a shame.

Anyone is free to pick this up and do a PR for it. @guaiamum's suggestion of where to add it to the docs seems good to me. The gist is: parameters.docs.iframeHeight can be a number that defines the min height in pixels - so not "200px" but just 200. It defaults to 100.

  1. The iframes don't automatically get resized based on their content, which would be nice.

I agree that this would improve the DX of iframes in docs. It's non-trivial, because only content within the iframe can know its size, but we want to set it from the outside. I imagine we can inject a script in the iframe that measures the root element and then does a postMessage to let the docs UI know it's preferred size, after witch the iframe element is resized.

caveats:

goodwinchris commented 1 year ago

For what its worth, I've found issues forcing a height on a story. When adding a height:

<Canvas>
  <Story story={stories.Default} height="70px" />
</Canvas>

Storybook is generating this CSS:

#story--components-textarea--default {
  min-height: 70px;
  transform: translateZ(0);
  overflow: auto;
}

That overflow: auto; is breaking my focus outlines:

CleanShot 2023-03-30 at 11 01 53@2x