Shared TypeScript type definitions for React Spectrum components and hooks, providing common interfaces for DOM interactions, styling, accessibility, internationalization, and component behavior across the React Spectrum ecosystem
—
Responsive design system with design tokens for dimensions, colors, spacing, and comprehensive layout props supporting flexbox, grid, positioning, and responsive breakpoints.
Comprehensive design token system for consistent styling across components.
/**
* Dimension values including size tokens and responsive units
*/
type DimensionValue =
| "size-0" | "size-10" | "size-25" | "size-40" | "size-50"
| "size-65" | "size-75" | "size-85" | "size-100" | "size-115"
| "size-125" | "size-130" | "size-150" | "size-160" | "size-175"
| "size-200" | "size-225" | "size-250" | "size-275" | "size-300"
| "size-325" | "size-350" | "size-400" | "size-450" | "size-500"
| "size-550" | "size-600" | "size-675" | "size-700" | "size-800"
| "size-900" | "size-1000" | "size-1200" | "size-1250" | "size-1600"
| "size-1700" | "size-2000" | "size-2400" | "size-3000" | "size-3400"
| "size-3600" | "size-4600" | "size-5000" | "size-6000"
// Static size tokens (fixed pixel values)
| "static-size-0" | "static-size-10" | "static-size-25" | "static-size-50"
| "static-size-40" | "static-size-65" | "static-size-100" | "static-size-115"
| "static-size-125" | "static-size-130" | "static-size-150" | "static-size-160"
| "static-size-175" | "static-size-200" | "static-size-225" | "static-size-250"
| "static-size-300" | "static-size-400" | "static-size-450" | "static-size-500"
| "static-size-550" | "static-size-600" | "static-size-700" | "static-size-800"
| "static-size-900" | "static-size-1000" | "static-size-1200" | "static-size-1700"
| "static-size-2400" | "static-size-2600" | "static-size-3400" | "static-size-3600"
| "static-size-4600" | "static-size-5000" | "static-size-6000"
// Special sizing
| "single-line-height" | "single-line-width"
// Custom values
| (string & {})
| number;
/**
* Color values including semantic and static colors
*/
type ColorValue =
// Semantic colors
| "celery-400" | "celery-500" | "celery-600" | "celery-700"
| "chartreuse-400" | "chartreuse-500" | "chartreuse-600" | "chartreuse-700"
| "yellow-400" | "yellow-500" | "yellow-600" | "yellow-700"
| "magenta-400" | "magenta-500" | "magenta-600" | "magenta-700"
| "fuchsia-400" | "fuchsia-500" | "fuchsia-600" | "fuchsia-700"
| "purple-400" | "purple-500" | "purple-600" | "purple-700"
| "indigo-400" | "indigo-500" | "indigo-600" | "indigo-700"
| "seafoam-400" | "seafoam-500" | "seafoam-600" | "seafoam-700"
| "red-400" | "red-500" | "red-600" | "red-700"
| "orange-400" | "orange-500" | "orange-600" | "orange-700"
| "green-400" | "green-500" | "green-600" | "green-700"
| "blue-400" | "blue-500" | "blue-600" | "blue-700"
// Gray scale
| "gray-50" | "gray-75" | "gray-100" | "gray-200" | "gray-300"
| "gray-400" | "gray-500" | "gray-600" | "gray-700" | "gray-800" | "gray-900"
// Static colors (fixed across themes)
| "static-black" | "static-white" | "static-blue"
| "static-gray-50" | "static-gray-75" | "static-gray-100" | "static-gray-200"
| "static-gray-300" | "static-gray-400" | "static-gray-500" | "static-gray-600"
| "static-gray-700" | "static-gray-800" | "static-gray-900"
// ... many more static color variants
| SemanticColorValue;
/** Semantic color aliases */
type SemanticColorValue = "negative" | "notice" | "positive" | "informative";
/** Border size values */
type BorderSizeValue = "thin" | "thick" | "thicker" | "thickest" | "none";
/** Border radius values */
type BorderRadiusValue = "xsmall" | "small" | "regular" | "medium" | "large";
/** Icon color values */
type IconColorValue = "negative" | "notice" | "positive" | "informative";
/** Background color values */
type BackgroundColorValue = "default" | "disabled" | "transparent" | "label-gray" | ColorValue;
/** Border color values */
type BorderColorValue = "default" | BorderColorAlias | ColorValue;
/** Color version for design system compatibility */
type ColorVersion = 5 | 6;Responsive prop system supporting multiple breakpoints.
/**
* Responsive prop object with breakpoint support
* @template T The type of the property value
*/
type ResponsiveProp<T> = {
/** Base value (mobile-first) */
base?: T;
/** Small breakpoint */
S?: T;
/** Medium breakpoint */
M?: T;
/** Large breakpoint */
L?: T;
/** Custom breakpoint names */
[custom: string]: T | undefined;
};
/**
* Responsive value can be a single value or responsive object
* @template T The type of the property value
*/
type Responsive<T> = T | ResponsiveProp<T>;Core styling properties for layout, spacing, and visual appearance.
/**
* Base style properties for all components
*/
interface StyleProps {
/** Sets the CSS className for the element. Only use as a last resort. Use style props instead. */
UNSAFE_className?: string;
/** Sets inline style for the element. Only use as a last resort. Use style props instead. */
UNSAFE_style?: CSSProperties;
// Margin properties
/** The margin for all four sides of the element */
margin?: Responsive<DimensionValue>;
/** The margin for the logical start side of the element, depending on layout direction */
marginStart?: Responsive<DimensionValue>;
/** The margin for the logical end side of an element, depending on layout direction */
marginEnd?: Responsive<DimensionValue>;
/** The margin for the top side of the element */
marginTop?: Responsive<DimensionValue>;
/** The margin for the bottom side of the element */
marginBottom?: Responsive<DimensionValue>;
/** The margin for both the left and right sides of the element */
marginX?: Responsive<DimensionValue>;
/** The margin for both the top and bottom sides of the element */
marginY?: Responsive<DimensionValue>;
// Dimension properties
/** The width of the element */
width?: Responsive<DimensionValue>;
/** The height of the element */
height?: Responsive<DimensionValue>;
/** The minimum width of the element */
minWidth?: Responsive<DimensionValue>;
/** The minimum height of the element */
minHeight?: Responsive<DimensionValue>;
/** The maximum width of the element */
maxWidth?: Responsive<DimensionValue>;
/** The maximum height of the element */
maxHeight?: Responsive<DimensionValue>;
// Flex item properties
/** When used in a flex layout, specifies how the element will grow or shrink to fit the space available */
flex?: Responsive<string | number | boolean>;
/** When used in a flex layout, specifies how the element will grow to fit the space available */
flexGrow?: Responsive<number>;
/** When used in a flex layout, specifies how the element will shrink to fit the space available */
flexShrink?: Responsive<number>;
/** When used in a flex layout, specifies the initial main size of the element */
flexBasis?: Responsive<number | string>;
/** Specifies how the element is justified inside a flex or grid container */
justifySelf?: Responsive<"auto" | "normal" | "start" | "end" | "flex-start" | "flex-end" | "self-start" | "self-end" | "center" | "left" | "right" | "stretch">;
/** Overrides the alignItems property of a flex or grid container */
alignSelf?: Responsive<"auto" | "normal" | "start" | "end" | "center" | "flex-start" | "flex-end" | "self-start" | "self-end" | "stretch">;
/** The layout order for the element within a flex or grid container */
order?: Responsive<number>;
// Grid item properties
/** When used in a grid layout, specifies the named grid area that the element should be placed in within the grid */
gridArea?: Responsive<string>;
/** When used in a grid layout, specifies the column the element should be placed in within the grid */
gridColumn?: Responsive<string>;
/** When used in a grid layout, specifies the row the element should be placed in within the grid */
gridRow?: Responsive<string>;
/** When used in a grid layout, specifies the starting column to span within the grid */
gridColumnStart?: Responsive<string>;
/** When used in a grid layout, specifies the ending column to span within the grid */
gridColumnEnd?: Responsive<string>;
/** When used in a grid layout, specifies the starting row to span within the grid */
gridRowStart?: Responsive<string>;
/** When used in a grid layout, specifies the ending row to span within the grid */
gridRowEnd?: Responsive<string>;
// Positioning properties
/** Specifies how the element is positioned */
position?: Responsive<"static" | "relative" | "absolute" | "fixed" | "sticky">;
/** The stacking order for the element */
zIndex?: Responsive<number>;
/** The top position for the element */
top?: Responsive<DimensionValue>;
/** The bottom position for the element */
bottom?: Responsive<DimensionValue>;
/** The logical start position for the element, depending on layout direction */
start?: Responsive<DimensionValue>;
/** The logical end position for the element, depending on layout direction */
end?: Responsive<DimensionValue>;
/** The left position for the element. Consider using start instead for RTL support */
left?: Responsive<DimensionValue>;
/** The right position for the element. Consider using end instead for RTL support */
right?: Responsive<DimensionValue>;
/** Hides the element */
isHidden?: Responsive<boolean>;
}Extended style properties with colors and borders for visual components.
/**
* Extended style properties with color and border support
* @template C The color version (5 or 6)
*/
interface ViewStyleProps<C extends ColorVersion> extends StyleProps {
/**
* The Spectrum color token version number
* @default 5
*/
colorVersion?: C;
/** The background color for the element */
backgroundColor?: Responsive<BackgroundColor[C]>;
// Border width properties
/** The width of the element's border on all four sides */
borderWidth?: Responsive<BorderSizeValue>;
/** The width of the border on the logical start side, depending on the layout direction */
borderStartWidth?: Responsive<BorderSizeValue>;
/** The width of the border on the logical end side, depending on the layout direction */
borderEndWidth?: Responsive<BorderSizeValue>;
/** The width of the top border */
borderTopWidth?: Responsive<BorderSizeValue>;
/** The width of the bottom border */
borderBottomWidth?: Responsive<BorderSizeValue>;
/** The width of the left and right borders */
borderXWidth?: Responsive<BorderSizeValue>;
/** The width of the top and bottom borders */
borderYWidth?: Responsive<BorderSizeValue>;
// Border color properties
/** The color of the element's border on all four sides */
borderColor?: Responsive<BorderColor[C]>;
/** The color of the border on the logical start side, depending on the layout direction */
borderStartColor?: Responsive<BorderColor[C]>;
/** The color of the border on the logical end side, depending on the layout direction */
borderEndColor?: Responsive<BorderColor[C]>;
/** The color of the top border */
borderTopColor?: Responsive<BorderColor[C]>;
/** The color of the bottom border */
borderBottomColor?: Responsive<BorderColor[C]>;
/** The color of the left and right borders */
borderXColor?: Responsive<BorderColor[C]>;
/** The color of the top and bottom borders */
borderYColor?: Responsive<BorderColor[C]>;
// Border radius properties
/** The border radius on all four sides of the element */
borderRadius?: Responsive<BorderRadiusValue>;
/** The border radius for the top start corner of the element, depending on the layout direction */
borderTopStartRadius?: Responsive<BorderRadiusValue>;
/** The border radius for the top end corner of the element, depending on the layout direction */
borderTopEndRadius?: Responsive<BorderRadiusValue>;
/** The border radius for the bottom start corner of the element, depending on the layout direction */
borderBottomStartRadius?: Responsive<BorderRadiusValue>;
/** The border radius for the bottom end corner of the element, depending on the layout direction */
borderBottomEndRadius?: Responsive<BorderRadiusValue>;
// Padding properties
/** The padding for all four sides of the element */
padding?: Responsive<DimensionValue>;
/** The padding for the logical start side of the element, depending on layout direction */
paddingStart?: Responsive<DimensionValue>;
/** The padding for the logical end side of an element, depending on layout direction */
paddingEnd?: Responsive<DimensionValue>;
/** The padding for the top side of the element */
paddingTop?: Responsive<DimensionValue>;
/** The padding for the bottom side of the element */
paddingBottom?: Responsive<DimensionValue>;
/** The padding for both the left and right sides of the element */
paddingX?: Responsive<DimensionValue>;
/** The padding for both the top and bottom sides of the element */
paddingY?: Responsive<DimensionValue>;
/** Species what to do when the element's content is too long to fit its size */
overflow?: Responsive<string>;
}Properties for controlling alignment in flex and grid layouts.
/**
* Box alignment properties for flex and grid layouts
*/
interface BoxAlignmentStyleProps {
/** The distribution of space around items along the main axis */
justifyContent?: Responsive<"start" | "end" | "center" | "left" | "right" | "space-between" | "space-around" | "space-evenly" | "stretch" | "baseline" | "first baseline" | "last baseline" | "safe center" | "unsafe center">;
/** The distribution of space around child items along the cross axis */
alignContent?: Responsive<"start" | "end" | "center" | "space-between" | "space-around" | "space-evenly" | "stretch" | "baseline" | "first baseline" | "last baseline" | "safe center" | "unsafe center">;
/** The alignment of children within their container */
alignItems?: Responsive<"start" | "end" | "center" | "stretch" | "self-start" | "self-end" | "baseline" | "first baseline" | "last baseline" | "safe center" | "unsafe center">;
/** The space to display between both rows and columns */
gap?: Responsive<DimensionValue>;
/** The space to display between columns */
columnGap?: Responsive<DimensionValue>;
/** The space to display between rows */
rowGap?: Responsive<DimensionValue>;
}Properties specific to flexbox layouts.
/**
* Flex layout properties
*/
interface FlexStyleProps extends BoxAlignmentStyleProps, StyleProps {
/**
* The direction in which to layout children
* @default "row"
*/
direction?: Responsive<"row" | "column" | "row-reverse" | "column-reverse">;
/**
* Whether to wrap items onto multiple lines
* @default false
*/
wrap?: Responsive<boolean | "wrap" | "nowrap" | "wrap-reverse">;
}Properties specific to CSS Grid layouts.
/**
* Grid layout properties
*/
interface GridStyleProps extends BoxAlignmentStyleProps, StyleProps {
/** Defines named grid areas */
areas?: Responsive<string[]>;
/** Defines the sizes of each row in the grid */
rows?: Responsive<string | DimensionValue[]>;
/** Defines the sizes of each column in the grid */
columns?: Responsive<string | DimensionValue[]>;
/** Defines the size of implicitly generated columns */
autoColumns?: Responsive<DimensionValue>;
/** Defines the size of implicitly generated rows */
autoRows?: Responsive<DimensionValue>;
/** Controls how auto-placed items are flowed into the grid */
autoFlow?: Responsive<"row" | "column" | "row dense" | "column dense">;
/** Defines the default justifySelf for all items in the grid */
justifyItems?: Responsive<"auto" | "normal" | "start" | "end" | "center" | "left" | "right" | "stretch" | "self-start" | "self-end" | "baseline" | "first baseline" | "last baseline" | "safe center" | "unsafe center" | "legacy right" | "legacy left" | "legacy center">;
}Usage Examples:
import {
StyleProps,
ViewStyleProps,
FlexStyleProps,
GridStyleProps,
DimensionValue,
ColorValue,
Responsive
} from "@react-types/shared";
// Basic styled component
interface StyledBoxProps extends StyleProps {
children: React.ReactNode;
}
function StyledBox({ children, ...styleProps }: StyledBoxProps) {
return (
<div
style={{
// Convert style props to CSS properties
// In a real implementation, you'd use a style processing library
margin: resolveResponsiveValue(styleProps.margin),
padding: resolveResponsiveValue(styleProps.padding),
width: resolveResponsiveValue(styleProps.width),
height: resolveResponsiveValue(styleProps.height),
display: styleProps.isHidden ? "none" : undefined,
position: resolveResponsiveValue(styleProps.position)
}}
>
{children}
</div>
);
}
// Utility to resolve responsive values (simplified implementation)
function resolveResponsiveValue<T>(value: Responsive<T> | undefined): T | undefined {
if (!value) return undefined;
if (typeof value === "object" && "base" in value) {
// In a real implementation, you'd check current breakpoint
// and return the appropriate value
return value.base || value.S || value.M || value.L;
}
return value as T;
}
// Flex container component
interface FlexProps extends FlexStyleProps {
children: React.ReactNode;
as?: keyof JSX.IntrinsicElements;
}
function Flex({
children,
as: Component = "div",
direction = "row",
wrap = false,
justifyContent,
alignItems,
gap,
...styleProps
}: FlexProps) {
return (
<Component
style={{
display: "flex",
flexDirection: resolveResponsiveValue(direction),
flexWrap: resolveResponsiveValue(wrap) === true ? "wrap" : resolveResponsiveValue(wrap) as any,
justifyContent: resolveResponsiveValue(justifyContent),
alignItems: resolveResponsiveValue(alignItems),
gap: resolveResponsiveValue(gap),
// Apply other style props
margin: resolveResponsiveValue(styleProps.margin),
padding: resolveResponsiveValue(styleProps.padding),
width: resolveResponsiveValue(styleProps.width),
height: resolveResponsiveValue(styleProps.height)
}}
>
{children}
</Component>
);
}
// Grid container component
interface GridProps extends GridStyleProps {
children: React.ReactNode;
as?: keyof JSX.IntrinsicElements;
}
function Grid({
children,
as: Component = "div",
columns,
rows,
areas,
gap,
autoFlow,
justifyItems,
alignItems,
...styleProps
}: GridProps) {
const gridTemplateAreas = resolveResponsiveValue(areas)?.map(area => `"${area}"`).join(" ");
return (
<Component
style={{
display: "grid",
gridTemplateColumns: Array.isArray(resolveResponsiveValue(columns))
? (resolveResponsiveValue(columns) as DimensionValue[]).join(" ")
: resolveResponsiveValue(columns),
gridTemplateRows: Array.isArray(resolveResponsiveValue(rows))
? (resolveResponsiveValue(rows) as DimensionValue[]).join(" ")
: resolveResponsiveValue(rows),
gridTemplateAreas,
gridAutoFlow: resolveResponsiveValue(autoFlow),
justifyItems: resolveResponsiveValue(justifyItems),
alignItems: resolveResponsiveValue(alignItems),
gap: resolveResponsiveValue(gap),
// Apply other style props
margin: resolveResponsiveValue(styleProps.margin),
padding: resolveResponsiveValue(styleProps.padding),
width: resolveResponsiveValue(styleProps.width),
height: resolveResponsiveValue(styleProps.height)
}}
>
{children}
</Component>
);
}
// Card component with view styling
interface CardProps extends ViewStyleProps<5> {
children: React.ReactNode;
variant?: "elevated" | "outlined" | "filled";
}
function Card({
children,
variant = "elevated",
backgroundColor = "default",
borderRadius = "medium",
padding = "size-200",
...styleProps
}: CardProps) {
const getVariantStyles = () => {
switch (variant) {
case "elevated":
return {
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
border: "none"
};
case "outlined":
return {
border: "1px solid var(--spectrum-border-color-mid)",
boxShadow: "none"
};
case "filled":
return {
backgroundColor: "var(--spectrum-background-color-gray-50)",
border: "none",
boxShadow: "none"
};
default:
return {};
}
};
return (
<div
style={{
...getVariantStyles(),
backgroundColor: resolveResponsiveValue(backgroundColor),
borderRadius: resolveResponsiveValue(borderRadius),
padding: resolveResponsiveValue(padding),
// Apply other style props
margin: resolveResponsiveValue(styleProps.margin),
width: resolveResponsiveValue(styleProps.width),
height: resolveResponsiveValue(styleProps.height)
}}
>
{children}
</div>
);
}
// Responsive design examples
function ResponsiveLayoutExamples() {
return (
<div>
{/* Responsive margins and padding */}
<StyledBox
margin={{ base: "size-100", M: "size-200", L: "size-300" }}
padding={{ base: "size-50", M: "size-100" }}
width={{ base: "100%", M: "size-3000", L: "size-4600" }}
>
<h2>Responsive Box</h2>
<p>This box has different margins and padding at different breakpoints.</p>
</StyledBox>
{/* Responsive flex layout */}
<Flex
direction={{ base: "column", M: "row" }}
gap={{ base: "size-100", M: "size-200" }}
justifyContent={{ base: "stretch", M: "space-between" }}
margin="size-300"
>
<Card padding="size-150" flex={{ base: "none", M: 1 }}>
<h3>Card 1</h3>
<p>Stacks vertically on mobile, horizontally on desktop.</p>
</Card>
<Card padding="size-150" flex={{ base: "none", M: 1 }}>
<h3>Card 2</h3>
<p>Equal width on desktop.</p>
</Card>
<Card padding="size-150" flex={{ base: "none", M: 1 }}>
<h3>Card 3</h3>
<p>Responsive flex behavior.</p>
</Card>
</Flex>
{/* Responsive grid layout */}
<Grid
columns={{
base: "1fr",
S: "repeat(2, 1fr)",
M: "repeat(3, 1fr)",
L: "repeat(4, 1fr)"
}}
gap={{ base: "size-100", M: "size-200" }}
margin="size-300"
>
{Array.from({ length: 8 }, (_, i) => (
<Card key={i} padding="size-150">
<h4>Grid Item {i + 1}</h4>
<p>Responsive grid columns.</p>
</Card>
))}
</Grid>
{/* Complex grid with areas */}
<Grid
areas={[
"header header header",
"sidebar main main",
"footer footer footer"
]}
rows={["auto", "1fr", "auto"]}
columns={["200px", "1fr", "1fr"]}
gap="size-200"
height="size-6000"
margin="size-300"
>
<Card gridArea="header" padding="size-150" backgroundColor="blue-100">
<h2>Header</h2>
</Card>
<Card gridArea="sidebar" padding="size-150" backgroundColor="green-100">
<h3>Sidebar</h3>
<ul>
<li>Nav Item 1</li>
<li>Nav Item 2</li>
<li>Nav Item 3</li>
</ul>
</Card>
<Card gridArea="main" padding="size-150" backgroundColor="gray-50">
<h3>Main Content</h3>
<p>This is the main content area with a responsive grid layout.</p>
</Card>
<Card gridArea="footer" padding="size-150" backgroundColor="purple-100">
<p>Footer content</p>
</Card>
</Grid>
{/* Positioning example */}
<div style={{ position: "relative", height: "400px", margin: "32px 0" }}>
<Card
position="absolute"
top="size-100"
start="size-100"
padding="size-150"
backgroundColor="red-100"
>
Positioned absolutely
</Card>
<Card
position="absolute"
bottom="size-100"
end="size-100"
padding="size-150"
backgroundColor="blue-100"
>
Bottom right positioned
</Card>
<Card
position="absolute"
top="50%"
start="50%"
padding="size-150"
backgroundColor="green-100"
style={{ transform: "translate(-50%, -50%)" }}
>
Centered with transform
</Card>
</div>
</div>
);
}
// Advanced styling utilities
class StyleUtils {
/**
* Convert design token to CSS value
*/
static resolveDimensionValue(value: DimensionValue): string {
if (typeof value === "number") {
return `${value}px`;
}
if (typeof value === "string") {
// In a real implementation, you'd have a token mapping
const tokenMap: Record<string, string> = {
"size-50": "4px",
"size-100": "8px",
"size-150": "12px",
"size-200": "16px",
"size-300": "24px",
"size-400": "32px",
"size-500": "40px",
// ... many more mappings
};
return tokenMap[value] || value;
}
return value;
}
/**
* Generate responsive CSS media queries
*/
static generateResponsiveCSS<T>(
property: string,
value: Responsive<T> | undefined,
resolver: (val: T) => string
): string {
if (!value) return "";
if (typeof value === "object" && "base" in value) {
let css = "";
if (value.base !== undefined) {
css += `${property}: ${resolver(value.base)};\n`;
}
if (value.S !== undefined) {
css += `@media (min-width: 480px) { ${property}: ${resolver(value.S)}; }\n`;
}
if (value.M !== undefined) {
css += `@media (min-width: 768px) { ${property}: ${resolver(value.M)}; }\n`;
}
if (value.L !== undefined) {
css += `@media (min-width: 1024px) { ${property}: ${resolver(value.L)}; }\n`;
}
return css;
}
return `${property}: ${resolver(value as T)};\n`;
}
/**
* Create a theme-aware color resolver
*/
static createColorResolver(colorVersion: ColorVersion = 5) {
return (color: ColorValue): string => {
// In a real implementation, you'd have theme-specific color mappings
const colorMap: Record<string, string> = {
"blue-400": colorVersion === 5 ? "#378ef0" : "#0d66d0",
"blue-500": colorVersion === 5 ? "#2680eb" : "#0054cc",
"blue-600": colorVersion === 5 ? "#1473e6" : "#0048b3",
"red-400": colorVersion === 5 ? "#ec5b62" : "#d83948",
"red-500": colorVersion === 5 ? "#e34850" : "#c9252d",
// ... many more color mappings
};
return colorMap[color] || color;
};
}
}
// Theme provider context
const ThemeContext = React.createContext<{
colorVersion: ColorVersion;
breakpoint: string;
}>({
colorVersion: 5,
breakpoint: "base"
});
function ThemeProvider({
children,
colorVersion = 5
}: {
children: React.ReactNode;
colorVersion?: ColorVersion;
}) {
const [breakpoint, setBreakpoint] = useState("base");
useEffect(() => {
const updateBreakpoint = () => {
const width = window.innerWidth;
if (width >= 1024) setBreakpoint("L");
else if (width >= 768) setBreakpoint("M");
else if (width >= 480) setBreakpoint("S");
else setBreakpoint("base");
};
updateBreakpoint();
window.addEventListener("resize", updateBreakpoint);
return () => window.removeEventListener("resize", updateBreakpoint);
}, []);
return (
<ThemeContext.Provider value={{ colorVersion, breakpoint }}>
{children}
</ThemeContext.Provider>
);
}
// Hook to use theme context
function useTheme() {
return useContext(ThemeContext);
}Install with Tessl CLI
npx tessl i tessl/npm-react-types--shared