Skip to content

Commit fbe879b

Browse files
[WC-2914]: add support for custom fonts in RichText widget (#1555)
2 parents 3a4761f + 6b039ac commit fbe879b

File tree

8 files changed

+78
-16
lines changed

8 files changed

+78
-16
lines changed

packages/pluggableWidgets/rich-text-web/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1010

1111
### Added
1212

13+
- We added support to add custom font families to Rich Text.
1314
- We added table support to Rich Text, now it is possible to add tables and configure their layout.
1415

1516
### Fixed

packages/pluggableWidgets/rich-text-web/src/RichText.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,22 @@
163163
<caption>Enable spell checking</caption>
164164
<description />
165165
</property>
166+
<property key="customFonts" type="object" isList="true" required="false">
167+
<caption>Custom fonts</caption>
168+
<description />
169+
<properties>
170+
<property key="fontName" type="string" required="false">
171+
<caption>Font name</caption>
172+
<category>Item</category>
173+
<description>A title for this font combination (e.g., Arial).</description>
174+
</property>
175+
<property key="fontStyle" type="string" required="false">
176+
<caption>Font style</caption>
177+
<category>Item</category>
178+
<description>The full CSS font-family declaration that will be applied (e.g., arial, helvetica, sans-serif).</description>
179+
</property>
180+
</properties>
181+
</property>
166182
</propertyGroup>
167183
</propertyGroup>
168184
<propertyGroup caption="Custom toolbar">

packages/pluggableWidgets/rich-text-web/src/__tests__/RichText.spec.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ describe("Rich Text", () => {
4343
maxHeightUnit: "none",
4444
maxHeight: 0,
4545
minHeight: 75,
46-
OverflowY: "auto"
46+
OverflowY: "auto",
47+
customFonts: []
4748
};
4849
});
4950

packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,15 @@ import {
1111
useLayoutEffect,
1212
useRef
1313
} from "react";
14-
import QuillTableBetter from "../utils/formats/quill-table-better/quill-table-better";
15-
import "../utils/formats/quill-table-better/assets/css/quill-table-better.scss";
14+
import { CustomFontsType } from "../../typings/RichTextProps";
15+
import { EditorDispatchContext } from "../store/EditorProvider";
16+
import { SET_FULLSCREEN_ACTION } from "../store/store";
1617
import "../utils/customPluginRegisters";
18+
import { FontStyleAttributor, formatCustomFonts } from "../utils/formats/fonts";
19+
import "../utils/formats/quill-table-better/assets/css/quill-table-better.scss";
20+
import QuillTableBetter from "../utils/formats/quill-table-better/quill-table-better";
21+
import { RESIZE_MODULE_CONFIG } from "../utils/formats/resizeModuleConfig";
22+
import { ACTION_DISPATCHER } from "../utils/helpers";
1723
import MxQuill from "../utils/MxQuill";
1824
import {
1925
enterKeyKeyboardHandler,
@@ -24,12 +30,9 @@ import {
2430
} from "./CustomToolbars/toolbarHandlers";
2531
import { useEmbedModal } from "./CustomToolbars/useEmbedModal";
2632
import Dialog from "./ModalDialog/Dialog";
27-
import { RESIZE_MODULE_CONFIG } from "../utils/formats/resizeModuleConfig";
28-
import { ACTION_DISPATCHER } from "../utils/helpers";
29-
import { EditorDispatchContext } from "../store/EditorProvider";
30-
import { SET_FULLSCREEN_ACTION } from "../store/store";
3133

3234
export interface EditorProps {
35+
customFonts: CustomFontsType[];
3336
defaultValue?: string;
3437
onTextChange?: (...args: [delta: Delta, oldContent: Delta, source: EmitterSource]) => void;
3538
onSelectionChange?: (...args: [range: Range, oldRange: Range, source: EmitterSource]) => void;
@@ -42,6 +45,9 @@ export interface EditorProps {
4245

4346
// Editor is an uncontrolled React component
4447
const Editor = forwardRef((props: EditorProps, ref: MutableRefObject<Quill | null>) => {
48+
const fonts = formatCustomFonts(props.customFonts);
49+
const FontStyle = new FontStyleAttributor(fonts);
50+
Quill.register(FontStyle, true);
4551
const { theme, defaultValue, style, className, toolbarId, onTextChange, onSelectionChange, readOnly } = props;
4652
const containerRef = useRef<HTMLDivElement>(null);
4753
const modalRef = useRef<HTMLDivElement>(null);

packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ function EditorWrapperInner(props: EditorWrapperProps): ReactElement {
185185
preset={preset}
186186
quill={quillRef.current}
187187
toolbarContent={toolbarPreset}
188+
customFonts={props.customFonts}
188189
/>
189190
</If>
190191
<Editor
@@ -207,6 +208,7 @@ function EditorWrapperInner(props: EditorWrapperProps): ReactElement {
207208
className={"widget-rich-text-container"}
208209
readOnly={stringAttribute.readOnly}
209210
key={`${toolbarId}_${stringAttribute.readOnly}`}
211+
customFonts={props.customFonts}
210212
/>
211213
</div>
212214
{enableStatusBar && (

packages/pluggableWidgets/rich-text-web/src/components/Toolbar.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import classNames from "classnames";
22
import Quill from "quill";
33
import { CSSProperties, ReactElement, RefObject, createElement, forwardRef } from "react";
4-
import { PresetEnum } from "typings/RichTextProps";
4+
import { CustomFontsType, PresetEnum } from "../../typings/RichTextProps";
5+
import { formatCustomFonts } from "../utils/formats/fonts";
56
import { FormatsContainer, ToolbarContext, presetToNumberConverter } from "./CustomToolbars/ToolbarWrapper";
67
import { TOOLBAR_MAPPING, toolbarContentType } from "./CustomToolbars/constants";
78

89
export interface ToolbarProps {
10+
customFonts?: CustomFontsType[];
911
id: string;
1012
preset: PresetEnum;
11-
style?: CSSProperties;
1213
quill?: Quill | null;
14+
style?: CSSProperties;
1315
toolbarContent: toolbarContentType[];
1416
}
1517

@@ -65,6 +67,16 @@ const Toolbar = forwardRef((props: ToolbarProps, ref: RefObject<HTMLDivElement>)
6567
{toolbarGroup.children.map((toolbar, idx) => {
6668
const currentToolbar = TOOLBAR_MAPPING[toolbar];
6769
const key = `toolbar_${id}_${index}_${idx}`;
70+
let value = currentToolbar.value;
71+
72+
if (currentToolbar.title === "Font type") {
73+
type FontListType = Array<{ value: string; description: string; style: string }>;
74+
value = [
75+
...(currentToolbar.value as FontListType),
76+
...formatCustomFonts(props.customFonts ?? [])
77+
].sort((a, b) => (a.value ?? "").localeCompare(b.value ?? ""));
78+
}
79+
6880
return currentToolbar.custom
6981
? createElement(currentToolbar.component, {
7082
key,
@@ -77,7 +89,7 @@ const Toolbar = forwardRef((props: ToolbarProps, ref: RefObject<HTMLDivElement>)
7789
key,
7890
className: classNames(currentToolbar.className),
7991
presetValue: currentToolbar.presetValue,
80-
value: currentToolbar.value,
92+
value,
8193
title: currentToolbar.title
8294
},
8395
currentToolbar.children && createElement(currentToolbar.children)

packages/pluggableWidgets/rich-text-web/src/utils/formats/fonts.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Scope, StyleAttributor } from "parchment";
2-
import Quill from "quill";
2+
import { CustomFontsType } from "../../../typings/RichTextProps";
33
import "./fonts.scss";
44

55
export const FONT_LIST = [
@@ -22,13 +22,21 @@ const config = {
2222
scope: Scope.INLINE
2323
};
2424

25-
class FontStyleAttributor extends StyleAttributor {
25+
export class FontStyleAttributor extends StyleAttributor {
26+
private fontList: typeof FONT_LIST = [];
27+
28+
constructor(fontList: typeof FONT_LIST) {
29+
super("font", "font-family", config);
30+
this.fontList = fontList;
31+
}
32+
2633
add(node: HTMLElement, value: any): boolean {
2734
if (!this.canAdd(node, value)) {
2835
return false;
2936
}
3037
node.dataset.value = value;
31-
const style = FONT_LIST.find(x => x.value === value)?.style;
38+
const allFonts = [...FONT_LIST, ...this.fontList];
39+
const style = allFonts.find(x => x.value === value)?.style;
3240
if (style) {
3341
super.add(node, style);
3442
} else {
@@ -46,6 +54,10 @@ class FontStyleAttributor extends StyleAttributor {
4654
}
4755
}
4856

49-
const FontStyle = new FontStyleAttributor("font", "font-family", config);
50-
51-
Quill.register(FontStyle, true);
57+
export function formatCustomFonts(fonts: CustomFontsType[] = []): typeof FONT_LIST {
58+
return fonts.map(font => ({
59+
value: font.fontName?.toLowerCase().split(" ").join("-") ?? "",
60+
description: font.fontName ?? "",
61+
style: font.fontStyle ?? ""
62+
}));
63+
}

packages/pluggableWidgets/rich-text-web/typings/RichTextProps.d.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ export type OverflowYEnum = "auto" | "scroll" | "hidden";
2323

2424
export type OnChangeTypeEnum = "onLeave" | "onDataChange";
2525

26+
export interface CustomFontsType {
27+
fontName: string;
28+
fontStyle: string;
29+
}
30+
2631
export type ToolbarConfigEnum = "basic" | "advanced";
2732

2833
export type CtItemTypeEnum = "separator" | "undo" | "redo" | "bold" | "italic" | "underline" | "strike" | "superScript" | "subScript" | "orderedList" | "bulletList" | "lowerAlphaList" | "checkList" | "minIndent" | "plusIndent" | "direction" | "link" | "image" | "video" | "formula" | "blockquote" | "code" | "codeBlock" | "viewCode" | "align" | "centerAlign" | "rightAlign" | "font" | "size" | "color" | "background" | "header" | "fullscreen" | "clean" | "tableBetter";
@@ -31,6 +36,11 @@ export interface AdvancedConfigType {
3136
ctItemType: CtItemTypeEnum;
3237
}
3338

39+
export interface CustomFontsPreviewType {
40+
fontName: string;
41+
fontStyle: string;
42+
}
43+
3444
export interface AdvancedConfigPreviewType {
3545
ctItemType: CtItemTypeEnum;
3646
}
@@ -59,6 +69,7 @@ export interface RichTextContainerProps {
5969
onLoad?: ActionValue;
6070
onChangeType: OnChangeTypeEnum;
6171
spellCheck: boolean;
72+
customFonts: CustomFontsType[];
6273
toolbarConfig: ToolbarConfigEnum;
6374
history: boolean;
6475
fontStyle: boolean;
@@ -100,6 +111,7 @@ export interface RichTextPreviewProps {
100111
onLoad: {} | null;
101112
onChangeType: OnChangeTypeEnum;
102113
spellCheck: boolean;
114+
customFonts: CustomFontsPreviewType[];
103115
toolbarConfig: ToolbarConfigEnum;
104116
history: boolean;
105117
fontStyle: boolean;

0 commit comments

Comments
 (0)