You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

247 lines
9.8 KiB

from typing import Literal, Optional
from . import globals # pylint: disable=redefined-builtin
from .element import Element
from .elements.mixins.value_element import ValueElement
from .functions.html import add_body_html
DrawerSides = Literal['left', 'right']
PageStickyPositions = Literal[
'top-right',
'top-left',
'bottom-right',
'bottom-left',
'top',
'right',
'bottom',
'left',
]
class Header(ValueElement):
def __init__(self, *,
value: bool = True,
fixed: bool = True,
bordered: bool = False,
elevated: bool = False,
add_scroll_padding: bool = False, # DEPRECATED: will be True in v1.4
) -> None:
'''Header
Note: The header is automatically placed above other layout elements in the DOM to improve accessibility.
To change the order, use the `move` method.
:param value: whether the header is already opened (default: `True`)
:param fixed: whether the header should be fixed to the top of the page (default: `True`)
:param bordered: whether the header should have a border (default: `False`)
:param elevated: whether the header should have a shadow (default: `False`)
:param add_scroll_padding: whether to automatically prevent link targets from being hidden behind the header (default: `False`, will be `True` in v1.4)
'''
with globals.get_client().layout:
super().__init__(tag='q-header', value=value, on_value_change=None)
self._classes = ['nicegui-header']
self._props['bordered'] = bordered
self._props['elevated'] = elevated
code = list(self.client.layout._props['view'])
code[1] = 'H' if fixed else 'h'
self.client.layout._props['view'] = ''.join(code)
self.move(target_index=0)
if add_scroll_padding:
add_body_html(f'''
<script>
window.onload = () => {{
const header = getElement({self.id}).$el;
new ResizeObserver(() => {{
document.documentElement.style.scrollPaddingTop = `${{header.offsetHeight}}px`;
}}).observe(header);
}};
</script>
''')
def toggle(self):
'''Toggle the header'''
self.value = not self.value
def show(self):
'''Show the header'''
self.value = True
def hide(self):
'''Hide the header'''
self.value = False
class Drawer(Element):
def __init__(self,
side: DrawerSides, *,
value: Optional[bool] = None,
fixed: bool = True,
bordered: bool = False,
elevated: bool = False,
top_corner: bool = False,
bottom_corner: bool = False) -> None:
'''Drawer
Note: Depending on the side, the drawer is automatically placed above or below the main page container in the DOM to improve accessibility.
To change the order, use the `move` method.
:param side: side of the page where the drawer should be placed (`left` or `right`)
:param value: whether the drawer is already opened (default: `None`, i.e. if layout width is above threshold)
:param fixed: whether the drawer is fixed or scrolls with the content (default: `True`)
:param bordered: whether the drawer should have a border (default: `False`)
:param elevated: whether the drawer should have a shadow (default: `False`)
:param top_corner: whether the drawer expands into the top corner (default: `False`)
:param bottom_corner: whether the drawer expands into the bottom corner (default: `False`)
'''
with globals.get_client().layout:
super().__init__('q-drawer')
if value is None:
self._props['show-if-above'] = True
else:
self._props['model-value'] = value
self._props['side'] = side
self._props['bordered'] = bordered
self._props['elevated'] = elevated
self._classes = ['nicegui-drawer']
code = list(self.client.layout._props['view'])
code[0 if side == 'left' else 2] = side[0].lower() if top_corner else 'h'
code[4 if side == 'left' else 6] = side[0].upper() if fixed else side[0].lower()
code[8 if side == 'left' else 10] = side[0].lower() if bottom_corner else 'f'
self.client.layout._props['view'] = ''.join(code)
page_container_index = self.client.layout.default_slot.children.index(self.client.page_container)
self.move(target_index=page_container_index if side == 'left' else page_container_index + 1)
def toggle(self) -> None:
'''Toggle the drawer'''
self.run_method('toggle')
def show(self) -> None:
'''Show the drawer'''
self.run_method('show')
def hide(self) -> None:
'''Hide the drawer'''
self.run_method('hide')
class LeftDrawer(Drawer):
def __init__(self, *,
value: Optional[bool] = None,
fixed: bool = True,
bordered: bool = False,
elevated: bool = False,
top_corner: bool = False,
bottom_corner: bool = False) -> None:
'''Left drawer
Note: The left drawer is automatically placed above the main page container in the DOM to improve accessibility.
To change the order, use the `move` method.
:param value: whether the drawer is already opened (default: `None`, i.e. if layout width is above threshold)
:param fixed: whether the drawer is fixed or scrolls with the content (default: `True`)
:param bordered: whether the drawer should have a border (default: `False`)
:param elevated: whether the drawer should have a shadow (default: `False`)
:param top_corner: whether the drawer expands into the top corner (default: `False`)
:param bottom_corner: whether the drawer expands into the bottom corner (default: `False`)
'''
super().__init__('left',
value=value,
fixed=fixed,
bordered=bordered,
elevated=elevated,
top_corner=top_corner,
bottom_corner=bottom_corner)
class RightDrawer(Drawer):
def __init__(self, *,
value: Optional[bool] = None,
fixed: bool = True,
bordered: bool = False,
elevated: bool = False,
top_corner: bool = False,
bottom_corner: bool = False) -> None:
'''Right drawer
Note: The right drawer is automatically placed below the main page container in the DOM to improve accessibility.
To change the order, use the `move` method.
:param value: whether the drawer is already opened (default: `None`, i.e. if layout width is above threshold)
:param fixed: whether the drawer is fixed or scrolls with the content (default: `True`)
:param bordered: whether the drawer should have a border (default: `False`)
:param elevated: whether the drawer should have a shadow (default: `False`)
:param top_corner: whether the drawer expands into the top corner (default: `False`)
:param bottom_corner: whether the drawer expands into the bottom corner (default: `False`)
'''
super().__init__('right',
value=value,
fixed=fixed,
bordered=bordered,
elevated=elevated,
top_corner=top_corner,
bottom_corner=bottom_corner)
class Footer(ValueElement):
def __init__(self, *,
value: bool = True,
fixed: bool = True,
bordered: bool = False,
elevated: bool = False) -> None:
'''Footer
Note: The footer is automatically placed below other layout elements in the DOM to improve accessibility.
To change the order, use the `move` method.
:param value: whether the footer is already opened (default: `True`)
:param fixed: whether the footer is fixed or scrolls with the content (default: `True`)
:param bordered: whether the footer should have a border (default: `False`)
:param elevated: whether the footer should have a shadow (default: `False`)
'''
with globals.get_client().layout:
super().__init__(tag='q-footer', value=value, on_value_change=None)
self.classes('nicegui-footer')
self._props['bordered'] = bordered
self._props['elevated'] = elevated
code = list(self.client.layout._props['view'])
code[9] = 'F' if fixed else 'f'
self.client.layout._props['view'] = ''.join(code)
self.move(target_index=-1)
def toggle(self) -> None:
'''Toggle the footer'''
self.value = not self.value
def show(self) -> None:
'''Show the footer'''
self.value = True
def hide(self) -> None:
'''Hide the footer'''
self.value = False
class PageSticky(Element):
def __init__(self, position: PageStickyPositions = 'bottom-right', x_offset: float = 0, y_offset: float = 0) -> None:
'''Page sticky
A sticky element that is always visible at the bottom of the page.
:param position: position of the sticky element (default: `'bottom-right'`)
:param x_offset: horizontal offset of the sticky element (default: `0`)
:param y_offset: vertical offset of the sticky element (default: `0`)
'''
super().__init__('q-page-sticky')
self._props['position'] = position
self._props['offset'] = [x_offset, y_offset]