@blocknote/core 0.32.0-hackdays.0 → 0.32.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 (85) hide show
  1. package/dist/blocknote.cjs +9 -9
  2. package/dist/blocknote.cjs.map +1 -1
  3. package/dist/blocknote.js +2122 -1918
  4. package/dist/blocknote.js.map +1 -1
  5. package/dist/en-CsgPjHa4.cjs +2 -0
  6. package/dist/en-CsgPjHa4.cjs.map +1 -0
  7. package/dist/{en-qGo6sk9V.js → en-Dx9fwHD4.js} +47 -1
  8. package/dist/en-Dx9fwHD4.js.map +1 -0
  9. package/dist/locales.cjs +1 -1
  10. package/dist/locales.cjs.map +1 -1
  11. package/dist/locales.js +1453 -30
  12. package/dist/locales.js.map +1 -1
  13. package/dist/style.css +1 -1
  14. package/dist/tsconfig.tsbuildinfo +1 -0
  15. package/dist/webpack-stats.json +1 -1
  16. package/package.json +1 -1
  17. package/src/api/blockManipulation/commands/insertBlocks/__snapshots__/insertBlocks.test.ts.snap +18 -0
  18. package/src/api/blockManipulation/commands/mergeBlocks/__snapshots__/mergeBlocks.test.ts.snap +10 -0
  19. package/src/api/blockManipulation/commands/moveBlocks/__snapshots__/moveBlocks.test.ts.snap +40 -0
  20. package/src/api/blockManipulation/commands/replaceBlocks/__snapshots__/replaceBlocks.test.ts.snap +23 -0
  21. package/src/api/blockManipulation/commands/splitBlock/__snapshots__/splitBlock.test.ts.snap +13 -0
  22. package/src/api/blockManipulation/commands/updateBlock/__snapshots__/updateBlock.test.ts.snap +50 -0
  23. package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +72 -74
  24. package/src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.ts +1 -0
  25. package/src/blocks/ListItemBlockContent/ToggleListItemBlockContent/ToggleListItemBlockContent.ts +104 -0
  26. package/src/blocks/ToggleWrapper/createToggleWrapper.ts +182 -0
  27. package/src/blocks/defaultBlockTypeGuards.ts +6 -2
  28. package/src/blocks/defaultBlocks.ts +2 -0
  29. package/src/editor/Block.css +112 -25
  30. package/src/editor/BlockNoteEditor.test.ts +1 -0
  31. package/src/editor/BlockNoteEditor.ts +18 -0
  32. package/src/editor/BlockNoteExtensions.ts +1 -1
  33. package/src/editor/BlockNoteTipTapEditor.ts +1 -0
  34. package/src/editor/editor.css +3 -0
  35. package/src/extensions/Collaboration/ForkYDocPlugin.ts +26 -8
  36. package/src/extensions/Collaboration/UndoPlugin.ts +3 -2
  37. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +4 -1
  38. package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +16 -4
  39. package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +12 -22
  40. package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +64 -0
  41. package/src/i18n/locales/ar.ts +46 -0
  42. package/src/i18n/locales/de.ts +65 -0
  43. package/src/i18n/locales/en.ts +46 -0
  44. package/src/i18n/locales/es.ts +46 -0
  45. package/src/i18n/locales/fr.ts +68 -0
  46. package/src/i18n/locales/he.ts +402 -0
  47. package/src/i18n/locales/hr.ts +46 -0
  48. package/src/i18n/locales/index.ts +1 -0
  49. package/src/i18n/locales/is.ts +67 -0
  50. package/src/i18n/locales/it.ts +67 -0
  51. package/src/i18n/locales/ja.ts +66 -0
  52. package/src/i18n/locales/ko.ts +46 -0
  53. package/src/i18n/locales/nl.ts +47 -0
  54. package/src/i18n/locales/no.ts +64 -0
  55. package/src/i18n/locales/pl.ts +52 -0
  56. package/src/i18n/locales/pt.ts +46 -0
  57. package/src/i18n/locales/ru.ts +62 -0
  58. package/src/i18n/locales/sk.ts +46 -0
  59. package/src/i18n/locales/uk.ts +46 -0
  60. package/src/i18n/locales/vi.ts +46 -0
  61. package/src/i18n/locales/zh-tw.ts +54 -0
  62. package/src/i18n/locales/zh.ts +54 -0
  63. package/src/index.ts +1 -0
  64. package/src/schema/blocks/createSpec.ts +3 -1
  65. package/types/src/api/blockManipulation/setupTestEnv.d.ts +42 -2
  66. package/types/src/blocks/HeadingBlockContent/HeadingBlockContent.d.ts +12 -3
  67. package/types/src/blocks/ListItemBlockContent/ToggleListItemBlockContent/ToggleListItemBlockContent.d.ts +46 -0
  68. package/types/src/blocks/ToggleWrapper/createToggleWrapper.d.ts +15 -0
  69. package/types/src/blocks/defaultBlockTypeGuards.d.ts +2 -2
  70. package/types/src/blocks/defaultBlocks.d.ts +84 -4
  71. package/types/src/editor/BlockNoteEditor.d.ts +14 -0
  72. package/types/src/extensions/Collaboration/UndoPlugin.d.ts +4 -1
  73. package/types/src/i18n/locales/en.d.ts +45 -0
  74. package/types/src/i18n/locales/he.d.ts +2 -0
  75. package/types/src/i18n/locales/index.d.ts +1 -0
  76. package/types/src/i18n/locales/sk.d.ts +45 -0
  77. package/types/src/index.d.ts +1 -0
  78. package/types/src/schema/blocks/createSpec.d.ts +2 -1
  79. package/dist/en-BXVKCwYt.cjs +0 -2
  80. package/dist/en-BXVKCwYt.cjs.map +0 -1
  81. package/dist/en-qGo6sk9V.js.map +0 -1
  82. package/types/src/api/blockManipulation/selections/selection.test.d.ts +0 -1
  83. package/types/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.d.ts +0 -5
  84. package/types/src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.test.d.ts +0 -1
  85. package/types/src/extensions/Collaboration/createCollaborationExtensions.d.ts +0 -17
@@ -15,26 +15,9 @@ BASIC STYLES
15
15
 
16
16
  .bn-block-content {
17
17
  padding: 3px 0;
18
+ display: flex;
18
19
  transition: font-size 0.2s;
19
20
  width: 100%;
20
- /*
21
- because the content elements are display: block
22
- we use flex to position them next to list markers
23
- */
24
- }
25
-
26
- /* We can't set `display: flex` on `.bn-block-content` while it has inline
27
- content (see #1629). However, it's necessary to set alignment of blocks
28
- without content as these can't use `text-align`, so this additional rule is
29
- used. */
30
- .bn-block-content:not(:has(.bn-inline-content)) {
31
- display: flex;
32
- }
33
-
34
- .bn-block-content::before {
35
- /* content: ""; */
36
- transition: all 0.2s;
37
- /*margin: 0px;*/
38
21
  }
39
22
 
40
23
  .bn-block-content.ProseMirror-selectednode > *,
@@ -44,6 +27,19 @@ used. */
44
27
  outline: 4px solid rgb(100, 160, 255);
45
28
  }
46
29
 
30
+ .bn-block-content::before {
31
+ content: "";
32
+ margin-right: 0;
33
+ transition: all 0.2s;
34
+ /* Workaround for selection issue on Chrome, see #1588 and also here:
35
+ https://discuss.prosemirror.net/t/mouse-down-selection-behaviour-different-on-chrome/8426
36
+ The :before element causes the selection to be set in the wrong place vs
37
+ other browsers. Setting no height fixes this, while list item indicators are
38
+ still displayed fine as overflow is not hidden. */
39
+ height: 0;
40
+ overflow: visible;
41
+ }
42
+
47
43
  .bn-inline-content {
48
44
  width: 100%;
49
45
  }
@@ -53,7 +49,7 @@ NESTED BLOCKS
53
49
  */
54
50
 
55
51
  .bn-block-group .bn-block-group {
56
- margin-left: 1.5em;
52
+ margin-left: 24px;
57
53
  }
58
54
 
59
55
  .bn-block-group .bn-block-group > .bn-block-outer {
@@ -134,6 +130,15 @@ NESTED BLOCKS
134
130
  [data-content-type="heading"][data-level="3"] {
135
131
  --level: 1.3em;
136
132
  }
133
+ [data-content-type="heading"][data-level="4"] {
134
+ --level: 1em;
135
+ }
136
+ [data-content-type="heading"][data-level="5"] {
137
+ --level: 0.9em;
138
+ }
139
+ [data-content-type="heading"][data-level="6"] {
140
+ --level: 0.8em;
141
+ }
137
142
 
138
143
  [data-prev-level="1"] {
139
144
  --prev-level: 3em;
@@ -144,6 +149,15 @@ NESTED BLOCKS
144
149
  [data-prev-level="3"] {
145
150
  --prev-level: 1.3em;
146
151
  }
152
+ [data-prev-level="4"] {
153
+ --prev-level: 1em;
154
+ }
155
+ [data-prev-level="5"] {
156
+ --prev-level: 0.9em;
157
+ }
158
+ [data-prev-level="6"] {
159
+ --prev-level: 0.8em;
160
+ }
147
161
 
148
162
  .bn-block-outer[data-prev-type="heading"] > .bn-block > .bn-block-content {
149
163
  font-size: var(--prev-level);
@@ -175,13 +189,14 @@ NESTED BLOCKS
175
189
  .bn-block-content::before {
176
190
  margin-right: 0;
177
191
  content: "";
178
- display: inline;
179
192
  }
180
193
 
181
194
  /* Ordered */
182
- .bn-block-content[data-content-type="numberedListItem"] {
195
+ .bn-block-content[data-content-type="numberedListItem"]::before {
183
196
  display: flex;
184
- gap: 0.5em;
197
+ justify-content: center;
198
+ min-width: 24px;
199
+ padding-right: 4px;
185
200
  }
186
201
 
187
202
  [data-content-type="numberedListItem"] {
@@ -209,9 +224,11 @@ NESTED BLOCKS
209
224
  }
210
225
 
211
226
  /* Unordered */
212
- .bn-block-content[data-content-type="bulletListItem"] {
227
+ .bn-block-content[data-content-type="bulletListItem"]::before {
213
228
  display: flex;
214
- gap: 0.5em;
229
+ justify-content: center;
230
+ min-width: 24px;
231
+ padding-right: 4px;
215
232
  }
216
233
 
217
234
  /* Checked */
@@ -220,9 +237,15 @@ NESTED BLOCKS
220
237
  width: 100%;
221
238
  }
222
239
 
240
+ .bn-block-content[data-content-type="checkListItem"] > div > div {
241
+ display: flex;
242
+ justify-content: center;
243
+ min-width: 24px;
244
+ padding-right: 4px;
245
+ }
246
+
223
247
  .bn-block-content[data-content-type="checkListItem"] > div > div > input {
224
248
  margin: 0;
225
- margin-inline-end: 0.5em;
226
249
  cursor: pointer;
227
250
  }
228
251
 
@@ -239,6 +262,70 @@ NESTED BLOCKS
239
262
  justify-content: flex-end;
240
263
  }
241
264
 
265
+ /* Toggle */
266
+ .bn-block-content:has(.bn-toggle-wrapper) > div {
267
+ display: flex;
268
+ flex-direction: column;
269
+ gap: 4px;
270
+ }
271
+
272
+ .bn-block:has(
273
+ > .bn-block-content > div > .bn-toggle-wrapper[data-show-children="false"]
274
+ )
275
+ > .bn-block-group,
276
+ .bn-block:has(
277
+ > .react-renderer
278
+ > .bn-block-content
279
+ > div
280
+ > .bn-toggle-wrapper[data-show-children="false"]
281
+ )
282
+ > .bn-block-group {
283
+ display: none;
284
+ }
285
+
286
+ .bn-toggle-wrapper {
287
+ display: flex;
288
+ align-items: center;
289
+ }
290
+
291
+ .bn-toggle-button {
292
+ color: var(--bn-colors-editor-text);
293
+ padding: 3px;
294
+ }
295
+
296
+ .bn-toggle-button > svg {
297
+ width: 18px;
298
+ height: 18px;
299
+ }
300
+
301
+ .bn-toggle-wrapper[data-show-children="true"] .bn-toggle-button {
302
+ transform: rotate(90deg);
303
+ }
304
+
305
+ .bn-toggle-add-block-button {
306
+ font-size: 16px;
307
+ color: var(--bn-colors-side-menu);
308
+ font-weight: normal;
309
+ margin-left: 22px;
310
+ padding-inline: 2px;
311
+ width: fit-content;
312
+ }
313
+
314
+ .bn-toggle-button,
315
+ .bn-toggle-add-block-button {
316
+ background: none;
317
+ border: none;
318
+ border-radius: var(--bn-border-radius-small);
319
+ cursor: pointer;
320
+ display: flex;
321
+ user-select: none;
322
+ }
323
+
324
+ .bn-toggle-button:hover,
325
+ .bn-toggle-add-block-button:hover {
326
+ background-color: var(--bn-colors-hovered-background);
327
+ }
328
+
242
329
  /* No list nesting */
243
330
  .bn-block-outer[data-prev-type="bulletListItem"]
244
331
  > .bn-block
@@ -52,6 +52,7 @@ it("immediately replaces doc", async () => {
52
52
  "id": "2",
53
53
  "props": {
54
54
  "backgroundColor": "default",
55
+ "isToggleable": false,
55
56
  "level": 1,
56
57
  "textAlignment": "left",
57
58
  "textColor": "default",
@@ -229,6 +229,18 @@ export type BlockNoteEditorOptions<
229
229
  class?: string;
230
230
  }) => Plugin;
231
231
 
232
+ /**
233
+ * Configuration for headings
234
+ */
235
+ heading?: {
236
+ /**
237
+ * The levels of headings that should be available in the editor.
238
+ * @note Configurable up to 6 levels of headings.
239
+ * @default [1, 2, 3]
240
+ */
241
+ levels?: (1 | 2 | 3 | 4 | 5 | 6)[];
242
+ };
243
+
232
244
  /**
233
245
  * The content that should be in the editor when it's created, represented as an array of partial block objects.
234
246
  */
@@ -527,6 +539,9 @@ export class BlockNoteEditor<
527
539
  headers: boolean;
528
540
  };
529
541
  codeBlock: CodeBlockOptions;
542
+ heading: {
543
+ levels: (1 | 2 | 3 | 4 | 5 | 6)[];
544
+ };
530
545
  };
531
546
 
532
547
  public static create<
@@ -580,6 +595,9 @@ export class BlockNoteEditor<
580
595
  supportedLanguages: options?.codeBlock?.supportedLanguages ?? {},
581
596
  createHighlighter: options?.codeBlock?.createHighlighter ?? undefined,
582
597
  },
598
+ heading: {
599
+ levels: options?.heading?.levels ?? [1, 2, 3],
600
+ },
583
601
  };
584
602
 
585
603
  // apply defaults
@@ -116,7 +116,7 @@ export const getBlockNoteExtensions = <
116
116
 
117
117
  if (opts.collaboration) {
118
118
  ret["ySyncPlugin"] = new SyncPlugin(opts.collaboration.fragment);
119
- ret["yUndoPlugin"] = new UndoPlugin();
119
+ ret["yUndoPlugin"] = new UndoPlugin({ editor: opts.editor });
120
120
 
121
121
  if (opts.collaboration.provider?.awareness) {
122
122
  ret["yCursorPlugin"] = new CursorPlugin(opts.collaboration);
@@ -302,6 +302,7 @@ export class BlockNoteTipTapEditor extends TiptapEditor {
302
302
  ) => {
303
303
  if (!element) {
304
304
  this.destroy();
305
+ this.isInitialized = false;
305
306
  } else {
306
307
  this.options.element = element;
307
308
  this.createViewAlternative(blockNoteEditor, contentComponent);
@@ -44,6 +44,9 @@ Tippy popups that are appended to document.body directly
44
44
  .bn-default-styles h1,
45
45
  .bn-default-styles h2,
46
46
  .bn-default-styles h3,
47
+ .bn-default-styles h4,
48
+ .bn-default-styles h5,
49
+ .bn-default-styles h6,
47
50
  .bn-default-styles li {
48
51
  margin: 0;
49
52
  padding: 0;
@@ -86,6 +86,7 @@ export class ForkYDocPlugin extends BlockNoteExtension<{
86
86
  private forkedState:
87
87
  | {
88
88
  originalFragment: Y.XmlFragment;
89
+ undoStack: Y.UndoManager["undoStack"];
89
90
  forkedFragment: Y.XmlFragment;
90
91
  }
91
92
  | undefined;
@@ -114,6 +115,8 @@ export class ForkYDocPlugin extends BlockNoteExtension<{
114
115
  const forkedFragment = this.findTypeInOtherYdoc(originalFragment, doc);
115
116
 
116
117
  this.forkedState = {
118
+ undoStack: yUndoPluginKey.getState(this.editor.prosemirrorState)!
119
+ .undoManager.undoStack,
117
120
  originalFragment,
118
121
  forkedFragment,
119
122
  };
@@ -128,7 +131,9 @@ export class ForkYDocPlugin extends BlockNoteExtension<{
128
131
  this.editor._tiptapEditor.registerPlugin(
129
132
  new SyncPlugin(forkedFragment).plugins[0],
130
133
  );
131
- this.editor._tiptapEditor.registerPlugin(new UndoPlugin().plugins[0]);
134
+ this.editor._tiptapEditor.registerPlugin(
135
+ new UndoPlugin({ editor: this.editor }).plugins[0],
136
+ );
132
137
  // No need to register the cursor plugin again, it's a local fork
133
138
  this.emit("forked", true);
134
139
  }
@@ -146,17 +151,15 @@ export class ForkYDocPlugin extends BlockNoteExtension<{
146
151
  this.editor._tiptapEditor.unregisterPlugin(ySyncPluginKey);
147
152
  this.editor._tiptapEditor.unregisterPlugin(yUndoPluginKey);
148
153
 
149
- const { originalFragment, forkedFragment } = this.forkedState;
150
- if (keepChanges) {
151
- // Apply any changes that have been made to the fork, onto the original doc
152
- const update = Y.encodeStateAsUpdate(forkedFragment.doc!);
153
- Y.applyUpdate(originalFragment.doc!, update);
154
- }
154
+ const { originalFragment, forkedFragment, undoStack } = this.forkedState;
155
155
  this.editor.extensions["ySyncPlugin"] = new SyncPlugin(originalFragment);
156
156
  this.editor.extensions["yCursorPlugin"] = new CursorPlugin(
157
157
  this.collaboration!,
158
158
  );
159
- this.editor.extensions["yUndoPlugin"] = new UndoPlugin();
159
+ this.editor.extensions["yUndoPlugin"] = new UndoPlugin({
160
+ editor: this.editor,
161
+ });
162
+
160
163
  // Register the plugins again, based on the original fragment
161
164
  this.editor._tiptapEditor.registerPlugin(
162
165
  this.editor.extensions["ySyncPlugin"].plugins[0],
@@ -167,6 +170,21 @@ export class ForkYDocPlugin extends BlockNoteExtension<{
167
170
  this.editor._tiptapEditor.registerPlugin(
168
171
  this.editor.extensions["yUndoPlugin"].plugins[0],
169
172
  );
173
+
174
+ // Reset the undo stack to the original undo stack
175
+ yUndoPluginKey.getState(
176
+ this.editor.prosemirrorState,
177
+ )!.undoManager.undoStack = undoStack;
178
+
179
+ if (keepChanges) {
180
+ // Apply any changes that have been made to the fork, onto the original doc
181
+ const update = Y.encodeStateAsUpdate(
182
+ forkedFragment.doc!,
183
+ Y.encodeStateVector(originalFragment.doc!),
184
+ );
185
+ // Applying this change will add to the undo stack, allowing it to be undone normally
186
+ Y.applyUpdate(originalFragment.doc!, update, this.editor);
187
+ }
170
188
  // Reset the forked state
171
189
  this.forkedState = undefined;
172
190
  this.emit("forked", false);
@@ -1,4 +1,5 @@
1
1
  import { yUndoPlugin } from "y-prosemirror";
2
+ import { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
2
3
  import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
3
4
 
4
5
  export class UndoPlugin extends BlockNoteExtension {
@@ -6,9 +7,9 @@ export class UndoPlugin extends BlockNoteExtension {
6
7
  return "yUndoPlugin";
7
8
  }
8
9
 
9
- constructor() {
10
+ constructor({ editor }: { editor: BlockNoteEditor<any, any, any> }) {
10
11
  super();
11
- this.addProsemirrorPlugin(yUndoPlugin());
12
+ this.addProsemirrorPlugin(yUndoPlugin({ trackedOrigins: [editor] }));
12
13
  }
13
14
 
14
15
  public get priority() {
@@ -130,7 +130,10 @@ export class FormattingToolbarView implements PluginView {
130
130
  };
131
131
 
132
132
  viewMousedownHandler = (e: MouseEvent) => {
133
- if (!this.isElementWithinEditorWrapper(e.target as Node)) {
133
+ if (
134
+ !this.isElementWithinEditorWrapper(e.target as Node) ||
135
+ e.button === 0
136
+ ) {
134
137
  this.preventShow = true;
135
138
  }
136
139
  };
@@ -434,7 +434,7 @@ export const KeyboardShortcutsExtension = Extension.create<{
434
434
  ]);
435
435
 
436
436
  const handleEnter = (withShift = false) => {
437
- return this.editor.commands.first(({ commands }) => [
437
+ return this.editor.commands.first(({ commands, tr }) => [
438
438
  // Removes a level of nesting if the block is empty & indented, while the selection is also empty & at the start
439
439
  // of the block.
440
440
  () =>
@@ -486,9 +486,21 @@ export const KeyboardShortcutsExtension = Extension.create<{
486
486
  // both enter and shift+enter.
487
487
  blockHardBreakShortcut === "enter"
488
488
  ) {
489
- return commands.insertContent({
490
- type: "hardBreak",
491
- });
489
+ const marks =
490
+ tr.storedMarks ||
491
+ tr.selection.$head
492
+ .marks()
493
+ .filter((m) =>
494
+ this.editor.extensionManager.splittableMarks.includes(
495
+ m.type.name,
496
+ ),
497
+ );
498
+
499
+ tr.insert(
500
+ tr.selection.head,
501
+ tr.doc.type.schema.nodes.hardBreak.create(),
502
+ ).ensureMarks(marks);
503
+ return true;
492
504
  }
493
505
 
494
506
  return false;
@@ -293,28 +293,18 @@ export class SuggestionMenuProseMirrorPlugin<
293
293
  },
294
294
 
295
295
  props: {
296
- handleTextInput(view, from, to, text) {
297
- // only on insert
298
- if (from === to) {
299
- const doc = view.state.doc;
300
- for (const str of triggerCharacters) {
301
- const snippet =
302
- str.length > 1
303
- ? doc.textBetween(from - str.length, from) + text
304
- : text;
305
-
306
- if (str === snippet) {
307
- view.dispatch(view.state.tr.insertText(text));
308
- view.dispatch(
309
- view.state.tr
310
- .setMeta(suggestionMenuPluginKey, {
311
- triggerCharacter: snippet,
312
- })
313
- .scrollIntoView(),
314
- );
315
- return true;
316
- }
317
- }
296
+ handleTextInput(view, _from, _to, text) {
297
+ if (triggerCharacters.includes(text)) {
298
+ view.dispatch(view.state.tr.insertText(text));
299
+ view.dispatch(
300
+ view.state.tr
301
+ .setMeta(suggestionMenuPluginKey, {
302
+ triggerCharacter: text,
303
+ })
304
+ .scrollIntoView(),
305
+ );
306
+
307
+ return true;
318
308
  }
319
309
  return false;
320
310
  },
@@ -137,6 +137,19 @@ export function getDefaultSlashMenuItems<
137
137
  });
138
138
  }
139
139
 
140
+ if (checkDefaultBlockTypeInSchema("toggleListItem", editor)) {
141
+ items.push({
142
+ onItemClick: () => {
143
+ insertOrUpdateBlock(editor, {
144
+ type: "toggleListItem",
145
+ });
146
+ },
147
+ badge: formatKeyboardShortcut("Mod-Shift-6"),
148
+ key: "toggle_list",
149
+ ...editor.dictionary.slash_menu.toggle_list,
150
+ });
151
+ }
152
+
140
153
  if (checkDefaultBlockTypeInSchema("numberedListItem", editor)) {
141
154
  items.push({
142
155
  onItemClick: () => {
@@ -302,6 +315,57 @@ export function getDefaultSlashMenuItems<
302
315
  });
303
316
  }
304
317
 
318
+ if (checkDefaultBlockTypeInSchema("heading", editor)) {
319
+ items.push(
320
+ {
321
+ onItemClick: () => {
322
+ insertOrUpdateBlock(editor, {
323
+ type: "heading",
324
+ props: { level: 1, isToggleable: true },
325
+ });
326
+ },
327
+ key: "toggle_heading",
328
+ ...editor.dictionary.slash_menu.toggle_heading,
329
+ },
330
+ {
331
+ onItemClick: () => {
332
+ insertOrUpdateBlock(editor, {
333
+ type: "heading",
334
+ props: { level: 2, isToggleable: true },
335
+ });
336
+ },
337
+
338
+ key: "toggle_heading_2",
339
+ ...editor.dictionary.slash_menu.toggle_heading_2,
340
+ },
341
+ {
342
+ onItemClick: () => {
343
+ insertOrUpdateBlock(editor, {
344
+ type: "heading",
345
+ props: { level: 3, isToggleable: true },
346
+ });
347
+ },
348
+ key: "toggle_heading_3",
349
+ ...editor.dictionary.slash_menu.toggle_heading_3,
350
+ },
351
+ );
352
+
353
+ editor.settings.heading.levels
354
+ .filter((level): level is 4 | 5 | 6 => level > 3)
355
+ .forEach((level) => {
356
+ items.push({
357
+ onItemClick: () => {
358
+ insertOrUpdateBlock(editor, {
359
+ type: "heading",
360
+ props: { level: level },
361
+ });
362
+ },
363
+ key: `heading_${level}`,
364
+ ...editor.dictionary.slash_menu[`heading_${level}`],
365
+ });
366
+ });
367
+ }
368
+
305
369
  items.push({
306
370
  onItemClick: () => {
307
371
  editor.openSuggestionMenu(":", {
@@ -20,6 +20,42 @@ export const ar: Dictionary = {
20
20
  aliases: ["ع3", "عنوان3", "عنوان فرعي"],
21
21
  group: "العناوين",
22
22
  },
23
+ heading_4: {
24
+ title: "عنوان 4",
25
+ subtext: "عنوان فرعي ثانوي صغير",
26
+ aliases: ["ع4", "عنوان4", "عنوان فرعي صغير"],
27
+ group: "العناوين الفرعية",
28
+ },
29
+ heading_5: {
30
+ title: "عنوان 5",
31
+ subtext: "عنوان فرعي صغير",
32
+ aliases: ["ع5", "عنوان5", "عنوان فرعي صغير"],
33
+ group: "العناوين الفرعية",
34
+ },
35
+ heading_6: {
36
+ title: "عنوان 6",
37
+ subtext: "أدنى مستوى للعناوين",
38
+ aliases: ["ع6", "عنوان6", "العنوان الفرعي الأدنى"],
39
+ group: "العناوين الفرعية",
40
+ },
41
+ toggle_heading: {
42
+ title: "عنوان قابل للطي 1",
43
+ subtext: "عنوان قابل للطي لإظهار وإخفاء المحتوى",
44
+ aliases: ["ع", "عنوان1", "ع1", "قابل للطي", "طي"],
45
+ group: "العناوين الفرعية",
46
+ },
47
+ toggle_heading_2: {
48
+ title: "عنوان قابل للطي 2",
49
+ subtext: "عنوان فرعي قابل للطي لإظهار وإخفاء المحتوى",
50
+ aliases: ["ع2", "عنوان2", "عنوان فرعي", "قابل للطي", "طي"],
51
+ group: "العناوين الفرعية",
52
+ },
53
+ toggle_heading_3: {
54
+ title: "عنوان قابل للطي 3",
55
+ subtext: "عنوان فرعي ثانوي قابل للطي لإظهار وإخفاء المحتوى",
56
+ aliases: ["ع3", "عنوان3", "عنوان فرعي", "قابل للطي", "طي"],
57
+ group: "العناوين الفرعية",
58
+ },
23
59
  quote: {
24
60
  title: "اقتباس",
25
61
  subtext: "اقتباس أو مقتطف",
@@ -52,6 +88,12 @@ export const ar: Dictionary = {
52
88
  ],
53
89
  group: "الكتل الأساسية",
54
90
  },
91
+ toggle_list: {
92
+ title: "قائمة قابلة للطي",
93
+ subtext: "قائمة بعناصر فرعية قابلة للإخفاء",
94
+ aliases: ["عناصر قائمة", "قائمة", "قائمة قابلة للطي", "قائمة منسدلة"],
95
+ group: "الكتل الأساسية",
96
+ },
55
97
  paragraph: {
56
98
  title: "فقرة",
57
99
  subtext: "تستخدم لنص الوثيقة الأساسي",
@@ -118,6 +160,7 @@ export const ar: Dictionary = {
118
160
  placeholders: {
119
161
  default: "أدخل نصًا أو اكتب '/' للأوامر",
120
162
  heading: "عنوان",
163
+ toggleListItem: "طيّ",
121
164
  bulletListItem: "قائمة",
122
165
  numberedListItem: "قائمة",
123
166
  checkListItem: "قائمة",
@@ -320,6 +363,9 @@ export const ar: Dictionary = {
320
363
  },
321
364
  },
322
365
  comments: {
366
+ edited: "تم التحرير",
367
+ save_button_text: "حفظ",
368
+ cancel_button_text: "إلغاء",
323
369
  actions: {
324
370
  add_reaction: "أضف تفاعلًا",
325
371
  resolve: "حل",