mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-25 16:09:42 +01:00
151 lines
6.7 KiB
JavaScript
151 lines
6.7 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.createSelectionBasedNodeView = exports.SelectionBasedNodeView = void 0;
|
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
const prosemirror_view_1 = require("prosemirror-view");
|
|
const prosemirror_state_1 = require("prosemirror-state");
|
|
const plugin_1 = require("./plugin");
|
|
const reactnodeview_1 = require("./reactnodeview");
|
|
const emotion_theming_1 = require("emotion-theming");
|
|
/**
|
|
* A ReactNodeView that handles React components sensitive
|
|
* to selection changes.
|
|
*
|
|
* If the selection changes, it will attempt to re-render the
|
|
* React component. Otherwise it does nothing.
|
|
*
|
|
* You can subclass `viewShouldUpdate` to include other
|
|
* props that your component might want to consider before
|
|
* entering the React lifecycle. These are usually props you
|
|
* compare in `shouldComponentUpdate`.
|
|
*
|
|
* An example:
|
|
*
|
|
* ```
|
|
* viewShouldUpdate(nextNode) {
|
|
* if (nextNode.attrs !== this.node.attrs) {
|
|
* return true;
|
|
* }
|
|
*
|
|
* return super.viewShouldUpdate(nextNode);
|
|
* }```
|
|
*/
|
|
class SelectionBasedNodeView extends reactnodeview_1.ReactNodeView {
|
|
constructor(node, editor, getPos, options) {
|
|
super(node, editor, getPos, options);
|
|
this.pos = -1;
|
|
this.isNodeInsideSelection = (from, to, pos, posEnd) => {
|
|
({ pos, posEnd } = this.getPositionsWithDefault(pos, posEnd));
|
|
if (typeof pos !== "number" || typeof posEnd !== "number") {
|
|
return false;
|
|
}
|
|
return from <= pos && to >= posEnd;
|
|
};
|
|
this.isSelectionInsideNode = (from, to, pos, posEnd) => {
|
|
({ pos, posEnd } = this.getPositionsWithDefault(pos, posEnd));
|
|
if (typeof pos !== "number" || typeof posEnd !== "number") {
|
|
return false;
|
|
}
|
|
return pos < from && to < posEnd;
|
|
};
|
|
this.isSelectedNode = (selection) => {
|
|
if (selection instanceof prosemirror_state_1.NodeSelection) {
|
|
const { selection: { from, to }, } = this.editor.view.state;
|
|
return (selection.node === this.node ||
|
|
// If nodes are not the same object, we check if they are referring to the same document node
|
|
(this.pos === from &&
|
|
this.posEnd === to &&
|
|
selection.node.eq(this.node)));
|
|
}
|
|
return false;
|
|
};
|
|
this.insideSelection = () => {
|
|
const { selection: { from, to }, } = this.editor.view.state;
|
|
return (this.isSelectedNode(this.editor.view.state.selection) ||
|
|
this.isSelectionInsideNode(from, to));
|
|
};
|
|
this.nodeInsideSelection = () => {
|
|
const { selection } = this.editor.view.state;
|
|
const { from, to } = selection;
|
|
return (this.isSelectedNode(selection) || this.isNodeInsideSelection(from, to));
|
|
};
|
|
this.onSelectionChange = () => {
|
|
this.update(this.node, [], prosemirror_view_1.DecorationSet.empty);
|
|
};
|
|
this.updatePos();
|
|
this.oldSelection = editor.view.state.selection;
|
|
this.selectionChangeState = plugin_1.stateKey.getState(this.editor.view.state);
|
|
this.selectionChangeState.subscribe(this.onSelectionChange);
|
|
}
|
|
render(props = {}, forwardRef) {
|
|
if (!this.options.component)
|
|
return null;
|
|
const theme = this.editor.storage.theme;
|
|
const isSelected = this.editor.isEditable &&
|
|
(this.insideSelection() || this.nodeInsideSelection());
|
|
return ((0, jsx_runtime_1.jsx)(emotion_theming_1.ThemeProvider, Object.assign({ theme: theme }, { children: (0, jsx_runtime_1.jsx)(this.options.component, Object.assign({}, props, { editor: this.editor, getPos: this.getPos, node: this.node, forwardRef: forwardRef, selected: isSelected, updateAttributes: (attr, options) => this.updateAttributes(attr, this.pos, options === null || options === void 0 ? void 0 : options.addToHistory, options === null || options === void 0 ? void 0 : options.preventUpdate) })) })));
|
|
}
|
|
/**
|
|
* Update current node's start and end positions.
|
|
*
|
|
* Prefer `this.pos` rather than getPos(), because calling getPos is
|
|
* expensive, unless you know you're definitely going to render.
|
|
*/
|
|
updatePos() {
|
|
if (typeof this.getPos === "boolean") {
|
|
return;
|
|
}
|
|
this.pos = this.getPos();
|
|
this.posEnd = this.pos + this.node.nodeSize;
|
|
}
|
|
getPositionsWithDefault(pos, posEnd) {
|
|
return {
|
|
pos: typeof pos !== "number" ? this.pos : pos,
|
|
posEnd: typeof posEnd !== "number" ? this.posEnd : posEnd,
|
|
};
|
|
}
|
|
viewShouldUpdate(nextNode) {
|
|
if (super.viewShouldUpdate(nextNode))
|
|
return true;
|
|
const { state: { selection }, } = this.editor.view;
|
|
// update selection
|
|
const oldSelection = this.oldSelection;
|
|
this.oldSelection = selection;
|
|
// update cached positions
|
|
const { pos: oldPos, posEnd: oldPosEnd } = this;
|
|
this.updatePos();
|
|
const { from, to } = selection;
|
|
const { from: oldFrom, to: oldTo } = oldSelection;
|
|
if (this.node.type.spec.selectable) {
|
|
const newNodeSelection = selection instanceof prosemirror_state_1.NodeSelection && selection.from === this.pos;
|
|
const oldNodeSelection = oldSelection instanceof prosemirror_state_1.NodeSelection && oldSelection.from === this.pos;
|
|
if ((newNodeSelection && !oldNodeSelection) ||
|
|
(oldNodeSelection && !newNodeSelection)) {
|
|
return true;
|
|
}
|
|
}
|
|
const movedInToSelection = this.isNodeInsideSelection(from, to) &&
|
|
!this.isNodeInsideSelection(oldFrom, oldTo);
|
|
const movedOutOfSelection = !this.isNodeInsideSelection(from, to) &&
|
|
this.isNodeInsideSelection(oldFrom, oldTo);
|
|
const moveOutFromOldSelection = this.isNodeInsideSelection(from, to, oldPos, oldPosEnd) &&
|
|
!this.isNodeInsideSelection(from, to);
|
|
if (movedInToSelection || movedOutOfSelection || moveOutFromOldSelection) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
destroy() {
|
|
this.selectionChangeState.unsubscribe(this.onSelectionChange);
|
|
super.destroy();
|
|
}
|
|
}
|
|
exports.SelectionBasedNodeView = SelectionBasedNodeView;
|
|
function createSelectionBasedNodeView(component, options) {
|
|
return ({ node, getPos, editor }) => {
|
|
const _getPos = () => (typeof getPos === "boolean" ? -1 : getPos());
|
|
return new SelectionBasedNodeView(node, editor, _getPos, Object.assign(Object.assign({}, options), { component })).init();
|
|
};
|
|
}
|
|
exports.createSelectionBasedNodeView = createSelectionBasedNodeView;
|