@lukso/web-components 1.155.1 → 1.156.1
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/dist/components/index.cjs +4 -4
- package/dist/components/index.js +4 -4
- package/dist/components/lukso-button/index.cjs +3 -3
- package/dist/components/lukso-button/index.js +3 -3
- package/dist/components/lukso-card/index.cjs +6 -6
- package/dist/components/lukso-card/index.js +6 -6
- package/dist/components/lukso-checkbox/index.cjs +3 -3
- package/dist/components/lukso-checkbox/index.js +3 -3
- package/dist/components/lukso-collapse/index.cjs +3 -3
- package/dist/components/lukso-collapse/index.js +3 -3
- package/dist/components/lukso-color-picker/index.cjs +4 -4
- package/dist/components/lukso-color-picker/index.js +4 -4
- package/dist/components/lukso-dropdown/index.cjs +4 -4
- package/dist/components/lukso-dropdown/index.js +4 -4
- package/dist/components/lukso-dropdown-option/index.cjs +2 -2
- package/dist/components/lukso-dropdown-option/index.js +2 -2
- package/dist/components/lukso-footer/index.cjs +2 -2
- package/dist/components/lukso-footer/index.js +2 -2
- package/dist/components/lukso-icon/icons/logo-hyperlane-mono.d.ts +3 -0
- package/dist/components/lukso-icon/icons/logo-hyperlane-mono.d.ts.map +1 -0
- package/dist/components/lukso-icon/icons/logo-hyperlane.d.ts +3 -0
- package/dist/components/lukso-icon/icons/logo-hyperlane.d.ts.map +1 -0
- package/dist/components/lukso-icon/icons/token-create.d.ts +3 -0
- package/dist/components/lukso-icon/icons/token-create.d.ts.map +1 -0
- package/dist/components/lukso-icon/index.cjs +136 -16
- package/dist/components/lukso-icon/index.d.ts +4 -4
- package/dist/components/lukso-icon/index.d.ts.map +1 -1
- package/dist/components/lukso-icon/index.js +136 -16
- package/dist/components/lukso-icon/lukso-icon.stories.d.ts +15 -1
- package/dist/components/lukso-icon/lukso-icon.stories.d.ts.map +1 -1
- package/dist/components/lukso-image/index.cjs +4 -4
- package/dist/components/lukso-image/index.js +4 -4
- package/dist/components/lukso-input/index.cjs +3 -3
- package/dist/components/lukso-input/index.js +3 -3
- package/dist/components/lukso-markdown/index.cjs +11 -5
- package/dist/components/lukso-markdown/index.d.ts +4 -2
- package/dist/components/lukso-markdown/index.d.ts.map +1 -1
- package/dist/components/lukso-markdown/index.js +11 -5
- package/dist/components/lukso-markdown/lukso-markdown.stories.d.ts +3 -0
- package/dist/components/lukso-markdown/lukso-markdown.stories.d.ts.map +1 -1
- package/dist/components/lukso-markdown-editor/index.cjs +512 -114
- package/dist/components/lukso-markdown-editor/index.d.ts +40 -1
- package/dist/components/lukso-markdown-editor/index.d.ts.map +1 -1
- package/dist/components/lukso-markdown-editor/index.js +512 -114
- package/dist/components/lukso-markdown-editor/lukso-markdown-editor.stories.d.ts +53 -1
- package/dist/components/lukso-markdown-editor/lukso-markdown-editor.stories.d.ts.map +1 -1
- package/dist/components/lukso-modal/index.cjs +2 -2
- package/dist/components/lukso-modal/index.js +2 -2
- package/dist/components/lukso-navbar/index.cjs +3 -3
- package/dist/components/lukso-navbar/index.js +3 -3
- package/dist/components/lukso-pagination/index.cjs +3 -3
- package/dist/components/lukso-pagination/index.js +3 -3
- package/dist/components/lukso-profile/index.cjs +3 -3
- package/dist/components/lukso-profile/index.js +3 -3
- package/dist/components/lukso-progress/index.cjs +3 -3
- package/dist/components/lukso-progress/index.js +3 -3
- package/dist/components/lukso-radio/index.cjs +3 -3
- package/dist/components/lukso-radio/index.js +3 -3
- package/dist/components/lukso-radio-group/index.cjs +3 -3
- package/dist/components/lukso-radio-group/index.js +3 -3
- package/dist/components/lukso-sanitize/index.cjs +3 -3
- package/dist/components/lukso-sanitize/index.js +3 -3
- package/dist/components/lukso-search/index.cjs +6 -6
- package/dist/components/lukso-search/index.js +6 -6
- package/dist/components/lukso-select/index.cjs +5 -5
- package/dist/components/lukso-select/index.js +5 -5
- package/dist/components/lukso-share/index.cjs +2 -2
- package/dist/components/lukso-share/index.js +2 -2
- package/dist/components/lukso-switch/index.cjs +3 -3
- package/dist/components/lukso-switch/index.js +3 -3
- package/dist/components/lukso-tag/index.cjs +3 -3
- package/dist/components/lukso-tag/index.js +3 -3
- package/dist/components/lukso-terms/index.cjs +3 -3
- package/dist/components/lukso-terms/index.js +3 -3
- package/dist/components/lukso-textarea/index.cjs +3 -3
- package/dist/components/lukso-textarea/index.js +3 -3
- package/dist/components/lukso-tooltip/index.cjs +3 -3
- package/dist/components/lukso-tooltip/index.js +3 -3
- package/dist/components/lukso-username/index.cjs +4 -4
- package/dist/components/lukso-username/index.js +4 -4
- package/dist/components/lukso-wizard/index.cjs +2 -2
- package/dist/components/lukso-wizard/index.js +2 -2
- package/dist/docs/Icons.stories.d.ts.map +1 -1
- package/dist/{index-D4HqZcbk.cjs → index-BR_I57SD.cjs} +2 -2
- package/dist/{index-D-a6OWyj.cjs → index-BvQ5tHy1.cjs} +1 -1
- package/dist/{index-1cnTXnRX.js → index-CzJGpXul.js} +3 -3
- package/dist/{index-CO57mpzm.cjs → index-DGEC4kLx.cjs} +5 -5
- package/dist/{index-CsepkLbs.js → index-DI0bldib.js} +1 -1
- package/dist/{index-KrWvJ44l.cjs → index-Da-0kQ05.cjs} +1 -1
- package/dist/{index-D9mdD_OM.cjs → index-QfURPzjM.cjs} +3 -3
- package/dist/{index-B5_11hN3.js → index-bOsUG-kI.js} +5 -5
- package/dist/{index-DFculCCQ.js → index-g9LnjUjQ.js} +2 -2
- package/dist/{index-BWp0TAbf.js → index-wzuGnJOC.js} +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.js +4 -4
- package/dist/{property-DkFGx5Fg.js → property-BohUfInC.js} +1 -1
- package/dist/{property-CLMAG2Rj.cjs → property-C7opy5D6.cjs} +1 -1
- package/dist/shared/tailwind-element/index.cjs +1 -1
- package/dist/shared/tailwind-element/index.js +1 -1
- package/dist/{state-DPXXwNMf.js → state-DJBtqv5G.js} +1 -1
- package/dist/{state-DXBdLH-W.cjs → state-De1ciDiG.cjs} +1 -1
- package/dist/{style-map-CXXmrGLe.js → style-map-BXvyZNeB.js} +1 -1
- package/dist/{style-map-BFG88xg5.cjs → style-map-BjMzqR4L.cjs} +1 -1
- package/dist/{unsafe-html-C4RqiLkE.js → unsafe-html-Bs5tNJGm.js} +1 -1
- package/dist/{unsafe-html-CxwvRvgp.cjs → unsafe-html-D9Z4CuNa.cjs} +1 -1
- package/dist/vitest.config.d.ts.map +1 -1
- package/package.json +1 -1
- package/tailwind.config.cjs +14 -1
- package/LICENSE +0 -21
- package/README.md +0 -146
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { T as TailwindStyledElement, E, x } from '../../index-
|
|
2
|
-
import { n, t } from '../../property-
|
|
3
|
-
import { r } from '../../state-
|
|
1
|
+
import { T as TailwindStyledElement, E, x } from '../../index-wzuGnJOC.js';
|
|
2
|
+
import { n, t } from '../../property-BohUfInC.js';
|
|
3
|
+
import { r } from '../../state-DJBtqv5G.js';
|
|
4
4
|
import { e } from '../../query-CHb9Ft_d.js';
|
|
5
5
|
import { c as ce } from '../../index-B9iart53.js';
|
|
6
6
|
import '../../tailwind-config.js';
|
|
@@ -48,9 +48,11 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
48
48
|
this.isHeadingDropdownOpen = false;
|
|
49
49
|
this.isColorDropdownOpen = false;
|
|
50
50
|
this.isListDropdownOpen = false;
|
|
51
|
+
this.isAlignmentDropdownOpen = false;
|
|
51
52
|
this.headingTriggerId = "heading-dropdown-trigger";
|
|
52
53
|
this.colorTriggerId = "color-dropdown-trigger";
|
|
53
54
|
this.listTriggerId = "list-dropdown-trigger";
|
|
55
|
+
this.alignmentTriggerId = "alignment-dropdown-trigger";
|
|
54
56
|
this.currentSelection = { start: 0, end: 0 };
|
|
55
57
|
this.savedSelection = null;
|
|
56
58
|
this.defaultColor = "#374151";
|
|
@@ -61,10 +63,12 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
61
63
|
h1: false,
|
|
62
64
|
h2: false,
|
|
63
65
|
h3: false,
|
|
66
|
+
h4: false,
|
|
64
67
|
color: false,
|
|
65
68
|
activeColor: this.defaultColor,
|
|
66
69
|
unorderedList: false,
|
|
67
|
-
orderedList: false
|
|
70
|
+
orderedList: false,
|
|
71
|
+
alignment: "left"
|
|
68
72
|
};
|
|
69
73
|
// Undo/Redo state
|
|
70
74
|
this.undoStack = [];
|
|
@@ -87,14 +91,19 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
87
91
|
if (this.isListDropdownOpen) {
|
|
88
92
|
this.isListDropdownOpen = false;
|
|
89
93
|
}
|
|
94
|
+
if (this.isAlignmentDropdownOpen) {
|
|
95
|
+
this.isAlignmentDropdownOpen = false;
|
|
96
|
+
}
|
|
90
97
|
return;
|
|
91
98
|
}
|
|
92
99
|
const isInsideHeadingDropdown = this.shadowRoot?.getElementById("headingDropdown")?.contains(target);
|
|
93
100
|
const isInsideColorDropdown = this.shadowRoot?.getElementById("colorDropdown")?.contains(target);
|
|
94
101
|
const isInsideListDropdown = this.shadowRoot?.getElementById("listDropdown")?.contains(target);
|
|
102
|
+
const isInsideAlignmentDropdown = this.shadowRoot?.getElementById("alignmentDropdown")?.contains(target);
|
|
95
103
|
const isHeadingTrigger = this.shadowRoot?.getElementById(this.headingTriggerId)?.contains(target);
|
|
96
104
|
const isColorTrigger = this.shadowRoot?.getElementById(this.colorTriggerId)?.contains(target);
|
|
97
105
|
const isListTrigger = this.shadowRoot?.getElementById(this.listTriggerId)?.contains(target);
|
|
106
|
+
const isAlignmentTrigger = this.shadowRoot?.getElementById(this.alignmentTriggerId)?.contains(target);
|
|
98
107
|
if (!isInsideHeadingDropdown && !isHeadingTrigger && this.isHeadingDropdownOpen) {
|
|
99
108
|
this.isHeadingDropdownOpen = false;
|
|
100
109
|
}
|
|
@@ -104,6 +113,9 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
104
113
|
if (!isInsideListDropdown && !isListTrigger && this.isListDropdownOpen) {
|
|
105
114
|
this.isListDropdownOpen = false;
|
|
106
115
|
}
|
|
116
|
+
if (!isInsideAlignmentDropdown && !isAlignmentTrigger && this.isAlignmentDropdownOpen) {
|
|
117
|
+
this.isAlignmentDropdownOpen = false;
|
|
118
|
+
}
|
|
107
119
|
};
|
|
108
120
|
this.styles = ce({
|
|
109
121
|
slots: {
|
|
@@ -116,6 +128,7 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
116
128
|
colorMenu: "relative",
|
|
117
129
|
headingMenu: "relative",
|
|
118
130
|
listMenu: "relative",
|
|
131
|
+
alignmentMenu: "relative",
|
|
119
132
|
label: "heading-inter-14-bold text-neutral-20",
|
|
120
133
|
description: "paragraph-inter-12-regular text-neutral-20",
|
|
121
134
|
divider: "w-[1px] h-4 bg-neutral-90"
|
|
@@ -328,7 +341,7 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
328
341
|
/**
|
|
329
342
|
* Apply or toggle heading formatting for the current line(s).
|
|
330
343
|
*
|
|
331
|
-
* @param level - 0 to remove heading, 1-
|
|
344
|
+
* @param level - 0 to remove heading, 1-4 for heading levels
|
|
332
345
|
*/
|
|
333
346
|
applyHeading(level) {
|
|
334
347
|
if (this.isReadonly || this.isDisabled) return;
|
|
@@ -450,7 +463,7 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
450
463
|
const beforeLines = before.split("\n");
|
|
451
464
|
for (let i = beforeLines.length - 1; i >= 0; i--) {
|
|
452
465
|
const line = beforeLines[i];
|
|
453
|
-
const orderedMatch = line.match(/^(\s*)(\d+)\.\s
|
|
466
|
+
const orderedMatch = line.match(/^(\s*)(\d+)\.\s+(.*)$/);
|
|
454
467
|
if (orderedMatch) {
|
|
455
468
|
counter = parseInt(orderedMatch[2], 10) + 1;
|
|
456
469
|
break;
|
|
@@ -519,6 +532,156 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
519
532
|
if (this.activeFormats.orderedList) return "ordered";
|
|
520
533
|
return "none";
|
|
521
534
|
}
|
|
535
|
+
/**
|
|
536
|
+
* Get the current alignment icon name based on activeFormats.
|
|
537
|
+
*/
|
|
538
|
+
getAlignmentIcon() {
|
|
539
|
+
switch (this.activeFormats.alignment) {
|
|
540
|
+
case "center":
|
|
541
|
+
return "textalign-center";
|
|
542
|
+
case "right":
|
|
543
|
+
return "textalign-right";
|
|
544
|
+
default:
|
|
545
|
+
return "textalign-left";
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Apply or toggle text alignment for the current line(s).
|
|
550
|
+
*
|
|
551
|
+
* @param alignment - 'left', 'center', or 'right'
|
|
552
|
+
*/
|
|
553
|
+
applyAlignment(alignment) {
|
|
554
|
+
if (this.isReadonly || this.isDisabled) return;
|
|
555
|
+
this.saveUndoStateBeforeChange();
|
|
556
|
+
this.withSelection((textarea, start, end, value) => {
|
|
557
|
+
const lineStart = value.lastIndexOf("\n", start - 1) + 1;
|
|
558
|
+
let lineEnd = value.indexOf("\n", end);
|
|
559
|
+
if (lineEnd === -1) lineEnd = value.length;
|
|
560
|
+
const before = value.slice(0, lineStart);
|
|
561
|
+
const selected = value.slice(lineStart, lineEnd);
|
|
562
|
+
const after = value.slice(lineEnd);
|
|
563
|
+
let transformed;
|
|
564
|
+
const currentAlignmentRegex = /<div style="text-align: (left|center|right);">(.*?)<\/div>/s;
|
|
565
|
+
const existingMatch = selected.match(currentAlignmentRegex);
|
|
566
|
+
if (existingMatch || this.hasNestedAlignment(selected)) {
|
|
567
|
+
if (existingMatch) {
|
|
568
|
+
const existingAlignment = existingMatch[1];
|
|
569
|
+
const innerContent = existingMatch[2];
|
|
570
|
+
if (existingAlignment === alignment) {
|
|
571
|
+
transformed = innerContent;
|
|
572
|
+
} else {
|
|
573
|
+
transformed = `<div style="text-align: ${alignment};">${innerContent}</div>`;
|
|
574
|
+
}
|
|
575
|
+
} else {
|
|
576
|
+
if (this.getNestedAlignment(selected) === alignment) {
|
|
577
|
+
transformed = this.removeNestedAlignment(selected);
|
|
578
|
+
} else {
|
|
579
|
+
transformed = this.replaceNestedAlignment(selected, alignment);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
} else {
|
|
583
|
+
if (alignment === "left") {
|
|
584
|
+
transformed = selected;
|
|
585
|
+
} else {
|
|
586
|
+
transformed = this.wrapContentWithAlignment(selected, alignment);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
this.value = before + transformed + after;
|
|
590
|
+
textarea.value = before + transformed + after;
|
|
591
|
+
const cursorPosition = before.length + transformed.length;
|
|
592
|
+
requestAnimationFrame(() => {
|
|
593
|
+
textarea.setSelectionRange(cursorPosition, cursorPosition);
|
|
594
|
+
this.updateActiveFormats();
|
|
595
|
+
});
|
|
596
|
+
this.dispatchChange();
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Check if content has nested alignment divs inside formatting markers.
|
|
601
|
+
*/
|
|
602
|
+
hasNestedAlignment(content) {
|
|
603
|
+
const alignmentRegex = /<div style="text-align: (left|center|right);">/;
|
|
604
|
+
return alignmentRegex.test(content);
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Get the alignment from nested alignment divs.
|
|
608
|
+
*/
|
|
609
|
+
getNestedAlignment(content) {
|
|
610
|
+
const alignmentMatch = content.match(
|
|
611
|
+
/<div style="text-align: (left|center|right);">/
|
|
612
|
+
);
|
|
613
|
+
return alignmentMatch ? alignmentMatch[1] : null;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Remove nested alignment divs from content.
|
|
617
|
+
*/
|
|
618
|
+
removeNestedAlignment(content) {
|
|
619
|
+
return content.replace(
|
|
620
|
+
/<div style="text-align: (left|center|right);">([^<]*?)<\/div>/g,
|
|
621
|
+
"$2"
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Replace nested alignment with a new alignment.
|
|
626
|
+
*/
|
|
627
|
+
replaceNestedAlignment(content, newAlignment) {
|
|
628
|
+
return content.replace(
|
|
629
|
+
/<div style="text-align: (left|center|right);">([^<]*?)<\/div>/g,
|
|
630
|
+
`<div style="text-align: ${newAlignment};">$2</div>`
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Wrap content with alignment div, ensuring proper nesting inside formatting markers.
|
|
635
|
+
* Examples:
|
|
636
|
+
* - **text** becomes **<div style="text-align: center;">text</div>**
|
|
637
|
+
* - *text* becomes *<div style="text-align: center;">text</div>*
|
|
638
|
+
* - # text becomes # <div style="text-align: center;">text</div>
|
|
639
|
+
*
|
|
640
|
+
* @param content - the content to wrap
|
|
641
|
+
* @param alignment - 'left', 'center' or 'right'
|
|
642
|
+
*/
|
|
643
|
+
wrapContentWithAlignment(content, alignment) {
|
|
644
|
+
const alignmentDiv = (innerContent) => `<div style="text-align: ${alignment};">${innerContent}</div>`;
|
|
645
|
+
const headingMatch = content.match(/^(#{1,6}\s+)(.*)$/);
|
|
646
|
+
if (headingMatch) {
|
|
647
|
+
const headingPrefix = headingMatch[1];
|
|
648
|
+
const headingText = headingMatch[2];
|
|
649
|
+
return headingPrefix + alignmentDiv(headingText);
|
|
650
|
+
}
|
|
651
|
+
const boldMatch = content.match(/^(\*\*)(.+?)(\*\*)$/s);
|
|
652
|
+
if (boldMatch) {
|
|
653
|
+
const innerText = boldMatch[2];
|
|
654
|
+
return `**${alignmentDiv(innerText)}**`;
|
|
655
|
+
}
|
|
656
|
+
const italicMatch = content.match(/^(\*)(.+?)(\*)$/s);
|
|
657
|
+
if (italicMatch) {
|
|
658
|
+
const innerText = italicMatch[2];
|
|
659
|
+
return `*${alignmentDiv(innerText)}*`;
|
|
660
|
+
}
|
|
661
|
+
const linkMatch = content.match(/^(\[)(.+?)(\]\([^)]+\))$/s);
|
|
662
|
+
if (linkMatch) {
|
|
663
|
+
const linkStart = linkMatch[1];
|
|
664
|
+
const linkText = linkMatch[2];
|
|
665
|
+
const linkEnd = linkMatch[3];
|
|
666
|
+
return linkStart + alignmentDiv(linkText) + linkEnd;
|
|
667
|
+
}
|
|
668
|
+
const colorMatch = content.match(
|
|
669
|
+
/^(<span style="color: [^"]+;">)(.+?)(<\/span>)$/s
|
|
670
|
+
);
|
|
671
|
+
if (colorMatch) {
|
|
672
|
+
const colorStart = colorMatch[1];
|
|
673
|
+
const colorText = colorMatch[2];
|
|
674
|
+
const colorEnd = colorMatch[3];
|
|
675
|
+
return colorStart + alignmentDiv(colorText) + colorEnd;
|
|
676
|
+
}
|
|
677
|
+
const listMatch = content.match(/^(\s*(?:[-*+]|\d+\.)\s+)(.*)$/);
|
|
678
|
+
if (listMatch) {
|
|
679
|
+
const listPrefix = listMatch[1];
|
|
680
|
+
const listText = listMatch[2];
|
|
681
|
+
return listPrefix + alignmentDiv(listText);
|
|
682
|
+
}
|
|
683
|
+
return alignmentDiv(content);
|
|
684
|
+
}
|
|
522
685
|
/**
|
|
523
686
|
* Toggle inline formatting by wrapping/unwrapping selection or current word.
|
|
524
687
|
*
|
|
@@ -736,8 +899,8 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
736
899
|
);
|
|
737
900
|
const headingMatch = currentLine.match(/^(#{1,6})\s/);
|
|
738
901
|
const headingLevel = headingMatch ? headingMatch[1].length : 0;
|
|
739
|
-
const unorderedListMatch = currentLine.match(/^\s*[-*+]\s
|
|
740
|
-
const orderedListMatch = currentLine.match(/^\s*\d+\.\s
|
|
902
|
+
const unorderedListMatch = currentLine.match(/^\s*[-*+]\s+/);
|
|
903
|
+
const orderedListMatch = currentLine.match(/^\s*\d+\.\s+/);
|
|
741
904
|
const hasUnorderedList = !!unorderedListMatch;
|
|
742
905
|
const hasOrderedList = !!orderedListMatch;
|
|
743
906
|
const colorRegex = /<span style="color: ([^"]+)">/;
|
|
@@ -752,6 +915,23 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
752
915
|
);
|
|
753
916
|
activeColor = beforeColorMatch?.[1] || selectedColorMatch?.[1] || "";
|
|
754
917
|
}
|
|
918
|
+
const alignmentRegex = /<div style="text-align: (left|center|right);">/;
|
|
919
|
+
let alignment = "left";
|
|
920
|
+
const alignmentMatch = currentLine.match(alignmentRegex);
|
|
921
|
+
if (alignmentMatch) {
|
|
922
|
+
alignment = alignmentMatch[1];
|
|
923
|
+
} else {
|
|
924
|
+
const beforeCurrentLine = this.value.slice(0, lineStart);
|
|
925
|
+
const alignmentStartMatch = beforeCurrentLine.match(
|
|
926
|
+
/.*<div style="text-align: (left|center|right);">[^<]*$/s
|
|
927
|
+
);
|
|
928
|
+
if (alignmentStartMatch) {
|
|
929
|
+
const afterCurrentLine = this.value.slice(lineEnd);
|
|
930
|
+
if (afterCurrentLine.includes("</div>")) {
|
|
931
|
+
alignment = alignmentStartMatch[1];
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
755
935
|
this.activeFormats = {
|
|
756
936
|
bold: hasBoldWrap,
|
|
757
937
|
italic: hasItalicWrap,
|
|
@@ -759,10 +939,12 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
759
939
|
h1: headingLevel === 1,
|
|
760
940
|
h2: headingLevel === 2,
|
|
761
941
|
h3: headingLevel === 3,
|
|
942
|
+
h4: headingLevel === 4,
|
|
762
943
|
color: hasColorWrap,
|
|
763
944
|
activeColor,
|
|
764
945
|
unorderedList: hasUnorderedList,
|
|
765
|
-
orderedList: hasOrderedList
|
|
946
|
+
orderedList: hasOrderedList,
|
|
947
|
+
alignment
|
|
766
948
|
};
|
|
767
949
|
}
|
|
768
950
|
/**
|
|
@@ -964,54 +1146,59 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
964
1146
|
return;
|
|
965
1147
|
}
|
|
966
1148
|
const { start: s, end: e } = this.expandSelectionToWord(start, end, value);
|
|
967
|
-
const
|
|
968
|
-
let selected = value.slice(s, e);
|
|
969
|
-
const after = value.slice(e);
|
|
970
|
-
const colorRegex = /<span style="color: ([^"]+)">(.*?)<\/span>/gs;
|
|
971
|
-
selected = selected.replace(colorRegex, "$2");
|
|
972
|
-
const fullColorRegex = /<span style="color: ([^"]+)">(.*?)<\/span>/g;
|
|
1149
|
+
const colorRegex = /<span style="color: ([^"]+)">(.*?)<\/span>/g;
|
|
973
1150
|
let match;
|
|
974
|
-
let
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
);
|
|
979
|
-
const searchOffset = Math.max(0, s - 100);
|
|
980
|
-
match = fullColorRegex.exec(searchText);
|
|
1151
|
+
let newValue = value;
|
|
1152
|
+
let foundSpan = false;
|
|
1153
|
+
colorRegex.lastIndex = 0;
|
|
1154
|
+
match = colorRegex.exec(value);
|
|
981
1155
|
while (match !== null) {
|
|
982
|
-
const
|
|
983
|
-
const
|
|
1156
|
+
const fullMatchStart = match.index;
|
|
1157
|
+
const fullMatchEnd = match.index + match[0].length;
|
|
984
1158
|
const spanOpenTag = `<span style="color: ${match[1]}">`;
|
|
985
|
-
const contentStart =
|
|
986
|
-
const contentEnd =
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1159
|
+
const contentStart = fullMatchStart + spanOpenTag.length;
|
|
1160
|
+
const contentEnd = fullMatchEnd - 7;
|
|
1161
|
+
const innerContent = match[2];
|
|
1162
|
+
match = colorRegex.exec(value);
|
|
1163
|
+
const selectionOverlaps = s >= contentStart && s < contentEnd || e > contentStart && e <= contentEnd || s <= contentStart && e >= contentEnd;
|
|
1164
|
+
if (selectionOverlaps) {
|
|
1165
|
+
newValue = value.slice(0, fullMatchStart) + innerContent + value.slice(fullMatchEnd);
|
|
1166
|
+
foundSpan = true;
|
|
1167
|
+
this.value = newValue;
|
|
1168
|
+
textarea.value = newValue;
|
|
1169
|
+
let newStart = s;
|
|
1170
|
+
let newEnd = e;
|
|
1171
|
+
if (s >= fullMatchStart) {
|
|
1172
|
+
const spanOpenTagLength = spanOpenTag.length;
|
|
1173
|
+
if (s >= contentStart) {
|
|
1174
|
+
newStart = s - spanOpenTagLength;
|
|
1175
|
+
} else if (s >= fullMatchStart) {
|
|
1176
|
+
newStart = fullMatchStart;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
if (e >= fullMatchStart) {
|
|
1180
|
+
const spanOpenTagLength = spanOpenTag.length;
|
|
1181
|
+
if (e <= contentEnd) {
|
|
1182
|
+
newEnd = e - spanOpenTagLength;
|
|
1183
|
+
} else {
|
|
1184
|
+
newEnd = e - spanOpenTagLength - 7;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
995
1187
|
requestAnimationFrame(() => {
|
|
996
|
-
textarea.setSelectionRange(
|
|
1188
|
+
textarea.setSelectionRange(
|
|
1189
|
+
Math.max(0, newStart),
|
|
1190
|
+
Math.max(0, newEnd)
|
|
1191
|
+
);
|
|
997
1192
|
this.updateActiveFormats();
|
|
998
1193
|
});
|
|
999
1194
|
this.dispatchChange();
|
|
1000
|
-
|
|
1001
|
-
break;
|
|
1195
|
+
return;
|
|
1002
1196
|
}
|
|
1003
|
-
match = fullColorRegex.exec(searchText);
|
|
1004
1197
|
}
|
|
1005
|
-
if (!
|
|
1006
|
-
this.value = before + selected + after;
|
|
1007
|
-
textarea.value = before + selected + after;
|
|
1008
|
-
const selStart = before.length;
|
|
1009
|
-
const selEnd = selStart + selected.length;
|
|
1198
|
+
if (!foundSpan) {
|
|
1010
1199
|
requestAnimationFrame(() => {
|
|
1011
|
-
textarea.setSelectionRange(selStart, selEnd);
|
|
1012
1200
|
this.updateActiveFormats();
|
|
1013
1201
|
});
|
|
1014
|
-
this.dispatchChange();
|
|
1015
1202
|
}
|
|
1016
1203
|
});
|
|
1017
1204
|
}
|
|
@@ -1022,6 +1209,7 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
1022
1209
|
if (this.activeFormats.h1) return 1;
|
|
1023
1210
|
if (this.activeFormats.h2) return 2;
|
|
1024
1211
|
if (this.activeFormats.h3) return 3;
|
|
1212
|
+
if (this.activeFormats.h4) return 4;
|
|
1025
1213
|
return 0;
|
|
1026
1214
|
}
|
|
1027
1215
|
/**
|
|
@@ -1089,17 +1277,21 @@ let LuksoMarkdownEditor = class extends TailwindStyledElement(style) {
|
|
|
1089
1277
|
const textarea = this.textareaEl?.shadowRoot?.querySelector(
|
|
1090
1278
|
"textarea"
|
|
1091
1279
|
);
|
|
1092
|
-
if (!textarea)
|
|
1280
|
+
if (!textarea) {
|
|
1281
|
+
return false;
|
|
1282
|
+
}
|
|
1093
1283
|
const start = textarea.selectionStart ?? 0;
|
|
1094
1284
|
const end = textarea.selectionEnd ?? 0;
|
|
1095
|
-
if (start !== end)
|
|
1285
|
+
if (start !== end) {
|
|
1286
|
+
return false;
|
|
1287
|
+
}
|
|
1096
1288
|
const value = this.value;
|
|
1097
1289
|
const lineStart = value.lastIndexOf("\n", start - 1) + 1;
|
|
1098
1290
|
let lineEnd = value.indexOf("\n", start);
|
|
1099
1291
|
if (lineEnd === -1) lineEnd = value.length;
|
|
1100
1292
|
const currentLine = value.slice(lineStart, lineEnd);
|
|
1101
|
-
const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s
|
|
1102
|
-
const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s
|
|
1293
|
+
const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s+(.*)$/);
|
|
1294
|
+
const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s+(.*)$/);
|
|
1103
1295
|
if (!unorderedMatch && !orderedMatch) {
|
|
1104
1296
|
return false;
|
|
1105
1297
|
}
|
|
@@ -1130,10 +1322,8 @@ ${indent}${marker} `;
|
|
|
1130
1322
|
this.value = newValue;
|
|
1131
1323
|
textarea.value = newValue;
|
|
1132
1324
|
const newCursor = start + prefix.length;
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
this.updateActiveFormats();
|
|
1136
|
-
});
|
|
1325
|
+
textarea.setSelectionRange(newCursor, newCursor);
|
|
1326
|
+
this.updateActiveFormats();
|
|
1137
1327
|
this.dispatchChange();
|
|
1138
1328
|
return true;
|
|
1139
1329
|
}
|
|
@@ -1155,40 +1345,35 @@ ${indent}${marker} `;
|
|
|
1155
1345
|
this.dispatchChange();
|
|
1156
1346
|
return true;
|
|
1157
1347
|
}
|
|
1158
|
-
|
|
1159
|
-
const
|
|
1160
|
-
const beforeLines = beforeText.split("\n");
|
|
1161
|
-
let lastNumberAtThisLevel = 0;
|
|
1162
|
-
for (let i = beforeLines.length - 1; i >= 0; i--) {
|
|
1163
|
-
const line = beforeLines[i];
|
|
1164
|
-
const match = line.match(/^(\s*)(\d+)\.\s*(.*)$/);
|
|
1165
|
-
if (match && match[1] === indent) {
|
|
1166
|
-
lastNumberAtThisLevel = parseInt(match[2], 10);
|
|
1167
|
-
break;
|
|
1168
|
-
} else if (line.trim() !== "" && !line.match(/^\s*[-*+]\s+/) && !match) {
|
|
1169
|
-
break;
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
if (lastNumberAtThisLevel > 0) {
|
|
1173
|
-
nextNumber = lastNumberAtThisLevel + 1;
|
|
1174
|
-
}
|
|
1348
|
+
const currentNumber = parseInt(numberStr, 10);
|
|
1349
|
+
const nextNumber = currentNumber + 1;
|
|
1175
1350
|
const before = value.slice(0, start);
|
|
1176
1351
|
const after = value.slice(start);
|
|
1177
1352
|
const prefix = `
|
|
1178
1353
|
${indent}${nextNumber}. `;
|
|
1179
|
-
|
|
1180
|
-
const
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
)
|
|
1185
|
-
|
|
1186
|
-
|
|
1354
|
+
let newValue = before + prefix + after;
|
|
1355
|
+
const lines = newValue.split("\n");
|
|
1356
|
+
const insertLineIndex = before.split("\n").length;
|
|
1357
|
+
const renumberStartIndex = insertLineIndex + 1;
|
|
1358
|
+
let currentNum = nextNumber + 1;
|
|
1359
|
+
const orderedRegex = /^(\s*)(\d+)\.\s+(.*)$/;
|
|
1360
|
+
for (let i = renumberStartIndex; i < lines.length; i++) {
|
|
1361
|
+
const line = lines[i];
|
|
1362
|
+
const match = line.match(orderedRegex);
|
|
1363
|
+
if (match && match[1] === indent) {
|
|
1364
|
+
const content2 = match[3];
|
|
1365
|
+
lines[i] = `${indent}${currentNum}. ${content2}`;
|
|
1366
|
+
currentNum++;
|
|
1367
|
+
} else if (match && match[1].length < indent.length) {
|
|
1368
|
+
break;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
newValue = lines.join("\n");
|
|
1372
|
+
this.value = newValue;
|
|
1373
|
+
textarea.value = newValue;
|
|
1187
1374
|
const newCursor = start + prefix.length;
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
this.updateActiveFormats();
|
|
1191
|
-
});
|
|
1375
|
+
textarea.setSelectionRange(newCursor, newCursor);
|
|
1376
|
+
this.updateActiveFormats();
|
|
1192
1377
|
this.dispatchChange();
|
|
1193
1378
|
return true;
|
|
1194
1379
|
}
|
|
@@ -1202,17 +1387,21 @@ ${indent}${nextNumber}. `;
|
|
|
1202
1387
|
const textarea = this.textareaEl?.shadowRoot?.querySelector(
|
|
1203
1388
|
"textarea"
|
|
1204
1389
|
);
|
|
1205
|
-
if (!textarea)
|
|
1390
|
+
if (!textarea) {
|
|
1391
|
+
return false;
|
|
1392
|
+
}
|
|
1206
1393
|
const start = textarea.selectionStart ?? 0;
|
|
1207
1394
|
const end = textarea.selectionEnd ?? 0;
|
|
1208
|
-
if (start !== end)
|
|
1395
|
+
if (start !== end) {
|
|
1396
|
+
return false;
|
|
1397
|
+
}
|
|
1209
1398
|
const value = this.value;
|
|
1210
1399
|
const lineStart = value.lastIndexOf("\n", start - 1) + 1;
|
|
1211
1400
|
let lineEnd = value.indexOf("\n", start);
|
|
1212
1401
|
if (lineEnd === -1) lineEnd = value.length;
|
|
1213
1402
|
const currentLine = value.slice(lineStart, lineEnd);
|
|
1214
|
-
const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s
|
|
1215
|
-
const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s
|
|
1403
|
+
const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s+(.*)$/);
|
|
1404
|
+
const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s+(.*)$/);
|
|
1216
1405
|
if (!unorderedMatch && !orderedMatch) {
|
|
1217
1406
|
return false;
|
|
1218
1407
|
}
|
|
@@ -1231,20 +1420,86 @@ ${indent}${nextNumber}. `;
|
|
|
1231
1420
|
} else if (orderedMatch) {
|
|
1232
1421
|
const currentIndent = orderedMatch[1] ?? "";
|
|
1233
1422
|
const content = orderedMatch[3] ?? "";
|
|
1234
|
-
|
|
1235
|
-
|
|
1423
|
+
if (content.trim() === "") {
|
|
1424
|
+
newLine = currentLine;
|
|
1425
|
+
const nestedLine = `${currentIndent}${indent}1. `;
|
|
1426
|
+
let newValue2 = before + newLine + "\n" + nestedLine + after;
|
|
1427
|
+
const parentIndent = currentIndent;
|
|
1428
|
+
const lines = newValue2.split("\n");
|
|
1429
|
+
const currentLineIndex = Math.floor(lineStart / (newValue2.indexOf("\n") + 1)) || newValue2.slice(0, lineStart).split("\n").length - 1;
|
|
1430
|
+
const currentLineMatch = lines[currentLineIndex]?.match(
|
|
1431
|
+
/^(\s*)(\d+)\.\s*(.*)$/
|
|
1432
|
+
);
|
|
1433
|
+
const nextExpectedNumber = currentLineMatch ? parseInt(currentLineMatch[2], 10) : 1;
|
|
1434
|
+
const orderedRegex = /^(\s*)(\d+)\.\s*(.*)$/;
|
|
1435
|
+
let currentNumber = nextExpectedNumber;
|
|
1436
|
+
for (let i = currentLineIndex + 2; i < lines.length; i++) {
|
|
1437
|
+
const line = lines[i];
|
|
1438
|
+
const orderedMatch2 = line.match(orderedRegex);
|
|
1439
|
+
if (orderedMatch2 && orderedMatch2[1] === parentIndent) {
|
|
1440
|
+
const content2 = orderedMatch2[3];
|
|
1441
|
+
lines[i] = `${parentIndent}${currentNumber}. ${content2}`;
|
|
1442
|
+
currentNumber++;
|
|
1443
|
+
} else if (orderedMatch2 && orderedMatch2[1].length < parentIndent.length) {
|
|
1444
|
+
break;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
newValue2 = lines.join("\n");
|
|
1448
|
+
const newCursor2 = lineStart + newLine.length + 1 + nestedLine.length;
|
|
1449
|
+
this.value = newValue2;
|
|
1450
|
+
textarea.value = newValue2;
|
|
1451
|
+
requestAnimationFrame(() => {
|
|
1452
|
+
textarea.setSelectionRange(newCursor2, newCursor2);
|
|
1453
|
+
this.updateActiveFormats();
|
|
1454
|
+
});
|
|
1455
|
+
this.dispatchChange();
|
|
1456
|
+
return true;
|
|
1457
|
+
} else {
|
|
1458
|
+
const newIndent = currentIndent + indent;
|
|
1459
|
+
let newNumber = 1;
|
|
1460
|
+
const beforeText = value.slice(0, lineStart);
|
|
1461
|
+
const lines = beforeText.split("\n");
|
|
1462
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
1463
|
+
const line = lines[i];
|
|
1464
|
+
const match = line.match(/^(\s*)(\d+)\.\s*(.*)$/);
|
|
1465
|
+
if (match && match[1] === newIndent) {
|
|
1466
|
+
newNumber = parseInt(match[2], 10) + 1;
|
|
1467
|
+
break;
|
|
1468
|
+
} else if (match && match[1].length < newIndent.length) {
|
|
1469
|
+
break;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
newLine = `${newIndent}${newNumber}. ${content}`;
|
|
1473
|
+
newCursorOffset = indent.length;
|
|
1474
|
+
}
|
|
1236
1475
|
} else {
|
|
1237
1476
|
return false;
|
|
1238
1477
|
}
|
|
1239
|
-
|
|
1478
|
+
let newValue = before + newLine + after;
|
|
1479
|
+
if (orderedMatch) {
|
|
1480
|
+
const newIndent = (orderedMatch[1] ?? "") + indent;
|
|
1481
|
+
newValue = this.renumberOrderedListItems(
|
|
1482
|
+
newValue,
|
|
1483
|
+
lineStart + newLine.length,
|
|
1484
|
+
// Start renumbering after the current line
|
|
1485
|
+
newIndent
|
|
1486
|
+
// Use the new indentation level
|
|
1487
|
+
);
|
|
1488
|
+
const parentIndent = orderedMatch[1] ?? "";
|
|
1489
|
+
newValue = this.renumberOrderedListItems(
|
|
1490
|
+
newValue,
|
|
1491
|
+
lineStart,
|
|
1492
|
+
// Start from this line for parent level
|
|
1493
|
+
parentIndent
|
|
1494
|
+
// Use the parent level indentation
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1240
1497
|
this.value = newValue;
|
|
1241
1498
|
textarea.value = newValue;
|
|
1242
1499
|
const cursorInLine = start - lineStart;
|
|
1243
1500
|
const newCursor = lineStart + cursorInLine + newCursorOffset;
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
this.updateActiveFormats();
|
|
1247
|
-
});
|
|
1501
|
+
textarea.setSelectionRange(newCursor, newCursor);
|
|
1502
|
+
this.updateActiveFormats();
|
|
1248
1503
|
this.dispatchChange();
|
|
1249
1504
|
return true;
|
|
1250
1505
|
}
|
|
@@ -1265,8 +1520,8 @@ ${indent}${nextNumber}. `;
|
|
|
1265
1520
|
let lineEnd = value.indexOf("\n", start);
|
|
1266
1521
|
if (lineEnd === -1) lineEnd = value.length;
|
|
1267
1522
|
const currentLine = value.slice(lineStart, lineEnd);
|
|
1268
|
-
const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s
|
|
1269
|
-
const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s
|
|
1523
|
+
const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s+(.*)$/);
|
|
1524
|
+
const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s+(.*)$/);
|
|
1270
1525
|
if (!unorderedMatch && !orderedMatch) {
|
|
1271
1526
|
return false;
|
|
1272
1527
|
}
|
|
@@ -1293,7 +1548,7 @@ ${indent}${nextNumber}. `;
|
|
|
1293
1548
|
const beforeLines = before.split("\n");
|
|
1294
1549
|
for (let i = beforeLines.length - 1; i >= 0; i--) {
|
|
1295
1550
|
const line = beforeLines[i];
|
|
1296
|
-
const match = line.match(/^(\s*)(\d+)\.\s
|
|
1551
|
+
const match = line.match(/^(\s*)(\d+)\.\s+(.*)$/);
|
|
1297
1552
|
if (match && match[1] === newIndent) {
|
|
1298
1553
|
newNumber = parseInt(match[2], 10) + 1;
|
|
1299
1554
|
break;
|
|
@@ -1345,13 +1600,13 @@ ${indent}${nextNumber}. `;
|
|
|
1345
1600
|
);
|
|
1346
1601
|
let nextExpectedNumber = 1;
|
|
1347
1602
|
const currentLine = lines[fromLineIndex];
|
|
1348
|
-
const currentMatch = currentLine?.match(/^(\s*)(\d+)\.\s
|
|
1603
|
+
const currentMatch = currentLine?.match(/^(\s*)(\d+)\.\s+(.*)$/);
|
|
1349
1604
|
if (currentMatch && currentMatch[1] === targetIndent) {
|
|
1350
1605
|
nextExpectedNumber = parseInt(currentMatch[2], 10) + 1;
|
|
1351
1606
|
} else {
|
|
1352
1607
|
for (let i = fromLineIndex - 1; i >= 0; i--) {
|
|
1353
1608
|
const line = lines[i];
|
|
1354
|
-
const orderedMatch = line.match(/^(\s*)(\d+)\.\s
|
|
1609
|
+
const orderedMatch = line.match(/^(\s*)(\d+)\.\s+(.*)$/);
|
|
1355
1610
|
if (orderedMatch && orderedMatch[1] === targetIndent) {
|
|
1356
1611
|
nextExpectedNumber = parseInt(orderedMatch[2], 10) + 1;
|
|
1357
1612
|
break;
|
|
@@ -1359,7 +1614,7 @@ ${indent}${nextNumber}. `;
|
|
|
1359
1614
|
}
|
|
1360
1615
|
}
|
|
1361
1616
|
let currentNumber = nextExpectedNumber;
|
|
1362
|
-
const orderedRegex = /^(\s*)(\d+)\.\s
|
|
1617
|
+
const orderedRegex = /^(\s*)(\d+)\.\s+(.*)$/;
|
|
1363
1618
|
for (let i = fromLineIndex + 1; i < lines.length; i++) {
|
|
1364
1619
|
const line = lines[i];
|
|
1365
1620
|
const orderedMatch = line.match(orderedRegex);
|
|
@@ -1392,7 +1647,7 @@ ${indent}${nextNumber}. `;
|
|
|
1392
1647
|
0,
|
|
1393
1648
|
value.slice(0, fromPosition).split("\n").length - 1
|
|
1394
1649
|
);
|
|
1395
|
-
const orderedRegex = /^(\s*)(\d+)\.\s
|
|
1650
|
+
const orderedRegex = /^(\s*)(\d+)\.\s+(.*)$/;
|
|
1396
1651
|
let currentSequenceNumber = 1;
|
|
1397
1652
|
let inSequence = false;
|
|
1398
1653
|
let currentIndent = "";
|
|
@@ -1433,8 +1688,8 @@ ${indent}${nextNumber}. `;
|
|
|
1433
1688
|
if (lineEnd === -1) lineEnd = value.length;
|
|
1434
1689
|
const currentLine = value.slice(lineStart, lineEnd);
|
|
1435
1690
|
const cursorPositionInLine = start - lineStart;
|
|
1436
|
-
const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s
|
|
1437
|
-
const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s
|
|
1691
|
+
const unorderedMatch = currentLine.match(/^(\s*)([-*+])\s+(.*)$/);
|
|
1692
|
+
const orderedMatch = currentLine.match(/^(\s*)(\d+)\.\s+(.*)$/);
|
|
1438
1693
|
if (!unorderedMatch && !orderedMatch) {
|
|
1439
1694
|
return false;
|
|
1440
1695
|
}
|
|
@@ -1453,25 +1708,46 @@ ${indent}${nextNumber}. `;
|
|
|
1453
1708
|
markerEndPosition = indent.length + numberStr.length + 2;
|
|
1454
1709
|
hasContent = content.trim().length > 0;
|
|
1455
1710
|
}
|
|
1456
|
-
|
|
1711
|
+
const isAtOrAfterMarker = cursorPositionInLine >= markerEndPosition;
|
|
1712
|
+
if (isAtOrAfterMarker && !hasContent) {
|
|
1457
1713
|
this.saveUndoStateBeforeChange();
|
|
1458
1714
|
const before = value.slice(0, lineStart);
|
|
1459
|
-
const after = value.slice(
|
|
1460
|
-
|
|
1461
|
-
)
|
|
1462
|
-
|
|
1715
|
+
const after = value.slice(lineEnd);
|
|
1716
|
+
let newValue;
|
|
1717
|
+
if (lineEnd === value.length) {
|
|
1718
|
+
newValue = before.endsWith("\n") ? before.slice(0, -1) : before;
|
|
1719
|
+
} else {
|
|
1720
|
+
newValue = before + after.slice(1);
|
|
1721
|
+
}
|
|
1463
1722
|
if (orderedMatch) {
|
|
1464
1723
|
const indent = orderedMatch[1] ?? "";
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1724
|
+
const lines = newValue.split("\n");
|
|
1725
|
+
const startLineIndex = Math.max(0, before.split("\n").length - 1);
|
|
1726
|
+
let nextNumber = 1;
|
|
1727
|
+
for (let i = startLineIndex - 1; i >= 0; i--) {
|
|
1728
|
+
const line = lines[i];
|
|
1729
|
+
const match = line.match(/^(\s*)(\d+)\.\s*(.*)$/);
|
|
1730
|
+
if (match && match[1] === indent) {
|
|
1731
|
+
nextNumber = parseInt(match[2], 10) + 1;
|
|
1732
|
+
break;
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
for (let i = startLineIndex; i < lines.length; i++) {
|
|
1736
|
+
const line = lines[i];
|
|
1737
|
+
const match = line.match(/^(\s*)(\d+)\.\s*(.*)$/);
|
|
1738
|
+
if (match && match[1] === indent) {
|
|
1739
|
+
lines[i] = `${indent}${nextNumber}. ${match[3]}`;
|
|
1740
|
+
nextNumber++;
|
|
1741
|
+
} else if (match && match[1].length < indent.length) {
|
|
1742
|
+
break;
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
newValue = lines.join("\n");
|
|
1470
1746
|
}
|
|
1471
1747
|
this.value = newValue;
|
|
1472
1748
|
textarea.value = newValue;
|
|
1473
1749
|
let newCursor = before.length;
|
|
1474
|
-
if (before.endsWith("\n")
|
|
1750
|
+
if (newCursor > 0 && before.endsWith("\n")) {
|
|
1475
1751
|
newCursor = before.length - 1;
|
|
1476
1752
|
}
|
|
1477
1753
|
requestAnimationFrame(() => {
|
|
@@ -1631,6 +1907,7 @@ ${indent}${nextNumber}. `;
|
|
|
1631
1907
|
e.stopPropagation();
|
|
1632
1908
|
this.isColorDropdownOpen = false;
|
|
1633
1909
|
this.isListDropdownOpen = false;
|
|
1910
|
+
this.isAlignmentDropdownOpen = false;
|
|
1634
1911
|
this.isHeadingDropdownOpen = !this.isHeadingDropdownOpen;
|
|
1635
1912
|
}}
|
|
1636
1913
|
aria-expanded=${this.isHeadingDropdownOpen ? "true" : "false"}
|
|
@@ -1704,6 +1981,18 @@ ${indent}${nextNumber}. `;
|
|
|
1704
1981
|
>
|
|
1705
1982
|
Heading 3
|
|
1706
1983
|
</lukso-dropdown-option>
|
|
1984
|
+
<lukso-dropdown-option
|
|
1985
|
+
?is-selected=${this.getActiveHeadingLevel() === 4}
|
|
1986
|
+
@click=${(e) => {
|
|
1987
|
+
e.stopPropagation();
|
|
1988
|
+
this.restoreFocusAndSelection();
|
|
1989
|
+
this.applyHeading(4);
|
|
1990
|
+
this.isHeadingDropdownOpen = false;
|
|
1991
|
+
}}
|
|
1992
|
+
size="medium"
|
|
1993
|
+
>
|
|
1994
|
+
Heading 4
|
|
1995
|
+
</lukso-dropdown-option>
|
|
1707
1996
|
</lukso-dropdown>
|
|
1708
1997
|
</div>
|
|
1709
1998
|
|
|
@@ -1733,6 +2022,7 @@ ${indent}${nextNumber}. `;
|
|
|
1733
2022
|
this.restoreFocusAndSelection();
|
|
1734
2023
|
this.isHeadingDropdownOpen = false;
|
|
1735
2024
|
this.isColorDropdownOpen = false;
|
|
2025
|
+
this.isAlignmentDropdownOpen = false;
|
|
1736
2026
|
this.isListDropdownOpen = !this.isListDropdownOpen;
|
|
1737
2027
|
}}
|
|
1738
2028
|
aria-expanded=${this.isListDropdownOpen ? "true" : "false"}
|
|
@@ -1805,6 +2095,108 @@ ${indent}${nextNumber}. `;
|
|
|
1805
2095
|
this.activeFormats.link
|
|
1806
2096
|
)}
|
|
1807
2097
|
|
|
2098
|
+
<!-- Text Alignment -->
|
|
2099
|
+
<div class=${this.styles().alignmentMenu()}>
|
|
2100
|
+
<lukso-tooltip text="Text alignment" placement="top">
|
|
2101
|
+
<lukso-button
|
|
2102
|
+
id=${this.alignmentTriggerId}
|
|
2103
|
+
@click=${(e) => {
|
|
2104
|
+
e.stopPropagation();
|
|
2105
|
+
this.restoreFocusAndSelection();
|
|
2106
|
+
this.isHeadingDropdownOpen = false;
|
|
2107
|
+
this.isColorDropdownOpen = false;
|
|
2108
|
+
this.isListDropdownOpen = false;
|
|
2109
|
+
this.isAlignmentDropdownOpen = !this.isAlignmentDropdownOpen;
|
|
2110
|
+
}}
|
|
2111
|
+
aria-expanded=${this.isAlignmentDropdownOpen ? "true" : "false"}
|
|
2112
|
+
aria-label="Text alignment"
|
|
2113
|
+
variant="secondary"
|
|
2114
|
+
size="small"
|
|
2115
|
+
custom-class=${this.toolbarButton({
|
|
2116
|
+
active: this.activeFormats.alignment !== "left"
|
|
2117
|
+
})}
|
|
2118
|
+
is-icon
|
|
2119
|
+
>
|
|
2120
|
+
<lukso-icon
|
|
2121
|
+
name=${this.getAlignmentIcon()}
|
|
2122
|
+
size="small"
|
|
2123
|
+
pack="vuesax"
|
|
2124
|
+
variant="linear"
|
|
2125
|
+
></lukso-icon>
|
|
2126
|
+
</lukso-button>
|
|
2127
|
+
</lukso-tooltip>
|
|
2128
|
+
<lukso-dropdown
|
|
2129
|
+
id="alignmentDropdown"
|
|
2130
|
+
trigger-id=""
|
|
2131
|
+
size="medium"
|
|
2132
|
+
?is-open=${this.isAlignmentDropdownOpen}
|
|
2133
|
+
>
|
|
2134
|
+
<lukso-dropdown-option
|
|
2135
|
+
?is-selected=${this.activeFormats.alignment === "left"}
|
|
2136
|
+
@click=${(e) => {
|
|
2137
|
+
e.stopPropagation();
|
|
2138
|
+
this.restoreFocusAndSelection();
|
|
2139
|
+
this.applyAlignment("left");
|
|
2140
|
+
this.isAlignmentDropdownOpen = false;
|
|
2141
|
+
}}
|
|
2142
|
+
size="medium"
|
|
2143
|
+
aria-label="Align left"
|
|
2144
|
+
>
|
|
2145
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
2146
|
+
<lukso-icon
|
|
2147
|
+
name="textalign-left"
|
|
2148
|
+
size="small"
|
|
2149
|
+
pack="vuesax"
|
|
2150
|
+
variant="linear"
|
|
2151
|
+
></lukso-icon>
|
|
2152
|
+
Left
|
|
2153
|
+
</div>
|
|
2154
|
+
</lukso-dropdown-option>
|
|
2155
|
+
<lukso-dropdown-option
|
|
2156
|
+
?is-selected=${this.activeFormats.alignment === "center"}
|
|
2157
|
+
@click=${(e) => {
|
|
2158
|
+
e.stopPropagation();
|
|
2159
|
+
this.restoreFocusAndSelection();
|
|
2160
|
+
this.applyAlignment("center");
|
|
2161
|
+
this.isAlignmentDropdownOpen = false;
|
|
2162
|
+
}}
|
|
2163
|
+
size="medium"
|
|
2164
|
+
aria-label="Align center"
|
|
2165
|
+
>
|
|
2166
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
2167
|
+
<lukso-icon
|
|
2168
|
+
name="textalign-center"
|
|
2169
|
+
size="small"
|
|
2170
|
+
pack="vuesax"
|
|
2171
|
+
variant="linear"
|
|
2172
|
+
></lukso-icon>
|
|
2173
|
+
Center
|
|
2174
|
+
</div>
|
|
2175
|
+
</lukso-dropdown-option>
|
|
2176
|
+
<lukso-dropdown-option
|
|
2177
|
+
?is-selected=${this.activeFormats.alignment === "right"}
|
|
2178
|
+
@click=${(e) => {
|
|
2179
|
+
e.stopPropagation();
|
|
2180
|
+
this.restoreFocusAndSelection();
|
|
2181
|
+
this.applyAlignment("right");
|
|
2182
|
+
this.isAlignmentDropdownOpen = false;
|
|
2183
|
+
}}
|
|
2184
|
+
size="medium"
|
|
2185
|
+
aria-label="Align right"
|
|
2186
|
+
>
|
|
2187
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
2188
|
+
<lukso-icon
|
|
2189
|
+
name="textalign-right"
|
|
2190
|
+
size="small"
|
|
2191
|
+
pack="vuesax"
|
|
2192
|
+
variant="linear"
|
|
2193
|
+
></lukso-icon>
|
|
2194
|
+
Right
|
|
2195
|
+
</div>
|
|
2196
|
+
</lukso-dropdown-option>
|
|
2197
|
+
</lukso-dropdown>
|
|
2198
|
+
</div>
|
|
2199
|
+
|
|
1808
2200
|
<!-- Color -->
|
|
1809
2201
|
<div class=${this.styles().colorMenu()}>
|
|
1810
2202
|
<lukso-tooltip text="Text color" placement="top">
|
|
@@ -1815,6 +2207,7 @@ ${indent}${nextNumber}. `;
|
|
|
1815
2207
|
this.restoreFocusAndSelection();
|
|
1816
2208
|
this.isHeadingDropdownOpen = false;
|
|
1817
2209
|
this.isListDropdownOpen = false;
|
|
2210
|
+
this.isAlignmentDropdownOpen = false;
|
|
1818
2211
|
if (!this.isColorDropdownOpen) {
|
|
1819
2212
|
const ta = this.textareaEl?.shadowRoot?.querySelector("textarea");
|
|
1820
2213
|
if (ta) {
|
|
@@ -1860,6 +2253,7 @@ ${indent}${nextNumber}. `;
|
|
|
1860
2253
|
this.isColorDropdownOpen = false;
|
|
1861
2254
|
}}
|
|
1862
2255
|
type="button"
|
|
2256
|
+
aria-label="Clear color"
|
|
1863
2257
|
>
|
|
1864
2258
|
Clear
|
|
1865
2259
|
</button>` : E}
|
|
@@ -1871,6 +2265,7 @@ ${indent}${nextNumber}. `;
|
|
|
1871
2265
|
style="background-color: ${color}"
|
|
1872
2266
|
title=${color}
|
|
1873
2267
|
aria-pressed=${this.activeFormats.activeColor === color ? "true" : "false"}
|
|
2268
|
+
aria-label="Color ${color}"
|
|
1874
2269
|
@click=${(e) => {
|
|
1875
2270
|
e.stopPropagation();
|
|
1876
2271
|
this.selectColor(color);
|
|
@@ -1937,7 +2332,7 @@ __decorateClass([
|
|
|
1937
2332
|
n({ type: String })
|
|
1938
2333
|
], LuksoMarkdownEditor.prototype, "value", 2);
|
|
1939
2334
|
__decorateClass([
|
|
1940
|
-
n({ type: String })
|
|
2335
|
+
n({ type: String, reflect: true })
|
|
1941
2336
|
], LuksoMarkdownEditor.prototype, "name", 2);
|
|
1942
2337
|
__decorateClass([
|
|
1943
2338
|
n({ type: String })
|
|
@@ -1987,6 +2382,9 @@ __decorateClass([
|
|
|
1987
2382
|
__decorateClass([
|
|
1988
2383
|
r()
|
|
1989
2384
|
], LuksoMarkdownEditor.prototype, "isListDropdownOpen", 2);
|
|
2385
|
+
__decorateClass([
|
|
2386
|
+
r()
|
|
2387
|
+
], LuksoMarkdownEditor.prototype, "isAlignmentDropdownOpen", 2);
|
|
1990
2388
|
__decorateClass([
|
|
1991
2389
|
r()
|
|
1992
2390
|
], LuksoMarkdownEditor.prototype, "currentSelection", 2);
|