|
2 | 2 |
|
3 | 3 | # %% auto 0 |
4 | 4 | __all__ = ['picocss', 'picolink', 'picocondcss', 'picocondlink', 'set_pico_cls', 'Html', 'A', 'AX', 'Checkbox', 'Card', 'Group', |
5 | | - 'Search', 'Grid', 'DialogX', 'Hidden', 'Container', 'Script', 'Style', 'run_js', 'Titled', 'jsd'] |
| 5 | + 'Search', 'Grid', 'DialogX', 'Hidden', 'Container', 'Script', 'Style', 'double_braces', 'undouble_braces', |
| 6 | + 'loose_format', 'ScriptX', 'replace_css_vars', 'StyleX', 'run_js', 'Titled', 'jsd'] |
6 | 7 |
|
7 | 8 | # %% ../nbs/02_xtend.ipynb 2 |
8 | 9 | from dataclasses import dataclass, asdict |
9 | 10 |
|
10 | 11 | from fastcore.utils import * |
| 12 | +from fastcore.xtras import partial_format |
11 | 13 | from fastcore.xml import * |
12 | 14 | from fastcore.meta import use_kwargs, delegates |
13 | 15 | from .components import * |
@@ -128,19 +130,58 @@ def Style(*c, **kwargs)->XT: |
128 | 130 | return xt_html('style', map(NotStr,c), **kwargs) |
129 | 131 |
|
130 | 132 | # %% ../nbs/02_xtend.ipynb 31 |
| 133 | +def double_braces(s): |
| 134 | + "Convert single braces to double braces if next to special chars or newline" |
| 135 | + s = re.sub(r'{(?=[\s:;\'"]|$)', '{{', s) |
| 136 | + return re.sub(r'(^|[\s:;\'"])}', r'\1}}', s) |
| 137 | + |
| 138 | +# %% ../nbs/02_xtend.ipynb 32 |
| 139 | +def undouble_braces(s): |
| 140 | + "Convert double braces to single braces if next to special chars or newline" |
| 141 | + s = re.sub(r'\{\{(?=[\s:;\'"]|$)', '{', s) |
| 142 | + return re.sub(r'(^|[\s:;\'"])\}\}', r'\1}', s) |
| 143 | + |
| 144 | +# %% ../nbs/02_xtend.ipynb 33 |
| 145 | +def loose_format(s, **kw): |
| 146 | + "String format `s` using `kw`, without being strict about braces outside of template params" |
| 147 | + return undouble_braces(partial_format(double_braces(s), **kw)[0]) |
| 148 | + |
| 149 | +# %% ../nbs/02_xtend.ipynb 34 |
| 150 | +def ScriptX(fname, type=None, _async=None, defer=None, charset=None, crossorigin=None, integrity=None, **kw): |
| 151 | + "Create a Script from the text of a file" |
| 152 | + attrs = ['src', 'type', 'async', 'defer', 'charset', 'crossorigin', 'integrity', 'nomodule'] |
| 153 | + scr_kw = {k:kw.pop(k) for k in attrs if k in kw} |
| 154 | + s = loose_format(Path(fname).read_text(), **kw) |
| 155 | + return Script(s, **scr_kw) |
| 156 | + |
| 157 | +# %% ../nbs/02_xtend.ipynb 35 |
| 158 | +def replace_css_vars(css, pre='tpl', **kwargs): |
| 159 | + def replace_var(m): |
| 160 | + var_name = m.group(1).replace('-', '_') |
| 161 | + return kwargs.get(var_name, m.group(0)) |
| 162 | + return re.sub(fr'var\(--{pre}-([\w-]+)\)', replace_var, css) |
| 163 | + |
| 164 | +# %% ../nbs/02_xtend.ipynb 36 |
| 165 | +def StyleX(fname, **kw): |
| 166 | + s = Path(fname).read_text() |
| 167 | + attrs = ['type', 'media', 'scoped', 'title', 'nonce', 'integrity', 'crossorigin'] |
| 168 | + sty_kw = {k:kw.pop(k) for k in attrs if k in kw} |
| 169 | + return Style(replace_css_vars(s, **kw), **sty_kw) |
| 170 | + |
| 171 | +# %% ../nbs/02_xtend.ipynb 37 |
131 | 172 | def run_js(js, id=None, **kw): |
132 | 173 | "Run `js` script, auto-generating `id` based on name of caller if needed, and js-escaping any `kw` params" |
133 | 174 | if not id: id = sys._getframe(1).f_code.co_name |
134 | 175 | kw = {k:dumps(v) for k,v in kw.items()} |
135 | 176 | return Script(js.format(**kw), id=id, hx_swap_oob='true') |
136 | 177 |
|
137 | | -# %% ../nbs/02_xtend.ipynb 32 |
| 178 | +# %% ../nbs/02_xtend.ipynb 38 |
138 | 179 | @delegates(xt_hx, keep=True) |
139 | 180 | def Titled(title:str="FastHTML app", *args, **kwargs)->XT: |
140 | 181 | "An HTML partial containing a `Title`, and `H1`, and any provided children" |
141 | 182 | return Title(title), Main(H1(title), *args, cls="container", **kwargs) |
142 | 183 |
|
143 | | -# %% ../nbs/02_xtend.ipynb 33 |
| 184 | +# %% ../nbs/02_xtend.ipynb 39 |
144 | 185 | def jsd(org, repo, root, path, prov='gh', typ='script', ver=None, esm=False, **kwargs)->XT: |
145 | 186 | "jsdelivr `Script` or CSS `Link` tag, or URL" |
146 | 187 | ver = '@'+ver if ver else '' |
|
0 commit comments