@react-email/editor 0.0.0-experimental.5 → 0.0.0-experimental.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +340 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +339 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +761 -14
- package/dist/index.mjs +735 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -3
package/dist/index.js
CHANGED
|
@@ -39,6 +39,16 @@ let prismjs = require("prismjs");
|
|
|
39
39
|
prismjs = __toESM(prismjs);
|
|
40
40
|
let __tiptap_extension_placeholder = require("@tiptap/extension-placeholder");
|
|
41
41
|
__tiptap_extension_placeholder = __toESM(__tiptap_extension_placeholder);
|
|
42
|
+
let __tiptap_react = require("@tiptap/react");
|
|
43
|
+
__tiptap_react = __toESM(__tiptap_react);
|
|
44
|
+
let lucide_react = require("lucide-react");
|
|
45
|
+
lucide_react = __toESM(lucide_react);
|
|
46
|
+
let react = require("react");
|
|
47
|
+
react = __toESM(react);
|
|
48
|
+
let __radix_ui_react_popover = require("@radix-ui/react-popover");
|
|
49
|
+
__radix_ui_react_popover = __toESM(__radix_ui_react_popover);
|
|
50
|
+
let __tiptap_react_menus = require("@tiptap/react/menus");
|
|
51
|
+
__tiptap_react_menus = __toESM(__tiptap_react_menus);
|
|
42
52
|
|
|
43
53
|
//#region src/core/email-node.ts
|
|
44
54
|
var EmailNode = class EmailNode extends __tiptap_core.Node {
|
|
@@ -70,6 +80,48 @@ var EmailNode = class EmailNode extends __tiptap_core.Node {
|
|
|
70
80
|
}
|
|
71
81
|
};
|
|
72
82
|
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/core/event-bus.ts
|
|
85
|
+
const EVENT_PREFIX = "@react-email/editor:";
|
|
86
|
+
var EditorEventBus = class {
|
|
87
|
+
prefixEventName(eventName) {
|
|
88
|
+
return `${EVENT_PREFIX}${String(eventName)}`;
|
|
89
|
+
}
|
|
90
|
+
dispatch(eventName, payload, options) {
|
|
91
|
+
const target = options?.target ?? window;
|
|
92
|
+
const prefixedEventName = this.prefixEventName(eventName);
|
|
93
|
+
const event = new CustomEvent(prefixedEventName, {
|
|
94
|
+
detail: payload,
|
|
95
|
+
bubbles: false,
|
|
96
|
+
cancelable: false
|
|
97
|
+
});
|
|
98
|
+
target.dispatchEvent(event);
|
|
99
|
+
}
|
|
100
|
+
on(eventName, handler, options) {
|
|
101
|
+
const target = options?.target ?? window;
|
|
102
|
+
const prefixedEventName = this.prefixEventName(eventName);
|
|
103
|
+
const abortController = new AbortController();
|
|
104
|
+
const wrappedHandler = (event) => {
|
|
105
|
+
const customEvent = event;
|
|
106
|
+
const result = handler(customEvent.detail);
|
|
107
|
+
if (result instanceof Promise) result.catch((error) => {
|
|
108
|
+
console.error(`Error in async event handler for ${prefixedEventName}:`, {
|
|
109
|
+
event: customEvent.detail,
|
|
110
|
+
error
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
target.addEventListener(prefixedEventName, wrappedHandler, {
|
|
115
|
+
...options,
|
|
116
|
+
signal: abortController.signal
|
|
117
|
+
});
|
|
118
|
+
return { unsubscribe: () => {
|
|
119
|
+
abortController.abort();
|
|
120
|
+
} };
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const editorEventBus = new EditorEventBus();
|
|
124
|
+
|
|
73
125
|
//#endregion
|
|
74
126
|
//#region src/extensions/alignment-attribute.tsx
|
|
75
127
|
const AlignmentAttribute = __tiptap_core.Extension.create({
|
|
@@ -803,6 +855,25 @@ const CodeBlockPrism = EmailNode.from(__tiptap_extension_code_block.default.exte
|
|
|
803
855
|
]
|
|
804
856
|
];
|
|
805
857
|
},
|
|
858
|
+
addKeyboardShortcuts() {
|
|
859
|
+
return {
|
|
860
|
+
...this.parent?.(),
|
|
861
|
+
"Mod-a": ({ editor }) => {
|
|
862
|
+
const { state } = editor;
|
|
863
|
+
const { selection } = state;
|
|
864
|
+
const { $from } = selection;
|
|
865
|
+
for (let depth = $from.depth; depth >= 1; depth--) if ($from.node(depth).type.name === this.name) {
|
|
866
|
+
const blockStart = $from.start(depth);
|
|
867
|
+
const blockEnd = $from.end(depth);
|
|
868
|
+
if (selection.from === blockStart && selection.to === blockEnd) return false;
|
|
869
|
+
const tr = state.tr.setSelection(__tiptap_pm_state.TextSelection.create(state.doc, blockStart, blockEnd));
|
|
870
|
+
editor.view.dispatch(tr);
|
|
871
|
+
return true;
|
|
872
|
+
}
|
|
873
|
+
return false;
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
},
|
|
806
877
|
addProseMirrorPlugins() {
|
|
807
878
|
return [...this.parent?.() || [], PrismPlugin({
|
|
808
879
|
name: this.name,
|
|
@@ -957,20 +1028,42 @@ const ColumnsColumn = EmailNode.create({
|
|
|
957
1028
|
];
|
|
958
1029
|
},
|
|
959
1030
|
addKeyboardShortcuts() {
|
|
960
|
-
return {
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1031
|
+
return {
|
|
1032
|
+
Backspace: ({ editor }) => {
|
|
1033
|
+
const { state } = editor;
|
|
1034
|
+
const { selection } = state;
|
|
1035
|
+
const { empty, $from } = selection;
|
|
1036
|
+
if (!empty) return false;
|
|
1037
|
+
for (let depth = $from.depth; depth >= 1; depth--) {
|
|
1038
|
+
if ($from.pos !== $from.start(depth)) break;
|
|
1039
|
+
const indexInParent = $from.index(depth - 1);
|
|
1040
|
+
if (indexInParent === 0) continue;
|
|
1041
|
+
const prevNode = $from.node(depth - 1).child(indexInParent - 1);
|
|
1042
|
+
if (COLUMN_PARENT_SET.has(prevNode.type.name)) {
|
|
1043
|
+
const deleteFrom = $from.before(depth) - prevNode.nodeSize;
|
|
1044
|
+
const deleteTo = $from.before(depth);
|
|
1045
|
+
editor.view.dispatch(state.tr.delete(deleteFrom, deleteTo));
|
|
1046
|
+
return true;
|
|
1047
|
+
}
|
|
1048
|
+
break;
|
|
1049
|
+
}
|
|
1050
|
+
return false;
|
|
1051
|
+
},
|
|
1052
|
+
"Mod-a": ({ editor }) => {
|
|
1053
|
+
const { state } = editor;
|
|
1054
|
+
const { $from } = state.selection;
|
|
1055
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
1056
|
+
if ($from.node(d).type.name !== "columnsColumn") continue;
|
|
1057
|
+
const columnStart = $from.start(d);
|
|
1058
|
+
const columnEnd = $from.end(d);
|
|
1059
|
+
const { from, to } = state.selection;
|
|
1060
|
+
if (from === columnStart && to === columnEnd) return false;
|
|
1061
|
+
editor.view.dispatch(state.tr.setSelection(__tiptap_pm_state.TextSelection.create(state.doc, columnStart, columnEnd)));
|
|
1062
|
+
return true;
|
|
1063
|
+
}
|
|
1064
|
+
return false;
|
|
971
1065
|
}
|
|
972
|
-
|
|
973
|
-
} };
|
|
1066
|
+
};
|
|
974
1067
|
},
|
|
975
1068
|
renderToReactEmail({ children, node, styles }) {
|
|
976
1069
|
const inlineStyles = inlineCssToJs(node.attrs?.style);
|
|
@@ -1561,10 +1654,658 @@ const TableHeader = __tiptap_core.Node.create({
|
|
|
1561
1654
|
}
|
|
1562
1655
|
});
|
|
1563
1656
|
|
|
1657
|
+
//#endregion
|
|
1658
|
+
//#region src/extensions/uppercase.ts
|
|
1659
|
+
const Uppercase = __tiptap_core.Mark.create({
|
|
1660
|
+
name: "uppercase",
|
|
1661
|
+
addOptions() {
|
|
1662
|
+
return { HTMLAttributes: {} };
|
|
1663
|
+
},
|
|
1664
|
+
parseHTML() {
|
|
1665
|
+
return [{
|
|
1666
|
+
tag: "span",
|
|
1667
|
+
getAttrs: (node) => {
|
|
1668
|
+
if (node.style.textTransform === "uppercase") return {};
|
|
1669
|
+
return false;
|
|
1670
|
+
}
|
|
1671
|
+
}];
|
|
1672
|
+
},
|
|
1673
|
+
renderHTML({ HTMLAttributes }) {
|
|
1674
|
+
return [
|
|
1675
|
+
"span",
|
|
1676
|
+
(0, __tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes, { style: "text-transform: uppercase" }),
|
|
1677
|
+
0
|
|
1678
|
+
];
|
|
1679
|
+
},
|
|
1680
|
+
addCommands() {
|
|
1681
|
+
return {
|
|
1682
|
+
setUppercase: () => ({ commands }) => {
|
|
1683
|
+
return commands.setMark(this.name);
|
|
1684
|
+
},
|
|
1685
|
+
toggleUppercase: () => ({ commands }) => {
|
|
1686
|
+
return commands.toggleMark(this.name);
|
|
1687
|
+
},
|
|
1688
|
+
unsetUppercase: () => ({ commands }) => {
|
|
1689
|
+
return commands.unsetMark(this.name);
|
|
1690
|
+
}
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
});
|
|
1694
|
+
|
|
1695
|
+
//#endregion
|
|
1696
|
+
//#region src/utils/set-text-alignment.ts
|
|
1697
|
+
function setTextAlignment(editor, alignment) {
|
|
1698
|
+
const { from, to } = editor.state.selection;
|
|
1699
|
+
const tr = editor.state.tr;
|
|
1700
|
+
editor.state.doc.nodesBetween(from, to, (node, pos) => {
|
|
1701
|
+
if (node.isTextblock) {
|
|
1702
|
+
const prop = "align" in node.attrs ? "align" : "alignment";
|
|
1703
|
+
tr.setNodeMarkup(pos, null, {
|
|
1704
|
+
...node.attrs,
|
|
1705
|
+
[prop]: alignment
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
});
|
|
1709
|
+
editor.view.dispatch(tr);
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
//#endregion
|
|
1713
|
+
//#region src/ui/bubble-menu/context.tsx
|
|
1714
|
+
const BubbleMenuContext = react.createContext(null);
|
|
1715
|
+
function useBubbleMenuContext() {
|
|
1716
|
+
const context = react.useContext(BubbleMenuContext);
|
|
1717
|
+
if (!context) throw new Error("BubbleMenu compound components must be used within <BubbleMenu.Root>");
|
|
1718
|
+
return context;
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
//#endregion
|
|
1722
|
+
//#region src/ui/bubble-menu/item.tsx
|
|
1723
|
+
function BubbleMenuItem({ name, isActive, onCommand, className, children,...rest }) {
|
|
1724
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1725
|
+
type: "button",
|
|
1726
|
+
"aria-label": name,
|
|
1727
|
+
"aria-pressed": isActive,
|
|
1728
|
+
className,
|
|
1729
|
+
"data-re-bubble-menu-item": "",
|
|
1730
|
+
"data-item": name,
|
|
1731
|
+
...isActive ? { "data-active": "" } : {},
|
|
1732
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
1733
|
+
onClick: onCommand,
|
|
1734
|
+
...rest,
|
|
1735
|
+
children
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
//#endregion
|
|
1740
|
+
//#region src/ui/bubble-menu/align-center.tsx
|
|
1741
|
+
function BubbleMenuAlignCenter({ className, children }) {
|
|
1742
|
+
const { editor } = useBubbleMenuContext();
|
|
1743
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuItem, {
|
|
1744
|
+
name: "align-center",
|
|
1745
|
+
isActive: (0, __tiptap_react.useEditorState)({
|
|
1746
|
+
editor,
|
|
1747
|
+
selector: ({ editor: editor$1 }) => editor$1?.isActive({ alignment: "center" }) ?? false
|
|
1748
|
+
}),
|
|
1749
|
+
onCommand: () => setTextAlignment(editor, "center"),
|
|
1750
|
+
className,
|
|
1751
|
+
children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.AlignCenterIcon, {})
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
//#endregion
|
|
1756
|
+
//#region src/ui/bubble-menu/align-left.tsx
|
|
1757
|
+
function BubbleMenuAlignLeft({ className, children }) {
|
|
1758
|
+
const { editor } = useBubbleMenuContext();
|
|
1759
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuItem, {
|
|
1760
|
+
name: "align-left",
|
|
1761
|
+
isActive: (0, __tiptap_react.useEditorState)({
|
|
1762
|
+
editor,
|
|
1763
|
+
selector: ({ editor: editor$1 }) => editor$1?.isActive({ alignment: "left" }) ?? false
|
|
1764
|
+
}),
|
|
1765
|
+
onCommand: () => setTextAlignment(editor, "left"),
|
|
1766
|
+
className,
|
|
1767
|
+
children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.AlignLeftIcon, {})
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
//#endregion
|
|
1772
|
+
//#region src/ui/bubble-menu/align-right.tsx
|
|
1773
|
+
function BubbleMenuAlignRight({ className, children }) {
|
|
1774
|
+
const { editor } = useBubbleMenuContext();
|
|
1775
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuItem, {
|
|
1776
|
+
name: "align-right",
|
|
1777
|
+
isActive: (0, __tiptap_react.useEditorState)({
|
|
1778
|
+
editor,
|
|
1779
|
+
selector: ({ editor: editor$1 }) => editor$1?.isActive({ alignment: "right" }) ?? false
|
|
1780
|
+
}),
|
|
1781
|
+
onCommand: () => setTextAlignment(editor, "right"),
|
|
1782
|
+
className,
|
|
1783
|
+
children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.AlignRightIcon, {})
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
//#endregion
|
|
1788
|
+
//#region src/ui/bubble-menu/create-mark-bubble-item.tsx
|
|
1789
|
+
function createMarkBubbleItem(config) {
|
|
1790
|
+
function MarkBubbleItem({ className, children }) {
|
|
1791
|
+
const { editor } = useBubbleMenuContext();
|
|
1792
|
+
const isActive = (0, __tiptap_react.useEditorState)({
|
|
1793
|
+
editor,
|
|
1794
|
+
selector: ({ editor: editor$1 }) => {
|
|
1795
|
+
if (config.activeParams) return editor$1?.isActive(config.activeName, config.activeParams) ?? false;
|
|
1796
|
+
return editor$1?.isActive(config.activeName) ?? false;
|
|
1797
|
+
}
|
|
1798
|
+
});
|
|
1799
|
+
const handleCommand = () => {
|
|
1800
|
+
const chain = editor.chain().focus();
|
|
1801
|
+
const method = chain[config.command];
|
|
1802
|
+
if (method) method.call(chain).run();
|
|
1803
|
+
};
|
|
1804
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuItem, {
|
|
1805
|
+
name: config.name,
|
|
1806
|
+
isActive,
|
|
1807
|
+
onCommand: handleCommand,
|
|
1808
|
+
className,
|
|
1809
|
+
children: children ?? config.icon
|
|
1810
|
+
});
|
|
1811
|
+
}
|
|
1812
|
+
MarkBubbleItem.displayName = `BubbleMenu${config.name.charAt(0).toUpperCase() + config.name.slice(1)}`;
|
|
1813
|
+
return MarkBubbleItem;
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
//#endregion
|
|
1817
|
+
//#region src/ui/bubble-menu/bold.tsx
|
|
1818
|
+
const BubbleMenuBold = createMarkBubbleItem({
|
|
1819
|
+
name: "bold",
|
|
1820
|
+
activeName: "bold",
|
|
1821
|
+
command: "toggleBold",
|
|
1822
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.BoldIcon, {})
|
|
1823
|
+
});
|
|
1824
|
+
|
|
1825
|
+
//#endregion
|
|
1826
|
+
//#region src/ui/bubble-menu/code.tsx
|
|
1827
|
+
const BubbleMenuCode = createMarkBubbleItem({
|
|
1828
|
+
name: "code",
|
|
1829
|
+
activeName: "code",
|
|
1830
|
+
command: "toggleCode",
|
|
1831
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.CodeIcon, {})
|
|
1832
|
+
});
|
|
1833
|
+
|
|
1834
|
+
//#endregion
|
|
1835
|
+
//#region src/ui/bubble-menu/group.tsx
|
|
1836
|
+
function BubbleMenuItemGroup({ className, children }) {
|
|
1837
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("fieldset", {
|
|
1838
|
+
className,
|
|
1839
|
+
"data-re-bubble-menu-group": "",
|
|
1840
|
+
children
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
//#endregion
|
|
1845
|
+
//#region src/ui/bubble-menu/italic.tsx
|
|
1846
|
+
const BubbleMenuItalic = createMarkBubbleItem({
|
|
1847
|
+
name: "italic",
|
|
1848
|
+
activeName: "italic",
|
|
1849
|
+
command: "toggleItalic",
|
|
1850
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ItalicIcon, {})
|
|
1851
|
+
});
|
|
1852
|
+
|
|
1853
|
+
//#endregion
|
|
1854
|
+
//#region src/ui/bubble-menu/utils.ts
|
|
1855
|
+
const SAFE_PROTOCOLS = new Set([
|
|
1856
|
+
"http:",
|
|
1857
|
+
"https:",
|
|
1858
|
+
"mailto:",
|
|
1859
|
+
"tel:"
|
|
1860
|
+
]);
|
|
1861
|
+
/**
|
|
1862
|
+
* Basic URL validation and auto-prefixing.
|
|
1863
|
+
* Rejects dangerous schemes (javascript:, data:, vbscript:, etc.).
|
|
1864
|
+
* Returns the valid URL string or null.
|
|
1865
|
+
*/
|
|
1866
|
+
function getUrlFromString(str) {
|
|
1867
|
+
if (str === "#") return str;
|
|
1868
|
+
try {
|
|
1869
|
+
const url = new URL(str);
|
|
1870
|
+
if (SAFE_PROTOCOLS.has(url.protocol)) return str;
|
|
1871
|
+
return null;
|
|
1872
|
+
} catch {}
|
|
1873
|
+
try {
|
|
1874
|
+
if (str.includes(".") && !str.includes(" ")) return new URL(`https://${str}`).toString();
|
|
1875
|
+
} catch {}
|
|
1876
|
+
return null;
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
//#endregion
|
|
1880
|
+
//#region src/ui/bubble-menu/link-selector.tsx
|
|
1881
|
+
function BubbleMenuLinkSelector({ className, showToggle = true, validateUrl, onLinkApply, onLinkRemove, children }) {
|
|
1882
|
+
const { editor } = useBubbleMenuContext();
|
|
1883
|
+
const [isOpen, setIsOpen] = react.useState(false);
|
|
1884
|
+
const editorState = (0, __tiptap_react.useEditorState)({
|
|
1885
|
+
editor,
|
|
1886
|
+
selector: ({ editor: editor$1 }) => ({
|
|
1887
|
+
isLinkActive: editor$1?.isActive("link") ?? false,
|
|
1888
|
+
hasLink: Boolean(editor$1?.getAttributes("link").href),
|
|
1889
|
+
currentHref: editor$1?.getAttributes("link").href || ""
|
|
1890
|
+
})
|
|
1891
|
+
});
|
|
1892
|
+
react.useEffect(() => {
|
|
1893
|
+
const subscription = editorEventBus.on("bubble-menu:add-link", () => {
|
|
1894
|
+
setIsOpen(true);
|
|
1895
|
+
});
|
|
1896
|
+
return () => {
|
|
1897
|
+
setIsOpen(false);
|
|
1898
|
+
subscription.unsubscribe();
|
|
1899
|
+
};
|
|
1900
|
+
}, []);
|
|
1901
|
+
if (!editorState) return null;
|
|
1902
|
+
const handleOpenLink = () => {
|
|
1903
|
+
setIsOpen(!isOpen);
|
|
1904
|
+
};
|
|
1905
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1906
|
+
"data-re-link-selector": "",
|
|
1907
|
+
...isOpen ? { "data-open": "" } : {},
|
|
1908
|
+
...editorState.hasLink ? { "data-has-link": "" } : {},
|
|
1909
|
+
className,
|
|
1910
|
+
children: [showToggle && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1911
|
+
type: "button",
|
|
1912
|
+
"aria-expanded": isOpen,
|
|
1913
|
+
"aria-haspopup": "true",
|
|
1914
|
+
"aria-label": "Add link",
|
|
1915
|
+
"aria-pressed": editorState.isLinkActive && editorState.hasLink,
|
|
1916
|
+
"data-re-link-selector-trigger": "",
|
|
1917
|
+
onClick: handleOpenLink,
|
|
1918
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.LinkIcon, {})
|
|
1919
|
+
}), isOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkForm, {
|
|
1920
|
+
editor,
|
|
1921
|
+
currentHref: editorState.currentHref,
|
|
1922
|
+
validateUrl,
|
|
1923
|
+
onLinkApply,
|
|
1924
|
+
onLinkRemove,
|
|
1925
|
+
setIsOpen,
|
|
1926
|
+
children
|
|
1927
|
+
})]
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
function LinkForm({ editor, currentHref, validateUrl, onLinkApply, onLinkRemove, setIsOpen, children }) {
|
|
1931
|
+
const inputRef = react.useRef(null);
|
|
1932
|
+
const formRef = react.useRef(null);
|
|
1933
|
+
const displayHref = currentHref === "#" ? "" : currentHref;
|
|
1934
|
+
const [inputValue, setInputValue] = react.useState(displayHref);
|
|
1935
|
+
react.useEffect(() => {
|
|
1936
|
+
const timeoutId = setTimeout(() => {
|
|
1937
|
+
inputRef.current?.focus();
|
|
1938
|
+
}, 0);
|
|
1939
|
+
return () => clearTimeout(timeoutId);
|
|
1940
|
+
}, []);
|
|
1941
|
+
react.useEffect(() => {
|
|
1942
|
+
const handleKeyDown = (event) => {
|
|
1943
|
+
if (event.key === "Escape") {
|
|
1944
|
+
if (editor.getAttributes("link").href === "#") editor.chain().unsetLink().run();
|
|
1945
|
+
setIsOpen(false);
|
|
1946
|
+
}
|
|
1947
|
+
};
|
|
1948
|
+
const handleClickOutside = (event) => {
|
|
1949
|
+
if (formRef.current && !formRef.current.contains(event.target)) {
|
|
1950
|
+
const form = formRef.current;
|
|
1951
|
+
const submitEvent = new Event("submit", {
|
|
1952
|
+
bubbles: true,
|
|
1953
|
+
cancelable: true
|
|
1954
|
+
});
|
|
1955
|
+
form.dispatchEvent(submitEvent);
|
|
1956
|
+
setIsOpen(false);
|
|
1957
|
+
}
|
|
1958
|
+
};
|
|
1959
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1960
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
1961
|
+
return () => {
|
|
1962
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
1963
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
1964
|
+
};
|
|
1965
|
+
}, [editor, setIsOpen]);
|
|
1966
|
+
function handleSubmit(e) {
|
|
1967
|
+
e.preventDefault();
|
|
1968
|
+
const value = inputValue.trim();
|
|
1969
|
+
if (value === "") {
|
|
1970
|
+
setLinkHref(editor, "");
|
|
1971
|
+
setIsOpen(false);
|
|
1972
|
+
focusEditor(editor);
|
|
1973
|
+
onLinkRemove?.();
|
|
1974
|
+
return;
|
|
1975
|
+
}
|
|
1976
|
+
const finalValue = (validateUrl ?? getUrlFromString)(value);
|
|
1977
|
+
if (!finalValue) {
|
|
1978
|
+
setLinkHref(editor, "");
|
|
1979
|
+
setIsOpen(false);
|
|
1980
|
+
focusEditor(editor);
|
|
1981
|
+
onLinkRemove?.();
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
setLinkHref(editor, finalValue);
|
|
1985
|
+
setIsOpen(false);
|
|
1986
|
+
focusEditor(editor);
|
|
1987
|
+
onLinkApply?.(finalValue);
|
|
1988
|
+
}
|
|
1989
|
+
function handleUnlink(e) {
|
|
1990
|
+
e.stopPropagation();
|
|
1991
|
+
setLinkHref(editor, "");
|
|
1992
|
+
setIsOpen(false);
|
|
1993
|
+
focusEditor(editor);
|
|
1994
|
+
onLinkRemove?.();
|
|
1995
|
+
}
|
|
1996
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
1997
|
+
ref: formRef,
|
|
1998
|
+
"data-re-link-selector-form": "",
|
|
1999
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
2000
|
+
onClick: (e) => e.stopPropagation(),
|
|
2001
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
2002
|
+
onSubmit: handleSubmit,
|
|
2003
|
+
children: [
|
|
2004
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2005
|
+
ref: inputRef,
|
|
2006
|
+
"data-re-link-selector-input": "",
|
|
2007
|
+
value: inputValue,
|
|
2008
|
+
onFocus: (e) => e.stopPropagation(),
|
|
2009
|
+
onChange: (e) => setInputValue(e.target.value),
|
|
2010
|
+
placeholder: "Paste a link",
|
|
2011
|
+
type: "text"
|
|
2012
|
+
}),
|
|
2013
|
+
children,
|
|
2014
|
+
displayHref ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2015
|
+
type: "button",
|
|
2016
|
+
"aria-label": "Remove link",
|
|
2017
|
+
"data-re-link-selector-unlink": "",
|
|
2018
|
+
onClick: handleUnlink,
|
|
2019
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.UnlinkIcon, {})
|
|
2020
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2021
|
+
type: "submit",
|
|
2022
|
+
"aria-label": "Apply link",
|
|
2023
|
+
"data-re-link-selector-apply": "",
|
|
2024
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
2025
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, {})
|
|
2026
|
+
})
|
|
2027
|
+
]
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
function setLinkHref(editor, href) {
|
|
2031
|
+
if (href.length === 0) {
|
|
2032
|
+
editor.chain().unsetLink().run();
|
|
2033
|
+
return;
|
|
2034
|
+
}
|
|
2035
|
+
const { from, to } = editor.state.selection;
|
|
2036
|
+
if (from === to) {
|
|
2037
|
+
editor.chain().extendMarkRange("link").setLink({ href }).setTextSelection({
|
|
2038
|
+
from,
|
|
2039
|
+
to
|
|
2040
|
+
}).run();
|
|
2041
|
+
return;
|
|
2042
|
+
}
|
|
2043
|
+
editor.chain().setLink({ href }).run();
|
|
2044
|
+
}
|
|
2045
|
+
function focusEditor(editor) {
|
|
2046
|
+
setTimeout(() => {
|
|
2047
|
+
editor.commands.focus();
|
|
2048
|
+
}, 0);
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
//#endregion
|
|
2052
|
+
//#region src/ui/bubble-menu/node-selector.tsx
|
|
2053
|
+
const NodeSelectorContext = react.createContext(null);
|
|
2054
|
+
function useNodeSelectorContext() {
|
|
2055
|
+
const context = react.useContext(NodeSelectorContext);
|
|
2056
|
+
if (!context) throw new Error("NodeSelector compound components must be used within <NodeSelector.Root>");
|
|
2057
|
+
return context;
|
|
2058
|
+
}
|
|
2059
|
+
function NodeSelectorRoot({ omit = [], open: controlledOpen, onOpenChange, className, children }) {
|
|
2060
|
+
const { editor } = useBubbleMenuContext();
|
|
2061
|
+
const [uncontrolledOpen, setUncontrolledOpen] = react.useState(false);
|
|
2062
|
+
const isControlled = controlledOpen !== void 0;
|
|
2063
|
+
const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
|
|
2064
|
+
const setIsOpen = react.useCallback((value) => {
|
|
2065
|
+
if (!isControlled) setUncontrolledOpen(value);
|
|
2066
|
+
onOpenChange?.(value);
|
|
2067
|
+
}, [isControlled, onOpenChange]);
|
|
2068
|
+
const editorState = (0, __tiptap_react.useEditorState)({
|
|
2069
|
+
editor,
|
|
2070
|
+
selector: ({ editor: editor$1 }) => ({
|
|
2071
|
+
isParagraphActive: (editor$1?.isActive("paragraph") ?? false) && !editor$1?.isActive("bulletList") && !editor$1?.isActive("orderedList"),
|
|
2072
|
+
isHeading1Active: editor$1?.isActive("heading", { level: 1 }) ?? false,
|
|
2073
|
+
isHeading2Active: editor$1?.isActive("heading", { level: 2 }) ?? false,
|
|
2074
|
+
isHeading3Active: editor$1?.isActive("heading", { level: 3 }) ?? false,
|
|
2075
|
+
isBulletListActive: editor$1?.isActive("bulletList") ?? false,
|
|
2076
|
+
isOrderedListActive: editor$1?.isActive("orderedList") ?? false,
|
|
2077
|
+
isBlockquoteActive: editor$1?.isActive("blockquote") ?? false,
|
|
2078
|
+
isCodeBlockActive: editor$1?.isActive("codeBlock") ?? false
|
|
2079
|
+
})
|
|
2080
|
+
});
|
|
2081
|
+
const allItems = react.useMemo(() => [
|
|
2082
|
+
{
|
|
2083
|
+
name: "Text",
|
|
2084
|
+
icon: lucide_react.TextIcon,
|
|
2085
|
+
command: () => editor.chain().focus().clearNodes().toggleNode("paragraph", "paragraph").run(),
|
|
2086
|
+
isActive: editorState?.isParagraphActive ?? false
|
|
2087
|
+
},
|
|
2088
|
+
{
|
|
2089
|
+
name: "Title",
|
|
2090
|
+
icon: lucide_react.Heading1,
|
|
2091
|
+
command: () => editor.chain().focus().clearNodes().toggleHeading({ level: 1 }).run(),
|
|
2092
|
+
isActive: editorState?.isHeading1Active ?? false
|
|
2093
|
+
},
|
|
2094
|
+
{
|
|
2095
|
+
name: "Subtitle",
|
|
2096
|
+
icon: lucide_react.Heading2,
|
|
2097
|
+
command: () => editor.chain().focus().clearNodes().toggleHeading({ level: 2 }).run(),
|
|
2098
|
+
isActive: editorState?.isHeading2Active ?? false
|
|
2099
|
+
},
|
|
2100
|
+
{
|
|
2101
|
+
name: "Heading",
|
|
2102
|
+
icon: lucide_react.Heading3,
|
|
2103
|
+
command: () => editor.chain().focus().clearNodes().toggleHeading({ level: 3 }).run(),
|
|
2104
|
+
isActive: editorState?.isHeading3Active ?? false
|
|
2105
|
+
},
|
|
2106
|
+
{
|
|
2107
|
+
name: "Bullet List",
|
|
2108
|
+
icon: lucide_react.List,
|
|
2109
|
+
command: () => editor.chain().focus().clearNodes().toggleBulletList().run(),
|
|
2110
|
+
isActive: editorState?.isBulletListActive ?? false
|
|
2111
|
+
},
|
|
2112
|
+
{
|
|
2113
|
+
name: "Numbered List",
|
|
2114
|
+
icon: lucide_react.ListOrdered,
|
|
2115
|
+
command: () => editor.chain().focus().clearNodes().toggleOrderedList().run(),
|
|
2116
|
+
isActive: editorState?.isOrderedListActive ?? false
|
|
2117
|
+
},
|
|
2118
|
+
{
|
|
2119
|
+
name: "Quote",
|
|
2120
|
+
icon: lucide_react.TextQuote,
|
|
2121
|
+
command: () => editor.chain().focus().clearNodes().toggleNode("paragraph", "paragraph").toggleBlockquote().run(),
|
|
2122
|
+
isActive: editorState?.isBlockquoteActive ?? false
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
name: "Code",
|
|
2126
|
+
icon: lucide_react.Code,
|
|
2127
|
+
command: () => editor.chain().focus().clearNodes().toggleCodeBlock().run(),
|
|
2128
|
+
isActive: editorState?.isCodeBlockActive ?? false
|
|
2129
|
+
}
|
|
2130
|
+
], [editor, editorState]);
|
|
2131
|
+
const items = react.useMemo(() => allItems.filter((item) => !omit.includes(item.name)), [allItems, omit]);
|
|
2132
|
+
const activeItem = react.useMemo(() => items.find((item) => item.isActive) ?? { name: "Multiple" }, [items]);
|
|
2133
|
+
const contextValue = react.useMemo(() => ({
|
|
2134
|
+
items,
|
|
2135
|
+
activeItem,
|
|
2136
|
+
isOpen,
|
|
2137
|
+
setIsOpen
|
|
2138
|
+
}), [
|
|
2139
|
+
items,
|
|
2140
|
+
activeItem,
|
|
2141
|
+
isOpen,
|
|
2142
|
+
setIsOpen
|
|
2143
|
+
]);
|
|
2144
|
+
if (!editorState || items.length === 0) return null;
|
|
2145
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NodeSelectorContext.Provider, {
|
|
2146
|
+
value: contextValue,
|
|
2147
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__radix_ui_react_popover.Root, {
|
|
2148
|
+
open: isOpen,
|
|
2149
|
+
onOpenChange: setIsOpen,
|
|
2150
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2151
|
+
"data-re-node-selector": "",
|
|
2152
|
+
...isOpen ? { "data-open": "" } : {},
|
|
2153
|
+
className,
|
|
2154
|
+
children
|
|
2155
|
+
})
|
|
2156
|
+
})
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2159
|
+
function NodeSelectorTrigger({ className, children }) {
|
|
2160
|
+
const { activeItem, isOpen, setIsOpen } = useNodeSelectorContext();
|
|
2161
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__radix_ui_react_popover.Trigger, {
|
|
2162
|
+
"data-re-node-selector-trigger": "",
|
|
2163
|
+
className,
|
|
2164
|
+
onClick: () => setIsOpen(!isOpen),
|
|
2165
|
+
children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: activeItem.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronDown, {})] })
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2168
|
+
function NodeSelectorContent({ className, align = "start", children }) {
|
|
2169
|
+
const { items, setIsOpen } = useNodeSelectorContext();
|
|
2170
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__radix_ui_react_popover.Content, {
|
|
2171
|
+
align,
|
|
2172
|
+
"data-re-node-selector-content": "",
|
|
2173
|
+
className,
|
|
2174
|
+
children: children ? children(items, () => setIsOpen(false)) : items.map((item) => {
|
|
2175
|
+
const Icon = item.icon;
|
|
2176
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
2177
|
+
type: "button",
|
|
2178
|
+
"data-re-node-selector-item": "",
|
|
2179
|
+
...item.isActive ? { "data-active": "" } : {},
|
|
2180
|
+
onClick: () => {
|
|
2181
|
+
item.command();
|
|
2182
|
+
setIsOpen(false);
|
|
2183
|
+
},
|
|
2184
|
+
children: [
|
|
2185
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {}),
|
|
2186
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: item.name }),
|
|
2187
|
+
item.isActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, {})
|
|
2188
|
+
]
|
|
2189
|
+
}, item.name);
|
|
2190
|
+
})
|
|
2191
|
+
});
|
|
2192
|
+
}
|
|
2193
|
+
function BubbleMenuNodeSelector({ omit = [], className, triggerContent, open, onOpenChange }) {
|
|
2194
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(NodeSelectorRoot, {
|
|
2195
|
+
omit,
|
|
2196
|
+
open,
|
|
2197
|
+
onOpenChange,
|
|
2198
|
+
className,
|
|
2199
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(NodeSelectorTrigger, { children: triggerContent }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NodeSelectorContent, {})]
|
|
2200
|
+
});
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
//#endregion
|
|
2204
|
+
//#region src/ui/bubble-menu/root.tsx
|
|
2205
|
+
function BubbleMenuRoot({ excludeNodes = [], placement = "bottom", offset = 8, onHide, className, children }) {
|
|
2206
|
+
const { editor } = (0, __tiptap_react.useCurrentEditor)();
|
|
2207
|
+
if (!editor) return null;
|
|
2208
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tiptap_react_menus.BubbleMenu, {
|
|
2209
|
+
editor,
|
|
2210
|
+
"data-re-bubble-menu": "",
|
|
2211
|
+
shouldShow: ({ editor: editor$1, view }) => {
|
|
2212
|
+
for (const node of excludeNodes) if (editor$1.isActive(node)) return false;
|
|
2213
|
+
if (view.dom.classList.contains("dragging")) return false;
|
|
2214
|
+
return editor$1.view.state.selection.content().size > 0;
|
|
2215
|
+
},
|
|
2216
|
+
options: {
|
|
2217
|
+
placement,
|
|
2218
|
+
offset,
|
|
2219
|
+
onHide
|
|
2220
|
+
},
|
|
2221
|
+
className,
|
|
2222
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BubbleMenuContext.Provider, {
|
|
2223
|
+
value: { editor },
|
|
2224
|
+
children
|
|
2225
|
+
})
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
//#endregion
|
|
2230
|
+
//#region src/ui/bubble-menu/separator.tsx
|
|
2231
|
+
function BubbleMenuSeparator({ className }) {
|
|
2232
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("hr", {
|
|
2233
|
+
className,
|
|
2234
|
+
"data-re-bubble-menu-separator": ""
|
|
2235
|
+
});
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
//#endregion
|
|
2239
|
+
//#region src/ui/bubble-menu/strike.tsx
|
|
2240
|
+
const BubbleMenuStrike = createMarkBubbleItem({
|
|
2241
|
+
name: "strike",
|
|
2242
|
+
activeName: "strike",
|
|
2243
|
+
command: "toggleStrike",
|
|
2244
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.StrikethroughIcon, {})
|
|
2245
|
+
});
|
|
2246
|
+
|
|
2247
|
+
//#endregion
|
|
2248
|
+
//#region src/ui/bubble-menu/underline.tsx
|
|
2249
|
+
const BubbleMenuUnderline = createMarkBubbleItem({
|
|
2250
|
+
name: "underline",
|
|
2251
|
+
activeName: "underline",
|
|
2252
|
+
command: "toggleUnderline",
|
|
2253
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.UnderlineIcon, {})
|
|
2254
|
+
});
|
|
2255
|
+
|
|
2256
|
+
//#endregion
|
|
2257
|
+
//#region src/ui/bubble-menu/uppercase.tsx
|
|
2258
|
+
const BubbleMenuUppercase = createMarkBubbleItem({
|
|
2259
|
+
name: "uppercase",
|
|
2260
|
+
activeName: "uppercase",
|
|
2261
|
+
command: "toggleUppercase",
|
|
2262
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.CaseUpperIcon, {})
|
|
2263
|
+
});
|
|
2264
|
+
|
|
2265
|
+
//#endregion
|
|
2266
|
+
//#region src/ui/bubble-menu/index.ts
|
|
2267
|
+
const BubbleMenu = {
|
|
2268
|
+
Root: BubbleMenuRoot,
|
|
2269
|
+
ItemGroup: BubbleMenuItemGroup,
|
|
2270
|
+
Separator: BubbleMenuSeparator,
|
|
2271
|
+
Item: BubbleMenuItem,
|
|
2272
|
+
Bold: BubbleMenuBold,
|
|
2273
|
+
Italic: BubbleMenuItalic,
|
|
2274
|
+
Underline: BubbleMenuUnderline,
|
|
2275
|
+
Strike: BubbleMenuStrike,
|
|
2276
|
+
Code: BubbleMenuCode,
|
|
2277
|
+
Uppercase: BubbleMenuUppercase,
|
|
2278
|
+
AlignLeft: BubbleMenuAlignLeft,
|
|
2279
|
+
AlignCenter: BubbleMenuAlignCenter,
|
|
2280
|
+
AlignRight: BubbleMenuAlignRight,
|
|
2281
|
+
NodeSelector: Object.assign(BubbleMenuNodeSelector, {
|
|
2282
|
+
Root: NodeSelectorRoot,
|
|
2283
|
+
Trigger: NodeSelectorTrigger,
|
|
2284
|
+
Content: NodeSelectorContent
|
|
2285
|
+
}),
|
|
2286
|
+
LinkSelector: BubbleMenuLinkSelector
|
|
2287
|
+
};
|
|
2288
|
+
|
|
1564
2289
|
//#endregion
|
|
1565
2290
|
exports.AlignmentAttribute = AlignmentAttribute;
|
|
1566
2291
|
exports.Body = Body;
|
|
1567
2292
|
exports.Bold = Bold;
|
|
2293
|
+
exports.BubbleMenu = BubbleMenu;
|
|
2294
|
+
exports.BubbleMenuAlignCenter = BubbleMenuAlignCenter;
|
|
2295
|
+
exports.BubbleMenuAlignLeft = BubbleMenuAlignLeft;
|
|
2296
|
+
exports.BubbleMenuAlignRight = BubbleMenuAlignRight;
|
|
2297
|
+
exports.BubbleMenuBold = BubbleMenuBold;
|
|
2298
|
+
exports.BubbleMenuCode = BubbleMenuCode;
|
|
2299
|
+
exports.BubbleMenuItalic = BubbleMenuItalic;
|
|
2300
|
+
exports.BubbleMenuItem = BubbleMenuItem;
|
|
2301
|
+
exports.BubbleMenuItemGroup = BubbleMenuItemGroup;
|
|
2302
|
+
exports.BubbleMenuLinkSelector = BubbleMenuLinkSelector;
|
|
2303
|
+
exports.BubbleMenuNodeSelector = BubbleMenuNodeSelector;
|
|
2304
|
+
exports.BubbleMenuRoot = BubbleMenuRoot;
|
|
2305
|
+
exports.BubbleMenuSeparator = BubbleMenuSeparator;
|
|
2306
|
+
exports.BubbleMenuStrike = BubbleMenuStrike;
|
|
2307
|
+
exports.BubbleMenuUnderline = BubbleMenuUnderline;
|
|
2308
|
+
exports.BubbleMenuUppercase = BubbleMenuUppercase;
|
|
1568
2309
|
exports.Button = Button;
|
|
1569
2310
|
exports.COLUMN_PARENT_TYPES = COLUMN_PARENT_TYPES;
|
|
1570
2311
|
exports.ClassAttribute = ClassAttribute;
|
|
@@ -1575,6 +2316,9 @@ exports.EmailNode = EmailNode;
|
|
|
1575
2316
|
exports.FourColumns = FourColumns;
|
|
1576
2317
|
exports.MAX_COLUMNS_DEPTH = MAX_COLUMNS_DEPTH;
|
|
1577
2318
|
exports.MaxNesting = MaxNesting;
|
|
2319
|
+
exports.NodeSelectorContent = NodeSelectorContent;
|
|
2320
|
+
exports.NodeSelectorRoot = NodeSelectorRoot;
|
|
2321
|
+
exports.NodeSelectorTrigger = NodeSelectorTrigger;
|
|
1578
2322
|
exports.Placeholder = Placeholder;
|
|
1579
2323
|
exports.PreservedStyle = PreservedStyle;
|
|
1580
2324
|
exports.PreviewText = PreviewText;
|
|
@@ -1587,5 +2331,8 @@ exports.TableHeader = TableHeader;
|
|
|
1587
2331
|
exports.TableRow = TableRow;
|
|
1588
2332
|
exports.ThreeColumns = ThreeColumns;
|
|
1589
2333
|
exports.TwoColumns = TwoColumns;
|
|
2334
|
+
exports.Uppercase = Uppercase;
|
|
2335
|
+
exports.editorEventBus = editorEventBus;
|
|
1590
2336
|
exports.getColumnsDepth = getColumnsDepth;
|
|
1591
|
-
exports.processStylesForUnlink = processStylesForUnlink;
|
|
2337
|
+
exports.processStylesForUnlink = processStylesForUnlink;
|
|
2338
|
+
exports.setTextAlignment = setTextAlignment;
|