from typing import TypedDict, Union, Literal, Tuple, Optional, cast # --- Units and Sizes --- MediaQueryCheck = Literal["max-width", "min-width", "max-height", "min-height"] Unit = Literal["px", "em", "rem", "%", "vh", "vw"] Size = Tuple[float, Unit] # e.g., (16.0, "px") MediaQuery = Tuple[MediaQueryCheck, float, Unit] # --- Colors --- RGB = Tuple[float, float, float] # 0-255 or 0.0-1.0 RGBA = Tuple[float, float, float, float] # includes alpha Color = Union[RGB, RGBA] # --- Positions --- PositionKeyword = Literal["static", "relative", "absolute", "fixed", "sticky"] # --- Display --- Display = Literal["none", "block", "inline", "inline-block", "flex", "grid"] # --- Alignment --- TextAlign = Literal["left", "right", "center", "justify", "start", "end"] # --- Overflow --- Overflow = Literal["visible", "hidden", "scroll", "auto", "clip"] # --- Border Style --- BorderStyle = Literal["none", "solid", "dashed", "dotted", "double", "groove", "ridge", "inset", "outset"] # --- Length / Size or keyword --- AutoSize = Union[Size, Literal["auto"]] class CSS(TypedDict, total=False): color: Color backgroundColor: Color fontSize: Size margin: Union[AutoSize, Tuple[AutoSize, AutoSize], Tuple[AutoSize, AutoSize, AutoSize, AutoSize]] padding: Union[AutoSize, Tuple[AutoSize, AutoSize], Tuple[AutoSize, AutoSize, AutoSize, AutoSize]] width: AutoSize height: AutoSize display: Display position: PositionKeyword top: AutoSize left: AutoSize right: AutoSize bottom: AutoSize textAlign: TextAlign overflow: Overflow borderColor: Color borderWidth: Size borderStyle: BorderStyle opacity: float # 0.0 to 1.0 zIndex: int lineHeight: Union[float, Size] # --- Media Queries --- ChildMQ = Tuple[Size, MediaQueryCheck] ScopedCSS = Tuple[MediaQuery, CSS] def Styles( color: Optional[Color] = None, backgroundColor: Optional[Color] = None, fontSize: Optional[Size] = None, display: Optional[Display] = None, ) -> CSS: return cast(CSS, {k: v for k, v in locals().items() if v is not None}) def ScopedStyles( mediaQuery: MediaQuery, styles: CSS ) -> ScopedCSS: return (mediaQuery, styles) test = ScopedStyles( ("max-width", 1024, "px"), { "fontSize":(16, "px"), "color":(255, 0, 0), "backgroundColor":(0, 255, 0), "display":"flex", } ) print(test)