Skip to content

Commit

Permalink
fix: try to find valid endpoint for text selection (#1760)
Browse files Browse the repository at this point in the history
  • Loading branch information
ocavue committed Jun 30, 2022
1 parent c532dcc commit f274e22
Show file tree
Hide file tree
Showing 19 changed files with 66 additions and 162 deletions.
8 changes: 6 additions & 2 deletions packages/jest-prosemirror/src/jest-prosemirror-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,9 @@ interface DispatchTextSelectionProps extends TestEditorViewProps {
export function dispatchTextSelection(props: DispatchTextSelectionProps): void {
const { view, start, end } = props;
const { state } = view;
const tr = state.tr.setSelection(TextSelection.create(state.doc, start, end));
const tr = state.tr.setSelection(
TextSelection.between(state.doc.resolve(start), state.doc.resolve(end ?? start)),
);

view.dispatch(tr);
}
Expand All @@ -212,7 +214,9 @@ interface DispatchAnchorTextSelectionProps extends TestEditorViewProps, AnchorHe
export function dispatchAnchorTextSelection(props: DispatchAnchorTextSelectionProps): void {
const { view, anchor, head } = props;
const { state } = view;
const tr = state.tr.setSelection(TextSelection.create(state.doc, anchor, head));
const tr = state.tr.setSelection(
TextSelection.between(state.doc.resolve(anchor), state.doc.resolve(head)),
);

view.dispatch(tr);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/jest-prosemirror/src/jest-prosemirror-nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ interface CreateTextSelectionProps extends TaggedDocProps {
function createTextSelection({ taggedDoc, start, end }: CreateTextSelectionProps) {
const $start = taggedDoc.resolve(start);
const $end = end && start <= end ? taggedDoc.resolve(end) : taggedDoc.resolve($start.end());
return new TextSelection($start, $end);
return TextSelection.between($start, $end);
}

const supportedTags = new Set(['cursor', 'node', 'start', 'end', 'anchor', 'all', 'gap']);
Expand Down Expand Up @@ -81,7 +81,7 @@ export function initSelection(taggedDoc: ProsemirrorNode): Selection | undefined
}

if (isNumber(cursor)) {
return new TextSelection(taggedDoc.resolve(cursor));
return TextSelection.near(taggedDoc.resolve(cursor));
}

if (isNumber(gap)) {
Expand All @@ -90,7 +90,7 @@ export function initSelection(taggedDoc: ProsemirrorNode): Selection | undefined
}

if (isNumber(anchor) && isNumber(head)) {
return TextSelection.create(taggedDoc, anchor, head);
return TextSelection.between(taggedDoc.resolve(anchor), taggedDoc.resolve(head));
}

if (isNumber(start)) {
Expand Down
18 changes: 7 additions & 11 deletions packages/remirror__core-utils/__tests__/command-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,13 @@ describe('replaceText', () => {
});

it('can specify from and to', () => {
const from = doc(p('Ignore'), '<cursor>');
const to = doc(p('Ignore'), h1('Content'));

const from = doc(p('<cursor>Ignore'), p(''));
const to = doc(p('Ignore'), p('Content'));
expect(
replaceText({
appendText: '',
type: schema.nodes.heading,
content: 'Content',
range: { from: 8, to: 8 },
range: { from: 9, to: 9 },
}),
).toTransform({
from,
Expand All @@ -201,12 +199,10 @@ describe('replaceText', () => {
});

it('can append text', () => {
const from = doc(p('Ignore'), '<cursor>');
const from = doc(p('Ignore'), p('<cursor>'));
const to = doc(p('Ignore'), p('Content '));

expect(
replaceText({ appendText: ' ', type: schema.nodes.paragraph, content: 'Content' }),
).toTransform({
expect(replaceText({ appendText: ' ', content: 'Content' })).toTransform({
from,
to,
});
Expand Down Expand Up @@ -266,8 +262,8 @@ describe('toggleWrap', () => {
});

it('lifts the node when already wrapped', () => {
const from = doc(p(blockquote('Lift <cursor>me')));
const to = doc(blockquote('Lift me'));
const from = doc(blockquote(blockquote(p('Lift <cursor>me'))));
const to = doc(blockquote(p('Lift me')));

expect(toggleWrap(schema.nodes.blockquote)).toTransform({ from, to });
});
Expand Down
130 changes: 10 additions & 120 deletions packages/remirror__core-utils/__tests__/prosemirror-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,12 @@ import {
findParentNode,
findParentNodeOfType,
findPositionOfNodeAfter,
findPositionOfNodeBefore,
findSelectedNodeOfType,
hasTransactionChanged,
isNodeActive,
isNodeOfType,
isSelectionEmpty,
removeNodeAtPosition,
removeNodeBefore,
schemaToJSON,
} from '../';

Expand Down Expand Up @@ -72,106 +70,6 @@ describe('removeNodeAtPosition', () => {
});
});

describe('removeNodeBefore', () => {
it('does nothing if there is no nodeBefore', () => {
const {
state: { tr },
} = createEditor(doc(p('<cursor>')));
const steps = tr.steps;

removeNodeBefore(tr);
expect(steps).toBe(tr.steps);
});

it('supports removing tables', () => {
const {
state: { tr },
} = createEditor(doc(p('one'), table(row(tdEmpty), row(tdEmpty)), '<cursor>', p('two')));
removeNodeBefore(tr);

expect(tr.doc).toEqualProsemirrorNode(doc(p('one'), p('two')));
});

it('supports removing blockquotes', () => {
const {
state: { tr },
} = createEditor(doc(p('one'), blockquote(p('')), '<cursor>', p('two')));
removeNodeBefore(tr);

expect(tr.doc).toEqualProsemirrorNode(doc(p('one'), p('two')));
});

it('supports removing leaf nodes (atom)', () => {
const {
state: { tr },
} = createEditor(doc(p('one'), atomBlock(), '<cursor>', p('two')));
removeNodeBefore(tr);

expect(tr.doc).toEqualProsemirrorNode(doc(p('one'), p('two')));
});
});

describe('findPositionOfNodeBefore', () => {
it('returns `undefined` when none exists', () => {
const {
state: { selection },
} = createEditor(doc(p('<cursor>')));
const result = findPositionOfNodeBefore(selection);

expect(result).toBeUndefined();
});

it('supports tables', () => {
const node = table(row(tdEmpty), row(tdEmpty));
const {
state: { selection },
} = createEditor(doc(p('abcd'), node, '<cursor>'));
const result = findPositionOfNodeBefore(selection);

expect(result).toEqual({ pos: 6, start: 7, end: 20, depth: 1, node });
});

it('supports blockquotes', () => {
const node = blockquote(p(''));
const {
state: { selection },
} = createEditor(doc(p('abcd'), node, '<cursor>'));
const position = findPositionOfNodeBefore(selection);

expect(position).toEqual({ pos: 6, start: 7, end: 10, depth: 1, node });
});

it('supports nested leaf nodes', () => {
const node = atomBlock();
const {
state: { selection },
} = createEditor(doc(p('abcd'), table(row(td(p('1'), node, '<cursor>')))));
const position = findPositionOfNodeBefore(selection);

expect(position).toEqual({ pos: 12, start: 13, end: 13, depth: 4, node });
});

it('supports non-nested leaf nodes', () => {
const node = atomBlock();
const {
state: { selection },
} = createEditor(doc(p('abcd'), node, '<cursor>'));
const position = findPositionOfNodeBefore(selection);

expect(position).toEqual({ pos: 6, start: 7, end: 7, depth: 1, node });
});

it('supports leaf nodes with with nested inline atom nodes', () => {
const node = atomContainer(atomBlock());
const {
state: { selection },
} = createEditor(doc(p('abcd'), node, '<cursor>'));
const position = findPositionOfNodeBefore(selection);

expect(position).toEqual({ pos: 6, start: 7, end: 9, depth: 1, node });
});
});

describe('findPositionOfNodeAfter', () => {
it('returns `undefined` when none exists', () => {
const {
Expand All @@ -184,20 +82,16 @@ describe('findPositionOfNodeAfter', () => {

it('supports tables', () => {
const node = table(row(tdEmpty), row(tdEmpty));
const {
state: { selection },
} = createEditor(doc(p('abcd'), '<cursor>', node));
const result = findPositionOfNodeAfter(selection);
const { state } = createEditor(doc(p('abcd'), node));
const position = findPositionOfNodeAfter(state.doc.resolve(6));

expect(result).toEqual({ pos: 6, start: 7, end: 20, depth: 1, node });
expect(position).toEqual({ pos: 6, start: 7, end: 20, depth: 1, node });
});

it('supports blockquotes', () => {
const node = blockquote(p(''));
const {
state: { selection },
} = createEditor(doc(p('abcd'), '<cursor>', node));
const position = findPositionOfNodeAfter(selection);
const { state } = createEditor(doc(p('abcd'), node));
const position = findPositionOfNodeAfter(state.doc.resolve(6));

expect(position).toEqual({ pos: 6, start: 7, end: 10, depth: 1, node });
});
Expand All @@ -214,20 +108,16 @@ describe('findPositionOfNodeAfter', () => {

it('supports non-nested leaf nodes', () => {
const node = atomBlock();
const {
state: { selection },
} = createEditor(doc(p('abcd'), '<cursor>', node));
const position = findPositionOfNodeAfter(selection);
const { state } = createEditor(doc(p('abcd'), node));
const position = findPositionOfNodeAfter(state.doc.resolve(6));

expect(position).toEqual({ pos: 6, start: 7, end: 7, depth: 1, node });
});

it('supports leaf nodes with with nested inline atom nodes', () => {
const node = atomContainer(atomBlock());
const {
state: { selection },
} = createEditor(doc(p('abcd'), '<cursor>', node));
const position = findPositionOfNodeAfter(selection);
const { state } = createEditor(doc(p('abcd'), node));
const position = findPositionOfNodeAfter(state.doc.resolve(6));

expect(position).toEqual({ pos: 6, start: 7, end: 9, depth: 1, node });
});
Expand Down Expand Up @@ -483,7 +373,7 @@ describe('findParentNodeOfType', () => {
describe('nodeActive', () => {
it('shows active when within an active region', () => {
const { state, schema: sch } = createEditor(
doc(p('Something', blockquote('is <cursor>in blockquote'))),
doc(p('Something', blockquote(p('is <cursor>in blockquote')))),
);

expect(isNodeActive({ state, type: sch.nodes.blockquote })).toBeTrue();
Expand Down
8 changes: 5 additions & 3 deletions packages/remirror__core-utils/src/command-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ export interface UpdateMarkProps extends Partial<RangeProps>, Partial<Attributes
export function updateMark(props: UpdateMarkProps): CommandFunction {
return ({ dispatch, tr }) => {
const { type, attrs = object(), appendText, range } = props;
const selection = range ? TextSelection.create(tr.doc, range.from, range.to) : tr.selection;
const selection = range
? TextSelection.between(tr.doc.resolve(range.from), tr.doc.resolve(range.to))
: tr.selection;
const { $from, from, to } = selection;
let applicable = $from.depth === 0 ? tr.doc.type.allowsMarkType(type) : false;

Expand Down Expand Up @@ -327,9 +329,9 @@ export function preserveSelection(selection: Selection, tr: Transaction): void {

if (empty) {
// Update the transaction with the new text selection.
tr.setSelection(TextSelection.create(tr.doc, head));
tr.setSelection(TextSelection.near(tr.doc.resolve(head)));
} else {
tr.setSelection(TextSelection.create(tr.doc, anchor, head));
tr.setSelection(TextSelection.between(tr.doc.resolve(anchor), tr.doc.resolve(head)));
}
}

Expand Down
8 changes: 5 additions & 3 deletions packages/remirror__core-utils/src/core-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,9 @@ export function getSelectedGroup(
let { from, to } = state.selection;

const getChar = (start: number, end: number) =>
getTextContentFromSlice(TextSelection.create(state.doc, start, end).content());
getTextContentFromSlice(
TextSelection.between(state.doc.resolve(start), state.doc.resolve(end)).content(),
);

for (
let char = getChar(from - 1, from);
Expand Down Expand Up @@ -1072,15 +1074,15 @@ export function getTextSelection(selection: PrimitiveSelection, doc: Prosemirror
const anchor = clampToDocument(pos.anchor);
const head = clampToDocument(pos.head);

return TextSelection.create(doc, anchor, head);
return TextSelection.between(doc.resolve(anchor), doc.resolve(head));
}

// In this case assume that `from` is the fixed anchor and `to` is the movable
// head.
const anchor = clampToDocument(pos.from);
const head = clampToDocument(pos.to);

return TextSelection.create(doc, anchor, head);
return TextSelection.between(doc.resolve(anchor), doc.resolve(head));
}

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/remirror__core-utils/src/prosemirror-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ export function findParentNodeOfType(
* ```
*
* @param selection - the prosemirror selection
*
* @deprecated This util is hard to use and not that useful
*/
export function findPositionOfNodeBefore(
value: Selection | ResolvedPos | EditorState | Transaction,
Expand Down Expand Up @@ -347,6 +349,8 @@ export function findPositionOfNodeBefore(
* ```
*
* @param tr
*
* @deprecated This util is hard to use and not that useful
*/
export function removeNodeBefore(tr: Transaction): Transaction {
const result = findPositionOfNodeBefore(tr.selection);
Expand Down Expand Up @@ -433,6 +437,8 @@ interface FindParentNodeProps extends StateSelectionPosProps {
* ```
*
* @param selection - the prosemirror selection
*
* @deprecated This util is hard to use and not that useful
*/
export function findPositionOfNodeAfter(
value: Selection | ResolvedPos | EditorState,
Expand Down Expand Up @@ -475,6 +481,8 @@ export function findPositionOfNodeAfter(
* ```
*
* @param tr
*
* @deprecated This util is hard to use and not that useful
*/
export function removeNodeAfter(tr: Transaction): Transaction {
const result = findPositionOfNodeAfter(tr.selection);
Expand Down
4 changes: 2 additions & 2 deletions packages/remirror__core/src/builtins/commands-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ export class CommandsExtension extends PlainExtension<CommandOptions> {
* commands.selectText(10);
*
* // Use a ProseMirror selection
* commands.selectText(new TextSelection(state.doc.resolve(10)))
* commands.selectText(TextSelection.near(state.doc.resolve(10)))
* ```
*
* Although this is called `selectText` you can provide your own selection
Expand Down Expand Up @@ -602,7 +602,7 @@ export class CommandsExtension extends PlainExtension<CommandOptions> {
return false;
}

dispatch?.(tr.setSelection(TextSelection.create(tr.doc, tr.selection.anchor)));
dispatch?.(tr.setSelection(TextSelection.near(tr.selection.$anchor)));
return true;
};
}
Expand Down

0 comments on commit f274e22

Please sign in to comment.