diff --git a/packages/react-components/src/Button/Button.tsx b/packages/react-components/src/Button/Button.tsx deleted file mode 100644 index 9738b37784..0000000000 --- a/packages/react-components/src/Button/Button.tsx +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2017-2023 @polkadot/react-components authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import type { ButtonProps } from './types'; - -import React, { useCallback, useEffect } from 'react'; -import styled from 'styled-components'; - -import Icon from '../Icon'; -import Spinner from '../Spinner'; - -function Button ({ activeOnEnter, children, className = '', dataTestId = '', icon, isBasic, isBusy, isCircular, isDisabled, isFull, isIcon, isSelected, isToplevel, label, onClick, isReadOnly = !onClick, onMouseEnter, onMouseLeave, tabIndex, withoutLink }: ButtonProps): React.ReactElement { - const _onClick = useCallback( - (): void => { - !(isBusy || isDisabled) && onClick && onClick(); - }, - [isBusy, isDisabled, onClick] - ); - - const _onMouseEnter = useCallback((): void => { - onMouseEnter && onMouseEnter(); - }, [onMouseEnter]); - - const _onMouseLeave = useCallback((): void => { - onMouseLeave && onMouseLeave(); - }, [onMouseLeave]); - - const listenKeyboard = useCallback((event: KeyboardEvent): void => { - if (!isBusy && !isDisabled && event.key === 'Enter') { - onClick && onClick(); - } - }, [isBusy, isDisabled, onClick]); - - useEffect(() => { - if (activeOnEnter) { - window.addEventListener('keydown', listenKeyboard, true); - } - - return () => { - if (activeOnEnter) { - window.removeEventListener('keydown', listenKeyboard, true); - } - }; - }, [activeOnEnter, listenKeyboard]); - - return ( - - {icon && } - {label} - {children} - {isBusy && ( - - )} - - ); -} - -const ICON_PADDING = 0.5; - -const StyledButton = styled.button` - background: transparent; - border: none; - color: inherit; - cursor: pointer; - line-height: 1; - margin: 0; - outline: none; - position: relative; - vertical-align: middle; - text-align: center; - - &:not(.hasLabel) { - padding: 0.7em; - - .ui--Icon { - padding: 0.6rem; - margin: -0.6rem; - } - } - - &:not(.isCircular) { - border-radius: 0.25rem; - } - - &:focus { - outline:0; - } - - &.hasLabel { - padding: 0.7rem 1.1rem 0.7rem ${1.1 - ICON_PADDING}rem; - - .ui--Icon { - margin-right: 0.425rem !important; - } - } - - &.isBasic { - background: var(--bg-table); - } - - &.isCircular { - border-radius: 10rem; - } - - &.isDisabled, &.isReadOnly { - background: none; - box-shadow: none; - cursor: not-allowed; - } - - &.isBusy { - cursor: wait; - } - - &.isFull { - display: block; - width: 100%; - } - - &.isIcon { - background: transparent; - } - - .ui--Button-overlay { - background: rgba(253, 252, 251, 0.75); - bottom: 0; - left: 0; - position: absolute; - right: 0; - top: 0; - visibility: hidden; - } - - .ui--Icon { - border-radius: 50%; - box-sizing: content-box; - height: 1rem; - margin: -${ICON_PADDING}rem 0; - padding: ${ICON_PADDING}rem; - width: 1rem; - } - - &.isDisabled { - color: #bcbbba; - } -`; - -export default React.memo(Button); diff --git a/packages/react-components/src/Button/Group.tsx b/packages/react-components/src/Button/Group.tsx index f1e600e819..e19badd291 100644 --- a/packages/react-components/src/Button/Group.tsx +++ b/packages/react-components/src/Button/Group.tsx @@ -1,12 +1,16 @@ // Copyright 2017-2023 @polkadot/react-components authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { GroupProps } from './types'; - import React from 'react'; import styled from 'styled-components'; -function ButtonGroup ({ children, className = '', isCentered }: GroupProps): React.ReactElement { +interface Props { + children?: React.ReactNode; + className?: string; + isCentered?: boolean; +} + +function ButtonGroup ({ children, className = '', isCentered }: Props): React.ReactElement { return ( {children} diff --git a/packages/react-components/src/Button/index.tsx b/packages/react-components/src/Button/index.tsx index a6921c28eb..6b1ec79265 100644 --- a/packages/react-components/src/Button/index.tsx +++ b/packages/react-components/src/Button/index.tsx @@ -1,12 +1,164 @@ // Copyright 2017-2023 @polkadot/react-components authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { ButtonType } from './types'; +import type { ButtonProps as Props } from './types'; -import IButton from './Button'; +import React, { useCallback, useEffect } from 'react'; +import styled from 'styled-components'; + +import Icon from '../Icon'; +import Spinner from '../Spinner'; import Group from './Group'; -const Button = IButton as unknown as ButtonType; +function ButtonBase ({ activeOnEnter, children, className = '', dataTestId = '', icon, isBasic, isBusy, isCircular, isDisabled, isFull, isIcon, isSelected, isToplevel, label, onClick, isReadOnly = !onClick, onMouseEnter, onMouseLeave, tabIndex, withoutLink }: Props): React.ReactElement { + const _onClick = useCallback( + (): void => { + !(isBusy || isDisabled) && onClick && onClick(); + }, + [isBusy, isDisabled, onClick] + ); + + const _onMouseEnter = useCallback((): void => { + onMouseEnter && onMouseEnter(); + }, [onMouseEnter]); + + const _onMouseLeave = useCallback((): void => { + onMouseLeave && onMouseLeave(); + }, [onMouseLeave]); + + const listenKeyboard = useCallback((event: KeyboardEvent): void => { + if (!isBusy && !isDisabled && event.key === 'Enter') { + onClick && onClick(); + } + }, [isBusy, isDisabled, onClick]); + + useEffect(() => { + if (activeOnEnter) { + window.addEventListener('keydown', listenKeyboard, true); + } + + return () => { + if (activeOnEnter) { + window.removeEventListener('keydown', listenKeyboard, true); + } + }; + }, [activeOnEnter, listenKeyboard]); + + return ( + + {icon && } + {label} + {children} + {isBusy && ( + + )} + + ); +} + +const ICON_PADDING = 0.5; + +const StyledButton = styled.button` + background: transparent; + border: none; + color: inherit; + cursor: pointer; + line-height: 1; + margin: 0; + outline: none; + position: relative; + vertical-align: middle; + text-align: center; + + &:not(.hasLabel) { + padding: 0.7em; + + .ui--Icon { + padding: 0.6rem; + margin: -0.6rem; + } + } + + &:not(.isCircular) { + border-radius: 0.25rem; + } + + &:focus { + outline:0; + } + + &.hasLabel { + padding: 0.7rem 1.1rem 0.7rem ${1.1 - ICON_PADDING}rem; + + .ui--Icon { + margin-right: 0.425rem !important; + } + } + + &.isBasic { + background: var(--bg-table); + } + + &.isCircular { + border-radius: 10rem; + } + + &.isDisabled, &.isReadOnly { + background: none; + box-shadow: none; + cursor: not-allowed; + } + + &.isBusy { + cursor: wait; + } + + &.isFull { + display: block; + width: 100%; + } + + &.isIcon { + background: transparent; + } + + .ui--Button-overlay { + background: rgba(253, 252, 251, 0.75); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + visibility: hidden; + } + + .ui--Icon { + border-radius: 50%; + box-sizing: content-box; + height: 1rem; + margin: -${ICON_PADDING}rem 0; + padding: ${ICON_PADDING}rem; + width: 1rem; + } + + &.isDisabled { + color: #bcbbba; + } +`; + +const Button = React.memo(ButtonBase) as unknown as typeof ButtonBase & { + Group: typeof Group +}; Button.Group = Group; diff --git a/packages/react-components/src/Button/types.ts b/packages/react-components/src/Button/types.ts index c0c7a04887..a02f075a15 100644 --- a/packages/react-components/src/Button/types.ts +++ b/packages/react-components/src/Button/types.ts @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 import type { IconName } from '@fortawesome/fontawesome-svg-core'; -import type { BareProps } from '../types'; export type Button$Callback = () => void | Promise; @@ -29,15 +28,3 @@ export interface ButtonProps { tooltip?: React.ReactNode; withoutLink?: boolean; } - -export type DividerProps = BareProps; - -export interface GroupProps { - children?: React.ReactNode; - className?: string; - isCentered?: boolean; -} - -export type ButtonType = React.ComponentType & { - Group: React.ComponentType; -}; diff --git a/packages/react-components/src/Chart/Base.tsx b/packages/react-components/src/Chart/Base.tsx index dcfa79e2c3..776e28da1f 100644 --- a/packages/react-components/src/Chart/Base.tsx +++ b/packages/react-components/src/Chart/Base.tsx @@ -1,12 +1,15 @@ // Copyright 2017-2023 @polkadot/react-components authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { BaseProps } from './types'; - import React from 'react'; import styled from 'styled-components'; -function BaseChart ({ children, className = '' }: BaseProps): React.ReactElement { +interface Props { + children: React.ReactNode; + className?: string; +} + +function BaseChart ({ children, className = '' }: Props): React.ReactElement { return ( {children} diff --git a/packages/react-components/src/Chart/Doughnut.tsx b/packages/react-components/src/Chart/Doughnut.tsx index c297947c04..de6ebc1ef8 100644 --- a/packages/react-components/src/Chart/Doughnut.tsx +++ b/packages/react-components/src/Chart/Doughnut.tsx @@ -1,7 +1,7 @@ // Copyright 2017-2023 @polkadot/react-components authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { DoughnutProps } from './types'; +import type { BN } from '@polkadot/util'; import React from 'react'; import { Doughnut } from 'react-chartjs-2'; @@ -10,6 +10,18 @@ import { bnToBn } from '@polkadot/util'; import Base from './Base'; +interface DoughnutValue { + colors: string[]; + label: string; + value: number | BN; +} + +export interface Props { + className?: string; + size?: number; + values: DoughnutValue[]; +} + interface Options { colorNormal: string[]; colorHover: string[]; @@ -17,7 +29,7 @@ interface Options { labels: string[]; } -function ChartDoughnut ({ className = '', size = 100, values }: DoughnutProps): React.ReactElement { +function ChartDoughnut ({ className = '', size = 100, values }: Props): React.ReactElement { const options: Options = { colorHover: [], colorNormal: [], @@ -33,7 +45,7 @@ function ChartDoughnut ({ className = '', size = 100, values }: DoughnutProps): }); return ( - + { const dataset = data.datasets[0]; @@ -70,7 +86,7 @@ function calculateOptions (aspectRatio: number, values: HorizBarValue[], jsonVal }; } -function ChartHorizBar ({ aspectRatio = 8, className = '', max = 100, showLabels = false, values }: HorizBarProps): React.ReactElement | null { +function ChartHorizBar ({ aspectRatio = 8, className = '', max = 100, showLabels = false, values }: Props): React.ReactElement | null { const [{ chartData, chartOptions, jsonValues }, setState] = useState({}); useEffect((): void => { @@ -87,7 +103,7 @@ function ChartHorizBar ({ aspectRatio = 8, className = '', max = 100, showLabels // HACK on width/height to get the aspectRatio to work return ( -
+
| null { +function LineChart ({ className = '', colors, labels, legends, options, values }: Props): React.ReactElement | null { const chartOptions = useMemo( () => getOptions(options), [options] @@ -125,7 +133,7 @@ function LineChart ({ className, colors, labels, legends, options, values }: Lin ); return ( -
+
); } -function Columar ({ children, className = '', is60, is100, isPadded = true, isReverse, size = 'default' }: Props): React.ReactElement { +function ColumarBase ({ children, className = '', is60, is100, isPadded = true, isReverse, size = 'default' }: Props): React.ReactElement { return ( {children} @@ -133,6 +133,10 @@ const StyledDiv = styled.div` } `; +const Columar = React.memo(ColumarBase) as unknown as typeof ColumarBase & { + Column: typeof Column +}; + Columar.Column = Column; export default Columar; diff --git a/packages/react-components/src/Dropdown.tsx b/packages/react-components/src/Dropdown.tsx index 688652abfc..5a81f8d99d 100644 --- a/packages/react-components/src/Dropdown.tsx +++ b/packages/react-components/src/Dropdown.tsx @@ -44,7 +44,7 @@ export type IDropdown