diff --git a/apps/www/package.json b/apps/www/package.json index 9eae9f0fd9..ded08ae726 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -82,6 +82,7 @@ "@udecode/plate-line-height": "workspace:^", "@udecode/plate-link": "workspace:^", "@udecode/plate-list": "workspace:^", + "@udecode/plate-marks-affinity": "workspace:^", "@udecode/plate-media": "workspace:^", "@udecode/plate-mention": "workspace:^", "@udecode/plate-node-id": "workspace:^", diff --git a/apps/www/src/registry/default/example/playground-demo.tsx b/apps/www/src/registry/default/example/playground-demo.tsx index 63ddbd822c..3ba32f0c13 100644 --- a/apps/www/src/registry/default/example/playground-demo.tsx +++ b/apps/www/src/registry/default/example/playground-demo.tsx @@ -33,6 +33,10 @@ import { createSubscriptPlugin, createSuperscriptPlugin, createUnderlinePlugin, + MARK_BOLD, + MARK_ITALIC, + MARK_STRIKETHROUGH, + MARK_UNDERLINE, } from '@udecode/plate-basic-marks'; import { createBlockquotePlugin, @@ -49,7 +53,7 @@ import { ELEMENT_CODE_BLOCK, } from '@udecode/plate-code-block'; import { createComboboxPlugin } from '@udecode/plate-combobox'; -import { createCommentsPlugin } from '@udecode/plate-comments'; +import { createCommentsPlugin, MARK_COMMENT } from '@udecode/plate-comments'; import { createPlugins, Plate, @@ -63,6 +67,11 @@ import { createFontBackgroundColorPlugin, createFontColorPlugin, createFontSizePlugin, + MARK_BG_COLOR, + MARK_COLOR, + MARK_FONT_FAMILY, + MARK_FONT_SIZE, + MARK_FONT_WEIGHT, } from '@udecode/plate-font'; import { createHeadingPlugin, @@ -83,6 +92,7 @@ import { createColumnPlugin } from '@udecode/plate-layout'; import { createLineHeightPlugin } from '@udecode/plate-line-height'; import { createLinkPlugin } from '@udecode/plate-link'; import { createListPlugin, createTodoListPlugin } from '@udecode/plate-list'; +import { createMarkAffinityPlugin } from '@udecode/plate-marks-affinity'; import { createImagePlugin, createMediaEmbedPlugin, @@ -191,6 +201,22 @@ export const usePlaygroundPlugins = ({ createItalicPlugin({ enabled: !!enabled.italic }), createUnderlinePlugin({ enabled: !!enabled.underline }), createStrikethroughPlugin({ enabled: !!enabled.strikethrough }), + createMarkAffinityPlugin({ + options: { + validMarks: [ + MARK_BG_COLOR, + MARK_BOLD, + MARK_COLOR, + MARK_UNDERLINE, + MARK_FONT_FAMILY, + MARK_FONT_SIZE, + MARK_FONT_WEIGHT, + MARK_ITALIC, + MARK_STRIKETHROUGH, + MARK_COMMENT, + ], + }, + }), createCodePlugin({ enabled: !!enabled.code }), createSubscriptPlugin({ enabled: !!enabled.subscript }), createSuperscriptPlugin({ enabled: !!enabled.superscript }), diff --git a/packages/mark-affinity/.npmignore b/packages/mark-affinity/.npmignore new file mode 100644 index 0000000000..7d3b305b17 --- /dev/null +++ b/packages/mark-affinity/.npmignore @@ -0,0 +1,3 @@ +__tests__ +__test-utils__ +__mocks__ diff --git a/packages/mark-affinity/README.md b/packages/mark-affinity/README.md new file mode 100644 index 0000000000..2dd18ce2ab --- /dev/null +++ b/packages/mark-affinity/README.md @@ -0,0 +1,15 @@ +# Plate marks affinity plugins + +This package implements the following futures: +For example, if the editor has "boldn|ormal" and the user presses the left arrow key or +backspace and then types, the resulting text will not be bold. If the editor has "bol|dnormal" +and the user presses the right arrow key and types, the resulting text will be bold. + +## Documentation + +Check out +[Basic Marks](https://platejs.org/docs/basic-marks-affinity). + +## License + +[MIT](../../LICENSE) diff --git a/packages/mark-affinity/package.json b/packages/mark-affinity/package.json new file mode 100644 index 0000000000..536500d636 --- /dev/null +++ b/packages/mark-affinity/package.json @@ -0,0 +1,63 @@ +{ + "name": "@udecode/plate-marks-affinity", + "version": "31.0.0", + "description": "marks affinity plugin for Plate", + "license": "MIT", + "homepage": "https://platejs.org", + "repository": { + "type": "git", + "url": "https://github.com/udecode/plate.git" + }, + "bugs": { + "url": "https://github.com/udecode/plate/issues" + }, + "sideEffects": false, + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "files": [ + "dist/**/*" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "module": "./dist/index.mjs", + "require": "./dist/index.js" + } + }, + "scripts": { + "build": "yarn p:build", + "build:watch": "yarn p:build:watch", + "brl": "yarn p:brl", + "clean": "yarn p:clean", + "lint": "yarn p:lint", + "lint:fix": "yarn p:lint:fix", + "test": "yarn p:test", + "test:watch": "yarn p:test:watch", + "typecheck": "yarn p:typecheck" + }, + "dependencies": { + "lodash": "^4.17.21" + }, + "devDependencies": { + "@udecode/plate-common": "workspace:^" + }, + "peerDependencies": { + "@udecode/plate-common": ">=31.3.2", + "react": ">=16.8.0", + "react-dom": ">=16.8.0", + "slate": ">=0.94.0", + "slate-history": ">=0.93.0", + "slate-hyperscript": ">=0.66.0", + "slate-react": ">=0.99.0" + }, + "keywords": [ + "plate", + "plugin", + "slate" + ], + "publishConfig": { + "access": "public" + } +} diff --git a/packages/mark-affinity/src/createMarkAffinityPlugin.ts b/packages/mark-affinity/src/createMarkAffinityPlugin.ts new file mode 100644 index 0000000000..e2d684ee7f --- /dev/null +++ b/packages/mark-affinity/src/createMarkAffinityPlugin.ts @@ -0,0 +1,13 @@ +import { createPluginFactory } from '@udecode/plate-common'; + +import { MarkAffinityPlugin } from './types'; +import { withMarkAffinity } from './withMarkAffinity'; + +export const KEY_MARK_AFFINITY = 'mark-affinity'; + +export const createMarkAffinityPlugin = createPluginFactory( + { + key: KEY_MARK_AFFINITY, + withOverrides: withMarkAffinity, + } +); diff --git a/packages/mark-affinity/src/index.ts b/packages/mark-affinity/src/index.ts new file mode 100644 index 0000000000..6eb6f4ba5e --- /dev/null +++ b/packages/mark-affinity/src/index.ts @@ -0,0 +1,9 @@ +/** + * @file Automatically generated by barrelsby. + */ + +export * from './createMarkAffinityPlugin'; +export * from './types'; +export * from './withMarkAffinity'; +export * from './queries/index'; +export * from './transforms/index'; diff --git a/packages/mark-affinity/src/queries/getMarkBoundary.ts b/packages/mark-affinity/src/queries/getMarkBoundary.ts new file mode 100644 index 0000000000..022279da0d --- /dev/null +++ b/packages/mark-affinity/src/queries/getMarkBoundary.ts @@ -0,0 +1,53 @@ +import { + getNodeEntry, + getRange, + isEndPoint, + isSelectionExpanded, + isStartPoint, + isText, + PlateEditor, + TText, +} from '@udecode/plate-common'; +import { NodeEntry, Path } from 'slate'; + +import { MarkBoundary } from '../types'; + +export const getMarkBoundary = (editor: PlateEditor): MarkBoundary | null => { + const { selection } = editor; + if (!selection || isSelectionExpanded(editor)) return null; + const point = selection.anchor; + + const selectedLeafRange = getRange(editor, point.path); + + const direction = (() => { + if (isStartPoint(editor, point, selectedLeafRange)) { + return 'backward'; + } + + if (isEndPoint(editor, point, selectedLeafRange)) { + return 'forward'; + } + + return null; + })(); + + if (!direction) return null; + + const currentLeafEntry = getNodeEntry(editor, point.path)!; + + if (direction === 'backward' && point.path.at(-1) === 0) + return [null, currentLeafEntry]; + + const adjacentPathFn = direction === 'forward' ? Path.next : Path.previous; + const adjacentPath = adjacentPathFn(point.path); + const adjacentNode = getNodeEntry(editor, adjacentPath) ?? null; + + const adjacentLeafEntry = + adjacentNode && isText(adjacentNode[0]) + ? (adjacentNode as NodeEntry) + : null; + + return direction === 'forward' + ? [currentLeafEntry, adjacentLeafEntry] + : [adjacentLeafEntry, currentLeafEntry]; +}; diff --git a/packages/mark-affinity/src/queries/getMarkBoundaryAffinity.ts b/packages/mark-affinity/src/queries/getMarkBoundaryAffinity.ts new file mode 100644 index 0000000000..459af0129f --- /dev/null +++ b/packages/mark-affinity/src/queries/getMarkBoundaryAffinity.ts @@ -0,0 +1,54 @@ +import { + getNodeProps, + IS_FIREFOX, + PlateEditor, + TText, +} from '@udecode/plate-common'; +import isEqual from 'lodash/isEqual'; + +import { MarkBoundary } from '../types'; + +export const getMarkBoundaryAffinity = ( + editor: PlateEditor, + markBoundary: MarkBoundary +): 'forward' | 'backward' | 'new-mark' => { + const { marks, selection } = editor; + if (!selection) return 'new-mark'; + const marksMatchLeaf = (leaf: TText) => + marks && isEqual(getNodeProps(leaf), marks); + const [backwardLeafEntry, forwardLeafEntry] = markBoundary; + + if (!backwardLeafEntry || !forwardLeafEntry) { + const leafEntry = backwardLeafEntry || forwardLeafEntry; + const affinityIsTowardsLeaf = !marks || marksMatchLeaf(leafEntry[0]); + if (affinityIsTowardsLeaf) { + return leafEntry === backwardLeafEntry ? 'backward' : 'forward'; + } + return 'new-mark'; + } + + const marksDirection: 'forward' | 'backward' | null = + marks && + (() => { + if (backwardLeafEntry && marksMatchLeaf(backwardLeafEntry[0])) + return 'backward'; + if (forwardLeafEntry && marksMatchLeaf(forwardLeafEntry[0])) + return 'forward'; + return null; + })(); + + const selectionDirection = + selection.anchor.offset === 0 ? 'forward' : 'backward'; + + if (selectionDirection === 'backward' && marksDirection === 'forward') + return 'forward'; + + if ( + IS_FIREFOX && + selectionDirection === 'forward' && + marksDirection !== 'backward' + ) + return 'forward'; + + return 'backward'; +}; diff --git a/packages/mark-affinity/src/queries/index.ts b/packages/mark-affinity/src/queries/index.ts new file mode 100644 index 0000000000..95ad6c2bd2 --- /dev/null +++ b/packages/mark-affinity/src/queries/index.ts @@ -0,0 +1,6 @@ +/** + * @file Automatically generated by barrelsby. + */ + +export * from './getMarkBoundary'; +export * from './getMarkBoundaryAffinity'; diff --git a/packages/mark-affinity/src/transforms/index.ts b/packages/mark-affinity/src/transforms/index.ts new file mode 100644 index 0000000000..cc9ffc3ed9 --- /dev/null +++ b/packages/mark-affinity/src/transforms/index.ts @@ -0,0 +1,5 @@ +/** + * @file Automatically generated by barrelsby. + */ + +export * from './setMarkBoundaryAffinity'; diff --git a/packages/mark-affinity/src/transforms/setMarkBoundaryAffinity.ts b/packages/mark-affinity/src/transforms/setMarkBoundaryAffinity.ts new file mode 100644 index 0000000000..c0b433ed25 --- /dev/null +++ b/packages/mark-affinity/src/transforms/setMarkBoundaryAffinity.ts @@ -0,0 +1,35 @@ +import { getEndPoint, getNodeProps, PlateEditor } from '@udecode/plate-common'; +import { Point } from 'slate'; + +import { MarkBoundary } from '../types'; + +export const setMarkBoundaryAffinity = ( + editor: PlateEditor, + markBoundary: MarkBoundary, + affinity: 'forward' | 'backward' +) => { + const setMarks = (marks: typeof editor.marks) => { + editor.marks = marks; + editor.onChange(); + }; + + const selectPoint = (point: Point) => { + editor.setSelection({ anchor: point, focus: point }); + }; + if (affinity === 'backward') { + const [backwardLeafEntry] = markBoundary; + if (backwardLeafEntry === null) return setMarks(null); + const endOfBackward = getEndPoint(editor, backwardLeafEntry[1]); + selectPoint(endOfBackward); + setMarks(null); + return; + } + + const [backwardLeafEntry, forwardLeafEntry] = markBoundary; + if (backwardLeafEntry === null) return setMarks(null); + if (forwardLeafEntry === null) return setMarks({}); + + const endOfBackward = getEndPoint(editor, backwardLeafEntry[1]); + selectPoint(endOfBackward); + setMarks(getNodeProps(forwardLeafEntry[0])); +}; diff --git a/packages/mark-affinity/src/types.ts b/packages/mark-affinity/src/types.ts new file mode 100644 index 0000000000..11262bc3be --- /dev/null +++ b/packages/mark-affinity/src/types.ts @@ -0,0 +1,11 @@ +import { TText } from '@udecode/plate-common'; +import { NodeEntry } from 'slate'; + +export interface MarkAffinityPlugin { + validMarks?: string[]; +} + +export type MarkBoundary = + | [NodeEntry, NodeEntry] + | [NodeEntry, null] + | [null, NodeEntry]; diff --git a/packages/mark-affinity/src/withMarkAffinity.ts b/packages/mark-affinity/src/withMarkAffinity.ts new file mode 100644 index 0000000000..3683c582d4 --- /dev/null +++ b/packages/mark-affinity/src/withMarkAffinity.ts @@ -0,0 +1,118 @@ +import { + getMarks, + getPluginOptions, + isSelectionExpanded, + PlateEditor, +} from '@udecode/plate-common'; + +import { KEY_MARK_AFFINITY } from './createMarkAffinityPlugin'; +import { getMarkBoundary } from './queries/getMarkBoundary'; +import { getMarkBoundaryAffinity } from './queries/getMarkBoundaryAffinity'; +import { setMarkBoundaryAffinity } from './transforms/setMarkBoundaryAffinity'; +import { MarkAffinityPlugin } from './types'; + +export const withMarkAffinity = (editor: PlateEditor) => { + const { deleteBackward, move } = editor; + + /** + * On backspace, if the deletion results in the cursor being at a mark + * boundary, then the affinity should be forward. If the deletion removes + * a character from the left mark, then the affinity should be backward. + */ + editor.deleteBackward = (unit) => { + if ( + unit === 'character' && + editor.selection && + !isSelectionExpanded(editor) + ) { + const [leftMarkEntryBefore] = getMarkBoundary(editor) ?? [null]; + const removingFromLeftMark = + leftMarkEntryBefore && leftMarkEntryBefore[0].text.length > 1; + + deleteBackward(unit); + + const afterMarkBoundary = getMarkBoundary(editor); + + if (afterMarkBoundary) { + setMarkBoundaryAffinity( + editor, + afterMarkBoundary, + removingFromLeftMark ? 'backward' : 'forward' + ); + } + return; + } + + deleteBackward(unit); + }; + + editor.move = (options) => { + const { unit = 'character', distance = 1, reverse = false } = options || {}; + if ( + unit === 'character' && + distance === 1 && + editor.selection && + !isSelectionExpanded(editor) + ) { + /** + * check the validMarks exclude the marks which have padding like `MARK_CODE` + */ + const { validMarks } = getPluginOptions( + editor, + KEY_MARK_AFFINITY + ); + const _marks = getMarks(editor); + const marks = _marks ? Object.keys(_marks) : []; + + //TODO: note the comment_x + if (!validMarks) return move(options); + if (marks.length > 0) { + for (const mark of marks) { + if (!validMarks.includes(mark)) return move(options); + } + } + + const beforeMarkBoundary = getMarkBoundary(editor); + + /** + * If the cursor is at the start or end of a list of text nodes + * then moving outside the mark should set the + * affinity accordingly. + */ + if ( + beforeMarkBoundary && + beforeMarkBoundary[reverse ? 0 : 1] === null && + getMarkBoundaryAffinity(editor, beforeMarkBoundary) === + (reverse ? 'forward' : 'backward') + ) { + setMarkBoundaryAffinity( + editor, + beforeMarkBoundary, + reverse ? 'backward' : 'forward' + ); + return; + } + + move(options); + + const afterMarkBoundary = getMarkBoundary(editor); + + /** + * If the move places the cursor at a mark boundary, then the affinity + * should be set to the direction the cursor came from. + */ + if (afterMarkBoundary) { + setMarkBoundaryAffinity( + editor, + afterMarkBoundary, + reverse ? 'forward' : 'backward' + ); + } + return; + } + + move(options); + }; + + return editor; +}; diff --git a/packages/mark-affinity/tsconfig.json b/packages/mark-affinity/tsconfig.json new file mode 100644 index 0000000000..0db2a27277 --- /dev/null +++ b/packages/mark-affinity/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../config/tsconfig.build.json", + "compilerOptions": { + "declarationDir": "./dist", + "outDir": "./dist" + }, + "include": [ + "src" + ] +} diff --git a/packages/utils/src/environment.ts b/packages/utils/src/environment.ts index 3f8433153e..2ee95ae332 100644 --- a/packages/utils/src/environment.ts +++ b/packages/utils/src/environment.ts @@ -1,2 +1,5 @@ export const IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent); + +export const IS_FIREFOX = + typeof navigator !== 'undefined' && /Firefox/.test(navigator.userAgent); diff --git a/yarn.lock b/yarn.lock index 9068ba5417..81e1cb55a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5901,7 +5901,7 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-indent-list@npm:31.2.2, @udecode/plate-indent-list@workspace:^, @udecode/plate-indent-list@workspace:packages/indent-list": +"@udecode/plate-indent-list@npm:31.4.0, @udecode/plate-indent-list@workspace:^, @udecode/plate-indent-list@workspace:packages/indent-list": version: 0.0.0-use.local resolution: "@udecode/plate-indent-list@workspace:packages/indent-list" dependencies: @@ -6037,6 +6037,23 @@ __metadata: languageName: unknown linkType: soft +"@udecode/plate-marks-affinity@workspace:^, @udecode/plate-marks-affinity@workspace:packages/mark-affinity": + version: 0.0.0-use.local + resolution: "@udecode/plate-marks-affinity@workspace:packages/mark-affinity" + dependencies: + "@udecode/plate-common": "workspace:^" + lodash: "npm:^4.17.21" + peerDependencies: + "@udecode/plate-common": ">=31.3.2" + react: ">=16.8.0" + react-dom: ">=16.8.0" + slate: ">=0.94.0" + slate-history: ">=0.93.0" + slate-hyperscript: ">=0.66.0" + slate-react: ">=0.99.0" + languageName: unknown + linkType: soft + "@udecode/plate-media@npm:31.0.0, @udecode/plate-media@workspace:^, @udecode/plate-media@workspace:packages/media": version: 0.0.0-use.local resolution: "@udecode/plate-media@workspace:packages/media" @@ -6187,13 +6204,13 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-serializer-csv@npm:31.3.3, @udecode/plate-serializer-csv@workspace:^, @udecode/plate-serializer-csv@workspace:packages/serializer-csv": +"@udecode/plate-serializer-csv@npm:31.4.0, @udecode/plate-serializer-csv@workspace:^, @udecode/plate-serializer-csv@workspace:packages/serializer-csv": version: 0.0.0-use.local resolution: "@udecode/plate-serializer-csv@workspace:packages/serializer-csv" dependencies: "@types/papaparse": "npm:^5.3.14" "@udecode/plate-common": "workspace:^" - "@udecode/plate-table": "npm:31.3.3" + "@udecode/plate-table": "npm:31.4.0" papaparse: "npm:^5.4.1" peerDependencies: "@udecode/plate-common": ">=31.3.2" @@ -6206,17 +6223,17 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-serializer-docx@npm:31.3.3, @udecode/plate-serializer-docx@workspace:^, @udecode/plate-serializer-docx@workspace:packages/serializer-docx": +"@udecode/plate-serializer-docx@npm:31.4.0, @udecode/plate-serializer-docx@workspace:^, @udecode/plate-serializer-docx@workspace:packages/serializer-docx": version: 0.0.0-use.local resolution: "@udecode/plate-serializer-docx@workspace:packages/serializer-docx" dependencies: "@udecode/plate-common": "workspace:^" "@udecode/plate-heading": "npm:31.0.0" "@udecode/plate-indent": "npm:31.1.0" - "@udecode/plate-indent-list": "npm:31.2.2" + "@udecode/plate-indent-list": "npm:31.4.0" "@udecode/plate-media": "npm:31.0.0" "@udecode/plate-paragraph": "npm:31.0.0" - "@udecode/plate-table": "npm:31.3.3" + "@udecode/plate-table": "npm:31.4.0" validator: "npm:^13.11.0" peerDependencies: "@udecode/plate-common": ">=31.3.2" @@ -6247,7 +6264,7 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-serializer-md@npm:31.3.4, @udecode/plate-serializer-md@workspace:^, @udecode/plate-serializer-md@workspace:packages/serializer-md": +"@udecode/plate-serializer-md@npm:31.4.0, @udecode/plate-serializer-md@workspace:^, @udecode/plate-serializer-md@workspace:packages/serializer-md": version: 0.0.0-use.local resolution: "@udecode/plate-serializer-md@workspace:packages/serializer-md" dependencies: @@ -6309,7 +6326,7 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-table@npm:31.3.3, @udecode/plate-table@workspace:^, @udecode/plate-table@workspace:packages/table": +"@udecode/plate-table@npm:31.4.0, @udecode/plate-table@workspace:^, @udecode/plate-table@workspace:packages/table": version: 0.0.0-use.local resolution: "@udecode/plate-table@workspace:packages/table" dependencies: @@ -6335,7 +6352,7 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-toggle@npm:31.1.0, @udecode/plate-toggle@workspace:^, @udecode/plate-toggle@workspace:packages/toggle": +"@udecode/plate-toggle@npm:31.4.0, @udecode/plate-toggle@workspace:^, @udecode/plate-toggle@workspace:packages/toggle": version: 0.0.0-use.local resolution: "@udecode/plate-toggle@workspace:packages/toggle" dependencies: @@ -6464,7 +6481,7 @@ __metadata: "@udecode/plate-highlight": "npm:31.0.0" "@udecode/plate-horizontal-rule": "npm:31.0.0" "@udecode/plate-indent": "npm:31.1.0" - "@udecode/plate-indent-list": "npm:31.2.2" + "@udecode/plate-indent-list": "npm:31.4.0" "@udecode/plate-kbd": "npm:31.0.0" "@udecode/plate-line-height": "npm:31.0.0" "@udecode/plate-link": "npm:31.0.0" @@ -6477,14 +6494,14 @@ __metadata: "@udecode/plate-reset-node": "npm:31.0.0" "@udecode/plate-resizable": "npm:31.0.0" "@udecode/plate-select": "npm:31.0.0" - "@udecode/plate-serializer-csv": "npm:31.3.3" - "@udecode/plate-serializer-docx": "npm:31.3.3" + "@udecode/plate-serializer-csv": "npm:31.4.0" + "@udecode/plate-serializer-docx": "npm:31.4.0" "@udecode/plate-serializer-html": "npm:31.1.0" - "@udecode/plate-serializer-md": "npm:31.3.4" + "@udecode/plate-serializer-md": "npm:31.4.0" "@udecode/plate-suggestion": "npm:31.0.0" "@udecode/plate-tabbable": "npm:31.0.0" - "@udecode/plate-table": "npm:31.3.3" - "@udecode/plate-toggle": "npm:31.1.0" + "@udecode/plate-table": "npm:31.4.0" + "@udecode/plate-toggle": "npm:31.4.0" "@udecode/plate-trailing-block": "npm:31.0.0" peerDependencies: react: ">=16.8.0" @@ -21340,6 +21357,7 @@ __metadata: "@udecode/plate-line-height": "workspace:^" "@udecode/plate-link": "workspace:^" "@udecode/plate-list": "workspace:^" + "@udecode/plate-marks-affinity": "workspace:^" "@udecode/plate-media": "workspace:^" "@udecode/plate-mention": "workspace:^" "@udecode/plate-node-id": "workspace:^"