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

Storybook: Support proper extraction of TypeScript prop types #38842

Merged
merged 25 commits into from
Mar 1, 2022

Conversation

mirka
Copy link
Member

@mirka mirka commented Feb 16, 2022

Description

This PR clears the path for proper extraction of component prop types to use in our Storybook and documentation. Given our ongoing investment in TypeScript migrations, it would be great to leverage this as much as possible.

I tweaked two components here (Heading and Divider) to demonstrate what it could look like. A big benefit is that the prop type documentation and all Controls can be generated automatically for the most part, with inline descriptions ✨ In some cases we may want to override or hide specific controls, but other than that we get everything for free.

Details

After a lot of experimentation, I figured out some things that were preventing Storybook's react-docgen-typescript from properly extracting props information from our TypeScript/JSDocs. Here's what's required for proper type extraction:

  • The component has to be written in actual TypeScript, not just typed with a JSDoc comment 😅
  • The WordPressComponentProps type alias needs to be imported from a proper .ts source file. The problem was that our components were importing it via ui/context/index.js, which is not a .ts file.
  • The contextConnect() HOC needs to be in TypeScript.
  • The connected component needs to be exported individually as a named export, not just as default.

What this means for TypeScript migration and story authoring

As more components are converted to TypeScript and their stories are improved, we can expect that most consumer devs will want to interact with Storybook primarily through the Docs view, rather than the Canvas. Especially with code samples (92354c9) visible for each story, it's much easier to understand how to use the components. And for the default story, the Controls are available right in the Docs view. Canvas view will only be necessary for advanced debugging.

Eventually, I imagine we'll want to make the Docs mode version of our Storybook to be our canonical documentation, instead of the limited Component Reference currently on the dotorg site.

So whenever possible, it'll be beneficial for us to write TypeScript and Storybook stories in a way that makes sense for the Docs view. For example:

  • Are there any weird props that show up in Docs view that you want to hide? Consider whether it should be Omit-ed at the TypeScript level. (Example: Context: Omit as prop in types #38844)
  • Are some stories showing unhelpful code snippets in Docs view? See if you can tweak the story to show an understandable code sample.

Testing Instructions

  1. npm run storybook:dev
  2. See stories for Heading and Divider. Compare with the ones on https://wordpress.github.io/gutenberg/
  3. If you're interested, try npx start-storybook -c ./storybook -p 50240 --docs to see how it would look like in Docs mode.

Screenshots

CleanShot.2022-02-16.at.09.10.25-converted.mp4

Types of changes

  • Minor, non-consumer-facing changes (Changing files to .ts, re-exporting as named components)
  • Storybook changes

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • I've tested my changes with keyboard and screen readers.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR (please manually search all *.native.js files for terms that need renaming or removal).
  • I've updated related schemas if appropriate.

@mirka mirka added [Type] Developer Documentation Documentation for developers [Package] Components /packages/components Storybook Storybook and its stories for components labels Feb 16, 2022
@mirka mirka requested a review from ciampo February 16, 2022 00:22
@mirka mirka requested a review from ajitbohra as a code owner February 16, 2022 00:22
@mirka mirka self-assigned this Feb 16, 2022
@github-actions
Copy link

github-actions bot commented Feb 16, 2022

Size Change: +852 B (0%)

Total Size: 1.15 MB

Filename Size Change
build/api-fetch/index.min.js 2.27 kB +21 B (+1%)
build/block-editor/index.min.js 143 kB +37 B (0%)
build/block-library/blocks/button/editor-rtl.css 445 B -25 B (-5%)
build/block-library/blocks/button/editor.css 445 B -25 B (-5%)
build/block-library/blocks/code/style-rtl.css 103 B +13 B (+14%) ⚠️
build/block-library/blocks/code/style.css 103 B +13 B (+14%) ⚠️
build/block-library/blocks/code/theme-rtl.css 124 B -7 B (-5%)
build/block-library/blocks/code/theme.css 124 B -7 B (-5%)
build/block-library/blocks/cover/style-rtl.css 1.56 kB -10 B (-1%)
build/block-library/blocks/cover/style.css 1.56 kB -10 B (-1%)
build/block-library/blocks/navigation/editor-rtl.css 2.01 kB +33 B (+2%)
build/block-library/blocks/navigation/editor.css 2.02 kB +33 B (+2%)
build/block-library/blocks/tag-cloud/style-rtl.css 226 B +12 B (+6%) 🔍
build/block-library/blocks/tag-cloud/style.css 227 B +12 B (+6%) 🔍
build/block-library/common-rtl.css 934 B +13 B (+1%)
build/block-library/common.css 932 B +13 B (+1%)
build/block-library/editor-rtl.css 9.89 kB +8 B (0%)
build/block-library/editor.css 9.9 kB +8 B (0%)
build/block-library/index.min.js 167 kB +72 B (0%)
build/block-library/style-rtl.css 11.4 kB +14 B (0%)
build/block-library/style.css 11.4 kB +14 B (0%)
build/block-library/theme-rtl.css 665 B -7 B (-1%)
build/block-library/theme.css 670 B -6 B (-1%)
build/components/index.min.js 215 kB +49 B (0%)
build/components/style-rtl.css 15.6 kB +31 B (0%)
build/components/style.css 15.6 kB +32 B (0%)
build/compose/index.min.js 11.2 kB +16 B (0%)
build/customize-widgets/index.min.js 11.2 kB -197 B (-2%)
build/customize-widgets/style-rtl.css 1.39 kB -103 B (-7%)
build/customize-widgets/style.css 1.39 kB -102 B (-7%)
build/data/index.min.js 7.65 kB +169 B (+2%)
build/edit-post/index.min.js 29.9 kB -1 B (0%)
build/edit-site/index.min.js 42.1 kB -16 B (0%)
build/edit-site/style-rtl.css 7.23 kB +5 B (0%)
build/edit-site/style.css 7.22 kB +5 B (0%)
build/edit-widgets/index.min.js 16.5 kB -132 B (-1%)
build/edit-widgets/style-rtl.css 4.12 kB -48 B (-1%)
build/edit-widgets/style.css 4.13 kB -45 B (-1%)
build/editor/index.min.js 38.5 kB -17 B (0%)
build/element/index.min.js 4.29 kB +971 B (+29%) 🚨
build/url/index.min.js 1.94 kB +16 B (+1%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 993 B
build/admin-manifest/index.min.js 1.24 kB
build/annotations/index.min.js 2.77 kB
build/autop/index.min.js 2.15 kB
build/blob/index.min.js 487 B
build/block-directory/index.min.js 6.49 kB
build/block-directory/style-rtl.css 1.01 kB
build/block-directory/style.css 1.01 kB
build/block-editor/default-editor-styles-rtl.css 378 B
build/block-editor/default-editor-styles.css 378 B
build/block-editor/style-rtl.css 14.8 kB
build/block-editor/style.css 14.8 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 65 B
build/block-library/blocks/archives/style.css 65 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 111 B
build/block-library/blocks/audio/style.css 111 B
build/block-library/blocks/audio/theme-rtl.css 125 B
build/block-library/blocks/audio/theme.css 125 B
build/block-library/blocks/block/editor-rtl.css 161 B
build/block-library/blocks/block/editor.css 161 B
build/block-library/blocks/button/style-rtl.css 560 B
build/block-library/blocks/button/style.css 560 B
build/block-library/blocks/buttons/editor-rtl.css 292 B
build/block-library/blocks/buttons/editor.css 292 B
build/block-library/blocks/buttons/style-rtl.css 275 B
build/block-library/blocks/buttons/style.css 275 B
build/block-library/blocks/calendar/style-rtl.css 207 B
build/block-library/blocks/calendar/style.css 207 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 79 B
build/block-library/blocks/categories/style.css 79 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 406 B
build/block-library/blocks/columns/style.css 406 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-template/style-rtl.css 127 B
build/block-library/blocks/comment-template/style.css 127 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-query-loop/editor-rtl.css 95 B
build/block-library/blocks/comments-query-loop/editor.css 95 B
build/block-library/blocks/cover/editor-rtl.css 546 B
build/block-library/blocks/cover/editor.css 547 B
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 417 B
build/block-library/blocks/embed/style.css 417 B
build/block-library/blocks/embed/theme-rtl.css 124 B
build/block-library/blocks/embed/theme.css 124 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 255 B
build/block-library/blocks/file/style.css 255 B
build/block-library/blocks/file/view.min.js 353 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 965 B
build/block-library/blocks/gallery/editor.css 967 B
build/block-library/blocks/gallery/style-rtl.css 1.61 kB
build/block-library/blocks/gallery/style.css 1.61 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 159 B
build/block-library/blocks/group/editor.css 159 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 114 B
build/block-library/blocks/heading/style.css 114 B
build/block-library/blocks/html/editor-rtl.css 332 B
build/block-library/blocks/html/editor.css 333 B
build/block-library/blocks/image/editor-rtl.css 731 B
build/block-library/blocks/image/editor.css 730 B
build/block-library/blocks/image/style-rtl.css 518 B
build/block-library/blocks/image/style.css 523 B
build/block-library/blocks/image/theme-rtl.css 124 B
build/block-library/blocks/image/theme.css 124 B
build/block-library/blocks/latest-comments/style-rtl.css 284 B
build/block-library/blocks/latest-comments/style.css 284 B
build/block-library/blocks/latest-posts/editor-rtl.css 199 B
build/block-library/blocks/latest-posts/editor.css 198 B
build/block-library/blocks/latest-posts/style-rtl.css 447 B
build/block-library/blocks/latest-posts/style.css 446 B
build/block-library/blocks/list/style-rtl.css 94 B
build/block-library/blocks/list/style.css 94 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 493 B
build/block-library/blocks/media-text/style.css 490 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 649 B
build/block-library/blocks/navigation-link/editor.css 650 B
build/block-library/blocks/navigation-link/style-rtl.css 94 B
build/block-library/blocks/navigation-link/style.css 94 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation-submenu/view.min.js 375 B
build/block-library/blocks/navigation/style-rtl.css 1.89 kB
build/block-library/blocks/navigation/style.css 1.88 kB
build/block-library/blocks/navigation/view.min.js 2.85 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 363 B
build/block-library/blocks/page-list/editor.css 363 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 157 B
build/block-library/blocks/paragraph/editor.css 157 B
build/block-library/blocks/paragraph/style-rtl.css 273 B
build/block-library/blocks/paragraph/style.css 273 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/style-rtl.css 446 B
build/block-library/blocks/post-comments-form/style.css 446 B
build/block-library/blocks/post-comments/style-rtl.css 521 B
build/block-library/blocks/post-comments/style.css 521 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 721 B
build/block-library/blocks/post-featured-image/editor.css 721 B
build/block-library/blocks/post-featured-image/style-rtl.css 153 B
build/block-library/blocks/post-featured-image/style.css 153 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 323 B
build/block-library/blocks/post-template/style.css 323 B
build/block-library/blocks/post-terms/style-rtl.css 73 B
build/block-library/blocks/post-terms/style.css 73 B
build/block-library/blocks/post-title/style-rtl.css 80 B
build/block-library/blocks/post-title/style.css 80 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 198 B
build/block-library/blocks/pullquote/editor.css 198 B
build/block-library/blocks/pullquote/style-rtl.css 389 B
build/block-library/blocks/pullquote/style.css 388 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 234 B
build/block-library/blocks/query-pagination/style.css 231 B
build/block-library/blocks/query/editor-rtl.css 131 B
build/block-library/blocks/query/editor.css 132 B
build/block-library/blocks/quote/style-rtl.css 201 B
build/block-library/blocks/quote/style.css 201 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 397 B
build/block-library/blocks/search/style.css 398 B
build/block-library/blocks/search/theme-rtl.css 64 B
build/block-library/blocks/search/theme.css 64 B
build/block-library/blocks/separator/editor-rtl.css 99 B
build/block-library/blocks/separator/editor.css 99 B
build/block-library/blocks/separator/style-rtl.css 233 B
build/block-library/blocks/separator/style.css 233 B
build/block-library/blocks/separator/theme-rtl.css 172 B
build/block-library/blocks/separator/theme.css 172 B
build/block-library/blocks/shortcode/editor-rtl.css 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/editor-rtl.css 744 B
build/block-library/blocks/site-logo/editor.css 744 B
build/block-library/blocks/site-logo/style-rtl.css 181 B
build/block-library/blocks/site-logo/style.css 181 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 84 B
build/block-library/blocks/site-title/editor.css 84 B
build/block-library/blocks/social-link/editor-rtl.css 177 B
build/block-library/blocks/social-link/editor.css 177 B
build/block-library/blocks/social-links/editor-rtl.css 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.37 kB
build/block-library/blocks/social-links/style.css 1.36 kB
build/block-library/blocks/spacer/editor-rtl.css 332 B
build/block-library/blocks/spacer/editor.css 332 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 471 B
build/block-library/blocks/table/editor.css 472 B
build/block-library/blocks/table/style-rtl.css 481 B
build/block-library/blocks/table/style.css 481 B
build/block-library/blocks/table/theme-rtl.css 188 B
build/block-library/blocks/table/theme.css 188 B
build/block-library/blocks/template-part/editor-rtl.css 235 B
build/block-library/blocks/template-part/editor.css 235 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 87 B
build/block-library/blocks/verse/style.css 87 B
build/block-library/blocks/video/editor-rtl.css 571 B
build/block-library/blocks/video/editor.css 572 B
build/block-library/blocks/video/style-rtl.css 173 B
build/block-library/blocks/video/style.css 173 B
build/block-library/blocks/video/theme-rtl.css 124 B
build/block-library/blocks/video/theme.css 124 B
build/block-library/reset-rtl.css 474 B
build/block-library/reset.css 474 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/blocks/index.min.js 46.4 kB
build/core-data/index.min.js 13.9 kB
build/data-controls/index.min.js 663 B
build/date/index.min.js 31.9 kB
build/deprecated/index.min.js 518 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.53 kB
build/edit-navigation/index.min.js 16.2 kB
build/edit-navigation/style-rtl.css 3.76 kB
build/edit-navigation/style.css 3.76 kB
build/edit-post/classic-rtl.css 546 B
build/edit-post/classic.css 547 B
build/edit-post/style-rtl.css 7.19 kB
build/edit-post/style.css 7.18 kB
build/editor/style-rtl.css 3.71 kB
build/editor/style.css 3.71 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 6.62 kB
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.66 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.79 kB
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.83 kB
build/keycodes/index.min.js 1.41 kB
build/list-reusable-blocks/index.min.js 1.75 kB
build/list-reusable-blocks/style-rtl.css 838 B
build/list-reusable-blocks/style.css 838 B
build/media-utils/index.min.js 2.94 kB
build/notices/index.min.js 957 B
build/nux/index.min.js 2.12 kB
build/nux/style-rtl.css 747 B
build/nux/style.css 743 B
build/plugins/index.min.js 1.98 kB
build/preferences/index.min.js 1.2 kB
build/primitives/index.min.js 949 B
build/priority-queue/index.min.js 611 B
build/react-i18n/index.min.js 704 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.69 kB
build/reusable-blocks/index.min.js 2.24 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 11.1 kB
build/server-side-render/index.min.js 1.61 kB
build/shortcode/index.min.js 1.52 kB
build/token-list/index.min.js 668 B
build/viewport/index.min.js 1.08 kB
build/warning/index.min.js 280 B
build/widgets/index.min.js 7.18 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.07 kB

compressed-size-action

@mirka mirka added the [Status] In Progress Tracking issues with work in progress label Feb 16, 2022
@mirka mirka force-pushed the storybook/prop-type-extraction branch 2 times, most recently from 8387880 to 9366c7a Compare February 16, 2022 23:17
@mirka mirka removed the [Status] In Progress Tracking issues with work in progress label Feb 16, 2022
Copy link
Contributor

@ciampo ciampo left a comment

Choose a reason for hiding this comment

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

Thank you @mirka , seeing this exploratory work taking shape makes very excited!

A big benefit is that the prop type documentation and all Controls can be generated automatically for the most part, with inline descriptions ✨ In some cases we may want to override or hide specific controls, but other than that we get everything for free.

This is great! It will interesting to see, as we experiment with this, which other limitations we're going to hit. In that sense, it's going to be very important for us to choose the docgen "engine" that fits our needs the most.

After a lot of experimentation, I figured out some things that were preventing

This part was very interesting to read, but it all made sense to me. This also legitimises the priority that we should give to #35744

we can expect that most consumer devs will want to interact with Storybook primarily through the Docs view

Yes 🚀

Eventually, I imagine we'll want to make the Docs mode version of our Storybook to be our canonical documentation, instead of the limited Component Reference currently on the dotorg site.
...
So whenever possible, it'll be beneficial for us to write TypeScript and Storybook stories in a way that makes sense for the Docs view.

That's what I have in mind, too.

Are there any weird props that show up in Docs view that you want to hide? Consider whether it should be Omit-ed at the TypeScript level. (Example: #38844)

Specifically on the as prop, I think it'd be good to expose it, since some components are polymorphic, while others are not. WDYT ?

Are some stories showing unhelpful code snippets in Docs view? See if you can tweak the story to show an understandable code sample.

This will probably need a story-by-story "human" review.

Maybe a good balance for our story examples could be:

  • Default story: expose as many props as possible, so that a dev can tweak them while reading the docs
  • Non-default stories: more specific example/scenarios, with very few controls exposed

How much work is left in order to get this extraction to a "good enough" point? Woudl it require all components and Storybook examples to be migrated to TypeScript first?

packages/components/src/divider/stories/index.tsx Outdated Show resolved Hide resolved
packages/components/src/divider/stories/index.tsx Outdated Show resolved Hide resolved
packages/components/src/divider/stories/index.tsx Outdated Show resolved Hide resolved
@mirka
Copy link
Member Author

mirka commented Feb 18, 2022

it's going to be very important for us to choose the docgen "engine" that fits our needs the most.

Right. FWIW, out of the two docgens that Storybook supports, react-docgen is a non-starter because it doesn’t support imported types 😬 And react-docgen-typescript seems to be the only remaining major option for React TS stuff, so we might not have much of a choice.

Specifically on the as prop, I think it'd be good to expose it, since some components are polymorphic, while others are not. WDYT ?

Yes, it will be present for polymorphic components, and omitted from non-polymorphic components, if that’s what you’re asking 👍

Maybe a good balance for our story examples could be:

  • Default story: expose as many props as possible, so that a dev can tweak them while reading the docs
  • Non-default stories: more specific example/scenarios, with very few controls exposed

The thing is, all props recognized by the docgen will automatically be exposed as Controls on all stories by default. At that point, if we want to hide any Controls we have to disable each one specifically (denylist). This is how Storybook works, and it’s not something we can easily change to be an allowlist system. (The only reason we weren’t getting this behavior is because the majority of our types are currently unrecognizable by the docgens 😅)

So in most cases I don’t think it is worth the effort to carefully curate the set of Controls exposed on specific stories.

This might seem like an annoyance, but ultimately I think the behavior is sensible, and informs us how we should be approaching the different Storybook sections. The Docs view code snippet is for understanding which props are being explicitly set. The Canvas view is for advanced tinkering and debugging, in which case we actually do want to expose as many Controls as possible.

Is that reasonable?

How much work is left in order to get this extraction to a "good enough" point? Woudl it require all components and Storybook examples to be migrated to TypeScript first?

I think we can approach it in a “progressive enhancement” way. First off we can merge this PR, since it doesn’t have ill effects on any existing stories. Then every time a TS conversion is complete, we can tweak the stories for that component so it makes use of the type data. Once the majority of TS conversions are complete, we can set the default tab to Docs. Once 100% of the TS conversions are complete, we can remove markdown docs and point everyone to the Storybook.

@ciampo
Copy link
Contributor

ciampo commented Feb 21, 2022

out of the two docgens that Storybook supports, react-docgen is a non-starter because it doesn’t support imported types 😬 And react-docgen-typescript seems to be the only remaining major option for React TS stuff, so we might not have much of a choice.

That's good to know. Out of curiosity, what does react-docgen do better than react-docgen-typescript? Are both projects currently well maintained and easy to contribute to? Just trying to make sure that picking a docgen now won't hurt us in the future.

Yes, it will be present for polymorphic components, and omitted from non-polymorphic components, if that’s what you’re asking 👍

Yup, awesome!

The thing is, all props recognized by the docgen will automatically be exposed as Controls on all stories by default. At that point, if we want to hide any Controls we have to disable each one specifically (denylist) ... So in most cases I don’t think it is worth the effort to carefully curate the set of Controls exposed on specific stories.
...
The Docs view code snippet is for understanding which props are being explicitly set. The Canvas view is for advanced tinkering and debugging, in which case we actually do want to expose as many Controls as possible.

Is that reasonable?

Yes, thank you for the explanation. I guess we should stil add multiple stories to the Canvas view showcasing specific scenarios / recipes?

I think we can approach it in a “progressive enhancement” way. First off we can merge this PR, since it doesn’t have ill effects on any existing stories. Then every time a TS conversion is complete, we can tweak the stories for that component so it makes use of the type data. Once the majority of TS conversions are complete, we can set the default tab to Docs. Once 100% of the TS conversions are complete, we can remove markdown docs and point everyone to the Storybook.

Sounds like a plan to me. I will give this PR a final review then!

@mirka mirka force-pushed the storybook/prop-type-extraction branch from ee1922b to a556b52 Compare February 21, 2022 16:57
Copy link
Contributor

@ciampo ciampo left a comment

Choose a reason for hiding this comment

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

Apart from the previous comment and the inline comments, here's some additional thoughts:

  1. Is there a way to sort the props displayed in the docs alphabetically? When there's a lot props, it may help to have a way of sorting them so that a user can easily find them (Ideally we could even group them, but it may be a task that we want to tackle separately)
  2. A lot of props can't be expanded to their "raw" value (e.g the adjustLineHeightForInnerControls prop of Heading has a type of TextAdjustLineHeightForInnerControls). Although this is not great, the opposite approach (i.e expanding every alias) could be even worse. Probably better for now to keep the alias expansion deactivated?
  3. When guessing a prop type for the associated control, Storybook seems to default to Object, which is often not the right choice (this happens, for example, for all CSS-related props) and can undermine the usefulness of the docs. Probably the only solution here is to manually override those control types for each story that gets converted?
  4. As a special case of the previous point, the as prop is also presented as an Object. Clicking on the "Set object" button currently crashes Storybook
  5. We should also look into adding a description for the as prop in the WordPressComponent typerybook defaults to an Object type, which breaks storybook

And finally, some additional feedback specific to the Heading and Divider stories:

  • Heading: not something introduced by this PR, but exposing the component through the new story revealed quite a few unpredictable (and very likely unintended) behaviors, especially around tweaking character-based and line-based truncation. Also, the display prop value always gets overridden by a `display: block' rule declared later
  • Divider: in the default "Horizontal" story (which is used to highlight all Divider props), the user is able to select vertical for the orientation, but currently the story doesn't really support that use case (i.e. the Divider can't be seen). We should probably:
    • Update the story by adding a flex wrapper
    • Update the docs of the orientation prop

@mirka mirka force-pushed the storybook/prop-type-extraction branch from a556b52 to 354c730 Compare February 22, 2022 19:16
@mirka
Copy link
Member Author

mirka commented Feb 22, 2022

I think we're in a pretty good place, thanks to your feedback! All issues addressed.

That's good to know. Out of curiosity, what does react-docgen do better than react-docgen-typescript? Are both projects currently well maintained and easy to contribute to? Just trying to make sure that picking a docgen now won't hurt us in the future.

I don’t have much information aside from the comparison table, but apparently it’s faster and has fewer bugs, albeit with lower quality type analysis? Both repos seem reasonably active.

I guess we should stil add multiple stories to the Canvas view showcasing specific scenarios / recipes?

Exactly! When there are a lot of items being exposed in the props table, it’s important that we showcase the common usage examples with stories.

  1. Is there a way to sort the props displayed in the docs alphabetically?

Done ✅ Required props first, then the rest are alphabetical.

  1. A lot of props can't be expanded to their "raw" value (e.g the adjustLineHeightForInnerControls prop of Heading has a type of TextAdjustLineHeightForInnerControls). Although this is not great, the opposite approach (i.e expanding every alias) could be even worse. Probably better for now to keep the alias expansion deactivated?

Yes, also I think another way of approaching it in certain cases is to actually not use a type alias. Like in your example, TextAdjustLineHeightForInnerControls does not really need to be an alias. Interestingly, the logic whether to expand or not seems to be the same as in IntelliSense, so overusing them makes it harder to understand in IDEs too.

Before After
type alias collapsed in VS Code IntelliSense hover types expanded
  1. When guessing a prop type for the associated control, Storybook seems to default to Object, which is often not the right choice (this happens, for example, for all CSS-related props) and can undermine the usefulness of the docs. Probably the only solution here is to manually override those control types for each story that gets converted?

Currently, yes. Let’s see how often it happens. FWIW, there is a already a basic mechanism to regex-match and map props to certain controls. It doesn’t support our needs yet, but the code looks pretty straightforward so it might be a good place to contribute. (I went ahead and upvoted in an upstream feature request.)

  1. As a special case of the previous point, the as prop is also presented as an Object. Clicking on the "Set object" button currently crashes Storybook

Fixed ✅

  1. We should also look into adding a description for the as prop in the WordPressComponent

Done ✅

And finally, some additional feedback specific to the Heading and Divider stories:

  • Heading: Moved follow-ups to the TS migration issue notes for the Text component.
  • Divider: Will follow up after I try to add storybook-description-loader

@mirka mirka requested a review from ciampo February 22, 2022 19:31
Copy link
Contributor

@ciampo ciampo left a comment

Choose a reason for hiding this comment

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

Basically, a solid 👍 to all of your answers above 🚀

I left a few inline comments, but I am preentively approving this PR as they are all small changes — feel free to merge after resolving them if you think so!

Also, 👍 re. the proposed follow-ups:

packages/components/src/ui/context/wordpress-component.ts Outdated Show resolved Hide resolved
Comment on lines +31 to +36
adjustLineHeightForInnerControls?:
| boolean
| 'large'
| 'medium'
| 'small'
| 'xSmall';
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe the "limit" for expanding type aliases is if the types that are unioned are all of the same general type or not?

E.g. a union of just strings could be "easier" to expand for the docgen, while a union of strings and boolean may be kept un-expanded?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't know 🤷

Copy link
Contributor

Choose a reason for hiding this comment

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

Me neither, but good to keep at the back of our minds for future work :)

letterSpacing: { control: { type: 'text' } },
lineHeight: { control: { type: 'text' } },
optimizeReadabilityFor: { control: { type: 'color' } },
variant: { control: { type: 'radio' }, options: [ 'muted' ] },
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: using a radio with only one option, it's not possible to "deselect" that option, once selected

Copy link
Member Author

Choose a reason for hiding this comment

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

Kind of like the "reset" problem in the editor sidebar! I actually think this is consistent with all controls (especially auto-generated ones), in that you can't really go back to the undefined state once you set a value. We could of course add an undefined option, but I think the overall design intent is to use the "Reset controls" button ↩️ in the top right.

I'm not sure how I feel about this yet! On one hand I don't want to establish a pattern of adding a lot of manual tweaks to auto-generated controls, because it increases maintenance burden. But in some cases it may be annoying to have to hit Reset each time. So... maybe worth it for heavily trafficked props like variant on Button?

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed. Let's leave it as-is (and rely on the reset button for now). I believe we are amongst the heavy users of this Storybook anyway, so we can make this change if we ever feel like it's really needed.

component: Heading,
title: 'Components (Experimental)/Heading',
argTypes: {
adjustLineHeightForInnerControls: { control: { type: 'text' } },
Copy link
Contributor

Choose a reason for hiding this comment

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

adjustLineHeightForInnerControls can also be a boolean — should we add true and false to the list of possible values, maybe in a dropdown-like control?

Copy link
Member Author

Choose a reason for hiding this comment

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

Mmm yeah, this one’s a bit overcomplicated too. Based on the code, true gives the same result as 'medium', and false gives the same result as undefined. Before we graduate <Text> from experimental status, I'd prefer removing the boolean types from this prop API. (Kind of similar to your UnitControl cleanup!)

I'll note this in the TS refactor tracking issue.

Copy link
Contributor

Choose a reason for hiding this comment

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

Just to close the circle, this was finally done in #54953 !

Comment on lines +19 to +20
letterSpacing: { control: { type: 'text' } },
lineHeight: { control: { type: 'text' } },
Copy link
Contributor

Choose a reason for hiding this comment

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

These values can be both strings or numbers, is there a way to achieve that with controls?

Copy link
Member Author

Choose a reason for hiding this comment

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

The object control can strictly cover both, since that's basically a JSON string input so it differentiates between 1 and "1". Though in the vast majority of cases I think a normal text control would be sufficient for tinkering and better for UX (because people will have trouble recognizing that they need to quote their strings in a object control).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Components /packages/components Storybook Storybook and its stories for components [Type] Developer Documentation Documentation for developers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants