Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MEP 0003: UI Elements #3

Merged
merged 19 commits into from
Nov 16, 2022
Prev Previous commit
Next Next commit
edits
  • Loading branch information
akshayka committed Nov 13, 2022
commit fee354f1a57cd0b1129f1f2aacfb603a99f3791b
47 changes: 24 additions & 23 deletions mep-0003.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Implementation: XXX
## Abstract

This MEP lays out a design for creating user interface (UI) elements
as cell outputs, and synchronizing their value on the frontend and with the
kernel The main concerns of the design are:
as cell outputs, and synchronizing their values on the frontend and with the
kernel. The main concerns of the design are:

- the concept of a UI element as an HTML element with a value
- syntax for accessing a UI element's value
Expand All @@ -20,7 +20,7 @@ kernel The main concerns of the design are:
- synchronizing a UI element's value in the frontend with its value in the
kernel
- a simple rule that determines which cells are run when a UI element is interacted with
- a simple mechanism for making custom elements
- a mechanism for making custom elements

## Motivation

Expand All @@ -32,7 +32,7 @@ to make custom UI elements as well as make any Python object render as a UI
element. While some open-source libraries and commercial editing tools provide
subsets of this functionality in ad-hoc ways, to our knowledge no tool like
marimo (open-source or otherwise) exists for Python developers. In particular,
no tool provides a pure Python experience, in which both experiments and
no tool provides a pure Python experience in which both experiments and
applications are built using an extensible, modular, and composable programming
framework. Because UI elements are key to enabling both rapid experimentation
and app development, it is vital that they are carefully designed.
Expand All @@ -55,13 +55,14 @@ Its value may change when interacted with.

### The `UIElement` type

A `UIElement` is a Python class representing an HTML element that has a value,
stored in a property called `value`. This value can be set at creation time by
the user, to designate a default value for the element. After creation, the
value cannot be changed by user code.
A `UIElement` is a Python class representing an HTML element that has a value.
This value can be set at creation time by the user, to designate a default
value for the element. After creation, the value cannot be changed by user
code.

The `UIElement` class implements the `formatting.MIME` protocol, and its
`__mime__` method returns an output of type `text/html`.
`__mime__` method returns an output of type `text/html`. Its value is made
available through a property called `value`.


The frontend can render the same `UIElement` multiple times, with multiple
Expand Down Expand Up @@ -93,13 +94,13 @@ dictionary, and set.

We defer the design of `marimo.ui` to a future MEP.

## A Runtime rule
## A runtime rule

A single rule determines which cells will run after a `UIElement` is interacted
with: any cell referring to one or more of the names bound to a `UIElement`
will be run whenever a UI Element sends a value to the kernel. By
will be run whenever a UI element sends a value to the kernel. By
"referring", we mean that the cell has a name bound to the element among its
_refs_.
refs.

### Examples
**A simple example.**
Expand Down Expand Up @@ -163,18 +164,18 @@ pointless. However, in some cases, the fact that constructor cells are not run m
> cell a
```python
# this cell won't do what its author wanted it to do ...
slider = mo.ui.slider(start=1, stop=10)
x = slider.value
text = mo.ui.text()
contents = text.value
```

> cell b
```python
slider
contents
```

Interacting with the emitted slider will _not_ update the value of `x`. To
prevent confusion, we raise an exception at runtime when a
`UIElement`'s value is accessed in the cell that created it. In particular,
`UIElement`'s value is accessed in the cell that created it. Here,
line `2` of cell `a` would raise an exception.

**Cells that reference and output a UI element.**
Expand Down Expand Up @@ -203,7 +204,7 @@ text = mo.ui.text()
> cell b:
```python
contents = text.value
text, contents
text, f"character count: {len(contents)}"
```


Expand Down Expand Up @@ -270,8 +271,8 @@ which the UI element is root.
**Object ID.**
A `ui-element` has a single attribute, `object-id`, which
uniquely identifies a `UIElement` object in the Python kernel. There may
be multiple `<ui-elements>` on the page with the same object id if the same
element is shown multiple times on the page.
be multiple `<ui-element>` tags on the page with the same object id if the same
(Python) element is shown multiple times on the page.

**Communication.** The `ui-element`'s child sends a custom event,
`marimo-value-input`, when its value has been updated:
Expand All @@ -280,9 +281,9 @@ element is shown multiple times on the page.
type marimoValueInputEventType = CustomEvent<{ value: any }>;
```

In response, the `<ui-element>` sends a `marimo-value-update` event
to all other objects sharing its object id to inform them that their values need
to be updated:
In response, the `ui-element` component sends a `marimo-value-update` event
to all other `ui-element`s sharing its object id to inform them that their
values need to be updated:

```typescript
type marimoValueUpdateEventType = CustomEvent<{ value: any }>;
Expand All @@ -299,7 +300,7 @@ that render their content in a shadow DOM. This has the following advantages:

- Styles are isolated from the editor.
- The implementation of the UI element is separate from the editor code
and framework agnostic.
and is framework agnostic.
- UI elements are easily composed using slots.
- UI elements are easy to create from Python --- we send over
an HTML tag with attributes encoding the arguments of the UI element, and the
Expand Down