```{toctree} --- maxdepth: 2 hidden: true --- ``` spaday-codemirror logo, a code editor inside a browser window [CodeMirror 6](https://codemirror.net/) code editor for [spaday](https://github.com/1kbgz/spaday). [![Build Status](https://github.com/1kbgz/spaday-codemirror/actions/workflows/build.yaml/badge.svg?branch=main&event=push)](https://github.com/1kbgz/spaday-codemirror/actions/workflows/build.yaml) [![codecov](https://codecov.io/gh/1kbgz/spaday-codemirror/branch/main/graph/badge.svg)](https://codecov.io/gh/1kbgz/spaday-codemirror) [![License](https://img.shields.io/github/license/1kbgz/spaday-codemirror)](https://github.com/1kbgz/spaday-codemirror) [![PyPI](https://img.shields.io/pypi/v/spaday-codemirror.svg)](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).