Skip to content

Commit

Permalink
feat: ignore suggester matches
Browse files Browse the repository at this point in the history
  • Loading branch information
ifiokjr committed Sep 25, 2019
1 parent d060eb1 commit de8d774
Show file tree
Hide file tree
Showing 13 changed files with 363 additions and 73 deletions.
2 changes: 1 addition & 1 deletion @remirror/extension-emoji/src/emoji-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export class EmojiExtension extends Extension<EmojiExtensionOptions> {
// const fn = debounce(100, sortEmojiMatches);

return {
ignoreDecorations: true,
noDecorations: true,
invalidPrefixCharacters: escapeStringRegex(suggestionCharacter),
char: suggestionCharacter,
name: this.name,
Expand Down
4 changes: 2 additions & 2 deletions @remirror/extension-mention/src/mention-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ export class MentionExtension extends MarkExtension<MentionExtensionOptions> {
matchers,
onChange,
onExit,
ignoreDecorations,
noDecorations,
keyBindings,
onCharacterEntry,
suggestTag,
Expand All @@ -232,7 +232,7 @@ export class MentionExtension extends MarkExtension<MentionExtensionOptions> {
return {
...DEFAULT_MATCHER,
...matcher,
ignoreDecorations,
noDecorations,
suggestTag,
onChange,
onExit,
Expand Down
2 changes: 1 addition & 1 deletion @remirror/extension-mention/src/mention-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export interface MentionExtensionOptions
extends MarkExtensionOptions,
Pick<
Suggester<MentionExtensionSuggestCommand>,
'suggestTag' | 'ignoreDecorations' | 'onChange' | 'onExit' | 'onCharacterEntry' | 'keyBindings'
'suggestTag' | 'noDecorations' | 'onChange' | 'onExit' | 'onCharacterEntry' | 'keyBindings'
> {
/**
* Provide a custom matcher with options
Expand Down
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project will adhere to [Semantic Versioning](https://semver.org/spec/v2

## [Unreleased]

### Added

- `jest-prosemirror`: New snapshot serializer exported as `prosemirrorSerializer`.
- `jest-prosemirror`: New debug method.
- `prosemirror-suggest`: Now supports ignored matches to prevent matches from appearing in ignored sections.

## [0.5.0] - 2019-09-23

### Added
Expand Down
52 changes: 50 additions & 2 deletions packages/jest-prosemirror/src/jest-prosemirror-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
ProsemirrorNode,
isString,
} from '@remirror/core';
import { EventType, fireEvent } from '@testing-library/dom';
import { EventType, fireEvent, prettyDOM } from '@testing-library/dom';
import { inputRules } from 'prosemirror-inputrules';
import { AllSelection, NodeSelection, TextSelection } from 'prosemirror-state';
import { TaggedProsemirrorNode } from 'prosemirror-test-builder';
Expand Down Expand Up @@ -166,6 +166,30 @@ export const press = <GSchema extends EditorSchema = any>({ view, char }: PressP
});
};

/**
* Simulate a backspace key press..
*/
export const backspace = <GSchema extends EditorSchema = any>({
view,
times = 1,
}: TestEditorViewParams<GSchema> & { times?: number }) => {
const { selection, tr } = view.state;
const { from, empty } = selection;

if (empty) {
view.dispatch(tr.delete(from - times, from));
return;
}

tr.deleteSelection();

if (times > 1) {
tr.delete(from - (times - 1), from);
}

view.dispatch(tr);
};

interface KeyboardShortcutParams<GSchema extends EditorSchema = any> extends TestEditorViewParams<GSchema> {
/**
* The keyboard shortcut to run
Expand Down Expand Up @@ -340,6 +364,10 @@ export const createEditor = <GSchema extends EditorSchema = any>(
});
}

const debug = () => {
console.log(prettyDOM(view.dom as HTMLElement));
};

const createReturnValue = () => {
const { selection, doc } = view.state;
const returnValue = {
Expand Down Expand Up @@ -470,6 +498,22 @@ export const createEditor = <GSchema extends EditorSchema = any>(
return createReturnValue();
},

/**
* Simulates a backspace keypress and deletes text backwards.
*/
backspace: (times?: number) => {
backspace({ view, times });
return createReturnValue();
},

/**
* Logs to the dom for help debugging your tests.
*/
debug: () => {
debug();
return createReturnValue();
},

/**
* Fire an event in the editor (very hit and miss).
*
Expand All @@ -485,7 +529,7 @@ export const createEditor = <GSchema extends EditorSchema = any>(
* for easier testing of the current state of the editor.
*/
callback: (fn: (content: ReturnValueCallbackParams<GSchema>) => void) => {
fn(pick(returnValue, ['start', 'end', 'state', 'view', 'schema', 'selection', 'doc']));
fn({ ...pick(returnValue, ['start', 'end', 'state', 'view', 'schema', 'selection', 'doc']), debug });
return createReturnValue();
},

Expand Down Expand Up @@ -515,6 +559,10 @@ export interface ReturnValueCallbackParams<GSchema extends EditorSchema = any>
end: number;
schema: GSchema;
doc: ProsemirrorNode;
/**
* Pretty log the current view to the dom.
*/
debug(): void;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/prosemirror-suggest/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const suggestEmojis: Suggester = {
* In this example we don't need decorations (in fact they cause problems when the
* emoji string replaces the query text in the dom).
*/
ignoreDecorations: true,
noDecorations: true,
char: ':', // The character to match against
name: 'emoji-suggestion', // a unique name
appendText: '', // Text to append to the created match
Expand Down Expand Up @@ -133,7 +133,7 @@ This `Suggester` interface provides the options object which is used within the
| [appendText](https://github.com/ifiokjr/remirror/blob/canary/docs/api/prosemirror-suggest.suggester.appendtext.md) | <code>string</code> | Text to append after the mention has been added. |
| [char](https://github.com/ifiokjr/remirror/blob/canary/docs/api/prosemirror-suggest.suggester.char.md) | <code>string</code> | The character to match against. |
| [decorationsTag](https://github.com/ifiokjr/remirror/blob/canary/docs/api/prosemirror-suggest.suggester.decorationstag.md) | <code>keyof HTMLElementTagNameMap</code> | Tag which wraps an active match. |
| [ignoreDecorations](https://github.com/ifiokjr/remirror/blob/canary/docs/api/prosemirror-suggest.suggester.ignoredecorations.md) | <code>boolean</code> | When true, decorations are not created when this mention is being edited.. |
| [noDecorations](https://github.com/ifiokjr/remirror/blob/canary/docs/api/prosemirror-suggest.suggester.ignoredecorations.md) | <code>boolean</code> | When true, decorations are not created when this mention is being edited.. |
| [invalidPrefixCharacters](https://github.com/ifiokjr/remirror/blob/canary/docs/api/prosemirror-suggest.suggester.invalidprefixcharacters.md) | <code>RegExp &#124; string</code> | A regex expression used to invalidate the text directly before the match. |
| [keyBindings](https://github.com/ifiokjr/remirror/blob/canary/docs/api/prosemirror-suggest.suggester.keybindings.md) | <code>SuggestKeyBindingMap&lt;GCommand&gt;</code> | An object that describes how certain key bindings should be handled. |
| [matchOffset](https://github.com/ifiokjr/remirror/blob/canary/docs/api/prosemirror-suggest.suggester.matchoffset.md) | <code>number</code> | Sets the characters that need to be present after the initial character match before a match is triggered.<!-- -->For example with <code>char</code> = <code>@</code> the following is true.<!-- -->- <code>matchOffset: 0</code> matches <code>'@'</code> immediately - <code>matchOffset: 1</code> matches <code>'@a'</code> but not <code>'@'</code> - <code>matchOffset: 2</code> matches <code>'@ab'</code> but not <code>'@a'</code> or <code>'@'</code> - <code>matchOffset: 3</code> matches <code>'@abc'</code> but not <code>'@ab'</code> or <code>'@a'</code> or <code>'@'</code> - And so on... |
Expand Down
39 changes: 39 additions & 0 deletions packages/prosemirror-suggest/src/__tests__/suggest-plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,42 @@ test('handles jumping with two suggesters', () => {
expect(handlers2.onChange).not.toHaveBeenCalled();
});
});

test('ignore matches', () => {
let clearIgnored: () => void;
const handlers = {
onExit: jest.fn(
({
addIgnored,
range: { from },
suggester: { char, name },
clearIgnored: clear,
}: SuggestExitHandlerParams) => {
addIgnored({ from, char, name });
clearIgnored = clear;
},
),
onChange: jest.fn(),
};
const plugin = suggest({ char: '@', name: 'at', ...handlers });

createEditor(doc(p('<cursor>')), { plugins: [plugin] })
.insertText('@abc ')
.callback(() => {
expect(handlers.onExit).toHaveBeenCalledTimes(1);
expect(handlers.onChange).toHaveBeenCalledTimes(4);
jest.clearAllMocks();
})
.backspace(3)
.callback(() => expect(handlers.onChange).not.toHaveBeenCalled())
.insertText('b ')
.callback(() => {
expect(handlers.onExit).not.toHaveBeenCalled();
clearIgnored();
})
.backspace(2)
.insertText('bc')
.callback(() => {
expect(handlers.onChange).toHaveBeenCalledTimes(3);
});
});
2 changes: 1 addition & 1 deletion packages/prosemirror-suggest/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
* // suggestion in the dom.
* // In this example we don't need decorations (in fact they cause problems when the
* // emoji string replaces the query text in the dom).
* ignoreDecorations: true,
* noDecorations: true,
* char: ':', // The character to match against
* name: 'emoji-suggestion', // a unique name
* appendText: '', // Text to append to the created match
Expand Down
24 changes: 13 additions & 11 deletions packages/prosemirror-suggest/src/suggest-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@ export const DEFAULT_SUGGEST_ACTIONS = { command: noop, create: noop, remove: no
const defaultHandler = () => false;

export const DEFAULT_SUGGESTER = {
startOfLine: false,
supportedCharacters: /[\w\d_]+/,
matchOffset: 0,
appendText: '',
suggestTag: 'span' as 'span',
suggestClassName: 'suggest',
onChange: defaultHandler,
onExit: defaultHandler,
onCharacterEntry: defaultHandler,
keyBindings: {},
createCommand: () => noop,
getStage: () => 'new' as const,
ignoreDecorations: false,
validPrefixCharacters: /^[\s\0]?$/,
ignoredClassName: undefined as any,
ignoredTag: 'span',
invalidPrefixCharacters: undefined as any,
keyBindings: {},
matchOffset: 0,
noDecorations: false,
onChange: defaultHandler,
onCharacterEntry: defaultHandler,
onExit: defaultHandler,
startOfLine: false,
suggestClassName: 'suggest',
suggestTag: 'span',
supportedCharacters: /[\w\d_]+/,
validPrefixCharacters: /^[\s\0]?$/,
};

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/prosemirror-suggest/src/suggest-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const getSuggestPluginState = <GSchema extends EditorSchema = any>(state:
* // suggestion in the dom.
* // In this example we don't need decorations (in fact they cause problems when the
* // emoji string replaces the query text in the dom).
* ignoreDecorations: true,
* noDecorations: true,
* char: ':', // The character to match against
* name: 'emoji-suggestion', // a unique name
* appendText: '', // Text to append to the created match
Expand Down

0 comments on commit de8d774

Please sign in to comment.