@octane-xplat/tiptap 0.9.0 → 0.10.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 +56 -3
- package/dist/macos/browser.d.ts +1 -0
- package/dist/macos/browser.js +2 -0
- package/dist/native/index3.js +14 -10
- package/dist/native/octane-client-build.json +1 -1
- package/dist/web/index2.js +31 -30
- package/dist/web/octane-client-build.json +1 -1
- package/package.json +6 -5
- package/src/Editor.macos.tsx +9 -0
- package/src/TiptapEditor.tsrx +7 -5
- package/src/TiptapEditor.web.tsrx +19 -23
- package/src/browser-entry.web.tsx +5 -0
- package/src/index.macos.ts +7 -13
- package/src/types.ts +7 -1
- package/types/index.macos.d.ts +7 -0
- package/types/types.d.ts +6 -1
package/dist/native/index3.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { ensureJSONBridge, htmlToJSON, jsonBridgeReady, jsonToHTML } from "./index2.js";
|
|
2
|
-
import { defineUniversalComponent, hookSlots, universalComponent, universalPlan, universalProps, universalValue, useCallback, useEffect, useRef } from "@nativescript-community/octane";
|
|
2
|
+
import { defineUniversalComponent, hookSlots, universalComponent, universalPlan, universalProps, universalValue, useCallback, useEffect, useImperativeHandle, useRef, useState } from "@nativescript-community/octane";
|
|
3
3
|
import { RichTextEditor, supported } from "@octane-xplat/richtext";
|
|
4
4
|
//#region src/TiptapEditor.tsrx
|
|
5
|
-
var _hs$ = /* @__PURE__ */ hookSlots(
|
|
5
|
+
var _hs$ = /* @__PURE__ */ hookSlots(8);
|
|
6
6
|
var _h$0 = /* @__PURE__ */ Symbol(_hs$);
|
|
7
7
|
var _h$1 = /* @__PURE__ */ Symbol(_hs$ + 1);
|
|
8
8
|
var _h$2 = /* @__PURE__ */ Symbol(_hs$ + 2);
|
|
9
9
|
var _h$3 = /* @__PURE__ */ Symbol(_hs$ + 3);
|
|
10
10
|
var _h$4 = /* @__PURE__ */ Symbol(_hs$ + 4);
|
|
11
11
|
var _h$5 = /* @__PURE__ */ Symbol(_hs$ + 5);
|
|
12
|
+
var _h$6 = /* @__PURE__ */ Symbol(_hs$ + 6);
|
|
13
|
+
var _h$7 = /* @__PURE__ */ Symbol(_hs$ + 7);
|
|
12
14
|
var __octaneUniversalPlan0 = universalPlan("nativescript", {
|
|
13
15
|
"kind": "slot",
|
|
14
16
|
"slot": 0
|
|
@@ -16,11 +18,13 @@ var __octaneUniversalPlan0 = universalPlan("nativescript", {
|
|
|
16
18
|
var supported$1 = supported;
|
|
17
19
|
var TiptapEditor = defineUniversalComponent("nativescript", function TiptapEditor(props) {
|
|
18
20
|
const inner = useRef(null, _h$0);
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
+
const [exposedHandle, setHandle] = useState(null, _h$1);
|
|
22
|
+
useImperativeHandle(props.ref, () => exposedHandle, [exposedHandle], _h$2);
|
|
23
|
+
const jsonReady = useRef(false, _h$3);
|
|
24
|
+
const lastJSON = useRef(void 0, _h$4);
|
|
21
25
|
const bindHost = useCallback((h) => {
|
|
22
26
|
inner.current = h;
|
|
23
|
-
|
|
27
|
+
setHandle((previous) => previous?.native === h?.native ? previous : h ? {
|
|
24
28
|
getHTML: () => h.getHTML(),
|
|
25
29
|
setHTML: (html) => h.setHTML(html),
|
|
26
30
|
getJSON: () => jsonBridgeReady() ? htmlToJSON(h.getHTML()) : null,
|
|
@@ -41,14 +45,14 @@ var TiptapEditor = defineUniversalComponent("nativescript", function TiptapEdito
|
|
|
41
45
|
blur: () => h.blur(),
|
|
42
46
|
isFocused: () => h.isFocused(),
|
|
43
47
|
native: h.native
|
|
44
|
-
});
|
|
45
|
-
}, [], _h$
|
|
48
|
+
} : null);
|
|
49
|
+
}, [], _h$5);
|
|
46
50
|
useEffect(() => {
|
|
47
51
|
ensureJSONBridge().then((ok) => {
|
|
48
52
|
jsonReady.current = ok;
|
|
49
53
|
props.onJSONReady?.(ok);
|
|
50
54
|
});
|
|
51
|
-
}, [], _h$
|
|
55
|
+
}, [], _h$6);
|
|
52
56
|
useEffect(() => {
|
|
53
57
|
if (!props.json || !jsonBridgeReady() || !inner.current) return;
|
|
54
58
|
const stamp = JSON.stringify(props.json);
|
|
@@ -58,7 +62,7 @@ var TiptapEditor = defineUniversalComponent("nativescript", function TiptapEdito
|
|
|
58
62
|
lastJSON.current = stamp;
|
|
59
63
|
inner.current.setHTML(html);
|
|
60
64
|
}
|
|
61
|
-
}, [props.json], _h$
|
|
65
|
+
}, [props.json], _h$7);
|
|
62
66
|
const emitJSON = () => {
|
|
63
67
|
if (!inner.current || !jsonBridgeReady()) return;
|
|
64
68
|
const doc = htmlToJSON(inner.current.getHTML());
|
|
@@ -133,7 +137,7 @@ var TiptapEditor = defineUniversalComponent("nativescript", function TiptapEdito
|
|
|
133
137
|
],
|
|
134
138
|
[
|
|
135
139
|
"set",
|
|
136
|
-
"
|
|
140
|
+
"ref",
|
|
137
141
|
bindHost
|
|
138
142
|
],
|
|
139
143
|
[
|
package/dist/web/index2.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { __s, bag3, clone, componentSlot, hookSlots, setStyle, template, useEffect, useRef, withSlot } from "octane";
|
|
1
|
+
import { __s, bag3, clone, componentSlot, hookSlots, setStyle, template, useEffect, useImperativeHandle, useRef, withSlot } from "octane";
|
|
2
2
|
import { updateFreshClassName } from "octane/internal/client";
|
|
3
3
|
import { EditorContent, useEditor } from "@octanejs/tiptap";
|
|
4
4
|
import StarterKit from "@tiptap/starter-kit";
|
|
5
5
|
//#region src/TiptapEditor.web.tsrx
|
|
6
6
|
var _t$0 = /* @__PURE__ */ template("<div></div>");
|
|
7
|
-
var _hs$ = /* @__PURE__ */ hookSlots(
|
|
8
|
-
var _h$
|
|
7
|
+
var _hs$ = /* @__PURE__ */ hookSlots(10);
|
|
8
|
+
var _h$5 = /* @__PURE__ */ Symbol(_hs$ + 5);
|
|
9
9
|
var supported = true;
|
|
10
10
|
var COMMAND = {
|
|
11
11
|
bold: (c) => c.toggleBold(),
|
|
@@ -26,18 +26,6 @@ var COMMAND = {
|
|
|
26
26
|
heading5: (c) => c.toggleHeading({ level: 5 }),
|
|
27
27
|
heading6: (c) => c.toggleHeading({ level: 6 })
|
|
28
28
|
};
|
|
29
|
-
var IS_ACTIVE = {
|
|
30
|
-
bold: (e) => e.isActive("bold"),
|
|
31
|
-
italic: (e) => e.isActive("italic"),
|
|
32
|
-
underline: (e) => e.isActive("underline"),
|
|
33
|
-
strikethrough: (e) => e.isActive("strike"),
|
|
34
|
-
code: (e) => e.isActive("code"),
|
|
35
|
-
blockquote: (e) => e.isActive("blockquote"),
|
|
36
|
-
bulletList: (e) => e.isActive("bulletList"),
|
|
37
|
-
orderedList: (e) => e.isActive("orderedList"),
|
|
38
|
-
codeBlock: (e) => e.isActive("codeBlock"),
|
|
39
|
-
link: (e) => e.isActive("link")
|
|
40
|
-
};
|
|
41
29
|
var ACTIVE_OF = [
|
|
42
30
|
["bold", "bold"],
|
|
43
31
|
["italic", "italic"],
|
|
@@ -89,10 +77,12 @@ function activeFormats(editor) {
|
|
|
89
77
|
var TiptapEditor = /* @__PURE__ */ __s(function TiptapEditor(props, __s, __extra) {
|
|
90
78
|
const lastEmitted = useRef(void 0, _hs$ + 0);
|
|
91
79
|
const lastJSON = useRef(void 0, _hs$ + 1);
|
|
92
|
-
const
|
|
93
|
-
const
|
|
80
|
+
const lastHTMLInput = useRef(JSON.stringify([props.json !== void 0, props.value]), _hs$ + 2);
|
|
81
|
+
const lastJSONInput = useRef(JSON.stringify(props.json), _hs$ + 3);
|
|
82
|
+
const bound = useRef(void 0, _hs$ + 4);
|
|
83
|
+
const editor = withSlot(_h$5, useEditor, {
|
|
94
84
|
extensions: [StarterKit],
|
|
95
|
-
content: props.
|
|
85
|
+
content: props.json ?? props.value ?? "",
|
|
96
86
|
editable: props.editable !== false,
|
|
97
87
|
autofocus: props.autofocus ?? false,
|
|
98
88
|
onCreate: () => props.onReady?.(),
|
|
@@ -113,21 +103,32 @@ var TiptapEditor = /* @__PURE__ */ __s(function TiptapEditor(props, __s, __extra
|
|
|
113
103
|
})
|
|
114
104
|
});
|
|
115
105
|
useEffect(() => {
|
|
116
|
-
if (!editor
|
|
106
|
+
if (!editor) return;
|
|
107
|
+
const stamp = JSON.stringify([props.json !== void 0, props.value]);
|
|
108
|
+
if (stamp === lastHTMLInput.current) return;
|
|
109
|
+
lastHTMLInput.current = stamp;
|
|
110
|
+
if (props.value === void 0 || props.json !== void 0) return;
|
|
117
111
|
if (props.value === lastEmitted.current) return;
|
|
118
112
|
editor.commands.setContent(props.value);
|
|
119
|
-
}, [
|
|
113
|
+
}, [
|
|
114
|
+
editor,
|
|
115
|
+
props.value,
|
|
116
|
+
props.json
|
|
117
|
+
], _hs$ + 6);
|
|
120
118
|
useEffect(() => {
|
|
121
|
-
if (!editor
|
|
122
|
-
|
|
119
|
+
if (!editor) return;
|
|
120
|
+
const stamp = JSON.stringify(props.json);
|
|
121
|
+
if (stamp === lastJSONInput.current) return;
|
|
122
|
+
lastJSONInput.current = stamp;
|
|
123
|
+
if (props.json === void 0 || stamp === lastJSON.current) return;
|
|
123
124
|
editor.commands.setContent(props.json);
|
|
124
|
-
}, [editor, props.json], _hs$ +
|
|
125
|
+
}, [editor, props.json], _hs$ + 7);
|
|
125
126
|
useEffect(() => {
|
|
126
127
|
if (!editor) return;
|
|
127
128
|
editor.setEditable(props.editable !== false);
|
|
128
|
-
}, [editor, props.editable], _hs$ +
|
|
129
|
-
|
|
130
|
-
if (!editor
|
|
129
|
+
}, [editor, props.editable], _hs$ + 8);
|
|
130
|
+
useImperativeHandle(props.ref, () => {
|
|
131
|
+
if (!editor) return null;
|
|
131
132
|
const e = editor;
|
|
132
133
|
bound.current = {
|
|
133
134
|
getHTML: () => e.getHTML(),
|
|
@@ -150,7 +151,7 @@ var TiptapEditor = /* @__PURE__ */ __s(function TiptapEditor(props, __s, __extra
|
|
|
150
151
|
else e.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
|
|
151
152
|
},
|
|
152
153
|
removeLink: () => e.chain().focus().unsetLink().run(),
|
|
153
|
-
isActive: (format) =>
|
|
154
|
+
isActive: (format) => activeFormats(e).includes(format),
|
|
154
155
|
undo: () => e.commands.undo(),
|
|
155
156
|
redo: () => e.commands.redo(),
|
|
156
157
|
focus: () => e.commands.focus(),
|
|
@@ -158,8 +159,8 @@ var TiptapEditor = /* @__PURE__ */ __s(function TiptapEditor(props, __s, __extra
|
|
|
158
159
|
isFocused: () => e.isFocused,
|
|
159
160
|
native: e
|
|
160
161
|
};
|
|
161
|
-
|
|
162
|
-
}, [editor], _hs$ +
|
|
162
|
+
return bound.current;
|
|
163
|
+
}, [editor], _hs$ + 9);
|
|
163
164
|
if (__s.block.pending && !__s.block.crossRenderUpdate) return;
|
|
164
165
|
let _b = __s.slots[0];
|
|
165
166
|
if (_b === void 0) {
|
|
@@ -176,7 +177,7 @@ var TiptapEditor = /* @__PURE__ */ __s(function TiptapEditor(props, __s, __extra
|
|
|
176
177
|
_b.c = _v;
|
|
177
178
|
}
|
|
178
179
|
}
|
|
179
|
-
componentSlot(__s, 1, _b.b, EditorContent, { "editor": editor }, void 0, void 0, 2, void 0, void 0, "c:
|
|
180
|
+
componentSlot(__s, 1, _b.b, EditorContent, { "editor": editor }, void 0, void 0, 2, void 0, void 0, "c:e9be3bbb");
|
|
180
181
|
});
|
|
181
182
|
//#endregion
|
|
182
183
|
export { TiptapEditor, supported };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octane-xplat/tiptap",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Unified rich-text editor facade for Octane xplat —
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "Unified rich-text editor facade for Octane xplat — live tiptap on web/AppKit, Aztec + tiptap document model on Android",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cross-platform",
|
|
7
7
|
"editor",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
|
31
31
|
"macos": {
|
|
32
|
-
"types": "./types/index.d.ts",
|
|
32
|
+
"types": "./types/index.macos.d.ts",
|
|
33
33
|
"default": "./src/index.macos.ts"
|
|
34
34
|
},
|
|
35
35
|
"web": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@octane-xplat/richtext": "0.
|
|
51
|
+
"@octane-xplat/richtext": "0.10.0",
|
|
52
52
|
"@octanejs/tiptap": "0.0.51",
|
|
53
53
|
"@tiptap/core": "3.28.0",
|
|
54
54
|
"@tiptap/pm": "3.28.0",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@nativescript-community/octane": "0.2.4",
|
|
61
61
|
"@nativescript/core": "9.1.2",
|
|
62
|
+
"@octane-xplat/macos-renderer": "0.10.0",
|
|
62
63
|
"@octanejs/vite-plugin": "0.1.61",
|
|
63
64
|
"octane": "0.6.3",
|
|
64
65
|
"typescript": "5.9.3",
|
|
@@ -87,6 +88,6 @@
|
|
|
87
88
|
}
|
|
88
89
|
},
|
|
89
90
|
"scripts": {
|
|
90
|
-
"build": "vite build && vite build --mode native && tsc -p tsconfig.types.json && node ../../scripts/check-native-dist.mjs"
|
|
91
|
+
"build": "vite build && vite build --mode native && tsc -p tsconfig.types.json && node ../../scripts/check-native-dist.mjs && node ../richtext/build-browser.mjs"
|
|
91
92
|
}
|
|
92
93
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** @jsxImportSource @octane-xplat/macos-renderer */
|
|
2
|
+
import type { TiptapEditorProps } from './types'
|
|
3
|
+
import browser from '../dist/macos/browser.js'
|
|
4
|
+
import { NativeEditor } from '@octane-xplat/richtext/macos-host'
|
|
5
|
+
|
|
6
|
+
/** AppKit mounts the local editor engine in WKWebView. */
|
|
7
|
+
export function TiptapEditor(props: TiptapEditorProps) {
|
|
8
|
+
return <NativeEditor {...props} browser={browser} />
|
|
9
|
+
}
|
package/src/TiptapEditor.tsrx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @jsxImportSource @nativescript-community/octane */
|
|
2
|
-
import { useCallback, useEffect, useRef } from 'octane'
|
|
2
|
+
import { useState, useImperativeHandle, useCallback, useEffect, useRef } from 'octane'
|
|
3
3
|
import { RichTextEditor, supported as leafSupported } from '@octane-xplat/richtext'
|
|
4
4
|
import type { RichTextEditorHandle } from '@octane-xplat/richtext'
|
|
5
5
|
import type { TiptapEditorHandle, TiptapEditorProps } from './types'
|
|
@@ -12,13 +12,15 @@ export const supported = leafSupported
|
|
|
12
12
|
* renderToHTMLString) handles JSON interchange on top of it. */
|
|
13
13
|
export function TiptapEditor(props: TiptapEditorProps) @{
|
|
14
14
|
const inner = useRef<RichTextEditorHandle | null>(null)
|
|
15
|
+
const [exposedHandle, setHandle] = useState<TiptapEditorHandle | null>(null)
|
|
16
|
+
useImperativeHandle<TiptapEditorHandle | null>(props.ref, () => exposedHandle, [exposedHandle])
|
|
15
17
|
const jsonReady = useRef(false)
|
|
16
18
|
const lastJSON = useRef<string | undefined>(undefined)
|
|
17
19
|
|
|
18
|
-
const bindHost = useCallback((h: RichTextEditorHandle) => {
|
|
20
|
+
const bindHost = useCallback((h: RichTextEditorHandle | null) => {
|
|
19
21
|
inner.current = h
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
setHandle((previous) => previous?.native === h?.native ? previous : h ? ({
|
|
22
24
|
getHTML: () => h.getHTML(),
|
|
23
25
|
setHTML: (html: string) => h.setHTML(html),
|
|
24
26
|
getJSON: () => (jsonBridgeReady() ? htmlToJSON(h.getHTML()) : null),
|
|
@@ -39,7 +41,7 @@ export function TiptapEditor(props: TiptapEditorProps) @{
|
|
|
39
41
|
blur: () => h.blur(),
|
|
40
42
|
isFocused: () => h.isFocused(),
|
|
41
43
|
native: h.native,
|
|
42
|
-
} satisfies TiptapEditorHandle)
|
|
44
|
+
} satisfies TiptapEditorHandle) : null)
|
|
43
45
|
}, [])
|
|
44
46
|
|
|
45
47
|
// The bridge loads once per process — dynamic imports of the DOM-free
|
|
@@ -89,7 +91,7 @@ export function TiptapEditor(props: TiptapEditorProps) @{
|
|
|
89
91
|
onSelectionChange={props.onSelectionChange}
|
|
90
92
|
onFocus={props.onFocus}
|
|
91
93
|
onBlur={props.onBlur}
|
|
92
|
-
|
|
94
|
+
ref={bindHost}
|
|
93
95
|
android={props.android}
|
|
94
96
|
ios={props.ios}
|
|
95
97
|
row={props.row}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useRef } from 'octane'
|
|
1
|
+
import { useImperativeHandle, useEffect, useRef } from 'octane'
|
|
2
2
|
import { EditorContent, useEditor } from '@octanejs/tiptap'
|
|
3
3
|
import StarterKit from '@tiptap/starter-kit'
|
|
4
4
|
import type { TiptapEditorHandle, TiptapEditorProps, TiptapFormat } from './types'
|
|
@@ -27,19 +27,6 @@ const COMMAND: Record<WebFormat, (chain: any) => any> = {
|
|
|
27
27
|
heading6: (c) => c.toggleHeading({ level: 6 }),
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
const IS_ACTIVE: Partial<Record<TiptapFormat, (editor: any) => boolean>> = {
|
|
31
|
-
bold: (e) => e.isActive('bold'),
|
|
32
|
-
italic: (e) => e.isActive('italic'),
|
|
33
|
-
underline: (e) => e.isActive('underline'),
|
|
34
|
-
strikethrough: (e) => e.isActive('strike'),
|
|
35
|
-
code: (e) => e.isActive('code'),
|
|
36
|
-
blockquote: (e) => e.isActive('blockquote'),
|
|
37
|
-
bulletList: (e) => e.isActive('bulletList'),
|
|
38
|
-
orderedList: (e) => e.isActive('orderedList'),
|
|
39
|
-
codeBlock: (e) => e.isActive('codeBlock'),
|
|
40
|
-
link: (e) => e.isActive('link'),
|
|
41
|
-
}
|
|
42
|
-
|
|
43
30
|
const ACTIVE_OF: [TiptapFormat, string, any?][] = [
|
|
44
31
|
['bold', 'bold'],
|
|
45
32
|
['italic', 'italic'],
|
|
@@ -74,11 +61,13 @@ function activeFormats(editor: any): TiptapFormat[] {
|
|
|
74
61
|
export function TiptapEditor(props: TiptapEditorProps) @{
|
|
75
62
|
const lastEmitted = useRef<string | undefined>(undefined)
|
|
76
63
|
const lastJSON = useRef<string | undefined>(undefined)
|
|
64
|
+
const lastHTMLInput = useRef(JSON.stringify([props.json !== undefined, props.value]))
|
|
65
|
+
const lastJSONInput = useRef(JSON.stringify(props.json))
|
|
77
66
|
const bound = useRef<TiptapEditorHandle | undefined>(undefined)
|
|
78
67
|
|
|
79
68
|
const editor = useEditor({
|
|
80
69
|
extensions: [StarterKit],
|
|
81
|
-
content: (props.
|
|
70
|
+
content: (props.json ?? props.value ?? '') as any,
|
|
82
71
|
editable: props.editable !== false,
|
|
83
72
|
autofocus: props.autofocus ?? false,
|
|
84
73
|
onCreate: () => props.onReady?.(),
|
|
@@ -103,14 +92,21 @@ export function TiptapEditor(props: TiptapEditorProps) @{
|
|
|
103
92
|
// External `value` changes push setContent; editor-emitted HTML is skipped
|
|
104
93
|
// (the transaction already owns the doc).
|
|
105
94
|
useEffect(() => {
|
|
106
|
-
if (!editor
|
|
95
|
+
if (!editor) return
|
|
96
|
+
const stamp = JSON.stringify([props.json !== undefined, props.value])
|
|
97
|
+
if (stamp === lastHTMLInput.current) return
|
|
98
|
+
lastHTMLInput.current = stamp
|
|
99
|
+
if (props.value === undefined || props.json !== undefined) return
|
|
107
100
|
if (props.value === lastEmitted.current) return
|
|
108
101
|
editor.commands.setContent(props.value)
|
|
109
|
-
}, [editor, props.value])
|
|
102
|
+
}, [editor, props.value, props.json])
|
|
110
103
|
|
|
111
104
|
useEffect(() => {
|
|
112
|
-
if (!editor
|
|
113
|
-
|
|
105
|
+
if (!editor) return
|
|
106
|
+
const stamp = JSON.stringify(props.json)
|
|
107
|
+
if (stamp === lastJSONInput.current) return
|
|
108
|
+
lastJSONInput.current = stamp
|
|
109
|
+
if (props.json === undefined || stamp === lastJSON.current) return
|
|
114
110
|
editor.commands.setContent(props.json as any)
|
|
115
111
|
}, [editor, props.json])
|
|
116
112
|
|
|
@@ -121,8 +117,8 @@ export function TiptapEditor(props: TiptapEditorProps) @{
|
|
|
121
117
|
|
|
122
118
|
// The handle rebinds whenever the editor instance appears — stable
|
|
123
119
|
// afterward (useEditor keeps the instance identity).
|
|
124
|
-
|
|
125
|
-
if (!editor
|
|
120
|
+
useImperativeHandle<TiptapEditorHandle | null>(props.ref, () => {
|
|
121
|
+
if (!editor) return null
|
|
126
122
|
const e: any = editor
|
|
127
123
|
bound.current = {
|
|
128
124
|
getHTML: () => e.getHTML(),
|
|
@@ -141,7 +137,7 @@ export function TiptapEditor(props: TiptapEditorProps) @{
|
|
|
141
137
|
}
|
|
142
138
|
},
|
|
143
139
|
removeLink: () => e.chain().focus().unsetLink().run(),
|
|
144
|
-
isActive: (format) =>
|
|
140
|
+
isActive: (format) => activeFormats(e).includes(format),
|
|
145
141
|
undo: () => e.commands.undo(),
|
|
146
142
|
redo: () => e.commands.redo(),
|
|
147
143
|
focus: () => e.commands.focus(),
|
|
@@ -150,7 +146,7 @@ export function TiptapEditor(props: TiptapEditorProps) @{
|
|
|
150
146
|
native: e,
|
|
151
147
|
}
|
|
152
148
|
|
|
153
|
-
|
|
149
|
+
return bound.current
|
|
154
150
|
}, [editor])
|
|
155
151
|
|
|
156
152
|
<div className={['vx-richtext', props.className]} style={props.style}>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createRoot } from 'octane'
|
|
2
|
+
import { TiptapEditor } from './TiptapEditor.web.tsrx'
|
|
3
|
+
import { installEditorDocument } from '@octane-xplat/richtext/browser-transport'
|
|
4
|
+
const root = createRoot(document.getElementById('root')!)
|
|
5
|
+
installEditorDocument((props) => root.render(<TiptapEditor {...props} />))
|
package/src/index.macos.ts
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export const supported =
|
|
4
|
-
|
|
5
|
-
/** AppKit host has no rich-text surface yet. */
|
|
6
|
-
export function TiptapEditor(_props: TiptapEditorProps): null {
|
|
7
|
-
return null
|
|
8
|
-
}
|
|
9
|
-
|
|
1
|
+
export { TiptapEditor } from './Editor.macos'
|
|
2
|
+
/** The AppKit/WKWebView backend is implemented. */
|
|
3
|
+
export const supported = true
|
|
10
4
|
export type * from './types'
|
|
11
5
|
|
|
12
|
-
/**
|
|
13
|
-
export function ensureJSONBridge(): Promise<boolean> {
|
|
14
|
-
return
|
|
6
|
+
/** The local bundle includes its JSON model; wait for onReady before reading a document. */
|
|
7
|
+
export async function ensureJSONBridge(): Promise<boolean> {
|
|
8
|
+
return true
|
|
15
9
|
}
|
|
16
10
|
|
|
17
11
|
export function jsonBridgeReady(): boolean {
|
|
18
|
-
return
|
|
12
|
+
return true
|
|
19
13
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Octane } from 'octane/jsx-runtime'
|
|
2
|
+
|
|
1
3
|
/** Format vocabulary shared by the web (tiptap StarterKit) and native
|
|
2
4
|
* (Aztec) backends. On web, starter-kit covers everything except
|
|
3
5
|
* taskList/highlight/subscript/superscript/align* — those no-op there and
|
|
@@ -34,12 +36,14 @@ export type TiptapFormat =
|
|
|
34
36
|
export type TiptapJSON = { type: string; content?: unknown[] } & Record<string, unknown>
|
|
35
37
|
|
|
36
38
|
export interface TiptapEditorHandle {
|
|
39
|
+
/** AppKit: returns the latest WebKit snapshot; commands are asynchronous. */
|
|
37
40
|
getHTML(): string
|
|
38
41
|
/** Web: `commands.setContent` (undo-aware). Native: Aztec `fromHtml` —
|
|
39
42
|
* resets undo history. */
|
|
40
43
|
setHTML(html: string): void
|
|
41
44
|
/** Doc JSON, or null while the native schema modules are still loading /
|
|
42
45
|
* on a runtime that can't host them (`json` flag). Web is always ready. */
|
|
46
|
+
/** AppKit: latest live engine JSON snapshot; null before onReady. */
|
|
43
47
|
getJSON(): TiptapJSON | null
|
|
44
48
|
setJSON(doc: TiptapJSON): void
|
|
45
49
|
apply(format: TiptapFormat): void
|
|
@@ -53,6 +57,7 @@ export interface TiptapEditorHandle {
|
|
|
53
57
|
isFocused(): boolean
|
|
54
58
|
/** The platform surface — a tiptap `Editor` on web, `AztecText` on
|
|
55
59
|
* Android. */
|
|
60
|
+
/** AppKit: the XplatEditorHost transport, not the browser engine instance. */
|
|
56
61
|
native: any
|
|
57
62
|
}
|
|
58
63
|
|
|
@@ -73,13 +78,14 @@ export interface TiptapEditorProps {
|
|
|
73
78
|
/** Fires once when the native JSON bridge settles — `true` if the
|
|
74
79
|
* DOM-free tiptap modules loaded, `false` on runtimes that can't host
|
|
75
80
|
* them (JSON calls then no-op / return null). Never fires on web. */
|
|
81
|
+
/** AppKit: fires true with mounted engine readiness; no headless conversion bridge. */
|
|
76
82
|
onJSONReady?: (ready: boolean) => void
|
|
77
83
|
onChange?: (html: string) => void
|
|
78
84
|
onJSONChange?: (doc: TiptapJSON) => void
|
|
79
85
|
onSelectionChange?: (event: { start: number; end: number; active: TiptapFormat[] }) => void
|
|
80
86
|
onFocus?: () => void
|
|
81
87
|
onBlur?: () => void
|
|
82
|
-
|
|
88
|
+
ref?: Octane.Ref<TiptapEditorHandle>
|
|
83
89
|
android?: Record<string, any>
|
|
84
90
|
ios?: Record<string, any>
|
|
85
91
|
row?: number | string
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { UniversalComponent } from 'octane/universal'
|
|
2
|
+
import type { TiptapEditorProps } from '../src/types'
|
|
3
|
+
export declare const TiptapEditor: UniversalComponent<TiptapEditorProps>
|
|
4
|
+
export declare const supported: boolean
|
|
5
|
+
export type * from '../src/types'
|
|
6
|
+
export declare function ensureJSONBridge(): Promise<boolean>
|
|
7
|
+
export declare function jsonBridgeReady(): boolean
|
package/types/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Octane } from 'octane/jsx-runtime';
|
|
1
2
|
/** Format vocabulary shared by the web (tiptap StarterKit) and native
|
|
2
3
|
* (Aztec) backends. On web, starter-kit covers everything except
|
|
3
4
|
* taskList/highlight/subscript/superscript/align* — those no-op there and
|
|
@@ -10,12 +11,14 @@ export type TiptapJSON = {
|
|
|
10
11
|
content?: unknown[];
|
|
11
12
|
} & Record<string, unknown>;
|
|
12
13
|
export interface TiptapEditorHandle {
|
|
14
|
+
/** AppKit: returns the latest WebKit snapshot; commands are asynchronous. */
|
|
13
15
|
getHTML(): string;
|
|
14
16
|
/** Web: `commands.setContent` (undo-aware). Native: Aztec `fromHtml` —
|
|
15
17
|
* resets undo history. */
|
|
16
18
|
setHTML(html: string): void;
|
|
17
19
|
/** Doc JSON, or null while the native schema modules are still loading /
|
|
18
20
|
* on a runtime that can't host them (`json` flag). Web is always ready. */
|
|
21
|
+
/** AppKit: latest live engine JSON snapshot; null before onReady. */
|
|
19
22
|
getJSON(): TiptapJSON | null;
|
|
20
23
|
setJSON(doc: TiptapJSON): void;
|
|
21
24
|
apply(format: TiptapFormat): void;
|
|
@@ -29,6 +32,7 @@ export interface TiptapEditorHandle {
|
|
|
29
32
|
isFocused(): boolean;
|
|
30
33
|
/** The platform surface — a tiptap `Editor` on web, `AztecText` on
|
|
31
34
|
* Android. */
|
|
35
|
+
/** AppKit: the XplatEditorHost transport, not the browser engine instance. */
|
|
32
36
|
native: any;
|
|
33
37
|
}
|
|
34
38
|
export interface TiptapEditorProps {
|
|
@@ -48,6 +52,7 @@ export interface TiptapEditorProps {
|
|
|
48
52
|
/** Fires once when the native JSON bridge settles — `true` if the
|
|
49
53
|
* DOM-free tiptap modules loaded, `false` on runtimes that can't host
|
|
50
54
|
* them (JSON calls then no-op / return null). Never fires on web. */
|
|
55
|
+
/** AppKit: fires true with mounted engine readiness; no headless conversion bridge. */
|
|
51
56
|
onJSONReady?: (ready: boolean) => void;
|
|
52
57
|
onChange?: (html: string) => void;
|
|
53
58
|
onJSONChange?: (doc: TiptapJSON) => void;
|
|
@@ -58,7 +63,7 @@ export interface TiptapEditorProps {
|
|
|
58
63
|
}) => void;
|
|
59
64
|
onFocus?: () => void;
|
|
60
65
|
onBlur?: () => void;
|
|
61
|
-
|
|
66
|
+
ref?: Octane.Ref<TiptapEditorHandle>;
|
|
62
67
|
android?: Record<string, any>;
|
|
63
68
|
ios?: Record<string, any>;
|
|
64
69
|
row?: number | string;
|