leksy-editor 2.0.0 → 2.1.0
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/constant.js +52 -3
- package/index.js +1 -0
- package/package.json +1 -1
- package/tab.js +88 -7
package/constant.js
CHANGED
|
@@ -390,6 +390,7 @@ const CSS = {
|
|
|
390
390
|
overflow-y: auto;
|
|
391
391
|
z-index: 9999;
|
|
392
392
|
color: var(--text-color);
|
|
393
|
+
height: 100vh;
|
|
393
394
|
}
|
|
394
395
|
|
|
395
396
|
.tabs-container .tab-header {
|
|
@@ -401,14 +402,33 @@ const CSS = {
|
|
|
401
402
|
align-items: center;
|
|
402
403
|
border-bottom: 1px solid var(--base-white-dark);
|
|
403
404
|
}
|
|
404
|
-
.tabs-container .tab-header .tab-add-button
|
|
405
|
+
.tabs-container .tab-header .tab-add-button,
|
|
406
|
+
.tabs-container .tab-header .tab-expand-button {
|
|
405
407
|
cursor: pointer;
|
|
406
408
|
border: none;
|
|
407
409
|
background: transparent;
|
|
410
|
+
width: 24px;
|
|
411
|
+
height: 24px;
|
|
408
412
|
}
|
|
409
|
-
.tabs-container .tab-header .tab-
|
|
413
|
+
.tabs-container .tab-header .tab-expand-button {
|
|
414
|
+
display: none;
|
|
415
|
+
}
|
|
416
|
+
.tabs-container .tab-header .tab-add-button svg,
|
|
417
|
+
.tabs-container .tab-header .tab-expand-button svg {
|
|
410
418
|
fill: var(--text-color);
|
|
411
419
|
}
|
|
420
|
+
.tabs-container .tab-header .tab-expand-button svg {
|
|
421
|
+
margin-bottom: 4px;
|
|
422
|
+
rotate: 180deg;
|
|
423
|
+
}
|
|
424
|
+
.tabs-container .tab-header .tab-expand-button.show svg {
|
|
425
|
+
rotate: 0deg;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.tabs-container .tab-items {
|
|
429
|
+
overflow-y: auto;
|
|
430
|
+
transition: max-height 0.3s ease, opacity 0.2s ease;
|
|
431
|
+
}
|
|
412
432
|
|
|
413
433
|
.tabs-container .tab-items .tab-item {
|
|
414
434
|
padding: 8px;
|
|
@@ -515,6 +535,7 @@ const CSS = {
|
|
|
515
535
|
box-shadow: 0 2px 5px var(--shadow);
|
|
516
536
|
z-index: 10001;
|
|
517
537
|
max-height: 200px;
|
|
538
|
+
overflow-y: auto;
|
|
518
539
|
}
|
|
519
540
|
#leksy-editor-tab-context-menu .tab-submenu .tab-menu-item {
|
|
520
541
|
text-overflow: ellipsis;
|
|
@@ -529,7 +550,35 @@ const CSS = {
|
|
|
529
550
|
height: 14px;
|
|
530
551
|
margin-right: 4px;
|
|
531
552
|
}
|
|
532
|
-
|
|
553
|
+
`,
|
|
554
|
+
IFRAME_MEDIA_QUERY: `
|
|
555
|
+
@media only screen and (max-width: 991px) {
|
|
556
|
+
.tabs-container {
|
|
557
|
+
position: fixed;
|
|
558
|
+
outline: 1px solid grey;
|
|
559
|
+
width: 100%;
|
|
560
|
+
bottom: 0px;
|
|
561
|
+
border-radius: 16px 16px 0 0;
|
|
562
|
+
}
|
|
563
|
+
.tabs-container {
|
|
564
|
+
height: unset;
|
|
565
|
+
}
|
|
566
|
+
.tabs-container .tab-items {
|
|
567
|
+
max-height: 0;
|
|
568
|
+
opacity: 0;
|
|
569
|
+
}
|
|
570
|
+
.tabs-container .tab-header .tab-expand-button {
|
|
571
|
+
display: inline-block;
|
|
572
|
+
}
|
|
573
|
+
.tabs-container .tab-items.show {
|
|
574
|
+
max-height: 30vh;
|
|
575
|
+
opacity: 1;
|
|
576
|
+
}
|
|
577
|
+
.tabs-container .tab-items .tab-item .tab-dropdown {
|
|
578
|
+
visibility: visible;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
`,
|
|
533
582
|
}
|
|
534
583
|
|
|
535
584
|
const RESIZER_PLUGINS = [
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leksy-editor",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Leksy Editor is an alternative to traditional WYSIWYG editors, designed primarily for creating mail templates, blogs, and documents without any content manipulation.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"directories": {
|
package/tab.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { v4 as uuidv4 } from 'uuid';
|
|
2
2
|
import { SVG } from "./constant";
|
|
3
|
-
import { insertOutlinesItems } from './utilities';
|
|
3
|
+
import { destroyAnchorPopover, destroyImageResizer, destroyTableEditPlugin, insertOutlinesItems } from './utilities';
|
|
4
4
|
|
|
5
5
|
const initTabs = (core, options) => {
|
|
6
6
|
if (!options.showTabs) return;
|
|
@@ -133,7 +133,7 @@ const renderTabs = (core, options) => {
|
|
|
133
133
|
renderTabs(core, options);
|
|
134
134
|
}
|
|
135
135
|
switchTab(core, tab.tabId, options);
|
|
136
|
-
},
|
|
136
|
+
}, 250);
|
|
137
137
|
};
|
|
138
138
|
|
|
139
139
|
tabItem.ondblclick = () => {
|
|
@@ -210,8 +210,12 @@ const renderTabs = (core, options) => {
|
|
|
210
210
|
|
|
211
211
|
const tabListContainer = document.createElement('div');
|
|
212
212
|
tabListContainer.className = 'tab-items'
|
|
213
|
+
tabListContainer.addEventListener('scroll', () => {
|
|
214
|
+
core.state.tabItemsScrollHeight = tabListContainer.scrollTop;
|
|
215
|
+
});
|
|
213
216
|
renderLevel(core.state.tabs, tabListContainer, 0);
|
|
214
217
|
core.elements.tabsContainer.appendChild(tabListContainer);
|
|
218
|
+
tabListContainer.scrollTop = core.state.tabItemsScrollHeight || 0;
|
|
215
219
|
|
|
216
220
|
const tabHeader = document.createElement('span');
|
|
217
221
|
tabHeader.className = 'tab-header';
|
|
@@ -219,13 +223,32 @@ const renderTabs = (core, options) => {
|
|
|
219
223
|
const headerTitle = document.createElement('span');
|
|
220
224
|
headerTitle.innerHTML = "Tabs";
|
|
221
225
|
|
|
226
|
+
const rightDiv = document.createElement('div')
|
|
222
227
|
const addBtn = document.createElement('button');
|
|
223
228
|
addBtn.className = 'tab-add-button'
|
|
224
229
|
addBtn.type = 'button';
|
|
225
230
|
addBtn.innerHTML = SVG.PLUS;
|
|
226
231
|
addBtn.onclick = () => createTab(core, options);
|
|
232
|
+
|
|
233
|
+
const expandBtn = document.createElement('button');
|
|
234
|
+
expandBtn.className = 'tab-expand-button'
|
|
235
|
+
expandBtn.type = 'button';
|
|
236
|
+
expandBtn.innerHTML = SVG.ARROW_DOWN;
|
|
237
|
+
expandBtn.onclick = () => {
|
|
238
|
+
core.state.isTabExpandInResponsive = !core.state.isTabExpandInResponsive
|
|
239
|
+
expandBtn.classList.toggle('show')
|
|
240
|
+
tabListContainer.classList.toggle('show')
|
|
241
|
+
}
|
|
242
|
+
if (core.state.isTabExpandInResponsive) {
|
|
243
|
+
expandBtn.classList.add('show')
|
|
244
|
+
tabListContainer.classList.add('show')
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
rightDiv.appendChild(addBtn);
|
|
248
|
+
rightDiv.appendChild(expandBtn);
|
|
249
|
+
|
|
227
250
|
tabHeader.appendChild(headerTitle);
|
|
228
|
-
tabHeader.appendChild(
|
|
251
|
+
tabHeader.appendChild(rightDiv);
|
|
229
252
|
core.elements.tabsContainer.prepend(tabHeader);
|
|
230
253
|
}
|
|
231
254
|
|
|
@@ -235,8 +258,10 @@ const showContextMenu = (core, tab, event, level, options) => {
|
|
|
235
258
|
|
|
236
259
|
const menu = document.createElement('div');
|
|
237
260
|
menu.id = 'leksy-editor-tab-context-menu';
|
|
238
|
-
|
|
239
|
-
|
|
261
|
+
|
|
262
|
+
// temporary visibility to measure
|
|
263
|
+
menu.style.visibility = 'hidden';
|
|
264
|
+
menu.style.display = 'block';
|
|
240
265
|
|
|
241
266
|
const closeMenu = (e) => {
|
|
242
267
|
if (!menu.contains(e.target)) {
|
|
@@ -281,17 +306,43 @@ const showContextMenu = (core, tab, event, level, options) => {
|
|
|
281
306
|
item.onmouseenter = () => {
|
|
282
307
|
submenu = document.createElement('div');
|
|
283
308
|
submenu.className = 'tab-submenu';
|
|
309
|
+
submenu.style.position = 'absolute';
|
|
310
|
+
submenu.style.left = '100%';
|
|
311
|
+
submenu.style.top = '0';
|
|
312
|
+
submenu.style.visibility = 'hidden';
|
|
284
313
|
|
|
285
314
|
items.forEach(subItem => {
|
|
286
315
|
const subOption = createOption(subItem.tabTitle, SVG.TABLE_OF_CONTENT, () => {
|
|
287
|
-
moveTabInto(core, tab.tabId, subItem.tabId);
|
|
316
|
+
moveTabInto(core, tab.tabId, subItem.tabId, options);
|
|
288
317
|
});
|
|
318
|
+
|
|
289
319
|
if (subItem.level > 0) {
|
|
290
320
|
subOption.style.paddingLeft = `${16 + subItem.level * 10}px`;
|
|
291
321
|
}
|
|
322
|
+
|
|
292
323
|
submenu.appendChild(subOption);
|
|
293
324
|
});
|
|
325
|
+
|
|
294
326
|
item.appendChild(submenu);
|
|
327
|
+
|
|
328
|
+
const rect = submenu.getBoundingClientRect();
|
|
329
|
+
const itemRect = item.getBoundingClientRect();
|
|
330
|
+
|
|
331
|
+
const viewportWidth = core.elements.iframeWindow.documentElement.clientWidth;
|
|
332
|
+
const viewportHeight = core.elements.iframeWindow.documentElement.clientHeight;
|
|
333
|
+
|
|
334
|
+
// if no space on right → open left
|
|
335
|
+
if (rect.right > viewportWidth) {
|
|
336
|
+
submenu.style.left = 'auto';
|
|
337
|
+
submenu.style.right = '100%';
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// if no space bottom → shift up
|
|
341
|
+
if (rect.bottom > viewportHeight) {
|
|
342
|
+
submenu.style.top = `${viewportHeight - itemRect.top - rect.height}px`;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
submenu.style.visibility = 'visible';
|
|
295
346
|
};
|
|
296
347
|
|
|
297
348
|
item.onmouseleave = () => {
|
|
@@ -341,7 +392,7 @@ const showContextMenu = (core, tab, event, level, options) => {
|
|
|
341
392
|
menu.appendChild(createOption('Move out', SVG.DELETE, () => outdentTab(core, tab.tabId, options)));
|
|
342
393
|
}
|
|
343
394
|
|
|
344
|
-
menu.appendChild(createOption(tab.showOutlines ? 'Hide
|
|
395
|
+
menu.appendChild(createOption(tab.showOutlines ? 'Hide outlines' : 'Show outlines', SVG.LIST_BULLETS, () => {
|
|
345
396
|
tab.showOutlines = !tab.showOutlines;
|
|
346
397
|
renderTabs(core, options);
|
|
347
398
|
if (tab.showOutlines) switchTab(core, tab.tabId, options);
|
|
@@ -349,6 +400,32 @@ const showContextMenu = (core, tab, event, level, options) => {
|
|
|
349
400
|
|
|
350
401
|
core.elements.iframeWindow.body.appendChild(menu);
|
|
351
402
|
core.elements.iframeWindow.addEventListener('click', closeMenu);
|
|
403
|
+
|
|
404
|
+
const rect = menu.getBoundingClientRect();
|
|
405
|
+
const menuWidth = rect.width;
|
|
406
|
+
const menuHeight = rect.height;
|
|
407
|
+
|
|
408
|
+
const viewportWidth = core.elements.iframeWindow.documentElement.clientWidth;
|
|
409
|
+
const viewportHeight = core.elements.iframeWindow.documentElement.clientHeight;
|
|
410
|
+
|
|
411
|
+
let left = event.clientX;
|
|
412
|
+
let top = event.clientY;
|
|
413
|
+
|
|
414
|
+
// if not enough space on right → open to left
|
|
415
|
+
if (left + menuWidth > viewportWidth) {
|
|
416
|
+
left = event.clientX - menuWidth;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// if not enough space on bottom → open above
|
|
420
|
+
if (top + menuHeight > viewportHeight) {
|
|
421
|
+
top = event.clientY - menuHeight;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
menu.style.left = `${left}px`;
|
|
425
|
+
menu.style.top = `${top}px`;
|
|
426
|
+
menu.style.visibility = 'visible';
|
|
427
|
+
|
|
428
|
+
|
|
352
429
|
};
|
|
353
430
|
|
|
354
431
|
const createTab = (core, options) => {
|
|
@@ -368,6 +445,10 @@ const createTab = (core, options) => {
|
|
|
368
445
|
const switchTab = (core, tabId, options) => {
|
|
369
446
|
if (core.state.currentTabId === tabId) return;
|
|
370
447
|
|
|
448
|
+
destroyImageResizer(options, core)
|
|
449
|
+
destroyTableEditPlugin(options, core)
|
|
450
|
+
destroyAnchorPopover(core)
|
|
451
|
+
|
|
371
452
|
const currentTab = findTab(core.state.tabs, core.state.currentTabId);
|
|
372
453
|
if (currentTab) {
|
|
373
454
|
currentTab.content = core.elements.editor.innerHTML;
|