diff --git a/packages/core/src/plugins/reset-mark.ts b/packages/core/src/plugins/reset-mark.ts index acf3bd0d..c0f332a7 100644 --- a/packages/core/src/plugins/reset-mark.ts +++ b/packages/core/src/plugins/reset-mark.ts @@ -1,5 +1,8 @@ import { Plugin as PMPlugin, TextSelection } from 'prosemirror-state'; +/** + * Remove the StoredMark when the text corresponding to the Mark range is deleted. + */ export const edimResetMarkPlugins = (): PMPlugin[] => { const plugins: PMPlugin[] = [ new PMPlugin({ @@ -7,16 +10,13 @@ export const edimResetMarkPlugins = (): PMPlugin[] => { if (!transactions.some((tr) => tr.docChanged)) { return; } - if (!(newState.selection instanceof TextSelection)) { return; } - const { $cursor } = newState.selection; if (!$cursor || !newState.storedMarks) { return; } - return newState.tr.setStoredMarks([]); }, }), diff --git a/packages/docs/src/components/editor/prose-mirror.tsx b/packages/docs/src/components/editor/prose-mirror.tsx index 00992ec8..769d2641 100644 --- a/packages/docs/src/components/editor/prose-mirror.tsx +++ b/packages/docs/src/components/editor/prose-mirror.tsx @@ -21,6 +21,7 @@ export const ProseMirror = (props: ProseMirrorProps) => { ...props, }); editorViewRef.current = view; + console.log(view); return () => { view.destroy(); }; diff --git a/packages/docs/src/components/examples/packages/flat-task-list.tsx b/packages/docs/src/components/examples/packages/flat-task-list.tsx index dcbab145..1d33a757 100644 --- a/packages/docs/src/components/examples/packages/flat-task-list.tsx +++ b/packages/docs/src/components/examples/packages/flat-task-list.tsx @@ -55,11 +55,161 @@ export const FlatTaskListExample = (props: ProseMirrorProps) => { type: 'doc', content: [ { - type: 'paragraph', + type: 'task_list', content: [ { - type: 'text', - text: 'This is a minimal example of a ProseMirror editor with a few plugins.', + type: 'task_list_item', + attrs: { + indent: 1, + align: 'left', + checked: false, + }, + content: [ + { + type: 'paragraph', + attrs: { + align: 'left', + }, + content: [ + { + type: 'text', + text: 'asdfa', + }, + ], + }, + ], + }, + { + type: 'task_list_item', + attrs: { + indent: 2, + align: 'left', + checked: false, + }, + content: [ + { + type: 'paragraph', + attrs: { + align: 'left', + }, + content: [ + { + type: 'text', + text: 'asdfasdf', + }, + ], + }, + ], + }, + { + type: 'task_list_item', + attrs: { + indent: 2, + align: 'left', + checked: false, + }, + content: [ + { + type: 'paragraph', + attrs: { + align: 'left', + }, + content: [ + { + type: 'text', + text: 'asdfasdf', + }, + ], + }, + ], + }, + { + type: 'task_list_item', + attrs: { + indent: 1, + align: 'left', + checked: true, + }, + content: [ + { + type: 'paragraph', + attrs: { + align: 'left', + }, + content: [ + { + type: 'text', + text: 'asdfasdfasdf', + }, + ], + }, + ], + }, + { + type: 'task_list_item', + attrs: { + indent: 1, + align: 'left', + checked: true, + }, + content: [ + { + type: 'paragraph', + attrs: { + align: 'left', + }, + content: [ + { + type: 'text', + text: 'asdfas', + }, + ], + }, + ], + }, + { + type: 'task_list_item', + attrs: { + indent: 2, + align: 'left', + checked: false, + }, + content: [ + { + type: 'paragraph', + attrs: { + align: 'left', + }, + content: [ + { + type: 'text', + text: 'fdasdf', + }, + ], + }, + ], + }, + { + type: 'task_list_item', + attrs: { + indent: 2, + align: 'left', + checked: false, + }, + content: [ + { + type: 'paragraph', + attrs: { + align: 'left', + }, + content: [ + { + type: 'text', + text: 'asdfasdf', + }, + ], + }, + ], }, ], }, diff --git a/packages/flat-list/src/commands/indent-list-item.ts b/packages/flat-list/src/commands/indent-list-item.ts index 21f1a8bd..98673845 100644 --- a/packages/flat-list/src/commands/indent-list-item.ts +++ b/packages/flat-list/src/commands/indent-list-item.ts @@ -71,6 +71,7 @@ export const indentListItem = ( return tr; } return tr.setNodeMarkup(pos, node.type, { + ...attrs, indent: expectedIndent, }); }, tr); diff --git a/packages/flat-task-list/src/index.ts b/packages/flat-task-list/src/index.ts index bbaa8be2..853bbe8f 100644 --- a/packages/flat-task-list/src/index.ts +++ b/packages/flat-task-list/src/index.ts @@ -1,4 +1,3 @@ export * from './schemas'; export * from './plugins'; -export * from './node-views'; export * from './components'; diff --git a/packages/flat-task-list/src/node-views/index.ts b/packages/flat-task-list/src/node-views/index.ts deleted file mode 100644 index c0439592..00000000 --- a/packages/flat-task-list/src/node-views/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './task-list-item-node-view'; diff --git a/packages/flat-task-list/src/node-views/task-list-item-node-view.ts b/packages/flat-task-list/src/node-views/task-list-item-node-view.ts deleted file mode 100644 index 0fd4aecd..00000000 --- a/packages/flat-task-list/src/node-views/task-list-item-node-view.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { html } from '@edim-editor/ui'; - -export const A = () => { - return html`
`; -} \ No newline at end of file diff --git a/packages/flat-task-list/src/plugins/flat-task-list.ts b/packages/flat-task-list/src/plugins/flat-task-list.ts index 14abae91..3a0f9a43 100644 --- a/packages/flat-task-list/src/plugins/flat-task-list.ts +++ b/packages/flat-task-list/src/plugins/flat-task-list.ts @@ -3,6 +3,7 @@ import { Plugin as PMPlugin } from 'prosemirror-state'; import { edimTaskListInputRulePlugins } from './input-rules'; import { edimFlatTaskListKeymapPlugins } from './keymaps'; import { edimFlatTaskListMergePlugins } from './merge'; +import { edimTaskListItemNodeViewPlugins } from './task-list-item'; export interface EdimFlatTaskListPluginConfigs { taskListNodeType: NodeType; @@ -13,6 +14,9 @@ export const edimFlatTaskListPlugins = ( configs: EdimFlatTaskListPluginConfigs, ): PMPlugin[] => { return [ + ...edimTaskListItemNodeViewPlugins({ + taskListItemNodeType: configs.taskListItemNodeType, + }), ...edimTaskListInputRulePlugins({ taskListNodeType: configs.taskListNodeType, }), diff --git a/packages/flat-task-list/src/plugins/index.ts b/packages/flat-task-list/src/plugins/index.ts index 813bda09..76626c4d 100644 --- a/packages/flat-task-list/src/plugins/index.ts +++ b/packages/flat-task-list/src/plugins/index.ts @@ -2,3 +2,4 @@ export * from './input-rules'; export * from './keymaps'; export * from './flat-task-list'; export * from './merge'; +export * from './task-list-item'; diff --git a/packages/flat-task-list/src/plugins/task-list-item.ts b/packages/flat-task-list/src/plugins/task-list-item.ts new file mode 100644 index 00000000..8bf68fac --- /dev/null +++ b/packages/flat-task-list/src/plugins/task-list-item.ts @@ -0,0 +1,62 @@ +import { NodeType } from 'prosemirror-model'; +import { Plugin as PMPlugin } from 'prosemirror-state'; +import { createNode } from '../utils'; +import { EdimFlatTaskListItemAttrs } from '../schemas'; + +export interface EdimTaskListItemNodeViewPluginConfigs { + taskListItemNodeType: NodeType; +} + +export const edimTaskListItemNodeViewPlugins = ( + configs: EdimTaskListItemNodeViewPluginConfigs, +): PMPlugin[] => { + const plugins: PMPlugin[] = [ + new PMPlugin({ + props: { + nodeViews: { + [configs.taskListItemNodeType.name]: (node, view, getPos) => { + const li = createNode(node); + + li.addEventListener('mousedown', (event) => { + const rect = li.getBoundingClientRect(); + const clickX = event.clientX; + const liLeftX = rect.left; + + const paddingLeftValue = li + .computedStyleMap() + .get('padding-left') as CSSUnitValue; + const paddingLeft = paddingLeftValue.value; + + if (clickX > liLeftX + paddingLeft) { + return; + } + + const pos = getPos(); + if (pos === undefined) { + return; + } + + const attrs = node.attrs as EdimFlatTaskListItemAttrs; + const tr = view.state.tr.setNodeMarkup( + pos, + configs.taskListItemNodeType, + { + ...attrs, + checked: !attrs.checked, + }, + ); + view.dispatch(tr); + }); + + return { + dom: li, + contentDOM: li, + destroy: () => {}, + }; + }, + }, + }, + }), + ]; + return plugins; +}; diff --git a/packages/flat-task-list/src/schemas/task-list-item.ts b/packages/flat-task-list/src/schemas/task-list-item.ts index 7a769e9d..c3329526 100644 --- a/packages/flat-task-list/src/schemas/task-list-item.ts +++ b/packages/flat-task-list/src/schemas/task-list-item.ts @@ -4,6 +4,7 @@ import { parseQuillIndent, parseQuillTextAlign, } from '@edim-editor/core'; +import { createNode } from '../utils'; export const EDIM_DEFAULT_FLAT_TASK_LIST_ITEM_NODE_NAME = 'task_list_item'; @@ -47,12 +48,12 @@ export const edimFlatTaskListItemNodes = ( { tag: 'li', getAttrs(node) { - const dom = node as HTMLElement; + const dom = node as HTMLLIElement; const align = dom.getAttribute('data-text-align'); const quillAlign = parseQuillTextAlign(dom); const indent = dom.dataset['indent']; const quillIndent = parseQuillIndent(dom); - const checked = dom.dataset['checked']; + const checked = dom.dataset['checked'] === 'true'; if (dom.parentElement && isQuillTaskList(dom.parentElement)) { return { @@ -71,25 +72,30 @@ export const edimFlatTaskListItemNodes = ( }, ], toDOM(node) { - const attrs = node.attrs as EdimFlatTaskListItemAttrs; - const classes = ['edim-task-list-item']; - if (attrs.align && attrs.align !== 'left') { - classes.push(`edim-align-${attrs.align}`); - } - classes.push(`edim-indent-${attrs.indent || 1}`); - if (attrs.checked) { - classes.push('edim-task-list-item-checked'); - } - return [ - 'li', - { - class: classes.join(' '), - 'data-text-align': attrs.align || 'left', - 'data-indent': attrs.indent || 1, - 'data-checked': attrs.checked ? 'true' : 'false', - }, - 0, - ]; + const li = createNode(node); + return { + dom: li, + contentDOM: li, + }; + // const attrs = node.attrs as EdimFlatTaskListItemAttrs; + // const classes = ['edim-task-list-item']; + // if (attrs.align && attrs.align !== 'left') { + // classes.push(`edim-align-${attrs.align}`); + // } + // classes.push(`edim-indent-${attrs.indent || 1}`); + // if (attrs.checked) { + // classes.push('edim-task-list-item-checked'); + // } + // return [ + // 'li', + // { + // class: classes.join(' '), + // 'data-text-align': attrs.align || 'left', + // 'data-indent': attrs.indent || 1, + // 'data-checked': attrs.checked ? 'true' : 'false', + // }, + // 0, + // ]; }, defining: true, }; diff --git a/packages/flat-task-list/src/utils/create-node.ts b/packages/flat-task-list/src/utils/create-node.ts new file mode 100644 index 00000000..6e7290e0 --- /dev/null +++ b/packages/flat-task-list/src/utils/create-node.ts @@ -0,0 +1,21 @@ +import { Node } from 'prosemirror-model'; +import { EdimFlatTaskListItemAttrs } from '../schemas'; + +export const createNode = (node: Node) => { + const attrs = node.attrs as EdimFlatTaskListItemAttrs; + const classes = ['edim-task-list-item']; + if (attrs.align && attrs.align !== 'left') { + classes.push(`edim-align-${attrs.align}`); + } + classes.push(`edim-indent-${attrs.indent || 1}`); + if (attrs.checked) { + classes.push('edim-task-list-item-checked'); + } + + const li = document.createElement('li'); + li.classList.add(...classes); + li.dataset['textAlign'] = attrs.align || 'left'; + li.dataset['indent'] = `${attrs.indent || 1}`; + li.dataset['checked'] = attrs.checked ? 'true' : 'false'; + return li; +} \ No newline at end of file diff --git a/packages/flat-task-list/src/utils/index.ts b/packages/flat-task-list/src/utils/index.ts new file mode 100644 index 00000000..17c2b577 --- /dev/null +++ b/packages/flat-task-list/src/utils/index.ts @@ -0,0 +1 @@ +export * from './create-node'; diff --git a/packages/flat-task-list/styles/flat-task-list.scss b/packages/flat-task-list/styles/flat-task-list.scss index 82ea71a8..a3a24276 100644 --- a/packages/flat-task-list/styles/flat-task-list.scss +++ b/packages/flat-task-list/styles/flat-task-list.scss @@ -9,8 +9,6 @@ list-style-type: none; li.edim-task-list-item { - - word-break: break-all; line-height: normal; @@ -33,19 +31,20 @@ @for $i from 1 through 6 { &.edim-indent-#{$i} { - margin-left: 30px * $i; + padding-left: 30px * $i; } } &::before { cursor: pointer; vertical-align: top; - margin-left: -1.5em; - margin-right: 0.3em; + position: absolute; + margin-left: -30px; text-align: right; display: inline-block; white-space: nowrap; - width: 1.2em; + text-align: center; + width: 30px; content: '\2610'; } diff --git a/packages/preset/src/schemas/preset.ts b/packages/preset/src/schemas/preset.ts index 2881abf5..5f816f3f 100644 --- a/packages/preset/src/schemas/preset.ts +++ b/packages/preset/src/schemas/preset.ts @@ -33,11 +33,11 @@ export const edimPresetSchema = () => ...edimBaseNodes(), ...edimParagraphNodes(), ...edimHeadingNodes(), + ...edimFlatTaskListNodes(), + ...edimFlatTaskListItemNodes(), ...edimFlatBulletListNodes(), ...edimFlatOrderedListNodes(), ...edimFlatListItemNodes(), - ...edimFlatTaskListNodes(), - ...edimFlatTaskListItemNodes(), ...edimBlockquoteNodes(), ...edimHorizontalRuleNodes(), ...edimCodeBlockNodes(),