jsx elements
This commit is contained in:
parent
194eea5a21
commit
838ce7acb3
90
pss.py
90
pss.py
@ -1,90 +0,0 @@
|
||||
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)
|
59
py_jsx.py
Normal file
59
py_jsx.py
Normal file
@ -0,0 +1,59 @@
|
||||
from typing import List, Protocol, Tuple
|
||||
|
||||
class StrArgsToStr(Protocol):
|
||||
def __call__(self, *children: str) -> str:
|
||||
...
|
||||
|
||||
ClassArg = str|List[str]|Tuple[str, ...]|None
|
||||
|
||||
def MakeAttrs(classes:ClassArg, id:str|None, attributes: dict[str, str | None]) -> str:
|
||||
|
||||
if classes:
|
||||
attributes['class'] = " ".join(classes) if isinstance(classes, (list, tuple)) else classes
|
||||
|
||||
if id:
|
||||
attributes['id'] = id
|
||||
|
||||
attrList: List[str] = [""]
|
||||
for key, value in attributes.items():
|
||||
if value:
|
||||
attrList.append(f'{key}="{value}"')
|
||||
return " ".join(attrList)
|
||||
|
||||
def ElWrapped(name: str, classes:ClassArg = None, id:str|None = None, attrs: dict[str, str | None] = {}, children:ClassArg = ()) -> StrArgsToStr:
|
||||
def Wrapped(*children:str):
|
||||
return f'<{name}{MakeAttrs(classes, id, attrs)}>{" ".join(children)}</{name}>'
|
||||
return Wrapped
|
||||
|
||||
def ElInline(name: str, classes:ClassArg = None, id:str|None = None, attrs: dict[str, str | None] = {}) -> str:
|
||||
return f'<{name} {MakeAttrs(classes, id, attrs)}/>'
|
||||
|
||||
def SimpleWrapped(name:str):
|
||||
def proxy(classes:ClassArg = None, id:str|None = None):
|
||||
return ElWrapped(name, classes, id)
|
||||
return proxy
|
||||
|
||||
def SimpleInline(name:str):
|
||||
def proxy(classes:ClassArg = None, id:str|None = None):
|
||||
return ElInline(name, classes, id)
|
||||
return proxy
|
||||
|
||||
def A(classes:ClassArg = None, id:str|None = None, href:str|None = None, target:str|None = None) -> StrArgsToStr:
|
||||
return ElWrapped("a", classes, id, {"href":href, "target":id})
|
||||
|
||||
def IMG(classes:ClassArg = None, id:str|None = None, src:str|None = None):
|
||||
return ElInline("img", classes, id, {"src":src})
|
||||
|
||||
DIV = SimpleWrapped("div")
|
||||
P = SimpleWrapped("P")
|
||||
BR = SimpleInline("br")
|
||||
HR = SimpleInline("hr")
|
||||
SPAN = SimpleWrapped("span")
|
||||
|
||||
print(
|
||||
|
||||
DIV(classes="outer")
|
||||
(
|
||||
A(classes="CTA Orange", href="www.link")("click")
|
||||
)
|
||||
)
|
138
pyle_sheets.py
Normal file
138
pyle_sheets.py
Normal file
@ -0,0 +1,138 @@
|
||||
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)
|
Loading…
Reference in New Issue
Block a user