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 3b922b7 commit 3d7e352
Show file tree
Hide file tree
Showing 3 changed files with 106 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
9 changes: 8 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,12 @@ 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> & {
// required
component: T
}
) => JSX.Element
export default Button
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 @@
// @charcoal-ui/react is not listed as a dependency so 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="" />
</>
)
}

0 comments on commit 3d7e352

Please sign in to comment.