Przeglądaj źródła

Introduce an `html` module with plain HTML elements (#3900)

Following up on
https://github.com/zauberzeug/nicegui/discussions/572#discussioncomment-10476200,
this PR introduces an `html` module for creating plain HTML elements.
They are basically shortcuts for `ui.element(<tag>)` and allow passing
inner HTML as optional positional argument and arbitrary attributes as
keyword arguments. Nesting, classes, styling and event subscriptions
work like with regular NiceGUI elements. Here's a quick demo:

```py
from nicegui import html

with html.p():
    html.a('Link', href='https://google.com').classes('text-red-500')
    html.hr()
    html.button('Button').on('click', lambda: print('Hello World'))
    html.img(src='https://picsum.photos/400/300', width='200')
```

Open tasks:

- [x] Should we exclude "unusable" elements like `html`, `head`, and
`body`? This might not be obvious in all cases.
- [x] Add it to the documentation.
- [x] Add pytests for some elements like `button`?

---------

Co-authored-by: Rodja Trappe <rodja@zauberzeug.com>
Falko Schindler 6 miesięcy temu
rodzic
commit
3e65af2827

+ 2 - 1
nicegui/__init__.py

@@ -1,4 +1,4 @@
-from . import elements, run, ui
+from . import elements, html, run, ui
 from .api_router import APIRouter
 from .app.app import App
 from .client import Client
@@ -16,6 +16,7 @@ __all__ = [
     'context',
     'ElementFilter',
     'elements',
+    'html',
     'run',
     'Tailwind',
     'ui',

+ 113 - 0
nicegui/html.py

@@ -0,0 +1,113 @@
+from typing import Optional
+
+from .element import Element
+
+
+def _create_html_element(tag: str):
+    class HTMLElement(Element):
+        def __init__(self, inner_html: Optional[str] = None, **kwargs) -> None:
+            super().__init__(tag)
+            self._text = inner_html
+            self.props.update(**kwargs)
+    return HTMLElement
+
+
+a = _create_html_element('a')
+abbr = _create_html_element('abbr')
+acronym = _create_html_element('acronym')
+address = _create_html_element('address')
+area = _create_html_element('area')
+article = _create_html_element('article')
+aside = _create_html_element('aside')
+audio = _create_html_element('audio')
+b = _create_html_element('b')
+basefont = _create_html_element('basefont')
+bdi = _create_html_element('bdi')
+bdo = _create_html_element('bdo')
+big = _create_html_element('big')
+blockquote = _create_html_element('blockquote')
+br = _create_html_element('br')
+button = _create_html_element('button')
+canvas = _create_html_element('canvas')
+caption = _create_html_element('caption')
+cite = _create_html_element('cite')
+code = _create_html_element('code')
+col = _create_html_element('col')
+colgroup = _create_html_element('colgroup')
+data = _create_html_element('data')
+datalist = _create_html_element('datalist')
+dd = _create_html_element('dd')
+del_ = _create_html_element('del')
+details = _create_html_element('details')
+dfn = _create_html_element('dfn')
+dialog = _create_html_element('dialog')
+div = _create_html_element('div')
+dl = _create_html_element('dl')
+dt = _create_html_element('dt')
+em = _create_html_element('em')
+embed = _create_html_element('embed')
+fieldset = _create_html_element('fieldset')
+figcaption = _create_html_element('figcaption')
+figure = _create_html_element('figure')
+footer = _create_html_element('footer')
+form = _create_html_element('form')
+h1 = _create_html_element('h1')
+hgroup = _create_html_element('hgroup')
+hr = _create_html_element('hr')
+i = _create_html_element('i')
+iframe = _create_html_element('iframe')
+img = _create_html_element('img')
+input_ = _create_html_element('input')
+ins = _create_html_element('ins')
+kbd = _create_html_element('kbd')
+label = _create_html_element('label')
+legend = _create_html_element('legend')
+li = _create_html_element('li')
+main = _create_html_element('main')
+map_ = _create_html_element('map')
+mark = _create_html_element('mark')
+menu = _create_html_element('menu')
+meter = _create_html_element('meter')
+nav = _create_html_element('nav')
+object_ = _create_html_element('object')
+ol = _create_html_element('ol')
+optgroup = _create_html_element('optgroup')
+option = _create_html_element('option')
+output = _create_html_element('output')
+p = _create_html_element('p')
+param = _create_html_element('param')
+picture = _create_html_element('picture')
+pre = _create_html_element('pre')
+progress = _create_html_element('progress')
+q = _create_html_element('q')
+rp = _create_html_element('rp')
+rt = _create_html_element('rt')
+ruby = _create_html_element('ruby')
+s = _create_html_element('s')
+samp = _create_html_element('samp')
+search = _create_html_element('search')
+section = _create_html_element('section')
+select = _create_html_element('select')
+small = _create_html_element('small')
+source = _create_html_element('source')
+span = _create_html_element('span')
+strong = _create_html_element('strong')
+sub = _create_html_element('sub')
+summary = _create_html_element('summary')
+sup = _create_html_element('sup')
+svg = _create_html_element('svg')
+table = _create_html_element('table')
+tbody = _create_html_element('tbody')
+td = _create_html_element('td')
+template = _create_html_element('template')
+textarea = _create_html_element('textarea')
+tfoot = _create_html_element('tfoot')
+th = _create_html_element('th')
+thead = _create_html_element('thead')
+time = _create_html_element('time')
+track = _create_html_element('track')
+u = _create_html_element('u')
+ul = _create_html_element('ul')
+var = _create_html_element('var')
+video = _create_html_element('video')
+wbr = _create_html_element('wbr')

+ 17 - 0
tests/test_html.py

@@ -0,0 +1,17 @@
+from nicegui import html, ui
+from nicegui.testing import Screen
+
+
+def test_html_element(screen: Screen):
+    ui.html('This is strong.', tag='strong')
+
+    screen.open('/')
+    assert screen.find_by_tag('strong').text == 'This is strong.'
+
+
+def test_html_button(screen: Screen):
+    html.button('Click me').on('click', lambda: ui.notify('Hi!'))
+
+    screen.open('/')
+    screen.click('Click me')
+    screen.should_contain('Hi!')

+ 21 - 0
website/documentation/content/section_text_elements.py

@@ -20,3 +20,24 @@ doc.intro(markdown_documentation)
 doc.intro(restructured_text_documentation)
 doc.intro(mermaid_documentation)
 doc.intro(html_documentation)
+
+
+@doc.demo('Other HTML Elements', '''
+    There is an `html` module that allows you to insert other HTML elements like `<span>`, `<div>`, `<p>`, etc.
+    It is equivalent to using the `ui.element` method with the `tag` argument.
+
+    Like with any other element, you can add classes, style, props, tooltips and events.
+    One convenience is that the keyword arguments are automatically added to the element's `props` dictionary.
+''')
+def other_html_elements():
+    from nicegui import html, ui
+
+    with html.section().style('font-size: 120%'):
+        html.strong('This is bold.') \
+            .classes('cursor-pointer') \
+            .on('click', lambda: ui.notify('Bold!'))
+        html.hr()
+        html.em('This is italic.').tooltip('Nice!')
+        with ui.row():
+            html.img().props('src=https://placehold.co/60')
+            html.img(src='https://placehold.co/60')