jodit 4.15.10 → 4.15.13

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 (74) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +7 -0
  3. package/es2015/jodit.css +21 -1
  4. package/es2015/jodit.fat.min.css +1 -1
  5. package/es2015/jodit.fat.min.js +7 -7
  6. package/es2015/jodit.js +228 -8
  7. package/es2015/jodit.min.css +1 -1
  8. package/es2015/jodit.min.js +5 -5
  9. package/es2015/plugins/debug/debug.css +1 -1
  10. package/es2015/plugins/debug/debug.js +1 -1
  11. package/es2015/plugins/debug/debug.min.js +1 -1
  12. package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
  13. package/es2015/plugins/speech-recognize/speech-recognize.js +1 -1
  14. package/es2015/plugins/speech-recognize/speech-recognize.min.js +1 -1
  15. package/es2018/jodit.fat.min.css +1 -1
  16. package/es2018/jodit.fat.min.js +5 -5
  17. package/es2018/jodit.min.css +1 -1
  18. package/es2018/jodit.min.js +5 -5
  19. package/es2018/plugins/debug/debug.min.js +1 -1
  20. package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
  21. package/es2021/jodit.css +21 -1
  22. package/es2021/jodit.fat.min.css +1 -1
  23. package/es2021/jodit.fat.min.js +5 -5
  24. package/es2021/jodit.js +227 -8
  25. package/es2021/jodit.min.css +1 -1
  26. package/es2021/jodit.min.js +5 -5
  27. package/es2021/plugins/debug/debug.css +1 -1
  28. package/es2021/plugins/debug/debug.js +1 -1
  29. package/es2021/plugins/debug/debug.min.js +1 -1
  30. package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
  31. package/es2021/plugins/speech-recognize/speech-recognize.js +1 -1
  32. package/es2021/plugins/speech-recognize/speech-recognize.min.js +1 -1
  33. package/es2021.en/jodit.css +21 -1
  34. package/es2021.en/jodit.fat.min.css +1 -1
  35. package/es2021.en/jodit.fat.min.js +10 -10
  36. package/es2021.en/jodit.js +227 -8
  37. package/es2021.en/jodit.min.css +1 -1
  38. package/es2021.en/jodit.min.js +9 -9
  39. package/es2021.en/plugins/debug/debug.css +1 -1
  40. package/es2021.en/plugins/debug/debug.js +1 -1
  41. package/es2021.en/plugins/debug/debug.min.js +1 -1
  42. package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
  43. package/es2021.en/plugins/speech-recognize/speech-recognize.js +1 -1
  44. package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +1 -1
  45. package/es5/jodit.css +22 -2
  46. package/es5/jodit.fat.min.css +1 -1
  47. package/es5/jodit.fat.min.js +2 -2
  48. package/es5/jodit.js +282 -8
  49. package/es5/jodit.min.css +3 -3
  50. package/es5/jodit.min.js +2 -2
  51. package/es5/plugins/debug/debug.css +1 -1
  52. package/es5/plugins/debug/debug.js +1 -1
  53. package/es5/plugins/debug/debug.min.js +1 -1
  54. package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
  55. package/es5/plugins/speech-recognize/speech-recognize.js +1 -1
  56. package/es5/plugins/speech-recognize/speech-recognize.min.js +1 -1
  57. package/es5/polyfills.fat.min.js +1 -1
  58. package/es5/polyfills.js +1 -1
  59. package/es5/polyfills.min.js +1 -1
  60. package/esm/core/constants.d.ts +2 -0
  61. package/esm/core/constants.js +3 -1
  62. package/esm/modules/toolbar/button/button.d.ts +14 -0
  63. package/esm/modules/toolbar/button/button.js +102 -4
  64. package/esm/plugins/all.d.ts +1 -0
  65. package/esm/plugins/all.js +1 -0
  66. package/esm/plugins/index.d.ts +1 -0
  67. package/esm/plugins/index.js +1 -0
  68. package/esm/plugins/toolbar-navigation/toolbar-navigation.d.ts +42 -0
  69. package/esm/plugins/toolbar-navigation/toolbar-navigation.js +113 -0
  70. package/package.json +1 -1
  71. package/types/core/constants.d.ts +2 -0
  72. package/types/modules/toolbar/button/button.d.ts +14 -0
  73. package/types/plugins/index.d.ts +1 -0
  74. package/types/plugins/toolbar-navigation/toolbar-navigation.d.ts +42 -0
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.10
4
+ * Version: v4.15.13
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.10
4
+ * Version: v4.15.13
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.10
4
+ * Version: v4.15.13
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.10
4
+ * Version: v4.15.13
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.10
4
+ * Version: v4.15.13
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.10
4
+ * Version: v4.15.13
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.10
4
+ * Version: v4.15.13
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
package/es5/polyfills.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.10
4
+ * Version: v4.15.13
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.10
4
+ * Version: v4.15.13
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -45,6 +45,8 @@ export declare const KEY_TAB = "Tab";
45
45
  export declare const KEY_ENTER = "Enter";
46
46
  export declare const KEY_ESC = "Escape";
47
47
  export declare const KEY_ALT = "Alt";
48
+ export declare const KEY_HOME = "Home";
49
+ export declare const KEY_END = "End";
48
50
  export declare const KEY_LEFT = "ArrowLeft";
49
51
  export declare const KEY_UP = "ArrowUp";
50
52
  export declare const KEY_RIGHT = "ArrowRight";
@@ -3,7 +3,7 @@
3
3
  * Released under MIT see LICENSE.txt in the project root for license information.
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
- export const APP_VERSION = "4.15.10";
6
+ export const APP_VERSION = "4.15.13";
7
7
  // prettier-ignore
8
8
  export const ES = "es2020";
9
9
  export const IS_ES_MODERN = true;
@@ -53,6 +53,8 @@ export const KEY_TAB = 'Tab';
53
53
  export const KEY_ENTER = 'Enter';
54
54
  export const KEY_ESC = 'Escape';
55
55
  export const KEY_ALT = 'Alt';
56
+ export const KEY_HOME = 'Home';
57
+ export const KEY_END = 'End';
56
58
  export const KEY_LEFT = 'ArrowLeft';
57
59
  export const KEY_UP = 'ArrowUp';
58
60
  export const KEY_RIGHT = 'ArrowRight';
@@ -67,6 +67,20 @@ export declare class ToolbarButton<T extends IViewBased = IViewBased> extends UI
67
67
  */
68
68
  protected onTriggerClick(e: MouseEvent): void;
69
69
  protected onTriggerKeyDown(e: KeyboardEvent): void;
70
+ /**
71
+ * `ArrowDown` on a button with a trigger opens its dropdown and moves the
72
+ * focus into it, like the WAI-ARIA menu button pattern
73
+ */
74
+ protected onButtonKeyDown(e: KeyboardEvent): void;
75
+ /**
76
+ * Inside the dropdown: `ArrowDown`/`ArrowUp` walk the items, `Escape` and
77
+ * `ArrowUp` on the first item close it and give the focus back to the button
78
+ */
79
+ private __onPopupKeyDown;
80
+ /**
81
+ * Visible controls of the opened dropdown that can take the focus
82
+ */
83
+ private __popupFocusables;
70
84
  private openedPopup;
71
85
  /**
72
86
  * Create an open popup list
@@ -14,7 +14,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
14
14
  return c > 3 && r && Object.defineProperty(target, key, r), r;
15
15
  };
16
16
  import { STATUSES } from "../../../core/component/statuses.js";
17
- import { KEY_ENTER, KEY_SPACE } from "../../../core/constants.js";
17
+ import { KEY_DOWN, KEY_ENTER, KEY_ESC, KEY_SPACE, KEY_UP } from "../../../core/constants.js";
18
18
  import { autobind } from "../../../core/decorators/autobind/autobind.js";
19
19
  import { cacheHTML } from "../../../core/decorators/cache/cache.js";
20
20
  import { component, getComponentClass } from "../../../core/decorators/component/component.js";
@@ -35,6 +35,15 @@ import { findControlType } from "../../../core/ui/helpers/get-control-type.js";
35
35
  import { Icon } from "../../../core/ui/icon.js";
36
36
  import { Popup } from "../../../core/ui/popup/popup.js";
37
37
  import { makeCollection } from "../factory.js";
38
+ const INPUT_TAGS = new Set(['input', 'textarea', 'select']);
39
+ const FOCUSABLE_SELECTOR = [
40
+ 'button:not([disabled])',
41
+ 'a[href]',
42
+ 'input:not([disabled]):not([type="hidden"])',
43
+ 'select:not([disabled])',
44
+ 'textarea:not([disabled])',
45
+ '[tabindex]:not([tabindex="-1"])'
46
+ ].join(',');
38
47
  let ToolbarButton = class ToolbarButton extends UIButton {
39
48
  className() {
40
49
  return 'ToolbarButton';
@@ -290,13 +299,88 @@ let ToolbarButton = class ToolbarButton extends UIButton {
290
299
  }
291
300
  }
292
301
  onTriggerKeyDown(e) {
293
- if (this.state.disabled ||
294
- ![KEY_ENTER, KEY_SPACE, ' '].includes(e.key)) {
302
+ if (this.state.disabled) {
303
+ return;
304
+ }
305
+ if (e.key === KEY_DOWN) {
306
+ this.onButtonKeyDown(e);
307
+ return;
308
+ }
309
+ if (![KEY_ENTER, KEY_SPACE, ' '].includes(e.key)) {
295
310
  return;
296
311
  }
297
312
  e.preventDefault();
298
313
  this.trigger.click();
299
314
  }
315
+ /**
316
+ * `ArrowDown` on a button with a trigger opens its dropdown and moves the
317
+ * focus into it, like the WAI-ARIA menu button pattern
318
+ */
319
+ onButtonKeyDown(e) {
320
+ var _a;
321
+ if (e.key !== KEY_DOWN ||
322
+ this.state.disabled ||
323
+ !this.state.hasTrigger ||
324
+ e.altKey ||
325
+ e.ctrlKey ||
326
+ e.metaKey) {
327
+ return;
328
+ }
329
+ e.preventDefault();
330
+ e.stopPropagation();
331
+ if (!this.openedPopup) {
332
+ this.trigger.click();
333
+ }
334
+ (_a = this.__popupFocusables()[0]) === null || _a === void 0 ? void 0 : _a.focus();
335
+ }
336
+ /**
337
+ * Inside the dropdown: `ArrowDown`/`ArrowUp` walk the items, `Escape` and
338
+ * `ArrowUp` on the first item close it and give the focus back to the button
339
+ */
340
+ __onPopupKeyDown(e) {
341
+ if (!this.openedPopup || e.altKey || e.ctrlKey || e.metaKey) {
342
+ return;
343
+ }
344
+ const target = e.target;
345
+ // A text field keeps the arrow keys for itself
346
+ if (Dom.isTag(target, INPUT_TAGS) && e.key !== KEY_ESC) {
347
+ return;
348
+ }
349
+ const items = this.__popupFocusables(), index = items.indexOf(target);
350
+ switch (e.key) {
351
+ case KEY_ESC:
352
+ this.__closePopup();
353
+ break;
354
+ case KEY_UP:
355
+ if (index <= 0) {
356
+ this.__closePopup();
357
+ }
358
+ else {
359
+ items[index - 1].focus();
360
+ }
361
+ break;
362
+ case KEY_DOWN:
363
+ if (!items.length) {
364
+ return;
365
+ }
366
+ items[(index + 1) % items.length].focus();
367
+ break;
368
+ default:
369
+ return;
370
+ }
371
+ e.preventDefault();
372
+ e.stopPropagation();
373
+ }
374
+ /**
375
+ * Visible controls of the opened dropdown that can take the focus
376
+ */
377
+ __popupFocusables() {
378
+ const popup = this.openedPopup;
379
+ if (!popup) {
380
+ return [];
381
+ }
382
+ return Array.from(popup.container.querySelectorAll(FOCUSABLE_SELECTOR)).filter(elm => Boolean(elm.offsetParent));
383
+ }
300
384
  /**
301
385
  * Create an open popup list
302
386
  */
@@ -377,7 +461,8 @@ let ToolbarButton = class ToolbarButton extends UIButton {
377
461
  this.openedPopup = new Popup(this.j, false);
378
462
  this.j.e
379
463
  .on(this.ow, 'mousedown touchstart', this.onOutsideClick)
380
- .on('escape closeAllPopups', this.onOutsideClick);
464
+ .on('escape closeAllPopups', this.onOutsideClick)
465
+ .on(this.openedPopup.container, 'keydown', this.__onPopupKeyDown);
381
466
  return this.openedPopup;
382
467
  }
383
468
  __closePopup() {
@@ -395,12 +480,19 @@ let ToolbarButton = class ToolbarButton extends UIButton {
395
480
  this.j.e
396
481
  .off(this.ow, 'mousedown touchstart', this.onOutsideClick)
397
482
  .off('escape closeAllPopups', this.onOutsideClick);
483
+ // The keyboard brought the focus into the dropdown: give it back to
484
+ // the button, otherwise it would fall out to the document
485
+ const { activeElement } = this.od, hadFocus = activeElement &&
486
+ Dom.isOrContains(popup.container, activeElement);
398
487
  this.state.activated = false;
399
488
  popup.close();
400
489
  popup.destruct();
401
490
  if (this.trigger) {
402
491
  attr(this.trigger, 'aria-expanded', false);
403
492
  }
493
+ if (hadFocus) {
494
+ this.focus();
495
+ }
404
496
  }
405
497
  /**
406
498
  * Click handler
@@ -460,6 +552,12 @@ __decorate([
460
552
  __decorate([
461
553
  watch('trigger:keydown')
462
554
  ], ToolbarButton.prototype, "onTriggerKeyDown", null);
555
+ __decorate([
556
+ watch('button:keydown')
557
+ ], ToolbarButton.prototype, "onButtonKeyDown", null);
558
+ __decorate([
559
+ autobind
560
+ ], ToolbarButton.prototype, "__onPopupKeyDown", null);
463
561
  __decorate([
464
562
  autobind
465
563
  ], ToolbarButton.prototype, "onOutsideClick", null);
@@ -66,6 +66,7 @@ import "./ai-assistant/ai-assistant";
66
66
  import "./tab/tab";
67
67
  import "./table/table";
68
68
  import "./table-keyboard-navigation/table-keyboard-navigation";
69
+ import "./toolbar-navigation/toolbar-navigation";
69
70
  import "./video/video";
70
71
  import "./wrap-nodes/wrap-nodes";
71
72
  import "./dtd/dtd";
@@ -67,6 +67,7 @@ import "./ai-assistant/ai-assistant.js";
67
67
  import "./tab/tab.js";
68
68
  import "./table/table.js";
69
69
  import "./table-keyboard-navigation/table-keyboard-navigation.js";
70
+ import "./toolbar-navigation/toolbar-navigation.js";
70
71
  import "./video/video.js";
71
72
  import "./wrap-nodes/wrap-nodes.js";
72
73
  import "./dtd/dtd.js";
@@ -66,6 +66,7 @@ import "./ai-assistant/ai-assistant";
66
66
  import "./tab/tab";
67
67
  import "./table/table";
68
68
  import "./table-keyboard-navigation/table-keyboard-navigation";
69
+ import "./toolbar-navigation/toolbar-navigation";
69
70
  import "./video/video";
70
71
  import "./wrap-nodes/wrap-nodes";
71
72
  import "./dtd/dtd";
@@ -29,5 +29,6 @@ import "./redo-undo/redo-undo.js";
29
29
  import "./size/size.js";
30
30
  import "./stat/stat.js";
31
31
  import "./table/table.js";
32
+ import "./toolbar-navigation/toolbar-navigation.js";
32
33
  import "./wrap-nodes/wrap-nodes.js";
33
34
  import "./dtd/dtd.js";
@@ -0,0 +1,42 @@
1
+ /*!
2
+ * Jodit Editor (https://xdsoft.net/jodit/)
3
+ * Released under MIT see LICENSE.txt in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+ /**
7
+ * [[include:plugins/toolbar-navigation/README.md]]
8
+ * @packageDocumentation
9
+ * @module plugins/toolbar-navigation
10
+ */
11
+ import type { IJodit } from "../../types/index";
12
+ import { Plugin } from "../../core/plugin/index";
13
+ /**
14
+ * Makes the toolbar reachable from the keyboard, as described by the WAI-ARIA
15
+ * authoring practices for a `role="toolbar"` widget.
16
+ *
17
+ * The focus is moved programmatically, so this works whatever
18
+ * {@link Config.allowTabNavigation} does with the tab order — including the
19
+ * default, where the buttons take no part in the page tab order.
20
+ */
21
+ export declare class toolbarNavigation extends Plugin {
22
+ /** @override */
23
+ protected afterInit(jodit: IJodit): void;
24
+ /** @override */
25
+ protected beforeDestruct(): void;
26
+ /**
27
+ * Moves the focus to the first button of the toolbar.
28
+ *
29
+ * Bound to `Alt+F10` by default; remap it like any other command:
30
+ * `commandToHotkeys: { focusToolbar: 'alt+0' }`
31
+ */
32
+ focusToolbar(): false;
33
+ /**
34
+ * Arrow keys / `Home` / `End` walk the buttons, `Escape` leaves the toolbar
35
+ */
36
+ protected onKeyDown(e: KeyboardEvent): boolean | void;
37
+ /**
38
+ * Toolbar buttons that can take the focus right now
39
+ */
40
+ private __buttons;
41
+ private __isRtl;
42
+ }
@@ -0,0 +1,113 @@
1
+ /*!
2
+ * Jodit Editor (https://xdsoft.net/jodit/)
3
+ * Released under MIT see LICENSE.txt in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
7
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
8
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
9
+ r = Reflect.decorate(decorators, target, key, desc);
10
+ else
11
+ for (var i = decorators.length - 1; i >= 0; i--)
12
+ if (d = decorators[i])
13
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
15
+ };
16
+ import { KEY_END, KEY_ESC, KEY_HOME, KEY_LEFT, KEY_RIGHT } from "../../core/constants.js";
17
+ import { autobind } from "../../core/decorators/autobind/autobind.js";
18
+ import { watch } from "../../core/decorators/watch/watch.js";
19
+ import { Dom } from "../../core/dom/dom.js";
20
+ import { pluginSystem } from "../../core/global.js";
21
+ import { attr } from "../../core/helpers/utils/attr.js";
22
+ import { Plugin } from "../../core/plugin/index.js";
23
+ const INPUT_TAGS = new Set(['input', 'textarea', 'select']);
24
+ /**
25
+ * Makes the toolbar reachable from the keyboard, as described by the WAI-ARIA
26
+ * authoring practices for a `role="toolbar"` widget.
27
+ *
28
+ * The focus is moved programmatically, so this works whatever
29
+ * {@link Config.allowTabNavigation} does with the tab order — including the
30
+ * default, where the buttons take no part in the page tab order.
31
+ */
32
+ export class toolbarNavigation extends Plugin {
33
+ /** @override */
34
+ afterInit(jodit) {
35
+ jodit.registerCommand('focusToolbar', {
36
+ hotkeys: 'alt+f10',
37
+ exec: this.focusToolbar
38
+ });
39
+ }
40
+ /** @override */
41
+ beforeDestruct() { }
42
+ /**
43
+ * Moves the focus to the first button of the toolbar.
44
+ *
45
+ * Bound to `Alt+F10` by default; remap it like any other command:
46
+ * `commandToHotkeys: { focusToolbar: 'alt+0' }`
47
+ */
48
+ focusToolbar() {
49
+ const [first] = this.__buttons();
50
+ first === null || first === void 0 ? void 0 : first.focus();
51
+ return false;
52
+ }
53
+ /**
54
+ * Arrow keys / `Home` / `End` walk the buttons, `Escape` leaves the toolbar
55
+ */
56
+ onKeyDown(e) {
57
+ if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey) {
58
+ return;
59
+ }
60
+ const target = e.target;
61
+ // A control that needs the arrow keys for itself
62
+ if (Dom.isTag(target, INPUT_TAGS) ||
63
+ (Dom.isHTMLElement(target) && target.isContentEditable)) {
64
+ return;
65
+ }
66
+ const buttons = this.__buttons();
67
+ if (!buttons.length) {
68
+ return;
69
+ }
70
+ switch (e.key) {
71
+ case KEY_ESC:
72
+ this.j.s.focus();
73
+ break;
74
+ case KEY_HOME:
75
+ buttons[0].focus();
76
+ break;
77
+ case KEY_END:
78
+ buttons[buttons.length - 1].focus();
79
+ break;
80
+ case KEY_LEFT:
81
+ case KEY_RIGHT: {
82
+ const index = buttons.findIndex(button => button.container.contains(target));
83
+ if (index === -1) {
84
+ return;
85
+ }
86
+ const forward = (e.key === KEY_RIGHT) !== this.__isRtl(), next = index + (forward ? 1 : -1);
87
+ buttons[(next + buttons.length) % buttons.length].focus();
88
+ break;
89
+ }
90
+ default:
91
+ return;
92
+ }
93
+ e.preventDefault();
94
+ e.stopPropagation();
95
+ return false;
96
+ }
97
+ /**
98
+ * Toolbar buttons that can take the focus right now
99
+ */
100
+ __buttons() {
101
+ return this.j.toolbar.buttons.filter(button => !button.state.disabled && button.container.isConnected);
102
+ }
103
+ __isRtl() {
104
+ return attr(this.j.toolbar.container, 'dir') === 'rtl';
105
+ }
106
+ }
107
+ __decorate([
108
+ autobind
109
+ ], toolbarNavigation.prototype, "focusToolbar", null);
110
+ __decorate([
111
+ watch('j.toolbar.container:keydown.toolbar-navigation')
112
+ ], toolbarNavigation.prototype, "onKeyDown", null);
113
+ pluginSystem.add('toolbarNavigation', toolbarNavigation);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jodit",
3
- "version": "4.15.10",
3
+ "version": "4.15.13",
4
4
  "description": "Jodit is an awesome and useful wysiwyg editor with filebrowser",
5
5
  "main": "esm/index.js",
6
6
  "types": "types/index.d.ts",
@@ -45,6 +45,8 @@ export declare const KEY_TAB = "Tab";
45
45
  export declare const KEY_ENTER = "Enter";
46
46
  export declare const KEY_ESC = "Escape";
47
47
  export declare const KEY_ALT = "Alt";
48
+ export declare const KEY_HOME = "Home";
49
+ export declare const KEY_END = "End";
48
50
  export declare const KEY_LEFT = "ArrowLeft";
49
51
  export declare const KEY_UP = "ArrowUp";
50
52
  export declare const KEY_RIGHT = "ArrowRight";
@@ -67,6 +67,20 @@ export declare class ToolbarButton<T extends IViewBased = IViewBased> extends UI
67
67
  */
68
68
  protected onTriggerClick(e: MouseEvent): void;
69
69
  protected onTriggerKeyDown(e: KeyboardEvent): void;
70
+ /**
71
+ * `ArrowDown` on a button with a trigger opens its dropdown and moves the
72
+ * focus into it, like the WAI-ARIA menu button pattern
73
+ */
74
+ protected onButtonKeyDown(e: KeyboardEvent): void;
75
+ /**
76
+ * Inside the dropdown: `ArrowDown`/`ArrowUp` walk the items, `Escape` and
77
+ * `ArrowUp` on the first item close it and give the focus back to the button
78
+ */
79
+ private __onPopupKeyDown;
80
+ /**
81
+ * Visible controls of the opened dropdown that can take the focus
82
+ */
83
+ private __popupFocusables;
70
84
  private openedPopup;
71
85
  /**
72
86
  * Create an open popup list
@@ -66,6 +66,7 @@ import "./ai-assistant/ai-assistant";
66
66
  import "./tab/tab";
67
67
  import "./table/table";
68
68
  import "./table-keyboard-navigation/table-keyboard-navigation";
69
+ import "./toolbar-navigation/toolbar-navigation";
69
70
  import "./video/video";
70
71
  import "./wrap-nodes/wrap-nodes";
71
72
  import "./dtd/dtd";
@@ -0,0 +1,42 @@
1
+ /*!
2
+ * Jodit Editor (https://xdsoft.net/jodit/)
3
+ * Released under MIT see LICENSE.txt in the project root for license information.
4
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+ /**
7
+ * [[include:plugins/toolbar-navigation/README.md]]
8
+ * @packageDocumentation
9
+ * @module plugins/toolbar-navigation
10
+ */
11
+ import type { IJodit } from "../../types/index";
12
+ import { Plugin } from "../../core/plugin/index";
13
+ /**
14
+ * Makes the toolbar reachable from the keyboard, as described by the WAI-ARIA
15
+ * authoring practices for a `role="toolbar"` widget.
16
+ *
17
+ * The focus is moved programmatically, so this works whatever
18
+ * {@link Config.allowTabNavigation} does with the tab order — including the
19
+ * default, where the buttons take no part in the page tab order.
20
+ */
21
+ export declare class toolbarNavigation extends Plugin {
22
+ /** @override */
23
+ protected afterInit(jodit: IJodit): void;
24
+ /** @override */
25
+ protected beforeDestruct(): void;
26
+ /**
27
+ * Moves the focus to the first button of the toolbar.
28
+ *
29
+ * Bound to `Alt+F10` by default; remap it like any other command:
30
+ * `commandToHotkeys: { focusToolbar: 'alt+0' }`
31
+ */
32
+ focusToolbar(): false;
33
+ /**
34
+ * Arrow keys / `Home` / `End` walk the buttons, `Escape` leaves the toolbar
35
+ */
36
+ protected onKeyDown(e: KeyboardEvent): boolean | void;
37
+ /**
38
+ * Toolbar buttons that can take the focus right now
39
+ */
40
+ private __buttons;
41
+ private __isRtl;
42
+ }