Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .changeset/twelve-laws-press copy 2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
'@udecode/slate': patch
---

- Fix `editor.api.last(at, { level: 0 })` when editor has no children, it should return `undefined`. Fixes error on cmd+a > backspace.
- Fix `editor.tf.removeNodes` when `previousEmptyBlock` is true without `at` option, it should return early.
- Fixes #3960
- Add `RangeApi.contains` to check if a range fully contains another range (both start and end points).
- Add `editor.api.isSelected(target, { contains?: boolean })` to check if a path or range is selected by the current selection. When `contains` is true, checks if selection fully contains the target.
- `editor.tf.insertText` now support both legacy slate transforms `editor.insertText` and `Transforms.insertText`:
- `editor.insertText` -> `editor.tf.insertText` without `at` option. In addition, `marks: false` option can be used to exclude current marks. Default is `true`.
- `Transforms.insertText` -> `editor.tf.insertText` with `at` option
- Add `editor.api.next` option `from`:
- `from?: 'after' | 'child'` (default: `'after'`): Determines where to start traversing from
- `'after'`: Start from the point after the current location
- `'child'`: Start from the first child of the current path. `at` must be a path.
- Add `editor.api.previous` option `from`:
- `from?: 'before' | 'parent'` (default: `'before'`): Determines where to start traversing from
- `'before'`: Start from the point before the current location
- `'parent'`: Start from the parent of the current path. `at` must be a path.
13 changes: 13 additions & 0 deletions .changeset/twelve-laws-press copy 3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@udecode/plate-markdown': minor
---

- `editor.api.markdown.deserialize`:
- Improve support for indented lists: nested lists, mixed ordered and unordered lists
- Fix: markdown codeblock without language should not set `lang: undefined` to the node
- Add options:
- `memoize`: Enable block-level memoization with `_memo` property, so it is compatible with `PlateStatic` memoization.
- `parse`: Filter out specific markdown token types (e.g. 'space')
- `processor`: Customize the markdown processor
- Add `parseMarkdownBlocks`: Extract and filter markdown tokens using marked lexer
- Fix `editor.api.markdown.serialize` indenting should be 3 spaces instead of 2.
7 changes: 7 additions & 0 deletions .changeset/twelve-laws-press copy 4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@udecode/plate-selection': minor
---

- Fix: after deleting all blocks using block selection, focus the empty editor.
- Feature: shift+up/down block selection to expand/shrink selection. Supports nested blocks.
- Feature: up/down support nested blocks
5 changes: 5 additions & 0 deletions .changeset/twelve-laws-press copy 5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@udecode/plate-comments': patch
---

- Fix `insertComment` - it should not deselect the editor after inserting a comment.
6 changes: 6 additions & 0 deletions .changeset/twelve-laws-press copy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@udecode/plate-core': patch
---

- Fix `tf.reset` missing `options` argument. Fixes editor reset on select all > backspace using `ResetNodePlugin`.
- `PlateStatic` element and leaf rendering is now memoized with `React.memo` so you can safely update `editor.children`. For elements, it compares the `element` reference or `element._memo` value. The latter can be used to memoize based on the markdown string instead of the `element` reference. For example, `deserializeMd` with `memoize: true` will set `element._memo` for that purpose.
13 changes: 13 additions & 0 deletions .changeset/twelve-laws-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@udecode/plate-ai': minor
---

Breaking changes (experimental):

- `AIChatPlugin`: Remove `createAIEditor` option
- Fix `editor.tf.replaceSelection`:
- Improved single block selection case with full range check
- Fixed text properties inheritance when replacing selection
- In block selection mode, select the replaced blocks
- Add `useAIChatEditor`: Creates an editor, registers in the AI chat plugin, and deserializes the
content into `editor.children` with block-level memoization.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.

apps/www/src/app/api/ai

**/tsconfig.tsbuildinfo

.yarn/*
Expand Down
4 changes: 2 additions & 2 deletions apps/www/content/docs/cn/plugin-methods.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -315,13 +315,13 @@ const MyPlugin = createPlatePlugin({
transforms: {
insertText(text) {
// 自定义逻辑
console.log('Inserting:', text);
console.info('Inserting:', text);

// 调用原始方法
insertText(text);

// 后续逻辑
console.log('Inserted:', text);
console.info('Inserted:', text);
},
},
api: {
Expand Down
51 changes: 50 additions & 1 deletion apps/www/content/docs/en/ai.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ docs:

- Combobox menu with predefined commands:
- Generate: continue writing, add summary, explain
- Edit: improve writing, make it longer or shorter, fix spelling & grammar, simplify language
- Edit: improve writing, emojify, make it longer or shorter, fix spelling & grammar, simplify language
- Three trigger modes:
- Cursor mode: trigger at block end
- Selection mode: trigger with selected text
Expand Down Expand Up @@ -442,3 +442,52 @@ Special undo operation for AI changes:

- Undoes the last operation if it was AI-generated
- Removes the redo stack entry to prevent redoing AI operations

### useAIChatEditor

A hook that creates an editor for AI chat responses, registers it in the AI chat plugin, and deserializes markdown content with block-level memoization.

<APIParameters>
<APIItem name="content" type="string">
The markdown content to deserialize into the editor.
</APIItem>
<APIItem name="options" type="object" optional>
<APISubList>
<APISubListItem parent="options" name="memoize" type="boolean" optional>
Enable block-level memoization with `_memo` property. Defaults to true.
</APISubListItem>
<APISubListItem parent="options" name="parser" type="ParseMarkdownBlocksOptions" optional>
Options for the markdown token parser. Can filter out specific token types.
</APISubListItem>
<APISubListItem parent="options" name="processor" type="(processor: Processor) => Processor" optional>
Function to customize the markdown processor.
</APISubListItem>
<APISubListItem parent="options" name="...editorOptions" type="Partial<CreatePlateEditorOptions>" optional>
Additional options passed to `usePlateEditor`.
</APISubListItem>
</APISubList>
</APIItem>

<APIReturns>
<APIItem type="PlateEditor">
The configured editor instance with deserialized content.
</APIItem>
</APIReturns>

```tsx
const AIChatEditor = ({ content }: { content: string }) => {
const aiEditor = useAIChatEditor(content, {
plugins: [
// Your editor plugins
MarkdownPlugin,
// etc...
],
// Optional markdown parser options
parser: {
exclude: ['space'],
},
});

return <Editor editor={aiEditor} />;
};
```
73 changes: 73 additions & 0 deletions apps/www/content/docs/en/block-selection.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,18 @@ A set of IDs for the currently selected blocks.

- **Default:** `new Set()`
</APIItem>

<APIItem name="anchorId" type="string | null" optional>
(Internal) The ID of the anchor block in the current selection. Used for shift-based selection.

- **Default:** `null`
</APIItem>

<APIItem name="isSelectable" type="(element: TElement, path: Path) => boolean" optional>
Function to determine if a block element is selectable.

- **Default:** `() => true`
</APIItem>
</APIOptions>

### BlockMenuPlugin
Expand Down Expand Up @@ -371,3 +383,64 @@ Returns fragment prop for the currently selected blocks.
### useSelectionArea

A hook that initializes and manages the selection area functionality.

### editor.api.blockSelection.isSelectable

Checks if a block element is selectable.

<APIParameters>
<APIItem name="element" type="TElement">
The block element to check.
</APIItem>
<APIItem name="path" type="Path">
The path to the block element.
</APIItem>
</APIParameters>

<APIReturns>
<APIItem type="boolean">
Returns true if the block is selectable.
</APIItem>
</APIReturns>

### editor.api.blockSelection.moveSelection

Moves the selection up or down to the next selectable block.

<APIParameters>
<APIItem name="direction" type="'up' | 'down'">
The direction to move the selection.
</APIItem>
</APIParameters>

When moving up:
- Gets the previous selectable block from the top-most selected block
- Sets it as the new anchor
- Clears previous selection and selects only this block

When moving down:
- Gets the next selectable block from the bottom-most selected block
- Sets it as the new anchor
- Clears previous selection and selects only this block

### editor.api.blockSelection.shiftSelection

Expands or shrinks the selection based on the anchor block.

<APIParameters>
<APIItem name="direction" type="'up' | 'down'">
The direction to expand/shrink the selection.
</APIItem>
</APIParameters>

For SHIFT + DOWN:
- If anchor is top-most: Expands down by adding block below bottom-most
- Otherwise: Shrinks from top-most (unless top-most is the anchor)

For SHIFT + UP:
- If anchor is bottom-most: Expands up by adding block above top-most
- Otherwise: Shrinks from bottom-most (unless bottom-most is the anchor)

The anchor block always remains selected. If no anchor is set, it defaults to:
- Bottom-most block for SHIFT + UP
- Top-most block for SHIFT + DOWN
54 changes: 40 additions & 14 deletions apps/www/content/docs/en/components/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,36 @@ Since Plate UI is not a component library, a changelog is maintained here.

Use the [CLI](https://platejs.org/docs/components/cli) to install the latest version of the components.

## December 2024 #17
## January 2025 #18

### December 28 #17.8
### January 12 #18.2

- `export-toolbar-button`: add `katex` support
- `plate-element`: remove `relative` className
- All components using the `PlateElement` have had redundant `relative` class names removed.
### December 27 #17.7
- `ai-plugins`: remove `createAIEditor`, it's now created in `ai-chat-editor`
- `ai-chat-editor`: just use `useAIChatEditor` (v42.1)
- `ai-menu`: avoid collisions, remove `aiEditorRef`
- `command`: add `focus-visible:outline-none`
- `editor-static`: update `aiChat` padding
- `transforms`: fix `insertBlock` used by slash commands: it should insert a new block if the newly inserted block is of the same type as the command.
- `block-selection-plugins`: update `BlockSelectionPlugin`

- `fixed-toolbar-buttons`: add `font-size-toolbar-button`
- `floating-toolbar`: add `inline-equation-toolbar-button`
- `turn-into-dropdown-menu`: Fix: after turn into other block, the editor should regain focus.
- `insert-dropdown-menu`: add `inline equation` and `equation` & fix the focus issue
- `slash-input-element`: add `equation` and `inline equation`

### December 25 #17.6
```tsx
BlockSelectionPlugin.configure(({ editor }) => ({
options: {
enableContextMenu: true,
isSelectable: (element, path) => {
return (
!['code_line', 'column', 'td'].includes(element.type) &&
!editor.api.block({ above: true, at: path, match: { type: 'tr' } })
);
},
},
}))
```

v42

### January 8 #18.1

- v42 migration
- `table-element`, `table-element-static`
- Move icons to `table-icons`
- Remove `colgroup`, col width is now set in `table-cell-element`
Expand All @@ -44,6 +55,21 @@ v42
- `table-dropdown-menu`: new insert table interface.
- `column-group-element`: fix `ColumnFloatingToolbar` onColumnChange

## December 2024 #17

### December 28 #17.8

- `export-toolbar-button`: add `katex` support
- `plate-element`: remove `relative` className
- All components using the `PlateElement` have had redundant `relative` class names removed.
### December 27 #17.7

- `fixed-toolbar-buttons`: add `font-size-toolbar-button`
- `floating-toolbar`: add `inline-equation-toolbar-button`
- `turn-into-dropdown-menu`: Fix: after turn into other block, the editor should regain focus.
- `insert-dropdown-menu`: add `inline equation` and `equation` & fix the focus issue
- `slash-input-element`: add `equation` and `inline equation`

### December 23 #17.5

- `table-element`: fix selection
Expand Down
40 changes: 40 additions & 0 deletions apps/www/content/docs/en/markdown.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const value = editor.api.markdown.deserialize('**Hello world!**');
### Slate to Markdown

Currently supported plugins: paragraph, link, list, heading, italic, bold and code.
List indentation uses 3 spaces instead of 2.

```tsx
const editor = createPlateEditor({
Expand Down Expand Up @@ -114,6 +115,19 @@ Converts a Markdown string to a Slate value.
<APIItem name="markdown" type="string">
The Markdown string to be deserialized.
</APIItem>
<APIItem name="options" type="DeserializeMdOptions" optional>
<APISubList>
<APISubListItem parent="options" name="memoize" type="boolean" optional>
Enable block-level memoization with `_memo` property, making it compatible with `PlateStatic` memoization.
</APISubListItem>
<APISubListItem parent="options" name="parser" type="ParseMarkdownBlocksOptions" optional>
Options for the token parser. Can filter out specific markdown token types (e.g. 'space').
</APISubListItem>
<APISubListItem parent="options" name="processor" type="(processor: Processor) => Processor" optional>
A function that allows you to customize the markdown processor.
</APISubListItem>
</APISubList>
</APIItem>
</APIParameters>

<APIReturns>
Expand All @@ -140,4 +154,30 @@ The Slate nodes to serialize. If not provided, the entire editor value will be u
<APIItem type="string">
A Markdown string representing the serialized Slate content.
</APIItem>
</APIReturns>

### parseMarkdownBlocks

Extracts and filters markdown tokens using marked lexer.

<APIParameters>
<APIItem name="markdown" type="string">
The Markdown string to parse into tokens.
</APIItem>
<APIItem name="options" type="ParseMarkdownBlocksOptions" optional>
<APISubList>
<APISubListItem parent="options" name="exclude" type="string[]" optional>
Array of token types to exclude (e.g. ['space', 'hr']).
</APISubListItem>
<APISubListItem parent="options" name="trim" type="boolean" optional>
Whether to trim end of the content. Defaults to true.
</APISubListItem>
</APISubList>
</APIItem>
</APIParameters>

<APIReturns>
<APIItem type="Token[]">
An array of markdown tokens.
</APIItem>
</APIReturns>
4 changes: 2 additions & 2 deletions apps/www/content/docs/en/plugin.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,13 @@ const CustomPlugin = createPlatePlugin({
transforms: {
deleteForward(options) {
// Custom logic before deletion
console.log('Deleting forward...');
console.info('Deleting forward...');

// Call original transform
deleteForward(options);

// Custom logic after deletion
console.log('Deleted forward');
console.info('Deleted forward');
},
},
// Override API methods
Expand Down
2 changes: 1 addition & 1 deletion apps/www/public/r/styles/default/ai-demo.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"type": "registry:example"
},
{
"content": "import { jsx } from '@udecode/plate-test-utils';\n\njsx;\n\nexport const aiValue: any = (\n <fragment>\n <hh2>AI Menu</hh2>\n <hp>Generate and refine content with AI.</hp>\n <hp>Access the AI menu in many ways:</hp>\n <hp indent={1} listStyleType=\"decimal\">\n <htext>Press \"⌘ + J\".</htext>\n </hp>\n <hp indent={1} listStart={2} listStyleType=\"decimal\">\n <htext>Select text and click \"Ask AI\" in the floating toolbar</htext>\n </hp>\n <hp indent={1} listStart={3} listStyleType=\"decimal\">\n <htext>Right-click a block and select \"Ask AI\"</htext>\n </hp>\n <hp indent={1} listStart={4} listStyleType=\"decimal\">\n <htext>Press space in an empty block. Try it out:</htext>\n </hp>\n <hp indent={2} listStyleType=\"disc\">\n <htext />\n </hp>\n <hp>Once opened, you can:</hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Search commands in the input field:</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Use arrow keys to navigate, Enter to select</htext>\n </hp>\n <hp>\n <htext>Generating commands:</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Continue writing</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Add a summary</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Explain</htext>\n </hp>\n <hp>\n <htext>Generating suggestions:</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Accept</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Discard</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Try again</htext>\n </hp>\n <hp>\n <htext>Editing commands:</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Improve writing</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Make it longer or shorter</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Fix spelling & grammar</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Simplify language</htext>\n </hp>\n <hp>Editing suggestions:</hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Replace the selection</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Insert below</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Discard</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Try again</htext>\n </hp>\n <hp>\n <htext>Note: chat history is preserved until the menu is closed.</htext>\n </hp>\n </fragment>\n);\n",
"content": "import { jsx } from '@udecode/plate-test-utils';\n\njsx;\n\nexport const aiValue: any = (\n <fragment>\n <hh2>AI Menu</hh2>\n <hp>Generate and refine content with AI.</hp>\n <hp>Access the AI menu in many ways:</hp>\n <hp indent={1} listStyleType=\"decimal\">\n <htext>Press \"⌘ + J\".</htext>\n </hp>\n <hp indent={1} listStart={2} listStyleType=\"decimal\">\n <htext>Select text and click \"Ask AI\" in the floating toolbar</htext>\n </hp>\n <hp indent={1} listStart={3} listStyleType=\"decimal\">\n <htext>Right-click a block and select \"Ask AI\"</htext>\n </hp>\n <hp indent={1} listStart={4} listStyleType=\"decimal\">\n <htext>Press space in an empty block. Try it out:</htext>\n </hp>\n <hp indent={2} listStyleType=\"disc\">\n <htext />\n </hp>\n <hp>Once opened, you can:</hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Search commands in the input field:</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Use arrow keys to navigate, Enter to select</htext>\n </hp>\n <hp>\n <htext>Generating commands:</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Continue writing</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Add a summary</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Explain</htext>\n </hp>\n <hp>\n <htext>Generating suggestions:</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Accept</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Discard</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Try again</htext>\n </hp>\n <hp>\n <htext>Editing commands:</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Improve writing</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Emojify</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Make it longer or shorter</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Fix spelling & grammar</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Simplify language</htext>\n </hp>\n <hp>Editing suggestions:</hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Replace the selection</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Insert below</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Discard</htext>\n </hp>\n <hp indent={1} listStyleType=\"disc\">\n <htext>Try again</htext>\n </hp>\n <hp>\n <htext>Note: chat history is preserved until the menu is closed.</htext>\n </hp>\n </fragment>\n);\n",
"path": "example/values/ai-value.tsx",
"target": "components/ai-value.tsx",
"type": "registry:example"
Expand Down
Loading
Loading