kempo-ui 0.3.8 → 0.3.10

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 (248) hide show
  1. package/dist/components/CodeEditor.js +96 -0
  2. package/dist/components/HtmlEditor.js +155 -30
  3. package/dist/components/codeEditorControls/CodeEditorControl.js +17 -0
  4. package/dist/components/codeEditorControls/ControlGroup.js +12 -0
  5. package/dist/components/codeEditorControls/ControlSpacer.js +6 -0
  6. package/dist/components/codeEditorControls/CopyCode.js +9 -0
  7. package/dist/components/codeEditorControls/EditorTheme.js +26 -0
  8. package/dist/components/codeEditorControls/FindReplace.js +7 -0
  9. package/dist/components/codeEditorControls/FoldAll.js +7 -0
  10. package/dist/components/codeEditorControls/FontSize.js +13 -0
  11. package/dist/components/codeEditorControls/FormatCode.js +9 -0
  12. package/dist/components/codeEditorControls/Fullscreen.js +12 -0
  13. package/dist/components/codeEditorControls/LanguageSelect.js +15 -0
  14. package/dist/components/codeEditorControls/Minimap.js +8 -0
  15. package/dist/components/codeEditorControls/Redo.js +7 -0
  16. package/dist/components/codeEditorControls/Undo.js +7 -0
  17. package/dist/components/codeEditorControls/WordWrap.js +8 -0
  18. package/dist/components/htmlEditorControls/AlignCenter.js +4 -4
  19. package/dist/components/htmlEditorControls/AlignJustify.js +4 -4
  20. package/dist/components/htmlEditorControls/AlignLeft.js +4 -4
  21. package/dist/components/htmlEditorControls/AlignRight.js +4 -4
  22. package/dist/components/htmlEditorControls/Bold.js +4 -4
  23. package/dist/components/htmlEditorControls/BulletList.js +4 -4
  24. package/dist/components/htmlEditorControls/ClearFormatting.js +4 -4
  25. package/dist/components/htmlEditorControls/CodeBlock.js +2 -2
  26. package/dist/components/htmlEditorControls/ControlGroup.js +2 -4
  27. package/dist/components/htmlEditorControls/CreateLink.js +3 -3
  28. package/dist/components/htmlEditorControls/FormatBlock.js +4 -4
  29. package/dist/components/htmlEditorControls/FormatCode.js +1 -0
  30. package/dist/components/htmlEditorControls/HtmlEditorControl.js +2 -2
  31. package/dist/components/htmlEditorControls/InlineCode.js +2 -2
  32. package/dist/components/htmlEditorControls/InsertTable.js +3 -3
  33. package/dist/components/htmlEditorControls/Italic.js +4 -4
  34. package/dist/components/htmlEditorControls/Mode.js +3 -3
  35. package/dist/components/htmlEditorControls/NumberList.js +4 -4
  36. package/dist/components/htmlEditorControls/Strikethrough.js +4 -4
  37. package/dist/components/htmlEditorControls/TextBackgroundColor.js +1 -1
  38. package/dist/components/htmlEditorControls/TextColor.js +1 -1
  39. package/dist/components/htmlEditorControls/Underline.js +4 -4
  40. package/docs/components/accordion.html +2 -0
  41. package/docs/components/aside.html +2 -0
  42. package/docs/components/card.html +2 -0
  43. package/docs/components/code-editor.html +491 -0
  44. package/docs/components/color-picker.html +2 -0
  45. package/docs/components/content-slider.html +2 -0
  46. package/docs/components/context.html +2 -0
  47. package/docs/components/dialog.html +2 -0
  48. package/docs/components/dropdown.html +2 -0
  49. package/docs/components/filter-list.html +2 -0
  50. package/docs/components/focus-capture.html +2 -0
  51. package/docs/components/html-editor.html +525 -212
  52. package/docs/components/hybrid-component.html +2 -0
  53. package/docs/components/icon.html +2 -0
  54. package/docs/components/import.html +2 -0
  55. package/docs/components/light-component.html +2 -0
  56. package/docs/components/nav-spacer.html +2 -0
  57. package/docs/components/nav.html +2 -0
  58. package/docs/components/photo-viewer.html +2 -0
  59. package/docs/components/resize.html +2 -0
  60. package/docs/components/shadow-component.html +2 -0
  61. package/docs/components/show-more.html +2 -0
  62. package/docs/components/sortable.html +2 -0
  63. package/docs/components/spinner.html +2 -0
  64. package/docs/components/split.html +2 -0
  65. package/docs/components/table.html +2 -0
  66. package/docs/components/tableControls.html +2 -0
  67. package/docs/components/tableCustomFields.html +2 -0
  68. package/docs/components/tableFetchRecords.html +2 -0
  69. package/docs/components/tableFieldSortHide.html +2 -0
  70. package/docs/components/tablePagination.html +2 -0
  71. package/docs/components/tablePlaceholder.html +2 -0
  72. package/docs/components/tableRecordEditing.html +2 -0
  73. package/docs/components/tableRecordFiltering.html +2 -0
  74. package/docs/components/tableRecordHiding.html +2 -0
  75. package/docs/components/tableRecordSearching.html +2 -0
  76. package/docs/components/tableRecordSelection.html +2 -0
  77. package/docs/components/tableRowControls.html +2 -0
  78. package/docs/components/tableServerSync.html +2 -0
  79. package/docs/components/tableSorting.html +2 -0
  80. package/docs/components/tabs.html +2 -0
  81. package/docs/components/tags.html +2 -0
  82. package/docs/components/theme-select.html +2 -0
  83. package/docs/components/theme-switcher.html +2 -0
  84. package/docs/components/timestamp.html +2 -0
  85. package/docs/components/toast.html +2 -0
  86. package/docs/components/toggle.html +2 -0
  87. package/docs/components/tree.html +2 -0
  88. package/docs/icons/auto_fix_high.svg +1 -0
  89. package/docs/icons/content_copy.svg +1 -0
  90. package/docs/icons/contrast.svg +1 -0
  91. package/docs/icons/frame_source.svg +1 -0
  92. package/docs/icons/fullscreen.svg +1 -0
  93. package/docs/icons/fullscreen_exit.svg +1 -0
  94. package/docs/icons/map.svg +1 -0
  95. package/docs/icons/redo.svg +1 -0
  96. package/docs/icons/text_decrease.svg +1 -0
  97. package/docs/icons/text_increase.svg +1 -0
  98. package/docs/icons/undo.svg +1 -0
  99. package/docs/icons/unfold_less.svg +1 -0
  100. package/docs/icons/unfold_more.svg +1 -0
  101. package/docs/icons/wrap_text.svg +1 -0
  102. package/docs/index.html +8 -0
  103. package/docs/src/components/CodeEditor.js +96 -0
  104. package/docs/src/components/HtmlEditor.js +155 -30
  105. package/docs/src/components/codeEditorControls/CodeEditorControl.js +17 -0
  106. package/docs/src/components/codeEditorControls/ControlGroup.js +12 -0
  107. package/docs/src/components/codeEditorControls/ControlSpacer.js +6 -0
  108. package/docs/src/components/codeEditorControls/CopyCode.js +9 -0
  109. package/docs/src/components/codeEditorControls/EditorTheme.js +26 -0
  110. package/docs/src/components/codeEditorControls/FindReplace.js +7 -0
  111. package/docs/src/components/codeEditorControls/FoldAll.js +7 -0
  112. package/docs/src/components/codeEditorControls/FontSize.js +13 -0
  113. package/docs/src/components/codeEditorControls/FormatCode.js +9 -0
  114. package/docs/src/components/codeEditorControls/Fullscreen.js +12 -0
  115. package/docs/src/components/codeEditorControls/LanguageSelect.js +15 -0
  116. package/docs/src/components/codeEditorControls/Minimap.js +8 -0
  117. package/docs/src/components/codeEditorControls/Redo.js +7 -0
  118. package/docs/src/components/codeEditorControls/Undo.js +7 -0
  119. package/docs/src/components/codeEditorControls/WordWrap.js +8 -0
  120. package/docs/src/components/htmlEditorControls/AlignCenter.js +4 -4
  121. package/docs/src/components/htmlEditorControls/AlignJustify.js +4 -4
  122. package/docs/src/components/htmlEditorControls/AlignLeft.js +4 -4
  123. package/docs/src/components/htmlEditorControls/AlignRight.js +4 -4
  124. package/docs/src/components/htmlEditorControls/Bold.js +4 -4
  125. package/docs/src/components/htmlEditorControls/BulletList.js +4 -4
  126. package/docs/src/components/htmlEditorControls/ClearFormatting.js +4 -4
  127. package/docs/src/components/htmlEditorControls/CodeBlock.js +2 -2
  128. package/docs/src/components/htmlEditorControls/ControlGroup.js +2 -4
  129. package/docs/src/components/htmlEditorControls/CreateLink.js +3 -3
  130. package/docs/src/components/htmlEditorControls/FormatBlock.js +4 -4
  131. package/docs/src/components/htmlEditorControls/FormatCode.js +1 -0
  132. package/docs/src/components/htmlEditorControls/HtmlEditorControl.js +2 -2
  133. package/docs/src/components/htmlEditorControls/InlineCode.js +2 -2
  134. package/docs/src/components/htmlEditorControls/InsertTable.js +3 -3
  135. package/docs/src/components/htmlEditorControls/Italic.js +4 -4
  136. package/docs/src/components/htmlEditorControls/Mode.js +3 -3
  137. package/docs/src/components/htmlEditorControls/NumberList.js +4 -4
  138. package/docs/src/components/htmlEditorControls/Strikethrough.js +4 -4
  139. package/docs/src/components/htmlEditorControls/TextBackgroundColor.js +1 -1
  140. package/docs/src/components/htmlEditorControls/TextColor.js +1 -1
  141. package/docs/src/components/htmlEditorControls/Underline.js +4 -4
  142. package/docs/utils/context.html +2 -0
  143. package/docs/utils/cookie.html +2 -0
  144. package/docs/utils/debounce.html +2 -0
  145. package/docs/utils/drag.html +2 -0
  146. package/docs/utils/elevation.html +2 -0
  147. package/docs/utils/formatTimestamp.html +2 -0
  148. package/docs/utils/object.html +2 -0
  149. package/docs/utils/propConverters.html +2 -0
  150. package/docs/utils/string.html +2 -0
  151. package/docs/utils/theme.html +2 -0
  152. package/docs/utils/toTitleCase.html +2 -0
  153. package/docs/utils/type.html +2 -0
  154. package/docs/utils/wait.html +2 -0
  155. package/docs-src/components/code-editor.page.html +235 -0
  156. package/docs-src/components/html-editor.page.html +528 -214
  157. package/docs-src/index.page.html +6 -0
  158. package/docs-src/nav.fragment.html +2 -0
  159. package/icons/auto_fix_high.svg +1 -0
  160. package/icons/content_copy.svg +1 -0
  161. package/icons/contrast.svg +1 -0
  162. package/icons/frame_source.svg +1 -0
  163. package/icons/fullscreen.svg +1 -0
  164. package/icons/fullscreen_exit.svg +1 -0
  165. package/icons/map.svg +1 -0
  166. package/icons/redo.svg +1 -0
  167. package/icons/text_decrease.svg +1 -0
  168. package/icons/text_increase.svg +1 -0
  169. package/icons/undo.svg +1 -0
  170. package/icons/unfold_less.svg +1 -0
  171. package/icons/unfold_more.svg +1 -0
  172. package/icons/wrap_text.svg +1 -0
  173. package/llm.txt +2 -1
  174. package/package.json +3 -3
  175. package/src/components/CodeEditor.js +495 -0
  176. package/src/components/HtmlEditor.js +527 -152
  177. package/src/components/codeEditorControls/CodeEditorControl.js +134 -0
  178. package/src/components/codeEditorControls/ControlGroup.js +70 -0
  179. package/src/components/codeEditorControls/ControlSpacer.js +23 -0
  180. package/src/components/codeEditorControls/CopyCode.js +37 -0
  181. package/src/components/codeEditorControls/EditorTheme.js +81 -0
  182. package/src/components/codeEditorControls/FindReplace.js +35 -0
  183. package/src/components/codeEditorControls/FoldAll.js +49 -0
  184. package/src/components/codeEditorControls/FontSize.js +45 -0
  185. package/src/components/codeEditorControls/FormatCode.js +37 -0
  186. package/src/components/codeEditorControls/Fullscreen.js +72 -0
  187. package/src/components/codeEditorControls/LanguageSelect.js +74 -0
  188. package/src/components/codeEditorControls/Minimap.js +60 -0
  189. package/src/components/codeEditorControls/Redo.js +35 -0
  190. package/src/components/codeEditorControls/Undo.js +35 -0
  191. package/src/components/codeEditorControls/WordWrap.js +60 -0
  192. package/src/components/htmlEditorControls/AlignCenter.js +2 -4
  193. package/src/components/htmlEditorControls/AlignJustify.js +2 -4
  194. package/src/components/htmlEditorControls/AlignLeft.js +2 -4
  195. package/src/components/htmlEditorControls/AlignRight.js +2 -4
  196. package/src/components/htmlEditorControls/Bold.js +2 -4
  197. package/src/components/htmlEditorControls/BulletList.js +2 -4
  198. package/src/components/htmlEditorControls/ClearFormatting.js +2 -4
  199. package/src/components/htmlEditorControls/CodeBlock.js +3 -19
  200. package/src/components/htmlEditorControls/ControlGroup.js +16 -41
  201. package/src/components/htmlEditorControls/CreateLink.js +3 -5
  202. package/src/components/htmlEditorControls/FormatBlock.js +2 -4
  203. package/src/components/htmlEditorControls/FormatCode.js +7 -0
  204. package/src/components/htmlEditorControls/HtmlEditorControl.js +43 -5
  205. package/src/components/htmlEditorControls/InlineCode.js +3 -5
  206. package/src/components/htmlEditorControls/InsertTable.js +9 -53
  207. package/src/components/htmlEditorControls/Italic.js +2 -4
  208. package/src/components/htmlEditorControls/Mode.js +2 -0
  209. package/src/components/htmlEditorControls/NumberList.js +2 -4
  210. package/src/components/htmlEditorControls/Strikethrough.js +2 -4
  211. package/src/components/htmlEditorControls/TextBackgroundColor.js +0 -6
  212. package/src/components/htmlEditorControls/TextColor.js +0 -6
  213. package/src/components/htmlEditorControls/Underline.js +2 -4
  214. package/tests/components/CodeEditor.browser-test.js +297 -0
  215. package/tests/components/HtmlEditor.browser-test.js +207 -0
  216. package/tests/components/codeEditorControls/CopyCode.browser-test.js +57 -0
  217. package/tests/components/codeEditorControls/EditorTheme.browser-test.js +70 -0
  218. package/tests/components/codeEditorControls/FindReplace.browser-test.js +57 -0
  219. package/tests/components/codeEditorControls/FoldAll.browser-test.js +92 -0
  220. package/tests/components/codeEditorControls/FontSize.browser-test.js +74 -0
  221. package/tests/components/codeEditorControls/Fullscreen.browser-test.js +152 -0
  222. package/tests/components/codeEditorControls/LanguageSelect.browser-test.js +82 -0
  223. package/tests/components/codeEditorControls/Minimap.browser-test.js +84 -0
  224. package/tests/components/codeEditorControls/ModeVisibility.browser-test.js +82 -0
  225. package/tests/components/codeEditorControls/UndoRedo.browser-test.js +85 -0
  226. package/tests/components/codeEditorControls/WordWrap.browser-test.js +95 -0
  227. package/tests/components/htmlEditorControls/Align.browser-test.js +203 -0
  228. package/tests/components/htmlEditorControls/Bold.browser-test.js +127 -0
  229. package/tests/components/htmlEditorControls/BulletList.browser-test.js +127 -0
  230. package/tests/components/htmlEditorControls/CharacterCount.browser-test.js +106 -0
  231. package/tests/components/htmlEditorControls/ClearFormatting.browser-test.js +127 -0
  232. package/tests/components/htmlEditorControls/CodeBlock.browser-test.js +143 -0
  233. package/tests/components/htmlEditorControls/ControlGroup.browser-test.js +116 -0
  234. package/tests/components/htmlEditorControls/ControlSpacer.browser-test.js +69 -0
  235. package/tests/components/htmlEditorControls/CreateLink.browser-test.js +129 -0
  236. package/tests/components/htmlEditorControls/DropdownControl.browser-test.js +138 -0
  237. package/tests/components/htmlEditorControls/FormatBlock.browser-test.js +163 -0
  238. package/tests/components/htmlEditorControls/FormatCode.browser-test.js +155 -0
  239. package/tests/components/htmlEditorControls/InlineCode.browser-test.js +127 -0
  240. package/tests/components/htmlEditorControls/InsertTable.browser-test.js +129 -0
  241. package/tests/components/htmlEditorControls/Italic.browser-test.js +127 -0
  242. package/tests/components/htmlEditorControls/Mode.browser-test.js +138 -0
  243. package/tests/components/htmlEditorControls/NumberList.browser-test.js +127 -0
  244. package/tests/components/htmlEditorControls/Strikethrough.browser-test.js +127 -0
  245. package/tests/components/htmlEditorControls/TextBackgroundColor.browser-test.js +136 -0
  246. package/tests/components/htmlEditorControls/TextColor.browser-test.js +136 -0
  247. package/tests/components/htmlEditorControls/Underline.browser-test.js +127 -0
  248. package/tests/components/htmlEditorControls/WordCount.browser-test.js +106 -0
@@ -6,7 +6,7 @@ import { getCalculatedTheme, subscribeToTheme } from '../utils/theme.js';
6
6
  import Dialog from './Dialog.js';
7
7
 
8
8
  /*
9
- Default CDN URLs
9
+ Default CDN URLs
10
10
  */
11
11
  const LEXICAL_VERSION = '0.43.0';
12
12
  const MONACO_VERSION = '0.52.2';
@@ -23,11 +23,13 @@ export default class HtmlEditor extends ShadowComponent {
23
23
  value: { type: String, reflect: true },
24
24
  selection: { type: Object, state: true },
25
25
  mode: { type: String, reflect: true },
26
+ controls: { type: String, reflect: true },
26
27
  lexicalSrc: { type: String, attribute: 'lexical-src' },
27
28
  monacoSrc: { type: String, attribute: 'monaco-src' },
28
29
  nodes: { type: String },
29
30
  hasTopToolbar: { type: Boolean, state: true },
30
- hasBottomToolbar: { type: Boolean, state: true }
31
+ hasBottomToolbar: { type: Boolean, state: true },
32
+ fullscreen: { type: Boolean, reflect: true }
31
33
  };
32
34
 
33
35
  constructor() {
@@ -38,6 +40,8 @@ export default class HtmlEditor extends ShadowComponent {
38
40
  this.selection = null;
39
41
  this.cursor = null;
40
42
  this.mode = 'visual';
43
+ this.controls = '';
44
+ this.controlsLoaded = false;
41
45
  this.lexicalSrc = '';
42
46
  this.monacoSrc = '';
43
47
  this.nodes = '';
@@ -48,6 +52,11 @@ export default class HtmlEditor extends ShadowComponent {
48
52
  this.savedSelection = null;
49
53
  this.lexicalEditor = null;
50
54
  this.monacoEditor = null;
55
+ this.editorTheme = 'auto';
56
+ this.wordWrap = true;
57
+ this.minimapEnabled = false;
58
+ this.fontSize = 14;
59
+ this.fullscreen = false;
51
60
  this.lx = {};
52
61
  this.debouncedSyncValue = debounce(() => this.syncValueFromLexical(), 300);
53
62
  }
@@ -57,7 +66,7 @@ export default class HtmlEditor extends ShadowComponent {
57
66
  */
58
67
  connectedCallback() {
59
68
  super.connectedCallback();
60
- if(this.hasAttribute('value')){
69
+ if (this.hasAttribute('value')) {
61
70
  this.value = this.getAttribute('value');
62
71
  }
63
72
  this.slotObserver = new MutationObserver(() => this.updateToolbarVisibility());
@@ -71,21 +80,32 @@ export default class HtmlEditor extends ShadowComponent {
71
80
  this.cleanupFns?.forEach(fn => fn?.());
72
81
  this.monacoEditor?.dispose();
73
82
  this.unsubscribeTheme?.();
74
- if(this.syncShadowSelection) document.removeEventListener('selectionchange', this.syncShadowSelection);
83
+ if (this.syncShadowSelection) document.removeEventListener('selectionchange', this.syncShadowSelection);
84
+ if(this.fullscreen) this.exitFullscreen();
75
85
  }
76
86
 
77
87
  updateToolbarVisibility() {
78
- this.hasTopToolbar = Array.from(this.children).some(c => c.getAttribute('slot') === 'toolbar-top');
79
- this.hasBottomToolbar = Array.from(this.children).some(c => c.getAttribute('slot') === 'toolbar-bottom');
88
+ const slots = new Set(Array.from(this.children).map(c => c.getAttribute('slot')));
89
+ const set = this.constructor.controlSets[this.controls] ?? null;
90
+ this.hasTopToolbar =
91
+ !!(set?.topLeft || set?.topRight) ||
92
+ ['toolbar-top', 'toolbar-top-left', 'toolbar-top-right'].some(s => slots.has(s));
93
+ this.hasBottomToolbar =
94
+ !!(set?.bottomLeft || set?.bottomRight) ||
95
+ ['toolbar-bottom', 'toolbar-bottom-left', 'toolbar-bottom-right'].some(s => slots.has(s));
80
96
  }
81
97
 
82
98
  updated(changedProperties) {
83
99
  super.updated(changedProperties);
84
- if(changedProperties.has('value') && !this.skipValueSync){
85
- if(this.lexicalValueSync){
100
+ if (changedProperties.has('controls')) {
101
+ this.updateToolbarVisibility();
102
+ if (this.controls && this.controls !== 'none') this.loadControls();
103
+ }
104
+ if (changedProperties.has('value') && !this.skipValueSync) {
105
+ if (this.lexicalValueSync) {
86
106
  this.lexicalValueSync = false;
87
107
  } else {
88
- if(this.lexicalEditor && this.mode === 'visual' && !this.isVisualCompatible(this.value)){
108
+ if (this.lexicalEditor && this.mode === 'visual' && !this.isVisualCompatible(this.value)) {
89
109
  this.skipLexicalExport = true;
90
110
  this.mode = 'code';
91
111
  } else {
@@ -98,12 +118,17 @@ export default class HtmlEditor extends ShadowComponent {
98
118
  bubbles: true
99
119
  }));
100
120
  }
101
- if(changedProperties.has('mode')){
121
+ if (changedProperties.has('mode')) {
122
+ const scrollY = window.scrollY;
102
123
  this.handleModeSwitch(changedProperties.get('mode'));
103
124
  this.dispatchEvent(new CustomEvent('mode-changed', {
104
125
  detail: { mode: this.mode },
105
126
  bubbles: true
106
127
  }));
128
+ requestAnimationFrame(() => window.scrollTo(0, scrollY));
129
+ }
130
+ if(changedProperties.has('fullscreen')){
131
+ requestAnimationFrame(() => this.monacoEditor?.layout());
107
132
  }
108
133
  }
109
134
 
@@ -120,8 +145,56 @@ export default class HtmlEditor extends ShadowComponent {
120
145
  /*
121
146
  Module Loading
122
147
  */
148
+ async loadControls() {
149
+ if (this.controlsLoaded) return;
150
+ this.controlsLoaded = true;
151
+ const base = new URL('./htmlEditorControls/', import.meta.url).href;
152
+ await Promise.all([
153
+ import(/* @vite-ignore */ `${base}Bold.js`),
154
+ import(/* @vite-ignore */ `${base}Italic.js`),
155
+ import(/* @vite-ignore */ `${base}Underline.js`),
156
+ import(/* @vite-ignore */ `${base}Strikethrough.js`),
157
+ import(/* @vite-ignore */ `${base}InlineCode.js`),
158
+ import(/* @vite-ignore */ `${base}DropdownControl.js`),
159
+ import(/* @vite-ignore */ `${base}FormatBlock.js`),
160
+ import(/* @vite-ignore */ `${base}CodeBlock.js`),
161
+ import(/* @vite-ignore */ `${base}BulletList.js`),
162
+ import(/* @vite-ignore */ `${base}NumberList.js`),
163
+ import(/* @vite-ignore */ `${base}AlignLeft.js`),
164
+ import(/* @vite-ignore */ `${base}AlignCenter.js`),
165
+ import(/* @vite-ignore */ `${base}AlignRight.js`),
166
+ import(/* @vite-ignore */ `${base}AlignJustify.js`),
167
+ import(/* @vite-ignore */ `${base}TextColor.js`),
168
+ import(/* @vite-ignore */ `${base}TextBackgroundColor.js`),
169
+ import(/* @vite-ignore */ `${base}ClearFormatting.js`),
170
+ import(/* @vite-ignore */ `${base}CreateLink.js`),
171
+ import(/* @vite-ignore */ `${base}InsertTable.js`),
172
+ import(/* @vite-ignore */ `${base}ControlGroup.js`),
173
+ import(/* @vite-ignore */ `${base}ControlSpacer.js`),
174
+ import(/* @vite-ignore */ `${base}Mode.js`),
175
+ import(/* @vite-ignore */ `${base}WordCount.js`),
176
+ import(/* @vite-ignore */ `${base}CharacterCount.js`),
177
+ ]);
178
+ const cecBase = new URL('./codeEditorControls/', import.meta.url).href;
179
+ await Promise.all([
180
+ import(/* @vite-ignore */ `${cecBase}FormatCode.js`),
181
+ import(/* @vite-ignore */ `${cecBase}CopyCode.js`),
182
+ import(/* @vite-ignore */ `${cecBase}Undo.js`),
183
+ import(/* @vite-ignore */ `${cecBase}Redo.js`),
184
+ import(/* @vite-ignore */ `${cecBase}WordWrap.js`),
185
+ import(/* @vite-ignore */ `${cecBase}Minimap.js`),
186
+ import(/* @vite-ignore */ `${cecBase}FindReplace.js`),
187
+ import(/* @vite-ignore */ `${cecBase}FontSize.js`),
188
+ import(/* @vite-ignore */ `${cecBase}FoldAll.js`),
189
+ import(/* @vite-ignore */ `${cecBase}EditorTheme.js`),
190
+ import(/* @vite-ignore */ `${cecBase}Fullscreen.js`),
191
+ import(/* @vite-ignore */ `${cecBase}ControlGroup.js`),
192
+ ]);
193
+ this.requestUpdate();
194
+ }
195
+
123
196
  async loadNodeModules() {
124
- if(!this.nodes?.trim()) return [];
197
+ if (!this.nodes?.trim()) return [];
125
198
  const base = new URL('./htmlEditorNodes/', import.meta.url).href;
126
199
  const modules = await Promise.all(
127
200
  this.nodes.split(',').map(n => n.trim()).filter(Boolean).map(n => import(/* @vite-ignore */ `${base}${n}.js`))
@@ -130,7 +203,7 @@ export default class HtmlEditor extends ShadowComponent {
130
203
  }
131
204
 
132
205
  async loadLexicalModules() {
133
- const base = this.lexicalSrc || DEFAULT_LEXICAL_BASE;
206
+ const base = this.lexicalSrc || window.kempo?.lexicalUrl || DEFAULT_LEXICAL_BASE;
134
207
  const url = pkg => lexicalUrl(base, pkg);
135
208
  const [lexical, richText, lexicalHtml, history, list, link, selection, table, code] = await Promise.all([
136
209
  import(/* @vite-ignore */ url('lexical')),
@@ -152,7 +225,7 @@ export default class HtmlEditor extends ShadowComponent {
152
225
  span: () => ({
153
226
  conversion: domNode => {
154
227
  const style = domNode.getAttribute('style');
155
- if(!style) return null;
228
+ if (!style) return null;
156
229
  const node = lexical.$createTextNode(domNode.textContent);
157
230
  node.setStyle(style);
158
231
  return { node };
@@ -200,15 +273,15 @@ export default class HtmlEditor extends ShadowComponent {
200
273
  richText.registerRichText(this.lexicalEditor),
201
274
  history.registerHistory(this.lexicalEditor, history.createEmptyHistoryState(), 300)
202
275
  ];
203
- if(list.registerList) this.cleanupFns.push(list.registerList(this.lexicalEditor));
204
- if(table.registerTable) this.cleanupFns.push(table.registerTable(this.lexicalEditor));
205
- if(code.registerCodeHighlighting) this.cleanupFns.push(code.registerCodeHighlighting(this.lexicalEditor));
206
- if(link.registerLink) this.cleanupFns.push(link.registerLink(this.lexicalEditor, {
276
+ if (list.registerList) this.cleanupFns.push(list.registerList(this.lexicalEditor));
277
+ if (table.registerTable) this.cleanupFns.push(table.registerTable(this.lexicalEditor));
278
+ if (code.registerCodeHighlighting) this.cleanupFns.push(code.registerCodeHighlighting(this.lexicalEditor));
279
+ if (link.registerLink) this.cleanupFns.push(link.registerLink(this.lexicalEditor, {
207
280
  validateUrl: url => { try { new URL(url); return true; } catch { return false; } }
208
281
  }));
209
282
 
210
- if(this.value){
211
- if(this.isVisualCompatible(this.value)){
283
+ if (this.value) {
284
+ if (this.isVisualCompatible(this.value)) {
212
285
  this.importHtmlToLexical(this.value);
213
286
  } else {
214
287
  this.skipLexicalExport = true;
@@ -217,7 +290,7 @@ export default class HtmlEditor extends ShadowComponent {
217
290
  }
218
291
 
219
292
  this.lexicalEditor.registerUpdateListener(({ dirtyElements, dirtyLeaves }) => {
220
- if(dirtyElements.size === 0 && dirtyLeaves.size === 0) return;
293
+ if (dirtyElements.size === 0 && dirtyLeaves.size === 0) return;
221
294
  this.debouncedSyncValue();
222
295
  this.dispatchEvent(new CustomEvent('input', {
223
296
  detail: { value: this.exportHtmlFromLexical() },
@@ -232,14 +305,14 @@ export default class HtmlEditor extends ShadowComponent {
232
305
  );
233
306
 
234
307
  this.syncShadowSelection = () => {
235
- if(this.mode !== 'visual' || !this.lexicalEditor) return;
308
+ if (this.mode !== 'visual' || !this.lexicalEditor) return;
236
309
  const shadowSel = this.shadowRoot.getSelection?.();
237
- if(!shadowSel || shadowSel.rangeCount === 0) return;
310
+ if (!shadowSel || shadowSel.rangeCount === 0) return;
238
311
  const range = shadowSel.getRangeAt(0);
239
- if(!this.lexicalContainer.contains(range.startContainer)) return;
312
+ if (!this.lexicalContainer.contains(range.startContainer)) return;
240
313
  this.lexicalEditor.update(() => {
241
314
  const lexSel = lexical.$createRangeSelectionFromDom(shadowSel, this.lexicalEditor);
242
- if(lexSel) lexical.$setSelection(lexSel);
315
+ if (lexSel) lexical.$setSelection(lexSel);
243
316
  }, { discrete: true });
244
317
  this.updateSelection();
245
318
  };
@@ -247,21 +320,21 @@ export default class HtmlEditor extends ShadowComponent {
247
320
  }
248
321
 
249
322
  async initMonaco() {
250
- if(this.monacoEditor) return;
251
- if(this.monacoInitPromise) return this.monacoInitPromise;
323
+ if (this.monacoEditor) return;
324
+ if (this.monacoInitPromise) return this.monacoInitPromise;
252
325
  this.monacoInitPromise = this._initMonaco();
253
326
  await this.monacoInitPromise;
254
327
  this.monacoInitPromise = null;
255
328
  }
256
329
 
257
330
  async _initMonaco() {
258
- const src = this.monacoSrc || DEFAULT_MONACO_SRC;
331
+ const src = this.monacoSrc || window.kempo?.monacoUrl || DEFAULT_MONACO_SRC;
259
332
 
260
333
  await new Promise((resolve, reject) => {
261
- if(window.monaco){ resolve(); return; }
262
- if(window.require?.defined?.('vs/editor/editor.main')){ resolve(); return; }
334
+ if (window.monaco) { resolve(); return; }
335
+ if (window.require?.defined?.('vs/editor/editor.main')) { resolve(); return; }
263
336
  const existing = document.querySelector(`script[src="${src}/vs/loader.js"]`);
264
- if(existing){
337
+ if (existing) {
265
338
  existing.addEventListener('load', () => {
266
339
  window.require.config({ paths: { vs: `${src}/vs` } });
267
340
  window.require(['vs/editor/editor.main'], () => resolve(), reject);
@@ -281,17 +354,18 @@ export default class HtmlEditor extends ShadowComponent {
281
354
  this.monacoEditor = window.monaco.editor.create(this.monacoContainer, {
282
355
  value: formatCode(this.value),
283
356
  language: 'html',
284
- theme: getCalculatedTheme() === 'dark' ? 'vs-dark' : 'vs',
285
- minimap: { enabled: false },
286
- wordWrap: 'on',
287
- fontSize: 14,
357
+ theme: this.resolveMonacoTheme(),
358
+ minimap: { enabled: this.minimapEnabled },
359
+ wordWrap: this.wordWrap ? 'on' : 'off',
360
+ fontSize: this.fontSize,
288
361
  scrollBeyondLastLine: false,
289
362
  automaticLayout: true,
290
- tabSize: 2
363
+ tabSize: 2,
364
+ padding: { top: 8 }
291
365
  });
292
366
 
293
367
  const monacoCSS = document.querySelector('link[href*="monaco"][href*="editor.main.css"]');
294
- if(monacoCSS){
368
+ if (monacoCSS) {
295
369
  const link = document.createElement('link');
296
370
  link.rel = 'stylesheet';
297
371
  link.href = monacoCSS.href;
@@ -299,7 +373,7 @@ export default class HtmlEditor extends ShadowComponent {
299
373
  }
300
374
 
301
375
  this.unsubscribeTheme = subscribeToTheme(() => {
302
- if(this.monacoEditor) window.monaco.editor.setTheme(getCalculatedTheme() === 'dark' ? 'vs-dark' : 'vs');
376
+ if (this.monacoEditor && this.editorTheme === 'auto') window.monaco.editor.setTheme(this.resolveMonacoTheme());
303
377
  });
304
378
 
305
379
  this.monacoEditor.onDidChangeModelContent(() => {
@@ -316,21 +390,21 @@ export default class HtmlEditor extends ShadowComponent {
316
390
  Content Sync
317
391
  */
318
392
  importHtmlToLexical(htmlString) {
319
- if(!this.lexicalEditor || !this.lx.lexicalHtml) return;
393
+ if (!this.lexicalEditor || !this.lx.lexicalHtml) return;
320
394
  const { lexical, lexicalHtml } = this.lx;
321
395
  const processed = (this.nodePreprocessors || []).reduce((str, fn) => fn(str), htmlString);
322
396
  this.lexicalEditor.update(() => {
323
397
  const root = lexical.$getRoot();
324
398
  root.clear();
325
- if(!processed?.trim()) return;
399
+ if (!processed?.trim()) return;
326
400
  const dom = new DOMParser().parseFromString(processed, 'text/html');
327
401
  const nodes = lexicalHtml.$generateNodesFromDOM(this.lexicalEditor, dom);
328
- if(nodes.length > 0) lexical.$insertNodes(nodes);
402
+ if (nodes.length > 0) lexical.$insertNodes(nodes);
329
403
  }, { discrete: true });
330
404
  }
331
405
 
332
406
  exportHtmlFromLexical() {
333
- if(!this.lexicalEditor || !this.lx.lexicalHtml) return this.value;
407
+ if (!this.lexicalEditor || !this.lx.lexicalHtml) return this.value;
334
408
  let result = '';
335
409
  this.lexicalEditor.getEditorState().read(() => {
336
410
  result = this.lx.lexicalHtml.$generateHtmlFromNodes(this.lexicalEditor, null);
@@ -339,16 +413,16 @@ export default class HtmlEditor extends ShadowComponent {
339
413
  }
340
414
 
341
415
  isVisualCompatible(htmlStr) {
342
- if(!htmlStr?.trim()) return true;
416
+ if (!htmlStr?.trim()) return true;
343
417
  const incompatibleTags = new Set(['script', 'style', 'meta', 'link', 'head', 'iframe', 'object', 'embed', 'canvas', 'video', 'audio', 'form', 'input', 'button', 'select', 'textarea', 'fieldset', 'label', 'noscript', 'template', 'slot', 'svg', 'math']);
344
418
  const checkers = this.nodeCompatCheckers || [];
345
419
  const doc = new DOMParser().parseFromString(htmlStr, 'text/html');
346
420
  const walker = document.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);
347
421
  let node;
348
- while((node = walker.nextNode())){
349
- if(checkers.some(check => check(node))) continue;
350
- if(node.nodeType === Node.COMMENT_NODE) return false;
351
- if(incompatibleTags.has(node.tagName?.toLowerCase())) return false;
422
+ while ((node = walker.nextNode())) {
423
+ if (checkers.some(check => check(node))) continue;
424
+ if (node.nodeType === Node.COMMENT_NODE) return false;
425
+ if (incompatibleTags.has(node.tagName?.toLowerCase())) return false;
352
426
  }
353
427
  return true;
354
428
  }
@@ -357,16 +431,16 @@ export default class HtmlEditor extends ShadowComponent {
357
431
  const doc = new DOMParser().parseFromString(html, 'text/html');
358
432
  doc.body.querySelectorAll('[class]').forEach(el => {
359
433
  const classes = Array.from(el.classList).filter(c => !c.startsWith('k-editor-') && c !== 'td-u' && c !== 'td-lt');
360
- if(classes.length === 0) el.removeAttribute('class');
434
+ if (classes.length === 0) el.removeAttribute('class');
361
435
  else el.className = classes.join(' ');
362
436
  });
363
437
  doc.body.querySelectorAll('[style]').forEach(el => {
364
438
  const style = el.style.cssText.replace(/white-space:\s*pre-wrap;?\s*/g, '').trim();
365
- if(!style) el.removeAttribute('style');
439
+ if (!style) el.removeAttribute('style');
366
440
  else el.style.cssText = style;
367
441
  });
368
442
  doc.body.querySelectorAll('span:not([class]):not([style]):not([id])').forEach(span => {
369
- if(!span.attributes.length) span.replaceWith(...span.childNodes);
443
+ if (!span.attributes.length) span.replaceWith(...span.childNodes);
370
444
  });
371
445
  doc.body.querySelectorAll('b > strong, i > em, b > b, strong > strong, i > i, em > em').forEach(inner => {
372
446
  inner.replaceWith(...inner.childNodes);
@@ -379,30 +453,30 @@ export default class HtmlEditor extends ShadowComponent {
379
453
  }
380
454
 
381
455
  syncValueFromLexical() {
382
- if(!this.lexicalEditor) return;
456
+ if (!this.lexicalEditor) return;
383
457
  this.lexicalValueSync = true;
384
458
  this.value = this.exportHtmlFromLexical();
385
459
  this.updateFormValue();
386
460
  }
387
461
 
388
462
  syncContentToEditors() {
389
- if(this.mode === 'visual' && this.lexicalEditor){
463
+ if (this.mode === 'visual' && this.lexicalEditor) {
390
464
  this.importHtmlToLexical(this.value);
391
465
  }
392
466
  }
393
467
 
394
468
  async handleModeSwitch(previousMode) {
395
- if(this.mode === 'code'){
396
- if(this.lexicalEditor && !this.skipLexicalExport) this.value = this.exportHtmlFromLexical();
469
+ if (this.mode === 'code') {
470
+ if (this.lexicalEditor && !this.skipLexicalExport) this.value = this.exportHtmlFromLexical();
397
471
  this.skipLexicalExport = false;
398
472
  await this.initMonaco();
399
- if(this.monacoEditor){
473
+ if (this.monacoEditor) {
400
474
  this.monacoEditor.setValue(formatCode(this.value));
401
475
  this.monacoEditor.layout();
402
476
  }
403
- } else if(this.mode === 'visual'){
404
- if(this.monacoEditor) this.value = this.monacoEditor.getValue();
405
- if(this.lexicalEditor) this.importHtmlToLexical(this.value);
477
+ } else if (this.mode === 'visual') {
478
+ if (this.monacoEditor) this.value = this.monacoEditor.getValue();
479
+ if (this.lexicalEditor) this.importHtmlToLexical(this.value);
406
480
  }
407
481
  this.requestUpdate();
408
482
  }
@@ -426,14 +500,14 @@ export default class HtmlEditor extends ShadowComponent {
426
500
  Selection Management
427
501
  */
428
502
  updateSelection = () => {
429
- if(this.mode !== 'visual' || !this.lexicalEditor){
503
+ if (this.mode !== 'visual' || !this.lexicalEditor) {
430
504
  this.selection = null;
431
505
  return;
432
506
  }
433
507
  const { lexical } = this.lx;
434
508
  this.lexicalEditor.getEditorState().read(() => {
435
509
  const sel = lexical.$getSelection();
436
- if(lexical.$isRangeSelection(sel) && !sel.isCollapsed()){
510
+ if (lexical.$isRangeSelection(sel) && !sel.isCollapsed()) {
437
511
  this.selection = { text: sel.getTextContent(), collapsed: false };
438
512
  } else {
439
513
  this.selection = null;
@@ -446,11 +520,11 @@ export default class HtmlEditor extends ShadowComponent {
446
520
  Public Methods - Mode Control
447
521
  */
448
522
  setMode(mode) {
449
- if(!['visual', 'code'].includes(mode)) return this;
450
- if(mode === 'visual' && !this.isVisualCompatible(this.getValue())){
523
+ if (!['visual', 'code'].includes(mode)) return this;
524
+ if (mode === 'visual' && !this.isVisualCompatible(this.getValue())) {
451
525
  Dialog.confirm(
452
526
  'This html contains code that is not compatible with the visual editor, the incompatible code will be lost',
453
- response => { if(response) this.mode = mode; },
527
+ response => { if (response) this.mode = mode; },
454
528
  { title: 'Warning', confirmText: 'Change Anyways' }
455
529
  );
456
530
  return this;
@@ -467,18 +541,18 @@ export default class HtmlEditor extends ShadowComponent {
467
541
  Public Methods - Content Management
468
542
  */
469
543
  getValue() {
470
- if(this.mode === 'visual' && this.lexicalEditor){
544
+ if (this.mode === 'visual' && this.lexicalEditor) {
471
545
  this.skipValueSync = true;
472
546
  this.value = this.exportHtmlFromLexical();
473
547
  this.skipValueSync = false;
474
- } else if(this.mode === 'code' && this.monacoEditor){
548
+ } else if (this.mode === 'code' && this.monacoEditor) {
475
549
  return this.monacoEditor.getValue();
476
550
  }
477
551
  return this.value;
478
552
  }
479
553
 
480
554
  setValue(htmlStr) {
481
- if(this.lexicalEditor && this.mode === 'visual' && !this.isVisualCompatible(htmlStr)){
555
+ if (this.lexicalEditor && this.mode === 'visual' && !this.isVisualCompatible(htmlStr)) {
482
556
  this.value = htmlStr;
483
557
  this.skipLexicalExport = true;
484
558
  this.mode = 'code';
@@ -487,8 +561,8 @@ export default class HtmlEditor extends ShadowComponent {
487
561
  }
488
562
  this.skipValueSync = true;
489
563
  this.value = htmlStr;
490
- if(this.mode === 'visual') this.syncContentToEditors();
491
- else if(this.mode === 'code' && this.monacoEditor) this.monacoEditor.setValue(formatCode(htmlStr));
564
+ if (this.mode === 'visual') this.syncContentToEditors();
565
+ else if (this.mode === 'code' && this.monacoEditor) this.monacoEditor.setValue(formatCode(htmlStr));
492
566
  this.updateFormValue();
493
567
  this.skipValueSync = false;
494
568
  return this;
@@ -521,11 +595,16 @@ export default class HtmlEditor extends ShadowComponent {
521
595
  return this;
522
596
  }
523
597
 
598
+ inlineCode() {
599
+ this.lexicalFormat('code');
600
+ return this;
601
+ }
602
+
524
603
  /*
525
604
  Public Methods - Lists
526
605
  */
527
606
  orderedList() {
528
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
607
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
529
608
  this.lexicalEditor.update(() => {
530
609
  this.lx.list.$insertList('number');
531
610
  }, { discrete: true });
@@ -533,7 +612,7 @@ export default class HtmlEditor extends ShadowComponent {
533
612
  }
534
613
 
535
614
  unorderedList() {
536
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
615
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
537
616
  this.lexicalEditor.update(() => {
538
617
  this.lx.list.$insertList('bullet');
539
618
  }, { discrete: true });
@@ -567,44 +646,44 @@ export default class HtmlEditor extends ShadowComponent {
567
646
  Public Methods - Text Color
568
647
  */
569
648
  setTextColor(color) {
570
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
649
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
571
650
  const { lexical, selection } = this.lx;
572
651
  this.lexicalEditor.update(() => {
573
652
  const sel = lexical.$getSelection();
574
- if(!lexical.$isRangeSelection(sel)) return;
653
+ if (!lexical.$isRangeSelection(sel)) return;
575
654
  selection.$patchStyleText(sel, { color });
576
655
  }, { discrete: true });
577
656
  return this;
578
657
  }
579
658
 
580
659
  removeTextColor() {
581
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
660
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
582
661
  const { lexical, selection } = this.lx;
583
662
  this.lexicalEditor.update(() => {
584
663
  const sel = lexical.$getSelection();
585
- if(!lexical.$isRangeSelection(sel)) return;
664
+ if (!lexical.$isRangeSelection(sel)) return;
586
665
  selection.$patchStyleText(sel, { color: null });
587
666
  }, { discrete: true });
588
667
  return this;
589
668
  }
590
669
 
591
670
  setTextBackgroundColor(color) {
592
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
671
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
593
672
  const { lexical, selection } = this.lx;
594
673
  this.lexicalEditor.update(() => {
595
674
  const sel = lexical.$getSelection();
596
- if(!lexical.$isRangeSelection(sel)) return;
675
+ if (!lexical.$isRangeSelection(sel)) return;
597
676
  selection.$patchStyleText(sel, { 'background-color': color });
598
677
  }, { discrete: true });
599
678
  return this;
600
679
  }
601
680
 
602
681
  removeTextBackgroundColor() {
603
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
682
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
604
683
  const { lexical, selection } = this.lx;
605
684
  this.lexicalEditor.update(() => {
606
685
  const sel = lexical.$getSelection();
607
- if(!lexical.$isRangeSelection(sel)) return;
686
+ if (!lexical.$isRangeSelection(sel)) return;
608
687
  selection.$patchStyleText(sel, { 'background-color': null });
609
688
  }, { discrete: true });
610
689
  return this;
@@ -614,13 +693,13 @@ export default class HtmlEditor extends ShadowComponent {
614
693
  Public Methods - Formatting Control
615
694
  */
616
695
  removeFormat() {
617
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
696
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
618
697
  const { lexical, selection } = this.lx;
619
698
  this.lexicalEditor.update(() => {
620
699
  const sel = lexical.$getSelection();
621
- if(!lexical.$isRangeSelection(sel)) return;
700
+ if (!lexical.$isRangeSelection(sel)) return;
622
701
  sel.getNodes().forEach(node => {
623
- if(lexical.$isTextNode(node)) node.setFormat(0);
702
+ if (lexical.$isTextNode(node)) node.setFormat(0);
624
703
  });
625
704
  selection.$patchStyleText(sel, { color: null, 'background-color': null });
626
705
  }, { discrete: true });
@@ -628,29 +707,29 @@ export default class HtmlEditor extends ShadowComponent {
628
707
  }
629
708
 
630
709
  formatBlock(tag) {
631
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
710
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
632
711
  const { lexical, richText, code } = this.lx;
633
712
  this.lexicalEditor.update(() => {
634
713
  const sel = lexical.$getSelection();
635
- if(!lexical.$isRangeSelection(sel)) return;
714
+ if (!lexical.$isRangeSelection(sel)) return;
636
715
  const anchor = sel.anchor.getNode();
637
716
  const topLevel = anchor.getTopLevelElementOrThrow();
638
717
  const isCodeNode = code.$isCodeNode(topLevel);
639
718
 
640
719
  let newBlock;
641
- if(tag === 'p'){
720
+ if (tag === 'p') {
642
721
  newBlock = lexical.$createParagraphNode();
643
- } else if(tag.match(/^h[1-6]$/)){
722
+ } else if (tag.match(/^h[1-6]$/)) {
644
723
  newBlock = richText.$createHeadingNode(tag);
645
- } else if(tag === 'blockquote'){
724
+ } else if (tag === 'blockquote') {
646
725
  newBlock = richText.$createQuoteNode();
647
- } else if(tag === 'pre'){
726
+ } else if (tag === 'pre') {
648
727
  newBlock = code.$createCodeNode();
649
728
  } else {
650
729
  return;
651
730
  }
652
731
 
653
- if(isCodeNode && tag !== 'pre'){
732
+ if (isCodeNode && tag !== 'pre') {
654
733
  const text = topLevel.getTextContent();
655
734
  topLevel.replace(newBlock);
656
735
  newBlock.append(lexical.$createTextNode(text));
@@ -664,8 +743,68 @@ export default class HtmlEditor extends ShadowComponent {
664
743
  return this;
665
744
  }
666
745
 
746
+ isSelectionInCodeBlock() {
747
+ if (this.mode !== 'visual' || !this.lexicalEditor) return false;
748
+ let result = false;
749
+ const { lexical, code } = this.lx;
750
+ this.lexicalEditor.getEditorState().read(() => {
751
+ const sel = lexical.$getSelection();
752
+ if (!lexical.$isRangeSelection(sel)) return;
753
+ result = code.$isCodeNode(sel.anchor.getNode().getTopLevelElementOrThrow());
754
+ });
755
+ return result;
756
+ }
757
+
758
+ getTableAtSelection() {
759
+ if (this.mode !== 'visual' || !this.lexicalEditor) return null;
760
+ let result = null;
761
+ const { lexical, table } = this.lx;
762
+ this.lexicalEditor.getEditorState().read(() => {
763
+ const sel = lexical.$getSelection();
764
+ if (!lexical.$isRangeSelection(sel)) return;
765
+ let node = sel.anchor.getNode();
766
+ while (node) {
767
+ if (table.$isTableNode(node)) {
768
+ const rows = node.getChildren();
769
+ const cellData = [];
770
+ let hasHeaders = false;
771
+ let cols = 0;
772
+ rows.forEach((row, rowIndex) => {
773
+ const rowData = [];
774
+ row.getChildren().forEach(cell => {
775
+ if (rowIndex === 0 && table.$isTableCellNode(cell) && cell.getHeaderStyles() === table.TableCellHeaderStates.ROW) hasHeaders = true;
776
+ rowData.push(cell.getTextContent());
777
+ });
778
+ if (rowData.length > cols) cols = rowData.length;
779
+ cellData.push(rowData);
780
+ });
781
+ result = {
782
+ key: node.getKey(),
783
+ rows: hasHeaders ? rows.length - 1 : rows.length,
784
+ cols,
785
+ hasHeaders,
786
+ cellData
787
+ };
788
+ break;
789
+ }
790
+ node = node.getParent();
791
+ }
792
+ });
793
+ return result;
794
+ }
795
+
796
+ removeTableByKey(key) {
797
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
798
+ const { lexical } = this.lx;
799
+ this.lexicalEditor.update(() => {
800
+ const node = lexical.$getNodeByKey(key);
801
+ if (node) node.remove();
802
+ }, { discrete: true });
803
+ return this;
804
+ }
805
+
667
806
  insertHTML(htmlStr) {
668
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
807
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
669
808
  const { lexical, lexicalHtml } = this.lx;
670
809
  this.lexicalEditor.update(() => {
671
810
  const dom = new DOMParser().parseFromString(htmlStr, 'text/html');
@@ -680,14 +819,14 @@ export default class HtmlEditor extends ShadowComponent {
680
819
  }
681
820
 
682
821
  insertTable(rows, columns, includeHeaders = false, cellData = null) {
683
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
822
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
684
823
  const { lexical, table } = this.lx;
685
824
  this.lexicalEditor.update(() => {
686
825
  const totalRows = rows + (includeHeaders ? 1 : 0);
687
826
  const rowNodes = [];
688
- for(let r = 0; r < totalRows; r++){
827
+ for (let r = 0; r < totalRows; r++) {
689
828
  const cells = [];
690
- for(let c = 0; c < columns; c++){
829
+ for (let c = 0; c < columns; c++) {
691
830
  const isHeader = includeHeaders && r === 0;
692
831
  const headerState = isHeader ? table.TableCellHeaderStates.ROW : table.TableCellHeaderStates.NO_STATUS;
693
832
  const cell = table.$createTableCellNode(headerState);
@@ -701,7 +840,7 @@ export default class HtmlEditor extends ShadowComponent {
701
840
  }
702
841
  const tableNode = table.$createTableNode().append(...rowNodes);
703
842
  const sel = lexical.$getSelection();
704
- if(lexical.$isRangeSelection(sel)){
843
+ if (lexical.$isRangeSelection(sel)) {
705
844
  const anchor = sel.anchor.getNode();
706
845
  const topLevel = anchor.getTopLevelElementOrThrow();
707
846
  topLevel.insertAfter(tableNode);
@@ -722,11 +861,11 @@ export default class HtmlEditor extends ShadowComponent {
722
861
  }
723
862
 
724
863
  replaceSelectionWithElement(element) {
725
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
864
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
726
865
  const { lexical, lexicalHtml } = this.lx;
727
866
  this.lexicalEditor.update(() => {
728
867
  const sel = lexical.$getSelection();
729
- if(!lexical.$isRangeSelection(sel)) return;
868
+ if (!lexical.$isRangeSelection(sel)) return;
730
869
  sel.removeText();
731
870
  const dom = new DOMParser().parseFromString(element.outerHTML, 'text/html');
732
871
  const nodes = lexicalHtml.$generateNodesFromDOM(this.lexicalEditor, dom);
@@ -736,9 +875,9 @@ export default class HtmlEditor extends ShadowComponent {
736
875
  }
737
876
 
738
877
  wrapSelection(before, after, savedSelection = null) {
739
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
878
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
740
879
  const text = savedSelection || this.getSelectedText();
741
- if(!text) return this;
880
+ if (!text) return this;
742
881
  return this.insertHTML(before + text + after);
743
882
  }
744
883
 
@@ -746,12 +885,12 @@ export default class HtmlEditor extends ShadowComponent {
746
885
  Public Methods - Selection Management
747
886
  */
748
887
  getSelection() {
749
- if(this.mode !== 'visual' || !this.lexicalEditor) return null;
888
+ if (this.mode !== 'visual' || !this.lexicalEditor) return null;
750
889
  let result = null;
751
890
  const { lexical } = this.lx;
752
891
  this.lexicalEditor.getEditorState().read(() => {
753
892
  const sel = lexical.$getSelection();
754
- if(!lexical.$isRangeSelection(sel) || sel.isCollapsed()) return;
893
+ if (!lexical.$isRangeSelection(sel) || sel.isCollapsed()) return;
755
894
  result = { text: sel.getTextContent(), html: sel.getTextContent(), selection: sel };
756
895
  });
757
896
  return result;
@@ -759,11 +898,11 @@ export default class HtmlEditor extends ShadowComponent {
759
898
 
760
899
  getSelectedText() {
761
900
  let text = '';
762
- if(this.mode !== 'visual' || !this.lexicalEditor) return text;
901
+ if (this.mode !== 'visual' || !this.lexicalEditor) return text;
763
902
  const { lexical } = this.lx;
764
903
  this.lexicalEditor.getEditorState().read(() => {
765
904
  const sel = lexical.$getSelection();
766
- if(lexical.$isRangeSelection(sel)) text = sel.getTextContent();
905
+ if (lexical.$isRangeSelection(sel)) text = sel.getTextContent();
767
906
  });
768
907
  return text;
769
908
  }
@@ -773,14 +912,14 @@ export default class HtmlEditor extends ShadowComponent {
773
912
  }
774
913
 
775
914
  selectAll() {
776
- if(this.mode === 'visual' && this.lexicalEditor){
915
+ if (this.mode === 'visual' && this.lexicalEditor) {
777
916
  const { lexical } = this.lx;
778
917
  this.lexicalEditor.update(() => {
779
918
  lexical.$selectAll();
780
919
  }, { discrete: true });
781
- } else if(this.monacoEditor){
920
+ } else if (this.monacoEditor) {
782
921
  const model = this.monacoEditor.getModel();
783
- if(model) this.monacoEditor.setSelection(model.getFullModelRange());
922
+ if (model) this.monacoEditor.setSelection(model.getFullModelRange());
784
923
  }
785
924
  return this;
786
925
  }
@@ -790,24 +929,24 @@ export default class HtmlEditor extends ShadowComponent {
790
929
  }
791
930
 
792
931
  deleteSelection() {
793
- if(this.mode === 'visual'){
932
+ if (this.mode === 'visual') {
794
933
  this.lexicalCmd('DELETE_CHARACTER_COMMAND', false);
795
- } else if(this.monacoEditor){
934
+ } else if (this.monacoEditor) {
796
935
  this.monacoEditor.trigger('keyboard', 'deleteAllLeft', null);
797
936
  }
798
937
  return this;
799
938
  }
800
939
 
801
940
  getValueWithSelectionMarkers() {
802
- if(this.mode !== 'visual' || !this.lexicalEditor){
941
+ if (this.mode !== 'visual' || !this.lexicalEditor) {
803
942
  return { html: this.value, hasCursor: false, hasSelection: false, selectedText: '' };
804
943
  }
805
944
  let result = { html: this.exportHtmlFromLexical(), hasCursor: false, hasSelection: false, selectedText: '' };
806
945
  const { lexical } = this.lx;
807
946
  this.lexicalEditor.getEditorState().read(() => {
808
947
  const sel = lexical.$getSelection();
809
- if(!lexical.$isRangeSelection(sel)) return;
810
- if(sel.isCollapsed()){
948
+ if (!lexical.$isRangeSelection(sel)) return;
949
+ if (sel.isCollapsed()) {
811
950
  result.hasCursor = true;
812
951
  } else {
813
952
  result.hasSelection = true;
@@ -837,7 +976,7 @@ export default class HtmlEditor extends ShadowComponent {
837
976
  Public Methods - Links and Media
838
977
  */
839
978
  createLink(url) {
840
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
979
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
841
980
  const { link } = this.lx;
842
981
  this.lexicalEditor.update(() => {
843
982
  link.$toggleLink(url);
@@ -846,11 +985,11 @@ export default class HtmlEditor extends ShadowComponent {
846
985
  }
847
986
 
848
987
  createLinkWithText(url, text) {
849
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
988
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
850
989
  const { lexical, link } = this.lx;
851
990
  this.lexicalEditor.update(() => {
852
991
  const sel = lexical.$getSelection();
853
- if(lexical.$isRangeSelection(sel) && !sel.isCollapsed()) sel.removeText();
992
+ if (lexical.$isRangeSelection(sel) && !sel.isCollapsed()) sel.removeText();
854
993
  const linkNode = link.$createLinkNode(url);
855
994
  linkNode.append(lexical.$createTextNode(text));
856
995
  lexical.$insertNodes([linkNode]);
@@ -859,14 +998,14 @@ export default class HtmlEditor extends ShadowComponent {
859
998
  }
860
999
 
861
1000
  unlink() {
862
- if(this.mode !== 'visual' || !this.lexicalEditor) return this;
1001
+ if (this.mode !== 'visual' || !this.lexicalEditor) return this;
863
1002
  const { lexical, link } = this.lx;
864
1003
  this.lexicalEditor.update(() => {
865
1004
  const sel = lexical.$getSelection();
866
- if(!lexical.$isRangeSelection(sel)) return;
1005
+ if (!lexical.$isRangeSelection(sel)) return;
867
1006
  sel.getNodes().forEach(node => {
868
1007
  const parent = node.getParent();
869
- if(parent && link.$isLinkNode?.(parent)){
1008
+ if (parent && link.$isLinkNode?.(parent)) {
870
1009
  parent.getChildren().forEach(child => parent.insertBefore(child));
871
1010
  parent.remove();
872
1011
  }
@@ -883,56 +1022,193 @@ export default class HtmlEditor extends ShadowComponent {
883
1022
  Public Methods - History
884
1023
  */
885
1024
  undo() {
886
- this.lexicalCmd('UNDO_COMMAND', undefined);
1025
+ if (this.mode === 'code') this.monacoEditor?.trigger('toolbar', 'undo');
1026
+ else this.lexicalCmd('UNDO_COMMAND', undefined);
887
1027
  return this;
888
1028
  }
889
1029
 
890
1030
  redo() {
891
- this.lexicalCmd('REDO_COMMAND', undefined);
1031
+ if (this.mode === 'code') this.monacoEditor?.trigger('toolbar', 'redo');
1032
+ else this.lexicalCmd('REDO_COMMAND', undefined);
1033
+ return this;
1034
+ }
1035
+
1036
+ /*
1037
+ Public Methods - Code Editor Controls
1038
+ */
1039
+ copyToClipboard() {
1040
+ navigator.clipboard.writeText(this.getValue());
1041
+ return this;
1042
+ }
1043
+
1044
+ setEditorTheme(theme) {
1045
+ if (['auto', 'light', 'dark'].includes(theme)) this.editorTheme = theme;
1046
+ if (this.monacoEditor) window.monaco.editor.setTheme(this.resolveMonacoTheme());
1047
+ return this;
1048
+ }
1049
+
1050
+ openFind() {
1051
+ this.monacoEditor?.getAction('actions.find')?.run();
1052
+ return this;
1053
+ }
1054
+
1055
+ foldAll() {
1056
+ this.monacoEditor?.getAction('editor.foldAll')?.run();
1057
+ return this;
1058
+ }
1059
+
1060
+ unfoldAll() {
1061
+ this.monacoEditor?.getAction('editor.unfoldAll')?.run();
1062
+ return this;
1063
+ }
1064
+
1065
+ enterFullscreen() {
1066
+ this.fullscreen = true;
1067
+ document.body.classList.add('no-scroll');
1068
+ this.dispatchEvent(new CustomEvent('fullscreen-changed', { detail: { fullscreen: true }, bubbles: true }));
1069
+ return this;
1070
+ }
1071
+
1072
+ exitFullscreen() {
1073
+ this.fullscreen = false;
1074
+ document.body.classList.remove('no-scroll');
1075
+ this.dispatchEvent(new CustomEvent('fullscreen-changed', { detail: { fullscreen: false }, bubbles: true }));
1076
+ return this;
1077
+ }
1078
+
1079
+ toggleFullscreen() {
1080
+ return this.fullscreen ? this.exitFullscreen() : this.enterFullscreen();
1081
+ }
1082
+
1083
+ increaseFontSize() {
1084
+ this.fontSize = Math.min(this.fontSize + 2, 40);
1085
+ this.monacoEditor?.updateOptions({ fontSize: this.fontSize });
1086
+ return this;
1087
+ }
1088
+
1089
+ decreaseFontSize() {
1090
+ this.fontSize = Math.max(this.fontSize - 2, 8);
1091
+ this.monacoEditor?.updateOptions({ fontSize: this.fontSize });
1092
+ return this;
1093
+ }
1094
+
1095
+ setWordWrap(enabled) {
1096
+ this.wordWrap = enabled;
1097
+ this.monacoEditor?.updateOptions({ wordWrap: enabled ? 'on' : 'off' });
1098
+ return this;
1099
+ }
1100
+
1101
+ setMinimap(enabled) {
1102
+ this.minimapEnabled = enabled;
1103
+ this.monacoEditor?.updateOptions({ minimap: { enabled } });
892
1104
  return this;
893
1105
  }
894
1106
 
1107
+ resolveMonacoTheme() {
1108
+ if (this.editorTheme === 'dark') return 'vs-dark';
1109
+ if (this.editorTheme === 'light') return 'vs';
1110
+ return getCalculatedTheme() === 'dark' ? 'vs-dark' : 'vs';
1111
+ }
1112
+
895
1113
  /*
896
1114
  Utility Methods
897
1115
  */
898
1116
  lexicalCmd(commandName, payload) {
899
- if(this.mode !== 'visual' || !this.lexicalEditor) return;
1117
+ if (this.mode !== 'visual' || !this.lexicalEditor) return;
900
1118
  const cmd = this.lx.lexical?.[commandName];
901
- if(cmd) this.lexicalEditor.dispatchCommand(cmd, payload);
1119
+ if (cmd) this.lexicalEditor.dispatchCommand(cmd, payload);
902
1120
  }
903
1121
 
904
1122
  lexicalFormat(format) {
905
- if(this.mode !== 'visual' || !this.lexicalEditor) return;
1123
+ if (this.mode !== 'visual' || !this.lexicalEditor) return;
906
1124
  const { lexical } = this.lx;
907
1125
  this.lexicalEditor.update(() => {
908
1126
  const sel = lexical.$getSelection();
909
- if(lexical.$isRangeSelection(sel)) sel.formatText(format);
1127
+ if (lexical.$isRangeSelection(sel)) sel.formatText(format);
910
1128
  }, { discrete: true });
911
1129
  }
912
1130
 
913
1131
  lexicalFormatElement(alignment) {
914
- if(this.mode !== 'visual' || !this.lexicalEditor) return;
1132
+ if (this.mode !== 'visual' || !this.lexicalEditor) return;
915
1133
  this.lexicalEditor.dispatchCommand(this.lx.lexical.FORMAT_ELEMENT_COMMAND, alignment);
916
1134
  }
917
1135
 
918
1136
  /*
919
1137
  Rendering
920
1138
  */
1139
+ render() {
1140
+ const set = this.constructor.controlSets[this.controls] ?? {};
1141
+ return html`
1142
+ ${this.hasTopToolbar ? html`
1143
+ <div class="toolbar-top bb">
1144
+ <div class="toolbar-start">
1145
+ <slot name="toolbar-top-left">${set.topLeft ?? ''}</slot>
1146
+ </div>
1147
+ <div class="toolbar-end">
1148
+ <slot name="toolbar-top-right">${set.topRight ?? ''}</slot>
1149
+ </div>
1150
+ </div>
1151
+ ` : ''}
1152
+ <div class="editor-container">
1153
+ <div
1154
+ class="lexical-editor"
1155
+ contenteditable="true"
1156
+ ?hidden=${this.mode !== 'visual'}
1157
+ ></div>
1158
+ <div
1159
+ class="monaco-editor-container"
1160
+ ?hidden=${this.mode !== 'code'}
1161
+ ></div>
1162
+ </div>
1163
+ ${this.hasBottomToolbar ? html`
1164
+ <div class="toolbar-bottom bt">
1165
+ <div class="toolbar-start">
1166
+ <slot name="toolbar-bottom-left">${set.bottomLeft ?? ''}</slot>
1167
+ </div>
1168
+ <div class="toolbar-end">
1169
+ <slot name="toolbar-bottom-right">${set.bottomRight ?? ''}</slot>
1170
+ </div>
1171
+ </div>
1172
+ ` : ''}
1173
+ `;
1174
+ }
1175
+
1176
+
921
1177
  static styles = css`
922
1178
  :host {
923
1179
  display: flex;
924
1180
  flex-direction: column;
925
1181
  gap: 0;
926
- height: 300px;
1182
+ height: 400px;
1183
+ background: var(--c_bg, rgb(249, 249, 249));
1184
+ }
1185
+ :host([fullscreen]) {
1186
+ position: fixed;
1187
+ top: 0;
1188
+ left: 0;
1189
+ width: 100vw !important;
1190
+ height: 100vh !important;
1191
+ z-index: 10000;
927
1192
  }
928
1193
  .toolbar-top,
929
1194
  .toolbar-bottom {
930
1195
  display: flex;
931
- flex-wrap: wrap;
932
1196
  align-items: center;
933
- gap: 0;
934
1197
  background: var(--bg-secondary);
935
1198
  min-height: 40px;
1199
+ width: 100%;
1200
+ }
1201
+ .toolbar-start {
1202
+ display: flex;
1203
+ flex-wrap: wrap;
1204
+ align-items: center;
1205
+ }
1206
+ .toolbar-end {
1207
+ display: flex;
1208
+ flex-wrap: wrap-reverse;
1209
+ align-items: center;
1210
+ justify-content: flex-end;
1211
+ margin-left: auto;
936
1212
  }
937
1213
  .editor-container {
938
1214
  position: relative;
@@ -1006,36 +1282,135 @@ export default class HtmlEditor extends ShadowComponent {
1006
1282
  .monaco-editor-container {
1007
1283
  border: 1px solid var(--border-color);
1008
1284
  }
1009
- [hidden] {
1010
- display: none !important;
1011
- }
1012
1285
  `;
1013
1286
 
1014
- render() {
1015
- return html`
1016
- ${this.hasTopToolbar ? html`
1017
- <div class="toolbar-top bb">
1018
- <slot name="toolbar-top"></slot>
1019
- </div>
1020
- ` : ''}
1021
- <div class="editor-container">
1022
- <div
1023
- class="lexical-editor"
1024
- contenteditable="true"
1025
- ?hidden=${this.mode !== 'visual'}
1026
- ></div>
1027
- <div
1028
- class="monaco-editor-container"
1029
- ?hidden=${this.mode !== 'code'}
1030
- ></div>
1031
- </div>
1032
- ${this.hasBottomToolbar ? html`
1033
- <div class="toolbar-bottom bt">
1034
- <slot name="toolbar-bottom"></slot>
1035
- </div>
1036
- ` : ''}
1037
- `;
1038
- }
1287
+ /*
1288
+ Static Properties
1289
+ */
1290
+ static controlSets = {
1291
+ minimal: {
1292
+ topLeft: html`
1293
+ <k-hec-group>
1294
+ <k-hec-bold></k-hec-bold>
1295
+ <k-hec-italic></k-hec-italic>
1296
+ <k-hec-underline></k-hec-underline>
1297
+ </k-hec-group>
1298
+ <k-hec-group>
1299
+ <k-hec-bullet-list></k-hec-bullet-list>
1300
+ <k-hec-number-list></k-hec-number-list>
1301
+ </k-hec-group>
1302
+ `,
1303
+ topRight: null,
1304
+ bottomLeft: null,
1305
+ bottomRight: null,
1306
+ },
1307
+ normal: {
1308
+ topLeft: html`
1309
+ <k-hec-group>
1310
+ <k-hec-bold></k-hec-bold>
1311
+ <k-hec-italic></k-hec-italic>
1312
+ <k-hec-underline></k-hec-underline>
1313
+ <k-hec-strikethrough></k-hec-strikethrough>
1314
+ </k-hec-group>
1315
+ <k-hec-inline-code></k-hec-inline-code>
1316
+ <k-hec-dropdown>
1317
+ <k-icon slot="icon" name="format_paragraph"></k-icon>
1318
+ <span slot="label">Text Style</span>
1319
+ <k-hec-format-block tag="p">Paragraph</k-hec-format-block>
1320
+ <k-hec-format-block tag="h1">Heading 1</k-hec-format-block>
1321
+ <k-hec-format-block tag="h2">Heading 2</k-hec-format-block>
1322
+ <k-hec-format-block tag="h3">Heading 3</k-hec-format-block>
1323
+ <k-hec-format-block tag="blockquote">Blockquote</k-hec-format-block>
1324
+ <k-hec-code-block></k-hec-code-block>
1325
+ </k-hec-dropdown>
1326
+ <k-hec-group>
1327
+ <k-hec-bullet-list></k-hec-bullet-list>
1328
+ <k-hec-number-list></k-hec-number-list>
1329
+ </k-hec-group>
1330
+ `,
1331
+ topRight: html`
1332
+ <k-hec-group>
1333
+ <k-hec-align-left></k-hec-align-left>
1334
+ <k-hec-align-center></k-hec-align-center>
1335
+ <k-hec-align-right></k-hec-align-right>
1336
+ </k-hec-group>
1337
+ <k-hec-create-link></k-hec-create-link>
1338
+ <k-cec-format-code></k-cec-format-code>
1339
+ <k-hec-mode></k-hec-mode>
1340
+ `,
1341
+ bottomLeft: html`<k-hec-word-count></k-hec-word-count>`,
1342
+ bottomRight: null,
1343
+ },
1344
+ full: {
1345
+ topLeft: html`
1346
+ <k-hec-group>
1347
+ <k-hec-bold></k-hec-bold>
1348
+ <k-hec-italic></k-hec-italic>
1349
+ <k-hec-underline></k-hec-underline>
1350
+ <k-hec-strikethrough></k-hec-strikethrough>
1351
+ </k-hec-group>
1352
+ <k-hec-inline-code></k-hec-inline-code>
1353
+ <k-hec-dropdown>
1354
+ <k-icon slot="icon" name="format_paragraph"></k-icon>
1355
+ <span slot="label">Text Style</span>
1356
+ <k-hec-format-block tag="p">Paragraph</k-hec-format-block>
1357
+ <k-hec-format-block tag="h1">Heading 1</k-hec-format-block>
1358
+ <k-hec-format-block tag="h2">Heading 2</k-hec-format-block>
1359
+ <k-hec-format-block tag="h3">Heading 3</k-hec-format-block>
1360
+ <k-hec-format-block tag="blockquote">Blockquote</k-hec-format-block>
1361
+ <k-hec-code-block></k-hec-code-block>
1362
+ </k-hec-dropdown>
1363
+ <k-hec-group>
1364
+ <k-hec-bullet-list></k-hec-bullet-list>
1365
+ <k-hec-number-list></k-hec-number-list>
1366
+ </k-hec-group>
1367
+ `,
1368
+ topRight: html`
1369
+ <k-hec-group>
1370
+ <k-hec-align-left></k-hec-align-left>
1371
+ <k-hec-align-center></k-hec-align-center>
1372
+ <k-hec-align-right></k-hec-align-right>
1373
+ <k-hec-align-justify></k-hec-align-justify>
1374
+ </k-hec-group>
1375
+ <k-hec-create-link></k-hec-create-link>
1376
+ <k-hec-group>
1377
+ <k-hec-text-color></k-hec-text-color>
1378
+ <k-hec-text-background-color></k-hec-text-background-color>
1379
+ </k-hec-group>
1380
+ <k-hec-clear-formatting></k-hec-clear-formatting>
1381
+ <k-hec-insert-table></k-hec-insert-table>
1382
+ <k-cec-group>
1383
+ <k-cec-undo></k-cec-undo>
1384
+ <k-cec-redo></k-cec-redo>
1385
+ </k-cec-group>
1386
+ <k-cec-group>
1387
+ <k-cec-format-code></k-cec-format-code>
1388
+ <k-cec-copy-code></k-cec-copy-code>
1389
+ <k-cec-find-replace></k-cec-find-replace>
1390
+ </k-cec-group>
1391
+ <k-cec-group>
1392
+ <k-cec-word-wrap></k-cec-word-wrap>
1393
+ <k-cec-minimap></k-cec-minimap>
1394
+ <k-cec-fold-all></k-cec-fold-all>
1395
+ </k-cec-group>
1396
+ <k-cec-font-size></k-cec-font-size>
1397
+ <k-cec-editor-theme></k-cec-editor-theme>
1398
+ <k-hec-mode></k-hec-mode>
1399
+ <k-cec-fullscreen></k-cec-fullscreen>
1400
+ `,
1401
+ bottomLeft: html`
1402
+ <k-hec-word-count></k-hec-word-count>
1403
+ <k-hec-character-count></k-hec-character-count>
1404
+ `,
1405
+ bottomRight: null,
1406
+ },
1407
+ "": {
1408
+ topLeft: null,
1409
+ topRight: null,
1410
+ bottomLeft: null,
1411
+ bottomRight: null,
1412
+ }
1413
+ };
1039
1414
  }
1040
1415
 
1041
1416
  customElements.define('k-html-editor', HtmlEditor);