Bot releases are hidden (Show)
Published by whawker 11 months ago
TLDR: Remirror aims to be a better citizen, by not imposing our architectural decisions on to you.
This version aims to make it easier to use Remirror in existing applications, by not imposing our architectural decisions on to you.
The core of Remirror v2 relied on packages such as @mui/material
to power our menus and toolbars, and @lingui/core
to provide internationalisation (i18n) support.
However, after gathering feedback from the Remirror community, we found that most users wanted to integrate Remirror into existing applications, where design systems were already in place, and i18n solutions already present.
This meant Remirror's core created unnecessary pain points - translations needed to be encoded specifically for Remirror, in a different way to the rest of the application. For other users the menus we provided didn't fit with their application's existing design system, so Remirror ended up bloating the application unnecessarily with MUI components that weren't even used.
To alleviate these pain points we have removed these features from the core, and moved them into optional packages.
This enables Remirror to continue to support its main goal:
[!NOTE]
Remirror goal: "From Newbie to Pro"
Designed to grow with your skill set. Start with the out-of-the-box editor. Customize with components, React hooks, down to bare metal ProseMirror.
Our "out-of-the-box" editors (components exposed via @remirror/react-editors
) include these new optional packages by default, so should have no breaking changes.
However, for more advanced scenarios we can use our Lego principle, allowing Remirror users to choose modules that make sense for their use case and build bespoke experiences for their applications.
[!NOTE]
"Out-of-the-box" (@remirror/react-editors
) editors unaffected, these have been updated to keep v2 behaviour.
In Remirror v3, we want to allow any i18n library to be used with Remirror, instead of forcing Lingui upon you.
The root <Remirror />
component now supports an i18nFormat
prop, that allows you to plug in any i18n library, by implementing a definition for this function.
If you want to keep the existing behaviour from v2, you can pass the i18nFormat
function exposed from the now optional package @remirror/i18n
We have Storybook examples showing integrations with many populate i18n libraries, and our "How to migrate" section below.
[!NOTE]
"Out-of-the-box" (@remirror/react-editors
) editors unaffected, these have been updated to keep v2 behaviour.
Remirror v3 decouples the React core of Remirror from MUI, reducing the size of @remirror/react
considerably, as installing @remirror/react
will no longer bundle @mui/material
too
The MUI components (menus and toolbars) previously exposed by @remirror/react
have been moved to a new optional package - @remirror/react-ui
.
Additionally, these MUI components should now adhere to the theme of the parent application, if you're already using MUI.
The components themselves should have no breaking changes, only their import paths have changed.
For a full list of affected components, please see our "How to migrate" section below.
[!NOTE]
This is an internal change, there should be no breaking changes to the public API.
Our decorators (i.e. @extension
, @command
, @keyBinding
, etc), have been updated to use ES Stage-3 decorators syntax, instead of TypeScript's experimental decorator syntax.
We've made a small change to ensure mention atoms are included in plain text by returning their label
attribute value.
This can be modified using the nodeOverrides
API and overriding the leafText
function.
Remirror v3 also removes deprecated features, but in the vast majority of changes alternatives exist. We have highlighted a few of the key removals below, but the rest with be covered in the migration guide
SearchExtension
removed, please use FindExtension
insteadThe FindExtension
moves out of beta and into the core, as it offers more features and is more performant than the removed SearchExtension
.
Furthermore, to make the find functionality easy to use, we have added a new <FindButton />
component to the optional @remirror/react-ui
package.
This button can be used within a Toolbar
(also exposed via @remirror/react-ui
) to present a find and replace popup in the top right of your editor.
isEnabled
removed, use enabled
insteadWhen using commands or chained commands, you can "dry run" the command to see if it can be executed against the current editor state.
For instance, you can check if toggleBold
is enabled by running toggleBold.enabled()
which returns a boolean indicating whether it is possible, without actually changing the editor's state.
.isEnabled()
was an alias of .enabled()
, but this alias has now been removed. Please use .enabled()
instead.
Please consult the migration guide and reach out on Discord if you run into any issues.
As this is a beta version we'd really love your feedback to check everything works as expected. Please raise any issues on GitHub or via our Discord server.
As always, reach out to use via our Discord server if you have any suggestions on how we could improve Remirror in general.
Published by ifiokjr over 3 years ago
The new version of remirror
comes with a number of enhancements and quite a few breaking changes if you were using the [email protected].*
pre-releases.
The following sections outline the breaking changes and how they can be migrated if your last version was @next
. For those upgrading from 0.11.0
the library has changed drastically and you'd be better off browsing the documentation.
remirror/extensions
When you install the top level remirror
package you are given access to every extension developed by remirror
via the remirror/extension
entry point.
- import { BoldExtension } from 'remirror/extension/bold';
- import { ItalicExtension } from 'remirror/extension/italic';
+ import { BoldExtension, ItalicExtension } from 'remirror/extensions';
You can also still install the extensions directly from their scoped packages.
import { BoldExtension } from '@remirror/extension-bold';
remirror/react
which has been replaced by @remirror/react
If your code is importing from remirror/react
you should now change the import to @remirror/react
.
- import { useManager } from 'remirror/react';
+ import { useRemirror } from '@remirror/react';
@remirror/react
APIuseRemirror
to now be called useRemirrorContext
.@remirror/react-components
package.@remirror/react
exports all the hooks, components, core modules and react specific extensions from @remirror/react-core
, @remirror/react-components
, @remirror/react-hooks
and @remirror/extension-react
.useManager
was too focused on the implementation details. We've updated the API to be used in a different way and useRemirror
is now the way to initialize an editor.
import React from 'react';
import { BoldExtension, ItalicExtension, UnderlineExtension } from 'remirror/extensions';
import { Remirror, useRemirror } from '@remirror/react';
const extensions = () => [new BoldExtension(), new ItalicExtension(), new UnderlineExtension()];
const Editor = () => {
const { manager } = useRemirror({ extensions });
return <Remirror manager={manager} />;
};
The previous useRemirror
is now called useRemirrorContext
since it plucks the context from the outer Remirror
Component. The has been renamed to <RemirrorProvider />
<Remirror />
and automatically renders an editor.
When no children are provided to the <Remirror />
component it will automatically render a container div
where the prosemirror editor will be placed. If you do add children it is up to you to import the <EditorComponent />
and add it to the children or set the autoRender
prop to 'start' | 'end' | true
.
has been marked as useManager
@internal
(although it is still exported) and going forward you should be using useRemirror
as shown in the above example.
@remirror/extension-tables
@remirror/preset-table
is now @remirror/extension-tables
. The TableExtension
uses the new createExtension
method to inject the TableRowExtension
which in turn injects the TableCellExtension
and TableHeaderCellExtension
. To use tables in your editor the following is sufficient.
import { TableExtension } from 'remirror/extensions';
import { Remirror, useRemirror } from '@remirror/react';
const Editor = () => {
const { manager } = useRemirror({ extensions: () => [TableExtension()] });
return <Remirror manager={manager} />;
};
@remirror/extension-positioner
New Rect
interface returned by the positioner x: number; y: number; width: number; height: number;
Added visible
property which shows if the position currently visible within the editor viewport.
Improved scrolling when using the positioner.
Fixed a lot of bugs in the positioner API.
This DOMRect represents an absolute position within the document. It is up to your consuming component to consume the rect.
Renamed the positioners in line with the new functionality.
import React from 'react';
import { BoldExtension, CorePreset, ItalicExtension, MarkdownExtension } from 'remirror/extension';
import { Remirror, useRemirror } from '@remirror/react';
const Editor = () => {
const { manager, onChange, state } = useRemirror({
extensions: () => [new BoldExtension(), new ItalicExtension()],
content: '<p><strong>I am strong.</strong> and <em>I am emphasized</em></p>',
stringHandler: 'html',
});
return <Remirror manager={manager} onChange={onChange} state={state} />;
};
@remirror/react-hooks
useKeymap
to useKeymaps
. The original useKeymap
now has a different signature.import { useCallback } from 'react';
import { BoldExtension } from 'remirror/extensions';
import { Remirror, useHelpers, useKeymap, useRemirror, useRemirrorContext } from '@remirror/react';
const hooks = [
() => {
const active = useActive();
const { insertText } = useCommands();
const boldActive = active.bold();
const handler = useCallback(() => {
if (!boldActive) {
return false;
}
return insertText.original('\n\nWoah there!')(props);
}, [boldActive, insertText]);
useKeymap('Shift-Enter', handler); // Add the handler to the keypress pattern.
},
];
const Editor = () => {
const { manager } = useRemirror({ extensions: () => [new BoldExtension()] });
return <Remirror manager={manager} hooks={hooks} />;
};
Editor selection now defaults to the end
of the document. You can change the starting point as shown below.
import { Remirror, useRemirror } from '@remirror/react';
const Editor = () => {
const { manager, state } = useRemirror({ selection: 'start' });
return <Remirror manger={manager} initialState={state} />;
};
All interfaces which were named with the pattern *Parameter
have been renamed to to *Props
. The only exceptions are *FrameworkParameter
which are now *FrameworkOptions
.
Remove Presets
completely. In their place a function that returns a list of Extension
s should be used. They were clunky, difficult to use and provided little to no value.
Remove @remirror/core
entry-point and add all core exports to the main remirror
entry-point.
Add all Extension
s and Preset
package exports to the remirror/extensions
subdirectory. It doesn't include framework specific exports which are made available from @remirror/react
.
Rename @remirror/preset-table
to @remirror/extension-tables
.
Rename preset-list
to extension-lists
. ListPreset
is now BulletListExtension
and OrderListExtension
.
Create new decorator pattern for adding @commands
, @helper
functions and @keyBindings
.
Deprecate tags
property on extension and encourage the use of createTags
which is a method instead.
Rename interface CreatePluginReturn
to CreateExtensionPlugin
.
Add support for directly updating the doc
attributes.
Deprecate top level context methods focus
and blur
. They should now be consumed as commands.
The following packages have been removed.
@remirror/showcase
@remirror/react-social
@remirror/react-wysiwyg
@remirror/extension-auto-link
. The functionality is now self-contained within @remirror/extension-link
.ExtensionStore
createDecorations
extension method for adding decorations to the ProseMirror EditorView
.onInitState
, onApplyState
, and onApplyTransaction
lifecycle methods. These correspond exactly the the plugin methods which ProseMirror exposes and can be used to create plugin functionality without creating a new plugin.@command
, @keyBinding
, @helper
decorators for increased type safety when configuring extensions.NamedShortcut
keybindings which can be set on the keymap extension. Currently remirror
defaults to using the same shortcuts as Google Docs.nodeOverrides
property to the extensions which for advanced users allows overriding of the default NodeSpec
and MarkSpec
.addOrReplacePlugins
to updatePlugins
in ExtensionStore
.reconfigureStatePlugins
and auto apply it for all plugin updating methods.Make sure all your commands in an extension are annotated with a return type of CommandFunction
. Failure to do so will break all type inference wherever the extension is used.
import { CommandFunction } from 'remirror';
When setting the name of the extension make sure to use as const
otherwise it will be a string and ruin autocompletion for extension names, nodes and marks.
class MyExtension extends PlainExtension {
get name() {
return 'makeItConst' as const;
}
}
The Remirror
component now has a convenient hooks props. The hooks prop takes an array of zero parameter hook functions which are rendered into the RemirrorContext
. It's a shorthand to writing out your own components. You can see the pattern in use above.
There are new hooks for working with commands.
Each command has an original
method attached for using the original command that was used to create the command. The original command has the same type signature as the (...args: any[]) => CommandFunction
. So you would call it with the command arguments and then also provide the CommandProps. This is useful when composing commands together or using commands within keyBindings which need to return a boolean.
insertText.original
being used in the useKeymap
example above.useCommands()
provides all the commands as hook. useChainedCommands
provides all the chainable commands.
import { useCallback } from 'react';
import { useChainedCommands, useKeymap } from '@remirror/react';
function useLetItGo() {
const chain = useChainedCommands();
const handler = useCallback(() => {
chain.selectText('all').insertText('Let it goo 🤫').run();
}, [chain]);
// Whenever the user types `a` they let it all go
useKeymap('a', handler);
}
4.3
. Several of the new features make use of the new types and it is a requirement to upgrade.prosemirror-*
packages.Published by ifiokjr almost 4 years ago
4504aadb
#830 Thanks @ifiokjr! - Rename deprecated error constant from COMMANDS_CALLED_IN_OUTER_SCOPE
to SCHEMA
.4504aadb
#830 Thanks @ifiokjr! - Add getActiveNode
function which returns the information for an active node of the provided type.
4504aadb
#830 Thanks @ifiokjr! - Add getMarkRanges
which supports retrieving all the mark ranges from within the provided selection.
4504aadb
#830 Thanks @ifiokjr! - Preserve attributes when toggling a block node. This allows for better support when using extraAttributes
and fixes #819.
302bdf7e
#829 Thanks @benjie! - Fix regexp for image filetype check.
34a7981d
#828 Thanks @tommoor! - YJS fixes for scrolling while remote clients are editing and incorrect remote selections.
Published by ifiokjr almost 4 years ago
Published by ifiokjr almost 4 years ago
Published by ifiokjr almost 4 years ago
4ae3c9b2
#812 Thanks @whawker! - Fix rendered HTML when selecting or applying marks to part of a link.
Behaviour before fix.
<p>
<a href="/">My partially</a>
<a href="/"><span class="selection">selected</span></a>
<a href="/">link</a>
</p>
Behaviour after fix.
<p>
<a href="/">
My partially
<span class="selection">selected</span>
link
</a>
</p>
Published by ifiokjr almost 4 years ago
This is (hopefully 🤞) the release before the beta release.
Published by ifiokjr almost 4 years ago
1adea88a
#801 Thanks @ifiokjr! - Add new primitive commands to CommandsExtension
.
setBlockNodeType
toggleWrappingNode
toggleBlockNodeItem
wrapInNode
removeMark
ee1ab4f3
#805 Thanks @ifiokjr! - Add GetMarkRange
interface to exports from @remirror/core-utils
.
1adea88a
#801 Thanks @ifiokjr! - Improve type signatures of command utility functions to also include an optional range.
4bdcac77
#805 Thanks @ifiokjr! - Add click
and clickMark
handlers to the EventsExtension
. These new events are available to hooks created with useExtension(EventsExtension)
and also exposed via the new createEventHandlers
extension method. These methods provides utilities for determining whether the position clicked was within a specific node or mark.
b65ea785
#805 Thanks @ifiokjr! - Add onClick
handler to LinkExtension
which is called with the event: MouseEvent
and data: LinkClickData
which includes the href
and all the GetMarkRange
properties.
Export extra types from the @remirror/extension-link
package.
LinkAttributes
LinkClickData
DefaultProtocol
3ee20d40
#805 Thanks @ifiokjr! - Add onClick
handler to MentionExtension
which is called with event: MouseEvent
and markRange: GetMarkRange
.
c2268721
#805 Thanks @ifiokjr! - Add onClick
handler to MentionAtomExtension
which is called with the event: MouseEvent
and nodeWithPosition: NodeWithPosition
.
Published by ifiokjr almost 4 years ago
b1df359b
#780 Thanks @ocavue! - Add new@remirror/extension-codemirror5
package which can be used as an alternative to the @remirror/extension-codeblock
for representing code blocks with syntax highlighting in your editor.
d720bcd4
#791 Thanks @ifiokjr! - Rename codemirror package to include the version number: @remirror/extension-codemirror5
. This is to allow a future seperate version which supports codemirror@6
.
Make codemirror
and @types/codemirror
peer dependencies of the @remirror/extension-codemirror5
package. Most setups will need to install codemirror in order to add language support to the code editor. To avoid bundling multiple versions of the same codebase a peer dependency architecture seems to work.
e9d95fa4
#786 Thanks @ifiokjr! - Export PrioritizedKeyBindings
from @remirror/core
and remirror/core
entry points.
1b5bf359
#788 Thanks @ifiokjr! - Make draggability
configurable for MentionAtomExtension
as mentioned in #777.
8a6d5c34
#781 Thanks @whawker! - The behaviour of commands.updateLink.isEnabled()
has been fixed to return false
when the link
mark can't be applied to the selection. This was fixed by a change in the @remirror/core-utils
package.
e9d95fa4
#786 Thanks @ifiokjr! - Fix problems around destroying the YjsExtension
provider and the CMD+SHIFT+Z
keymap not registering as mentioned in #772.
1a0348e7
#789 Thanks @ifiokjr! - Fix removeMark
when called with dispatch = undefined
. This means that command.<NAME>.isEnabled()
checks should all be fixed if they are using removeMark
as mentioned in #784.
Published by ifiokjr almost 4 years ago
a1d65df6
#775 Thanks @whawker! - Fixes extensions that were erroneously adding extra attributes to the DOM twice.
Attributes were correctly added using their toDOM handler, but also incorrectly in their raw form.
Example
const linkExtension = new LinkExtension({
extraAttributes: {
custom: {
default: 'my default',
parseDOM: (dom) => dom.getAttribute('data-custom'),
toDOM: (attrs) => ['data-custom', attrs.custom],
},
},
});
Resulted in
<a data-custom="my default" custom="my default" <!-- extra attribute rendered in raw form -->
href="https://remirror.io" rel="noopener noreferrer nofollow"></a
>
5fd944c6
#770 Thanks @whawker! - Prevent callouts being merged when removing content in between callout nodes.
Published by ifiokjr almost 4 years ago
bdaa6af7
#767 Thanks @whawker! - 🎉 New extension @remirror/extension-callout
This extension adds support for a new callout node.
These can be used to add info
, warning
, error
or success
banners to your document.
The default callout type is info
, but this can be changed by using the defaultType
option of CalloutExtension
.
import { RemirrorManager } from 'remirror/core';
import { CalloutExtension } from 'remirror/extension/callout';
import { CorePreset } from 'remirror/preset/core';
// Create the callout extension
const calloutExtension = new CalloutExtension();
const corePreset = new CorePreset();
// Create the Editor Manager with the callout extension passed through.
const manager = RemirrorManager.create([calloutExtension, corePreset]);
// Pass the dom element to the editor. If you are using `@remirror/react` or
// other framework wrappers then this is handled for you.
const element = document.createElement('div');
document.body.append(element);
// Add the view to the editor manager.
manager.addView(element);
// Wrap with an error callout at the current selection
manager.store.commands.toggleCallout({ type: 'error' });
caf2588d
#766 Thanks @ronnyroeller! - Allow links to be clickable
Anchor tags in contenteditable are not clickable by default. To allow users nonetheless to open them, this commit adds an optional clickhandler to open the link.
Published by ifiokjr almost 4 years ago
Published by ifiokjr about 4 years ago
d27c6e1a
#758 Thanks @ifiokjr! - Pass through defaultAppendTextValue
property to onChange
handler of MentionExtension
.359486f6
#754 Thanks @whawker! - Add an onUpdatedLink
event handler to the link extension for determining when a link has been added to the document.d27c6e1a
#758 Thanks @ifiokjr! - Support EditorState | Selection | ResolvedPos
for the findParentNodeOfType
function.Published by ifiokjr about 4 years ago
Published by ifiokjr about 4 years ago
56349ca5
#744 Thanks @ifiokjr! - Add new options to the YjsExtension
to support full configuration of the y-prosemirror
plugins.
BREAKING: 💥 Remove WebrtcProvider
. It was always required via TypeScript but now the default implementation throws an error if you don't install and provide the provider you want to use. The readme
has been updated to reflect this change.
BREAKING: 💥 yjs
is now a peerDependency
and you will need to install it in your codebase to consume the YjsExtension
. This change follows from the above breaking change. For example, to configure any provider will need to provide your desired Doc
from the yjs
package.
Published by ifiokjr about 4 years ago
73e81b43
#739 Thanks @ronnyroeller! - Configure blockseparator to concat multi-block content
getAnnotations()
return all currently set annotations and enriches them with the text of the annotation. This can be used e.g. to show a list of all annotations outside the editor context. Before, text from multiple blocks (in a multi-block annotation) was concatenated without any separated. Now, one can define via the "blockseparator" option which string to use as separator. For example, one could use a newline character to separate text from different blocks.
0198b9fc
#740 Thanks @whawker! - Add strike mark to the jest-prosemirror
schema
Published by ifiokjr about 4 years ago