Skip to content

Commit 44c794c

Browse files
committed
v2
1 parent f431866 commit 44c794c

198 files changed

Lines changed: 7845 additions & 9276 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
- Barrels: If you change package exports, move public files, add/remove files under exported folders, or CI says `pnpm brl` produced changes, run `pnpm brl` before final verification/commit and include the generated barrel updates.
2626
- Do not write TDD cases for dead code/legacy removal assertions (for example: "should not contain old API X anymore"). Remove the dead path directly and keep tests focused on current behavior.
2727
- Prefer inline when used once; extract constants only when reused.
28+
- Type inference is mandatory for Plate/Plite callback APIs. Do not add explicit callback parameter annotations like `(tx: EditorUpdateTransaction)` to silence TypeScript when the API should infer them; fix the owning generic/API type instead. Explicit annotations are only acceptable at exported public signatures or true external boundary adapters.
2829

2930
## Tooling
3031

.agents/skills/plate-next/SKILL.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ Rules:
9090
like `PreInsertOptions`, explicit callback parameter annotations, or
9191
`Parameters<typeof fn>` plumbing just to silence TypeScript. Fix the owning
9292
API/source typing so the call site stays inferred.
93+
- Do not add local fixture-shape aliases in tests, such as
94+
`type EditorFixture = { children; selection }`, to hide weak hyperscript
95+
typing. If many tests need the same JSX/editor fixture shape, repair or
96+
export the test-utils owner type and let call sites use that source-owned
97+
fixture type without local casts.
9398
- Preserve main-style inline test setup. Do not extract `const plugins`,
9499
`const options`, helper variables, or wrapper factories from a test just to
95100
placate migrated types when `origin/main` kept the setup inline. Inline
@@ -280,6 +285,8 @@ Default suspicion list:
280285
- explicit callback/helper types in tests that replace inference from
281286
`createBasePlugin`, `createBaseEditor`, plugin config, tx groups, or editor
282287
API calls.
288+
- local JSX/editor fixture aliases in tests, especially `{ children; selection
289+
}` shapes that should come from `@platejs/test-utils`.
283290
- duplicate Plate helpers around Plite APIs.
284291
- docs/examples that teach legacy compatibility instead of latest state.
285292

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
- Barrels: If you change package exports, move public files, add/remove files under exported folders, or CI says `pnpm brl` produced changes, run `pnpm brl` before final verification/commit and include the generated barrel updates.
3131
- Do not write TDD cases for dead code/legacy removal assertions (for example: "should not contain old API X anymore"). Remove the dead path directly and keep tests focused on current behavior.
3232
- Prefer inline when used once; extract constants only when reused.
33+
- Type inference is mandatory for Plate/Plite callback APIs. Do not add explicit callback parameter annotations like `(tx: EditorUpdateTransaction)` to silence TypeScript when the API should infer them; fix the owning generic/API type instead. Explicit annotations are only acceptable at exported public signatures or true external boundary adapters.
3334

3435
## Tooling
3536

packages/core/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@
6464
"nanoid": "^5.1.5",
6565
"optics-ts": "2.4.1",
6666
"react-compiler-runtime": "^1.0.0",
67-
"scroll-into-view-if-needed": "^3.1.0",
6867
"use-deep-compare": "^1.3.0",
6968
"zustand": "^5.0.5",
7069
"zustand-x": "6.2.1"

packages/core/src/internal/plugin/pipeTransformInitialValue.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const pipeTransformInitialValue = (editor: BaseEditor) => {
1212
editor.runtime.pluginCache.transformInitialValue.forEach((key) => {
1313
const p = editor.getPlugin({ key });
1414

15-
if (isEditOnly(editor.api.dom.isReadOnly(), p, 'transformInitialValue')) {
15+
if (isEditOnly(editor.read.view.isReadOnly(), p, 'transformInitialValue')) {
1616
return;
1717
}
1818

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/** @jsx jsxt */
2+
3+
import { jsxt } from '@platejs/test-utils';
4+
5+
jsxt;
6+
7+
import { createBaseEditor } from '../../lib/editor';
8+
import { createBasePlugin } from '../../lib/plugin';
9+
10+
describe('plate change handlers', () => {
11+
it('dispatches node change handlers from Plite node change events', () => {
12+
const onNodeChange = mock();
13+
const NodeObserverPlugin = createBasePlugin({
14+
handlers: { onNodeChange },
15+
key: 'nodeObserver',
16+
});
17+
const editor = createBaseEditor({
18+
plugins: [NodeObserverPlugin],
19+
value: [{ children: [{ text: 'hello' }], type: 'p' }],
20+
});
21+
22+
onNodeChange.mockClear();
23+
24+
editor.update.nodes.set({ variant: 'lead' } as any, { at: [0] });
25+
26+
expect(onNodeChange).toHaveBeenCalledTimes(1);
27+
expect(onNodeChange.mock.calls[0]?.[0]).toMatchObject({
28+
node: {
29+
children: [{ text: 'hello' }],
30+
type: 'p',
31+
variant: 'lead',
32+
},
33+
operation: {
34+
path: [0],
35+
type: 'set_node',
36+
},
37+
prevNode: {
38+
children: [{ text: 'hello' }],
39+
type: 'p',
40+
},
41+
});
42+
});
43+
44+
it('dispatches text change handlers from Plite text change events', () => {
45+
const onTextChange = mock();
46+
const TextObserverPlugin = createBasePlugin({
47+
handlers: { onTextChange },
48+
key: 'textObserver',
49+
});
50+
const editor = createBaseEditor({
51+
plugins: [TextObserverPlugin],
52+
selection: {
53+
anchor: { offset: 5, path: [0, 0] },
54+
focus: { offset: 5, path: [0, 0] },
55+
},
56+
value: [{ children: [{ text: 'hello' }], type: 'p' }],
57+
});
58+
59+
onTextChange.mockClear();
60+
61+
editor.update.text.insert('!');
62+
63+
expect(onTextChange).toHaveBeenCalledTimes(1);
64+
expect(onTextChange.mock.calls[0]?.[0]).toMatchObject({
65+
node: {
66+
children: [{ text: 'hello!' }],
67+
type: 'p',
68+
},
69+
operation: {
70+
offset: 5,
71+
path: [0, 0],
72+
text: '!',
73+
type: 'insert_text',
74+
},
75+
prevText: 'hello',
76+
text: 'hello!',
77+
});
78+
});
79+
});
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import type { Descendant, NodeOperation, TextOperation } from '@platejs/plite';
2+
import { defineEditorExtension } from '@platejs/plite';
3+
4+
import type { BaseEditor } from '../../lib/editor';
5+
import { pipeOnNodeChange } from '../../lib/utils/pipeOnNodeChange';
6+
import { pipeOnTextChange } from '../../lib/utils/pipeOnTextChange';
7+
8+
type PlateNodeChangeCallback = (options: {
9+
editor: BaseEditor;
10+
node: Descendant;
11+
operation: NodeOperation;
12+
prevNode: Descendant;
13+
}) => void;
14+
15+
type PlateTextChangeCallback = (options: {
16+
editor: BaseEditor;
17+
node: Descendant;
18+
operation: TextOperation;
19+
prevText: string;
20+
text: string;
21+
}) => void;
22+
23+
type PlateChangeCallbacks = {
24+
onNodeChange?: PlateNodeChangeCallback | null;
25+
onTextChange?: PlateTextChangeCallback | null;
26+
};
27+
28+
const PLATE_CHANGE_CALLBACKS = new WeakMap<BaseEditor, PlateChangeCallbacks>();
29+
30+
export const setPlateChangeCallbacks = (
31+
editor: BaseEditor,
32+
callbacks: PlateChangeCallbacks
33+
) => {
34+
PLATE_CHANGE_CALLBACKS.set(editor, callbacks);
35+
};
36+
37+
const getPlateChangeCallbacks = (editor: BaseEditor): PlateChangeCallbacks =>
38+
PLATE_CHANGE_CALLBACKS.get(editor) ?? {};
39+
40+
export const createPlateChangeHandlersExtension = (editor: BaseEditor) =>
41+
defineEditorExtension({
42+
name: 'plate:change-handlers',
43+
onNodeChange({ node, operation, prevNode }) {
44+
if (
45+
editor.runtime.pluginCache.handlers.onNodeChange.length === 0 &&
46+
!getPlateChangeCallbacks(editor).onNodeChange
47+
) {
48+
return;
49+
}
50+
51+
const handled = pipeOnNodeChange(editor, node, prevNode, operation);
52+
53+
if (handled) return;
54+
55+
getPlateChangeCallbacks(editor).onNodeChange?.({
56+
editor,
57+
node,
58+
operation,
59+
prevNode,
60+
});
61+
},
62+
onTextChange({ node, operation, prevText, text }) {
63+
if (
64+
editor.runtime.pluginCache.handlers.onTextChange.length === 0 &&
65+
!getPlateChangeCallbacks(editor).onTextChange
66+
) {
67+
return;
68+
}
69+
70+
const handled = pipeOnTextChange(editor, node, text, prevText, operation);
71+
72+
if (handled) return;
73+
74+
getPlateChangeCallbacks(editor).onTextChange?.({
75+
editor,
76+
node,
77+
operation,
78+
prevText,
79+
text,
80+
});
81+
},
82+
});

packages/core/src/internal/plugin/resolveCreatePluginTest.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
import type {
2-
AnyPluginConfig,
3-
PluginConfig,
4-
} from '../../lib/plugin/SlatePlugin';
1+
import type { AnyPluginConfig } from '../../lib/plugin/SlatePlugin';
52

63
import { createBaseEditor } from '../../lib/editor';
7-
import {
8-
createBasePlugin,
9-
type CreateBasePluginInput,
10-
} from '../../lib/plugin/createBasePlugin';
4+
import { createBasePlugin } from '../../lib/plugin/createBasePlugin';
115
import { resolvePlugin } from './resolvePlugin';
126

137
export const resolvePluginTest = <P extends AnyPluginConfig>(p: P) => {
@@ -24,8 +18,10 @@ export const resolvePluginTest = <P extends AnyPluginConfig>(p: P) => {
2418
return editor.getPlugin({ key });
2519
};
2620

27-
export const resolveCreatePluginTest = ((plugin: CreateBasePluginInput) => {
28-
const p = createBasePlugin<PluginConfig>(plugin);
21+
export const resolveCreatePluginTest = ((
22+
plugin: Parameters<typeof createBasePlugin>[0]
23+
) => {
24+
const p = createBasePlugin(plugin);
2925

3026
const editor = createBaseEditor({
3127
plugins: [p],

0 commit comments

Comments
 (0)