Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/button-redesign.md
Original file line number Diff line number Diff line change
@@ -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"`).
8 changes: 1 addition & 7 deletions apps/docs/scripts/ui-components.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand Down
11 changes: 11 additions & 0 deletions apps/docs/src/components/ui-examples/button.module.css
Original file line number Diff line number Diff line change
@@ -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);
}
34 changes: 33 additions & 1 deletion apps/docs/src/components/ui-examples/button.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<ComponentPreview>
<Button variant="primary">Button</Button>
<div className={styles['example']}>
<div className={styles['row']}>
{SOLID_VARIANTS.map((variant) => (
<Button key={variant} variant={variant} size="m">
{variant}
</Button>
))}
</div>
<div className={styles['row']}>
{GHOST_VARIANTS.map((variant) => (
<Button key={variant} variant={variant} size="m">
{variant}
</Button>
))}
</div>
<div className={styles['row']}>
<Button shape="square" prefixIcon={<Plus />} aria-label="Add" />
<Button shape="round" prefixIcon={<X />} aria-label="Close" />
<Button isLoading>Loading</Button>
</div>
</div>
</ComponentPreview>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.

<ButtonExample client:visible />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 2 additions & 3 deletions packages/sdk/src/components/button-submit/button-submit.tsx
Original file line number Diff line number Diff line change
@@ -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<React.ComponentProps<typeof Button>, 'children'> & {
type Props = Omit<LabelButtonProps, 'children'> & {
classNameWrapper?: string;
isPending: boolean;
children: React.ReactNode;
Expand All @@ -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. */}
<Button {...buttonProps}>{children}</Button>
{isPending && <Spinner className={styles['icon--spinner']} />}
</span>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
.placeholder-button {
.placeholder-button::after {
border-style: dashed;
}
Original file line number Diff line number Diff line change
@@ -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<React.ComponentProps<typeof Button>, 'children'>;
} & Omit<LabelButtonProps, 'children'>;

export function PlaceholderButton({ label, size = 'extra-small', ...props }: Props) {
export function PlaceholderButton({ label, size = 'xs', ...props }: Props) {
return (
<Button className={styles['placeholder-button']} size={size} variant="secondary" {...props}>
<PlusCircle weight="bold" />
<Button
className={styles['placeholder-button']}
size={size}
variant="secondary"
prefixIcon={<PlusCircle weight="bold" />}
{...props}
>
{label}
</Button>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ export function ExportModal() {
<div className={styles['container']}>
<SyntaxHighlighterLazy value={storeData} onChange={noop} isDisabled />
<div className={styles['actions']}>
<Button variant="primary" onClick={handleCopy}>
<Icon name="Copy" />
<Button variant="primary" prefixIcon={<Icon name="Copy" />} onClick={handleCopy}>
{t('tooltips.copy')}
</Button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,19 @@ export function ImportModal() {
)}
<div className={styles['actions']}>
{warnings.length > 0 && errors.length === 0 && (
<Button variant="warning" onClick={() => handleImport({ shouldIgnoreWarnings: true })}>
<Icon name="DownloadSimple" />
<Button
variant="warning"
prefixIcon={<Icon name="DownloadSimple" />}
onClick={() => handleImport({ shouldIgnoreWarnings: true })}
>
{t('importExport.ignoreAndImport')}
</Button>
)}
<Button variant="primary" onClick={() => handleImport({ shouldIgnoreWarnings: false })}>
<Icon name="DownloadSimple" />
<Button
variant="primary"
prefixIcon={<Icon name="DownloadSimple" />}
onClick={() => handleImport({ shouldIgnoreWarnings: false })}
>
{t('importExport.import')}
</Button>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -57,8 +57,8 @@ function AiToolsControl({ path, handleChange, data, enabled, uischema }: AiTools
const icon = toolOption?.icon;
const label = toolOption?.label;

const sharedButtonProps: Partial<ComponentProps<typeof Button>> = {
variant: 'secondary',
const sharedButtonProps = {
variant: 'ghost-secondary' as const,
className: styles['selected-tool-button'],
onClick: () => openEditorModal(toolData),
disabled: isDisabled,
Expand All @@ -68,8 +68,7 @@ function AiToolsControl({ path, handleChange, data, enabled, uischema }: AiTools
<FormControlWithLabel key={toolData.id || index} label={`Tool #${index + 1}`}>
<div className={styles['tool-row']}>
{icon ? (
<Button {...sharedButtonProps}>
<Icon name={icon} />
<Button {...sharedButtonProps} prefixIcon={<Icon name={icon} />}>
{label}
</Button>
) : (
Expand All @@ -82,8 +81,7 @@ function AiToolsControl({ path, handleChange, data, enabled, uischema }: AiTools
</FormControlWithLabel>
);
})}
<Button variant="primary" onClick={(_) => openEditorModal()} disabled={isDisabled}>
<PlusCircle />
<Button variant="primary" prefixIcon={<PlusCircle />} onClick={(_) => openEditorModal()} disabled={isDisabled}>
{t('addToolSlot')}
</Button>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,15 @@ export const ConditionsForm = forwardRef<ConditionsFormHandle, ConditionsFormPro
/>
))}
</div>
<Button className={styles['add-button']} size="small" variant="secondary" onClick={addCondition}>
<Icon name="PlusCircle" />
</Button>
<Button
className={styles['add-button']}
size="s"
variant="secondary"
shape="square"
prefixIcon={<Icon name="PlusCircle" />}
aria-label="Add condition"
onClick={addCondition}
/>
</form>
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export function DeleteConfirmationButtons({ onDeleteClick, onCancelClick }: Dele
<Button variant="secondary" onClick={onCancelClick}>
{t('deleteConfirmation.cancel')}
</Button>
<Button onClick={onDeleteClick} size="medium" variant="error" autoFocus>
<Button onClick={onDeleteClick} size="m" variant="critical" autoFocus>
{t('deleteConfirmation.delete')}
</Button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function PaletteFooter({ onTemplateClick }: Props) {
return (
<div className={styles['container']}>
<OptionalFooterContent>
<Button disabled={isReadOnly} variant="secondary" onClick={onTemplateClick} size="small">
<Button disabled={isReadOnly} variant="secondary" onClick={onTemplateClick} size="s">
{t('palette.templates')}
</Button>
</OptionalFooterContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function PropertiesBarComponent({
}
footer={
isExpanded && (
<Button onClick={onDeleteClick} variant="ghost-destructive">
<Button onClick={onDeleteClick} variant="ghost-critical">
{selection?.node ? deleteNodeLabel : deleteEdgeLabel}
</Button>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,12 @@ export function PaneList({ className, setActivePane }: Props) {
title="workflowsSettings.tab.globalVariables"
description="workflowsSettings.tab.globalVariablesDescription"
>
<Button variant="secondary" size="extra-small" onClick={() => setActivePane(VARIABLE_PANE.ADD)}>
<Icon name="Plus" />
<Button
variant="secondary"
size="xs"
prefixIcon={<Icon name="Plus" />}
onClick={() => setActivePane(VARIABLE_PANE.ADD)}
>
{t('workflowsSettings.tab.addVariable')}
</Button>
</TabHeader>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ export function PaneRemoveVariable({ className, setActivePane, id }: Props) {
{variable && (
<div className={styles['buttons']}>
<ButtonSubmit
size="medium"
size="m"
onClick={handleRemove}
variant="error"
variant="critical"
isPending={false}
disabled={nodesWithVariable.length > 0}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export function VariableForm(props: Props) {
/>
</FormControlWithLabel>
<div className={styles['buttons']}>
<ButtonSubmit size="medium" type="submit" isPending={false}>
<ButtonSubmit size="m" type="submit" isPending={false}>
{t(props.variant === 'add' ? 'workflowsSettings.tab.addVariable' : 'common.save')}
</ButtonSubmit>
</div>
Expand Down
Loading
Loading