138 lines
4.2 KiB
Python
138 lines
4.2 KiB
Python
from typing import TypedDict, Union, Literal, Tuple, Optional, cast
|
|
import re
|
|
|
|
# --- Units and Sizes ---
|
|
MediaQueryCheck = Literal["max-width", "min-width", "max-height", "min-height"]
|
|
Unit = Literal["px", "em", "rem", "%", "vh", "vw"]
|
|
Size = Tuple[float, Unit]
|
|
MediaQuery = Tuple[MediaQueryCheck, float, Unit]
|
|
|
|
# --- Colors ---
|
|
RGB = Tuple[float, float, float]
|
|
RGBA = Tuple[float, float, float, float]
|
|
Color = Union[RGB, RGBA]
|
|
|
|
CSSValue = Union[Size, Color, str]
|
|
|
|
# --- 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]
|
|
|
|
def Styles(
|
|
color: Optional[Color] = None,
|
|
backgroundColor: Optional[Color] = None,
|
|
fontSize: Optional[Size] = None,
|
|
margin: Optional[Union[AutoSize, Tuple[AutoSize, AutoSize], Tuple[AutoSize, AutoSize, AutoSize, AutoSize]]] = None,
|
|
padding: Optional[Union[AutoSize, Tuple[AutoSize, AutoSize], Tuple[AutoSize, AutoSize, AutoSize, AutoSize]]] = None,
|
|
width: Optional[AutoSize] = None,
|
|
height: Optional[AutoSize] = None,
|
|
display: Optional[Display] = None,
|
|
position: Optional[PositionKeyword] = None,
|
|
top: Optional[AutoSize] = None,
|
|
left: Optional[AutoSize] = None,
|
|
right: Optional[AutoSize] = None,
|
|
bottom: Optional[AutoSize] = None,
|
|
textAlign: Optional[TextAlign] = None,
|
|
overflow: Optional[Overflow] = None,
|
|
borderColor: Optional[Color] = None,
|
|
borderWidth: Optional[Size] = None,
|
|
borderStyle: Optional[BorderStyle] = None,
|
|
opacity: Optional[float] = None,
|
|
zIndex: Optional[int] = None,
|
|
lineHeight: Optional[Union[float, Size]] = None,
|
|
) -> CSS:
|
|
"""
|
|
Function alternative to create a block of CSS styles.
|
|
"""
|
|
return cast(CSS, {k: v for k, v in locals().items() if v is not None})
|
|
|
|
def Sheet(mq:MediaQuery, *css:CSS):
|
|
"""
|
|
Serialize a CSS sheet with a media query and multiple CSS dictionaries.
|
|
"""
|
|
lines:list[str] = []
|
|
lines.append(f"@media ({mq[0]}: {mq[1]}{mq[2]}) {{")
|
|
|
|
def camel_to_kebab(name):
|
|
# Insert hyphen before capital letters and convert to lowercase
|
|
s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1-\2', name)
|
|
kebab = re.sub(r'([a-z0-9])([A-Z])', r'\1-\2', s1).lower()
|
|
return kebab
|
|
|
|
def concat(joiner:str, tuple:Union[RGB, RGBA, Size])->str:
|
|
return joiner.join(str(item) for item in tuple)
|
|
|
|
|
|
merged:CSS = {}
|
|
for d in css:
|
|
merged = {**merged, **d}
|
|
|
|
|
|
for key, value in merged.items():
|
|
text = value
|
|
if isinstance(value, tuple):
|
|
size = len(value)
|
|
if size < 3:
|
|
text = concat("", value)
|
|
elif size == 3:
|
|
text = "rgb(" + concat(", ", value) + ")"
|
|
elif size == 4:
|
|
text = "rgba(" + concat(", ", value) + ")"
|
|
|
|
lines.append(f" {camel_to_kebab(key)}: {text};")
|
|
|
|
lines.append("}")
|
|
return "\n".join(lines)
|
|
|
|
test = Sheet(
|
|
("max-width", 1024, "px"),
|
|
{
|
|
"fontSize":(16, "px"),
|
|
"color":(255, 0, 0),
|
|
"backgroundColor":(0, 255, 0),
|
|
"display":"block",
|
|
},
|
|
Styles(
|
|
color=(0, 0, 255),
|
|
backgroundColor=(255, 255, 0),
|
|
)
|
|
)
|
|
|
|
print(test) |