Bridge plugins

Example Bridge plugins and their usage
bridge = get_bridge(show_logger=True, wait=5)

HTMX API

Method - htmx.swap()

Performs swapping (and settling) of HTML content

Parameters
  • target - the HTML element or string selector of swap target
  • content - string representation of content to be swapped
  • swapSpec - swapping specification, representing parameters from hx-swap
    • swapStyle (required) - swapping style (innerHTML, outerHTML, beforebegin etc)
    • swapDelay, settleDelay (number) - delays before swapping and settling respectively
    • transition (bool) - whether to use HTML transitions for swap
    • ignoreTitle (bool) - disables page title updates
    • head (string) - specifies head tag handling strategy (merge or append). Leave empty to disable head handling
    • scroll, scrollTarget, show, showTarget, focusScroll - specifies scroll handling after swap
  • swapOptions - additional optional parameters for swapping
    • select - selector for the content to be swapped (equivalent of hx-select)
    • selectOOB - selector for the content to be swapped out-of-band (equivalent of hx-select-oob)
    • eventInfo - an object to be attached to htmx:afterSwap and htmx:afterSettle elements
    • anchor - an anchor element that triggered scroll, will be scrolled into view on settle. Provides simple alternative to full scroll handling
    • contextElement - DOM element that serves as context to swapping operation. Currently used to find extensions enabled for specific element
    • afterSwapCallback, afterSettleCallback - callback functions called after swap and settle respectively. Take no arguments
Example
    // swap #output element inner HTML with div element with "Swapped!" text
    htmx.swap("#output", "<div>Swapped!</div>", {swapStyle: 'innerHTML'});

HTMX Commander

Python wrapper of HTMX API.

Currently only implemented htmx.swap() manually. If useful, I’ll automate wrappers generation from htmx docs.

commander_esm = bundled(commander_js)(debugger=DEBUG(), ts=True)

source

HTMXCommander

 HTMXCommander (*args, **kwargs)

Main AnyWidget base class.

cleanupwidgets('cmdr')

cmdr = HTMXCommander.create(timeout=2)#DEBUG(2))

Test swap

<div id="output-99">Original</div>
Original
cmdr.swap('#output-99', '<div>Swapped!</div>', swapStyle='innerHTML')
cmdr.close()

—-

First steps exploring automation. Skip it.

# HTMXCommander plugin
We can use HTMXCommander by itself. But probably, it’ll be more useful as a bridge plugin.

source

HTMXCommanderPlugin

 HTMXCommanderPlugin (ctx:str='', src:str|pathlib.Path='', bridge=None)

Inherit from this to have all attr accesses in self._xtra passed down to self.default

bridge.add_plugins((cmdr := HTMXCommanderPlugin()), wait=5)
(d := Div(id='output-9999')('Original 2'))
Original 2
cmdr.swap(d, Div('Swapped 2'), swapStyle='innerHTML')
def swap(self,*args, **kwargs): 
    bridge.commander.swap(self, *args, **kwargs)
FC.patch_to(FT)(swap)
div = Div(id='output-99999')('Original 3')
div
Original 3
div.swap('<div>Swapped 3</div>', swapStyle='innerHTML')

NBHooksPlugin

Python-only bridge plugin to help us inspect, control, and modify cell outputs.

Note: in VSCode output_capture is unreliable, unfortunately, and don’t play well with the debugger. Jeremy rules in almost everything programming-wise, but in this I’m more aligned with Carson: Grug Brained Developers need powerful (graphical, I double Grug) debuggers. How very much I would rather not use VSCode notebooks.

You can switch on/off the capturer. We’ll hopefully be able to develop alternatives down the road.


source

NBHooksPlugin

 NBHooksPlugin (*args, **kwargs)

Inherit from this to have all attr accesses in self._xtra passed down to self.default

bridge_cfg.update(auto_id=True, auto_show=True)
{'auto_show': True, 'auto_mount': False, 'auto_id': True, 'bundle_cfg': {'out_dir': [Path('/Users/vic/dev/repo/project/bridget/bridget/js'), Path('/Users/vic/dev/repo/project/bridget/bridget')], 'rewrite_imports': True, 'import_name': 'brdimport'}, 'bootstrap': False, 'current_did': None}
bridge.add_plugins(NBHooksPlugin())
cprint(bridge.nbhooks.brdd.dhs)
deque(maxlen=100)
HTML(f"2, 3, 5, 7")
11, 13, 17, 19, 23, 29
test_eq(__nb__[__lastcellinfo__.cell_id].outputs[0].metadata['brd_did'], bridge.nbhooks.dh.display_id)
__nb__[__lastcellinfo__.cell_id]
NBCell@1
  • idx: 1
  • source: HTML(f"2, 3, 5, 7")
  • id: Y102sZmlsZQ==
  • cell_type: code
  • outputs
      0
      • output_type: display_data
      • data
        • text/plain: <bridget.helpers.HTML object>
        • text/html: 2, 3, 5, 7 <brd-mark id="bb29686bf-936c32eb-f67649d1-ed04a9ab"></brd-mark>
      • metadata: {'bridge': {'captured': True}, 'brd_did': 'bb29686bf-936c32eb-f67649d1-ed04a9ab'}
      1
      • output_type: execute_result
      • execution_count: 36
      • data
        • text/plain: <bridget.helpers.HTML object>
        • text/html: 2, 3, 5, 7
      • metadata: {}
  • execution_count: 36
bridge.nbhooks.brdd.dhs[-2].update(HTML(f"11, 13, 17, 19, 23, 29"))
# cprint(__cellinfo__)
ci = __cellinfo__
displaydh(HTML(f"It’s a fact everybody already knows,<br>Single rich man, man he gotta propose."))
HTML(' ')
It’s a fact everybody already knows,
Single rich man, man he gotta propose.
New in town, what’s he thinking? Nobody cares,
Every mama scheming, whisperin’ prayers.
bridge.nbhooks.dh.update(HTML(f"New in town, what’s he thinking? Nobody cares,<br>Every mama scheming, whisperin’ prayers."))
cprint(__cellinfo__)
{
    'source': 'bridge.nbhooks.dh.update(HTML(f"New in town, what’s he thinking? Nobody cares,<br>Every mama scheming, whisperin’ 
prayers."))\ncprint(__cellinfo__)',
    'cell_id': 'Y106sZmlsZQ==',
    'exec_result': {'result': None}
}
speech_Batty = """I've seen things you people wouldn't believe.
Attack ships on fire off the shoulder of Orion.
I watched C-beams glitter in the dark near the Tannhäuser Gate.
All those moments will be lost in time, like tears in rain.
Time to die.""".split('\n')

HTML('<br>'.join(speech_Batty[:-2]) + "<div class='what-follows' style='color: red;'>...</div>")
I've seen things you people wouldn't believe.
Attack ships on fire off the shoulder of Orion.
I watched C-beams glitter in the dark near the Tannhäuser Gate.
All those moments will be lost in time, like tears in rain.
Time to die.
bridge.commander.swap(
    f"div[data-brt-id={bridge.nbhooks.dh.display_id}]>.what-follows", 
    Div(style={'color':'darkgreen'})(speech_Batty[-2], Br(), speech_Batty[-1]),
    swapStyle='outerHTML')
bridge.nbhooks.dh.update(HTML('<br>'.join(speech_Batty)))

<zero-md>

Ridiculously simple zero-config markdown displayer

md_samp = '''
# &lt;zero-md&gt;

> Ridiculously simple zero-config markdown displayer

A vanilla markdown-to-html web component based on
[Custom Elements V1 specs](https://www.w3.org/TR/custom-elements/) to load and display an external
MD file.

Featuring:

- [x] Math rendering via [`KaTeX`](https://github.com/KaTeX/KaTeX)
- [x] [`Mermaid`](https://github.com/mermaid-js/mermaid) diagrams
- [x] Syntax highlighting via [`highlight.js`](https://github.com/highlightjs/highlight.js)

```python
a = {'a': 'asdf', 'b': 10}
print("local server is listening on port 8080")
```
'''

Markdown(md_samp)

<zero-md>

Ridiculously simple zero-config markdown displayer

A vanilla markdown-to-html web component based on Custom Elements V1 specs to load and display an external MD file.

Featuring:

a = {'a': 'asdf', 'b': 10}
print("local server is listening on port 8080")
bridge.logger.show()
bridge.loader.load_links({'zeromd':zeromd_scr})
from fasthtml.components import Zero_md, Template
from bridget.bridge_widget import StyleV
def render_local_md(md, css=''):
    css_template = Template(StyleV(css), data_append=True)
    return Zero_md(css_template, Script(md, type="text/markdown"))
md_ft = render_local_md(md_samp)
with bridge_cfg(auto_show=False): display(md_ft)
<zero-md><template data-append>    <style></style>
</template><script type="text/markdown">
# &lt;zero-md&gt;

> Ridiculously simple zero-config markdown displayer

A vanilla markdown-to-html web component based on
[Custom Elements V1 specs](https://www.w3.org/TR/custom-elements/) to load and display an external
MD file.

Featuring:

- [x] Math rendering via [`KaTeX`](https://github.com/KaTeX/KaTeX)
- [x] [`Mermaid`](https://github.com/mermaid-js/mermaid) diagrams
- [x] Syntax highlighting via [`highlight.js`](https://github.com/highlightjs/highlight.js)

```python
a = {'a': 'asdf', 'b': 10}
print("local server is listening on port 8080")

:::
:::


::: {#0ac19a8b .cell}
``` {.python .cell-code}
md_ft
bridge.nbhooks.dh.update(render_local_md('## Hi again!'))

Recap of NBHooks features:

As a bridge plugin, NBHooks provides:

  1. Wrapper of CellExecInfo to provide current and last cell info, including cell id.
  2. Add metadata to all displayed rich media
  3. Add metadata to cell output.
cleanupwidgets('bridge')

bridge = get_bridge(show_logger=True)
bridge.add_plugins(NBHooksPlugin())

1. Capture cell info

with cell id if possible: Jupyter Notebook/Lab, VSCode-ish; nbclassic doesn’t gen cell ids.

Will be handy when we have access to notebook state.

cprint(ci := __cellinfo__)
test_eq(__cellinfo__['source'][:26], 'cprint(ci := __cellinfo__)')
# test_eq(brd.csi.dh['cell_id'], cid)
{
    'source': "cprint(ci := __cellinfo__)\ntest_eq(__cellinfo__['source'][:26], 'cprint(ci := __cellinfo__)')\n# 
test_eq(brd.csi.dh['cell_id'], cid)",
    'cell_id': 'Y132sZmlsZQ==',
    'exec_result': {'result': None}
}

2. Every rich cell output, those made with display(…), or last cell expression, is captured and converted to transient

i.e., equivalent to display(…,display_id=True).
NBHooks stores the DisplayHandle, and cellinfo got the display_id in __cellinfo__.did

display(Markdown("""`The World in His Arms`"""))
bridge.nbhooks.dh.update(A(href='https://en.wikipedia.org/wiki/The_World_in_His_Arms')('The World in His Arms'))
bridge.nbhooks.dh.update(Image(url='https://upload.wikimedia.org/wikipedia/commons/4/4b/WorldInHisArms-poster.jpg', height=150))

Capture automatic cell output also

Div('asdf')
qwer
# bridge.nbhooks.dh.update(HTML('<div>qwer</div>'))
bridge.nbhooks.dh.update(HTML(Div('qwer')))

3. All HTML captured outputs have Bridge metadata (see Brd_Mark)

We use a custom element to mark the parent element in the front-end. HTML display objects allow us to add this custom element (brd_mark) easily. We’d also like to tag other rich outputs but we can’t do it with only IPython/Kernel mechanisms.

did = '23579111317'
HTML(Div(f"My parent element has a `data-brd-id` attribute with value '{did}'. Inspect me!"), 
    metadata={'brd_did': did})
My parent element has a `data-brd-id` attribute with value '23579111317'. Inspect me!
test_eq(__nb__[__lastcellinfo__.cell_id].outputs[0]['data']['text/html'].split('\n')[-1], f'<brd-mark id="{did}"></brd-mark>')

4. HTMX API (WIP)

Besides DisplayHandler.update(…) you can modify the HTML outputs directly with HTMX API python wrapper (swap only for now).