Skip to content

Commit

Permalink
fix(lexical-editor): make font sizes configurable through theme (#4454)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pavel910 authored Dec 19, 2024
1 parent f0224a2 commit 4ee6137
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,24 @@ import {
TypographyPlugin,
UnderlineAction,
LexicalEditorConfig,
LinkPlugin
LinkPlugin,
useRichTextEditor
} from "@webiny/lexical-editor";

const { ToolbarElement, Plugin } = LexicalEditorConfig;

const FontSizeActionWithTheme = () => {
const { theme } = useRichTextEditor();

const fontSizes = theme?.styles?.fontSizes?.heading ?? FontSizeAction.FONT_SIZES_FALLBACK;

return <FontSizeAction fontSizes={fontSizes} />;
};

export const HeadingEditorPreset = () => {
return (
<LexicalEditorConfig>
<ToolbarElement name="fontSize" element={<FontSizeAction />} />
<ToolbarElement name="fontSize" element={<FontSizeActionWithTheme />} />
<ToolbarElement name="fontColor" element={<FontColorAction />} />
<ToolbarElement name="typography" element={<TypographyAction />} />
<ToolbarElement name="textAlignment" element={<TextAlignmentAction />} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,24 @@ import {
UnderlineAction,
ListPlugin,
LexicalEditorConfig,
LinkPlugin
LinkPlugin,
useRichTextEditor
} from "@webiny/lexical-editor";

const { ToolbarElement, Plugin } = LexicalEditorConfig;

const FontSizeActionWithTheme = () => {
const { theme } = useRichTextEditor();

const fontSizes = theme?.styles?.fontSizes?.paragraph ?? FontSizeAction.FONT_SIZES_FALLBACK;

return <FontSizeAction fontSizes={fontSizes} />;
};

export const ParagraphEditorPreset = () => {
return (
<LexicalEditorConfig>
<ToolbarElement name="fontSize" element={<FontSizeAction />} />
<ToolbarElement name="fontSize" element={<FontSizeActionWithTheme />} />
<ToolbarElement name="fontColor" element={<FontColorAction />} />
<ToolbarElement name="typography" element={<TypographyAction />} />
<ToolbarElement name="textAlignment" element={<TextAlignmentAction />} />
Expand Down
4 changes: 0 additions & 4 deletions packages/lexical-editor/src/components/Toolbar/Toolbar.css
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,6 @@ i.font-color,
margin: 0 4px;
}

.toolbar-item.font-size {
width: 70px;
}

.lexical-dropdown-container {
position: absolute;
bottom: -5px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import { DropDown, DropDownItem } from "~/ui/DropDown";
import { useDeriveValueFromSelection } from "~/hooks/useCurrentSelection";
import { useRichTextEditor } from "~/hooks";

const FONT_SIZE_OPTIONS: string[] = [
export interface FontSize {
id: string;
name: string;
value: string;
}

export const FONT_SIZES_FALLBACK: FontSize[] = [
"8px",
"9px",
"10px",
Expand All @@ -24,7 +30,18 @@ const FONT_SIZE_OPTIONS: string[] = [
"60px",
"72px",
"96px"
];
].map(size => ({
id: size,
name: size,
value: size,
default: size === "15px"
}));

const emptyOption: FontSize = {
value: "",
name: "Font Size",
id: "empty"
};

function dropDownActiveClass(active: boolean) {
if (active) {
Expand All @@ -34,61 +51,66 @@ function dropDownActiveClass(active: boolean) {
}

interface FontSizeDropDownProps {
fontSizes: FontSize[];
editor: LexicalEditor;
value: string;
value: string | undefined;
disabled?: boolean;
}

function FontSizeDropDown(props: FontSizeDropDownProps): JSX.Element {
const { editor, value, disabled = false } = props;
const { editor, value, fontSizes, disabled = false } = props;

const handleClick = useCallback(
(option: string) => {
(option: FontSize) => {
editor.update(() => {
const selection = $getSelection();
if ($isRangeSelection(selection)) {
$patchStyleText(selection, {
["font-size"]: option
["font-size"]: option.value
});
}
});
},
[editor]
);

const selectedOption = fontSizes.find(opt => opt.value === value) ?? emptyOption;

return (
<DropDown
disabled={disabled}
buttonClassName="toolbar-item font-size"
buttonLabel={value}
buttonLabel={selectedOption.name}
buttonAriaLabel={"Formatting options for font size"}
>
{FONT_SIZE_OPTIONS.map(option => (
{fontSizes.map(option => (
<DropDownItem
className={`item fontsize-item ${dropDownActiveClass(value === option)}`}
className={`item fontsize-item ${dropDownActiveClass(value === option.id)}`}
onClick={() => handleClick(option)}
key={option}
key={option.id}
>
<span className="text">{option}</span>
<span className="text">{option.name}</span>
</DropDownItem>
))}
</DropDown>
);
}

const defaultSize = "15px";
interface FontSizeActionProps {
fontSizes?: FontSize[];
}

export const FontSizeAction = () => {
const FontSize = ({ fontSizes = FONT_SIZES_FALLBACK }: FontSizeActionProps) => {
const { editor } = useRichTextEditor();
const [isEditable, setIsEditable] = useState(() => editor.isEditable());
const fontSize = useDeriveValueFromSelection(({ rangeSelection }) => {
if (!rangeSelection) {
return defaultSize;
return undefined;
}
try {
return $getSelectionStyleValueForProperty(rangeSelection, "font-size", "15px");
return $getSelectionStyleValueForProperty(rangeSelection, "font-size");
} catch {
return defaultSize;
return undefined;
}
});

Expand All @@ -102,7 +124,14 @@ export const FontSizeAction = () => {

return (
<>
<FontSizeDropDown disabled={!isEditable} value={fontSize} editor={editor} />
<FontSizeDropDown
disabled={!isEditable}
value={fontSize}
editor={editor}
fontSizes={fontSizes}
/>
</>
);
};

export const FontSizeAction = Object.assign(FontSize, { FONT_SIZES_FALLBACK });
14 changes: 13 additions & 1 deletion packages/theme/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ export type ThemeBreakpoints = {

/*
* Typography section
* We want to allow custom strings as well, thus the (string & {}).
*/
export type TypographyType = "headings" | "paragraphs" | "quotes" | "lists" | string;
// eslint-disable-next-line @typescript-eslint/ban-types
export type TypographyType = "headings" | "paragraphs" | "quotes" | "lists" | (string & {});
export type TypographyStyle = {
id: string;
name: string;
Expand All @@ -39,8 +41,18 @@ export type TypographyStyle = {
export type Typography = Record<TypographyType, Readonly<TypographyStyle[]>>;
export type ThemeTypographyStyleItems = TypographyStyle[];

export interface FontSize {
id: string;
name: string;
value: string;
}

export interface ThemeStyles {
colors: Record<string, any>;
fontSizes?: {
heading?: FontSize[];
paragraph?: FontSize[];
};
borderRadius?: number;
typography: Typography;
elements: Record<string, Record<string, any> | StylesObject>;
Expand Down

0 comments on commit 4ee6137

Please sign in to comment.