@mieweb/ui 0.7.1-dev.0 → 0.7.1-dev.2
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/dist/collabKit-QZL4P5T5.js +48 -0
- package/dist/collabKit-QZL4P5T5.js.map +1 -0
- package/dist/collabKit-UF7E6V3N.cjs +72 -0
- package/dist/collabKit-UF7E6V3N.cjs.map +1 -0
- package/dist/kerebron.cjs +60 -17
- package/dist/kerebron.cjs.map +1 -1
- package/dist/kerebron.d.cts +39 -1
- package/dist/kerebron.d.ts +39 -1
- package/dist/kerebron.js +60 -17
- package/dist/kerebron.js.map +1 -1
- package/package.json +22 -7
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ExtensionYjs } from '@kerebron/extension-yjs';
|
|
2
|
+
import { WebsocketProvider } from '@kerebron/extension-yjs/WebsocketProvider';
|
|
3
|
+
import { MarkYChange } from '@kerebron/extension-yjs/MarkYChange';
|
|
4
|
+
import * as awarenessProtocol from 'y-protocols/awareness';
|
|
5
|
+
import * as Y from 'yjs';
|
|
6
|
+
|
|
7
|
+
// src/components/RichEditor/collabKit.ts
|
|
8
|
+
function defaultWsUrl() {
|
|
9
|
+
const loc = globalThis.location;
|
|
10
|
+
const protocol = loc && loc.protocol === "https:" ? "wss:" : "ws:";
|
|
11
|
+
const host = loc ? loc.host : "localhost";
|
|
12
|
+
return `${protocol}//${host}/yjs`;
|
|
13
|
+
}
|
|
14
|
+
var HuddleYjsKit = class {
|
|
15
|
+
constructor(url, params, WebSocketImpl) {
|
|
16
|
+
this.url = url;
|
|
17
|
+
this.params = params;
|
|
18
|
+
this.WebSocketImpl = WebSocketImpl;
|
|
19
|
+
}
|
|
20
|
+
url;
|
|
21
|
+
params;
|
|
22
|
+
WebSocketImpl;
|
|
23
|
+
name = "yjs-editor";
|
|
24
|
+
getExtensions() {
|
|
25
|
+
const url = this.url;
|
|
26
|
+
const params = this.params;
|
|
27
|
+
const WebSocketImpl = this.WebSocketImpl ?? globalThis.WebSocket;
|
|
28
|
+
const createYjsProvider = (roomId) => {
|
|
29
|
+
const ydoc = new Y.Doc({ gc: false });
|
|
30
|
+
const provider = new WebsocketProvider(url, roomId, ydoc, {
|
|
31
|
+
connect: true,
|
|
32
|
+
awareness: new awarenessProtocol.Awareness(ydoc),
|
|
33
|
+
params,
|
|
34
|
+
protocols: [],
|
|
35
|
+
WebSocketPolyfill: WebSocketImpl,
|
|
36
|
+
resyncInterval: -1,
|
|
37
|
+
maxBackoffTime: 2500,
|
|
38
|
+
disableBc: false
|
|
39
|
+
});
|
|
40
|
+
return [provider, ydoc];
|
|
41
|
+
};
|
|
42
|
+
return [new MarkYChange(), new ExtensionYjs({ createYjsProvider })];
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export { HuddleYjsKit, defaultWsUrl };
|
|
47
|
+
//# sourceMappingURL=collabKit-QZL4P5T5.js.map
|
|
48
|
+
//# sourceMappingURL=collabKit-QZL4P5T5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/RichEditor/collabKit.ts"],"names":[],"mappings":";;;;;;;AAsBO,SAAS,YAAA,GAAuB;AACrC,EAAA,MAAM,MAAM,UAAA,CAAW,QAAA;AACvB,EAAA,MAAM,QAAA,GAAW,GAAA,IAAO,GAAA,CAAI,QAAA,KAAa,WAAW,MAAA,GAAS,KAAA;AAC7D,EAAA,MAAM,IAAA,GAAO,GAAA,GAAM,GAAA,CAAI,IAAA,GAAO,WAAA;AAC9B,EAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,EAAA,EAAK,IAAI,CAAA,IAAA,CAAA;AAC7B;AAGO,IAAM,eAAN,MAAwC;AAAA,EAE7C,WAAA,CACmB,GAAA,EACA,MAAA,EACA,aAAA,EACjB;AAHiB,IAAA,IAAA,CAAA,GAAA,GAAA,GAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,aAAA,GAAA,aAAA;AAAA,EAChB;AAAA,EAHgB,GAAA;AAAA,EACA,MAAA;AAAA,EACA,aAAA;AAAA,EAJnB,IAAA,GAAO,YAAA;AAAA,EAOP,aAAA,GAAgB;AACd,IAAA,MAAM,MAAM,IAAA,CAAK,GAAA;AACjB,IAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,IAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,aAAA,IAAiB,UAAA,CAAW,SAAA;AACvD,IAAA,MAAM,iBAAA,GAAoB,CAAC,MAAA,KAA+C;AACxE,MAAA,MAAM,OAAO,IAAM,CAAA,CAAA,GAAA,CAAI,EAAE,EAAA,EAAI,OAAO,CAAA;AAGpC,MAAA,MAAM,QAAA,GAAW,IAAI,iBAAA,CAAkB,GAAA,EAAK,QAAQ,IAAA,EAAM;AAAA,QACxD,OAAA,EAAS,IAAA;AAAA,QACT,SAAA,EAAW,IAAsB,iBAAA,CAAA,SAAA,CAAU,IAAI,CAAA;AAAA,QAC/C,MAAA;AAAA,QACA,WAAW,EAAC;AAAA,QACZ,iBAAA,EAAmB,aAAA;AAAA,QACnB,cAAA,EAAgB,EAAA;AAAA,QAChB,cAAA,EAAgB,IAAA;AAAA,QAChB,SAAA,EAAW;AAAA,OACZ,CAAA;AACD,MAAA,OAAO,CAAC,UAAU,IAAI,CAAA;AAAA,IACxB,CAAA;AACA,IAAA,OAAO,CAAC,IAAI,WAAA,EAAY,EAAG,IAAI,YAAA,CAAa,EAAE,iBAAA,EAAmB,CAAC,CAAA;AAAA,EACpE;AACF","file":"collabKit-QZL4P5T5.js","sourcesContent":["/**\n * Collaborative (Yjs) editor kit for {@link RichEditor}.\n *\n * Kept in its own module — loaded via dynamic `import()` from `editorKits.ts`\n * only when a `collab` config is passed — so `@kerebron/extension-yjs`, `yjs`\n * and `y-protocols` stay truly optional peers: plain-mode consumers never load\n * them and don't need them installed.\n *\n * We deliberately do not use `@kerebron/editor-kits`' own `YjsEditorKit`: it\n * constructs the `WebsocketProvider` with no query params, leaving no way to\n * authenticate the socket. Here we thread caller-supplied `params` (e.g. an\n * auth token) into the provider so the backend `/yjs` route can authorize the\n * room.\n */\nimport type { EditorKit } from '@kerebron/editor';\nimport { ExtensionYjs } from '@kerebron/extension-yjs';\nimport { WebsocketProvider } from '@kerebron/extension-yjs/WebsocketProvider';\nimport { MarkYChange } from '@kerebron/extension-yjs/MarkYChange';\nimport * as awarenessProtocol from 'y-protocols/awareness';\nimport * as Y from 'yjs';\n\n/** Derive the default `/yjs` websocket URL from the current page origin. */\nexport function defaultWsUrl(): string {\n const loc = globalThis.location;\n const protocol = loc && loc.protocol === 'https:' ? 'wss:' : 'ws:';\n const host = loc ? loc.host : 'localhost';\n return `${protocol}//${host}/yjs`;\n}\n\n/** MarkYChange + ExtensionYjs, with an authenticated websocket provider. */\nexport class HuddleYjsKit implements EditorKit {\n name = 'yjs-editor';\n constructor(\n private readonly url: string,\n private readonly params: Record<string, string>,\n private readonly WebSocketImpl?: typeof globalThis.WebSocket\n ) {}\n\n getExtensions() {\n const url = this.url;\n const params = this.params;\n const WebSocketImpl = this.WebSocketImpl ?? globalThis.WebSocket;\n const createYjsProvider = (roomId: string): [WebsocketProvider, Y.Doc] => {\n const ydoc = new Y.Doc({ gc: false });\n // The provider's opts default is a *default parameter*, not a merge, so we\n // must pass every field when we want to set `params`.\n const provider = new WebsocketProvider(url, roomId, ydoc, {\n connect: true,\n awareness: new awarenessProtocol.Awareness(ydoc),\n params,\n protocols: [],\n WebSocketPolyfill: WebSocketImpl,\n resyncInterval: -1,\n maxBackoffTime: 2500,\n disableBc: false,\n });\n return [provider, ydoc];\n };\n return [new MarkYChange(), new ExtensionYjs({ createYjsProvider })];\n }\n}\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var extensionYjs = require('@kerebron/extension-yjs');
|
|
4
|
+
var WebsocketProvider = require('@kerebron/extension-yjs/WebsocketProvider');
|
|
5
|
+
var MarkYChange = require('@kerebron/extension-yjs/MarkYChange');
|
|
6
|
+
var awarenessProtocol = require('y-protocols/awareness');
|
|
7
|
+
var Y = require('yjs');
|
|
8
|
+
|
|
9
|
+
function _interopNamespace(e) {
|
|
10
|
+
if (e && e.__esModule) return e;
|
|
11
|
+
var n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
Object.keys(e).forEach(function (k) {
|
|
14
|
+
if (k !== 'default') {
|
|
15
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return e[k]; }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var awarenessProtocol__namespace = /*#__PURE__*/_interopNamespace(awarenessProtocol);
|
|
28
|
+
var Y__namespace = /*#__PURE__*/_interopNamespace(Y);
|
|
29
|
+
|
|
30
|
+
// src/components/RichEditor/collabKit.ts
|
|
31
|
+
function defaultWsUrl() {
|
|
32
|
+
const loc = globalThis.location;
|
|
33
|
+
const protocol = loc && loc.protocol === "https:" ? "wss:" : "ws:";
|
|
34
|
+
const host = loc ? loc.host : "localhost";
|
|
35
|
+
return `${protocol}//${host}/yjs`;
|
|
36
|
+
}
|
|
37
|
+
var HuddleYjsKit = class {
|
|
38
|
+
constructor(url, params, WebSocketImpl) {
|
|
39
|
+
this.url = url;
|
|
40
|
+
this.params = params;
|
|
41
|
+
this.WebSocketImpl = WebSocketImpl;
|
|
42
|
+
}
|
|
43
|
+
url;
|
|
44
|
+
params;
|
|
45
|
+
WebSocketImpl;
|
|
46
|
+
name = "yjs-editor";
|
|
47
|
+
getExtensions() {
|
|
48
|
+
const url = this.url;
|
|
49
|
+
const params = this.params;
|
|
50
|
+
const WebSocketImpl = this.WebSocketImpl ?? globalThis.WebSocket;
|
|
51
|
+
const createYjsProvider = (roomId) => {
|
|
52
|
+
const ydoc = new Y__namespace.Doc({ gc: false });
|
|
53
|
+
const provider = new WebsocketProvider.WebsocketProvider(url, roomId, ydoc, {
|
|
54
|
+
connect: true,
|
|
55
|
+
awareness: new awarenessProtocol__namespace.Awareness(ydoc),
|
|
56
|
+
params,
|
|
57
|
+
protocols: [],
|
|
58
|
+
WebSocketPolyfill: WebSocketImpl,
|
|
59
|
+
resyncInterval: -1,
|
|
60
|
+
maxBackoffTime: 2500,
|
|
61
|
+
disableBc: false
|
|
62
|
+
});
|
|
63
|
+
return [provider, ydoc];
|
|
64
|
+
};
|
|
65
|
+
return [new MarkYChange.MarkYChange(), new extensionYjs.ExtensionYjs({ createYjsProvider })];
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
exports.HuddleYjsKit = HuddleYjsKit;
|
|
70
|
+
exports.defaultWsUrl = defaultWsUrl;
|
|
71
|
+
//# sourceMappingURL=collabKit-UF7E6V3N.cjs.map
|
|
72
|
+
//# sourceMappingURL=collabKit-UF7E6V3N.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/RichEditor/collabKit.ts"],"names":["Y","WebsocketProvider","awarenessProtocol","MarkYChange","ExtensionYjs"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBO,SAAS,YAAA,GAAuB;AACrC,EAAA,MAAM,MAAM,UAAA,CAAW,QAAA;AACvB,EAAA,MAAM,QAAA,GAAW,GAAA,IAAO,GAAA,CAAI,QAAA,KAAa,WAAW,MAAA,GAAS,KAAA;AAC7D,EAAA,MAAM,IAAA,GAAO,GAAA,GAAM,GAAA,CAAI,IAAA,GAAO,WAAA;AAC9B,EAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,EAAA,EAAK,IAAI,CAAA,IAAA,CAAA;AAC7B;AAGO,IAAM,eAAN,MAAwC;AAAA,EAE7C,WAAA,CACmB,GAAA,EACA,MAAA,EACA,aAAA,EACjB;AAHiB,IAAA,IAAA,CAAA,GAAA,GAAA,GAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,aAAA,GAAA,aAAA;AAAA,EAChB;AAAA,EAHgB,GAAA;AAAA,EACA,MAAA;AAAA,EACA,aAAA;AAAA,EAJnB,IAAA,GAAO,YAAA;AAAA,EAOP,aAAA,GAAgB;AACd,IAAA,MAAM,MAAM,IAAA,CAAK,GAAA;AACjB,IAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,IAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,aAAA,IAAiB,UAAA,CAAW,SAAA;AACvD,IAAA,MAAM,iBAAA,GAAoB,CAAC,MAAA,KAA+C;AACxE,MAAA,MAAM,OAAO,IAAMA,YAAA,CAAA,GAAA,CAAI,EAAE,EAAA,EAAI,OAAO,CAAA;AAGpC,MAAA,MAAM,QAAA,GAAW,IAAIC,mCAAA,CAAkB,GAAA,EAAK,QAAQ,IAAA,EAAM;AAAA,QACxD,OAAA,EAAS,IAAA;AAAA,QACT,SAAA,EAAW,IAAsBC,4BAAA,CAAA,SAAA,CAAU,IAAI,CAAA;AAAA,QAC/C,MAAA;AAAA,QACA,WAAW,EAAC;AAAA,QACZ,iBAAA,EAAmB,aAAA;AAAA,QACnB,cAAA,EAAgB,EAAA;AAAA,QAChB,cAAA,EAAgB,IAAA;AAAA,QAChB,SAAA,EAAW;AAAA,OACZ,CAAA;AACD,MAAA,OAAO,CAAC,UAAU,IAAI,CAAA;AAAA,IACxB,CAAA;AACA,IAAA,OAAO,CAAC,IAAIC,uBAAA,EAAY,EAAG,IAAIC,yBAAA,CAAa,EAAE,iBAAA,EAAmB,CAAC,CAAA;AAAA,EACpE;AACF","file":"collabKit-UF7E6V3N.cjs","sourcesContent":["/**\n * Collaborative (Yjs) editor kit for {@link RichEditor}.\n *\n * Kept in its own module — loaded via dynamic `import()` from `editorKits.ts`\n * only when a `collab` config is passed — so `@kerebron/extension-yjs`, `yjs`\n * and `y-protocols` stay truly optional peers: plain-mode consumers never load\n * them and don't need them installed.\n *\n * We deliberately do not use `@kerebron/editor-kits`' own `YjsEditorKit`: it\n * constructs the `WebsocketProvider` with no query params, leaving no way to\n * authenticate the socket. Here we thread caller-supplied `params` (e.g. an\n * auth token) into the provider so the backend `/yjs` route can authorize the\n * room.\n */\nimport type { EditorKit } from '@kerebron/editor';\nimport { ExtensionYjs } from '@kerebron/extension-yjs';\nimport { WebsocketProvider } from '@kerebron/extension-yjs/WebsocketProvider';\nimport { MarkYChange } from '@kerebron/extension-yjs/MarkYChange';\nimport * as awarenessProtocol from 'y-protocols/awareness';\nimport * as Y from 'yjs';\n\n/** Derive the default `/yjs` websocket URL from the current page origin. */\nexport function defaultWsUrl(): string {\n const loc = globalThis.location;\n const protocol = loc && loc.protocol === 'https:' ? 'wss:' : 'ws:';\n const host = loc ? loc.host : 'localhost';\n return `${protocol}//${host}/yjs`;\n}\n\n/** MarkYChange + ExtensionYjs, with an authenticated websocket provider. */\nexport class HuddleYjsKit implements EditorKit {\n name = 'yjs-editor';\n constructor(\n private readonly url: string,\n private readonly params: Record<string, string>,\n private readonly WebSocketImpl?: typeof globalThis.WebSocket\n ) {}\n\n getExtensions() {\n const url = this.url;\n const params = this.params;\n const WebSocketImpl = this.WebSocketImpl ?? globalThis.WebSocket;\n const createYjsProvider = (roomId: string): [WebsocketProvider, Y.Doc] => {\n const ydoc = new Y.Doc({ gc: false });\n // The provider's opts default is a *default parameter*, not a merge, so we\n // must pass every field when we want to set `params`.\n const provider = new WebsocketProvider(url, roomId, ydoc, {\n connect: true,\n awareness: new awarenessProtocol.Awareness(ydoc),\n params,\n protocols: [],\n WebSocketPolyfill: WebSocketImpl,\n resyncInterval: -1,\n maxBackoffTime: 2500,\n disableBc: false,\n });\n return [provider, ydoc];\n };\n return [new MarkYChange(), new ExtensionYjs({ createYjsProvider })];\n }\n}\n"]}
|
package/dist/kerebron.cjs
CHANGED
|
@@ -2,16 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
var react = require('react');
|
|
4
4
|
var editor = require('@kerebron/editor');
|
|
5
|
-
var AdvancedEditorKit = require('@kerebron/editor-kits/AdvancedEditorKit');
|
|
6
5
|
var web = require('@kerebron/wasm/web');
|
|
6
|
+
var AdvancedEditorKit = require('@kerebron/editor-kits/AdvancedEditorKit');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
var CodeEditorKit = require('@kerebron/editor-kits/CodeEditorKit');
|
|
9
9
|
|
|
10
10
|
// src/components/RichEditor/RichEditor.tsx
|
|
11
|
+
var unsafeExtensions = ["autocomplete", "hover"];
|
|
12
|
+
var SafeAdvancedEditorKit = class {
|
|
13
|
+
constructor(forCollab) {
|
|
14
|
+
this.forCollab = forCollab;
|
|
15
|
+
}
|
|
16
|
+
forCollab;
|
|
17
|
+
name = "advanced-editor";
|
|
18
|
+
getExtensions() {
|
|
19
|
+
const dropped = [...unsafeExtensions];
|
|
20
|
+
if (this.forCollab) dropped.push("history");
|
|
21
|
+
return new AdvancedEditorKit.AdvancedEditorKit().getExtensions().filter(
|
|
22
|
+
(extension) => !("name" in extension && dropped.includes(extension.name))
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
async function createEditorKits(config) {
|
|
27
|
+
if (!config) return [new SafeAdvancedEditorKit(false)];
|
|
28
|
+
const { HuddleYjsKit, defaultWsUrl } = await import('./collabKit-UF7E6V3N.cjs');
|
|
29
|
+
const url = config.wsUrl ?? defaultWsUrl();
|
|
30
|
+
return [
|
|
31
|
+
new SafeAdvancedEditorKit(true),
|
|
32
|
+
new HuddleYjsKit(url, config.params ?? {}, config.WebSocketPolyfill)
|
|
33
|
+
];
|
|
34
|
+
}
|
|
11
35
|
var RichEditor = ({
|
|
12
36
|
value = "",
|
|
13
37
|
onChange,
|
|
14
|
-
showPreview = false
|
|
38
|
+
showPreview = false,
|
|
39
|
+
collab
|
|
15
40
|
}) => {
|
|
16
41
|
const editorRef = react.useRef(null);
|
|
17
42
|
const editorInstance = react.useRef(null);
|
|
@@ -20,13 +45,9 @@ var RichEditor = ({
|
|
|
20
45
|
const [md, setMd] = react.useState("");
|
|
21
46
|
react.useEffect(() => {
|
|
22
47
|
if (!editorRef.current) return;
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
assetLoad: web.createAssetLoad("/kerebron-wasm"),
|
|
27
|
-
editorKits: [new AdvancedEditorKit.AdvancedEditorKit()]
|
|
28
|
-
});
|
|
29
|
-
editorInstance.current = editor$1;
|
|
48
|
+
const element = editorRef.current;
|
|
49
|
+
let disposed = false;
|
|
50
|
+
let editor$1 = null;
|
|
30
51
|
const onTransaction = async () => {
|
|
31
52
|
if (!editorInstance.current) return;
|
|
32
53
|
try {
|
|
@@ -38,15 +59,37 @@ var RichEditor = ({
|
|
|
38
59
|
console.error("Failed to save markdown:", err);
|
|
39
60
|
}
|
|
40
61
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
62
|
+
const setup = async () => {
|
|
63
|
+
const editorKits = await createEditorKits(collab);
|
|
64
|
+
if (disposed) return;
|
|
65
|
+
editor$1 = editor.CoreEditor.create({
|
|
66
|
+
element,
|
|
67
|
+
uri: "file:///untitled.md",
|
|
68
|
+
assetLoad: web.createAssetLoad("/kerebron-wasm"),
|
|
69
|
+
editorKits
|
|
70
|
+
});
|
|
71
|
+
editorInstance.current = editor$1;
|
|
72
|
+
editor$1.addEventListener("transaction", onTransaction);
|
|
73
|
+
const joinRoom = () => {
|
|
74
|
+
if (collab && editor$1 && !disposed) {
|
|
75
|
+
editor$1.run.changeRoom?.(collab.room);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
if (value) {
|
|
79
|
+
await editor$1.loadDocumentText("text/x-markdown", value);
|
|
80
|
+
await onTransaction();
|
|
81
|
+
joinRoom();
|
|
82
|
+
} else {
|
|
83
|
+
void onTransaction();
|
|
84
|
+
joinRoom();
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
setup().catch((err) => console.error("Failed to set up editor:", err));
|
|
47
88
|
return () => {
|
|
48
|
-
|
|
49
|
-
|
|
89
|
+
disposed = true;
|
|
90
|
+
editorInstance.current = null;
|
|
91
|
+
editor$1?.removeEventListener("transaction", onTransaction);
|
|
92
|
+
editor$1?.destroy();
|
|
50
93
|
};
|
|
51
94
|
}, []);
|
|
52
95
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
package/dist/kerebron.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/RichEditor/RichEditor.tsx","../src/components/RichEditor/CodeEditor.tsx"],"names":["useRef","useState","useEffect","editor","CoreEditor","createAssetLoad","AdvancedEditorKit","jsx","jsxs","CodeEditorKit"],"mappings":"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","file":"kerebron.cjs","sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\n\nimport { CoreEditor } from '@kerebron/editor';\nimport { AdvancedEditorKit } from '@kerebron/editor-kits/AdvancedEditorKit';\nimport { createAssetLoad } from '@kerebron/wasm/web';\n\nexport interface RichEditorProps {\n /** Initial markdown content to load into the editor. */\n value?: string;\n /** Called with the editor's markdown content whenever it changes. */\n onChange?: (value: string) => void;\n /** Whether to render the live markdown output preview. Defaults to `false`. */\n showPreview?: boolean;\n}\n\nconst RichEditor: React.FC<RichEditorProps> = ({\n value = '',\n onChange,\n showPreview = false,\n}) => {\n const editorRef = useRef<HTMLDivElement>(null);\n const editorInstance = useRef<CoreEditor | null>(null);\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const [md, setMd] = useState<string>('');\n\n useEffect(() => {\n if (!editorRef.current) return;\n\n // Initialize the editor\n const editor = CoreEditor.create({\n element: editorRef.current,\n uri: 'file:///untitled.md',\n assetLoad: createAssetLoad('/kerebron-wasm'),\n editorKits: [new AdvancedEditorKit()],\n });\n\n editorInstance.current = editor;\n\n // Listen to transactions and update markdown preview\n const onTransaction = async () => {\n if (!editorInstance.current) return;\n\n try {\n const buffer =\n await editorInstance.current.saveDocument('text/x-markdown');\n const markdown = new globalThis.TextDecoder().decode(buffer);\n setMd(markdown);\n onChangeRef.current?.(markdown);\n } catch (err) {\n console.error('Failed to save markdown:', err);\n }\n };\n\n editor.addEventListener('transaction', onTransaction);\n\n // Seed initial content, then populate the preview once on mount.\n if (value) {\n editor\n .loadDocumentText('text/x-markdown', value)\n .then(() => onTransaction())\n .catch((err) => console.error('Failed to load markdown:', err));\n } else {\n void onTransaction();\n }\n\n // Cleanup on unmount\n return () => {\n editor.removeEventListener('transaction', onTransaction);\n editor.destroy();\n };\n // Initial `value` is intentionally only applied on mount (uncontrolled).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <div>\n <div>\n <div ref={editorRef} className=\"kb-component\" />\n </div>\n\n {showPreview && (\n <div>\n <div>\n <h5>Markdown Output</h5>\n <pre>{md}</pre>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nRichEditor.displayName = 'RichEditor';\n\nexport { RichEditor };\n","import React, { useEffect, useRef } from 'react';\n\nimport { CoreEditor } from '@kerebron/editor';\nimport { CodeEditorKit } from '@kerebron/editor-kits/CodeEditorKit';\nimport { createAssetLoad } from '@kerebron/wasm/web';\n\nexport interface CodeEditorProps {\n /** Initial source code to load into the editor. */\n value?: string;\n /** Called with the editor's contents whenever they change. */\n onChange?: (value: string) => void;\n /** Language/grammar to use for syntax highlighting. Defaults to `typescript`. */\n lang?: string;\n}\n\nconst CodeEditor: React.FC<CodeEditorProps> = ({\n value = '',\n onChange,\n lang = 'typescript',\n}) => {\n const editorRef = useRef<HTMLDivElement>(null);\n const editorInstance = useRef<CoreEditor | null>(null);\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n useEffect(() => {\n const root = editorRef.current;\n if (!root) return;\n\n const applySelectLabel = () => {\n root.querySelectorAll('select.codejar-select').forEach((element) => {\n if (!element.getAttribute('aria-label')) {\n element.setAttribute('aria-label', 'Code editor language');\n }\n });\n };\n\n applySelectLabel();\n const observer = new MutationObserver(() => applySelectLabel());\n observer.observe(root, { childList: true, subtree: true });\n return () => observer.disconnect();\n }, []);\n\n useEffect(() => {\n if (!editorRef.current) return;\n\n // Initialize the editor\n const editor = CoreEditor.create({\n element: editorRef.current,\n uri: 'file:///untitled.ts',\n assetLoad: createAssetLoad('/kerebron-wasm'),\n editorKits: [new CodeEditorKit(lang)],\n });\n\n editorInstance.current = editor;\n\n // Surface edits to callers.\n const onTransaction = async () => {\n if (!editorInstance.current) return;\n\n try {\n const buffer = await editorInstance.current.saveDocument('text/plain');\n onChangeRef.current?.(new globalThis.TextDecoder().decode(buffer));\n } catch (err) {\n console.error('Failed to read code:', err);\n }\n };\n\n editor.addEventListener('transaction', onTransaction);\n\n // Seed initial content on mount.\n if (value) {\n editor\n .loadDocumentText('text/plain', value)\n .catch((err) => console.error('Failed to load code:', err));\n }\n\n // Cleanup on unmount\n return () => {\n editor.removeEventListener('transaction', onTransaction);\n editor.destroy();\n };\n // Initial `value`/`lang` are intentionally only applied on mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <div>\n <div>\n <div ref={editorRef} className=\"kb-component\" />\n </div>\n </div>\n );\n};\n\nCodeEditor.displayName = 'CodeEditor';\n\nexport { CodeEditor };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/RichEditor/editorKits.ts","../src/components/RichEditor/RichEditor.tsx","../src/components/RichEditor/CodeEditor.tsx"],"names":["AdvancedEditorKit","useRef","useState","useEffect","editor","CoreEditor","createAssetLoad","jsx","jsxs","CodeEditorKit"],"mappings":"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","file":"kerebron.cjs","sourcesContent":["/**\n * Editor kit assembly for {@link RichEditor}, for both plain and collaborative\n * (Yjs) mode.\n *\n * Both modes start from {@link AdvancedEditorKit} and drop the extensions that\n * are unsafe for our usage — see {@link unsafeExtensions} — then collaborative\n * mode adds the Yjs pieces on top.\n *\n * The Yjs pieces live in `collabKit.ts` behind a dynamic `import()`, so\n * `@kerebron/extension-yjs`, `yjs` and `y-protocols` remain truly optional\n * peers — plain-mode consumers never load them.\n */\nimport type { EditorKit } from '@kerebron/editor';\nimport { AdvancedEditorKit } from '@kerebron/editor-kits/AdvancedEditorKit';\n\nexport interface CollabConfig {\n /** Room id — one shared document per room (e.g. a post id). */\n room: string;\n /**\n * WebSocket base URL for the Yjs relay. Defaults to\n * `<ws|wss>://<location.host>/yjs`. The room id is appended by the provider.\n */\n wsUrl?: string;\n /** Extra query params for the socket (e.g. `{ token }` for auth). */\n params?: Record<string, string>;\n /**\n * Custom WebSocket implementation handed to the Yjs provider — e.g. a\n * loopback socket for demos/tests, or a polyfill outside the browser.\n * Defaults to `globalThis.WebSocket`.\n */\n WebSocketPolyfill?: typeof globalThis.WebSocket;\n}\n\n/**\n * Extensions dropped from {@link AdvancedEditorKit}, and why.\n *\n * `autocomplete` and `hover` debounce their DOM handlers (200ms) and then call\n * `dispatchMeta`, which reads `this.editor.state` with no guard that the editor\n * is still alive. Any teardown or document swap inside that debounce window\n * lands the deferred call on a dead view and throws\n * `null.matchesNode()` inside ProseMirror's `EditorView.updateStateInner`,\n * leaving the view permanently broken. Two ways to hit it:\n * - remount (e.g. a `key` change) while the pointer is over the editor, which\n * fires the debounced `onMouseLeave` after the view is destroyed;\n * - a Yjs remote update replacing the document tree under a pending callback.\n * The first applies to *every* editor, so both extensions come out in both\n * modes. No functional cost — autocomplete popups and node-hover tooltips are\n * compositor conveniences, not required for editing.\n *\n * `history` is collab-only: ExtensionYjs supplies its own CRDT-aware undo/redo\n * and the editor throws `Extension conflict: yjs vs history` if both are\n * present. Plain mode keeps it, so undo/redo still works there.\n */\nconst unsafeExtensions = ['autocomplete', 'hover'] as const;\n\n/** {@link AdvancedEditorKit} minus {@link unsafeExtensions} (and, for collab\n * mode, minus `history`). */\nclass SafeAdvancedEditorKit implements EditorKit {\n name = 'advanced-editor';\n constructor(private readonly forCollab: boolean) {}\n\n getExtensions() {\n const dropped: string[] = [...unsafeExtensions];\n if (this.forCollab) dropped.push('history');\n\n return new AdvancedEditorKit()\n .getExtensions()\n .filter(\n (extension) =>\n !('name' in extension && dropped.includes(extension.name))\n );\n }\n}\n\n/** MarkYChange + ExtensionYjs live in `collabKit.ts` (lazy-loaded). */\n\n/**\n * Build the editor kits for a session. Pass `config` to join a collaborative\n * room; omit it for a plain local editor.\n *\n * Async because collaborative mode lazy-loads the Yjs kit (and its optional\n * peer deps) on first use; plain mode resolves immediately.\n */\nexport async function createEditorKits(\n config?: CollabConfig\n): Promise<EditorKit[]> {\n if (!config) return [new SafeAdvancedEditorKit(false)];\n\n const { HuddleYjsKit, defaultWsUrl } = await import('./collabKit');\n const url = config.wsUrl ?? defaultWsUrl();\n return [\n new SafeAdvancedEditorKit(true),\n new HuddleYjsKit(url, config.params ?? {}, config.WebSocketPolyfill),\n ];\n}\n","import React, { useEffect, useRef, useState } from 'react';\n\nimport { CoreEditor } from '@kerebron/editor';\nimport { createAssetLoad } from '@kerebron/wasm/web';\n\nimport { createEditorKits, type CollabConfig } from './editorKits';\n\nexport type { CollabConfig } from './editorKits';\n\nexport interface RichEditorProps {\n /** Initial markdown content to load into the editor. */\n value?: string;\n /** Called with the editor's markdown content whenever it changes. */\n onChange?: (value: string) => void;\n /** Whether to render the live markdown output preview. Defaults to `false`. */\n showPreview?: boolean;\n /**\n * Enable live collaborative editing (Yjs) for the given room. When set, the\n * editor connects to the `/yjs` websocket relay and every peer in the same\n * `room` co-edits one shared document. Uncontrolled like `value` — remount via\n * `key` to switch rooms.\n */\n collab?: CollabConfig;\n}\n\nconst RichEditor: React.FC<RichEditorProps> = ({\n value = '',\n onChange,\n showPreview = false,\n collab,\n}) => {\n const editorRef = useRef<HTMLDivElement>(null);\n const editorInstance = useRef<CoreEditor | null>(null);\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const [md, setMd] = useState<string>('');\n\n useEffect(() => {\n if (!editorRef.current) return;\n const element = editorRef.current;\n\n // Set on cleanup so async continuations (kit loading and the\n // `loadDocumentText` chain) don't touch the editor after `destroy()`.\n let disposed = false;\n let editor: CoreEditor | null = null;\n\n // Listen to transactions and update markdown preview\n const onTransaction = async () => {\n if (!editorInstance.current) return;\n\n try {\n const buffer =\n await editorInstance.current.saveDocument('text/x-markdown');\n const markdown = new globalThis.TextDecoder().decode(buffer);\n setMd(markdown);\n onChangeRef.current?.(markdown);\n } catch (err) {\n console.error('Failed to save markdown:', err);\n }\n };\n\n // Initialize the editor. Both modes drop the teardown-unsafe extensions;\n // collaborative mode additionally swaps `history` for the Yjs CRDT sync\n // and lazy-loads the Yjs kit (see `editorKits.ts` for why).\n const setup = async () => {\n const editorKits = await createEditorKits(collab);\n if (disposed) return;\n\n editor = CoreEditor.create({\n element,\n uri: 'file:///untitled.md',\n assetLoad: createAssetLoad('/kerebron-wasm'),\n editorKits,\n });\n\n editorInstance.current = editor;\n editor.addEventListener('transaction', onTransaction);\n\n // Seed initial content, then populate the preview once on mount.\n //\n // In collaborative mode we still load the local markdown first, then join\n // the room: the Yjs binding seeds an *empty* shared document from this\n // content on the first join, and overwrites the editor with the shared\n // content when the room already has edits — so the stored markdown is the\n // starting point without ever double-inserting.\n const joinRoom = () => {\n if (collab && editor && !disposed) {\n (\n editor.run as Record<string, (...args: unknown[]) => boolean>\n ).changeRoom?.(collab.room);\n }\n };\n\n if (value) {\n await editor.loadDocumentText('text/x-markdown', value);\n await onTransaction();\n joinRoom();\n } else {\n void onTransaction();\n joinRoom();\n }\n };\n\n setup().catch((err) => console.error('Failed to set up editor:', err));\n\n // Cleanup on unmount\n return () => {\n disposed = true;\n editorInstance.current = null; // makes onTransaction's guard effective\n editor?.removeEventListener('transaction', onTransaction);\n editor?.destroy();\n };\n // Initial `value`/`collab` are intentionally only applied on mount\n // (uncontrolled). Remount via `key` to switch rooms.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <div>\n <div>\n <div ref={editorRef} className=\"kb-component\" />\n </div>\n\n {showPreview && (\n <div>\n <div>\n <h5>Markdown Output</h5>\n <pre>{md}</pre>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nRichEditor.displayName = 'RichEditor';\n\nexport { RichEditor };\n","import React, { useEffect, useRef } from 'react';\n\nimport { CoreEditor } from '@kerebron/editor';\nimport { CodeEditorKit } from '@kerebron/editor-kits/CodeEditorKit';\nimport { createAssetLoad } from '@kerebron/wasm/web';\n\nexport interface CodeEditorProps {\n /** Initial source code to load into the editor. */\n value?: string;\n /** Called with the editor's contents whenever they change. */\n onChange?: (value: string) => void;\n /** Language/grammar to use for syntax highlighting. Defaults to `typescript`. */\n lang?: string;\n}\n\nconst CodeEditor: React.FC<CodeEditorProps> = ({\n value = '',\n onChange,\n lang = 'typescript',\n}) => {\n const editorRef = useRef<HTMLDivElement>(null);\n const editorInstance = useRef<CoreEditor | null>(null);\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n useEffect(() => {\n const root = editorRef.current;\n if (!root) return;\n\n const applySelectLabel = () => {\n root.querySelectorAll('select.codejar-select').forEach((element) => {\n if (!element.getAttribute('aria-label')) {\n element.setAttribute('aria-label', 'Code editor language');\n }\n });\n };\n\n applySelectLabel();\n const observer = new MutationObserver(() => applySelectLabel());\n observer.observe(root, { childList: true, subtree: true });\n return () => observer.disconnect();\n }, []);\n\n useEffect(() => {\n if (!editorRef.current) return;\n\n // Initialize the editor\n const editor = CoreEditor.create({\n element: editorRef.current,\n uri: 'file:///untitled.ts',\n assetLoad: createAssetLoad('/kerebron-wasm'),\n editorKits: [new CodeEditorKit(lang)],\n });\n\n editorInstance.current = editor;\n\n // Surface edits to callers.\n const onTransaction = async () => {\n if (!editorInstance.current) return;\n\n try {\n const buffer = await editorInstance.current.saveDocument('text/plain');\n onChangeRef.current?.(new globalThis.TextDecoder().decode(buffer));\n } catch (err) {\n console.error('Failed to read code:', err);\n }\n };\n\n editor.addEventListener('transaction', onTransaction);\n\n // Seed initial content on mount.\n if (value) {\n editor\n .loadDocumentText('text/plain', value)\n .catch((err) => console.error('Failed to load code:', err));\n }\n\n // Cleanup on unmount\n return () => {\n editor.removeEventListener('transaction', onTransaction);\n editor.destroy();\n };\n // Initial `value`/`lang` are intentionally only applied on mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <div>\n <div>\n <div ref={editorRef} className=\"kb-component\" />\n </div>\n </div>\n );\n};\n\nCodeEditor.displayName = 'CodeEditor';\n\nexport { CodeEditor };\n"]}
|
package/dist/kerebron.d.cts
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
import React__default from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Editor kit assembly for {@link RichEditor}, for both plain and collaborative
|
|
5
|
+
* (Yjs) mode.
|
|
6
|
+
*
|
|
7
|
+
* Both modes start from {@link AdvancedEditorKit} and drop the extensions that
|
|
8
|
+
* are unsafe for our usage — see {@link unsafeExtensions} — then collaborative
|
|
9
|
+
* mode adds the Yjs pieces on top.
|
|
10
|
+
*
|
|
11
|
+
* The Yjs pieces live in `collabKit.ts` behind a dynamic `import()`, so
|
|
12
|
+
* `@kerebron/extension-yjs`, `yjs` and `y-protocols` remain truly optional
|
|
13
|
+
* peers — plain-mode consumers never load them.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
interface CollabConfig {
|
|
17
|
+
/** Room id — one shared document per room (e.g. a post id). */
|
|
18
|
+
room: string;
|
|
19
|
+
/**
|
|
20
|
+
* WebSocket base URL for the Yjs relay. Defaults to
|
|
21
|
+
* `<ws|wss>://<location.host>/yjs`. The room id is appended by the provider.
|
|
22
|
+
*/
|
|
23
|
+
wsUrl?: string;
|
|
24
|
+
/** Extra query params for the socket (e.g. `{ token }` for auth). */
|
|
25
|
+
params?: Record<string, string>;
|
|
26
|
+
/**
|
|
27
|
+
* Custom WebSocket implementation handed to the Yjs provider — e.g. a
|
|
28
|
+
* loopback socket for demos/tests, or a polyfill outside the browser.
|
|
29
|
+
* Defaults to `globalThis.WebSocket`.
|
|
30
|
+
*/
|
|
31
|
+
WebSocketPolyfill?: typeof globalThis.WebSocket;
|
|
32
|
+
}
|
|
33
|
+
|
|
3
34
|
interface RichEditorProps {
|
|
4
35
|
/** Initial markdown content to load into the editor. */
|
|
5
36
|
value?: string;
|
|
@@ -7,6 +38,13 @@ interface RichEditorProps {
|
|
|
7
38
|
onChange?: (value: string) => void;
|
|
8
39
|
/** Whether to render the live markdown output preview. Defaults to `false`. */
|
|
9
40
|
showPreview?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Enable live collaborative editing (Yjs) for the given room. When set, the
|
|
43
|
+
* editor connects to the `/yjs` websocket relay and every peer in the same
|
|
44
|
+
* `room` co-edits one shared document. Uncontrolled like `value` — remount via
|
|
45
|
+
* `key` to switch rooms.
|
|
46
|
+
*/
|
|
47
|
+
collab?: CollabConfig;
|
|
10
48
|
}
|
|
11
49
|
declare const RichEditor: React__default.FC<RichEditorProps>;
|
|
12
50
|
|
|
@@ -20,4 +58,4 @@ interface CodeEditorProps {
|
|
|
20
58
|
}
|
|
21
59
|
declare const CodeEditor: React__default.FC<CodeEditorProps>;
|
|
22
60
|
|
|
23
|
-
export { CodeEditor, type CodeEditorProps, RichEditor, type RichEditorProps };
|
|
61
|
+
export { CodeEditor, type CodeEditorProps, type CollabConfig, RichEditor, type RichEditorProps };
|
package/dist/kerebron.d.ts
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
import React__default from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Editor kit assembly for {@link RichEditor}, for both plain and collaborative
|
|
5
|
+
* (Yjs) mode.
|
|
6
|
+
*
|
|
7
|
+
* Both modes start from {@link AdvancedEditorKit} and drop the extensions that
|
|
8
|
+
* are unsafe for our usage — see {@link unsafeExtensions} — then collaborative
|
|
9
|
+
* mode adds the Yjs pieces on top.
|
|
10
|
+
*
|
|
11
|
+
* The Yjs pieces live in `collabKit.ts` behind a dynamic `import()`, so
|
|
12
|
+
* `@kerebron/extension-yjs`, `yjs` and `y-protocols` remain truly optional
|
|
13
|
+
* peers — plain-mode consumers never load them.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
interface CollabConfig {
|
|
17
|
+
/** Room id — one shared document per room (e.g. a post id). */
|
|
18
|
+
room: string;
|
|
19
|
+
/**
|
|
20
|
+
* WebSocket base URL for the Yjs relay. Defaults to
|
|
21
|
+
* `<ws|wss>://<location.host>/yjs`. The room id is appended by the provider.
|
|
22
|
+
*/
|
|
23
|
+
wsUrl?: string;
|
|
24
|
+
/** Extra query params for the socket (e.g. `{ token }` for auth). */
|
|
25
|
+
params?: Record<string, string>;
|
|
26
|
+
/**
|
|
27
|
+
* Custom WebSocket implementation handed to the Yjs provider — e.g. a
|
|
28
|
+
* loopback socket for demos/tests, or a polyfill outside the browser.
|
|
29
|
+
* Defaults to `globalThis.WebSocket`.
|
|
30
|
+
*/
|
|
31
|
+
WebSocketPolyfill?: typeof globalThis.WebSocket;
|
|
32
|
+
}
|
|
33
|
+
|
|
3
34
|
interface RichEditorProps {
|
|
4
35
|
/** Initial markdown content to load into the editor. */
|
|
5
36
|
value?: string;
|
|
@@ -7,6 +38,13 @@ interface RichEditorProps {
|
|
|
7
38
|
onChange?: (value: string) => void;
|
|
8
39
|
/** Whether to render the live markdown output preview. Defaults to `false`. */
|
|
9
40
|
showPreview?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Enable live collaborative editing (Yjs) for the given room. When set, the
|
|
43
|
+
* editor connects to the `/yjs` websocket relay and every peer in the same
|
|
44
|
+
* `room` co-edits one shared document. Uncontrolled like `value` — remount via
|
|
45
|
+
* `key` to switch rooms.
|
|
46
|
+
*/
|
|
47
|
+
collab?: CollabConfig;
|
|
10
48
|
}
|
|
11
49
|
declare const RichEditor: React__default.FC<RichEditorProps>;
|
|
12
50
|
|
|
@@ -20,4 +58,4 @@ interface CodeEditorProps {
|
|
|
20
58
|
}
|
|
21
59
|
declare const CodeEditor: React__default.FC<CodeEditorProps>;
|
|
22
60
|
|
|
23
|
-
export { CodeEditor, type CodeEditorProps, RichEditor, type RichEditorProps };
|
|
61
|
+
export { CodeEditor, type CodeEditorProps, type CollabConfig, RichEditor, type RichEditorProps };
|
package/dist/kerebron.js
CHANGED
|
@@ -1,15 +1,40 @@
|
|
|
1
1
|
import { useRef, useState, useEffect } from 'react';
|
|
2
2
|
import { CoreEditor } from '@kerebron/editor';
|
|
3
|
-
import { AdvancedEditorKit } from '@kerebron/editor-kits/AdvancedEditorKit';
|
|
4
3
|
import { createAssetLoad } from '@kerebron/wasm/web';
|
|
4
|
+
import { AdvancedEditorKit } from '@kerebron/editor-kits/AdvancedEditorKit';
|
|
5
5
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
6
|
import { CodeEditorKit } from '@kerebron/editor-kits/CodeEditorKit';
|
|
7
7
|
|
|
8
8
|
// src/components/RichEditor/RichEditor.tsx
|
|
9
|
+
var unsafeExtensions = ["autocomplete", "hover"];
|
|
10
|
+
var SafeAdvancedEditorKit = class {
|
|
11
|
+
constructor(forCollab) {
|
|
12
|
+
this.forCollab = forCollab;
|
|
13
|
+
}
|
|
14
|
+
forCollab;
|
|
15
|
+
name = "advanced-editor";
|
|
16
|
+
getExtensions() {
|
|
17
|
+
const dropped = [...unsafeExtensions];
|
|
18
|
+
if (this.forCollab) dropped.push("history");
|
|
19
|
+
return new AdvancedEditorKit().getExtensions().filter(
|
|
20
|
+
(extension) => !("name" in extension && dropped.includes(extension.name))
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
async function createEditorKits(config) {
|
|
25
|
+
if (!config) return [new SafeAdvancedEditorKit(false)];
|
|
26
|
+
const { HuddleYjsKit, defaultWsUrl } = await import('./collabKit-QZL4P5T5.js');
|
|
27
|
+
const url = config.wsUrl ?? defaultWsUrl();
|
|
28
|
+
return [
|
|
29
|
+
new SafeAdvancedEditorKit(true),
|
|
30
|
+
new HuddleYjsKit(url, config.params ?? {}, config.WebSocketPolyfill)
|
|
31
|
+
];
|
|
32
|
+
}
|
|
9
33
|
var RichEditor = ({
|
|
10
34
|
value = "",
|
|
11
35
|
onChange,
|
|
12
|
-
showPreview = false
|
|
36
|
+
showPreview = false,
|
|
37
|
+
collab
|
|
13
38
|
}) => {
|
|
14
39
|
const editorRef = useRef(null);
|
|
15
40
|
const editorInstance = useRef(null);
|
|
@@ -18,13 +43,9 @@ var RichEditor = ({
|
|
|
18
43
|
const [md, setMd] = useState("");
|
|
19
44
|
useEffect(() => {
|
|
20
45
|
if (!editorRef.current) return;
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
assetLoad: createAssetLoad("/kerebron-wasm"),
|
|
25
|
-
editorKits: [new AdvancedEditorKit()]
|
|
26
|
-
});
|
|
27
|
-
editorInstance.current = editor;
|
|
46
|
+
const element = editorRef.current;
|
|
47
|
+
let disposed = false;
|
|
48
|
+
let editor = null;
|
|
28
49
|
const onTransaction = async () => {
|
|
29
50
|
if (!editorInstance.current) return;
|
|
30
51
|
try {
|
|
@@ -36,15 +57,37 @@ var RichEditor = ({
|
|
|
36
57
|
console.error("Failed to save markdown:", err);
|
|
37
58
|
}
|
|
38
59
|
};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
60
|
+
const setup = async () => {
|
|
61
|
+
const editorKits = await createEditorKits(collab);
|
|
62
|
+
if (disposed) return;
|
|
63
|
+
editor = CoreEditor.create({
|
|
64
|
+
element,
|
|
65
|
+
uri: "file:///untitled.md",
|
|
66
|
+
assetLoad: createAssetLoad("/kerebron-wasm"),
|
|
67
|
+
editorKits
|
|
68
|
+
});
|
|
69
|
+
editorInstance.current = editor;
|
|
70
|
+
editor.addEventListener("transaction", onTransaction);
|
|
71
|
+
const joinRoom = () => {
|
|
72
|
+
if (collab && editor && !disposed) {
|
|
73
|
+
editor.run.changeRoom?.(collab.room);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
if (value) {
|
|
77
|
+
await editor.loadDocumentText("text/x-markdown", value);
|
|
78
|
+
await onTransaction();
|
|
79
|
+
joinRoom();
|
|
80
|
+
} else {
|
|
81
|
+
void onTransaction();
|
|
82
|
+
joinRoom();
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
setup().catch((err) => console.error("Failed to set up editor:", err));
|
|
45
86
|
return () => {
|
|
46
|
-
|
|
47
|
-
|
|
87
|
+
disposed = true;
|
|
88
|
+
editorInstance.current = null;
|
|
89
|
+
editor?.removeEventListener("transaction", onTransaction);
|
|
90
|
+
editor?.destroy();
|
|
48
91
|
};
|
|
49
92
|
}, []);
|
|
50
93
|
return /* @__PURE__ */ jsxs("div", { children: [
|
package/dist/kerebron.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/RichEditor/RichEditor.tsx","../src/components/RichEditor/CodeEditor.tsx"],"names":["useRef","useEffect","CoreEditor","createAssetLoad","jsx"],"mappings":"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","file":"kerebron.js","sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\n\nimport { CoreEditor } from '@kerebron/editor';\nimport { AdvancedEditorKit } from '@kerebron/editor-kits/AdvancedEditorKit';\nimport { createAssetLoad } from '@kerebron/wasm/web';\n\nexport interface RichEditorProps {\n /** Initial markdown content to load into the editor. */\n value?: string;\n /** Called with the editor's markdown content whenever it changes. */\n onChange?: (value: string) => void;\n /** Whether to render the live markdown output preview. Defaults to `false`. */\n showPreview?: boolean;\n}\n\nconst RichEditor: React.FC<RichEditorProps> = ({\n value = '',\n onChange,\n showPreview = false,\n}) => {\n const editorRef = useRef<HTMLDivElement>(null);\n const editorInstance = useRef<CoreEditor | null>(null);\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const [md, setMd] = useState<string>('');\n\n useEffect(() => {\n if (!editorRef.current) return;\n\n // Initialize the editor\n const editor = CoreEditor.create({\n element: editorRef.current,\n uri: 'file:///untitled.md',\n assetLoad: createAssetLoad('/kerebron-wasm'),\n editorKits: [new AdvancedEditorKit()],\n });\n\n editorInstance.current = editor;\n\n // Listen to transactions and update markdown preview\n const onTransaction = async () => {\n if (!editorInstance.current) return;\n\n try {\n const buffer =\n await editorInstance.current.saveDocument('text/x-markdown');\n const markdown = new globalThis.TextDecoder().decode(buffer);\n setMd(markdown);\n onChangeRef.current?.(markdown);\n } catch (err) {\n console.error('Failed to save markdown:', err);\n }\n };\n\n editor.addEventListener('transaction', onTransaction);\n\n // Seed initial content, then populate the preview once on mount.\n if (value) {\n editor\n .loadDocumentText('text/x-markdown', value)\n .then(() => onTransaction())\n .catch((err) => console.error('Failed to load markdown:', err));\n } else {\n void onTransaction();\n }\n\n // Cleanup on unmount\n return () => {\n editor.removeEventListener('transaction', onTransaction);\n editor.destroy();\n };\n // Initial `value` is intentionally only applied on mount (uncontrolled).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <div>\n <div>\n <div ref={editorRef} className=\"kb-component\" />\n </div>\n\n {showPreview && (\n <div>\n <div>\n <h5>Markdown Output</h5>\n <pre>{md}</pre>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nRichEditor.displayName = 'RichEditor';\n\nexport { RichEditor };\n","import React, { useEffect, useRef } from 'react';\n\nimport { CoreEditor } from '@kerebron/editor';\nimport { CodeEditorKit } from '@kerebron/editor-kits/CodeEditorKit';\nimport { createAssetLoad } from '@kerebron/wasm/web';\n\nexport interface CodeEditorProps {\n /** Initial source code to load into the editor. */\n value?: string;\n /** Called with the editor's contents whenever they change. */\n onChange?: (value: string) => void;\n /** Language/grammar to use for syntax highlighting. Defaults to `typescript`. */\n lang?: string;\n}\n\nconst CodeEditor: React.FC<CodeEditorProps> = ({\n value = '',\n onChange,\n lang = 'typescript',\n}) => {\n const editorRef = useRef<HTMLDivElement>(null);\n const editorInstance = useRef<CoreEditor | null>(null);\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n useEffect(() => {\n const root = editorRef.current;\n if (!root) return;\n\n const applySelectLabel = () => {\n root.querySelectorAll('select.codejar-select').forEach((element) => {\n if (!element.getAttribute('aria-label')) {\n element.setAttribute('aria-label', 'Code editor language');\n }\n });\n };\n\n applySelectLabel();\n const observer = new MutationObserver(() => applySelectLabel());\n observer.observe(root, { childList: true, subtree: true });\n return () => observer.disconnect();\n }, []);\n\n useEffect(() => {\n if (!editorRef.current) return;\n\n // Initialize the editor\n const editor = CoreEditor.create({\n element: editorRef.current,\n uri: 'file:///untitled.ts',\n assetLoad: createAssetLoad('/kerebron-wasm'),\n editorKits: [new CodeEditorKit(lang)],\n });\n\n editorInstance.current = editor;\n\n // Surface edits to callers.\n const onTransaction = async () => {\n if (!editorInstance.current) return;\n\n try {\n const buffer = await editorInstance.current.saveDocument('text/plain');\n onChangeRef.current?.(new globalThis.TextDecoder().decode(buffer));\n } catch (err) {\n console.error('Failed to read code:', err);\n }\n };\n\n editor.addEventListener('transaction', onTransaction);\n\n // Seed initial content on mount.\n if (value) {\n editor\n .loadDocumentText('text/plain', value)\n .catch((err) => console.error('Failed to load code:', err));\n }\n\n // Cleanup on unmount\n return () => {\n editor.removeEventListener('transaction', onTransaction);\n editor.destroy();\n };\n // Initial `value`/`lang` are intentionally only applied on mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <div>\n <div>\n <div ref={editorRef} className=\"kb-component\" />\n </div>\n </div>\n );\n};\n\nCodeEditor.displayName = 'CodeEditor';\n\nexport { CodeEditor };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/RichEditor/editorKits.ts","../src/components/RichEditor/RichEditor.tsx","../src/components/RichEditor/CodeEditor.tsx"],"names":["useRef","useEffect","CoreEditor","createAssetLoad","jsx"],"mappings":"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","file":"kerebron.js","sourcesContent":["/**\n * Editor kit assembly for {@link RichEditor}, for both plain and collaborative\n * (Yjs) mode.\n *\n * Both modes start from {@link AdvancedEditorKit} and drop the extensions that\n * are unsafe for our usage — see {@link unsafeExtensions} — then collaborative\n * mode adds the Yjs pieces on top.\n *\n * The Yjs pieces live in `collabKit.ts` behind a dynamic `import()`, so\n * `@kerebron/extension-yjs`, `yjs` and `y-protocols` remain truly optional\n * peers — plain-mode consumers never load them.\n */\nimport type { EditorKit } from '@kerebron/editor';\nimport { AdvancedEditorKit } from '@kerebron/editor-kits/AdvancedEditorKit';\n\nexport interface CollabConfig {\n /** Room id — one shared document per room (e.g. a post id). */\n room: string;\n /**\n * WebSocket base URL for the Yjs relay. Defaults to\n * `<ws|wss>://<location.host>/yjs`. The room id is appended by the provider.\n */\n wsUrl?: string;\n /** Extra query params for the socket (e.g. `{ token }` for auth). */\n params?: Record<string, string>;\n /**\n * Custom WebSocket implementation handed to the Yjs provider — e.g. a\n * loopback socket for demos/tests, or a polyfill outside the browser.\n * Defaults to `globalThis.WebSocket`.\n */\n WebSocketPolyfill?: typeof globalThis.WebSocket;\n}\n\n/**\n * Extensions dropped from {@link AdvancedEditorKit}, and why.\n *\n * `autocomplete` and `hover` debounce their DOM handlers (200ms) and then call\n * `dispatchMeta`, which reads `this.editor.state` with no guard that the editor\n * is still alive. Any teardown or document swap inside that debounce window\n * lands the deferred call on a dead view and throws\n * `null.matchesNode()` inside ProseMirror's `EditorView.updateStateInner`,\n * leaving the view permanently broken. Two ways to hit it:\n * - remount (e.g. a `key` change) while the pointer is over the editor, which\n * fires the debounced `onMouseLeave` after the view is destroyed;\n * - a Yjs remote update replacing the document tree under a pending callback.\n * The first applies to *every* editor, so both extensions come out in both\n * modes. No functional cost — autocomplete popups and node-hover tooltips are\n * compositor conveniences, not required for editing.\n *\n * `history` is collab-only: ExtensionYjs supplies its own CRDT-aware undo/redo\n * and the editor throws `Extension conflict: yjs vs history` if both are\n * present. Plain mode keeps it, so undo/redo still works there.\n */\nconst unsafeExtensions = ['autocomplete', 'hover'] as const;\n\n/** {@link AdvancedEditorKit} minus {@link unsafeExtensions} (and, for collab\n * mode, minus `history`). */\nclass SafeAdvancedEditorKit implements EditorKit {\n name = 'advanced-editor';\n constructor(private readonly forCollab: boolean) {}\n\n getExtensions() {\n const dropped: string[] = [...unsafeExtensions];\n if (this.forCollab) dropped.push('history');\n\n return new AdvancedEditorKit()\n .getExtensions()\n .filter(\n (extension) =>\n !('name' in extension && dropped.includes(extension.name))\n );\n }\n}\n\n/** MarkYChange + ExtensionYjs live in `collabKit.ts` (lazy-loaded). */\n\n/**\n * Build the editor kits for a session. Pass `config` to join a collaborative\n * room; omit it for a plain local editor.\n *\n * Async because collaborative mode lazy-loads the Yjs kit (and its optional\n * peer deps) on first use; plain mode resolves immediately.\n */\nexport async function createEditorKits(\n config?: CollabConfig\n): Promise<EditorKit[]> {\n if (!config) return [new SafeAdvancedEditorKit(false)];\n\n const { HuddleYjsKit, defaultWsUrl } = await import('./collabKit');\n const url = config.wsUrl ?? defaultWsUrl();\n return [\n new SafeAdvancedEditorKit(true),\n new HuddleYjsKit(url, config.params ?? {}, config.WebSocketPolyfill),\n ];\n}\n","import React, { useEffect, useRef, useState } from 'react';\n\nimport { CoreEditor } from '@kerebron/editor';\nimport { createAssetLoad } from '@kerebron/wasm/web';\n\nimport { createEditorKits, type CollabConfig } from './editorKits';\n\nexport type { CollabConfig } from './editorKits';\n\nexport interface RichEditorProps {\n /** Initial markdown content to load into the editor. */\n value?: string;\n /** Called with the editor's markdown content whenever it changes. */\n onChange?: (value: string) => void;\n /** Whether to render the live markdown output preview. Defaults to `false`. */\n showPreview?: boolean;\n /**\n * Enable live collaborative editing (Yjs) for the given room. When set, the\n * editor connects to the `/yjs` websocket relay and every peer in the same\n * `room` co-edits one shared document. Uncontrolled like `value` — remount via\n * `key` to switch rooms.\n */\n collab?: CollabConfig;\n}\n\nconst RichEditor: React.FC<RichEditorProps> = ({\n value = '',\n onChange,\n showPreview = false,\n collab,\n}) => {\n const editorRef = useRef<HTMLDivElement>(null);\n const editorInstance = useRef<CoreEditor | null>(null);\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const [md, setMd] = useState<string>('');\n\n useEffect(() => {\n if (!editorRef.current) return;\n const element = editorRef.current;\n\n // Set on cleanup so async continuations (kit loading and the\n // `loadDocumentText` chain) don't touch the editor after `destroy()`.\n let disposed = false;\n let editor: CoreEditor | null = null;\n\n // Listen to transactions and update markdown preview\n const onTransaction = async () => {\n if (!editorInstance.current) return;\n\n try {\n const buffer =\n await editorInstance.current.saveDocument('text/x-markdown');\n const markdown = new globalThis.TextDecoder().decode(buffer);\n setMd(markdown);\n onChangeRef.current?.(markdown);\n } catch (err) {\n console.error('Failed to save markdown:', err);\n }\n };\n\n // Initialize the editor. Both modes drop the teardown-unsafe extensions;\n // collaborative mode additionally swaps `history` for the Yjs CRDT sync\n // and lazy-loads the Yjs kit (see `editorKits.ts` for why).\n const setup = async () => {\n const editorKits = await createEditorKits(collab);\n if (disposed) return;\n\n editor = CoreEditor.create({\n element,\n uri: 'file:///untitled.md',\n assetLoad: createAssetLoad('/kerebron-wasm'),\n editorKits,\n });\n\n editorInstance.current = editor;\n editor.addEventListener('transaction', onTransaction);\n\n // Seed initial content, then populate the preview once on mount.\n //\n // In collaborative mode we still load the local markdown first, then join\n // the room: the Yjs binding seeds an *empty* shared document from this\n // content on the first join, and overwrites the editor with the shared\n // content when the room already has edits — so the stored markdown is the\n // starting point without ever double-inserting.\n const joinRoom = () => {\n if (collab && editor && !disposed) {\n (\n editor.run as Record<string, (...args: unknown[]) => boolean>\n ).changeRoom?.(collab.room);\n }\n };\n\n if (value) {\n await editor.loadDocumentText('text/x-markdown', value);\n await onTransaction();\n joinRoom();\n } else {\n void onTransaction();\n joinRoom();\n }\n };\n\n setup().catch((err) => console.error('Failed to set up editor:', err));\n\n // Cleanup on unmount\n return () => {\n disposed = true;\n editorInstance.current = null; // makes onTransaction's guard effective\n editor?.removeEventListener('transaction', onTransaction);\n editor?.destroy();\n };\n // Initial `value`/`collab` are intentionally only applied on mount\n // (uncontrolled). Remount via `key` to switch rooms.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <div>\n <div>\n <div ref={editorRef} className=\"kb-component\" />\n </div>\n\n {showPreview && (\n <div>\n <div>\n <h5>Markdown Output</h5>\n <pre>{md}</pre>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nRichEditor.displayName = 'RichEditor';\n\nexport { RichEditor };\n","import React, { useEffect, useRef } from 'react';\n\nimport { CoreEditor } from '@kerebron/editor';\nimport { CodeEditorKit } from '@kerebron/editor-kits/CodeEditorKit';\nimport { createAssetLoad } from '@kerebron/wasm/web';\n\nexport interface CodeEditorProps {\n /** Initial source code to load into the editor. */\n value?: string;\n /** Called with the editor's contents whenever they change. */\n onChange?: (value: string) => void;\n /** Language/grammar to use for syntax highlighting. Defaults to `typescript`. */\n lang?: string;\n}\n\nconst CodeEditor: React.FC<CodeEditorProps> = ({\n value = '',\n onChange,\n lang = 'typescript',\n}) => {\n const editorRef = useRef<HTMLDivElement>(null);\n const editorInstance = useRef<CoreEditor | null>(null);\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n useEffect(() => {\n const root = editorRef.current;\n if (!root) return;\n\n const applySelectLabel = () => {\n root.querySelectorAll('select.codejar-select').forEach((element) => {\n if (!element.getAttribute('aria-label')) {\n element.setAttribute('aria-label', 'Code editor language');\n }\n });\n };\n\n applySelectLabel();\n const observer = new MutationObserver(() => applySelectLabel());\n observer.observe(root, { childList: true, subtree: true });\n return () => observer.disconnect();\n }, []);\n\n useEffect(() => {\n if (!editorRef.current) return;\n\n // Initialize the editor\n const editor = CoreEditor.create({\n element: editorRef.current,\n uri: 'file:///untitled.ts',\n assetLoad: createAssetLoad('/kerebron-wasm'),\n editorKits: [new CodeEditorKit(lang)],\n });\n\n editorInstance.current = editor;\n\n // Surface edits to callers.\n const onTransaction = async () => {\n if (!editorInstance.current) return;\n\n try {\n const buffer = await editorInstance.current.saveDocument('text/plain');\n onChangeRef.current?.(new globalThis.TextDecoder().decode(buffer));\n } catch (err) {\n console.error('Failed to read code:', err);\n }\n };\n\n editor.addEventListener('transaction', onTransaction);\n\n // Seed initial content on mount.\n if (value) {\n editor\n .loadDocumentText('text/plain', value)\n .catch((err) => console.error('Failed to load code:', err));\n }\n\n // Cleanup on unmount\n return () => {\n editor.removeEventListener('transaction', onTransaction);\n editor.destroy();\n };\n // Initial `value`/`lang` are intentionally only applied on mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n <div>\n <div>\n <div ref={editorRef} className=\"kb-component\" />\n </div>\n </div>\n );\n};\n\nCodeEditor.displayName = 'CodeEditor';\n\nexport { CodeEditor };\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mieweb/ui",
|
|
3
|
-
"version": "0.7.1-dev.
|
|
3
|
+
"version": "0.7.1-dev.2",
|
|
4
4
|
"description": "A themeable, accessible React component library built with Tailwind CSS",
|
|
5
5
|
"author": "Medical Informatics Engineering, Inc.",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -232,10 +232,13 @@
|
|
|
232
232
|
"prepublishOnly": "npm run build"
|
|
233
233
|
},
|
|
234
234
|
"peerDependencies": {
|
|
235
|
-
"@kerebron/editor": ">=0.
|
|
236
|
-
"@kerebron/editor-kits": ">=0.
|
|
237
|
-
"@kerebron/
|
|
235
|
+
"@kerebron/editor": ">=0.8.6",
|
|
236
|
+
"@kerebron/editor-kits": ">=0.8.6",
|
|
237
|
+
"@kerebron/extension-yjs": ">=0.8.6",
|
|
238
|
+
"@kerebron/wasm": ">=0.8.6",
|
|
238
239
|
"@mieweb/datavis": "=1.6.0",
|
|
240
|
+
"y-protocols": ">=1.0.6",
|
|
241
|
+
"yjs": ">=13.6.0",
|
|
239
242
|
"ag-grid-community": ">=32.0.0",
|
|
240
243
|
"ag-grid-react": ">=32.0.0",
|
|
241
244
|
"datavis-ace": "=4.1.0",
|
|
@@ -260,9 +263,18 @@
|
|
|
260
263
|
"@kerebron/editor-kits": {
|
|
261
264
|
"optional": true
|
|
262
265
|
},
|
|
266
|
+
"@kerebron/extension-yjs": {
|
|
267
|
+
"optional": true
|
|
268
|
+
},
|
|
263
269
|
"@kerebron/wasm": {
|
|
264
270
|
"optional": true
|
|
265
271
|
},
|
|
272
|
+
"y-protocols": {
|
|
273
|
+
"optional": true
|
|
274
|
+
},
|
|
275
|
+
"yjs": {
|
|
276
|
+
"optional": true
|
|
277
|
+
},
|
|
266
278
|
"@mieweb/datavis": {
|
|
267
279
|
"optional": true
|
|
268
280
|
},
|
|
@@ -341,9 +353,10 @@
|
|
|
341
353
|
"@esheet/fields": "0.0.3",
|
|
342
354
|
"@esheet/renderer": "0.0.3",
|
|
343
355
|
"@eslint/js": "^9.39.3",
|
|
344
|
-
"@kerebron/editor": "0.
|
|
345
|
-
"@kerebron/editor-kits": "0.
|
|
346
|
-
"@kerebron/
|
|
356
|
+
"@kerebron/editor": "^0.8.6",
|
|
357
|
+
"@kerebron/editor-kits": "^0.8.6",
|
|
358
|
+
"@kerebron/extension-yjs": "^0.8.6",
|
|
359
|
+
"@kerebron/wasm": "^0.8.6",
|
|
347
360
|
"@mieweb/datavis": "=1.6.0",
|
|
348
361
|
"@monaco-editor/react": "^4.7.0",
|
|
349
362
|
"@playwright/test": "^1.58.2",
|
|
@@ -414,7 +427,9 @@
|
|
|
414
427
|
"vite": "^7.3.2",
|
|
415
428
|
"vitest": "^3.2.6",
|
|
416
429
|
"wavesurfer.js": "^7.12.1",
|
|
430
|
+
"y-protocols": "^1.0.6",
|
|
417
431
|
"ychart": "file:./packages/ychart",
|
|
432
|
+
"yjs": "^13.6.30",
|
|
418
433
|
"zod": "^4.4.3",
|
|
419
434
|
"zustand": "^5.0.14"
|
|
420
435
|
},
|