style.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. from typing import TYPE_CHECKING, Dict, Generic, Optional, TypeVar
  2. if TYPE_CHECKING:
  3. from .element import Element
  4. T = TypeVar('T', bound='Element')
  5. class Style(dict, Generic[T]):
  6. def __init__(self, *args, element: T, **kwargs) -> None:
  7. super().__init__(*args, **kwargs)
  8. self.element = element
  9. def __call__(self,
  10. add: Optional[str] = None, *,
  11. remove: Optional[str] = None,
  12. replace: Optional[str] = None) -> T:
  13. """Apply, remove, or replace CSS definitions.
  14. Removing or replacing styles can be helpful if the predefined style is not desired.
  15. :param add: semicolon-separated list of styles to add to the element
  16. :param remove: semicolon-separated list of styles to remove from the element
  17. :param replace: semicolon-separated list of styles to use instead of existing ones
  18. """
  19. style_dict = {**self} if replace is None else {}
  20. for key in self.parse(remove):
  21. style_dict.pop(key, None)
  22. style_dict.update(self.parse(add))
  23. style_dict.update(self.parse(replace))
  24. if self != style_dict:
  25. self.clear()
  26. self.update(style_dict)
  27. self.element.update()
  28. return self.element
  29. @staticmethod
  30. def parse(text: Optional[str]) -> Dict[str, str]:
  31. """Parse a string of styles into a dictionary."""
  32. result = {}
  33. for word in (text or '').split(';'):
  34. word = word.strip() # noqa: PLW2901
  35. if word:
  36. key, value = word.split(':', 1)
  37. result[key.strip()] = value.strip()
  38. return result