Skip to content
Closed
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
7 changes: 7 additions & 0 deletions .changeset/cyan-needles-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@primer/react": major
---

- Changes `leadingIcon` and `trailingIcon` to `leadingVisual` and `trailingVisual`
- Removes `Button.Counter` as a child component, replacing it with a `count` prop. This change allows us to use the `trailingVisual` slot for counters.
- Removes the `outline` button variant as we wish to only support `invisible` buttons.
8 changes: 4 additions & 4 deletions docs/content/ActionMenu.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ const fieldTypes = [
{icon: NumberIcon, name: 'Number'},
{icon: CalendarIcon, name: 'Date'},
{icon: SingleSelectIcon, name: 'Single select'},
{icon: IterationsIcon, name: 'Iteration'}
{icon: IterationsIcon, name: 'Iteration'},
]

const Example = () => {
Expand All @@ -191,7 +191,7 @@ const Example = () => {

return (
<ActionMenu>
<ActionMenu.Button aria-label="Select field type" leadingIcon={selectedType.icon}>
<ActionMenu.Button aria-label="Select field type" leadingVisual={selectedType.icon}>
{selectedType.name}
</ActionMenu.Button>
<ActionMenu.Overlay width="medium">
Expand Down Expand Up @@ -275,7 +275,7 @@ render(
</ActionList.Item>
</ActionList>
</ActionMenu.Overlay>
</ActionMenu>
</ActionMenu>,
)
```

Expand Down Expand Up @@ -368,7 +368,7 @@ render(
stableApi: true,
addressedApiFeedback: false,
hasDesignGuidelines: true,
hasFigmaComponent: true
hasFigmaComponent: true,
}}
/>

Expand Down
29 changes: 8 additions & 21 deletions docs/content/Button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,6 @@ The `danger` variant of `Button` is used to warn users about potentially destruc
<Button variant="danger">Danger</Button>
```

### Outline button

The `outline` variant of `Button` is typically used as a secondary button

```jsx live
<Button variant="outline">Outline</Button>
```

### Invisible button

The `invisible` variant of `Button` indicates that the action is a low priority one.
Expand Down Expand Up @@ -66,11 +58,11 @@ It is recommended to use an octicon here.

```jsx live
<>
<Button leadingIcon={SearchIcon}>Search</Button>
<Button trailingIcon={SearchIcon} sx={{mt: 2}}>
<Button leadingVisual={SearchIcon}>Search</Button>
<Button trailingVisual={SearchIcon} sx={{mt: 2}}>
Search
</Button>
<Button leadingIcon={SearchIcon} trailingIcon={CheckIcon} sx={{mt: 2}}>
<Button leadingVisual={SearchIcon} trailingVisual={CheckIcon} sx={{mt: 2}}>
Search
</Button>
</>
Expand All @@ -96,17 +88,12 @@ A separate component called `IconButton` is used if the action shows only an ico
</>
```

### Counter component
### Button with counter

A common use case for primer is a button with a counter component which shows the child count value.
We provide `Button.Counter` as a composite component which requires you to provide a number as child.
The counter will match the `variant` styles of the parent button.
To show a count value as a trailing visual inside `Button`, pass a value to the `count` prop. The counter will match the `variant` styles of the parent button.

```jsx live
<Button>
Watch
<Button.Counter>1</Button.Counter>
</Button>
<Button count="1">Watch</Button>
```

### Block button
Expand Down Expand Up @@ -142,12 +129,12 @@ Native `<button>` HTML attributes are forwarded to the underlying React `button`
/>
<PropsTableRow name="block" type="boolean" description="Full width button fills the parent container" />
<PropsTableRow
name="leadingIcon"
name="leadingVisual"
type="Component"
description="provide an octicon. It will be placed before the button text"
/>
<PropsTableRow
name="trailingIcon"
name="trailingVisual"
type="Component"
description="provide an octicon. It will be placed after the button text"
/>
Expand Down
20 changes: 7 additions & 13 deletions src/Button/Button.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,15 @@ export const Danger = () => <Button variant="danger">Danger</Button>

export const Invisible = () => <Button variant="invisible">Invisible</Button>

export const Outline = () => <Button variant="outline">Outline</Button>
export const LeadingVisual = () => <Button leadingVisual={HeartIcon}>Leading visual</Button>

export const LeadingVisual = () => <Button leadingIcon={HeartIcon}>Leading visual</Button>

export const TrailingVisual = () => <Button trailingIcon={EyeIcon}>Trailing visual</Button>
export const TrailingVisual = () => <Button trailingVisual={EyeIcon}>Trailing visual</Button>

export const TrailingCounter = () => {
const [count, setCount] = useState(0)
return (
<Button onClick={() => setCount(count + 1)}>
<Button onClick={() => setCount(count + 1)} trailingVisualCount={count}>
Watch
<Button.Counter>{count}</Button.Counter>
</Button>
)
}
Expand All @@ -47,23 +44,20 @@ export const InvisibleVariants = () => {
return (
<div style={{display: 'flex', flexDirection: 'row', gap: '1rem'}}>
<Button variant="invisible">Button</Button>
<Button variant="invisible" leadingIcon={SearchIcon}>
<Button variant="invisible" leadingVisual={SearchIcon}>
Button
</Button>
<Button variant="invisible" trailingAction={TriangleDownIcon}>
Button
</Button>
<Button variant="invisible">
<Button variant="invisible" trailingVisualCount={count}>
Button
<Button.Counter>{count}</Button.Counter>
</Button>
<Button variant="invisible" leadingIcon={EyeIcon}>
<Button variant="invisible" leadingVisual={EyeIcon} trailingVisualCount={count}>
Button
<Button.Counter>{count}</Button.Counter>
</Button>
<Button variant="invisible" leadingIcon={EyeIcon} trailingAction={TriangleDownIcon}>
<Button variant="invisible" leadingVisual={EyeIcon} trailingAction={TriangleDownIcon} trailingVisualCount={count}>
Button
<Button.Counter>{count}</Button.Counter>
</Button>
</div>
)
Expand Down
8 changes: 4 additions & 4 deletions src/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export default {
type: 'boolean',
},
},
leadingIcon: OcticonArgType([EyeClosedIcon, EyeIcon, SearchIcon, XIcon, HeartIcon]),
trailingIcon: OcticonArgType([EyeClosedIcon, EyeIcon, SearchIcon, XIcon, HeartIcon]),
leadingVisual: OcticonArgType([EyeClosedIcon, EyeIcon, SearchIcon, XIcon, HeartIcon]),
trailingVisual: OcticonArgType([EyeClosedIcon, EyeIcon, SearchIcon, XIcon, HeartIcon]),
trailingAction: OcticonArgType([TriangleDownIcon]),
trailingVisualCount: {
control: {
Expand All @@ -50,8 +50,8 @@ export default {
disabled: false,
variant: 'default',
alignContent: 'center',
trailingIcon: null,
leadingIcon: null,
trailingVisual: null,
leadingVisual: null,
trailingAction: null,
trailingVisualCount: undefined,
},
Expand Down
27 changes: 20 additions & 7 deletions src/Button/ButtonBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ import {useTheme} from '../ThemeProvider'
import {ButtonProps, StyledButton} from './types'
import {getVariantStyles, getButtonStyles, getAlignContentSize} from './styles'
import {useRefObjectAsForwardedRef} from '../hooks/useRefObjectAsForwardedRef'
import CounterLabel from '../CounterLabel'
declare let __DEV__: boolean

const defaultSxProp = {}
const ButtonBase = forwardRef<HTMLElement, ButtonProps>(
({children, as: Component = 'button', sx: sxProp = defaultSxProp, ...props}, forwardedRef): JSX.Element => {
const {
leadingIcon: LeadingIcon,
trailingIcon: TrailingIcon,
leadingVisual: LeadingVisual,
trailingVisual: TrailingVisual,
trailingAction: TrailingAction,
trailingVisualCount: trailingVisualCount,
variant = 'default',
size = 'medium',
alignContent = 'center',
Expand Down Expand Up @@ -61,20 +63,31 @@ const ButtonBase = forwardRef<HTMLElement, ButtonProps>(
ref={innerRef}
data-component={block ? 'block' : null}
data-size={size === 'small' || size === 'large' ? size : undefined}
data-no-visuals={!LeadingIcon && !TrailingIcon && !TrailingAction ? true : undefined}
data-no-visuals={
!LeadingVisual && !TrailingVisual && !TrailingAction && !trailingVisualCount ? true : undefined
}
>
<Box as="span" data-component="buttonContent" sx={getAlignContentSize(alignContent)}>
{LeadingIcon && (
{LeadingVisual && (
<Box as="span" data-component="leadingVisual" sx={{...iconWrapStyles}}>
<LeadingIcon />
<LeadingVisual />
</Box>
)}
{children && <span data-component="text">{children}</span>}
{TrailingIcon && (
{TrailingVisual && (
<Box as="span" data-component="trailingVisual" sx={{...iconWrapStyles}}>
<TrailingIcon />
<TrailingVisual />
</Box>
)}
{trailingVisualCount !== undefined ? (
<Box as="span" data-component="trailingVisual" sx={{...iconWrapStyles}}>
<CounterLabel data-component="ButtonCounter">{trailingVisualCount}</CounterLabel>
</Box>
) : TrailingVisual ? (
<Box as="span" data-component="trailingVisual" sx={{...iconWrapStyles}}>
<TrailingVisual />
</Box>
) : null}
</Box>
{TrailingAction && (
<Box as="span" data-component="trailingAction" sx={{...iconWrapStyles}}>
Expand Down
17 changes: 0 additions & 17 deletions src/Button/ButtonCounter.tsx

This file was deleted.

10 changes: 2 additions & 8 deletions src/Button/LinkButton.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,14 @@ export const Invisible = () => (
</Button>
)

export const Outline = () => (
<Button as="a" href="/" variant="outline">
Invisible
</Button>
)

export const LeadingVisual = () => (
<Button as="a" href="/" leadingIcon={HeartIcon}>
<Button as="a" href="/" leadingVisual={HeartIcon}>
Leading visual
</Button>
)

export const TrailingVisual = () => (
<Button as="a" href="/" trailingIcon={EyeIcon}>
<Button as="a" href="/" trailingVisual={EyeIcon}>
Trailing visual
</Button>
)
Expand Down
8 changes: 4 additions & 4 deletions src/Button/LinkButton.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export default {
type: 'boolean',
},
},
leadingIcon: OcticonArgType([EyeClosedIcon, EyeIcon, SearchIcon, XIcon, HeartIcon]),
trailingIcon: OcticonArgType([EyeClosedIcon, EyeIcon, SearchIcon, XIcon, HeartIcon]),
leadingVisual: OcticonArgType([EyeClosedIcon, EyeIcon, SearchIcon, XIcon, HeartIcon]),
trailingVisual: OcticonArgType([EyeClosedIcon, EyeIcon, SearchIcon, XIcon, HeartIcon]),
trailingAction: OcticonArgType([ChevronRightIcon]),
trailingVisualCount: {
control: {
Expand All @@ -45,8 +45,8 @@ export default {
size: 'medium',
variant: 'default',
alignContent: 'center',
trailingIcon: null,
leadingIcon: null,
trailingVisual: null,
leadingVisual: null,
href: '/',
},
} as Meta<typeof Button>
Expand Down
5 changes: 1 addition & 4 deletions src/Button/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import {ButtonComponent} from './Button'
import {Counter} from './ButtonCounter'
import {IconButton} from './IconButton'
import {LinkButton} from './LinkButton'
export type {ButtonProps, IconButtonProps} from './types'
export {IconButton, LinkButton}

export const Button = Object.assign(ButtonComponent, {
Counter,
})
export const Button = Object.assign(ButtonComponent)
46 changes: 0 additions & 46 deletions src/Button/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,52 +127,6 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
'&[data-no-visuals]': {
color: 'accent.fg',
},
'&:has([data-component="ButtonCounter"])': {
color: 'btn.text',
},
},
outline: {
color: 'btn.outline.text',
boxShadow: `${theme?.shadows.btn.shadow}`,
borderColor: 'btn.border',
backgroundColor: 'btn.bg',

'&:hover:not([disabled])': {
color: 'btn.outline.hoverText',
backgroundColor: 'btn.outline.hoverBg',
borderColor: 'btn.outline.hoverBorder',
boxShadow: `${theme?.shadows.btn.outline.hoverShadow}`,
'[data-component=ButtonCounter]': {
backgroundColor: 'btn.outline.hoverCounterBg',
color: 'inherit',
},
},
'&:active:not([disabled])': {
color: 'btn.outline.selectedText',
backgroundColor: 'btn.outline.selectedBg',
boxShadow: `${theme?.shadows.btn.outline.selectedShadow}`,
borderColor: 'btn.outline.selectedBorder',
},

'&:disabled': {
color: 'btn.outline.disabledText',
backgroundColor: 'btn.outline.disabledBg',
borderColor: 'btn.border',
'[data-component=ButtonCounter]': {
backgroundColor: 'btn.outline.disabledCounterBg',
color: 'inherit',
},
},
'[data-component=ButtonCounter]': {
backgroundColor: 'btn.outline.counterBg',
color: 'btn.outline.text',
},
'&[aria-expanded=true]': {
color: 'btn.outline.selectedText',
backgroundColor: 'btn.outline.selectedBg',
boxShadow: `${theme?.shadows.btn.outline.selectedShadow}`,
borderColor: 'btn.outline.selectedBorder',
},
},
}
return style[variant]
Expand Down
6 changes: 3 additions & 3 deletions src/Button/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const StyledButton = styled.button<SxProp>`
${sx};
`

export type VariantType = 'default' | 'primary' | 'invisible' | 'danger' | 'outline'
export type VariantType = 'default' | 'primary' | 'invisible' | 'danger'

export type Size = 'small' | 'medium' | 'large'

Expand Down Expand Up @@ -49,11 +49,11 @@ export type ButtonProps = {
/**
* The leading icon comes before button content
*/
leadingIcon?: React.FunctionComponent<React.PropsWithChildren<IconProps>>
leadingVisual?: React.FunctionComponent<React.PropsWithChildren<IconProps>>
/**
* The trailing icon comes after button content
*/
trailingIcon?: React.FunctionComponent<React.PropsWithChildren<IconProps>>
trailingVisual?: React.FunctionComponent<React.PropsWithChildren<IconProps>>
/**
* Trailing action appears to the right of the trailing visual and is always locked to the end
*/
Expand Down
2 changes: 1 addition & 1 deletion src/PageHeader/PageHeader.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ const Template: Story = args => (
</PageHeader.ContextBar>

<PageHeader.ContextAreaActions hidden={!args.hasContextAreaAction}>
<Button size="small" leadingIcon={GitBranchIcon}>
<Button size="small" leadingVisual={GitBranchIcon}>
Main
</Button>
<IconButton size="small" aria-label="More" icon={KebabHorizontalIcon} />
Expand Down
Loading