Skip to content

Commit

Permalink
add support for rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonas-C committed Jan 31, 2025
1 parent 2f7aa14 commit ddf40b5
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 11 deletions.
34 changes: 34 additions & 0 deletions packages/editor/src/core/createRenderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Copyright (c) 2025-present, NDLA.
*
* This source code is licensed under the GPLv3 license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import type { CreateSlateElementRenderer, CreateSlateLeafRenderer } from ".";

export const createElementRenderer: CreateSlateElementRenderer = (renderFn) => (editor) => {
const { renderElement } = editor;

editor.renderElement = (props) => {
const ret = renderFn(props);
if (ret) {
return ret;
} else return renderElement?.(props);
};

return editor;
};

export const createLeafRenderer: CreateSlateLeafRenderer = (renderFn) => (editor) => {
const { renderLeaf } = editor;

editor.renderLeaf = (props) => {
const ret = renderFn(props);
if (ret) {
return ret;
} else return renderLeaf?.(props);
};
return editor;
};
11 changes: 10 additions & 1 deletion packages/editor/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

import type { Descendant, Editor, Node, Path } from "slate";
import type { KeyboardEventLike } from "is-hotkey";
import type { KeyboardEvent } from "react";
import type { KeyboardEvent, JSX } from "react";
import type { ElementType } from "../types";
import type { RenderElementProps, RenderLeafProps } from "slate-react";

type KeyConditionFn = (event: KeyboardEventLike) => boolean;

Expand Down Expand Up @@ -107,3 +108,11 @@ export interface ConfigurableSlateSerializer<TOptions extends {} | undefined = u
extends SlateSerializer<TOptions> {
configure: (options: MappedConfigurationOption<TOptions>) => ConfigurableSlateSerializer<TOptions>;
}

export type SlateRenderer = (editor: Editor) => Editor;

export type ElementRenderer = (props: RenderElementProps) => JSX.Element | undefined;
export type LeafRenderer = (props: RenderLeafProps) => JSX.Element | undefined;

export type CreateSlateElementRenderer = (fn: ElementRenderer) => (editor: Editor) => Editor;
export type CreateSlateLeafRenderer = (fn: LeafRenderer) => (editor: Editor) => Editor;
28 changes: 25 additions & 3 deletions packages/editor/src/editor/createSlate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
*/

import { createEditor, Element, type Editor } from "slate";
import type { SlatePlugin } from "../core";
import type { ElementRenderer, LeafRenderer, SlatePlugin, SlateRenderer } from "../core";
import { LoggerManager } from "../editor/logger/Logger";
import { withHistory } from "slate-history";
import { withReact } from "slate-react";
import { withLogger } from "../editor/logger/withLogger";
import { createElementRenderer, createLeafRenderer } from "../core/createRenderer";

export const withPlugins = (editor: Editor, plugins?: SlatePlugin[]) => {
if (plugins) {
Expand All @@ -22,13 +23,34 @@ export const withPlugins = (editor: Editor, plugins?: SlatePlugin[]) => {
return editor;
};

export const withRenderers = (editor: Editor, renderers?: SlateRenderer[]) => {
if (renderers) {
return renderers.reduce((editor, renderer) => renderer(editor), editor);
}

return editor;
};

interface CreateSlate {
plugins?: SlatePlugin[];
logger?: LoggerManager;
elementRenderers?: ElementRenderer[];
leafRenderers?: LeafRenderer[];
}

export const createSlate = ({ plugins, logger = new LoggerManager({ debug: false }) }: CreateSlate): Editor => {
const editor = withPlugins(withReact(withHistory(withLogger(createEditor(), logger))), plugins);
export const createSlate = ({
plugins,
elementRenderers,
leafRenderers,
logger = new LoggerManager({ debug: false }),
}: CreateSlate): Editor => {
const editor = withRenderers(
withRenderers(
withPlugins(withReact(withHistory(withLogger(createEditor(), logger))), plugins),
elementRenderers?.map(createElementRenderer),
),
leafRenderers?.map(createLeafRenderer),
);

editor.hasVoids = (element) => element.children.some((n) => Element.isElement(n) && editor.isVoid(n));

Expand Down
11 changes: 8 additions & 3 deletions packages/editor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ export type {
MappedConfigurationOption,
SlatePlugin,
SlateSerializer,
SlateRenderer,
ElementRenderer,
LeafRenderer,
CreateSlateElementRenderer,
CreateSlateLeafRenderer,
} from "./core";
export { mergeOptions } from "./core/mergeOptions";

export { createSlate, withPlugins } from "./editor/createSlate";
export { createSlate, withPlugins, withRenderers } from "./editor/createSlate";
export { withLogger } from "./editor/logger/withLogger";
export { LoggerManager, type LoggerOptions, loggerManager } from "./editor/logger/Logger";

Expand Down Expand Up @@ -66,7 +71,7 @@ export type {
export { LIST_ELEMENT_TYPE, LIST_ITEM_ELEMENT_TYPE, LIST_TYPES, LIST_PLUGIN } from "./plugins/list/listTypes";
export { isListElement, isListItemElement } from "./plugins/list/queries/listElementQueries";
export { toggleList } from "./plugins/list/transforms/toggleList";
export { useListToolbarButton } from "./plugins/list/hooks/useListToolbarButton";
export { useListToolbarButton, useListToolbarButtonState } from "./plugins/list/hooks/useListToolbarButton";
export { listOnBackspace } from "./plugins/list/handlers/listOnBackspace";
export { listOnEnter } from "./plugins/list/handlers/listOnEnter";
export { listOnTab } from "./plugins/list/handlers/listOnTab";
Expand All @@ -76,7 +81,7 @@ export { markSerializer } from "./plugins/mark/markSerializer";
export type { CustomText, MarkType } from "./plugins/mark/markTypes";
export { marks, MARK_PLUGIN } from "./plugins/mark/markTypes";
export { toggleMark } from "./plugins/mark/toggleMark";
export { useMarkToolbarButton } from "./plugins/mark/hooks/useMarkToolbarButton";
export { useMarkToolbarButton, useMarkToolbarButtonState } from "./plugins/mark/hooks/useMarkToolbarButton";

export { paragraphPlugin } from "./plugins/paragraph/paragraphPlugin";
export { paragraphSerializer } from "./plugins/paragraph/paragraphSerializer";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { Transforms, type Editor } from "slate";
import type { HeadingElement } from "../headingTypes";
import { HEADING_ELEMENT_TYPE, type HeadingElement } from "../headingTypes";
import { isHeadingElement } from "../queries/headingQueries";

export const toggleHeading = (editor: Editor, level: HeadingElement["level"]) => {
Expand All @@ -20,7 +20,7 @@ export const toggleHeading = (editor: Editor, level: HeadingElement["level"]) =>
// TODO: This should be configurable
Transforms.setNodes(editor, { type: "paragraph" }, { at: editor.selection });
} else {
Transforms.setNodes(editor, { type: "heading", level }, { at: editor.selection });
Transforms.setNodes(editor, { type: HEADING_ELEMENT_TYPE, level }, { at: editor.selection });
}
return true;
};
6 changes: 4 additions & 2 deletions packages/editor/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
*
*/

import type { KeyboardEventHandler, JSX } from "react";
import type { BaseEditor, Element } from "slate";
import type { HistoryEditor } from "slate-history";
import type { ReactEditor } from "slate-react";
import type { ReactEditor, RenderElementProps, RenderLeafProps } from "slate-react";
import type { LinkElement } from "../plugins/link/linkTypes";
import type { ParagraphElement } from "../plugins/paragraph/paragraphTypes";
import type { CustomText } from "../plugins/mark/markTypes";
import type { KeyboardEventHandler } from "react";
import type { BreakElement } from "../plugins/break/breakTypes";
import type { ListElement, ListItemElement } from "../plugins/list/listTypes";
import type { SectionElement } from "../plugins/section/sectionTypes";
Expand All @@ -26,6 +26,8 @@ export interface CustomEditor {
pluginOptions: Map<string, unknown>;
getPluginOptions: <T>(pluginName: string) => T | undefined;
hasVoids: (element: Element) => boolean;
renderElement?: (props: RenderElementProps) => JSX.Element | undefined;
renderLeaf?: (props: RenderLeafProps) => JSX.Element | undefined;
}

export type ElementType = Element["type"];
Expand Down

0 comments on commit ddf40b5

Please sign in to comment.