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

feat: improve RadioButton and RadioButtonGroup types #16648

Merged
merged 1 commit into from
Jun 12, 2024

Conversation

cuppajoey
Copy link
Contributor

In #16186, the selection argument of RadioButtonGroup's onChange prop was changed to ReactNode instead of string | number as written in the PR description. In addition to fixing that I have added some missing types and improved others.

Changelog

  • Export prop interfaces for RadioButton and RadioButtonGroup.
  • Narrow onChange argument type for RadioButtonGroupProps.
  • Reference RadioButtonProps for RadioButtonGroup types where we are expecting a RadioButton value.
  • Add missing types for component refs and event handlers in RadioButton and RadioButtonGroup.
  • Simplify getRadioButtons() with a type assertion on children argument and refactoring to use an early return statement.

Testing / Reviewing

  • Check RadioButton and RadioButtonGroup for type errors
  • Check for regressions with RadioButtons used inside of a group (e.g., radio buttons are still correctly displayed and the group value changes when radio selections change.)

Changes:
- Export prop interfaces for `RadioButton` and `RadioButtonGroup`.
- Narrow `onChange` argument type for `RadioButtonGroupProps`.
- Reference `RadioButtonProps` for `RadioButtonGroup` types where
  we are expecting a `RadioButton` value.
- Add missing types for component `refs` and event handlers in
  `RadioButton` and `RadioButtonGroup`.
- Simplify `getRadioButtons()` with a type assertion on `children`
  argument and refactoring to use an early return statement.
@cuppajoey cuppajoey requested a review from a team as a code owner June 3, 2024 20:49
Copy link

netlify bot commented Jun 3, 2024

Deploy Preview for v11-carbon-react ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 67a0f1c
🔍 Latest deploy log https://app.netlify.com/sites/v11-carbon-react/deploys/665e2c3f667afa0008e88eef
😎 Deploy Preview https://deploy-preview-16648--v11-carbon-react.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link

netlify bot commented Jun 3, 2024

Deploy Preview for carbon-elements ready!

Name Link
🔨 Latest commit 67a0f1c
🔍 Latest deploy log https://app.netlify.com/sites/carbon-elements/deploys/665e2c3f27f3390008f197fb
😎 Deploy Preview https://deploy-preview-16648--carbon-elements.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link
Contributor Author

@cuppajoey cuppajoey left a comment

Choose a reason for hiding this comment

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

As a review aid, I left a few comments for additional context.

@@ -98,80 +98,85 @@ export interface RadioButtonProps
required?: boolean;
}

const RadioButton = React.forwardRef((props: RadioButtonProps, ref) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ref is now correctly typed.

Most of the following diff below is due to prettier's formatting adjusting the indentation. I recommend viewing with ⚙️ whitespace changes hidden.

Comment on lines +75 to +76
value: RadioButtonProps['value'],
name: RadioButtonProps['name'],
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can directly reference other types within the same interface when the expected value is the same (e.g., props.name and props.value are what we're passing to the onChange handler).

Referencing types this way provides more context and reduces the work later, should RadioButton types change in the future.

This is also how it was originally typed (See DefinitelyTyped)

Comment on lines +126 to +131
const innerLabelClasses = classNames(
`${prefix}--radio-button__label-text`,
{
[`${prefix}--visually-hidden`]: hideLabel,
}
);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was an automatic prettier adjustment.

const uid = useId('radio-button');
const uniqueId = id || uid;

function handleOnChange(event: React.ChangeEvent<HTMLInputElement>) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As a bonus, I added some missing types while working in these files.

@@ -87,10 +88,11 @@ export interface RadioButtonGroupProps
* the group changes
*/
onChange?: (
selection: React.ReactNode,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The selection will be the same as the RadioButton value. ReactNode is too broad.

if (!selected && (radioButton as ReactElement)?.props.checked) {
newProps.checked = true;
const mappedChildren = React.Children.map(
children as ReactElement<RadioButtonProps>,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

children is now typed as a RadioButton allowing us to inherit the types from RadioButtonProps. Previously, all prop values referenced in this function were typed as any.

This way, we no longer need to keep asserting the type of radioButton.

Comment on lines +175 to +177
if (!radioButton) {
return;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The null-check from 🔴 184 was moved up here as an early return.

Copy link
Contributor

@guidari guidari left a comment

Choose a reason for hiding this comment

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

LGTM! 🚀

@@ -230,7 +241,7 @@ const RadioButtonGroup = React.forwardRef(
const divRef = useRef<HTMLDivElement>(null);

// Slug is always size `mini`
let normalizedSlug;
let normalizedSlug: ReactElement | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be done across all components for Type Safety and Clarity

Copy link
Contributor

@2nikhiltom 2nikhiltom left a comment

Choose a reason for hiding this comment

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

Looks good to me 🔥

@alisonjoseph alisonjoseph added this pull request to the merge queue Jun 12, 2024
Merged via the queue into carbon-design-system:main with commit e582548 Jun 12, 2024
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants