Skip to content

Commit

Permalink
fixes #517
Browse files Browse the repository at this point in the history
  • Loading branch information
jph00 committed Oct 13, 2024
1 parent e91b9af commit 5b6e565
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 33 deletions.
3 changes: 3 additions & 0 deletions fasthtml/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
'fasthtml.core.StringConvertor.to_string': ('api/core.html#stringconvertor.to_string', 'fasthtml/core.py'),
'fasthtml.core.WS_RouteX': ('api/core.html#ws_routex', 'fasthtml/core.py'),
'fasthtml.core.WS_RouteX.__init__': ('api/core.html#ws_routex.__init__', 'fasthtml/core.py'),
'fasthtml.core._add_ids': ('api/core.html#_add_ids', 'fasthtml/core.py'),
'fasthtml.core._annotations': ('api/core.html#_annotations', 'fasthtml/core.py'),
'fasthtml.core._apply_ft': ('api/core.html#_apply_ft', 'fasthtml/core.py'),
'fasthtml.core._find_p': ('api/core.html#_find_p', 'fasthtml/core.py'),
Expand Down Expand Up @@ -98,10 +99,12 @@
'fasthtml.core.get_key': ('api/core.html#get_key', 'fasthtml/core.py'),
'fasthtml.core.parse_form': ('api/core.html#parse_form', 'fasthtml/core.py'),
'fasthtml.core.parsed_date': ('api/core.html#parsed_date', 'fasthtml/core.py'),
'fasthtml.core.pusher': ('api/core.html#pusher', 'fasthtml/core.py'),
'fasthtml.core.reg_re_param': ('api/core.html#reg_re_param', 'fasthtml/core.py'),
'fasthtml.core.serve': ('api/core.html#serve', 'fasthtml/core.py'),
'fasthtml.core.signal_shutdown': ('api/core.html#signal_shutdown', 'fasthtml/core.py'),
'fasthtml.core.snake2hyphens': ('api/core.html#snake2hyphens', 'fasthtml/core.py'),
'fasthtml.core.unqid': ('api/core.html#unqid', 'fasthtml/core.py'),
'fasthtml.core.uri': ('api/core.html#uri', 'fasthtml/core.py')},
'fasthtml.fastapp': { 'fasthtml.fastapp._app_factory': ('api/fastapp.html#_app_factory', 'fasthtml/fastapp.py'),
'fasthtml.fastapp._get_tbl': ('api/fastapp.html#_get_tbl', 'fasthtml/fastapp.py'),
Expand Down
9 changes: 7 additions & 2 deletions fasthtml/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,21 @@ def attrmap_x(o):
# %% ../nbs/api/01_components.ipynb
fh_cfg['attrmap']=attrmap_x
fh_cfg['valmap' ]=valmap
fh_cfg['ft_cls' ]=FT
fh_cfg['auto_id' ]=False

# %% ../nbs/api/01_components.ipynb
def ft_html(tag: str, *c, id=None, cls=None, title=None, style=None, attrmap=None, valmap=None, ft_cls=FT, **kwargs):
def ft_html(tag: str, *c, id=None, cls=None, title=None, style=None, attrmap=None, valmap=None, ft_cls=None, auto_id=None, **kwargs):
ds,c = partition(c, risinstance(dict))
for d in ds: kwargs = {**kwargs, **d}
if ft_cls is None: ft_cls = fh_cfg.ft_cls
if attrmap is None: attrmap=fh_cfg.attrmap
if valmap is None: valmap =fh_cfg.valmap
if auto_id is None: auto_id = fh_cfg.auto_id
if auto_id and not id: id = unqid()
kwargs['id'],kwargs['cls'],kwargs['title'],kwargs['style'] = id,cls,title,style
tag,c,kw = ft(tag, *c, attrmap=attrmap, valmap=valmap, **kwargs).list
if tag in named and 'id' in kw and 'name' not in kw: kw['name'] = kw['id']
if tag in named and id and 'name' not in kw: kw['name'] = kw['id']
return ft_cls(tag,c,kw, void_=tag in voids)

# %% ../nbs/api/01_components.ipynb
Expand Down
50 changes: 47 additions & 3 deletions fasthtml/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/00_core.ipynb.

# %% auto 0
__all__ = ['empty', 'htmx_hdrs', 'fh_cfg', 'htmx_resps', 'htmxsrc', 'htmxwssrc', 'fhjsscr', 'htmxctsrc', 'surrsrc', 'scopesrc',
'viewport', 'charset', 'all_meths', 'parsed_date', 'snake2hyphens', 'HtmxHeaders', 'HttpHeader',
__all__ = ['empty', 'htmx_hdrs', 'fh_cfg', 'htmx_resps', 'htmx_exts', 'htmxsrc', 'htmxwssrc', 'fhjsscr', 'htmxctsrc', 'surrsrc',
'scopesrc', 'viewport', 'charset', 'all_meths', 'parsed_date', 'snake2hyphens', 'HtmxHeaders', 'HttpHeader',
'HtmxResponseHeaders', 'form2dict', 'parse_form', 'flat_xt', 'Beforeware', 'EventStream', 'signal_shutdown',
'WS_RouteX', 'uri', 'decode_uri', 'flat_tuple', 'Redirect', 'RouteX', 'RouterX', 'get_key', 'def_hdrs',
'FastHTML', 'serve', 'Client', 'cookie', 'reg_re_param', 'MiddlewareBase', 'FtResponse']
'FastHTML', 'serve', 'Client', 'cookie', 'reg_re_param', 'MiddlewareBase', 'FtResponse', 'unqid', 'pusher']

# %% ../nbs/api/00_core.ipynb
import json,uuid,inspect,types,uvicorn,signal,asyncio,threading
Expand All @@ -30,6 +30,8 @@
from dateutil import parser as dtparse
from httpx import ASGITransport, AsyncClient
from anyio import from_thread
from uuid import uuid4
from base64 import b85encode,b64encode

from .starlette import *

Expand Down Expand Up @@ -461,6 +463,17 @@ def add_ws(self, path: str, recv: callable, conn:callable=None, disconn:callable
route = WS_RouteX(self._app, path, recv=recv, conn=conn, disconn=disconn, name=name)
self._add_route(route)

# %% ../nbs/api/00_core.ipynb
htmx_exts = {
"head-support": "https://unpkg.com/htmx-ext-head-support@2.0.1/head-support.js",
"preload": "https://unpkg.com/htmx-ext-preload@2.0.1/preload.js",
"class-tools": "https://unpkg.com/htmx-ext-class-tools@2.0.1/class-tools.js",
"loading-states": "https://unpkg.com/htmx-ext-loading-states@2.0.0/loading-states.js",
"multi-swap": "https://unpkg.com/htmx-ext-multi-swap@2.0.0/multi-swap.js",
"path-deps": "https://unpkg.com/htmx-ext-path-deps@2.0.0/path-deps.js",
"remove-me": "https://unpkg.com/htmx-ext-remove-me@2.0.0/remove-me.js"
}

# %% ../nbs/api/00_core.ipynb
htmxsrc = Script(src="https://unpkg.com/htmx.org@next/dist/htmx.min.js")
htmxwssrc = Script(src="https://unpkg.com/htmx-ext-ws/ws.js")
Expand Down Expand Up @@ -663,3 +676,34 @@ def __response__(self, req):
cts,httphdrs,tasks = _xt_cts(req, self.content)
headers = {**(self.headers or {}), **httphdrs}
return self.cls(cts, status_code=self.status_code, headers=headers, media_type=self.media_type, background=tasks)

# %% ../nbs/api/00_core.ipynb
def unqid():
res = b64encode(uuid4().bytes)
return '_' + res.decode().rstrip('=').translate(str.maketrans('+/', '_-'))

# %% ../nbs/api/00_core.ipynb
def _add_ids(s):
if not isinstance(s, FT): return
if not getattr(s, 'id', None): s.id = unqid()
for c in s.children: _add_ids(c)

# %% ../nbs/api/00_core.ipynb
def pusher(app, dest_id='_dest', auto_id=True):
queue = asyncio.Queue()

@app.ws("/ws")
async def ws(ws, send):
while True: await send(await queue.get())

@app.route
def index():
return Div(id=dest_id, hx_trigger='load', ws_send=True, hx_ext="ws", ws_connect="/ws")

def push(*s):
id = getattr(s[0], 'id', None)
if not id: s = Div(*s, hx_swap_oob='innerHTML', id=dest_id)
if auto_id: _add_ids(s)
queue.put_nowait(s)

return push
76 changes: 76 additions & 0 deletions nbs/api/00_core.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
"from dateutil import parser as dtparse\n",
"from httpx import ASGITransport, AsyncClient\n",
"from anyio import from_thread\n",
"from uuid import uuid4\n",
"from base64 import b85encode,b64encode\n",
"\n",
"from fasthtml.starlette import *\n",
"\n",
Expand Down Expand Up @@ -1204,6 +1206,25 @@
" self._add_route(route)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6d9cc95f",
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"htmx_exts = {\n",
" \"head-support\": \"https://unpkg.com/htmx-ext-head-support@2.0.1/head-support.js\", \n",
" \"preload\": \"https://unpkg.com/htmx-ext-preload@2.0.1/preload.js\", \n",
" \"class-tools\": \"https://unpkg.com/htmx-ext-class-tools@2.0.1/class-tools.js\", \n",
" \"loading-states\": \"https://unpkg.com/htmx-ext-loading-states@2.0.0/loading-states.js\", \n",
" \"multi-swap\": \"https://unpkg.com/htmx-ext-multi-swap@2.0.0/multi-swap.js\", \n",
" \"path-deps\": \"https://unpkg.com/htmx-ext-path-deps@2.0.0/path-deps.js\", \n",
" \"remove-me\": \"https://unpkg.com/htmx-ext-remove-me@2.0.0/remove-me.js\"\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down Expand Up @@ -2627,6 +2648,61 @@
"assert '<title>Foo</title>' in txt and '<h1>bar</h1>' in txt and '<html>' in txt"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9dc1025e",
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"def unqid():\n",
" res = b64encode(uuid4().bytes)\n",
" return '_' + res.decode().rstrip('=').translate(str.maketrans('+/', '_-'))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5b67e014",
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"def _add_ids(s):\n",
" if not isinstance(s, FT): return\n",
" if not getattr(s, 'id', None): s.id = unqid()\n",
" for c in s.children: _add_ids(c)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2721eb83",
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"def pusher(app, dest_id='_dest', auto_id=True):\n",
" queue = asyncio.Queue()\n",
"\n",
" @app.ws(\"/ws\")\n",
" async def ws(ws, send):\n",
" while True: await send(await queue.get())\n",
"\n",
" @app.route\n",
" def index():\n",
" return Div(id=dest_id, hx_trigger='load', ws_send=True, hx_ext=\"ws\", ws_connect=\"/ws\")\n",
"\n",
" def push(*s):\n",
" id = getattr(s[0], 'id', None)\n",
" if not id: s = Div(*s, hx_swap_oob='innerHTML', id=dest_id)\n",
" if auto_id: _add_ids(s)\n",
" queue.put_nowait(s)\n",
"\n",
" return push"
]
},
{
"cell_type": "markdown",
"id": "474e14b4",
Expand Down
41 changes: 13 additions & 28 deletions nbs/api/01_components.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,9 @@
"source": [
"#| export\n",
"fh_cfg['attrmap']=attrmap_x\n",
"fh_cfg['valmap' ]=valmap"
"fh_cfg['valmap' ]=valmap\n",
"fh_cfg['ft_cls' ]=FT\n",
"fh_cfg['auto_id' ]=False"
]
},
{
Expand All @@ -187,14 +189,17 @@
"outputs": [],
"source": [
"#| export\n",
"def ft_html(tag: str, *c, id=None, cls=None, title=None, style=None, attrmap=None, valmap=None, ft_cls=FT, **kwargs):\n",
"def ft_html(tag: str, *c, id=None, cls=None, title=None, style=None, attrmap=None, valmap=None, ft_cls=None, auto_id=None, **kwargs):\n",
" ds,c = partition(c, risinstance(dict))\n",
" for d in ds: kwargs = {**kwargs, **d}\n",
" if ft_cls is None: ft_cls = fh_cfg.ft_cls\n",
" if attrmap is None: attrmap=fh_cfg.attrmap\n",
" if valmap is None: valmap =fh_cfg.valmap\n",
" if auto_id is None: auto_id = fh_cfg.auto_id\n",
" if auto_id and not id: id = unqid()\n",
" kwargs['id'],kwargs['cls'],kwargs['title'],kwargs['style'] = id,cls,title,style\n",
" tag,c,kw = ft(tag, *c, attrmap=attrmap, valmap=valmap, **kwargs).list\n",
" if tag in named and 'id' in kw and 'name' not in kw: kw['name'] = kw['id']\n",
" if tag in named and id and 'name' not in kw: kw['name'] = kw['id']\n",
" return ft_cls(tag,c,kw, void_=tag in voids)"
]
},
Expand Down Expand Up @@ -224,7 +229,6 @@
"text/markdown": [
"```html\n",
"<a @click_dot_away=\"1\"></a>\n",
"\n",
"```"
],
"text/plain": [
Expand All @@ -251,7 +255,6 @@
"text/markdown": [
"```html\n",
"<a @click.away=\"1\"></a>\n",
"\n",
"```"
],
"text/plain": [
Expand All @@ -278,7 +281,6 @@
"text/markdown": [
"```html\n",
"<a @click.away=\"1\"></a>\n",
"\n",
"```"
],
"text/plain": [
Expand All @@ -305,7 +307,6 @@
"text/markdown": [
"```html\n",
"<a hx-vals='{\"a\": 1}'></a>\n",
"\n",
"```"
],
"text/plain": [
Expand Down Expand Up @@ -374,10 +375,7 @@
"data": {
"text/markdown": [
"```html\n",
"<form hx-post=\"/\" hx-target=\"#tgt\" id=\"frm\" name=\"frm\">\n",
" <button hx-target=\"#foo\" id=\"btn\" name=\"btn\"></button>\n",
"</form>\n",
"\n",
"<form hx-post=\"/\" hx-target=\"#tgt\" id=\"frm\" name=\"frm\"><button hx-target=\"#foo\" id=\"btn\" name=\"btn\"></button></form>\n",
"```"
],
"text/plain": [
Expand Down Expand Up @@ -449,23 +447,10 @@
"data": {
"text/markdown": [
"```html\n",
"<form>\n",
" <fieldset name=\"stuff\">\n",
" <input value=\"Profit\" id=\"title\" class=\"char\" name=\"title\">\n",
" <label class=\"px-2\">\n",
" <input type=\"checkbox\" name=\"done\" data-foo=\"bar\" class=\"checkboxer\" checked=\"1\">\n",
"Done\n",
" </label>\n",
" <input type=\"hidden\" id=\"id\" name=\"id\" value=\"2\">\n",
" <select name=\"opt\">\n",
" <option value=\"a\"></option>\n",
" <option value=\"b\" selected=\"1\"></option>\n",
" </select>\n",
" <textarea id=\"details\" name=\"details\">Details</textarea>\n",
" <button>Save</button>\n",
" </fieldset>\n",
"</form>\n",
"\n",
"<form><fieldset name=\"stuff\"> <input value=\"Profit\" id=\"title\" class=\"char\" name=\"title\">\n",
"<label class=\"px-2\"> <input type=\"checkbox\" name=\"done\" data-foo=\"bar\" class=\"checkboxer\" checked=\"1\">\n",
"Done</label> <input type=\"hidden\" id=\"id\" name=\"id\" value=\"2\">\n",
"<select name=\"opt\"><option value=\"a\"></option><option value=\"b\" selected=\"1\"></option></select><textarea id=\"details\" name=\"details\">Details</textarea><button>Save</button></fieldset></form>\n",
"```"
],
"text/plain": [
Expand Down

0 comments on commit 5b6e565

Please sign in to comment.