Mount an editor
The honest minimum: register a node type, add one, frame it. Xen is the default theme — no setup.
{
"version": "xenolith.v1",
"nodes": [
{
"id": "greeter",
"type": "Greeter",
"position": {
"x": 0,
"y": 0
},
"render": {
"title": "Greeter"
},
"state": {
"msg": "Hello, Xenolith"
},
"pins": [
{
"id": "greeter:out",
"kind": "data",
"direction": "out",
"type": "string",
"multiple": true,
"label": "Out"
}
],
"widgets": [
{
"id": "msg",
"type": "text",
"key": "msg",
"label": "Message",
"freeFloating": true
}
]
}
],
"edges": []
} import { XenolithGraph } from '@xenolithengine/graph-react'
import { buildMount } from '@xenolithengine/demo/mount'
import { DemoStage } from '../Layout.js'
/** Island: the honest minimum — Xen is the default theme; load one node (mount.json) and frame it. */
export function MountDemo() {
return (
<DemoStage>
<XenolithGraph className="xeno" resizeToWindow={false} onReady={(editor) => buildMount(editor)} />
</DemoStage>
)
} // The honest minimum: no theme (Xen is the default), one node, framed. The node is DATA (mount.json)
// loaded with editor.loadJSON — the smallest possible xenolith.v1 graph.
import type { XenolithEditor } from '@xenolithengine/graph-editor'
import graph from './mount.json'
export function buildMount(editor: XenolithEditor): void {
editor.loadJSON(graph)
editor.fitView({ padding: 80, maxZoom: 1 })
} <script setup lang="ts">
// Vue 3 SFC — the honest minimum: load one node, frame it. Xen is the default theme.
import { XenolithGraph } from '@xenolithengine/graph-vue'
import { buildMount } from '@xenolithengine/demo/mount'
</script>
<template>
<div class="app" style="position:absolute;inset:0;">
<XenolithGraph class="xeno" :resize-to-window="false" @ready="buildMount" />
</div>
</template> // The honest minimum: no theme (Xen is the default), one node, framed. The node is DATA (mount.json)
// loaded with editor.loadJSON — the smallest possible xenolith.v1 graph.
import type { XenolithEditor } from '@xenolithengine/graph-editor'
import graph from './mount.json'
export function buildMount(editor: XenolithEditor): void {
editor.loadJSON(graph)
editor.fitView({ padding: 80, maxZoom: 1 })
} // Svelte adapter — mount. The idiomatic Svelte surface is `<div use:xenolith={props}>`; for
// programmatic setup (registering schemas, framing) we use the imperative `createXenolithGraph`
// primitive the adapter exposes alongside the action. This mount runs on the site under a
// vanilla loader because the per-example router boots Svelte demos as plain TS.
import { createXenolithGraph } from '@xenolithengine/graph-svelte'
import { buildMount } from '@xenolithengine/demo/mount'
export async function mount(target: HTMLElement): Promise<() => void> {
const slot = document.createElement('div')
slot.style.cssText = 'position:absolute;inset:0;'
target.appendChild(slot)
const binding = await createXenolithGraph(slot, { resizeToWindow: false })
buildMount(binding.editor)
return () => { binding.destroy(); slot.remove() }
} // The honest minimum: no theme (Xen is the default), one node, framed. The node is DATA (mount.json)
// loaded with editor.loadJSON — the smallest possible xenolith.v1 graph.
import type { XenolithEditor } from '@xenolithengine/graph-editor'
import graph from './mount.json'
export function buildMount(editor: XenolithEditor): void {
editor.loadJSON(graph)
editor.fitView({ padding: 80, maxZoom: 1 })
} // Solid adapter — mount. Idiomatic Solid surface is `<div use:xenolith={props} />` (the directive
// re-dispatches events with colon names: `on:node:click`). For programmatic editor access we use
// the parallel imperative primitive `createXenolithGraph`, which the adapter exposes alongside the
// directive — the caller owns teardown.
import { createXenolithGraph } from '@xenolithengine/graph-solid'
import { buildMount } from '@xenolithengine/demo/mount'
export async function mount(target: HTMLElement): Promise<() => void> {
const slot = document.createElement('div')
slot.style.cssText = 'position:absolute;inset:0;'
target.appendChild(slot)
const binding = await createXenolithGraph(slot, { resizeToWindow: false })
buildMount(binding.editor)
return () => { binding.destroy(); slot.remove() }
} // The honest minimum: no theme (Xen is the default), one node, framed. The node is DATA (mount.json)
// loaded with editor.loadJSON — the smallest possible xenolith.v1 graph.
import type { XenolithEditor } from '@xenolithengine/graph-editor'
import graph from './mount.json'
export function buildMount(editor: XenolithEditor): void {
editor.loadJSON(graph)
editor.fitView({ padding: 80, maxZoom: 1 })
} // Angular standalone component — mount. The `<xenolith-graph>` component exposes a `(ready)`
// emitter that fires once the editor is mounted; we do the imperative seed work there.
import { Component } from '@angular/core'
import { XenolithGraphComponent } from '@xenolithengine/graph-angular'
import type { XenolithEditor } from '@xenolithengine/graph-editor'
import { buildMount } from '@xenolithengine/demo/mount'
@Component({
selector: 'mount-demo',
standalone: true,
imports: [XenolithGraphComponent],
template: `
<div class="app" style="position:absolute;inset:0;">
<xenolith-graph
class="xeno"
[resizeToWindow]="false"
(ready)="onReady($event)">
</xenolith-graph>
</div>
`,
})
export class MountDemoComponent {
onReady(editor: XenolithEditor): void {
buildMount(editor)
}
} // The honest minimum: no theme (Xen is the default), one node, framed. The node is DATA (mount.json)
// loaded with editor.loadJSON — the smallest possible xenolith.v1 graph.
import type { XenolithEditor } from '@xenolithengine/graph-editor'
import graph from './mount.json'
export function buildMount(editor: XenolithEditor): void {
editor.loadJSON(graph)
editor.fitView({ padding: 80, maxZoom: 1 })
}