mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-26 09:16:22 +02:00
feat: add new autoformat and drag-and-drop functionality to the editor, refactor list handling and update dependencies
This commit is contained in:
parent
1450e22f54
commit
93a0487e56
14 changed files with 972 additions and 321 deletions
|
|
@ -1,7 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import type { AutoformatBlockRule, AutoformatRule } from '@platejs/autoformat';
|
||||
import type { SlateEditor } from 'platejs';
|
||||
import type { AutoformatRule } from '@platejs/autoformat';
|
||||
|
||||
import {
|
||||
autoformatArrow,
|
||||
|
|
@ -13,38 +12,9 @@ import {
|
|||
autoformatSmartQuotes,
|
||||
} from '@platejs/autoformat';
|
||||
import { insertEmptyCodeBlock } from '@platejs/code-block';
|
||||
import { toggleList, toggleTaskList, unwrapList } from '@platejs/list-classic';
|
||||
import { toggleList } from '@platejs/list';
|
||||
import { openNextToggles } from '@platejs/toggle/react';
|
||||
import { ElementApi, isType, KEYS } from 'platejs';
|
||||
|
||||
const preFormat: AutoformatBlockRule['preFormat'] = (editor) =>
|
||||
unwrapList(editor);
|
||||
|
||||
const format = (editor: SlateEditor, customFormatting: any) => {
|
||||
if (editor.selection) {
|
||||
const parentEntry = editor.api.parent(editor.selection);
|
||||
|
||||
if (!parentEntry) return;
|
||||
|
||||
const [node] = parentEntry;
|
||||
|
||||
if (ElementApi.isElement(node) && !isType(editor, node, KEYS.codeBlock)) {
|
||||
customFormatting();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const formatTaskList = (editor: SlateEditor, defaultChecked = false) => {
|
||||
format(editor, () => toggleTaskList(editor, defaultChecked));
|
||||
};
|
||||
|
||||
const formatList = (editor: SlateEditor, elementType: string) => {
|
||||
format(editor, () =>
|
||||
toggleList(editor, {
|
||||
type: elementType,
|
||||
})
|
||||
);
|
||||
};
|
||||
import { KEYS } from 'platejs';
|
||||
|
||||
const autoformatMarks: AutoformatRule[] = [
|
||||
{
|
||||
|
|
@ -123,49 +93,41 @@ const autoformatBlocks: AutoformatRule[] = [
|
|||
{
|
||||
match: '# ',
|
||||
mode: 'block',
|
||||
preFormat,
|
||||
type: KEYS.h1,
|
||||
},
|
||||
{
|
||||
match: '## ',
|
||||
mode: 'block',
|
||||
preFormat,
|
||||
type: KEYS.h2,
|
||||
},
|
||||
{
|
||||
match: '### ',
|
||||
mode: 'block',
|
||||
preFormat,
|
||||
type: KEYS.h3,
|
||||
},
|
||||
{
|
||||
match: '#### ',
|
||||
mode: 'block',
|
||||
preFormat,
|
||||
type: KEYS.h4,
|
||||
},
|
||||
{
|
||||
match: '##### ',
|
||||
mode: 'block',
|
||||
preFormat,
|
||||
type: KEYS.h5,
|
||||
},
|
||||
{
|
||||
match: '###### ',
|
||||
mode: 'block',
|
||||
preFormat,
|
||||
type: KEYS.h6,
|
||||
},
|
||||
{
|
||||
match: '> ',
|
||||
mode: 'block',
|
||||
preFormat,
|
||||
type: KEYS.blockquote,
|
||||
},
|
||||
{
|
||||
match: '```',
|
||||
mode: 'block',
|
||||
preFormat,
|
||||
type: KEYS.codeBlock,
|
||||
format: (editor) => {
|
||||
insertEmptyCodeBlock(editor, {
|
||||
|
|
@ -198,29 +160,52 @@ const autoformatLists: AutoformatRule[] = [
|
|||
{
|
||||
match: ['* ', '- '],
|
||||
mode: 'block',
|
||||
preFormat,
|
||||
type: KEYS.li,
|
||||
format: (editor) => formatList(editor, KEYS.ulClassic),
|
||||
type: 'list',
|
||||
format: (editor) => {
|
||||
toggleList(editor, {
|
||||
listStyleType: KEYS.ul,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
match: [String.raw`^\d+\.$ `, String.raw`^\d+\)$ `],
|
||||
matchByRegex: true,
|
||||
mode: 'block',
|
||||
preFormat,
|
||||
type: KEYS.li,
|
||||
format: (editor) => formatList(editor, KEYS.olClassic),
|
||||
type: 'list',
|
||||
format: (editor, { matchString }) => {
|
||||
toggleList(editor, {
|
||||
listRestartPolite: Number(matchString) || 1,
|
||||
listStyleType: KEYS.ol,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
match: '[] ',
|
||||
match: ['[] '],
|
||||
mode: 'block',
|
||||
type: KEYS.taskList,
|
||||
format: (editor) => formatTaskList(editor, false),
|
||||
type: 'list',
|
||||
format: (editor) => {
|
||||
toggleList(editor, {
|
||||
listStyleType: KEYS.listTodo,
|
||||
});
|
||||
editor.tf.setNodes({
|
||||
checked: false,
|
||||
listStyleType: KEYS.listTodo,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
match: '[x] ',
|
||||
match: ['[x] '],
|
||||
mode: 'block',
|
||||
type: KEYS.taskList,
|
||||
format: (editor) => formatTaskList(editor, true),
|
||||
type: 'list',
|
||||
format: (editor) => {
|
||||
toggleList(editor, {
|
||||
listStyleType: KEYS.listTodo,
|
||||
});
|
||||
editor.tf.setNodes({
|
||||
checked: true,
|
||||
listStyleType: KEYS.listTodo,
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -238,13 +223,16 @@ export const AutoformatKit = [
|
|||
...autoformatArrow,
|
||||
...autoformatMath,
|
||||
...autoformatLists,
|
||||
].map((rule) => ({
|
||||
...rule,
|
||||
query: (editor) =>
|
||||
!editor.api.some({
|
||||
match: { type: editor.getType(KEYS.codeBlock) },
|
||||
}),
|
||||
})),
|
||||
].map(
|
||||
(rule): AutoformatRule => ({
|
||||
...rule,
|
||||
query: (editor) =>
|
||||
!editor.api.some({
|
||||
match: { type: editor.getType(KEYS.codeBlock) },
|
||||
}),
|
||||
})
|
||||
),
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
23
surfsense_web/components/editor/plugins/dnd-kit.tsx
Normal file
23
surfsense_web/components/editor/plugins/dnd-kit.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
'use client';
|
||||
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
|
||||
import { DndPlugin } from '@platejs/dnd';
|
||||
|
||||
import { BlockDraggable } from '@/components/ui/block-draggable';
|
||||
|
||||
export const DndKit = [
|
||||
DndPlugin.configure({
|
||||
options: {
|
||||
enableScroller: true,
|
||||
},
|
||||
render: {
|
||||
aboveNodes: BlockDraggable,
|
||||
aboveSlate: ({ children }) => (
|
||||
<DndProvider backend={HTML5Backend}>{children}</DndProvider>
|
||||
),
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import {
|
||||
BulletedListPlugin,
|
||||
ListItemContentPlugin,
|
||||
ListItemPlugin,
|
||||
ListPlugin,
|
||||
NumberedListPlugin,
|
||||
TaskListPlugin,
|
||||
} from '@platejs/list-classic/react';
|
||||
|
||||
import {
|
||||
BulletedListElement,
|
||||
ListItemElement,
|
||||
NumberedListElement,
|
||||
TaskListElement,
|
||||
} from '@/components/ui/list-classic-node';
|
||||
|
||||
export const ListKit = [
|
||||
ListPlugin,
|
||||
ListItemPlugin,
|
||||
ListItemContentPlugin,
|
||||
BulletedListPlugin.configure({
|
||||
node: { component: BulletedListElement },
|
||||
shortcuts: { toggle: { keys: 'mod+alt+5' } },
|
||||
}),
|
||||
NumberedListPlugin.configure({
|
||||
node: { component: NumberedListElement },
|
||||
shortcuts: { toggle: { keys: 'mod+alt+6' } },
|
||||
}),
|
||||
TaskListPlugin.configure({
|
||||
node: { component: TaskListElement },
|
||||
shortcuts: { toggle: { keys: 'mod+alt+7' } },
|
||||
}),
|
||||
ListItemPlugin.withComponent(ListItemElement),
|
||||
];
|
||||
26
surfsense_web/components/editor/plugins/list-kit.tsx
Normal file
26
surfsense_web/components/editor/plugins/list-kit.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
'use client';
|
||||
|
||||
import { ListPlugin } from '@platejs/list/react';
|
||||
import { KEYS } from 'platejs';
|
||||
|
||||
import { IndentKit } from '@/components/editor/plugins/indent-kit';
|
||||
import { BlockList } from '@/components/ui/block-list';
|
||||
|
||||
export const ListKit = [
|
||||
...IndentKit,
|
||||
ListPlugin.configure({
|
||||
inject: {
|
||||
targetPlugins: [
|
||||
...KEYS.heading,
|
||||
KEYS.p,
|
||||
KEYS.blockquote,
|
||||
KEYS.codeBlock,
|
||||
KEYS.toggle,
|
||||
],
|
||||
},
|
||||
render: {
|
||||
belowNodes: BlockList,
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue