query.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. from typing import Optional
  2. from typing_extensions import Self
  3. from ..classes import Classes
  4. from ..context import context
  5. from ..element import Element
  6. from ..props import Props
  7. from ..style import Style
  8. class QueryElement(Element, component='query.js'):
  9. def __init__(self, selector: str) -> None:
  10. super().__init__()
  11. self._props['selector'] = selector
  12. self._props['classes'] = []
  13. self._props['style'] = {}
  14. self._props['props'] = {}
  15. class Query:
  16. def __init__(self, selector: str) -> None:
  17. """Query Selector
  18. To manipulate elements like the document body, you can use the `ui.query` function.
  19. With the query result you can add classes, styles, and attributes like with every other UI element.
  20. This can be useful for example to change the background color of the page (e.g. `ui.query('body').classes('bg-green')`).
  21. :param selector: the CSS selector (e.g. "body", "#my-id", ".my-class", "div > p")
  22. """
  23. for element in context.client.elements.values():
  24. if isinstance(element, QueryElement) and element.props['selector'] == selector:
  25. self.element = element
  26. break
  27. else:
  28. self.element = QueryElement(selector)
  29. def classes(self,
  30. add: Optional[str] = None, *,
  31. remove: Optional[str] = None,
  32. toggle: Optional[str] = None,
  33. replace: Optional[str] = None,
  34. ) -> Self:
  35. """Apply, remove, toggle, or replace HTML classes.
  36. This allows modifying the look of the element or its layout using `Tailwind <https://v3.tailwindcss.com/>`_ or `Quasar <https://quasar.dev/>`_ classes.
  37. Removing or replacing classes can be helpful if predefined classes are not desired.
  38. :param add: whitespace-delimited string of classes
  39. :param remove: whitespace-delimited string of classes to remove from the element
  40. :param toggle: whitespace-delimited string of classes to toggle (*added in version 2.7.0*)
  41. :param replace: whitespace-delimited string of classes to use instead of existing ones
  42. """
  43. classes = Classes.update_list(self.element.props['classes'], add, remove, toggle, replace)
  44. new_classes = [c for c in classes if c not in self.element.props['classes']]
  45. old_classes = [c for c in self.element.props['classes'] if c not in classes]
  46. if new_classes:
  47. self.element.run_method('add_classes', new_classes)
  48. if old_classes:
  49. self.element.run_method('remove_classes', old_classes)
  50. self.element.props['classes'] = classes
  51. return self
  52. def style(self, add: Optional[str] = None, *, remove: Optional[str] = None, replace: Optional[str] = None) \
  53. -> Self:
  54. """Apply, remove, or replace CSS definitions.
  55. Removing or replacing styles can be helpful if the predefined style is not desired.
  56. :param add: semicolon-separated list of styles to add to the element
  57. :param remove: semicolon-separated list of styles to remove from the element
  58. :param replace: semicolon-separated list of styles to use instead of existing ones
  59. """
  60. old_style = Style.parse(remove)
  61. for key in old_style:
  62. self.element.props['style'].pop(key, None)
  63. if old_style:
  64. self.element.run_method('remove_style', list(old_style))
  65. self.element.props['style'].update(Style.parse(add))
  66. self.element.props['style'].update(Style.parse(replace))
  67. if self.element.props['style']:
  68. self.element.run_method('add_style', self.element.props['style'])
  69. return self
  70. def props(self, add: Optional[str] = None, *, remove: Optional[str] = None) -> Self:
  71. """Add or remove props.
  72. This allows modifying the look of the element or its layout using `Quasar <https://quasar.dev/>`_ props.
  73. Since props are simply applied as HTML attributes, they can be used with any HTML element.
  74. Boolean properties are assumed ``True`` if no value is specified.
  75. :param add: whitespace-delimited list of either boolean values or key=value pair to add
  76. :param remove: whitespace-delimited list of property keys to remove
  77. """
  78. old_props = Props.parse(remove)
  79. for key in old_props:
  80. self.element.props['props'].pop(key, None)
  81. if old_props:
  82. self.element.run_method('remove_props', list(old_props))
  83. new_props = Props.parse(add)
  84. self.element.props['props'].update(new_props)
  85. if self.element.props['props']:
  86. self.element.run_method('add_props', self.element.props['props'])
  87. return self