The @apostrophecms/smilies
extension
The @apostrophecms/smilies
extension adds a host of text shortcuts for smilie and other emojis, plus my favorite non-emoji, :ashrug
(¯\_(ツ)_/¯
). You can see the full list in the modules/@apostrophecms/smilies/lib/replacementEmojis.js
file. This extension also takes a tone
option passed in the smiliesConfig
object in either the per-area or global rich-text-widget configuration. This option takes a number from 1-5 to provide a skin tone for modifiable emojis. Note that which emojis are modifiable varies based on operating system. See the repository README for more detailed information.
The overall structure of the module is almost the same as the typography module that we covered in the first tutorial so we will only briefly review the repetative files in this extension.
The index.js
file improves the rich-text-widget and extends the getBrowserData()
method. This allows us to pass global and per-area configuration to the widget through the smiliesConfig
object.
The first extension also had a ui/apos/tiptap-extensions
folder containing the core code to instantiate the Tiptap extension. The smilie.js
file collects the per-area and project-wide configuration options and instantiates the extension.
The biggest change here from the typography extension code is the presence of a lib
folder with two files. Let's look more closely at these files.
The lib
folder
The smilies/lib/extensions-smilies.js
file provides the code that extends the Tiptap functionality like the @tiptap/extension-typography
files did for our first module.
Let's walk through the most relevant parts of this code.
import { textInputRule, Extension } from '@tiptap/core';
We start by importing two key methods from the Tiptap core package. The Extension
method is a foundational component that follows a factory pattern, providing an interface for creating objects without specifying the exact class of objects. It exposes a number of lifecycle methods and hooks that are then available for extending editor functionality.
Some commonly used Tiptap methods and hooks
You can read more about these methods and hooks in the Tiptap API documentation and ProseMirror reference documentation.
addInputRules()
: Used to define input rules that automatically replace or format text as the user types. For example, you could create an input rule to automatically replace:)
with an emoji smiley face. These rules are useful for adding simple, automated text transformations based on user input.onTransaction()
: This hook gets called every time a new ProseMirror transaction occurs. It allows you to respond to changes in the editor's state. This will be used in the third extension.addCommands()
: This method allows you to define custom commands that you can later call via the editor's API. Commands are functions that perform actions like changing text, formatting, or even adding/removing nodes. This method is used in the third extension.addExtensions()
: Enables the addition of other extensions as dependencies. This means your extension can rely on features provided by other extensions.addKeyboardShortcuts()
: Enables the addition of keyboard shortcuts to execute specific commands or functionalities. You can define what should happen when a particular key or set of keys is pressed.addNodeView()
: Allows for the customization of how nodes (like paragraphs, headings, etc.) are rendered. This is especially useful if you want to add interactive components within the editor.addPasteRules()
: Defines how the editor should handle pasted content. This is particularly useful if you want to clean up or transform the content that a user pastes into the editor.addAttributes()
: Adds custom attributes to existing nodes or marks. This can be useful for adding data attributes, classes, or inline styles.onCreate()
andonDestroy()
: Lifecycle hooks that get called when the extension is created or destroyed, respectively. They can be useful for setting up and tearing down anything associated with your extension.
In the Smilies extension, the addInputRules()
method is used to dynamically create and add a series of textInputRule
instances to an array.
The replacementEmojis.js
file in the lib
folder contains each of those rules as an array of objects. Each object has two properties. The find
property takes a regular expression pattern matching the characters that should be replaced within the editor as the user types. The replace
property takes a string that contains the character(s) that should replace the matched string. Note that any special characters, like in the replace
string need to be escaped.
const Smilie = Extension.create({
name: 'smilie',
addInputRules() {
const inputRules = [];
const tone = this.options.tone || 2;
const convertedEmojis = changeTone(replacementEmojis, tone);
for (let index = 0; index < convertedEmojis.length; index++) {
inputRules[index] = textInputRule(convertedEmojis[index]);
}
return inputRules;
},
});
Going back to the smilies/lib/extension-smilies.js
file, the Smilie
variable is where all the main Tiptap magic occurs. First, we are using the Extension.create()
method to instantiate our new extension. This isn't specific to just this extension - your own custom extensions would need to use this. We are passing an object to this method.
First up in this object, there is a name
property. Adding a unique name allows you to refer to the extension in different editor instances, excluding it, or changing the configuration, for example.
Next, we are using the addInputRules()
method of the Extension()
. Again, this helper method is used to define input rules that automatically replace or format text as the user types. It needs to return an array of rules, as we defined in the replacementEmojis.js
file. For each extension, Tiptap will call this method to compile an array of all the rules.
The remainder of this code uses the tone
option passed when the extension is instantiated by the smilies/ui/apos/tiptap-extensions/smilie.js
. A great improvement to this extension would be the addition of an additional UI element to change the emoji skin tone as it is added.
In conclusion, in this tutorial we created a basic text replacement extension that can be used as a template for your custom extensions. This could be as simple as changing out the replacementEmojis.js
file with your own text strings, or using this extension as a foundation for more complex functionality. The flexibility of this setup allows for a wide range of creative applications, from adding custom emoji sets to implementing unique text transformation features. By leveraging and modifying the concepts presented here, you can create powerful and unique text editing experiences that cater to a diverse array of use cases.