alinea
Version:
Headless git-based CMS
563 lines (559 loc) • 21.6 kB
JavaScript
import {
dist_default
} from "../../chunks/chunk-A5O3N2GS.js";
import "../../chunks/chunk-NZLE2WMY.js";
// src/field/richtext/RichTextToolbar.tsx
import { FieldToolbar } from "alinea/dashboard/view/entry/FieldToolbar";
import { IconButton } from "alinea/dashboard/view/IconButton";
import { HStack, Icon, px, Typo } from "alinea/ui";
import { DropdownMenu } from "alinea/ui/DropdownMenu";
import { IcAlignCenter } from "alinea/ui/icons/IcAlignCenter";
import { IcAlignJustify } from "alinea/ui/icons/IcAlignJustify";
import { IcAlignLeft } from "alinea/ui/icons/IcAlignLeft";
import { IcAlignRight } from "alinea/ui/icons/IcAlignRight";
import { IcRoundFormatBold } from "alinea/ui/icons/IcRoundFormatBold";
import { IcRoundFormatClear } from "alinea/ui/icons/IcRoundFormatClear";
import { IcRoundFormatItalic } from "alinea/ui/icons/IcRoundFormatItalic";
import { IcRoundFormatListBulleted } from "alinea/ui/icons/IcRoundFormatListBulleted";
import { IcRoundFormatListNumbered } from "alinea/ui/icons/IcRoundFormatListNumbered";
import { IcRoundHorizontalRule } from "alinea/ui/icons/IcRoundHorizontalRule";
import { IcRoundLink } from "alinea/ui/icons/IcRoundLink";
import { IcRoundQuote } from "alinea/ui/icons/IcRoundQuote";
import { IcRoundSubscript } from "alinea/ui/icons/IcRoundSubscript";
import { IcRoundSuperscript } from "alinea/ui/icons/IcRoundSuperscript";
import { IcRoundTextFields } from "alinea/ui/icons/IcRoundTextFields";
import { IcRoundUnfoldMore } from "alinea/ui/icons/IcRoundUnfoldMore";
import { TableDelete } from "alinea/ui/icons/TableDelete";
import { TableDeleteColumn } from "alinea/ui/icons/TableDeleteColumn";
import { TableDeleteRow } from "alinea/ui/icons/TableDeleteRow";
import { TableHeaderCell } from "alinea/ui/icons/TableHeaderCell";
import { TableHeaderColumn } from "alinea/ui/icons/TableHeaderColumn";
import { TableHeaderRow } from "alinea/ui/icons/TableHeaderRow";
import { TableInsert } from "alinea/ui/icons/TableInsert";
import { TableInsertColumnAfter } from "alinea/ui/icons/TableInsertColumnAfter";
import { TableInsertColumnBefore } from "alinea/ui/icons/TableInsertColumnBefore";
import { TableInsertRowAfter } from "alinea/ui/icons/TableInsertRowAfter";
import { TableInsertRowBefore } from "alinea/ui/icons/TableInsertRowBefore";
import { TableMergeCells } from "alinea/ui/icons/TableMergeCells";
import { TableSplitCell } from "alinea/ui/icons/TableSplitCell";
import { forwardRef } from "react";
import { attributesToReference, referenceToAttributes } from "./ReferenceLink.js";
// src/field/richtext/RichTextToolbar.module.scss
var RichTextToolbar_module_default = {
"root": "alinea-RichTextToolbar",
"root-separator": "alinea-RichTextToolbar-separator",
"rootSeparator": "alinea-RichTextToolbar-separator",
"root-dropdown": "alinea-RichTextToolbar-dropdown",
"rootDropdown": "alinea-RichTextToolbar-dropdown"
};
// src/field/richtext/RichTextToolbar.tsx
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var styles = dist_default(RichTextToolbar_module_default);
var Styles = /* @__PURE__ */ ((Styles2) => {
Styles2["paragraph"] = "Normal text";
Styles2["h1"] = "Heading 1";
Styles2["h2"] = "Heading 2";
Styles2["h3"] = "Heading 3";
Styles2["h4"] = "Heading 4";
Styles2["h5"] = "Heading 5";
return Styles2;
})(Styles || {});
var HrDivider = () => /* @__PURE__ */ jsx(
"hr",
{
style: {
border: "none",
marginBlock: "2px",
borderTop: "1px solid var(--alinea-outline)"
}
}
);
var RichTextToolbar = forwardRef(function RichTextToolbar2({ pickLink, editor, focusToggle, enableTables }, ref) {
function exec() {
return editor.chain().focus(null, { scrollIntoView: false });
}
const selectedStyle = editor.isActive("heading", { level: 1 }) ? "h1" : editor.isActive("heading", { level: 2 }) ? "h2" : editor.isActive("heading", { level: 3 }) ? "h3" : editor.isActive("heading", { level: 4 }) ? "h4" : editor.isActive("heading", { level: 5 }) ? "h5" : "paragraph";
const selectedTable = editor.isActive("table");
function handleLink() {
const attrs = editor.getAttributes("link");
const existing = attributesToReference(attrs);
const { view, state } = editor;
const { from, to } = view.state.selection;
const isSelection = from !== to;
return pickLink({
link: existing,
title: attrs.title,
blank: attrs.target === "_blank",
hasLink: Boolean(existing),
requireDescription: !isSelection
}).then((picked) => {
if (!picked || !picked.link) {
exec().unsetLink().run();
return;
}
const link = picked.link;
const attrs2 = {
title: picked.title,
...referenceToAttributes(link),
target: link._target ?? (picked.blank ? "_blank" : void 0)
};
if (existing) {
exec().extendMarkRange("link").setLink(attrs2).run();
} else if (isSelection) {
exec().setLink(attrs2).run();
} else {
exec().insertContent({
type: "text",
text: picked.title || link._title || link._url || "",
marks: [{ type: "link", attrs: attrs2 }]
}).run();
}
}).catch(console.error);
}
return /* @__PURE__ */ jsx(FieldToolbar.Slot, { children: /* @__PURE__ */ jsx(
"div",
{
ref,
tabIndex: -1,
className: styles.root(),
onFocus: (e) => focusToggle(e.currentTarget),
onBlur: (e) => focusToggle(e.relatedTarget),
children: /* @__PURE__ */ jsxs(HStack, { gap: 10, center: true, style: { height: "100%", padding: `${px(4)} 0` }, children: [
/* @__PURE__ */ jsxs(DropdownMenu.Root, { top: true, children: [
/* @__PURE__ */ jsx(
DropdownMenu.Trigger,
{
title: "Heading/paragraph",
className: styles.root.dropdown(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 10, center: true, children: [
/* @__PURE__ */ jsx("span", { children: Styles[selectedStyle] }),
/* @__PURE__ */ jsx(Icon, { icon: IcRoundUnfoldMore })
] })
}
),
/* @__PURE__ */ jsxs(DropdownMenu.Items, { children: [
/* @__PURE__ */ jsx(DropdownMenu.Item, { onClick: () => exec().clearNodes().run(), children: /* @__PURE__ */ jsx(Typo.P, { children: "Normal text" }) }),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().setHeading({ level: 1 }).run(),
children: /* @__PURE__ */ jsx(Typo.H1, { flat: true, children: "Heading 1" })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().setHeading({ level: 2 }).run(),
children: /* @__PURE__ */ jsx(Typo.H2, { flat: true, children: "Heading 2" })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().setHeading({ level: 3 }).run(),
children: /* @__PURE__ */ jsx(Typo.H3, { flat: true, children: "Heading 3" })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().setHeading({ level: 4 }).run(),
children: /* @__PURE__ */ jsx(Typo.H4, { flat: true, children: "Heading 4" })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().setHeading({ level: 5 }).run(),
children: /* @__PURE__ */ jsx(Typo.H5, { flat: true, children: "Heading 5" })
}
)
] })
] }),
enableTables && /* @__PURE__ */ jsxs(DropdownMenu.Root, { top: true, children: [
/* @__PURE__ */ jsx(
DropdownMenu.Trigger,
{
title: "Table",
className: styles.root.dropdown(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 10, center: true, children: [
/* @__PURE__ */ jsx("span", { children: "Table" }),
/* @__PURE__ */ jsx(Icon, { icon: IcRoundUnfoldMore })
] })
}
),
/* @__PURE__ */ jsx(DropdownMenu.Items, { children: selectedTable ? /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().mergeCells().run(),
disabled: !editor.can().mergeCells(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableMergeCells, size: 20 }),
"Merge cells"
] })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().splitCell().run(),
disabled: !editor.can().splitCell(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableSplitCell, size: 20 }),
"Split cell"
] })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().toggleHeaderCell().run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableHeaderCell, size: 20 }),
"Toggle header cell"
] })
}
),
/* @__PURE__ */ jsx(HrDivider, {}),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().addColumnBefore().run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableInsertColumnBefore, size: 20 }),
"Insert column before"
] })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().addColumnAfter().run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableInsertColumnAfter, size: 20 }),
"Insert column after"
] })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().toggleHeaderColumn().run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableHeaderColumn, size: 20 }),
"Toggle header column"
] })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().deleteColumn().run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableDeleteColumn, size: 20 }),
"Delete column"
] })
}
),
/* @__PURE__ */ jsx(HrDivider, {}),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().addRowBefore().run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableInsertRowBefore, size: 20 }),
"Insert row before"
] })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().addRowAfter().run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableInsertRowAfter, size: 20 }),
"Insert row after"
] })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().toggleHeaderRow().run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableHeaderRow, size: 20 }),
"Toggle header row"
] })
}
),
/* @__PURE__ */ jsx(DropdownMenu.Item, { onClick: () => exec().deleteRow().run(), children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableDeleteRow, size: 20 }),
"Delete row"
] }) }),
/* @__PURE__ */ jsx(HrDivider, {}),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().deleteTable().run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableDelete, size: 20 }),
"Delete table"
] })
}
)
] }) : /* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(Icon, { icon: TableInsert, size: 20 }),
"Insert table"
] })
}
) })
] }),
/* @__PURE__ */ jsx("div", { className: styles.root.separator() }),
/* @__PURE__ */ jsx(
IconButton,
{
icon: IcRoundFormatBold,
size: 18,
title: "Bold",
onClick: (e) => {
e.preventDefault();
exec().toggleBold().run();
},
active: editor.isActive("bold")
}
),
/* @__PURE__ */ jsx(
IconButton,
{
icon: IcRoundFormatItalic,
size: 18,
title: "Italic",
onClick: (e) => {
e.preventDefault();
exec().toggleItalic().run();
},
active: editor.isActive("italic")
}
),
/* @__PURE__ */ jsxs(DropdownMenu.Root, { top: true, children: [
/* @__PURE__ */ jsx(
DropdownMenu.Trigger,
{
title: "Alignment",
className: styles.root.dropdown(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 10, center: true, children: [
/* @__PURE__ */ jsx(
Icon,
{
icon: editor.isActive({ textAlign: "center" }) ? IcAlignCenter : editor.isActive({ textAlign: "right" }) ? IcAlignRight : editor.isActive({ textAlign: "justify" }) ? IcAlignJustify : IcAlignLeft,
size: 18
}
),
/* @__PURE__ */ jsx(Icon, { icon: IcRoundUnfoldMore })
] })
}
),
/* @__PURE__ */ jsxs(DropdownMenu.Items, { children: [
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().setTextAlign("left").run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(
Icon,
{
round: true,
icon: IcAlignLeft,
title: "Align left",
active: editor.isActive({ textAlign: "left" })
}
),
/* @__PURE__ */ jsx("span", { children: "Left" })
] })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().setTextAlign("center").run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(
Icon,
{
round: true,
icon: IcAlignCenter,
title: "Align center",
active: editor.isActive({ textAlign: "center" })
}
),
/* @__PURE__ */ jsx("span", { children: "Center" })
] })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().setTextAlign("right").run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(
Icon,
{
round: true,
icon: IcAlignRight,
title: "Align right",
active: editor.isActive({ textAlign: "right" })
}
),
/* @__PURE__ */ jsx("span", { children: "Right" })
] })
}
),
/* @__PURE__ */ jsx(
DropdownMenu.Item,
{
onClick: () => exec().setTextAlign("justify").run(),
children: /* @__PURE__ */ jsxs(HStack, { gap: 8, center: true, children: [
/* @__PURE__ */ jsx(
Icon,
{
round: true,
icon: IcAlignJustify,
title: "Align justify",
active: editor.isActive({ textAlign: "justify" })
}
),
/* @__PURE__ */ jsx("span", { children: "Justify" })
] })
}
)
] })
] }),
/* @__PURE__ */ jsx(
IconButton,
{
icon: IcRoundFormatClear,
size: 18,
title: "Clear format",
onClick: (e) => {
e.preventDefault();
exec().unsetAllMarks().run();
exec().unsetTextAlign().run();
}
}
),
/* @__PURE__ */ jsx("div", { className: styles.root.separator() }),
/* @__PURE__ */ jsx(
IconButton,
{
icon: IcRoundFormatListBulleted,
size: 18,
title: "Bullet list",
onClick: (e) => {
e.preventDefault();
exec().toggleBulletList().run();
},
active: editor.isActive("bulletList")
}
),
/* @__PURE__ */ jsx(
IconButton,
{
icon: IcRoundFormatListNumbered,
size: 18,
title: "Ordered list",
onClick: (e) => {
e.preventDefault();
exec().toggleOrderedList().run();
},
active: editor.isActive("orderedList")
}
),
/* @__PURE__ */ jsx("div", { className: styles.root.separator() }),
/* @__PURE__ */ jsx(
IconButton,
{
icon: IcRoundLink,
size: 18,
title: "Link",
onClick: handleLink,
active: editor.isActive("link")
}
),
/* @__PURE__ */ jsx("div", { className: styles.root.separator() }),
/* @__PURE__ */ jsx(
IconButton,
{
icon: IcRoundQuote,
size: 18,
title: "Blockquote",
onClick: (e) => {
e.preventDefault();
exec().toggleBlockquote().run();
},
active: editor.isActive("blockquote")
}
),
/* @__PURE__ */ jsx(
IconButton,
{
icon: IcRoundHorizontalRule,
size: 18,
title: "Horizontal Rule",
onClick: (e) => {
e.preventDefault();
exec().setHorizontalRule().run();
}
}
),
/* @__PURE__ */ jsx("div", { className: styles.root.separator() }),
/* @__PURE__ */ jsx(
IconButton,
{
icon: IcRoundTextFields,
size: 18,
title: "Small",
onClick: (e) => {
e.preventDefault();
exec().toggleSmall().run();
},
active: editor.isActive("small")
}
),
/* @__PURE__ */ jsx(
IconButton,
{
icon: IcRoundSubscript,
size: 18,
title: "Subscript",
onClick: (e) => {
e.preventDefault();
exec().toggleSubscript().run();
},
active: editor.isActive("subscript")
}
),
/* @__PURE__ */ jsx(
IconButton,
{
icon: IcRoundSuperscript,
size: 18,
title: "Superscript",
onClick: (e) => {
e.preventDefault();
exec().toggleSuperscript().run();
},
active: editor.isActive("superscript")
}
)
] })
}
) });
});
export {
RichTextToolbar
};