From c8b169da8cb7eae0957e0ab5e7370b071093a224 Mon Sep 17 00:00:00 2001
From: soryu <soryu@soryu.co>
Date: Tue, 28 Apr 2026 00:18:40 +0100
Subject: feat: Document UI for directive orchestration with Lexical editor
 (#93)

* WIP: heartbeat checkpoint

* feat: soryu-co/soryu - makima: Save previous goal on update and include history in re-planning prompt

* feat: soryu-co/soryu - makima: Install Lexical and create base document editor component

* feat: soryu-co/soryu - makima: Create directive file system sidebar and document layout

* feat: soryu-co/soryu - makima: Create custom Lexical step diagram block

* feat: soryu-co/soryu - makima: Add context menu and goal auto-update integration

* WIP: heartbeat checkpoint
---
 .../components/document/nodes/StepsDiagramNode.tsx | 91 ++++++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 frontend/src/components/document/nodes/StepsDiagramNode.tsx

(limited to 'frontend/src/components/document/nodes/StepsDiagramNode.tsx')

diff --git a/frontend/src/components/document/nodes/StepsDiagramNode.tsx b/frontend/src/components/document/nodes/StepsDiagramNode.tsx
new file mode 100644
index 0000000..8b37f52
--- /dev/null
+++ b/frontend/src/components/document/nodes/StepsDiagramNode.tsx
@@ -0,0 +1,91 @@
+import {
+  DecoratorNode,
+  DOMExportOutput,
+  LexicalNode,
+  NodeKey,
+  SerializedLexicalNode,
+  Spread,
+} from 'lexical';
+import React from 'react';
+import { StepsDiagramComponent } from './StepsDiagramComponent';
+
+export type SerializedStepsDiagramNode = Spread<
+  {
+    directiveId: string;
+  },
+  SerializedLexicalNode
+>;
+
+export class StepsDiagramNode extends DecoratorNode<JSX.Element> {
+  __directiveId: string;
+
+  static getType(): string {
+    return 'steps-diagram';
+  }
+
+  static clone(node: StepsDiagramNode): StepsDiagramNode {
+    return new StepsDiagramNode(node.__directiveId, node.__key);
+  }
+
+  constructor(directiveId: string, key?: NodeKey) {
+    super(key);
+    this.__directiveId = directiveId;
+  }
+
+  createDOM(): HTMLElement {
+    const div = document.createElement('div');
+    div.className = 'steps-diagram-block';
+    return div;
+  }
+
+  updateDOM(): boolean {
+    return false;
+  }
+
+  decorate(): JSX.Element {
+    return <StepsDiagramComponent directiveId={this.__directiveId} />;
+  }
+
+  exportJSON(): SerializedStepsDiagramNode {
+    return {
+      ...super.exportJSON(),
+      type: 'steps-diagram',
+      directiveId: this.__directiveId,
+      version: 1,
+    };
+  }
+
+  static importJSON(serializedNode: SerializedStepsDiagramNode): StepsDiagramNode {
+    return $createStepsDiagramNode(serializedNode.directiveId);
+  }
+
+  isInline(): boolean {
+    return false;
+  }
+
+  canInsertTextBefore(): boolean {
+    return false;
+  }
+
+  canInsertTextAfter(): boolean {
+    return false;
+  }
+
+  exportDOM(): DOMExportOutput {
+    const element = document.createElement('div');
+    element.className = 'steps-diagram-block';
+    element.setAttribute('data-directive-id', this.__directiveId);
+    element.textContent = '[Steps Diagram]';
+    return { element };
+  }
+}
+
+export function $createStepsDiagramNode(directiveId: string): StepsDiagramNode {
+  return new StepsDiagramNode(directiveId);
+}
+
+export function $isStepsDiagramNode(
+  node: LexicalNode | null | undefined,
+): node is StepsDiagramNode {
+  return node instanceof StepsDiagramNode;
+}
-- 
cgit v1.2.3

