Skip to content

Commit 33a327c

Browse files
committed
Support inference extra props from as props
1 parent 1a2f813 commit 33a327c

File tree

3 files changed

+74
-13
lines changed

3 files changed

+74
-13
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"react-dom": "^16.13.1",
5252
"react-scripts": "^3.4.1",
5353
"reakit": "^1.1.2",
54+
"reakit-utils": "^0.13.1",
5455
"theme-ui": "^0.3.1",
5556
"ts-loader": "^8.0.1",
5657
"tsdx": "^0.13.2",

src/Button.stories.tsx

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import React from 'react'
1+
import React, { useReducer, useRef, useEffect, forwardRef, Ref } from 'react'
22
import { ThemeProvider } from 'theme-ui'
33
import { withA11y } from '@storybook/addon-a11y'
44
import { withKnobs, text, color, boolean } from '@storybook/addon-knobs'
5-
import { Checkbox, useCheckboxState } from 'reakit'
65

76
import Button from '.'
87

@@ -46,8 +45,55 @@ export function TheSXProp() {
4645
)
4746
}
4847

49-
export function TheAsProp() {
50-
const checkbox = useCheckboxState()
48+
export function TheAsPropWithIntrinsicElement() {
49+
const ref = useRef<HTMLAnchorElement>(null)
50+
const [checked, toggle] = useReducer((value) => !value, false)
51+
52+
useEffect(() => {
53+
console.warn(
54+
`TheAsPropWithIntrinsicElement: Detects properly type of \`ref\` from \`as\``,
55+
ref.current
56+
)
57+
}, [])
58+
59+
return (
60+
<ThemeProvider
61+
theme={{
62+
colors: {
63+
background: '#FFFFFF',
64+
primary: '#2F323A',
65+
secondary: '#4F5D75',
66+
},
67+
}}
68+
>
69+
<Button ref={ref} as="a" target="_blank" onClick={toggle}>
70+
{checked ? '😄 Happy' : '😞 Sad'}
71+
</Button>
72+
</ThemeProvider>
73+
)
74+
}
75+
76+
const Link = forwardRef(function Link(
77+
{ children, ...props }: JSX.IntrinsicElements['a'],
78+
ref: Ref<HTMLAnchorElement>
79+
) {
80+
return (
81+
<a ref={ref} {...props}>
82+
{children}
83+
</a>
84+
)
85+
})
86+
87+
export function TheAsPropWithCustomElement() {
88+
const ref = useRef<HTMLAnchorElement>(null)
89+
const [checked, toggle] = useReducer((value) => !value, false)
90+
91+
useEffect(() => {
92+
console.warn(
93+
`TheAsPropWithCustomElement: Detects properly type of \`ref\` from \`as\``,
94+
ref.current
95+
)
96+
}, [])
5197

5298
return (
5399
<ThemeProvider
@@ -59,9 +105,9 @@ export function TheAsProp() {
59105
},
60106
}}
61107
>
62-
<Checkbox {...checkbox} as={Button}>
63-
{checkbox.state ? '😄 Happy' : '😞 Sad'}
64-
</Checkbox>
108+
<Button ref={ref} as={Link} target="_blank" onClick={toggle}>
109+
{checked ? '😄 Happy' : '😞 Sad'}
110+
</Button>
65111
</ThemeProvider>
66112
)
67113
}

src/index.tsx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
1-
import React, { forwardRef, Ref } from 'react'
1+
import React, { forwardRef, Ref, PropsWithoutRef } from 'react'
22
import { Button as A11yButton, ButtonProps as A11yProps } from 'reakit'
3+
import { PropsWithAs, As } from 'reakit-utils/types'
34
import {
45
Button as ThemeAwareButton,
56
ButtonProps as ThemeAwareProps,
67
} from 'theme-ui'
78

8-
type Props = A11yProps & ThemeAwareProps
9+
type Component<DefaultAs extends As, DefaultProps> = {
10+
<T extends As = DefaultAs>(
11+
props: PropsWithAs<PropsWithoutRef<DefaultProps>, T>
12+
): JSX.Element
13+
}
14+
15+
type ButtonProps = A11yProps & { as?: As }
916

10-
function Button({ as, ...props }: Props, ref: Ref<HTMLButtonElement>) {
11-
return <A11yButton {...props} ref={ref} as={as ?? ThemeAwareButton} />
17+
const Button = (
18+
{ as = ThemeAwareButton, ...props }: ButtonProps,
19+
ref: Ref<As>
20+
) => {
21+
return <A11yButton ref={ref} as={as} {...props} />
1222
}
1323

14-
export { A11yProps, ThemeAwareProps }
15-
export default forwardRef(Button)
24+
export { ButtonProps, A11yProps, ThemeAwareProps }
25+
26+
export default forwardRef(Button) as Component<
27+
typeof ThemeAwareButton,
28+
A11yProps
29+
>

0 commit comments

Comments
 (0)