소스 검색

#411 introduce ui.background as a singleton element

Falko Schindler 2 년 전
부모
커밋
cb58c164f0
4개의 변경된 파일113개의 추가작업 그리고 8개의 파일을 삭제
  1. 13 8
      nicegui/element.py
  2. 32 0
      nicegui/elements/background.js
  3. 67 0
      nicegui/elements/background.py
  4. 1 0
      nicegui/ui.py

+ 13 - 8
nicegui/element.py

@@ -125,6 +125,16 @@ class Element(ABC, Visibility):
                 raise ValueError(f'Unknown key {key}')
         return dict_
 
+    @staticmethod
+    def _update_classes_list(
+            classes: List[str],
+            add: Optional[str] = None, remove: Optional[str] = None, replace: Optional[str] = None) -> List[str]:
+        class_list = classes if replace is None else []
+        class_list = [c for c in class_list if c not in (remove or '').split()]
+        class_list += (add or '').split()
+        class_list += (replace or '').split()
+        return list(dict.fromkeys(class_list))  # NOTE: remove duplicates while preserving order
+
     def classes(self, add: Optional[str] = None, *, remove: Optional[str] = None, replace: Optional[str] = None) \
             -> Self:
         """Apply, remove, or replace HTML classes.
@@ -137,11 +147,7 @@ class Element(ABC, Visibility):
         :param remove: whitespace-delimited string of classes to remove from the element
         :param replace: whitespace-delimited string of classes to use instead of existing ones
         """
-        class_list = self._classes if replace is None else []
-        class_list = [c for c in class_list if c not in (remove or '').split()]
-        class_list += (add or '').split()
-        class_list += (replace or '').split()
-        new_classes = list(dict.fromkeys(class_list))  # NOTE: remove duplicates while preserving order
+        new_classes = self._update_classes_list(self._classes, add, remove, replace)
         if self._classes != new_classes:
             self._classes = new_classes
             self.update()
@@ -169,11 +175,10 @@ class Element(ABC, Visibility):
         :param add: semicolon-separated list of styles to add to the element
         :param remove: semicolon-separated list of styles to remove from the element
         :param replace: semicolon-separated list of styles to use instead of existing ones
-         """
+        """
         style_dict = deepcopy(self._style) if replace is None else {}
         for key in self._parse_style(remove):
-            if key in style_dict:
-                del style_dict[key]
+            style_dict.pop(key, None)
         style_dict.update(self._parse_style(add))
         style_dict.update(self._parse_style(replace))
         if self._style != style_dict:

+ 32 - 0
nicegui/elements/background.js

@@ -0,0 +1,32 @@
+export default {
+  mounted() {
+    this.add_classes(this.classes);
+    this.add_style(this.style);
+    this.add_props(this.props);
+  },
+  methods: {
+    add_classes(classes) {
+      document.body.classList.add(...classes);
+    },
+    remove_classes(classes) {
+      document.body.classList.remove(...classes);
+    },
+    add_style(style) {
+      Object.entries(style).forEach(([key, value]) => (document.body.style[key] = value));
+    },
+    remove_style(keys) {
+      keys.forEach((key) => document.body.style.removeProperty(key));
+    },
+    add_props(props) {
+      Object.entries(props).forEach(([key, value]) => document.body.setAttribute(key, value));
+    },
+    remove_props(keys) {
+      keys.forEach((key) => document.body.removeAttribute(key));
+    },
+  },
+  props: {
+    classes: Array,
+    style: Object,
+    props: Object,
+  },
+};

+ 67 - 0
nicegui/elements/background.py

@@ -0,0 +1,67 @@
+from abc import ABCMeta
+from typing import Any, Dict, Optional, Tuple
+
+from typing_extensions import Self
+
+from ..dependencies import register_component
+from ..element import Element
+
+register_component('background', __file__, 'background.js')
+
+
+class AbstractSingleton(ABCMeta):
+
+    def __init__(cls, name: str, bases: Tuple, dict: Dict[str, Any]) -> None:
+        super().__init__(name, bases, dict)
+        cls.instance = None
+
+    def __call__(cls, *args: Any, **kwargs: Any) -> Any:
+        if cls.instance is None:
+            cls.instance = super().__call__(*args, **kwargs)
+        return cls.instance
+
+
+class Background(Element, metaclass=AbstractSingleton):
+
+    def __init__(self) -> None:
+        super().__init__('background')
+        self._props['classes'] = []
+        self._props['style'] = {}
+        self._props['props'] = {}
+
+    def classes(self, add: Optional[str] = None, *, remove: Optional[str] = None, replace: Optional[str] = None) \
+            -> Self:
+        classes = self._update_classes_list(self._props['classes'], add, remove, replace)
+        new_classes = [c for c in classes if c not in self._props['classes']]
+        old_classes = [c for c in self._props['classes'] if c not in classes]
+        if new_classes:
+            self.run_method('add_classes', new_classes)
+        if old_classes:
+            self.run_method('remove_classes', old_classes)
+        self._props['classes'] = classes
+        return self
+
+    def style(self, add: Optional[str] = None, *, remove: Optional[str] = None, replace: Optional[str] = None) \
+            -> Self:
+        old_style = Element._parse_style(remove)
+        for key in old_style:
+            self._props['style'].pop(key, None)
+        if old_style:
+            self.run_method('remove_style', list(old_style))
+        self._props['style'].update(Element._parse_style(add))
+        self._props['style'].update(Element._parse_style(replace))
+        if self._props['style']:
+            self.run_method('add_style', self._props['style'])
+        return self
+
+    def props(self, add: Optional[str] = None, *, remove: Optional[str] = None) -> Self:
+        old_props = self._parse_props(remove)
+        for key in old_props:
+            self._props['props'].pop(key, None)
+        if old_props:
+            self.run_method('remove_props', list(old_props))
+        new_props = self._parse_props(add)
+        self._props['props'].update(new_props)
+        if self._props['props']:
+            self.run_method('add_props', self._props['props'])
+        return self

+ 1 - 0
nicegui/ui.py

@@ -3,6 +3,7 @@ import os
 from .element import Element as element
 from .elements.audio import Audio as audio
 from .elements.avatar import Avatar as avatar
+from .elements.background import Background as background
 from .elements.badge import Badge as badge
 from .elements.button import Button as button
 from .elements.card import Card as card