diff --git a/.changeset/button-redesign.md b/.changeset/button-redesign.md new file mode 100644 index 000000000..13df30f89 --- /dev/null +++ b/.changeset/button-redesign.md @@ -0,0 +1,6 @@ +--- +'@workflowbuilder/ui': major +'@workflowbuilder/sdk': minor +--- + +`Button` takes `variant`, `size` and `shape` and composes its content from `prefixIcon`, `children` and `suffixIcon`; the label/icon/icon+label subtypes and their prop types are gone. Migrate variants (`gray` and the former outlined `secondary` both become the solid grey `secondary` — reach for `ghost-secondary` where an outlined treatment should stay — `error` is `critical`, `ghost-destructive` is `ghost-critical`), sizes (`extra-large`…`extra-small` become `xl`…`xs`), and `shape="circle"` (now `"round"`). diff --git a/apps/docs/scripts/ui-components.mjs b/apps/docs/scripts/ui-components.mjs index 2ca13c574..8abe83075 100644 --- a/apps/docs/scripts/ui-components.mjs +++ b/apps/docs/scripts/ui-components.mjs @@ -12,13 +12,7 @@ export const COMPONENTS = [ { slug: 'accordion', name: 'Accordion', propsType: 'AccordionProps', dir: 'accordion' }, { slug: 'avatar', name: 'Avatar', propsType: 'AvatarProps', dir: 'avatar' }, - // No single props type - one of three variants depending on `children`. - { - slug: 'button', - name: 'Button', - propsType: ['LabelButtonProps', 'IconButtonProps', 'IconLabelButtonProps'], - dir: 'button', - }, + { slug: 'button', name: 'Button', propsType: ['LabelButtonProps', 'IconButtonProps'], dir: 'button' }, { slug: 'checkbox', name: 'Checkbox', propsType: 'CheckboxProps', dir: 'checkbox' }, { slug: 'chips', name: 'Chip', propsType: 'ChipProps', dir: 'chips' }, { slug: 'collapsible', name: 'Collapsible', propsType: 'CollapsibleProps', dir: 'collapsible' }, diff --git a/apps/docs/src/components/ui-examples/button.module.css b/apps/docs/src/components/ui-examples/button.module.css new file mode 100644 index 000000000..d97af383e --- /dev/null +++ b/apps/docs/src/components/ui-examples/button.module.css @@ -0,0 +1,11 @@ +.example { + display: flex; + flex-direction: column; + gap: var(--wb-space-150); +} + +.row { + display: flex; + flex-wrap: wrap; + gap: var(--wb-space-100); +} diff --git a/apps/docs/src/components/ui-examples/button.tsx b/apps/docs/src/components/ui-examples/button.tsx index c2e5a32e9..f869f3e63 100644 --- a/apps/docs/src/components/ui-examples/button.tsx +++ b/apps/docs/src/components/ui-examples/button.tsx @@ -1,11 +1,43 @@ +import { Plus, X } from '@phosphor-icons/react'; import { Button } from '@workflowbuilder/ui'; +import styles from './button.module.css'; + import { ComponentPreview } from './component-preview'; +const SOLID_VARIANTS = ['primary', 'secondary', 'critical', 'success', 'warning'] as const; +const GHOST_VARIANTS = [ + 'ghost-primary', + 'ghost-secondary', + 'ghost-critical', + 'ghost-success', + 'ghost-warning', +] as const; + export function ButtonExample() { return ( - +
+
+ {SOLID_VARIANTS.map((variant) => ( + + ))} +
+
+ {GHOST_VARIANTS.map((variant) => ( + + ))} +
+
+ +
+
); } diff --git a/apps/docs/src/content/docs/ui-library/ui-components/button.mdx b/apps/docs/src/content/docs/ui-library/ui-components/button.mdx index 7fa976bfb..37b03ef89 100644 --- a/apps/docs/src/content/docs/ui-library/ui-components/button.mdx +++ b/apps/docs/src/content/docs/ui-library/ui-components/button.mdx @@ -7,11 +7,8 @@ import CssVariablesTable from '../../../../components/api/css-variables-table.as import PropsTable from '../../../../components/api/props-table.astro'; import { ButtonExample } from '../../../../components/ui-examples/button'; -`Button` is a flexible, type-safe component that automatically selects the -correct type (label, icon, or icon + label) based on the structure of its -`children`. A single string renders a label button, a single React element -renders an icon button, and a string combined with icons renders an icon-label -button. +`Button` renders its label from `children` and accepts optional `prefixIcon` and +`suffixIcon` props. Use the `square` or `round` shape for icon-only buttons. diff --git a/packages/sdk/src/components/button-submit/button-submit.module.css b/packages/sdk/src/components/button-submit/button-submit.module.css index adf5e92d2..5ae36f913 100644 --- a/packages/sdk/src/components/button-submit/button-submit.module.css +++ b/packages/sdk/src/components/button-submit/button-submit.module.css @@ -10,8 +10,8 @@ --spinner-color: var(--wb-ui-text-onaccent-default); } -.container--ghost-destructive { - --spinner-color: var(--ax-public-button-ghost-destructive-color); +.container--ghost-critical { + --spinner-color: var(--ax-public-button-ghost-critical-color); } .container--pending button { diff --git a/packages/sdk/src/components/button-submit/button-submit.tsx b/packages/sdk/src/components/button-submit/button-submit.tsx index 57810ed7d..74d5d46ba 100644 --- a/packages/sdk/src/components/button-submit/button-submit.tsx +++ b/packages/sdk/src/components/button-submit/button-submit.tsx @@ -1,10 +1,10 @@ import { Spinner } from '@phosphor-icons/react'; -import { Button } from '@workflowbuilder/ui'; +import { Button, type LabelButtonProps } from '@workflowbuilder/ui'; import clsx from 'clsx'; import styles from './button-submit.module.css'; -type Props = Omit, 'children'> & { +type Props = Omit & { classNameWrapper?: string; isPending: boolean; children: React.ReactNode; @@ -22,7 +22,6 @@ export function ButtonSubmit({ classNameWrapper = '', isPending = false, childre classNameWrapper, )} > - {/* @ts-expect-error The rules for children are complex, and there is no easy way to pass them to a wrapper. */} {isPending && } diff --git a/packages/sdk/src/features/diagram/nodes/components/placeholder-button/placeholder-button.module.css b/packages/sdk/src/features/diagram/nodes/components/placeholder-button/placeholder-button.module.css index 44e0e4e7e..f8929ccf6 100644 --- a/packages/sdk/src/features/diagram/nodes/components/placeholder-button/placeholder-button.module.css +++ b/packages/sdk/src/features/diagram/nodes/components/placeholder-button/placeholder-button.module.css @@ -1,3 +1,3 @@ -.placeholder-button { +.placeholder-button::after { border-style: dashed; } diff --git a/packages/sdk/src/features/diagram/nodes/components/placeholder-button/placeholder-button.tsx b/packages/sdk/src/features/diagram/nodes/components/placeholder-button/placeholder-button.tsx index 02463a587..5be8e259f 100644 --- a/packages/sdk/src/features/diagram/nodes/components/placeholder-button/placeholder-button.tsx +++ b/packages/sdk/src/features/diagram/nodes/components/placeholder-button/placeholder-button.tsx @@ -1,16 +1,21 @@ import { PlusCircle } from '@phosphor-icons/react'; -import { Button } from '@workflowbuilder/ui'; +import { Button, type LabelButtonProps } from '@workflowbuilder/ui'; import styles from './placeholder-button.module.css'; type Props = { label: string; -} & Omit, 'children'>; +} & Omit; -export function PlaceholderButton({ label, size = 'extra-small', ...props }: Props) { +export function PlaceholderButton({ label, size = 'xs', ...props }: Props) { return ( - ); diff --git a/packages/sdk/src/features/integration/components/import-export/export-modal/export-modal.tsx b/packages/sdk/src/features/integration/components/import-export/export-modal/export-modal.tsx index db77b0809..0ac0af000 100644 --- a/packages/sdk/src/features/integration/components/import-export/export-modal/export-modal.tsx +++ b/packages/sdk/src/features/integration/components/import-export/export-modal/export-modal.tsx @@ -32,8 +32,7 @@ export function ExportModal() {
-
diff --git a/packages/sdk/src/features/integration/components/import-export/import-modal/import-modal.tsx b/packages/sdk/src/features/integration/components/import-export/import-modal/import-modal.tsx index 6f2710374..f92cf6261 100644 --- a/packages/sdk/src/features/integration/components/import-export/import-modal/import-modal.tsx +++ b/packages/sdk/src/features/integration/components/import-export/import-modal/import-modal.tsx @@ -69,13 +69,19 @@ export function ImportModal() { )}
{warnings.length > 0 && errors.length === 0 && ( - )} -
diff --git a/packages/sdk/src/features/json-form/controls/ai-tools-control/ai-tools-control.tsx b/packages/sdk/src/features/json-form/controls/ai-tools-control/ai-tools-control.tsx index cc11d8182..d2c4ef34c 100644 --- a/packages/sdk/src/features/json-form/controls/ai-tools-control/ai-tools-control.tsx +++ b/packages/sdk/src/features/json-form/controls/ai-tools-control/ai-tools-control.tsx @@ -1,6 +1,6 @@ import { PlusCircle, Trash } from '@phosphor-icons/react'; import { Button, NavButton } from '@workflowbuilder/ui'; -import { type ComponentProps, useCallback } from 'react'; +import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { Icon } from '@workflow-builder/icons'; @@ -57,8 +57,8 @@ function AiToolsControl({ path, handleChange, data, enabled, uischema }: AiTools const icon = toolOption?.icon; const label = toolOption?.label; - const sharedButtonProps: Partial> = { - variant: 'secondary', + const sharedButtonProps = { + variant: 'ghost-secondary' as const, className: styles['selected-tool-button'], onClick: () => openEditorModal(toolData), disabled: isDisabled, @@ -68,8 +68,7 @@ function AiToolsControl({ path, handleChange, data, enabled, uischema }: AiTools
{icon ? ( - ) : ( @@ -82,8 +81,7 @@ function AiToolsControl({ path, handleChange, data, enabled, uischema }: AiTools ); })} - diff --git a/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-form/conditions-form.tsx b/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-form/conditions-form.tsx index ccce534ff..fdd4dce6d 100644 --- a/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-form/conditions-form.tsx +++ b/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-form/conditions-form.tsx @@ -99,9 +99,15 @@ export const ConditionsForm = forwardRef ))}
- + -
diff --git a/packages/sdk/src/features/palette/components/footer/palette-footer.tsx b/packages/sdk/src/features/palette/components/footer/palette-footer.tsx index 872236283..499fb1a95 100644 --- a/packages/sdk/src/features/palette/components/footer/palette-footer.tsx +++ b/packages/sdk/src/features/palette/components/footer/palette-footer.tsx @@ -17,7 +17,7 @@ export function PaletteFooter({ onTemplateClick }: Props) { return (
- diff --git a/packages/sdk/src/features/properties-bar/components/properties-bar/properties-bar.tsx b/packages/sdk/src/features/properties-bar/components/properties-bar/properties-bar.tsx index 3099440c0..52c6c13ed 100644 --- a/packages/sdk/src/features/properties-bar/components/properties-bar/properties-bar.tsx +++ b/packages/sdk/src/features/properties-bar/components/properties-bar/properties-bar.tsx @@ -88,7 +88,7 @@ function PropertiesBarComponent({ } footer={ isExpanded && ( - ) diff --git a/packages/sdk/src/features/variables/modals/tab-global-variables/pane-list/pane-list.tsx b/packages/sdk/src/features/variables/modals/tab-global-variables/pane-list/pane-list.tsx index ab691e0c6..de6ffe2ab 100644 --- a/packages/sdk/src/features/variables/modals/tab-global-variables/pane-list/pane-list.tsx +++ b/packages/sdk/src/features/variables/modals/tab-global-variables/pane-list/pane-list.tsx @@ -31,8 +31,12 @@ export function PaneList({ className, setActivePane }: Props) { title="workflowsSettings.tab.globalVariables" description="workflowsSettings.tab.globalVariablesDescription" > - diff --git a/packages/sdk/src/features/variables/modals/tab-global-variables/pane-remove-variable/pane-remove-variable.tsx b/packages/sdk/src/features/variables/modals/tab-global-variables/pane-remove-variable/pane-remove-variable.tsx index 6e354f13c..2ed0fdc41 100644 --- a/packages/sdk/src/features/variables/modals/tab-global-variables/pane-remove-variable/pane-remove-variable.tsx +++ b/packages/sdk/src/features/variables/modals/tab-global-variables/pane-remove-variable/pane-remove-variable.tsx @@ -58,9 +58,9 @@ export function PaneRemoveVariable({ className, setActivePane, id }: Props) { {variable && (
0} > diff --git a/packages/sdk/src/features/variables/modals/tab-global-variables/variable-form/variable-form.tsx b/packages/sdk/src/features/variables/modals/tab-global-variables/variable-form/variable-form.tsx index 98a75d12d..dc5703e3d 100644 --- a/packages/sdk/src/features/variables/modals/tab-global-variables/variable-form/variable-form.tsx +++ b/packages/sdk/src/features/variables/modals/tab-global-variables/variable-form/variable-form.tsx @@ -123,7 +123,7 @@ export function VariableForm(props: Props) { />
- + {t(props.variant === 'add' ? 'workflowsSettings.tab.addVariable' : 'common.save')}
diff --git a/packages/ui/src/components/button/regular-button/button.tsx b/packages/ui/src/components/button/regular-button/button.tsx index 1667083d8..402685037 100644 --- a/packages/ui/src/components/button/regular-button/button.tsx +++ b/packages/ui/src/components/button/regular-button/button.tsx @@ -1,108 +1,76 @@ import clsx from 'clsx'; -import { ReactElement, forwardRef } from 'react'; +import { forwardRef } from 'react'; +import type { MouseEvent } from 'react'; import borderRadiusStyles from '../styles/border-radius.module.css'; +import fontSizeStyles from '../styles/font-size.module.css'; +import gapStyles from '../styles/gap.module.css'; +import heightStyles from '../styles/height.module.css'; +import iconPaddingStyles from '../styles/icon-padding.module.css'; +import iconSizeStyles from '../styles/icon-size.module.css'; +import paddingStyles from '../styles/padding.module.css'; import variantStyles from '../styles/variant.module.css'; +import loaderStyles from './loader.module.css'; -import { hasChildrenWithStringAndIcons, hasIconChildrenOnly, hasStringChildrenOnly } from '../guards'; -import { IconButton, IconButtonProps } from './icon-button/icon-button'; -import { IconLabelButton, IconLabelButtonProps } from './icon-label-button/icon-label-button'; -import { LabelButton, LabelButtonProps } from './label-button/label-button'; +import { BaseButton } from '../base-button/base-button'; +import type { ButtonProps } from './types'; -type WithRef = T & { - ref?: React.Ref; -}; +export const Button = forwardRef((props, ref) => { + const { + children, + className, + isLoading = false, + onClick, + prefixIcon, + shape = 'default', + size = 'm', + suffixIcon, + variant = 'primary', + ...rest + } = props; -/** - * ButtonProps defines **discriminated overloads** for the Button component using - * **structural discrimination** rather than a `type` field. - * - * The component dynamically determines which button variant to render based on the - * **structure of the `children` prop**: - * - * - If `children` is a single `string`, it's treated as a **Label Button**. - * - If `children` is a single icon (ReactElement), it's treated as an **Icon Button**. - * - If `children` includes both a string and one or two icons (before/after), - * it's treated as an **Icon Label Button**. - * - * Based on the inferred variant, **only props specific to that variant are allowed**. - * This ensures that incorrect prop combinations (e.g., passing label-specific props - * to an Icon Button) are caught at compile time. - * - * This is intentionally implemented with **overloads** instead of a union type, - * which would incorrectly allow mixing props between types and compromise type safety. - */ -type ButtonProps = { - (props: WithRef): ReactElement; - (props: WithRef): ReactElement; - (props: WithRef): ReactElement; -}; + const isIconOnly = shape !== 'default'; + const hiddenContentClassName = clsx({ [loaderStyles['hide-content']]: isLoading }); -const ButtonComponent = forwardRef( - ({ className, variant = 'primary', size = 'medium', ...props }, ref) => { - const buttonProps = { - ref, - ...props, - className: clsx(variantStyles[variant], borderRadiusStyles[size], className), - variant, - size, - }; - - if (hasStringChildrenOnly(props)) { - return {props.children}; - } - - if (hasIconChildrenOnly(props)) { - return {props.children}; + function handleClick(event: MouseEvent) { + if (isLoading) { + event.preventDefault(); + return; } + onClick?.(event); + } - if (hasChildrenWithStringAndIcons(props)) { - return {props.children}; - } - - // Unreachable for type-checked callers; guards dynamic children TS cannot see. - console.error( - 'Button: `children` did not match a supported variant (label, icon, or icon + label). Rendering nothing.', - ); - return null; - }, -); - -/** - * Button is a flexible, and type-safe component that automatically selects - * the correct type (Label Button, Icon Button, or Icon Label Button) based on the - * structure of its `children` prop. - * - * **Automatic Type Selection (Structural Discrimination)** - * The component uses the shape of `children` to infer which button variant to render: - * - **Label Button**: If `children` is a single `string` - * - **Icon Button**: If `children` is a single React element (e.g., an icon) - * - **Icon Label Button**: If `children` is a combination of string + icon(s) - * - * **Type Safety via Overloads** - * Each variant supports its own unique set of props. Thanks to TypeScript overloads, - * only the correct props for a given structure are allowed—invalid combinations - * are caught at compile time. - * - * **How to Use** - * - * ```tsx - * // Label Button - * - * // Icon Button - * - * // Icon Label Button - * ``` - * - * This approach ensures: - * - Simplified usage with fewer props - * - No accidental mixing of incompatible props - * - Autocomplete and type-checking experience - */ -export const Button = ButtonComponent as ButtonProps; + return ( + + {isIconOnly ? ( + {prefixIcon} + ) : ( + <> + {prefixIcon != null && ( + {prefixIcon} + )} + {children} + {suffixIcon != null && ( + {suffixIcon} + )} + + )} + {isLoading && } + + ); +}); diff --git a/packages/ui/src/components/button/regular-button/icon-button/icon-button.tsx b/packages/ui/src/components/button/regular-button/icon-button/icon-button.tsx deleted file mode 100644 index 55402c84e..000000000 --- a/packages/ui/src/components/button/regular-button/icon-button/icon-button.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import clsx from 'clsx'; -import { forwardRef } from 'react'; - -import borderRadiusStyles from '../../styles/border-radius.module.css'; -import iconPaddingStyles from '../../styles/icon-padding.module.css'; -import iconSizeStyles from '../../styles/icon-size.module.css'; - -import { BaseButton } from '../../base-button/base-button'; -import { IconNode, Shape } from '../../types'; -import { BaseRegularButtonProps } from '../types'; - -export type IconButtonProps = { - shape?: Shape; - children: IconNode; -} & BaseRegularButtonProps; - -export const IconButton = forwardRef( - ({ size = 'medium', shape = 'default', children, ...props }, ref) => ( - - {children} - - ), -); diff --git a/packages/ui/src/components/button/regular-button/icon-label-button/icon-label-button.tsx b/packages/ui/src/components/button/regular-button/icon-label-button/icon-label-button.tsx deleted file mode 100644 index ec53f6a4e..000000000 --- a/packages/ui/src/components/button/regular-button/icon-label-button/icon-label-button.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import clsx from 'clsx'; -import { forwardRef } from 'react'; - -import fontSizeStyles from '../../styles/font-size.module.css'; -import gapStyles from '../../styles/gap.module.css'; -import paddingStyles from '../../styles/icon-label-button-padding.module.css'; -import iconSizeStyles from '../../styles/icon-size.module.css'; - -import { BaseButton } from '../../base-button/base-button'; -import { IconNode } from '../../types'; -import { BaseRegularButtonProps } from '../types'; - -export type IconLabelButtonProps = { - children: [IconNode, string] | [string, IconNode] | [IconNode, string, IconNode]; -} & BaseRegularButtonProps; - -export const IconLabelButton = forwardRef( - ({ size = 'medium', children, ...props }, ref) => ( - - {children} - - ), -); diff --git a/packages/ui/src/components/button/regular-button/label-button/label-button.tsx b/packages/ui/src/components/button/regular-button/label-button/label-button.tsx deleted file mode 100644 index ab0041b7b..000000000 --- a/packages/ui/src/components/button/regular-button/label-button/label-button.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import clsx from 'clsx'; -import { forwardRef } from 'react'; - -import fontSizeStyles from '../../styles/font-size.module.css'; -import paddingStyles from '../../styles/label-button-padding.module.css'; -import loaderStyles from './loader.module.css'; - -import { BaseButton } from '../../base-button/base-button'; -import { BaseRegularButtonProps } from '../types'; - -export type LabelButtonProps = { - isLoading?: boolean; - children: string; -} & BaseRegularButtonProps; - -export const LabelButton = forwardRef( - ({ size = 'medium', isLoading, children, ...props }, ref) => ( - - {{children}} - {isLoading && } - - ), -); diff --git a/packages/ui/src/components/button/regular-button/label-button/loader.module.css b/packages/ui/src/components/button/regular-button/loader.module.css similarity index 93% rename from packages/ui/src/components/button/regular-button/label-button/loader.module.css rename to packages/ui/src/components/button/regular-button/loader.module.css index f4370f8a3..f2aa8ae00 100644 --- a/packages/ui/src/components/button/regular-button/label-button/loader.module.css +++ b/packages/ui/src/components/button/regular-button/loader.module.css @@ -1,7 +1,7 @@ :root { --ax-public-button-loader-dot-size: 0.3125rem; --ax-public-button-loader-dot-border-radius: 0.3125rem; - --ax-public-button-loader-dot-color: var(--wb-ui-text-onaccent-default); + --ax-public-button-loader-dot-color: currentColor; --ax-public-button-loader-animation-duration: 0.75s; } @@ -10,7 +10,7 @@ pointer-events: none; } - .hide-label { + .hide-content { opacity: 0; } @@ -51,6 +51,7 @@ 0% { opacity: 1; } + 100% { opacity: 0.2; } diff --git a/packages/ui/src/components/button/regular-button/types.ts b/packages/ui/src/components/button/regular-button/types.ts index c18dc4bdf..31bb89162 100644 --- a/packages/ui/src/components/button/regular-button/types.ts +++ b/packages/ui/src/components/button/regular-button/types.ts @@ -1,24 +1,57 @@ -import { SIZES, Size } from '../../../shared/types/size'; -import { rangeBetween } from '../../../shared/utils/arrays'; -import { BaseButtonProps } from '../types'; +import type { ButtonHTMLAttributes, ReactNode } from 'react'; + +import type { TooltipVariant } from '../../tooltip/types'; export const BUTTON_VARIANTS = [ 'primary', 'secondary', - 'gray', - 'error', - 'warning', + 'critical', 'success', - 'ghost-destructive', + 'warning', + 'ghost-primary', + 'ghost-secondary', + 'ghost-critical', + 'ghost-success', + 'ghost-warning', ] as const; -export const BUTTON_SIZES = rangeBetween(SIZES, 'extra-small', 'extra-large'); +export type ButtonVariant = (typeof BUTTON_VARIANTS)[number]; + +export const BUTTON_SIZES = ['xl', 'l', 'm', 's', 'xs'] as const; -export type ButtonSize = Extract; +export type ButtonSize = (typeof BUTTON_SIZES)[number]; -export type Variant = (typeof BUTTON_VARIANTS)[number]; +export const BUTTON_SHAPES = ['default', 'square', 'round'] as const; -export type BaseRegularButtonProps = BaseButtonProps & { - variant?: Variant; +export type ButtonShape = (typeof BUTTON_SHAPES)[number]; + +export type LabelButtonProps = { + /** @default 'primary' */ + variant?: ButtonVariant; + /** @default 'm' */ + size?: ButtonSize; + /** @default 'default' */ + shape?: 'default'; + children: ReactNode; + prefixIcon?: ReactNode; + suffixIcon?: ReactNode; + isLoading?: boolean; + tooltip?: string; + tooltipType?: TooltipVariant; +} & Omit, 'children'>; + +export type IconButtonProps = { + /** @default 'primary' */ + variant?: ButtonVariant; + /** @default 'm' */ size?: ButtonSize; -}; + shape: 'square' | 'round'; + prefixIcon: ReactNode; + children?: never; + suffixIcon?: never; + isLoading?: boolean; + tooltip?: string; + tooltipType?: TooltipVariant; +} & Omit, 'children'>; + +export type ButtonProps = LabelButtonProps | IconButtonProps; diff --git a/packages/ui/src/components/button/styles/border-radius.module.css b/packages/ui/src/components/button/styles/border-radius.module.css index acec76951..379f7258d 100644 --- a/packages/ui/src/components/button/styles/border-radius.module.css +++ b/packages/ui/src/components/button/styles/border-radius.module.css @@ -6,6 +6,12 @@ --ax-public-button-border-radius-extra-small: var(--wb-radius-50); --ax-public-button-border-radius-circle: var(--wb-radius-full); + --ax-public-button-border-radius-xl: var(--wb-radius-100); + --ax-public-button-border-radius-l: var(--wb-radius-100); + --ax-public-button-border-radius-m: var(--wb-radius-75); + --ax-public-button-border-radius-s: var(--wb-radius-50); + --ax-public-button-border-radius-xs: var(--wb-radius-50); + --ax-public-button-border-radius-round: var(--wb-radius-full); } @layer ui.component { @@ -34,4 +40,28 @@ .circle { border-radius: var(--ax-public-button-border-radius-circle); } + + .xl { + border-radius: var(--ax-public-button-border-radius-xl); + } + + .l { + border-radius: var(--ax-public-button-border-radius-l); + } + + .m { + border-radius: var(--ax-public-button-border-radius-m); + } + + .s { + border-radius: var(--ax-public-button-border-radius-s); + } + + .xs { + border-radius: var(--ax-public-button-border-radius-xs); + } + + .round { + border-radius: var(--ax-public-button-border-radius-round); + } } diff --git a/packages/ui/src/components/button/styles/font-size.module.css b/packages/ui/src/components/button/styles/font-size.module.css index e65ebb472..54e58bad6 100644 --- a/packages/ui/src/components/button/styles/font-size.module.css +++ b/packages/ui/src/components/button/styles/font-size.module.css @@ -12,4 +12,18 @@ .extra-small { composes: ax-public-button-small from global; } + + .xl { + composes: wb-text-label-xl-emphasized from global; + } + + .l { + composes: wb-text-label-l-emphasized from global; + } + + .m, + .s, + .xs { + composes: wb-text-label-m-emphasized from global; + } } diff --git a/packages/ui/src/components/button/styles/gap.module.css b/packages/ui/src/components/button/styles/gap.module.css index 05b4f5a54..3de98bdf6 100644 --- a/packages/ui/src/components/button/styles/gap.module.css +++ b/packages/ui/src/components/button/styles/gap.module.css @@ -4,6 +4,11 @@ --ax-public-button-gap-medium: var(--wb-space-100); --ax-public-button-gap-small: var(--wb-space-100); --ax-public-button-gap-extra-small: var(--wb-space-100); + --ax-public-button-gap-xl: var(--wb-space-100); + --ax-public-button-gap-l: var(--wb-space-100); + --ax-public-button-gap-m: var(--wb-space-100); + --ax-public-button-gap-s: var(--wb-space-100); + --ax-public-button-gap-xs: var(--wb-space-100); } @layer ui.component { @@ -26,4 +31,24 @@ .extra-small { gap: var(--ax-public-button-gap-extra-small); } + + .xl { + gap: var(--ax-public-button-gap-xl); + } + + .l { + gap: var(--ax-public-button-gap-l); + } + + .m { + gap: var(--ax-public-button-gap-m); + } + + .s { + gap: var(--ax-public-button-gap-s); + } + + .xs { + gap: var(--ax-public-button-gap-xs); + } } diff --git a/packages/ui/src/components/button/styles/height.module.css b/packages/ui/src/components/button/styles/height.module.css new file mode 100644 index 000000000..abbb43307 --- /dev/null +++ b/packages/ui/src/components/button/styles/height.module.css @@ -0,0 +1,29 @@ +:root { + --ax-public-button-height-xl: var(--wb-size-600); + --ax-public-button-height-l: 2.625rem; + --ax-public-button-height-m: 2.25rem; + --ax-public-button-height-s: var(--wb-size-400); + --ax-public-button-height-xs: 1.75rem; +} + +@layer ui.component { + .xl { + height: var(--ax-public-button-height-xl); + } + + .l { + height: var(--ax-public-button-height-l); + } + + .m { + height: var(--ax-public-button-height-m); + } + + .s { + height: var(--ax-public-button-height-s); + } + + .xs { + height: var(--ax-public-button-height-xs); + } +} diff --git a/packages/ui/src/components/button/styles/icon-padding.module.css b/packages/ui/src/components/button/styles/icon-padding.module.css index fd139eafe..8d41c9cbe 100644 --- a/packages/ui/src/components/button/styles/icon-padding.module.css +++ b/packages/ui/src/components/button/styles/icon-padding.module.css @@ -4,6 +4,11 @@ --ax-public-button-icon-padding-medium: var(--wb-space-112); --ax-public-button-icon-padding-small: var(--wb-space-87); --ax-public-button-icon-padding-extra-small: var(--wb-space-75); + --ax-public-button-icon-padding-xl: var(--wb-space-150); + --ax-public-button-icon-padding-l: var(--wb-space-137); + --ax-public-button-icon-padding-m: var(--wb-space-112); + --ax-public-button-icon-padding-s: var(--wb-space-87); + --ax-public-button-icon-padding-xs: var(--wb-space-75); } @layer ui.component { @@ -26,4 +31,24 @@ .extra-small { padding: var(--ax-public-button-icon-padding-extra-small); } + + .xl { + padding: var(--ax-public-button-icon-padding-xl); + } + + .l { + padding: var(--ax-public-button-icon-padding-l); + } + + .m { + padding: var(--ax-public-button-icon-padding-m); + } + + .s { + padding: var(--ax-public-button-icon-padding-s); + } + + .xs { + padding: var(--ax-public-button-icon-padding-xs); + } } diff --git a/packages/ui/src/components/button/styles/icon-size.module.css b/packages/ui/src/components/button/styles/icon-size.module.css index e965778ff..c62e35052 100644 --- a/packages/ui/src/components/button/styles/icon-size.module.css +++ b/packages/ui/src/components/button/styles/icon-size.module.css @@ -4,6 +4,11 @@ --ax-public-icon-size-medium: 1.125rem /* missing token */; --ax-public-icon-size-small: 1.125rem /* missing token */; --ax-public-icon-size-extra-small: 1rem /* missing token */; + --ax-public-icon-size-xl: var(--wb-size-300); + --ax-public-icon-size-l: calc(var(--wb-size-300) - var(--wb-space-50)); + --ax-public-icon-size-m: calc(var(--wb-size-300) - var(--wb-space-75)); + --ax-public-icon-size-s: calc(var(--wb-size-300) - var(--wb-space-75)); + --ax-public-icon-size-xs: var(--wb-size-200); } @layer ui.component { @@ -41,4 +46,41 @@ height: var(--ax-public-icon-size-extra-small); } } + + .icon { + display: flex; + flex: none; + align-items: center; + justify-content: center; + + svg { + width: 100%; + height: 100%; + } + } + + .xl > .icon { + width: var(--ax-public-icon-size-xl); + height: var(--ax-public-icon-size-xl); + } + + .l > .icon { + width: var(--ax-public-icon-size-l); + height: var(--ax-public-icon-size-l); + } + + .m > .icon { + width: var(--ax-public-icon-size-m); + height: var(--ax-public-icon-size-m); + } + + .s > .icon { + width: var(--ax-public-icon-size-s); + height: var(--ax-public-icon-size-s); + } + + .xs > .icon { + width: var(--ax-public-icon-size-xs); + height: var(--ax-public-icon-size-xs); + } } diff --git a/packages/ui/src/components/button/styles/padding.module.css b/packages/ui/src/components/button/styles/padding.module.css new file mode 100644 index 000000000..d9d478802 --- /dev/null +++ b/packages/ui/src/components/button/styles/padding.module.css @@ -0,0 +1,29 @@ +:root { + --ax-public-button-padding-xl: var(--wb-space-200) var(--wb-space-200); + --ax-public-button-padding-l: var(--wb-space-175) var(--wb-space-200); + --ax-public-button-padding-m: var(--wb-space-150) var(--wb-space-150); + --ax-public-button-padding-s: var(--wb-space-125) var(--wb-space-125); + --ax-public-button-padding-xs: var(--wb-space-100) var(--wb-space-100); +} + +@layer ui.component { + .xl { + padding: var(--ax-public-button-padding-xl); + } + + .l { + padding: var(--ax-public-button-padding-l); + } + + .m { + padding: var(--ax-public-button-padding-m); + } + + .s { + padding: var(--ax-public-button-padding-s); + } + + .xs { + padding: var(--ax-public-button-padding-xs); + } +} diff --git a/packages/ui/src/components/button/styles/variant.module.css b/packages/ui/src/components/button/styles/variant.module.css index 067629d4e..3b3c6ac50 100644 --- a/packages/ui/src/components/button/styles/variant.module.css +++ b/packages/ui/src/components/button/styles/variant.module.css @@ -1,180 +1,290 @@ :root { - --ax-public-button-border-size: 0.0625rem; + --ax-public-button-border-size: var(--wb-size-12); --ax-public-button-primary-background: var(--wb-components-button-solid-primary-default); --ax-public-button-primary-background-hover: var(--wb-components-button-solid-primary-hover); --ax-public-button-primary-background-active: var(--wb-components-button-solid-primary-active); --ax-public-button-primary-background-focus: var(--wb-components-button-solid-primary-focus); - - --ax-public-button-secondary-border-color: var(--wb-ui-stroke-subtle); - --ax-public-button-secondary-color: var(--wb-ui-text-default); - --ax-public-button-secondary-border-color-hover: var(--wb-ui-stroke-focus); - --ax-public-button-secondary-color-active: var(--wb-ui-text-subtle-default); - --ax-public-button-secondary-border-color-active: var(--wb-ui-stroke-focus); - --ax-public-button-secondary-border-color-focus: var(--wb-ui-stroke-focus); - --ax-public-button-secondary-border-color-disabled: var(--wb-ui-stroke-subtle); - --ax-public-button-secondary-color-disabled: var(--wb-ui-text-ghost-default); - - --ax-public-button-ghost-destructive-background-color: var(--wb-components-button-ghost-critical-default); - --ax-public-button-ghost-destructive-border-color: var(--wb-components-button-ghost-critical-stroke-default); - --ax-public-button-ghost-destructive-color: var(--wb-ui-text-critical-default); - --ax-public-button-ghost-destructive-background-color-hover: var(--wb-components-button-ghost-critical-hover); - --ax-public-button-ghost-destructive-background-color-active: var(--wb-components-button-ghost-critical-active); - --ax-public-button-ghost-destructive-background-color-focus: var(--wb-components-button-ghost-critical-focus); - --ax-public-button-ghost-destructive-background-color-disabled: var(--wb-components-button-ghost-critical-disabled); - --ax-public-button-ghost-destructive-color-disabled: var(--wb-ui-text-critical-disabled); - - --ax-public-button-gray-background: var(--wb-components-button-solid-gray-default); - --ax-public-button-gray-background-hover: var(--wb-components-button-solid-gray-hover); - --ax-public-button-gray-background-active: var(--wb-components-button-solid-gray-active); - --ax-public-button-gray-background-focus: var(--wb-components-button-solid-gray-focus); - - --ax-public-button-error-background: var(--wb-components-button-solid-critical-default); - --ax-public-button-error-background-hover: var(--wb-components-button-solid-critical-hover); - --ax-public-button-error-background-active: var(--wb-components-button-solid-critical-active); - --ax-public-button-error-background-focus: var(--wb-components-button-solid-critical-focus); + --ax-public-button-primary-background-disabled: var(--wb-components-button-solid-disabled); + --ax-public-button-primary-color: var(--wb-ui-text-onaccent-default); + --ax-public-button-primary-color-disabled: var(--wb-ui-text-disabled); + + --ax-public-button-secondary-background: var(--wb-components-button-solid-gray-default); + --ax-public-button-secondary-background-hover: var(--wb-components-button-solid-gray-hover); + --ax-public-button-secondary-background-active: var(--wb-components-button-solid-gray-active); + --ax-public-button-secondary-background-focus: var(--wb-components-button-solid-gray-focus); + --ax-public-button-secondary-background-disabled: var(--wb-components-button-solid-disabled); + --ax-public-button-secondary-color: var(--wb-ui-text-onaccent-default); + --ax-public-button-secondary-color-disabled: var(--wb-ui-text-disabled); + + --ax-public-button-critical-background: var(--wb-components-button-solid-critical-default); + --ax-public-button-critical-background-hover: var(--wb-components-button-solid-critical-hover); + --ax-public-button-critical-background-active: var(--wb-components-button-solid-critical-active); + --ax-public-button-critical-background-focus: var(--wb-components-button-solid-critical-focus); + --ax-public-button-critical-background-disabled: var(--wb-components-button-solid-disabled); + --ax-public-button-critical-color: var(--wb-ui-text-onaccent-default); + --ax-public-button-critical-color-disabled: var(--wb-ui-text-disabled); --ax-public-button-success-background: var(--wb-components-button-solid-success-default); --ax-public-button-success-background-hover: var(--wb-components-button-solid-success-hover); --ax-public-button-success-background-active: var(--wb-components-button-solid-success-active); --ax-public-button-success-background-focus: var(--wb-components-button-solid-success-focus); + --ax-public-button-success-background-disabled: var(--wb-components-button-solid-disabled); + --ax-public-button-success-color: var(--wb-ui-text-onaccent-default); + --ax-public-button-success-color-disabled: var(--wb-ui-text-disabled); --ax-public-button-warning-background: var(--wb-components-button-solid-warning-default); --ax-public-button-warning-background-hover: var(--wb-components-button-solid-warning-hover); --ax-public-button-warning-background-active: var(--wb-components-button-solid-warning-active); --ax-public-button-warning-background-focus: var(--wb-components-button-solid-warning-focus); + --ax-public-button-warning-background-disabled: var(--wb-components-button-solid-disabled); + --ax-public-button-warning-color: var(--wb-ui-text-onaccent-default); + --ax-public-button-warning-color-disabled: var(--wb-ui-text-disabled); + + --ax-public-button-ghost-primary-background-color: var(--wb-components-button-ghost-primary-default); + --ax-public-button-ghost-primary-background-color-hover: var(--wb-components-button-ghost-primary-hover); + --ax-public-button-ghost-primary-background-color-active: var(--wb-components-button-ghost-primary-active); + --ax-public-button-ghost-primary-background-color-focus: var(--wb-components-button-ghost-primary-focus); + --ax-public-button-ghost-primary-background-color-disabled: var(--wb-components-button-ghost-primary-disabled); + --ax-public-button-ghost-primary-border-color: var(--wb-components-button-ghost-primary-stroke-default); + --ax-public-button-ghost-primary-color: var(--wb-ui-text-action-default); + --ax-public-button-ghost-primary-color-disabled: var(--wb-ui-text-action-disabled); + + --ax-public-button-ghost-secondary-background-color: var(--wb-colors-transparent); + --ax-public-button-ghost-secondary-background-color-hover: var(--wb-colors-transparent); + --ax-public-button-ghost-secondary-background-color-active: var(--wb-colors-transparent); + --ax-public-button-ghost-secondary-background-color-focus: var(--wb-colors-transparent); + --ax-public-button-ghost-secondary-background-color-disabled: var(--wb-colors-transparent); + --ax-public-button-ghost-secondary-border-color: var(--wb-ui-stroke-subtle); + --ax-public-button-ghost-secondary-border-color-hover: var(--wb-colors-gray-500); + --ax-public-button-ghost-secondary-border-color-active: var(--wb-colors-gray-500); + --ax-public-button-ghost-secondary-border-color-focus: var(--wb-colors-gray-500); + --ax-public-button-ghost-secondary-border-color-disabled: var(--wb-ui-stroke-subtle); + --ax-public-button-ghost-secondary-color: var(--wb-ui-text-default); + --ax-public-button-ghost-secondary-color-disabled: var(--wb-ui-text-ghost-default); + + --ax-public-button-ghost-critical-background-color: var(--wb-components-button-ghost-critical-default); + --ax-public-button-ghost-critical-background-color-hover: var(--wb-components-button-ghost-critical-hover); + --ax-public-button-ghost-critical-background-color-active: var(--wb-components-button-ghost-critical-active); + --ax-public-button-ghost-critical-background-color-focus: var(--wb-components-button-ghost-critical-focus); + --ax-public-button-ghost-critical-background-color-disabled: var(--wb-components-button-ghost-critical-disabled); + --ax-public-button-ghost-critical-border-color: var(--wb-components-button-ghost-critical-stroke-default); + --ax-public-button-ghost-critical-color: var(--wb-ui-text-critical-default); + --ax-public-button-ghost-critical-color-disabled: var(--wb-ui-text-critical-disabled); + + --ax-public-button-ghost-success-background-color: var(--wb-components-button-ghost-success-default); + --ax-public-button-ghost-success-background-color-hover: var(--wb-components-button-ghost-success-hover); + --ax-public-button-ghost-success-background-color-active: var(--wb-components-button-ghost-success-active); + --ax-public-button-ghost-success-background-color-focus: var(--wb-components-button-ghost-success-focus); + --ax-public-button-ghost-success-background-color-disabled: var(--wb-components-button-ghost-success-disabled); + --ax-public-button-ghost-success-border-color: var(--wb-components-button-ghost-success-stroke-default); + --ax-public-button-ghost-success-color: var(--wb-ui-text-success-default); + --ax-public-button-ghost-success-color-disabled: var(--wb-ui-text-success-disabled); + + --ax-public-button-ghost-warning-background-color: var(--wb-components-button-ghost-warning-default); + --ax-public-button-ghost-warning-background-color-hover: var(--wb-components-button-ghost-warning-hover); + --ax-public-button-ghost-warning-background-color-active: var(--wb-components-button-ghost-warning-active); + --ax-public-button-ghost-warning-background-color-focus: var(--wb-components-button-ghost-warning-focus); + --ax-public-button-ghost-warning-background-color-disabled: var(--wb-components-button-ghost-warning-disabled); + --ax-public-button-ghost-warning-border-color: var(--wb-components-button-ghost-warning-stroke-default); + --ax-public-button-ghost-warning-color: var(--wb-ui-text-warning-default); + --ax-public-button-ghost-warning-color-disabled: var(--wb-ui-text-warning-disabled); } @layer ui.component { - button { - &:not(:disabled) { - &.primary { - background-color: var(--ax-public-button-primary-background); - - &:hover { - background-color: var(--ax-public-button-primary-background-hover); - } - - &:active { - background-color: var(--ax-public-button-primary-background-active); - } - - &:focus-visible { - background-color: var(--ax-public-button-primary-background-focus); - } - } - - &.secondary { - border: var(--ax-public-button-border-size) solid var(--ax-public-button-secondary-border-color); - background-color: transparent; - color: var(--ax-public-button-secondary-color); - - &:hover { - border-color: var(--ax-public-button-secondary-border-color-hover); - } - - &:active { - border-color: var(--ax-public-button-secondary-border-color-active); - color: var(--ax-public-button-secondary-color-active); - } - - &:focus-visible { - border-color: var(--ax-public-button-secondary-border-color-focus); - } - - &:disabled { - border-color: var(--ax-public-button-secondary-border-color-disabled); - color: var(--ax-public-button-secondary-color-disabled); - } - } - - &.ghost-destructive { - border: var(--ax-public-button-border-size) solid var(--ax-public-button-ghost-destructive-border-color); - background-color: var(--ax-public-button-ghost-destructive-background-color); - color: var(--ax-public-button-ghost-destructive-color); - - &:hover { - background-color: var(--ax-public-button-ghost-destructive-background-color-hover); - } - - &:active { - background-color: var(--ax-public-button-ghost-destructive-background-color-active); - } - - &:focus-visible { - background-color: var(--ax-public-button-ghost-destructive-background-color-focus); - border-width: 2px; - } - - &:disabled { - background-color: var(--ax-public-button-ghost-destructive-background-color-disabled); - color: var(--ax-public-button-ghost-destructive-color-disabled); - } - } - - &.gray { - background-color: var(--ax-public-button-gray-background); - - &:hover { - background-color: var(--ax-public-button-gray-background-hover); - } - - &:active { - background-color: var(--ax-public-button-gray-background-active); - } - - &:focus-visible { - background-color: var(--ax-public-button-gray-background-focus); - } - } - - &.error { - background-color: var(--ax-public-button-error-background); - - &:hover { - background-color: var(--ax-public-button-error-background-hover); - } - - &:active { - background-color: var(--ax-public-button-error-background-active); - } - - &:focus-visible { - background-color: var(--ax-public-button-error-background-focus); - } - } - - &.success { - background-color: var(--ax-public-button-success-background); - - &:hover { - background-color: var(--ax-public-button-success-background-hover); - } - - &:active { - background-color: var(--ax-public-button-success-background-active); - } - - &:focus-visible { - background-color: var(--ax-public-button-success-background-focus); - } - } - - &.warning { - background-color: var(--ax-public-button-warning-background); - - &:hover { - background-color: var(--ax-public-button-warning-background-hover); - } - - &:active { - background-color: var(--ax-public-button-warning-background-active); - } - - &:focus-visible { - background-color: var(--ax-public-button-warning-background-focus); - } - } + .primary { + --button-background: var(--ax-public-button-primary-background); + --button-background-hover: var(--ax-public-button-primary-background-hover); + --button-background-active: var(--ax-public-button-primary-background-active); + --button-background-focus: var(--ax-public-button-primary-background-focus); + --button-background-disabled: var(--ax-public-button-primary-background-disabled); + --button-color: var(--ax-public-button-primary-color); + --button-color-disabled: var(--ax-public-button-primary-color-disabled); + } + + .secondary { + --button-background: var(--ax-public-button-secondary-background); + --button-background-hover: var(--ax-public-button-secondary-background-hover); + --button-background-active: var(--ax-public-button-secondary-background-active); + --button-background-focus: var(--ax-public-button-secondary-background-focus); + --button-background-disabled: var(--ax-public-button-secondary-background-disabled); + --button-color: var(--ax-public-button-secondary-color); + --button-color-disabled: var(--ax-public-button-secondary-color-disabled); + } + + .critical { + --button-background: var(--ax-public-button-critical-background); + --button-background-hover: var(--ax-public-button-critical-background-hover); + --button-background-active: var(--ax-public-button-critical-background-active); + --button-background-focus: var(--ax-public-button-critical-background-focus); + --button-background-disabled: var(--ax-public-button-critical-background-disabled); + --button-color: var(--ax-public-button-critical-color); + --button-color-disabled: var(--ax-public-button-critical-color-disabled); + } + + .success { + --button-background: var(--ax-public-button-success-background); + --button-background-hover: var(--ax-public-button-success-background-hover); + --button-background-active: var(--ax-public-button-success-background-active); + --button-background-focus: var(--ax-public-button-success-background-focus); + --button-background-disabled: var(--ax-public-button-success-background-disabled); + --button-color: var(--ax-public-button-success-color); + --button-color-disabled: var(--ax-public-button-success-color-disabled); + } + + .warning { + --button-background: var(--ax-public-button-warning-background); + --button-background-hover: var(--ax-public-button-warning-background-hover); + --button-background-active: var(--ax-public-button-warning-background-active); + --button-background-focus: var(--ax-public-button-warning-background-focus); + --button-background-disabled: var(--ax-public-button-warning-background-disabled); + --button-color: var(--ax-public-button-warning-color); + --button-color-disabled: var(--ax-public-button-warning-color-disabled); + } + + .primary, + .secondary, + .critical, + .success, + .warning { + background-color: var(--button-background); + color: var(--button-color); + + &:not(:disabled):hover { + background-color: var(--button-background-hover); + } + + &:not(:disabled):active { + background-color: var(--button-background-active); + } + + &:not(:disabled):focus-visible { + background-color: var(--button-background-focus); + } + + &:disabled { + background-color: var(--button-background-disabled); + color: var(--button-color-disabled); + } + } + + .ghost-primary { + --button-background: var(--ax-public-button-ghost-primary-background-color); + --button-background-hover: var(--ax-public-button-ghost-primary-background-color-hover); + --button-background-active: var(--ax-public-button-ghost-primary-background-color-active); + --button-background-focus: var(--ax-public-button-ghost-primary-background-color-focus); + --button-background-disabled: var(--ax-public-button-ghost-primary-background-color-disabled); + --button-border-color: var(--ax-public-button-ghost-primary-border-color); + --button-border-color-hover: var(--ax-public-button-ghost-primary-border-color); + --button-border-color-active: var(--ax-public-button-ghost-primary-border-color); + --button-border-color-focus: var(--ax-public-button-ghost-primary-border-color); + --button-border-color-disabled: var(--ax-public-button-ghost-primary-border-color); + --button-color: var(--ax-public-button-ghost-primary-color); + --button-color-disabled: var(--ax-public-button-ghost-primary-color-disabled); + } + + .ghost-secondary { + --button-background: var(--ax-public-button-ghost-secondary-background-color); + --button-background-hover: var(--ax-public-button-ghost-secondary-background-color-hover); + --button-background-active: var(--ax-public-button-ghost-secondary-background-color-active); + --button-background-focus: var(--ax-public-button-ghost-secondary-background-color-focus); + --button-background-disabled: var(--ax-public-button-ghost-secondary-background-color-disabled); + --button-border-color: var(--ax-public-button-ghost-secondary-border-color); + --button-border-color-hover: var(--ax-public-button-ghost-secondary-border-color-hover); + --button-border-color-active: var(--ax-public-button-ghost-secondary-border-color-active); + --button-border-color-focus: var(--ax-public-button-ghost-secondary-border-color-focus); + --button-border-color-disabled: var(--ax-public-button-ghost-secondary-border-color-disabled); + --button-color: var(--ax-public-button-ghost-secondary-color); + --button-color-disabled: var(--ax-public-button-ghost-secondary-color-disabled); + } + + .ghost-critical { + --button-background: var(--ax-public-button-ghost-critical-background-color); + --button-background-hover: var(--ax-public-button-ghost-critical-background-color-hover); + --button-background-active: var(--ax-public-button-ghost-critical-background-color-active); + --button-background-focus: var(--ax-public-button-ghost-critical-background-color-focus); + --button-background-disabled: var(--ax-public-button-ghost-critical-background-color-disabled); + --button-border-color: var(--ax-public-button-ghost-critical-border-color); + --button-border-color-hover: var(--ax-public-button-ghost-critical-border-color); + --button-border-color-active: var(--ax-public-button-ghost-critical-border-color); + --button-border-color-focus: var(--ax-public-button-ghost-critical-border-color); + --button-border-color-disabled: var(--ax-public-button-ghost-critical-border-color); + --button-color: var(--ax-public-button-ghost-critical-color); + --button-color-disabled: var(--ax-public-button-ghost-critical-color-disabled); + } + + .ghost-success { + --button-background: var(--ax-public-button-ghost-success-background-color); + --button-background-hover: var(--ax-public-button-ghost-success-background-color-hover); + --button-background-active: var(--ax-public-button-ghost-success-background-color-active); + --button-background-focus: var(--ax-public-button-ghost-success-background-color-focus); + --button-background-disabled: var(--ax-public-button-ghost-success-background-color-disabled); + --button-border-color: var(--ax-public-button-ghost-success-border-color); + --button-border-color-hover: var(--ax-public-button-ghost-success-border-color); + --button-border-color-active: var(--ax-public-button-ghost-success-border-color); + --button-border-color-focus: var(--ax-public-button-ghost-success-border-color); + --button-border-color-disabled: var(--ax-public-button-ghost-success-border-color); + --button-color: var(--ax-public-button-ghost-success-color); + --button-color-disabled: var(--ax-public-button-ghost-success-color-disabled); + } + + .ghost-warning { + --button-background: var(--ax-public-button-ghost-warning-background-color); + --button-background-hover: var(--ax-public-button-ghost-warning-background-color-hover); + --button-background-active: var(--ax-public-button-ghost-warning-background-color-active); + --button-background-focus: var(--ax-public-button-ghost-warning-background-color-focus); + --button-background-disabled: var(--ax-public-button-ghost-warning-background-color-disabled); + --button-border-color: var(--ax-public-button-ghost-warning-border-color); + --button-border-color-hover: var(--ax-public-button-ghost-warning-border-color); + --button-border-color-active: var(--ax-public-button-ghost-warning-border-color); + --button-border-color-focus: var(--ax-public-button-ghost-warning-border-color); + --button-border-color-disabled: var(--ax-public-button-ghost-warning-border-color); + --button-color: var(--ax-public-button-ghost-warning-color); + --button-color-disabled: var(--ax-public-button-ghost-warning-color-disabled); + } + + .ghost-primary, + .ghost-secondary, + .ghost-critical, + .ghost-success, + .ghost-warning { + --button-border-color-current: var(--button-border-color); + + background-color: var(--button-background); + color: var(--button-color); + + &::after { + content: ''; + position: absolute; + inset: 0; + border: var(--ax-public-button-border-size) solid var(--button-border-color-current); + border-radius: inherit; + pointer-events: none; + } + + &:not(:disabled):hover { + --button-border-color-current: var(--button-border-color-hover); + + background-color: var(--button-background-hover); + } + + &:not(:disabled):active { + --button-border-color-current: var(--button-border-color-active); + + background-color: var(--button-background-active); + } + + &:not(:disabled):focus-visible { + --button-border-color-current: var(--button-border-color-focus); + + background-color: var(--button-background-focus); + } + + &:disabled { + --button-border-color-current: var(--button-border-color-disabled); + + background-color: var(--button-background-disabled); + color: var(--button-color-disabled); } } } diff --git a/packages/ui/src/components/snackbar/components/action-buttons.tsx b/packages/ui/src/components/snackbar/components/action-buttons.tsx index ef4d02067..32dc2f8fd 100644 --- a/packages/ui/src/components/snackbar/components/action-buttons.tsx +++ b/packages/ui/src/components/snackbar/components/action-buttons.tsx @@ -1,6 +1,6 @@ import { X } from '@phosphor-icons/react'; import { NavButton } from '@ui/components/button/nav-button/nav-button'; -import { Variant } from '@ui/components/button/regular-button/types'; +import { ButtonVariant } from '@ui/components/button/regular-button/types'; import styles from './action-buttons.module.css'; @@ -16,9 +16,9 @@ type ActionButtonsProps = { }; export function ActionButtons({ variant, buttonLabel, onButtonClick, close, onClose }: ActionButtonsProps) { - const buttonTypeMap: Record = { + const buttonTypeMap: Record = { [SnackbarType.DEFAULT]: 'primary', - [SnackbarType.ERROR]: 'error', + [SnackbarType.ERROR]: 'critical', [SnackbarType.INFO]: 'primary', [SnackbarType.WARNING]: 'warning', [SnackbarType.SUCCESS]: 'success',