"""Breakpoints utility.""" from __future__ import annotations from typing import TypeVar breakpoints_values = ["30em", "48em", "62em", "80em", "96em"] breakpoint_names = ["xs", "sm", "md", "lg", "xl"] def set_breakpoints(values: tuple[str, str, str, str, str]): """Overwrite default breakpoint values. Args: values: CSS values in order defining the breakpoints of responsive layouts """ breakpoints_values.clear() breakpoints_values.extend(values) K = TypeVar("K", bound=str) V = TypeVar("V") class Breakpoints(dict[K, V]): """A responsive styling helper.""" def factorize(self): """Removes references to breakpoints names and instead replaces them with their corresponding values. Returns: The factorized breakpoints. """ return Breakpoints( { ( breakpoints_values[breakpoint_names.index(k)] if k in breakpoint_names else ("0px" if k == "initial" else k) ): v for k, v in self.items() if v is not None } ) @classmethod def create( cls, custom: dict[K, V] | None = None, initial: V | None = None, xs: V | None = None, sm: V | None = None, md: V | None = None, lg: V | None = None, xl: V | None = None, ): """Create a new instance of the helper. Only provide a custom component OR use named props. Args: custom: Custom mapping using CSS values or variables. initial: Styling when in the initial width xs: Styling when in the extra-small width sm: Styling when in the small width md: Styling when in the medium width lg: Styling when in the large width xl: Styling when in the extra-large width Raises: ValueError: If both custom and any other named parameters are provided. Returns: The responsive mapping. """ thresholds = [initial, xs, sm, md, lg, xl] if custom is not None: if any(threshold is not None for threshold in thresholds): raise ValueError("Named props cannot be used with custom thresholds") return Breakpoints(custom) else: return Breakpoints( { k: v for k, v in zip( ["initial", *breakpoint_names], thresholds, strict=True ) if v is not None } ) breakpoints = Breakpoints.create T = TypeVar("T") Responsive = T | Breakpoints[str, T]