```{toctree}
---
maxdepth: 2
hidden: true
---
```
[CodeMirror 6](https://codemirror.net/) code editor for [spaday](https://github.com/1kbgz/spaday).
[](https://github.com/1kbgz/spaday-codemirror/actions/workflows/build.yaml)
[](https://codecov.io/gh/1kbgz/spaday-codemirror)
[](https://github.com/1kbgz/spaday-codemirror)
[](https://pypi.python.org/pypi/spaday-codemirror)
## Usage
`spaday-codemirror` provides one custom element, ``, and its typed spaday binding, `CodeMirror`. The package registers itself as the `codemirror` component package, so pages load its assets with `packages=["codemirror"]`.
```python
from spaday.backends.starlette import serve
from spaday_codemirror import CodeMirror
def page():
return CodeMirror(doc="print('hello')\n", language="python", theme="dark", tab_size=4)
app = serve(page, packages=["codemirror"])
```
To send edits to Python, bind `editor-change` to an action, e.g. `.on("editor-change", SendPatch("editor", "doc", event_value("doc")))`, and route the `spaday:patch` intent to your model. [`example.py`](spaday_codemirror/example.py) does this over a websocket.
Without Python, load `cdn/index.js` and `css/index.css` from `spaday_codemirror/extension/` (or `js/dist/`) and use the tag directly:
```html
```
### Properties
Attributes share the property names.
| Property | Type | Default | Description |
| ---------------- | --------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------ |
| `doc` | `string` | `""` | Editor contents |
| `language` | `"python"` \| `"javascript"` \| `"json"` \| `"markdown"` \| `"plain"` | `"plain"` | Syntax mode |
| `theme` | `"light"` \| `"dark"` | `"light"` | Color theme (`dark` uses One Dark) |
| `read_only` | `boolean` | `false` | Disallow user edits |
| `line_numbers` | `boolean` | `true` | Show the line-number gutter |
| `tab_size` | `number` | `4` | Tab width and indent unit, in spaces |
| `selection` | `{anchor: number, head?: number} \| null` | `null` | Main selection; property only. `head` defaults to `anchor`; `null` leaves it as-is |
| `remote_cursors` | `{peer, anchor, head?, label?, color?}[]` | `[]` | Remote selections; positions are tracked as the document changes. Labels and colors are optional |
Setting a property updates the existing `EditorView` in place, so focus and scroll position are kept. Property changes never emit events.
### Theming
Editor chrome follows spaday's shell palette. Component tokens can be set on the editor or any
ancestor; `spaday_codemirror.TOKENS` exposes the same names for Python `css()` calls.
| Token | Controls | Shell fallback |
| ------------------------------------- | ----------------------------- | ----------------- |
| `--spa-codemirror-surface` | Editor background | `--spa-surface` |
| `--spa-codemirror-text` | Editor and panel text | `--spa-muted` |
| `--spa-codemirror-gutter-surface` | Gutter and panel background | `--spa-surface-2` |
| `--spa-codemirror-gutter-text` | Line numbers | `--spa-muted` |
| `--spa-codemirror-border` | Editor, gutter, panel borders | `--spa-border` |
| `--spa-codemirror-focus` | Focused editor border | `--spa-accent` |
| `--spa-codemirror-cursor` | Caret and drop cursor | `--spa-accent` |
| `--spa-codemirror-selection` | Selection background | Theme default |
| `--spa-codemirror-active-line` | Active-line background | Theme default |
| `--spa-codemirror-active-line-gutter` | Active line-number background | Theme default |
Syntax colors remain owned by CodeMirror's light and One Dark themes. For example,
`CodeMirror(...).css(spa_codemirror_surface="#111", spa_codemirror_text="#ddd")` changes one
editor without changing the rest of the application.
### Events
Both events bubble and are composed.
| Event | `detail` | Fired when |
| ------------------ | ----------------------------------------------------------------- | -------------------------------------------- |
| `editor-change` | `{doc, changes: [{from, to, insert}], selection: {anchor, head}}` | The user edits the document |
| `editor-selection` | `{selection: {anchor, head}}` | The user moves the selection without editing |
### Cursor awareness
`connectCursorAwareness(editor, client, modelId)` publishes local selections through transports
awareness, renders remote selections, maps their positions across document changes, and removes them
when peers disconnect. Its optional `local` and `remote` callbacks attach and present application
metadata. The collaboration example uses those callbacks for names and colors; the shared cursor state
only requires a peer ID and selection.
## Browser examples
- [Hosted Pyodide example](https://1kbgz.github.io/spaday-codemirror/lite/): the example page running in a Python Web Worker.
- [`spaday_codemirror/example.py`](spaday_codemirror/example.py): two editors wired to a transports-hosted model, plus a gallery covering every language and representative settings. Python computes metrics and a normalized preview on each edit, and has Normalize and Reset actions.
- [`spaday_codemirror/collaboration.py`](spaday_codemirror/collaboration.py): one CRDT-backed document shared by Alice and Bob, with a read-only Viewer. Open two user links in separate tabs to see character-level edits and ephemeral cursor awareness flow through Spaday and transports. The example assigns names and colors in its browser adapter; production applications should derive identity from authenticated websocket sessions.
- [`js/examples/`](js/examples/): the Pyodide page and worker.
## Run the examples locally
```bash
make develop
make build
python -m spaday_codemirror.example # http://127.0.0.1:8031/
python -m spaday_codemirror.collaboration # http://127.0.0.1:8032/
```
Build and test the Pyodide example:
```bash
make test-pyodide-example
cd dist/lite && python -m http.server
```
> [!NOTE]
> This library was generated using [copier](https://copier.readthedocs.io/en/stable/) from the [Base Python Project Template repository](https://github.com/python-project-templates/base).