1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00
lens/src/renderer/components/icon/icon.tsx
Sebastian Malton 17291a1709 Remove custom <Icon /> component
- Move to using Material-UI's <Icon /> and <SvgIcon />

- Move to using Material-UI's <Tooltip />

- Move to using Material-UI's <IconButton />

- Switch *.svg webpack importer so we can import then as React
  components

- Export the above to the extension API

- Move to using the Material-UI's component names for menuItem.icon's.
  This means that they are now in PascalCase instead of snake_case

- Remove the Material-UI font

Signed-off-by: Sebastian Malton <sebastian@malton.name>
2021-04-15 16:23:52 -04:00

125 lines
3.5 KiB
TypeScript

import "./icon.scss";
import React, { ReactNode } from "react";
import { findDOMNode } from "react-dom";
import { NavLink } from "react-router-dom";
import { LocationDescriptor } from "history";
import { autobind, cssNames } from "../../utils";
import { TooltipDecoratorProps, withTooltip } from "../tooltip";
import isNumber from "lodash/isNumber";
export interface IconProps extends React.HTMLAttributes<any>, TooltipDecoratorProps {
material?: string; // material-icon, see available names at https://material.io/icons/
link?: LocationDescriptor; // render icon as NavLink from react-router-dom
href?: string; // render icon as hyperlink
size?: string | number; // icon-size
small?: boolean; // pre-defined icon-size
smallest?: boolean; // pre-defined icon-size
big?: boolean; // pre-defined icon-size
active?: boolean; // apply active-state styles
interactive?: boolean; // indicates that icon is interactive and highlight it on focus/hover
focusable?: boolean; // allow focus to the icon + show .active styles (default: "true", when icon is interactive)
sticker?: boolean;
disabled?: boolean;
}
@withTooltip
export class Icon extends React.PureComponent<IconProps> {
static defaultProps: IconProps = {
focusable: true,
};
get isInteractive() {
const { interactive, onClick, href, link } = this.props;
return interactive ?? !!(onClick || href || link);
}
@autobind()
onClick(evt: React.MouseEvent) {
if (this.props.disabled) {
return;
}
if (this.props.onClick) {
this.props.onClick(evt);
}
}
@autobind()
onKeyDown(evt: React.KeyboardEvent<any>) {
switch (evt.nativeEvent.code) {
case "Space":
case "Enter": {
// eslint-disable-next-line react/no-find-dom-node
const icon = findDOMNode(this) as HTMLElement;
setTimeout(() => icon.click());
evt.preventDefault();
break;
}
}
if (this.props.onKeyDown) {
this.props.onKeyDown(evt);
}
}
render() {
const { isInteractive } = this;
const {
// skip passing props to icon's html element
className, href, link, material, size, smallest, small, big,
disabled, sticker, active, focusable, children,
interactive: _interactive,
onClick: _onClick,
onKeyDown: _onKeyDown,
...elemProps
} = this.props;
let iconContent: ReactNode;
const iconProps: Partial<IconProps> = {
className: cssNames("Icon", className,
{ material, interactive: isInteractive, disabled, sticker, active, focusable },
!size ? { smallest, small, big } : {}
),
onClick: isInteractive ? this.onClick : undefined,
onKeyDown: isInteractive ? this.onKeyDown : undefined,
tabIndex: isInteractive && focusable && !disabled ? 0 : undefined,
style: size ? { "--size": size + (isNumber(size) ? "px" : "") } as React.CSSProperties : undefined,
...elemProps
};
// render as material-icon
if (material) {
iconContent = <span className="icon">{material}</span>;
}
// wrap icon's content passed from decorator
iconProps.children = (
<>
{iconContent}
{children}
</>
);
// render icon type
if (link) {
const { className, children } = iconProps;
return (
<NavLink className={className} to={link}>
{children}
</NavLink>
);
}
if (href) {
return <a {...iconProps} href={href}/>;
}
return <i {...iconProps} />;
}
}