y-mxgraph 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,7 @@ Yjs binding for draw.io (mxGraph) documents, enabling real-time collaborative ed
10
10
  - **Real-time collaboration** via y-webrtc, y-websocket, or any Yjs provider
11
11
  - **Undo/Redo support** with Y.UndoManager
12
12
  - **Collaborative cursors** via y-protocols Awareness
13
+ - **iframe Bridge** for isolated draw.io instances synced via postMessage
13
14
  - **Full TypeScript** support
14
15
 
15
16
  ## Installation
@@ -52,6 +53,7 @@ App.main((app) => {
52
53
  - [Getting Started](https://mizuka-wu.github.io/y-mxgraph/en/guide/getting-started)
53
54
  - [API Reference](https://mizuka-wu.github.io/y-mxgraph/en/api/)
54
55
  - [Architecture](https://mizuka-wu.github.io/y-mxgraph/en/guide/architecture)
56
+ - [iframe Bridge](https://mizuka-wu.github.io/y-mxgraph/en/guide/iframe-bridge)
55
57
 
56
58
  ## Development
57
59
 
@@ -76,14 +78,63 @@ pnpm --filter y-mxgraph test
76
78
  # Single-page mode (draw.io loaded directly in the current page)
77
79
  pnpm --filter @y-mxgraph/demo dev
78
80
 
79
- # iframe mode (parent page runs WebRTC Provider, two iframes each run draw.io + y-mxgraph, synced via postMessage)
80
- # Visit http://localhost:5173/iframe-mode.html
81
+ # iframe mode (server page runs WebRTC Provider, iframes each run draw.io + y-mxgraph, synced via postMessage)
82
+ # Visit http://localhost:5173/iframe.html
81
83
 
82
84
  # WebSocket server mode (centralized server with file persistence)
83
85
  pnpm --filter @y-mxgraph/ws-demo server # Start server on port 1234
84
86
  pnpm --filter @y-mxgraph/ws-demo dev # Start client on port 5174
85
87
  ```
86
88
 
89
+ ## iframe Bridge
90
+
91
+ `@y-mxgraph/iframe-bridge` enables collaborative editing in iframe-isolated environments. The **server** (parent page) manages the network connection (y-webrtc, y-websocket, etc.) and syncs Y.Doc + Awareness to one or more **providers** (iframe children) via `postMessage`.
92
+
93
+ ```text
94
+ ┌─────────────────────────────────────────────────────────────┐
95
+ │ Server (parent page) │
96
+ │ ┌──────────┐ ┌───────────┐ ┌──────────────────────────┐ │
97
+ │ │ Y.Doc │ │ Awareness │ │ Provider (y-webrtc, etc) │ │
98
+ │ └────┬─────┘ └─────┬─────┘ └──────────────────────────┘ │
99
+ │ │ │ │
100
+ │ └──────┬───────┘ │
101
+ │ ▼ │
102
+ │ createIframeBridgeServer(doc, awareness) │
103
+ │ │ postMessage │
104
+ └──────────────│──────────────────────────────────────────────┘
105
+
106
+ ┌──────────┴──────────┐
107
+ ▼ ▼
108
+ ┌─────────────┐ ┌─────────────┐
109
+ │ Iframe A │ │ Iframe B │
110
+ │ create... │ │ create... │
111
+ │ Provider() │ │ Provider() │
112
+ │ │ │ │
113
+ │ local Y.Doc │ │ local Y.Doc │
114
+ │ + draw.io │ │ + draw.io │
115
+ └─────────────┘ └─────────────┘
116
+ ```
117
+
118
+ ```ts
119
+ // Server (parent page)
120
+ import { createIframeBridgeServer } from 'y-mxgraph/iframe-bridge/server';
121
+
122
+ const doc = new Y.Doc();
123
+ const provider = new WebrtcProvider(roomName, doc, { signaling });
124
+ const bridge = createIframeBridgeServer(doc, provider.awareness);
125
+ bridge.addIframe(iframeElement, 'child-1');
126
+
127
+ // Provider (iframe child)
128
+ import { createIframeBridgeProvider } from 'y-mxgraph/iframe-bridge/provider';
129
+
130
+ const doc = new Y.Doc();
131
+ const awareness = new Awareness(doc);
132
+ const bridge = createIframeBridgeProvider(doc, awareness);
133
+ // awareness states are automatically synced with the server
134
+ ```
135
+
136
+ See [iframe Bridge documentation](https://mizuka-wu.github.io/y-mxgraph/en/guide/iframe-bridge) for details.
137
+
87
138
  ## Docs
88
139
 
89
140
  ```bash
package/README.zh-CN.md CHANGED
@@ -10,6 +10,7 @@ Yjs 与 draw.io (mxGraph) 文档的双向绑定库,让 draw.io 支持实时多
10
10
  - **实时协作** 支持 y-webrtc、y-websocket 及任意 Yjs Provider
11
11
  - **撤销/重做** 集成 Y.UndoManager
12
12
  - **协同光标** 基于 y-protocols Awareness 渲染远端光标与选区
13
+ - **iframe Bridge** 通过 postMessage 同步隔离的 draw.io 实例
13
14
  - **完整 TypeScript** 类型支持
14
15
 
15
16
  ## 安装
@@ -46,6 +47,56 @@ App.main((app) => {
46
47
  - [快速开始](https://mizuka-wu.github.io/y-mxgraph/guide/getting-started)
47
48
  - [API 参考](https://mizuka-wu.github.io/y-mxgraph/api/)
48
49
  - [实现原理](https://mizuka-wu.github.io/y-mxgraph/guide/architecture)
50
+ - [iframe Bridge](https://mizuka-wu.github.io/y-mxgraph/guide/iframe-bridge)
51
+
52
+ ## iframe Bridge
53
+
54
+ `@y-mxgraph/iframe-bridge` 支持在 iframe 隔离环境中进行协同编辑。**Server**(父页面)管理网络连接(y-webrtc、y-websocket 等),通过 `postMessage` 将 Y.Doc 和 Awareness 同步到一个或多个 **Provider**(iframe 子页面)。
55
+
56
+ ```text
57
+ ┌─────────────────────────────────────────────────────────────┐
58
+ │ Server(父页面) │
59
+ │ ┌──────────┐ ┌───────────┐ ┌──────────────────────────┐ │
60
+ │ │ Y.Doc │ │ Awareness │ │ Provider (y-webrtc 等) │ │
61
+ │ └────┬─────┘ └─────┬─────┘ └──────────────────────────┘ │
62
+ │ │ │ │
63
+ │ └──────┬───────┘ │
64
+ │ ▼ │
65
+ │ createIframeBridgeServer(doc, awareness) │
66
+ │ │ postMessage │
67
+ └──────────────│──────────────────────────────────────────────┘
68
+
69
+ ┌──────────┴──────────┐
70
+ ▼ ▼
71
+ ┌─────────────┐ ┌─────────────┐
72
+ │ Iframe A │ │ Iframe B │
73
+ │ create... │ │ create... │
74
+ │ Provider() │ │ Provider() │
75
+ │ │ │ │
76
+ │ 本地 Y.Doc │ │ 本地 Y.Doc │
77
+ │ + draw.io │ │ + draw.io │
78
+ └─────────────┘ └─────────────┘
79
+ ```
80
+
81
+ ```ts
82
+ // Server(父页面)
83
+ import { createIframeBridgeServer } from '@y-mxgraph/iframe-bridge/server';
84
+
85
+ const doc = new Y.Doc();
86
+ const provider = new WebrtcProvider(roomName, doc, { signaling });
87
+ const bridge = createIframeBridgeServer(doc, provider.awareness);
88
+ bridge.addIframe(iframeElement, 'child-1');
89
+
90
+ // Provider(iframe 子页面)
91
+ import { createIframeBridgeProvider } from '@y-mxgraph/iframe-bridge/provider';
92
+
93
+ const doc = new Y.Doc();
94
+ const awareness = new Awareness(doc);
95
+ const bridge = createIframeBridgeProvider(doc, awareness);
96
+ // awareness 状态自动与 server 同步
97
+ ```
98
+
99
+ 详见 [iframe Bridge 文档](https://mizuka-wu.github.io/y-mxgraph/guide/iframe-bridge)。
49
100
 
50
101
  ## 本地开发
51
102
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/binding/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAiBvD,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,iBAAiB,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAC9B,SAAS,GACT,cAAc,GACd,cAAc,CAAC;AAEnB,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACX,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EACH,OAAO,GACP;QACE,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACN;;OAEG;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACzD;AA0KD;;;;;;;GAOG;AACH,qBAAa,OAAO;IAClB,wBAAwB;IACxB,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACpB,6BAA6B;IAC7B,OAAO,CAAC,YAAY,CAAe;IACnC,sBAAsB;IACtB,OAAO,CAAC,kBAAkB,CAAS;IACnC,4BAA4B;IAC5B,OAAO,CAAC,cAAc,CAAS;IAC/B,2BAA2B;IAC3B,OAAO,CAAC,UAAU,CAAa;IAC/B,oBAAoB;IACpB,OAAO,CAAC,WAAW,CAKT;IACV,gCAAgC;IAChC,OAAO,CAAC,mBAAmB,CAAC,CAAa;IACzC,yBAAyB;IACzB,OAAO,CAAC,kBAAkB,CAAC,CAAa;IACxC,aAAa;IACb,OAAO,CAAC,sBAAsB,CAAyB;IAEvD,+CAA+C;IAC/C,OAAO,KAAK,2BAA2B,GAEtC;gBAEW,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,qBAAqB;IA4I5D;;;OAGG;IACH,OAAO,CAAC,IAAI,UAAQ,GAAG,IAAI;IAS3B;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,oBAAoB,CAAC,SAAS,SAAc,GAAG,MAAM;IAa5D;;;OAGG;IACH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO;CAGzE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/binding/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAiBvD,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,iBAAiB,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAC9B,SAAS,GACT,cAAc,GACd,cAAc,CAAC;AAEnB,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACX,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EACH,OAAO,GACP;QACE,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACN;;OAEG;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACzD;AA0KD;;;;;;;GAOG;AACH,qBAAa,OAAO;IAClB,wBAAwB;IACxB,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACpB,6BAA6B;IAC7B,OAAO,CAAC,YAAY,CAAe;IACnC,sBAAsB;IACtB,OAAO,CAAC,kBAAkB,CAAS;IACnC,4BAA4B;IAC5B,OAAO,CAAC,cAAc,CAAS;IAC/B,2BAA2B;IAC3B,OAAO,CAAC,UAAU,CAAa;IAC/B,oBAAoB;IACpB,OAAO,CAAC,WAAW,CAKT;IACV,gCAAgC;IAChC,OAAO,CAAC,mBAAmB,CAAC,CAAa;IACzC,yBAAyB;IACzB,OAAO,CAAC,kBAAkB,CAAC,CAAa;IACxC,aAAa;IACb,OAAO,CAAC,sBAAsB,CAAyB;IAEvD,+CAA+C;IAC/C,OAAO,KAAK,2BAA2B,GAEtC;gBAEW,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,qBAAqB;IA6I5D;;;OAGG;IACH,OAAO,CAAC,IAAI,UAAQ,GAAG,IAAI;IAS3B;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,oBAAoB,CAAC,SAAS,SAAc,GAAG,MAAM;IAa5D;;;OAGG;IACH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO;CAGzE"}
@@ -0,0 +1,2 @@
1
+ export { createIframeBridgeProvider, type IframeBridgeProvider, } from "@y-mxgraph/iframe-bridge/provider";
2
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/iframe-bridge/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,mCAAmC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createIframeBridgeServer, type IframeBridgeServer, } from "@y-mxgraph/iframe-bridge/server";
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/iframe-bridge/server.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,KAAK,kBAAkB,GACxB,MAAM,iCAAiC,CAAC"}
package/index.d.ts CHANGED
@@ -3,4 +3,6 @@ export type { BindDrawioFileOptions, InitialContentStrategy } from "./binding";
3
3
  export { xml2doc, doc2xml } from "./transformer";
4
4
  export { LOCAL_ORIGIN } from "./helper/origin";
5
5
  export { DEFAULT_USER_NAME_KEY, DEFAULT_USER_COLOR_KEY, } from "./binding/collaborator";
6
+ export { createIframeBridgeProvider, createIframeBridgeServer, } from "@y-mxgraph/iframe-bridge";
7
+ export type { IframeBridgeProvider, IframeBridgeServer, } from "@y-mxgraph/iframe-bridge";
6
8
  //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "y-mxgraph",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Yjs binding for draw.io (mxGraph) documents",
5
5
  "keywords": [
6
6
  "yjs",
package/y-mxgraph.cjs.js CHANGED
@@ -4,6 +4,7 @@ const xmlJs = require("xml-js");
4
4
  const Y = require("yjs");
5
5
  const lodashEs = require("lodash-es");
6
6
  const colord = require("colord");
7
+ const iframeBridge = require("@y-mxgraph/iframe-bridge");
7
8
  function _interopNamespaceDefault(e) {
8
9
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
9
10
  if (e) {
@@ -1623,7 +1624,7 @@ class Binding {
1623
1624
  generatePatch(events);
1624
1625
  return;
1625
1626
  }
1626
- if (this.shouldReplaceWhenDocHasData) {
1627
+ if (this.shouldReplaceWhenDocHasData && !transaction.local) {
1627
1628
  const mxfileMap = doc.getMap(key);
1628
1629
  const diagramMap = mxfileMap.get(key$1);
1629
1630
  if (diagramMap && diagramMap.size > 0) {
@@ -1725,6 +1726,14 @@ class Binding {
1725
1726
  return new Binding(file, options);
1726
1727
  }
1727
1728
  }
1729
+ Object.defineProperty(exports, "createIframeBridgeProvider", {
1730
+ enumerable: true,
1731
+ get: () => iframeBridge.createIframeBridgeProvider
1732
+ });
1733
+ Object.defineProperty(exports, "createIframeBridgeServer", {
1734
+ enumerable: true,
1735
+ get: () => iframeBridge.createIframeBridgeServer
1736
+ });
1728
1737
  exports.Binding = Binding;
1729
1738
  exports.DEFAULT_USER_COLOR_KEY = DEFAULT_USER_COLOR_KEY;
1730
1739
  exports.DEFAULT_USER_NAME_KEY = DEFAULT_USER_NAME_KEY;