prantlf / storybook-multilevel-sort

Applies specific sort order to more than two levels of chapters and stories in Storybook.
https://storybook.js.org/addons/storybook-multilevel-sort/
Other
8 stars 4 forks source link

Use the new Framework API? #8

Open jonniebigodes opened 1 year ago

jonniebigodes commented 1 year ago

Hey @prantlf ! I'm one of the Storybook maintainers. I focus primarily on documentation and community outreach. I'm opening up this issue and letting you know that the Storybook API for building addons is currently being updated to factor in the changes introduced by the upcoming 7.0 release. If you're interested in making the required changes to help the community from benefiting from using your addon, we've prepared an abridged guide for the required changes here, and if you have any questions or issues, please reach out to us in the #prerelease channel in our Discord Server.

Hope you have a great day!

Stay safe

prantlf commented 1 year ago

Thank you, @jonniebigodes, for your attention to my humble plugin! I'm sorry for the delay with the update.

I haven't been able to upgrade all my projects yet, because some parts of the ecosystem aren't ready yet (Stencil). But so far, I'm ready to adapt this addon.

Your documentation about the change of the storySort is very helpful. And also alarming :-) Because of this:

NOTE: v7-style sorting is statically analyzed by Storybook, which puts a variety of constraints versus v6:

  • Sorting must be specified in the user's .storybook/preview.js. It cannot be specified by an addon or preset.
  • The preview.js export should not be generated by a function.
  • storySort must be a self-contained function that does not reference external variables.

It appears, that you don't execute preview.js as a JavaScript module any more. It appears, that you parse it to extract the exported object only. This is a problem for external implementations of storySort, which cannot be self-contained, because thy are implemented in a shared NPM module, which needs to be imported. (The configuration can be usually inlined, because it's not usually used beyond one projects.)

I'm trying a workaround "smuggling" data to storySort via globalThis. I'm going to write more about it later tonight.

prantlf commented 1 year ago

The idea how to implement the custom sorting with Storybook 7:

  1. Move the sort function and configuration to main.js:
// the shared sort implementation
import sortStories from 'storybook-multilevel-sort'

// the sort configuration
const storyOrder = { ... }

// make both identifiers above usable from storySort
globalThis['storybook-multilevel-sort'] = { sortStories, storyOrder }
  1. Replace the storySort in preview.js with this code:
export const parameters = {
  options: {
    storySort: (story1, story2) => {
      const { sortStories, storyOrder } = globalThis['storybook-multilevel-sort']
      return sortStories(storyOrder, story1, story2)
    }
  }
}

It feels rather ugly, doesn't it? :-) I made the final interface a little nicer, which is described in the migration instructions. It can be tested with the package storybook-multilevel-sort@2.0.0-next.0.

Alternatively, I could pass the configuration to globalThis using an otherwise empty add-on, for example in main.js:

export default {
  addons: [
    {
      name: 'storybook-multilevel-sort',
      options: {
        storyOrder: { ... }
      }
    }
  ]
}

If storySort had access to anything from the context of the Storybook execution, like add-ons, I wouldn't need the hack with globalThis. For example, an extra parameter could be passed to storySort, which could be filled by some API:

storySort(story1, story2, context)

What do you think, @jonniebigodes?

prantlf commented 1 year ago

I wasn't able to write an addon encapsulating the custom sort. Consuming the sort configuration and exposing the storySort implementation works, with a nice interface in ./storybook/main.js:

const storyOrder = { ... }

export default {
  addons: [
    { name: 'storybook-multilevel-sort', options: { storyOrder } }
  ]
}

However, I couldn't figure out how to supply the storySort parameter as a default from my preview.js. I'd have to copy & paste the same following code to each Storybook projects's ./storybook/preview.js:

export default {
  parameters: { 
    options: {
      storySort: (story1, story2) =>
        globalThis['storybook-multilevel-sort:storySort'](story1, story2)
    }
  }
}

If I can't figure it out, I'll abandon the idea of an addon interface (#11) and merge the pure functional interface to be called in ./storybook/main.js and ./storybook/preview.js explicitly (#10).

prantlf commented 1 year ago

I merged the #10 and released 2.0.0 to allow upgrading to Storybook 7 now. The interface remains functional as it was in versions 1.x. The new limitation of Storybook 7 needs modifying both ./storybook/main.js and ./storybook/preview.js, as mentioned in a comment above and documented in the article about configuration migration.

I'd still like to simplify the interface by converting this package to a Storybook addon. I've kept the half-way conversion in #11 to be able to explore the possibilities in the future.

jrencz commented 1 year ago

Hi, @prantlf can you plz share some update on this one?

prantlf commented 1 year ago

Yes, I can, @jrencz. My previous comment was probably not clear. So:

I'm not happy with the Storybook 7 API, which makes writing addons like this more difficult than the Storybook 6 API, and users of this addon need to edit two configuration files instead of one. But it doesn't mean that the currently available solution doesn't work.