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

fix: element component + subcomponent type conventions #1273

Merged
merged 41 commits into from
Jan 26, 2022

Conversation

jzempel
Copy link
Member

@jzempel jzempel commented Jan 21, 2022

Description

A sweep over all exported Garden element components to bring the code inline with the internal "Element component + subcomponent type conventions" coding RFC. Standard coding conventions are outlined in the updated API docs, which provide a good starting point for framing the PR review.

Detail

A website follow-on from this PR is expected to auto (rather than manually) generate all subcomponent prop sheet documentation, which should represent a significant uptick in efficiency and consistency.

Checklist

  • πŸ‘Œ design updates are Garden Designer approved (add the
    designer as a reviewer)
  • 🌐 demo is up-to-date (yarn start)
  • ⬅️ renders as expected with reversed (RTL) direction
  • 🀘 renders as expected with Bedrock CSS (?bedrock)
  • β™Ώ analyzed via axe and evaluated using VoiceOver
  • πŸ’‚β€β™‚οΈ includes new unit tests
  • πŸ“ tested in Chrome, Firefox, Safari, Edge, and IE11

@jzempel jzempel requested a review from a team as a code owner January 21, 2022 15:14
/**
* @deprecated use ITimelineItemProps instead
*/
export type IItem = ITimelineItemProps;
Copy link
Member Author

Choose a reason for hiding this comment

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

IElementSubElement naming is used rather than ISubElement for consistent subcomponent type exports that avoid naming confusion or conflicts with other subcomponent types. i.e. Timeline.Item vs Stepper.Item just as a contrived example.

@@ -5,5 +5,5 @@
* found at http://www.apache.org/licenses/LICENSE-2.0.
*/

export { default as Avatar } from './elements/Avatar';
Copy link
Member Author

Choose a reason for hiding this comment

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

no more mix of default vs named exports

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

As MonthSelector was neither an exported component or subcomponent, I didn't have it in view for this PR. But I'll go ahead and update the outlier.

Comment on lines +22 to +37
export const HeaderItemIcon = ({
children,
...props
}: PropsWithChildren<HTMLAttributes<HTMLElement>>) => {
const element = Children.only(children) as ReactHTMLElement<HTMLElement>;

return <StyledHeaderItemIcon as={Element as any} {...props} />;
if (isValidElement(element)) {
const Icon = ({
// eslint-disable-next-line @typescript-eslint/no-unused-vars
theme,
...iconProps
}: ThemeProps<DefaultTheme> & HTMLAttributes<HTMLElement>) =>
cloneElement<HTMLAttributes<HTMLElement>, HTMLElement>(element, { ...props, ...iconProps });

return <StyledHeaderItemIcon as={Icon} {...props} />;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Direct clone of Icon type elements is a future inconsistency that should be addressed throughout the codebase. This change is simply buttoning-up the types for props.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could you explain more on this matter?

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 could πŸ˜‰ What are you looking for exactly? Perhaps we should talk offline. I've captured some of the inconsistencies in our version planning doc.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nothing in particular, was just wondering, however if we have this recorded, we should be okay.

@coveralls
Copy link

coveralls commented Jan 21, 2022

Coverage Status

Coverage decreased (-0.003%) to 95.768% when pulling db114b2 on jzempel/element-types into c711002 on main.

Comment on lines +226 to +227
3. The `displayName` definition should be set to the exported component name and
satisfies linter checks for runtime naming
Copy link
Contributor

Choose a reason for hiding this comment

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

I am a little confused here.. "should be set to the exported component name", would that be Element or ElementComponent?

Copy link
Member Author

@jzempel jzempel Jan 24, 2022

Choose a reason for hiding this comment

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

The only exported component is Element – so that should be the displayName. Do I need to take another crack at the verbiage here?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, I may have taken it too literally with how it is worded? The linting work correctly so it shouldn't be an issue... I just understood it as (example):

/**
 * @extends HTMLAttributes<HTMLDivElement>
 */
export const Accordion = AccordionComponent as typeof AccordionComponent & {
  ...
};

Accordion.displayName = 'Accordion';

Instead of what we are actually doing:

AccordionComponent.displayName = 'Accordion';

/**
 * @extends HTMLAttributes<HTMLDivElement>
 */
export const Accordion = AccordionComponent as typeof AccordionComponent & {
  ...
};

Since Accordion is what is being exported. Possibly making a distinction between element's and styled-components` would help.. not too sure frankly.

Copy link
Member Author

Choose a reason for hiding this comment

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

Your (example) can't happen – it breaks both displayName linting and JSDoc parsing.

We actually need the "actually doing" version. And the point is to highlight the necessary AccordionComponent.displayName = 'Accordion'; mismatch – which satisfies both linting and provides the necessary connective tissue for JSDoc parsing via garden cmd-docgen.

- Only add prop JSDoc to Typescript prop interfaces
- Refrain from documenting React `defaultProps`
- Refrain from documenting styled components props
- Use `@ignore` to prevent a prop from being added to generated documentation
Copy link
Contributor

Choose a reason for hiding this comment

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

When would @ignore usage be appropriate? I did notice ButtonGroups isSelected prop as one usage within react-components, would this hide functionality or is it intended for the internal API?

Copy link
Member Author

Choose a reason for hiding this comment

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

This rare notation hides props that should only be used internally and not intended for external use. Should I state that here?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would help to state that, maybe using the internal props as an example would frame its purpose better.

docs/api.md Show resolved Hide resolved
packages/forms/src/index.ts Outdated Show resolved Hide resolved
packages/modals/src/elements/DrawerModal/Header.tsx Outdated Show resolved Hide resolved
Copy link
Contributor

@mtomcal mtomcal left a comment

Choose a reason for hiding this comment

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

This is some amazing code collapse here. πŸ‘

@@ -64,5 +62,3 @@ IconButton.defaultProps = {
isBasic: true,
size: 'medium'
};

export default IconButton;
Copy link
Contributor

@mtomcal mtomcal Jan 24, 2022

Choose a reason for hiding this comment

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

We should be prepared with a boilerplate message (not in code) if any consumers directly import default from these components that they will be broken. They should not be importing files directly in the first place but we might see chatter about this regardless for this and any migrations of subcomponents to their new files.

cloneElement<HTMLAttributes<HTMLElement>, HTMLElement>(element, { ...props, ...iconProps });

return <StyledNavItemIcon as={Icon} {...props} />;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the objective of this expanded logic?

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems this is a repeat of #1273 (comment) but different file. Would like to hear the offline breakdown of what this is doing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Exact same as #1273 (comment)

Copy link
Contributor

@hzhu hzhu left a comment

Choose a reason for hiding this comment

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

These are much needed updates that keep the project structured well. Thanks!

docs/documentation.md Outdated Show resolved Hide resolved
@Francois-Esquire
Copy link
Contributor

@jzempel this PR brings much needed refinement to the project/packages, thank you πŸ™Œ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

None yet

6 participants