@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.
Files changed (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +86 -0
  3. package/UPSTREAM.md +21 -0
  4. package/dist/EditorIcon.js +75 -0
  5. package/dist/FormatConstants.js +20 -0
  6. package/dist/MDXEditor.js +189 -0
  7. package/dist/MarkdownEditor.js +281 -0
  8. package/dist/PersistentMarkdownEditor.js +358 -0
  9. package/dist/RealmWithPlugins.js +35 -0
  10. package/dist/core.d.ts +3232 -0
  11. package/dist/core.js +354 -0
  12. package/dist/defaultSvgIcons.js +371 -0
  13. package/dist/directive-editors/AdmonitionDirectiveDescriptor.js +28 -0
  14. package/dist/directive-editors/GenericDirectiveEditor.js +37 -0
  15. package/dist/exportMarkdownFromLexical.js +262 -0
  16. package/dist/horizontalRuleShortcut.js +37 -0
  17. package/dist/importMarkdownToLexical.js +172 -0
  18. package/dist/index.d.ts +86 -0
  19. package/dist/index.js +8 -0
  20. package/dist/jsx-editors/GenericJsxEditor.js +84 -0
  21. package/dist/mdastUtilHtmlComment.js +125 -0
  22. package/dist/persistence.d.ts +128 -0
  23. package/dist/persistence.js +4 -0
  24. package/dist/plugins/codeblock/CodeBlockNode.js +183 -0
  25. package/dist/plugins/codeblock/CodeBlockVisitor.js +14 -0
  26. package/dist/plugins/codeblock/MdastCodeVisitor.js +23 -0
  27. package/dist/plugins/codeblock/findCodeBlockDescriptor.js +8 -0
  28. package/dist/plugins/codeblock/index.js +46 -0
  29. package/dist/plugins/codemirror/CodeMirrorEditor.js +145 -0
  30. package/dist/plugins/codemirror/index.js +115 -0
  31. package/dist/plugins/codemirror/useCodeMirrorRef.js +101 -0
  32. package/dist/plugins/core/GenericHTMLNode.js +118 -0
  33. package/dist/plugins/core/LexicalGenericHTMLNodeVisitor.js +15 -0
  34. package/dist/plugins/core/LexicalLinebreakVisitor.js +10 -0
  35. package/dist/plugins/core/LexicalParagraphVisitor.js +10 -0
  36. package/dist/plugins/core/LexicalRootVisitor.js +10 -0
  37. package/dist/plugins/core/LexicalTextVisitor.js +160 -0
  38. package/dist/plugins/core/MdastBreakVisitor.js +10 -0
  39. package/dist/plugins/core/MdastFormattingVisitor.js +81 -0
  40. package/dist/plugins/core/MdastHTMLNode.js +120 -0
  41. package/dist/plugins/core/MdastHTMLVisitor.js +17 -0
  42. package/dist/plugins/core/MdastParagraphVisitor.js +23 -0
  43. package/dist/plugins/core/MdastRootVisitor.js +9 -0
  44. package/dist/plugins/core/MdastTextVisitor.js +16 -0
  45. package/dist/plugins/core/NestedLexicalEditor.js +221 -0
  46. package/dist/plugins/core/PropertyPopover.js +75 -0
  47. package/dist/plugins/core/SharedHistoryPlugin.js +10 -0
  48. package/dist/plugins/core/index.js +692 -0
  49. package/dist/plugins/core/ui/DownshiftAutoComplete.js +89 -0
  50. package/dist/plugins/core/ui/PopoverUtils.js +22 -0
  51. package/dist/plugins/diff-source/DiffSourceWrapper.js +24 -0
  52. package/dist/plugins/diff-source/DiffViewer.js +84 -0
  53. package/dist/plugins/diff-source/SourceEditor.js +60 -0
  54. package/dist/plugins/diff-source/index.js +27 -0
  55. package/dist/plugins/directives/DirectiveNode.js +107 -0
  56. package/dist/plugins/directives/DirectiveVisitor.js +10 -0
  57. package/dist/plugins/directives/MdastDirectiveVisitor.js +30 -0
  58. package/dist/plugins/directives/index.js +45 -0
  59. package/dist/plugins/frontmatter/FrontmatterEditor.js +137 -0
  60. package/dist/plugins/frontmatter/FrontmatterNode.js +70 -0
  61. package/dist/plugins/frontmatter/LexicalFrontmatterVisitor.js +10 -0
  62. package/dist/plugins/frontmatter/MdastFrontmatterVisitor.js +10 -0
  63. package/dist/plugins/frontmatter/index.js +113 -0
  64. package/dist/plugins/headings/LexicalHeadingVisitor.js +11 -0
  65. package/dist/plugins/headings/MdastHeadingVisitor.js +10 -0
  66. package/dist/plugins/headings/index.js +63 -0
  67. package/dist/plugins/image/EditImageToolbar.js +58 -0
  68. package/dist/plugins/image/ImageDialog.js +132 -0
  69. package/dist/plugins/image/ImageEditor.js +279 -0
  70. package/dist/plugins/image/ImageNode.js +187 -0
  71. package/dist/plugins/image/ImagePlaceholder.js +9 -0
  72. package/dist/plugins/image/ImageResizer.js +223 -0
  73. package/dist/plugins/image/LexicalImageVisitor.js +42 -0
  74. package/dist/plugins/image/MdastImageVisitor.js +91 -0
  75. package/dist/plugins/image/index.js +364 -0
  76. package/dist/plugins/jsx/LexicalJsxNode.js +103 -0
  77. package/dist/plugins/jsx/LexicalJsxVisitor.js +27 -0
  78. package/dist/plugins/jsx/LexicalMdxExpressionNode.js +130 -0
  79. package/dist/plugins/jsx/LexicalMdxExpressionVisitor.js +14 -0
  80. package/dist/plugins/jsx/MdastMdxExpressionVisitor.js +11 -0
  81. package/dist/plugins/jsx/MdastMdxJsEsmVisitor.js +8 -0
  82. package/dist/plugins/jsx/MdastMdxJsxElementVisitor.js +28 -0
  83. package/dist/plugins/jsx/index.js +97 -0
  84. package/dist/plugins/jsx/jsxTagName.js +7 -0
  85. package/dist/plugins/link/AutoLinkPlugin.js +18 -0
  86. package/dist/plugins/link/LexicalLinkVisitor.js +10 -0
  87. package/dist/plugins/link/MdastLinkVisitor.js +14 -0
  88. package/dist/plugins/link/index.js +34 -0
  89. package/dist/plugins/link-dialog/LinkDialog.js +262 -0
  90. package/dist/plugins/link-dialog/index.js +304 -0
  91. package/dist/plugins/lists/CheckListPlugin.js +270 -0
  92. package/dist/plugins/lists/LexicalListItemVisitor.js +41 -0
  93. package/dist/plugins/lists/LexicalListVisitor.js +13 -0
  94. package/dist/plugins/lists/MdastListItemVisitor.js +11 -0
  95. package/dist/plugins/lists/MdastListVisitor.js +19 -0
  96. package/dist/plugins/lists/NotesListItemNode.js +22 -0
  97. package/dist/plugins/lists/index.js +111 -0
  98. package/dist/plugins/markdown-shortcut/index.js +114 -0
  99. package/dist/plugins/maxlength/index.js +36 -0
  100. package/dist/plugins/quote/LexicalQuoteVisitor.js +10 -0
  101. package/dist/plugins/quote/MdastBlockQuoteVisitor.js +10 -0
  102. package/dist/plugins/quote/index.js +18 -0
  103. package/dist/plugins/remote/index.js +52 -0
  104. package/dist/plugins/search/index.js +360 -0
  105. package/dist/plugins/table/LexicalTableVisitor.js +10 -0
  106. package/dist/plugins/table/MdastTableVisitor.js +10 -0
  107. package/dist/plugins/table/TableEditor.js +527 -0
  108. package/dist/plugins/table/TableNode.js +208 -0
  109. package/dist/plugins/table/index.js +66 -0
  110. package/dist/plugins/thematic-break/LexicalThematicBreakVisitor.js +10 -0
  111. package/dist/plugins/thematic-break/MdastThematicBreakVisitor.js +10 -0
  112. package/dist/plugins/thematic-break/index.js +27 -0
  113. package/dist/plugins/toolbar/components/BlockTypeSelect.js +62 -0
  114. package/dist/plugins/toolbar/components/BoldItalicUnderlineToggles.js +98 -0
  115. package/dist/plugins/toolbar/components/ChangeAdmonitionType.js +43 -0
  116. package/dist/plugins/toolbar/components/ChangeCodeMirrorLanguage.js +42 -0
  117. package/dist/plugins/toolbar/components/CodeToggle.js +21 -0
  118. package/dist/plugins/toolbar/components/CreateLink.js +24 -0
  119. package/dist/plugins/toolbar/components/DiffSourceToggleWrapper.js +42 -0
  120. package/dist/plugins/toolbar/components/HighlightToggle.js +28 -0
  121. package/dist/plugins/toolbar/components/InsertAdmonition.js +34 -0
  122. package/dist/plugins/toolbar/components/InsertCodeBlock.js +23 -0
  123. package/dist/plugins/toolbar/components/InsertFrontmatter.js +28 -0
  124. package/dist/plugins/toolbar/components/InsertImage.js +29 -0
  125. package/dist/plugins/toolbar/components/InsertTable.js +25 -0
  126. package/dist/plugins/toolbar/components/InsertThematicBreak.js +23 -0
  127. package/dist/plugins/toolbar/components/KitchenSinkToolbar.js +82 -0
  128. package/dist/plugins/toolbar/components/ListsToggle.js +29 -0
  129. package/dist/plugins/toolbar/components/UndoRedo.js +60 -0
  130. package/dist/plugins/toolbar/index.js +32 -0
  131. package/dist/plugins/toolbar/primitives/DialogButton.js +130 -0
  132. package/dist/plugins/toolbar/primitives/TooltipWrap.js +17 -0
  133. package/dist/plugins/toolbar/primitives/select.js +76 -0
  134. package/dist/plugins/toolbar/primitives/toolbar.js +144 -0
  135. package/dist/registerCodeBoundaryEscape.js +40 -0
  136. package/dist/styles/lexical-theme.module.css.js +62 -0
  137. package/dist/styles/lexicalTheme.js +32 -0
  138. package/dist/styles/ui.module.css.js +296 -0
  139. package/dist/styles.css +2838 -0
  140. package/dist/utils/detectMac.js +16 -0
  141. package/dist/utils/fp.js +44 -0
  142. package/dist/utils/isPartOftheEditorUI.js +12 -0
  143. package/dist/utils/lexicalHelpers.js +185 -0
  144. package/dist/utils/makeHslTransparent.js +6 -0
  145. package/dist/utils/mergeStyleAttributes.js +22 -0
  146. package/dist/utils/uuid4.js +10 -0
  147. package/dist/utils/voidEmitter.js +15 -0
  148. 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
+ };