I know that there are a lot of questions similars to this one but I already tried each one of them and I still can't make it work.
Well, I'm building my own ui-library using typescript and styled-components. Honestly I'm pretty newbie on TS so there is a chance that I missing something obvious, so any advice will be appreciated.
Now going to what matters, here it is some code:
/// THIS IS IN THE PROJECT I'M TRYING TO USE MY LIBRARY
<Button
size={4}
>
My cool button
</Button>
As you can see, I'm passing size
prop to Button component of my own library. This prop is received by the library here:
const Button = (props: IButtonProps) => {
return (
<StyledButton {...props}>
{props.leftIcon && <ButtonIcon marginRight={props.iconSpacing}>{props.leftIcon}</ButtonIcon>}
{props.children}
{props.rightIcon && <ButtonIcon marginLeft={props.iconSpacing}>{props.rightIcon}</ButtonIcon>}
</StyledButton>
)
}
And now as you can see I have the <StyledButton>
using styled-components where I'm spreading the props:
const StyledButton = styled.button<IButtonProps>`
// Other properties
padding: ${props => props.theme.paddings[props.size as SizeTypes ?? 4]};
// More properties
And the problem is exactly here. When I pass size={4}
from the project using the library, I got the error in the title.
Of course I already defined a DeafultTheme
with my objects and it's properties:
import 'styled-components'
declare module 'styled-components' {
export interface DefaultTheme {
// Some objects
paddings: {
1: string,
2: string,
3: string,
4: string,
5: string,
6: string,
7: string,
8: string
};
// More objects
}
}
And a theme
consuming it:
import { DefaultTheme } from 'styled-components';
const theme: DefaultTheme = {
paddings: {
1: '2px',
2: '4px',
3: '6px',
4: '8px',
5: '10px',
6: '12px',
7: '16px',
8: '24px',
}
};
export { theme };
Finally, my IButtonProps
interface:
interface IButtonProps extends React.ComponentPropsWithoutRef<'button'> {
onClick?: (evt: React.FormEvent<HTMLElement>) => void;
bg?: string;
size: number;
spacing: number;
fontSize?: string;
fontWeight?: string;
borderRadius: number;
color?: string;
iconSpacing?: number;
leftIcon?: React.ReactElement;
rightIcon?: React.ReactElement;
children?: React.ReactNode;
}
export { IButtonProps };
If there is something else that could give you more input in order to help me I will of course edit the post.
Thanks in advance!
CodePudding user response:
I just wrote a simple example which works well. Maybe you can find the differences between your and mine.
https://codesandbox.io/s/flamboyant-leaf-y4oyh?file=/src/App.js
import styled, { ThemeProvider } from "styled-components";
const paddingMap = {
1: "10px",
2: "20px",
3: "30px",
4: "40px"
};
const StyledButton = styled.button`
font-size: ${(props) => props.theme.padding[props.size ?? 4]};
`;
const Button = (props) => {
return <StyledButton {...props} />;
};
export default function App() {
return (
<ThemeProvider theme={{ padding: paddingMap }}>
<div className="App">
<Button>my default button</Button>
<Button size={4}>my size 4 button</Button>
<Button size={3}>my size 3 button</Button>
<Button size={2}>my size 2 button</Button>
<Button size={1}>my size 1 button</Button>
</div>
</ThemeProvider>
);
}
CodePudding user response:
As I said in the comments, I was making an obvious mistake: I forgot to embebe my components with theme
object.
So I made a new ThemeWrapper.tsx
component with a ThemeProvider
provider that passes the theme
to each children
prop (the components of the library):
import * as React from 'react';
import { ThemeProvider } from 'styled-components'
import { theme } from './theme';
const ThemeWrapper: React.FC = ({ children }) => {
return (
<ThemeProvider theme={theme}>
{children}
</ThemeProvider>
)
};
export { ThemeWrapper };
And in my Button.tsx
component:
const Button = (props: IButtonProps) => {
return (
<>
<ThemeWrapper> --> Pay attention at this.
<StyledButton {...props}>
{props.leftIcon && <ButtonIcon mr={props.leftIconSpacing}>{props.leftIcon}</ButtonIcon>}
{props.children}
{props.rightIcon && <ButtonIcon ml={props.rightIconSpacing}>{props.rightIcon}</ButtonIcon>}
</StyledButton>
</ThemeWrapper>
</>
)
}
Thank you!