diff --git a/docs/src/components/BrandedTile.tsx b/docs/src/components/BrandedTile.tsx index 55020dfcd6..0ac2a0bf41 100644 --- a/docs/src/components/BrandedTile.tsx +++ b/docs/src/components/BrandedTile.tsx @@ -1,6 +1,5 @@ import React from "react"; import { Heading, Stack, Button, mediaQueries as mq } from "@kiwicom/orbit-components"; -import { StyledButtonPrimitive } from "@kiwicom/orbit-components/lib/primitives/ButtonPrimitive"; import useTheme from "@kiwicom/orbit-components/lib/hooks/useTheme"; import styled, { css } from "styled-components"; @@ -40,18 +39,18 @@ const StyledWrapper = styled.a<{ primary: string; type?: "primary" | "secondary" ${boxShadowActive}; } - ${StyledButtonPrimitive} { + .orbit-button-primitive { pointer-events: none; background: ${getBgColor({ theme, type, color })}; } - &:hover ${StyledButtonPrimitive} { + &:hover .orbit-button-primitive { background: ${getBgColorHover({ theme, type, color })} } - &:focus ${StyledButtonPrimitive} { + &:focus .orbit-button-primitive { background: ${getBgColor({ theme, type, color })} } - &:active ${StyledButtonPrimitive} { + &:active .orbit-button-primitive { background: ${getBgColorActive({ theme, type, color })} } `}; diff --git a/packages/orbit-components/src/Button/Button.stories.tsx b/packages/orbit-components/src/Button/Button.stories.tsx index 007118720c..2263f32984 100644 --- a/packages/orbit-components/src/Button/Button.stories.tsx +++ b/packages/orbit-components/src/Button/Button.stories.tsx @@ -11,9 +11,9 @@ import SPACINGS_AFTER from "../common/getSpacingToken/consts"; import Button from "."; const getIcons = (name: string, defaultIcon: string) => - select(name, Object.keys(Icons), defaultIcon); + select(name, ["none", ...Object.keys(Icons)], defaultIcon); -const getIcon = (source: string | null) => (source ? Icons[source] : null); +const getIcon = (source: string) => (source in Icons ? Icons[source] : null); export default { title: "Button", diff --git a/packages/orbit-components/src/Button/consts.ts b/packages/orbit-components/src/Button/consts.ts index e75ed5983e..ebe6bac42d 100644 --- a/packages/orbit-components/src/Button/consts.ts +++ b/packages/orbit-components/src/Button/consts.ts @@ -15,24 +15,3 @@ export enum SIZE_OPTIONS { NORMAL = "normal", LARGE = "large", } - -export enum TOKENS { - // Size tokens - heightButton = "heightButton", - loadingWidth = "loadingWidth", - loadingHeight = "loadingHeight", - fontSizeButton = "fontSizeButton", - paddingButton = "paddingButton", - paddingButtonWithIcons = "paddingButtonWithIcons", - paddingButtonWithLeftIcon = "paddingButtonWithLeftIcon", - paddingButtonWithRightIcon = "paddingButtonWithRightIcon", - // Type tokens - backgroundButton = "backgroundButton", - backgroundButtonHover = "backgroundButtonHover", - backgroundButtonActive = "backgroundButtonActive", - backgroundButtonFocus = "backgroundButtonFocus", - colorTextButton = "colorTextButton", - colorTextButtonHover = "colorTextButtonHover", - colorTextButtonActive = "colorTextButtonActive", - borderColorButtonFocus = "borderColorButtonFocus", -} diff --git a/packages/orbit-components/src/Button/helpers/getButtonBoxShadow.ts b/packages/orbit-components/src/Button/helpers/getButtonBoxShadow.ts deleted file mode 100644 index a6c22d0b5f..0000000000 --- a/packages/orbit-components/src/Button/helpers/getButtonBoxShadow.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { convertHexToRgba } from "@kiwicom/orbit-design-tokens"; -import type { Interpolation } from "styled-components"; - -import { TOKENS, TYPE_OPTIONS } from "../consts"; -import { BUTTON_STATES } from "../../primitives/ButtonPrimitive/common/consts"; -import getButtonTypeToken from "./getButtonTypeToken"; -import type { Type, ButtonStates } from "../types"; -import type { Theme } from "../../defaultTheme"; - -const opacity = { - [TYPE_OPTIONS.PRIMARY]: 15, - [TYPE_OPTIONS.SECONDARY]: 8, - [TYPE_OPTIONS.CRITICAL]: 15, - [TYPE_OPTIONS.WHITE]: 8, - [TYPE_OPTIONS.PRIMARY_SUBTLE]: 8, - [TYPE_OPTIONS.CRITICAL_SUBTLE]: 8, - [TYPE_OPTIONS.BUNDLE_BASIC]: 15, - [TYPE_OPTIONS.BUNDLE_MEDIUM]: 15, - [TYPE_OPTIONS.BUNDLE_TOP]: 15, -}; - -interface BoxShadowProps { - state: ButtonStates; - disabled: boolean; - theme: Theme; - type: Type; -} - -const getButtonBoxShadow = ({ - state, - disabled, - theme, - type, -}: BoxShadowProps): Interpolation | null => { - const wrappedButtonTypeToken = (name: string) => getButtonTypeToken({ name, type, theme }); - if (disabled) return null; - - if (state === BUTTON_STATES.ACTIVE) { - return `inset 0 0 6px 3px ${convertHexToRgba(theme.orbit.paletteInkDark, opacity[type])};`; - } - - if (state === BUTTON_STATES.FOCUS) { - return `0 0 0 3px ${wrappedButtonTypeToken(TOKENS.borderColorButtonFocus)}`; - } - - return null; -}; - -export default getButtonBoxShadow; diff --git a/packages/orbit-components/src/Button/helpers/getButtonIconForeground.ts b/packages/orbit-components/src/Button/helpers/getButtonIconForeground.ts deleted file mode 100644 index 912ee33825..0000000000 --- a/packages/orbit-components/src/Button/helpers/getButtonIconForeground.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TOKENS } from "../consts"; -import getButtonTypeToken from "./getButtonTypeToken"; -import type { Theme } from "../../defaultTheme"; -import type { Type } from "../types"; - -const getButtonIconForeground = ({ - theme, - type, -}: { - theme: Theme; - type: Type; -}): { - foreground: string; - foregroundHover: string; - foregroundActive: string; - foregroundFocus: string; -} => { - const wrappedTypeToken = (name: string) => getButtonTypeToken({ name, type, theme }); - return { - foreground: wrappedTypeToken(TOKENS.colorTextButton), - foregroundHover: wrappedTypeToken(TOKENS.colorTextButtonHover), - foregroundActive: wrappedTypeToken(TOKENS.colorTextButtonActive), - foregroundFocus: wrappedTypeToken(TOKENS.colorTextButtonActive), - }; -}; - -export default getButtonIconForeground; diff --git a/packages/orbit-components/src/Button/helpers/getButtonStyles.ts b/packages/orbit-components/src/Button/helpers/getButtonStyles.ts deleted file mode 100644 index b470dbae48..0000000000 --- a/packages/orbit-components/src/Button/helpers/getButtonStyles.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { BUTTON_STATES } from "../../primitives/ButtonPrimitive/common/consts"; -import getButtonTypeToken from "./getButtonTypeToken"; -import { TOKENS } from "../consts"; -import getButtonBoxShadow from "./getButtonBoxShadow"; -import type { Theme } from "../../defaultTheme"; -import type { Type, ButtonStates } from "../types"; - -const getButtonStyles = ({ - disabled, - theme, - type, -}: { - disabled: boolean; - theme: Theme; - type: Type; -}): { - background: string; - backgroundHover: string; - backgroundActive: string; - backgroundFocus: string | null; - foreground: string; - foregroundHover: string; - foregroundActive: string; -} => { - const wrappedBoxShadow = (state: ButtonStates) => - getButtonBoxShadow({ state, disabled, theme, type }); - const wrappedTypeToken = (name: string) => getButtonTypeToken({ name, type, theme }); - const boxShadow = { - boxShadow: wrappedBoxShadow(BUTTON_STATES.DEFAULT), - boxShadowHover: wrappedBoxShadow(BUTTON_STATES.HOVER), - boxShadowActive: wrappedBoxShadow(BUTTON_STATES.ACTIVE), - }; - return { - background: wrappedTypeToken(TOKENS.backgroundButton), - backgroundHover: wrappedTypeToken(TOKENS.backgroundButtonHover), - backgroundActive: wrappedTypeToken(TOKENS.backgroundButtonActive), - backgroundFocus: null, - foreground: wrappedTypeToken(TOKENS.colorTextButton), - foregroundHover: wrappedTypeToken(TOKENS.colorTextButtonHover), - foregroundActive: wrappedTypeToken(TOKENS.colorTextButtonActive), - ...boxShadow, - }; -}; - -export default getButtonStyles; diff --git a/packages/orbit-components/src/Button/helpers/getButtonTypeToken.ts b/packages/orbit-components/src/Button/helpers/getButtonTypeToken.ts deleted file mode 100644 index 3daea49868..0000000000 --- a/packages/orbit-components/src/Button/helpers/getButtonTypeToken.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { convertHexToRgba } from "@kiwicom/orbit-design-tokens"; - -import type { Theme } from "../../defaultTheme"; -import type { Type } from "../types"; -import { TOKENS, TYPE_OPTIONS } from "../consts"; - -const getButtonTypeToken = ({ - name, - type, - theme, -}: { - name: string; - type: Type; - theme: Theme; -}): string => { - const tokens = { - [TOKENS.backgroundButton]: { - [TYPE_OPTIONS.PRIMARY]: theme.orbit.buttonPrimaryBackground, - [TYPE_OPTIONS.SECONDARY]: theme.orbit.buttonSecondaryBackground, - [TYPE_OPTIONS.CRITICAL]: theme.orbit.buttonCriticalBackground, - [TYPE_OPTIONS.WHITE]: theme.orbit.buttonWhiteBackground, - [TYPE_OPTIONS.PRIMARY_SUBTLE]: theme.orbit.buttonPrimarySubtleBackground, - [TYPE_OPTIONS.CRITICAL_SUBTLE]: theme.orbit.buttonCriticalSubtleBackground, - [TYPE_OPTIONS.BUNDLE_BASIC]: theme.orbit.buttonBundleBasicBackground, - [TYPE_OPTIONS.BUNDLE_MEDIUM]: theme.orbit.buttonBundleMediumBackground, - [TYPE_OPTIONS.BUNDLE_TOP]: theme.orbit.buttonBundleTopBackground, - }, - [TOKENS.backgroundButtonHover]: { - [TYPE_OPTIONS.PRIMARY]: theme.orbit.buttonPrimaryBackgroundHover, - [TYPE_OPTIONS.SECONDARY]: theme.orbit.buttonSecondaryBackgroundHover, - [TYPE_OPTIONS.CRITICAL]: theme.orbit.buttonCriticalBackgroundHover, - [TYPE_OPTIONS.WHITE]: theme.orbit.backgroundButtonWhiteHover, - [TYPE_OPTIONS.PRIMARY_SUBTLE]: theme.orbit.buttonPrimarySubtleBackgroundHover, - [TYPE_OPTIONS.CRITICAL_SUBTLE]: theme.orbit.buttonCriticalSubtleBackgroundHover, - [TYPE_OPTIONS.BUNDLE_BASIC]: theme.orbit.buttonBundleBasicBackgroundHover, - [TYPE_OPTIONS.BUNDLE_MEDIUM]: theme.orbit.buttonBundleMediumBackgroundHover, - [TYPE_OPTIONS.BUNDLE_TOP]: theme.orbit.buttonBundleTopBackgroundHover, - }, - [TOKENS.backgroundButtonActive]: { - [TYPE_OPTIONS.PRIMARY]: theme.orbit.buttonPrimaryBackgroundActive, - [TYPE_OPTIONS.SECONDARY]: theme.orbit.buttonSecondaryBackgroundActive, - [TYPE_OPTIONS.CRITICAL]: theme.orbit.buttonCriticalBackgroundActive, - [TYPE_OPTIONS.WHITE]: theme.orbit.backgroundButtonWhiteActive, - [TYPE_OPTIONS.PRIMARY_SUBTLE]: theme.orbit.buttonPrimarySubtleBackgroundActive, - [TYPE_OPTIONS.CRITICAL_SUBTLE]: theme.orbit.buttonCriticalSubtleBackgroundActive, - [TYPE_OPTIONS.BUNDLE_BASIC]: theme.orbit.buttonBundleBasicBackgroundActive, - [TYPE_OPTIONS.BUNDLE_MEDIUM]: theme.orbit.buttonBundleMediumBackgroundActive, - [TYPE_OPTIONS.BUNDLE_TOP]: theme.orbit.buttonBundleTopBackgroundActive, - }, - [TOKENS.backgroundButtonFocus]: { - [TYPE_OPTIONS.PRIMARY]: convertHexToRgba(theme.orbit.paletteProductNormal, 10), - [TYPE_OPTIONS.SECONDARY]: convertHexToRgba(theme.orbit.paletteInkNormal, 10), - [TYPE_OPTIONS.CRITICAL]: convertHexToRgba(theme.orbit.paletteRedNormal, 10), - [TYPE_OPTIONS.WHITE]: convertHexToRgba(theme.orbit.paletteWhite, 20), - [TYPE_OPTIONS.PRIMARY_SUBTLE]: theme.orbit.buttonPrimarySubtleBackground, - [TYPE_OPTIONS.CRITICAL_SUBTLE]: theme.orbit.buttonCriticalSubtleBackground, - [TYPE_OPTIONS.BUNDLE_BASIC]: theme.orbit.buttonBundleBasicBackground, - [TYPE_OPTIONS.BUNDLE_MEDIUM]: theme.orbit.buttonBundleMediumBackground, - [TYPE_OPTIONS.BUNDLE_TOP]: theme.orbit.buttonBundleTopBackground, - }, - [TOKENS.colorTextButton]: { - [TYPE_OPTIONS.PRIMARY]: theme.orbit.buttonPrimaryForeground, - [TYPE_OPTIONS.SECONDARY]: theme.orbit.buttonSecondaryForeground, - [TYPE_OPTIONS.CRITICAL]: theme.orbit.buttonCriticalForeground, - [TYPE_OPTIONS.WHITE]: theme.orbit.buttonWhiteForeground, - [TYPE_OPTIONS.PRIMARY_SUBTLE]: theme.orbit.buttonPrimarySubtleForeground, - [TYPE_OPTIONS.CRITICAL_SUBTLE]: theme.orbit.buttonCriticalSubtleForeground, - [TYPE_OPTIONS.BUNDLE_BASIC]: theme.orbit.paletteWhite, - [TYPE_OPTIONS.BUNDLE_MEDIUM]: theme.orbit.paletteWhite, - [TYPE_OPTIONS.BUNDLE_TOP]: theme.orbit.paletteWhite, - }, - [TOKENS.colorTextButtonHover]: { - [TYPE_OPTIONS.PRIMARY]: theme.orbit.buttonPrimaryForegroundHover, - [TYPE_OPTIONS.SECONDARY]: theme.orbit.buttonSecondaryForegroundHover, - [TYPE_OPTIONS.CRITICAL]: theme.orbit.buttonCriticalForegroundHover, - [TYPE_OPTIONS.WHITE]: theme.orbit.buttonWhiteForegroundHover, - [TYPE_OPTIONS.PRIMARY_SUBTLE]: theme.orbit.buttonPrimarySubtleForegroundHover, - [TYPE_OPTIONS.CRITICAL_SUBTLE]: theme.orbit.buttonCriticalSubtleForegroundHover, - [TYPE_OPTIONS.BUNDLE_BASIC]: theme.orbit.paletteWhite, - [TYPE_OPTIONS.BUNDLE_MEDIUM]: theme.orbit.paletteWhite, - [TYPE_OPTIONS.BUNDLE_TOP]: theme.orbit.paletteWhite, - }, - [TOKENS.colorTextButtonActive]: { - [TYPE_OPTIONS.PRIMARY]: theme.orbit.buttonPrimaryForegroundActive, - [TYPE_OPTIONS.SECONDARY]: theme.orbit.buttonSecondaryForegroundActive, - [TYPE_OPTIONS.CRITICAL]: theme.orbit.buttonCriticalForegroundActive, - [TYPE_OPTIONS.WHITE]: theme.orbit.buttonWhiteForegroundActive, - [TYPE_OPTIONS.PRIMARY_SUBTLE]: theme.orbit.buttonPrimarySubtleForegroundActive, - [TYPE_OPTIONS.CRITICAL_SUBTLE]: theme.orbit.buttonCriticalSubtleForegroundActive, - [TYPE_OPTIONS.BUNDLE_BASIC]: theme.orbit.paletteWhite, - [TYPE_OPTIONS.BUNDLE_MEDIUM]: theme.orbit.paletteWhite, - [TYPE_OPTIONS.BUNDLE_TOP]: theme.orbit.paletteWhite, - }, - [TOKENS.borderColorButtonFocus]: { - [TYPE_OPTIONS.PRIMARY]: convertHexToRgba(theme.orbit.paletteProductNormal, 50), - [TYPE_OPTIONS.SECONDARY]: convertHexToRgba(theme.orbit.paletteInkNormal, 30), - [TYPE_OPTIONS.CRITICAL]: convertHexToRgba(theme.orbit.paletteRedNormal, 50), - // because it's not possible to see outline on the white bg, we use active token - [TYPE_OPTIONS.WHITE]: convertHexToRgba(theme.orbit.paletteWhiteActive, 50), - [TYPE_OPTIONS.PRIMARY_SUBTLE]: convertHexToRgba(theme.orbit.paletteProductNormal, 50), - [TYPE_OPTIONS.CRITICAL_SUBTLE]: convertHexToRgba(theme.orbit.paletteRedNormal, 50), - // TODO: currently we do not have tokens for these colors - [TYPE_OPTIONS.BUNDLE_BASIC]: convertHexToRgba(`#E13E3B`, 50), - [TYPE_OPTIONS.BUNDLE_MEDIUM]: convertHexToRgba(`#3719AB`, 50), - [TYPE_OPTIONS.BUNDLE_TOP]: convertHexToRgba(`#2D2D2E`, 50), - }, - }; - - return tokens[name][type]; -}; - -export default getButtonTypeToken; diff --git a/packages/orbit-components/src/Button/index.tsx b/packages/orbit-components/src/Button/index.tsx index a2ff4024a1..1964c9ed39 100644 --- a/packages/orbit-components/src/Button/index.tsx +++ b/packages/orbit-components/src/Button/index.tsx @@ -1,35 +1,115 @@ "use client"; import * as React from "react"; +import cx from "clsx"; -import { TYPE_OPTIONS } from "./consts"; import ButtonPrimitive from "../primitives/ButtonPrimitive"; -import getIconContainer from "../primitives/ButtonPrimitive/common/getIconContainer"; -import getCommonProps from "../primitives/ButtonPrimitive/common/getCommonProps"; -import useTheme from "../hooks/useTheme"; -import getButtonStyles from "./helpers/getButtonStyles"; -import getButtonIconForeground from "./helpers/getButtonIconForeground"; -import type { Props } from "./types"; +import type { Props, Size, Type } from "./types"; + +const sizeStyles: Record = { + small: "h-button-small text-small [&_svg]:h-icon-small [&_svg]:w-icon-small", + normal: "h-button-normal text-normal [&_svg]:h-icon-medium [&_svg]:w-icon-medium", + large: "h-button-large text-large [&_svg]:h-icon-large [&_svg]:w-icon-large", +}; + +const paddingNoIconsStyles: Record = { + small: "px-button-padding-sm", + normal: "px-button-padding-md", + large: "px-button-padding-xl", +}; + +const paddingLeftIconStyles: Record = { + small: "ps-button-padding-xs pe-button-padding-sm", + normal: "ps-button-padding-sm pe-button-padding-md", + large: "ps-button-padding-lg pe-button-padding-xl", +}; + +const paddingRightIconStyles: Record = { + small: "ps-button-padding-sm pe-button-padding-xs", + normal: "ps-button-padding-md pe-button-padding-sm", + large: "ps-button-padding-xl pe-button-padding-lg", +}; + +const paddingBothIconsStyles: Record = { + small: "px-button-padding-xs", + normal: "px-button-padding-sm", + large: "px-button-padding-lg", +}; + +const circledStyles: Record = { + small: "rounded-button-circled-small", + normal: "rounded-button-circled-normal", + large: "rounded-button-circled-large", +}; + +const circledIconOnlyStyles: Record = { + small: "w-button-small", + normal: "w-button-normal", + large: "w-button-large", +}; + +const typeStyles: Record = { + primary: + "bg-button-primary-background hover:bg-button-primary-background-hover active:bg-button-primary-background-active disabled:bg-button-primary-background focus:bg-button-primary-background-focus text-button-primary-foreground focus:text-button-primary-foreground-focus active:text-button-primary-foreground-active hover:text-button-primary-foreground-hover disabled:text-button-primary-foreground active:shadow-button-active", + secondary: + "bg-button-secondary-background hover:bg-button-secondary-background-hover active:bg-button-secondary-background-active disabled:bg-button-secondary-background focus:bg-button-secondary-background-focus text-button-secondary-foreground focus:text-button-secondary-foreground-focus active:text-button-secondary-foreground-active hover:text-button-secondary-foreground-hover disabled:text-button-secondary-foreground active:shadow-button-active-pale", + critical: + "bg-button-critical-background hover:bg-button-critical-background-hover active:bg-button-critical-background-active disabled:bg-button-critical-background focus:bg-button-critical-background-focus text-button-critical-foreground focus:text-button-critical-foreground-focus active:text-button-critical-foreground-active hover:text-button-critical-foreground-hover disabled:text-button-critical-foreground active:shadow-button-active", + primarySubtle: + "bg-button-primary-subtle-background hover:bg-button-primary-subtle-background-hover active:bg-button-primary-subtle-active-background disabled:bg-button-primary-subtle-background focus:bg-button-primary-subtle-background-focus text-button-primary-subtle-foreground focus:text-button-primary-subtle-foreground-focus active:text-button-primary-subtle-foreground-active hover:text-button-primary-subtle-foreground-hover disabled:text-button-primary-subtle-foreground active:shadow-button-active-pale", + criticalSubtle: + "bg-button-critical-subtle-background hover:bg-button-critical-subtle-background-hover active:bg-button-critical-subtle-active-background disabled:bg-button-critical-subtle-background focus:bg-button-critical-subtle-background-focus text-button-critical-subtle-foreground focus:text-button-critical-subtle-foreground-focus active:text-button-critical-subtle-foreground-active hover:text-button-critical-subtle-foreground-hover disabled:text-button-critical-subtle-foreground active:shadow-button-active-pale", + white: + "bg-button-white-background hover:bg-button-white-background-hover active:bg-button-white-background-active disabled:bg-button-white-background focus:bg-button-white-background-focus text-button-white-foreground focus:text-button-white-foreground-focus active:text-button-white-foreground-active hover:text-button-white-foreground-hover disabled:text-button-white-foreground active:shadow-button-active-pale", + bundleBasic: + "bg-button-bundle-basic-background hover:bg-button-bundle-basic-background-hover active:bg-button-bundle-basic-background-active disabled:bg-button-bundle-basic-background focus:bg-button-bundle-basic-background-focus text-white-foreground focus:text-white-foreground-focus active:text-white-foreground-active hover:text-white-foreground-hover disabled:text-white-foreground active:shadow-button-active", + bundleMedium: + "bg-button-bundle-medium-background hover:bg-button-bundle-medium-background-hover active:bg-button-bundle-medium-background-active disabled:bg-button-bundle-medium-background focus:bg-button-bundle-medium-background-focus text-white-foreground focus:text-white-foreground-focus active:text-white-foreground-active hover:text-white-foreground-hover disabled:text-white-foreground active:shadow-button-active", + bundleTop: + "bg-button-bundle-top-background hover:bg-button-bundle-top-background-hover active:bg-button-bundle-top-background-active disabled:bg-button-bundle-top-background focus:bg-button-bundle-top-background-focus text-white-foreground focus:text-white-foreground-focus active:text-white-foreground-active hover:text-white-foreground-hover disabled:text-white-foreground active:shadow-button-active", +}; + +/** + * This is necessary for elements since they don't have the `disabled` attribute. + */ +const typeDisabledStyled: Record = { + primary: "bg-button-primary-background text-button-primary-foreground", + secondary: "bg-button-secondary-background text-button-secondary-foreground", + critical: "bg-button-critical-background text-button-critical-foreground", + primarySubtle: "bg-button-primary-subtle-background text-button-primary-subtle-foreground", + criticalSubtle: "bg-button-critical-subtle-background text-button-critical-subtle-foreground", + white: "bg-button-white-background text-button-white-foreground", + bundleBasic: "bg-button-bundle-basic-background text-white-foreground", + bundleMedium: "bg-button-bundle-medium-background text-white-foreground", + bundleTop: "bg-button-bundle-top-background text-white-foreground", +}; const Button = React.forwardRef( - ({ type = TYPE_OPTIONS.PRIMARY, size, disabled = false, ...props }, ref) => { - const theme = useTheme(); - const propsWithTheme = { theme, size, ...props }; - const commonProps = getCommonProps(propsWithTheme); - const buttonStyles = getButtonStyles({ type, theme, disabled }); - const icons = getIconContainer({ - ...propsWithTheme, - iconForeground: getButtonIconForeground({ type, theme }), - }); + ( + { type = "primary", size = "normal", children, iconLeft, iconRight, disabled, ...props }, + ref, + ) => { return ( + className={cx( + "orbit-button space-x-xs rtl:space-x-reverse", + sizeStyles[size], + disabled === true ? typeDisabledStyled[type] : typeStyles[type], + children != null && iconLeft == null && iconRight == null && paddingNoIconsStyles[size], + children != null && iconLeft != null && iconRight == null && paddingLeftIconStyles[size], + children != null && iconLeft == null && iconRight != null && paddingRightIconStyles[size], + children != null && iconLeft != null && iconRight != null && paddingBothIconsStyles[size], + props.circled === true && circledStyles[size], + props.circled === true && children == null && circledIconOnlyStyles[size], + )} + > + {children} + ); }, ); diff --git a/packages/orbit-components/src/Button/types.d.ts b/packages/orbit-components/src/Button/types.d.ts index d1f17f0112..d0e57de61d 100644 --- a/packages/orbit-components/src/Button/types.d.ts +++ b/packages/orbit-components/src/Button/types.d.ts @@ -8,6 +8,8 @@ import type { FullWidthConditionalProps, } from "../primitives/ButtonPrimitive/types"; +export type { Size }; + export type Type = | "primary" | "secondary" diff --git a/packages/orbit-components/src/ButtonGroup/index.tsx b/packages/orbit-components/src/ButtonGroup/index.tsx index fadd388fa9..462f24641b 100644 --- a/packages/orbit-components/src/ButtonGroup/index.tsx +++ b/packages/orbit-components/src/ButtonGroup/index.tsx @@ -5,14 +5,13 @@ import styled, { css } from "styled-components"; import defaultTheme from "../defaultTheme"; import { borderRadius, rtlSpacing } from "../utils/rtl"; -import { StyledButtonPrimitive } from "../primitives/ButtonPrimitive"; import mq from "../utils/mediaQuery"; import type { Props } from "./types"; const StyledButtonGroup = styled.div` display: flex; - ${StyledButtonPrimitive} { + .orbit-button-primitive { border-radius: 0; margin: ${({ theme }) => rtlSpacing(theme.orbit.marginButtonGroup)}; @@ -26,7 +25,7 @@ const StyledButtonGroup = styled.div` } } ${mq.tablet(css` - ${StyledButtonPrimitive} { + .orbit-button-primitive { :first-child { border-radius: ${({ theme }) => borderRadius(`${theme.orbit.borderRadiusNormal} 0 0 ${theme.orbit.borderRadiusNormal}`)}; diff --git a/packages/orbit-components/src/InputField/index.tsx b/packages/orbit-components/src/InputField/index.tsx index 94c38eaa76..5364eaeb7a 100644 --- a/packages/orbit-components/src/InputField/index.tsx +++ b/packages/orbit-components/src/InputField/index.tsx @@ -19,7 +19,6 @@ import InformationCircle from "../icons/InformationCircle"; import FormLabel from "../FormLabel"; import useErrorTooltip from "../ErrorFormTooltip/hooks/useErrorTooltip"; import formElementFocus from "./helpers/formElementFocus"; -import { StyledButtonPrimitiveIconContainer } from "../primitives/ButtonPrimitive/components/ButtonPrimitiveIconContainer"; import mq from "../utils/mediaQuery"; import type { Props } from "./types"; @@ -187,7 +186,7 @@ export const Prefix = styled(({ children, className, iconRef }) => ( height: ${theme.orbit.heightIconNormal}; } - ${StyledButtonPrimitiveIconContainer} { + .orbit-button-primitive-icon { color: ${theme.orbit.colorIconSecondary}; } `} @@ -208,7 +207,7 @@ const Suffix = styled(({ children, className }) =>
{c pointer-events: ${disabled && "none"}; z-index: 3; - ${StyledButtonPrimitiveIconContainer} { + .orbit-button-primitive-icon { color: ${theme.orbit.colorIconSecondary}; } diff --git a/packages/orbit-components/src/Modal/ModalFooter/index.tsx b/packages/orbit-components/src/Modal/ModalFooter/index.tsx index dc5751378e..feac45eb0a 100644 --- a/packages/orbit-components/src/Modal/ModalFooter/index.tsx +++ b/packages/orbit-components/src/Modal/ModalFooter/index.tsx @@ -10,7 +10,6 @@ import { rtlSpacing } from "../../utils/rtl"; import { ModalContext } from "../ModalContext"; import { QUERIES } from "../../utils/mediaQuery/consts"; import useModalContextFunctions from "../helpers/useModalContextFunctions"; -import { StyledButtonPrimitive } from "../../primitives/ButtonPrimitive"; import type { Props } from "./types"; const StyledChild = styled.div<{ flex?: Props["flex"] }>` @@ -38,7 +37,7 @@ export const StyledModalFooter = styled.div<{ box-sizing: border-box; transition: ${transition(["box-shadow"], "fast", "ease-in-out")}; @media (max-width: ${+getBreakpointWidth(QUERIES.LARGEMOBILE, theme, true) - 1}px) { - ${StyledButtonPrimitive} { + .orbit-button-primitive { font-size: ${theme.orbit.fontSizeButtonNormal}; height: ${theme.orbit.heightButtonNormal}; } diff --git a/packages/orbit-components/src/Modal/index.tsx b/packages/orbit-components/src/Modal/index.tsx index 3dde973e9a..277ebbcac0 100644 --- a/packages/orbit-components/src/Modal/index.tsx +++ b/packages/orbit-components/src/Modal/index.tsx @@ -11,7 +11,6 @@ import ModalCloseButton from "./ModalCloseButton"; import { SIZES, CLOSE_BUTTON_DATA_TEST } from "./consts"; import KEY_CODE_MAP from "../common/keyMaps"; import defaultTheme from "../defaultTheme"; -import { StyledButtonPrimitive } from "../primitives/ButtonPrimitive"; import media from "../utils/mediaQuery"; import { right } from "../utils/rtl"; import transition from "../utils/transition"; @@ -151,7 +150,7 @@ const CloseContainer = styled.div<{ margin: 0; } - ${StyledButtonPrimitive} { + .orbit-button-primitive { pointer-events: auto; margin-${right}: ${theme.orbit.spaceXXSmall}; diff --git a/packages/orbit-components/src/Popover/components/ContentWrapper.tsx b/packages/orbit-components/src/Popover/components/ContentWrapper.tsx index c70617114a..7445ad63b7 100644 --- a/packages/orbit-components/src/Popover/components/ContentWrapper.tsx +++ b/packages/orbit-components/src/Popover/components/ContentWrapper.tsx @@ -13,7 +13,6 @@ import transition from "../../utils/transition"; import useClickOutside from "../../hooks/useClickOutside"; import useLockScrolling from "../../hooks/useLockScrolling"; import { ModalContext } from "../../Modal/ModalContext"; -import { StyledButtonPrimitive } from "../../primitives/ButtonPrimitive"; import { PLACEMENTS } from "../../common/consts"; import boundingClientRect from "../../utils/boundingClientRect"; import type { Offset } from "../types"; @@ -82,7 +81,7 @@ const StyledActions = styled.div` padding: ${popoverPadding}; padding-top: ${theme.orbit.spaceSmall}; background-color: ${theme.orbit.paletteWhite}; - ${StyledButtonPrimitive} { + .orbit-button-primitive { width: 100%; flex: 1 1 auto; } @@ -92,7 +91,7 @@ const StyledActions = styled.div` left: auto; border-bottom-left-radius: ${theme.orbit.borderRadiusNormal}; border-bottom-right-radius: 3px; - ${StyledButtonPrimitive} { + .orbit-button-primitive { width: auto; flex-grow: 0; } diff --git a/packages/orbit-components/src/Stepper/__tests__/index.test.tsx b/packages/orbit-components/src/Stepper/__tests__/index.test.tsx index b093208a9d..ba69dc49ed 100644 --- a/packages/orbit-components/src/Stepper/__tests__/index.test.tsx +++ b/packages/orbit-components/src/Stepper/__tests__/index.test.tsx @@ -49,8 +49,6 @@ describe("Stepper", () => { await user.click(screen.getByLabelText(IncrementLabel)); expect(onIncrement).toHaveBeenCalled(); await user.click(screen.getByLabelText(DecrementLabel)); - expect(screen.getByLabelText("Decrement")).toHaveStyle({ background: "transparent" }); - expect(screen.getByLabelText("Increment")).toHaveStyle({ background: "transparent" }); expect(onDecrement).toHaveBeenCalled(); await user.tab(); diff --git a/packages/orbit-components/src/primitives/ButtonPrimitive/components/ButtonPrimitiveContent.tsx b/packages/orbit-components/src/primitives/ButtonPrimitive/components/ButtonPrimitiveContent.tsx deleted file mode 100644 index bb56ca92fc..0000000000 --- a/packages/orbit-components/src/primitives/ButtonPrimitive/components/ButtonPrimitiveContent.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from "react"; -import styled, { css } from "styled-components"; - -import defaultTheme from "../../../defaultTheme"; - -interface Props { - loading?: boolean; - contentAlign: string | null; -} - -const StyledButtonPrimitiveContent = styled.div>` - ${({ contentAlign, loading }) => css` - visibility: ${loading && "hidden"}; - height: 100%; - display: flex; - justify-content: ${contentAlign}; - flex-basis: 100%; - align-items: center; - `} -`; - -StyledButtonPrimitiveContent.defaultProps = { - theme: defaultTheme, -}; - -const ButtonPrimitiveContent = ({ children, ...props }: React.PropsWithChildren) => ( - {children} -); - -export default ButtonPrimitiveContent; diff --git a/packages/orbit-components/src/primitives/ButtonPrimitive/components/ButtonPrimitiveContentChildren.tsx b/packages/orbit-components/src/primitives/ButtonPrimitive/components/ButtonPrimitiveContentChildren.tsx deleted file mode 100644 index 33dd1d11e0..0000000000 --- a/packages/orbit-components/src/primitives/ButtonPrimitive/components/ButtonPrimitiveContentChildren.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import * as React from "react"; -import styled, { css } from "styled-components"; - -import { left } from "../../../utils/rtl"; -import defaultTheme from "../../../defaultTheme"; - -interface Props { - centered?: boolean; - hasIcon: boolean; - contentWidth?: string | null; -} - -const StyledButtonPrimitiveContentChildren = styled.div` - ${({ hasIcon, contentWidth, centered }) => css` - display: inline-block; - width: ${contentWidth}; - line-height: 1; - text-align: ${hasIcon && !centered && left}; - `} -`; - -StyledButtonPrimitiveContentChildren.defaultProps = { - theme: defaultTheme, -}; - -const ButtonPrimitiveContentChildren = ({ - children, - hasIcon, - contentWidth, - centered, -}: React.PropsWithChildren) => ( - - {children} - -); - -export default ButtonPrimitiveContentChildren; diff --git a/packages/orbit-components/src/primitives/ButtonPrimitive/components/ButtonPrimitiveIconContainer.tsx b/packages/orbit-components/src/primitives/ButtonPrimitive/components/ButtonPrimitiveIconContainer.tsx deleted file mode 100644 index c7ce27e17e..0000000000 --- a/packages/orbit-components/src/primitives/ButtonPrimitive/components/ButtonPrimitiveIconContainer.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import styled, { css } from "styled-components"; -import * as React from "react"; - -import defaultTheme from "../../../defaultTheme"; -import transition from "../../../utils/transition"; - -interface Props { - margin?: string | null; - width?: string | null; - height?: string | null; -} - -export const StyledButtonPrimitiveIconContainer = styled(({ className, children }) => ( -
{children}
-))` - ${({ margin, width, height }) => css` - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - margin: ${margin}; - color: currentColor; - transition: ${transition(["background", "box-shadow", "color"], "fast", "ease-in-out")}; - > svg { - width: ${width}; - height: ${height}; - } - `} -`; - -StyledButtonPrimitiveIconContainer.defaultProps = { - theme: defaultTheme, -}; - -const ButtonPrimitiveIconContainer = ({ - margin, - width, - height, - children, -}: React.PropsWithChildren) => ( - - {children} - -); - -export default ButtonPrimitiveIconContainer; diff --git a/packages/orbit-components/src/primitives/ButtonPrimitive/index.js.flow b/packages/orbit-components/src/primitives/ButtonPrimitive/index.js.flow index c7f4d599b9..196f7e98f7 100644 --- a/packages/orbit-components/src/primitives/ButtonPrimitive/index.js.flow +++ b/packages/orbit-components/src/primitives/ButtonPrimitive/index.js.flow @@ -3,7 +3,6 @@ DOCUMENTATION: https://orbit.kiwi/utilities/buttonprimitive/ */ import * as React from "react"; -import type { StyledComponent } from "styled-components"; import type { Globals, Component } from "../../common/common.js.flow"; import type { spaceAfter } from "../../common/getSpacingToken/index.js.flow"; @@ -110,6 +109,4 @@ export type Props = {| ...PrimitiveTypes, |}; -declare export var StyledButtonPrimitive: StyledComponent; - declare export default React.AbstractComponent; diff --git a/packages/orbit-components/src/primitives/ButtonPrimitive/index.tsx b/packages/orbit-components/src/primitives/ButtonPrimitive/index.tsx index cd071a45ba..bdde42521d 100644 --- a/packages/orbit-components/src/primitives/ButtonPrimitive/index.tsx +++ b/packages/orbit-components/src/primitives/ButtonPrimitive/index.tsx @@ -1,263 +1,297 @@ "use client"; import * as React from "react"; -import styled, { css } from "styled-components"; +import cx from "clsx"; -import defaultTheme from "../../defaultTheme"; import Loading from "../../Loading"; -import getSpacingToken from "../../common/getSpacingToken"; -import ButtonPrimitiveContent from "./components/ButtonPrimitiveContent"; -import ButtonPrimitiveIconContainer, { - StyledButtonPrimitiveIconContainer, -} from "./components/ButtonPrimitiveIconContainer"; -import ButtonPrimitiveContentChildren from "./components/ButtonPrimitiveContentChildren"; -import mq from "../../utils/mediaQuery"; import createRel from "./common/createRel"; import onKeyDown from "../../utils/handleKeyDown"; +import { getSpaceAfterClasses } from "../../common/tailwind"; import type { Props } from "./types"; -const iconContainerColor = (color: string, important = true) => css` - ${StyledButtonPrimitiveIconContainer} { - color: ${color} ${important && "!important"}; - } -`; - -interface StyleProps extends Props { - onlyIcon: boolean; +interface ComponentProps extends Props { className?: string; + style?: React.CSSProperties; } -export const StyledButtonPrimitive = styled( - React.forwardRef( - ( - { - asComponent = "button", - id, - dataTest, - submit, - disabled, - ariaControls, - ariaExpanded, - ariaLabelledby, - ariaCurrent, - title, - className, - rel, - href, - external, - tabIndex, - onClick, - role, - download, - ...props - }, - ref, - ) => { - const isButtonWithHref = asComponent === "button" && href; - const Component = isButtonWithHref ? "a" : asComponent; - const buttonType = submit ? "submit" : "button"; - - const handleKeyDown = (ev: React.KeyboardEvent) => - asComponent === "div" ? onKeyDown(onClick)(ev) : undefined; - - return ( - - {props.children} - - ); - }, - ), -)` - ${({ - foreground, +const ButtonPrimitiveComponent = React.forwardRef(function Component( + { + asComponent = "button", + dataTest, + submit, disabled, - fullWidth, + ariaControls, + ariaExpanded, + ariaLabelledby, + ariaCurrent, + title, + rel, href, - theme, - asComponent, - circled, - padding, - background, - fontWeight, - fontSize, - height, - width, - onlyIcon, - icons, - foregroundHover, - foregroundActive, - foregroundFocus, - backgroundHover, - backgroundActive, - backgroundFocus, - boxShadow, - boxShadowHover, - boxShadowFocus, - boxShadowActive, - underlined, - }) => css` - height: ${height}; - position: relative; - display: ${href || asComponent === "a" ? "inline-flex" : "flex"}; - justify-content: space-between; - align-items: center; - box-sizing: border-box; - appearance: none !important; - text-align: center; - text-decoration: ${underlined ? "underline" : "none"}; - flex: ${fullWidth ? "1 1 auto" : "0 0 auto"}; - max-width: 100%; - background: ${background}; - color: ${foreground}!important; - border: 0; - outline: ${boxShadowFocus && "0"}; - padding: ${padding}; - border-radius: ${circled ? height : "6px"}; - font-family: ${theme.orbit.fontFamily}; - font-weight: ${fontWeight || theme.orbit.fontWeightMedium}; - font-size: ${fontSize}; - cursor: ${disabled ? "not-allowed" : "pointer"}; - transition: all ${theme.orbit.durationFast} ease-in-out !important; - opacity: ${disabled && theme.orbit.opacityButtonDisabled}; - margin-bottom: ${getSpacingToken}; - width: ${fullWidth ? "100%" : width || (onlyIcon && height) || "auto"}; - box-shadow: ${boxShadow}; - & > * { - vertical-align: middle; - } - - ${mq.tablet(css` - border-radius: ${circled ? height : theme.orbit.borderRadiusNormal}; - `)} - - ${icons && icons.foreground && iconContainerColor(icons.foreground, false)}; - - & .orbit-loading-spinner { - width: ${icons && icons.width}; - height: ${icons && icons.height}; - stroke: ${theme.orbit.paletteWhite}; - } - - &:hover { - ${!disabled && - css` - background: ${backgroundHover}; - color: ${foregroundHover}!important; - box-shadow: ${boxShadowHover}; - text-decoration: none; - ${icons && icons.foregroundHover && iconContainerColor(icons.foregroundHover)}; - `}; - } - - :focus { - box-shadow: ${boxShadowFocus}; - background: ${backgroundFocus}; - color: ${foregroundFocus}!important; - text-decoration: none; - ${icons && icons.foregroundFocus && iconContainerColor(icons.foregroundFocus)}; - } + external, + onClick, + children, + ...props + }: ComponentProps, + ref: React.ForwardedRef, +) { + const isButtonWithHref = asComponent === "button" && href; + const Element = isButtonWithHref ? "a" : asComponent; + const buttonType = submit ? "submit" : "button"; - :focus:not(:focus-visible) { - box-shadow: none; - background: ${background}; - color: ${foregroundFocus}!important; - text-decoration: none; - ${icons && icons.foregroundFocus && iconContainerColor(icons.foregroundFocus)}; - } - :-moz-focusring, - :focus-visible { - box-shadow: ${boxShadowFocus}; - background: ${backgroundFocus}; - color: ${foregroundFocus}!important; - text-decoration: none; - ${icons && icons.foregroundFocus && iconContainerColor(icons.foregroundFocus)}; - } + const handleKeyDown = (ev: React.KeyboardEvent) => + asComponent === "div" ? onKeyDown(onClick)(ev) : undefined; - &:hover:focus { - background: ${backgroundHover}; - } - &:active, - &:active:focus { - ${!disabled && - css` - background: ${backgroundActive}; - box-shadow: ${boxShadowActive}; - color: ${foregroundActive}!important; - text-decoration: none; - ${icons && icons.foregroundActive && iconContainerColor(icons.foregroundActive)}; - `}; - } - `}; -`; + return ( + elements + onClick={disabled ? undefined : onClick} + {...props} + > + {children} + + ); +}); -StyledButtonPrimitive.defaultProps = { - theme: defaultTheme, -}; +ButtonPrimitiveComponent.displayName = "ButtonPrimitiveComponent"; const ButtonPrimitive = React.forwardRef( - (props, ref) => { - const { - loading, - disabled, + ( + { + // Elements children, iconLeft, iconRight, - // Need to setup null values so the object exits by default - icons = { width: null, height: null, leftMargin: null, rightMargin: null }, + // Container vars + height, + padding, contentAlign = "center", + fontWeight, + fontSize, + foreground, + foregroundHover, + foregroundActive, + foregroundFocus, + background, + backgroundHover, + backgroundActive, + backgroundFocus, + boxShadow, + boxShadowHover, + boxShadowFocus, + boxShadowActive, + // Content vars contentWidth, + // Icon vars + icons, + // Modificators fullWidth, centered, - } = props; - const { width, height, leftMargin, rightMargin } = icons; - const isDisabled = loading || disabled; - const onlyIcon = Boolean(iconLeft && !children); + underlined, + circled, + spaceAfter, + // Status + loading, + disabled, + // Rest + className, + ...props + }: Props, + ref, + ) => { + const isLink = props.href != null || props.asComponent === "a"; + const isDisabled = loading === true || disabled === true; + + const varsButton = { + "--button-height": height, + "--button-padding": padding, + "--button-content-align": contentAlign, + "--button-font-weight": fontWeight, + "--button-font-size": fontSize, + "--button-foreground": foreground, + "--button-foreground-hover": foregroundHover, + "--button-foreground-active": foregroundActive, + "--button-foreground-focus": foregroundFocus, + "--button-background": background, + "--button-background-hover": backgroundHover, + "--button-background-active": backgroundActive, + "--button-background-focus": backgroundFocus, + "--button-box-shadow": boxShadow, + "--button-box-shadow-hover": boxShadowHover, + "--button-box-shadow-focus": boxShadowFocus, + "--button-box-shadow-active": boxShadowActive, + // loader + "--button-icon-width": icons?.width, + "--button-icon-height": icons?.height, + } as React.CSSProperties; + + const varsContent = { + "--button-content-width": contentWidth, + } as React.CSSProperties; + + const varsIcons = { + "--button-icon-width": icons?.width, + "--button-icon-height": icons?.height, + "--button-icon-left-margin": icons?.leftMargin, + "--button-icon-right-margin": icons?.rightMargin, + "--button-icon-foreground": icons?.foreground, + "--button-icon-foreground-focus": icons?.foregroundFocus, + "--button-icon-foreground-hover": icons?.foregroundHover, + "--button-icon-foreground-active": icons?.foregroundActive, + } as React.CSSProperties; return ( - + *]:align-middle [&_.orbit-loading-spinner]:stroke-[currentColor]", + fullWidth && "w-full", + centered || children == null ? "justify-center" : "justify-[var(--button-content-align)]", + circled !== true && "rounded-large tb:rounded-normal", + isDisabled + ? "cursor-not-allowed opacity-30" + : "hover:no-underline focus:no-underline active:no-underline", + isLink ? "inline-flex" : "flex", + underlined && "underline", + boxShadowFocus != null && "outline-none", + spaceAfter != null && getSpaceAfterClasses(spaceAfter), + // loader + varsButton["--button-icon-height"] != null && + "[&_.orbit-loading-spinner]:h-[var(--button-icon-height)]", + varsButton["--button-icon-width"] != null && + "[&_.orbit-loading-spinner]:w-[var(--button-icon-width)]", + // button vars + varsButton["--button-height"] != null && "h-[var(--button-height)]", + varsButton["--button-height"] != null && + circled === true && + "rounded-[var(--button-height)]", + varsButton["--button-height"] != null && children == null && "w-[var(--button-height)]", + varsButton["--button-padding"] != null && "p-[var(--button-padding)]", + varsButton["--button-font-weight"] == null + ? "font-medium" + : "font-[var(--button-font-weight)]", + varsButton["--button-font-size"] != null && "text-[length:var(--button-font-size)]", + varsButton["--button-foreground"] != null && "text-[color:var(--button-foreground)]", + varsButton["--button-foreground-hover"] != null && + !isDisabled && + "hover:text-[color:var(--button-foreground-hover)]", + varsButton["--button-foreground-active"] != null && + !isDisabled && + "active:text-[color:var(--button-foreground-active)] active:focus:text-[color:var(--button-foreground-active)]", + varsButton["--button-foreground-focus"] != null && + !isDisabled && + "focus:text-[color:var(--button-foreground-focus)]", + varsButton["--button-background"] != null && "bg-[var(--button-background)]", + varsButton["--button-background-hover"] != null && + !isDisabled && + "hover:bg-[var(--button-background-hover)] hover:focus:bg-[var(--button-background-hover)]", + varsButton["--button-background-active"] != null && + !isDisabled && + "active:bg-[var(--button-background-active)] active:focus:bg-[var(--button-background-active)]", + varsButton["--button-background-focus"] != null && + !isDisabled && + "focus:bg-[var(--button-background-focus)]", + varsButton["--button-box-shadow"] != null && "[box-shadow:var(--button-box-shadow)]", + varsButton["--button-box-shadow-hover"] != null && + !isDisabled && + "hover:[box-shadow:var(--button-box-shadow-hover)]", + varsButton["--button-box-shadow-focus"] != null && + !isDisabled && + "focus:[box-shadow:var(--button-box-shadow-focus)]", + varsButton["--button-box-shadow-active"] != null && + !isDisabled && + "active:[box-shadow:var(--button-box-shadow-active)] active:focus:[box-shadow:var(--button-box-shadow-active)]", + )} + style={varsButton} + > {loading && } - - {iconLeft && ( - - {iconLeft} - - )} - {children && ( - - {children} - - )} - {iconRight && ( - - {iconRight} - - )} - - + + {iconLeft != null && ( +
svg]:h-[var(--button-icon-height)]", + varsIcons["--button-icon-width"] != null && "[&>svg]:w-[var(--button-icon-width)]", + varsIcons["--button-icon-left-margin"] != null && + children != null && + "m-[var(--button-icon-left-margin)]", + varsIcons["--button-icon-foreground"] != null && + "text-[color:var(--button-icon-foreground)]", + varsIcons["--button-icon-foreground-hover"] != null && + !isDisabled && + "group-hover:text-[color:var(--button-icon-foreground-hover)]", + varsIcons["--button-icon-foreground-focus"] != null && + !isDisabled && + "group-focus:text-[color:var(--button-icon-foreground-focus)]", + varsIcons["--button-icon-foreground-active"] != null && + !isDisabled && + "group-active:text-[color:var(--button-icon-foreground-active)] group-active:group-focus:text-[color:var(--button-icon-foreground-active)]", + )} + style={varsIcons} + > + {iconLeft} +
+ )} + {children != null && ( +
+ {children} +
+ )} + {iconRight != null && ( +
svg]:h-[var(--button-icon-height)]", + varsIcons["--button-icon-width"] != null && "[&>svg]:w-[var(--button-icon-width)]", + varsIcons["--button-icon-right-margin"] != null && + "m-[var(--button-icon-right-margin)]", + varsIcons["--button-icon-foreground"] != null && + "text-[color:var(--button-icon-foreground)]", + varsIcons["--button-icon-foreground-hover"] != null && + !isDisabled && + "group-hover:text-[color:var(--button-icon-foreground-hover)]", + varsIcons["--button-icon-foreground-focus"] != null && + !isDisabled && + "group-focus:text-[color:var(--button-icon-foreground-focus)]", + varsIcons["--button-icon-foreground-active"] != null && + !isDisabled && + "group-active:text-[color:var(--button-icon-foreground-active)] group-active:group-focus:text-[color:var(--button-icon-foreground-active)]", + )} + style={varsIcons} + > + {iconRight} +
+ )} + ); }, ); diff --git a/packages/orbit-components/src/primitives/ButtonPrimitive/types.d.ts b/packages/orbit-components/src/primitives/ButtonPrimitive/types.d.ts index 311acb963b..d646af264a 100644 --- a/packages/orbit-components/src/primitives/ButtonPrimitive/types.d.ts +++ b/packages/orbit-components/src/primitives/ButtonPrimitive/types.d.ts @@ -32,6 +32,7 @@ export interface ButtonCommonProps extends Common.Globals, Common.SpaceAfter { readonly centered?: boolean; readonly children?: React.ReactNode; readonly circled?: boolean; + readonly className?: string; readonly underlined?: boolean; readonly disabled?: boolean; readonly download?: boolean | string; diff --git a/packages/orbit-design-tokens/output/deprecated-tokens.json b/packages/orbit-design-tokens/output/deprecated-tokens.json index 7a5059300e..b3766d5844 100644 --- a/packages/orbit-design-tokens/output/deprecated-tokens.json +++ b/packages/orbit-design-tokens/output/deprecated-tokens.json @@ -1287,6 +1287,66 @@ "category": "Size (width, height)", "version": "6.0.0" }, + "buttonSmallPadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, + "buttonSmallBothIconsPadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, + "buttonSmallLeftIconPadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, + "buttonSmallRightIconPadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, + "buttonNormalPadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, + "buttonNormalBothIconsPadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, + "buttonNormalLeftIconPadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, + "buttonNormalRightIconPadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, + "buttonLargePadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, + "buttonLargeBothIconsPadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, + "buttonLargeLeftIconPadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, + "buttonLargeRightIconPadding": { + "replacement": null, + "category": "Spacing", + "version": "6.0.0" + }, "boxShadowButtonFocus": { "replacement": null, "category": "Box shadow", @@ -1607,21 +1667,6 @@ "category": "Size (width, height)", "version": "6.0.0" }, - "opacityButtonDisabled": { - "replacement": "buttonDisabledOpacity", - "category": "Opacity", - "version": "6.0.0" - }, - "opacityCheckboxDisabled": { - "replacement": "formElementDisabledOpacity", - "category": "Opacity", - "version": "6.0.0" - }, - "opacityRadioButtonDisabled": { - "replacement": "formElementDisabledOpacity", - "category": "Opacity", - "version": "6.0.0" - }, "borderStyleCard": { "replacement": null, "category": null, @@ -1832,6 +1877,16 @@ "category": "Size (width, height)", "version": "6.0.0" }, + "opacityCheckboxDisabled": { + "replacement": "formElementDisabledOpacity", + "category": "Opacity", + "version": "6.0.0" + }, + "opacityRadioButtonDisabled": { + "replacement": "formElementDisabledOpacity", + "category": "Opacity", + "version": "6.0.0" + }, "fontWeightHeadingDisplay": { "replacement": "headingDisplayFontWeight", "category": null, diff --git a/packages/orbit-design-tokens/output/docs-tokens.json b/packages/orbit-design-tokens/output/docs-tokens.json index 6d6827ec52..39e3b096a0 100644 --- a/packages/orbit-design-tokens/output/docs-tokens.json +++ b/packages/orbit-design-tokens/output/docs-tokens.json @@ -7898,7 +7898,7 @@ "buttonSmallPadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -7922,7 +7922,7 @@ "buttonSmallBothIconsPadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -7946,7 +7946,7 @@ "buttonSmallLeftIconPadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -7970,7 +7970,7 @@ "buttonSmallRightIconPadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -8017,7 +8017,7 @@ "buttonNormalPadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -8041,7 +8041,7 @@ "buttonNormalBothIconsPadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -8065,7 +8065,7 @@ "buttonNormalLeftIconPadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -8089,7 +8089,7 @@ "buttonNormalRightIconPadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -8136,7 +8136,7 @@ "buttonLargePadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -8160,7 +8160,7 @@ "buttonLargeBothIconsPadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -8184,7 +8184,7 @@ "buttonLargeLeftIconPadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -8208,7 +8208,7 @@ "buttonLargeRightIconPadding": { "type": "size", "category": "spacing", - "deprecated": false, + "deprecated": true, "replacement": null, "schema": { "namespace": "component", @@ -8370,50 +8370,142 @@ "value": "rgb(255, 255, 255)" } }, - "buttonDisabledOpacity": { - "type": "opacity", + "buttonWithoutTextPadding": { + "type": "size", "deprecated": false, "replacement": null, "schema": { "namespace": "component", "object": "button", - "variant": "disabled", - "subVariant": "opacity" + "variant": "without-text", + "subVariant": "padding" }, "javascript": { - "name": "buttonDisabledOpacity", - "value": "0.3" + "name": "buttonWithoutTextPadding", + "value": "0" }, "foundation": { - "name": "buttonDisabledOpacity", + "name": "buttonWithoutTextPadding", "value": "none" }, "scss": { - "name": "buttonDisabledOpacity", - "value": "0.3" + "name": "buttonWithoutTextPadding", + "value": "0" } }, - "buttonWithoutTextPadding": { + "buttonPaddingXSmall": { "type": "size", "deprecated": false, "replacement": null, "schema": { "namespace": "component", "object": "button", - "variant": "without-text", - "subVariant": "padding" + "variant": "padding", + "subVariant": "x-small" }, "javascript": { - "name": "buttonWithoutTextPadding", - "value": "0" + "name": "buttonPaddingXSmall", + "value": "8px" }, "foundation": { - "name": "buttonWithoutTextPadding", + "name": "buttonPaddingXSmall", + "value": "foundation.space.xSmall" + }, + "scss": { + "name": "buttonPaddingXSmall", + "value": "8px" + } + }, + "buttonPaddingSmall": { + "type": "size", + "deprecated": false, + "replacement": null, + "schema": { + "namespace": "component", + "object": "button", + "variant": "padding", + "subVariant": "small" + }, + "javascript": { + "name": "buttonPaddingSmall", + "value": "12px" + }, + "foundation": { + "name": "buttonPaddingSmall", + "value": "foundation.space.small" + }, + "scss": { + "name": "buttonPaddingSmall", + "value": "12px" + } + }, + "buttonPaddingNormal": { + "type": "size", + "deprecated": false, + "replacement": null, + "schema": { + "namespace": "component", + "object": "button", + "variant": "padding", + "subVariant": "normal" + }, + "javascript": { + "name": "buttonPaddingNormal", + "value": "16px" + }, + "foundation": { + "name": "buttonPaddingNormal", + "value": "foundation.space.medium" + }, + "scss": { + "name": "buttonPaddingNormal", + "value": "16px" + } + }, + "buttonPaddingLarge": { + "type": "size", + "deprecated": false, + "replacement": null, + "schema": { + "namespace": "component", + "object": "button", + "variant": "padding", + "subVariant": "large" + }, + "javascript": { + "name": "buttonPaddingLarge", + "value": "24px" + }, + "foundation": { + "name": "buttonPaddingLarge", + "value": "foundation.space.large" + }, + "scss": { + "name": "buttonPaddingLarge", + "value": "24px" + } + }, + "buttonPaddingXLarge": { + "type": "size", + "deprecated": false, + "replacement": null, + "schema": { + "namespace": "component", + "object": "button", + "variant": "padding", + "subVariant": "x-large" + }, + "javascript": { + "name": "buttonPaddingXLarge", + "value": "28px" + }, + "foundation": { + "name": "buttonPaddingXLarge", "value": "none" }, "scss": { - "name": "buttonWithoutTextPadding", - "value": "0" + "name": "buttonPaddingXLarge", + "value": "28px" } }, "buttonPrimarySubtleBackground": { @@ -10803,75 +10895,6 @@ "value": "13px" } }, - "opacityButtonDisabled": { - "type": "opacity", - "deprecated": true, - "replacement": "buttonDisabledOpacity", - "schema": { - "namespace": "component", - "object": "opacity", - "variant": "button", - "subVariant": "disabled" - }, - "javascript": { - "name": "opacityButtonDisabled", - "value": "0.3" - }, - "foundation": { - "name": "opacityButtonDisabled", - "value": "none" - }, - "scss": { - "name": "opacityButtonDisabled", - "value": "0.3" - } - }, - "opacityCheckboxDisabled": { - "type": "opacity", - "deprecated": true, - "replacement": "formElementDisabledOpacity", - "schema": { - "namespace": "component", - "object": "opacity", - "variant": "checkbox", - "subVariant": "disabled" - }, - "javascript": { - "name": "opacityCheckboxDisabled", - "value": "0.5" - }, - "foundation": { - "name": "opacityCheckboxDisabled", - "value": "none" - }, - "scss": { - "name": "opacityCheckboxDisabled", - "value": "0.5" - } - }, - "opacityRadioButtonDisabled": { - "type": "opacity", - "deprecated": true, - "replacement": "formElementDisabledOpacity", - "schema": { - "namespace": "component", - "object": "opacity", - "variant": "radio-button", - "subVariant": "disabled" - }, - "javascript": { - "name": "opacityRadioButtonDisabled", - "value": "0.5" - }, - "foundation": { - "name": "opacityRadioButtonDisabled", - "value": "none" - }, - "scss": { - "name": "opacityRadioButtonDisabled", - "value": "0.5" - } - }, "borderStyleCard": { "type": "border-style", "deprecated": true, @@ -12574,6 +12597,52 @@ "value": "2px" } }, + "opacityCheckboxDisabled": { + "type": "opacity", + "deprecated": true, + "replacement": "formElementDisabledOpacity", + "schema": { + "namespace": "component", + "object": "opacity", + "variant": "checkbox", + "subVariant": "disabled" + }, + "javascript": { + "name": "opacityCheckboxDisabled", + "value": "0.5" + }, + "foundation": { + "name": "opacityCheckboxDisabled", + "value": "none" + }, + "scss": { + "name": "opacityCheckboxDisabled", + "value": "0.5" + } + }, + "opacityRadioButtonDisabled": { + "type": "opacity", + "deprecated": true, + "replacement": "formElementDisabledOpacity", + "schema": { + "namespace": "component", + "object": "opacity", + "variant": "radio-button", + "subVariant": "disabled" + }, + "javascript": { + "name": "opacityRadioButtonDisabled", + "value": "0.5" + }, + "foundation": { + "name": "opacityRadioButtonDisabled", + "value": "none" + }, + "scss": { + "name": "opacityRadioButtonDisabled", + "value": "0.5" + } + }, "headingDisplayFontSize": { "type": "size", "deprecated": false, diff --git a/packages/orbit-design-tokens/output/tokens.css b/packages/orbit-design-tokens/output/tokens.css index 70b69c2970..ce302e1459 100644 --- a/packages/orbit-design-tokens/output/tokens.css +++ b/packages/orbit-design-tokens/output/tokens.css @@ -360,8 +360,12 @@ --button-info-foreground: rgb(255, 255, 255); --button-info-foreground-hover: rgb(255, 255, 255); --button-info-foreground-active: rgb(255, 255, 255); - --button-disabled-opacity: 30; --button-without-text-padding: 0; + --button-padding-x-small: 8; + --button-padding-small: 12; + --button-padding-normal: 16; + --button-padding-large: 24; + --button-padding-x-large: 28; --button-primary-subtle-background: rgb(225, 244, 243); --button-primary-subtle-background-hover: rgb(214, 240, 236); --button-primary-subtle-background-active: rgb(191, 232, 226); @@ -465,9 +469,6 @@ --font-size-heading-title-4: 16; --font-size-heading-title-5: 15; --font-size-heading-title-6: 13; - --opacity-button-disabled: 30; - --opacity-checkbox-disabled: 50; - --opacity-radio-button-disabled: 50; --border-style-card: solid; --border-style-input: solid; --border-width-card: 1; @@ -543,6 +544,8 @@ --form-element-label-filled: rgb(105, 125, 149); --form-element-prefix-foreground: rgb(105, 125, 149); --margin-top-form-feedback: 2; + --opacity-checkbox-disabled: 50; + --opacity-radio-button-disabled: 50; --heading-display-font-size: 40; --heading-display-font-weight: 700; --heading-display-line-height: 44; diff --git a/packages/orbit-design-tokens/output/tokens.less b/packages/orbit-design-tokens/output/tokens.less index 9945cd8339..5a220555f9 100644 --- a/packages/orbit-design-tokens/output/tokens.less +++ b/packages/orbit-design-tokens/output/tokens.less @@ -359,8 +359,12 @@ @button-info-foreground: rgb(255, 255, 255); @button-info-foreground-hover: rgb(255, 255, 255); @button-info-foreground-active: rgb(255, 255, 255); -@button-disabled-opacity: 30; @button-without-text-padding: 0; +@button-padding-x-small: 8; +@button-padding-small: 12; +@button-padding-normal: 16; +@button-padding-large: 24; +@button-padding-x-large: 28; @button-primary-subtle-background: rgb(225, 244, 243); @button-primary-subtle-background-hover: rgb(214, 240, 236); @button-primary-subtle-background-active: rgb(191, 232, 226); @@ -464,9 +468,6 @@ @font-size-heading-title-4: 16; @font-size-heading-title-5: 15; @font-size-heading-title-6: 13; -@opacity-button-disabled: 30; -@opacity-checkbox-disabled: 50; -@opacity-radio-button-disabled: 50; @border-style-card: solid; @border-style-input: solid; @border-width-card: 1; @@ -542,6 +543,8 @@ @form-element-label-filled: rgb(105, 125, 149); @form-element-prefix-foreground: rgb(105, 125, 149); @margin-top-form-feedback: 2; +@opacity-checkbox-disabled: 50; +@opacity-radio-button-disabled: 50; @heading-display-font-size: 40; @heading-display-font-weight: 700; @heading-display-line-height: 44; diff --git a/packages/orbit-design-tokens/output/tokens.scss b/packages/orbit-design-tokens/output/tokens.scss index f41cb38cf7..a8251636ae 100644 --- a/packages/orbit-design-tokens/output/tokens.scss +++ b/packages/orbit-design-tokens/output/tokens.scss @@ -370,8 +370,12 @@ $button-info-background-active: rgb(1, 80, 142); $button-info-foreground: rgb(255, 255, 255); $button-info-foreground-hover: rgb(255, 255, 255); $button-info-foreground-active: rgb(255, 255, 255); -$button-disabled-opacity: 0.3; $button-without-text-padding: 0; +$button-padding-x-small: 8px; +$button-padding-small: 12px; +$button-padding-normal: 16px; +$button-padding-large: 24px; +$button-padding-x-large: 28px; $button-primary-subtle-background: rgb(225, 244, 243); $button-primary-subtle-background-hover: rgb(214, 240, 236); $button-primary-subtle-background-active: rgb(191, 232, 226); @@ -475,9 +479,6 @@ $font-size-heading-title-3: 18px; $font-size-heading-title-4: 16px; $font-size-heading-title-5: 15px; $font-size-heading-title-6: 13px; -$opacity-button-disabled: 0.3; -$opacity-checkbox-disabled: 0.5; -$opacity-radio-button-disabled: 0.5; $border-style-card: solid; $border-style-input: solid; $border-width-card: 1px; @@ -555,6 +556,8 @@ $form-element-label-foreground: rgb(79, 94, 113); $form-element-label-filled: rgb(105, 125, 149); $form-element-prefix-foreground: rgb(105, 125, 149); $margin-top-form-feedback: 2px; +$opacity-checkbox-disabled: 0.5; +$opacity-radio-button-disabled: 0.5; $heading-display-font-size: 40px; $heading-display-font-weight: 700; $heading-display-line-height: 44px; diff --git a/packages/orbit-design-tokens/output/tokens.styl b/packages/orbit-design-tokens/output/tokens.styl index bf38be3439..2841a5d4fd 100644 --- a/packages/orbit-design-tokens/output/tokens.styl +++ b/packages/orbit-design-tokens/output/tokens.styl @@ -359,8 +359,12 @@ $button-info-background-active= rgb(1, 80, 142); $button-info-foreground= rgb(255, 255, 255); $button-info-foreground-hover= rgb(255, 255, 255); $button-info-foreground-active= rgb(255, 255, 255); -$button-disabled-opacity= 30; $button-without-text-padding= 0; +$button-padding-x-small= 8; +$button-padding-small= 12; +$button-padding-normal= 16; +$button-padding-large= 24; +$button-padding-x-large= 28; $button-primary-subtle-background= rgb(225, 244, 243); $button-primary-subtle-background-hover= rgb(214, 240, 236); $button-primary-subtle-background-active= rgb(191, 232, 226); @@ -464,9 +468,6 @@ $font-size-heading-title-3= 18; $font-size-heading-title-4= 16; $font-size-heading-title-5= 15; $font-size-heading-title-6= 13; -$opacity-button-disabled= 30; -$opacity-checkbox-disabled= 50; -$opacity-radio-button-disabled= 50; $border-style-card= solid; $border-style-input= solid; $border-width-card= 1; @@ -542,6 +543,8 @@ $form-element-label-foreground= rgb(79, 94, 113); $form-element-label-filled= rgb(105, 125, 149); $form-element-prefix-foreground= rgb(105, 125, 149); $margin-top-form-feedback= 2; +$opacity-checkbox-disabled= 50; +$opacity-radio-button-disabled= 50; $heading-display-font-size= 40; $heading-display-font-weight= 700; $heading-display-line-height= 44; diff --git a/packages/orbit-design-tokens/output/tokens.xml b/packages/orbit-design-tokens/output/tokens.xml index aff5c4bc25..8efad7cae5 100644 --- a/packages/orbit-design-tokens/output/tokens.xml +++ b/packages/orbit-design-tokens/output/tokens.xml @@ -1443,14 +1443,30 @@ buttonInfoForegroundActive #FFFFFF - - buttonDisabledOpacity - 30 - buttonWithoutTextPadding 0 + + buttonPaddingXSmall + 8 + + + buttonPaddingSmall + 12 + + + buttonPaddingNormal + 16 + + + buttonPaddingLarge + 24 + + + buttonPaddingXLarge + 28 + buttonPrimarySubtleBackground #E1F4F3 @@ -1863,18 +1879,6 @@ fontSizeHeadingTitle6 13 - - opacityButtonDisabled - 30 - - - opacityCheckboxDisabled - 50 - - - opacityRadioButtonDisabled - 50 - borderStyleCard solid @@ -2175,6 +2179,14 @@ marginTopFormFeedback 2 + + opacityCheckboxDisabled + 50 + + + opacityRadioButtonDisabled + 50 + headingDisplayFontSize 40 diff --git a/packages/orbit-design-tokens/src/__tests__/__snapshots__/index.test.ts.snap b/packages/orbit-design-tokens/src/__tests__/__snapshots__/index.test.ts.snap index e90ec12c28..e9250009b3 100644 --- a/packages/orbit-design-tokens/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/orbit-design-tokens/src/__tests__/__snapshots__/index.test.ts.snap @@ -232,7 +232,6 @@ exports[`defaultTokens should match snapshot 1`] = ` "buttonCriticalSubtleForeground": "#970C0C", "buttonCriticalSubtleForegroundActive": "#6D0909", "buttonCriticalSubtleForegroundHover": "#890B0B", - "buttonDisabledOpacity": "0.3", "buttonInfoBackground": "#0172CB", "buttonInfoBackgroundActive": "#01508E", "buttonInfoBackgroundHover": "#0161AC", @@ -267,6 +266,11 @@ exports[`defaultTokens should match snapshot 1`] = ` "buttonNormalLeftIconPadding": "0 16px 0 12px", "buttonNormalPadding": "0 16px", "buttonNormalRightIconPadding": "0 12px 0 16px", + "buttonPaddingLarge": "24px", + "buttonPaddingNormal": "16px", + "buttonPaddingSmall": "12px", + "buttonPaddingXLarge": "28px", + "buttonPaddingXSmall": "8px", "buttonPrimaryBackground": "#00A58E", "buttonPrimaryBackgroundActive": "#008472", "buttonPrimaryBackgroundHover": "#009580", @@ -626,7 +630,6 @@ exports[`defaultTokens should match snapshot 1`] = ` "modalSmallWidth": "540px", "modifierScaleButtonActive": 0.95, "modifierScaleCheckboxRadioActive": 0.95, - "opacityButtonDisabled": "0.3", "opacityCheckboxDisabled": "0.5", "opacityOverlay": "0.8", "opacityRadioButtonDisabled": "0.5", diff --git a/packages/orbit-design-tokens/src/__tests__/deprecatedTokens.test.ts b/packages/orbit-design-tokens/src/__tests__/deprecatedTokens.test.ts index a064eecaf6..dcc8b4d046 100644 --- a/packages/orbit-design-tokens/src/__tests__/deprecatedTokens.test.ts +++ b/packages/orbit-design-tokens/src/__tests__/deprecatedTokens.test.ts @@ -509,7 +509,6 @@ const oldTokens = () => { // category:Opacity // description: opacityOverlay: theme.base.opacityLarge, - opacityButtonDisabled: theme.base.opacitySmall, opacityRadioButtonDisabled: theme.base.opacityMedium, opacityCheckboxDisabled: theme.base.opacityMedium, // category:Font weight diff --git a/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-large-padding.json b/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-large-padding.json index 060186ca2b..50bcd890f4 100644 --- a/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-large-padding.json +++ b/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-large-padding.json @@ -11,7 +11,9 @@ "top-bottom": 0, "left-right": 28 } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" }, "both-icons-padding": { "type": "size", @@ -22,7 +24,9 @@ "top-bottom": 0, "left-right": "{foundation.space.medium}" } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" }, "left-icon-padding": { "type": "size", @@ -35,7 +39,9 @@ "bottom": 0, "left": "{foundation.space.medium}" } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" }, "right-icon-padding": { "type": "size", @@ -48,7 +54,9 @@ "bottom": 0, "left": 28 } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" } } }, diff --git a/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-normal-padding.json b/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-normal-padding.json index 107c9aa523..7ec87211d1 100644 --- a/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-normal-padding.json +++ b/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-normal-padding.json @@ -11,7 +11,9 @@ "top-bottom": 0, "left-right": "{foundation.space.medium}" } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" }, "both-icons-padding": { "type": "size", @@ -22,7 +24,9 @@ "top-bottom": 0, "left-right": "{foundation.space.small}" } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" }, "left-icon-padding": { "type": "size", @@ -35,7 +39,9 @@ "bottom": 0, "left": "{foundation.space.small}" } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" }, "right-icon-padding": { "type": "size", @@ -48,7 +54,9 @@ "bottom": 0, "left": "{foundation.space.medium}" } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" } } }, diff --git a/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-opacity.json b/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-opacity.json deleted file mode 100644 index 72b4165169..0000000000 --- a/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-opacity.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "component": { - "button": { - "disabled": { - "opacity": { - "type": "opacity", - "value": 30 - } - } - }, - "opacity": { - "button": { - "disabled": { - "type": "opacity", - "value": 30, - "deprecated": true, - "deprecated-replace": "{component.button.disabled.opacity}", - "deprecated-version": "6.0.0" - } - } - } - } -} diff --git a/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-padding.json b/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-padding.json index f7766b47ff..9dc7a706a3 100644 --- a/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-padding.json +++ b/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-padding.json @@ -6,6 +6,28 @@ "type": "size", "value": "0" } + }, + "padding": { + "x-small": { + "type": "size", + "value": "{foundation.space.x-small}" + }, + "small": { + "type": "size", + "value": "{foundation.space.small}" + }, + "normal": { + "type": "size", + "value": "{foundation.space.medium}" + }, + "large": { + "type": "size", + "value": "{foundation.space.large}" + }, + "x-large": { + "type": "size", + "value": 28 + } } }, "padding": { diff --git a/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-small-padding.json b/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-small-padding.json index c662234465..a5b544a0f1 100644 --- a/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-small-padding.json +++ b/packages/orbit-design-tokens/src/dictionary/definitions/component/button/button-small-padding.json @@ -11,7 +11,9 @@ "top-bottom": 0, "left-right": "{foundation.space.small}" } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" }, "both-icons-padding": { "type": "size", @@ -22,7 +24,9 @@ "top-bottom": 0, "left-right": "{foundation.space.x-small}" } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" }, "left-icon-padding": { "type": "size", @@ -35,7 +39,9 @@ "bottom": 0, "left": "{foundation.space.x-small}" } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" }, "right-icon-padding": { "type": "size", @@ -48,7 +54,9 @@ "bottom": 0, "left": "{foundation.space.small}" } - } + }, + "deprecated": true, + "deprecated-version": "6.0.0" } } }, diff --git a/packages/orbit-design-tokens/src/js/createTokens.ts b/packages/orbit-design-tokens/src/js/createTokens.ts index d5a2cdfd4e..3411657a67 100644 --- a/packages/orbit-design-tokens/src/js/createTokens.ts +++ b/packages/orbit-design-tokens/src/js/createTokens.ts @@ -375,8 +375,12 @@ export interface Tokens { buttonInfoForeground: string; buttonInfoForegroundHover: string; buttonInfoForegroundActive: string; - buttonDisabledOpacity: string; buttonWithoutTextPadding: string; + buttonPaddingXSmall: string; + buttonPaddingSmall: string; + buttonPaddingNormal: string; + buttonPaddingLarge: string; + buttonPaddingXLarge: string; buttonPrimarySubtleBackground: string; buttonPrimarySubtleBackgroundHover: string; buttonPrimarySubtleBackgroundActive: string; @@ -480,9 +484,6 @@ export interface Tokens { fontSizeHeadingTitle4: string; fontSizeHeadingTitle5: string; fontSizeHeadingTitle6: string; - opacityButtonDisabled: string; - opacityCheckboxDisabled: string; - opacityRadioButtonDisabled: string; borderStyleCard: string; borderStyleInput: string; borderWidthCard: string; @@ -558,6 +559,8 @@ export interface Tokens { formElementLabelFilledForeground: string; formElementPrefixForeground: string; marginTopFormFeedback: string; + opacityCheckboxDisabled: string; + opacityRadioButtonDisabled: string; headingDisplayFontSize: string; headingDisplayFontWeight: string; headingDisplayLineHeight: string; @@ -1230,8 +1233,12 @@ const createTokens: CreateTokens = foundation => ({ buttonInfoForeground: foundation.palette.white.normal, buttonInfoForegroundHover: foundation.palette.white.normal, buttonInfoForegroundActive: foundation.palette.white.normal, - buttonDisabledOpacity: "0.3", buttonWithoutTextPadding: "0", + buttonPaddingXSmall: foundation.space.XSmall, + buttonPaddingSmall: foundation.space.small, + buttonPaddingNormal: foundation.space.medium, + buttonPaddingLarge: foundation.space.large, + buttonPaddingXLarge: "28px", buttonPrimarySubtleBackground: foundation.palette.product.light, buttonPrimarySubtleBackgroundHover: foundation.palette.product.lightHover, buttonPrimarySubtleBackgroundActive: foundation.palette.product.lightActive, @@ -1341,9 +1348,6 @@ const createTokens: CreateTokens = foundation => ({ fontSizeHeadingTitle4: foundation.fontSize.large, fontSizeHeadingTitle5: foundation.fontSize.normal, fontSizeHeadingTitle6: foundation.fontSize.small, - opacityButtonDisabled: "0.3", - opacityCheckboxDisabled: "0.5", - opacityRadioButtonDisabled: "0.5", borderStyleCard: "solid", borderStyleInput: "solid", borderWidthCard: "1px", @@ -1447,6 +1451,8 @@ const createTokens: CreateTokens = foundation => ({ formElementLabelFilledForeground: foundation.palette.ink.light, formElementPrefixForeground: foundation.palette.ink.light, marginTopFormFeedback: foundation.space.XXXSmall, + opacityCheckboxDisabled: "0.5", + opacityRadioButtonDisabled: "0.5", headingDisplayFontSize: "40px", headingDisplayFontWeight: foundation.fontWeight.bold, headingDisplayLineHeight: "44px", diff --git a/packages/orbit-tailwind-preset/src/__tests__/helpers.test.ts b/packages/orbit-tailwind-preset/src/__tests__/helpers.test.ts index c1ca20e220..bc473d1c5b 100644 --- a/packages/orbit-tailwind-preset/src/__tests__/helpers.test.ts +++ b/packages/orbit-tailwind-preset/src/__tests__/helpers.test.ts @@ -202,9 +202,6 @@ describe("orbit-tailwind-preset", () => { expect(getComponentLevelToken("button", "background")).toMatchInlineSnapshot(` { - "button-bundle-basic-background": "linear-gradient(to top right, #E13E3B 0%, #E87E09 100%)", - "button-bundle-medium-background": "linear-gradient(to top right, #3719AB 0%, #8539DB 100%)", - "button-bundle-top-background": "linear-gradient(to top right, #2D2D2E 0%, #696E73 100%)", "button-critical-background": "#D21C1C", "button-critical-subtle-background": "#FAEAEA", "button-info-background": "#0172CB", @@ -222,9 +219,6 @@ describe("orbit-tailwind-preset", () => { expect(getComponentLevelToken("button", "backgroundHover")).toMatchInlineSnapshot(` { - "button-bundle-basic-background-hover": "linear-gradient(to top right, #BD2825 0%, #D67000 100%)", - "button-bundle-medium-background-hover": "linear-gradient(to top right, #2D1393 0%, #7343AA 100%)", - "button-bundle-top-background-hover": "linear-gradient(to top right, #171718 0%, #51575C 100%)", "button-critical-background-hover": "#B91919", "button-critical-subtle-background-hover": "#F8E2E2", "button-info-background-hover": "#0161AC", diff --git a/packages/orbit-tailwind-preset/src/presets/__tests__/__snapshots__/configs.test.ts.snap b/packages/orbit-tailwind-preset/src/presets/__tests__/__snapshots__/configs.test.ts.snap index 6a9d0f76db..8821f2d2e5 100644 --- a/packages/orbit-tailwind-preset/src/presets/__tests__/__snapshots__/configs.test.ts.snap +++ b/packages/orbit-tailwind-preset/src/presets/__tests__/__snapshots__/configs.test.ts.snap @@ -618,15 +618,6 @@ exports[`orbitPreset should match snapshot 1`] = ` "basic": "#D7331C", "medium": "#3B1EB0", }, - "button-bundle-basic-background": "linear-gradient(to top right, #E13E3B 0%, #E87E09 100%)", - "button-bundle-basic-background-active": "linear-gradient(to top right, #9F1816 0%, #C36802 100%)", - "button-bundle-basic-background-hover": "linear-gradient(to top right, #BD2825 0%, #D67000 100%)", - "button-bundle-medium-background": "linear-gradient(to top right, #3719AB 0%, #8539DB 100%)", - "button-bundle-medium-background-active": "linear-gradient(to top right, #250F79 0%, #5A3485 100%)", - "button-bundle-medium-background-hover": "linear-gradient(to top right, #2D1393 0%, #7343AA 100%)", - "button-bundle-top-background": "linear-gradient(to top right, #2D2D2E 0%, #696E73 100%)", - "button-bundle-top-background-active": "linear-gradient(to top right, #101011 0%, #51575C)", - "button-bundle-top-background-hover": "linear-gradient(to top right, #171718 0%, #51575C 100%)", "button-critical-background": "#D21C1C", "button-critical-background-active": "#9D1515", "button-critical-background-hover": "#B91919", @@ -775,6 +766,15 @@ exports[`orbitPreset should match snapshot 1`] = ` }, }, "backgroundImage": { + "button-bundle-basic-background": "linear-gradient(to top right, #E13E3B 0%, #E87E09 100%)", + "button-bundle-basic-background-active": "linear-gradient(to top right, #9F1816 0%, #C36802 100%)", + "button-bundle-basic-background-hover": "linear-gradient(to top right, #BD2825 0%, #D67000 100%)", + "button-bundle-medium-background": "linear-gradient(to top right, #3719AB 0%, #8539DB 100%)", + "button-bundle-medium-background-active": "linear-gradient(to top right, #250F79 0%, #5A3485 100%)", + "button-bundle-medium-background-hover": "linear-gradient(to top right, #2D1393 0%, #7343AA 100%)", + "button-bundle-top-background": "linear-gradient(to top right, #2D2D2E 0%, #696E73 100%)", + "button-bundle-top-background-active": "linear-gradient(to top right, #101011 0%, #51575C)", + "button-bundle-top-background-hover": "linear-gradient(to top right, #171718 0%, #51575C 100%)", "gradient-to-b": "linear-gradient(to bottom, var(--tw-gradient-stops))", "gradient-to-bl": "linear-gradient(to bottom left, var(--tw-gradient-stops))", "gradient-to-br": "linear-gradient(to bottom right, var(--tw-gradient-stops))", @@ -999,6 +999,9 @@ exports[`orbitPreset should match snapshot 1`] = ` "95": "0.95", }, "borderRadius": { + "button-circled-large": "52px", + "button-circled-normal": "44px", + "button-circled-small": "32px", "circle": "50%", "dialog-desktop": "9px", "dialog-mobile": "12px", @@ -1030,6 +1033,9 @@ exports[`orbitPreset should match snapshot 1`] = ` "boxShadow": { "action": "0 0 2px 0 rgba(37, 42, 49, 0.16),0 1px 4px 0 rgba(37, 42, 49, 0.12)", "action-active": "0 1px 4px 0 rgba(37, 42, 49, 0.16),0 4px 8px 0 rgba(37, 42, 49, 0.12)", + "button-active": "inset 0 0 6px 3px rgba(37, 42, 49, 0.15)", + "button-active-pale": "inset 0 0 6px 3px rgba(37, 42, 49, 0.08)", + "button-focus": "0 0 4px 1px rgba(1, 114, 203, 0.3)", "country-flag": "inset 0 0 0 1px rgba(37, 42, 49, 0.1)", "fixed": "0 0 2px 0 rgba(37, 42, 49, 0.16),0 2px 4px 0 rgba(37, 42, 49, 0.12)", "fixed-reverse": "0 0 2px 0 rgba(37, 42, 49, 0.16),0 -2px 4px 0 rgba(37, 42, 49, 0.12)", @@ -2525,6 +2531,11 @@ exports[`orbitPreset should match snapshot 1`] = ` "button-normal-left-icon-padding": "0 16px 0 12px", "button-normal-padding": "0 16px", "button-normal-right-icon-padding": "0 12px 0 16px", + "button-padding-lg": "24px", + "button-padding-md": "16px", + "button-padding-sm": "12px", + "button-padding-xl": "28px", + "button-padding-xs": "8px", "button-small-both-icons-padding": "0 8px", "button-small-left-icon-padding": "0 12px 0 8px", "button-small-padding": "0 12px", @@ -3556,6 +3567,9 @@ exports[`orbitPreset should match snapshot 1`] = ` "8/12": "66.666667%", "9/12": "75%", "auto": "auto", + "button-large": "52px", + "button-normal": "44px", + "button-small": "32px", "checkbox": "20px", "country-flag-medium": "24px", "country-flag-small": "16px", diff --git a/packages/orbit-tailwind-preset/src/presets/components/index.ts b/packages/orbit-tailwind-preset/src/presets/components/index.ts index 40a2f3b774..44fc472c85 100644 --- a/packages/orbit-tailwind-preset/src/presets/components/index.ts +++ b/packages/orbit-tailwind-preset/src/presets/components/index.ts @@ -1,5 +1,5 @@ import plugin from "tailwindcss/plugin"; -import { defaultTokens } from "@kiwicom/orbit-design-tokens"; +import { convertHexToRgba, defaultTokens } from "@kiwicom/orbit-design-tokens"; import type { Config } from "tailwindcss"; import orbitFoundationPreset from "../foundation"; @@ -151,6 +151,9 @@ const cfg = (options?: Options): Config => { "modal-normal-width": defaultTokens.modalNormalWidth, "modal-large-width": defaultTokens.modalLargeWidth, "modal-extra-large-width": defaultTokens.modalExtraLargeWidth, + "button-small": defaultTokens.heightButtonSmall, + "button-normal": defaultTokens.heightButtonNormal, + "button-large": defaultTokens.heightButtonLarge, checkbox: defaultTokens.widthCheckbox, "country-flag-small": defaultTokens.countryFlagSmallWidth, "country-flag-medium": defaultTokens.countryFlagMediumWidth, @@ -166,10 +169,18 @@ const cfg = (options?: Options): Config => { ...getComponentLevelToken("button", "padding"), ...getComponentLevelToken("formElement", "padding"), table: defaultTokens.paddingTable, + "button-padding-xs": defaultTokens.buttonPaddingXSmall, + "button-padding-sm": defaultTokens.buttonPaddingSmall, + "button-padding-md": defaultTokens.buttonPaddingNormal, + "button-padding-lg": defaultTokens.buttonPaddingLarge, + "button-padding-xl": defaultTokens.buttonPaddingXLarge, }, borderRadius: { "dialog-desktop": defaultTokens.dialogBorderRadiusDesktop, "dialog-mobile": defaultTokens.dialogBorderRadiusMobile, + "button-circled-small": defaultTokens.heightButtonSmall, + "button-circled-normal": defaultTokens.heightButtonNormal, + "button-circled-large": defaultTokens.heightButtonLarge, }, borderColor: { ...Object.keys(defaultTokens).reduce((acc, token) => { @@ -195,7 +206,28 @@ const cfg = (options?: Options): Config => { "form-element-focus": defaultTokens.formElementBorderColorFocus, "form-element-error": defaultTokens.formElementBorderColorError, }, + backgroundImage: { + "button-bundle-basic-background": defaultTokens.buttonBundleBasicBackground, + "button-bundle-basic-background-hover": defaultTokens.buttonBundleBasicBackgroundHover, + "button-bundle-basic-background-active": defaultTokens.buttonBundleBasicBackgroundActive, + "button-bundle-medium-background": defaultTokens.buttonBundleMediumBackground, + "button-bundle-medium-background-hover": defaultTokens.buttonBundleMediumBackgroundHover, + "button-bundle-medium-background-active": + defaultTokens.buttonBundleMediumBackgroundActive, + "button-bundle-top-background": defaultTokens.buttonBundleTopBackground, + "button-bundle-top-background-hover": defaultTokens.buttonBundleTopBackgroundHover, + "button-bundle-top-background-active": defaultTokens.buttonBundleTopBackgroundActive, + }, boxShadow: { + "button-focus": defaultTokens.boxShadowButtonFocus, + "button-active": `inset 0 0 6px 3px ${convertHexToRgba( + defaultTokens.paletteInkDark, + 15, + )}`, + "button-active-pale": `inset 0 0 6px 3px ${convertHexToRgba( + defaultTokens.paletteInkDark, + 8, + )}`, "country-flag": defaultTokens.countryFlagShadow, }, keyframes: { diff --git a/packages/orbit-tailwind-preset/src/presets/foundation/helpers.ts b/packages/orbit-tailwind-preset/src/presets/foundation/helpers.ts index e40c071fd7..32d72d2110 100644 --- a/packages/orbit-tailwind-preset/src/presets/foundation/helpers.ts +++ b/packages/orbit-tailwind-preset/src/presets/foundation/helpers.ts @@ -88,6 +88,11 @@ export const getComponentLevelToken = ( const t = type.toLowerCase(); if (k.startsWith(c) && k.endsWith(t)) { + // Button bundles are linear gradients + if (key.includes("buttonBundle")) { + return acc; + } + if (defaultTokens[key]) { acc[kebabCase(key)] = defaultTokens[key]; }