SDK Editor

@nuforge/editor adalah SDK tingkat tinggi untuk membangun page builder visual Anda sendiri di atas runtime. Setiap operasi dapat di-undo — di balik layar tiap metode membungkus nu.change, sehingga menyatu rapi dengan history runtime. Catatan: situs nuforge tidak menyediakan editor bawaan. SDK ini adalah perangkat yang Anda gunakan untuk membangunnya sendiri.

Memulai

Buat sebuah editor dengan membungkus instance runtime Nu:

import { createEditor, defineBlock, el, text } from '@nuforge/editor';

const editor = createEditor(nu);

Mutasi

Setiap mutasi di bawah ini dapat di-undo. Masing-masing adalah pembungkus tipis dan eksplisit di atas nu.change:

insertNode(parent, child, index?)
moveNode(dragged, target, position) // position is 'before' | 'after' | 'inside'
removeNode(node)
setExpression(node, key, source)
setText(node, value)
setTag(node, tag)
setProp(node, key, expr)
removeProp(node, key)
updateProps(node, map)
addClass(node, name)
removeClass(node, name)
setClassCondition(node, name, source)
setCondition(node, source) // sets @if
clearCondition(node)
setEach(node, listSource, itemName, indexName?) // sets @each
clearEach(node)

Komponen & state

Kelola komponen dan state reaktifnya. Mengganti nama komponen juga menulis ulang setiap referensi <Name/> yang menunjuk ke komponen itu:

addComponent(name)
renameComponent(component, name) // also updates <Name/> references
removeComponent(component)
duplicateComponent(component)
addState(component, name, initSource)
setStateInit(...)
removeState(...)
addComponentProp(component, name, initSource)
setComponentPropInit(...)
removeComponentProp(...)

Kueri

Baca tree saat ini tanpa mengubahnya. Ini berguna untuk merender panel, breadcrumb, dan target drag:

getComponents()
getComponent(name)
getRootTemplate(component)
getChildren(node)
getSiblings(node)
getNodeIndex(node)
getNodePath(node)

Block

Editor menyimpan registry block bangunan yang dapat disisipkan. Daftarkan sebuah block dengan defineBlock, lalu sisipkan ke node induk mana pun:

editor.blocks.register(
  defineBlock({
    id: 'button',
    label: 'Button',
    create: () => el('button', {}, [text('Click me')]),
  }),
);

editor.insertBlock('button', parentNode);

Di dalam create sebuah block, Anda membangun node template dengan helper builder: el(tag, props?, children?) membuat node elemen, text(value) membuat node teks, dan lit(value) membuat sebuah nilai literal.

Command & subscription

Daftarkan command bernama dan berlangganan perubahan agar UI Anda tetap sinkron:

editor.commands.register({ id, label, run });
editor.commands.run(id);

editor.onChange((entries) => {});
editor.onStructureChange(() => {});

Gunakan editor.onChange untuk pembaruan berbutir halus dan editor.onStructureChange ketika bentuk tree berubah (node disisipkan, dipindah, atau dihapus).

Canvas React

Subpath @nuforge/editor/react menyediakan canvas iframe yang dapat dipilih dan terisolasi gaya:

import { IframeCanvas, templateIdFromElement, useStructureRevision } from '@nuforge/editor/react';

<IframeCanvas frame={frame} selectedId={selectedId} onSelect={setSelectedId} />

IframeCanvas merender frame di dalam iframe yang terisolasi gaya, sehingga CSS aplikasi host tidak pernah bocor ke canvas (dan sebaliknya). Ketika pengguna mengklik sebuah elemen, ia memetakan elemen DOM yang diklik kembali ke template id-nya dengan templateIdFromElement dan melaporkannya melalui onSelect. Gunakan useStructureRevision untuk membaca ulang canvas ketika struktur tree berubah.

Ini primitif yang fleksibel, bukan UI tetap:

  • renderBox — bangun overlay sendiri dari rect selected / hovered / drop dan selectedLabel (tag elemen terpilih). Gambar border, badge tag, atau toolbar aksi (set pointerEvents: 'auto' pada bagian interaktif). Kosongkan untuk tanpa overlay.
  • srcDoc — sediakan dokumen awal iframe, sehingga <head>-nya bisa memuat web font, stylesheet CDN, tag <script>, dll. Frame di-portal ke <body>.
  • onDropOnNode(targetId, position, event) — aktifkan drop-ke-canvas; padukan dengan editor.insertBlockAt(blockId, target, position) untuk menjatuhkan block palette (rect drop menggerakkan indikator live).

Lihat panduan builder bertahap untuk kode lengkapnya.

Clipboard

Copy / cut / paste / duplicate tingkat-node — semuanya undoable:

editor.copyNode(node); // atau editor.cutNode(node) untuk copy + hapus
editor.canPaste(); // true

// tempel salinan baru (id baru) sebelum / sesudah / di dalam target
const pasted = editor.pasteNode(target, 'after');

// duplikasi node tepat setelah dirinya
const copy = editor.duplicateNode(node);

pasteNode dan duplicateNode mengembalikan node yang disisipkan (dengan id baru), jadi Anda bisa langsung menyeleksinya.

Drag-and-drop di canvas

dropPositionFromPointer mengubah posisi pointer menjadi posisi drop before / after / inside terhadap rect elemen — inti reusable dari DnD canvas. Pakai untuk menggerakkan indikator drop dan mutasi akhirnya:

import { dropPositionFromPointer } from '@nuforge/editor';

function onDragOver(e: React.DragEvent, targetEl: HTMLElement) {
  const rect = targetEl.getBoundingClientRect();
  const position = dropPositionFromPointer(e.clientY, rect, { allowInside: true });
  // → sorot indikator drop untuk `position`
}

function onDrop(draggedNode, targetNode, position) {
  editor.moveNode(draggedNode, targetNode, position); // atau editor.insertBlock(id, targetNode)
}

Inspector berbasis schema

Sebuah block mendeklarasikan prop yang dapat disunting sebagai schema (props: PropSchemaField[]). <PropFields> me-render satu kontrol per field (text / number / checkbox / select / expression), jadi Anda tidak perlu menulis form manual per block:

import { PropFields } from '@nuforge/editor/react';

<PropFields
  fields={block.props ?? []}
  values={{ label: 'Click me', disabled: false }}
  onChange={(name, value) => editor.setProp(node, name, t.literal({ value }))}
/>;

PropFields bersifat headless — beri gaya lewat className dan CSS Anda sendiri, lalu sambungkan onChange ke editor.setProp / setExpression.

Langkah berikutnya

  • Runtime — inti reaktif yang dimutasi oleh editor.
  • Codegen — ubah AST yang telah disunting menjadi kode siap kirim.