kempo-ui 0.4.5 → 0.4.6

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 (170) hide show
  1. package/dist/components/Chat.js +201 -0
  2. package/dist/components/CodeEditor.js +21 -2
  3. package/dist/components/Dropdown.js +1 -1
  4. package/dist/components/HtmlEditor.js +42 -3
  5. package/dist/components/MarkdownEditor.js +173 -0
  6. package/dist/components/Resize.js +12 -2
  7. package/dist/components/markdownEditorControls/Bold.js +11 -0
  8. package/dist/components/markdownEditorControls/BulletList.js +11 -0
  9. package/dist/components/markdownEditorControls/Code.js +11 -0
  10. package/dist/components/markdownEditorControls/FormatBlock.js +30 -0
  11. package/dist/components/markdownEditorControls/Heading.js +11 -0
  12. package/dist/components/markdownEditorControls/Image.js +93 -0
  13. package/dist/components/markdownEditorControls/Italic.js +11 -0
  14. package/dist/components/markdownEditorControls/Link.js +11 -0
  15. package/dist/components/markdownEditorControls/MarkdownEditorControl.js +39 -0
  16. package/dist/components/markdownEditorControls/Menu.js +30 -0
  17. package/dist/components/markdownEditorControls/NumberedList.js +11 -0
  18. package/dist/components/markdownEditorControls/Quote.js +11 -0
  19. package/dist/components/markdownEditorControls/SpeechToText.js +16 -0
  20. package/dist/components/markdownEditorControls/Strikethrough.js +11 -0
  21. package/dist/components/markdownEditorControls/Table.js +80 -0
  22. package/dist/utils/marked.esm.js +1 -0
  23. package/dist/utils/renderMarkdown.js +1 -0
  24. package/dist/utils/sanitizeHtml.js +1 -0
  25. package/docs/components/accordion.html +12 -0
  26. package/docs/components/aside.html +12 -0
  27. package/docs/components/calendar.html +12 -0
  28. package/docs/components/card.html +12 -0
  29. package/docs/components/chat.html +715 -0
  30. package/docs/components/code-editor.html +48 -0
  31. package/docs/components/color-picker.html +12 -0
  32. package/docs/components/combobox.html +12 -0
  33. package/docs/components/content-slider.html +12 -0
  34. package/docs/components/context.html +12 -0
  35. package/docs/components/dialog.html +12 -0
  36. package/docs/components/dropdown.html +12 -0
  37. package/docs/components/filter-list.html +12 -0
  38. package/docs/components/focus-capture.html +12 -0
  39. package/docs/components/html-editor.html +53 -0
  40. package/docs/components/hybrid-component.html +12 -0
  41. package/docs/components/icon.html +12 -0
  42. package/docs/components/import.html +12 -0
  43. package/docs/components/light-component.html +12 -0
  44. package/docs/components/markdown-editor.html +924 -0
  45. package/docs/components/nav-spacer.html +12 -0
  46. package/docs/components/nav.html +12 -0
  47. package/docs/components/photo-viewer.html +12 -0
  48. package/docs/components/progress.html +12 -0
  49. package/docs/components/resize.html +15 -0
  50. package/docs/components/rich-textarea.html +650 -0
  51. package/docs/components/shadow-component.html +12 -0
  52. package/docs/components/show-more.html +12 -0
  53. package/docs/components/slider.html +12 -0
  54. package/docs/components/sortable.html +12 -0
  55. package/docs/components/speech-to-text.html +12 -0
  56. package/docs/components/spinner.html +12 -0
  57. package/docs/components/split.html +12 -0
  58. package/docs/components/table.html +12 -0
  59. package/docs/components/tableControls.html +12 -0
  60. package/docs/components/tableCustomFields.html +12 -0
  61. package/docs/components/tableFetchRecords.html +12 -0
  62. package/docs/components/tableFieldSortHide.html +12 -0
  63. package/docs/components/tablePagination.html +12 -0
  64. package/docs/components/tablePlaceholder.html +12 -0
  65. package/docs/components/tableRecordEditing.html +12 -0
  66. package/docs/components/tableRecordFiltering.html +12 -0
  67. package/docs/components/tableRecordHiding.html +12 -0
  68. package/docs/components/tableRecordSearching.html +12 -0
  69. package/docs/components/tableRecordSelection.html +12 -0
  70. package/docs/components/tableRowControls.html +12 -0
  71. package/docs/components/tableServerSync.html +12 -0
  72. package/docs/components/tableSorting.html +12 -0
  73. package/docs/components/tabs.html +12 -0
  74. package/docs/components/tags.html +12 -0
  75. package/docs/components/text-to-speech.html +12 -0
  76. package/docs/components/theme-select.html +12 -0
  77. package/docs/components/theme-switcher.html +12 -0
  78. package/docs/components/time.html +12 -0
  79. package/docs/components/timestamp.html +12 -0
  80. package/docs/components/toast.html +12 -0
  81. package/docs/components/toggle.html +12 -0
  82. package/docs/components/tree.html +12 -0
  83. package/docs/components/voice-selector.html +12 -0
  84. package/docs/icons/done_all.svg +1 -0
  85. package/docs/icons/format_quote.svg +1 -0
  86. package/docs/icons/format_strikethrough.svg +1 -0
  87. package/docs/icons/send.svg +1 -0
  88. package/docs/icons/text_fields.svg +1 -0
  89. package/docs/index.html +30 -0
  90. package/docs/src/components/Chat.js +201 -0
  91. package/docs/src/components/CodeEditor.js +21 -2
  92. package/docs/src/components/Dropdown.js +1 -1
  93. package/docs/src/components/HtmlEditor.js +42 -3
  94. package/docs/src/components/MarkdownEditor.js +173 -0
  95. package/docs/src/components/Resize.js +12 -2
  96. package/docs/src/components/markdownEditorControls/Bold.js +11 -0
  97. package/docs/src/components/markdownEditorControls/BulletList.js +11 -0
  98. package/docs/src/components/markdownEditorControls/Code.js +11 -0
  99. package/docs/src/components/markdownEditorControls/FormatBlock.js +30 -0
  100. package/docs/src/components/markdownEditorControls/Heading.js +11 -0
  101. package/docs/src/components/markdownEditorControls/Image.js +93 -0
  102. package/docs/src/components/markdownEditorControls/Italic.js +11 -0
  103. package/docs/src/components/markdownEditorControls/Link.js +11 -0
  104. package/docs/src/components/markdownEditorControls/MarkdownEditorControl.js +39 -0
  105. package/docs/src/components/markdownEditorControls/Menu.js +30 -0
  106. package/docs/src/components/markdownEditorControls/NumberedList.js +11 -0
  107. package/docs/src/components/markdownEditorControls/Quote.js +11 -0
  108. package/docs/src/components/markdownEditorControls/SpeechToText.js +16 -0
  109. package/docs/src/components/markdownEditorControls/Strikethrough.js +11 -0
  110. package/docs/src/components/markdownEditorControls/Table.js +80 -0
  111. package/docs/src/utils/marked.esm.js +1 -0
  112. package/docs/src/utils/renderMarkdown.js +1 -0
  113. package/docs/src/utils/sanitizeHtml.js +1 -0
  114. package/docs/utils/context.html +12 -0
  115. package/docs/utils/cookie.html +12 -0
  116. package/docs/utils/debounce.html +12 -0
  117. package/docs/utils/drag.html +12 -0
  118. package/docs/utils/elevation.html +16 -10
  119. package/docs/utils/formatTimestamp.html +12 -0
  120. package/docs/utils/object.html +12 -0
  121. package/docs/utils/propConverters.html +12 -0
  122. package/docs/utils/sanitizeHtml.html +555 -0
  123. package/docs/utils/string.html +12 -0
  124. package/docs/utils/theme.html +12 -0
  125. package/docs/utils/toTitleCase.html +12 -0
  126. package/docs/utils/type.html +12 -0
  127. package/docs/utils/voice.html +12 -0
  128. package/docs/utils/wait.html +12 -0
  129. package/docs-src/components/chat.page.html +230 -0
  130. package/docs-src/components/code-editor.page.html +36 -0
  131. package/docs-src/components/html-editor.page.html +41 -0
  132. package/docs-src/components/markdown-editor.page.html +439 -0
  133. package/docs-src/components/resize.page.html +3 -0
  134. package/docs-src/index.page.html +18 -0
  135. package/docs-src/nav.fragment.html +12 -0
  136. package/docs-src/utils/elevation.page.html +4 -10
  137. package/docs-src/utils/sanitizeHtml.page.html +73 -0
  138. package/icons/done_all.svg +1 -0
  139. package/icons/format_quote.svg +1 -0
  140. package/icons/format_strikethrough.svg +1 -0
  141. package/icons/send.svg +1 -0
  142. package/icons/text_fields.svg +1 -0
  143. package/llms.txt +5 -2
  144. package/package.json +3 -2
  145. package/src/components/Chat.js +435 -0
  146. package/src/components/CodeEditor.js +58 -2
  147. package/src/components/Dropdown.js +1 -1
  148. package/src/components/HtmlEditor.js +84 -4
  149. package/src/components/MarkdownEditor.js +654 -0
  150. package/src/components/Resize.js +17 -1
  151. package/src/components/markdownEditorControls/Bold.js +30 -0
  152. package/src/components/markdownEditorControls/BulletList.js +30 -0
  153. package/src/components/markdownEditorControls/Code.js +39 -0
  154. package/src/components/markdownEditorControls/FormatBlock.js +102 -0
  155. package/src/components/markdownEditorControls/Heading.js +45 -0
  156. package/src/components/markdownEditorControls/Image.js +250 -0
  157. package/src/components/markdownEditorControls/Italic.js +30 -0
  158. package/src/components/markdownEditorControls/Link.js +74 -0
  159. package/src/components/markdownEditorControls/MarkdownEditorControl.js +158 -0
  160. package/src/components/markdownEditorControls/Menu.js +86 -0
  161. package/src/components/markdownEditorControls/NumberedList.js +69 -0
  162. package/src/components/markdownEditorControls/Quote.js +30 -0
  163. package/src/components/markdownEditorControls/SpeechToText.js +65 -0
  164. package/src/components/markdownEditorControls/Strikethrough.js +35 -0
  165. package/src/components/markdownEditorControls/Table.js +164 -0
  166. package/src/utils/marked.esm.js +77 -0
  167. package/src/utils/renderMarkdown.js +29 -0
  168. package/src/utils/sanitizeHtml.js +137 -0
  169. package/tests/components/Chat.browser-test.js +540 -0
  170. package/tests/utils/sanitizeHtml.browser-test.js +179 -0
@@ -0,0 +1,201 @@
1
+ import{html as e,css as t,nothing as s}from"../lit-all.min.js";import i from"./ShadowComponent.js";import o from"../utils/sanitizeHtml.js";import a from"../utils/renderMarkdown.js";import"./MarkdownEditor.js";import"./markdownEditorControls/Bold.js";import"./markdownEditorControls/Italic.js";import"./markdownEditorControls/Code.js";import"./markdownEditorControls/Link.js";import"./markdownEditorControls/BulletList.js";import"./markdownEditorControls/NumberedList.js";import"./markdownEditorControls/Quote.js";import"./Spinner.js";import"./Icon.js";const r=new Set(["sending","delivered","read","failed"]);export default class n extends i{static properties={enterNewline:{type:Boolean,reflect:!0,attribute:"enter-newline"},showStatus:{type:String,reflect:!0,attribute:"show-status"},placeholder:{type:String,reflect:!0},disabled:{type:Boolean,reflect:!0},messages:{state:!0}};constructor(){super(),this.enterNewline=!1,this.showStatus=null,this.placeholder="Type a message...",this.disabled=!1,this.messages=[]}updated(e){super.updated(e),e.has("messages")&&this.#e()}addMessage(e={}){const t="outgoing"===e.type?"outgoing":"incoming",s=e.id||("undefined"!=typeof crypto&&"function"==typeof crypto.randomUUID?crypto.randomUUID():`msg-${Date.now()}-${Math.random().toString(36).slice(2,10)}`),i={id:s,type:t,html:o(e.html||""),status:r.has(e.status)?e.status:"outgoing"===t?"delivered":"read",sender:e.sender||"",timestamp:e.timestamp instanceof Date?e.timestamp:new Date};return this.messages=[...this.messages,i],s}updateMessage(e,t={}){let s=!1;return this.messages=this.messages.map(i=>{if(i.id!==e)return i;s=!0;const a={...i};return void 0!==t.html&&(a.html=o(t.html)),void 0!==t.status&&r.has(t.status)&&(a.status=t.status),void 0!==t.sender&&(a.sender=t.sender),t.timestamp instanceof Date&&(a.timestamp=t.timestamp),a}),s}removeMessage(e){const t=this.messages.length;return this.messages=this.messages.filter(t=>t.id!==e),this.messages.length!==t}clear(){this.messages=[]}send(){if(this.disabled)return null;const e=this.shadowRoot?.querySelector("k-markdown-editor");if(!e)return null;const t=(e.value||"").trim();if(!t)return null;const s=o(a(t,{breaks:!0})),i=this.addMessage({type:"outgoing",html:s,status:this.#t?"sending":"delivered"});return e.clear(),this.dispatchEvent(new CustomEvent("send",{detail:{id:i,html:s,markdown:t},bubbles:!0})),i}handleSendClick=()=>this.send();handleEditorKeydown=e=>{if(this.disabled)return;if("Enter"!==e.key||e.ctrlKey||e.metaKey||e.altKey)return;(this.enterNewline?e.shiftKey:!e.shiftKey)&&(e.preventDefault(),this.send())};#e=()=>{this.updateComplete.then(()=>{const e=this.shadowRoot?.querySelector(".window");e&&(e.scrollTop=e.scrollHeight)})};get#s(){for(let e=this.messages.length-1;e>=0;e--)if("outgoing"===this.messages[e].type)return this.messages[e].id;return null}get#t(){return null!=this.showStatus&&"false"!==this.showStatus}get#i(){return"icons"===this.showStatus?"icons":"text"}#o(e,t){return!!this.#t&&("outgoing"===e.type&&("sending"===e.status||"failed"===e.status||e.id===t))}#a(e){return"icons"===this.#i?this.#r(e):this.#n(e)}#n(t){return"sending"===t?e`<span class="status sending"><k-spinner size="xs"></k-spinner> Sending&hellip;</span>`:"delivered"===t?e`<span class="status">Delivered</span>`:"read"===t?e`<span class="status">Read</span>`:"failed"===t?e`<span class="status failed"><k-icon name="error"></k-icon> Not Delivered</span>`:s}#r(t){return"sending"===t?e`<span class="status status-icon-only"><k-spinner size="xs" title="Sending"></k-spinner></span>`:"delivered"===t?e`<span class="status status-icon-only"><k-icon name="check" title="Delivered"></k-icon></span>`:"read"===t?e`<span class="status status-icon-only"><k-icon name="done_all" title="Read"></k-icon></span>`:"failed"===t?e`<span class="status status-icon-only failed"><k-icon name="error" title="Not Delivered"></k-icon></span>`:s}#d(t,i){const o=this.#o(t,i);return e`
2
+ <div
3
+ class="message ${t.type} ${t.status}"
4
+ data-id=${t.id}
5
+ >
6
+ ${t.sender?e`<div class="sender">${t.sender}</div>`:s}
7
+ <div class="bubble">
8
+ <div class="content" .innerHTML=${t.html}></div>
9
+ </div>
10
+ ${o?this.#a(t.status):s}
11
+ </div>
12
+ `}render(){const t=this.#s;return e`
13
+ <div class="window" role="log" aria-live="polite">
14
+ ${this.messages.map(e=>this.#d(e,t))}
15
+ </div>
16
+ <div class="input-area">
17
+ <k-markdown-editor
18
+ class="editor"
19
+ placeholder=${this.placeholder}
20
+ ?disabled=${this.disabled}
21
+ @keydown=${this.handleEditorKeydown}
22
+ >
23
+ <div slot="controls-top" class="controls-top">
24
+ <slot name="controls-top">
25
+ <k-md-bold></k-md-bold>
26
+ <k-md-italic></k-md-italic>
27
+ <k-md-code></k-md-code>
28
+ <k-md-link></k-md-link>
29
+ <k-md-bullet-list></k-md-bullet-list>
30
+ <k-md-numbered-list></k-md-numbered-list>
31
+ <k-md-quote></k-md-quote>
32
+ </slot>
33
+ </div>
34
+ <div slot="controls-bottom" class="controls-bottom">
35
+ <slot name="controls-bottom"></slot>
36
+ <button
37
+ type="button"
38
+ class="send-btn primary"
39
+ ?disabled=${this.disabled}
40
+ @click=${this.handleSendClick}
41
+ aria-label="Send message"
42
+ title="Send message"
43
+ >
44
+ <k-icon name="send"></k-icon>
45
+ </button>
46
+ </div>
47
+ </k-markdown-editor>
48
+ </div>
49
+ `}static styles=t`
50
+ :host {
51
+ --window_min_height: 16rem;
52
+ --window_max_height: 32rem;
53
+ --chat_padding: 0.5rem;
54
+ --chat_gap: 0.5rem;
55
+ --message_radius: 1rem;
56
+ --message_max_width: 75%;
57
+ --bubble_padding: 0.5rem 0.75rem;
58
+ --bubble_bg__incoming: var(--c_bg__alt);
59
+ --bubble_bg__outgoing: var(--c_primary);
60
+ --bubble_tc__outgoing: white;
61
+ --send_btn_bg: var(--c_primary);
62
+ --send_btn_tc: white;
63
+
64
+ display: flex;
65
+ flex-direction: column;
66
+ border: 1px solid var(--c_border);
67
+ border-radius: var(--radius);
68
+ background: var(--c_bg);
69
+ /* Note: NO overflow:hidden on the host — that would clip the input
70
+ area's focus shadow. Each child clips its own content against the
71
+ shared rounded corners instead. */
72
+ }
73
+ :host([disabled]) {
74
+ opacity: 0.6;
75
+ }
76
+ .window {
77
+ flex: 1 1 auto;
78
+ min-height: var(--window_min_height);
79
+ max-height: var(--window_max_height);
80
+ overflow-y: auto;
81
+ padding: var(--chat_padding);
82
+ display: flex;
83
+ flex-direction: column;
84
+ gap: var(--chat_gap);
85
+ scroll-behavior: smooth;
86
+ /* Match the chat's outer rounded corners on the top edge so messages
87
+ don't render past them. */
88
+ border-top-left-radius: var(--radius);
89
+ border-top-right-radius: var(--radius);
90
+ }
91
+ .message {
92
+ display: flex;
93
+ flex-direction: column;
94
+ max-width: var(--message_max_width);
95
+ gap: 0.125rem;
96
+ }
97
+ .message.outgoing {
98
+ align-self: flex-end;
99
+ align-items: flex-end;
100
+ }
101
+ .message.incoming {
102
+ align-self: flex-start;
103
+ align-items: flex-start;
104
+ }
105
+ .sender {
106
+ font-size: 0.75rem;
107
+ color: var(--tc_muted);
108
+ }
109
+ .bubble {
110
+ padding: var(--bubble_padding);
111
+ border-radius: var(--message_radius);
112
+ background: var(--bubble_bg__incoming);
113
+ color: var(--tc);
114
+ word-wrap: break-word;
115
+ overflow-wrap: anywhere;
116
+ }
117
+ .message.outgoing .bubble {
118
+ background: var(--bubble_bg__outgoing);
119
+ color: var(--bubble_tc__outgoing);
120
+ }
121
+ .message.outgoing.sending .bubble {
122
+ opacity: 0.7;
123
+ }
124
+ .message.outgoing.failed .bubble {
125
+ background: var(--c_danger, #d32f2f);
126
+ }
127
+ .content {
128
+ line-height: 1.4;
129
+ }
130
+ .content p:first-child { margin-top: 0; }
131
+ .content p:last-child { margin-bottom: 0; }
132
+ /* iMessage-style small grey label below the message bubble. */
133
+ .status {
134
+ display: inline-flex;
135
+ align-items: center;
136
+ gap: 0.25rem;
137
+ font-size: 0.7rem;
138
+ color: var(--tc_muted);
139
+ margin-top: 0.125rem;
140
+ }
141
+ .status.failed {
142
+ color: var(--c_danger, #d32f2f);
143
+ }
144
+ .status k-spinner,
145
+ .status k-icon {
146
+ font-size: 0.8rem;
147
+ }
148
+ .status-icon-only {
149
+ font-size: 0.95rem;
150
+ }
151
+ .input-area {
152
+ position: relative;
153
+ border-top: 1px solid var(--c_border);
154
+ border-bottom-left-radius: var(--radius);
155
+ border-bottom-right-radius: var(--radius);
156
+ }
157
+ .editor {
158
+ /* Markdown editor fills the bottom of the chat. CSS custom properties
159
+ pierce shadow boundaries -- '--height' sets the initial size of the
160
+ editor's internal Resize wrapper. */
161
+ --height: 13rem;
162
+ display: block;
163
+ width: 100%;
164
+ }
165
+ .controls-top,
166
+ .controls-bottom {
167
+ display: flex;
168
+ align-items: center;
169
+ flex-wrap: wrap;
170
+ gap: 0.125rem;
171
+ }
172
+ .controls-bottom {
173
+ width: 100%;
174
+ }
175
+ .send-btn {
176
+ margin-left: auto;
177
+ display: inline-flex;
178
+ align-items: center;
179
+ justify-content: center;
180
+ width: 2rem;
181
+ height: 2rem;
182
+ padding: 0;
183
+ border: 1px solid transparent;
184
+ border-radius: 50%;
185
+ background: var(--c_primary);
186
+ color: white;
187
+ cursor: pointer;
188
+ transition: opacity var(--animation_ms);
189
+ }
190
+ .send-btn:hover:not(:disabled) {
191
+ opacity: 0.9;
192
+ }
193
+ .send-btn:focus-visible {
194
+ outline: none;
195
+ box-shadow: var(--focus_shadow);
196
+ }
197
+ .send-btn:disabled {
198
+ cursor: not-allowed;
199
+ opacity: 0.5;
200
+ }
201
+ `}customElements.define("k-chat",n);
@@ -1,4 +1,4 @@
1
- import{html as t,css as e}from"../lit-all.min.js";import o from"./ShadowComponent.js";import i from"../utils/formatCode.js";import{getCalculatedTheme as s,subscribeToTheme as r}from"../utils/theme.js";export default class a extends o{static formAssociated=!0;static properties={name:{type:String,reflect:!0},value:{type:String,reflect:!0},language:{type:String,reflect:!0},monacoSrc:{type:String,attribute:"monaco-src"},controls:{type:String,reflect:!0},editorTheme:{type:String,attribute:"editor-theme",reflect:!0},hasTopToolbar:{type:Boolean,state:!0},hasBottomToolbar:{type:Boolean,state:!0},fullscreen:{type:Boolean,reflect:!0},wordWrap:{type:Boolean},minimapEnabled:{type:Boolean}};constructor(){super(),this.internals=this.attachInternals(),this.name="",this.value="",this.language="javascript",this.monacoSrc="",this.controls="",this.controlsLoaded=!1,this.hasTopToolbar=!1,this.hasBottomToolbar=!1,this.monacoEditor=null,this.skipValueSync=!1,this.editorTheme="auto",this.wordWrap=!0,this.minimapEnabled=!1,this.fontSize=14,this.fullscreen=!1}connectedCallback(){super.connectedCallback(),this.hasAttribute("value")&&(this.value=this.getAttribute("value")),this.slotObserver=new MutationObserver(()=>this.updateToolbarVisibility()),this.slotObserver.observe(this,{childList:!0,subtree:!0}),this.updateToolbarVisibility()}disconnectedCallback(){super.disconnectedCallback(),this.slotObserver?.disconnect(),this.monacoEditor?.dispose(),this.unsubscribeTheme?.(),this.fullscreen&&this.exitFullscreen()}updateToolbarVisibility(){const t=new Set(Array.from(this.children).map(t=>t.getAttribute("slot"))),e=this.constructor.controlSets[this.controls]??null;this.hasTopToolbar=!(!e?.topLeft&&!e?.topRight)||["toolbar-top","toolbar-top-left","toolbar-top-right"].some(e=>t.has(e)),this.hasBottomToolbar=!(!e?.bottomLeft&&!e?.bottomRight)||["toolbar-bottom","toolbar-bottom-left","toolbar-bottom-right"].some(e=>t.has(e))}updated(t){if(super.updated(t),t.has("controls")&&(this.updateToolbarVisibility(),this.controls&&"none"!==this.controls&&this.loadControls()),t.has("value")&&!this.skipValueSync&&(this.monacoEditor&&this.monacoEditor.getValue()!==this.value&&this.monacoEditor.setValue(this.value),this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))),t.has("language")&&this.monacoEditor){const t=this.monacoEditor.getModel();t&&window.monaco.editor.setModelLanguage(t,this.language),this.dispatchEvent(new CustomEvent("language-changed",{detail:{language:this.language},bubbles:!0}))}t.has("editorTheme")&&this.monacoEditor&&(window.monaco.editor.setTheme(this.resolveMonacoTheme()),this.dispatchEvent(new CustomEvent("editor-theme-changed",{detail:{editorTheme:this.editorTheme},bubbles:!0}))),t.has("wordWrap")&&(this.monacoEditor?.updateOptions({wordWrap:this.wordWrap?"on":"off"}),this.dispatchEvent(new CustomEvent("word-wrap-changed",{detail:{wordWrap:this.wordWrap},bubbles:!0}))),t.has("minimapEnabled")&&(this.monacoEditor?.updateOptions({minimap:{enabled:this.minimapEnabled}}),this.dispatchEvent(new CustomEvent("minimap-changed",{detail:{minimapEnabled:this.minimapEnabled},bubbles:!0}))),t.has("fullscreen")&&(this.fullscreen||this.monacoEditor?.layout({width:0,height:0}),requestAnimationFrame(()=>this.monacoEditor?.layout()))}async firstUpdated(){this.monacoContainer=this.shadowRoot.querySelector(".monaco-editor-container"),await this.initMonaco(),this.dispatchEvent(new CustomEvent("ready",{detail:{value:this.value},bubbles:!0}))}async loadControls(){if(this.controlsLoaded)return;this.controlsLoaded=!0;const t=new URL("./codeEditorControls/",import.meta.url).href;await Promise.all([import(`${t}FormatCode.js`),import(`${t}CopyCode.js`),import(`${t}EditorTheme.js`),import(`${t}Undo.js`),import(`${t}Redo.js`),import(`${t}WordWrap.js`),import(`${t}Minimap.js`),import(`${t}FindReplace.js`),import(`${t}FontSize.js`),import(`${t}FoldAll.js`),import(`${t}LanguageSelect.js`),import(`${t}Fullscreen.js`),import(`${t}ControlGroup.js`),import(`${t}ControlSpacer.js`)]),this.requestUpdate()}async initMonaco(){if(!this.monacoEditor){if(this.monacoInitPromise)return this.monacoInitPromise;this.monacoInitPromise=this._initMonaco(),await this.monacoInitPromise,this.monacoInitPromise=null}}async _initMonaco(){const t=this.monacoSrc||window.kempo?.monacoUrl||"https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min";await new Promise((e,o)=>{if(window.monaco)return void e();if(window.require?.defined?.("vs/editor/editor.main"))return void e();const i=document.querySelector(`script[src="${t}/vs/loader.js"]`);if(i)return void i.addEventListener("load",()=>{window.require.config({paths:{vs:`${t}/vs`}}),window.require(["vs/editor/editor.main"],()=>e(),o)});const s=document.createElement("script");s.src=`${t}/vs/loader.js`,s.onload=()=>{window.require.config({paths:{vs:`${t}/vs`}}),window.require(["vs/editor/editor.main"],()=>e(),o)},s.onerror=o,document.head.appendChild(s)}),this.monacoEditor=window.monaco.editor.create(this.monacoContainer,{value:this.value,language:this.language,theme:this.resolveMonacoTheme(),minimap:{enabled:!1},wordWrap:"on",fontSize:14,scrollBeyondLastLine:!1,automaticLayout:!0,tabSize:2,padding:{top:8}});const e=document.querySelector('link[href*="monaco"][href*="editor.main.css"]');if(e){const t=document.createElement("link");t.rel="stylesheet",t.href=e.href,this.shadowRoot.appendChild(t)}this.unsubscribeTheme=r(()=>{this.monacoEditor&&"auto"===this.editorTheme&&window.monaco.editor.setTheme(this.resolveMonacoTheme())}),this.monacoEditor.onDidChangeModelContent(()=>{this.skipValueSync=!0,this.value=this.monacoEditor.getValue(),this.skipValueSync=!1,this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0})),this.dispatchEvent(new CustomEvent("input",{detail:{value:this.value},bubbles:!0}))})}updateFormValue(){this.internals.setFormValue(this.getValue())}formResetCallback(){this.value=""}formStateRestoreCallback(t){this.value=t}getValue(){return this.monacoEditor?this.monacoEditor.getValue():this.value}setValue(t){return this.skipValueSync=!0,this.value=t,this.monacoEditor&&this.monacoEditor.setValue(t),this.updateFormValue(),this.skipValueSync=!1,this}clear(){return this.setValue("")}formatCode(){return this.monacoEditor?.getAction("editor.action.formatDocument")?.run(),this}selectAll(){if(!this.monacoEditor)return this;const t=this.monacoEditor.getModel();return t&&this.monacoEditor.setSelection(t.getFullModelRange()),this}getSelectedText(){return this.monacoEditor&&this.monacoEditor.getModel()?.getValueInRange(this.monacoEditor.getSelection())||""}focus(){return this.monacoEditor?.focus(),this}setLanguage(t){return this.language=t,this}setEditorTheme(t){return["auto","light","dark"].includes(t)&&(this.editorTheme=t),this}copyToClipboard(){return navigator.clipboard.writeText(this.getValue()),this}undo(){return this.monacoEditor?.trigger("toolbar","undo"),this}redo(){return this.monacoEditor?.trigger("toolbar","redo"),this}setWordWrap(t){return this.wordWrap=t,this}setMinimap(t){return this.minimapEnabled=t,this}toggleWordWrap(){return this.setWordWrap(!this.wordWrap)}toggleMinimap(){return this.setMinimap(!this.minimapEnabled)}openFind(){return this.monacoEditor?.getAction("actions.find")?.run(),this}increaseFontSize(){return this.fontSize=Math.min(this.fontSize+2,40),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}decreaseFontSize(){return this.fontSize=Math.max(this.fontSize-2,8),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}foldAll(){return this.monacoEditor?.getAction("editor.foldAll")?.run(),this}unfoldAll(){return this.monacoEditor?.getAction("editor.unfoldAll")?.run(),this}enterFullscreen(){return this.fullscreen=!0,document.body.classList.add("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!0},bubbles:!0})),this}exitFullscreen(){return this.fullscreen=!1,document.body.classList.remove("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!1},bubbles:!0})),this}toggleFullscreen(){return this.fullscreen?this.exitFullscreen():this.enterFullscreen()}resolveMonacoTheme(){return"dark"===this.editorTheme?"vs-dark":"light"===this.editorTheme?"vs":"dark"===s()?"vs-dark":"vs"}static controlSets={full:{topLeft:t`
1
+ import{html as t,css as e}from"../lit-all.min.js";import o from"./ShadowComponent.js";import i from"../utils/formatCode.js";import{getCalculatedTheme as s,subscribeToTheme as a}from"../utils/theme.js";export default class r extends o{static formAssociated=!0;static properties={name:{type:String,reflect:!0},value:{type:String,reflect:!0},language:{type:String,reflect:!0},monacoSrc:{type:String,attribute:"monaco-src"},controls:{type:String,reflect:!0},editorTheme:{type:String,attribute:"editor-theme",reflect:!0},hasTopToolbar:{type:Boolean,state:!0},hasBottomToolbar:{type:Boolean,state:!0},fullscreen:{type:Boolean,reflect:!0},wordWrap:{type:Boolean},minimapEnabled:{type:Boolean},disabled:{type:Boolean,reflect:!0},readonly:{type:Boolean,reflect:!0},required:{type:Boolean,reflect:!0}};constructor(){super(),this.internals=this.attachInternals(),this.name="",this.value="",this.language="javascript",this.monacoSrc="",this.controls="",this.controlsLoaded=!1,this.hasTopToolbar=!1,this.hasBottomToolbar=!1,this.monacoEditor=null,this.skipValueSync=!1,this.editorTheme="auto",this.wordWrap=!0,this.minimapEnabled=!1,this.fontSize=14,this.fullscreen=!1,this.disabled=!1,this.readonly=!1,this.required=!1}connectedCallback(){super.connectedCallback(),this.hasAttribute("value")&&(this.value=this.getAttribute("value")),this.slotObserver=new MutationObserver(()=>this.updateToolbarVisibility()),this.slotObserver.observe(this,{childList:!0,subtree:!0}),this.updateToolbarVisibility()}disconnectedCallback(){super.disconnectedCallback(),this.slotObserver?.disconnect(),this.monacoEditor?.dispose(),this.unsubscribeTheme?.(),this.fullscreen&&this.exitFullscreen()}updateToolbarVisibility(){const t=new Set(Array.from(this.children).map(t=>t.getAttribute("slot"))),e=this.constructor.controlSets[this.controls]??null;this.hasTopToolbar=!(!e?.topLeft&&!e?.topRight)||["toolbar-top","toolbar-top-left","toolbar-top-right"].some(e=>t.has(e)),this.hasBottomToolbar=!(!e?.bottomLeft&&!e?.bottomRight)||["toolbar-bottom","toolbar-bottom-left","toolbar-bottom-right"].some(e=>t.has(e))}updated(t){if(super.updated(t),t.has("controls")&&(this.updateToolbarVisibility(),this.controls&&"none"!==this.controls&&this.loadControls()),t.has("value")&&!this.skipValueSync&&(this.monacoEditor&&this.monacoEditor.getValue()!==this.value&&this.monacoEditor.setValue(this.value),this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))),t.has("language")&&this.monacoEditor){const t=this.monacoEditor.getModel();t&&window.monaco.editor.setModelLanguage(t,this.language),this.dispatchEvent(new CustomEvent("language-changed",{detail:{language:this.language},bubbles:!0}))}t.has("editorTheme")&&this.monacoEditor&&(window.monaco.editor.setTheme(this.resolveMonacoTheme()),this.dispatchEvent(new CustomEvent("editor-theme-changed",{detail:{editorTheme:this.editorTheme},bubbles:!0}))),t.has("wordWrap")&&(this.monacoEditor?.updateOptions({wordWrap:this.wordWrap?"on":"off"}),this.dispatchEvent(new CustomEvent("word-wrap-changed",{detail:{wordWrap:this.wordWrap},bubbles:!0}))),t.has("minimapEnabled")&&(this.monacoEditor?.updateOptions({minimap:{enabled:this.minimapEnabled}}),this.dispatchEvent(new CustomEvent("minimap-changed",{detail:{minimapEnabled:this.minimapEnabled},bubbles:!0}))),t.has("fullscreen")&&(this.fullscreen||this.monacoEditor?.layout({width:0,height:0}),requestAnimationFrame(()=>this.monacoEditor?.layout())),(t.has("disabled")||t.has("readonly"))&&this.monacoEditor?.updateOptions({readOnly:this.disabled||this.readonly}),(t.has("value")||t.has("required")||t.has("disabled"))&&this.#t()}#t=()=>{this.disabled?this.internals.setValidity({}):this.required&&!(this.getValue()||"").trim()?this.internals.setValidity({valueMissing:!0},"Please fill out this field.",this.monacoContainer||this):this.internals.setValidity({})};async firstUpdated(){this.monacoContainer=this.shadowRoot.querySelector(".monaco-editor-container"),await this.initMonaco(),this.dispatchEvent(new CustomEvent("ready",{detail:{value:this.value},bubbles:!0}))}async loadControls(){if(this.controlsLoaded)return;this.controlsLoaded=!0;const t=new URL("./codeEditorControls/",import.meta.url).href;await Promise.all([import(`${t}FormatCode.js`),import(`${t}CopyCode.js`),import(`${t}EditorTheme.js`),import(`${t}Undo.js`),import(`${t}Redo.js`),import(`${t}WordWrap.js`),import(`${t}Minimap.js`),import(`${t}FindReplace.js`),import(`${t}FontSize.js`),import(`${t}FoldAll.js`),import(`${t}LanguageSelect.js`),import(`${t}Fullscreen.js`),import(`${t}ControlGroup.js`),import(`${t}ControlSpacer.js`)]),this.requestUpdate()}async initMonaco(){if(!this.monacoEditor){if(this.monacoInitPromise)return this.monacoInitPromise;this.monacoInitPromise=this._initMonaco(),await this.monacoInitPromise,this.monacoInitPromise=null}}async _initMonaco(){const t=this.monacoSrc||window.kempo?.monacoUrl||"https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min";await new Promise((e,o)=>{if(window.monaco)return void e();if(window.require?.defined?.("vs/editor/editor.main"))return void e();const i=document.querySelector(`script[src="${t}/vs/loader.js"]`);if(i)return void i.addEventListener("load",()=>{window.require.config({paths:{vs:`${t}/vs`}}),window.require(["vs/editor/editor.main"],()=>e(),o)});const s=document.createElement("script");s.src=`${t}/vs/loader.js`,s.onload=()=>{window.require.config({paths:{vs:`${t}/vs`}}),window.require(["vs/editor/editor.main"],()=>e(),o)},s.onerror=o,document.head.appendChild(s)}),this.monacoEditor=window.monaco.editor.create(this.monacoContainer,{value:this.value,language:this.language,theme:this.resolveMonacoTheme(),minimap:{enabled:!1},wordWrap:"on",fontSize:14,scrollBeyondLastLine:!1,automaticLayout:!0,tabSize:2,padding:{top:8},readOnly:this.disabled||this.readonly});const e=document.querySelector('link[href*="monaco"][href*="editor.main.css"]');if(e){const t=document.createElement("link");t.rel="stylesheet",t.href=e.href,this.shadowRoot.appendChild(t)}this.unsubscribeTheme=a(()=>{this.monacoEditor&&"auto"===this.editorTheme&&window.monaco.editor.setTheme(this.resolveMonacoTheme())}),this.monacoEditor.onDidChangeModelContent(()=>{this.skipValueSync=!0,this.value=this.monacoEditor.getValue(),this.skipValueSync=!1,this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0})),this.dispatchEvent(new CustomEvent("input",{detail:{value:this.value},bubbles:!0}))})}updateFormValue(){this.internals.setFormValue(this.getValue())}formResetCallback(){this.value=""}formStateRestoreCallback(t){this.value=t}formDisabledCallback(t){this.disabled=t}getValue(){return this.monacoEditor?this.monacoEditor.getValue():this.value}setValue(t){return this.skipValueSync=!0,this.value=t,this.monacoEditor&&this.monacoEditor.setValue(t),this.updateFormValue(),this.skipValueSync=!1,this}clear(){return this.setValue("")}formatCode(){return this.monacoEditor?.getAction("editor.action.formatDocument")?.run(),this}selectAll(){if(!this.monacoEditor)return this;const t=this.monacoEditor.getModel();return t&&this.monacoEditor.setSelection(t.getFullModelRange()),this}getSelectedText(){return this.monacoEditor&&this.monacoEditor.getModel()?.getValueInRange(this.monacoEditor.getSelection())||""}focus(){return this.monacoEditor?.focus(),this}setLanguage(t){return this.language=t,this}setEditorTheme(t){return["auto","light","dark"].includes(t)&&(this.editorTheme=t),this}copyToClipboard(){return navigator.clipboard.writeText(this.getValue()),this}undo(){return this.monacoEditor?.trigger("toolbar","undo"),this}redo(){return this.monacoEditor?.trigger("toolbar","redo"),this}setWordWrap(t){return this.wordWrap=t,this}setMinimap(t){return this.minimapEnabled=t,this}toggleWordWrap(){return this.setWordWrap(!this.wordWrap)}toggleMinimap(){return this.setMinimap(!this.minimapEnabled)}openFind(){return this.monacoEditor?.getAction("actions.find")?.run(),this}increaseFontSize(){return this.fontSize=Math.min(this.fontSize+2,40),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}decreaseFontSize(){return this.fontSize=Math.max(this.fontSize-2,8),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}foldAll(){return this.monacoEditor?.getAction("editor.foldAll")?.run(),this}unfoldAll(){return this.monacoEditor?.getAction("editor.unfoldAll")?.run(),this}enterFullscreen(){return this.fullscreen=!0,document.body.classList.add("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!0},bubbles:!0})),this}exitFullscreen(){return this.fullscreen=!1,document.body.classList.remove("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!1},bubbles:!0})),this}toggleFullscreen(){return this.fullscreen?this.exitFullscreen():this.enterFullscreen()}resolveMonacoTheme(){return"dark"===this.editorTheme?"vs-dark":"light"===this.editorTheme?"vs":"dark"===s()?"vs-dark":"vs"}static controlSets={full:{topLeft:t`
2
2
  <k-cec-group>
3
3
  <k-cec-undo></k-cec-undo>
4
4
  <k-cec-redo></k-cec-redo>
@@ -69,6 +69,25 @@ import{html as t,css as e}from"../lit-all.min.js";import o from"./ShadowComponen
69
69
  [hidden] {
70
70
  display: none !important;
71
71
  }
72
+ :host([disabled]) {
73
+ opacity: 0.6;
74
+ }
75
+ /* disabled blocks all interaction -- toolbar AND editor. Monaco's
76
+ readOnly already prevents typing; pointer-events: none also stops
77
+ focus / cursor placement, matching native form control semantics. */
78
+ :host([disabled]) .toolbar-top,
79
+ :host([disabled]) .toolbar-bottom,
80
+ :host([disabled]) .editor-container {
81
+ pointer-events: none;
82
+ }
83
+ /* readonly keeps the editor interactive (so users can place a cursor
84
+ to select / copy) but mutes the toolbar so its buttons can't
85
+ mutate the document. */
86
+ :host([readonly]) .toolbar-top,
87
+ :host([readonly]) .toolbar-bottom {
88
+ pointer-events: none;
89
+ opacity: 0.5;
90
+ }
72
91
  `;render(){const e=this.constructor.controlSets[this.controls]??{};return t`
73
92
  ${this.hasTopToolbar?t`
74
93
  <div class="toolbar-top bb">
@@ -93,4 +112,4 @@ import{html as t,css as e}from"../lit-all.min.js";import o from"./ShadowComponen
93
112
  </div>
94
113
  </div>
95
114
  `:""}
96
- `}}customElements.define("k-code-editor",a);
115
+ `}}customElements.define("k-code-editor",r);
@@ -14,7 +14,7 @@ import{html as e,css as t}from"../lit-all.min.js";import o from"./ShadowComponen
14
14
  display: none;
15
15
  position: fixed;
16
16
  position-anchor: --dropdown-trigger;
17
- z-index: 70;
17
+ z-index: 30;
18
18
  min-width: anchor-size(width);
19
19
  background: var(--c_bg);
20
20
  border: 1px solid var(--c_border);
@@ -1,4 +1,4 @@
1
- import{html as e,css as t}from"../lit-all.min.js";import i from"./ShadowComponent.js";import o from"../utils/formatCode.js";import l from"../utils/debounce.js";import{getCalculatedTheme as r,subscribeToTheme as s}from"../utils/theme.js";import a from"./Dialog.js";export default class c extends i{static formAssociated=!0;static properties={name:{type:String,reflect:!0},value:{type:String,reflect:!0},selection:{type:Object,state:!0},mode:{type:String,reflect:!0},controls:{type:String,reflect:!0},lexicalSrc:{type:String,attribute:"lexical-src"},monacoSrc:{type:String,attribute:"monaco-src"},nodes:{type:String},hasTopToolbar:{type:Boolean,state:!0},hasBottomToolbar:{type:Boolean,state:!0},fullscreen:{type:Boolean,reflect:!0}};constructor(){super(),this.internals=this.attachInternals(),this.name="",this.value="",this.selection=null,this.cursor=null,this.mode="visual",this.controls="",this.controlsLoaded=!1,this.lexicalSrc="",this.monacoSrc="",this.nodes="",this.hasTopToolbar=!1,this.hasBottomToolbar=!1,this.skipValueSync=!1,this.lexicalValueSync=!1,this.savedSelection=null,this.lexicalEditor=null,this.monacoEditor=null,this.editorTheme="auto",this.wordWrap=!0,this.minimapEnabled=!1,this.fontSize=14,this.fullscreen=!1,this.lx={},this.debouncedSyncValue=l(()=>this.syncValueFromLexical(),300)}connectedCallback(){super.connectedCallback(),this.hasAttribute("value")&&(this.value=this.getAttribute("value")),this.slotObserver=new MutationObserver(()=>this.updateToolbarVisibility()),this.slotObserver.observe(this,{childList:!0,subtree:!0}),this.updateToolbarVisibility()}disconnectedCallback(){super.disconnectedCallback(),this.slotObserver?.disconnect(),this.cleanupFns?.forEach(e=>e?.()),this.monacoEditor?.dispose(),this.unsubscribeTheme?.(),this.fullscreen&&this.exitFullscreen()}updateToolbarVisibility(){const e=new Set(Array.from(this.children).map(e=>e.getAttribute("slot"))),t=this.constructor.controlSets[this.controls]??null;this.hasTopToolbar=!(!t?.topLeft&&!t?.topRight)||["toolbar-top","toolbar-top-left","toolbar-top-right"].some(t=>e.has(t)),this.hasBottomToolbar=!(!t?.bottomLeft&&!t?.bottomRight)||["toolbar-bottom","toolbar-bottom-left","toolbar-bottom-right"].some(t=>e.has(t))}updated(e){if(super.updated(e),e.has("controls")&&(this.updateToolbarVisibility(),this.controls&&"none"!==this.controls&&this.loadControls()),e.has("value")&&!this.skipValueSync&&(this.lexicalValueSync?this.lexicalValueSync=!1:this.lexicalEditor&&"visual"===this.mode&&!this.isVisualCompatible(this.value)?(this.skipLexicalExport=!0,this.mode="code"):this.syncContentToEditors(),this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))),e.has("mode")){const t=window.scrollY;this.handleModeSwitch(e.get("mode")),this.dispatchEvent(new CustomEvent("mode-changed",{detail:{mode:this.mode},bubbles:!0})),requestAnimationFrame(()=>window.scrollTo(0,t))}e.has("fullscreen")&&requestAnimationFrame(()=>this.monacoEditor?.layout())}async firstUpdated(){this.lexicalContainer=this.shadowRoot.querySelector(".lexical-editor"),this.monacoContainer=this.shadowRoot.querySelector(".monaco-editor-container"),await this.initLexical(),this.dispatchEvent(new CustomEvent("ready",{detail:{value:this.value},bubbles:!0}))}async loadControls(){if(this.controlsLoaded)return;this.controlsLoaded=!0;const e=new URL("./htmlEditorControls/",import.meta.url).href;await Promise.all([import(`${e}Bold.js`),import(`${e}Italic.js`),import(`${e}Underline.js`),import(`${e}Strikethrough.js`),import(`${e}InlineCode.js`),import(`${e}DropdownControl.js`),import(`${e}FormatBlock.js`),import(`${e}CodeBlock.js`),import(`${e}BulletList.js`),import(`${e}NumberList.js`),import(`${e}AlignLeft.js`),import(`${e}AlignCenter.js`),import(`${e}AlignRight.js`),import(`${e}AlignJustify.js`),import(`${e}TextColor.js`),import(`${e}TextBackgroundColor.js`),import(`${e}ClearFormatting.js`),import(`${e}CreateLink.js`),import(`${e}InsertTable.js`),import(`${e}ControlGroup.js`),import(`${e}ControlSpacer.js`),import(`${e}Mode.js`),import(`${e}WordCount.js`),import(`${e}CharacterCount.js`)]);const t=new URL("./codeEditorControls/",import.meta.url).href;await Promise.all([import(`${t}FormatCode.js`),import(`${t}CopyCode.js`),import(`${t}Undo.js`),import(`${t}Redo.js`),import(`${t}WordWrap.js`),import(`${t}Minimap.js`),import(`${t}FindReplace.js`),import(`${t}FontSize.js`),import(`${t}FoldAll.js`),import(`${t}EditorTheme.js`),import(`${t}Fullscreen.js`),import(`${t}ControlGroup.js`)]),this.requestUpdate()}async loadNodeModules(){if(!this.nodes?.trim())return[];const e=new URL("./htmlEditorNodes/",import.meta.url).href;return(await Promise.all(this.nodes.split(",").map(e=>e.trim()).filter(Boolean).map(t=>import(`${e}${t}.js`)))).map(e=>e.default?.lexicalNode).filter(Boolean)}async loadLexicalModules(){const e=this.lexicalSrc||window.kempo?.lexicalUrl||"https://esm.sh",t=t=>((e,t)=>`${e}/${t}@0.43.0`)(e,t),[i,o,l,r,s,a,c,n,h]=await Promise.all([import(t("lexical")),import(t("@lexical/rich-text")),import(t("@lexical/html")),import(t("@lexical/history")),import(t("@lexical/list")),import(t("@lexical/link")),import(t("@lexical/selection")),import(t("@lexical/table")),import(t("@lexical/code"))]);this.lx={lexical:i,richText:o,lexicalHtml:l,history:r,list:s,link:a,selection:c,table:n,code:h},this.StyledTextNode=class extends i.TextNode{static getType(){return"styled-text"}static clone(e){return new this(e.__text,e.__key)}static importDOM(){return{span:()=>({conversion:e=>{const t=e.getAttribute("style");if(!t)return null;const o=i.$createTextNode(e.textContent);return o.setStyle(t),{node:o}},priority:1})}}static importJSON(e){return i.$createTextNode(e.text)}exportJSON(){return{...super.exportJSON(),type:"styled-text"}}}}async initLexical(){await this.loadLexicalModules(),this.customNodes=await this.loadNodeModules(),this.nodeCompatCheckers=this.customNodes.filter(e=>"function"==typeof e.isVisualCompatible).map(e=>e.isVisualCompatible),this.nodePreprocessors=this.customNodes.filter(e=>"function"==typeof e.preprocessHtml).map(e=>e.preprocessHtml);const{lexical:e,richText:t,history:i,list:o,link:l,table:r,code:s}=this.lx,a={namespace:"KempoHtmlEditor",theme:{paragraph:"k-editor-p",heading:{h1:"k-editor-h1",h2:"k-editor-h2",h3:"k-editor-h3",h4:"k-editor-h4",h5:"k-editor-h5",h6:"k-editor-h6"},text:{underline:"td-u",strikethrough:"td-lt"},list:{ul:"k-editor-ul",ol:"k-editor-ol",listitem:"k-editor-li"},link:"k-editor-link",quote:"k-editor-quote",code:"k-editor-code-block",codeHighlight:{},table:"k-editor-table",tableCell:"k-editor-table-cell",tableCellHeader:"k-editor-table-cell-header"},nodes:[t.HeadingNode,t.QuoteNode,o.ListNode,o.ListItemNode,l.LinkNode,r.TableNode,r.TableCellNode,r.TableRowNode,s.CodeNode,s.CodeHighlightNode,this.StyledTextNode,...this.customNodes],onError:console.error,editorState:null};this.lexicalEditor=e.createEditor(a),this.lexicalEditor.setRootElement(this.lexicalContainer),this.lexicalEditor._window=new Proxy(window,{get:(e,t)=>{if("getSelection"===t)return()=>this.shadowRoot.getSelection();const i=Reflect.get(e,t);return"function"==typeof i?i.bind(e):i}}),this.cleanupFns=[t.registerRichText(this.lexicalEditor),i.registerHistory(this.lexicalEditor,i.createEmptyHistoryState(),300)],o.registerList&&this.cleanupFns.push(o.registerList(this.lexicalEditor)),r.registerTable&&this.cleanupFns.push(r.registerTable(this.lexicalEditor)),s.registerCodeHighlighting&&this.cleanupFns.push(s.registerCodeHighlighting(this.lexicalEditor)),l.registerLink&&this.cleanupFns.push(l.registerLink(this.lexicalEditor,{validateUrl:e=>{try{return new URL(e),!0}catch{return!1}}})),this.value&&(this.isVisualCompatible(this.value)?this.importHtmlToLexical(this.value):(this.skipLexicalExport=!0,this.mode="code")),this.lexicalEditor.registerUpdateListener(({dirtyElements:e,dirtyLeaves:t})=>{0===e.size&&0===t.size||(this.debouncedSyncValue(),this.dispatchEvent(new CustomEvent("input",{detail:{value:this.exportHtmlFromLexical()},bubbles:!0})))}),this.lexicalEditor.registerCommand(e.SELECTION_CHANGE_COMMAND,()=>(this.updateSelection(),!1),e.COMMAND_PRIORITY_LOW)}async initMonaco(){if(!this.monacoEditor){if(this.monacoInitPromise)return this.monacoInitPromise;this.monacoInitPromise=this._initMonaco(),await this.monacoInitPromise,this.monacoInitPromise=null}}async _initMonaco(){const e=this.monacoSrc||window.kempo?.monacoUrl||"https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min";await new Promise((t,i)=>{if(window.monaco)return void t();if(window.require?.defined?.("vs/editor/editor.main"))return void t();const o=document.querySelector(`script[src="${e}/vs/loader.js"]`);if(o)return void o.addEventListener("load",()=>{window.require.config({paths:{vs:`${e}/vs`}}),window.require(["vs/editor/editor.main"],()=>t(),i)});const l=document.createElement("script");l.src=`${e}/vs/loader.js`,l.onload=()=>{window.require.config({paths:{vs:`${e}/vs`}}),window.require(["vs/editor/editor.main"],()=>t(),i)},l.onerror=i,document.head.appendChild(l)}),this.monacoEditor=window.monaco.editor.create(this.monacoContainer,{value:o(this.value),language:"html",theme:this.resolveMonacoTheme(),minimap:{enabled:this.minimapEnabled},wordWrap:this.wordWrap?"on":"off",fontSize:this.fontSize,scrollBeyondLastLine:!1,automaticLayout:!0,tabSize:2,padding:{top:8}});const t=document.querySelector('link[href*="monaco"][href*="editor.main.css"]');if(t){const e=document.createElement("link");e.rel="stylesheet",e.href=t.href,this.shadowRoot.appendChild(e)}this.unsubscribeTheme=s(()=>{this.monacoEditor&&"auto"===this.editorTheme&&window.monaco.editor.setTheme(this.resolveMonacoTheme())}),this.monacoEditor.onDidChangeModelContent(()=>{this.skipValueSync=!0,this.value=this.monacoEditor.getValue(),this.skipValueSync=!1,this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0})),this.dispatchEvent(new CustomEvent("input",{detail:{value:this.value},bubbles:!0}))})}importHtmlToLexical(e){if(!this.lexicalEditor||!this.lx.lexicalHtml)return;const{lexical:t,lexicalHtml:i}=this.lx,o=(this.nodePreprocessors||[]).reduce((e,t)=>t(e),e);this.lexicalEditor.update(()=>{if(t.$getRoot().clear(),!o?.trim())return;const e=(new DOMParser).parseFromString(o,"text/html"),l=i.$generateNodesFromDOM(this.lexicalEditor,e);l.length>0&&t.$insertNodes(l)},{discrete:!0})}exportHtmlFromLexical(){if(!this.lexicalEditor||!this.lx.lexicalHtml)return this.value;let e="";return this.lexicalEditor.getEditorState().read(()=>{e=this.lx.lexicalHtml.$generateHtmlFromNodes(this.lexicalEditor,null)}),this.cleanExportedHtml(e)}isVisualCompatible(e){if(!e?.trim())return!0;const t=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"]),i=this.nodeCompatCheckers||[],o=(new DOMParser).parseFromString(e,"text/html"),l=document.createTreeWalker(o.body,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT);let r;for(;r=l.nextNode();)if(!i.some(e=>e(r))){if(r.nodeType===Node.COMMENT_NODE)return!1;if(t.has(r.tagName?.toLowerCase()))return!1}return!0}cleanExportedHtml(e){const t=(new DOMParser).parseFromString(e,"text/html");return t.body.querySelectorAll("[class]").forEach(e=>{const t=Array.from(e.classList).filter(e=>!e.startsWith("k-editor-")&&"td-u"!==e&&"td-lt"!==e);0===t.length?e.removeAttribute("class"):e.className=t.join(" ")}),t.body.querySelectorAll("[style]").forEach(e=>{const t=e.style.cssText.replace(/white-space:\s*pre-wrap;?\s*/g,"").trim();t?e.style.cssText=t:e.removeAttribute("style")}),t.body.querySelectorAll("span:not([class]):not([style]):not([id])").forEach(e=>{e.attributes.length||e.replaceWith(...e.childNodes)}),t.body.querySelectorAll("b > strong, i > em, b > b, strong > strong, i > i, em > em").forEach(e=>{e.replaceWith(...e.childNodes)}),t.body.querySelectorAll("pre[data-highlight-language], code[data-highlight-language]").forEach(e=>{e.removeAttribute("data-highlight-language"),e.removeAttribute("data-language")}),t.body.innerHTML}syncValueFromLexical(){this.lexicalEditor&&(this.lexicalValueSync=!0,this.value=this.exportHtmlFromLexical(),this.updateFormValue())}syncContentToEditors(){"visual"===this.mode&&this.lexicalEditor&&this.importHtmlToLexical(this.value)}async handleModeSwitch(e){"code"===this.mode?(this.lexicalEditor&&!this.skipLexicalExport&&(this.value=this.exportHtmlFromLexical()),this.skipLexicalExport=!1,await this.initMonaco(),this.monacoEditor&&(this.monacoEditor.setValue(o(this.value)),this.monacoEditor.layout())):"visual"===this.mode&&(this.monacoEditor&&(this.value=this.monacoEditor.getValue()),this.lexicalEditor&&this.importHtmlToLexical(this.value)),this.requestUpdate()}updateFormValue(){this.internals.setFormValue(this.getValue())}formResetCallback(){this.value=""}formStateRestoreCallback(e){this.value=e}updateSelection=()=>{if("visual"!==this.mode||!this.lexicalEditor)return void(this.selection=null);const{lexical:e}=this.lx;this.lexicalEditor.getEditorState().read(()=>{const t=e.$getSelection();e.$isRangeSelection(t)&&!t.isCollapsed()?this.selection={text:t.getTextContent(),collapsed:!1}:(this.selection=null,this.cursor=t?{anchor:t.anchor,focus:t.focus}:null)})};setMode(e){return["visual","code"].includes(e)?"visual"!==e||this.isVisualCompatible(this.getValue())?(this.mode=e,this):(a.confirm("This html contains code that is not compatible with the visual editor, the incompatible code will be lost",t=>{t&&(this.mode=e)},{title:"Warning",confirmText:"Change Anyways"}),this):this}toggleMode(){return this.setMode("visual"===this.mode?"code":"visual")}getValue(){if("visual"===this.mode&&this.lexicalEditor)this.skipValueSync=!0,this.value=this.exportHtmlFromLexical(),this.skipValueSync=!1;else if("code"===this.mode&&this.monacoEditor)return this.monacoEditor.getValue();return this.value}setValue(e){return this.lexicalEditor&&"visual"===this.mode&&!this.isVisualCompatible(e)?(this.value=e,this.skipLexicalExport=!0,this.mode="code",this.updateFormValue(),this):(this.skipValueSync=!0,this.value=e,"visual"===this.mode?this.syncContentToEditors():"code"===this.mode&&this.monacoEditor&&this.monacoEditor.setValue(o(e)),this.updateFormValue(),this.skipValueSync=!1,this)}clear(){return this.setValue("")}bold(){return this.lexicalFormat("bold"),this}italic(){return this.lexicalFormat("italic"),this}underline(){return this.lexicalFormat("underline"),this}strikethrough(){return this.lexicalFormat("strikethrough"),this}inlineCode(){return this.lexicalFormat("code"),this}orderedList(){return"visual"===this.mode&&this.lexicalEditor?(this.lexicalEditor.update(()=>{this.lx.list.$insertList("number")},{discrete:!0}),this):this}unorderedList(){return"visual"===this.mode&&this.lexicalEditor?(this.lexicalEditor.update(()=>{this.lx.list.$insertList("bullet")},{discrete:!0}),this):this}alignLeft(){return this.lexicalFormatElement("left"),this}alignCenter(){return this.lexicalFormatElement("center"),this}alignRight(){return this.lexicalFormatElement("right"),this}alignJustify(){return this.lexicalFormatElement("justify"),this}setTextColor(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,selection:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&i.$patchStyleText(o,{color:e})},{discrete:!0}),this}removeTextColor(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&t.$patchStyleText(i,{color:null})},{discrete:!0}),this}setTextBackgroundColor(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,selection:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&i.$patchStyleText(o,{"background-color":e})},{discrete:!0}),this}removeTextBackgroundColor(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&t.$patchStyleText(i,{"background-color":null})},{discrete:!0}),this}removeFormat(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&(i.getNodes().forEach(t=>{e.$isTextNode(t)&&t.setFormat(0)}),t.$patchStyleText(i,{color:null,"background-color":null}))},{discrete:!0}),this}formatBlock(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,richText:i,code:o}=this.lx;return this.lexicalEditor.update(()=>{const l=t.$getSelection();if(!t.$isRangeSelection(l))return;const r=l.anchor.getNode().getTopLevelElementOrThrow(),s=o.$isCodeNode(r);let a;if("p"===e)a=t.$createParagraphNode();else if(e.match(/^h[1-6]$/))a=i.$createHeadingNode(e);else if("blockquote"===e)a=i.$createQuoteNode();else{if("pre"!==e)return;a=o.$createCodeNode()}if(s&&"pre"!==e){const e=r.getTextContent();r.replace(a),a.append(t.$createTextNode(e))}else{const e=r.getChildren();r.replace(a),e.forEach(e=>a.append(e))}a.selectEnd()},{discrete:!0}),this}isSelectionInCodeBlock(){if("visual"!==this.mode||!this.lexicalEditor)return!1;let e=!1;const{lexical:t,code:i}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&(e=i.$isCodeNode(o.anchor.getNode().getTopLevelElementOrThrow()))}),e}getTableAtSelection(){if("visual"!==this.mode||!this.lexicalEditor)return null;let e=null;const{lexical:t,table:i}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const o=t.$getSelection();if(!t.$isRangeSelection(o))return;let l=o.anchor.getNode();for(;l;){if(i.$isTableNode(l)){const t=l.getChildren(),o=[];let r=!1,s=0;t.forEach((e,t)=>{const l=[];e.getChildren().forEach(e=>{0===t&&i.$isTableCellNode(e)&&e.getHeaderStyles()===i.TableCellHeaderStates.ROW&&(r=!0),l.push(e.getTextContent())}),l.length>s&&(s=l.length),o.push(l)}),e={key:l.getKey(),rows:r?t.length-1:t.length,cols:s,hasHeaders:r,cellData:o};break}l=l.getParent()}}),e}removeTableByKey(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t}=this.lx;return this.lexicalEditor.update(()=>{const i=t.$getNodeByKey(e);i&&i.remove()},{discrete:!0}),this}insertHTML(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,lexicalHtml:i}=this.lx;return this.lexicalEditor.update(()=>{const o=(new DOMParser).parseFromString(e,"text/html"),l=i.$generateNodesFromDOM(this.lexicalEditor,o);t.$insertNodes(l)},{discrete:!0}),this}insertAtCursor(e){return this.insertHTML(e)}insertTable(e,t,i=!1,o=null){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:l,table:r}=this.lx;return this.lexicalEditor.update(()=>{const s=e+(i?1:0),a=[];for(let e=0;e<s;e++){const s=[];for(let a=0;a<t;a++){const t=i&&0===e,c=t?r.TableCellHeaderStates.ROW:r.TableCellHeaderStates.NO_STATUS,n=r.$createTableCellNode(c),h=o?.[e]?.[a]??(t?`Header ${a+1}`:""),d=l.$createParagraphNode();d.append(l.$createTextNode(h||" ")),n.append(d),s.push(n)}a.push(r.$createTableRowNode().append(...s))}const c=r.$createTableNode().append(...a),n=l.$getSelection();if(l.$isRangeSelection(n)){n.anchor.getNode().getTopLevelElementOrThrow().insertAfter(c);const e=l.$createParagraphNode();c.insertAfter(e),e.selectEnd()}else{const e=l.$getRoot();e.append(c),e.append(l.$createParagraphNode())}},{discrete:!0}),this}insertElementAtCursor(e){return this.insertHTML(e.outerHTML)}replaceSelectionWithElement(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,lexicalHtml:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();if(!t.$isRangeSelection(o))return;o.removeText();const l=(new DOMParser).parseFromString(e.outerHTML,"text/html"),r=i.$generateNodesFromDOM(this.lexicalEditor,l);t.$insertNodes(r)},{discrete:!0}),this}wrapSelection(e,t,i=null){if("visual"!==this.mode||!this.lexicalEditor)return this;const o=i||this.getSelectedText();return o?this.insertHTML(e+o+t):this}getSelection(){if("visual"!==this.mode||!this.lexicalEditor)return null;let e=null;const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&!i.isCollapsed()&&(e={text:i.getTextContent(),html:i.getTextContent(),selection:i})}),e}getSelectedText(){let e="";if("visual"!==this.mode||!this.lexicalEditor)return e;const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&(e=i.getTextContent())}),e}getSelectedHTML(){return this.getSelectedText()}selectAll(){if("visual"===this.mode&&this.lexicalEditor){const{lexical:e}=this.lx;this.lexicalEditor.update(()=>{e.$selectAll()},{discrete:!0})}else if(this.monacoEditor){const e=this.monacoEditor.getModel();e&&this.monacoEditor.setSelection(e.getFullModelRange())}return this}replaceSelection(e){return this.insertHTML(e)}deleteSelection(){return"visual"===this.mode?this.lexicalCmd("DELETE_CHARACTER_COMMAND",!1):this.monacoEditor&&this.monacoEditor.trigger("keyboard","deleteAllLeft",null),this}getValueWithSelectionMarkers(){if("visual"!==this.mode||!this.lexicalEditor)return{html:this.value,hasCursor:!1,hasSelection:!1,selectedText:""};let e={html:this.exportHtmlFromLexical(),hasCursor:!1,hasSelection:!1,selectedText:""};const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&(i.isCollapsed()?e.hasCursor=!0:(e.hasSelection=!0,e.selectedText=i.getTextContent()))}),e}setValueFromSelectionMarkers(e){return this.setValue(e)}captureSelection(){return this.selection}restoreSavedSelection(){return!1}clearSavedSelection(){this.savedSelection=null}createLink(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{link:t}=this.lx;return this.lexicalEditor.update(()=>{t.$toggleLink(e)},{discrete:!0}),this}createLinkWithText(e,t){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:i,link:o}=this.lx;return this.lexicalEditor.update(()=>{const l=i.$getSelection();i.$isRangeSelection(l)&&!l.isCollapsed()&&l.removeText();const r=o.$createLinkNode(e);r.append(i.$createTextNode(t)),i.$insertNodes([r])},{discrete:!0}),this}unlink(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,link:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&i.getNodes().forEach(e=>{const i=e.getParent();i&&t.$isLinkNode?.(i)&&(i.getChildren().forEach(e=>i.insertBefore(e)),i.remove())})},{discrete:!0}),this}insertImage(e){return this.insertHTML(`<img src="${encodeURI(e)}" />`)}undo(){return"code"===this.mode?this.monacoEditor?.trigger("toolbar","undo"):this.lexicalCmd("UNDO_COMMAND",void 0),this}redo(){return"code"===this.mode?this.monacoEditor?.trigger("toolbar","redo"):this.lexicalCmd("REDO_COMMAND",void 0),this}copyToClipboard(){return navigator.clipboard.writeText(this.getValue()),this}setEditorTheme(e){return["auto","light","dark"].includes(e)&&(this.editorTheme=e),this.monacoEditor&&window.monaco.editor.setTheme(this.resolveMonacoTheme()),this}openFind(){return this.monacoEditor?.getAction("actions.find")?.run(),this}foldAll(){return this.monacoEditor?.getAction("editor.foldAll")?.run(),this}unfoldAll(){return this.monacoEditor?.getAction("editor.unfoldAll")?.run(),this}enterFullscreen(){return this.fullscreen=!0,document.body.classList.add("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!0},bubbles:!0})),this}exitFullscreen(){return this.fullscreen=!1,document.body.classList.remove("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!1},bubbles:!0})),this}toggleFullscreen(){return this.fullscreen?this.exitFullscreen():this.enterFullscreen()}increaseFontSize(){return this.fontSize=Math.min(this.fontSize+2,40),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}decreaseFontSize(){return this.fontSize=Math.max(this.fontSize-2,8),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}setWordWrap(e){return this.wordWrap=e,this.monacoEditor?.updateOptions({wordWrap:e?"on":"off"}),this}setMinimap(e){return this.minimapEnabled=e,this.monacoEditor?.updateOptions({minimap:{enabled:e}}),this}resolveMonacoTheme(){return"dark"===this.editorTheme?"vs-dark":"light"===this.editorTheme?"vs":"dark"===r()?"vs-dark":"vs"}lexicalCmd(e,t){if("visual"!==this.mode||!this.lexicalEditor)return;const i=this.lx.lexical?.[e];i&&this.lexicalEditor.dispatchCommand(i,t)}lexicalFormat(e){if("visual"!==this.mode||!this.lexicalEditor)return;const{lexical:t}=this.lx;this.lexicalEditor.update(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&i.formatText(e)},{discrete:!0})}lexicalFormatElement(e){"visual"===this.mode&&this.lexicalEditor&&this.lexicalEditor.dispatchCommand(this.lx.lexical.FORMAT_ELEMENT_COMMAND,e)}render(){const t=this.constructor.controlSets[this.controls]??{};return e`
1
+ import{html as e,css as t}from"../lit-all.min.js";import i from"./ShadowComponent.js";import o from"../utils/formatCode.js";import l from"../utils/debounce.js";import{getCalculatedTheme as r,subscribeToTheme as s}from"../utils/theme.js";import a from"./Dialog.js";export default class c extends i{static formAssociated=!0;static properties={name:{type:String,reflect:!0},value:{type:String,reflect:!0},selection:{type:Object,state:!0},mode:{type:String,reflect:!0},controls:{type:String,reflect:!0},lexicalSrc:{type:String,attribute:"lexical-src"},monacoSrc:{type:String,attribute:"monaco-src"},nodes:{type:String},hasTopToolbar:{type:Boolean,state:!0},hasBottomToolbar:{type:Boolean,state:!0},fullscreen:{type:Boolean,reflect:!0},disabled:{type:Boolean,reflect:!0},readonly:{type:Boolean,reflect:!0},required:{type:Boolean,reflect:!0}};constructor(){super(),this.internals=this.attachInternals(),this.name="",this.value="",this.selection=null,this.cursor=null,this.mode="visual",this.controls="",this.controlsLoaded=!1,this.lexicalSrc="",this.monacoSrc="",this.nodes="",this.hasTopToolbar=!1,this.hasBottomToolbar=!1,this.skipValueSync=!1,this.lexicalValueSync=!1,this.savedSelection=null,this.lexicalEditor=null,this.monacoEditor=null,this.editorTheme="auto",this.wordWrap=!0,this.minimapEnabled=!1,this.fontSize=14,this.fullscreen=!1,this.disabled=!1,this.readonly=!1,this.required=!1,this.lx={},this.debouncedSyncValue=l(()=>this.syncValueFromLexical(),300)}connectedCallback(){super.connectedCallback(),this.hasAttribute("value")&&(this.value=this.getAttribute("value")),this.slotObserver=new MutationObserver(()=>this.updateToolbarVisibility()),this.slotObserver.observe(this,{childList:!0,subtree:!0}),this.updateToolbarVisibility()}disconnectedCallback(){super.disconnectedCallback(),this.slotObserver?.disconnect(),this.cleanupFns?.forEach(e=>e?.()),this.monacoEditor?.dispose(),this.unsubscribeTheme?.(),this.fullscreen&&this.exitFullscreen()}updateToolbarVisibility(){const e=new Set(Array.from(this.children).map(e=>e.getAttribute("slot"))),t=this.constructor.controlSets[this.controls]??null;this.hasTopToolbar=!(!t?.topLeft&&!t?.topRight)||["toolbar-top","toolbar-top-left","toolbar-top-right"].some(t=>e.has(t)),this.hasBottomToolbar=!(!t?.bottomLeft&&!t?.bottomRight)||["toolbar-bottom","toolbar-bottom-left","toolbar-bottom-right"].some(t=>e.has(t))}updated(e){if(super.updated(e),e.has("controls")&&(this.updateToolbarVisibility(),this.controls&&"none"!==this.controls&&this.loadControls()),e.has("value")&&!this.skipValueSync&&(this.lexicalValueSync?this.lexicalValueSync=!1:this.lexicalEditor&&"visual"===this.mode&&!this.isVisualCompatible(this.value)?(this.skipLexicalExport=!0,this.mode="code"):this.syncContentToEditors(),this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))),e.has("mode")){const t=window.scrollY;this.handleModeSwitch(e.get("mode")),this.dispatchEvent(new CustomEvent("mode-changed",{detail:{mode:this.mode},bubbles:!0})),requestAnimationFrame(()=>window.scrollTo(0,t))}if(e.has("fullscreen")&&requestAnimationFrame(()=>this.monacoEditor?.layout()),e.has("disabled")||e.has("readonly")){const e=this.disabled||this.readonly;this.lexicalEditor?.setEditable(!e),this.monacoEditor?.updateOptions({readOnly:e})}(e.has("value")||e.has("required")||e.has("disabled"))&&this.#e()}#e=()=>{if(this.disabled)return void this.internals.setValidity({});const e=!(this.value||"").replace(/<[^>]+>/g,"").trim();this.required&&e?this.internals.setValidity({valueMissing:!0},"Please fill out this field.",this.lexicalContainer||this):this.internals.setValidity({})};async firstUpdated(){this.lexicalContainer=this.shadowRoot.querySelector(".lexical-editor"),this.monacoContainer=this.shadowRoot.querySelector(".monaco-editor-container"),await this.initLexical(),this.dispatchEvent(new CustomEvent("ready",{detail:{value:this.value},bubbles:!0}))}async loadControls(){if(this.controlsLoaded)return;this.controlsLoaded=!0;const e=new URL("./htmlEditorControls/",import.meta.url).href;await Promise.all([import(`${e}Bold.js`),import(`${e}Italic.js`),import(`${e}Underline.js`),import(`${e}Strikethrough.js`),import(`${e}InlineCode.js`),import(`${e}DropdownControl.js`),import(`${e}FormatBlock.js`),import(`${e}CodeBlock.js`),import(`${e}BulletList.js`),import(`${e}NumberList.js`),import(`${e}AlignLeft.js`),import(`${e}AlignCenter.js`),import(`${e}AlignRight.js`),import(`${e}AlignJustify.js`),import(`${e}TextColor.js`),import(`${e}TextBackgroundColor.js`),import(`${e}ClearFormatting.js`),import(`${e}CreateLink.js`),import(`${e}InsertTable.js`),import(`${e}ControlGroup.js`),import(`${e}ControlSpacer.js`),import(`${e}Mode.js`),import(`${e}WordCount.js`),import(`${e}CharacterCount.js`)]);const t=new URL("./codeEditorControls/",import.meta.url).href;await Promise.all([import(`${t}FormatCode.js`),import(`${t}CopyCode.js`),import(`${t}Undo.js`),import(`${t}Redo.js`),import(`${t}WordWrap.js`),import(`${t}Minimap.js`),import(`${t}FindReplace.js`),import(`${t}FontSize.js`),import(`${t}FoldAll.js`),import(`${t}EditorTheme.js`),import(`${t}Fullscreen.js`),import(`${t}ControlGroup.js`)]),this.requestUpdate()}async loadNodeModules(){if(!this.nodes?.trim())return[];const e=new URL("./htmlEditorNodes/",import.meta.url).href;return(await Promise.all(this.nodes.split(",").map(e=>e.trim()).filter(Boolean).map(t=>import(`${e}${t}.js`)))).map(e=>e.default?.lexicalNode).filter(Boolean)}async loadLexicalModules(){const e=this.lexicalSrc||window.kempo?.lexicalUrl||"https://esm.sh",t=t=>((e,t)=>`${e}/${t}@0.43.0`)(e,t),[i,o,l,r,s,a,c,n,h]=await Promise.all([import(t("lexical")),import(t("@lexical/rich-text")),import(t("@lexical/html")),import(t("@lexical/history")),import(t("@lexical/list")),import(t("@lexical/link")),import(t("@lexical/selection")),import(t("@lexical/table")),import(t("@lexical/code"))]);this.lx={lexical:i,richText:o,lexicalHtml:l,history:r,list:s,link:a,selection:c,table:n,code:h},this.StyledTextNode=class extends i.TextNode{static getType(){return"styled-text"}static clone(e){return new this(e.__text,e.__key)}static importDOM(){return{span:()=>({conversion:e=>{const t=e.getAttribute("style");if(!t)return null;const o=i.$createTextNode(e.textContent);return o.setStyle(t),{node:o}},priority:1})}}static importJSON(e){return i.$createTextNode(e.text)}exportJSON(){return{...super.exportJSON(),type:"styled-text"}}}}async initLexical(){await this.loadLexicalModules(),this.customNodes=await this.loadNodeModules(),this.nodeCompatCheckers=this.customNodes.filter(e=>"function"==typeof e.isVisualCompatible).map(e=>e.isVisualCompatible),this.nodePreprocessors=this.customNodes.filter(e=>"function"==typeof e.preprocessHtml).map(e=>e.preprocessHtml);const{lexical:e,richText:t,history:i,list:o,link:l,table:r,code:s}=this.lx,a={namespace:"KempoHtmlEditor",theme:{paragraph:"k-editor-p",heading:{h1:"k-editor-h1",h2:"k-editor-h2",h3:"k-editor-h3",h4:"k-editor-h4",h5:"k-editor-h5",h6:"k-editor-h6"},text:{underline:"td-u",strikethrough:"td-lt"},list:{ul:"k-editor-ul",ol:"k-editor-ol",listitem:"k-editor-li"},link:"k-editor-link",quote:"k-editor-quote",code:"k-editor-code-block",codeHighlight:{},table:"k-editor-table",tableCell:"k-editor-table-cell",tableCellHeader:"k-editor-table-cell-header"},nodes:[t.HeadingNode,t.QuoteNode,o.ListNode,o.ListItemNode,l.LinkNode,r.TableNode,r.TableCellNode,r.TableRowNode,s.CodeNode,s.CodeHighlightNode,this.StyledTextNode,...this.customNodes],onError:console.error,editorState:null};this.lexicalEditor=e.createEditor(a),this.lexicalEditor.setRootElement(this.lexicalContainer),(this.disabled||this.readonly)&&this.lexicalEditor.setEditable(!1),this.lexicalEditor._window=new Proxy(window,{get:(e,t)=>{if("getSelection"===t)return()=>this.shadowRoot.getSelection();const i=Reflect.get(e,t);return"function"==typeof i?i.bind(e):i}}),this.cleanupFns=[t.registerRichText(this.lexicalEditor),i.registerHistory(this.lexicalEditor,i.createEmptyHistoryState(),300)],o.registerList&&this.cleanupFns.push(o.registerList(this.lexicalEditor)),r.registerTable&&this.cleanupFns.push(r.registerTable(this.lexicalEditor)),s.registerCodeHighlighting&&this.cleanupFns.push(s.registerCodeHighlighting(this.lexicalEditor)),l.registerLink&&this.cleanupFns.push(l.registerLink(this.lexicalEditor,{validateUrl:e=>{try{return new URL(e),!0}catch{return!1}}})),this.value&&(this.isVisualCompatible(this.value)?this.importHtmlToLexical(this.value):(this.skipLexicalExport=!0,this.mode="code")),this.lexicalEditor.registerUpdateListener(({dirtyElements:e,dirtyLeaves:t})=>{0===e.size&&0===t.size||(this.debouncedSyncValue(),this.dispatchEvent(new CustomEvent("input",{detail:{value:this.exportHtmlFromLexical()},bubbles:!0})))}),this.lexicalEditor.registerCommand(e.SELECTION_CHANGE_COMMAND,()=>(this.updateSelection(),!1),e.COMMAND_PRIORITY_LOW)}async initMonaco(){if(!this.monacoEditor){if(this.monacoInitPromise)return this.monacoInitPromise;this.monacoInitPromise=this._initMonaco(),await this.monacoInitPromise,this.monacoInitPromise=null}}async _initMonaco(){const e=this.monacoSrc||window.kempo?.monacoUrl||"https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min";await new Promise((t,i)=>{if(window.monaco)return void t();if(window.require?.defined?.("vs/editor/editor.main"))return void t();const o=document.querySelector(`script[src="${e}/vs/loader.js"]`);if(o)return void o.addEventListener("load",()=>{window.require.config({paths:{vs:`${e}/vs`}}),window.require(["vs/editor/editor.main"],()=>t(),i)});const l=document.createElement("script");l.src=`${e}/vs/loader.js`,l.onload=()=>{window.require.config({paths:{vs:`${e}/vs`}}),window.require(["vs/editor/editor.main"],()=>t(),i)},l.onerror=i,document.head.appendChild(l)}),this.monacoEditor=window.monaco.editor.create(this.monacoContainer,{value:o(this.value),language:"html",theme:this.resolveMonacoTheme(),minimap:{enabled:this.minimapEnabled},wordWrap:this.wordWrap?"on":"off",fontSize:this.fontSize,scrollBeyondLastLine:!1,automaticLayout:!0,tabSize:2,padding:{top:8},readOnly:this.disabled||this.readonly});const t=document.querySelector('link[href*="monaco"][href*="editor.main.css"]');if(t){const e=document.createElement("link");e.rel="stylesheet",e.href=t.href,this.shadowRoot.appendChild(e)}this.unsubscribeTheme=s(()=>{this.monacoEditor&&"auto"===this.editorTheme&&window.monaco.editor.setTheme(this.resolveMonacoTheme())}),this.monacoEditor.onDidChangeModelContent(()=>{this.skipValueSync=!0,this.value=this.monacoEditor.getValue(),this.skipValueSync=!1,this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0})),this.dispatchEvent(new CustomEvent("input",{detail:{value:this.value},bubbles:!0}))})}importHtmlToLexical(e){if(!this.lexicalEditor||!this.lx.lexicalHtml)return;const{lexical:t,lexicalHtml:i}=this.lx,o=(this.nodePreprocessors||[]).reduce((e,t)=>t(e),e);this.lexicalEditor.update(()=>{if(t.$getRoot().clear(),!o?.trim())return;const e=(new DOMParser).parseFromString(o,"text/html"),l=i.$generateNodesFromDOM(this.lexicalEditor,e);l.length>0&&t.$insertNodes(l)},{discrete:!0})}exportHtmlFromLexical(){if(!this.lexicalEditor||!this.lx.lexicalHtml)return this.value;let e="";return this.lexicalEditor.getEditorState().read(()=>{e=this.lx.lexicalHtml.$generateHtmlFromNodes(this.lexicalEditor,null)}),this.cleanExportedHtml(e)}isVisualCompatible(e){if(!e?.trim())return!0;const t=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"]),i=this.nodeCompatCheckers||[],o=(new DOMParser).parseFromString(e,"text/html"),l=document.createTreeWalker(o.body,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT);let r;for(;r=l.nextNode();)if(!i.some(e=>e(r))){if(r.nodeType===Node.COMMENT_NODE)return!1;if(t.has(r.tagName?.toLowerCase()))return!1}return!0}cleanExportedHtml(e){const t=(new DOMParser).parseFromString(e,"text/html");return t.body.querySelectorAll("[class]").forEach(e=>{const t=Array.from(e.classList).filter(e=>!e.startsWith("k-editor-")&&"td-u"!==e&&"td-lt"!==e);0===t.length?e.removeAttribute("class"):e.className=t.join(" ")}),t.body.querySelectorAll("[style]").forEach(e=>{const t=e.style.cssText.replace(/white-space:\s*pre-wrap;?\s*/g,"").trim();t?e.style.cssText=t:e.removeAttribute("style")}),t.body.querySelectorAll("span:not([class]):not([style]):not([id])").forEach(e=>{e.attributes.length||e.replaceWith(...e.childNodes)}),t.body.querySelectorAll("b > strong, i > em, b > b, strong > strong, i > i, em > em").forEach(e=>{e.replaceWith(...e.childNodes)}),t.body.querySelectorAll("pre[data-highlight-language], code[data-highlight-language]").forEach(e=>{e.removeAttribute("data-highlight-language"),e.removeAttribute("data-language")}),t.body.innerHTML}syncValueFromLexical(){this.lexicalEditor&&(this.lexicalValueSync=!0,this.value=this.exportHtmlFromLexical(),this.updateFormValue())}syncContentToEditors(){"visual"===this.mode&&this.lexicalEditor&&this.importHtmlToLexical(this.value)}async handleModeSwitch(e){"code"===this.mode?(this.lexicalEditor&&!this.skipLexicalExport&&(this.value=this.exportHtmlFromLexical()),this.skipLexicalExport=!1,await this.initMonaco(),this.monacoEditor&&(this.monacoEditor.setValue(o(this.value)),this.monacoEditor.layout())):"visual"===this.mode&&(this.monacoEditor&&(this.value=this.monacoEditor.getValue()),this.lexicalEditor&&this.importHtmlToLexical(this.value)),this.requestUpdate()}updateFormValue(){this.internals.setFormValue(this.getValue())}formResetCallback(){this.value=""}formStateRestoreCallback(e){this.value=e}formDisabledCallback(e){this.disabled=e}updateSelection=()=>{if("visual"!==this.mode||!this.lexicalEditor)return void(this.selection=null);const{lexical:e}=this.lx;this.lexicalEditor.getEditorState().read(()=>{const t=e.$getSelection();e.$isRangeSelection(t)&&!t.isCollapsed()?this.selection={text:t.getTextContent(),collapsed:!1}:(this.selection=null,this.cursor=t?{anchor:t.anchor,focus:t.focus}:null)})};setMode(e){return["visual","code"].includes(e)?"visual"!==e||this.isVisualCompatible(this.getValue())?(this.mode=e,this):(a.confirm("This html contains code that is not compatible with the visual editor, the incompatible code will be lost",t=>{t&&(this.mode=e)},{title:"Warning",confirmText:"Change Anyways"}),this):this}toggleMode(){return this.setMode("visual"===this.mode?"code":"visual")}getValue(){if("visual"===this.mode&&this.lexicalEditor)this.skipValueSync=!0,this.value=this.exportHtmlFromLexical(),this.skipValueSync=!1;else if("code"===this.mode&&this.monacoEditor)return this.monacoEditor.getValue();return this.value}setValue(e){return this.lexicalEditor&&"visual"===this.mode&&!this.isVisualCompatible(e)?(this.value=e,this.skipLexicalExport=!0,this.mode="code",this.updateFormValue(),this):(this.skipValueSync=!0,this.value=e,"visual"===this.mode?this.syncContentToEditors():"code"===this.mode&&this.monacoEditor&&this.monacoEditor.setValue(o(e)),this.updateFormValue(),this.skipValueSync=!1,this)}clear(){return this.setValue("")}bold(){return this.lexicalFormat("bold"),this}italic(){return this.lexicalFormat("italic"),this}underline(){return this.lexicalFormat("underline"),this}strikethrough(){return this.lexicalFormat("strikethrough"),this}inlineCode(){return this.lexicalFormat("code"),this}orderedList(){return"visual"===this.mode&&this.lexicalEditor?(this.lexicalEditor.update(()=>{this.lx.list.$insertList("number")},{discrete:!0}),this):this}unorderedList(){return"visual"===this.mode&&this.lexicalEditor?(this.lexicalEditor.update(()=>{this.lx.list.$insertList("bullet")},{discrete:!0}),this):this}alignLeft(){return this.lexicalFormatElement("left"),this}alignCenter(){return this.lexicalFormatElement("center"),this}alignRight(){return this.lexicalFormatElement("right"),this}alignJustify(){return this.lexicalFormatElement("justify"),this}setTextColor(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,selection:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&i.$patchStyleText(o,{color:e})},{discrete:!0}),this}removeTextColor(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&t.$patchStyleText(i,{color:null})},{discrete:!0}),this}setTextBackgroundColor(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,selection:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&i.$patchStyleText(o,{"background-color":e})},{discrete:!0}),this}removeTextBackgroundColor(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&t.$patchStyleText(i,{"background-color":null})},{discrete:!0}),this}removeFormat(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&(i.getNodes().forEach(t=>{e.$isTextNode(t)&&t.setFormat(0)}),t.$patchStyleText(i,{color:null,"background-color":null}))},{discrete:!0}),this}formatBlock(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,richText:i,code:o}=this.lx;return this.lexicalEditor.update(()=>{const l=t.$getSelection();if(!t.$isRangeSelection(l))return;const r=l.anchor.getNode().getTopLevelElementOrThrow(),s=o.$isCodeNode(r);let a;if("p"===e)a=t.$createParagraphNode();else if(e.match(/^h[1-6]$/))a=i.$createHeadingNode(e);else if("blockquote"===e)a=i.$createQuoteNode();else{if("pre"!==e)return;a=o.$createCodeNode()}if(s&&"pre"!==e){const e=r.getTextContent();r.replace(a),a.append(t.$createTextNode(e))}else{const e=r.getChildren();r.replace(a),e.forEach(e=>a.append(e))}a.selectEnd()},{discrete:!0}),this}isSelectionInCodeBlock(){if("visual"!==this.mode||!this.lexicalEditor)return!1;let e=!1;const{lexical:t,code:i}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&(e=i.$isCodeNode(o.anchor.getNode().getTopLevelElementOrThrow()))}),e}getTableAtSelection(){if("visual"!==this.mode||!this.lexicalEditor)return null;let e=null;const{lexical:t,table:i}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const o=t.$getSelection();if(!t.$isRangeSelection(o))return;let l=o.anchor.getNode();for(;l;){if(i.$isTableNode(l)){const t=l.getChildren(),o=[];let r=!1,s=0;t.forEach((e,t)=>{const l=[];e.getChildren().forEach(e=>{0===t&&i.$isTableCellNode(e)&&e.getHeaderStyles()===i.TableCellHeaderStates.ROW&&(r=!0),l.push(e.getTextContent())}),l.length>s&&(s=l.length),o.push(l)}),e={key:l.getKey(),rows:r?t.length-1:t.length,cols:s,hasHeaders:r,cellData:o};break}l=l.getParent()}}),e}removeTableByKey(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t}=this.lx;return this.lexicalEditor.update(()=>{const i=t.$getNodeByKey(e);i&&i.remove()},{discrete:!0}),this}insertHTML(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,lexicalHtml:i}=this.lx;return this.lexicalEditor.update(()=>{const o=(new DOMParser).parseFromString(e,"text/html"),l=i.$generateNodesFromDOM(this.lexicalEditor,o);t.$insertNodes(l)},{discrete:!0}),this}insertAtCursor(e){return this.insertHTML(e)}insertTable(e,t,i=!1,o=null){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:l,table:r}=this.lx;return this.lexicalEditor.update(()=>{const s=e+(i?1:0),a=[];for(let e=0;e<s;e++){const s=[];for(let a=0;a<t;a++){const t=i&&0===e,c=t?r.TableCellHeaderStates.ROW:r.TableCellHeaderStates.NO_STATUS,n=r.$createTableCellNode(c),h=o?.[e]?.[a]??(t?`Header ${a+1}`:""),d=l.$createParagraphNode();d.append(l.$createTextNode(h||" ")),n.append(d),s.push(n)}a.push(r.$createTableRowNode().append(...s))}const c=r.$createTableNode().append(...a),n=l.$getSelection();if(l.$isRangeSelection(n)){n.anchor.getNode().getTopLevelElementOrThrow().insertAfter(c);const e=l.$createParagraphNode();c.insertAfter(e),e.selectEnd()}else{const e=l.$getRoot();e.append(c),e.append(l.$createParagraphNode())}},{discrete:!0}),this}insertElementAtCursor(e){return this.insertHTML(e.outerHTML)}replaceSelectionWithElement(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,lexicalHtml:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();if(!t.$isRangeSelection(o))return;o.removeText();const l=(new DOMParser).parseFromString(e.outerHTML,"text/html"),r=i.$generateNodesFromDOM(this.lexicalEditor,l);t.$insertNodes(r)},{discrete:!0}),this}wrapSelection(e,t,i=null){if("visual"!==this.mode||!this.lexicalEditor)return this;const o=i||this.getSelectedText();return o?this.insertHTML(e+o+t):this}getSelection(){if("visual"!==this.mode||!this.lexicalEditor)return null;let e=null;const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&!i.isCollapsed()&&(e={text:i.getTextContent(),html:i.getTextContent(),selection:i})}),e}getSelectedText(){let e="";if("visual"!==this.mode||!this.lexicalEditor)return e;const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&(e=i.getTextContent())}),e}getSelectedHTML(){return this.getSelectedText()}selectAll(){if("visual"===this.mode&&this.lexicalEditor){const{lexical:e}=this.lx;this.lexicalEditor.update(()=>{e.$selectAll()},{discrete:!0})}else if(this.monacoEditor){const e=this.monacoEditor.getModel();e&&this.monacoEditor.setSelection(e.getFullModelRange())}return this}replaceSelection(e){return this.insertHTML(e)}deleteSelection(){return"visual"===this.mode?this.lexicalCmd("DELETE_CHARACTER_COMMAND",!1):this.monacoEditor&&this.monacoEditor.trigger("keyboard","deleteAllLeft",null),this}getValueWithSelectionMarkers(){if("visual"!==this.mode||!this.lexicalEditor)return{html:this.value,hasCursor:!1,hasSelection:!1,selectedText:""};let e={html:this.exportHtmlFromLexical(),hasCursor:!1,hasSelection:!1,selectedText:""};const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&(i.isCollapsed()?e.hasCursor=!0:(e.hasSelection=!0,e.selectedText=i.getTextContent()))}),e}setValueFromSelectionMarkers(e){return this.setValue(e)}captureSelection(){return this.selection}restoreSavedSelection(){return!1}clearSavedSelection(){this.savedSelection=null}createLink(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{link:t}=this.lx;return this.lexicalEditor.update(()=>{t.$toggleLink(e)},{discrete:!0}),this}createLinkWithText(e,t){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:i,link:o}=this.lx;return this.lexicalEditor.update(()=>{const l=i.$getSelection();i.$isRangeSelection(l)&&!l.isCollapsed()&&l.removeText();const r=o.$createLinkNode(e);r.append(i.$createTextNode(t)),i.$insertNodes([r])},{discrete:!0}),this}unlink(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,link:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&i.getNodes().forEach(e=>{const i=e.getParent();i&&t.$isLinkNode?.(i)&&(i.getChildren().forEach(e=>i.insertBefore(e)),i.remove())})},{discrete:!0}),this}insertImage(e){return this.insertHTML(`<img src="${encodeURI(e)}" />`)}undo(){return"code"===this.mode?this.monacoEditor?.trigger("toolbar","undo"):this.lexicalCmd("UNDO_COMMAND",void 0),this}redo(){return"code"===this.mode?this.monacoEditor?.trigger("toolbar","redo"):this.lexicalCmd("REDO_COMMAND",void 0),this}copyToClipboard(){return navigator.clipboard.writeText(this.getValue()),this}setEditorTheme(e){return["auto","light","dark"].includes(e)&&(this.editorTheme=e),this.monacoEditor&&window.monaco.editor.setTheme(this.resolveMonacoTheme()),this}openFind(){return this.monacoEditor?.getAction("actions.find")?.run(),this}foldAll(){return this.monacoEditor?.getAction("editor.foldAll")?.run(),this}unfoldAll(){return this.monacoEditor?.getAction("editor.unfoldAll")?.run(),this}enterFullscreen(){return this.fullscreen=!0,document.body.classList.add("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!0},bubbles:!0})),this}exitFullscreen(){return this.fullscreen=!1,document.body.classList.remove("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!1},bubbles:!0})),this}toggleFullscreen(){return this.fullscreen?this.exitFullscreen():this.enterFullscreen()}increaseFontSize(){return this.fontSize=Math.min(this.fontSize+2,40),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}decreaseFontSize(){return this.fontSize=Math.max(this.fontSize-2,8),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}setWordWrap(e){return this.wordWrap=e,this.monacoEditor?.updateOptions({wordWrap:e?"on":"off"}),this}setMinimap(e){return this.minimapEnabled=e,this.monacoEditor?.updateOptions({minimap:{enabled:e}}),this}resolveMonacoTheme(){return"dark"===this.editorTheme?"vs-dark":"light"===this.editorTheme?"vs":"dark"===r()?"vs-dark":"vs"}lexicalCmd(e,t){if("visual"!==this.mode||!this.lexicalEditor)return;const i=this.lx.lexical?.[e];i&&this.lexicalEditor.dispatchCommand(i,t)}lexicalFormat(e){if("visual"!==this.mode||!this.lexicalEditor)return;const{lexical:t}=this.lx;this.lexicalEditor.update(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&i.formatText(e)},{discrete:!0})}lexicalFormatElement(e){"visual"===this.mode&&this.lexicalEditor&&this.lexicalEditor.dispatchCommand(this.lx.lexical.FORMAT_ELEMENT_COMMAND,e)}render(){const t=this.constructor.controlSets[this.controls]??{};return e`
2
2
  ${this.hasTopToolbar?e`
3
3
  <div class="toolbar-top bb">
4
4
  <div class="toolbar-start">
@@ -12,7 +12,7 @@ import{html as e,css as t}from"../lit-all.min.js";import i from"./ShadowComponen
12
12
  <div class="editor-container">
13
13
  <div
14
14
  class="lexical-editor"
15
- contenteditable="true"
15
+ contenteditable=${this.disabled||this.readonly?"false":"true"}
16
16
  ?hidden=${"visual"!==this.mode}
17
17
  ></div>
18
18
  <div
@@ -46,6 +46,26 @@ import{html as e,css as t}from"../lit-all.min.js";import i from"./ShadowComponen
46
46
  height: 100vh !important;
47
47
  z-index: 10000;
48
48
  }
49
+ :host([disabled]) {
50
+ opacity: 0.6;
51
+ }
52
+ /* disabled blocks all interaction -- toolbar AND editor. Lexical
53
+ and Monaco both prevent typing on their own; pointer-events: none
54
+ also stops focus / cursor placement, matching native form control
55
+ semantics. */
56
+ :host([disabled]) .toolbar-top,
57
+ :host([disabled]) .toolbar-bottom,
58
+ :host([disabled]) .editor-container {
59
+ pointer-events: none;
60
+ }
61
+ /* readonly keeps the editor interactive (so users can place a cursor
62
+ to select / copy) but mutes the toolbar so its buttons can't
63
+ mutate the document. */
64
+ :host([readonly]) .toolbar-top,
65
+ :host([readonly]) .toolbar-bottom {
66
+ pointer-events: none;
67
+ opacity: 0.5;
68
+ }
49
69
  .toolbar-top,
50
70
  .toolbar-bottom {
51
71
  display: flex;
@@ -80,7 +100,7 @@ import{html as e,css as t}from"../lit-all.min.js";import i from"./ShadowComponen
80
100
  overflow: auto;
81
101
  }
82
102
  .lexical-editor {
83
- padding: 1rem;
103
+ padding: var(--editor_padding, 1rem);
84
104
  border: 1px solid var(--border-color);
85
105
  background: var(--bg-primary);
86
106
  color: var(--text-primary);
@@ -88,6 +108,25 @@ import{html as e,css as t}from"../lit-all.min.js";import i from"./ShadowComponen
88
108
  font-size: inherit;
89
109
  line-height: 1.5;
90
110
  outline: none;
111
+ /* Always show a slim scrollbar when content overflows (macOS would
112
+ otherwise hide overlay scrollbars when not actively scrolling,
113
+ leaving users unaware they can scroll back). */
114
+ scrollbar-width: thin;
115
+ scrollbar-color: var(--c_border, rgba(128,128,128,0.4)) transparent;
116
+ }
117
+ .lexical-editor::-webkit-scrollbar {
118
+ width: 8px;
119
+ height: 8px;
120
+ }
121
+ .lexical-editor::-webkit-scrollbar-track {
122
+ background: transparent;
123
+ }
124
+ .lexical-editor::-webkit-scrollbar-thumb {
125
+ background: var(--c_border, rgba(128,128,128,0.4));
126
+ border-radius: 4px;
127
+ }
128
+ .lexical-editor::-webkit-scrollbar-thumb:hover {
129
+ background: rgba(128,128,128,0.7);
91
130
  }
92
131
  .lexical-editor:focus {
93
132
  border-color: var(--primary-color);