chore: Migrating dashboard/components/menu from jsx to tsx (#13361)
* fix: constant icon size
* clean up
* dashboard/components/menu jsx -> tsx
* more types
* package-lock.json sync
* package-lock fix
* fix
* lint fix
* added comment about event type
diff --git a/superset-frontend/src/dashboard/components/menu/BackgroundStyleDropdown.jsx b/superset-frontend/src/dashboard/components/menu/BackgroundStyleDropdown.tsx
similarity index 81%
rename from superset-frontend/src/dashboard/components/menu/BackgroundStyleDropdown.jsx
rename to superset-frontend/src/dashboard/components/menu/BackgroundStyleDropdown.tsx
index 93b5de2..34dcdf9 100644
--- a/superset-frontend/src/dashboard/components/menu/BackgroundStyleDropdown.jsx
+++ b/superset-frontend/src/dashboard/components/menu/BackgroundStyleDropdown.tsx
@@ -17,19 +17,21 @@
* under the License.
*/
import React from 'react';
-import PropTypes from 'prop-types';
import cx from 'classnames';
import backgroundStyleOptions from '../../util/backgroundStyleOptions';
-import PopoverDropdown from './PopoverDropdown';
+import PopoverDropdown, {
+ OptionProps,
+ OnChangeHandler,
+} from './PopoverDropdown';
-const propTypes = {
- id: PropTypes.string.isRequired,
- value: PropTypes.string.isRequired,
- onChange: PropTypes.func.isRequired,
-};
+interface BackgroundStyleDropdownProps {
+ id: string;
+ value: string;
+ onChange: OnChangeHandler;
+}
-function renderButton(option) {
+function renderButton(option: OptionProps) {
return (
<div className={cx('background-style-option', option.className)}>
{`${option.label} background`}
@@ -37,7 +39,7 @@
);
}
-function renderOption(option) {
+function renderOption(option: OptionProps) {
return (
<div className={cx('background-style-option', option.className)}>
{option.label}
@@ -45,7 +47,7 @@
);
}
-export default class BackgroundStyleDropdown extends React.PureComponent {
+export default class BackgroundStyleDropdown extends React.PureComponent<BackgroundStyleDropdownProps> {
render() {
const { id, value, onChange } = this.props;
return (
@@ -60,5 +62,3 @@
);
}
}
-
-BackgroundStyleDropdown.propTypes = propTypes;
diff --git a/superset-frontend/src/dashboard/components/menu/HoverMenu.jsx b/superset-frontend/src/dashboard/components/menu/HoverMenu.tsx
similarity index 74%
rename from superset-frontend/src/dashboard/components/menu/HoverMenu.jsx
rename to superset-frontend/src/dashboard/components/menu/HoverMenu.tsx
index ef46b58..6fa21ec 100644
--- a/superset-frontend/src/dashboard/components/menu/HoverMenu.jsx
+++ b/superset-frontend/src/dashboard/components/menu/HoverMenu.tsx
@@ -16,23 +16,22 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React from 'react';
-import PropTypes from 'prop-types';
+import React, { RefObject } from 'react';
import cx from 'classnames';
-const propTypes = {
- position: PropTypes.oneOf(['left', 'top']),
- innerRef: PropTypes.func,
- children: PropTypes.node,
-};
+interface HoverMenuProps {
+ position: 'left' | 'top';
+ innerRef: RefObject<HTMLDivElement>;
+ children: React.ReactNode;
+}
-const defaultProps = {
- position: 'left',
- innerRef: null,
- children: null,
-};
+export default class HoverMenu extends React.PureComponent<HoverMenuProps> {
+ static defaultProps = {
+ position: 'left',
+ innerRef: null,
+ children: null,
+ };
-export default class HoverMenu extends React.PureComponent {
render() {
const { innerRef, position, children } = this.props;
return (
@@ -49,6 +48,3 @@
);
}
}
-
-HoverMenu.propTypes = propTypes;
-HoverMenu.defaultProps = defaultProps;
diff --git a/superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.jsx b/superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.tsx
similarity index 82%
rename from superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.jsx
rename to superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.tsx
index 62a289a..c9fc042 100644
--- a/superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.jsx
+++ b/superset-frontend/src/dashboard/components/menu/MarkdownModeDropdown.tsx
@@ -17,16 +17,15 @@
* under the License.
*/
import React from 'react';
-import PropTypes from 'prop-types';
import { t } from '@superset-ui/core';
-import PopoverDropdown from './PopoverDropdown';
+import PopoverDropdown, { OnChangeHandler } from './PopoverDropdown';
-const propTypes = {
- id: PropTypes.string.isRequired,
- value: PropTypes.string.isRequired,
- onChange: PropTypes.func.isRequired,
-};
+interface MarkdownModeDropdownProps {
+ id: string;
+ value: string;
+ onChange: OnChangeHandler;
+}
const dropdownOptions = [
{
@@ -39,7 +38,7 @@
},
];
-export default class MarkdownModeDropdown extends React.PureComponent {
+export default class MarkdownModeDropdown extends React.PureComponent<MarkdownModeDropdownProps> {
render() {
const { id, value, onChange } = this.props;
@@ -53,5 +52,3 @@
);
}
}
-
-MarkdownModeDropdown.propTypes = propTypes;
diff --git a/superset-frontend/src/dashboard/components/menu/PopoverDropdown.jsx b/superset-frontend/src/dashboard/components/menu/PopoverDropdown.tsx
similarity index 69%
rename from superset-frontend/src/dashboard/components/menu/PopoverDropdown.jsx
rename to superset-frontend/src/dashboard/components/menu/PopoverDropdown.tsx
index d67cd38..15f56ed 100644
--- a/superset-frontend/src/dashboard/components/menu/PopoverDropdown.jsx
+++ b/superset-frontend/src/dashboard/components/menu/PopoverDropdown.tsx
@@ -17,33 +17,29 @@
* under the License.
*/
import React from 'react';
-import PropTypes from 'prop-types';
import cx from 'classnames';
-import { styled, withTheme } from '@superset-ui/core';
+import { styled, withTheme, SupersetThemeProps } from '@superset-ui/core';
import { Dropdown, Menu } from 'src/common/components';
import Icon from 'src/components/Icon';
-const propTypes = {
- id: PropTypes.string.isRequired,
- options: PropTypes.arrayOf(
- PropTypes.shape({
- value: PropTypes.string.isRequired,
- label: PropTypes.string.isRequired,
- className: PropTypes.string,
- }),
- ).isRequired,
- onChange: PropTypes.func.isRequired,
- value: PropTypes.string.isRequired,
- renderButton: PropTypes.func,
- renderOption: PropTypes.func,
-};
+export interface OptionProps {
+ value: string;
+ label: string;
+ className?: string;
+}
-const defaultProps = {
- renderButton: option => option.label,
- renderOption: option => (
- <div className={option.className}>{option.label}</div>
- ),
-};
+export type OnChangeHandler = (key: React.Key) => void;
+export type RenderElementHandler = (option: OptionProps) => JSX.Element;
+
+interface PopoverDropdownProps {
+ id: string;
+ options: OptionProps[];
+ onChange: OnChangeHandler;
+ value: string;
+ theme: SupersetThemeProps['theme'];
+ renderButton: RenderElementHandler;
+ renderOption: RenderElementHandler;
+}
const MenuItem = styled(Menu.Item)`
&.ant-menu-item {
@@ -75,31 +71,34 @@
}
`;
-class PopoverDropdown extends React.PureComponent {
- constructor(props) {
+interface HandleSelectProps {
+ key: React.Key;
+}
+
+class PopoverDropdown extends React.PureComponent<PopoverDropdownProps> {
+ constructor(props: PopoverDropdownProps) {
super(props);
this.handleSelect = this.handleSelect.bind(this);
}
- handleSelect({ key }) {
+ handleSelect({ key }: HandleSelectProps) {
this.props.onChange(key);
}
+ static defaultProps = {
+ renderButton: (option: OptionProps) => option.label,
+ renderOption: (option: OptionProps) => (
+ <div className={option.className}>{option.label}</div>
+ ),
+ };
+
render() {
- const {
- id,
- value,
- options,
- renderButton,
- renderOption,
- theme,
- } = this.props;
+ const { value, options, renderButton, renderOption, theme } = this.props;
const selected = options.find(opt => opt.value === value);
return (
<Dropdown
- id={id}
- trigger="click"
+ trigger={['click']}
overlayStyle={{ zIndex: theme.zIndex.max }}
overlay={
<Menu onClick={this.handleSelect}>
@@ -118,7 +117,7 @@
}
>
<div role="button" css={{ display: 'flex', alignItems: 'center' }}>
- {renderButton(selected)}
+ {selected && renderButton(selected)}
<Icon name="caret-down" css={{ marginTop: 4 }} />
</div>
</Dropdown>
@@ -126,7 +125,4 @@
}
}
-PopoverDropdown.propTypes = propTypes;
-PopoverDropdown.defaultProps = defaultProps;
-
export default withTheme(PopoverDropdown);
diff --git a/superset-frontend/src/dashboard/components/menu/WithPopoverMenu.jsx b/superset-frontend/src/dashboard/components/menu/WithPopoverMenu.tsx
similarity index 67%
rename from superset-frontend/src/dashboard/components/menu/WithPopoverMenu.jsx
rename to superset-frontend/src/dashboard/components/menu/WithPopoverMenu.tsx
index dcd8dcf..df44b4e 100644
--- a/superset-frontend/src/dashboard/components/menu/WithPopoverMenu.jsx
+++ b/superset-frontend/src/dashboard/components/menu/WithPopoverMenu.tsx
@@ -17,44 +17,59 @@
* under the License.
*/
import React from 'react';
-import PropTypes from 'prop-types';
import cx from 'classnames';
-const propTypes = {
- children: PropTypes.node,
- disableClick: PropTypes.bool,
- menuItems: PropTypes.arrayOf(PropTypes.node),
- onChangeFocus: PropTypes.func,
- isFocused: PropTypes.bool,
- shouldFocus: PropTypes.func,
- editMode: PropTypes.bool.isRequired,
- style: PropTypes.object,
+type ShouldFocusContainer = HTMLDivElement & {
+ contains: (event_target: EventTarget & HTMLElement) => Boolean;
};
-const defaultProps = {
- children: null,
- disableClick: false,
- onChangeFocus: null,
- menuItems: [],
- isFocused: false,
- shouldFocus: (event, container) =>
- container?.contains(event.target) ||
- event.target.id === 'menu-item' ||
- event.target.parentNode?.id === 'menu-item',
- style: null,
-};
+interface WithPopoverMenuProps {
+ children: React.ReactNode;
+ disableClick: Boolean;
+ menuItems: React.ReactNode[];
+ onChangeFocus: (focus: Boolean) => void;
+ isFocused: Boolean;
+ // Event argument is left as "any" because of the clash. In defaultProps it seems
+ // like it should be React.FocusEvent<>, however from handleClick() we can also
+ // derive that type is EventListenerOrEventListenerObject.
+ shouldFocus: (event: any, container: ShouldFocusContainer) => Boolean;
+ editMode: Boolean;
+ style: React.CSSProperties;
+}
-class WithPopoverMenu extends React.PureComponent {
- constructor(props) {
+interface WithPopoverMenuState {
+ isFocused: Boolean;
+}
+
+export default class WithPopoverMenu extends React.PureComponent<
+ WithPopoverMenuProps,
+ WithPopoverMenuState
+> {
+ container: ShouldFocusContainer;
+
+ static defaultProps = {
+ children: null,
+ disableClick: false,
+ onChangeFocus: null,
+ menuItems: [],
+ isFocused: false,
+ shouldFocus: (event: any, container: ShouldFocusContainer) =>
+ container?.contains(event.target) ||
+ event.target.id === 'menu-item' ||
+ event.target.parentNode?.id === 'menu-item',
+ style: null,
+ };
+
+ constructor(props: WithPopoverMenuProps) {
super(props);
this.state = {
- isFocused: props.isFocused,
+ isFocused: props.isFocused!,
};
this.setRef = this.setRef.bind(this);
this.handleClick = this.handleClick.bind(this);
}
- UNSAFE_componentWillReceiveProps(nextProps) {
+ UNSAFE_componentWillReceiveProps(nextProps: WithPopoverMenuProps) {
if (nextProps.editMode && nextProps.isFocused && !this.state.isFocused) {
document.addEventListener('click', this.handleClick);
document.addEventListener('drag', this.handleClick);
@@ -71,11 +86,11 @@
document.removeEventListener('drag', this.handleClick);
}
- setRef(ref) {
+ setRef(ref: ShouldFocusContainer) {
this.container = ref;
}
- handleClick(event) {
+ handleClick(event: any) {
if (!this.props.editMode) {
return;
}
@@ -84,6 +99,7 @@
shouldFocus: shouldFocusFunc,
disableClick,
} = this.props;
+
const shouldFocus = shouldFocusFunc(event, this.container);
if (!disableClick && shouldFocus && !this.state.isFocused) {
@@ -121,9 +137,9 @@
style={style}
>
{children}
- {editMode && isFocused && menuItems.length > 0 && (
+ {editMode && isFocused && (menuItems?.length ?? 0) > 0 && (
<div className="popover-menu">
- {menuItems.map((node, i) => (
+ {menuItems.map((node: React.ReactNode, i: Number) => (
<div className="menu-item" key={`menu-item-${i}`}>
{node}
</div>
@@ -134,8 +150,3 @@
);
}
}
-
-WithPopoverMenu.propTypes = propTypes;
-WithPopoverMenu.defaultProps = defaultProps;
-
-export default WithPopoverMenu;