Skip to content

Commit

Permalink
feat: add package @remirror/extension-track-changes
Browse files Browse the repository at this point in the history
New package based on prosemirror website demo.
  • Loading branch information
ifiokjr committed Jun 15, 2020
1 parent c61dc5c commit e458b2a
Show file tree
Hide file tree
Showing 14 changed files with 830 additions and 23 deletions.
7 changes: 0 additions & 7 deletions @remirror/core-helpers/src/core-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,13 +459,6 @@ export function isEmptyArray(value: unknown): value is never[] {
return isArray(value) && value.length === 0;
}

/**
* Predicate check that the value is not empty.
*/
export function isNotEmpty(value: unknown) {
return value !== '' || !isEmptyArray(value) || !isEmptyObject(value);
}

/**
* Identifies the value as having a remirror identifier. This is the core
* predicate check for the remirror library.
Expand Down
23 changes: 19 additions & 4 deletions @remirror/core/src/builtins/plugins-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ErrorConstant, ExtensionPriority, ManagerPhase } from '@remirror/core-c
import { invariant, isEmptyArray, object } from '@remirror/core-helpers';
import { EditorSchema, ProsemirrorPlugin } from '@remirror/core-types';
import { getPluginState } from '@remirror/core-utils';
import { Plugin, PluginKey, PluginSpec } from '@remirror/pm/state';
import { EditorState, Plugin, PluginKey, PluginSpec } from '@remirror/pm/state';

import {
AnyExtension,
Expand Down Expand Up @@ -79,10 +79,10 @@ export class PluginsExtension extends PlainExtension {

// Assign the plugin key to the extension name.
this.pluginKeys[extension.name] = key;
const getter = <State>() => getPluginState<State>(key, this.store.getState());
const getter = this.getPluginStateCreator(key, extension);

extension.pluginKey = key;
extension.getPluginState = getter;
extension.constructor.prototype.getPluginState = getter;

this.stateGetters.set(extension.name, getter);
this.stateGetters.set(extension.constructor, getter);
Expand All @@ -105,6 +105,17 @@ export class PluginsExtension extends PlainExtension {
}
}

private readonly getPluginStateCreator = (key: PluginKey, extension: AnyExtension) => <State>(
state?: EditorState,
) => {
invariant(this.store.phase >= ManagerPhase.EditorView || state, {
code: ErrorConstant.MANAGER_PHASE_ERROR,
message: `The 'getPluginState' method of '${extension.constructor.name}' must be called with a current state if called before the 'view' has been added to the manager.`,
});

return getPluginState<State>(key, state ?? this.store.getState());
};

/**
* Add or replace a plugin.
*/
Expand Down Expand Up @@ -327,8 +338,12 @@ declare global {
*
* This is only available after the initialize stage of the editor manager
* lifecycle.
*
* If you would like to use it before that e.g. in the decorations prop of
* the `createPlugin` method, you can call it with a current state which
* will be used to retrieve the plugin state.
*/
getPluginState: <State>() => State;
getPluginState: <State>(state?: EditorState) => State;

/**
* The plugin key for custom plugin created by this extension. This only
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
DefaultExtensionOptions,
getPluginMeta,
HandlerKeyList,
isNotEmpty,
isEmptyArray,
isNullOrUndefined,
isNumber,
isString,
Expand Down Expand Up @@ -118,7 +118,7 @@ export class PositionTrackerExtension extends PlainExtension<PositionTrackerOpti
const decorations = this.getPluginState<DecorationSet>();
const found = decorations.find(undefined, undefined, (spec) => spec.id === id);

return isNotEmpty(found.length) ? found[0].from : undefined;
return !isEmptyArray(found) ? found[0].from : undefined;
},

/**
Expand Down
9 changes: 2 additions & 7 deletions @remirror/extension-search/src/search-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
isString,
KeyBindingCommandFunction,
KeyBindings,
ManagerPhase,
object,
PlainExtension,
ProsemirrorNode,
Expand Down Expand Up @@ -185,12 +184,8 @@ export class SearchExtension extends PlainExtension<SearchOptions> {
},

props: {
decorations: () => {
if (this.store.phase >= ManagerPhase.EditorView) {
return this.getPluginState();
}

return DecorationSet.empty;
decorations: (state) => {
return this.getPluginState(state);
},
},
};
Expand Down
6 changes: 6 additions & 0 deletions @remirror/extension-track-changes/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const config = require('../../support/jest/jest.config');

module.exports = {
...config,
displayName: { name: require('./package.json').name.replace('@remirror/', ''), color: 'pink' },
};
39 changes: 39 additions & 0 deletions @remirror/extension-track-changes/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "@remirror/extension-track-changes",
"version": "0.0.0",
"description": "Track user changes in your remirror editor.",
"keywords": [
"remirror",
"extension"
],
"homepage": "https://github.com/remirror/remirror/tree/next/@remirror/extension-track-changes",
"repository": "https://github.com/remirror/remirror/tree/master/@remirror/extension-track-changes",
"license": "MIT",
"contributors": [
"Ifiok Jr. <ifiokotung@gmail.com>"
],
"sideEffects": false,
"main": "dist/extension-track-changes.cjs.js",
"module": "dist/extension-track-changes.esm.js",
"types": "dist/extension-track-changes.cjs.d.ts",
"files": [
"dist"
],
"dependencies": {
"@babel/runtime": "^7.10.2"
},
"devDependencies": {
"@remirror/core": "^0.11.0",
"@remirror/pm": "^0.0.0"
},
"peerDependencies": {
"@remirror/core": "^0.11.0",
"@remirror/pm": "^0.0.0"
},
"publishConfig": {
"access": "public"
},
"meta": {
"sizeLimit": "5 KB"
}
}
44 changes: 44 additions & 0 deletions @remirror/extension-track-changes/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# @remirror/extension-track-changes

> Track user changes in your remirror editor.
[![Version][version]][npm] [![Weekly Downloads][downloads-badge]][npm]
[![Bundled size][size-badge]][size] [![Typed Codebase][typescript]](./src/index.ts)
![MIT License][license]

[version]: https://flat.badgen.net/npm/v/@remirror/extension-track-changes
[npm]: https://npmjs.com/package/@remirror/extension-track-changes
[license]: https://flat.badgen.net/badge/license/MIT/purple
[size]: https://bundlephobia.com/result?p=@remirror/extension-track-changes
[size-badge]: https://flat.badgen.net/bundlephobia/minzip/@remirror/extension-track-changes
[typescript]: https://flat.badgen.net/badge/icon/TypeScript?icon=typescript&label
[downloads-badge]: https://badgen.net/npm/dw/@remirror/extension-track-changes/red?icon=npm

## Installation

```bash
# yarn
yarn add @remirror/extension-track-changes @remirror/pm

# pnpm
pnpm add @remirror/extension-track-changes @remirror/pm

# npm
npm install @remirror/extension-track-changes @remirror/pm
```

## Usage

The following code creates an instance of this extension.

```ts
import { TrackChangesExtension } from '@remirror/extension-track-changes';

const extension = new TrackChangesExtension();
```

## Credits

This package was bootstrapped with [monots].

[monots]: https://github.com/monots/monots
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { renderEditor } from 'jest-remirror';

import { isExtensionValid } from '@remirror/test-fixtures';

import { TrackChangesExtension, TrackChangesOptions } from '..';

test('is valid', () => {
expect(isExtensionValid(TrackChangesExtension, {}));
});

function create(options?: TrackChangesOptions) {
const {
add,
nodes: { p, doc },
view,
commands,
helpers,
} = renderEditor([new TrackChangesExtension(options)]);
const node = doc(p('This is not yet committed'));

return { add, p, doc, view, commands, node, helpers };
}

test('#commitChange', () => {
const { add, commands, node, helpers } = create();

const { insertText } = add(node);

commands.commitChange('first commit');
expect(helpers.getCommits()).toHaveLength(1);

insertText('\nmore stuff');
commands.commitChange('commit two');

expect(helpers.getCommits().map((commit) => commit.message)).toMatchInlineSnapshot(`
Array [
"first commit",
"commit two",
]
`);
});

describe('#revertCommit', () => {
it('can revert the commit', () => {
const { add, commands, node, helpers, view } = create();

const { insertText } = add(node);
commands.commitChange('first commit');

insertText('\nmore stuff');
commands.commitChange('commit two');

commands.revertCommit();

expect(helpers.getCommits().map((commit) => commit.message)).toMatchInlineSnapshot(`
Array [
"first commit",
"commit two",
"Revert: 'commit two'",
]
`);

expect(view.state.doc).toEqualRemirrorDocument(node);
});

it('can revert any of the commits', () => {
const { add, commands, node, helpers, view, doc, p } = create();

const { insertText } = add(node);
commands.commitChange('first commit');

insertText('\nmore stuff');
commands.commitChange('commit two');
insertText(' final changes');
commands.commitChange('final commit');

const commit = helpers.getCommit(1);
commands.revertCommit(commit);

expect(helpers.getCommits().map((commit) => commit.message)).toMatchInlineSnapshot(`
Array [
"first commit",
"commit two",
"final commit",
"Revert: 'commit two'",
]
`);

expect(view.state.doc).toEqualRemirrorDocument(
doc(p('This is not yet committed final changes')),
);
});

it.todo('test when the first commit is reverted');
});
1 change: 1 addition & 0 deletions @remirror/extension-track-changes/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './track-changes-extension';

0 comments on commit e458b2a

Please sign in to comment.