@mgdis/mg-components 6.20.0 → 6.22.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 (205) hide show
  1. package/dist/cjs/{index-TUElr4Wv.js → index-BxB20_Vw.js} +54 -0
  2. package/dist/cjs/{index-Bp6wZzau.js → index-C2viYwrR.js} +1761 -80
  3. package/dist/cjs/loader.cjs.js +2 -2
  4. package/dist/cjs/mg-action-more_37.cjs.entry.js +761 -371
  5. package/dist/cjs/mg-alert.cjs.entry.js +17 -9
  6. package/dist/cjs/mg-breadcrumb.cjs.entry.js +63 -0
  7. package/dist/cjs/mg-components.cjs.js +3 -3
  8. package/dist/cjs/mg-fieldset.cjs.entry.js +24 -7
  9. package/dist/cjs/mg-input-combobox.cjs.entry.js +49 -19
  10. package/dist/cjs/mg-input-file.cjs.entry.js +384 -0
  11. package/dist/cjs/mg-input-rich-text-editor.cjs.entry.js +40096 -15821
  12. package/dist/cjs/{mg-input.conf-D7jmj_lh.js → mg-input.conf-BNpeATnq.js} +7 -0
  13. package/dist/cjs/mg-loader.cjs.entry.js +8 -6
  14. package/dist/cjs/mg-progress.cjs.entry.js +19 -9
  15. package/dist/collection/assets/icons/index.js +1 -1
  16. package/dist/collection/collection-manifest.json +5 -3
  17. package/dist/collection/components/atoms/internals/mg-character-left/mg-character-left.js +1 -1
  18. package/dist/collection/components/atoms/internals/mg-input-title/mg-input-title.js +1 -1
  19. package/dist/collection/components/atoms/mg-card/mg-card.js +1 -1
  20. package/dist/collection/components/atoms/mg-divider/mg-divider.js +1 -1
  21. package/dist/collection/components/atoms/mg-icon/mg-icon.js +2 -2
  22. package/dist/collection/components/atoms/mg-tag/mg-tag.js +1 -1
  23. package/dist/collection/components/atoms/mg-tooltip/mg-tooltip-content/mg-tooltip-content.js +1 -1
  24. package/dist/collection/components/atoms/mg-tooltip/mg-tooltip.js +1 -1
  25. package/dist/collection/components/molecules/inputs/mg-input/mg-input.conf.js +6 -0
  26. package/dist/collection/components/molecules/inputs/mg-input/mg-input.js +1 -1
  27. package/dist/collection/components/molecules/inputs/mg-input-checkbox/MgInputCheckboxList.js +2 -2
  28. package/dist/collection/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox-paginated/mg-input-checkbox-paginated.js +2 -2
  29. package/dist/collection/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.js +1 -1
  30. package/dist/collection/components/molecules/inputs/mg-input-combobox/mg-input-combobox.js +1 -1
  31. package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.js +1 -1
  32. package/dist/collection/components/molecules/inputs/mg-input-file/mg-input-file.js +877 -0
  33. package/dist/collection/components/molecules/inputs/mg-input-numeric/mg-input-numeric.js +1 -1
  34. package/dist/collection/components/molecules/inputs/mg-input-password/mg-input-password.js +2 -2
  35. package/dist/collection/components/molecules/inputs/mg-input-radio/mg-input-radio.js +1 -1
  36. package/dist/collection/components/molecules/inputs/mg-input-rich-text-editor/editor/custom-properties.scss +212 -0
  37. package/dist/collection/components/molecules/inputs/mg-input-rich-text-editor/editor/editor.conf.js +1 -0
  38. package/dist/collection/components/molecules/inputs/mg-input-rich-text-editor/editor/index.js +300 -94
  39. package/dist/collection/components/molecules/inputs/mg-input-rich-text-editor/mg-input-rich-text-editor.conf.js +29 -0
  40. package/dist/collection/components/molecules/inputs/mg-input-rich-text-editor/mg-input-rich-text-editor.js +163 -53
  41. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.js +1 -1
  42. package/dist/collection/components/molecules/inputs/mg-input-text/mg-input-text.js +2 -2
  43. package/dist/collection/components/molecules/inputs/mg-input-textarea/mg-input-textarea.js +1 -1
  44. package/dist/collection/components/molecules/inputs/mg-input-toggle/mg-input-toggle.js +1 -1
  45. package/dist/collection/components/molecules/internals/mg-item-more/mg-item-more.js +3 -36
  46. package/dist/collection/components/molecules/menus/mg-menu/mg-menu.conf.js +0 -4
  47. package/dist/collection/components/molecules/menus/mg-menu/mg-menu.js +21 -43
  48. package/dist/collection/components/molecules/menus/mg-menu-item/mg-menu-item.js +65 -38
  49. package/dist/collection/components/molecules/mg-action-more/mg-action-more.js +2 -2
  50. package/dist/collection/components/molecules/mg-alert/mg-alert.js +1 -1
  51. package/dist/collection/components/molecules/mg-breadcrumb/mg-breadcrumb.conf.js +1 -0
  52. package/dist/collection/components/molecules/mg-breadcrumb/mg-breadcrumb.js +92 -0
  53. package/dist/collection/components/molecules/mg-details/mg-details.js +1 -1
  54. package/dist/collection/components/molecules/mg-fieldset/mg-fieldset.js +12 -3
  55. package/dist/collection/components/molecules/mg-form/mg-form.js +12 -2
  56. package/dist/collection/components/molecules/mg-illustrated-message/mg-illustrated-message.js +1 -1
  57. package/dist/collection/components/molecules/mg-loader/mg-loader.js +1 -1
  58. package/dist/collection/components/molecules/mg-message/mg-message.js +2 -2
  59. package/dist/collection/components/molecules/mg-modal/mg-modal.js +2 -2
  60. package/dist/collection/components/molecules/mg-panel/mg-panel.js +1 -1
  61. package/dist/collection/components/molecules/mg-popover/mg-popover-content/mg-popover-content.js +1 -1
  62. package/dist/collection/components/molecules/mg-popover/mg-popover.js +1 -1
  63. package/dist/collection/components/molecules/mg-progress/mg-progress.js +1 -1
  64. package/dist/collection/components/molecules/mg-skip-links/mg-skip-links.js +1 -1
  65. package/dist/collection/components/molecules/mg-table/mg-table.js +37 -0
  66. package/dist/collection/components/molecules/mg-tabs/mg-tabs.conf.js +0 -4
  67. package/dist/collection/components/molecules/mg-tabs/mg-tabs.js +13 -33
  68. package/dist/collection/locales/en/messages.json +14 -0
  69. package/dist/collection/locales/fr/messages.json +14 -0
  70. package/dist/components/events.utils.js +1 -23
  71. package/dist/components/index.d.ts +2 -0
  72. package/dist/components/index.js +1 -1
  73. package/dist/components/index2.js +1 -408
  74. package/dist/components/index3.js +1 -476
  75. package/dist/components/mg-action-more.js +1 -254
  76. package/dist/components/mg-alert.js +1 -224
  77. package/dist/components/mg-badge.js +1 -6
  78. package/dist/components/mg-badge2.js +1 -113
  79. package/dist/components/mg-breadcrumb.d.ts +11 -0
  80. package/dist/components/mg-breadcrumb.js +1 -0
  81. package/dist/components/mg-button.js +1 -6
  82. package/dist/components/mg-button2.js +1 -275
  83. package/dist/components/mg-card.js +1 -6
  84. package/dist/components/mg-card2.js +1 -92
  85. package/dist/components/mg-character-left.js +1 -6
  86. package/dist/components/mg-character-left2.js +1 -75
  87. package/dist/components/mg-details.js +1 -104
  88. package/dist/components/mg-divider.js +1 -6
  89. package/dist/components/mg-divider2.js +1 -49
  90. package/dist/components/mg-fieldset.js +1 -209
  91. package/dist/components/mg-form.js +1 -302
  92. package/dist/components/mg-icon.js +1 -6
  93. package/dist/components/mg-icon2.js +1 -188
  94. package/dist/components/mg-illustrated-message.js +1 -129
  95. package/dist/components/mg-input-checkbox-paginated.js +1 -6
  96. package/dist/components/mg-input-checkbox-paginated2.js +1 -135
  97. package/dist/components/mg-input-checkbox.js +1 -762
  98. package/dist/components/mg-input-combobox.js +1 -940
  99. package/dist/components/mg-input-date.js +1 -463
  100. package/dist/components/mg-input-file.d.ts +11 -0
  101. package/dist/components/mg-input-file.js +1 -0
  102. package/dist/components/mg-input-numeric.js +1 -592
  103. package/dist/components/mg-input-password.js +1 -360
  104. package/dist/components/mg-input-radio.js +1 -392
  105. package/dist/components/mg-input-rich-text-editor.js +1663 -16797
  106. package/dist/components/mg-input-select.js +1 -6
  107. package/dist/components/mg-input-select2.js +1 -481
  108. package/dist/components/mg-input-text.js +1 -6
  109. package/dist/components/mg-input-text2.js +1 -514
  110. package/dist/components/mg-input-textarea.js +1 -412
  111. package/dist/components/mg-input-title.js +1 -6
  112. package/dist/components/mg-input-title2.js +1 -81
  113. package/dist/components/mg-input-toggle.js +1 -371
  114. package/dist/components/mg-input.conf.js +1 -0
  115. package/dist/components/mg-input.js +1 -6
  116. package/dist/components/mg-input2.js +1 -459
  117. package/dist/components/mg-item-more.js +1 -6
  118. package/dist/components/mg-item-more2.js +1 -505
  119. package/dist/components/mg-loader.js +1 -6
  120. package/dist/components/mg-loader2.js +1 -74
  121. package/dist/components/mg-menu-item.js +1 -6
  122. package/dist/components/mg-menu-item2.js +1 -485
  123. package/dist/components/mg-menu.js +1 -6
  124. package/dist/components/mg-message.js +1 -6
  125. package/dist/components/mg-message2.js +1 -146
  126. package/dist/components/mg-modal.js +1 -184
  127. package/dist/components/mg-pagination.js +1 -234
  128. package/dist/components/mg-panel.js +1 -350
  129. package/dist/components/mg-popover-content.js +1 -6
  130. package/dist/components/mg-popover-content2.js +1 -96
  131. package/dist/components/mg-popover.js +1 -6
  132. package/dist/components/mg-popover2.js +1 -312
  133. package/dist/components/mg-progress.js +1 -123
  134. package/dist/components/mg-skip-links.js +1 -78
  135. package/dist/components/mg-table.js +1 -319
  136. package/dist/components/mg-tabs.js +1 -6
  137. package/dist/components/mg-tabs2.js +1 -315
  138. package/dist/components/mg-tag.js +1 -133
  139. package/dist/components/mg-tooltip-content.js +1 -6
  140. package/dist/components/mg-tooltip-content2.js +1 -42
  141. package/dist/components/mg-tooltip.js +1 -6
  142. package/dist/components/mg-tooltip2.js +1 -421
  143. package/dist/components/popper.js +1 -1790
  144. package/dist/esm/{index-BluNKQ3L.js → index-DFwaH2hS.js} +1761 -80
  145. package/dist/esm/{index-CNX6lq0x.js → index-DSEloqPn.js} +54 -1
  146. package/dist/esm/loader.js +3 -3
  147. package/dist/esm/mg-action-more_37.entry.js +761 -371
  148. package/dist/esm/mg-alert.entry.js +17 -9
  149. package/dist/esm/mg-breadcrumb.entry.js +61 -0
  150. package/dist/esm/mg-components.js +4 -4
  151. package/dist/esm/mg-fieldset.entry.js +24 -7
  152. package/dist/esm/mg-input-combobox.entry.js +49 -19
  153. package/dist/esm/mg-input-file.entry.js +382 -0
  154. package/dist/esm/mg-input-rich-text-editor.entry.js +40083 -15808
  155. package/dist/esm/{mg-input.conf-DDnrE1hD.js → mg-input.conf-C9rmNQIL.js} +7 -1
  156. package/dist/esm/mg-loader.entry.js +8 -6
  157. package/dist/esm/mg-progress.entry.js +19 -9
  158. package/dist/mg-components/locales/en/messages.json +14 -0
  159. package/dist/mg-components/locales/fr/messages.json +14 -0
  160. package/dist/mg-components/mg-components.esm.js +1 -1
  161. package/dist/mg-components/p-0482eb9f.entry.js +1 -0
  162. package/dist/mg-components/{p-7132bca1.entry.js → p-2ee92f38.entry.js} +1 -1
  163. package/dist/mg-components/{p-916dfb6d.entry.js → p-3b653226.entry.js} +1 -1
  164. package/dist/mg-components/p-5745fbea.entry.js +1 -0
  165. package/dist/mg-components/p-C9rmNQIL.js +1 -0
  166. package/dist/mg-components/p-DFwaH2hS.js +2 -0
  167. package/dist/mg-components/p-DSEloqPn.js +1 -0
  168. package/dist/mg-components/p-adec7fcc.entry.js +1 -0
  169. package/dist/mg-components/p-c63f97f0.entry.js +1658 -0
  170. package/dist/mg-components/p-c8c8cfc1.entry.js +1 -0
  171. package/dist/mg-components/p-cc793586.entry.js +1 -0
  172. package/dist/mg-components/p-d5e69c95.entry.js +1 -0
  173. package/dist/types/assets/icons/index.d.ts +2 -0
  174. package/dist/types/components/molecules/inputs/mg-input/mg-input.conf.d.ts +7 -1
  175. package/dist/types/components/molecules/inputs/mg-input-file/mg-input-file.d.ts +210 -0
  176. package/dist/types/components/molecules/inputs/mg-input-rich-text-editor/editor/editor.conf.d.ts +17 -0
  177. package/dist/types/components/molecules/inputs/mg-input-rich-text-editor/editor/index.d.ts +27 -19
  178. package/dist/types/components/molecules/inputs/mg-input-rich-text-editor/mg-input-rich-text-editor.conf.d.ts +3 -0
  179. package/dist/types/components/molecules/inputs/mg-input-rich-text-editor/mg-input-rich-text-editor.d.ts +50 -16
  180. package/dist/types/components/molecules/internals/mg-item-more/mg-item-more.conf.d.ts +0 -5
  181. package/dist/types/components/molecules/internals/mg-item-more/mg-item-more.d.ts +1 -6
  182. package/dist/types/components/molecules/menus/mg-menu/mg-menu.conf.d.ts +2 -10
  183. package/dist/types/components/molecules/menus/mg-menu/mg-menu.d.ts +7 -7
  184. package/dist/types/components/molecules/menus/mg-menu-item/mg-menu-item.d.ts +12 -8
  185. package/dist/types/components/molecules/mg-breadcrumb/mg-breadcrumb.conf.d.ts +18 -0
  186. package/dist/types/components/molecules/mg-breadcrumb/mg-breadcrumb.d.ts +34 -0
  187. package/dist/types/components/molecules/mg-table/mg-table.d.ts +6 -0
  188. package/dist/types/components/molecules/mg-tabs/mg-tabs.conf.d.ts +1 -9
  189. package/dist/types/components/molecules/mg-tabs/mg-tabs.d.ts +4 -4
  190. package/dist/types/components.d.ts +302 -46
  191. package/dist/types/stencil-public-runtime.d.ts +76 -12
  192. package/ide/intellij/web-types.json +483 -51
  193. package/ide/vscode/css-custom-data.json +10 -2
  194. package/ide/vscode/html-custom-data.json +445 -104
  195. package/package.json +24 -23
  196. package/dist/collection/components/molecules/inputs/mg-input-rich-text-editor/editor/editor.scss +0 -1
  197. package/dist/mg-components/p-016bd291.entry.js +0 -1
  198. package/dist/mg-components/p-186a6139.entry.js +0 -1
  199. package/dist/mg-components/p-BluNKQ3L.js +0 -2
  200. package/dist/mg-components/p-CNX6lq0x.js +0 -1
  201. package/dist/mg-components/p-DDnrE1hD.js +0 -1
  202. package/dist/mg-components/p-cd061b38.entry.js +0 -1
  203. package/dist/mg-components/p-d2c72f09.entry.js +0 -1
  204. package/dist/mg-components/p-d5a276eb.entry.js +0 -1
  205. package/ide/vscode/custom.css-data.json +0 -425
@@ -1,109 +1,315 @@
1
1
  import { isValidString } from "@mgdis/core-ui-helpers/dist/utils";
2
- import Quill from "quill";
2
+ import { Jodit } from "jodit";
3
+ // Import Jodit plugins
4
+ import "jodit/esm/plugins/select/select.js";
5
+ import "jodit/esm/plugins/resizer/resizer.js";
6
+ import "jodit/esm/plugins/table/table.js";
7
+ import "jodit/esm/plugins/select-cells/select-cells.js";
8
+ import "jodit/esm/plugins/resize-cells/resize-cells.js";
9
+ import "jodit/esm/plugins/table-keyboard-navigation/table-keyboard-navigation.js";
10
+ import "jodit/esm/plugins/inline-popup/inline-popup.js";
11
+ import "jodit/esm/plugins/clean-html/clean-html.js";
12
+ import "jodit/esm/plugins/delete/delete.js";
13
+ import "jodit/esm/plugins/file/file.js";
14
+ import "jodit/esm/plugins/print/print.js";
15
+ import "jodit/esm/plugins/source/source.js";
16
+ const DEFAULT_ROWS = 5;
3
17
  /**
4
- * HTML element type guard
5
- * @param element - element to test
6
- * @returns truthy if element is an HTMLElement
18
+ * Converts rows count to Jodit editor min-height CSS value.
19
+ * Uses CSS variables --mg-b-font-size and --mg-b-line-height to compute height.
20
+ * @param rows - Number of rows
21
+ * @returns Height as CSS value in pixels (wysiwyg area + toolbar height of 40px + 2px borders)
22
+ * @throws If required CSS variables (--mg-b-font-size, --mg-b-line-height) are missing
7
23
  */
8
- const isHtmlElement = (element) => Boolean(element.tagName);
9
- /**
10
- * Implements the range API properly in Native Shadow
11
- * @param rootNode - root node
12
- * @returns selection
13
- */
14
- const getNativeRange = (rootNode) => {
15
- try {
16
- if (typeof document.createElement('div').attachShadow({ mode: 'open' }).getSelection === 'function') {
17
- // In Chromium, the shadow root has a getSelection function which returns the range
18
- return rootNode.getSelection().getRangeAt(0);
19
- }
20
- const selection = window.getSelection();
21
- // Webkit range retrieval is done with getComposedRanges (see: https://bugs.webkit.org/show_bug.cgi?id=163921)
22
- if (typeof selection.getComposedRanges === 'function') {
23
- return selection.getComposedRanges(rootNode)[0];
24
- }
25
- // Gecko implements the range API properly in Native Shadow: https://developer.mozilla.org/en-US/docs/Web/API/Selection/getRangeAt
26
- return selection.getRangeAt(0);
24
+ export const rowsToEditorHeight = (rows) => {
25
+ const root = document.documentElement;
26
+ const computedStyle = getComputedStyle(root);
27
+ const fontSizeValue = computedStyle.getPropertyValue('--mg-b-font-size').trim();
28
+ const lineHeightValue = computedStyle.getPropertyValue('--mg-b-line-height').trim();
29
+ if (fontSizeValue === '') {
30
+ throw new Error('mg-input-rich-text-editor: CSS variable --mg-b-font-size is not defined.');
27
31
  }
28
- catch (_a) {
29
- return null;
32
+ if (lineHeightValue === '') {
33
+ throw new Error('mg-input-rich-text-editor: CSS variable --mg-b-line-height is not defined.');
30
34
  }
35
+ const fontSizeRem = parseFloat(fontSizeValue.replace('rem', ''));
36
+ const lineHeight = parseFloat(lineHeightValue);
37
+ const htmlFontSize = parseFloat(getComputedStyle(root).fontSize);
38
+ const fontSizePx = fontSizeRem * htmlFontSize;
39
+ const lineHeightPx = fontSizePx * lineHeight;
40
+ const paddingVertical = 0.8 * htmlFontSize;
41
+ const contentHeight = lineHeightPx * rows;
42
+ const wysiwygHeight = contentHeight + paddingVertical * 2;
43
+ const toolbarHeight = 40;
44
+ const borderHeight = 2;
45
+ const totalHeight = wysiwygHeight + toolbarHeight + borderHeight;
46
+ return `${Math.round(totalHeight)}px`;
31
47
  };
32
48
  /**
33
- * Quill overrides to support shadow dom
34
- * https://github.com/slab/quill/issues/2961#issuecomment-1775999845
35
- * @param editor - Quill instance
49
+ * Configures Jodit editor
50
+ * @param element - Component element (HTMLMgInputRichTextEditorElement)
51
+ * @param editorElement - Textarea element for the editor
52
+ * @param config - Editor configuration options
53
+ * @returns Configured Jodit editor instance
36
54
  */
37
- const setQuillOverrides = (editor) => {
38
- const getRootNode = () => editor.root.getRootNode();
39
- // Original implementation uses document.active element but with an imlplementation in web-component with shadow root we need compare with it.
40
- editor.selection.hasFocus = () => getRootNode().activeElement === editor.root;
41
- // Original implementation uses document.getSelection which does not work in Native Shadow.
42
- // Replace document.getSelection with shadow dom equivalent (different for each browser)
43
- editor.selection.getNativeRange = () => {
44
- const nativeRange = getNativeRange(getRootNode());
45
- return Boolean(nativeRange) ? editor.selection.normalizeNative(nativeRange) : null;
55
+ export const defineEditor = (element, editorElement, config) => {
56
+ const { value, modules, readOnly, disabled, placeholder, rows = DEFAULT_ROWS, handleTextChange, handleFocus, handleBlur } = config;
57
+ // Configure Jodit
58
+ // Note: Using Record<string, unknown> to avoid TypeScript complexity issues with Jodit's deeply nested Config type
59
+ // The actual configuration follows Jodit's Config interface from jodit/esm/types
60
+ const joditConfig = {
61
+ readonly: readOnly === true,
62
+ // When readOnly (readonly or disabled), disable ALL toolbar buttons including plugin buttons (print, source).
63
+ // By default Jodit keeps source, print, fullsize, about, dots active in read-only mode.
64
+ // Set to [] so that when setReadOnly(true) is called (now or later), no toolbar buttons stay active.
65
+ activeButtonsInReadOnly: [],
66
+ placeholder: placeholder || '', // Avoid `Type something...` placeholder by default
67
+ // Set tabIndex to 0 to enable keyboard navigation with Tab key when enabled
68
+ // When disabled, use -1 to exclude the editor from Tab navigation
69
+ tabIndex: disabled === true ? -1 : 0,
70
+ buttons: modules,
71
+ // Disable features we don't want
72
+ showXPathInStatusbar: false,
73
+ showCharsCounter: false,
74
+ showWordsCounter: false,
75
+ toolbarAdaptive: false,
76
+ // Configure source editor mode
77
+ sourceEditor: 'area',
78
+ // This ensures tooltips and popups are created inside the component's shadow root
79
+ shadowRoot: element.shadowRoot,
80
+ // Provide ownerDocument and ownerWindow to ensure Jodit uses the correct context
81
+ ownerDocument: element.shadowRoot.ownerDocument,
82
+ ownerWindow: window,
83
+ // Prevent fullscreen from breaking component's shadow root isolation
84
+ globalFullSize: false,
85
+ // Set min-height from rows (wysiwyg + toolbar + borders)
86
+ minHeight: rowsToEditorHeight(rows),
87
+ // Resizer configuration
88
+ allowResizeTags: new Set(['img', 'table']),
89
+ resizer: {
90
+ showSize: true,
91
+ hideSizeTimeout: 1000,
92
+ useAspectRatio: new Set(['img']), // Preserve aspect ratio for images only
93
+ forImageChangeAttributes: true,
94
+ min_width: 10,
95
+ min_height: 10,
96
+ },
97
+ // Inline toolbar configuration
98
+ toolbarInline: true,
99
+ tableAllowCellSelection: true,
100
+ popup: {
101
+ a: Jodit.atom(['link', 'unlink', 'delete']),
102
+ },
46
103
  };
47
- // Original implementation relies on Selection.addRange to programatically set the range, which does not work in Webkit with Native Shadow. Selection.addRange works fine in Chromium and Gecko.
48
- editor.selection.setNativeRange = (startContainer, startOffset, endContainer = startContainer, endOffset = startOffset, force = false) => {
49
- if ([startContainer === null || startContainer === void 0 ? void 0 : startContainer.parentNode, editor.root.parentNode, endContainer === null || endContainer === void 0 ? void 0 : endContainer.parentNode].some(node => node == null)) {
50
- return;
51
- }
52
- const selection = window.getSelection();
53
- if (!editor.selection.hasFocus())
54
- editor.root.focus();
55
- const native = (editor.selection.getNativeRange() || {}).native;
56
- if (!Boolean(native) ||
57
- force ||
58
- startContainer !== native.startContainer ||
59
- startOffset !== native.startOffset ||
60
- endContainer !== native.endContainer ||
61
- endOffset !== native.endOffset) {
62
- if (isHtmlElement(startContainer) && startContainer.tagName === 'BR') {
63
- startOffset = [].indexOf.call(startContainer.parentNode.childNodes, startContainer);
64
- startContainer = startContainer.parentNode;
104
+ // Initialize Jodit editor
105
+ const joditInstance = Jodit.make(editorElement, joditConfig);
106
+ // Add custom classes
107
+ // These classes are added to Jodit's DOM elements for styling purposes
108
+ const wrapperElement = editorElement.parentElement;
109
+ const addCustomClass = (selector, className) => {
110
+ wrapperElement.querySelector(selector).classList.add(className);
111
+ };
112
+ /**
113
+ * Helpers for Jodit toolbar accessibility.
114
+ * @returns Toolbar element or null if not found
115
+ */
116
+ const getJoditToolbarElement = () => wrapperElement.querySelector('.jodit-toolbar__box');
117
+ /**
118
+ * Get the WYSIWYG editor element.
119
+ * @returns WYSIWYG element or null if not found
120
+ */
121
+ const getJoditWysiwygElement = () => wrapperElement.querySelector('.jodit-wysiwyg');
122
+ /**
123
+ * Get focusable toolbar buttons.
124
+ * @returns Array of focusable toolbar buttons
125
+ */
126
+ const getFocusableToolbarButtons = (toolbarEl) => {
127
+ if (toolbarEl === null)
128
+ return null;
129
+ // Find all buttons within the toolbar, excluding disabled ones
130
+ const buttons = Array.from(toolbarEl.querySelectorAll('button:not([disabled])'));
131
+ // Filter out buttons that are not visible or are in popups/dropdowns
132
+ return buttons.filter(button => {
133
+ const isVisible = button.offsetParent !== null;
134
+ const isInToolbar = toolbarEl.contains(button);
135
+ // Exclude buttons in popups or dropdowns (they have their own navigation)
136
+ const isInPopup = button.closest('.jodit-popup, .jodit-dropdown') !== null;
137
+ return isVisible && isInToolbar && !isInPopup;
138
+ });
139
+ };
140
+ addCustomClass('.jodit-container', 'mg-c-input__container');
141
+ addCustomClass('.jodit-toolbar__box', 'mg-c-input__toolbar-box');
142
+ addCustomClass('.jodit-workplace', 'mg-c-input__workplace');
143
+ addCustomClass('.jodit-wysiwyg', 'mg-c-input__wysiwyg');
144
+ // Improve toolbar accessibility
145
+ // Add ARIA attributes and keyboard navigation to the toolbar container for better screen reader support
146
+ const toolbarElement = getJoditToolbarElement();
147
+ if (toolbarElement !== null) {
148
+ // Set role="toolbar" to identify this as a toolbar widget
149
+ // This helps screen readers understand the toolbar's purpose and enables proper keyboard navigation
150
+ toolbarElement.setAttribute('role', 'toolbar');
151
+ toolbarElement.setAttribute('aria-label', 'Text formatting toolbar');
152
+ /**
153
+ * Handle keyboard navigation within the toolbar
154
+ * Implements ARIA toolbar pattern: ArrowLeft/Right for navigation, Home/End for first/last
155
+ */
156
+ const handleToolbarKeyDown = (event) => {
157
+ // Only handle keys when focus is within the toolbar
158
+ const target = event.target;
159
+ if (!toolbarElement.contains(target) || target.tagName !== 'BUTTON') {
160
+ return;
65
161
  }
66
- if (isHtmlElement(endContainer) && endContainer.tagName === 'BR') {
67
- endOffset = [].indexOf.call(endContainer.parentNode.childNodes, endContainer);
68
- endContainer = endContainer.parentNode;
162
+ const buttons = getFocusableToolbarButtons(toolbarElement);
163
+ if (buttons === null || buttons.length === 0)
164
+ return;
165
+ const currentIndex = buttons.indexOf(target);
166
+ if (currentIndex === -1)
167
+ return;
168
+ let targetIndex = currentIndex;
169
+ switch (event.key) {
170
+ case 'ArrowLeft':
171
+ event.preventDefault();
172
+ event.stopPropagation();
173
+ // Move to previous button, wrap to last if at first
174
+ targetIndex = currentIndex > 0 ? currentIndex - 1 : buttons.length - 1;
175
+ buttons[targetIndex].focus();
176
+ break;
177
+ case 'ArrowRight':
178
+ event.preventDefault();
179
+ event.stopPropagation();
180
+ // Move to next button, wrap to first if at last
181
+ targetIndex = currentIndex < buttons.length - 1 ? currentIndex + 1 : 0;
182
+ buttons[targetIndex].focus();
183
+ break;
184
+ case 'Home':
185
+ event.preventDefault();
186
+ event.stopPropagation();
187
+ // Move to first button
188
+ buttons[0].focus();
189
+ break;
190
+ case 'End':
191
+ event.preventDefault();
192
+ event.stopPropagation();
193
+ // Move to last button
194
+ buttons[buttons.length - 1].focus();
195
+ break;
196
+ case 'Tab':
197
+ // Allow Tab to work normally (exit toolbar)
198
+ break;
199
+ default:
200
+ // Let other keys work normally (Enter, Space, etc.)
201
+ return;
202
+ }
203
+ };
204
+ /**
205
+ * Hide SVG icons from screen readers in toolbar buttons.
206
+ * Toolbar buttons already have aria-label, so SVG icons are purely decorative.
207
+ * Without aria-hidden, VoiceOver announces them as images.
208
+ */
209
+ const hideToolbarSvgsFromScreenReaders = () => {
210
+ toolbarElement.querySelectorAll('svg').forEach(svg => {
211
+ svg.setAttribute('aria-hidden', 'true');
212
+ });
213
+ };
214
+ // Hide SVG icons from screen readers on first render
215
+ hideToolbarSvgsFromScreenReaders();
216
+ // Set up event listeners for keyboard navigation
217
+ toolbarElement.addEventListener('keydown', handleToolbarKeyDown, true);
218
+ // Hide SVGs when toolbar content changes (buttons can be added/removed dynamically)
219
+ const toolbarObserver = new MutationObserver(() => {
220
+ hideToolbarSvgsFromScreenReaders();
221
+ });
222
+ toolbarObserver.observe(toolbarElement, {
223
+ childList: true,
224
+ subtree: true,
225
+ attributes: true,
226
+ attributeFilter: ['disabled'],
227
+ });
228
+ }
229
+ // Transfer accessibility attributes from the hidden textarea to the WYSIWYG editor
230
+ // The textarea is hidden by Jodit (display: none), so its aria-describedby is not accessible.
231
+ // We need to transfer it to the actual editable element (.jodit-wysiwyg) so screen readers
232
+ // can properly announce help text and error messages.
233
+ if (getJoditWysiwygElement() !== null) {
234
+ const wysiwygElement = getJoditWysiwygElement();
235
+ if (wysiwygElement !== null) {
236
+ // mg-input sets aria-describedby on the textarea in its componentDidLoad (child runs before parent)
237
+ const ariaDescribedBy = editorElement.getAttribute('aria-describedby');
238
+ if (ariaDescribedBy !== null) {
239
+ wysiwygElement.setAttribute('aria-describedby', ariaDescribedBy);
69
240
  }
70
- selection.setBaseAndExtent(startContainer, startOffset, endContainer, endOffset);
241
+ // Also set role="textbox" and aria-multiline="true" for proper screen reader support
242
+ wysiwygElement.setAttribute('role', 'textbox');
243
+ wysiwygElement.setAttribute('aria-multiline', 'true');
244
+ // Sync disabled state for screen readers (aria-disabled only when true, omitted otherwise)
245
+ if (disabled === true) {
246
+ wysiwygElement.setAttribute('aria-disabled', 'true');
247
+ }
248
+ else {
249
+ wysiwygElement.removeAttribute('aria-disabled');
250
+ }
251
+ // Associate the editor with the label for screen readers and label click
252
+ const identifier = element.identifier;
253
+ if (identifier !== '') {
254
+ wrapperElement.removeAttribute('id');
255
+ wysiwygElement.id = identifier;
256
+ // Make label click focus the editor like a native input.
257
+ const titleId = `${identifier}-title`;
258
+ const titleElement = element.shadowRoot.querySelector('mg-input-title');
259
+ if (titleElement !== null && titleElement !== undefined) {
260
+ if (titleElement.id !== titleId) {
261
+ titleElement.id = titleId;
262
+ }
263
+ titleElement.addEventListener('click', () => {
264
+ joditInstance.focus();
265
+ });
266
+ }
267
+ // Link to the label for screen readers
268
+ wysiwygElement.setAttribute('aria-labelledby', titleId);
269
+ }
270
+ // Set up a MutationObserver to sync aria-describedby changes from textarea to wysiwyg
271
+ // This handles dynamic updates when error messages appear/disappear
272
+ const observer = new MutationObserver(() => {
273
+ const updatedAriaDescribedBy = editorElement.getAttribute('aria-describedby');
274
+ if (updatedAriaDescribedBy !== null) {
275
+ wysiwygElement.setAttribute('aria-describedby', updatedAriaDescribedBy);
276
+ }
277
+ else {
278
+ wysiwygElement.removeAttribute('aria-describedby');
279
+ }
280
+ });
281
+ observer.observe(editorElement, {
282
+ attributes: true,
283
+ attributeFilter: ['aria-describedby'],
284
+ });
285
+ // Set up Shift+Tab interception on the wysiwyg element (contenteditable)
286
+ // This intercepts Shift+Tab from the editor to redirect to the first toolbar button
287
+ const handleWysiwygShiftTab = (event) => {
288
+ // Only handle Shift+Tab (backward navigation)
289
+ if (event.key !== 'Tab' || !event.shiftKey) {
290
+ return;
291
+ }
292
+ const buttons = getFocusableToolbarButtons(getJoditToolbarElement());
293
+ if (buttons !== null && buttons.length > 0) {
294
+ // Prevent default Tab behavior to intercept navigation
295
+ event.preventDefault();
296
+ event.stopPropagation();
297
+ // Focus first toolbar button directly
298
+ buttons[0].focus();
299
+ }
300
+ };
301
+ // Listen for keydown events directly on the wysiwyg element
302
+ wysiwygElement.addEventListener('keydown', handleWysiwygShiftTab, true);
71
303
  }
72
- };
73
- // Subscribe to selection change separately, because emitter in Quill doesn't catch this event in Shadow DOM
74
- document.addEventListener('selectionchange', () => {
75
- editor.selection.update();
76
- });
77
- };
78
- /**
79
- * Fixes for handling text selection in Quill when used within the Shadow DOM.
80
- * - Fixes focus detection
81
- * - Adapts native range handling to work with the Shadow DOM
82
- * - Correctly manages text selection across Shadow DOM boundaries
83
- * - Sets up selection change events
84
- * @returns Quill instance
85
- */
86
- export const defineEditor = (wrapperElement, { value, modules, readOnly, placeholder, handleTextChange, handleFocus, handleBlur }) => {
87
- const toolbarOptions = {
88
- toolbar: [['bold', 'italic', 'underline'], [{ list: 'ordered' }, { list: 'bullet' }], ['link'], ['clean']],
89
- };
90
- const editor = new Quill(wrapperElement.querySelector('div'), {
91
- theme: 'snow',
92
- modules: modules || toolbarOptions,
93
- readOnly,
94
- placeholder,
95
- });
96
- if (isValidString(value) && /<[a-z][\s\S]*>/i.test(value)) {
97
- editor.clipboard.dangerouslyPasteHTML(value);
98
304
  }
99
- else if (isValidString(value)) {
100
- editor.setText(value);
305
+ // Set initial value
306
+ if (isValidString(value)) {
307
+ joditInstance.value = value;
101
308
  }
102
- const editorContent = wrapperElement.querySelector('.ql-editor');
103
- editorContent.addEventListener('focus', handleFocus);
104
- editorContent.addEventListener('blur', handleBlur);
105
- // Add an event listener for the text-change event
106
- editor.on('text-change', handleTextChange);
107
- setQuillOverrides(editor);
108
- return editor;
309
+ // Set up event listeners
310
+ joditInstance.events.on('change', handleTextChange);
311
+ joditInstance.events.on('focus', handleFocus);
312
+ joditInstance.events.on('blur', handleBlur);
313
+ // Return the Jodit instance directly
314
+ return joditInstance;
109
315
  };
@@ -0,0 +1,29 @@
1
+ /** Default toolbar modules when the modules prop is not set. */
2
+ export const DEFAULT_MODULES = [
3
+ 'bold',
4
+ 'italic',
5
+ 'underline',
6
+ 'strikethrough',
7
+ 'eraser',
8
+ '|',
9
+ 'ul',
10
+ 'ol',
11
+ '|',
12
+ 'superscript',
13
+ 'subscript',
14
+ '|',
15
+ 'brush',
16
+ '|',
17
+ 'link',
18
+ 'image',
19
+ 'file',
20
+ '|',
21
+ 'table',
22
+ '|',
23
+ 'undo',
24
+ 'redo',
25
+ '|',
26
+ 'print',
27
+ '|',
28
+ 'source',
29
+ ];