@nkzw/mdx-editor 0.1.0
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/LICENSE +21 -0
- package/README.md +86 -0
- package/UPSTREAM.md +21 -0
- package/dist/EditorIcon.js +75 -0
- package/dist/FormatConstants.js +20 -0
- package/dist/MDXEditor.js +189 -0
- package/dist/MarkdownEditor.js +281 -0
- package/dist/PersistentMarkdownEditor.js +358 -0
- package/dist/RealmWithPlugins.js +35 -0
- package/dist/core.d.ts +3232 -0
- package/dist/core.js +354 -0
- package/dist/defaultSvgIcons.js +371 -0
- package/dist/directive-editors/AdmonitionDirectiveDescriptor.js +28 -0
- package/dist/directive-editors/GenericDirectiveEditor.js +37 -0
- package/dist/exportMarkdownFromLexical.js +262 -0
- package/dist/horizontalRuleShortcut.js +37 -0
- package/dist/importMarkdownToLexical.js +172 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.js +8 -0
- package/dist/jsx-editors/GenericJsxEditor.js +84 -0
- package/dist/mdastUtilHtmlComment.js +125 -0
- package/dist/persistence.d.ts +128 -0
- package/dist/persistence.js +4 -0
- package/dist/plugins/codeblock/CodeBlockNode.js +183 -0
- package/dist/plugins/codeblock/CodeBlockVisitor.js +14 -0
- package/dist/plugins/codeblock/MdastCodeVisitor.js +23 -0
- package/dist/plugins/codeblock/findCodeBlockDescriptor.js +8 -0
- package/dist/plugins/codeblock/index.js +46 -0
- package/dist/plugins/codemirror/CodeMirrorEditor.js +145 -0
- package/dist/plugins/codemirror/index.js +115 -0
- package/dist/plugins/codemirror/useCodeMirrorRef.js +101 -0
- package/dist/plugins/core/GenericHTMLNode.js +118 -0
- package/dist/plugins/core/LexicalGenericHTMLNodeVisitor.js +15 -0
- package/dist/plugins/core/LexicalLinebreakVisitor.js +10 -0
- package/dist/plugins/core/LexicalParagraphVisitor.js +10 -0
- package/dist/plugins/core/LexicalRootVisitor.js +10 -0
- package/dist/plugins/core/LexicalTextVisitor.js +160 -0
- package/dist/plugins/core/MdastBreakVisitor.js +10 -0
- package/dist/plugins/core/MdastFormattingVisitor.js +81 -0
- package/dist/plugins/core/MdastHTMLNode.js +120 -0
- package/dist/plugins/core/MdastHTMLVisitor.js +17 -0
- package/dist/plugins/core/MdastParagraphVisitor.js +23 -0
- package/dist/plugins/core/MdastRootVisitor.js +9 -0
- package/dist/plugins/core/MdastTextVisitor.js +16 -0
- package/dist/plugins/core/NestedLexicalEditor.js +221 -0
- package/dist/plugins/core/PropertyPopover.js +75 -0
- package/dist/plugins/core/SharedHistoryPlugin.js +10 -0
- package/dist/plugins/core/index.js +692 -0
- package/dist/plugins/core/ui/DownshiftAutoComplete.js +89 -0
- package/dist/plugins/core/ui/PopoverUtils.js +22 -0
- package/dist/plugins/diff-source/DiffSourceWrapper.js +24 -0
- package/dist/plugins/diff-source/DiffViewer.js +84 -0
- package/dist/plugins/diff-source/SourceEditor.js +60 -0
- package/dist/plugins/diff-source/index.js +27 -0
- package/dist/plugins/directives/DirectiveNode.js +107 -0
- package/dist/plugins/directives/DirectiveVisitor.js +10 -0
- package/dist/plugins/directives/MdastDirectiveVisitor.js +30 -0
- package/dist/plugins/directives/index.js +45 -0
- package/dist/plugins/frontmatter/FrontmatterEditor.js +137 -0
- package/dist/plugins/frontmatter/FrontmatterNode.js +70 -0
- package/dist/plugins/frontmatter/LexicalFrontmatterVisitor.js +10 -0
- package/dist/plugins/frontmatter/MdastFrontmatterVisitor.js +10 -0
- package/dist/plugins/frontmatter/index.js +113 -0
- package/dist/plugins/headings/LexicalHeadingVisitor.js +11 -0
- package/dist/plugins/headings/MdastHeadingVisitor.js +10 -0
- package/dist/plugins/headings/index.js +63 -0
- package/dist/plugins/image/EditImageToolbar.js +58 -0
- package/dist/plugins/image/ImageDialog.js +132 -0
- package/dist/plugins/image/ImageEditor.js +279 -0
- package/dist/plugins/image/ImageNode.js +187 -0
- package/dist/plugins/image/ImagePlaceholder.js +9 -0
- package/dist/plugins/image/ImageResizer.js +223 -0
- package/dist/plugins/image/LexicalImageVisitor.js +42 -0
- package/dist/plugins/image/MdastImageVisitor.js +91 -0
- package/dist/plugins/image/index.js +364 -0
- package/dist/plugins/jsx/LexicalJsxNode.js +103 -0
- package/dist/plugins/jsx/LexicalJsxVisitor.js +27 -0
- package/dist/plugins/jsx/LexicalMdxExpressionNode.js +130 -0
- package/dist/plugins/jsx/LexicalMdxExpressionVisitor.js +14 -0
- package/dist/plugins/jsx/MdastMdxExpressionVisitor.js +11 -0
- package/dist/plugins/jsx/MdastMdxJsEsmVisitor.js +8 -0
- package/dist/plugins/jsx/MdastMdxJsxElementVisitor.js +28 -0
- package/dist/plugins/jsx/index.js +97 -0
- package/dist/plugins/jsx/jsxTagName.js +7 -0
- package/dist/plugins/link/AutoLinkPlugin.js +18 -0
- package/dist/plugins/link/LexicalLinkVisitor.js +10 -0
- package/dist/plugins/link/MdastLinkVisitor.js +14 -0
- package/dist/plugins/link/index.js +34 -0
- package/dist/plugins/link-dialog/LinkDialog.js +262 -0
- package/dist/plugins/link-dialog/index.js +304 -0
- package/dist/plugins/lists/CheckListPlugin.js +270 -0
- package/dist/plugins/lists/LexicalListItemVisitor.js +41 -0
- package/dist/plugins/lists/LexicalListVisitor.js +13 -0
- package/dist/plugins/lists/MdastListItemVisitor.js +11 -0
- package/dist/plugins/lists/MdastListVisitor.js +19 -0
- package/dist/plugins/lists/NotesListItemNode.js +22 -0
- package/dist/plugins/lists/index.js +111 -0
- package/dist/plugins/markdown-shortcut/index.js +114 -0
- package/dist/plugins/maxlength/index.js +36 -0
- package/dist/plugins/quote/LexicalQuoteVisitor.js +10 -0
- package/dist/plugins/quote/MdastBlockQuoteVisitor.js +10 -0
- package/dist/plugins/quote/index.js +18 -0
- package/dist/plugins/remote/index.js +52 -0
- package/dist/plugins/search/index.js +360 -0
- package/dist/plugins/table/LexicalTableVisitor.js +10 -0
- package/dist/plugins/table/MdastTableVisitor.js +10 -0
- package/dist/plugins/table/TableEditor.js +527 -0
- package/dist/plugins/table/TableNode.js +208 -0
- package/dist/plugins/table/index.js +66 -0
- package/dist/plugins/thematic-break/LexicalThematicBreakVisitor.js +10 -0
- package/dist/plugins/thematic-break/MdastThematicBreakVisitor.js +10 -0
- package/dist/plugins/thematic-break/index.js +27 -0
- package/dist/plugins/toolbar/components/BlockTypeSelect.js +62 -0
- package/dist/plugins/toolbar/components/BoldItalicUnderlineToggles.js +98 -0
- package/dist/plugins/toolbar/components/ChangeAdmonitionType.js +43 -0
- package/dist/plugins/toolbar/components/ChangeCodeMirrorLanguage.js +42 -0
- package/dist/plugins/toolbar/components/CodeToggle.js +21 -0
- package/dist/plugins/toolbar/components/CreateLink.js +24 -0
- package/dist/plugins/toolbar/components/DiffSourceToggleWrapper.js +42 -0
- package/dist/plugins/toolbar/components/HighlightToggle.js +28 -0
- package/dist/plugins/toolbar/components/InsertAdmonition.js +34 -0
- package/dist/plugins/toolbar/components/InsertCodeBlock.js +23 -0
- package/dist/plugins/toolbar/components/InsertFrontmatter.js +28 -0
- package/dist/plugins/toolbar/components/InsertImage.js +29 -0
- package/dist/plugins/toolbar/components/InsertTable.js +25 -0
- package/dist/plugins/toolbar/components/InsertThematicBreak.js +23 -0
- package/dist/plugins/toolbar/components/KitchenSinkToolbar.js +82 -0
- package/dist/plugins/toolbar/components/ListsToggle.js +29 -0
- package/dist/plugins/toolbar/components/UndoRedo.js +60 -0
- package/dist/plugins/toolbar/index.js +32 -0
- package/dist/plugins/toolbar/primitives/DialogButton.js +130 -0
- package/dist/plugins/toolbar/primitives/TooltipWrap.js +17 -0
- package/dist/plugins/toolbar/primitives/select.js +76 -0
- package/dist/plugins/toolbar/primitives/toolbar.js +144 -0
- package/dist/registerCodeBoundaryEscape.js +40 -0
- package/dist/styles/lexical-theme.module.css.js +62 -0
- package/dist/styles/lexicalTheme.js +32 -0
- package/dist/styles/ui.module.css.js +296 -0
- package/dist/styles.css +2838 -0
- package/dist/utils/detectMac.js +16 -0
- package/dist/utils/fp.js +44 -0
- package/dist/utils/isPartOftheEditorUI.js +12 -0
- package/dist/utils/lexicalHelpers.js +185 -0
- package/dist/utils/makeHslTransparent.js +6 -0
- package/dist/utils/mergeStyleAttributes.js +22 -0
- package/dist/utils/uuid4.js +10 -0
- package/dist/utils/voidEmitter.js +15 -0
- package/package.json +133 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { DecoratorNode } from "lexical";
|
|
3
|
+
import { noop } from "../../utils/fp.js";
|
|
4
|
+
import { TableEditor } from "./TableEditor.js";
|
|
5
|
+
const EMPTY_CELL = { type: "tableCell", children: [] };
|
|
6
|
+
function coordinatesEmitter() {
|
|
7
|
+
let subscription = noop;
|
|
8
|
+
return {
|
|
9
|
+
publish: (coords) => {
|
|
10
|
+
subscription(coords);
|
|
11
|
+
},
|
|
12
|
+
subscribe: (cb) => {
|
|
13
|
+
subscription = cb;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
class TableNode extends DecoratorNode {
|
|
18
|
+
/** @internal */
|
|
19
|
+
__mdastNode;
|
|
20
|
+
/** @internal */
|
|
21
|
+
focusEmitter = coordinatesEmitter();
|
|
22
|
+
/** @internal */
|
|
23
|
+
static getType() {
|
|
24
|
+
return "table";
|
|
25
|
+
}
|
|
26
|
+
/** @internal */
|
|
27
|
+
static clone(node) {
|
|
28
|
+
return new TableNode(structuredClone(node.__mdastNode), node.__key);
|
|
29
|
+
}
|
|
30
|
+
/** @internal */
|
|
31
|
+
static importJSON(serializedNode) {
|
|
32
|
+
return $createTableNode(serializedNode.mdastNode);
|
|
33
|
+
}
|
|
34
|
+
/** @internal */
|
|
35
|
+
static importDOM() {
|
|
36
|
+
return {
|
|
37
|
+
table: () => {
|
|
38
|
+
return {
|
|
39
|
+
conversion: $convertTableElement,
|
|
40
|
+
priority: 3
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** @internal */
|
|
46
|
+
exportJSON() {
|
|
47
|
+
return {
|
|
48
|
+
mdastNode: structuredClone(this.__mdastNode),
|
|
49
|
+
type: "table",
|
|
50
|
+
version: 1
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Returns the mdast node that this node is constructed from.
|
|
55
|
+
*/
|
|
56
|
+
getMdastNode() {
|
|
57
|
+
return this.__mdastNode;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns the number of rows in the table.
|
|
61
|
+
*/
|
|
62
|
+
getRowCount() {
|
|
63
|
+
return this.__mdastNode.children.length;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Returns the number of columns in the table.
|
|
67
|
+
*/
|
|
68
|
+
getColCount() {
|
|
69
|
+
return this.__mdastNode.children[0]?.children.length || 0;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Constructs a new {@link TableNode} with the specified MDAST table node as the object to edit.
|
|
73
|
+
* See {@link https://github.com/micromark/micromark-extension-gfm-table | micromark/micromark-extension-gfm-table} for more information on the MDAST table node.
|
|
74
|
+
*/
|
|
75
|
+
constructor(mdastNode, key) {
|
|
76
|
+
super(key);
|
|
77
|
+
this.__mdastNode = mdastNode ?? { type: "table", children: [] };
|
|
78
|
+
}
|
|
79
|
+
/** @internal */
|
|
80
|
+
createDOM() {
|
|
81
|
+
return document.createElement("div");
|
|
82
|
+
}
|
|
83
|
+
/** @internal */
|
|
84
|
+
updateDOM() {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
/** @internal */
|
|
88
|
+
updateCellContents(colIndex, rowIndex, children) {
|
|
89
|
+
const self = this.getWritable();
|
|
90
|
+
const table = self.__mdastNode;
|
|
91
|
+
const row = table.children[rowIndex];
|
|
92
|
+
const cells = row.children;
|
|
93
|
+
const cell = cells[colIndex];
|
|
94
|
+
const cellsClone = Array.from(cells);
|
|
95
|
+
const cellClone = { ...cell, children };
|
|
96
|
+
const rowClone = { ...row, children: cellsClone };
|
|
97
|
+
cellsClone[colIndex] = cellClone;
|
|
98
|
+
table.children[rowIndex] = rowClone;
|
|
99
|
+
}
|
|
100
|
+
insertColumnAt(colIndex) {
|
|
101
|
+
const self = this.getWritable();
|
|
102
|
+
const table = self.__mdastNode;
|
|
103
|
+
for (let rowIndex = 0; rowIndex < table.children.length; rowIndex++) {
|
|
104
|
+
const row = table.children[rowIndex];
|
|
105
|
+
const cells = row.children;
|
|
106
|
+
const cellsClone = Array.from(cells);
|
|
107
|
+
const rowClone = { ...row, children: cellsClone };
|
|
108
|
+
cellsClone.splice(colIndex, 0, structuredClone(EMPTY_CELL));
|
|
109
|
+
table.children[rowIndex] = rowClone;
|
|
110
|
+
}
|
|
111
|
+
if (table.align && table.align.length > 0) {
|
|
112
|
+
table.align.splice(colIndex, 0, "left");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
deleteColumnAt(colIndex) {
|
|
116
|
+
const self = this.getWritable();
|
|
117
|
+
const table = self.__mdastNode;
|
|
118
|
+
for (let rowIndex = 0; rowIndex < table.children.length; rowIndex++) {
|
|
119
|
+
const row = table.children[rowIndex];
|
|
120
|
+
const cells = row.children;
|
|
121
|
+
const cellsClone = Array.from(cells);
|
|
122
|
+
const rowClone = { ...row, children: cellsClone };
|
|
123
|
+
cellsClone.splice(colIndex, 1);
|
|
124
|
+
table.children[rowIndex] = rowClone;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
insertRowAt(y) {
|
|
128
|
+
const self = this.getWritable();
|
|
129
|
+
const table = self.__mdastNode;
|
|
130
|
+
const newRow = {
|
|
131
|
+
type: "tableRow",
|
|
132
|
+
children: Array.from({ length: this.getColCount() }, () => structuredClone(EMPTY_CELL))
|
|
133
|
+
};
|
|
134
|
+
table.children.splice(y, 0, newRow);
|
|
135
|
+
}
|
|
136
|
+
deleteRowAt(rowIndex) {
|
|
137
|
+
if (this.getRowCount() === 1) {
|
|
138
|
+
this.selectNext();
|
|
139
|
+
this.remove();
|
|
140
|
+
} else {
|
|
141
|
+
this.getWritable().__mdastNode.children.splice(rowIndex, 1);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
addRowToBottom() {
|
|
145
|
+
this.insertRowAt(this.getRowCount());
|
|
146
|
+
}
|
|
147
|
+
addColumnToRight() {
|
|
148
|
+
this.insertColumnAt(this.getColCount());
|
|
149
|
+
}
|
|
150
|
+
setColumnAlign(colIndex, align) {
|
|
151
|
+
const self = this.getWritable();
|
|
152
|
+
const table = self.__mdastNode;
|
|
153
|
+
table.align ??= [];
|
|
154
|
+
table.align[colIndex] = align;
|
|
155
|
+
}
|
|
156
|
+
/** @internal */
|
|
157
|
+
decorate(parentEditor) {
|
|
158
|
+
return /* @__PURE__ */ jsx(TableEditor, { lexicalTable: this, mdastNode: this.__mdastNode, parentEditor });
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Focuses the table cell at the specified coordinates.
|
|
162
|
+
* Pass `undefined` to remove the focus.
|
|
163
|
+
*/
|
|
164
|
+
select(coords) {
|
|
165
|
+
this.focusEmitter.publish(coords ?? [0, 0]);
|
|
166
|
+
}
|
|
167
|
+
/** @internal */
|
|
168
|
+
isInline() {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function $isTableNode(node) {
|
|
173
|
+
return node instanceof TableNode;
|
|
174
|
+
}
|
|
175
|
+
function $createTableNode(mdastNode) {
|
|
176
|
+
return new TableNode(mdastNode);
|
|
177
|
+
}
|
|
178
|
+
function $convertTableElement(element) {
|
|
179
|
+
const rows = element.querySelectorAll("tr");
|
|
180
|
+
const children = Array.from(rows).map((row) => {
|
|
181
|
+
return {
|
|
182
|
+
type: "tableRow",
|
|
183
|
+
children: Array.from(row.querySelectorAll("td, th")).map((cell) => {
|
|
184
|
+
return {
|
|
185
|
+
type: "tableCell",
|
|
186
|
+
children: [
|
|
187
|
+
{
|
|
188
|
+
type: "text",
|
|
189
|
+
value: cell.textContent
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
};
|
|
193
|
+
})
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
return {
|
|
197
|
+
node: new TableNode({
|
|
198
|
+
type: "table",
|
|
199
|
+
children
|
|
200
|
+
})
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
export {
|
|
204
|
+
$convertTableElement,
|
|
205
|
+
$createTableNode,
|
|
206
|
+
$isTableNode,
|
|
207
|
+
TableNode
|
|
208
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { realmPlugin } from "../../RealmWithPlugins.js";
|
|
2
|
+
import { Signal, map } from "@mdxeditor/gurx";
|
|
3
|
+
import { gfmTableToMarkdown, gfmTableFromMarkdown } from "mdast-util-gfm-table";
|
|
4
|
+
import { gfmTable } from "micromark-extension-gfm-table";
|
|
5
|
+
import { insertDecoratorNode$, addToMarkdownExtension$, addExportVisitor$, addLexicalNode$, addImportVisitor$, addSyntaxExtension$, addMdastExtension$ } from "../core/index.js";
|
|
6
|
+
import { LexicalTableVisitor } from "./LexicalTableVisitor.js";
|
|
7
|
+
import { MdastTableVisitor } from "./MdastTableVisitor.js";
|
|
8
|
+
import { $createTableNode, TableNode } from "./TableNode.js";
|
|
9
|
+
import { $convertTableElement, $isTableNode } from "./TableNode.js";
|
|
10
|
+
function seedTable(rows = 1, columns = 1) {
|
|
11
|
+
const table = {
|
|
12
|
+
type: "table",
|
|
13
|
+
children: []
|
|
14
|
+
};
|
|
15
|
+
for (let i = 0; i < rows; i++) {
|
|
16
|
+
const tableRow = {
|
|
17
|
+
type: "tableRow",
|
|
18
|
+
children: []
|
|
19
|
+
};
|
|
20
|
+
for (let j = 0; j < columns; j++) {
|
|
21
|
+
const cell = {
|
|
22
|
+
type: "tableCell",
|
|
23
|
+
children: []
|
|
24
|
+
};
|
|
25
|
+
tableRow.children.push(cell);
|
|
26
|
+
}
|
|
27
|
+
table.children.push(tableRow);
|
|
28
|
+
}
|
|
29
|
+
return table;
|
|
30
|
+
}
|
|
31
|
+
const insertTable$ = Signal((r) => {
|
|
32
|
+
r.link(
|
|
33
|
+
r.pipe(
|
|
34
|
+
insertTable$,
|
|
35
|
+
map(({ rows, columns }) => {
|
|
36
|
+
return () => $createTableNode(seedTable(rows, columns));
|
|
37
|
+
})
|
|
38
|
+
),
|
|
39
|
+
insertDecoratorNode$
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
const tablePlugin = realmPlugin({
|
|
43
|
+
init(realm, params) {
|
|
44
|
+
realm.pubIn({
|
|
45
|
+
// import
|
|
46
|
+
[addMdastExtension$]: gfmTableFromMarkdown(),
|
|
47
|
+
[addSyntaxExtension$]: gfmTable(),
|
|
48
|
+
[addImportVisitor$]: MdastTableVisitor,
|
|
49
|
+
// export
|
|
50
|
+
[addLexicalNode$]: TableNode,
|
|
51
|
+
[addExportVisitor$]: LexicalTableVisitor,
|
|
52
|
+
[addToMarkdownExtension$]: gfmTableToMarkdown({
|
|
53
|
+
tableCellPadding: params?.tableCellPadding ?? true,
|
|
54
|
+
tablePipeAlign: params?.tablePipeAlign ?? true
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
export {
|
|
60
|
+
$convertTableElement,
|
|
61
|
+
$createTableNode,
|
|
62
|
+
$isTableNode,
|
|
63
|
+
TableNode,
|
|
64
|
+
insertTable$,
|
|
65
|
+
tablePlugin
|
|
66
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { $isHorizontalRuleNode } from "@lexical/extension";
|
|
2
|
+
const LexicalThematicBreakVisitor = {
|
|
3
|
+
testLexicalNode: $isHorizontalRuleNode,
|
|
4
|
+
visitLexicalNode({ actions }) {
|
|
5
|
+
actions.addAndStepInto("thematicBreak");
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
export {
|
|
9
|
+
LexicalThematicBreakVisitor
|
|
10
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { $createHorizontalRuleNode } from "@lexical/react/LexicalHorizontalRuleNode.js";
|
|
2
|
+
const MdastThematicBreakVisitor = {
|
|
3
|
+
testNode: "thematicBreak",
|
|
4
|
+
visitNode({ actions }) {
|
|
5
|
+
actions.addAndStepInto($createHorizontalRuleNode());
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
export {
|
|
9
|
+
MdastThematicBreakVisitor
|
|
10
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { realmPlugin } from "../../RealmWithPlugins.js";
|
|
2
|
+
import { INSERT_HORIZONTAL_RULE_COMMAND, HorizontalRuleNode } from "@lexical/react/LexicalHorizontalRuleNode.js";
|
|
3
|
+
import { HorizontalRulePlugin } from "@lexical/react/LexicalHorizontalRulePlugin.js";
|
|
4
|
+
import { Action, withLatestFrom } from "@mdxeditor/gurx";
|
|
5
|
+
import { activeEditor$, addComposerChild$, addExportVisitor$, addLexicalNode$, addImportVisitor$, addActivePlugin$ } from "../core/index.js";
|
|
6
|
+
import { LexicalThematicBreakVisitor } from "./LexicalThematicBreakVisitor.js";
|
|
7
|
+
import { MdastThematicBreakVisitor } from "./MdastThematicBreakVisitor.js";
|
|
8
|
+
const insertThematicBreak$ = Action((r) => {
|
|
9
|
+
r.sub(r.pipe(insertThematicBreak$, withLatestFrom(activeEditor$)), ([, theEditor]) => {
|
|
10
|
+
theEditor?.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, void 0);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
const thematicBreakPlugin = realmPlugin({
|
|
14
|
+
init(realm) {
|
|
15
|
+
realm.pubIn({
|
|
16
|
+
[addActivePlugin$]: "thematicBreak",
|
|
17
|
+
[addImportVisitor$]: MdastThematicBreakVisitor,
|
|
18
|
+
[addLexicalNode$]: HorizontalRuleNode,
|
|
19
|
+
[addExportVisitor$]: LexicalThematicBreakVisitor,
|
|
20
|
+
[addComposerChild$]: HorizontalRulePlugin
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
export {
|
|
25
|
+
insertThematicBreak$,
|
|
26
|
+
thematicBreakPlugin
|
|
27
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { $createHeadingNode, $createQuoteNode } from "@lexical/rich-text";
|
|
3
|
+
import { usePublisher, useCellValue } from "@mdxeditor/gurx";
|
|
4
|
+
import { $createParagraphNode } from "lexical";
|
|
5
|
+
import { convertSelectionToNode$, currentBlockType$, activePlugins$, useTranslation } from "../../core/index.js";
|
|
6
|
+
import { allowedHeadingLevels$ } from "../../headings/index.js";
|
|
7
|
+
import { Select } from "../primitives/select.js";
|
|
8
|
+
const BlockTypeSelect = () => {
|
|
9
|
+
const convertSelectionToNode = usePublisher(convertSelectionToNode$);
|
|
10
|
+
const currentBlockType = useCellValue(currentBlockType$);
|
|
11
|
+
const activePlugins = useCellValue(activePlugins$);
|
|
12
|
+
const hasQuote = activePlugins.includes("quote");
|
|
13
|
+
const hasHeadings = activePlugins.includes("headings");
|
|
14
|
+
const t = useTranslation();
|
|
15
|
+
if (!hasQuote && !hasHeadings) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const items = [
|
|
19
|
+
{ label: t("toolbar.blockTypes.paragraph", "Paragraph"), value: "paragraph" }
|
|
20
|
+
];
|
|
21
|
+
if (hasQuote) {
|
|
22
|
+
items.push({ label: t("toolbar.blockTypes.quote", "Quote"), value: "quote" });
|
|
23
|
+
}
|
|
24
|
+
if (hasHeadings) {
|
|
25
|
+
const allowedHeadingLevels = useCellValue(allowedHeadingLevels$);
|
|
26
|
+
items.push(
|
|
27
|
+
...allowedHeadingLevels.map(
|
|
28
|
+
(n) => ({ label: t("toolbar.blockTypes.heading", "Heading {{level}}", { level: n }), value: `h${n}` })
|
|
29
|
+
)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return /* @__PURE__ */ jsx(
|
|
33
|
+
Select,
|
|
34
|
+
{
|
|
35
|
+
value: currentBlockType,
|
|
36
|
+
onChange: (blockType) => {
|
|
37
|
+
switch (blockType) {
|
|
38
|
+
case "quote":
|
|
39
|
+
convertSelectionToNode(() => $createQuoteNode());
|
|
40
|
+
break;
|
|
41
|
+
case "paragraph":
|
|
42
|
+
convertSelectionToNode(() => $createParagraphNode());
|
|
43
|
+
break;
|
|
44
|
+
case "":
|
|
45
|
+
break;
|
|
46
|
+
default:
|
|
47
|
+
if (blockType.startsWith("h")) {
|
|
48
|
+
convertSelectionToNode(() => $createHeadingNode(blockType));
|
|
49
|
+
} else {
|
|
50
|
+
throw new Error(`Unknown block type: ${blockType}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
triggerTitle: t("toolbar.blockTypeSelect.selectBlockTypeTooltip", "Select block type"),
|
|
55
|
+
placeholder: t("toolbar.blockTypeSelect.placeholder", "Block type"),
|
|
56
|
+
items
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
export {
|
|
61
|
+
BlockTypeSelect
|
|
62
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useTranslation, currentFormat$, iconComponentFor$, applyFormat$ } from "../../core/index.js";
|
|
3
|
+
import { useCellValues, usePublisher } from "@mdxeditor/gurx";
|
|
4
|
+
import { IS_BOLD, IS_ITALIC, IS_UNDERLINE, IS_STRIKETHROUGH, IS_SUPERSCRIPT, IS_SUBSCRIPT } from "../../../FormatConstants.js";
|
|
5
|
+
import { ToggleSingleGroupWithItem } from "../primitives/toolbar.js";
|
|
6
|
+
import styles from "../../../styles/ui.module.css.js";
|
|
7
|
+
const FormatButton = ({ format, addTitle, removeTitle, icon, formatName }) => {
|
|
8
|
+
const [currentFormat, iconComponentFor] = useCellValues(currentFormat$, iconComponentFor$);
|
|
9
|
+
const applyFormat = usePublisher(applyFormat$);
|
|
10
|
+
const active = (currentFormat & format) !== 0;
|
|
11
|
+
return /* @__PURE__ */ jsx(
|
|
12
|
+
ToggleSingleGroupWithItem,
|
|
13
|
+
{
|
|
14
|
+
title: active ? removeTitle : addTitle,
|
|
15
|
+
on: active,
|
|
16
|
+
onValueChange: () => {
|
|
17
|
+
applyFormat(formatName);
|
|
18
|
+
},
|
|
19
|
+
children: iconComponentFor(icon)
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
const BoldItalicUnderlineToggles = ({ options }) => {
|
|
24
|
+
const t = useTranslation();
|
|
25
|
+
const showAllButtons = typeof options === "undefined";
|
|
26
|
+
return /* @__PURE__ */ jsxs("div", { className: styles.toolbarGroupOfGroups, children: [
|
|
27
|
+
showAllButtons || options.includes("Bold") ? /* @__PURE__ */ jsx(
|
|
28
|
+
FormatButton,
|
|
29
|
+
{
|
|
30
|
+
format: IS_BOLD,
|
|
31
|
+
addTitle: t("toolbar.bold", "Bold"),
|
|
32
|
+
removeTitle: t("toolbar.removeBold", "Remove bold"),
|
|
33
|
+
icon: "format_bold",
|
|
34
|
+
formatName: "bold"
|
|
35
|
+
}
|
|
36
|
+
) : null,
|
|
37
|
+
showAllButtons || options.includes("Italic") ? /* @__PURE__ */ jsx(
|
|
38
|
+
FormatButton,
|
|
39
|
+
{
|
|
40
|
+
format: IS_ITALIC,
|
|
41
|
+
addTitle: t("toolbar.italic", "Italic"),
|
|
42
|
+
removeTitle: t("toolbar.removeItalic", "Remove italic"),
|
|
43
|
+
icon: "format_italic",
|
|
44
|
+
formatName: "italic"
|
|
45
|
+
}
|
|
46
|
+
) : null,
|
|
47
|
+
showAllButtons || options.includes("Underline") ? /* @__PURE__ */ jsx(
|
|
48
|
+
FormatButton,
|
|
49
|
+
{
|
|
50
|
+
format: IS_UNDERLINE,
|
|
51
|
+
addTitle: t("toolbar.underline", "Underline"),
|
|
52
|
+
removeTitle: t("toolbar.removeUnderline", "Remove underline"),
|
|
53
|
+
icon: "format_underlined",
|
|
54
|
+
formatName: "underline"
|
|
55
|
+
}
|
|
56
|
+
) : null
|
|
57
|
+
] });
|
|
58
|
+
};
|
|
59
|
+
const StrikeThroughSupSubToggles = ({ options }) => {
|
|
60
|
+
const t = useTranslation();
|
|
61
|
+
const showAllButtons = typeof options === "undefined";
|
|
62
|
+
return /* @__PURE__ */ jsxs("div", { className: styles.toolbarGroupOfGroups, children: [
|
|
63
|
+
showAllButtons || options.includes("Strikethrough") ? /* @__PURE__ */ jsx(
|
|
64
|
+
FormatButton,
|
|
65
|
+
{
|
|
66
|
+
format: IS_STRIKETHROUGH,
|
|
67
|
+
addTitle: t("toolbar.strikethrough", "Strikethrough"),
|
|
68
|
+
removeTitle: t("toolbar.removeStrikethrough", "Remove strikethrough"),
|
|
69
|
+
icon: "strikeThrough",
|
|
70
|
+
formatName: "strikethrough"
|
|
71
|
+
}
|
|
72
|
+
) : null,
|
|
73
|
+
showAllButtons || options.includes("Sup") ? /* @__PURE__ */ jsx(
|
|
74
|
+
FormatButton,
|
|
75
|
+
{
|
|
76
|
+
format: IS_SUPERSCRIPT,
|
|
77
|
+
addTitle: t("toolbar.superscript", "Superscript"),
|
|
78
|
+
removeTitle: t("toolbar.removeSuperscript", "Remove superscript"),
|
|
79
|
+
icon: "superscript",
|
|
80
|
+
formatName: "superscript"
|
|
81
|
+
}
|
|
82
|
+
) : null,
|
|
83
|
+
showAllButtons || options.includes("Sub") ? /* @__PURE__ */ jsx(
|
|
84
|
+
FormatButton,
|
|
85
|
+
{
|
|
86
|
+
format: IS_SUBSCRIPT,
|
|
87
|
+
addTitle: t("toolbar.subscript", "Subscript"),
|
|
88
|
+
removeTitle: t("toolbar.removeSubscript", "Remove subscript"),
|
|
89
|
+
icon: "subscript",
|
|
90
|
+
formatName: "subscript"
|
|
91
|
+
}
|
|
92
|
+
) : null
|
|
93
|
+
] });
|
|
94
|
+
};
|
|
95
|
+
export {
|
|
96
|
+
BoldItalicUnderlineToggles,
|
|
97
|
+
StrikeThroughSupSubToggles
|
|
98
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { editorInFocus$, rootEditor$, useTranslation } from "../../core/index.js";
|
|
3
|
+
import { Select } from "../primitives/select.js";
|
|
4
|
+
import { ADMONITION_TYPES } from "../../../directive-editors/AdmonitionDirectiveDescriptor.js";
|
|
5
|
+
import { useCellValues } from "@mdxeditor/gurx";
|
|
6
|
+
function admonitionLabelsMap(t) {
|
|
7
|
+
return {
|
|
8
|
+
note: t("admonitions.note", "Note"),
|
|
9
|
+
tip: t("admonitions.tip", "Tip"),
|
|
10
|
+
danger: t("admonitions.danger", "Danger"),
|
|
11
|
+
info: t("admonitions.info", "Info"),
|
|
12
|
+
caution: t("admonitions.caution", "Caution")
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const ChangeAdmonitionType = () => {
|
|
16
|
+
const [editorInFocus, rootEditor] = useCellValues(editorInFocus$, rootEditor$);
|
|
17
|
+
const admonitionNode = editorInFocus.rootNode;
|
|
18
|
+
const t = useTranslation();
|
|
19
|
+
const labels = admonitionLabelsMap(t);
|
|
20
|
+
return /* @__PURE__ */ jsx(
|
|
21
|
+
Select,
|
|
22
|
+
{
|
|
23
|
+
value: admonitionNode.getMdastNode().name,
|
|
24
|
+
onChange: (name) => {
|
|
25
|
+
rootEditor?.update(() => {
|
|
26
|
+
admonitionNode.setMdastNode({ ...admonitionNode.getMdastNode(), name });
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
rootEditor.update(() => {
|
|
29
|
+
admonitionNode.getLatest().select();
|
|
30
|
+
});
|
|
31
|
+
}, 80);
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
triggerTitle: t("admonitions.changeType", "Select admonition type"),
|
|
35
|
+
placeholder: t("admonitions.placeholder", "Admonition type"),
|
|
36
|
+
items: ADMONITION_TYPES.map((type) => ({ label: labels[type], value: type }))
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
export {
|
|
41
|
+
ChangeAdmonitionType,
|
|
42
|
+
admonitionLabelsMap
|
|
43
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCellValues } from "@mdxeditor/gurx";
|
|
3
|
+
import styles from "../../../styles/ui.module.css.js";
|
|
4
|
+
import { $isCodeBlockNode } from "../../codeblock/CodeBlockNode.js";
|
|
5
|
+
import { codeBlockLanguages$, getCodeBlockLanguageSelectData, EMPTY_VALUE } from "../../codemirror/index.js";
|
|
6
|
+
import { editorInFocus$, activeEditor$, useTranslation } from "../../core/index.js";
|
|
7
|
+
import { Select } from "../primitives/select.js";
|
|
8
|
+
const ChangeCodeMirrorLanguage = () => {
|
|
9
|
+
const [editorInFocus, theEditor, codeBlockLanguages] = useCellValues(editorInFocus$, activeEditor$, codeBlockLanguages$);
|
|
10
|
+
const codeBlockNode = $isCodeBlockNode(editorInFocus.rootNode) ? editorInFocus.rootNode : null;
|
|
11
|
+
const t = useTranslation();
|
|
12
|
+
if (!codeBlockNode) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const rawLanguage = codeBlockNode.getLanguage();
|
|
16
|
+
const { value: currentLanguage, items } = getCodeBlockLanguageSelectData(codeBlockLanguages, rawLanguage);
|
|
17
|
+
return /* @__PURE__ */ jsxs("div", { className: styles.selectWithLabel, children: [
|
|
18
|
+
/* @__PURE__ */ jsx("label", { children: t("codeBlock.language", "Code block language") }),
|
|
19
|
+
/* @__PURE__ */ jsx(
|
|
20
|
+
Select,
|
|
21
|
+
{
|
|
22
|
+
value: currentLanguage || EMPTY_VALUE,
|
|
23
|
+
onChange: (language) => {
|
|
24
|
+
theEditor?.update(() => {
|
|
25
|
+
codeBlockNode.setLanguage(language === EMPTY_VALUE ? "" : language);
|
|
26
|
+
setTimeout(() => {
|
|
27
|
+
theEditor.update(() => {
|
|
28
|
+
codeBlockNode.getLatest().select();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
triggerTitle: t("codeBlock.selectLanguage", "Select code block language"),
|
|
34
|
+
placeholder: t("codeBlock.language", "Code block language"),
|
|
35
|
+
items
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
] });
|
|
39
|
+
};
|
|
40
|
+
export {
|
|
41
|
+
ChangeCodeMirrorLanguage
|
|
42
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { IS_CODE } from "../../../FormatConstants.js";
|
|
3
|
+
import { currentFormat$, iconComponentFor$, applyFormat$, useTranslation } from "../../core/index.js";
|
|
4
|
+
import { MultipleChoiceToggleGroup } from "../primitives/toolbar.js";
|
|
5
|
+
import { useCellValues, usePublisher } from "@mdxeditor/gurx";
|
|
6
|
+
const CodeToggle = () => {
|
|
7
|
+
const [currentFormat, iconComponentFor] = useCellValues(currentFormat$, iconComponentFor$);
|
|
8
|
+
const applyFormat = usePublisher(applyFormat$);
|
|
9
|
+
const t = useTranslation();
|
|
10
|
+
const codeIsOn = (currentFormat & IS_CODE) !== 0;
|
|
11
|
+
const title = codeIsOn ? t("toolbar.removeInlineCode", "Remove code format") : t("toolbar.inlineCode", "Inline code format");
|
|
12
|
+
return /* @__PURE__ */ jsx(
|
|
13
|
+
MultipleChoiceToggleGroup,
|
|
14
|
+
{
|
|
15
|
+
items: [{ title, contents: iconComponentFor("code"), active: codeIsOn, onChange: applyFormat.bind(null, "code") }]
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
export {
|
|
20
|
+
CodeToggle
|
|
21
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ButtonWithTooltip } from "../primitives/toolbar.js";
|
|
3
|
+
import { openLinkEditDialog$ } from "../../link-dialog/index.js";
|
|
4
|
+
import { usePublisher, useCellValue } from "@mdxeditor/gurx";
|
|
5
|
+
import { iconComponentFor$, useTranslation } from "../../core/index.js";
|
|
6
|
+
const CreateLink = () => {
|
|
7
|
+
const openLinkDialog = usePublisher(openLinkEditDialog$);
|
|
8
|
+
const iconComponentFor = useCellValue(iconComponentFor$);
|
|
9
|
+
const t = useTranslation();
|
|
10
|
+
return /* @__PURE__ */ jsx(
|
|
11
|
+
ButtonWithTooltip,
|
|
12
|
+
{
|
|
13
|
+
"aria-label": t("toolbar.link", "Create link"),
|
|
14
|
+
title: t("toolbar.link", "Create link"),
|
|
15
|
+
onClick: (_) => {
|
|
16
|
+
openLinkDialog();
|
|
17
|
+
},
|
|
18
|
+
children: iconComponentFor("link")
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
export {
|
|
23
|
+
CreateLink
|
|
24
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { viewMode$, iconComponentFor$, useTranslation } from "../../core/index.js";
|
|
3
|
+
import { useCellValues, usePublisher } from "@mdxeditor/gurx";
|
|
4
|
+
import styles from "../../../styles/ui.module.css.js";
|
|
5
|
+
import { SingleChoiceToggleGroup } from "../primitives/toolbar.js";
|
|
6
|
+
const DiffSourceToggleWrapper = ({
|
|
7
|
+
children,
|
|
8
|
+
SourceToolbar,
|
|
9
|
+
options = ["rich-text", "diff", "source"]
|
|
10
|
+
}) => {
|
|
11
|
+
const [viewMode, iconComponentFor] = useCellValues(viewMode$, iconComponentFor$);
|
|
12
|
+
const changeViewMode = usePublisher(viewMode$);
|
|
13
|
+
const t = useTranslation();
|
|
14
|
+
const toggleGroupItems = [];
|
|
15
|
+
if (options.includes("rich-text")) {
|
|
16
|
+
toggleGroupItems.push({ title: t("toolbar.richText", "Rich text"), contents: iconComponentFor("rich_text"), value: "rich-text" });
|
|
17
|
+
}
|
|
18
|
+
if (options.includes("diff")) {
|
|
19
|
+
toggleGroupItems.push({ title: t("toolbar.diffMode", "Diff mode"), contents: iconComponentFor("difference"), value: "diff" });
|
|
20
|
+
}
|
|
21
|
+
if (options.includes("source")) {
|
|
22
|
+
toggleGroupItems.push({ title: t("toolbar.source", "Source mode"), contents: iconComponentFor("markdown"), value: "source" });
|
|
23
|
+
}
|
|
24
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
25
|
+
viewMode === "rich-text" ? children : viewMode === "diff" ? /* @__PURE__ */ jsx("span", { className: styles.toolbarTitleMode, children: t("toolbar.diffMode", "Diff mode") }) : SourceToolbar ?? /* @__PURE__ */ jsx("span", { className: styles.toolbarTitleMode, children: t("toolbar.source", "Source mode") }),
|
|
26
|
+
/* @__PURE__ */ jsx("div", { className: styles.diffSourceToggleWrapper, children: /* @__PURE__ */ jsx(
|
|
27
|
+
SingleChoiceToggleGroup,
|
|
28
|
+
{
|
|
29
|
+
className: styles.diffSourceToggle,
|
|
30
|
+
ggClassName: styles.ggDiffSourceToggle,
|
|
31
|
+
value: viewMode,
|
|
32
|
+
items: toggleGroupItems,
|
|
33
|
+
onChange: (value) => {
|
|
34
|
+
changeViewMode(value === "" ? "rich-text" : value);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
) })
|
|
38
|
+
] });
|
|
39
|
+
};
|
|
40
|
+
export {
|
|
41
|
+
DiffSourceToggleWrapper
|
|
42
|
+
};
|