Skip to content

Commit

Permalink
Button: Make button visuals overridable by sx
Browse files Browse the repository at this point in the history
  • Loading branch information
broccolinisoup committed Aug 29, 2023
1 parent 438f67e commit b7ced96
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 5 deletions.
6 changes: 5 additions & 1 deletion src/Button/Button.dev.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {SearchIcon, TriangleDownIcon, EyeIcon} from '@primer/octicons-react'
import {SearchIcon, TriangleDownIcon, EyeIcon, IssueClosedIcon} from '@primer/octicons-react'
import React from 'react'
import {Button, IconButton} from '.'
import {default as Text} from '../Text'

export default {
title: 'Components/Button/DevOnly',
Expand Down Expand Up @@ -70,6 +71,9 @@ export const TestSxProp = () => {
<Button leadingIcon={SearchIcon} variant="invisible" sx={{color: 'firebrick'}}>
Red
</Button>
<Button leadingIcon={IssueClosedIcon} sx={{color: 'done.fg'}}>
<Text sx={{color: 'fg.default'}}>Close issue</Text>
</Button>
<Button
size="small"
variant="invisible"
Expand Down
18 changes: 14 additions & 4 deletions src/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,31 @@ export function generateCustomSxProp(
props: Partial<Pick<ButtonProps, 'size' | 'block' | 'leadingIcon' | 'trailingIcon' | 'trailingAction'>>,
providedSx: BetterSystemStyleObject,
) {
// Possible data attributes: data-size, data-block, data-no-visuals
const cssSelectorList = []
// Possible data attributes for button component: data-size, data-block, data-no-visuals
const size = props.size && props.size !== 'medium' ? `[data-size="${props.size}"]` : '' // medium is a default size therefore it doesn't have a data attribute that used for styling
const block = props.block ? `[data-block="block"]` : ''
const noVisuals = props.leadingIcon || props.trailingIcon || props.trailingAction ? '' : '[data-no-visuals="true"]'

// this is custom selector. We need to make sure we add the data attributes to the base css class (& -> &[data-attributename="value"]])
// We need to make sure we add the data attributes to the base css class (& -> &[data-attributename="value"]]) otherwise sx styles are applied due to data attribute has more specificity than class selector
const cssSelector = `&${size}${block}${noVisuals}` // &[data-size="small"][data-block="block"][data-no-visuals="true"]
cssSelectorList.push(cssSelector)

// Possible data attributes for children of button component: data-component="leadingVisual", data-component="trailingVisual", data-component="trailingAction"
// When sx is used in the parent button component, these styles aren't applied to its children (leadingIcon, trailingIcon, trailingAction)
// Because sx only applies to the base selector which is "&", but we want it to be applied to '& [data-component="leadingVisual"]'
if (props.leadingIcon) cssSelectorList.push(`& [data-component="leadingVisual"]`)
if (props.trailingIcon) cssSelectorList.push(`& [data-component="trailingVisual"]`)
if (props.trailingAction) cssSelectorList.push(`& [data-component="trailingAction"]`)

const customSxProp: {
[key: string]: BetterSystemStyleObject
} = {}

if (!providedSx) return customSxProp
else {
customSxProp[cssSelector] = providedSx
for (const selector of cssSelectorList) {
customSxProp[selector] = providedSx
}
return customSxProp
}
}
Expand Down

0 comments on commit b7ced96

Please sign in to comment.