@react-email/editor 0.0.0-experimental.20 → 0.0.0-experimental.22
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.cjs +191 -242
- package/dist/index.d.cts +86 -107
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +86 -107
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +191 -244
- package/dist/index.mjs.map +1 -1
- package/dist/ui/themes/default.css +20 -1
- package/package.json +9 -5
package/dist/index.cjs
CHANGED
|
@@ -37,6 +37,8 @@ let _tiptap_starter_kit = require("@tiptap/starter-kit");
|
|
|
37
37
|
_tiptap_starter_kit = __toESM(_tiptap_starter_kit);
|
|
38
38
|
let _tiptap_extension_blockquote = require("@tiptap/extension-blockquote");
|
|
39
39
|
_tiptap_extension_blockquote = __toESM(_tiptap_extension_blockquote);
|
|
40
|
+
let _tiptap_extension_bold = require("@tiptap/extension-bold");
|
|
41
|
+
_tiptap_extension_bold = __toESM(_tiptap_extension_bold);
|
|
40
42
|
let _tiptap_extension_bullet_list = require("@tiptap/extension-bullet-list");
|
|
41
43
|
_tiptap_extension_bullet_list = __toESM(_tiptap_extension_bullet_list);
|
|
42
44
|
let _tiptap_extension_code = require("@tiptap/extension-code");
|
|
@@ -67,15 +69,19 @@ let _tiptap_extension_placeholder = require("@tiptap/extension-placeholder");
|
|
|
67
69
|
_tiptap_extension_placeholder = __toESM(_tiptap_extension_placeholder);
|
|
68
70
|
let _tiptap_extension_strike = require("@tiptap/extension-strike");
|
|
69
71
|
_tiptap_extension_strike = __toESM(_tiptap_extension_strike);
|
|
72
|
+
let _tiptap_extension_superscript = require("@tiptap/extension-superscript");
|
|
73
|
+
_tiptap_extension_superscript = __toESM(_tiptap_extension_superscript);
|
|
74
|
+
let _tiptap_extension_underline = require("@tiptap/extension-underline");
|
|
75
|
+
_tiptap_extension_underline = __toESM(_tiptap_extension_underline);
|
|
70
76
|
let _tiptap_html = require("@tiptap/html");
|
|
71
77
|
let lucide_react = require("lucide-react");
|
|
72
78
|
let _radix_ui_react_popover = require("@radix-ui/react-popover");
|
|
73
79
|
_radix_ui_react_popover = __toESM(_radix_ui_react_popover);
|
|
74
80
|
let _tiptap_react_menus = require("@tiptap/react/menus");
|
|
81
|
+
let _floating_ui_react_dom = require("@floating-ui/react-dom");
|
|
75
82
|
let _tiptap_suggestion = require("@tiptap/suggestion");
|
|
76
83
|
_tiptap_suggestion = __toESM(_tiptap_suggestion);
|
|
77
|
-
let
|
|
78
|
-
tippy_js = __toESM(tippy_js);
|
|
84
|
+
let react_dom = require("react-dom");
|
|
79
85
|
|
|
80
86
|
//#region src/core/event-bus.ts
|
|
81
87
|
const EVENT_PREFIX = "@react-email/editor:";
|
|
@@ -690,95 +696,23 @@ const Body = EmailNode.create({
|
|
|
690
696
|
|
|
691
697
|
//#endregion
|
|
692
698
|
//#region src/extensions/bold.tsx
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
* This extension allows you to mark text as bold.
|
|
711
|
-
* @see https://tiptap.dev/api/marks/bold
|
|
712
|
-
*/
|
|
713
|
-
const Bold = EmailMark.create({
|
|
714
|
-
name: "bold",
|
|
715
|
-
addOptions() {
|
|
716
|
-
return { HTMLAttributes: {} };
|
|
717
|
-
},
|
|
718
|
-
parseHTML() {
|
|
719
|
-
return [
|
|
720
|
-
{ tag: "strong" },
|
|
721
|
-
{
|
|
722
|
-
tag: "b",
|
|
723
|
-
getAttrs: (node) => node.style.fontWeight !== "normal" && null
|
|
724
|
-
},
|
|
725
|
-
{
|
|
726
|
-
style: "font-weight=400",
|
|
727
|
-
clearMark: (mark) => mark.type.name === this.name
|
|
728
|
-
}
|
|
729
|
-
];
|
|
730
|
-
},
|
|
731
|
-
renderHTML({ HTMLAttributes }) {
|
|
732
|
-
return [
|
|
733
|
-
"strong",
|
|
734
|
-
(0, _tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
|
|
735
|
-
0
|
|
736
|
-
];
|
|
737
|
-
},
|
|
738
|
-
renderToReactEmail({ children, style }) {
|
|
739
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
740
|
-
style,
|
|
741
|
-
children
|
|
742
|
-
});
|
|
743
|
-
},
|
|
744
|
-
addCommands() {
|
|
745
|
-
return {
|
|
746
|
-
setBold: () => ({ commands }) => {
|
|
747
|
-
return commands.setMark(this.name);
|
|
748
|
-
},
|
|
749
|
-
toggleBold: () => ({ commands }) => {
|
|
750
|
-
return commands.toggleMark(this.name);
|
|
751
|
-
},
|
|
752
|
-
unsetBold: () => ({ commands }) => {
|
|
753
|
-
return commands.unsetMark(this.name);
|
|
754
|
-
}
|
|
755
|
-
};
|
|
756
|
-
},
|
|
757
|
-
addKeyboardShortcuts() {
|
|
758
|
-
return {
|
|
759
|
-
"Mod-b": () => this.editor.commands.toggleBold(),
|
|
760
|
-
"Mod-B": () => this.editor.commands.toggleBold()
|
|
761
|
-
};
|
|
762
|
-
},
|
|
763
|
-
addInputRules() {
|
|
764
|
-
return [(0, _tiptap_core.markInputRule)({
|
|
765
|
-
find: starInputRegex,
|
|
766
|
-
type: this.type
|
|
767
|
-
}), (0, _tiptap_core.markInputRule)({
|
|
768
|
-
find: underscoreInputRegex,
|
|
769
|
-
type: this.type
|
|
770
|
-
})];
|
|
771
|
-
},
|
|
772
|
-
addPasteRules() {
|
|
773
|
-
return [(0, _tiptap_core.markPasteRule)({
|
|
774
|
-
find: starPasteRegex,
|
|
775
|
-
type: this.type
|
|
776
|
-
}), (0, _tiptap_core.markPasteRule)({
|
|
777
|
-
find: underscorePasteRegex,
|
|
778
|
-
type: this.type
|
|
779
|
-
})];
|
|
780
|
-
}
|
|
781
|
-
});
|
|
699
|
+
const BoldWithoutFontWeightInference = _tiptap_extension_bold.default.extend({ parseHTML() {
|
|
700
|
+
return [
|
|
701
|
+
{ tag: "strong" },
|
|
702
|
+
{
|
|
703
|
+
tag: "b",
|
|
704
|
+
getAttrs: (node) => node.style.fontWeight !== "normal" && null
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
style: "font-weight=400",
|
|
708
|
+
clearMark: (mark) => mark.type.name === this.name
|
|
709
|
+
}
|
|
710
|
+
];
|
|
711
|
+
} });
|
|
712
|
+
const Bold = EmailMark.from(BoldWithoutFontWeightInference, ({ children, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
713
|
+
style,
|
|
714
|
+
children
|
|
715
|
+
}));
|
|
782
716
|
|
|
783
717
|
//#endregion
|
|
784
718
|
//#region src/extensions/bullet-list.tsx
|
|
@@ -1778,33 +1712,11 @@ const StyleAttribute = _tiptap_core.Extension.create({
|
|
|
1778
1712
|
|
|
1779
1713
|
//#endregion
|
|
1780
1714
|
//#region src/extensions/sup.tsx
|
|
1781
|
-
|
|
1782
|
-
* This extension allows you to mark text as superscript.
|
|
1783
|
-
* @see https://tiptap.dev/api/marks/superscript
|
|
1784
|
-
*/
|
|
1785
|
-
const Sup = EmailMark.create({
|
|
1715
|
+
const SupBase = _tiptap_extension_superscript.default.extend({
|
|
1786
1716
|
name: "sup",
|
|
1787
|
-
addOptions() {
|
|
1788
|
-
return { HTMLAttributes: {} };
|
|
1789
|
-
},
|
|
1790
|
-
parseHTML() {
|
|
1791
|
-
return [{ tag: "sup" }];
|
|
1792
|
-
},
|
|
1793
|
-
renderHTML({ HTMLAttributes }) {
|
|
1794
|
-
return [
|
|
1795
|
-
"sup",
|
|
1796
|
-
(0, _tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes),
|
|
1797
|
-
0
|
|
1798
|
-
];
|
|
1799
|
-
},
|
|
1800
|
-
renderToReactEmail({ children, style }) {
|
|
1801
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("sup", {
|
|
1802
|
-
style,
|
|
1803
|
-
children
|
|
1804
|
-
});
|
|
1805
|
-
},
|
|
1806
1717
|
addCommands() {
|
|
1807
1718
|
return {
|
|
1719
|
+
...this.parent?.(),
|
|
1808
1720
|
setSup: () => ({ commands }) => {
|
|
1809
1721
|
return commands.setMark(this.name);
|
|
1810
1722
|
},
|
|
@@ -1817,6 +1729,10 @@ const Sup = EmailMark.create({
|
|
|
1817
1729
|
};
|
|
1818
1730
|
}
|
|
1819
1731
|
});
|
|
1732
|
+
const Sup = EmailMark.from(SupBase, ({ children, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("sup", {
|
|
1733
|
+
style,
|
|
1734
|
+
children
|
|
1735
|
+
}));
|
|
1820
1736
|
|
|
1821
1737
|
//#endregion
|
|
1822
1738
|
//#region src/extensions/table.tsx
|
|
@@ -2004,6 +1920,13 @@ const TableHeader = _tiptap_core.Node.create({
|
|
|
2004
1920
|
}
|
|
2005
1921
|
});
|
|
2006
1922
|
|
|
1923
|
+
//#endregion
|
|
1924
|
+
//#region src/extensions/underline.tsx
|
|
1925
|
+
const Underline = EmailMark.from(_tiptap_extension_underline.default, ({ children, style }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("u", {
|
|
1926
|
+
style,
|
|
1927
|
+
children
|
|
1928
|
+
}));
|
|
1929
|
+
|
|
2007
1930
|
//#endregion
|
|
2008
1931
|
//#region src/extensions/uppercase.tsx
|
|
2009
1932
|
const Uppercase = EmailMark.create({
|
|
@@ -2241,6 +2164,7 @@ const starterKitExtensions = {
|
|
|
2241
2164
|
Divider,
|
|
2242
2165
|
Link,
|
|
2243
2166
|
Sup,
|
|
2167
|
+
Underline,
|
|
2244
2168
|
Uppercase,
|
|
2245
2169
|
PreservedStyle,
|
|
2246
2170
|
Table,
|
|
@@ -2285,6 +2209,7 @@ const StarterKit = _tiptap_core.Extension.create({
|
|
|
2285
2209
|
Divider: {},
|
|
2286
2210
|
Link: {},
|
|
2287
2211
|
Sup: {},
|
|
2212
|
+
Underline: {},
|
|
2288
2213
|
Uppercase: {},
|
|
2289
2214
|
PreservedStyle: {},
|
|
2290
2215
|
Table: {},
|
|
@@ -3122,7 +3047,7 @@ function BubbleMenuNodeSelector({ omit = [], className, triggerContent, open, on
|
|
|
3122
3047
|
|
|
3123
3048
|
//#endregion
|
|
3124
3049
|
//#region src/ui/bubble-menu/root.tsx
|
|
3125
|
-
function BubbleMenuRoot({ excludeNodes = [], placement = "bottom", offset = 8, onHide, className, children }) {
|
|
3050
|
+
function BubbleMenuRoot({ excludeNodes = [], placement = "bottom", offset: offset$1 = 8, onHide, className, children }) {
|
|
3126
3051
|
const { editor } = (0, _tiptap_react.useCurrentEditor)();
|
|
3127
3052
|
if (!editor) return null;
|
|
3128
3053
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tiptap_react_menus.BubbleMenu, {
|
|
@@ -3135,7 +3060,7 @@ function BubbleMenuRoot({ excludeNodes = [], placement = "bottom", offset = 8, o
|
|
|
3135
3060
|
},
|
|
3136
3061
|
options: {
|
|
3137
3062
|
placement,
|
|
3138
|
-
offset,
|
|
3063
|
+
offset: offset$1,
|
|
3139
3064
|
onHide
|
|
3140
3065
|
},
|
|
3141
3066
|
className,
|
|
@@ -3175,7 +3100,7 @@ const BubbleMenuUppercase = createMarkBubbleItem({
|
|
|
3175
3100
|
|
|
3176
3101
|
//#endregion
|
|
3177
3102
|
//#region src/ui/bubble-menu/default.tsx
|
|
3178
|
-
function BubbleMenuDefault({ excludeItems = [], excludeNodes, placement, offset, onHide, className }) {
|
|
3103
|
+
function BubbleMenuDefault({ excludeItems = [], excludeNodes, placement, offset: offset$1, onHide, className }) {
|
|
3179
3104
|
const [isNodeSelectorOpen, setIsNodeSelectorOpen] = react.useState(false);
|
|
3180
3105
|
const [isLinkSelectorOpen, setIsLinkSelectorOpen] = react.useState(false);
|
|
3181
3106
|
const has = (item) => !excludeItems.includes(item);
|
|
@@ -3197,7 +3122,7 @@ function BubbleMenuDefault({ excludeItems = [], excludeNodes, placement, offset,
|
|
|
3197
3122
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(BubbleMenuRoot, {
|
|
3198
3123
|
excludeNodes,
|
|
3199
3124
|
placement,
|
|
3200
|
-
offset,
|
|
3125
|
+
offset: offset$1,
|
|
3201
3126
|
onHide: handleHide,
|
|
3202
3127
|
className,
|
|
3203
3128
|
children: [
|
|
@@ -3294,7 +3219,7 @@ function ButtonBubbleMenuEditLink({ className, children, onClick, onMouseDown, .
|
|
|
3294
3219
|
|
|
3295
3220
|
//#endregion
|
|
3296
3221
|
//#region src/ui/button-bubble-menu/root.tsx
|
|
3297
|
-
function ButtonBubbleMenuRoot({ onHide, placement = "top", offset = 8, className, children }) {
|
|
3222
|
+
function ButtonBubbleMenuRoot({ onHide, placement = "top", offset: offset$1 = 8, className, children }) {
|
|
3298
3223
|
const { editor } = (0, _tiptap_react.useCurrentEditor)();
|
|
3299
3224
|
const [isEditing, setIsEditing] = react.useState(false);
|
|
3300
3225
|
if (!editor) return null;
|
|
@@ -3304,7 +3229,7 @@ function ButtonBubbleMenuRoot({ onHide, placement = "top", offset = 8, className
|
|
|
3304
3229
|
shouldShow: ({ editor: e, view }) => e.isActive("button") && !view.dom.classList.contains("dragging"),
|
|
3305
3230
|
options: {
|
|
3306
3231
|
placement,
|
|
3307
|
-
offset,
|
|
3232
|
+
offset: offset$1,
|
|
3308
3233
|
onHide: () => {
|
|
3309
3234
|
setIsEditing(false);
|
|
3310
3235
|
onHide?.();
|
|
@@ -3336,10 +3261,10 @@ function ButtonBubbleMenuToolbar({ children, ...rest }) {
|
|
|
3336
3261
|
|
|
3337
3262
|
//#endregion
|
|
3338
3263
|
//#region src/ui/button-bubble-menu/default.tsx
|
|
3339
|
-
function ButtonBubbleMenuDefault({ excludeItems = [], placement, offset, onHide, className }) {
|
|
3264
|
+
function ButtonBubbleMenuDefault({ excludeItems = [], placement, offset: offset$1, onHide, className }) {
|
|
3340
3265
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ButtonBubbleMenuRoot, {
|
|
3341
3266
|
placement,
|
|
3342
|
-
offset,
|
|
3267
|
+
offset: offset$1,
|
|
3343
3268
|
onHide,
|
|
3344
3269
|
className,
|
|
3345
3270
|
children: !excludeItems.includes("edit-link") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ButtonBubbleMenuToolbar, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ButtonBubbleMenuEditLink, {}) })
|
|
@@ -3389,7 +3314,7 @@ function ImageBubbleMenuEditLink({ className, children, onClick, onMouseDown, ..
|
|
|
3389
3314
|
|
|
3390
3315
|
//#endregion
|
|
3391
3316
|
//#region src/ui/image-bubble-menu/root.tsx
|
|
3392
|
-
function ImageBubbleMenuRoot({ onHide, placement = "top", offset = 8, className, children }) {
|
|
3317
|
+
function ImageBubbleMenuRoot({ onHide, placement = "top", offset: offset$1 = 8, className, children }) {
|
|
3393
3318
|
const { editor } = (0, _tiptap_react.useCurrentEditor)();
|
|
3394
3319
|
const [isEditing, setIsEditing] = react.useState(false);
|
|
3395
3320
|
if (!editor) return null;
|
|
@@ -3399,7 +3324,7 @@ function ImageBubbleMenuRoot({ onHide, placement = "top", offset = 8, className,
|
|
|
3399
3324
|
shouldShow: ({ editor: e, view }) => e.isActive("image") && !view.dom.classList.contains("dragging"),
|
|
3400
3325
|
options: {
|
|
3401
3326
|
placement,
|
|
3402
|
-
offset,
|
|
3327
|
+
offset: offset$1,
|
|
3403
3328
|
onHide: () => {
|
|
3404
3329
|
setIsEditing(false);
|
|
3405
3330
|
onHide?.();
|
|
@@ -3431,10 +3356,10 @@ function ImageBubbleMenuToolbar({ children, ...rest }) {
|
|
|
3431
3356
|
|
|
3432
3357
|
//#endregion
|
|
3433
3358
|
//#region src/ui/image-bubble-menu/default.tsx
|
|
3434
|
-
function ImageBubbleMenuDefault({ excludeItems = [], placement, offset, onHide, className }) {
|
|
3359
|
+
function ImageBubbleMenuDefault({ excludeItems = [], placement, offset: offset$1, onHide, className }) {
|
|
3435
3360
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageBubbleMenuRoot, {
|
|
3436
3361
|
placement,
|
|
3437
|
-
offset,
|
|
3362
|
+
offset: offset$1,
|
|
3438
3363
|
onHide,
|
|
3439
3364
|
className,
|
|
3440
3365
|
children: !excludeItems.includes("edit-link") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageBubbleMenuToolbar, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageBubbleMenuEditLink, {}) })
|
|
@@ -3606,7 +3531,7 @@ function LinkBubbleMenuOpenLink({ className, children, ...rest }) {
|
|
|
3606
3531
|
|
|
3607
3532
|
//#endregion
|
|
3608
3533
|
//#region src/ui/link-bubble-menu/root.tsx
|
|
3609
|
-
function LinkBubbleMenuRoot({ onHide, placement = "top", offset = 8, className, children }) {
|
|
3534
|
+
function LinkBubbleMenuRoot({ onHide, placement = "top", offset: offset$1 = 8, className, children }) {
|
|
3610
3535
|
const { editor } = (0, _tiptap_react.useCurrentEditor)();
|
|
3611
3536
|
const [isEditing, setIsEditing] = react.useState(false);
|
|
3612
3537
|
const linkHref = (0, _tiptap_react.useEditorState)({
|
|
@@ -3620,7 +3545,7 @@ function LinkBubbleMenuRoot({ onHide, placement = "top", offset = 8, className,
|
|
|
3620
3545
|
shouldShow: ({ editor: e }) => e.isActive("link") && e.view.state.selection.content().size === 0,
|
|
3621
3546
|
options: {
|
|
3622
3547
|
placement,
|
|
3623
|
-
offset,
|
|
3548
|
+
offset: offset$1,
|
|
3624
3549
|
onHide: () => {
|
|
3625
3550
|
setIsEditing(false);
|
|
3626
3551
|
onHide?.();
|
|
@@ -3676,11 +3601,11 @@ function LinkBubbleMenuUnlink({ className, children, onClick, onMouseDown, ...re
|
|
|
3676
3601
|
|
|
3677
3602
|
//#endregion
|
|
3678
3603
|
//#region src/ui/link-bubble-menu/default.tsx
|
|
3679
|
-
function LinkBubbleMenuDefault({ excludeItems = [], placement, offset, onHide, className, validateUrl, onLinkApply, onLinkRemove }) {
|
|
3604
|
+
function LinkBubbleMenuDefault({ excludeItems = [], placement, offset: offset$1, onHide, className, validateUrl, onLinkApply, onLinkRemove }) {
|
|
3680
3605
|
const has = (item) => !excludeItems.includes(item);
|
|
3681
3606
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(LinkBubbleMenuRoot, {
|
|
3682
3607
|
placement,
|
|
3683
|
-
offset,
|
|
3608
|
+
offset: offset$1,
|
|
3684
3609
|
onHide,
|
|
3685
3610
|
className,
|
|
3686
3611
|
children: [(has("edit-link") || has("open-link") || has("unlink")) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(LinkBubbleMenuToolbar, { children: [
|
|
@@ -3766,42 +3691,14 @@ function CommandItem({ item, selected, onSelect }) {
|
|
|
3766
3691
|
children: [item.icon, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: item.title })]
|
|
3767
3692
|
});
|
|
3768
3693
|
}
|
|
3769
|
-
function CommandList({ items,
|
|
3770
|
-
const [selectedIndex, setSelectedIndex] = (0, react.useState)(0);
|
|
3694
|
+
function CommandList({ items, query, selectedIndex, onSelect }) {
|
|
3771
3695
|
const containerRef = (0, react.useRef)(null);
|
|
3772
|
-
(0, react.useEffect)(() => {
|
|
3773
|
-
setSelectedIndex(0);
|
|
3774
|
-
}, [items]);
|
|
3775
3696
|
(0, react.useLayoutEffect)(() => {
|
|
3776
3697
|
const container = containerRef.current;
|
|
3777
3698
|
if (!container) return;
|
|
3778
3699
|
const selected = container.querySelector("[data-selected]");
|
|
3779
3700
|
if (selected) updateScrollView(container, selected);
|
|
3780
3701
|
}, [selectedIndex]);
|
|
3781
|
-
const selectItem = (0, react.useCallback)((index) => {
|
|
3782
|
-
const item = items[index];
|
|
3783
|
-
if (item) command(item);
|
|
3784
|
-
}, [items, command]);
|
|
3785
|
-
(0, react.useImperativeHandle)(ref, () => ({ onKeyDown: ({ event }) => {
|
|
3786
|
-
if (items.length === 0) return false;
|
|
3787
|
-
if (event.key === "ArrowUp") {
|
|
3788
|
-
setSelectedIndex((i) => (i + items.length - 1) % items.length);
|
|
3789
|
-
return true;
|
|
3790
|
-
}
|
|
3791
|
-
if (event.key === "ArrowDown") {
|
|
3792
|
-
setSelectedIndex((i) => (i + 1) % items.length);
|
|
3793
|
-
return true;
|
|
3794
|
-
}
|
|
3795
|
-
if (event.key === "Enter") {
|
|
3796
|
-
selectItem(selectedIndex);
|
|
3797
|
-
return true;
|
|
3798
|
-
}
|
|
3799
|
-
return false;
|
|
3800
|
-
} }), [
|
|
3801
|
-
items.length,
|
|
3802
|
-
selectItem,
|
|
3803
|
-
selectedIndex
|
|
3804
|
-
]);
|
|
3805
3702
|
if (items.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3806
3703
|
"data-re-slash-command": "",
|
|
3807
3704
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -3814,7 +3711,7 @@ function CommandList({ items, command, query, ref }) {
|
|
|
3814
3711
|
ref: containerRef,
|
|
3815
3712
|
children: items.map((item, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommandItem, {
|
|
3816
3713
|
item,
|
|
3817
|
-
onSelect: () =>
|
|
3714
|
+
onSelect: () => onSelect(index),
|
|
3818
3715
|
selected: index === selectedIndex
|
|
3819
3716
|
}, item.title))
|
|
3820
3717
|
});
|
|
@@ -3830,7 +3727,7 @@ function CommandList({ items, command, query, ref }) {
|
|
|
3830
3727
|
const currentIndex = flatIndex++;
|
|
3831
3728
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommandItem, {
|
|
3832
3729
|
item,
|
|
3833
|
-
onSelect: () =>
|
|
3730
|
+
onSelect: () => onSelect(currentIndex),
|
|
3834
3731
|
selected: currentIndex === selectedIndex
|
|
3835
3732
|
}, item.title);
|
|
3836
3733
|
})] }, group.category))
|
|
@@ -4048,76 +3945,6 @@ const defaultSlashCommands = [
|
|
|
4048
3945
|
FOUR_COLUMNS
|
|
4049
3946
|
];
|
|
4050
3947
|
|
|
4051
|
-
//#endregion
|
|
4052
|
-
//#region src/ui/slash-command/extension.ts
|
|
4053
|
-
const SlashCommandExtension = _tiptap_core.Extension.create({
|
|
4054
|
-
name: "slash-command",
|
|
4055
|
-
addOptions() {
|
|
4056
|
-
return { suggestion: {
|
|
4057
|
-
char: "/",
|
|
4058
|
-
allow: ({ editor }) => !editor.isActive("codeBlock"),
|
|
4059
|
-
command: ({ editor, range, props }) => {
|
|
4060
|
-
props.command({
|
|
4061
|
-
editor,
|
|
4062
|
-
range
|
|
4063
|
-
});
|
|
4064
|
-
}
|
|
4065
|
-
} };
|
|
4066
|
-
},
|
|
4067
|
-
addProseMirrorPlugins() {
|
|
4068
|
-
return [(0, _tiptap_suggestion.default)({
|
|
4069
|
-
pluginKey: new _tiptap_pm_state.PluginKey("slash-command"),
|
|
4070
|
-
editor: this.editor,
|
|
4071
|
-
...this.options.suggestion
|
|
4072
|
-
})];
|
|
4073
|
-
}
|
|
4074
|
-
});
|
|
4075
|
-
|
|
4076
|
-
//#endregion
|
|
4077
|
-
//#region src/ui/slash-command/render.tsx
|
|
4078
|
-
function createRenderItems(component = CommandList) {
|
|
4079
|
-
return () => {
|
|
4080
|
-
let renderer = null;
|
|
4081
|
-
let popup = null;
|
|
4082
|
-
return {
|
|
4083
|
-
onStart: (props) => {
|
|
4084
|
-
renderer = new _tiptap_react.ReactRenderer(component, {
|
|
4085
|
-
props,
|
|
4086
|
-
editor: props.editor
|
|
4087
|
-
});
|
|
4088
|
-
if (!props.clientRect) return;
|
|
4089
|
-
popup = (0, tippy_js.default)("body", {
|
|
4090
|
-
getReferenceClientRect: props.clientRect,
|
|
4091
|
-
appendTo: () => document.body,
|
|
4092
|
-
content: renderer.element,
|
|
4093
|
-
showOnCreate: true,
|
|
4094
|
-
interactive: true,
|
|
4095
|
-
trigger: "manual",
|
|
4096
|
-
placement: "bottom-start"
|
|
4097
|
-
});
|
|
4098
|
-
},
|
|
4099
|
-
onUpdate: (props) => {
|
|
4100
|
-
if (!renderer) return;
|
|
4101
|
-
renderer.updateProps(props);
|
|
4102
|
-
if (popup?.[0] && props.clientRect) popup[0].setProps({ getReferenceClientRect: props.clientRect });
|
|
4103
|
-
},
|
|
4104
|
-
onKeyDown: (props) => {
|
|
4105
|
-
if (props.event.key === "Escape") {
|
|
4106
|
-
popup?.[0]?.hide();
|
|
4107
|
-
return true;
|
|
4108
|
-
}
|
|
4109
|
-
return renderer?.ref?.onKeyDown(props) ?? false;
|
|
4110
|
-
},
|
|
4111
|
-
onExit: () => {
|
|
4112
|
-
popup?.[0]?.destroy();
|
|
4113
|
-
renderer?.destroy();
|
|
4114
|
-
popup = null;
|
|
4115
|
-
renderer = null;
|
|
4116
|
-
}
|
|
4117
|
-
};
|
|
4118
|
-
};
|
|
4119
|
-
}
|
|
4120
|
-
|
|
4121
3948
|
//#endregion
|
|
4122
3949
|
//#region src/ui/slash-command/search.ts
|
|
4123
3950
|
function scoreItem(item, query) {
|
|
@@ -4148,22 +3975,144 @@ function filterAndRankItems(items, query) {
|
|
|
4148
3975
|
}
|
|
4149
3976
|
|
|
4150
3977
|
//#endregion
|
|
4151
|
-
//#region src/ui/slash-command/
|
|
3978
|
+
//#region src/ui/slash-command/root.tsx
|
|
3979
|
+
const pluginKey = new _tiptap_pm_state.PluginKey("slash-command");
|
|
3980
|
+
const INITIAL_STATE = {
|
|
3981
|
+
active: false,
|
|
3982
|
+
query: "",
|
|
3983
|
+
items: [],
|
|
3984
|
+
clientRect: null
|
|
3985
|
+
};
|
|
4152
3986
|
function defaultFilterItems(items, query, editor) {
|
|
4153
3987
|
return filterAndRankItems(isAtMaxColumnsDepth(editor) ? items.filter((item) => item.category !== "Layout" || !item.title.includes("column")) : items, query);
|
|
4154
3988
|
}
|
|
4155
|
-
function
|
|
4156
|
-
const
|
|
4157
|
-
const
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
3989
|
+
function SlashCommandRoot({ items: itemsProp, filterItems: filterItemsProp, char = "/", allow: allowProp, children }) {
|
|
3990
|
+
const { editor } = (0, _tiptap_react.useCurrentEditor)();
|
|
3991
|
+
const [state, setState] = (0, react.useState)(INITIAL_STATE);
|
|
3992
|
+
const [selectedIndex, setSelectedIndex] = (0, react.useState)(0);
|
|
3993
|
+
const itemsRef = (0, react.useRef)(itemsProp ?? defaultSlashCommands);
|
|
3994
|
+
const filterRef = (0, react.useRef)(filterItemsProp ?? defaultFilterItems);
|
|
3995
|
+
const allowRef = (0, react.useRef)(allowProp ?? (({ editor: e }) => !e.isActive("codeBlock")));
|
|
3996
|
+
itemsRef.current = itemsProp ?? defaultSlashCommands;
|
|
3997
|
+
filterRef.current = filterItemsProp ?? defaultFilterItems;
|
|
3998
|
+
allowRef.current = allowProp ?? (({ editor: e }) => !e.isActive("codeBlock"));
|
|
3999
|
+
const commandRef = (0, react.useRef)(null);
|
|
4000
|
+
const suggestionItemsRef = (0, react.useRef)([]);
|
|
4001
|
+
const selectedIndexRef = (0, react.useRef)(0);
|
|
4002
|
+
suggestionItemsRef.current = state.items;
|
|
4003
|
+
selectedIndexRef.current = selectedIndex;
|
|
4004
|
+
const { refs, floatingStyles } = (0, _floating_ui_react_dom.useFloating)({
|
|
4005
|
+
open: state.active,
|
|
4006
|
+
placement: "bottom-start",
|
|
4007
|
+
middleware: [
|
|
4008
|
+
(0, _floating_ui_react_dom.offset)(8),
|
|
4009
|
+
(0, _floating_ui_react_dom.flip)(),
|
|
4010
|
+
(0, _floating_ui_react_dom.shift)({ padding: 8 })
|
|
4011
|
+
],
|
|
4012
|
+
whileElementsMounted: _floating_ui_react_dom.autoUpdate
|
|
4013
|
+
});
|
|
4014
|
+
(0, react.useEffect)(() => {
|
|
4015
|
+
if (!state.clientRect) return;
|
|
4016
|
+
refs.setReference({ getBoundingClientRect: state.clientRect });
|
|
4017
|
+
}, [state.clientRect, refs]);
|
|
4018
|
+
(0, react.useEffect)(() => {
|
|
4019
|
+
setSelectedIndex(0);
|
|
4020
|
+
}, [state.items]);
|
|
4021
|
+
const onSelect = (0, react.useCallback)((index) => {
|
|
4022
|
+
const item = suggestionItemsRef.current[index];
|
|
4023
|
+
if (item && commandRef.current) commandRef.current(item);
|
|
4024
|
+
}, []);
|
|
4025
|
+
(0, react.useEffect)(() => {
|
|
4026
|
+
if (!editor) return;
|
|
4027
|
+
const plugin = (0, _tiptap_suggestion.default)({
|
|
4028
|
+
pluginKey,
|
|
4029
|
+
editor,
|
|
4030
|
+
char,
|
|
4031
|
+
allow: ({ editor: e }) => allowRef.current({ editor: e }),
|
|
4032
|
+
command: ({ editor: e, range, props }) => {
|
|
4033
|
+
props.command({
|
|
4034
|
+
editor: e,
|
|
4035
|
+
range
|
|
4036
|
+
});
|
|
4037
|
+
},
|
|
4038
|
+
items: ({ query, editor: e }) => filterRef.current(itemsRef.current, query, e),
|
|
4039
|
+
render: () => ({
|
|
4040
|
+
onStart: (props) => {
|
|
4041
|
+
commandRef.current = props.command;
|
|
4042
|
+
setState({
|
|
4043
|
+
active: true,
|
|
4044
|
+
query: props.query,
|
|
4045
|
+
items: props.items,
|
|
4046
|
+
clientRect: props.clientRect ?? null
|
|
4047
|
+
});
|
|
4048
|
+
},
|
|
4049
|
+
onUpdate: (props) => {
|
|
4050
|
+
commandRef.current = props.command;
|
|
4051
|
+
setState({
|
|
4052
|
+
active: true,
|
|
4053
|
+
query: props.query,
|
|
4054
|
+
items: props.items,
|
|
4055
|
+
clientRect: props.clientRect ?? null
|
|
4056
|
+
});
|
|
4057
|
+
},
|
|
4058
|
+
onKeyDown: ({ event }) => {
|
|
4059
|
+
if (event.key === "Escape") {
|
|
4060
|
+
setState(INITIAL_STATE);
|
|
4061
|
+
return true;
|
|
4062
|
+
}
|
|
4063
|
+
const items = suggestionItemsRef.current;
|
|
4064
|
+
if (items.length === 0) return false;
|
|
4065
|
+
if (event.key === "ArrowUp") {
|
|
4066
|
+
setSelectedIndex((i) => (i + items.length - 1) % items.length);
|
|
4067
|
+
return true;
|
|
4068
|
+
}
|
|
4069
|
+
if (event.key === "ArrowDown") {
|
|
4070
|
+
setSelectedIndex((i) => (i + 1) % items.length);
|
|
4071
|
+
return true;
|
|
4072
|
+
}
|
|
4073
|
+
if (event.key === "Enter") {
|
|
4074
|
+
const item = items[selectedIndexRef.current];
|
|
4075
|
+
if (item && commandRef.current) commandRef.current(item);
|
|
4076
|
+
return true;
|
|
4077
|
+
}
|
|
4078
|
+
return false;
|
|
4079
|
+
},
|
|
4080
|
+
onExit: () => {
|
|
4081
|
+
setState(INITIAL_STATE);
|
|
4082
|
+
requestAnimationFrame(() => {
|
|
4083
|
+
commandRef.current = null;
|
|
4084
|
+
});
|
|
4085
|
+
}
|
|
4086
|
+
})
|
|
4087
|
+
});
|
|
4088
|
+
editor.registerPlugin(plugin, (newPlugin, plugins) => [newPlugin, ...plugins]);
|
|
4089
|
+
return () => {
|
|
4090
|
+
editor.unregisterPlugin(pluginKey);
|
|
4091
|
+
};
|
|
4092
|
+
}, [editor, char]);
|
|
4093
|
+
if (!editor || !state.active) return null;
|
|
4094
|
+
const renderProps = {
|
|
4095
|
+
items: state.items,
|
|
4096
|
+
query: state.query,
|
|
4097
|
+
selectedIndex,
|
|
4098
|
+
onSelect
|
|
4099
|
+
};
|
|
4100
|
+
let content;
|
|
4101
|
+
if (children) content = children(renderProps);
|
|
4102
|
+
else content = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommandList, { ...renderProps });
|
|
4103
|
+
return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4104
|
+
ref: refs.setFloating,
|
|
4105
|
+
style: floatingStyles,
|
|
4106
|
+
children: content
|
|
4107
|
+
}), document.body);
|
|
4162
4108
|
}
|
|
4163
4109
|
|
|
4164
4110
|
//#endregion
|
|
4165
4111
|
//#region src/ui/slash-command/index.ts
|
|
4166
|
-
const SlashCommand =
|
|
4112
|
+
const SlashCommand = {
|
|
4113
|
+
Root: SlashCommandRoot,
|
|
4114
|
+
CommandList
|
|
4115
|
+
};
|
|
4167
4116
|
|
|
4168
4117
|
//#endregion
|
|
4169
4118
|
exports.AlignmentAttribute = AlignmentAttribute;
|
|
@@ -4259,9 +4208,9 @@ exports.TableHeader = TableHeader;
|
|
|
4259
4208
|
exports.TableRow = TableRow;
|
|
4260
4209
|
exports.ThreeColumns = ThreeColumns;
|
|
4261
4210
|
exports.TwoColumns = TwoColumns;
|
|
4211
|
+
exports.Underline = Underline;
|
|
4262
4212
|
exports.Uppercase = Uppercase;
|
|
4263
4213
|
exports.composeReactEmail = composeReactEmail;
|
|
4264
|
-
exports.createSlashCommand = createSlashCommand;
|
|
4265
4214
|
exports.defaultSlashCommands = defaultSlashCommands;
|
|
4266
4215
|
exports.editorEventBus = editorEventBus;
|
|
4267
4216
|
exports.filterAndRankItems = filterAndRankItems;
|