@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.
- package/demo/index.html +13 -6
- package/dist/index.js +143 -247
- package/dist/nile-rich-text-editor/nile-rich-text-editor.cjs.js +1 -1
- package/dist/nile-rich-text-editor/nile-rich-text-editor.cjs.js.map +1 -1
- package/dist/nile-rich-text-editor/nile-rich-text-editor.css.cjs.js +1 -1
- package/dist/nile-rich-text-editor/nile-rich-text-editor.css.cjs.js.map +1 -1
- package/dist/nile-rich-text-editor/nile-rich-text-editor.css.esm.js +68 -172
- package/dist/nile-rich-text-editor/nile-rich-text-editor.esm.js +1 -1
- package/dist/nile-rich-text-editor/nile-rte-select.cjs.js +1 -1
- package/dist/nile-rich-text-editor/nile-rte-select.cjs.js.map +1 -1
- package/dist/nile-rich-text-editor/nile-rte-select.esm.js +39 -39
- package/dist/nile-rich-text-editor/utils.cjs.js.map +1 -1
- package/dist/src/nile-rich-text-editor/nile-rich-text-editor.css.js +68 -172
- package/dist/src/nile-rich-text-editor/nile-rich-text-editor.css.js.map +1 -1
- package/dist/src/nile-rich-text-editor/nile-rich-text-editor.d.ts +0 -3
- package/dist/src/nile-rich-text-editor/nile-rich-text-editor.js +35 -125
- package/dist/src/nile-rich-text-editor/nile-rich-text-editor.js.map +1 -1
- package/dist/src/nile-rich-text-editor/nile-rte-select.js +62 -57
- package/dist/src/nile-rich-text-editor/nile-rte-select.js.map +1 -1
- package/dist/src/nile-rich-text-editor/rte-utils/content.d.ts +2 -0
- package/dist/src/nile-rich-text-editor/rte-utils/content.js +25 -0
- package/dist/src/nile-rich-text-editor/rte-utils/content.js.map +1 -0
- package/dist/src/nile-rich-text-editor/rte-utils/css.d.ts +1 -0
- package/dist/src/nile-rich-text-editor/rte-utils/css.js +9 -0
- package/dist/src/nile-rich-text-editor/rte-utils/css.js.map +1 -0
- package/dist/src/nile-rich-text-editor/rte-utils/dom.d.ts +2 -0
- package/dist/src/nile-rich-text-editor/rte-utils/dom.js +48 -0
- package/dist/src/nile-rich-text-editor/rte-utils/dom.js.map +1 -0
- package/dist/src/nile-rich-text-editor/rte-utils/formatting.d.ts +2 -0
- package/dist/src/nile-rich-text-editor/rte-utils/formatting.js +69 -0
- package/dist/src/nile-rich-text-editor/rte-utils/formatting.js.map +1 -0
- package/dist/src/nile-rich-text-editor/rte-utils/keys.d.ts +2 -0
- package/dist/src/nile-rich-text-editor/rte-utils/keys.js +38 -0
- package/dist/src/nile-rich-text-editor/rte-utils/keys.js.map +1 -0
- package/dist/src/nile-rich-text-editor/rte-utils/lists.d.ts +2 -0
- package/dist/src/nile-rich-text-editor/rte-utils/lists.js +28 -0
- package/dist/src/nile-rich-text-editor/rte-utils/lists.js.map +1 -0
- package/dist/src/nile-rich-text-editor/rte-utils/selection.d.ts +17 -0
- package/dist/src/nile-rich-text-editor/rte-utils/selection.js +39 -0
- package/dist/src/nile-rich-text-editor/rte-utils/selection.js.map +1 -0
- package/dist/src/nile-rich-text-editor/rte-utils/toolbar.d.ts +28 -0
- package/dist/src/nile-rich-text-editor/rte-utils/toolbar.js +161 -0
- package/dist/src/nile-rich-text-editor/rte-utils/toolbar.js.map +1 -0
- package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.d.ts +13 -0
- package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.js +119 -0
- package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.js.map +1 -0
- package/dist/src/nile-rich-text-editor/rte-utils/vars.d.ts +1 -0
- package/dist/src/nile-rich-text-editor/rte-utils/vars.js +14 -0
- package/dist/src/nile-rich-text-editor/rte-utils/vars.js.map +1 -0
- package/dist/src/nile-rich-text-editor/utils.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/nile-rich-text-editor/nile-rich-text-editor.css.ts +68 -172
- package/src/nile-rich-text-editor/nile-rich-text-editor.ts +74 -160
- package/src/nile-rich-text-editor/nile-rte-select.ts +178 -173
- package/src/nile-rich-text-editor/utils.ts +342 -341
- 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.
|
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
|
-
|
6
|
-
|
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
|
-
|
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
|
-
|
11
|
+
|
46
12
|
nile-rte-toolbar-item > nile-button::part(base) {
|
47
|
-
|
48
|
-
height:
|
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
|
-
|
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
|
-
|
158
|
-
|
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
|
-
|
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: '
|
37
|
-
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
|
-
|
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
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
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
|
-
|
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
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
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
|
-
|
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
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
const
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
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
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
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
|
|