@pilotiq/tiptap 3.10.0 → 3.10.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/react/CollabTextRenderer.d.ts.map +1 -1
- package/dist/react/CollabTextRenderer.js +26 -31
- package/dist/react/CollabTextRenderer.js.map +1 -1
- package/dist/react/MarkdownEditor.d.ts.map +1 -1
- package/dist/react/MarkdownEditor.js +58 -34
- package/dist/react/MarkdownEditor.js.map +1 -1
- package/dist/react/TiptapEditor.js +52 -38
- package/dist/react/TiptapEditor.js.map +1 -1
- package/dist/react/useAiInlineDiff.d.ts.map +1 -1
- package/dist/react/useAiInlineDiff.js +28 -4
- package/dist/react/useAiInlineDiff.js.map +1 -1
- package/dist/react/useAiSuggestionBridge.d.ts.map +1 -1
- package/dist/react/useAiSuggestionBridge.js +14 -7
- package/dist/react/useAiSuggestionBridge.js.map +1 -1
- package/dist/test/setup.d.ts +2 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/dist/test/setup.js +65 -0
- package/dist/test/setup.js.map +1 -0
- package/package.json +7 -3
- package/src/PlainTextEditor.dom.test.ts +111 -0
- package/src/react/BlockSidePanel.dom.test.tsx +38 -0
- package/src/react/CollabTextRenderer.tsx +29 -30
- package/src/react/MarkdownEditor.tsx +62 -32
- package/src/react/TiptapEditor.dom.test.tsx +112 -0
- package/src/react/TiptapEditor.tsx +59 -40
- package/src/react/useAiInlineDiff.ts +29 -3
- package/src/react/useAiSuggestionBridge.ts +14 -6
- package/src/test/setup.ts +64 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAiInlineDiff.js","sourceRoot":"","sources":["../../src/react/useAiInlineDiff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAGzC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EACL,gCAAgC,EAChC,6BAA6B,
|
|
1
|
+
{"version":3,"file":"useAiInlineDiff.js","sourceRoot":"","sources":["../../src/react/useAiInlineDiff.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAiSuggestionBridge.d.ts","sourceRoot":"","sources":["../../src/react/useAiSuggestionBridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,
|
|
1
|
+
{"version":3,"file":"useAiSuggestionBridge.d.ts","sourceRoot":"","sources":["../../src/react/useAiSuggestionBridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAIL,KAAK,iBAAiB,EAEvB,MAAM,wBAAwB,CAAA;AAG/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAA;IAEpD;;;;;;;;;OASG;IACH,yBAAyB,CAAC,EAAE,CAC1B,MAAM,EAAM,MAAM,EAClB,UAAU,EAAE,iBAAiB,KAC1B;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;CAC9C;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,4BAAiC,GACzC,IAAI,CA8IN;AAKD,YAAY,EAAE,iBAAiB,EAAE,CAAA"}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { useEffect, useRef } from 'react';
|
|
2
|
-
import { registerPendingSuggestionApplier, usePendingSuggestionsForField, } from '@pilotiq/pilotiq/react';
|
|
2
|
+
import { registerPendingSuggestionApplier, usePendingSuggestionsForField, useFormId, } from '@pilotiq/pilotiq/react';
|
|
3
3
|
import { aiSuggestionPluginKey } from '../extensions/AiSuggestionExtension.js';
|
|
4
4
|
export function useAiSuggestionBridge(editor, fieldName, options = {}) {
|
|
5
5
|
const { list, dismiss } = usePendingSuggestionsForField(fieldName);
|
|
6
|
+
// Scope the applier under the surrounding form's id — same reasoning
|
|
7
|
+
// as `useAiInlineDiff`: two editors with the same field name across
|
|
8
|
+
// different forms (main edit form vs. a Replicate modal, say) would
|
|
9
|
+
// otherwise race on `registerPendingSuggestionApplier(undefined, …)`
|
|
10
|
+
// and the last-mounted editor would steal every approval.
|
|
11
|
+
const formId = useFormId();
|
|
6
12
|
// Hold the latest `dismiss` in a ref so the editor-side listener — which
|
|
7
13
|
// installs once per editor — always reaches the up-to-date context API.
|
|
8
14
|
const dismissRef = useRef(dismiss);
|
|
@@ -131,11 +137,12 @@ export function useAiSuggestionBridge(editor, fieldName, options = {}) {
|
|
|
131
137
|
apply(suggestion.suggestedValue);
|
|
132
138
|
}
|
|
133
139
|
};
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
140
|
+
// formId comes from `useFormId()` on the form-context side — scopes
|
|
141
|
+
// the registration per-form so multi-form pages route approvals to
|
|
142
|
+
// the matching editor. Falls back to wildcard (`undefined`) when no
|
|
143
|
+
// FormRenderer is up-tree (modal action schemas, action-modal forms
|
|
144
|
+
// mounted outside the main page form).
|
|
145
|
+
return registerPendingSuggestionApplier(formId, fieldName, applier);
|
|
146
|
+
}, [editor, fieldName, formId]);
|
|
140
147
|
}
|
|
141
148
|
//# sourceMappingURL=useAiSuggestionBridge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAiSuggestionBridge.js","sourceRoot":"","sources":["../../src/react/useAiSuggestionBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAEzC,OAAO,EACL,gCAAgC,EAChC,6BAA6B,
|
|
1
|
+
{"version":3,"file":"useAiSuggestionBridge.js","sourceRoot":"","sources":["../../src/react/useAiSuggestionBridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/test/setup.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 6e test setup — boots jsdom into globalThis so React Testing
|
|
3
|
+
* Library + Tiptap render against a real-ish DOM. Loaded via the test
|
|
4
|
+
* script's `--import` flag *before* any test file is imported, so React
|
|
5
|
+
* sees the DOM globals at module-load time (RTL's `cleanup()` and
|
|
6
|
+
* `render()` both expect `document` + `window` to exist as globals).
|
|
7
|
+
*
|
|
8
|
+
* We register a minimal subset of DOM globals: the rest hang off
|
|
9
|
+
* `window`, which is how the browser code under test reaches them. The
|
|
10
|
+
* `assign` helper preserves `globalThis`'s native bindings (e.g. Node's
|
|
11
|
+
* `URL`) when jsdom exports a shadowing constructor that breaks
|
|
12
|
+
* downstream code (Tiptap uses `URL` in extension-link's autolink
|
|
13
|
+
* heuristic).
|
|
14
|
+
*/
|
|
15
|
+
import { JSDOM } from 'jsdom';
|
|
16
|
+
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>', {
|
|
17
|
+
url: 'http://localhost/',
|
|
18
|
+
pretendToBeVisual: true,
|
|
19
|
+
});
|
|
20
|
+
const window = dom.window;
|
|
21
|
+
// Properties that Tiptap, React 19, and RTL touch directly via the
|
|
22
|
+
// global namespace (rather than via the captured `window` reference).
|
|
23
|
+
// Keep this list tight — every override is a place where jsdom and Node
|
|
24
|
+
// can diverge subtly.
|
|
25
|
+
const globals = {
|
|
26
|
+
window,
|
|
27
|
+
document: window.document,
|
|
28
|
+
navigator: window.navigator,
|
|
29
|
+
HTMLElement: window.HTMLElement,
|
|
30
|
+
HTMLInputElement: window.HTMLInputElement,
|
|
31
|
+
HTMLTextAreaElement: window.HTMLTextAreaElement,
|
|
32
|
+
HTMLAnchorElement: window.HTMLAnchorElement,
|
|
33
|
+
HTMLDivElement: window.HTMLDivElement,
|
|
34
|
+
HTMLSpanElement: window.HTMLSpanElement,
|
|
35
|
+
Element: window.Element,
|
|
36
|
+
Node: window.Node,
|
|
37
|
+
Text: window.Text,
|
|
38
|
+
Event: window.Event,
|
|
39
|
+
MouseEvent: window.MouseEvent,
|
|
40
|
+
KeyboardEvent: window.KeyboardEvent,
|
|
41
|
+
CustomEvent: window.CustomEvent,
|
|
42
|
+
DocumentFragment: window.DocumentFragment,
|
|
43
|
+
Range: window.Range,
|
|
44
|
+
Selection: window.Selection,
|
|
45
|
+
MutationObserver: window.MutationObserver,
|
|
46
|
+
IntersectionObserver: window.IntersectionObserver,
|
|
47
|
+
ResizeObserver: window.ResizeObserver ?? class {
|
|
48
|
+
observe() { }
|
|
49
|
+
unobserve() { }
|
|
50
|
+
disconnect() { }
|
|
51
|
+
},
|
|
52
|
+
DOMRect: window.DOMRect,
|
|
53
|
+
getComputedStyle: window.getComputedStyle.bind(window),
|
|
54
|
+
requestAnimationFrame: (cb) => setTimeout(() => cb(performance.now()), 16),
|
|
55
|
+
cancelAnimationFrame: (id) => clearTimeout(id),
|
|
56
|
+
};
|
|
57
|
+
for (const [k, v] of Object.entries(globals)) {
|
|
58
|
+
Object.defineProperty(globalThis, k, { value: v, writable: true, configurable: true });
|
|
59
|
+
}
|
|
60
|
+
// React 19 + RTL require `IS_REACT_ACT_ENVIRONMENT` so `act()` warnings
|
|
61
|
+
// don't fire on every render. Without it, Tiptap's mount cascade
|
|
62
|
+
// produces dozens of warnings that swamp real test failures.
|
|
63
|
+
;
|
|
64
|
+
globalThis['IS_REACT_ACT_ENVIRONMENT'] = true;
|
|
65
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/test/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAE7B,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,2CAA2C,EAAE;IACjE,GAAG,EAAgB,mBAAmB;IACtC,iBAAiB,EAAE,IAAI;CACxB,CAAC,CAAA;AAEF,MAAM,MAAM,GAAG,GAAG,CAAC,MAA+C,CAAA;AAElE,mEAAmE;AACnE,sEAAsE;AACtE,wEAAwE;AACxE,sBAAsB;AACtB,MAAM,OAAO,GAA4B;IACvC,MAAM;IACN,QAAQ,EAAY,MAAM,CAAC,QAAQ;IACnC,SAAS,EAAW,MAAM,CAAC,SAAS;IACpC,WAAW,EAAS,MAAM,CAAC,WAAW;IACtC,gBAAgB,EAAI,MAAM,CAAC,gBAAgB;IAC3C,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;IAC/C,iBAAiB,EAAG,MAAM,CAAC,iBAAiB;IAC5C,cAAc,EAAM,MAAM,CAAC,cAAc;IACzC,eAAe,EAAK,MAAM,CAAC,eAAe;IAC1C,OAAO,EAAa,MAAM,CAAC,OAAO;IAClC,IAAI,EAAgB,MAAM,CAAC,IAAI;IAC/B,IAAI,EAAgB,MAAM,CAAC,IAAI;IAC/B,KAAK,EAAe,MAAM,CAAC,KAAK;IAChC,UAAU,EAAU,MAAM,CAAC,UAAU;IACrC,aAAa,EAAO,MAAM,CAAC,aAAa;IACxC,WAAW,EAAS,MAAM,CAAC,WAAW;IACtC,gBAAgB,EAAI,MAAM,CAAC,gBAAgB;IAC3C,KAAK,EAAe,MAAM,CAAC,KAAK;IAChC,SAAS,EAAW,MAAM,CAAC,SAAS;IACpC,gBAAgB,EAAI,MAAM,CAAC,gBAAgB;IAC3C,oBAAoB,EAAE,MAAM,CAAC,oBAAoB;IACjD,cAAc,EAAM,MAAM,CAAC,cAAc,IAAI;QAAQ,OAAO,KAAI,CAAC;QAAC,SAAS,KAAI,CAAC;QAAC,UAAU,KAAI,CAAC;KAAE;IAClG,OAAO,EAAa,MAAM,CAAC,OAAO;IAClC,gBAAgB,EAAI,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC;IACxD,qBAAqB,EAAE,CAAC,EAAwB,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAsB;IACrH,oBAAoB,EAAG,CAAC,EAAU,EAAE,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC;CACxD,CAAA;AAED,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IAC7C,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAA;AACxF,CAAC;AAED,wEAAwE;AACxE,iEAAiE;AACjE,6DAA6D;AAC7D,CAAC;AAAC,UAAsC,CAAC,0BAA0B,CAAC,GAAG,IAAI,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pilotiq/tiptap",
|
|
3
|
-
"version": "3.10.
|
|
3
|
+
"version": "3.10.2",
|
|
4
4
|
"description": "Tiptap rich-text editor adapter for @pilotiq/pilotiq — slash menu, draggable blocks, custom-block API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -58,6 +58,8 @@
|
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@base-ui/react": "^1",
|
|
61
|
+
"@testing-library/dom": "^10.4.1",
|
|
62
|
+
"@testing-library/react": "^16.3.2",
|
|
61
63
|
"@tiptap/core": "^3",
|
|
62
64
|
"@tiptap/extension-color": "3.22.4",
|
|
63
65
|
"@tiptap/extension-details": "3.22.4",
|
|
@@ -75,15 +77,17 @@
|
|
|
75
77
|
"@tiptap/react": "^3",
|
|
76
78
|
"@tiptap/starter-kit": "^3",
|
|
77
79
|
"@tiptap/suggestion": "^3",
|
|
80
|
+
"@types/jsdom": "^28.0.3",
|
|
78
81
|
"@types/node": "^20",
|
|
79
82
|
"@types/react": "^19",
|
|
80
83
|
"@types/react-dom": "^19",
|
|
81
84
|
"esbuild": "^0.27",
|
|
85
|
+
"jsdom": "^29.1.1",
|
|
82
86
|
"react": "^19",
|
|
83
87
|
"react-dom": "^19",
|
|
84
88
|
"tiptap-markdown": "^0.9",
|
|
85
89
|
"typescript": "^5",
|
|
86
|
-
"@pilotiq/pilotiq": "^0.
|
|
90
|
+
"@pilotiq/pilotiq": "^0.23.0"
|
|
87
91
|
},
|
|
88
92
|
"author": "Suleiman Shahbari",
|
|
89
93
|
"scripts": {
|
|
@@ -93,6 +97,6 @@
|
|
|
93
97
|
"typecheck": "tsc --noEmit",
|
|
94
98
|
"lint": "eslint src",
|
|
95
99
|
"clean": "rm -rf dist",
|
|
96
|
-
"test": "tsc -p tsconfig.test.json && node --test \"dist-test/**/*.test.js\"; EXIT=$?; rm -rf dist-test; exit $EXIT"
|
|
100
|
+
"test": "tsc -p tsconfig.test.json && node --import ./dist-test/test/setup.js --test \"dist-test/**/*.test.js\"; EXIT=$?; rm -rf dist-test; exit $EXIT"
|
|
97
101
|
}
|
|
98
102
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { Editor } from '@tiptap/core'
|
|
4
|
+
|
|
5
|
+
import { createPlainTextEditor, plainTextOf } from './PlainTextEditor.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Phase 6e proof-of-concept — mount a real Tiptap `Editor` against the
|
|
9
|
+
* jsdom DOM that `src/test/setup.ts` boots, exercise typing through the
|
|
10
|
+
* ProseMirror transaction API, and assert via the public surface.
|
|
11
|
+
*
|
|
12
|
+
* The pure-config tests in `PlainTextEditor.test.ts` cover schema-shape
|
|
13
|
+
* fixtures (`plainTextToDoc`); this file proves the config actually
|
|
14
|
+
* behaves correctly when mounted into the editor's lifecycle —
|
|
15
|
+
* `setContent` → `getJSON` → `plainTextOf` round-trip, multi-line
|
|
16
|
+
* separator handling, document constraint enforcement. Component-level
|
|
17
|
+
* coverage that previously lived only in the playground now has a
|
|
18
|
+
* fast in-process test.
|
|
19
|
+
*/
|
|
20
|
+
describe('createPlainTextEditor (DOM)', () => {
|
|
21
|
+
function mountInDom(multiline: boolean): { editor: Editor; el: HTMLDivElement } {
|
|
22
|
+
const el = document.createElement('div')
|
|
23
|
+
document.body.appendChild(el)
|
|
24
|
+
const editor = new Editor({
|
|
25
|
+
...createPlainTextEditor({ multiline, content: '' }),
|
|
26
|
+
element: el,
|
|
27
|
+
})
|
|
28
|
+
return { editor, el }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
it('single-line: setContent + plainTextOf round-trips one paragraph', () => {
|
|
32
|
+
const { editor } = mountInDom(false)
|
|
33
|
+
try {
|
|
34
|
+
editor.commands.setContent('hello world')
|
|
35
|
+
assert.equal(plainTextOf(editor), 'hello world')
|
|
36
|
+
} finally {
|
|
37
|
+
editor.destroy()
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('single-line: schema rejects multi-paragraph content (collapses to one)', () => {
|
|
42
|
+
const { editor } = mountInDom(false)
|
|
43
|
+
try {
|
|
44
|
+
// ProseMirror enforces the doc schema; PlainTextDocument's content
|
|
45
|
+
// expression is `paragraph` (a SINGLE paragraph) in single-line
|
|
46
|
+
// mode. Passing a multi-paragraph JSON tree should be coerced to
|
|
47
|
+
// one paragraph by Tiptap's repair pass rather than throwing.
|
|
48
|
+
editor.commands.setContent({
|
|
49
|
+
type: 'doc',
|
|
50
|
+
content: [
|
|
51
|
+
{ type: 'paragraph', content: [{ type: 'text', text: 'line one' }] },
|
|
52
|
+
{ type: 'paragraph', content: [{ type: 'text', text: 'line two' }] },
|
|
53
|
+
],
|
|
54
|
+
})
|
|
55
|
+
// The exact repair behavior is "keep what fits, drop the rest" —
|
|
56
|
+
// we don't assert the specific outcome (`line one` only vs the
|
|
57
|
+
// two joined), only that the result is single-paragraph and
|
|
58
|
+
// non-empty. Future Tiptap version bumps that change the repair
|
|
59
|
+
// strategy won't break this test.
|
|
60
|
+
const json = editor.getJSON()
|
|
61
|
+
assert.equal(json.content?.length, 1, 'single paragraph after repair')
|
|
62
|
+
assert.ok(plainTextOf(editor).length > 0, 'non-empty after repair')
|
|
63
|
+
assert.ok(!plainTextOf(editor).includes('\n'), 'no newline in single-line mode')
|
|
64
|
+
} finally {
|
|
65
|
+
editor.destroy()
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('multi-line: setContent across paragraphs serializes with \\n separators', () => {
|
|
70
|
+
const { editor } = mountInDom(true)
|
|
71
|
+
try {
|
|
72
|
+
editor.commands.setContent({
|
|
73
|
+
type: 'doc',
|
|
74
|
+
content: [
|
|
75
|
+
{ type: 'paragraph', content: [{ type: 'text', text: 'first' }] },
|
|
76
|
+
{ type: 'paragraph', content: [{ type: 'text', text: 'second' }] },
|
|
77
|
+
{ type: 'paragraph', content: [{ type: 'text', text: 'third' }] },
|
|
78
|
+
],
|
|
79
|
+
})
|
|
80
|
+
assert.equal(plainTextOf(editor), 'first\nsecond\nthird')
|
|
81
|
+
} finally {
|
|
82
|
+
editor.destroy()
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('multi-line: empty document returns empty string', () => {
|
|
87
|
+
const { editor } = mountInDom(true)
|
|
88
|
+
try {
|
|
89
|
+
assert.equal(plainTextOf(editor), '')
|
|
90
|
+
} finally {
|
|
91
|
+
editor.destroy()
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('typing via commands.insertContent updates the visible DOM', () => {
|
|
96
|
+
const { editor, el } = mountInDom(false)
|
|
97
|
+
try {
|
|
98
|
+
editor.commands.focus()
|
|
99
|
+
editor.commands.insertContent('typed via command')
|
|
100
|
+
assert.equal(plainTextOf(editor), 'typed via command')
|
|
101
|
+
// The ProseMirror view renders `.ProseMirror` inside the mount
|
|
102
|
+
// element; verify the text is in the visible DOM too (this is
|
|
103
|
+
// the assertion that pure-data fixtures can't make).
|
|
104
|
+
const pm = el.querySelector('.ProseMirror')
|
|
105
|
+
assert.ok(pm, 'ProseMirror view mounted')
|
|
106
|
+
assert.ok(pm!.textContent?.includes('typed via command'), 'text rendered in DOM')
|
|
107
|
+
} finally {
|
|
108
|
+
editor.destroy()
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { render, cleanup, screen } from '@testing-library/react'
|
|
5
|
+
|
|
6
|
+
import { clampPanelWidth } from './BlockSidePanel.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Phase 6e proof-of-concept — exercise React Testing Library's
|
|
10
|
+
* `render()` against the jsdom environment that `src/test/setup.ts`
|
|
11
|
+
* boots. The pure helper `clampPanelWidth` is already covered by the
|
|
12
|
+
* neighbouring `BlockSidePanel.test.ts`; this file proves the RTL
|
|
13
|
+
* surface (render / screen / cleanup) actually works in the test
|
|
14
|
+
* harness — every future component-level test for `BlockSidePanel`,
|
|
15
|
+
* `Toolbar`, `SlashMenu`, etc. uses the same primitives.
|
|
16
|
+
*/
|
|
17
|
+
describe('RTL render() (DOM)', () => {
|
|
18
|
+
it('renders a trivial React tree and queries it via `screen`', () => {
|
|
19
|
+
render(<div data-testid="probe">hello tiptap</div>)
|
|
20
|
+
try {
|
|
21
|
+
const node = screen.getByTestId('probe')
|
|
22
|
+
assert.equal(node.textContent, 'hello tiptap')
|
|
23
|
+
} finally {
|
|
24
|
+
cleanup()
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('exports clampPanelWidth as a stable pure helper (sanity)', () => {
|
|
29
|
+
// Cross-check: pure-data assertions still work alongside RTL
|
|
30
|
+
// mounts. `clampPanelWidth` is the helper tested via the
|
|
31
|
+
// pure-mode `BlockSidePanel.test.ts` already — re-asserting one
|
|
32
|
+
// case here confirms the dual-import surface (both pure tests
|
|
33
|
+
// and DOM tests in the same package) doesn't conflict.
|
|
34
|
+
assert.equal(clampPanelWidth(100), 240)
|
|
35
|
+
assert.equal(clampPanelWidth(320), 320)
|
|
36
|
+
assert.equal(clampPanelWidth(1000), 600)
|
|
37
|
+
})
|
|
38
|
+
})
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { useEffect, useMemo
|
|
1
|
+
import { useEffect, useMemo } from 'react'
|
|
2
2
|
import { useEditor, EditorContent, type Extension } from '@tiptap/react'
|
|
3
3
|
import type { AnyExtension } from '@tiptap/core'
|
|
4
4
|
import {
|
|
5
5
|
useCollabRoom,
|
|
6
6
|
getCollabExtensions,
|
|
7
|
-
|
|
7
|
+
useCollabSeed,
|
|
8
8
|
type CollabTextRendererProps,
|
|
9
9
|
} from '@pilotiq/pilotiq/react'
|
|
10
10
|
import { createPlainTextEditor, plainTextOf, plainTextToDoc } from '../PlainTextEditor.js'
|
|
@@ -154,41 +154,40 @@ export function CollabTextRenderer({
|
|
|
154
154
|
})
|
|
155
155
|
|
|
156
156
|
// First-load seed when collab is active. Collaboration starts the editor
|
|
157
|
-
// empty regardless of `defaultValue`; once the
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
//
|
|
157
|
+
// empty regardless of `defaultValue`; once the room's first sync
|
|
158
|
+
// resolves, `useCollabSeed` runs the callback inside `ydoc.transact`.
|
|
159
|
+
// Empty fragment + we have an initial value = first session for this
|
|
160
|
+
// record — push the SSR-rendered default into the editor once.
|
|
161
161
|
//
|
|
162
162
|
// Race caveat: two peers simultaneously mounting against a brand-new
|
|
163
163
|
// record (both seeing `fragment.length === 0`) can both seed and produce
|
|
164
164
|
// duplicated text. Same window as `TiptapEditor`'s rich-text seed path.
|
|
165
165
|
// Acceptable for now; can be tightened later via a deterministic
|
|
166
166
|
// first-writer election or a server-side seed handoff.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
167
|
+
//
|
|
168
|
+
// Subscribe-after-sync mirror: after the seed branch (or no-op when the
|
|
169
|
+
// fragment already has content from a remote peer), replay the editor's
|
|
170
|
+
// current text into `onChange`. The mount-time safety-net effect below
|
|
171
|
+
// fires once when the editor instance materializes, but in the cold-mount
|
|
172
|
+
// case (fresh peer joining a populated doc) y-prosemirror's `ySyncPlugin`
|
|
173
|
+
// view hook may run _forceRerender before the React owner has installed
|
|
174
|
+
// the `update` listener that drives `onUpdate` — leaving the hidden
|
|
175
|
+
// FormData input empty. Mirroring after `room.synced` resolves closes the
|
|
176
|
+
// gap. Idempotent — when `onUpdate` already propagated the value, this is
|
|
177
|
+
// a no-op `setText(sameValue)`. Same shape as the catch-up replay in
|
|
178
|
+
// `@pilotiq-pro/collab`'s `rowArrayBinding.subscribeRows`.
|
|
179
|
+
useCollabSeed(
|
|
180
|
+
editor && collabActive ? room : null,
|
|
181
|
+
collabName,
|
|
182
|
+
(doc) => {
|
|
183
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
184
|
+
const fragment = (doc as any).getXmlFragment(collabName)
|
|
185
|
+
if (fragment && fragment.length === 0 && defaultValue && editor) {
|
|
186
|
+
editor.commands.setContent(plainTextToDoc(defaultValue, multiline))
|
|
185
187
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
// Seed once per editor instance — keyed remount above resets `hasSeeded`.
|
|
190
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
191
|
-
}, [editor, collabActive, room])
|
|
188
|
+
if (editor) onChange(plainTextOf(editor))
|
|
189
|
+
},
|
|
190
|
+
)
|
|
192
191
|
|
|
193
192
|
// Bubble the editor's blur event up to the host. Tiptap exposes this via
|
|
194
193
|
// `editor.on('blur', ...)`. The simpler `onBlur` prop on `EditorContent`
|
|
@@ -14,7 +14,8 @@ import { Markdown } from '../markdownExtension.js'
|
|
|
14
14
|
import {
|
|
15
15
|
useCollabRoom,
|
|
16
16
|
getCollabExtensions,
|
|
17
|
-
|
|
17
|
+
useCollabSeed,
|
|
18
|
+
useToast,
|
|
18
19
|
type MarkdownEditorProps,
|
|
19
20
|
} from '@pilotiq/pilotiq/react'
|
|
20
21
|
import { AiSuggestionExtension } from '../extensions/AiSuggestionExtension.js'
|
|
@@ -180,6 +181,10 @@ export function MarkdownEditor({
|
|
|
180
181
|
const [sourceDraft, setSourceDraft] = useState<string>(defaultValue)
|
|
181
182
|
const [uploading, setUploading] = useState(false)
|
|
182
183
|
const fileInputRef = useRef<HTMLInputElement | null>(null)
|
|
184
|
+
// Toast handle for surfacing upload failures via the host's notification
|
|
185
|
+
// stack. Falls back to a no-op when no ToasterProvider is mounted
|
|
186
|
+
// (`useToast` returns a default context — see Toaster.tsx).
|
|
187
|
+
const { notify } = useToast()
|
|
183
188
|
|
|
184
189
|
// Collab extension factory output. Built once per editor mount (the
|
|
185
190
|
// factory closes over the room's ydoc + provider + field name); keyed
|
|
@@ -304,36 +309,45 @@ export function MarkdownEditor({
|
|
|
304
309
|
const isDiffActive = useIsAiInlineDiffActive(editor ?? null)
|
|
305
310
|
|
|
306
311
|
// First-load seed for collab. Collaboration starts the editor empty
|
|
307
|
-
// regardless of `content`; once the
|
|
308
|
-
//
|
|
309
|
-
// we have an initial value = first session for this
|
|
310
|
-
// the rich-text TiptapEditor seed path and the
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
312
|
+
// regardless of `content`; once the room's first sync resolves,
|
|
313
|
+
// `useCollabSeed` runs the callback inside `ydoc.transact`. Empty
|
|
314
|
+
// fragment + we have an initial value = first session for this
|
|
315
|
+
// record. Mirrors the rich-text TiptapEditor seed path and the
|
|
316
|
+
// CollabTextRenderer seed. Gates on `editor` so Tiptap v3's deferred
|
|
317
|
+
// `immediatelyRender: false` mount completes first.
|
|
318
|
+
//
|
|
319
|
+
// Subscribe-after-sync mirror: after the seed branch (or no-op when
|
|
320
|
+
// the fragment already has content from a remote peer), serialize
|
|
321
|
+
// the editor's current markdown and propagate via `onChange` so the
|
|
322
|
+
// host's hidden FormData input picks it up. The host (`MarkdownEditorHost`
|
|
323
|
+
// in pilotiq core) drives the hidden input from React state that's
|
|
324
|
+
// populated ONLY through `onChange`; in the cold-mount case
|
|
325
|
+
// (fresh peer joining a populated doc) y-prosemirror's `ySyncPlugin`
|
|
326
|
+
// view hook may run `_forceRerender` before the React owner has
|
|
327
|
+
// installed the `update` listener that drives `onUpdate` — leaving
|
|
328
|
+
// the input at its SSR-rendered `defaultValue`. Idempotent — when
|
|
329
|
+
// `onUpdate` already propagated the value, this is a no-op
|
|
330
|
+
// `setText(sameValue)`. Same shape as `TiptapEditor` /
|
|
331
|
+
// `CollabTextRenderer` / `rowArrayBinding.subscribeRows`.
|
|
332
|
+
useCollabSeed(
|
|
333
|
+
editor && collabActive ? room : null,
|
|
334
|
+
collabName,
|
|
335
|
+
(doc) => {
|
|
336
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
337
|
+
const fragment = (doc as any).getXmlFragment(collabName)
|
|
338
|
+
if (fragment && fragment.length === 0 && defaultValue && editor) {
|
|
339
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
340
|
+
const cmd = (editor.commands as any).setContent
|
|
341
|
+
if (cmd) cmd(defaultValue)
|
|
331
342
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
343
|
+
if (editor) {
|
|
344
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
345
|
+
const storage = (editor.storage as any).markdown
|
|
346
|
+
const md = typeof storage?.getMarkdown === 'function' ? storage.getMarkdown() : ''
|
|
347
|
+
onChange(md)
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
)
|
|
337
351
|
|
|
338
352
|
// Source-tab → Editor: parse the textarea back into the editor (this also
|
|
339
353
|
// emits onChange via the editor's onUpdate). One-way during the same flip.
|
|
@@ -381,9 +395,25 @@ export function MarkdownEditor({
|
|
|
381
395
|
if (fileAttachmentsDirectory) fd.append('directory', fileAttachmentsDirectory)
|
|
382
396
|
if (fileAttachmentsVisibility) fd.append('visibility', fileAttachmentsVisibility)
|
|
383
397
|
fd.append('fieldName', name)
|
|
384
|
-
|
|
398
|
+
let res: Response
|
|
399
|
+
try {
|
|
400
|
+
res = await fetch(uploadUrl, { method: 'POST', body: fd, headers: { Accept: 'application/json' } })
|
|
401
|
+
} catch {
|
|
402
|
+
// Network-level failure (offline, DNS, etc.) — surface as a
|
|
403
|
+
// toast since the user clicked Upload and would otherwise see
|
|
404
|
+
// only the spinner stop.
|
|
405
|
+
notify({ title: 'Upload failed', body: 'Could not reach the upload endpoint.', type: 'error' })
|
|
406
|
+
return
|
|
407
|
+
}
|
|
385
408
|
const data = await res.json().catch(() => ({} as { ok?: boolean; url?: string; error?: string }))
|
|
386
|
-
if (!res.ok || !data.ok || !data.url)
|
|
409
|
+
if (!res.ok || !data.ok || !data.url) {
|
|
410
|
+
notify({
|
|
411
|
+
title: 'Upload failed',
|
|
412
|
+
body: data.error ?? `Upload failed (status ${res.status}).`,
|
|
413
|
+
type: 'error',
|
|
414
|
+
})
|
|
415
|
+
return
|
|
416
|
+
}
|
|
387
417
|
const isImage = file.type.startsWith('image/')
|
|
388
418
|
if (isImage) {
|
|
389
419
|
editor.chain().focus().setImage({ src: data.url, alt: file.name }).run()
|