Skip to content

Commit

Permalink
introduce IconElement mixin (#3600)
Browse files Browse the repository at this point in the history
  • Loading branch information
falkoschindler authored Aug 27, 2024
1 parent 4042305 commit 99df6aa
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 35 deletions.
7 changes: 3 additions & 4 deletions nicegui/elements/avatar.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import Optional

from .mixins.color_elements import BackgroundColorElement, TextColorElement
from .mixins.icon_element import IconElement


class Avatar(BackgroundColorElement, TextColorElement):
class Avatar(IconElement, BackgroundColorElement, TextColorElement):
TEXT_COLOR_PROP = 'text-color'

def __init__(self,
Expand All @@ -28,10 +29,8 @@ def __init__(self,
:param square: removes border-radius so borders are squared (default: False)
:param rounded: applies a small standard border-radius for a squared shape of the component (default: False)
"""
super().__init__(tag='q-avatar', background_color=color, text_color=text_color)
super().__init__(tag='q-avatar', background_color=color, text_color=text_color, icon=icon)

if icon is not None:
self._props['icon'] = icon
self._props['square'] = square
self._props['rounded'] = rounded

Expand Down
8 changes: 3 additions & 5 deletions nicegui/elements/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
from ..events import ClickEventArguments, handle_event
from .mixins.color_elements import BackgroundColorElement
from .mixins.disableable_element import DisableableElement
from .mixins.icon_element import IconElement
from .mixins.text_element import TextElement


class Button(TextElement, DisableableElement, BackgroundColorElement):
class Button(IconElement, TextElement, DisableableElement, BackgroundColorElement):

def __init__(self,
text: str = '', *,
Expand All @@ -31,10 +32,7 @@ def __init__(self,
:param color: the color of the button (either a Quasar, Tailwind, or CSS color or `None`, default: 'primary')
:param icon: the name of an icon to be displayed on the button (default: `None`)
"""
super().__init__(tag='q-btn', text=text, background_color=color)

if icon:
self._props['icon'] = icon
super().__init__(tag='q-btn', text=text, background_color=color, icon=icon)

if on_click:
self.on_click(on_click)
Expand Down
8 changes: 3 additions & 5 deletions nicegui/elements/button_dropdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
from ..events import ClickEventArguments, handle_event
from .mixins.color_elements import BackgroundColorElement
from .mixins.disableable_element import DisableableElement
from .mixins.icon_element import IconElement
from .mixins.text_element import TextElement
from .mixins.value_element import ValueElement


class DropdownButton(TextElement, DisableableElement, BackgroundColorElement, ValueElement):
class DropdownButton(IconElement, TextElement, DisableableElement, BackgroundColorElement, ValueElement):

def __init__(self,
text: str = '', *,
Expand Down Expand Up @@ -38,10 +39,7 @@ def __init__(self,
:param split: whether to split the dropdown icon into a separate button (default: `False`)
"""
super().__init__(tag='q-btn-dropdown',
text=text, background_color=color, value=value, on_value_change=on_value_change)

if icon:
self._props['icon'] = icon
icon=icon, text=text, background_color=color, value=value, on_value_change=on_value_change)

if auto_close:
self._props['auto-close'] = True
Expand Down
7 changes: 3 additions & 4 deletions nicegui/elements/chip.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
from ..events import ClickEventArguments, handle_event
from .mixins.color_elements import BackgroundColorElement, TextColorElement
from .mixins.disableable_element import DisableableElement
from .mixins.icon_element import IconElement
from .mixins.selectable_element import SelectableElement
from .mixins.text_element import TextElement
from .mixins.value_element import ValueElement


class Chip(ValueElement, TextElement, BackgroundColorElement, TextColorElement, DisableableElement, SelectableElement):
class Chip(IconElement, ValueElement, TextElement, BackgroundColorElement, TextColorElement, DisableableElement, SelectableElement):
TEXT_COLOR_PROP = 'text-color'

def __init__(self,
Expand Down Expand Up @@ -43,10 +44,8 @@ def __init__(self,
:param on_value_change: callback which is invoked when the chip is removed or unremoved
"""
super().__init__(tag='q-chip', value=True, on_value_change=on_value_change,
text=text, text_color=text_color, background_color=color,
icon=icon, text=text, text_color=text_color, background_color=color,
selectable=selectable, selected=selected, on_selection_change=on_selection_change)
if icon:
self._props['icon'] = icon

self._props['removable'] = removable

Expand Down
6 changes: 3 additions & 3 deletions nicegui/elements/expansion.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from typing import Any, Callable, Optional

from .mixins.disableable_element import DisableableElement
from .mixins.icon_element import IconElement
from .mixins.text_element import TextElement
from .mixins.value_element import ValueElement


class Expansion(TextElement, ValueElement, DisableableElement):
class Expansion(IconElement, TextElement, ValueElement, DisableableElement):

def __init__(self,
text: str = '', *,
Expand All @@ -26,12 +27,11 @@ def __init__(self,
:param value: whether the expansion should be opened on creation (default: `False`)
:param on_value_change: callback to execute when value changes
"""
super().__init__(tag='q-expansion-item', text=text, value=value, on_value_change=on_value_change)
super().__init__(tag='q-expansion-item', icon=icon, text=text, value=value, on_value_change=on_value_change)
if caption is not None:
self._props['caption'] = caption
if group is not None:
self._props['group'] = group
self._props['icon'] = icon
self._classes.append('nicegui-expansion')

def open(self) -> None:
Expand Down
89 changes: 89 additions & 0 deletions nicegui/elements/mixins/icon_element.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from typing import Any, Callable, Optional, cast

from typing_extensions import Self

from ...binding import BindableProperty, bind, bind_from, bind_to
from ...element import Element


class IconElement(Element):
icon = BindableProperty(
on_change=lambda sender, icon: cast(Self, sender)._handle_icon_change(icon)) # pylint: disable=protected-access

def __init__(self, *, icon: Optional[str] = None, **kwargs: Any) -> None: # pylint: disable=redefined-builtin
super().__init__(**kwargs)
self.icon = icon
if icon is not None:
self._props['icon'] = icon

def bind_icon_to(self,
target_object: Any,
target_name: str = 'icon',
forward: Callable[..., Any] = lambda x: x,
) -> Self:
"""Bind the icon of this element to the target object's target_name property.
The binding works one way only, from this element to the target.
The update happens immediately and whenever a value changes.
:param target_object: The object to bind to.
:param target_name: The name of the property to bind to.
:param forward: A function to apply to the value before applying it to the target.
"""
bind_to(self, 'icon', target_object, target_name, forward)
return self

def bind_icon_from(self,
target_object: Any,
target_name: str = 'icon',
backward: Callable[..., Any] = lambda x: x,
) -> Self:
"""Bind the icon of this element from the target object's target_name property.
The binding works one way only, from the target to this element.
The update happens immediately and whenever a value changes.
:param target_object: The object to bind from.
:param target_name: The name of the property to bind from.
:param backward: A function to apply to the value before applying it to this element.
"""
bind_from(self, 'icon', target_object, target_name, backward)
return self

def bind_icon(self,
target_object: Any,
target_name: str = 'icon', *,
forward: Callable[..., Any] = lambda x: x,
backward: Callable[..., Any] = lambda x: x,
) -> Self:
"""Bind the icon of this element to the target object's target_name property.
The binding works both ways, from this element to the target and from the target to this element.
The update happens immediately and whenever a value changes.
The backward binding takes precedence for the initial synchronization.
:param target_object: The object to bind to.
:param target_name: The name of the property to bind to.
:param forward: A function to apply to the value before applying it to the target.
:param backward: A function to apply to the value before applying it to this element.
"""
bind(self, 'icon', target_object, target_name, forward=forward, backward=backward)
return self

def set_icon(self, icon: Optional[str]) -> None:
"""Set the icon of this element.
:param icon: The new icon.
"""
self.icon = icon

def _handle_icon_change(self, icon: Optional[str]) -> None:
"""Called when the icon of this element changes.
:param icon: The new icon.
"""
if icon is not None:
self._props['icon'] = icon
else:
self._props.pop('icon', None)
self.update()
7 changes: 3 additions & 4 deletions nicegui/elements/stepper.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from ..context import context
from ..element import Element
from .mixins.disableable_element import DisableableElement
from .mixins.icon_element import IconElement
from .mixins.value_element import ValueElement


Expand Down Expand Up @@ -51,7 +52,7 @@ def previous(self) -> None:
self.run_method('previous')


class Step(DisableableElement):
class Step(IconElement, DisableableElement):

def __init__(self, name: str, title: Optional[str] = None, icon: Optional[str] = None) -> None:
"""Step
Expand All @@ -63,12 +64,10 @@ def __init__(self, name: str, title: Optional[str] = None, icon: Optional[str] =
:param title: title of the step (default: `None`, meaning the same as `name`)
:param icon: icon of the step (default: `None`)
"""
super().__init__(tag='q-step')
super().__init__(tag='q-step', icon=icon)
self._props['name'] = name
self._props['title'] = title if title is not None else name
self._classes.append('nicegui-step')
if icon:
self._props['icon'] = icon
self.stepper = cast(ValueElement, context.slot.parent)
if self.stepper.value is None:
self.stepper.value = name
Expand Down
7 changes: 3 additions & 4 deletions nicegui/elements/tabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from ..context import context
from .mixins.disableable_element import DisableableElement
from .mixins.icon_element import IconElement
from .mixins.value_element import ValueElement


Expand All @@ -27,7 +28,7 @@ def _value_to_model_value(self, value: Any) -> Any:
return value._props['name'] if isinstance(value, (Tab, TabPanel)) else value # pylint: disable=protected-access


class Tab(DisableableElement):
class Tab(IconElement, DisableableElement):

def __init__(self, name: str, label: Optional[str] = None, icon: Optional[str] = None) -> None:
"""Tab
Expand All @@ -39,11 +40,9 @@ def __init__(self, name: str, label: Optional[str] = None, icon: Optional[str] =
:param label: label of the tab (default: `None`, meaning the same as `name`)
:param icon: icon of the tab (default: `None`)
"""
super().__init__(tag='q-tab')
super().__init__(tag='q-tab', icon=icon)
self._props['name'] = name
self._props['label'] = label if label is not None else name
if icon:
self._props['icon'] = icon
self.tabs = context.slot.parent


Expand Down
2 changes: 1 addition & 1 deletion nicegui/elements/teleport.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Union

from nicegui.element import Element
from ..element import Element


class Teleport(Element, component='teleport.js'):
Expand Down
9 changes: 4 additions & 5 deletions nicegui/elements/timeline.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Literal, Optional

from nicegui.element import Element
from ..element import Element
from .mixins.icon_element import IconElement


class Timeline(Element):
Expand All @@ -26,7 +27,7 @@ def __init__(self,
self._props['color'] = color


class TimelineEntry(Element):
class TimelineEntry(IconElement):

def __init__(self,
body: Optional[str] = None,
Expand Down Expand Up @@ -54,7 +55,7 @@ def __init__(self,
:param subtitle: Subtitle text.
:param color: Color or the timeline.
"""
super().__init__('q-timeline-entry')
super().__init__(tag='q-timeline-entry', icon=icon)
if body is not None:
self._props['body'] = body
self._props['side'] = side
Expand All @@ -63,8 +64,6 @@ def __init__(self,
self._props['tag'] = tag
if color is not None:
self._props['color'] = color
if icon is not None:
self._props['icon'] = icon
if avatar is not None:
self._props['avatar'] = avatar
if title is not None:
Expand Down

0 comments on commit 99df6aa

Please sign in to comment.