Skip to content

Commit

Permalink
allow toggling classes
Browse files Browse the repository at this point in the history
  • Loading branch information
falkoschindler committed Nov 21, 2024
1 parent 1f78c86 commit 7f3fcd5
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 9 deletions.
16 changes: 13 additions & 3 deletions nicegui/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@ def __init__(self, *args, element: T, **kwargs) -> None:
def __call__(self,
add: Optional[str] = None, *,
remove: Optional[str] = None,
toggle: Optional[str] = None,
replace: Optional[str] = None) -> T:
"""Apply, remove, or replace HTML classes.
"""Apply, remove, toggle, or replace HTML classes.
This allows modifying the look of the element or its layout using `Tailwind <https://tailwindcss.com/>`_ or `Quasar <https://quasar.dev/>`_ classes.
Removing or replacing classes can be helpful if predefined classes are not desired.
:param add: whitespace-delimited string of classes
:param remove: whitespace-delimited string of classes to remove from the element
:param toggle: whitespace-delimited string of classes to toggle
:param replace: whitespace-delimited string of classes to use instead of existing ones
"""
new_classes = self.update_list(self, add, remove, replace)
new_classes = self.update_list(self, add, remove, toggle, replace)
if self != new_classes:
self[:] = new_classes
self.element.update()
Expand All @@ -36,10 +38,18 @@ def __call__(self,
def update_list(classes: List[str],
add: Optional[str] = None,
remove: Optional[str] = None,
toggle: Optional[str] = None,
replace: Optional[str] = None) -> List[str]:
"""Update a list of classes."""
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
class_list = list(dict.fromkeys(class_list)) # NOTE: remove duplicates while preserving order
if toggle is not None:
for class_ in toggle.split():
if class_ in class_list:
class_list.remove(class_)
else:
class_list.append(class_)
return class_list
6 changes: 4 additions & 2 deletions nicegui/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,9 @@ def classes(self) -> Classes[Self]:
def default_classes(cls,
add: Optional[str] = None, *,
remove: Optional[str] = None,
toggle: Optional[str] = None,
replace: Optional[str] = None) -> type[Self]:
"""Apply, remove, or replace default HTML classes.
"""Apply, remove, toggle, or replace default HTML classes.
This allows modifying the look of the element or its layout using `Tailwind <https://tailwindcss.com/>`_ or `Quasar <https://quasar.dev/>`_ classes.
Expand All @@ -233,9 +234,10 @@ def default_classes(cls,
:param add: whitespace-delimited string of classes
:param remove: whitespace-delimited string of classes to remove from the element
:param toggle: whitespace-delimited string of classes to toggle
:param replace: whitespace-delimited string of classes to use instead of existing ones
"""
cls._default_classes = Classes.update_list(cls._default_classes, add, remove, replace)
cls._default_classes = Classes.update_list(cls._default_classes, add, remove, toggle, replace)
return cls

@property
Expand Down
13 changes: 9 additions & 4 deletions nicegui/elements/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,24 @@ def __init__(self, selector: str) -> None:
else:
self.element = QueryElement(selector)

def classes(self, add: Optional[str] = None, *, remove: Optional[str] = None, replace: Optional[str] = None) \
-> Self:
"""Apply, remove, or replace HTML classes.
def classes(self,
add: Optional[str] = None, *,
remove: Optional[str] = None,
toggle: Optional[str] = None,
replace: Optional[str] = None,
) -> Self:
"""Apply, remove, toggle, or replace HTML classes.
This allows modifying the look of the element or its layout using `Tailwind <https://tailwindcss.com/>`_ or `Quasar <https://quasar.dev/>`_ classes.
Removing or replacing classes can be helpful if predefined classes are not desired.
:param add: whitespace-delimited string of classes
:param remove: whitespace-delimited string of classes to remove from the element
:param toggle: whitespace-delimited string of classes to toggle
:param replace: whitespace-delimited string of classes to use instead of existing ones
"""
classes = Classes.update_list(self.element.props['classes'], add, remove, replace)
classes = Classes.update_list(self.element.props['classes'], add, remove, toggle, replace)
new_classes = [c for c in classes if c not in self.element.props['classes']]
old_classes = [c for c in self.element.props['classes'] if c not in classes]
if new_classes:
Expand Down
6 changes: 6 additions & 0 deletions tests/test_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ def assert_classes(classes: str) -> None:
label.classes(replace='four')
assert_classes('four')

label.classes(toggle='bg-red-500')
assert_classes('four bg-red-500')

label.classes(toggle='bg-red-500')
assert_classes('four')


@pytest.mark.parametrize('value,expected', [
(None, {}),
Expand Down

0 comments on commit 7f3fcd5

Please sign in to comment.