Skip to content

Commit

Permalink
fix: try support styled button
Browse files Browse the repository at this point in the history
  • Loading branch information
yue4u committed Jan 27, 2025
1 parent 42466af commit 20142a5
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 1 deletion.
19 changes: 19 additions & 0 deletions .storybook/src/v4.0.0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,25 @@ After
<Button component={NextLink} href="...">Link</Button>
```

### ButtonのGeneric propsについて

[Styled Componentの制限](https://github.com/styled-components/styled-components/issues/1803)により`styled(Button)`で拡張する場合propsがうまく推論されない場合があります。
Charcoal v4.1.0から過剰なpropsを検出する処理を追加したが、`component` propと合わせて使う時の型を配慮する必要があります。

サンプル

```tsx
// allow component
const StyledButton = styled(Button)`` as typeof Button
<StyledButton component={Link} to="#" />

// preserve component type
const StyledButtonA = styled(Button<'a'>)``
<StyledButtonA component="a" href="#" />
```

その他のケースは [packages/styled/src/styledButtonType.d.tsx](https://github.com/pixiv/charcoal/blob/main/packages/styled/src/styledButtonType.d.tsx) を参考してください。

## Checkbox

- `Checkbox``input`要素を`children`がない場合に label で囲わないようにしました。
Expand Down
8 changes: 7 additions & 1 deletion packages/react/src/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,11 @@ const Button = forwardRef(function Button<T extends React.ElementType>(
ref={ref}
/>
)
}) as <T extends React.ElementType = 'button'>(p: ButtonProps<T>) => JSX.Element
}) as <T extends React.ElementType = 'button'>(
p: 'button' extends T
? ButtonProps<'button'>
: ButtonProps<T> & {
component: T // required
}
) => JSX.Element
export default Button
1 change: 1 addition & 0 deletions packages/styled/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"test": "vitest run --passWithNoTests"
},
"devDependencies": {
"@charcoal-ui/react": "^4.0.1",
"@types/react": "^17.0.38",
"@types/react-test-renderer": "^17.0.2",
"@types/styled-components": "^5.1.21",
Expand Down
79 changes: 79 additions & 0 deletions packages/styled/src/styledButtonType.d.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// only use the type
import type { Button as ButtonType } from '@charcoal-ui/react'
import styled from 'styled-components'

declare const Button: typeof ButtonType

const Custom = ({ custom }: { custom: string }) => <>{custom}</>
const CustomGeneric = <C extends string>({ custom }: { custom: C }) => (
<>{custom}</>
)

const StyledButton = styled(Button)``
const StyledButtonAsButton = styled(Button<'button'>)``
const StyledButtonA = styled(Button<'a'>)``
const StyledButtonCustom = styled(Button<typeof Custom>)``
const StyledButtonCustomAsButton = styled(
Button<typeof Custom>
)`` as typeof Button
const StyledButtonCustomGeneric = styled(Button<typeof CustomGeneric>)``
const StyledButtonCustomGenericFoo = styled(
Button<typeof CustomGeneric<'foo'>>
)``

// for type test only
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function Tests() {
return (
<>
<StyledButton />
<StyledButton type="button" disabled />
{/* @ts-expect-error Property 'href' does not exist on type */}
<StyledButton href="" />

<StyledButtonAsButton type="button" disabled />
{/* @ts-expect-error Property 'href' does not exist on type */}
<StyledButtonAsButton href="" />

<StyledButtonA component="a" href="#" />
{/* @ts-expect-error Property 'component' is missing */}
<StyledButtonA href="#" />
{/* @ts-expect-error Property 'disabled' does not exist on type */}
<StyledButtonA disabled />
{/* @ts-expect-error Type '"button"' is not assignable to type '"a"' */}
<StyledButtonA component="button" href="" />

<StyledButtonCustom component={Custom} custom="" />
{/* @ts-expect-error Property 'component' is missing */}
<StyledButtonCustom custom="" />
{/* @ts-expect-error Type 'string' is not assignable */}
<StyledButtonCustom component="a" custom="" />

<StyledButtonCustomAsButton<'a'> component="a" href="#" />
<StyledButtonCustomAsButton<typeof CustomGeneric<'bar'>>
component={CustomGeneric}
custom="bar"
/>
<StyledButtonCustomAsButton component="a" href="#" />
{/* @ts-expect-error Property 'custom' does not exist on type */}
<StyledButtonCustomAsButton custom="" />
{/* @ts-expect-error Type 'href' is not assignable */}
<StyledButtonCustomAsButton<'button'> href="#" />

<StyledButtonCustomGeneric component={CustomGeneric} custom="" />

<StyledButtonCustomGenericFoo component={CustomGeneric} custom="foo" />
<StyledButtonCustomGenericFoo
component={CustomGeneric<'foo'>}
custom="foo"
/>
<StyledButtonCustomGenericFoo
/* @ts-expect-error Type '"foo"' is not assignable to type '"bar"' */
component={CustomGeneric<'bar'>}
custom="foo"
/>
{/* @ts-expect-error '""' is not assignable to type '"foo"' */}
<StyledButtonCustomGenericFoo custom="" />
</>
)
}
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2153,6 +2153,7 @@ __metadata:
resolution: "@charcoal-ui/styled@workspace:packages/styled"
dependencies:
"@charcoal-ui/foundation": ^4.0.1
"@charcoal-ui/react": ^4.0.1
"@charcoal-ui/theme": ^4.0.1
"@charcoal-ui/utils": ^4.0.1
"@types/react": ^17.0.38
Expand Down

0 comments on commit 20142a5

Please sign in to comment.