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
This commit is contained in:
Ayan Ginet 2021-03-04 21:40:42 +05:00 committed by GitHub
parent 95809e5e60
commit 483405fff9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 112 additions and 112 deletions

View File

@ -17,19 +17,21 @@
* under the License. * under the License.
*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames'; import cx from 'classnames';
import backgroundStyleOptions from '../../util/backgroundStyleOptions'; import backgroundStyleOptions from '../../util/backgroundStyleOptions';
import PopoverDropdown from './PopoverDropdown'; import PopoverDropdown, {
OptionProps,
OnChangeHandler,
} from './PopoverDropdown';
const propTypes = { interface BackgroundStyleDropdownProps {
id: PropTypes.string.isRequired, id: string;
value: PropTypes.string.isRequired, value: string;
onChange: PropTypes.func.isRequired, onChange: OnChangeHandler;
}; }
function renderButton(option) { function renderButton(option: OptionProps) {
return ( return (
<div className={cx('background-style-option', option.className)}> <div className={cx('background-style-option', option.className)}>
{`${option.label} background`} {`${option.label} background`}
@ -37,7 +39,7 @@ function renderButton(option) {
); );
} }
function renderOption(option) { function renderOption(option: OptionProps) {
return ( return (
<div className={cx('background-style-option', option.className)}> <div className={cx('background-style-option', option.className)}>
{option.label} {option.label}
@ -45,7 +47,7 @@ function renderOption(option) {
); );
} }
export default class BackgroundStyleDropdown extends React.PureComponent { export default class BackgroundStyleDropdown extends React.PureComponent<BackgroundStyleDropdownProps> {
render() { render() {
const { id, value, onChange } = this.props; const { id, value, onChange } = this.props;
return ( return (
@ -60,5 +62,3 @@ export default class BackgroundStyleDropdown extends React.PureComponent {
); );
} }
} }
BackgroundStyleDropdown.propTypes = propTypes;

View File

@ -16,23 +16,22 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
import React from 'react'; import React, { RefObject } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames'; import cx from 'classnames';
const propTypes = { interface HoverMenuProps {
position: PropTypes.oneOf(['left', 'top']), position: 'left' | 'top';
innerRef: PropTypes.func, innerRef: RefObject<HTMLDivElement>;
children: PropTypes.node, children: React.ReactNode;
}; }
const defaultProps = { export default class HoverMenu extends React.PureComponent<HoverMenuProps> {
position: 'left', static defaultProps = {
innerRef: null, position: 'left',
children: null, innerRef: null,
}; children: null,
};
export default class HoverMenu extends React.PureComponent {
render() { render() {
const { innerRef, position, children } = this.props; const { innerRef, position, children } = this.props;
return ( return (
@ -49,6 +48,3 @@ export default class HoverMenu extends React.PureComponent {
); );
} }
} }
HoverMenu.propTypes = propTypes;
HoverMenu.defaultProps = defaultProps;

View File

@ -17,16 +17,15 @@
* under the License. * under the License.
*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import { t } from '@superset-ui/core'; import { t } from '@superset-ui/core';
import PopoverDropdown from './PopoverDropdown'; import PopoverDropdown, { OnChangeHandler } from './PopoverDropdown';
const propTypes = { interface MarkdownModeDropdownProps {
id: PropTypes.string.isRequired, id: string;
value: PropTypes.string.isRequired, value: string;
onChange: PropTypes.func.isRequired, onChange: OnChangeHandler;
}; }
const dropdownOptions = [ const dropdownOptions = [
{ {
@ -39,7 +38,7 @@ const dropdownOptions = [
}, },
]; ];
export default class MarkdownModeDropdown extends React.PureComponent { export default class MarkdownModeDropdown extends React.PureComponent<MarkdownModeDropdownProps> {
render() { render() {
const { id, value, onChange } = this.props; const { id, value, onChange } = this.props;
@ -53,5 +52,3 @@ export default class MarkdownModeDropdown extends React.PureComponent {
); );
} }
} }
MarkdownModeDropdown.propTypes = propTypes;

View File

@ -17,33 +17,29 @@
* under the License. * under the License.
*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames'; 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 { Dropdown, Menu } from 'src/common/components';
import Icon from 'src/components/Icon'; import Icon from 'src/components/Icon';
const propTypes = { export interface OptionProps {
id: PropTypes.string.isRequired, value: string;
options: PropTypes.arrayOf( label: string;
PropTypes.shape({ className?: string;
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,
};
const defaultProps = { export type OnChangeHandler = (key: React.Key) => void;
renderButton: option => option.label, export type RenderElementHandler = (option: OptionProps) => JSX.Element;
renderOption: option => (
<div className={option.className}>{option.label}</div> interface PopoverDropdownProps {
), id: string;
}; options: OptionProps[];
onChange: OnChangeHandler;
value: string;
theme: SupersetThemeProps['theme'];
renderButton: RenderElementHandler;
renderOption: RenderElementHandler;
}
const MenuItem = styled(Menu.Item)` const MenuItem = styled(Menu.Item)`
&.ant-menu-item { &.ant-menu-item {
@ -75,31 +71,34 @@ const MenuItem = styled(Menu.Item)`
} }
`; `;
class PopoverDropdown extends React.PureComponent { interface HandleSelectProps {
constructor(props) { key: React.Key;
}
class PopoverDropdown extends React.PureComponent<PopoverDropdownProps> {
constructor(props: PopoverDropdownProps) {
super(props); super(props);
this.handleSelect = this.handleSelect.bind(this); this.handleSelect = this.handleSelect.bind(this);
} }
handleSelect({ key }) { handleSelect({ key }: HandleSelectProps) {
this.props.onChange(key); this.props.onChange(key);
} }
static defaultProps = {
renderButton: (option: OptionProps) => option.label,
renderOption: (option: OptionProps) => (
<div className={option.className}>{option.label}</div>
),
};
render() { render() {
const { const { value, options, renderButton, renderOption, theme } = this.props;
id,
value,
options,
renderButton,
renderOption,
theme,
} = this.props;
const selected = options.find(opt => opt.value === value); const selected = options.find(opt => opt.value === value);
return ( return (
<Dropdown <Dropdown
id={id} trigger={['click']}
trigger="click"
overlayStyle={{ zIndex: theme.zIndex.max }} overlayStyle={{ zIndex: theme.zIndex.max }}
overlay={ overlay={
<Menu onClick={this.handleSelect}> <Menu onClick={this.handleSelect}>
@ -118,7 +117,7 @@ class PopoverDropdown extends React.PureComponent {
} }
> >
<div role="button" css={{ display: 'flex', alignItems: 'center' }}> <div role="button" css={{ display: 'flex', alignItems: 'center' }}>
{renderButton(selected)} {selected && renderButton(selected)}
<Icon name="caret-down" css={{ marginTop: 4 }} /> <Icon name="caret-down" css={{ marginTop: 4 }} />
</div> </div>
</Dropdown> </Dropdown>
@ -126,7 +125,4 @@ class PopoverDropdown extends React.PureComponent {
} }
} }
PopoverDropdown.propTypes = propTypes;
PopoverDropdown.defaultProps = defaultProps;
export default withTheme(PopoverDropdown); export default withTheme(PopoverDropdown);

View File

@ -17,44 +17,59 @@
* under the License. * under the License.
*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames'; import cx from 'classnames';
const propTypes = { type ShouldFocusContainer = HTMLDivElement & {
children: PropTypes.node, contains: (event_target: EventTarget & HTMLElement) => Boolean;
disableClick: PropTypes.bool,
menuItems: PropTypes.arrayOf(PropTypes.node),
onChangeFocus: PropTypes.func,
isFocused: PropTypes.bool,
shouldFocus: PropTypes.func,
editMode: PropTypes.bool.isRequired,
style: PropTypes.object,
}; };
const defaultProps = { interface WithPopoverMenuProps {
children: null, children: React.ReactNode;
disableClick: false, disableClick: Boolean;
onChangeFocus: null, menuItems: React.ReactNode[];
menuItems: [], onChangeFocus: (focus: Boolean) => void;
isFocused: false, isFocused: Boolean;
shouldFocus: (event, container) => // Event argument is left as "any" because of the clash. In defaultProps it seems
container?.contains(event.target) || // like it should be React.FocusEvent<>, however from handleClick() we can also
event.target.id === 'menu-item' || // derive that type is EventListenerOrEventListenerObject.
event.target.parentNode?.id === 'menu-item', shouldFocus: (event: any, container: ShouldFocusContainer) => Boolean;
style: null, editMode: Boolean;
}; style: React.CSSProperties;
}
class WithPopoverMenu extends React.PureComponent { interface WithPopoverMenuState {
constructor(props) { 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); super(props);
this.state = { this.state = {
isFocused: props.isFocused, isFocused: props.isFocused!,
}; };
this.setRef = this.setRef.bind(this); this.setRef = this.setRef.bind(this);
this.handleClick = this.handleClick.bind(this); this.handleClick = this.handleClick.bind(this);
} }
UNSAFE_componentWillReceiveProps(nextProps) { UNSAFE_componentWillReceiveProps(nextProps: WithPopoverMenuProps) {
if (nextProps.editMode && nextProps.isFocused && !this.state.isFocused) { if (nextProps.editMode && nextProps.isFocused && !this.state.isFocused) {
document.addEventListener('click', this.handleClick); document.addEventListener('click', this.handleClick);
document.addEventListener('drag', this.handleClick); document.addEventListener('drag', this.handleClick);
@ -71,11 +86,11 @@ class WithPopoverMenu extends React.PureComponent {
document.removeEventListener('drag', this.handleClick); document.removeEventListener('drag', this.handleClick);
} }
setRef(ref) { setRef(ref: ShouldFocusContainer) {
this.container = ref; this.container = ref;
} }
handleClick(event) { handleClick(event: any) {
if (!this.props.editMode) { if (!this.props.editMode) {
return; return;
} }
@ -84,6 +99,7 @@ class WithPopoverMenu extends React.PureComponent {
shouldFocus: shouldFocusFunc, shouldFocus: shouldFocusFunc,
disableClick, disableClick,
} = this.props; } = this.props;
const shouldFocus = shouldFocusFunc(event, this.container); const shouldFocus = shouldFocusFunc(event, this.container);
if (!disableClick && shouldFocus && !this.state.isFocused) { if (!disableClick && shouldFocus && !this.state.isFocused) {
@ -121,9 +137,9 @@ class WithPopoverMenu extends React.PureComponent {
style={style} style={style}
> >
{children} {children}
{editMode && isFocused && menuItems.length > 0 && ( {editMode && isFocused && (menuItems?.length ?? 0) > 0 && (
<div className="popover-menu"> <div className="popover-menu">
{menuItems.map((node, i) => ( {menuItems.map((node: React.ReactNode, i: Number) => (
<div className="menu-item" key={`menu-item-${i}`}> <div className="menu-item" key={`menu-item-${i}`}>
{node} {node}
</div> </div>
@ -134,8 +150,3 @@ class WithPopoverMenu extends React.PureComponent {
); );
} }
} }
WithPopoverMenu.propTypes = propTypes;
WithPopoverMenu.defaultProps = defaultProps;
export default WithPopoverMenu;