@blocknote/core
Version:
A "Notion-style" block-based extensible text editor built on top of Prosemirror and Tiptap.
97 lines (89 loc) • 2.4 kB
text/typescript
import { Attributes, Mark } from "@tiptap/core";
import {
StyleConfig,
StyleImplementation,
StylePropSchema,
StyleSchemaFromSpecs,
StyleSpec,
StyleSpecs,
} from "./types.js";
export function stylePropsToAttributes(
propSchema: StylePropSchema,
): Attributes {
if (propSchema === "boolean") {
return {};
}
return {
stringValue: {
default: undefined,
keepOnSplit: true,
parseHTML: (element) => element.getAttribute("data-value"),
renderHTML: (attributes) =>
attributes.stringValue !== undefined
? {
"data-value": attributes.stringValue,
}
: {},
},
};
}
// Function that adds necessary classes and attributes to the `dom` element
// returned from a custom style's 'render' function, to ensure no data is lost
// on internal copy & paste.
export function addStyleAttributes<
SType extends string,
PSchema extends StylePropSchema,
>(
element: {
dom: HTMLElement;
contentDOM?: HTMLElement;
},
styleType: SType,
styleValue: PSchema extends "boolean" ? undefined : string,
propSchema: PSchema,
): {
dom: HTMLElement;
contentDOM?: HTMLElement;
} {
// Sets content type attribute
element.dom.setAttribute("data-style-type", styleType);
// Adds style value as an HTML attribute in kebab-case with "data-" prefix, if
// the style takes a string value.
if (propSchema === "string") {
element.dom.setAttribute("data-value", styleValue as string);
}
if (element.contentDOM !== undefined) {
element.contentDOM.setAttribute("data-editable", "");
}
return element;
}
// This helper function helps to instantiate a stylespec with a
// config and implementation that conform to the type of Config
export function createInternalStyleSpec<T extends StyleConfig>(
config: T,
implementation: StyleImplementation,
) {
return {
config,
implementation,
} satisfies StyleSpec<T>;
}
export function createStyleSpecFromTipTapMark<
T extends Mark,
P extends StylePropSchema,
>(mark: T, propSchema: P) {
return createInternalStyleSpec(
{
type: mark.name as T["name"],
propSchema,
},
{
mark,
},
);
}
export function getStyleSchemaFromSpecs<T extends StyleSpecs>(specs: T) {
return Object.fromEntries(
Object.entries(specs).map(([key, value]) => [key, value.config]),
) as StyleSchemaFromSpecs<T>;
}