From 6fa97f2de9918d50052187bccc596854c4bb873f Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Mon, 9 Sep 2024 17:33:06 +0200 Subject: [PATCH 1/4] fix(elements): fix prefixed props passing & logic in Button & IconButton --- src/elements/{Button.tsx => Button/index.tsx} | 82 +++++-------------- src/elements/Button/utils.ts | 59 +++++++++++++ src/elements/IconButton.tsx | 57 +++++++------ 3 files changed, 110 insertions(+), 88 deletions(-) rename src/elements/{Button.tsx => Button/index.tsx} (72%) create mode 100644 src/elements/Button/utils.ts diff --git a/src/elements/Button.tsx b/src/elements/Button/index.tsx similarity index 72% rename from src/elements/Button.tsx rename to src/elements/Button/index.tsx index 97a31d59c..d7bcfc6c8 100644 --- a/src/elements/Button.tsx +++ b/src/elements/Button/index.tsx @@ -2,9 +2,10 @@ import classnames from 'classnames' import { useCallback, useMemo, type MouseEvent, type ButtonHTMLAttributes, type FunctionComponent } from 'react' import styled from 'styled-components' -import { Accent, Size } from '../constants' -import { type IconProps } from '../types/definitions' -import { stopMouseEventPropagation } from '../utils/stopMouseEventPropagation' +import { interpolatePrimaryButtonThemedCss, interpolateSecondaryButtonThemedCss } from './utils' +import { Accent, Size } from '../../constants' +import { type IconProps } from '../../types/definitions' +import { stopMouseEventPropagation } from '../../utils/stopMouseEventPropagation' const ICON_SIZE: Record = { [Size.LARGE]: 20, @@ -56,14 +57,13 @@ export function Button({ [children, Icon, size] ) - const commonProps = useMemo( + const commonProps: BaseButtonProps = useMemo( () => ({ - as: StyledButton, + $isFullWidth: isFullWidth, + $size: size, children: commonChildren, className: classnames('Element-Button', className), - isFullWidth, onClick: handleClick, - size, type, ...nativeProps }), @@ -96,7 +96,12 @@ const PADDING: Record = { [Size.NORMAL]: '6px 12px', [Size.SMALL]: '5px 8px 4px' } -const StyledButton = styled.button<{ + +type BaseButtonProps = ButtonHTMLAttributes & { + $isFullWidth: boolean + $size: Size +} +const BaseButton = styled.button<{ $isFullWidth: boolean $size: Size }>` @@ -122,61 +127,11 @@ const ButtonLabel = styled.span` white-space: nowrap; ` -export const PrimaryButton = styled.button` - background-color: ${p => p.theme.color.charcoal}; - border: 1px solid ${p => p.theme.color.charcoal}; - color: ${p => p.theme.color.gainsboro}; - - &:hover, - &._hover { - background-color: ${p => p.theme.color.blueYonder}; - border: 1px solid ${p => p.theme.color.blueYonder}; - color: ${p => p.theme.color.white}; - } +const PrimaryButton = styled(BaseButton)(interpolatePrimaryButtonThemedCss) - &:active, - &._active { - background-color: ${p => p.theme.color.blueGray}; - border: 1px solid ${p => p.theme.color.blueGray}; - color: ${p => p.theme.color.white}; - } - - &:disabled, - &._disabled { - background-color: ${p => p.theme.color.lightGray}; - border: 1px solid ${p => p.theme.color.lightGray}; - color: ${p => p.theme.color.cultured}; - } -` - -export const SecondaryButton = styled.button` - background-color: transparent; - border: 1px solid ${p => p.theme.color.charcoal}; - color: ${p => p.theme.color.charcoal}; +const SecondaryButton = styled(BaseButton)(interpolateSecondaryButtonThemedCss) - &:hover, - &._hover { - background-color: ${p => p.theme.color.blueYonder25}; - border: 1px solid ${p => p.theme.color.blueYonder}; - color: ${p => p.theme.color.blueYonder}; - } - - &:active, - &._active { - background-color: ${p => p.theme.color.blueGray25}; - border: 1px solid ${p => p.theme.color.blueGray}; - color: ${p => p.theme.color.blueGray}; - } - - &:disabled, - &._disabled { - background-color: transparent; - border: 1px solid ${p => p.theme.color.lightGray}; - color: ${p => p.theme.color.lightGray}; - } -` - -export const TertiaryButton = styled.button` +const TertiaryButton = styled(BaseButton)` background-color: ${p => p.theme.color.white}; border: 1px solid ${p => p.theme.color.white}; color: ${p => p.theme.color.charcoal}; @@ -202,7 +157,8 @@ export const TertiaryButton = styled.button` color: ${p => p.theme.color.lightGray}; } ` -export const WarningButton = styled.button` + +const WarningButton = styled(BaseButton)` background-color: transparent; border: 1px solid ${p => p.theme.color.goldenPoppy}; color: ${p => p.theme.color.charcoal}; @@ -229,7 +185,7 @@ export const WarningButton = styled.button` color: ${p => p.theme.color.lightGray}; } ` -export const ErrorButton = styled.button` +const ErrorButton = styled(BaseButton)` background-color: transparent; border: 1px solid ${p => p.theme.color.maximumRed}; color: ${p => p.theme.color.charcoal}; diff --git a/src/elements/Button/utils.ts b/src/elements/Button/utils.ts new file mode 100644 index 000000000..7277340ac --- /dev/null +++ b/src/elements/Button/utils.ts @@ -0,0 +1,59 @@ +import { css } from 'styled-components' + +export function interpolatePrimaryButtonThemedCss() { + return css` + background-color: ${p => p.theme.color.charcoal}; + border: 1px solid ${p => p.theme.color.charcoal}; + color: ${p => p.theme.color.gainsboro}; + + &:hover, + &._hover { + background-color: ${p => p.theme.color.blueYonder}; + border: 1px solid ${p => p.theme.color.blueYonder}; + color: ${p => p.theme.color.white}; + } + + &:active, + &._active { + background-color: ${p => p.theme.color.blueGray}; + border: 1px solid ${p => p.theme.color.blueGray}; + color: ${p => p.theme.color.white}; + } + + &:disabled, + &._disabled { + background-color: ${p => p.theme.color.lightGray}; + border: 1px solid ${p => p.theme.color.lightGray}; + color: ${p => p.theme.color.cultured}; + } + ` +} + +export function interpolateSecondaryButtonThemedCss() { + return css` + background-color: transparent; + border: 1px solid ${p => p.theme.color.charcoal}; + color: ${p => p.theme.color.charcoal}; + + &:hover, + &._hover { + background-color: ${p => p.theme.color.blueYonder25}; + border: 1px solid ${p => p.theme.color.blueYonder}; + color: ${p => p.theme.color.blueYonder}; + } + + &:active, + &._active { + background-color: ${p => p.theme.color.blueGray25}; + border: 1px solid ${p => p.theme.color.blueGray}; + color: ${p => p.theme.color.blueGray}; + } + + &:disabled, + &._disabled { + background-color: transparent; + border: 1px solid ${p => p.theme.color.lightGray}; + color: ${p => p.theme.color.lightGray}; + } + ` +} diff --git a/src/elements/IconButton.tsx b/src/elements/IconButton.tsx index c96945ef2..64d78a4ae 100644 --- a/src/elements/IconButton.tsx +++ b/src/elements/IconButton.tsx @@ -2,7 +2,7 @@ import classnames from 'classnames' import { useMemo, type MouseEvent, type ButtonHTMLAttributes, type FunctionComponent, useCallback } from 'react' import styled from 'styled-components' -import { PrimaryButton, SecondaryButton } from './Button' +import { interpolatePrimaryButtonThemedCss, interpolateSecondaryButtonThemedCss } from './Button/utils' import { Accent, Size } from '../constants' import { type IconProps } from '../types/definitions' import { stopMouseEventPropagation } from '../utils/stopMouseEventPropagation' @@ -64,14 +64,14 @@ export function IconButton({ [color, Icon, iconSize, size] ) - const buttonProps = useMemo( + const buttonProps: BaseButtonProps = useMemo( () => ({ + $isCompact: isCompact, + $size: size, children: commonChildren, className: badgeNumber === undefined ? classnames('Element-IconButton', className) : classnames('Element-IconButton'), - isCompact, onClick: handleClick, - size, style: badgeNumber === undefined ? style : undefined, type, ...nativeProps @@ -84,13 +84,13 @@ export function IconButton({ return ( <> {badgeNumber === undefined ? ( - + ) : ( - + {badgeNumber} - + )} @@ -100,13 +100,13 @@ export function IconButton({ return ( <> {badgeNumber === undefined ? ( - + ) : ( - + {badgeNumber} - + )} @@ -116,13 +116,13 @@ export function IconButton({ return ( <> {badgeNumber === undefined ? ( - + ) : ( - + {badgeNumber} - + )} @@ -147,9 +147,9 @@ const LEFT_MARGIN: Record = { } const BadgeNumber = styled.div<{ - backgroundColor: string | undefined - color: string | undefined - size: Size + $backgroundColor: string | undefined + $color: string | undefined + $size: Size }>` display: inline-block; position: absolute; @@ -159,27 +159,34 @@ const BadgeNumber = styled.div<{ border-radius: 10px; top: -5px; line-height: 14px; - left: ${p => (p.size ? LEFT_MARGIN[p.size] : 25)}px; - background: ${p => (p.backgroundColor ? p.backgroundColor : p.theme.color.maximumRed)}; - color: ${p => (p.color ? p.color : p.theme.color.white)}; + left: ${p => (p.$size ? LEFT_MARGIN[p.$size] : 25)}px; + background: ${p => (p.$backgroundColor ? p.$backgroundColor : p.theme.color.maximumRed)}; + color: ${p => (p.$color ? p.$color : p.theme.color.white)}; font-size: 12px; letter-spacing: 0px; font-weight: 700; ` -// We can't use $-prefixed props here for some reason (maybe because the `as` prop exclude them?). -const StyledButton = styled.button<{ - isCompact: boolean | undefined - size: Size +type BaseButtonProps = ButtonHTMLAttributes & { + $isCompact: boolean | undefined + $size: Size +} +const BaseButton = styled.button<{ + $isCompact: boolean | undefined + $size: Size }>` align-items: center; border-style: solid; - border-width: ${p => (p.isCompact ? 0 : 1)}px; + border-width: ${p => (p.$isCompact ? 0 : 1)}px; display: flex; justify-content: center; - padding: ${p => (p.isCompact ? 0 : PADDING[p.size])}; + padding: ${p => (p.$isCompact ? 0 : PADDING[p.$size])}; ` +const PrimaryButton = styled(BaseButton)(interpolatePrimaryButtonThemedCss) + +const SecondaryButton = styled(BaseButton)(interpolateSecondaryButtonThemedCss) + const TertiaryButton = styled.button` background-color: transparent; border-color: transparent; From 03e94e4bbe96dbaae9c0c0e1f49a518728020ee3 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Mon, 9 Sep 2024 17:50:27 +0200 Subject: [PATCH 2/4] fix(elements): remove left 'as' prop in IconButton --- src/elements/IconButton.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/elements/IconButton.tsx b/src/elements/IconButton.tsx index 64d78a4ae..69f4c379a 100644 --- a/src/elements/IconButton.tsx +++ b/src/elements/IconButton.tsx @@ -116,13 +116,13 @@ export function IconButton({ return ( <> {badgeNumber === undefined ? ( - + ) : ( {badgeNumber} - + )} From e9ccb896aa9a491de1c2470226f6dd4722aad324 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Mon, 9 Sep 2024 18:00:13 +0200 Subject: [PATCH 3/4] refactor(elements): rename primary & secondary CSS getters in Button --- src/elements/Button/index.tsx | 6 +++--- src/elements/Button/utils.ts | 4 ++-- src/elements/IconButton.tsx | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/elements/Button/index.tsx b/src/elements/Button/index.tsx index d7bcfc6c8..dd902942e 100644 --- a/src/elements/Button/index.tsx +++ b/src/elements/Button/index.tsx @@ -2,7 +2,7 @@ import classnames from 'classnames' import { useCallback, useMemo, type MouseEvent, type ButtonHTMLAttributes, type FunctionComponent } from 'react' import styled from 'styled-components' -import { interpolatePrimaryButtonThemedCss, interpolateSecondaryButtonThemedCss } from './utils' +import { getPrimaryButtonCss, getSecondaryButtonCss } from './utils' import { Accent, Size } from '../../constants' import { type IconProps } from '../../types/definitions' import { stopMouseEventPropagation } from '../../utils/stopMouseEventPropagation' @@ -127,9 +127,9 @@ const ButtonLabel = styled.span` white-space: nowrap; ` -const PrimaryButton = styled(BaseButton)(interpolatePrimaryButtonThemedCss) +const PrimaryButton = styled(BaseButton)(getPrimaryButtonCss) -const SecondaryButton = styled(BaseButton)(interpolateSecondaryButtonThemedCss) +const SecondaryButton = styled(BaseButton)(getSecondaryButtonCss) const TertiaryButton = styled(BaseButton)` background-color: ${p => p.theme.color.white}; diff --git a/src/elements/Button/utils.ts b/src/elements/Button/utils.ts index 7277340ac..ccdf00874 100644 --- a/src/elements/Button/utils.ts +++ b/src/elements/Button/utils.ts @@ -1,6 +1,6 @@ import { css } from 'styled-components' -export function interpolatePrimaryButtonThemedCss() { +export function getPrimaryButtonCss() { return css` background-color: ${p => p.theme.color.charcoal}; border: 1px solid ${p => p.theme.color.charcoal}; @@ -29,7 +29,7 @@ export function interpolatePrimaryButtonThemedCss() { ` } -export function interpolateSecondaryButtonThemedCss() { +export function getSecondaryButtonCss() { return css` background-color: transparent; border: 1px solid ${p => p.theme.color.charcoal}; diff --git a/src/elements/IconButton.tsx b/src/elements/IconButton.tsx index 69f4c379a..9b2a5c43b 100644 --- a/src/elements/IconButton.tsx +++ b/src/elements/IconButton.tsx @@ -2,7 +2,7 @@ import classnames from 'classnames' import { useMemo, type MouseEvent, type ButtonHTMLAttributes, type FunctionComponent, useCallback } from 'react' import styled from 'styled-components' -import { interpolatePrimaryButtonThemedCss, interpolateSecondaryButtonThemedCss } from './Button/utils' +import { getPrimaryButtonCss, getSecondaryButtonCss } from './Button/utils' import { Accent, Size } from '../constants' import { type IconProps } from '../types/definitions' import { stopMouseEventPropagation } from '../utils/stopMouseEventPropagation' @@ -183,9 +183,9 @@ const BaseButton = styled.button<{ padding: ${p => (p.$isCompact ? 0 : PADDING[p.$size])}; ` -const PrimaryButton = styled(BaseButton)(interpolatePrimaryButtonThemedCss) +const PrimaryButton = styled(BaseButton)(getPrimaryButtonCss) -const SecondaryButton = styled(BaseButton)(interpolateSecondaryButtonThemedCss) +const SecondaryButton = styled(BaseButton)(getSecondaryButtonCss) const TertiaryButton = styled.button` background-color: transparent; From fceb4f00f1a53710b088afdfea1c96bc2dcd5a08 Mon Sep 17 00:00:00 2001 From: Ivan Gabriele Date: Mon, 9 Sep 2024 18:05:30 +0200 Subject: [PATCH 4/4] refactor(elements): rename utils to styles in Button --- src/elements/Button/index.tsx | 2 +- src/elements/Button/{utils.ts => styles.ts} | 0 src/elements/IconButton.tsx | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/elements/Button/{utils.ts => styles.ts} (100%) diff --git a/src/elements/Button/index.tsx b/src/elements/Button/index.tsx index dd902942e..812610b7d 100644 --- a/src/elements/Button/index.tsx +++ b/src/elements/Button/index.tsx @@ -2,7 +2,7 @@ import classnames from 'classnames' import { useCallback, useMemo, type MouseEvent, type ButtonHTMLAttributes, type FunctionComponent } from 'react' import styled from 'styled-components' -import { getPrimaryButtonCss, getSecondaryButtonCss } from './utils' +import { getPrimaryButtonCss, getSecondaryButtonCss } from './styles' import { Accent, Size } from '../../constants' import { type IconProps } from '../../types/definitions' import { stopMouseEventPropagation } from '../../utils/stopMouseEventPropagation' diff --git a/src/elements/Button/utils.ts b/src/elements/Button/styles.ts similarity index 100% rename from src/elements/Button/utils.ts rename to src/elements/Button/styles.ts diff --git a/src/elements/IconButton.tsx b/src/elements/IconButton.tsx index 9b2a5c43b..480d76178 100644 --- a/src/elements/IconButton.tsx +++ b/src/elements/IconButton.tsx @@ -2,7 +2,7 @@ import classnames from 'classnames' import { useMemo, type MouseEvent, type ButtonHTMLAttributes, type FunctionComponent, useCallback } from 'react' import styled from 'styled-components' -import { getPrimaryButtonCss, getSecondaryButtonCss } from './Button/utils' +import { getPrimaryButtonCss, getSecondaryButtonCss } from './Button/styles' import { Accent, Size } from '../constants' import { type IconProps } from '../types/definitions' import { stopMouseEventPropagation } from '../utils/stopMouseEventPropagation'