Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,37 @@
* 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`}
</div>
);
}

function renderOption(option) {
function renderOption(option: OptionProps) {
return (
<div className={cx('background-style-option', option.className)}>
{option.label}
</div>
);
}

export default class BackgroundStyleDropdown extends React.PureComponent {
export default class BackgroundStyleDropdown extends React.PureComponent<BackgroundStyleDropdownProps> {
render() {
const { id, value, onChange } = this.props;
return (
Expand All @@ -60,5 +62,3 @@ export default class BackgroundStyleDropdown extends React.PureComponent {
);
}
}

BackgroundStyleDropdown.propTypes = propTypes;
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -49,6 +48,3 @@ export default class HoverMenu extends React.PureComponent {
);
}
}

HoverMenu.propTypes = propTypes;
HoverMenu.defaultProps = defaultProps;
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
{
Expand All @@ -39,7 +38,7 @@ const dropdownOptions = [
},
];

export default class MarkdownModeDropdown extends React.PureComponent {
export default class MarkdownModeDropdown extends React.PureComponent<MarkdownModeDropdownProps> {
render() {
const { id, value, onChange } = this.props;

Expand All @@ -53,5 +52,3 @@ export default class MarkdownModeDropdown extends React.PureComponent {
);
}
}

MarkdownModeDropdown.propTypes = propTypes;
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

const defaultProps = {
renderButton: option => option.label,
renderOption: option => (
<div className={option.className}>{option.label}</div>
),
};
export interface OptionProps {
value: string;
label: string;
className?: string;
}

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 {
Expand Down Expand Up @@ -75,31 +71,34 @@ const MenuItem = styled(Menu.Item)`
}
`;

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}>
Expand All @@ -118,15 +117,12 @@ class PopoverDropdown extends React.PureComponent {
}
>
<div role="button" css={{ display: 'flex', alignItems: 'center' }}>
{renderButton(selected)}
{selected && renderButton(selected)}
<Icon name="caret-down" css={{ marginTop: 4 }} />
</div>
</Dropdown>
);
}
}

PopoverDropdown.propTypes = propTypes;
PopoverDropdown.defaultProps = defaultProps;

export default withTheme(PopoverDropdown);
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

interface WithPopoverMenuState {
isFocused: Boolean;
}

export default class WithPopoverMenu extends React.PureComponent<
WithPopoverMenuProps,
WithPopoverMenuState
> {
container: ShouldFocusContainer;

class WithPopoverMenu extends React.PureComponent {
constructor(props) {
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);
Expand All @@ -71,11 +86,11 @@ class WithPopoverMenu extends React.PureComponent {
document.removeEventListener('drag', this.handleClick);
}

setRef(ref) {
setRef(ref: ShouldFocusContainer) {
this.container = ref;
}

handleClick(event) {
handleClick(event: any) {
if (!this.props.editMode) {
return;
}
Expand All @@ -84,6 +99,7 @@ class WithPopoverMenu extends React.PureComponent {
shouldFocus: shouldFocusFunc,
disableClick,
} = this.props;

const shouldFocus = shouldFocusFunc(event, this.container);

if (!disableClick && shouldFocus && !this.state.isFocused) {
Expand Down Expand Up @@ -121,9 +137,9 @@ class WithPopoverMenu extends React.PureComponent {
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>
Expand All @@ -134,8 +150,3 @@ class WithPopoverMenu extends React.PureComponent {
);
}
}

WithPopoverMenu.propTypes = propTypes;
WithPopoverMenu.defaultProps = defaultProps;

export default WithPopoverMenu;