@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.
@@ -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(6);
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 jsonReady = useRef(false, _h$1);
20
- const lastJSON = useRef(void 0, _h$2);
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
- props.bind?.({
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$3);
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$4);
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$5);
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
- "bind",
140
+ "ref",
137
141
  bindHost
138
142
  ],
139
143
  [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
- "buildId": "02534c50-4097-48da-93e0-5e219c2d5b5c",
3
+ "buildId": "3880e698-2b9a-436f-af5a-a7ec180643bf",
4
4
  "mode": "production",
5
5
  "capabilities": {
6
6
  "independentHydration": false
@@ -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);
8
- var _h$3 = /* @__PURE__ */ Symbol(_hs$ + 3);
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 bound = useRef(void 0, _hs$ + 2);
93
- const editor = withSlot(_h$3, useEditor, {
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.value ?? props.json ?? "",
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 || props.value === void 0) return;
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
- }, [editor, props.value], _hs$ + 4);
113
+ }, [
114
+ editor,
115
+ props.value,
116
+ props.json
117
+ ], _hs$ + 6);
120
118
  useEffect(() => {
121
- if (!editor || props.json === void 0) return;
122
- if (JSON.stringify(props.json) === lastJSON.current) return;
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$ + 5);
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$ + 6);
129
- useEffect(() => {
130
- if (!editor || bound.current?.native === editor) return;
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) => IS_ACTIVE[format]?.(e) ?? false,
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
- props.bind?.(bound.current);
162
- }, [editor], _hs$ + 7);
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:077f1c5f");
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 };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
- "buildId": "877d10c5-3430-4ba4-9762-2bd655451b3d",
3
+ "buildId": "e01adeb4-b2cd-4b21-9fdd-57831df35c5b",
4
4
  "mode": "production",
5
5
  "capabilities": {
6
6
  "independentHydration": false
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@octane-xplat/tiptap",
3
- "version": "0.9.0",
4
- "description": "Unified rich-text editor facade for Octane xplat — @octanejs/tiptap on web, @octane-xplat/richtext (Aztec) + tiptap doc model on native",
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.9.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
+ }
@@ -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
- props.bind?.({
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
- bind={bindHost}
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.value ?? props.json ?? '') as any,
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 || props.value === undefined) return
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 || props.json === undefined) return
113
- if (JSON.stringify(props.json) === lastJSON.current) return
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
- useEffect(() => {
125
- if (!editor || bound.current?.native === editor) return
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) => IS_ACTIVE[format]?.(e) ?? false,
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
- props.bind?.(bound.current)
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} />))
@@ -1,19 +1,13 @@
1
- import type { TiptapEditorProps } from './types'
2
-
3
- export const supported = false
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
- /** No editor, no bridge. */
13
- export function ensureJSONBridge(): Promise<boolean> {
14
- return Promise.resolve(false)
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 false
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
- bind?: (handle: TiptapEditorHandle) => void
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
- bind?: (handle: TiptapEditorHandle) => void;
66
+ ref?: Octane.Ref<TiptapEditorHandle>;
62
67
  android?: Record<string, any>;
63
68
  ios?: Record<string, any>;
64
69
  row?: number | string;