@aquera/nile-elements 0.1.67-beta-1.4 → 0.1.67-beta-1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/demo/index.html +13 -6
  2. package/dist/index.js +143 -247
  3. package/dist/nile-rich-text-editor/nile-rich-text-editor.cjs.js +1 -1
  4. package/dist/nile-rich-text-editor/nile-rich-text-editor.cjs.js.map +1 -1
  5. package/dist/nile-rich-text-editor/nile-rich-text-editor.css.cjs.js +1 -1
  6. package/dist/nile-rich-text-editor/nile-rich-text-editor.css.cjs.js.map +1 -1
  7. package/dist/nile-rich-text-editor/nile-rich-text-editor.css.esm.js +68 -172
  8. package/dist/nile-rich-text-editor/nile-rich-text-editor.esm.js +1 -1
  9. package/dist/nile-rich-text-editor/nile-rte-select.cjs.js +1 -1
  10. package/dist/nile-rich-text-editor/nile-rte-select.cjs.js.map +1 -1
  11. package/dist/nile-rich-text-editor/nile-rte-select.esm.js +39 -39
  12. package/dist/nile-rich-text-editor/utils.cjs.js.map +1 -1
  13. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.css.js +68 -172
  14. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.css.js.map +1 -1
  15. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.d.ts +0 -3
  16. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.js +35 -125
  17. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.js.map +1 -1
  18. package/dist/src/nile-rich-text-editor/nile-rte-select.js +62 -57
  19. package/dist/src/nile-rich-text-editor/nile-rte-select.js.map +1 -1
  20. package/dist/src/nile-rich-text-editor/rte-utils/content.d.ts +2 -0
  21. package/dist/src/nile-rich-text-editor/rte-utils/content.js +25 -0
  22. package/dist/src/nile-rich-text-editor/rte-utils/content.js.map +1 -0
  23. package/dist/src/nile-rich-text-editor/rte-utils/css.d.ts +1 -0
  24. package/dist/src/nile-rich-text-editor/rte-utils/css.js +9 -0
  25. package/dist/src/nile-rich-text-editor/rte-utils/css.js.map +1 -0
  26. package/dist/src/nile-rich-text-editor/rte-utils/dom.d.ts +2 -0
  27. package/dist/src/nile-rich-text-editor/rte-utils/dom.js +48 -0
  28. package/dist/src/nile-rich-text-editor/rte-utils/dom.js.map +1 -0
  29. package/dist/src/nile-rich-text-editor/rte-utils/formatting.d.ts +2 -0
  30. package/dist/src/nile-rich-text-editor/rte-utils/formatting.js +69 -0
  31. package/dist/src/nile-rich-text-editor/rte-utils/formatting.js.map +1 -0
  32. package/dist/src/nile-rich-text-editor/rte-utils/keys.d.ts +2 -0
  33. package/dist/src/nile-rich-text-editor/rte-utils/keys.js +38 -0
  34. package/dist/src/nile-rich-text-editor/rte-utils/keys.js.map +1 -0
  35. package/dist/src/nile-rich-text-editor/rte-utils/lists.d.ts +2 -0
  36. package/dist/src/nile-rich-text-editor/rte-utils/lists.js +28 -0
  37. package/dist/src/nile-rich-text-editor/rte-utils/lists.js.map +1 -0
  38. package/dist/src/nile-rich-text-editor/rte-utils/selection.d.ts +17 -0
  39. package/dist/src/nile-rich-text-editor/rte-utils/selection.js +39 -0
  40. package/dist/src/nile-rich-text-editor/rte-utils/selection.js.map +1 -0
  41. package/dist/src/nile-rich-text-editor/rte-utils/toolbar.d.ts +28 -0
  42. package/dist/src/nile-rich-text-editor/rte-utils/toolbar.js +161 -0
  43. package/dist/src/nile-rich-text-editor/rte-utils/toolbar.js.map +1 -0
  44. package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.d.ts +13 -0
  45. package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.js +119 -0
  46. package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.js.map +1 -0
  47. package/dist/src/nile-rich-text-editor/rte-utils/vars.d.ts +1 -0
  48. package/dist/src/nile-rich-text-editor/rte-utils/vars.js +14 -0
  49. package/dist/src/nile-rich-text-editor/rte-utils/vars.js.map +1 -0
  50. package/dist/src/nile-rich-text-editor/utils.js.map +1 -1
  51. package/dist/tsconfig.tsbuildinfo +1 -1
  52. package/package.json +1 -1
  53. package/src/nile-rich-text-editor/nile-rich-text-editor.css.ts +68 -172
  54. package/src/nile-rich-text-editor/nile-rich-text-editor.ts +74 -160
  55. package/src/nile-rich-text-editor/nile-rte-select.ts +178 -173
  56. package/src/nile-rich-text-editor/utils.ts +342 -341
  57. package/vscode-html-custom-data.json +1 -1
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Webcomponent nile-elements following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "nile-elements",
6
- "version": "0.1.67-beta-1.4",
6
+ "version": "0.1.67-beta-1.6",
7
7
  "main": "dist/src/index.js",
8
8
  "type": "module",
9
9
  "module": "dist/src/index.js",
@@ -2,215 +2,111 @@
2
2
  import { css } from 'lit';
3
3
 
4
4
  export const styles = css`
5
- /* ---- SAFER RESET INSIDE THE EDITOR -------------------------------------- */
6
- .editor * {
7
- all: revert; /* keep your reset… */
8
- box-sizing: border-box; /* …but preserve sane layout */
9
- overflow-wrap: anywhere; /* break long words/URLs */
10
- word-break: break-word;
5
+ .editor * {
6
+ all: revert;
11
7
  }
12
8
 
13
- /* Let component & editor shrink inside flex/grid parents */
14
- nile-rich-text-editor,
15
- .editor {
16
- display: block;
17
- min-width: 0;
18
- max-width: 100%;
19
- font-family: inherit;
20
- }
21
-
22
- /* ---- TOOLBAR ------------------------------------------------------------- */
23
- nile-rte-toolbar,
24
- .toolbar {
25
- display: flex;
26
- flex-wrap: wrap; /* allow wrapping to next row */
27
- align-items: center;
28
- gap: 8px;
29
- padding: 8px;
30
- border: 1px solid #e5e7eb;
31
- border-bottom: none;
32
- border-radius: 8px 8px 0 0;
33
- background: #fff;
34
- box-sizing: border-box;
35
- width: 100%;
36
- }
37
-
38
- /* allow children to shrink instead of forcing overflow */
39
- nile-rte-toolbar > *,
40
- .toolbar > * {
41
- flex: 0 1 auto;
42
- min-width: 0;
43
- }
9
+ nile-rich-text-editor { position: relative; display: block; font-family: inherit; }
44
10
 
45
- /* buttons */
11
+
46
12
  nile-rte-toolbar-item > nile-button::part(base) {
47
- width: 32px;
48
- height: 32px;
49
- padding: 0 6px;
13
+
14
+ width:32px; height:32px; padding:0px 6px;
50
15
  border: none;
51
16
  }
52
-
53
- nile-rte-toolbar-item > button,
54
- .toolbar button,
55
- nile-rte-toolbar button {
56
- border: 1px solid #e5e7eb;
57
- background: #fff;
58
- border-radius: 6px;
59
- cursor: pointer;
60
- }
61
-
62
- nile-rte-toolbar-item > button nile-icon { pointer-events: none; }
63
-
64
- nile-rte-toolbar-item > button.active {
65
- border-color: #2563eb;
66
- background: #eff6ff;
67
- }
68
-
69
- /* selects should be able to shrink on small screens */
70
- nile-rte-select select {
71
- height: 32px;
72
- border: 1px solid #e5e7eb;
73
- border-radius: 6px;
74
- background: #fff;
75
- min-width: 0;
76
- max-width: 100%;
77
- }
78
-
79
- /* color input */
80
- nile-rte-color input[type="color"] {
81
- height: 32px;
82
- width: 36px;
83
- border: 1px solid #e5e7eb;
84
- padding: 0;
85
- border-radius: 6px;
86
- background: #fff;
87
- }
88
-
89
- nile-rte-divider {
90
- width: 1px;
91
- height: 20px;
92
- background: #e5e7eb;
93
- display: inline-block;
94
- margin: 0 4px;
95
- }
96
-
97
- /* ---- EDITOR AREA --------------------------------------------------------- */
98
- .editor {
99
- min-height: 160px;
100
- padding: 12px;
101
- border: 1px solid #e5e7eb;
102
- border-radius: 0 0 8px 8px;
103
- background: #fff;
104
- outline: none;
105
- white-space: pre-wrap;
106
- tab-size: 4;
107
- -moz-tab-size: 4;
108
- overflow-wrap: anywhere;
109
- box-sizing: border-box;
110
- width: 100%;
111
- }
112
-
113
17
 
114
- .editor p { margin: 1em 0; }
115
- .editor h1, .editor h2, .editor h3, .editor h4, .editor h5, .editor h6 {
116
- margin-left: 0;
117
- margin-right: 0;
118
- font-weight: bold;
119
- }
120
- .editor h1 { font-size: 2em; margin: 0.67em 0; }
121
- .editor h2 { font-size: 1.5em; margin: 0.83em 0; }
122
- .editor h3 { font-size: 1.17em; margin: 1em 0; }
123
- .editor h4 { font-size: 1em; margin: 1.33em 0; }
124
- .editor h5 { font-size: 0.83em; margin: 1.67em 0; }
125
- .editor h6 { font-size: 0.67em; margin: 2.33em 0; }
126
-
127
- /* Keep typical wide content inside the box */
128
- .editor img,
129
- .editor svg,
130
- .editor table,
131
- .editor pre,
132
- .editor code,
133
- .editor blockquote {
134
- max-width: 100%;
135
- box-sizing: border-box;
136
- }
137
-
138
- /* Make <pre> wrap on small screens */
139
- .editor pre {
140
- white-space: pre-wrap;
141
- word-break: break-word;
142
- }
18
+
143
19
 
144
- /* Long links shouldn’t push layout */
145
- .editor a { word-break: break-all; }
146
-
147
- /* ---- PREVIEW ------------------------------------------------------------- */
148
- nile-rte-preview {
149
- display: block;
150
- margin-top: 10px;
151
- padding: 10px;
152
- border: 1px dashed #cbd5e1;
153
- border-radius: 8px;
154
- background: #fafafa;
155
- }
156
20
 
157
- /* ---- COLOR TRIGGER (unchanged) ------------------------------------------ */
158
- .rte-color-trigger {
21
+ .toolbar, nile-rte-toolbar {
22
+ display:flex; align-items:center; gap:6px; padding:8px;
23
+ border:1px solid #e5e7eb; border-bottom:none; border-radius:8px 8px 0 0; background:#fff;
24
+ }
25
+
26
+ nile-rte-toolbar-item > button, .toolbar button, nile-rte-toolbar button {
27
+ border:1px solid #e5e7eb; background:#fff; border-radius:6px;
28
+ cursor:pointer;
29
+ }
30
+
31
+
32
+ /* Ensure clicks hit the button (not nested icon internals) */
33
+ nile-rte-toolbar-item > button nile-icon { pointer-events:none; }
34
+
35
+ nile-rte-toolbar-item > button.active { border-color:#2563eb; background:#eff6ff; }
36
+ nile-rte-select select { height:32px; border:1px solid #e5e7eb; border-radius:6px; background:#fff; }
37
+ nile-rte-color input[type="color"] { height:32px; width:36px; border:1px solid #e5e7eb; padding:0; border-radius:6px; background:#fff; }
38
+ nile-rte-divider { width:1px; height:20px; background:#e5e7eb; display:inline-block; margin:0 4px; }
39
+
40
+ .editor p { margin:1em 0; }
41
+ .editor h1 { font-size:2em, all: revert; display: block;
42
+ font-size: 2em;
43
+ margin-top: 0.67em;
44
+ margin-bottom: 0.67em;
45
+ margin-left: 0;
46
+ margin-right: 0;
47
+ font-weight: bold; }
48
+ .editor h2 { all: revert; display: block;
49
+ font-size: 1.5em;
50
+ margin-top: 0.83em;
51
+ margin-bottom: 0.83em;
52
+ margin-left: 0;
53
+ margin-right: 0;
54
+ font-weight: bold;}
55
+ .editor h3 { font-size:1.17em }
56
+ .editor h4 { font-size:1em }
57
+ .editor h5 { font-size:0.83em }
58
+ .editor h6 { font-size:0.67em }
59
+
60
+ .editor { min-height:160px; padding:12px; border:1px solid #e5e7eb; border-radius:0 0 8px 8px; background:#fff; outline:none; white-space: pre-wrap;
61
+ tab-size: 4;
62
+ -moz-tab-size: 4; }
63
+ nile-rte-preview { display:block; margin-top:10px; padding:10px; border:1px dashed #cbd5e1; border-radius:8px; background:#fafafa; }
64
+
65
+ .rte-color-trigger {
159
66
  display: inline-flex;
160
67
  align-items: center;
161
68
  justify-content: center;
162
- height: 28px;
163
- padding: 0 8px;
164
- border: 1px solid var(--nile-color-border, #d9d9d9);
69
+ /* border: 1px solid var(--nile-color-border, #d9d9d9); */
165
70
  border-radius: 6px;
166
71
  background: #fff;
167
72
  cursor: pointer;
73
+ border:none;
74
+
75
+
76
+ }
77
+ nile-button.rte-color-trigger::part(base){
78
+ width:32px; height:32px; padding:0px 6px;
168
79
  }
169
80
  .rte-color-trigger .glyph-stack {
170
- display: grid;
171
- grid-auto-rows: max-content;
81
+ display: grid; /* stack vertically */
82
+ grid-auto-rows: max-content;
172
83
  align-items: center;
173
84
  justify-items: center;
174
85
  line-height: 1;
175
86
  }
87
+
176
88
  .rte-color-trigger .glyph {
177
89
  font-size: 14px;
178
90
  line-height: 1;
179
- margin-bottom: 2px;
91
+ margin-bottom: 2px;
180
92
  }
93
+
181
94
  .rte-color-trigger .underline {
182
95
  width: 18px;
183
96
  height: 3px;
184
97
  border-radius: 2px;
185
- background: currentColor;
98
+ background: currentColor;
186
99
  }
100
+
101
+
187
102
  .rte-color-trigger .swatch-box {
188
103
  width: 18px;
189
104
  height: 16px;
190
105
  border-radius: 4px;
191
106
  border: 1px solid rgba(0,0,0,0.35);
192
- background: currentColor;
193
- }
194
-
195
- /* ---- RESPONSIVE TWEAKS --------------------------------------------------- */
196
- @media (max-width: 900px) {
197
- nile-rte-toolbar { gap: 6px; padding: 6px; }
198
- nile-rte-select select { max-width: 160px; }
199
- }
200
-
201
- @media (max-width: 600px) {
202
- nile-rte-toolbar { gap: 4px; }
203
- nile-rte-select select { max-width: 120px; }
204
- /* optional fallback if wrapping still feels tight */
205
- /* nile-rte-toolbar { overflow-x: auto; } */
107
+ background: currentColor; /* overridden via JS */
206
108
  }
207
109
 
208
- @media (max-width: 420px) {
209
- nile-rte-select select { max-width: 100px; }
210
- nile-rte-divider { display: none; }
211
- }
212
-
213
-
214
110
  `;
215
111
 
216
112
  export default [styles];
@@ -33,8 +33,8 @@ const DEFAULT_ICONS: Record<string, string> = {
33
33
  center: 'format_align_middle',
34
34
  right: 'format_align_right',
35
35
  justify: 'format_align_justify',
36
- ul: 'nile-ul',
37
- ol: 'nile-ol',
36
+ ul: 'format_list_bulleted',
37
+ ol: 'format_list_numbered',
38
38
  clear: 'error',
39
39
  };
40
40
 
@@ -177,60 +177,6 @@ private bgSwatchEl: HTMLElement | null = null;
177
177
  this.ensureAtLeastOneParagraph();
178
178
  }
179
179
 
180
- private onPaste = (e: ClipboardEvent) => {
181
- const html = e.clipboardData?.getData('text/html');
182
- if (!html) return; // let plain text/default paste happen
183
-
184
- e.preventDefault();
185
- this.focusAndRestore();
186
-
187
- const div = document.createElement('div');
188
- div.innerHTML = html;
189
-
190
- // strip layout-y attrs & styles
191
- const walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT);
192
- const layoutProps = new Set([
193
- 'width','height','max-width','min-width','margin','padding','position','left','right','top','bottom',
194
- 'float','display','border','line-height','white-space'
195
- ]);
196
-
197
- while (walker.nextNode()) {
198
- const el = walker.currentNode as HTMLElement;
199
- // remove HTML width/height attributes that cause fixed sizing
200
- el.removeAttribute('width');
201
- el.removeAttribute('height');
202
-
203
- // prune style properties if present
204
- if (el.hasAttribute('style')) {
205
- const style = el.getAttribute('style') || '';
206
- const kept = style.split(';').map(s => s.trim()).filter(Boolean).filter(rule => {
207
- const prop = rule.split(':')[0]?.trim().toLowerCase();
208
- return prop && !layoutProps.has(prop);
209
- });
210
- if (kept.length) el.setAttribute('style', kept.join('; ')); else el.removeAttribute('style');
211
- }
212
- }
213
-
214
- // insert sanitized fragment at the selection
215
- const sel = window.getSelection();
216
- if (sel && sel.rangeCount) {
217
- const range = sel.getRangeAt(0);
218
- range.deleteContents();
219
-
220
- const frag = document.createDocumentFragment();
221
- while (div.firstChild) frag.appendChild(div.firstChild);
222
- range.insertNode(frag);
223
-
224
- // move caret after paste
225
- sel.removeAllRanges();
226
- sel.addRange(range);
227
- }
228
-
229
- this.ensureAtLeastOneParagraph();
230
- this.updateContent();
231
- this.updateToolbarState();
232
- };
233
-
234
180
  private wireEditor() {
235
181
  this.editorEl.addEventListener('input', () => {
236
182
  this.ensureAtLeastOneParagraph();
@@ -238,9 +184,7 @@ private bgSwatchEl: HTMLElement | null = null;
238
184
  });
239
185
  this.editorEl.addEventListener('mouseup', () => this.saveSelection());
240
186
  this.editorEl.addEventListener('keyup', () => this.saveSelection());
241
- this.editorEl.addEventListener('keydown', this.onEditorKeydown);
242
- this.editorEl.addEventListener('paste', this.onPaste);
243
-
187
+ this.editorEl.addEventListener('keydown', this.onEditorKeydown);
244
188
  }
245
189
 
246
190
 
@@ -411,28 +355,28 @@ private bgSwatchEl: HTMLElement | null = null;
411
355
  input.title = label;
412
356
  input.value = value;
413
357
 
414
- // Build a custom trigger that shows the current color
415
- let trigger = child.querySelector(':scope > button.rte-color-trigger') as HTMLButtonElement | null;
358
+ let trigger = child.querySelector(':scope > nile-button') as HTMLElement | null;
416
359
  if (!trigger) {
417
- trigger = document.createElement('button');
418
- trigger.type = 'button';
419
- trigger.className = 'rte-color-trigger';
420
- trigger.setAttribute('aria-label', label);
421
-
360
+ const nb = document.createElement('nile-button');
361
+ (nb as any).variant = 'ghost';
362
+ nb.className = 'rte-color-trigger';
363
+ nb.setAttribute('aria-label', label);
364
+
422
365
  if (mode === 'background') {
423
- trigger.innerHTML = `
424
- <span class="swatch-box" aria-hidden="true"></span>
425
- `;
366
+ nb.innerHTML = `<span class="swatch-box" aria-hidden="true"></span>`;
426
367
  } else {
427
- trigger.innerHTML = `
428
- <span class="glyph-stack" aria-hidden="true">
429
- <span class="glyph">A</span>
430
- <span class="underline"></span>
431
- </span>
368
+ nb.innerHTML = `
369
+ <span class="glyph-stack" aria-hidden="true">
370
+ <span class="glyph">A</span>
371
+ <span class="underline"></span>
372
+ </span>
432
373
  `;
433
374
  }
434
- child.appendChild(trigger);
375
+
376
+ child.appendChild(nb);
377
+ trigger = nb;
435
378
  }
379
+
436
380
 
437
381
  // Cache swatch elements to update later
438
382
  const underline = trigger.querySelector('.underline') as HTMLElement | null;
@@ -724,93 +668,63 @@ private ensureAtLeastOneParagraph() {
724
668
  this.updateContent();
725
669
  }
726
670
 
727
- // replace your existing updateContent() with this
728
- private updateContent() {
729
- if (!this.editorEl) return;
730
- this.ensureAtLeastOneParagraph();
731
-
732
- const clone = this.editorEl.cloneNode(true) as HTMLElement;
733
-
734
- const origWalker = document.createTreeWalker(this.editorEl, NodeFilter.SHOW_ELEMENT);
735
- const cloneWalker = document.createTreeWalker(clone, NodeFilter.SHOW_ELEMENT);
736
-
737
- while (origWalker.nextNode() && cloneWalker.nextNode()) {
738
- const origEl = origWalker.currentNode as HTMLElement;
739
- const cloneEl = cloneWalker.currentNode as HTMLElement;
740
-
741
- // start clean
742
- cloneEl.removeAttribute('style');
743
-
744
- // rely on semantics for these; no inline styles
745
- if (['B','STRONG','I','EM','U','H1','H2','H3','H4','H5','H6'].includes(cloneEl.tagName)) {
746
- continue;
671
+ private updateContent() {
672
+ if (!this.editorEl) return;
673
+ this.ensureAtLeastOneParagraph();
674
+
675
+
676
+ const clone = this.editorEl.cloneNode(true) as HTMLElement;
677
+
678
+
679
+ const origWalker = document.createTreeWalker(this.editorEl, NodeFilter.SHOW_ELEMENT);
680
+ const cloneWalker = document.createTreeWalker(clone, NodeFilter.SHOW_ELEMENT);
681
+
682
+
683
+ const importantProps = [
684
+ 'font-weight',
685
+ 'font-style',
686
+ 'text-decoration',
687
+ 'color',
688
+ 'background-color',
689
+ 'font-size',
690
+ 'font-family',
691
+ 'text-align',
692
+ 'line-height',
693
+ 'letter-spacing',
694
+ 'white-space',
695
+ 'vertical-align'
696
+ ];
697
+
698
+ while (origWalker.nextNode() && cloneWalker.nextNode()) {
699
+ const origEl = origWalker.currentNode as HTMLElement;
700
+ const cloneEl = cloneWalker.currentNode as HTMLElement;
701
+ const computed = window.getComputedStyle(origEl);
702
+
703
+
704
+ const cssText = importantProps
705
+ .map(prop => `${prop}:${computed.getPropertyValue(prop)}`)
706
+ .join(';');
707
+
708
+
709
+ if (cssText.trim()) {
710
+ cloneEl.setAttribute('style', cssText);
711
+ }
747
712
  }
748
-
749
- const cssText = this.collectMinimalInline(origEl);
750
- if (cssText) cloneEl.setAttribute('style', cssText);
751
- }
752
-
753
- this.content = clone.innerHTML;
754
- if (this.previewEl) this.previewEl.innerHTML = this.content;
755
-
756
- this.dispatchEvent(new CustomEvent('content-changed', {
757
- detail: { content: this.content },
758
- bubbles: true,
759
- composed: true
760
- }));
761
- }
762
- private collectMinimalInline(el: HTMLElement): string {
763
- const cs = getComputedStyle(el);
764
- const ps = el.parentElement ? getComputedStyle(el.parentElement) : null;
765
-
766
- const out: string[] = [];
767
- const push = (prop: string, val?: string) => { if (val) out.push(`${prop}:${val}`); };
768
-
769
- // 1) text-align on block-ish containers (only if changed)
770
- if (['P','DIV','LI','TD','TH','BLOCKQUOTE','H1','H2','H3','H4','H5','H6'].includes(el.tagName)) {
771
- const ta = cs.textAlign;
772
- const pta = ps?.textAlign || 'start';
773
- if (ta !== pta && ta !== 'start') push('text-align', ta);
774
- }
775
-
776
- // 2) color (only if different from parent)
777
- if (!ps || cs.color !== ps.color) push('color', cs.color);
778
-
779
- // 3) background-color (only if not transparent)
780
- const bg = cs.backgroundColor;
781
- const isTransparent = /transparent|rgba\(\s*0\s*,\s*0\s*,\s*0\s*,\s*0\s*\)/i.test(bg);
782
- if (!isTransparent) push('background-color', bg);
783
-
784
- // 4) font-family (only if different from parent)
785
- const ff = this.normalizeFontFamily(cs.fontFamily);
786
- const pff = this.normalizeFontFamily(ps?.fontFamily || '');
787
- if (ff && ff !== pff) push('font-family', cs.fontFamily);
788
-
789
- // 5) font-size (only if explicitly set / typical inline span use)
790
- if (el.tagName === 'SPAN' || (el as HTMLElement).style.fontSize) {
791
- const fs = cs.fontSize;
792
- const pfs = ps?.fontSize;
793
- if (!pfs || fs !== pfs) push('font-size', fs);
794
- }
795
-
796
- // 6) list-style-type on UL/OL (only if non-default)
797
- if (el.tagName === 'UL' || el.tagName === 'OL') {
798
- const lst = cs.listStyleType;
799
- const def = el.tagName === 'UL' ? 'disc' : 'decimal';
800
- if (lst && lst !== def) push('list-style-type', lst);
713
+
714
+
715
+ this.content = clone.innerHTML;
716
+
717
+
718
+ if (this.previewEl) this.previewEl.innerHTML = this.content;
719
+
720
+
721
+ this.dispatchEvent(new CustomEvent('content-changed', {
722
+ detail: { content: this.content },
723
+ bubbles: true,
724
+ composed: true
725
+ }));
801
726
  }
802
-
803
- // 7) text-decoration-line (keep only if not the default and not coming from <u>)
804
- const tdl = cs.textDecorationLine;
805
- if (tdl && tdl !== 'none' && el.tagName !== 'U') push('text-decoration-line', tdl);
806
-
807
- return out.join(';');
808
- }
809
-
810
- private normalizeFontFamily(ff: string) {
811
- return (ff || '').replace(/["']/g, '').split(',')[0].trim().toLowerCase();
812
- }
813
-
727
+
814
728
 
815
729
 
816
730