Skip to content

Commit 2c1adee

Browse files
authored
refactor: rewrite IconSwitch in typescript (#19141)
1 parent 83f1e06 commit 2c1adee

File tree

8 files changed

+102
-38
lines changed

8 files changed

+102
-38
lines changed

packages/react/src/components/ContentSwitcher/ContentSwitcher.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,7 @@ import { getNextIndex, matches, keys } from '../../internal/keyboard';
2727
import { PrefixContext } from '../../internal/usePrefix';
2828
import { noopFn } from '../../internal/noopFn';
2929
import { IconSwitch } from '../Switch';
30-
31-
export interface SwitchEventHandlersParams {
32-
index?: number;
33-
name?: string | number;
34-
text?: string;
35-
key?: string | number;
36-
}
30+
import type { SwitchEventHandlersParams } from '../Switch/Switch';
3731

3832
export interface ContentSwitcherProps
3933
extends Omit<HTMLAttributes<HTMLElement>, 'onChange'> {

packages/react/src/components/IconButton/IconButton.stories.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ Default.args = {
5757

5858
Default.argTypes = {
5959
align: {
60+
// TODO:
61+
// 1. Should the deprecated options be deleted?
62+
// 2. The list doesn't include all of the options available in the
63+
// component. Is it supposed to?
6064
options: [
6165
'top',
6266
'top-left',

packages/react/src/components/Switch/IconSwitch.js renamed to packages/react/src/components/Switch/IconSwitch.tsx

Lines changed: 83 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,64 @@
66
*/
77

88
import PropTypes from 'prop-types';
9-
import React, { useState } from 'react';
9+
import React, {
10+
forwardRef,
11+
useState,
12+
type KeyboardEvent,
13+
type MouseEvent,
14+
type ReactNode,
15+
} from 'react';
1016
import classNames from 'classnames';
11-
import { IconButton } from '../IconButton';
17+
import { IconButton, type IconButtonProps } from '../IconButton';
1218
import { usePrefix } from '../../internal/usePrefix';
19+
import { noopFn } from '../../internal/noopFn';
20+
import type { SwitchEventHandlersParams } from './Switch';
1321

14-
const noopFn = () => {};
22+
interface IconSwitchProps
23+
extends Omit<IconButtonProps, 'onClick' | 'onKeyDown' | 'label' | 'name'> {
24+
/**
25+
* The index of the `IconSwitch`.
26+
*
27+
* Reserved for usage in `ContentSwitcher`.
28+
*/
29+
index?: number;
30+
31+
/**
32+
* The name of the `IconSwitch`.
33+
*/
34+
name?: string | number;
35+
36+
/**
37+
* A handler that is invoked when a user clicks on the control.
38+
*
39+
* Reserved for usage in `ContentSwitcher`.
40+
*/
41+
onClick?: (params: SwitchEventHandlersParams) => void;
42+
43+
/**
44+
* A handler that is invoked on the key down event for the control.
45+
*
46+
* Reserved for usage in `ContentSwitcher`.
47+
*/
48+
onKeyDown?: (params: SwitchEventHandlersParams) => void;
1549

16-
const IconSwitch = React.forwardRef(function Switch(props, tabRef) {
50+
/**
51+
* Whether the `IconSwitch` is selected.
52+
*
53+
* Reserved for usage in `ContentSwitcher`.
54+
*/
55+
selected?: boolean;
56+
57+
// TODO: Why isn't this prop named `label` to match the `IconButton` prop?
58+
/**
59+
* `Tooltip` text.
60+
*/
61+
text?: string;
62+
}
63+
64+
const frFn = forwardRef<HTMLButtonElement, IconSwitchProps>;
65+
66+
const IconSwitch = frFn((props, ref) => {
1767
const {
1868
align,
1969
children,
@@ -33,12 +83,13 @@ const IconSwitch = React.forwardRef(function Switch(props, tabRef) {
3383
const prefix = usePrefix();
3484
const [isHovered, setIsHovered] = useState(false);
3585

36-
const handleClick = (e) => {
37-
e.preventDefault();
86+
const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
87+
event.preventDefault();
3888
onClick({ index, name, text });
3989
};
4090

41-
const handleKeyDown = (event) => {
91+
const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {
92+
// TODO: `which` was deprecated years ago. When can its usage be deleted?
4293
const key = event.key || event.which;
4394

4495
onKeyDown({ index, name, text, key });
@@ -64,22 +115,11 @@ const IconSwitch = React.forwardRef(function Switch(props, tabRef) {
64115
}
65116
);
66117

67-
const commonProps = {
68-
onClick: handleClick,
69-
onKeyDown: handleKeyDown,
70-
className: classes,
71-
disabled,
72-
align,
73-
enterDelayMs,
74-
leaveDelayMs,
75-
size,
76-
};
77-
78118
return (
79119
<IconButton
80120
label={text}
81121
type="button"
82-
ref={tabRef}
122+
ref={ref}
83123
role="tab"
84124
tabIndex={selected || isHovered ? 0 : -1}
85125
onMouseEnter={handleMouseEnter}
@@ -90,7 +130,14 @@ const IconSwitch = React.forwardRef(function Switch(props, tabRef) {
90130
aria-label={text}
91131
wrapperClasses={iconButtonClasses}
92132
{...other}
93-
{...commonProps}>
133+
align={align}
134+
className={classes}
135+
disabled={disabled}
136+
enterDelayMs={enterDelayMs}
137+
leaveDelayMs={leaveDelayMs}
138+
onClick={handleClick}
139+
onKeyDown={handleKeyDown}
140+
size={size}>
94141
{children}
95142
</IconButton>
96143
);
@@ -114,17 +161,17 @@ IconSwitch.propTypes = {
114161
]),
115162

116163
/**
117-
* Provide child elements to be rendered inside of the Switch
164+
* Children to be rendered inside of the `IconSwitch`.
118165
*/
119166
children: PropTypes.node,
120167

121168
/**
122-
* Specify an optional className to be added to your Switch
169+
* Specify an optional className to be added to your `IconSwitch`.
123170
*/
124171
className: PropTypes.string,
125172

126173
/**
127-
* Specify whether or not the Switch should be disabled
174+
* Whether the `IconSwitch` should be disabled.
128175
*/
129176
disabled: PropTypes.bool,
130177

@@ -134,8 +181,9 @@ IconSwitch.propTypes = {
134181
enterDelayMs: PropTypes.number,
135182

136183
/**
137-
* The index of your Switch in your ContentSwitcher that is used for event handlers.
138-
* Reserved for usage in ContentSwitcher
184+
* The index of the `IconSwitch`.
185+
*
186+
* Reserved for usage in `ContentSwitcher`.
139187
*/
140188
index: PropTypes.number,
141189

@@ -145,34 +193,39 @@ IconSwitch.propTypes = {
145193
leaveDelayMs: PropTypes.number,
146194

147195
/**
148-
* Provide the name of your Switch that is used for event handlers
196+
* The name of the `IconSwitch`.
149197
*/
150198
name: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
151199

152200
/**
153201
* A handler that is invoked when a user clicks on the control.
154-
* Reserved for usage in ContentSwitcher
202+
*
203+
* Reserved for usage in `ContentSwitcher`.
155204
*/
156205
onClick: PropTypes.func,
157206

158207
/**
159208
* A handler that is invoked on the key down event for the control.
160-
* Reserved for usage in ContentSwitcher
209+
*
210+
* Reserved for usage in `ContentSwitcher`.
161211
*/
162212
onKeyDown: PropTypes.func,
163213

164214
/**
165-
* Whether your Switch is selected. Reserved for usage in ContentSwitcher
215+
* Whether the `IconSwitch` is selected.
216+
*
217+
* Reserved for usage in `ContentSwitcher`.
166218
*/
167219
selected: PropTypes.bool,
168220

221+
// TODO: Icon only variant of what? Isn't the `IconSwitch` always icon only?
169222
/**
170223
* Passed in from `ContentSwitcher` to render icon-only variant
171224
*/
172225
size: PropTypes.oneOf(['sm', 'md', 'lg']),
173226

174227
/**
175-
* Provide the visible text displayed by the Tooltip
228+
* `Tooltip` text.
176229
*/
177230
text: PropTypes.string,
178231
};

packages/react/src/components/Switch/Switch.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(function Switch(
101101
};
102102

103103
const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {
104+
// TODO: `which` was deprecated years ago. When can its usage be deleted?
104105
const key = event.key || event.which;
105106

106107
onKeyDown?.({ index, name, text, key });

packages/react/src/components/Toggletip/Toggletip.stories.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ export const Default = (args) => {
114114

115115
Default.argTypes = {
116116
align: {
117+
// TODO:
118+
// 1. Should the deprecated options be deleted?
119+
// 2. The list doesn't include all of the options available in the
120+
// component. Is it supposed to?
117121
options: [
118122
'top',
119123
'top-left',

packages/react/src/components/Tooltip/DefinitionTooltip.stories.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ Default.args = {
6868

6969
Default.argTypes = {
7070
align: {
71+
// TODO:
72+
// 1. Should the deprecated options be deleted?
73+
// 2. The list doesn't include all of the options available in the
74+
// component. Is it supposed to?
7175
options: [
7276
'top',
7377
'top-left',

packages/react/src/components/Tooltip/Tooltip.stories.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ export const Default = (args) => {
6666

6767
Default.argTypes = {
6868
align: {
69+
// TODO:
70+
// 1. Should the deprecated options be deleted?
71+
// 2. The list doesn't include all of the options available in the
72+
// component. Is it supposed to?
6973
options: [
7074
'top',
7175
'top-left',

packages/react/src/components/UIShell/HeaderPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { keys, match } from '../../internal/keyboard';
2020
import { useWindowEvent } from '../../internal/useEvent';
2121
import { useMergedRefs } from '../../internal/useMergedRefs';
2222
import Switcher from './Switcher';
23+
import { noopFn } from '../../internal/noopFn';
2324

2425
export interface HeaderPanelProps {
2526
/**
@@ -54,7 +55,6 @@ export interface HeaderPanelProps {
5455
onHeaderPanelFocus?: () => void;
5556
}
5657

57-
const noopFn = () => {};
5858
const HeaderPanel: React.FC<HeaderPanelProps> = React.forwardRef(
5959
function HeaderPanel(
6060
{

0 commit comments

Comments
 (0)