TextInput style Props type react native - reactjs

I'm trying to pass style as props to my custom TextInput component.I found this snippet to type button and label style in props :
import {
StyleProp,
Text,
TextStyle,
View,
ViewStyle
} from 'react-native';
interface IProps {
label: string;
buttonStyle?: StyleProp<ViewStyle>;
labelStyle?: StyleProp<TextStyle>;
}
// rest
but I did not find anything for TextInput nor any documentation about StyleProp
So what is the proper way to pass style to TextInput?

I was checking TextInputProps interface and I found TextStyle is also used for TextInput :
style?: StyleProp<TextStyle>;
so it can be used in these ways :
import {StyleSheet, TextInput, TextInputProps , StyleProp ,
TextStyle } from 'react-native';
type Props = {
style?: StyleProp<TextStyle>,
// or
style?: Pick<TextInputProps, "style">
};
const Input: React.FC<Props> = ({style: propStyles}) =>
<TextInput
style={ [styles.input, propStyles] }
/>
const styles = StyleSheet.create({
input: {...},
});

Related

How to extend Text component in react native elements

I'm trying to extend default theme, extending colors works like a charm, but if I try to extend Text component with more text styles, this doesnt work, I don't understand what I'm doing wrongm. This is my react-native-elements.d.ts file:
react-native-elements.d.ts
import 'react-native-elements';
import { ColorValue, StyleProp, TextStyle } from 'react-native';
type ColorSwatch = {
otherColor: string;
};
declare module 'react-native-elements' {
export interface Colors extends ColorSwatch {}
export interface TextProps {
h5Style: StyleProp<TextStyle>;
}
export interface FullTheme {
colors: RecursivePartial<Colors>;
Text: Partial<TextProps>;
}
}
I'm trying to implement the theme like this:
import { FullTheme } from 'react-native-elements';
export const theme: FullTheme = {
Text: {
h5Style: {
fontFamily: '',
},
}
}
This is the TS error in console:
Object literal may only specify known properties, but 'h5Style' does not exist in type 'Partial<TextProps>'. Did you mean to write 'h1Style'?
Looks like h5Style doesn't exist on the TextProps interface.

Typescript React; How to give type to JSS classes object

My react code:
import React from 'react';
import withStyles from "react-jss";
const styles = {
box: {
border: "2px solid #000"
}
};
interface ComponentProps {}
class Welcome extends React.Component<ComponentProps> {
render() {
const {classes, children} = this.props;
return(<div className={classes.box}></div>);
}
}
export default withStyles(styles)(Welcome);
In this const {classes, children} = this.props; is showing this error at classes:
Property 'classes' does not exist on type 'Readonly<ComponentProps> & Readonly<{ children?: ReactNode; }>'.ts(2339)
Only way to get rid of this error seems to be doing this;
interface ComponentProps {
classes:any
}
But using any is semantically wrong. What type should I give to classes, or is this not how jss is used in typescript-react?
(JSS how to use with TS: github.com/cssinjs/jss/blob/master/docs/react-jss-ts.md (only functional component))
It looks like you are using withStyles, which comes from material ui. Material UI has CSSProperties, which is what you need.
import { CSSProperties } from "#material-ui/styles";
interface ComponentProps {
classes: CSSProperties;
}
For a non-MUI solution, check out CSSType:
import CSS from "csstype";
interface ComponentProps {
classes: { [key: string]: CSS };
}

How do I extend react-bootstrap component using typescript?

I am using react-bootstrap#1.0.0-beta.14 and I am trying to create a custom Button component using react-bootstraps Button, adding another prop, isLoading.
Because of the way react-bootstrap types are defined I ended up importing some helpers types and copying a part of react-bootstrap types:
import React from 'react'
import { Button as Btn, ButtonProps } from 'react-bootstrap'
import { BsPrefixProps, ReplaceProps } from 'react-bootstrap/helpers'
interface Props {
isLoading?: boolean
}
type BtnProps<As extends React.ElementType = 'button'> = ReplaceProps<
As,
BsPrefixProps<As> & ButtonProps
>
export const Button: React.FC<BtnProps & Props> = ({ isLoading, disabled, ...props }) => {
return <Btn {...props} disabled={isLoading || disabled} />
}
This almost works. The error I got is telling me that ref prop types are wrong:
Types of property 'ref' are incompatible.
...
Type '(instance: HTMLButtonElement | null) => void' is not assignable to type '(instance: Button> | null) => void'.
I stripped most of the error message to get the relevant bit.
Do I need to wrap the component in forwardRef for this work?
you can see better way of doing is at following code piece.
import React from 'react';
import { Button, ButtonProps } from 'react-bootstrap'
interface PropType extends ButtonProps {
buttonText: string;
isSubmitting: boolean;
}
export const SubmitButton: React.FC<PropType> = (props: PropType) => {
let { isSubmitting, buttonText, ...remainingProps } = props;
return (
<Button variant="primary" type="submit" disabled={props.isSubmitting} style={{margin: 10}} {...remainingProps}>
{props.buttonText}
</Button>
)
}
So, I decided to solve this with a workaround:
export const Button: React.FC<Props & React.ButtonHTMLAttributes<HTMLButtonElement>> =
({ isLoading, disabled, ...props }) =>
<Btn disabled={isLoading || props.disabled} {...props} />
This is not ideal because in theory, Btn can be a different native element (not always a button) but it's good enough for my use case.
I am just wondering if the following simplification would not suffice?
import React from 'react'
import { Button as Btn, ButtonProps } from 'react-bootstrap'
interface Props {
isLoading?: boolean
}
export const Button: React.FC<ButtonProps & Props> = ({ isLoading, ...props }) => {
return <Btn {...props} disabled={isLoading || props.disabled} />
}
I know this was answered a while back, but I had a similar problem and am fairly happy I just about got to the 'right' solution. In detail it's here: https://shaderfun.com/2021/10/04/extending-boot-strap-in-type-script/
This example shows how I did it:
//imports
import React from "react";
import { Button, ButtonProps } from "react-bootstrap";
import { BsPrefixProps, ReplaceProps } from "react-bootstrap/helpers"
import { BsInfo } from 'react-icons/bs'
//handy type defintion to wrap up the replace+bsprefix bits of bootstrap
type BootstrapComponentProps<As extends React.ElementType, P> = ReplaceProps<As, BsPrefixProps<As> & P>
//our extended button properties
type NewButtonProps = {
//any new properties we want to add go here
} & ButtonProps
//boot-strap-ified full button properties with all the bells and whistles
type MyInfoButtonProperties<As extends React.ElementType = 'button'> =
BootstrapComponentProps<As, NewButtonProps>
//our button!
export function MyInfoButton<As extends React.ElementType = 'button'>(props: MyInfoButtonProperties<As>) {
return <Button {...props}
variant={props.variant || "light"}>
<BsInfo/>
</Button>
}
I was aiming to create a button that defaulted to 'light' and contained the BsInfo icon from react-icons.

React + Material-UI + Typescript: Inherit props from button to add different variants

I would like to extend the default Material-UI button to add more variants such as "square."
How can I define the prop interface to inherit/combine props.
Here's my code:
import React from "react";
import { Button as MuiButton } from "#material-ui/core";
import { ButtonProps as MuiButtonProps } from "#material-ui/core/Button";
interface ButtonProps extends MuiButtonProps {
variant?: "square";
}
const defaultProps = {};
const Button: React.FC<ButtonProps> = ({variant, children, ...props}) => {
return (
<MuiButton variant={variant} {...props}>
{props.children}
</MuiButton>;
)
};
Button.defaultProps = defaultProps;
export default Button;
Ideally, I would like to use this component like so:
<ExtendedButton href="/" variant="square">Click Me!</ExtendedButton>
The TYpeScript does not allows to override property when extending interfaces. So you should firstly exclude property from MuiButtonProps and then redefine it in ButtonProps.
import React from "react";
import { Button as MuiButton } from "#material-ui/core";
import { ButtonProps as MuiButtonProps } from "#material-ui/core/Button";
interface ButtonProps extends Pick<MuiButtonProps, Exclude<keyof MuiButtonProps, "variant">> {
variant?: "square" | MuiButtonProps["variant"];
}
Property exclusion with Pick and Exclude is for TypeScript 3.5 and below to 2.8. You may see another options to exclude properties depending on TypeScript version you use.
And as you wish to extend current type of existing property variant, you can use index access operator to get type of original variant property to union it with additional "square" type.

How to extend props for Material-UI components using Typescript?

I would like to extend the props of the Button component from Material-UI using typescript to be able pass additional props to it's children.
import { NavLink } from 'react-router-dom';
import { Button } from 'material-ui';
<Button
component={NavLink}
// NavLink props that needs to be added to typescript declarations
activeClassName={classes.activeButton}
exact={true}
to={to}
>
{title}
</Button>
I've tried to add the following declarations in ./app/types/material_ui.d.ts:
declare module 'material-ui' {
interface Button {
activeClassName?: any;
exact?: boolean;
to?: string;
}
}
Which throws the error "TS2693: 'Button' only refers to a type, but is being used as a value here.".
I've also tried the declaration:
import * as React from 'react';
import { PropTypes, StyledComponent } from 'material-ui';
import { ButtonBaseProps } from 'material-ui/ButtonBase';
declare module 'material-ui' {
export interface ButtonProps extends ButtonBaseProps {
color?: PropTypes.Color | 'contrast';
component?: React.ReactNode;
dense?: boolean;
disabled?: boolean;
disableFocusRipple?: boolean;
disableRipple?: boolean;
fab?: boolean;
href?: string;
raised?: boolean;
type?: string;
activeClassName?: any;
exact?: boolean;
to?: string;
}
export class Button extends StyledComponent<ButtonProps> { }
}
Which throws the error "TS2323: Cannot redeclare exported variable 'Button'".
My tsconfig.json looks like this:
{
"compilerOptions": {
...
"paths": {
"history": ["./node_modules/#types/history/index"],
"redux": ["./node_modules/#types/redux/index"],
"react": ["./node_modules/#types/react/index"],
"*": ["./app/types/*", "*"]
},
},
...
}
Finally the original type definition from Material-UI:
import * as React from 'react';
import { StyledComponent, PropTypes } from '..';
import { ButtonBaseProps } from '../ButtonBase';
export interface ButtonProps extends ButtonBaseProps {
color?: PropTypes.Color | 'contrast';
component?: React.ReactNode;
dense?: boolean;
disabled?: boolean;
disableFocusRipple?: boolean;
disableRipple?: boolean;
fab?: boolean;
href?: string;
raised?: boolean;
type?: string;
}
export default class Button extends StyledComponent<ButtonProps> {}
I am using material-ui 1.0.0-beta.8 with react 15.6.1, react-router-dom 4.2.2 and typescript 2.5.2.
import React, { FC } from 'react';
import { Button, ButtonProps } from '#material-ui/core';
interface IProps extends ButtonProps {} // your custom props
const ButtonHco: FC<IProps> = ({
variant,
color,
children,
size,
disabled
}) => {
return (
<Button variant={variant} color={color} size={size} disabled={disabled}>
{children}
</Button>
);
};
export default ButtonHco;
A bit late, but here is another solution. See also the MUI docs Usage of component prop
.
The following button uses the Link component. It allso uses the Link's specific props with their types. It allso adds its own sesific props.
import React from 'react'
import MuiButton, {ButtonProps} from '#material-ui/core/Button'
interface ButtonOptions {
// your custom options with their types
}
const Button = <C extends React.ElementType>(props: ButtonProps<C, {component?: C}> & ButtonOptions ) => {
return <MuiButton {...props}>{props.children}</MuiButton>
}
export default Button
// use like this:
import {Link} from 'react-router-dom'
<Button component={Link} to={'/somelocation'}>
The following code works for me
import { Button, StyledComponent } from 'material-ui';
import { ButtonProps } from 'material-ui/Button';
declare module 'material-ui' {
export interface MyProps {
exact?: boolean;
to?: string;
}
export class Button extends StyledComponent<ButtonProps & MyProps> {
}
}
I don't have the problem with "TS2693: 'Button' only refers to a type, but is being used as a value here. and I'm also using Typescript 2.5.2
Here is a minimalistic sample of extending a Material UI Button (untested).
The extended field will be simply appended after the button label.
import * as React from 'react';
import { ButtonProps } from '#material-ui/core/Button';
import { Button } from '#material-ui/core';
interface Props{
extendedField: string;
}
export class MyExtendedButton extends React.Component<ButtonProps & Props>{
render(){
const {
extendedField,
children,
...buttonProps,
} = this.props;
return (<Button {...buttonProps}>
{children}
: <span style={{color: 'red'}}>
{extendedField}
</span>
</Button>);
}
}

Resources