@last-rev/rich-text-editor v0.2.0
Last-Rev extended rich text editor
This is a fork and partial re-write of @contentful/field-editor-rich-text. We have expanded the editor to add the following functionality:
- Allow the user to apply theme colors to any selection of text
- Allow the user to apply theme typography elements to any selection of text
- Allow the user to apply special styles to unordered lists, driven by the theme colors and the thme listStyles
What has changed
Field Type
Due to server side validations that Contentful performs on the Rich Text field type, we have to back this new field with a JSON type. The behavior for the content entry user should be seamless and the field will look and behave like a contentful rich text field.
Configuration
Since we cannot use Contentful's rich text type, and since we have added new functionality for this field, we are driving the configuration of the fields from a seperate JSON field in a separate content item. There are two required instance parameters any time this extension is applied to a field: settingsId
(the ID of a content item that will hold the settings for this field) and settingsField
(the JSON type field within that content item that holds the configuration for this field).
the one required field within the settings JSON is themeURL
. This should point to a URL that will return a JSON of the themes for the site (see below for more details on the theme).
Everything else has reasonable defaults. The other fields are listed below:
enabledFormatting
- This is a string array with the following options to enable different formatting options for the field. if left out, all formatting will be enabled by default- "asset-hyperlink",
- "blockquote",
- "bold",
- "color",
- "code",
- "embedded-asset-block",
- "embedded-entry-block",
- "embedded-entry-inline",
- "entry-hyperlink",
- "heading-1",
- "heading-2",
- "heading-3",
- "heading-4",
- "heading-5",
- "heading-6",
- "hr",
- "hyperlink",
- "italic",
- "ordered-list",
- "superscript",
- "subscript",
- "table",
- "typography",
- "unordered-list"
linkedContentTypesByNodeType
- this is a map, keyed by node-type, and holding an array of content type IDs representing, for each node type (entry-hyperlink
,embedded-entry-inline
,embedded-entry-block
), which content types are allowed to be linked. The defaults if these are not set are that all content types will be allowed.listVariantsKey
- This is the key, within the components object, which contains the variants to use for the unordered list styles. (This is usually the name of the component on the client site that will be used to render an unordered list). If left blank, the standard unordered list will be used.
Example:
{
"themeURL": "http://mysite.com/api/theme",
"enabledFormatting": [
"asset-hyperlink",
"bold",
"color",
"embedded-asset-block",
"embedded-entry-block",
"embedded-entry-inline",
"entry-hyperlink",
"heading-1",
"heading-2",
"heading-3",
"hr",
"hyperlink",
"italic",
"typography",
"unordered-list"
],
"linkedContentTypesByNodeType":{
"entry-hyperlink": ["page", "blog"],
"embedded-entry-inline": ["link"],
"embedded-entry-block": ["collection", "card", "quote"]
},
"listVariantsKey": "UnorderedList"
}
Theme
The theme, which shouold be returned as a JSON object, is an extended from of the @mui theme format. For our purposes, we care about three fields:
typography
- This will be a key/value object with the key being the different typography style names and the object being the styles themselves.
palette
- We will go through each item in the palette and extract, from any item with a 'main' attribute, the key (the name of the palette option), and the value of the main attribute (the color value).
listStyles
- This is a custom addition to the @mui theme which will represent the different list style options available to choose from. this is an object whose keys represent the arbitrary name of the list style (for example, 'bullet' or 'check') and the value is the actual styles that will be applied for that list style.
Here is an example of what these fields would look like:
{
"palette": {
"primary": {
"main": "#9146ff",
"light": "#a76aff",
"dark": "#6530b2",
"contrastText": "white"
},
"secondary": {
"main": "#ffff55",
"light": "#ffff55",
"dark": "#c6b300",
"contrastText": "white"
}
},
"typography": {
"body1": {
"fontSize": "1rem",
"fontWeight": 400,
"lineHeight": 1.5,
"fontFamily": "\"Roboto\", \"Helvetica\", \"Arial\", sans-serif",
"letterSpacing": "0.00938em"
},
"body2": {
"fontSize": "1rem",
"fontWeight": 400,
"lineHeight": 1.5,
"fontFamily": "\"Roboto\", \"Helvetica\", \"Arial\", sans-serif",
"letterSpacing": "0.01071em"
}
},
"components": {
"UnorderedList": {
"defaultProps": {},
"styleOverrides": {},
"variants": [
{
"props": {
"variant": "lightBlueCheck"
},
"style": {
"listStyleImage": "url(\"...\")"
}
},
{
"props": {
"variant": "lightBlueCircleCheck"
},
"style": {
"listStyleImage": "url(\"...\")"
}
}
]
}
}
}
How to render
The data that is returned from this Rich Text field, is for most intents and puposes, identical to what is returned from a standard Contentful Rich Text field, with a few minor extensions to allow us to render the additional data.
Only a few minor changes to LastRev's "text" component will be needed to support these changes
Marks
In a standard contentful rich text field, a text node can be decorated with a mark (such as bold
or italic
). This is represented in this way:
{
type: 'text',
value: 'this is some bold text',
marks: [{
type: 'bold'
}]
}
In order to support more configuration for colors and typography, we have extended this mark object to also include a value. For standard marks, the value will just be true
, and for the two new marks (color
, typography
), the value will be a string matching the theme key for that style. For example:
{
type: 'text',
value: 'this is some colored and styled text',
marks: [{
type: 'color',
value: 'primary'
}, {
type: 'typography',
value: 'xlarge'
}]
}
Unordered Lists
To support the new options for the unordered list block node, we will optionally return two fields in the data object: listStyle
and listColor
:
{
type: 'unordered-list',
value: {/*...*/},
data: {
listStyle: 'check',
listColor: 'accent'
}
}