mirror of
https://github.com/apache/superset.git
synced 2024-09-16 02:29:39 -04:00
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:
parent
95809e5e60
commit
483405fff9
@ -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;
|
|
@ -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> {
|
||||||
|
static defaultProps = {
|
||||||
position: 'left',
|
position: 'left',
|
||||||
innerRef: null,
|
innerRef: null,
|
||||||
children: 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;
|
|
@ -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;
|
|
@ -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);
|
@ -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: 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithPopoverMenuState {
|
||||||
|
isFocused: Boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class WithPopoverMenu extends React.PureComponent<
|
||||||
|
WithPopoverMenuProps,
|
||||||
|
WithPopoverMenuState
|
||||||
|
> {
|
||||||
|
container: ShouldFocusContainer;
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
children: null,
|
children: null,
|
||||||
disableClick: false,
|
disableClick: false,
|
||||||
onChangeFocus: null,
|
onChangeFocus: null,
|
||||||
menuItems: [],
|
menuItems: [],
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
shouldFocus: (event, container) =>
|
shouldFocus: (event: any, container: ShouldFocusContainer) =>
|
||||||
container?.contains(event.target) ||
|
container?.contains(event.target) ||
|
||||||
event.target.id === 'menu-item' ||
|
event.target.id === 'menu-item' ||
|
||||||
event.target.parentNode?.id === 'menu-item',
|
event.target.parentNode?.id === 'menu-item',
|
||||||
style: null,
|
style: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
class WithPopoverMenu extends React.PureComponent {
|
constructor(props: WithPopoverMenuProps) {
|
||||||
constructor(props) {
|
|
||||||
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;
|
|
Loading…
Reference in New Issue
Block a user