Skip to content

Commit

Permalink
fix(react-core): each useChainedCommands call should refer to a new…
Browse files Browse the repository at this point in the history
… command chain (#2118)
  • Loading branch information
whawker committed Jul 13, 2023
1 parent db1a772 commit 1b37716
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 7 deletions.
15 changes: 15 additions & 0 deletions .changeset/itchy-cows-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@remirror/core': patch
'@remirror/react-core': patch
---

Add the ability to reset a command chain with `.new()`.

```ts
chain.toggleBold();
chain.new().toggleItalic().run(); // Only toggleItalic would be run
```

This is automatically executed for you when using the `useChainedCommands()` hook.

This ensures that when calling the hook multiple times, each command chain is independent of the other.
32 changes: 32 additions & 0 deletions packages/remirror__core/__tests__/commands-extension.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,38 @@ test('can chain commands', () => {
expect(editor.state.doc).toEqualRemirrorDocument(doc(p(bold(italic('my content')))));
});

test('can create a new command chain with `new()`', () => {
const editor = renderEditor([new BoldExtension(), new ItalicExtension()]);
const { doc, p } = editor.nodes;
const { italic } = editor.marks;
const { chain } = editor;

editor.add(doc(p('<start>my content<end>')));
chain.toggleBold();
chain.new().toggleItalic().run();

expect(editor.state.doc).toEqualRemirrorDocument(doc(p(italic('my content'))));
});

test('can use multiple commands chains with `.new()`', () => {
const editor = renderEditor([new BoldExtension(), new ItalicExtension()]);
const { doc, p } = editor.nodes;
const { bold, italic } = editor.marks;
const { chain: chain1 } = editor;

editor.add(doc(p('<start>my content<end>')));
chain1.toggleBold();

const chain2 = chain1.new();
chain2.toggleItalic().run();

expect(editor.state.doc).toEqualRemirrorDocument(doc(p(italic('my content'))));

chain1.run();

expect(editor.state.doc).toEqualRemirrorDocument(doc(p(bold(italic('my content')))));
});

test('clears range selection', () => {
const text = 'my content';

Expand Down
6 changes: 5 additions & 1 deletion packages/remirror__core/src/builtins/commands-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ export class CommandsExtension extends PlainExtension<CommandOptions> {
return true;
};

customChain.new = (tr?: Transaction) => {
return chain(tr);
};

return customChain;
};

Expand Down Expand Up @@ -1279,7 +1283,7 @@ interface ChainedFactoryProps {
/**
* The names that are forbidden from being used as a command name.
*/
const forbiddenNames = new Set(['run', 'chain', 'original', 'raw', 'enabled', 'tr']);
const forbiddenNames = new Set(['run', 'chain', 'original', 'raw', 'enabled', 'tr', 'new']);

declare global {
namespace Remirror {
Expand Down
26 changes: 21 additions & 5 deletions packages/remirror__core/src/extension/extension-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,21 @@ export interface ChainedCommandProps {
enabled: () => boolean;
}

export interface NewChainedCommandProps<
Extension extends AnyExtension,
Chained extends ChainedIntersection<Extension> = ChainedIntersection<Extension>,
> {
/**
* Returns a new chain, with an empty command set.
*
* ```ts
* chain.toggleBold();
* chain.new().toggleItalic().run(); // Only toggleItalic would be run
* ```
*/
new: (tr?: Transaction) => ChainedFromExtensions<Extension, Chained>;
}

export type ChainedIntersection<Extension extends AnyExtension> = UnionToIntersection<
MapToChainedCommand<GetCommands<Extension> | GetDecoratedCommands<Extension>>
>;
Expand All @@ -152,11 +167,12 @@ export type ChainedFromExtensions<
type _ChainedFromExtensions<
Extension extends AnyExtension,
Chained extends ChainedIntersection<Extension> = ChainedIntersection<Extension>,
> = ChainedCommandProps & {
[Command in keyof Chained]: Chained[Command] extends (...args: any[]) => any
? (...args: Parameters<Chained[Command]>) => ChainedFromExtensions<Extension>
: never;
};
> = ChainedCommandProps &
NewChainedCommandProps<Extension, Chained> & {
[Command in keyof Chained]: Chained[Command] extends (...args: any[]) => any
? (...args: Parameters<Chained[Command]>) => ChainedFromExtensions<Extension>
: never;
};

/**
* Utility type for pulling all the command names from a list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ import { useRemirrorContext } from './use-remirror-context';
export function useChainedCommands<
Extension extends AnyExtension = Remirror.Extensions | AnyExtension,
>(): ChainedFromExtensions<Extension> {
return useRemirrorContext<Extension>().chain;
return useRemirrorContext<Extension>().chain.new();
}

1 comment on commit 1b37716

@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.

🎉 Published on https://remirror.io as production
🚀 Deployed on https://64b028635ad959125c4ce162--remirror.netlify.app

Please sign in to comment.