@wrrdev/fenix-ui 1.1.13 → 1.1.15

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 (161) hide show
  1. package/README.md +6 -5
  2. package/dist/components/autocomplete/autocomplete.d.ts +11 -5
  3. package/dist/components/autocomplete/autocomplete.d.ts.map +1 -1
  4. package/dist/components/autocomplete/autocomplete.js +18 -2
  5. package/dist/components/autocomplete/autocomplete.js.map +1 -1
  6. package/dist/components/button/button.d.ts +15 -0
  7. package/dist/components/button/button.d.ts.map +1 -1
  8. package/dist/components/button/button.js +20 -1
  9. package/dist/components/button/button.js.map +1 -1
  10. package/dist/components/checkbox/checkbox.d.ts +20 -4
  11. package/dist/components/checkbox/checkbox.d.ts.map +1 -1
  12. package/dist/components/checkbox/checkbox.js +39 -2
  13. package/dist/components/checkbox/checkbox.js.map +1 -1
  14. package/dist/components/datepicker/datepicker.d.ts +16 -2
  15. package/dist/components/datepicker/datepicker.d.ts.map +1 -1
  16. package/dist/components/datepicker/datepicker.js +46 -2
  17. package/dist/components/datepicker/datepicker.js.map +1 -1
  18. package/dist/components/editor/commands.d.ts +27 -0
  19. package/dist/components/editor/commands.d.ts.map +1 -0
  20. package/dist/components/editor/commands.js +235 -0
  21. package/dist/components/editor/commands.js.map +1 -0
  22. package/dist/components/editor/editor.d.ts +83 -0
  23. package/dist/components/editor/editor.d.ts.map +1 -0
  24. package/dist/components/editor/editor.js +1951 -0
  25. package/dist/components/editor/editor.js.map +1 -0
  26. package/dist/components/editor/index.d.ts +12 -0
  27. package/dist/components/editor/index.d.ts.map +1 -0
  28. package/dist/components/editor/index.js +7 -0
  29. package/dist/components/editor/index.js.map +1 -0
  30. package/dist/components/editor/normalize-html.d.ts +33 -0
  31. package/dist/components/editor/normalize-html.d.ts.map +1 -0
  32. package/dist/components/editor/normalize-html.js +316 -0
  33. package/dist/components/editor/normalize-html.js.map +1 -0
  34. package/dist/components/editor/sanitize-html.d.ts +37 -0
  35. package/dist/components/editor/sanitize-html.d.ts.map +1 -0
  36. package/dist/components/editor/sanitize-html.js +247 -0
  37. package/dist/components/editor/sanitize-html.js.map +1 -0
  38. package/dist/components/editor/schema.d.ts +36 -0
  39. package/dist/components/editor/schema.d.ts.map +1 -0
  40. package/dist/components/editor/schema.js +232 -0
  41. package/dist/components/editor/schema.js.map +1 -0
  42. package/dist/components/editor/selection.d.ts +22 -0
  43. package/dist/components/editor/selection.d.ts.map +1 -0
  44. package/dist/components/editor/selection.js +97 -0
  45. package/dist/components/editor/selection.js.map +1 -0
  46. package/dist/components/editor/styles.d.ts +10 -0
  47. package/dist/components/editor/styles.d.ts.map +1 -0
  48. package/dist/components/editor/styles.js +446 -0
  49. package/dist/components/editor/styles.js.map +1 -0
  50. package/dist/components/editor/table-utils.d.ts +33 -0
  51. package/dist/components/editor/table-utils.d.ts.map +1 -0
  52. package/dist/components/editor/table-utils.js +150 -0
  53. package/dist/components/editor/table-utils.js.map +1 -0
  54. package/dist/components/fileupload/fileupload.d.ts +10 -2
  55. package/dist/components/fileupload/fileupload.d.ts.map +1 -1
  56. package/dist/components/fileupload/fileupload.js +17 -2
  57. package/dist/components/fileupload/fileupload.js.map +1 -1
  58. package/dist/components/floatlabel/floatlabel.d.ts +9 -3
  59. package/dist/components/floatlabel/floatlabel.d.ts.map +1 -1
  60. package/dist/components/floatlabel/floatlabel.js +22 -7
  61. package/dist/components/floatlabel/floatlabel.js.map +1 -1
  62. package/dist/components/input/input.d.ts +18 -7
  63. package/dist/components/input/input.d.ts.map +1 -1
  64. package/dist/components/input/input.js +33 -3
  65. package/dist/components/input/input.js.map +1 -1
  66. package/dist/components/knob/knob.d.ts +7 -3
  67. package/dist/components/knob/knob.d.ts.map +1 -1
  68. package/dist/components/knob/knob.js +4 -2
  69. package/dist/components/knob/knob.js.map +1 -1
  70. package/dist/components/multiselect/multiselect.d.ts +13 -3
  71. package/dist/components/multiselect/multiselect.d.ts.map +1 -1
  72. package/dist/components/multiselect/multiselect.js +27 -2
  73. package/dist/components/multiselect/multiselect.js.map +1 -1
  74. package/dist/components/radio/radio.d.ts +27 -4
  75. package/dist/components/radio/radio.d.ts.map +1 -1
  76. package/dist/components/radio/radio.js +67 -8
  77. package/dist/components/radio/radio.js.map +1 -1
  78. package/dist/components/rating/rating.d.ts +8 -4
  79. package/dist/components/rating/rating.d.ts.map +1 -1
  80. package/dist/components/rating/rating.js +5 -2
  81. package/dist/components/rating/rating.js.map +1 -1
  82. package/dist/components/select/select.d.ts +9 -3
  83. package/dist/components/select/select.d.ts.map +1 -1
  84. package/dist/components/select/select.js +11 -2
  85. package/dist/components/select/select.js.map +1 -1
  86. package/dist/components/slider/slider.d.ts +12 -6
  87. package/dist/components/slider/slider.d.ts.map +1 -1
  88. package/dist/components/slider/slider.js +10 -2
  89. package/dist/components/slider/slider.js.map +1 -1
  90. package/dist/components/switch/switch.d.ts +20 -4
  91. package/dist/components/switch/switch.d.ts.map +1 -1
  92. package/dist/components/switch/switch.js +40 -2
  93. package/dist/components/switch/switch.js.map +1 -1
  94. package/dist/components/textarea/textarea.d.ts +12 -5
  95. package/dist/components/textarea/textarea.d.ts.map +1 -1
  96. package/dist/components/textarea/textarea.js +12 -2
  97. package/dist/components/textarea/textarea.js.map +1 -1
  98. package/dist/components/toast/toast.d.ts +27 -15
  99. package/dist/components/toast/toast.d.ts.map +1 -1
  100. package/dist/components/toast/toast.js +205 -32
  101. package/dist/components/toast/toast.js.map +1 -1
  102. package/dist/components/toggle-button-group/toggle-button-group.d.ts +13 -5
  103. package/dist/components/toggle-button-group/toggle-button-group.d.ts.map +1 -1
  104. package/dist/components/toggle-button-group/toggle-button-group.js +19 -2
  105. package/dist/components/toggle-button-group/toggle-button-group.js.map +1 -1
  106. package/dist/core/base.d.ts +7 -0
  107. package/dist/core/base.d.ts.map +1 -1
  108. package/dist/core/base.js +4 -1
  109. package/dist/core/base.js.map +1 -1
  110. package/dist/core/form-element.d.ts +81 -0
  111. package/dist/core/form-element.d.ts.map +1 -0
  112. package/dist/core/form-element.js +129 -0
  113. package/dist/core/form-element.js.map +1 -0
  114. package/dist/core/jsx.d.ts +25 -1
  115. package/dist/core/jsx.d.ts.map +1 -1
  116. package/dist/core/jsx.js.map +1 -1
  117. package/dist/core/presets.d.ts +8 -3
  118. package/dist/core/presets.d.ts.map +1 -1
  119. package/dist/core/presets.js +6 -17
  120. package/dist/core/presets.js.map +1 -1
  121. package/dist/core/types.d.ts +4 -0
  122. package/dist/core/types.d.ts.map +1 -1
  123. package/dist/core/vue.d.ts +3 -1
  124. package/dist/core/vue.d.ts.map +1 -1
  125. package/dist/core/vue.js.map +1 -1
  126. package/dist/docs/app.d.ts.map +1 -1
  127. package/dist/docs/componentes/autocomplete.doc.d.ts.map +1 -1
  128. package/dist/docs/componentes/checkbox.doc.d.ts.map +1 -1
  129. package/dist/docs/componentes/datepicker.doc.d.ts.map +1 -1
  130. package/dist/docs/componentes/editor.doc.d.ts +6 -0
  131. package/dist/docs/componentes/editor.doc.d.ts.map +1 -0
  132. package/dist/docs/componentes/fileupload.doc.d.ts.map +1 -1
  133. package/dist/docs/componentes/index.d.ts.map +1 -1
  134. package/dist/docs/componentes/input.doc.d.ts.map +1 -1
  135. package/dist/docs/componentes/knob.doc.d.ts.map +1 -1
  136. package/dist/docs/componentes/multiselect.doc.d.ts.map +1 -1
  137. package/dist/docs/componentes/rating.doc.d.ts.map +1 -1
  138. package/dist/docs/componentes/select.doc.d.ts.map +1 -1
  139. package/dist/docs/componentes/slider.doc.d.ts.map +1 -1
  140. package/dist/docs/componentes/switch.doc.d.ts.map +1 -1
  141. package/dist/docs/componentes/textarea.doc.d.ts.map +1 -1
  142. package/dist/docs/componentes/toast.doc.d.ts.map +1 -1
  143. package/dist/docs/componentes/toggle-button-group.doc.d.ts.map +1 -1
  144. package/dist/docs/frameworks.d.ts +75 -0
  145. package/dist/docs/frameworks.d.ts.map +1 -0
  146. package/dist/docs/ui/code.d.ts +4 -0
  147. package/dist/docs/ui/code.d.ts.map +1 -1
  148. package/dist/fenix-ui.umd.min.js +786 -254
  149. package/dist/fenix-ui2.esm.js.map +1 -1
  150. package/dist/fenix-ui4.esm.js +4396 -172
  151. package/dist/fenix-ui4.esm.js.map +1 -1
  152. package/dist/fenix-ui5.esm.js +1 -0
  153. package/dist/fenix-ui5.esm.js.map +1 -1
  154. package/dist/index.d.ts +2 -0
  155. package/dist/index.d.ts.map +1 -1
  156. package/dist/index.js +18 -1
  157. package/dist/index.js.map +1 -1
  158. package/dist/plugins/auto-import.d.ts.map +1 -1
  159. package/dist/plugins/auto-import.js +1 -0
  160. package/dist/plugins/auto-import.js.map +1 -1
  161. package/package.json +5 -1
@@ -0,0 +1,1951 @@
1
+ var __typeError = (msg) => {
2
+ throw TypeError(msg);
3
+ };
4
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
9
+ var __privateWrapper = (obj, member, setter, getter) => ({
10
+ set _(value) {
11
+ __privateSet(obj, member, value, setter);
12
+ },
13
+ get _() {
14
+ return __privateGet(obj, member, getter);
15
+ }
16
+ });
17
+ var _built, _eventsBound, _initialized, _defaultValue, _value, _dirty, _sourceMode, _lastRange, _rafId, _emitTimer, _lastLimitError, _snapshotTimer, _history, _historyIndex, _imagePicker, _mediaFigure, _linkAnchor, _resizeDispose, _dialogReturnFocus, _dialogResolve, _disposers, _selectionRaf, _bodyOverflow, _FxEditor_instances, on_fn, bindEvents_fn, syncChrome_fn, applyCssVars_fn, updateEmpty_fn, updateCount_fn, fits_fn, limitError_fn, validate_fn, cleanHtml_fn, serialize_fn, applyValue_fn, scheduleEmit_fn, emitNow_fn, emitChange_fn, pushHistory_fn, scheduleSnapshot_fn, historyUndo_fn, historyRedo_fn, bindGlobalSelection_fn, restoreSelection_fn, syncBodyOverflow_fn, updateSourceUi_fn, releaseDialog_fn, renderToolbar_fn, updateToolbar_fn, handleToolbarKeydown_fn, moveToolbarTabStop_fn, trapDialogFocus_fn, execCommand_fn, afterCommand_fn, action_fn, handleKeydown_fn, tabInTable_fn, handleBeforeInput_fn, handlePaste_fn, handleDrop_fn, insertPlainText_fn, toggleSource_fn, applySource_fn, cancelSource_fn, openDialog_fn, fieldHtml_fn, submitDialog_fn, openLinkDialog_fn, openImageDialog_fn, toEmbedUrl_fn, openVideoDialog_fn, decorateMediaFigures_fn, syncQuickActions_fn, selectAnchor_fn, handleLinkOverlayClick_fn, openLink_fn, removeLink_fn, showLinkOverlay_fn, hideLinkOverlay_fn, positionLinkOverlay_fn, handleEditorClick_fn, showMediaOverlay_fn, hideMediaOverlay_fn, deleteMediaFigure_fn, positionMediaOverlay_fn, startResize_fn, endResize_fn, handleDoubleClick_fn, insertImage_fn, insertVideo_fn, insertEmbed_fn, insertTable_fn, insertColumns_fn, showTablePanel_fn, showColumnsPanel_fn, hidePanel_fn, currentTable_fn, tableAction_fn, handleImageFile_fn, fileToDataUrl_fn, error_fn;
18
+ import { FxFormElement } from "../../core/form-element.js";
19
+ import { defineElement } from "../../core/define.js";
20
+ import { esc } from "../../core/sanitize.js";
21
+ import { FENIX_ICON_BASE_CSS, fenixIconHtml } from "../../icons/base-css.js";
22
+ import { loadFenixIconsFont } from "../../icons/font.js";
23
+ import { sanitizeBody, sanitizeLinkUrl, sanitizeMediaUrl, sanitizeEmbedUrl } from "./sanitize-html.js";
24
+ import { normalizeElement } from "./normalize-html.js";
25
+ import { EDITOR_STYLES } from "./styles.js";
26
+ import { saveRange, getRange, placeCaretAtEnd, restoreRange, getBlock, closestInEditor } from "./selection.js";
27
+ import { formatBlock, nativeExec, insertHtml, removeFormat, toggleList, align, toggleInline, unlink, indent, escapeText, applyLink, escapeAttr } from "./commands.js";
28
+ import { mergeSelectedCells, splitCell } from "./table-utils.js";
29
+ const MAX_PASTE_BYTES = 1024 * 1024;
30
+ const MAX_IMAGE_BYTES = 8 * 1024 * 1024;
31
+ const LARGE_DOC_CHARS = 2e4;
32
+ const EMIT_DEBOUNCE_MS = 140;
33
+ const HISTORY_LIMIT = 50;
34
+ const QUICK_SVG = {
35
+ left: '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 10h10M4 14h16M4 18h10"/></svg>',
36
+ center: '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M7 10h10M4 14h16M7 18h10"/></svg>',
37
+ right: '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M10 10h10M4 14h16M10 18h10"/></svg>',
38
+ delete: '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18M8 6V4h8v2M6 6l1 15h10l1-15M10 10v7M14 10v7"/></svg>'
39
+ };
40
+ const _FxEditor = class _FxEditor extends FxFormElement {
41
+ constructor() {
42
+ super(...arguments);
43
+ __privateAdd(this, _FxEditor_instances);
44
+ __privateAdd(this, _built, false);
45
+ __privateAdd(this, _eventsBound, false);
46
+ __privateAdd(this, _initialized, false);
47
+ __privateAdd(this, _defaultValue, "");
48
+ __privateAdd(this, _value, "");
49
+ __privateAdd(this, _dirty, false);
50
+ __privateAdd(this, _sourceMode, false);
51
+ __privateAdd(this, _lastRange, null);
52
+ __privateAdd(this, _rafId, 0);
53
+ __privateAdd(this, _emitTimer, null);
54
+ __privateAdd(this, _lastLimitError, 0);
55
+ __privateAdd(this, _snapshotTimer, null);
56
+ __privateAdd(this, _history, []);
57
+ __privateAdd(this, _historyIndex, -1);
58
+ __privateAdd(this, _imagePicker, null);
59
+ __privateAdd(this, _mediaFigure, null);
60
+ __privateAdd(this, _linkAnchor, null);
61
+ __privateAdd(this, _resizeDispose, null);
62
+ __privateAdd(this, _dialogReturnFocus, null);
63
+ __privateAdd(this, _dialogResolve, null);
64
+ __privateAdd(this, _disposers, []);
65
+ __privateAdd(this, _selectionRaf, 0);
66
+ __privateAdd(this, _bodyOverflow, "");
67
+ }
68
+ static get observedAttributes() {
69
+ return [
70
+ "toolbar",
71
+ "features",
72
+ "placeholder",
73
+ "readonly",
74
+ "disabled",
75
+ "required",
76
+ "full",
77
+ "error",
78
+ "invalid",
79
+ "success",
80
+ "valid",
81
+ "show-count",
82
+ "paste-mode",
83
+ "min-height",
84
+ "max-height",
85
+ "fullscreen",
86
+ "maxlength"
87
+ ];
88
+ }
89
+ get editor() {
90
+ return this.root.querySelector(".content");
91
+ }
92
+ get source() {
93
+ return this.root.querySelector(".source");
94
+ }
95
+ get toolbarEl() {
96
+ return this.root.querySelector(".toolbar");
97
+ }
98
+ get value() {
99
+ if (__privateGet(this, _sourceMode) && this.source) return __privateMethod(this, _FxEditor_instances, serialize_fn).call(this);
100
+ if (__privateGet(this, _dirty)) __privateSet(this, _value, __privateMethod(this, _FxEditor_instances, serialize_fn).call(this));
101
+ return __privateGet(this, _value);
102
+ }
103
+ set value(next) {
104
+ const clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, next ?? "");
105
+ __privateSet(this, _value, clean);
106
+ __privateSet(this, _dirty, false);
107
+ if (!__privateGet(this, _defaultValue)) __privateSet(this, _defaultValue, clean);
108
+ __privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, clean);
109
+ this.updateFormValue();
110
+ }
111
+ get html() {
112
+ return this.value;
113
+ }
114
+ set html(next) {
115
+ this.value = next;
116
+ }
117
+ get text() {
118
+ return (this.editor?.textContent ?? "").replace(/\u200b/g, "").trim();
119
+ }
120
+ get defaultValue() {
121
+ return __privateGet(this, _defaultValue);
122
+ }
123
+ set defaultValue(next) {
124
+ __privateSet(this, _defaultValue, __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, next ?? ""));
125
+ if (!__privateGet(this, _dirty)) this.value = __privateGet(this, _defaultValue);
126
+ }
127
+ get disabled() {
128
+ return this.hasAttr("disabled");
129
+ }
130
+ set disabled(value) {
131
+ this.toggleAttr("disabled", Boolean(value));
132
+ }
133
+ get readonly() {
134
+ return this.hasAttr("readonly");
135
+ }
136
+ set readonly(value) {
137
+ this.toggleAttr("readonly", Boolean(value));
138
+ }
139
+ get required() {
140
+ return this.hasAttr("required");
141
+ }
142
+ set required(value) {
143
+ this.toggleAttr("required", Boolean(value));
144
+ }
145
+ get placeholder() {
146
+ return this.getAttr("placeholder");
147
+ }
148
+ set placeholder(value) {
149
+ this.setAttribute("placeholder", value);
150
+ }
151
+ get toolbar() {
152
+ const value = this.getAttr("toolbar", "standard");
153
+ return ["minimal", "basic", "standard", "full", "none"].includes(value) ? value : "standard";
154
+ }
155
+ set toolbar(value) {
156
+ this.setAttribute("toolbar", value);
157
+ }
158
+ get pasteMode() {
159
+ return this.getAttr("paste-mode", "clean") === "plain" ? "plain" : "clean";
160
+ }
161
+ set pasteMode(value) {
162
+ this.setAttribute("paste-mode", value);
163
+ }
164
+ get fullscreen() {
165
+ return this.hasAttr("fullscreen");
166
+ }
167
+ set fullscreen(value) {
168
+ this.toggleAttr("fullscreen", Boolean(value));
169
+ }
170
+ /** Limite de caracteres de texto (0 desativa). Padrão: 30.000. */
171
+ get maxlength() {
172
+ const value = Number.parseInt(this.getAttr("maxlength", "30000"), 10);
173
+ return Number.isFinite(value) && value > 0 ? value : 0;
174
+ }
175
+ set maxlength(value) {
176
+ if (Number.isFinite(value) && value >= 0) this.setAttribute("maxlength", String(Math.floor(value)));
177
+ else this.removeAttribute("maxlength");
178
+ }
179
+ connectedCallback() {
180
+ loadFenixIconsFont();
181
+ super.connectedCallback();
182
+ if (this.fullscreen) __privateMethod(this, _FxEditor_instances, syncBodyOverflow_fn).call(this);
183
+ if (!__privateGet(this, _initialized)) {
184
+ __privateSet(this, _initialized, true);
185
+ const initial = __privateGet(this, _value) || this.getAttr("value") || this.innerHTML;
186
+ this.replaceChildren();
187
+ __privateSet(this, _defaultValue, __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, initial));
188
+ __privateSet(this, _value, __privateGet(this, _defaultValue));
189
+ __privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, __privateGet(this, _defaultValue));
190
+ this.updateFormValue();
191
+ __privateMethod(this, _FxEditor_instances, pushHistory_fn).call(this, __privateGet(this, _value));
192
+ this.dispatchEvent(new CustomEvent("ready", { bubbles: true, composed: true }));
193
+ } else if (__privateGet(this, _built) && !__privateGet(this, _eventsBound)) {
194
+ __privateMethod(this, _FxEditor_instances, bindEvents_fn).call(this);
195
+ __privateSet(this, _eventsBound, true);
196
+ }
197
+ __privateMethod(this, _FxEditor_instances, bindGlobalSelection_fn).call(this);
198
+ }
199
+ disconnectedCallback() {
200
+ for (const dispose of __privateGet(this, _disposers)) dispose();
201
+ __privateSet(this, _disposers, []);
202
+ __privateSet(this, _eventsBound, false);
203
+ cancelAnimationFrame(__privateGet(this, _rafId));
204
+ cancelAnimationFrame(__privateGet(this, _selectionRaf));
205
+ if (__privateGet(this, _emitTimer)) clearTimeout(__privateGet(this, _emitTimer));
206
+ if (__privateGet(this, _snapshotTimer)) clearTimeout(__privateGet(this, _snapshotTimer));
207
+ __privateMethod(this, _FxEditor_instances, endResize_fn).call(this);
208
+ __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
209
+ __privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
210
+ if (this.hasAttr("fullscreen")) document.body.style.overflow = __privateGet(this, _bodyOverflow);
211
+ __privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, null);
212
+ super.disconnectedCallback();
213
+ }
214
+ attributeChangedCallback(name, oldValue, newValue) {
215
+ if (oldValue === newValue || !__privateGet(this, _built)) return;
216
+ if (name === "toolbar" || name === "features") __privateMethod(this, _FxEditor_instances, renderToolbar_fn).call(this);
217
+ if (name === "fullscreen") __privateMethod(this, _FxEditor_instances, syncBodyOverflow_fn).call(this);
218
+ __privateMethod(this, _FxEditor_instances, syncChrome_fn).call(this);
219
+ }
220
+ formResetCallback() {
221
+ __privateSet(this, _dirty, false);
222
+ this.value = __privateGet(this, _defaultValue);
223
+ }
224
+ getFormValue() {
225
+ return this.hasAttr("disabled") ? null : this.value;
226
+ }
227
+ render() {
228
+ if (__privateGet(this, _built)) return;
229
+ this.setTemplate(`
230
+ <div class="editor" part="editor">
231
+ <div class="toolbar" part="toolbar" role="toolbar" aria-label="Formatação" aria-orientation="horizontal"></div>
232
+ <div class="body">
233
+ <div class="content" part="content" contenteditable="true" role="textbox"
234
+ aria-multiline="true" spellcheck="true"></div>
235
+ <textarea class="source" part="source" spellcheck="false" hidden aria-label="HTML do conteúdo"></textarea>
236
+ <div class="media-overlay" part="media-overlay" hidden>
237
+ <span class="media-handle nw" data-handle="nw"></span>
238
+ <span class="media-handle ne" data-handle="ne"></span>
239
+ <span class="media-handle sw" data-handle="sw"></span>
240
+ <span class="media-handle se" data-handle="se"></span>
241
+ <span class="media-size"></span>
242
+ <button type="button" class="media-delete" data-media-action="delete" aria-label="Excluir mídia" title="Excluir mídia">${fenixIconHtml("delete")}</button>
243
+ </div>
244
+ <div class="link-overlay" part="link-overlay" hidden>
245
+ <button type="button" data-link-action="open">Abrir</button>
246
+ <button type="button" data-link-action="edit">Editar</button>
247
+ <button type="button" data-link-action="remove">Remover</button>
248
+ </div>
249
+ </div>
250
+ <div class="statusbar" part="statusbar">
251
+ <span class="count"></span>
252
+ <span class="source-actions" hidden>
253
+ <button type="button" class="btn source-apply">Aplicar</button>
254
+ <button type="button" class="btn source-cancel">Cancelar</button>
255
+ </span>
256
+ <slot name="footer"></slot>
257
+ </div>
258
+ <input type="file" class="image-picker" accept="image/*" hidden>
259
+ <div class="backdrop" part="dialog" hidden>
260
+ <div class="dialog" role="dialog" aria-modal="true" aria-labelledby="fx-editor-dialog-title">
261
+ <header>
262
+ <h3 id="fx-editor-dialog-title"></h3>
263
+ <button type="button" class="dialog-close" aria-label="Fechar">×</button>
264
+ </header>
265
+ <div class="dialog-body"></div>
266
+ <footer>
267
+ <button type="button" class="btn dialog-cancel">Cancelar</button>
268
+ <button type="button" class="btn dialog-ok">Aplicar</button>
269
+ </footer>
270
+ </div>
271
+ </div>
272
+ </div>
273
+ `);
274
+ __privateSet(this, _built, true);
275
+ __privateSet(this, _imagePicker, this.root.querySelector(".image-picker"));
276
+ __privateMethod(this, _FxEditor_instances, bindEvents_fn).call(this);
277
+ __privateSet(this, _eventsBound, true);
278
+ __privateMethod(this, _FxEditor_instances, renderToolbar_fn).call(this);
279
+ __privateMethod(this, _FxEditor_instances, syncChrome_fn).call(this);
280
+ }
281
+ /* ---------------------------------------------------------------------
282
+ * API pública
283
+ * ------------------------------------------------------------------ */
284
+ focus(options) {
285
+ this.editor?.focus(options ?? { preventScroll: true });
286
+ }
287
+ blur() {
288
+ this.editor?.blur();
289
+ }
290
+ execute(command, value) {
291
+ if (value !== void 0) {
292
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
293
+ nativeExec("styleWithCSS", "true");
294
+ nativeExec(command, value);
295
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
296
+ return;
297
+ }
298
+ __privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, command);
299
+ }
300
+ insertHTML(html) {
301
+ const clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, html);
302
+ const probe = document.createElement("div");
303
+ probe.innerHTML = clean;
304
+ const extra = probe.textContent?.length ?? 0;
305
+ if (!__privateMethod(this, _FxEditor_instances, fits_fn).call(this, extra)) {
306
+ __privateMethod(this, _FxEditor_instances, limitError_fn).call(this);
307
+ return;
308
+ }
309
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
310
+ insertHtml(this.editor, clean);
311
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
312
+ }
313
+ /** Mescla as células tocadas pela seleção. */
314
+ mergeCells() {
315
+ const table = __privateMethod(this, _FxEditor_instances, currentTable_fn).call(this);
316
+ const editor = this.editor;
317
+ const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
318
+ if (!table || !range) return false;
319
+ const merged = mergeSelectedCells(table, range);
320
+ if (!merged) return false;
321
+ placeCaretAtEnd(merged);
322
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
323
+ return true;
324
+ }
325
+ /** Divide a célula mesclada atual. */
326
+ splitCell() {
327
+ const table = __privateMethod(this, _FxEditor_instances, currentTable_fn).call(this);
328
+ const editor = this.editor;
329
+ const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
330
+ const cell = editor ? closestInEditor(editor, range?.startContainer ?? null, "td,th") : null;
331
+ if (!table || !cell) return false;
332
+ const created = splitCell(table, cell);
333
+ if (!created.length) return false;
334
+ placeCaretAtEnd(cell);
335
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
336
+ return true;
337
+ }
338
+ getHtml() {
339
+ return this.value;
340
+ }
341
+ setHtml(html) {
342
+ this.value = html;
343
+ }
344
+ getText() {
345
+ return this.text;
346
+ }
347
+ clear() {
348
+ this.value = "";
349
+ __privateSet(this, _dirty, false);
350
+ __privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, "");
351
+ this.updateFormValue();
352
+ __privateMethod(this, _FxEditor_instances, emitChange_fn).call(this);
353
+ this.focus();
354
+ }
355
+ undo() {
356
+ this.execute("undo");
357
+ }
358
+ redo() {
359
+ this.execute("redo");
360
+ }
361
+ saveSelection() {
362
+ if (this.editor) __privateSet(this, _lastRange, saveRange(this.editor) ?? __privateGet(this, _lastRange));
363
+ }
364
+ restoreSelection() {
365
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
366
+ }
367
+ openDialog(kind) {
368
+ if (kind === "link") void __privateMethod(this, _FxEditor_instances, openLinkDialog_fn).call(this);
369
+ else if (kind === "image") void __privateMethod(this, _FxEditor_instances, openImageDialog_fn).call(this);
370
+ else void __privateMethod(this, _FxEditor_instances, openVideoDialog_fn).call(this);
371
+ }
372
+ toggleSource() {
373
+ __privateMethod(this, _FxEditor_instances, toggleSource_fn).call(this);
374
+ }
375
+ toggleFullscreen() {
376
+ this.fullscreen = !this.fullscreen;
377
+ }
378
+ };
379
+ _built = new WeakMap();
380
+ _eventsBound = new WeakMap();
381
+ _initialized = new WeakMap();
382
+ _defaultValue = new WeakMap();
383
+ _value = new WeakMap();
384
+ _dirty = new WeakMap();
385
+ _sourceMode = new WeakMap();
386
+ _lastRange = new WeakMap();
387
+ _rafId = new WeakMap();
388
+ _emitTimer = new WeakMap();
389
+ _lastLimitError = new WeakMap();
390
+ _snapshotTimer = new WeakMap();
391
+ _history = new WeakMap();
392
+ _historyIndex = new WeakMap();
393
+ _imagePicker = new WeakMap();
394
+ _mediaFigure = new WeakMap();
395
+ _linkAnchor = new WeakMap();
396
+ _resizeDispose = new WeakMap();
397
+ _dialogReturnFocus = new WeakMap();
398
+ _dialogResolve = new WeakMap();
399
+ _disposers = new WeakMap();
400
+ _selectionRaf = new WeakMap();
401
+ _bodyOverflow = new WeakMap();
402
+ _FxEditor_instances = new WeakSet();
403
+ on_fn = function(target, type, handler, options) {
404
+ target.addEventListener(type, handler, options);
405
+ __privateGet(this, _disposers).push(() => target.removeEventListener(type, handler, options));
406
+ };
407
+ bindEvents_fn = function() {
408
+ const editor = this.editor;
409
+ const toolbar = this.toolbarEl;
410
+ if (!editor || !toolbar) return;
411
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "mousedown", (event) => {
412
+ const target = event.target;
413
+ __privateSet(this, _lastRange, saveRange(editor) ?? __privateGet(this, _lastRange));
414
+ __privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
415
+ if (target.closest("button")) event.preventDefault();
416
+ });
417
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "click", (event) => {
418
+ const target = event.target.closest("[data-cmd],[data-action]");
419
+ if (!target || target.disabled) return;
420
+ const cmd = target.dataset.cmd;
421
+ const action = target.dataset.action;
422
+ if (cmd) __privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, cmd);
423
+ else if (action) __privateMethod(this, _FxEditor_instances, action_fn).call(this, action);
424
+ });
425
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "change", (event) => {
426
+ const select = event.target.closest("[data-block]");
427
+ if (!select) return;
428
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
429
+ formatBlock(editor, select.value || "p");
430
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
431
+ });
432
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "input", (event) => {
433
+ const input = event.target.closest("[data-color]");
434
+ if (!input) return;
435
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
436
+ nativeExec("styleWithCSS", "true");
437
+ nativeExec(input.dataset.color ?? "foreColor", input.value);
438
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
439
+ });
440
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "keydown", (event) => __privateMethod(this, _FxEditor_instances, handleToolbarKeydown_fn).call(this, event));
441
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "focusin", (event) => {
442
+ const button = event.target.closest(".tb-btn");
443
+ if (button) __privateMethod(this, _FxEditor_instances, moveToolbarTabStop_fn).call(this, button);
444
+ });
445
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "input", (event) => {
446
+ event.stopPropagation();
447
+ __privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
448
+ __privateSet(this, _dirty, true);
449
+ __privateMethod(this, _FxEditor_instances, updateEmpty_fn).call(this);
450
+ __privateMethod(this, _FxEditor_instances, scheduleEmit_fn).call(this);
451
+ __privateMethod(this, _FxEditor_instances, scheduleSnapshot_fn).call(this);
452
+ });
453
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "focus", () => {
454
+ this.dispatchEvent(new CustomEvent("focus", { bubbles: true, composed: true }));
455
+ });
456
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "blur", () => {
457
+ __privateSet(this, _lastRange, saveRange(editor) ?? __privateGet(this, _lastRange));
458
+ __privateMethod(this, _FxEditor_instances, emitNow_fn).call(this);
459
+ __privateMethod(this, _FxEditor_instances, emitChange_fn).call(this);
460
+ this.dispatchEvent(new CustomEvent("blur", { bubbles: true, composed: true }));
461
+ });
462
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "keydown", (event) => __privateMethod(this, _FxEditor_instances, handleKeydown_fn).call(this, event));
463
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "beforeinput", (event) => __privateMethod(this, _FxEditor_instances, handleBeforeInput_fn).call(this, event));
464
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "paste", (event) => __privateMethod(this, _FxEditor_instances, handlePaste_fn).call(this, event));
465
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "dragover", (event) => event.preventDefault());
466
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "drop", (event) => __privateMethod(this, _FxEditor_instances, handleDrop_fn).call(this, event));
467
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "dblclick", (event) => __privateMethod(this, _FxEditor_instances, handleDoubleClick_fn).call(this, event));
468
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "click", (event) => __privateMethod(this, _FxEditor_instances, handleEditorClick_fn).call(this, event));
469
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "scroll", () => {
470
+ __privateMethod(this, _FxEditor_instances, positionMediaOverlay_fn).call(this);
471
+ __privateMethod(this, _FxEditor_instances, positionLinkOverlay_fn).call(this);
472
+ }, { passive: true });
473
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, window, "resize", () => {
474
+ __privateMethod(this, _FxEditor_instances, positionMediaOverlay_fn).call(this);
475
+ __privateMethod(this, _FxEditor_instances, positionLinkOverlay_fn).call(this);
476
+ });
477
+ const overlay = this.root.querySelector(".media-overlay");
478
+ if (overlay) {
479
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, overlay, "pointerdown", (event) => __privateMethod(this, _FxEditor_instances, startResize_fn).call(this, event));
480
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, overlay, "click", (event) => {
481
+ const action = event.target.closest("[data-media-action]");
482
+ if (action?.dataset.mediaAction === "delete") __privateMethod(this, _FxEditor_instances, deleteMediaFigure_fn).call(this);
483
+ });
484
+ }
485
+ const linkOverlay = this.root.querySelector(".link-overlay");
486
+ if (linkOverlay) {
487
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, linkOverlay, "click", (event) => __privateMethod(this, _FxEditor_instances, handleLinkOverlayClick_fn).call(this, event));
488
+ }
489
+ if (this.source) {
490
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, this.source, "input", () => {
491
+ __privateSet(this, _dirty, true);
492
+ __privateMethod(this, _FxEditor_instances, scheduleEmit_fn).call(this);
493
+ });
494
+ }
495
+ if (__privateGet(this, _imagePicker)) {
496
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, __privateGet(this, _imagePicker), "change", () => {
497
+ const file = __privateGet(this, _imagePicker)?.files?.[0];
498
+ if (file) void __privateMethod(this, _FxEditor_instances, handleImageFile_fn).call(this, file);
499
+ if (__privateGet(this, _imagePicker)) __privateGet(this, _imagePicker).value = "";
500
+ });
501
+ }
502
+ const backdrop = this.root.querySelector(".backdrop");
503
+ if (backdrop) {
504
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, backdrop, "click", (event) => {
505
+ if (event.target === backdrop) __privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, null);
506
+ });
507
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, backdrop, "keydown", (event) => __privateMethod(this, _FxEditor_instances, trapDialogFocus_fn).call(this, event));
508
+ }
509
+ const dialogBody = this.root.querySelector(".dialog-body");
510
+ if (dialogBody) {
511
+ __privateMethod(this, _FxEditor_instances, on_fn).call(this, dialogBody, "keydown", (event) => {
512
+ const target = event.target;
513
+ if (event.key === "Enter" && target.tagName !== "BUTTON") {
514
+ event.preventDefault();
515
+ __privateMethod(this, _FxEditor_instances, submitDialog_fn).call(this);
516
+ }
517
+ });
518
+ }
519
+ for (const selector of [".dialog-close", ".dialog-cancel"]) {
520
+ const btn = this.root.querySelector(selector);
521
+ if (btn) __privateMethod(this, _FxEditor_instances, on_fn).call(this, btn, "click", () => __privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, null));
522
+ }
523
+ const ok = this.root.querySelector(".dialog-ok");
524
+ if (ok) __privateMethod(this, _FxEditor_instances, on_fn).call(this, ok, "click", () => __privateMethod(this, _FxEditor_instances, submitDialog_fn).call(this));
525
+ const applySource = this.root.querySelector(".source-apply");
526
+ if (applySource) __privateMethod(this, _FxEditor_instances, on_fn).call(this, applySource, "click", () => __privateMethod(this, _FxEditor_instances, applySource_fn).call(this));
527
+ const cancelSource = this.root.querySelector(".source-cancel");
528
+ if (cancelSource) __privateMethod(this, _FxEditor_instances, on_fn).call(this, cancelSource, "click", () => __privateMethod(this, _FxEditor_instances, cancelSource_fn).call(this));
529
+ };
530
+ syncChrome_fn = function() {
531
+ const editor = this.editor;
532
+ if (!editor) return;
533
+ const locked = this.disabled || this.readonly;
534
+ editor.setAttribute("contenteditable", locked ? "false" : "true");
535
+ editor.setAttribute("aria-readonly", String(this.readonly));
536
+ editor.setAttribute("aria-disabled", String(this.disabled));
537
+ if (this.placeholder) editor.setAttribute("data-placeholder", this.placeholder);
538
+ else editor.removeAttribute("data-placeholder");
539
+ const toolbar = this.toolbarEl;
540
+ toolbar?.toggleAttribute("hidden", this.toolbar === "none" || this.readonly);
541
+ for (const control of Array.from(this.root.querySelectorAll(
542
+ ".tb-btn, .tb-select, .tb-color input"
543
+ ))) {
544
+ const isSourceToggle = control.closest('[data-action="source"]') !== null;
545
+ const isFullscreenToggle = control.closest('[data-action="fullscreen"]') !== null;
546
+ control.disabled = this.readonly || this.disabled || __privateGet(this, _sourceMode) && !isSourceToggle && !isFullscreenToggle;
547
+ }
548
+ __privateMethod(this, _FxEditor_instances, applyCssVars_fn).call(this);
549
+ __privateMethod(this, _FxEditor_instances, updateEmpty_fn).call(this);
550
+ __privateMethod(this, _FxEditor_instances, updateCount_fn).call(this);
551
+ __privateMethod(this, _FxEditor_instances, validate_fn).call(this);
552
+ __privateMethod(this, _FxEditor_instances, updateSourceUi_fn).call(this);
553
+ const fullscreenButton = this.root.querySelector('[data-action="fullscreen"]');
554
+ fullscreenButton?.classList.toggle("active", this.fullscreen);
555
+ fullscreenButton?.setAttribute("aria-pressed", String(this.fullscreen));
556
+ if (locked || __privateGet(this, _sourceMode)) __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
557
+ };
558
+ applyCssVars_fn = function() {
559
+ const min = this.getAttr("min-height");
560
+ const max = this.getAttr("max-height");
561
+ if (min) this.style.setProperty("--fx-editor-min-height", min);
562
+ else this.style.removeProperty("--fx-editor-min-height");
563
+ if (max) this.style.setProperty("--fx-editor-max-height", max);
564
+ else this.style.removeProperty("--fx-editor-max-height");
565
+ };
566
+ updateEmpty_fn = function() {
567
+ const editor = this.editor;
568
+ if (!editor) return;
569
+ const empty = !editor.textContent?.trim() && !editor.querySelector("img,video,iframe,table,hr");
570
+ editor.classList.toggle("is-empty", empty);
571
+ };
572
+ updateCount_fn = function() {
573
+ const count = this.root.querySelector(".count");
574
+ if (!count) return;
575
+ const statusbar = this.root.querySelector(".statusbar");
576
+ const hasFooter = this.querySelector('[slot="footer"]') !== null;
577
+ if (statusbar) statusbar.hidden = !__privateGet(this, _sourceMode) && !this.hasAttr("show-count") && !hasFooter;
578
+ if (!this.hasAttr("show-count")) {
579
+ count.textContent = "";
580
+ return;
581
+ }
582
+ const text = this.text;
583
+ const words = text ? text.split(/\s+/).filter(Boolean).length : 0;
584
+ count.textContent = `${words} palavra${words === 1 ? "" : "s"} · ${text.length} caractere${text.length === 1 ? "" : "s"}`;
585
+ };
586
+ fits_fn = function(extra) {
587
+ const max = this.maxlength;
588
+ if (!max) return true;
589
+ const editor = this.editor;
590
+ const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
591
+ const selected = range && !range.collapsed ? range.toString().length : 0;
592
+ return this.text.length - selected + extra <= max;
593
+ };
594
+ limitError_fn = function() {
595
+ const now = Date.now();
596
+ if (now - __privateGet(this, _lastLimitError) < 1200) return;
597
+ __privateSet(this, _lastLimitError, now);
598
+ __privateMethod(this, _FxEditor_instances, error_fn).call(this, `Limite de ${this.maxlength.toLocaleString("pt-BR")} caracteres atingido.`);
599
+ };
600
+ validate_fn = function() {
601
+ if (!this.internals || typeof this.internals.setValidity !== "function") return;
602
+ try {
603
+ if (this.required && !this.text) {
604
+ this.internals.setValidity(
605
+ { valueMissing: true },
606
+ "Preencha este campo.",
607
+ this.editor ?? void 0
608
+ );
609
+ } else {
610
+ this.internals.setValidity({});
611
+ }
612
+ } catch {
613
+ }
614
+ };
615
+ /** Sanitiza + normaliza em uma única parseada do HTML. */
616
+ cleanHtml_fn = function(html, forEditor = false) {
617
+ const body = sanitizeBody(html);
618
+ if (!body) return forEditor ? "<p><br></p>" : "";
619
+ return normalizeElement(body, { forEditor });
620
+ };
621
+ serialize_fn = function() {
622
+ if (__privateGet(this, _sourceMode) && this.source) {
623
+ return __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, this.source.value);
624
+ }
625
+ const editor = this.editor;
626
+ if (!editor) return "";
627
+ if (!editor.textContent?.trim() && !editor.querySelector("img,video,iframe,table,hr")) return "";
628
+ let clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, editor.innerHTML);
629
+ if (this.sanitizeHtml) {
630
+ clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, this.sanitizeHtml(clean));
631
+ }
632
+ return clean;
633
+ };
634
+ applyValue_fn = function(html) {
635
+ const editor = this.editor;
636
+ if (!editor) return;
637
+ __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
638
+ const normalized = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, html, true);
639
+ if (editor.innerHTML !== normalized) editor.innerHTML = normalized;
640
+ __privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
641
+ __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
642
+ __privateMethod(this, _FxEditor_instances, decorateMediaFigures_fn).call(this);
643
+ __privateMethod(this, _FxEditor_instances, updateEmpty_fn).call(this);
644
+ __privateMethod(this, _FxEditor_instances, updateCount_fn).call(this);
645
+ };
646
+ scheduleEmit_fn = function() {
647
+ cancelAnimationFrame(__privateGet(this, _rafId));
648
+ if (__privateGet(this, _emitTimer)) {
649
+ clearTimeout(__privateGet(this, _emitTimer));
650
+ __privateSet(this, _emitTimer, null);
651
+ }
652
+ const size = this.editor?.textContent?.length ?? 0;
653
+ if (size < LARGE_DOC_CHARS) {
654
+ __privateSet(this, _rafId, requestAnimationFrame(() => __privateMethod(this, _FxEditor_instances, emitNow_fn).call(this)));
655
+ return;
656
+ }
657
+ __privateSet(this, _emitTimer, setTimeout(() => {
658
+ __privateSet(this, _emitTimer, null);
659
+ __privateMethod(this, _FxEditor_instances, emitNow_fn).call(this);
660
+ }, EMIT_DEBOUNCE_MS));
661
+ };
662
+ emitNow_fn = function() {
663
+ cancelAnimationFrame(__privateGet(this, _rafId));
664
+ if (__privateGet(this, _emitTimer)) {
665
+ clearTimeout(__privateGet(this, _emitTimer));
666
+ __privateSet(this, _emitTimer, null);
667
+ }
668
+ const value = __privateMethod(this, _FxEditor_instances, serialize_fn).call(this);
669
+ __privateSet(this, _value, value);
670
+ __privateSet(this, _dirty, false);
671
+ const detail = { value, html: value, text: this.text };
672
+ for (const type of ["input", "valueChange"]) {
673
+ this.dispatchEvent(new CustomEvent(type, { bubbles: true, composed: true, detail }));
674
+ }
675
+ __privateMethod(this, _FxEditor_instances, updateCount_fn).call(this);
676
+ __privateMethod(this, _FxEditor_instances, validate_fn).call(this);
677
+ };
678
+ emitChange_fn = function() {
679
+ const value = this.value;
680
+ const detail = { value, html: value, text: this.text };
681
+ this.dispatchEvent(new CustomEvent("change", { bubbles: true, composed: true, detail }));
682
+ };
683
+ pushHistory_fn = function(html) {
684
+ if (__privateGet(this, _history)[__privateGet(this, _historyIndex)] === html) return;
685
+ __privateSet(this, _history, __privateGet(this, _history).slice(0, __privateGet(this, _historyIndex) + 1));
686
+ __privateGet(this, _history).push(html);
687
+ if (__privateGet(this, _history).length > HISTORY_LIMIT) __privateGet(this, _history).shift();
688
+ __privateSet(this, _historyIndex, __privateGet(this, _history).length - 1);
689
+ };
690
+ scheduleSnapshot_fn = function() {
691
+ if (__privateGet(this, _snapshotTimer)) clearTimeout(__privateGet(this, _snapshotTimer));
692
+ __privateSet(this, _snapshotTimer, setTimeout(() => {
693
+ __privateMethod(this, _FxEditor_instances, pushHistory_fn).call(this, __privateGet(this, _dirty) ? __privateMethod(this, _FxEditor_instances, serialize_fn).call(this) : __privateGet(this, _value));
694
+ }, 600));
695
+ };
696
+ historyUndo_fn = function() {
697
+ if (__privateGet(this, _historyIndex) <= 0) return;
698
+ __privateWrapper(this, _historyIndex)._--;
699
+ __privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, __privateGet(this, _history)[__privateGet(this, _historyIndex)]);
700
+ if (this.editor) placeCaretAtEnd(this.editor);
701
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
702
+ };
703
+ historyRedo_fn = function() {
704
+ if (__privateGet(this, _historyIndex) >= __privateGet(this, _history).length - 1) return;
705
+ __privateWrapper(this, _historyIndex)._++;
706
+ __privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, __privateGet(this, _history)[__privateGet(this, _historyIndex)]);
707
+ if (this.editor) placeCaretAtEnd(this.editor);
708
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
709
+ };
710
+ bindGlobalSelection_fn = function() {
711
+ const handler = () => {
712
+ const editor = this.editor;
713
+ if (!editor) return;
714
+ const range = getRange(editor, __privateGet(this, _lastRange));
715
+ if (!range) return;
716
+ __privateSet(this, _lastRange, range.cloneRange());
717
+ cancelAnimationFrame(__privateGet(this, _selectionRaf));
718
+ __privateSet(this, _selectionRaf, requestAnimationFrame(() => __privateMethod(this, _FxEditor_instances, updateToolbar_fn).call(this)));
719
+ };
720
+ document.addEventListener("selectionchange", handler);
721
+ __privateGet(this, _disposers).push(() => document.removeEventListener("selectionchange", handler));
722
+ };
723
+ restoreSelection_fn = function() {
724
+ const editor = this.editor;
725
+ if (!editor) return;
726
+ if (__privateGet(this, _lastRange)) restoreRange(editor, __privateGet(this, _lastRange));
727
+ else editor.focus({ preventScroll: true });
728
+ };
729
+ syncBodyOverflow_fn = function() {
730
+ if (this.fullscreen) {
731
+ __privateSet(this, _bodyOverflow, document.body.style.overflow);
732
+ document.body.style.overflow = "hidden";
733
+ } else {
734
+ document.body.style.overflow = __privateGet(this, _bodyOverflow);
735
+ }
736
+ };
737
+ updateSourceUi_fn = function() {
738
+ const source = this.source;
739
+ const content = this.editor;
740
+ const actions = this.root.querySelector(".source-actions");
741
+ if (actions) actions.toggleAttribute("hidden", !__privateGet(this, _sourceMode));
742
+ if (source) source.hidden = !__privateGet(this, _sourceMode);
743
+ if (content) content.hidden = __privateGet(this, _sourceMode);
744
+ const toggle = this.root.querySelector('[data-action="source"]');
745
+ toggle?.classList.toggle("active", __privateGet(this, _sourceMode));
746
+ toggle?.setAttribute("aria-pressed", String(__privateGet(this, _sourceMode)));
747
+ };
748
+ releaseDialog_fn = function(result) {
749
+ const backdrop = this.root.querySelector(".backdrop");
750
+ backdrop?.setAttribute("hidden", "");
751
+ const resolve = __privateGet(this, _dialogResolve);
752
+ __privateSet(this, _dialogResolve, null);
753
+ const returnFocus = __privateGet(this, _dialogReturnFocus);
754
+ __privateSet(this, _dialogReturnFocus, null);
755
+ resolve?.(result);
756
+ if (returnFocus && returnFocus.isConnected) returnFocus.focus({ preventScroll: true });
757
+ else __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
758
+ };
759
+ renderToolbar_fn = function() {
760
+ const toolbar = this.toolbarEl;
761
+ if (!toolbar) return;
762
+ const preset = this.toolbar;
763
+ if (preset === "none") {
764
+ toolbar.innerHTML = "";
765
+ toolbar.hidden = true;
766
+ return;
767
+ }
768
+ toolbar.hidden = false;
769
+ const features = new Set(
770
+ this.getAttr("features").split(",").map((item) => item.trim()).filter(Boolean)
771
+ );
772
+ const has = (feature) => features.size === 0 || features.has(feature);
773
+ const button = (cmd, icon, label, action = "") => `<button type="button" class="tb-btn" tabindex="-1" ${action ? `data-action="${action}"` : `data-cmd="${cmd}"`} title="${label}" aria-label="${label}" aria-pressed="false">${fenixIconHtml(icon)}</button>`;
774
+ const select = `<select class="tb-select" data-block aria-label="Formato do bloco">
775
+ <option value="p">Parágrafo</option>
776
+ <option value="h1">Título 1</option>
777
+ <option value="h2">Título 2</option>
778
+ <option value="h3">Título 3</option>
779
+ <option value="h4">Título 4</option>
780
+ <option value="blockquote">Citação</option>
781
+ <option value="pre">Código</option>
782
+ </select>`;
783
+ const history = button("undo", "undo", "Desfazer") + button("redo", "redo", "Refazer");
784
+ const inline = [
785
+ button("bold", "format_bold", "Negrito"),
786
+ button("italic", "format_italic", "Itálico"),
787
+ button("underline", "format_underlined", "Sublinhado"),
788
+ button("strikeThrough", "format_strikethrough", "Riscado"),
789
+ button("code", "code", "Código inline"),
790
+ button("removeFormat", "format_clear", "Limpar formatação")
791
+ ].join("");
792
+ const color = [
793
+ `<label class="tb-color" title="Cor do texto"><input type="color" data-color="foreColor" value="#111827" aria-label="Cor do texto"></label>`,
794
+ `<label class="tb-color" title="Realçar texto"><input type="color" data-color="hiliteColor" value="#fef08a" aria-label="Realçar texto"></label>`
795
+ ].join("");
796
+ const alignGroup = [
797
+ button("justifyLeft", "format_align_left", "Alinhar à esquerda"),
798
+ button("justifyCenter", "format_align_center", "Centralizar"),
799
+ button("justifyRight", "format_align_right", "Alinhar à direita"),
800
+ button("justifyFull", "format_align_justify", "Justificar")
801
+ ].join("");
802
+ const indentation = [
803
+ button("outdent", "format_indent_decrease", "Diminuir recuo", "outdent"),
804
+ button("indent", "format_indent_increase", "Aumentar recuo", "indent")
805
+ ].join("");
806
+ const lists = [
807
+ button("insertUnorderedList", "format_list_bulleted", "Lista com marcadores"),
808
+ button("insertOrderedList", "format_list_numbered", "Lista numerada")
809
+ ].join("");
810
+ const blocks = button("", "format_quote", "Citação", "blockquote") + button("", "code_blocks", "Bloco de código", "codeblock");
811
+ const insert = [];
812
+ if (has("link")) {
813
+ insert.push(button("", "link", "Link (Ctrl+K)", "link"));
814
+ insert.push(button("", "link_off", "Remover link", "unlink"));
815
+ }
816
+ if (preset !== "minimal") {
817
+ if (has("image")) insert.push(button("", "image", "Imagem", "image"));
818
+ if (has("video")) insert.push(button("", "videocam", "Vídeo", "video"));
819
+ if (has("table")) insert.push(button("", "table", "Tabela", "table"));
820
+ if (has("columns")) insert.push(button("", "view_column", "Colunas", "columns"));
821
+ insert.push(button("insertHorizontalRule", "horizontal_rule", "Linha horizontal"));
822
+ }
823
+ const tools = [];
824
+ if (preset === "standard" || preset === "full") {
825
+ if (has("source")) tools.push(button("", "code", "Ver HTML", "source"));
826
+ if (has("fullscreen")) tools.push(button("", "fullscreen", "Tela cheia", "fullscreen"));
827
+ }
828
+ const groups = [history, select + inline];
829
+ if (preset !== "minimal") groups.push(lists);
830
+ if (preset !== "minimal" && preset !== "basic") {
831
+ groups.push(color, alignGroup, indentation, blocks);
832
+ }
833
+ if (insert.length) groups.push(insert.join(""));
834
+ if (tools.length) groups.push(tools.join(""));
835
+ toolbar.innerHTML = groups.map((group) => `<div class="tb-group">${group}</div>`).join("") + `<div class="panel" data-panel hidden></div>`;
836
+ toolbar.querySelector(".tb-btn")?.setAttribute("tabindex", "0");
837
+ };
838
+ updateToolbar_fn = function() {
839
+ const editor = this.editor;
840
+ if (!editor) return;
841
+ const range = getRange(editor, __privateGet(this, _lastRange));
842
+ if (!range) return;
843
+ const setActive = (cmd, active) => {
844
+ const button = this.root.querySelector(`[data-cmd="${cmd}"]`);
845
+ if (!button) return;
846
+ button.classList.toggle("active", active);
847
+ button.setAttribute("aria-pressed", String(active));
848
+ };
849
+ const ancestor = (selector) => {
850
+ const node = range.startContainer;
851
+ const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
852
+ const match = el?.closest(selector);
853
+ return Boolean(match && editor.contains(match));
854
+ };
855
+ setActive("bold", ancestor("strong,b"));
856
+ setActive("italic", ancestor("em,i"));
857
+ setActive("underline", ancestor("u"));
858
+ setActive("strikeThrough", ancestor("s,del,strike"));
859
+ setActive("code", ancestor("code"));
860
+ setActive("insertUnorderedList", ancestor("ul"));
861
+ setActive("insertOrderedList", ancestor("ol"));
862
+ const block = getBlock(editor, range);
863
+ const blockTag = block?.tagName.toLowerCase() ?? "p";
864
+ const blockSelect = this.root.querySelector("[data-block]");
865
+ if (blockSelect) {
866
+ const value = Array.from(blockSelect.options).some((option) => option.value === blockTag) ? blockTag : "p";
867
+ blockSelect.value = value;
868
+ }
869
+ const alignment = block ? block.style.textAlign || "left" : "left";
870
+ setActive("justifyLeft", alignment === "left" || alignment === "start" || alignment === "");
871
+ setActive("justifyCenter", alignment === "center");
872
+ setActive("justifyRight", alignment === "right" || alignment === "end");
873
+ setActive("justifyFull", alignment === "justify");
874
+ };
875
+ handleToolbarKeydown_fn = function(event) {
876
+ const active = this.root.activeElement;
877
+ if (!active || !active.classList.contains("tb-btn")) return;
878
+ if (!["ArrowRight", "ArrowLeft", "Home", "End"].includes(event.key)) return;
879
+ const controls = Array.from(
880
+ this.toolbarEl?.querySelectorAll(
881
+ ".tb-btn:not(:disabled), .tb-select:not(:disabled), .tb-color input:not(:disabled)"
882
+ ) ?? []
883
+ );
884
+ if (!controls.length) return;
885
+ event.preventDefault();
886
+ let index = controls.indexOf(active);
887
+ if (event.key === "Home") index = 0;
888
+ else if (event.key === "End") index = controls.length - 1;
889
+ else index = (index + (event.key === "ArrowRight" ? 1 : -1) + controls.length) % controls.length;
890
+ const next = controls[index];
891
+ if (!next) return;
892
+ __privateMethod(this, _FxEditor_instances, moveToolbarTabStop_fn).call(this, next);
893
+ next.focus();
894
+ };
895
+ moveToolbarTabStop_fn = function(active) {
896
+ this.toolbarEl?.querySelectorAll(".tb-btn").forEach((button) => {
897
+ button.setAttribute("tabindex", button === active ? "0" : "-1");
898
+ });
899
+ };
900
+ trapDialogFocus_fn = function(event) {
901
+ if (!__privateGet(this, _dialogResolve) || event.key !== "Tab") return;
902
+ const dialog = this.root.querySelector(".dialog");
903
+ if (!dialog) return;
904
+ const focusables = Array.from(
905
+ dialog.querySelectorAll(
906
+ 'button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href], [tabindex]:not([tabindex="-1"])'
907
+ )
908
+ );
909
+ if (!focusables.length) return;
910
+ const first = focusables[0];
911
+ const last = focusables[focusables.length - 1];
912
+ const active = this.root.activeElement;
913
+ if (event.shiftKey && (active === first || !active || !dialog.contains(active))) {
914
+ event.preventDefault();
915
+ last.focus();
916
+ } else if (!event.shiftKey && (active === last || !active || !dialog.contains(active))) {
917
+ event.preventDefault();
918
+ first.focus();
919
+ }
920
+ };
921
+ execCommand_fn = function(cmd) {
922
+ const editor = this.editor;
923
+ if (!editor) return;
924
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
925
+ switch (cmd) {
926
+ case "undo":
927
+ if (!nativeExec("undo")) __privateMethod(this, _FxEditor_instances, historyUndo_fn).call(this);
928
+ break;
929
+ case "redo":
930
+ if (!nativeExec("redo")) __privateMethod(this, _FxEditor_instances, historyRedo_fn).call(this);
931
+ break;
932
+ case "bold":
933
+ toggleInline(editor, "strong");
934
+ break;
935
+ case "italic":
936
+ toggleInline(editor, "em");
937
+ break;
938
+ case "underline":
939
+ toggleInline(editor, "u");
940
+ break;
941
+ case "strikeThrough":
942
+ toggleInline(editor, "s");
943
+ break;
944
+ case "code":
945
+ toggleInline(editor, "code");
946
+ break;
947
+ case "justifyLeft":
948
+ align(editor, "left");
949
+ break;
950
+ case "justifyCenter":
951
+ align(editor, "center");
952
+ break;
953
+ case "justifyRight":
954
+ align(editor, "right");
955
+ break;
956
+ case "justifyFull":
957
+ align(editor, "justify");
958
+ break;
959
+ case "insertUnorderedList":
960
+ toggleList(editor, false);
961
+ break;
962
+ case "insertOrderedList":
963
+ toggleList(editor, true);
964
+ break;
965
+ case "removeFormat":
966
+ removeFormat(editor);
967
+ break;
968
+ case "insertHorizontalRule":
969
+ insertHtml(editor, "<hr><p><br></p>");
970
+ break;
971
+ case "foreColor":
972
+ case "hiliteColor":
973
+ nativeExec("styleWithCSS", "true");
974
+ nativeExec(cmd, this.root.querySelector(`[data-color="${cmd}"]`)?.value);
975
+ break;
976
+ default:
977
+ nativeExec(cmd);
978
+ }
979
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
980
+ };
981
+ afterCommand_fn = function() {
982
+ __privateSet(this, _dirty, true);
983
+ __privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
984
+ __privateMethod(this, _FxEditor_instances, decorateMediaFigures_fn).call(this);
985
+ __privateMethod(this, _FxEditor_instances, updateEmpty_fn).call(this);
986
+ __privateMethod(this, _FxEditor_instances, scheduleEmit_fn).call(this);
987
+ __privateMethod(this, _FxEditor_instances, scheduleSnapshot_fn).call(this);
988
+ __privateMethod(this, _FxEditor_instances, updateToolbar_fn).call(this);
989
+ };
990
+ action_fn = function(action) {
991
+ const editor = this.editor;
992
+ if (!editor) return;
993
+ switch (action) {
994
+ case "link":
995
+ void __privateMethod(this, _FxEditor_instances, openLinkDialog_fn).call(this);
996
+ break;
997
+ case "image":
998
+ void __privateMethod(this, _FxEditor_instances, openImageDialog_fn).call(this);
999
+ break;
1000
+ case "video":
1001
+ void __privateMethod(this, _FxEditor_instances, openVideoDialog_fn).call(this);
1002
+ break;
1003
+ case "table":
1004
+ __privateMethod(this, _FxEditor_instances, showTablePanel_fn).call(this);
1005
+ break;
1006
+ case "columns":
1007
+ __privateMethod(this, _FxEditor_instances, showColumnsPanel_fn).call(this);
1008
+ break;
1009
+ case "source":
1010
+ __privateMethod(this, _FxEditor_instances, toggleSource_fn).call(this);
1011
+ break;
1012
+ case "fullscreen":
1013
+ this.fullscreen = !this.fullscreen;
1014
+ break;
1015
+ case "blockquote":
1016
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1017
+ formatBlock(editor, "blockquote");
1018
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1019
+ break;
1020
+ case "codeblock":
1021
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1022
+ formatBlock(editor, "pre");
1023
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1024
+ break;
1025
+ case "indent":
1026
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1027
+ indent(editor, 24);
1028
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1029
+ break;
1030
+ case "outdent":
1031
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1032
+ indent(editor, -24);
1033
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1034
+ break;
1035
+ case "clear":
1036
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1037
+ removeFormat(editor);
1038
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1039
+ break;
1040
+ case "unlink":
1041
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1042
+ unlink(editor);
1043
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1044
+ break;
1045
+ }
1046
+ };
1047
+ handleKeydown_fn = function(event) {
1048
+ if (event.isComposing) return;
1049
+ const active = this.root.activeElement;
1050
+ const overlay = this.root.querySelector(".media-overlay");
1051
+ if (__privateGet(this, _mediaFigure) && (event.key === "Delete" || event.key === "Backspace") && (active === __privateGet(this, _mediaFigure) || __privateGet(this, _mediaFigure).contains(active) || Boolean(overlay && active && overlay.contains(active)))) {
1052
+ event.preventDefault();
1053
+ __privateMethod(this, _FxEditor_instances, deleteMediaFigure_fn).call(this);
1054
+ return;
1055
+ }
1056
+ const mod = event.ctrlKey || event.metaKey;
1057
+ const key = event.key.toLowerCase();
1058
+ if (mod && !event.altKey) {
1059
+ if (key === "b") {
1060
+ event.preventDefault();
1061
+ __privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, "bold");
1062
+ return;
1063
+ }
1064
+ if (key === "i") {
1065
+ event.preventDefault();
1066
+ __privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, "italic");
1067
+ return;
1068
+ }
1069
+ if (key === "u") {
1070
+ event.preventDefault();
1071
+ __privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, "underline");
1072
+ return;
1073
+ }
1074
+ if (key === "k") {
1075
+ event.preventDefault();
1076
+ void __privateMethod(this, _FxEditor_instances, openLinkDialog_fn).call(this);
1077
+ return;
1078
+ }
1079
+ if (key === "z" && !event.shiftKey) {
1080
+ event.preventDefault();
1081
+ __privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, "undo");
1082
+ return;
1083
+ }
1084
+ if (key === "y" || key === "z" && event.shiftKey) {
1085
+ event.preventDefault();
1086
+ __privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, "redo");
1087
+ return;
1088
+ }
1089
+ }
1090
+ if (event.key === "Escape") {
1091
+ if (__privateGet(this, _dialogResolve)) __privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, null);
1092
+ else if (__privateGet(this, _sourceMode)) __privateMethod(this, _FxEditor_instances, cancelSource_fn).call(this);
1093
+ else if (this.fullscreen) this.fullscreen = false;
1094
+ else if (__privateGet(this, _linkAnchor)) __privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
1095
+ else if (__privateGet(this, _mediaFigure)) __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
1096
+ else __privateMethod(this, _FxEditor_instances, hidePanel_fn).call(this);
1097
+ return;
1098
+ }
1099
+ if (event.key === "Tab" && __privateMethod(this, _FxEditor_instances, tabInTable_fn).call(this, event.shiftKey)) {
1100
+ event.preventDefault();
1101
+ }
1102
+ };
1103
+ tabInTable_fn = function(backwards) {
1104
+ const editor = this.editor;
1105
+ if (!editor) return false;
1106
+ const range = getRange(editor, __privateGet(this, _lastRange));
1107
+ if (!range) return false;
1108
+ const cell = closestInEditor(editor, range.startContainer, "td,th");
1109
+ const table = cell?.closest("table");
1110
+ if (!cell || !table) return false;
1111
+ const cells = Array.from(table.querySelectorAll("td,th"));
1112
+ let index = cells.indexOf(cell);
1113
+ if (index < 0) return false;
1114
+ if (backwards) {
1115
+ index = Math.max(0, index - 1);
1116
+ } else {
1117
+ index++;
1118
+ if (index >= cells.length) {
1119
+ const row = cell.parentElement;
1120
+ if (!row) return false;
1121
+ const clone = row.cloneNode(true);
1122
+ for (const cloned of Array.from(clone.querySelectorAll("td,th"))) {
1123
+ cloned.innerHTML = "<p><br></p>";
1124
+ }
1125
+ row.after(clone);
1126
+ cells.push(...Array.from(clone.querySelectorAll("td,th")));
1127
+ index = cells.indexOf(clone.querySelector("td,th"));
1128
+ }
1129
+ }
1130
+ const target = cells[index];
1131
+ if (!target) return false;
1132
+ const next = document.createRange();
1133
+ next.selectNodeContents(target);
1134
+ next.collapse(true);
1135
+ const selection = document.getSelection();
1136
+ selection?.removeAllRanges();
1137
+ selection?.addRange(next);
1138
+ return true;
1139
+ };
1140
+ handleBeforeInput_fn = function(event) {
1141
+ if (this.disabled || this.readonly || !this.maxlength) return;
1142
+ const type = event.inputType;
1143
+ if (type === "insertFromPaste" || type === "insertFromDrop" || type.startsWith("history") || type.startsWith("format")) {
1144
+ return;
1145
+ }
1146
+ const extra = event.data?.length ?? (type === "insertParagraph" || type === "insertLineBreak" ? 1 : 0);
1147
+ if (!extra) return;
1148
+ if (!__privateMethod(this, _FxEditor_instances, fits_fn).call(this, extra)) {
1149
+ event.preventDefault();
1150
+ __privateMethod(this, _FxEditor_instances, limitError_fn).call(this);
1151
+ }
1152
+ };
1153
+ handlePaste_fn = function(event) {
1154
+ const clipboard = event.clipboardData;
1155
+ if (!clipboard) return;
1156
+ const file = Array.from(clipboard.files ?? []).find((item) => item.type.startsWith("image/"));
1157
+ if (file) {
1158
+ event.preventDefault();
1159
+ void __privateMethod(this, _FxEditor_instances, handleImageFile_fn).call(this, file);
1160
+ return;
1161
+ }
1162
+ const html = clipboard.getData("text/html");
1163
+ const text = clipboard.getData("text/plain");
1164
+ if (html.length > MAX_PASTE_BYTES || text.length > MAX_PASTE_BYTES) return;
1165
+ event.preventDefault();
1166
+ if (!__privateMethod(this, _FxEditor_instances, fits_fn).call(this, text.length)) {
1167
+ __privateMethod(this, _FxEditor_instances, limitError_fn).call(this);
1168
+ return;
1169
+ }
1170
+ if (this.pasteMode === "plain" || !html) {
1171
+ __privateMethod(this, _FxEditor_instances, insertPlainText_fn).call(this, text);
1172
+ return;
1173
+ }
1174
+ const clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, html);
1175
+ if (!clean) {
1176
+ __privateMethod(this, _FxEditor_instances, insertPlainText_fn).call(this, text);
1177
+ return;
1178
+ }
1179
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1180
+ insertHtml(this.editor, clean);
1181
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1182
+ };
1183
+ handleDrop_fn = function(event) {
1184
+ const transfer = event.dataTransfer;
1185
+ if (!transfer) return;
1186
+ event.preventDefault();
1187
+ const file = Array.from(transfer.files ?? []).find((item) => item.type.startsWith("image/"));
1188
+ if (file) {
1189
+ void __privateMethod(this, _FxEditor_instances, handleImageFile_fn).call(this, file);
1190
+ return;
1191
+ }
1192
+ const html = transfer.getData("text/html");
1193
+ const text = transfer.getData("text/plain");
1194
+ if (!__privateMethod(this, _FxEditor_instances, fits_fn).call(this, text.length)) {
1195
+ __privateMethod(this, _FxEditor_instances, limitError_fn).call(this);
1196
+ return;
1197
+ }
1198
+ if (html) {
1199
+ insertHtml(this.editor, __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, html));
1200
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1201
+ } else if (text) {
1202
+ __privateMethod(this, _FxEditor_instances, insertPlainText_fn).call(this, text);
1203
+ }
1204
+ };
1205
+ insertPlainText_fn = function(text) {
1206
+ const paragraphs = text.replace(/\r\n/g, "\n").split(/\n{2,}/).map((block) => `<p>${escapeText(block).replace(/\n/g, "<br>")}</p>`).join("");
1207
+ insertHtml(this.editor, paragraphs || "<p><br></p>");
1208
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1209
+ };
1210
+ toggleSource_fn = function() {
1211
+ if (__privateGet(this, _sourceMode)) {
1212
+ __privateMethod(this, _FxEditor_instances, applySource_fn).call(this);
1213
+ return;
1214
+ }
1215
+ const source = this.source;
1216
+ if (!source) return;
1217
+ source.value = __privateMethod(this, _FxEditor_instances, serialize_fn).call(this);
1218
+ __privateSet(this, _sourceMode, true);
1219
+ __privateMethod(this, _FxEditor_instances, syncChrome_fn).call(this);
1220
+ source.focus();
1221
+ };
1222
+ applySource_fn = function() {
1223
+ const source = this.source;
1224
+ if (!source) return;
1225
+ const clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, source.value);
1226
+ __privateSet(this, _sourceMode, false);
1227
+ __privateSet(this, _value, clean);
1228
+ __privateSet(this, _dirty, false);
1229
+ __privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, clean);
1230
+ __privateMethod(this, _FxEditor_instances, syncChrome_fn).call(this);
1231
+ this.updateFormValue();
1232
+ __privateMethod(this, _FxEditor_instances, emitChange_fn).call(this);
1233
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1234
+ };
1235
+ cancelSource_fn = function() {
1236
+ __privateSet(this, _sourceMode, false);
1237
+ __privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, __privateGet(this, _value));
1238
+ __privateMethod(this, _FxEditor_instances, syncChrome_fn).call(this);
1239
+ };
1240
+ openDialog_fn = function(title, fields) {
1241
+ const backdrop = this.root.querySelector(".backdrop");
1242
+ const titleEl = this.root.querySelector(".dialog h3");
1243
+ const body = this.root.querySelector(".dialog-body");
1244
+ if (!backdrop || !titleEl || !body) return Promise.resolve(null);
1245
+ titleEl.textContent = title;
1246
+ body.innerHTML = fields.map((field) => __privateMethod(this, _FxEditor_instances, fieldHtml_fn).call(this, field)).join("");
1247
+ __privateSet(this, _dialogReturnFocus, this.root.activeElement ?? this.editor);
1248
+ backdrop.removeAttribute("hidden");
1249
+ const first = body.querySelector("input,select");
1250
+ first?.focus();
1251
+ return new Promise((resolve) => {
1252
+ __privateSet(this, _dialogResolve, resolve);
1253
+ });
1254
+ };
1255
+ fieldHtml_fn = function(field) {
1256
+ const label = esc(field.label);
1257
+ if (field.type === "select") {
1258
+ const options = (field.options ?? []).map((option) => `<option value="${esc(option.value)}" ${option.value === field.value ? "selected" : ""}>${esc(option.label)}</option>`).join("");
1259
+ return `<label class="field"><span>${label}</span><select data-field="${esc(field.name)}">${options}</select></label>`;
1260
+ }
1261
+ const type = field.type === "url" ? "url" : field.type === "number" ? "number" : "text";
1262
+ return `<label class="field"><span>${label}</span><input data-field="${esc(field.name)}" type="${type}" value="${esc(field.value ?? "")}" placeholder="${esc(field.placeholder ?? "")}"></label>`;
1263
+ };
1264
+ submitDialog_fn = function() {
1265
+ const body = this.root.querySelector(".dialog-body");
1266
+ if (!body) return;
1267
+ const result = {};
1268
+ for (const field of Array.from(body.querySelectorAll("[data-field]"))) {
1269
+ result[field.dataset.field ?? ""] = field.value.trim();
1270
+ }
1271
+ __privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, result);
1272
+ };
1273
+ openLinkDialog_fn = async function(existing) {
1274
+ __privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
1275
+ const editor = this.editor;
1276
+ if (!editor) return;
1277
+ if (existing) __privateMethod(this, _FxEditor_instances, selectAnchor_fn).call(this, existing);
1278
+ let range = getRange(editor, __privateGet(this, _lastRange));
1279
+ if (!range) {
1280
+ placeCaretAtEnd(editor);
1281
+ range = getRange(editor);
1282
+ __privateSet(this, _lastRange, range?.cloneRange() ?? null);
1283
+ }
1284
+ const anchor = existing ?? closestInEditor(editor, range?.startContainer ?? null, "a");
1285
+ const selected = range && !range.collapsed ? range.toString() : anchor?.textContent ?? "";
1286
+ const result = await __privateMethod(this, _FxEditor_instances, openDialog_fn).call(this, "Link", [
1287
+ { name: "url", label: "URL", type: "url", value: anchor?.getAttribute("href") ?? "", placeholder: "https://..." },
1288
+ { name: "text", label: "Texto (quando não há seleção)", value: selected, placeholder: "Texto do link" },
1289
+ {
1290
+ name: "target",
1291
+ label: "Abrir em",
1292
+ type: "select",
1293
+ value: anchor?.getAttribute("target") ?? "_blank",
1294
+ options: [
1295
+ { value: "_blank", label: "Nova aba" },
1296
+ { value: "_self", label: "Mesma aba" }
1297
+ ]
1298
+ }
1299
+ ]);
1300
+ if (!result) return;
1301
+ const href = sanitizeLinkUrl(result.url ?? "");
1302
+ if (!href) {
1303
+ __privateMethod(this, _FxEditor_instances, error_fn).call(this, "URL de link inválida.");
1304
+ return;
1305
+ }
1306
+ const target = result.target === "_self" ? "_self" : "_blank";
1307
+ const label = (result.text ?? "").trim() || (anchor ? void 0 : selected || href);
1308
+ if (anchor) {
1309
+ anchor.setAttribute("href", href);
1310
+ anchor.setAttribute("target", target);
1311
+ anchor.setAttribute("rel", "noopener noreferrer");
1312
+ if (label) anchor.textContent = label;
1313
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1314
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1315
+ return;
1316
+ }
1317
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1318
+ applyLink(editor, href, label ?? (selected || href), target);
1319
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1320
+ };
1321
+ openImageDialog_fn = async function(existing) {
1322
+ __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
1323
+ const figure = existing?.closest("figure");
1324
+ const caption = figure?.querySelector("figcaption")?.textContent ?? "";
1325
+ const alignValue = figure?.getAttribute("data-align") ?? "center";
1326
+ const widthValue = figure?.style.width?.replace("%", "") || "100";
1327
+ const dialog = __privateMethod(this, _FxEditor_instances, openDialog_fn).call(this, existing ? "Editar imagem" : "Inserir imagem", [
1328
+ { name: "src", label: "URL da imagem", type: "url", value: existing?.getAttribute("src") ?? "", placeholder: "https://..." },
1329
+ { name: "alt", label: "Texto alternativo", value: existing?.getAttribute("alt") ?? "" },
1330
+ { name: "caption", label: "Legenda", value: caption },
1331
+ {
1332
+ name: "width",
1333
+ label: "Largura",
1334
+ type: "select",
1335
+ value: widthValue,
1336
+ options: [
1337
+ { value: "25", label: "25%" },
1338
+ { value: "50", label: "50%" },
1339
+ { value: "75", label: "75%" },
1340
+ { value: "100", label: "100%" }
1341
+ ]
1342
+ },
1343
+ {
1344
+ name: "align",
1345
+ label: "Alinhamento",
1346
+ type: "select",
1347
+ value: alignValue,
1348
+ options: [
1349
+ { value: "left", label: "Esquerda" },
1350
+ { value: "center", label: "Centro" },
1351
+ { value: "right", label: "Direita" }
1352
+ ]
1353
+ }
1354
+ ]);
1355
+ const body = this.root.querySelector(".dialog-body");
1356
+ if (body) {
1357
+ const upload = document.createElement("button");
1358
+ upload.type = "button";
1359
+ upload.className = "btn";
1360
+ upload.textContent = "Escolher arquivo…";
1361
+ upload.addEventListener("click", () => {
1362
+ __privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, null);
1363
+ __privateGet(this, _imagePicker)?.click();
1364
+ });
1365
+ body.appendChild(upload);
1366
+ }
1367
+ const result = await dialog;
1368
+ if (!result) return;
1369
+ const src = sanitizeMediaUrl(result.src ?? "", "img");
1370
+ if (!src) {
1371
+ __privateMethod(this, _FxEditor_instances, error_fn).call(this, "URL de imagem inválida.");
1372
+ return;
1373
+ }
1374
+ if (existing && figure) {
1375
+ existing.setAttribute("src", src);
1376
+ existing.setAttribute("alt", result.alt ?? "");
1377
+ figure.setAttribute("data-align", result.align || "center");
1378
+ figure.style.width = `${result.width || 100}%`;
1379
+ const cap = figure.querySelector("figcaption");
1380
+ if (result.caption) {
1381
+ if (cap) cap.textContent = result.caption;
1382
+ else figure.insertAdjacentHTML("beforeend", `<figcaption>${escapeText(result.caption)}</figcaption>`);
1383
+ } else {
1384
+ cap?.remove();
1385
+ }
1386
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1387
+ return;
1388
+ }
1389
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1390
+ __privateMethod(this, _FxEditor_instances, insertImage_fn).call(this, src, result.alt ?? "", result.caption ?? "", result.width || "100", result.align || "center");
1391
+ };
1392
+ toEmbedUrl_fn = function(value) {
1393
+ try {
1394
+ const url = new URL(value);
1395
+ const host = url.hostname.replace(/^www\./, "");
1396
+ if (host === "youtu.be") {
1397
+ return `https://www.youtube-nocookie.com/embed/${url.pathname.slice(1)}`;
1398
+ }
1399
+ if (host === "youtube.com" || host === "m.youtube.com") {
1400
+ const id = url.searchParams.get("v");
1401
+ if (id) return `https://www.youtube-nocookie.com/embed/${id}`;
1402
+ if (url.pathname.startsWith("/shorts/")) {
1403
+ return `https://www.youtube-nocookie.com/embed/${url.pathname.split("/")[2] ?? ""}`;
1404
+ }
1405
+ }
1406
+ if (host === "vimeo.com") {
1407
+ const id = url.pathname.split("/").filter(Boolean)[0];
1408
+ if (id) return `https://player.vimeo.com/video/${id}`;
1409
+ }
1410
+ return value;
1411
+ } catch {
1412
+ return value;
1413
+ }
1414
+ };
1415
+ openVideoDialog_fn = async function() {
1416
+ const result = await __privateMethod(this, _FxEditor_instances, openDialog_fn).call(this, "Inserir vídeo", [
1417
+ { name: "src", label: "URL do vídeo ou embed", type: "url", placeholder: "https://.../video.mp4 ou YouTube/Vimeo" },
1418
+ { name: "caption", label: "Legenda", value: "" },
1419
+ {
1420
+ name: "width",
1421
+ label: "Largura",
1422
+ type: "select",
1423
+ value: "100",
1424
+ options: [
1425
+ { value: "50", label: "50%" },
1426
+ { value: "75", label: "75%" },
1427
+ { value: "100", label: "100%" }
1428
+ ]
1429
+ },
1430
+ {
1431
+ name: "align",
1432
+ label: "Alinhamento",
1433
+ type: "select",
1434
+ value: "center",
1435
+ options: [
1436
+ { value: "left", label: "Esquerda" },
1437
+ { value: "center", label: "Centro" },
1438
+ { value: "right", label: "Direita" }
1439
+ ]
1440
+ }
1441
+ ]);
1442
+ if (!result) return;
1443
+ const src = result.src ?? "";
1444
+ const embed = sanitizeEmbedUrl(__privateMethod(this, _FxEditor_instances, toEmbedUrl_fn).call(this, src));
1445
+ if (embed) {
1446
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1447
+ __privateMethod(this, _FxEditor_instances, insertEmbed_fn).call(this, embed, result.caption ?? "", result.width || "100", result.align || "center");
1448
+ return;
1449
+ }
1450
+ const media = sanitizeMediaUrl(src, "video");
1451
+ if (!media) {
1452
+ __privateMethod(this, _FxEditor_instances, error_fn).call(this, "URL de vídeo inválida.");
1453
+ return;
1454
+ }
1455
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1456
+ __privateMethod(this, _FxEditor_instances, insertVideo_fn).call(this, media, result.caption ?? "", result.width || "100", result.align || "center");
1457
+ };
1458
+ decorateMediaFigures_fn = function() {
1459
+ const editor = this.editor;
1460
+ if (!editor || __privateGet(this, _sourceMode)) return;
1461
+ for (const figure of Array.from(
1462
+ editor.querySelectorAll("figure.fx-image, figure.fx-video, figure.fx-embed")
1463
+ )) {
1464
+ if (figure.querySelector(":scope > .fx-media-quick")) {
1465
+ __privateMethod(this, _FxEditor_instances, syncQuickActions_fn).call(this, figure);
1466
+ continue;
1467
+ }
1468
+ for (const kind of ["left", "center", "right", "delete"]) {
1469
+ const label = kind === "delete" ? "Excluir mídia" : kind === "left" ? "Alinhar à esquerda" : kind === "center" ? "Centralizar" : "Alinhar à direita";
1470
+ const button = document.createElement("button");
1471
+ button.type = "button";
1472
+ button.className = `fx-media-quick quick-${kind}`;
1473
+ button.title = label;
1474
+ button.setAttribute("aria-label", label);
1475
+ if (kind === "delete") button.dataset.mediaDelete = "";
1476
+ else button.dataset.mediaAlign = kind;
1477
+ button.innerHTML = QUICK_SVG[kind];
1478
+ button.addEventListener("click", (event) => {
1479
+ event.preventDefault();
1480
+ event.stopPropagation();
1481
+ if (kind === "delete") {
1482
+ figure.remove();
1483
+ __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
1484
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1485
+ } else {
1486
+ figure.setAttribute("data-align", kind);
1487
+ __privateMethod(this, _FxEditor_instances, syncQuickActions_fn).call(this, figure);
1488
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1489
+ }
1490
+ });
1491
+ figure.appendChild(button);
1492
+ }
1493
+ __privateMethod(this, _FxEditor_instances, syncQuickActions_fn).call(this, figure);
1494
+ }
1495
+ };
1496
+ syncQuickActions_fn = function(figure) {
1497
+ const align2 = figure.getAttribute("data-align") || "center";
1498
+ for (const button of Array.from(
1499
+ figure.querySelectorAll(":scope > .fx-media-quick[data-media-align]")
1500
+ )) {
1501
+ button.classList.toggle("active", button.dataset.mediaAlign === align2);
1502
+ }
1503
+ };
1504
+ selectAnchor_fn = function(anchor) {
1505
+ const editor = this.editor;
1506
+ if (!editor) return;
1507
+ editor.focus({ preventScroll: true });
1508
+ const range = document.createRange();
1509
+ range.selectNodeContents(anchor);
1510
+ const selection = document.getSelection();
1511
+ if (!selection) return;
1512
+ selection.removeAllRanges();
1513
+ selection.addRange(range);
1514
+ __privateSet(this, _lastRange, range.cloneRange());
1515
+ };
1516
+ handleLinkOverlayClick_fn = function(event) {
1517
+ const action = event.target.closest("[data-link-action]");
1518
+ const anchor = __privateGet(this, _linkAnchor);
1519
+ if (!action || !anchor) return;
1520
+ event.preventDefault();
1521
+ event.stopPropagation();
1522
+ const kind = action.dataset.linkAction;
1523
+ if (kind === "open") __privateMethod(this, _FxEditor_instances, openLink_fn).call(this, anchor);
1524
+ else if (kind === "edit") void __privateMethod(this, _FxEditor_instances, openLinkDialog_fn).call(this, anchor);
1525
+ else if (kind === "remove") __privateMethod(this, _FxEditor_instances, removeLink_fn).call(this, anchor);
1526
+ };
1527
+ openLink_fn = function(anchor) {
1528
+ const href = anchor.getAttribute("href") ?? "";
1529
+ if (!href) return;
1530
+ __privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
1531
+ const target = anchor.getAttribute("target") === "_self" ? "_self" : "_blank";
1532
+ window.open(href, target, target === "_blank" ? "noopener,noreferrer" : void 0);
1533
+ };
1534
+ removeLink_fn = function(anchor) {
1535
+ const parent = anchor.parentNode;
1536
+ if (!parent) return;
1537
+ while (anchor.firstChild) parent.insertBefore(anchor.firstChild, anchor);
1538
+ anchor.remove();
1539
+ __privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
1540
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1541
+ this.editor?.focus({ preventScroll: true });
1542
+ };
1543
+ showLinkOverlay_fn = function(anchor) {
1544
+ __privateSet(this, _linkAnchor, anchor);
1545
+ const overlay = this.root.querySelector(".link-overlay");
1546
+ if (!overlay) return;
1547
+ const target = anchor.getAttribute("target") === "_self" ? "mesma janela" : "nova aba";
1548
+ const open = overlay.querySelector('[data-link-action="open"]');
1549
+ if (open) open.title = `Abrir na ${target}`;
1550
+ overlay.hidden = false;
1551
+ __privateMethod(this, _FxEditor_instances, positionLinkOverlay_fn).call(this);
1552
+ };
1553
+ hideLinkOverlay_fn = function() {
1554
+ __privateSet(this, _linkAnchor, null);
1555
+ const overlay = this.root.querySelector(".link-overlay");
1556
+ if (overlay) overlay.hidden = true;
1557
+ };
1558
+ positionLinkOverlay_fn = function() {
1559
+ const overlay = this.root.querySelector(".link-overlay");
1560
+ const anchor = __privateGet(this, _linkAnchor);
1561
+ const editor = this.editor;
1562
+ if (!overlay) return;
1563
+ if (!anchor || !editor || __privateGet(this, _sourceMode) || !anchor.isConnected || !editor.contains(anchor)) {
1564
+ overlay.hidden = true;
1565
+ return;
1566
+ }
1567
+ const body = overlay.parentElement;
1568
+ if (!body) return;
1569
+ const bodyRect = body.getBoundingClientRect();
1570
+ const rect = anchor.getBoundingClientRect();
1571
+ if (!rect.width || !rect.height || rect.bottom < bodyRect.top || rect.top > bodyRect.bottom) {
1572
+ overlay.hidden = true;
1573
+ return;
1574
+ }
1575
+ overlay.hidden = false;
1576
+ const width = overlay.offsetWidth || 180;
1577
+ const height = overlay.offsetHeight || 30;
1578
+ const left = Math.max(4, Math.min(rect.left - bodyRect.left, bodyRect.width - width - 4));
1579
+ let top = rect.bottom - bodyRect.top + 6;
1580
+ if (top + height > bodyRect.height) top = rect.top - bodyRect.top - height - 6;
1581
+ overlay.style.left = `${left}px`;
1582
+ overlay.style.top = `${Math.max(4, top)}px`;
1583
+ };
1584
+ handleEditorClick_fn = function(event) {
1585
+ const target = event.target;
1586
+ const anchor = target.closest("a[href]");
1587
+ if (anchor && this.editor?.contains(anchor)) {
1588
+ __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
1589
+ __privateMethod(this, _FxEditor_instances, showLinkOverlay_fn).call(this, anchor);
1590
+ if (event.ctrlKey || event.metaKey) {
1591
+ event.preventDefault();
1592
+ __privateMethod(this, _FxEditor_instances, openLink_fn).call(this, anchor);
1593
+ }
1594
+ return;
1595
+ }
1596
+ __privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
1597
+ const figure = target.closest("figure.fx-image, figure.fx-video, figure.fx-embed");
1598
+ if (figure) __privateMethod(this, _FxEditor_instances, showMediaOverlay_fn).call(this, figure);
1599
+ else __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
1600
+ };
1601
+ showMediaOverlay_fn = function(figure) {
1602
+ __privateSet(this, _mediaFigure, figure);
1603
+ figure.setAttribute("tabindex", "0");
1604
+ if (figure.classList.contains("fx-image")) figure.focus({ preventScroll: true });
1605
+ const overlay = this.root.querySelector(".media-overlay");
1606
+ if (!overlay) return;
1607
+ overlay.hidden = false;
1608
+ __privateMethod(this, _FxEditor_instances, positionMediaOverlay_fn).call(this);
1609
+ };
1610
+ hideMediaOverlay_fn = function() {
1611
+ __privateGet(this, _mediaFigure)?.removeAttribute("tabindex");
1612
+ __privateSet(this, _mediaFigure, null);
1613
+ const overlay = this.root.querySelector(".media-overlay");
1614
+ if (!overlay) return;
1615
+ overlay.hidden = true;
1616
+ const size = overlay.querySelector(".media-size");
1617
+ if (size) size.textContent = "";
1618
+ };
1619
+ deleteMediaFigure_fn = function() {
1620
+ const figure = __privateGet(this, _mediaFigure);
1621
+ if (!figure) return;
1622
+ figure.remove();
1623
+ __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
1624
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1625
+ this.editor?.focus({ preventScroll: true });
1626
+ };
1627
+ positionMediaOverlay_fn = function() {
1628
+ const overlay = this.root.querySelector(".media-overlay");
1629
+ const figure = __privateGet(this, _mediaFigure);
1630
+ const editor = this.editor;
1631
+ if (!overlay) return;
1632
+ if (!figure || !editor || __privateGet(this, _sourceMode) || !figure.isConnected || !editor.contains(figure)) {
1633
+ overlay.hidden = true;
1634
+ return;
1635
+ }
1636
+ const body = overlay.parentElement;
1637
+ if (!body) return;
1638
+ const bodyRect = body.getBoundingClientRect();
1639
+ const rect = figure.getBoundingClientRect();
1640
+ if (!rect.width || !rect.height || rect.bottom < bodyRect.top || rect.top > bodyRect.bottom) {
1641
+ overlay.hidden = true;
1642
+ return;
1643
+ }
1644
+ overlay.hidden = false;
1645
+ overlay.style.left = `${rect.left - bodyRect.left}px`;
1646
+ overlay.style.top = `${rect.top - bodyRect.top}px`;
1647
+ overlay.style.width = `${rect.width}px`;
1648
+ overlay.style.height = `${rect.height}px`;
1649
+ const size = overlay.querySelector(".media-size");
1650
+ if (size) size.textContent = `${Math.round(rect.width)} × ${Math.round(rect.height)}`;
1651
+ };
1652
+ startResize_fn = function(event) {
1653
+ const handle = event.target.closest("[data-handle]");
1654
+ const figure = __privateGet(this, _mediaFigure);
1655
+ const editor = this.editor;
1656
+ if (!handle || !figure || !editor) return;
1657
+ event.preventDefault();
1658
+ event.stopPropagation();
1659
+ __privateMethod(this, _FxEditor_instances, endResize_fn).call(this);
1660
+ const parent = figure.parentElement;
1661
+ if (!parent) return;
1662
+ const parentWidth = parent.getBoundingClientRect().width || editor.clientWidth;
1663
+ if (!parentWidth) return;
1664
+ const rect = figure.getBoundingClientRect();
1665
+ const startWidth = rect.width ? rect.width / parentWidth * 100 : Number.parseFloat(figure.style.width) || 100;
1666
+ const startX = event.clientX;
1667
+ const direction = handle.dataset.handle?.includes("w") ? -1 : 1;
1668
+ const move = (moveEvent) => {
1669
+ const deltaPct = (moveEvent.clientX - startX) * direction * 100 / parentWidth;
1670
+ const width = Math.min(100, Math.max(15, startWidth + deltaPct));
1671
+ figure.style.width = `${width.toFixed(1).replace(/\.0$/, "")}%`;
1672
+ __privateMethod(this, _FxEditor_instances, positionMediaOverlay_fn).call(this);
1673
+ };
1674
+ const up = () => {
1675
+ __privateMethod(this, _FxEditor_instances, endResize_fn).call(this);
1676
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1677
+ __privateMethod(this, _FxEditor_instances, positionMediaOverlay_fn).call(this);
1678
+ };
1679
+ window.addEventListener("pointermove", move);
1680
+ window.addEventListener("pointerup", up, { once: true });
1681
+ window.addEventListener("pointercancel", up, { once: true });
1682
+ __privateSet(this, _resizeDispose, () => {
1683
+ window.removeEventListener("pointermove", move);
1684
+ window.removeEventListener("pointerup", up);
1685
+ window.removeEventListener("pointercancel", up);
1686
+ });
1687
+ };
1688
+ endResize_fn = function() {
1689
+ var _a;
1690
+ (_a = __privateGet(this, _resizeDispose)) == null ? void 0 : _a.call(this);
1691
+ __privateSet(this, _resizeDispose, null);
1692
+ };
1693
+ handleDoubleClick_fn = function(event) {
1694
+ const target = event.target;
1695
+ const image = target.closest("img");
1696
+ if (image) {
1697
+ event.preventDefault();
1698
+ void __privateMethod(this, _FxEditor_instances, openImageDialog_fn).call(this, image);
1699
+ }
1700
+ };
1701
+ insertImage_fn = function(src, alt, caption, width, align2) {
1702
+ const html = `<figure class="fx-image" contenteditable="false" data-align="${escapeAttr(align2)}" style="width:${escapeAttr(width)}%"><img src="${escapeAttr(src)}" alt="${escapeAttr(alt)}" loading="lazy" decoding="async">${caption ? `<figcaption>${escapeText(caption)}</figcaption>` : ""}</figure><p><br></p>`;
1703
+ insertHtml(this.editor, html);
1704
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1705
+ };
1706
+ insertVideo_fn = function(src, caption, width, align2 = "center") {
1707
+ const html = `<figure class="fx-video" contenteditable="false" data-align="${escapeAttr(align2)}" style="width:${escapeAttr(width)}%"><video controls preload="metadata" src="${escapeAttr(src)}" style="width:100%"></video>${caption ? `<figcaption>${escapeText(caption)}</figcaption>` : ""}</figure><p><br></p>`;
1708
+ insertHtml(this.editor, html);
1709
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1710
+ };
1711
+ insertEmbed_fn = function(src, caption, width, align2 = "center") {
1712
+ const html = `<figure class="fx-embed" contenteditable="false" data-align="${escapeAttr(align2)}" style="width:${escapeAttr(width)}%"><iframe src="${escapeAttr(src)}" title="${escapeAttr(caption || "Vídeo")}" loading="lazy" allowfullscreen sandbox="allow-scripts allow-same-origin allow-presentation" referrerpolicy="strict-origin-when-cross-origin" style="width:100%;aspect-ratio:16/9;border:0"></iframe>${caption ? `<figcaption>${escapeText(caption)}</figcaption>` : ""}</figure><p><br></p>`;
1713
+ insertHtml(this.editor, html);
1714
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1715
+ };
1716
+ insertTable_fn = function(rows, cols) {
1717
+ const rowCount = Math.min(20, Math.max(1, rows));
1718
+ const colCount = Math.min(12, Math.max(1, cols));
1719
+ const width = (100 / colCount).toFixed(4).replace(/\.?0+$/, "");
1720
+ const colsHtml = `<colgroup>${Array.from({ length: colCount }, () => `<col style="width:${width}%">`).join("")}</colgroup>`;
1721
+ const head = `<thead><tr>${Array.from({ length: colCount }, () => '<th scope="col"><p><br></p></th>').join("")}</tr></thead>`;
1722
+ const bodyRows = Math.max(0, rowCount - 1);
1723
+ const body = bodyRows ? `<tbody>${Array.from(
1724
+ { length: bodyRows },
1725
+ () => `<tr>${Array.from({ length: colCount }, () => "<td><p><br></p></td>").join("")}</tr>`
1726
+ ).join("")}</tbody>` : "";
1727
+ const html = `<figure class="fx-table"><table>${colsHtml}${head}${body}</table></figure><p><br></p>`;
1728
+ insertHtml(this.editor, html);
1729
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1730
+ };
1731
+ insertColumns_fn = function(cols) {
1732
+ const count = Math.min(4, Math.max(1, cols));
1733
+ const width = (100 / count).toFixed(4).replace(/\.?0+$/, "");
1734
+ const cells = Array.from(
1735
+ { length: count },
1736
+ () => `<td style="width:${width}%;vertical-align:top;padding:8px"><p><br></p></td>`
1737
+ ).join("");
1738
+ const html = `<table class="fx-grid" role="presentation" data-cols="${count}" data-stack="sm" style="width:100%;border-collapse:collapse"><tbody><tr>${cells}</tr></tbody></table><p><br></p>`;
1739
+ insertHtml(this.editor, html);
1740
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1741
+ };
1742
+ showTablePanel_fn = function() {
1743
+ const panel = this.root.querySelector("[data-panel]");
1744
+ if (!panel) return;
1745
+ const table = __privateMethod(this, _FxEditor_instances, currentTable_fn).call(this);
1746
+ const grid = Array.from({ length: 64 }, (_, index) => {
1747
+ const rows = Math.floor(index / 8) + 1;
1748
+ const cols = index % 8 + 1;
1749
+ return `<button type="button" data-grid="${rows},${cols}" aria-label="${rows} por ${cols}"></button>`;
1750
+ }).join("");
1751
+ panel.innerHTML = `<p class="panel-title">Inserir tabela</p><div class="grid-picker">${grid}</div>` + (table ? `<p class="panel-title" style="margin-top:8px">Tabela atual</p><div class="panel-actions"><button type="button" class="btn" data-table-action="add-row">+ Linha</button><button type="button" class="btn" data-table-action="add-col">+ Coluna</button><button type="button" class="btn" data-table-action="del-row">− Linha</button><button type="button" class="btn" data-table-action="del-col">− Coluna</button><button type="button" class="btn" data-table-action="toggle-header">Cabeçalho</button><button type="button" class="btn" data-table-action="merge-cells">Mesclar</button><button type="button" class="btn" data-table-action="split-cell">Dividir</button><button type="button" class="btn" data-table-action="del-table">Excluir tabela</button></div>` : "");
1752
+ panel.removeAttribute("hidden");
1753
+ panel.querySelectorAll("[data-grid]").forEach((button) => {
1754
+ button.addEventListener("click", () => {
1755
+ const [rows, cols] = (button.dataset.grid ?? "").split(",").map(Number);
1756
+ __privateMethod(this, _FxEditor_instances, hidePanel_fn).call(this);
1757
+ __privateMethod(this, _FxEditor_instances, insertTable_fn).call(this, rows, cols);
1758
+ });
1759
+ });
1760
+ panel.querySelectorAll("[data-table-action]").forEach((button) => {
1761
+ button.addEventListener("click", () => {
1762
+ __privateMethod(this, _FxEditor_instances, tableAction_fn).call(this, button.dataset.tableAction ?? "");
1763
+ __privateMethod(this, _FxEditor_instances, hidePanel_fn).call(this);
1764
+ });
1765
+ });
1766
+ };
1767
+ showColumnsPanel_fn = function() {
1768
+ const panel = this.root.querySelector("[data-panel]");
1769
+ if (!panel) return;
1770
+ panel.innerHTML = `<p class="panel-title">Inserir colunas</p><div class="panel-actions">` + [1, 2, 3, 4].map((count) => `<button type="button" class="btn" data-columns="${count}">${count}</button>`).join("") + `</div>`;
1771
+ panel.removeAttribute("hidden");
1772
+ panel.querySelectorAll("[data-columns]").forEach((button) => {
1773
+ button.addEventListener("click", () => {
1774
+ __privateMethod(this, _FxEditor_instances, hidePanel_fn).call(this);
1775
+ __privateMethod(this, _FxEditor_instances, insertColumns_fn).call(this, Number(button.dataset.columns ?? 1));
1776
+ });
1777
+ });
1778
+ };
1779
+ hidePanel_fn = function() {
1780
+ this.root.querySelector("[data-panel]")?.setAttribute("hidden", "");
1781
+ };
1782
+ currentTable_fn = function() {
1783
+ const editor = this.editor;
1784
+ if (!editor) return null;
1785
+ const range = getRange(editor, __privateGet(this, _lastRange));
1786
+ return closestInEditor(editor, range?.startContainer ?? null, "table");
1787
+ };
1788
+ tableAction_fn = function(action) {
1789
+ const table = __privateMethod(this, _FxEditor_instances, currentTable_fn).call(this);
1790
+ if (!table) return;
1791
+ const editor = this.editor;
1792
+ const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
1793
+ const cell = editor ? closestInEditor(editor, range?.startContainer ?? null, "td,th") : null;
1794
+ const row = cell?.parentElement;
1795
+ if (action === "merge-cells") {
1796
+ if (!range) return;
1797
+ const merged = mergeSelectedCells(table, range);
1798
+ if (!merged) return;
1799
+ placeCaretAtEnd(merged);
1800
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1801
+ return;
1802
+ }
1803
+ if (action === "split-cell") {
1804
+ if (!cell) return;
1805
+ const created = splitCell(table, cell);
1806
+ if (!created.length) return;
1807
+ placeCaretAtEnd(cell);
1808
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1809
+ return;
1810
+ }
1811
+ if (action === "add-row" && row) {
1812
+ const clone = row.cloneNode(true);
1813
+ for (const cloneCell of Array.from(clone.querySelectorAll("td,th"))) {
1814
+ cloneCell.innerHTML = "<p><br></p>";
1815
+ }
1816
+ row.after(clone);
1817
+ } else if (action === "add-col" && cell) {
1818
+ const index = Array.from(row?.children ?? []).indexOf(cell);
1819
+ for (const currentRow of Array.from(table.rows)) {
1820
+ const target = currentRow.cells[Math.max(0, index)];
1821
+ const clone = (target ?? currentRow.cells[currentRow.cells.length - 1])?.cloneNode(false);
1822
+ if (!clone) continue;
1823
+ clone.innerHTML = "<p><br></p>";
1824
+ currentRow.insertBefore(clone, target?.nextSibling ?? null);
1825
+ }
1826
+ } else if (action === "del-row" && row && table.rows.length > 1) {
1827
+ row.remove();
1828
+ } else if (action === "del-col" && cell && table.rows[0]?.cells.length > 1) {
1829
+ const index = Array.from(row?.children ?? []).indexOf(cell);
1830
+ for (const currentRow of Array.from(table.rows)) {
1831
+ currentRow.cells[index]?.remove();
1832
+ }
1833
+ } else if (action === "toggle-header") {
1834
+ const thead = table.tHead;
1835
+ if (thead && thead.rows.length) {
1836
+ const headerRow = thead.rows[0];
1837
+ for (const headerCell of Array.from(headerRow.cells)) {
1838
+ const td = document.createElement("td");
1839
+ td.innerHTML = headerCell.innerHTML;
1840
+ headerCell.replaceWith(td);
1841
+ }
1842
+ const tbody = table.tBodies[0] ?? table.createTBody();
1843
+ tbody.insertBefore(headerRow, tbody.firstChild);
1844
+ thead.remove();
1845
+ } else {
1846
+ const firstRow = table.rows[0];
1847
+ if (firstRow) {
1848
+ for (const firstCell of Array.from(firstRow.cells)) {
1849
+ const th = document.createElement("th");
1850
+ th.setAttribute("scope", "col");
1851
+ th.innerHTML = firstCell.innerHTML;
1852
+ firstCell.replaceWith(th);
1853
+ }
1854
+ table.createTHead().appendChild(firstRow);
1855
+ }
1856
+ }
1857
+ } else if (action === "del-table") {
1858
+ const figure = table.closest("figure.fx-table");
1859
+ (figure ?? table).remove();
1860
+ }
1861
+ __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
1862
+ };
1863
+ handleImageFile_fn = async function(file) {
1864
+ if (!file.type.startsWith("image/")) {
1865
+ __privateMethod(this, _FxEditor_instances, error_fn).call(this, "O arquivo selecionado não é uma imagem.");
1866
+ return;
1867
+ }
1868
+ if (file.type === "image/svg+xml") {
1869
+ __privateMethod(this, _FxEditor_instances, error_fn).call(this, "SVG não é permitido por segurança. Use PNG, JPEG, WebP ou GIF.");
1870
+ return;
1871
+ }
1872
+ if (file.size > MAX_IMAGE_BYTES) {
1873
+ __privateMethod(this, _FxEditor_instances, error_fn).call(this, "Imagem muito grande (máximo 8 MB).");
1874
+ return;
1875
+ }
1876
+ let src = "";
1877
+ let alt = file.name.replace(/\.[a-z0-9]+$/i, "");
1878
+ try {
1879
+ if (this.uploadImage) {
1880
+ const uploaded = await this.uploadImage(file);
1881
+ if (typeof uploaded === "string") src = uploaded;
1882
+ else {
1883
+ src = uploaded.url;
1884
+ if (uploaded.alt) alt = uploaded.alt;
1885
+ }
1886
+ } else {
1887
+ src = await __privateMethod(this, _FxEditor_instances, fileToDataUrl_fn).call(this, file);
1888
+ }
1889
+ } catch {
1890
+ __privateMethod(this, _FxEditor_instances, error_fn).call(this, "Não foi possível processar a imagem.");
1891
+ return;
1892
+ }
1893
+ if (!src || !sanitizeMediaUrl(src, "img")) {
1894
+ __privateMethod(this, _FxEditor_instances, error_fn).call(this, "A imagem resultante não tem uma URL segura.");
1895
+ return;
1896
+ }
1897
+ __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
1898
+ __privateMethod(this, _FxEditor_instances, insertImage_fn).call(this, src, alt, "", "100", "center");
1899
+ };
1900
+ fileToDataUrl_fn = async function(file) {
1901
+ const dataUrl = await new Promise((resolve, reject) => {
1902
+ const reader = new FileReader();
1903
+ reader.onload = () => resolve(String(reader.result ?? ""));
1904
+ reader.onerror = () => reject(new Error("read-error"));
1905
+ reader.readAsDataURL(file);
1906
+ });
1907
+ if (file.type === "image/gif") return dataUrl;
1908
+ return new Promise((resolve) => {
1909
+ const image = new Image();
1910
+ image.onload = () => {
1911
+ const maxWidth = 1600;
1912
+ const scale = Math.min(1, maxWidth / (image.naturalWidth || maxWidth));
1913
+ if (scale >= 1) {
1914
+ resolve(dataUrl);
1915
+ return;
1916
+ }
1917
+ const canvas = document.createElement("canvas");
1918
+ canvas.width = Math.round((image.naturalWidth || maxWidth) * scale);
1919
+ canvas.height = Math.round((image.naturalHeight || maxWidth) * scale);
1920
+ const context = canvas.getContext("2d");
1921
+ if (!context) {
1922
+ resolve(dataUrl);
1923
+ return;
1924
+ }
1925
+ context.drawImage(image, 0, 0, canvas.width, canvas.height);
1926
+ resolve(canvas.toDataURL("image/webp", 0.85));
1927
+ };
1928
+ image.onerror = () => resolve(dataUrl);
1929
+ image.src = dataUrl;
1930
+ });
1931
+ };
1932
+ error_fn = function(message) {
1933
+ this.dispatchEvent(
1934
+ new CustomEvent("editor-error", {
1935
+ bubbles: true,
1936
+ composed: true,
1937
+ detail: { message }
1938
+ })
1939
+ );
1940
+ };
1941
+ _FxEditor.styles = `${FENIX_ICON_BASE_CSS}
1942
+ ${EDITOR_STYLES}`;
1943
+ let FxEditor = _FxEditor;
1944
+ function defineFxEditor() {
1945
+ return defineElement("fx-editor", FxEditor);
1946
+ }
1947
+ export {
1948
+ FxEditor,
1949
+ defineFxEditor
1950
+ };
1951
+ //# sourceMappingURL=editor.js.map