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

polish(theme-classic): guard against potential definition mistakes in Tabs #5674

Merged
merged 7 commits into from
Oct 14, 2021

Conversation

Josh-Cena
Copy link
Collaborator

@Josh-Cena Josh-Cena commented Oct 9, 2021

Breaking changes

  • Tabs fail-fast (throw) instead of fail-safe when suspicious (likely typo) config is encountered
  • Use defaultValue={null} if you want to tabs initially selected

Motivation

Followup from here: #5647 (comment)

Have you read the Contributing Guidelines on pull requests?

Yes

@netlify
Copy link

netlify bot commented Oct 9, 2021

✔️ [V2]
Built without sensitive environment variables

🔨 Explore the source changes: 6b76bc9

🔍 Inspect the deploy log: https://app.netlify.com/sites/docusaurus-2/deploys/6167fc0fef601400075a9148

😎 Browse the preview: https://deploy-preview-5674--docusaurus-2.netlify.app

@github-actions
Copy link

github-actions bot commented Oct 9, 2021

⚡️ Lighthouse report for the changes in this PR:

Category Score
🟠 Performance 74
🟢 Accessibility 98
🟢 Best practices 100
🟢 SEO 100
🟢 PWA 95

Lighthouse ran on https://deploy-preview-5674--docusaurus-2.netlify.app/

@Josh-Cena Josh-Cena changed the title polish(theme-classic): error if defaultValue is nonexistent polish(theme-classic): error if defaultValue is nonexistent + check for children type Oct 9, 2021
@Josh-Cena Josh-Cena changed the title polish(theme-classic): error if defaultValue is nonexistent + check for children type polish(theme-classic): make Tabs error if defaultValue is nonexistent + check for children type Oct 9, 2021
@Josh-Cena Josh-Cena changed the title polish(theme-classic): make Tabs error if defaultValue is nonexistent + check for children type polish(theme-classic): guard against potential definition mistakes in Tabs Oct 9, 2021
@slorber slorber added pr: breaking change Existing sites may not build successfully in the new version. Description contains more details. pr: new feature This PR adds a new API or behavior. labels Oct 13, 2021
Copy link
Collaborator

@slorber slorber left a comment

Choose a reason for hiding this comment

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

LGTM

Just some missing tests and conflicts to resolve.

What's the behavior if defaultValue=undefined ? different than null?

jest.config.js Outdated Show resolved Hide resolved
packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx Outdated Show resolved Hide resolved
@facebook-github-bot facebook-github-bot added the CLA Signed Signed Facebook CLA label Oct 13, 2021
@Josh-Cena
Copy link
Collaborator Author

What's the behavior if defaultValue={undefined}?

That's just the same as not providing the prop: we search in the children for default or default to the first tab.

Copy link
Collaborator

@slorber slorber left a comment

Choose a reason for hiding this comment

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

almost LGTM thanks

* @param comparator Compares two values and returns `true` if they are equal (duplicated).
* @returns Value of the elements `v` that have a preceding element `u` where `comparator(u, v) === true`. Values within the returned array are not guaranteed to be unique.
*/
export function getDuplicateValues<T>(
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd suggest reusing method names from lodash for simplicity: intersection / intersectionBy would be a more powerful abstraction:

https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_intersection

Also adding a little test for it with/without iteratee/comparator

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Actually—I've never used Lodash myself and I kind of feel lucky that I never got into Lodash's mindset🌚

I fail to see how intersection is related to getDuplicateValues though, since mine is only working on one array

Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually—I've never used Lodash myself and I kind of feel lucky that I never got into Lodash's mindset🌚

Not sure what you mean here. Lodash is a bit heavy for frontend but it remains a powerful abstraction to achieve many data transformations. JS is improving and adding some Lodash-like methods over time.

I fail to see how intersection is related to getDuplicateValues though, since mine is only working on one array

Oh you are right I'm dumb 🤪 this is a different API and Lodash doesn't have anything for duplicates

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Lodash is a bit heavy for frontend but it remains a powerful abstraction to achieve many data transformations.

Yeah, just meant that when I think of algorithms, I directly think in ES array methods, not the Lodash arsenal.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What I mean is that they thought about method names carefully. If something does not exist in JS and exist in Lodash, reusing method name of lodash (or at least getting some inspiration) is not a bad idea.

There's nothing related to duplicates in lodash afaik so not applicable in this case.

Still I'd probably not name it as getDuplicateValues because it's not a method name that looks like any lodash or native JS array method name either. I'd rather name it simply duplicates

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Makes sense

</>,
);
}).toMatchInlineSnapshot(`[Function]`); // This is just a check that the function returns. We don't care about the actual DOM.
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

What about adding a test to cover that <CustomTabItem value="1"/> would lead to the same final JSX (non-shallow) than <TabItem value="1"/>

I don't think we dogfood this case on our site yet so it's worth adding it to ensure this behavior remains possible over time

Thanks for adding those tests BTW, we need to start somewhere 😅

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't really understand what magic a CustomTabItem could do🧐 There's no styling / logic here anyways—is there a use-case?

Copy link
Collaborator

@slorber slorber Oct 14, 2021

Choose a reason for hiding this comment

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

Users could decorate a tab with a BrowserWindow comp or whatever they want, and add extra logic if they want.

This should work (and used to work)

<CustomTabs>
  <CustomTabItem value="v1">Tab 1</CustomTabItem>
  <CustomTabItem value="v2">Tab 2</CustomTabItem>
</CustomTabs>

This should also work but would be more verbose:

<Tabs>
  <TabItem value="v1">
    <BrowserWindow>Tab 1</BrowserWindow>
  </TabItem>
  <TabItem value="v2">
    <BrowserWindow>Tab 2</BrowserWindow>
  </TabItem>
</Tabs>

I'd like to add a new MDX infra so that themes and sites can register MDX shortcodes without any need to import anything:

<tabs>
  <tab-item value="v1" link="https://tab1link.com">
    Tab 1
  </tab-item>
  <tab-item value="v2" link="https://tab2link.com">
    Tab 2
  </tab-item>
</tabs>

tab-item could be replaced by MDX by:

function CustomTabItem({ children, link }) {
  return (
    <TabItem>
      <BrowserWindow>
        <div>{children}</div>
        <footer>
          <Link to={link}>Tab link</Link>
        </footer>
      </BrowserWindow>
    </TabItem>
  );
}

That's why we must ensure that this behavior is preserved other time

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Okay, I see. react-test-renderer renders the JSX to actual DOM, so if we are to verify the rendering result, we get HTML. Do you just want to check it gets accepted, or do you want the actual DOM to match (which I can't see... why it would not)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Actually, as I went down the rabbit hole, verifying it works and getting the DOM structure is non-trivial, because it's hooked into complicated things like docusaurus context and some scroll position utils🧐 I'm struggling with making it all work. Maybe if we are to improve the testing infra, we should create a dummy Layout?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's move on, I'd like to release soon, we'll figure out how to test this later and provide better test infra for the whole theme. This likely requires some extra refactorings

</>,
);
}).toMatchInlineSnapshot(`[Function]`); // This is just a check that the function returns. We don't care about the actual DOM.
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's move on, I'd like to release soon, we'll figure out how to test this later and provide better test infra for the whole theme. This likely requires some extra refactorings

@slorber slorber merged commit c8739ec into facebook:main Oct 14, 2021
@Josh-Cena Josh-Cena deleted the strict-tabs branch October 14, 2021 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed Signed Facebook CLA pr: breaking change Existing sites may not build successfully in the new version. Description contains more details. pr: new feature This PR adds a new API or behavior.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants