@eventuras/scribo 0.8.3 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/App.d.ts +11 -0
  2. package/dist/App.d.ts.map +1 -0
  3. package/dist/MarkdownEditor.d.ts +18 -0
  4. package/dist/MarkdownEditor.d.ts.map +1 -0
  5. package/dist/MarkdownEditor2.js +111 -0
  6. package/dist/MarkdownEditor2.js.map +1 -0
  7. package/dist/MarkdownInput.d.ts +27 -0
  8. package/dist/MarkdownInput.d.ts.map +1 -0
  9. package/dist/MarkdownInput.js +57 -0
  10. package/dist/MarkdownInput.js.map +1 -0
  11. package/dist/callout.js +5 -0
  12. package/dist/context/SharedHistoryContext.d.ts +11 -0
  13. package/dist/context/SharedHistoryContext.d.ts.map +1 -0
  14. package/dist/context/SharedHistoryContext.js +12 -0
  15. package/dist/context/SharedHistoryContext.js.map +1 -0
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/main.d.ts +5 -0
  19. package/dist/main.d.ts.map +1 -0
  20. package/dist/main.js +4 -0
  21. package/dist/nodes/EditorNodes.d.ts +4 -0
  22. package/dist/nodes/EditorNodes.d.ts.map +1 -0
  23. package/dist/nodes/EditorNodes.js +39 -0
  24. package/dist/nodes/EditorNodes.js.map +1 -0
  25. package/dist/nodes/callout/CalloutComponent.d.ts +6 -0
  26. package/dist/nodes/callout/CalloutComponent.d.ts.map +1 -0
  27. package/dist/nodes/callout/CalloutComponent.js +53 -0
  28. package/dist/nodes/callout/CalloutComponent.js.map +1 -0
  29. package/dist/nodes/callout/CalloutNode.d.ts +27 -0
  30. package/dist/nodes/callout/CalloutNode.d.ts.map +1 -0
  31. package/dist/nodes/callout/CalloutNode.js +153 -0
  32. package/dist/nodes/callout/CalloutNode.js.map +1 -0
  33. package/dist/nodes/callout/CalloutTransformer.d.ts +3 -0
  34. package/dist/nodes/callout/CalloutTransformer.d.ts.map +1 -0
  35. package/dist/nodes/callout/CalloutTransformer.js +48 -0
  36. package/dist/nodes/callout/CalloutTransformer.js.map +1 -0
  37. package/dist/nodes/callout/calloutPlugin.d.ts +3 -0
  38. package/dist/nodes/callout/calloutPlugin.d.ts.map +1 -0
  39. package/dist/nodes/callout/calloutPlugin.js +34 -0
  40. package/dist/nodes/callout/calloutPlugin.js.map +1 -0
  41. package/dist/nodes/callout/index.d.ts +6 -0
  42. package/dist/nodes/callout/index.d.ts.map +1 -0
  43. package/dist/nodes/schedule/ScheduleItemComponent.d.ts +9 -0
  44. package/dist/nodes/schedule/ScheduleItemComponent.d.ts.map +1 -0
  45. package/dist/nodes/schedule/ScheduleItemComponent.js +167 -0
  46. package/dist/nodes/schedule/ScheduleItemComponent.js.map +1 -0
  47. package/dist/nodes/schedule/ScheduleItemNode.d.ts +31 -0
  48. package/dist/nodes/schedule/ScheduleItemNode.d.ts.map +1 -0
  49. package/dist/nodes/schedule/ScheduleItemNode.js +94 -0
  50. package/dist/nodes/schedule/ScheduleItemNode.js.map +1 -0
  51. package/dist/nodes/schedule/ScheduleTransformer.d.ts +22 -0
  52. package/dist/nodes/schedule/ScheduleTransformer.d.ts.map +1 -0
  53. package/dist/nodes/schedule/ScheduleTransformer.js +60 -0
  54. package/dist/nodes/schedule/ScheduleTransformer.js.map +1 -0
  55. package/dist/nodes/schedule/index.d.ts +5 -0
  56. package/dist/nodes/schedule/index.d.ts.map +1 -0
  57. package/dist/nodes/schedule/schedulePlugin.d.ts +3 -0
  58. package/dist/nodes/schedule/schedulePlugin.d.ts.map +1 -0
  59. package/dist/nodes/schedule/schedulePlugin.js +33 -0
  60. package/dist/nodes/schedule/schedulePlugin.js.map +1 -0
  61. package/dist/plugins/AutoLinkPlugin.d.ts +3 -0
  62. package/dist/plugins/AutoLinkPlugin.d.ts.map +1 -0
  63. package/dist/plugins/AutoLinkPlugin.js +22 -0
  64. package/dist/plugins/AutoLinkPlugin.js.map +1 -0
  65. package/dist/plugins/FloatingLinkEditorPlugin.d.ts +7 -0
  66. package/dist/plugins/FloatingLinkEditorPlugin.d.ts.map +1 -0
  67. package/dist/plugins/FloatingLinkEditorPlugin2.js +302 -0
  68. package/dist/plugins/FloatingLinkEditorPlugin2.js.map +1 -0
  69. package/dist/plugins/HistoryPlugin.d.ts +26 -0
  70. package/dist/plugins/HistoryPlugin.d.ts.map +1 -0
  71. package/dist/plugins/LinkPlugin.d.ts +3 -0
  72. package/dist/plugins/LinkPlugin.d.ts.map +1 -0
  73. package/dist/plugins/LinkPlugin.js +18 -0
  74. package/dist/plugins/LinkPlugin.js.map +1 -0
  75. package/dist/plugins/ToolbarPlugin.d.ts +7 -0
  76. package/dist/plugins/ToolbarPlugin.d.ts.map +1 -0
  77. package/dist/plugins/ToolbarPlugin.js +372 -0
  78. package/dist/plugins/ToolbarPlugin.js.map +1 -0
  79. package/dist/schedule.js +4 -0
  80. package/dist/scribo.css +1977 -0
  81. package/dist/themes/EditorTheme.d.ts +4 -0
  82. package/dist/themes/EditorTheme.d.ts.map +1 -0
  83. package/dist/themes/EditorTheme2.js +107 -0
  84. package/dist/themes/EditorTheme2.js.map +1 -0
  85. package/dist/types.d.ts +26 -0
  86. package/dist/types.d.ts.map +1 -0
  87. package/dist/ui/ContentEditable.d.ts +6 -0
  88. package/dist/ui/ContentEditable.d.ts.map +1 -0
  89. package/dist/ui/ContentEditable2.js +14 -0
  90. package/dist/ui/ContentEditable2.js.map +1 -0
  91. package/dist/ui/DropDown.d.ts +18 -0
  92. package/dist/ui/DropDown.d.ts.map +1 -0
  93. package/dist/ui/DropDown.js +162 -0
  94. package/dist/ui/DropDown.js.map +1 -0
  95. package/dist/ui/Placeholder.d.ts +6 -0
  96. package/dist/ui/Placeholder.d.ts.map +1 -0
  97. package/dist/ui/Placeholder2.js +13 -0
  98. package/dist/ui/Placeholder2.js.map +1 -0
  99. package/dist/utils/environment.d.ts +24 -0
  100. package/dist/utils/environment.d.ts.map +1 -0
  101. package/dist/utils/environment.js +20 -0
  102. package/dist/utils/environment.js.map +1 -0
  103. package/dist/utils/getSelectedNode.d.ts +3 -0
  104. package/dist/utils/getSelectedNode.d.ts.map +1 -0
  105. package/dist/utils/getSelectedNode.js +23 -0
  106. package/dist/utils/getSelectedNode.js.map +1 -0
  107. package/dist/utils/setFloatingElemPosition.d.ts +2 -0
  108. package/dist/utils/setFloatingElemPosition.d.ts.map +1 -0
  109. package/dist/utils/setFloatingElemPositionForLinkEditor.d.ts +2 -0
  110. package/dist/utils/setFloatingElemPositionForLinkEditor.d.ts.map +1 -0
  111. package/dist/utils/setFloatingElemPositionForLinkEditor.js +33 -0
  112. package/dist/utils/setFloatingElemPositionForLinkEditor.js.map +1 -0
  113. package/dist/utils/url.d.ts +11 -0
  114. package/dist/utils/url.d.ts.map +1 -0
  115. package/dist/utils/url.js +33 -0
  116. package/dist/utils/url.js.map +1 -0
  117. package/dist/vite.svg +1 -0
  118. package/package.json +55 -38
  119. package/src/MarkdownEditor.css +61 -47
  120. package/src/MarkdownEditor.tsx +76 -29
  121. package/src/MarkdownInput.tsx +9 -10
  122. package/src/context/SharedHistoryContext.tsx +8 -16
  123. package/src/main.tsx +3 -3
  124. package/src/nodes/EditorNodes.ts +10 -10
  125. package/src/nodes/callout/Callout.css +94 -0
  126. package/src/nodes/callout/CalloutComponent.tsx +61 -0
  127. package/src/nodes/callout/CalloutNode.ts +197 -0
  128. package/src/nodes/callout/CalloutTransformer.ts +87 -0
  129. package/src/nodes/callout/calloutPlugin.ts +37 -0
  130. package/src/nodes/callout/index.ts +5 -0
  131. package/src/nodes/schedule/ScheduleItem.css +140 -0
  132. package/src/nodes/schedule/ScheduleItemComponent.tsx +195 -0
  133. package/src/nodes/schedule/ScheduleItemNode.ts +135 -0
  134. package/src/nodes/schedule/ScheduleTransformer.ts +80 -0
  135. package/src/nodes/schedule/index.ts +4 -0
  136. package/src/nodes/schedule/schedulePlugin.ts +33 -0
  137. package/src/plugins/AutoLinkPlugin.tsx +5 -10
  138. package/src/plugins/FloatingLinkEditorPlugin.tsx +42 -66
  139. package/src/plugins/HistoryPlugin.tsx +20 -30
  140. package/src/plugins/LinkPlugin.tsx +2 -3
  141. package/src/plugins/ToolbarPlugin.tsx +129 -141
  142. package/src/themes/EditorTheme.css +9 -5
  143. package/src/themes/EditorTheme.ts +89 -90
  144. package/src/types.ts +27 -0
  145. package/src/ui/ContentEditable.tsx +5 -5
  146. package/src/ui/DropDown.tsx +23 -41
  147. package/src/ui/Placeholder.tsx +21 -21
  148. package/src/utils/environment.ts +6 -12
  149. package/src/utils/getSelectedNode.ts +3 -5
  150. package/src/utils/setFloatingElemPosition.ts +2 -5
  151. package/src/utils/setFloatingElemPositionForLinkEditor.ts +1 -1
  152. package/src/utils/url.ts +4 -10
  153. package/tsconfig.json +8 -0
  154. package/CHANGELOG.md +0 -65
  155. package/README.md +0 -126
  156. package/RELEASE.md +0 -102
  157. package/eslint.config.js +0 -4
  158. package/src/App.css +0 -35
  159. package/src/App.tsx +0 -42
  160. package/src/index.tsx +0 -13
  161. package/tsconfig.node.json +0 -11
  162. package/vite.config.site.ts +0 -19
  163. package/vite.config.ts +0 -33
  164. /package/{src → dist}/vite-env.d.ts +0 -0
@@ -16,27 +16,23 @@ import {
16
16
  CODE_LANGUAGE_MAP,
17
17
  getLanguageFriendlyName,
18
18
  } from '@lexical/code';
19
- import { $isLinkNode, TOGGLE_LINK_COMMAND } from "@lexical/link";
19
+ import { $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
20
20
  import {
21
21
  $isListNode,
22
22
  INSERT_ORDERED_LIST_COMMAND,
23
23
  INSERT_UNORDERED_LIST_COMMAND,
24
24
  ListNode,
25
25
  REMOVE_LIST_COMMAND,
26
- } from "@lexical/list";
26
+ } from '@lexical/list';
27
27
  import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
28
28
  import {
29
29
  $createHeadingNode,
30
30
  $createQuoteNode,
31
31
  $isHeadingNode,
32
- HeadingTagType,
33
- } from "@lexical/rich-text";
34
- import { $setBlocksType } from "@lexical/selection";
35
- import {
36
- $findMatchingParent,
37
- $getNearestNodeOfType,
38
- mergeRegister,
39
- } from "@lexical/utils";
32
+ type HeadingTagType,
33
+ } from '@lexical/rich-text';
34
+ import { $setBlocksType } from '@lexical/selection';
35
+ import { $findMatchingParent, $getNearestNodeOfType, mergeRegister } from '@lexical/utils';
40
36
  import {
41
37
  $createParagraphNode,
42
38
  $getNodeByKey,
@@ -49,39 +45,37 @@ import {
49
45
  COMMAND_PRIORITY_NORMAL,
50
46
  FORMAT_TEXT_COMMAND,
51
47
  KEY_MODIFIER_COMMAND,
52
- LexicalEditor,
53
- NodeKey,
48
+ type LexicalEditor,
49
+ type NodeKey,
54
50
  REDO_COMMAND,
55
51
  SELECTION_CHANGE_COMMAND,
56
52
  UNDO_COMMAND,
57
53
  } from 'lexical';
58
- import { Dispatch, useCallback, useEffect, useState } from "react";
59
- import type {JSX} from 'react';
60
-
61
- import DropDown, { DropDownItem } from "../ui/DropDown";
62
- import { IS_APPLE } from "../utils/environment";
63
- import { getSelectedNode } from "../utils/getSelectedNode";
64
- import { sanitizeUrl } from "../utils/url";
54
+ import type { JSX } from 'react';
55
+ import { type Dispatch, useCallback, useEffect, useState } from 'react';
56
+ import type { ScriboToolbarButton } from '../types';
57
+ import DropDown, { DropDownItem } from '../ui/DropDown';
58
+ import { IS_APPLE } from '../utils/environment';
59
+ import { getSelectedNode } from '../utils/getSelectedNode';
60
+ import { sanitizeUrl } from '../utils/url';
65
61
 
66
62
  const blockTypeToBlockName = {
67
- paragraph: "Normal",
68
- h1: "Heading 1",
69
- h2: "Heading 2",
70
- h3: "Heading 3",
71
- h4: "Heading 4",
72
- bullet: "Bulleted List",
73
- check: "Check List",
74
- code: "Code Block",
75
- number: "Numbered List",
76
- quote: "Quote",
63
+ paragraph: 'Normal',
64
+ h1: 'Heading 1',
65
+ h2: 'Heading 2',
66
+ h3: 'Heading 3',
67
+ h4: 'Heading 4',
68
+ bullet: 'Bulleted List',
69
+ check: 'Check List',
70
+ code: 'Code Block',
71
+ number: 'Numbered List',
72
+ quote: 'Quote',
77
73
  };
78
74
 
79
75
  function getCodeLanguageOptions(): [string, string][] {
80
76
  const options: [string, string][] = [];
81
77
 
82
- for (const [lang, friendlyName] of Object.entries(
83
- CODE_LANGUAGE_FRIENDLY_NAME_MAP,
84
- )) {
78
+ for (const [lang, friendlyName] of Object.entries(CODE_LANGUAGE_FRIENDLY_NAME_MAP)) {
85
79
  options.push([lang, friendlyName]);
86
80
  }
87
81
 
@@ -91,41 +85,41 @@ function getCodeLanguageOptions(): [string, string][] {
91
85
  const CODE_LANGUAGE_OPTIONS = getCodeLanguageOptions();
92
86
 
93
87
  function dropDownActiveClass(active: boolean) {
94
- if (active) return "active dropdown-item-active";
95
- else return "";
88
+ if (active) return 'active dropdown-item-active';
89
+ else return '';
96
90
  }
97
91
 
98
92
  function BlockFormatDropDown({
99
93
  editor,
100
94
  blockType,
101
95
  disabled = false,
102
- }: {
96
+ }: Readonly<{
103
97
  blockType: keyof typeof blockTypeToBlockName;
104
98
  editor: LexicalEditor;
105
99
  disabled?: boolean;
106
- }): JSX.Element {
107
- const formatParagraph = () => {
108
- editor.update(() => {
109
- const selection = $getSelection();
110
- if ($isRangeSelection(selection)) {
111
- $setBlocksType(selection, () => $createParagraphNode());
112
- }
113
- });
114
- };
115
-
116
- const formatHeading = (headingSize: HeadingTagType) => {
117
- if (blockType !== headingSize) {
100
+ }>): JSX.Element {
101
+ const formatParagraph = () => {
118
102
  editor.update(() => {
119
103
  const selection = $getSelection();
120
104
  if ($isRangeSelection(selection)) {
121
- $setBlocksType(selection, () => $createHeadingNode(headingSize));
105
+ $setBlocksType(selection, () => $createParagraphNode());
122
106
  }
123
107
  });
124
- }
125
- };
108
+ };
109
+
110
+ const formatHeading = (headingSize: HeadingTagType) => {
111
+ if (blockType !== headingSize) {
112
+ editor.update(() => {
113
+ const selection = $getSelection();
114
+ if ($isRangeSelection(selection)) {
115
+ $setBlocksType(selection, () => $createHeadingNode(headingSize));
116
+ }
117
+ });
118
+ }
119
+ };
126
120
 
127
121
  const formatBulletList = () => {
128
- if (blockType !== "bullet") {
122
+ if (blockType !== 'bullet') {
129
123
  editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);
130
124
  } else {
131
125
  editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);
@@ -133,25 +127,25 @@ const formatHeading = (headingSize: HeadingTagType) => {
133
127
  };
134
128
 
135
129
  const formatNumberedList = () => {
136
- if (blockType !== "number") {
130
+ if (blockType !== 'number') {
137
131
  editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);
138
132
  } else {
139
133
  editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);
140
134
  }
141
135
  };
142
136
 
143
- const formatQuote = () => {
144
- if (blockType !== 'quote') {
145
- editor.update(() => {
146
- const selection = $getSelection();
147
- if ($isRangeSelection(selection)) {
148
- $setBlocksType(selection, () => $createQuoteNode());
149
- }
150
- });
151
- }
152
- };
137
+ const formatQuote = () => {
138
+ if (blockType !== 'quote') {
139
+ editor.update(() => {
140
+ const selection = $getSelection();
141
+ if ($isRangeSelection(selection)) {
142
+ $setBlocksType(selection, () => $createQuoteNode());
143
+ }
144
+ });
145
+ }
146
+ };
153
147
 
154
- const formatCode = () => {
148
+ const formatCode = () => {
155
149
  if (blockType !== 'code') {
156
150
  editor.update(() => {
157
151
  let selection = $getSelection();
@@ -177,61 +171,61 @@ const formatQuote = () => {
177
171
  <DropDown
178
172
  disabled={disabled}
179
173
  buttonClassName="toolbar-item block-controls"
180
- buttonIconClassName={"icon block-type " + blockType}
174
+ buttonIconClassName={'icon block-type ' + blockType}
181
175
  buttonLabel={blockTypeToBlockName[blockType]}
182
176
  buttonAriaLabel="Formatting options for text style"
183
177
  >
184
178
  <DropDownItem
185
- className={"item " + dropDownActiveClass(blockType === "paragraph")}
179
+ className={'item ' + dropDownActiveClass(blockType === 'paragraph')}
186
180
  onClick={formatParagraph}
187
181
  >
188
182
  <i className="icon paragraph" />
189
183
  <span className="text">Normal</span>
190
184
  </DropDownItem>
191
185
  <DropDownItem
192
- className={"item " + dropDownActiveClass(blockType === "h1")}
193
- onClick={() => formatHeading("h1")}
186
+ className={'item ' + dropDownActiveClass(blockType === 'h1')}
187
+ onClick={() => formatHeading('h1')}
194
188
  >
195
189
  <i className="icon h1" />
196
190
  <span className="text">Heading 1</span>
197
191
  </DropDownItem>
198
192
  <DropDownItem
199
- className={"item " + dropDownActiveClass(blockType === "h2")}
200
- onClick={() => formatHeading("h2")}
193
+ className={'item ' + dropDownActiveClass(blockType === 'h2')}
194
+ onClick={() => formatHeading('h2')}
201
195
  >
202
196
  <i className="icon h2" />
203
197
  <span className="text">Heading 2</span>
204
198
  </DropDownItem>
205
199
  <DropDownItem
206
- className={"item " + dropDownActiveClass(blockType === "h3")}
207
- onClick={() => formatHeading("h3")}
200
+ className={'item ' + dropDownActiveClass(blockType === 'h3')}
201
+ onClick={() => formatHeading('h3')}
208
202
  >
209
203
  <i className="icon h3" />
210
204
  <span className="text">Heading 3</span>
211
205
  </DropDownItem>
212
206
  <DropDownItem
213
- className={"item " + dropDownActiveClass(blockType === "h4")}
214
- onClick={() => formatHeading("h4")}
207
+ className={'item ' + dropDownActiveClass(blockType === 'h4')}
208
+ onClick={() => formatHeading('h4')}
215
209
  >
216
210
  <i className="icon h4" />
217
211
  <span className="text">Heading 4</span>
218
212
  </DropDownItem>
219
213
  <DropDownItem
220
- className={"item " + dropDownActiveClass(blockType === "bullet")}
214
+ className={'item ' + dropDownActiveClass(blockType === 'bullet')}
221
215
  onClick={formatBulletList}
222
216
  >
223
217
  <i className="icon bullet-list" />
224
218
  <span className="text">Bullet List</span>
225
219
  </DropDownItem>
226
220
  <DropDownItem
227
- className={"item " + dropDownActiveClass(blockType === "number")}
221
+ className={'item ' + dropDownActiveClass(blockType === 'number')}
228
222
  onClick={formatNumberedList}
229
223
  >
230
224
  <i className="icon numbered-list" />
231
225
  <span className="text">Numbered List</span>
232
226
  </DropDownItem>
233
227
  <DropDownItem
234
- className={"item " + dropDownActiveClass(blockType === "quote")}
228
+ className={'item ' + dropDownActiveClass(blockType === 'quote')}
235
229
  onClick={formatQuote}
236
230
  >
237
231
  <i className="icon quote" />
@@ -239,7 +233,8 @@ const formatQuote = () => {
239
233
  </DropDownItem>
240
234
  <DropDownItem
241
235
  className={'item ' + dropDownActiveClass(blockType === 'code')}
242
- onClick={formatCode}>
236
+ onClick={formatCode}
237
+ >
243
238
  <i className="icon code" />
244
239
  <span className="text">Code Block</span>
245
240
  </DropDownItem>
@@ -253,23 +248,22 @@ function Divider(): JSX.Element {
253
248
 
254
249
  export default function ToolbarPlugin({
255
250
  setIsLinkEditMode,
256
- }: {
251
+ toolbarButtons = [],
252
+ }: Readonly<{
257
253
  setIsLinkEditMode: Dispatch<boolean>;
258
- }): JSX.Element {
254
+ toolbarButtons?: ScriboToolbarButton[];
255
+ }>): JSX.Element {
259
256
  const [editor] = useLexicalComposerContext();
260
257
  const [activeEditor, setActiveEditor] = useState(editor);
261
- const [blockType, setBlockType] =
262
- useState<keyof typeof blockTypeToBlockName>("paragraph");
263
- const [selectedElementKey, setSelectedElementKey] = useState<NodeKey | null>(
264
- null,
265
- );
266
- const [isCode, setIsCode] = useState(false);
258
+ const [blockType, setBlockType] = useState<keyof typeof blockTypeToBlockName>('paragraph');
259
+ const [selectedElementKey, setSelectedElementKey] = useState<NodeKey | null>(null);
260
+ const [_isCode, setIsCode] = useState(false);
267
261
  const [isLink, setIsLink] = useState(false);
268
262
  const [isBold, setIsBold] = useState(false);
269
263
  const [isItalic, setIsItalic] = useState(false);
270
264
  const [canUndo, setCanUndo] = useState(false);
271
265
  const [canRedo, setCanRedo] = useState(false);
272
- const [codeLanguage, setCodeLanguage] = useState<string>("");
266
+ const [codeLanguage, setCodeLanguage] = useState<string>('');
273
267
  const [isEditable, setIsEditable] = useState(() => editor.isEditable());
274
268
 
275
269
  const $updateToolbar = useCallback(() => {
@@ -277,7 +271,7 @@ export default function ToolbarPlugin({
277
271
  if ($isRangeSelection(selection)) {
278
272
  const anchorNode = selection.anchor.getNode();
279
273
  let element =
280
- anchorNode.getKey() === "root"
274
+ anchorNode.getKey() === 'root'
281
275
  ? anchorNode
282
276
  : $findMatchingParent(anchorNode, (e) => {
283
277
  const parent = e.getParent();
@@ -292,9 +286,9 @@ export default function ToolbarPlugin({
292
286
  const elementDOM = activeEditor.getElementByKey(elementKey);
293
287
 
294
288
  // Update text format
295
- setIsCode(selection.hasFormat("code"));
296
- setIsBold(selection.hasFormat("bold"));
297
- setIsItalic(selection.hasFormat("italic"));
289
+ setIsCode(selection.hasFormat('code'));
290
+ setIsBold(selection.hasFormat('bold'));
291
+ setIsItalic(selection.hasFormat('italic'));
298
292
 
299
293
  // Update links
300
294
  const node = getSelectedNode(selection);
@@ -308,27 +302,17 @@ export default function ToolbarPlugin({
308
302
  if (elementDOM !== null) {
309
303
  setSelectedElementKey(elementKey);
310
304
  if ($isListNode(element)) {
311
- const parentList = $getNearestNodeOfType<ListNode>(
312
- anchorNode,
313
- ListNode,
314
- );
315
- const type = parentList
316
- ? parentList.getListType()
317
- : element.getListType();
305
+ const parentList = $getNearestNodeOfType<ListNode>(anchorNode, ListNode);
306
+ const type = parentList ? parentList.getListType() : element.getListType();
318
307
  setBlockType(type);
319
308
  } else {
320
- const type = $isHeadingNode(element)
321
- ? element.getTag()
322
- : element.getType();
309
+ const type = $isHeadingNode(element) ? element.getTag() : element.getType();
323
310
  if (type in blockTypeToBlockName) {
324
311
  setBlockType(type as keyof typeof blockTypeToBlockName);
325
312
  }
326
313
  if ($isCodeNode(element)) {
327
- const language =
328
- element.getLanguage() as keyof typeof CODE_LANGUAGE_MAP;
329
- setCodeLanguage(
330
- language ? CODE_LANGUAGE_MAP[language] || language : '',
331
- );
314
+ const language = element.getLanguage() as keyof typeof CODE_LANGUAGE_MAP;
315
+ setCodeLanguage(language ? CODE_LANGUAGE_MAP[language] || language : '');
332
316
  return;
333
317
  }
334
318
  }
@@ -344,7 +328,7 @@ export default function ToolbarPlugin({
344
328
  setActiveEditor(newEditor);
345
329
  return false;
346
330
  },
347
- COMMAND_PRIORITY_CRITICAL,
331
+ COMMAND_PRIORITY_CRITICAL
348
332
  );
349
333
  }, [editor, $updateToolbar]);
350
334
 
@@ -364,7 +348,7 @@ export default function ToolbarPlugin({
364
348
  setCanUndo(payload);
365
349
  return false;
366
350
  },
367
- COMMAND_PRIORITY_CRITICAL,
351
+ COMMAND_PRIORITY_CRITICAL
368
352
  ),
369
353
  activeEditor.registerCommand<boolean>(
370
354
  CAN_REDO_COMMAND,
@@ -372,8 +356,8 @@ export default function ToolbarPlugin({
372
356
  setCanRedo(payload);
373
357
  return false;
374
358
  },
375
- COMMAND_PRIORITY_CRITICAL,
376
- ),
359
+ COMMAND_PRIORITY_CRITICAL
360
+ )
377
361
  );
378
362
  }, [$updateToolbar, activeEditor, editor]);
379
363
 
@@ -384,27 +368,24 @@ export default function ToolbarPlugin({
384
368
  const event: KeyboardEvent = payload;
385
369
  const { code, ctrlKey, metaKey } = event;
386
370
 
387
- if (code === "KeyK" && (ctrlKey || metaKey)) {
371
+ if (code === 'KeyK' && (ctrlKey || metaKey)) {
388
372
  event.preventDefault();
389
373
  if (!isLink) {
390
374
  setIsLinkEditMode(true);
391
375
  } else {
392
376
  setIsLinkEditMode(false);
393
377
  }
394
- return activeEditor.dispatchCommand(
395
- TOGGLE_LINK_COMMAND,
396
- sanitizeUrl("https://"),
397
- );
378
+ return activeEditor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl('https://'));
398
379
  }
399
380
  return false;
400
381
  },
401
- COMMAND_PRIORITY_NORMAL,
382
+ COMMAND_PRIORITY_NORMAL
402
383
  );
403
384
  }, [activeEditor, isLink, setIsLinkEditMode]);
404
385
 
405
386
  const insertLink = useCallback(() => {
406
387
  if (!isLink) {
407
- editor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl("https://"));
388
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl('https://'));
408
389
  } else {
409
390
  editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
410
391
  }
@@ -421,7 +402,7 @@ export default function ToolbarPlugin({
421
402
  }
422
403
  });
423
404
  },
424
- [activeEditor, selectedElementKey],
405
+ [activeEditor, selectedElementKey]
425
406
  );
426
407
  return (
427
408
  <div className="toolbar">
@@ -430,7 +411,7 @@ export default function ToolbarPlugin({
430
411
  onClick={() => {
431
412
  activeEditor.dispatchCommand(UNDO_COMMAND, undefined);
432
413
  }}
433
- title={IS_APPLE ? "Undo (⌘Z)" : "Undo (Ctrl+Z)"}
414
+ title={IS_APPLE ? 'Undo (⌘Z)' : 'Undo (Ctrl+Z)'}
434
415
  type="button"
435
416
  className="toolbar-item spaced"
436
417
  aria-label="Undo"
@@ -442,7 +423,7 @@ export default function ToolbarPlugin({
442
423
  onClick={() => {
443
424
  activeEditor.dispatchCommand(REDO_COMMAND, undefined);
444
425
  }}
445
- title={IS_APPLE ? "Redo (⌘Y)" : "Redo (Ctrl+Y)"}
426
+ title={IS_APPLE ? 'Redo (⌘Y)' : 'Redo (Ctrl+Y)'}
446
427
  type="button"
447
428
  className="toolbar-item"
448
429
  aria-label="Redo"
@@ -452,15 +433,11 @@ export default function ToolbarPlugin({
452
433
  <Divider />
453
434
  {blockType in blockTypeToBlockName && activeEditor === editor && (
454
435
  <>
455
- <BlockFormatDropDown
456
- disabled={!isEditable}
457
- blockType={blockType}
458
- editor={editor}
459
- />
436
+ <BlockFormatDropDown disabled={!isEditable} blockType={blockType} editor={editor} />
460
437
  <Divider />
461
438
  </>
462
439
  )}
463
- {blockType === "code" ? (
440
+ {blockType === 'code' ? (
464
441
  <DropDown
465
442
  disabled={!isEditable}
466
443
  buttonClassName="toolbar-item code-language"
@@ -470,9 +447,7 @@ export default function ToolbarPlugin({
470
447
  {CODE_LANGUAGE_OPTIONS.map(([value, name]) => {
471
448
  return (
472
449
  <DropDownItem
473
- className={`item ${dropDownActiveClass(
474
- value === codeLanguage,
475
- )}`}
450
+ className={`item ${dropDownActiveClass(value === codeLanguage)}`}
476
451
  onClick={() => onCodeLanguageSelect(value)}
477
452
  key={value}
478
453
  >
@@ -486,35 +461,31 @@ export default function ToolbarPlugin({
486
461
  <button
487
462
  disabled={!isEditable}
488
463
  onClick={() => {
489
- activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND, "bold");
464
+ activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold');
490
465
  }}
491
- className={"toolbar-item spaced " + (isBold ? "active" : "")}
492
- title={IS_APPLE ? "Bold (⌘B)" : "Bold (Ctrl+B)"}
466
+ className={'toolbar-item spaced ' + (isBold ? 'active' : '')}
467
+ title={IS_APPLE ? 'Bold (⌘B)' : 'Bold (Ctrl+B)'}
493
468
  type="button"
494
- aria-label={`Format text as bold. Shortcut: ${
495
- IS_APPLE ? "⌘B" : "Ctrl+B"
496
- }`}
469
+ aria-label={`Format text as bold. Shortcut: ${IS_APPLE ? '⌘B' : 'Ctrl+B'}`}
497
470
  >
498
471
  <i className="format bold" />
499
472
  </button>
500
473
  <button
501
474
  disabled={!isEditable}
502
475
  onClick={() => {
503
- activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND, "italic");
476
+ activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic');
504
477
  }}
505
- className={"toolbar-item spaced " + (isItalic ? "active" : "")}
506
- title={IS_APPLE ? "Italic (⌘I)" : "Italic (Ctrl+I)"}
478
+ className={'toolbar-item spaced ' + (isItalic ? 'active' : '')}
479
+ title={IS_APPLE ? 'Italic (⌘I)' : 'Italic (Ctrl+I)'}
507
480
  type="button"
508
- aria-label={`Format text as italics. Shortcut: ${
509
- IS_APPLE ? "⌘I" : "Ctrl+I"
510
- }`}
481
+ aria-label={`Format text as italics. Shortcut: ${IS_APPLE ? '⌘I' : 'Ctrl+I'}`}
511
482
  >
512
483
  <i className="format italic" />
513
484
  </button>
514
485
  <button
515
486
  disabled={!isEditable}
516
487
  onClick={insertLink}
517
- className={"toolbar-item spaced " + (isLink ? "active" : "")}
488
+ className={'toolbar-item spaced ' + (isLink ? 'active' : '')}
518
489
  aria-label="Insert link"
519
490
  title="Insert link"
520
491
  type="button"
@@ -523,6 +494,23 @@ export default function ToolbarPlugin({
523
494
  </button>
524
495
  </>
525
496
  )}
497
+ {toolbarButtons.length > 0 && (
498
+ <>
499
+ <Divider />
500
+ {toolbarButtons.map((btn) => (
501
+ <button
502
+ type="button"
503
+ key={btn.key}
504
+ onClick={() => btn.onSelect(activeEditor)}
505
+ className="toolbar-item"
506
+ title={btn.label}
507
+ aria-label={btn.label}
508
+ >
509
+ <i className={`icon ${btn.iconClass ?? 'bullet-list'}`} />
510
+ </button>
511
+ ))}
512
+ </>
513
+ )}
526
514
  </div>
527
515
  );
528
516
  }
@@ -41,7 +41,8 @@
41
41
  margin: 0;
42
42
  }
43
43
 
44
- [data-theme="dark"] .EditorTheme__h1 {
44
+ [data-theme="dark"] .EditorTheme__h1,
45
+ [data-color-scheme="dark"] .EditorTheme__h1 {
45
46
  color: #ffffff;
46
47
  }
47
48
 
@@ -54,7 +55,8 @@
54
55
  margin: 0;
55
56
  }
56
57
 
57
- [data-theme="dark"] .EditorTheme__h2 {
58
+ [data-theme="dark"] .EditorTheme__h2,
59
+ [data-color-scheme="dark"] .EditorTheme__h2 {
58
60
  color: #ffffff;
59
61
  }
60
62
 
@@ -67,7 +69,8 @@
67
69
  margin: 0;
68
70
  }
69
71
 
70
- [data-theme="dark"] .EditorTheme__h3 {
72
+ [data-theme="dark"] .EditorTheme__h3,
73
+ [data-color-scheme="dark"] .EditorTheme__h3 {
71
74
  color: #ffffff;
72
75
  }
73
76
 
@@ -80,7 +83,8 @@
80
83
  margin: 0;
81
84
  }
82
85
 
83
- [data-theme="dark"] .EditorTheme__h4 {
86
+ [data-theme="dark"] .EditorTheme__h4,
87
+ [data-color-scheme="dark"] .EditorTheme__h4 {
84
88
  color: #ffffff;
85
89
  }
86
90
 
@@ -163,7 +167,7 @@
163
167
  top: 0;
164
168
  border-right: 1px solid #ccc;
165
169
  padding: 8px;
166
- color: #777;
170
+ color: #696969;
167
171
  white-space: pre-wrap;
168
172
  text-align: right;
169
173
  min-width: 25px;