Files
outline/shared/editor/nodes/CheckboxList.ts
T
Tom Moor 0f3f7b8da7 refactor: Remove useDictionary hook in favor of i18next t directly (#12282)
Plumbed `dictionary` props through editor components, menus, extensions,
and nodes. Replaces with `useTranslation()` in React contexts and direct
`t` imports from i18next elsewhere.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 20:24:50 -04:00

99 lines
2.5 KiB
TypeScript

import type {
NodeSpec,
NodeType,
Schema,
Node as ProsemirrorNode,
} from "prosemirror-model";
import { Plugin } from "prosemirror-state";
import { v4 as generateUuid } from "uuid";
import toggleList from "../commands/toggleList";
import type { MarkdownSerializerState } from "../lib/markdown/serializer";
import { listWrappingInputRule } from "../lib/listInputRule";
import { findBlockNodes } from "../queries/findChildren";
import { CheckboxListView } from "./CheckboxListView";
import Node from "./Node";
export default class CheckboxList extends Node {
get name() {
return "checkbox_list";
}
get schema(): NodeSpec {
return {
group: "block list",
content: "checkbox_item+",
attrs: {
id: { default: null },
},
toDOM: () => ["ul", { class: this.name }, 0],
parseDOM: [
{
tag: `[class="${this.name}"]`,
},
],
};
}
get plugins() {
const userIdentifier = this.editor.props.userId;
// Plugin to auto-assign IDs to checkbox lists
const assignIdsPlugin = new Plugin({
appendTransaction: (txs, _oldSt, newSt) => {
const hasDocChanges = txs.some((t) => t.docChanged);
if (!hasDocChanges) {
return null;
}
const checkboxLists = findBlockNodes(newSt.doc, true).filter(
(b) => b.node.type.name === this.name && !b.node.attrs.id
);
if (checkboxLists.length === 0) {
return null;
}
let modifyTx = newSt.tr;
checkboxLists.forEach((listBlock) => {
modifyTx.setNodeAttribute(listBlock.pos, "id", generateUuid());
});
return modifyTx;
},
});
// Plugin to provide NodeViews
const nodeViewPlugin = new Plugin({
props: {
nodeViews: {
[this.name]: (node, view, getPos) =>
new CheckboxListView(node, view, getPos, userIdentifier || ""),
},
},
});
return [assignIdsPlugin, nodeViewPlugin];
}
keys({ type, schema }: { type: NodeType; schema: Schema }) {
return {
"Shift-Ctrl-7": toggleList(type, schema.nodes.checkbox_item),
};
}
commands({ type, schema }: { type: NodeType; schema: Schema }) {
return () => toggleList(type, schema.nodes.checkbox_item);
}
inputRules({ type }: { type: NodeType }) {
return [listWrappingInputRule(/^-?\s*(\[\s?\])\s$/i, type)];
}
toMarkdown(state: MarkdownSerializerState, node: ProsemirrorNode) {
state.renderList(node, " ", () => "- ");
}
parseMarkdown() {
return { block: "checkbox_list" };
}
}