Skip to content

refactor(IssueLabel): update TypeScript types and add initial tests #6265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
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
1 change: 1 addition & 0 deletions packages/react/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ module.exports = {
'<rootDir>/src/__tests__/theme.test.ts',
'<rootDir>/src/__tests__/themeGet.test.ts',
'<rootDir>/src/__tests__/useSafeTimeout.test.ts',
'<rootDir>/src/experimental/IssueLabel',
'<rootDir>/src/experimental/Skeleton',
'<rootDir>/src/hooks/',
'<rootDir>/src/internal/utils/',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,54 +9,54 @@ const meta = {

export default meta

export const VariantPink = () => <IssueLabel variant="pink" text="Issue label" />
export const VariantPink = () => <IssueLabel variant="pink">Issue label</IssueLabel>

export const VariantPlum = () => <IssueLabel variant="plum" text="Issue label" />
export const VariantPlum = () => <IssueLabel variant="plum">Issue label</IssueLabel>

export const VariantPurple = () => <IssueLabel variant="purple" text="Issue label" />
export const VariantPurple = () => <IssueLabel variant="purple">Issue label</IssueLabel>

export const VariantIndigo = () => <IssueLabel variant="indigo" text="Issue label" />
export const VariantIndigo = () => <IssueLabel variant="indigo">Issue label</IssueLabel>

export const VariantBlue = () => <IssueLabel variant="blue" text="Issue label" />
export const VariantBlue = () => <IssueLabel variant="blue">Issue label</IssueLabel>

export const VariantCyan = () => <IssueLabel variant="cyan" text="Issue label" />
export const VariantCyan = () => <IssueLabel variant="cyan">Issue label</IssueLabel>

export const VariantTeal = () => <IssueLabel variant="teal" text="Issue label" />
export const VariantTeal = () => <IssueLabel variant="teal">Issue label</IssueLabel>

export const VariantPine = () => <IssueLabel variant="pine" text="Issue label" />
export const VariantPine = () => <IssueLabel variant="pine">Issue label</IssueLabel>

export const VariantGreen = () => <IssueLabel variant="green" text="Issue label" />
export const VariantGreen = () => <IssueLabel variant="green">Issue label</IssueLabel>

export const VariantLime = () => <IssueLabel variant="lime" text="Issue label" />
export const VariantLime = () => <IssueLabel variant="lime">Issue label</IssueLabel>

export const VariantOlive = () => <IssueLabel variant="olive" text="Issue label" />
export const VariantOlive = () => <IssueLabel variant="olive">Issue label</IssueLabel>

export const VariantLemon = () => <IssueLabel variant="lemon" text="Issue label" />
export const VariantLemon = () => <IssueLabel variant="lemon">Issue label</IssueLabel>

export const VariantYellow = () => <IssueLabel variant="yellow" text="Issue label" />
export const VariantYellow = () => <IssueLabel variant="yellow">Issue label</IssueLabel>

export const VariantOrange = () => <IssueLabel variant="orange" text="Issue label" />
export const VariantOrange = () => <IssueLabel variant="orange">Issue label</IssueLabel>

export const VariantRed = () => <IssueLabel variant="red" text="Issue label" />
export const VariantRed = () => <IssueLabel variant="red">Issue label</IssueLabel>

export const VariantCoral = () => <IssueLabel variant="coral" text="Issue label" />
export const VariantCoral = () => <IssueLabel variant="coral">Issue label</IssueLabel>

export const VariantGray = () => <IssueLabel variant="gray" text="Issue label" />
export const VariantGray = () => <IssueLabel variant="gray">Issue label</IssueLabel>

export const VariantBrown = () => <IssueLabel variant="brown" text="Issue label" />
export const VariantBrown = () => <IssueLabel variant="brown">Issue label</IssueLabel>

export const VariantAuburn = () => <IssueLabel variant="auburn" text="Issue label" />
export const VariantAuburn = () => <IssueLabel variant="auburn">Issue label</IssueLabel>

export const HexColor = (args: {fillColor: `#${string}`}) => (
<IssueLabel text="Issue label" fillColor={args.fillColor} />
<IssueLabel fillColor={args.fillColor}>Issue label</IssueLabel>
)
HexColor.args = {
fillColor: '#59B200',
}
HexColor.argTypes = {
fillColor: {control: {type: 'color'}},
variant: {table: {disable: true}},
text: {table: {disable: true}},
children: {table: {disable: true}},
id: {table: {disable: true}},
className: {table: {disable: true}},
onClick: {table: {disable: true}},
Expand All @@ -65,19 +65,19 @@ HexColor.argTypes = {
href: {table: {disable: true}},
}

export const AsLink = () => <IssueLabel href="/" text="Issue label" />
export const AsLink = () => <IssueLabel href="/">Issue label</IssueLabel>

export const AsButton = () => <IssueLabel text="Issue label" as="button" />
export const AsButton = () => <IssueLabel as="button">Issue label</IssueLabel>

export const OnClick = () => <IssueLabel text="Issue label" onClick={() => alert('clicked')} />
export const OnClick = () => <IssueLabel onClick={() => alert('clicked')}>Issue label</IssueLabel>

export const GroupOfLabels = () => (
<Stack direction="horizontal" gap="condensed" wrap="wrap">
<IssueLabel variant="blue" text="Issue label" />
<IssueLabel variant="purple" text="Another label" />
<IssueLabel variant="green" text="A third label" />
<IssueLabel variant="orange" text="Issue label" />
<IssueLabel variant="yellow" text="Another label" />
<IssueLabel variant="brown" text="A third label" />
<IssueLabel variant="blue">Issue label</IssueLabel>
<IssueLabel variant="purple">Another label</IssueLabel>
<IssueLabel variant="green">A third label</IssueLabel>
<IssueLabel variant="orange">Issue label</IssueLabel>
<IssueLabel variant="yellow">Another label</IssueLabel>
<IssueLabel variant="brown">A third label</IssueLabel>
</Stack>
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ const meta = {

export default meta

export const Default = () => <IssueLabel text="Issue label" />
export const Default = () => <IssueLabel>Issue label</IssueLabel>

export const Playground: StoryObj<typeof IssueLabel> = {
render: args => <IssueLabel {...args} />,
args: {
text: 'Issue label',
children: 'Issue label',
as: 'span',
},
argTypes: {
Expand Down Expand Up @@ -45,9 +45,6 @@ export const Playground: StoryObj<typeof IssueLabel> = {
'auburn',
],
},
text: {
control: 'text',
},
as: {
control: 'inline-radio',
options: ['span', 'button', 'a'],
Expand Down
19 changes: 19 additions & 0 deletions packages/react/src/experimental/IssueLabel/IssueLabel.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {describe, expect, it, vi} from 'vitest'

Check failure on line 1 in packages/react/src/experimental/IssueLabel/IssueLabel.test.tsx

View workflow job for this annotation

GitHub Actions / lint

'vi' is defined but never used
import {render, screen} from '@testing-library/react'

Check failure on line 2 in packages/react/src/experimental/IssueLabel/IssueLabel.test.tsx

View workflow job for this annotation

GitHub Actions / lint

'screen' is defined but never used
import userEvent from '@testing-library/user-event'

Check failure on line 3 in packages/react/src/experimental/IssueLabel/IssueLabel.test.tsx

View workflow job for this annotation

GitHub Actions / lint

'userEvent' is defined but never used
import {IssueLabel} from '../IssueLabel'

describe('IssueLabel', () => {
it('should support `className` on outermost element', () => {
const {container} = render(<IssueLabel className="custom-class">Label</IssueLabel>)
expect(container.firstChild).toHaveClass('custom-class')
})

it('should support merging `style` on outermost element', () => {
const {container} = render(<IssueLabel style={{color: 'red', backgroundColor: 'blue'}}>Label</IssueLabel>)
expect(container.firstChild).toHaveStyle({

Check failure on line 14 in packages/react/src/experimental/IssueLabel/IssueLabel.test.tsx

View workflow job for this annotation

GitHub Actions / test

src/experimental/IssueLabel/IssueLabel.test.tsx > IssueLabel > should support merging `style` on outermost element

Error: expect(element).toHaveStyle() - Expected + Received - backgroundColor: blue; - color: red; + color: rgb(255, 0, 0); ❯ src/experimental/IssueLabel/IssueLabel.test.tsx:14:33
color: 'red',
backgroundColor: 'blue',
})
})
})
65 changes: 20 additions & 45 deletions packages/react/src/experimental/IssueLabel/IssueLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import {useTheme} from '../../ThemeProvider'
import {clsx} from 'clsx'
import classes from './IssueLabel.module.css'
export type Hex = `#${string}`

type Hex = `#${string}`

type LabelColorVariant =
| 'pink'
Expand All @@ -26,35 +27,15 @@
| 'brown'
| 'auburn'

export interface IssueLabelProps {
type IssueLabelProps<As extends React.ElementType> = {
as?: As
fillColor?: Hex
variant?: LabelColorVariant
href?: string
as?: 'button' | 'a' | 'span'
text: React.ReactNode
id?: number | string
className?: string
onClick?: React.MouseEventHandler<HTMLSpanElement | HTMLButtonElement | HTMLAnchorElement>
onFocus?: React.FocusEventHandler<HTMLSpanElement | HTMLButtonElement | HTMLAnchorElement>
}

export function IssueLabel({
className,
fillColor,
variant = 'gray',
href,
onClick,
onFocus,
text,
as,
id,
...rest
}: IssueLabelProps) {
// Error handling: `href` and `onClick` should not be set simultaneously
if (href && onClick) {
throw new Error('`href` and `onClick` cannot both be set. Choose either a link (`<a>`) or a button (`<button>`).')
}
} & React.ComponentPropsWithoutRef<React.ElementType extends As ? 'span' : As>

function IssueLabel<As extends React.ElementType>(props: IssueLabelProps<As>) {
const {as, children, className, fillColor, onClick, style, variant = 'gray', ...rest} = props

Check failure on line 38 in packages/react/src/experimental/IssueLabel/IssueLabel.tsx

View workflow job for this annotation

GitHub Actions / lint

'as' is assigned a value but never used
const {resolvedColorScheme} = useTheme()
const mode = resolvedColorScheme?.startsWith('dark') ? 'dark' : 'light'
// TODO: get the bgColor, getting it from theme.colorScheme seems a bit sketchy
Expand All @@ -63,31 +44,25 @@
dark: '#0d1117',
}

// Determine the component type: Prioritize `as`, then fallback to `href` or `onClick` logic
let Component: 'a' | 'button' | 'span' = 'span' // Default to <span>

if (as) {
Component = as // use 'as' prop if provided
} else if (href) {
Component = 'a' // render as <a> if `href` is provided
let BaseComponent = 'span'
if ('href' in rest) {
BaseComponent = 'a'
} else if (onClick) {
Component = 'button' // render as <button> if `onClick` is provided
BaseComponent = 'button'
}

const anchorProps = href ? {href} : {}

return (
<Component
<BaseComponent
{...rest}
{...anchorProps}
onClick={onClick}
onFocus={onFocus}
id={id?.toString()}
className={clsx(classes.IssueLabel, className)}
className={clsx(className, classes.IssueLabel)}
data-variant={fillColor ? undefined : variant}
style={fillColor ? getColorsFromHex(fillColor, resolvedColorScheme, bgColors[mode]) : undefined}
onClick={onClick}
style={fillColor ? {...style, ...getColorsFromHex(fillColor, resolvedColorScheme, bgColors[mode])} : style}
>
{text}
</Component>
{children}
</BaseComponent>
)
}

export {IssueLabel}
export type {Hex, IssueLabelProps}
1 change: 1 addition & 0 deletions packages/react/vitest.config.browser.mts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export default defineConfig({
'src/__tests__/filterObject.test.ts',
'src/__tests__/theme.test.ts',
'src/__tests__/themeGet.test.ts',
'src/experimental/IssueLabel/**/*.test.?(c|m)[jt]s?(x)',
'src/experimental/Skeleton/**/*.test.?(c|m)[jt]s?(x)',
'src/hooks/**/*.test.?(c|m)[jt]s?(x)',
'src/internal/utils/**/*.test.?(c|m)[jt]s?(x)',
Expand Down
Loading