chore: Move editor into codebase (#2930)
This commit is contained in:
33
shared/editor/queries/findCollapsedNodes.ts
Normal file
33
shared/editor/queries/findCollapsedNodes.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Node } from "prosemirror-model";
|
||||
import { findBlockNodes, NodeWithPos } from "prosemirror-utils";
|
||||
|
||||
export default function findCollapsedNodes(doc: Node): NodeWithPos[] {
|
||||
const blocks = findBlockNodes(doc);
|
||||
const nodes: NodeWithPos[] = [];
|
||||
|
||||
let withinCollapsedHeading;
|
||||
|
||||
for (const block of blocks) {
|
||||
if (block.node.type.name === "heading") {
|
||||
if (
|
||||
!withinCollapsedHeading ||
|
||||
block.node.attrs.level <= withinCollapsedHeading
|
||||
) {
|
||||
if (block.node.attrs.collapsed) {
|
||||
if (!withinCollapsedHeading) {
|
||||
withinCollapsedHeading = block.node.attrs.level;
|
||||
}
|
||||
} else {
|
||||
withinCollapsedHeading = undefined;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (withinCollapsedHeading) {
|
||||
nodes.push(block);
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
9
shared/editor/queries/getColumnIndex.ts
Normal file
9
shared/editor/queries/getColumnIndex.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { CellSelection } from "prosemirror-tables";
|
||||
|
||||
export default function getColumnIndex(selection: CellSelection) {
|
||||
const isColSelection = selection.isColSelection && selection.isColSelection();
|
||||
if (!isColSelection) return undefined;
|
||||
|
||||
const path = (selection.$from as any).path;
|
||||
return path[path.length - 5];
|
||||
}
|
||||
40
shared/editor/queries/getMarkRange.ts
Normal file
40
shared/editor/queries/getMarkRange.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { ResolvedPos, MarkType } from "prosemirror-model";
|
||||
|
||||
export default function getMarkRange($pos?: ResolvedPos, type?: MarkType) {
|
||||
if (!$pos || !type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const start = $pos.parent.childAfter($pos.parentOffset);
|
||||
if (!start.node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const mark = start.node.marks.find((mark) => mark.type === type);
|
||||
if (!mark) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let startIndex = $pos.index();
|
||||
let startPos = $pos.start() + start.offset;
|
||||
let endIndex = startIndex + 1;
|
||||
let endPos = startPos + start.node.nodeSize;
|
||||
|
||||
while (
|
||||
startIndex > 0 &&
|
||||
mark.isInSet($pos.parent.child(startIndex - 1).marks)
|
||||
) {
|
||||
startIndex -= 1;
|
||||
startPos -= $pos.parent.child(startIndex).nodeSize;
|
||||
}
|
||||
|
||||
while (
|
||||
endIndex < $pos.parent.childCount &&
|
||||
mark.isInSet($pos.parent.child(endIndex).marks)
|
||||
) {
|
||||
endPos += $pos.parent.child(endIndex).nodeSize;
|
||||
endIndex += 1;
|
||||
}
|
||||
|
||||
return { from: startPos, to: endPos, mark };
|
||||
}
|
||||
14
shared/editor/queries/getParentListItem.ts
Normal file
14
shared/editor/queries/getParentListItem.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Node } from "prosemirror-model";
|
||||
import { EditorState } from "prosemirror-state";
|
||||
|
||||
export default function getParentListItem(
|
||||
state: EditorState
|
||||
): [Node, number] | void {
|
||||
const $head = state.selection.$head;
|
||||
for (let d = $head.depth; d > 0; d--) {
|
||||
const node = $head.node(d);
|
||||
if (["list_item", "checkbox_item"].includes(node.type.name)) {
|
||||
return [node, $head.before(d)];
|
||||
}
|
||||
}
|
||||
}
|
||||
9
shared/editor/queries/getRowIndex.ts
Normal file
9
shared/editor/queries/getRowIndex.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { CellSelection } from "prosemirror-tables";
|
||||
|
||||
export default function getRowIndex(selection: CellSelection) {
|
||||
const isRowSelection = selection.isRowSelection && selection.isRowSelection();
|
||||
if (!isRowSelection) return undefined;
|
||||
|
||||
const path = (selection.$from as any).path;
|
||||
return path[path.length - 8];
|
||||
}
|
||||
15
shared/editor/queries/isInCode.ts
Normal file
15
shared/editor/queries/isInCode.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { EditorState } from "prosemirror-state";
|
||||
import isMarkActive from "./isMarkActive";
|
||||
|
||||
export default function isInCode(state: EditorState): boolean {
|
||||
if (state.schema.nodes.code_block) {
|
||||
const $head = state.selection.$head;
|
||||
for (let d = $head.depth; d > 0; d--) {
|
||||
if ($head.node(d).type === state.schema.nodes.code_block) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isMarkActive(state.schema.marks.code_inline)(state);
|
||||
}
|
||||
16
shared/editor/queries/isInList.ts
Normal file
16
shared/editor/queries/isInList.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { EditorState } from "prosemirror-state";
|
||||
|
||||
export default function isInList(state: EditorState) {
|
||||
const $head = state.selection.$head;
|
||||
for (let d = $head.depth; d > 0; d--) {
|
||||
if (
|
||||
["ordered_list", "bullet_list", "checkbox_list"].includes(
|
||||
$head.node(d).type.name
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
9
shared/editor/queries/isList.ts
Normal file
9
shared/editor/queries/isList.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Node, Schema } from "prosemirror-model";
|
||||
|
||||
export default function isList(node: Node, schema: Schema) {
|
||||
return (
|
||||
node.type === schema.nodes.bullet_list ||
|
||||
node.type === schema.nodes.ordered_list ||
|
||||
node.type === schema.nodes.checkbox_list
|
||||
);
|
||||
}
|
||||
16
shared/editor/queries/isMarkActive.ts
Normal file
16
shared/editor/queries/isMarkActive.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { MarkType } from "prosemirror-model";
|
||||
import { EditorState } from "prosemirror-state";
|
||||
|
||||
const isMarkActive = (type: MarkType) => (state: EditorState): boolean => {
|
||||
if (!type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { from, $from, to, empty } = state.selection;
|
||||
|
||||
return !!(empty
|
||||
? type.isInSet(state.storedMarks || $from.marks())
|
||||
: state.doc.rangeHasMark(from, to, type));
|
||||
};
|
||||
|
||||
export default isMarkActive;
|
||||
23
shared/editor/queries/isNodeActive.ts
Normal file
23
shared/editor/queries/isNodeActive.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { NodeType } from "prosemirror-model";
|
||||
import { EditorState } from "prosemirror-state";
|
||||
import { findParentNode, findSelectedNodeOfType } from "prosemirror-utils";
|
||||
|
||||
const isNodeActive = (type: NodeType, attrs: Record<string, any> = {}) => (
|
||||
state: EditorState
|
||||
) => {
|
||||
if (!type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const node =
|
||||
findSelectedNodeOfType(type)(state.selection) ||
|
||||
findParentNode((node) => node.type === type)(state.selection);
|
||||
|
||||
if (!Object.keys(attrs).length || !node) {
|
||||
return !!node;
|
||||
}
|
||||
|
||||
return node.node.hasMarkup(type, { ...node.node.attrs, ...attrs });
|
||||
};
|
||||
|
||||
export default isNodeActive;
|
||||
Reference in New Issue
Block a user