Skip to content

Commit

Permalink
fix(entity-reference): add helper and command to entity-reference ext…
Browse files Browse the repository at this point in the history
…ension (#1742)

* fix(entity-reference): add `getEntityReferenceById` helper and `scrollToEntityReference` command

* Update packages/remirror__extension-entity-reference/src/entity-reference-extension.ts

Co-authored-by: ocavue <ocavue@users.noreply.github.com>

* Add unit test for selection of scrollIntoEntityReference command

* Add story for scrolling into an entity reference

* Update packages/remirror__extension-entity-reference/src/entity-reference-extension.ts

Co-authored-by: Will Hawker <whawker@users.noreply.github.com>

* Update packages/remirror__extension-entity-reference/src/entity-reference-extension.ts

Co-authored-by: Will Hawker <whawker@users.noreply.github.com>

* Update test scrollToEntityReferene to select all the doc instead of remove selection"

Remove unnecessary dispatch call

Co-authored-by: Idriss mahjoubi <mahjoubi.idriss@gmail.com>
Co-authored-by: ocavue <ocavue@users.noreply.github.com>
Co-authored-by: Will Hawker <whawker@users.noreply.github.com>
  • Loading branch information
4 people committed Jul 6, 2022
1 parent f2f053b commit 2e7d7f0
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,47 @@ describe('EntityReference marks', () => {
expect(entityReferences).toHaveLength(2);
});
});

describe('getEntityReferenceId', () => {
it('Returns entityReference by Id', () => {
add(doc(p('testing text')));
const entityReference = {
id: 'testId',
from: 1,
to: 8,
text: 'testing',
};
selectText({ from: entityReference.from, to: entityReference.to });
commands.addEntityReference(entityReference.id);
const entityReferenceFromDoc = helpers.getEntityReferenceById(entityReference.id);

expect(entityReferenceFromDoc).toEqual(entityReference);
});
});

describe('scrollIntoEntityReference', () => {
it('returns correct range when the selection is not empty', () => {
const editor = add(doc(p(DUMMY_TEXT)));
const entityReference = {
id: 'testId',
from: 3,
to: 8,
text: 'testing',
};
commands.selectText({ from: entityReference.from, to: entityReference.to });
commands.addEntityReference(entityReference.id);

// Fire an update to remove the current range selection and select all the document instead.
editor.commands.selectAll();

expect(editor.state.selection.from).not.toBe(entityReference.from);
expect(editor.state.selection.to).not.toBe(entityReference.to);

const selected = commands.scrollToEntityReference(entityReference.id);

expect(selected).toBeTrue();
expect(editor.state.selection.from).toBe(entityReference.from);
expect(editor.state.selection.to).toBe(entityReference.to);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
within,
} from '@remirror/core';
import { Node } from '@remirror/pm/model';
import { EditorStateConfig } from '@remirror/pm/state';
import { EditorStateConfig, TextSelection } from '@remirror/pm/state';
import { DecorationSet } from '@remirror/pm/view';

import { EntityReferenceMetaData, EntityReferenceOptions } from './types';
Expand Down Expand Up @@ -169,6 +169,33 @@ export class EntityReferenceExtension extends MarkExtension<EntityReferenceOptio
};
}

/**
* Dispatch a transaction that selects the range of the entity reference then scrolls to it.
*
* @param entityReferenceId - The entity's reference Id.
*
* @returns True if the scrolling was applied, else it returns false
*
*/
@command()
scrollToEntityReference(entityReferenceId: string): CommandFunction {
return ({ tr, dispatch }) => {
const entityReference = this.getEntityReferenceById(entityReferenceId);

if (!entityReference) {
return false;
}

const { doc } = tr;
const resolvedFrom = doc.resolve(entityReference.from);
const resolvedTo = doc.resolve(entityReference.to);
const entityReferenceSelection = TextSelection.between(resolvedFrom, resolvedTo);
// Select range and scroll into it
dispatch?.(tr.setSelection(entityReferenceSelection).scrollIntoView());
return true;
};
}

/**
* Get all disjoined entityReference attributes from the document.
*/
Expand Down Expand Up @@ -212,6 +239,23 @@ export class EntityReferenceExtension extends MarkExtension<EntityReferenceOptio
return joinDisjoinedEntityReferences(entityReferences);
}

/**
* @param entityReferenceId - The entity's reference Id.
*
* @returns EntityReference attributes from the editor's content, undefined if it doesn't exist.
*
*/
@helper()
getEntityReferenceById(entityReferenceId: string): Helper<EntityReferenceMetaData | undefined> {
const entityReferences = getEntityReferencesFromPluginState({
extension: this,
state: this.store.getState(),
}).flat();
return joinDisjoinedEntityReferences(entityReferences).find(
(entityReference) => entityReference.id === entityReferenceId,
);
}

/**
* @param pos - the position in the root document to find entityReference marks.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Highlights from './highlights';
import ScrollIntoHighlight from './scroll-to-highlight';

export default { title: 'Extensions / EntityReference' };

export { Highlights as Highlight };
export { ScrollIntoHighlight as ScrollIntoHighlight };
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'remirror/styles/all.css';
import './styles.css';

import React from 'react';
import { EntityReferenceExtension } from 'remirror/extensions';
import { Remirror, ThemeProvider, useRemirror } from '@remirror/react';

const extensions = () => [new EntityReferenceExtension()];

const TEST_ID = 'testId';
const lineBreakHTML = `<p><br class="ProseMirror-trailingBreak"></p>`;
const numberOfLineBreaks = 100;

const ScrollIntoHighlight = (): JSX.Element => {
const { manager, state, onChange } = useRemirror({
extensions: extensions,
content: `${lineBreakHTML.repeat(
numberOfLineBreaks,
)}<p>Highlight <span data-entity-reference=${TEST_ID}>important and interesting</span> text</p>`,
stringHandler: 'html',
});

return (
<ThemeProvider>
<Remirror manager={manager} onChange={onChange} initialContent={state} autoRender='end'>
<button
onMouseDown={(event) => event.preventDefault()}
onClick={() => manager.store.commands.scrollToEntityReference(TEST_ID)}
>
Scroll into highlight
</button>
</Remirror>
</ThemeProvider>
);
};

export default ScrollIntoHighlight;

1 comment on commit 2e7d7f0

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.