How to type a color prop?
This one is pretty hard to encode in TypeScript's type system. I believe a full fledged parser can do a better job in both speed and accuracy.
Anyway, if you really want to get some typecheking for your color
values from typescript then let's start with w3c color property description:
Values: <color value> | <color keyword> | currentColor | transparent | inherit
playground link for those who don't need explanations and what to look right into the code.
Well, color keyword
, currentColor
, transparent
and inherit
are pretty straightforward:
type Color = ColorValue | ColorKeyword | 'currentColor' | 'transparent' | 'inherit'
type ColorKeyword =
| "black"
| "silver"
| "gray"
...
| "rebeccapurple"
The tricky part is <color value>
:
The color can be specified as
* a hexadecimal RGB value: #faf or #ffaaff
* a RGB value: rgb(255, 160, 255) or rgb(100%, 62.5%, 100%)
Each value is from 0 to 255, or from 0% to 100%.
* a RGBA value: rgba(255, 160, 255, 1) or rgba(100%, 62.5%, 100%, 1)
This variant includes an “alpha” component to allow
specification of the opacity of a color. Values are
in the range 0.0 (fully transparent) to 1.0 (fully opaque).
* a HSL value: hsl(0, 100%, 50%)
A triple (hue, saturation, lightness). hue is an
angle in degrees. saturation and lightness are
percentages (0-100%).
* a HSLA value: hsla(0, 100%, 50%, 1)
This variant includes an “alpha” component to allow
specification of the opacity of a color. Values are
in the range 0.0 (fully transparent) to 1.0 (fully opaque).
hexadecimal RGB value
is still ok-ish:
type HexDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
type Hex3 = `${HexDigit}${HexDigit}${HexDigit}`
type RGBColor<T extends string> =
Lowercase<T> extends `#${Hex3}`
? T
: Lowercase<T> extends `#${Hex3}${infer Rest}`
? Rest extends Hex3
? T
: never
: never
We have to introduce type variable T
. Otherwise 'flat' union type:
type RGBColor = `#${Hex3}` | `#${Hex3}${Hex3}`
is going to consist of 16^3 + 16^6
constituents that's far beyound 100000
typescript limit for union types.
Let's introduce some helper types to work with numbers. We have to check the percents are not greater than 100%
and end with %
character.
type DecDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
type Digits0to4 = '0' | '1' | '2' | '3' | '4'
type OnlyDecDigits<T extends string> =
T extends `${DecDigit}${infer Rest}`
? Rest extends ''
? 1
: OnlyDecDigits<Rest>
: never
type IsDecNumber<T extends string> =
T extends `${infer Integer}.${infer Fractional}`
? Integer extends ''
? OnlyDecDigits<Fractional>
: Fractional extends ''
? OnlyDecDigits<Integer>
: OnlyDecDigits<Integer> & OnlyDecDigits<Fractional>
: OnlyDecDigits<T>
type IntegerPart<T extends string> =
T extends `${infer I}.${infer F}`
? I
: T
type IsInteger<T extends string> =
1 extends IsDecNumber<T>
? T extends IntegerPart<T>
? 1
: never
: never
type Less100<T extends string> =
IsDecNumber<T> extends 1
? IntegerPart<T> extends `${DecDigit}` | `${DecDigit}${DecDigit}` | '100'
? 1
: never
: never
type IsPercent<T extends string> =
'0' extends T
? 1
: T extends `${infer P}%`
? Less100<P>
: never
Also color values must be integers and not greater than 255
:
type Color255<T extends string> =
1 extends IsInteger<T>
? T extends `${DecDigit}`
| `${DecDigit}${DecDigit}`
| `1${DecDigit}${DecDigit}`
| `2${Digits0to4}${DecDigit}`
| `25${Digits0to4 | '5'}`
? 1
: never
: never
so, any color value can be encoded as an integer number in [0..255]
range or a percent:
type IsColorValue<T extends string> = IsPercent<T> | Color255<T>
Adding utility Trim
type to trim extra spaces on both ends:
type WhiteSpace = ' '
type Trim<T> = T extends `${WhiteSpace}${infer U}`
? Trim<U>
: T extends `${infer U}${WhiteSpace}`
? Trim<U>
: T;
That's enough for rgb
:
type RGB<T extends string> =
T extends `rgb(${infer R},${infer G},${infer B})`
? '111' extends `${IsColorValue<Trim<R>>}${IsColorValue<Trim<G>>}${IsColorValue<Trim<B>>}`
? T
: never
: never
For rgba
/hsla
we'll need opacity. Here we just ask for any valid number or a percent:
type Opacity<T extends string> = IsDecNumber<T> | IsPercent<T>
Now we can check rgba
values:
type RGBA<T extends string> =
T extends `rgba(${infer R},${infer G},${infer B},${infer O})`
? '1111' extends `${IsColorValue<Trim<R>>}${IsColorValue<Trim<G>>}${IsColorValue<Trim<B>>}${Opacity<Trim<O>>}`
? T
: never
: never
Adding degree checker for hsl
/hsla
:
type Degree<T extends string> =
1 extends IsInteger<T>
? T extends `${DecDigit}`
| `${DecDigit}${DecDigit}`
| `${'1' | '2'}${DecDigit}${DecDigit}`
| `3${Digits0to4 | '5'}${DecDigit}`
| '360'
? 1
: never
: never
and finally we can cover the last cases:
type HSL<T extends string> =
T extends `hsl(${infer H},${infer S},${infer L})`
? `111` extends `${Degree<Trim<H>>}${IsPercent<Trim<S>>}${IsPercent<Trim<L>>}`
? T
: never
:never
type HSLA<T extends string> =
T extends `hsla(${infer H},${infer S},${infer L},${infer O})`
? `1111` extends `${Degree<Trim<H>>}${IsPercent<Trim<S>>}${IsPercent<Trim<L>>}${Opacity<Trim<O>>}`
? T
: never
:never
So our final type will look like that:
type ColorValue<T extends string> = HexColor<T> | RGB<T> | RGBA<T> | HSL<T> | HSLA<T>
type Color<T extends string> = ColorValue<T> | ColorKeyword | 'currentColor' | 'transparent' | 'inherit'
playground link
How to pass props to react component to change text color
It will work if you change your h3
className to template string:
<h3 className={`${styles.h3} ${props.lightText ? styles.lightText : styles.darkText}`}>{props.text}</h3>
or at least last part of it:
<h3 className={styles.h3 + " " + `${props.lightText ? styles.lightText : styles.darkText}`}>{props.text}</h3>
Here you can find a lot of great examples how to add multiple classnames: How to add multiple classes to a ReactJS Component?
React props for passing color
The issue is here:
<div className="colors" style={{backgroundColor: {props.color}}}></div>
You need to do like this(remove extra currly braces):
<div className="colors" style={{backgroundColor: props.color}}></div>
react I want to change the color with the value passed by props
Assuming that the Box
component takes a colour as its colorScheme
prop, simply define a mapping from the backgroundColor
to the colour you want to apply.
const COLORS: Record<Props['backgroundColor'], string> = {
primary: "blue",
secondary: "green",
brand: "yellow"
};
export const Button: FunctionComponent<Props> = ({ backgroundColor, size, children }) => {
return (
<Box colorScheme={COLORS[backgroundColor]} size={size}>
{children}
</Box>
);
}
};
How to have custom colors as props with mui v5 react typescript?
Add appcolor as a possilbe type in your ButtonPropsType.ts
type ButtonPropsType = {
color?:
| "inherit"
| "primary"
| "secondary"
| "success"
| "error"
| "info"
| "warning"
| "appcolor"; //<-- Here
disabled?: boolean;
variant?: "text" | "outlined" | "contained";
};
Alternatively if you want to dynamically add options as needed, mui has an interface for that.
ButtonPropsTypes.ts
import { ButtonProps } from "@mui/material";
type ButtonPropsType = {
color?: ButtonProps["color"];
disabled?: boolean;
variant?: "text" | "outlined" | "contained";
};
export default ButtonPropsType;
createPalette.d.ts
import * as createPalette from "@mui/material/styles/createPalette";
declare module "@mui/material/styles/createPalette" {
interface PaletteOptions {
appcolor?: PaletteColorOptions;
}
interface Palette {
appcolor: PaletteColor;
}
}
declare module "@mui/material" {
interface ButtonPropsColorOverrides {
appcolor;
}
}
Related Topics
Invert Filter Not Working on Ie and Safari
Why Does Queryselector('Div Span') Match Even Though Queryselector('Div') Does Not
Style a D3 Element with Jquery and CSS
How to Have Select Filter in Ngtable
Find Unused Images, CSS Rules, Js Script Blocks
Make View 80% Width of Parent in React Native
Removing Legend on Charts with Chart.Js V2
Highlighting the Clicked Row of a Striped HTML Table
Dynamically Resize Columns in CSS Grid Layout with Mouse
How to Convert X,Y Coordinates to an Angle
How to Add Line Numbers to All Lines in Google Prettify
Javascript: Hiding and Showing Div Tag with a Toggle Button
Set A:Visited Style with JavaScript or Jquery
Blur Img's & Div's in HTML Using CSS