@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.
Files changed (110) hide show
  1. package/dist/components/index.cjs +4 -4
  2. package/dist/components/index.js +4 -4
  3. package/dist/components/lukso-button/index.cjs +3 -3
  4. package/dist/components/lukso-button/index.js +3 -3
  5. package/dist/components/lukso-card/index.cjs +6 -6
  6. package/dist/components/lukso-card/index.js +6 -6
  7. package/dist/components/lukso-checkbox/index.cjs +3 -3
  8. package/dist/components/lukso-checkbox/index.js +3 -3
  9. package/dist/components/lukso-collapse/index.cjs +3 -3
  10. package/dist/components/lukso-collapse/index.js +3 -3
  11. package/dist/components/lukso-color-picker/index.cjs +4 -4
  12. package/dist/components/lukso-color-picker/index.js +4 -4
  13. package/dist/components/lukso-dropdown/index.cjs +4 -4
  14. package/dist/components/lukso-dropdown/index.js +4 -4
  15. package/dist/components/lukso-dropdown-option/index.cjs +2 -2
  16. package/dist/components/lukso-dropdown-option/index.js +2 -2
  17. package/dist/components/lukso-footer/index.cjs +2 -2
  18. package/dist/components/lukso-footer/index.js +2 -2
  19. package/dist/components/lukso-icon/icons/logo-hyperlane-mono.d.ts +3 -0
  20. package/dist/components/lukso-icon/icons/logo-hyperlane-mono.d.ts.map +1 -0
  21. package/dist/components/lukso-icon/icons/logo-hyperlane.d.ts +3 -0
  22. package/dist/components/lukso-icon/icons/logo-hyperlane.d.ts.map +1 -0
  23. package/dist/components/lukso-icon/icons/token-create.d.ts +3 -0
  24. package/dist/components/lukso-icon/icons/token-create.d.ts.map +1 -0
  25. package/dist/components/lukso-icon/index.cjs +136 -16
  26. package/dist/components/lukso-icon/index.d.ts +4 -4
  27. package/dist/components/lukso-icon/index.d.ts.map +1 -1
  28. package/dist/components/lukso-icon/index.js +136 -16
  29. package/dist/components/lukso-icon/lukso-icon.stories.d.ts +15 -1
  30. package/dist/components/lukso-icon/lukso-icon.stories.d.ts.map +1 -1
  31. package/dist/components/lukso-image/index.cjs +4 -4
  32. package/dist/components/lukso-image/index.js +4 -4
  33. package/dist/components/lukso-input/index.cjs +3 -3
  34. package/dist/components/lukso-input/index.js +3 -3
  35. package/dist/components/lukso-markdown/index.cjs +11 -5
  36. package/dist/components/lukso-markdown/index.d.ts +4 -2
  37. package/dist/components/lukso-markdown/index.d.ts.map +1 -1
  38. package/dist/components/lukso-markdown/index.js +11 -5
  39. package/dist/components/lukso-markdown/lukso-markdown.stories.d.ts +3 -0
  40. package/dist/components/lukso-markdown/lukso-markdown.stories.d.ts.map +1 -1
  41. package/dist/components/lukso-markdown-editor/index.cjs +512 -114
  42. package/dist/components/lukso-markdown-editor/index.d.ts +40 -1
  43. package/dist/components/lukso-markdown-editor/index.d.ts.map +1 -1
  44. package/dist/components/lukso-markdown-editor/index.js +512 -114
  45. package/dist/components/lukso-markdown-editor/lukso-markdown-editor.stories.d.ts +53 -1
  46. package/dist/components/lukso-markdown-editor/lukso-markdown-editor.stories.d.ts.map +1 -1
  47. package/dist/components/lukso-modal/index.cjs +2 -2
  48. package/dist/components/lukso-modal/index.js +2 -2
  49. package/dist/components/lukso-navbar/index.cjs +3 -3
  50. package/dist/components/lukso-navbar/index.js +3 -3
  51. package/dist/components/lukso-pagination/index.cjs +3 -3
  52. package/dist/components/lukso-pagination/index.js +3 -3
  53. package/dist/components/lukso-profile/index.cjs +3 -3
  54. package/dist/components/lukso-profile/index.js +3 -3
  55. package/dist/components/lukso-progress/index.cjs +3 -3
  56. package/dist/components/lukso-progress/index.js +3 -3
  57. package/dist/components/lukso-radio/index.cjs +3 -3
  58. package/dist/components/lukso-radio/index.js +3 -3
  59. package/dist/components/lukso-radio-group/index.cjs +3 -3
  60. package/dist/components/lukso-radio-group/index.js +3 -3
  61. package/dist/components/lukso-sanitize/index.cjs +3 -3
  62. package/dist/components/lukso-sanitize/index.js +3 -3
  63. package/dist/components/lukso-search/index.cjs +6 -6
  64. package/dist/components/lukso-search/index.js +6 -6
  65. package/dist/components/lukso-select/index.cjs +5 -5
  66. package/dist/components/lukso-select/index.js +5 -5
  67. package/dist/components/lukso-share/index.cjs +2 -2
  68. package/dist/components/lukso-share/index.js +2 -2
  69. package/dist/components/lukso-switch/index.cjs +3 -3
  70. package/dist/components/lukso-switch/index.js +3 -3
  71. package/dist/components/lukso-tag/index.cjs +3 -3
  72. package/dist/components/lukso-tag/index.js +3 -3
  73. package/dist/components/lukso-terms/index.cjs +3 -3
  74. package/dist/components/lukso-terms/index.js +3 -3
  75. package/dist/components/lukso-textarea/index.cjs +3 -3
  76. package/dist/components/lukso-textarea/index.js +3 -3
  77. package/dist/components/lukso-tooltip/index.cjs +3 -3
  78. package/dist/components/lukso-tooltip/index.js +3 -3
  79. package/dist/components/lukso-username/index.cjs +4 -4
  80. package/dist/components/lukso-username/index.js +4 -4
  81. package/dist/components/lukso-wizard/index.cjs +2 -2
  82. package/dist/components/lukso-wizard/index.js +2 -2
  83. package/dist/docs/Icons.stories.d.ts.map +1 -1
  84. package/dist/{index-D4HqZcbk.cjs → index-BR_I57SD.cjs} +2 -2
  85. package/dist/{index-D-a6OWyj.cjs → index-BvQ5tHy1.cjs} +1 -1
  86. package/dist/{index-1cnTXnRX.js → index-CzJGpXul.js} +3 -3
  87. package/dist/{index-CO57mpzm.cjs → index-DGEC4kLx.cjs} +5 -5
  88. package/dist/{index-CsepkLbs.js → index-DI0bldib.js} +1 -1
  89. package/dist/{index-KrWvJ44l.cjs → index-Da-0kQ05.cjs} +1 -1
  90. package/dist/{index-D9mdD_OM.cjs → index-QfURPzjM.cjs} +3 -3
  91. package/dist/{index-B5_11hN3.js → index-bOsUG-kI.js} +5 -5
  92. package/dist/{index-DFculCCQ.js → index-g9LnjUjQ.js} +2 -2
  93. package/dist/{index-BWp0TAbf.js → index-wzuGnJOC.js} +1 -1
  94. package/dist/index.cjs +4 -4
  95. package/dist/index.js +4 -4
  96. package/dist/{property-DkFGx5Fg.js → property-BohUfInC.js} +1 -1
  97. package/dist/{property-CLMAG2Rj.cjs → property-C7opy5D6.cjs} +1 -1
  98. package/dist/shared/tailwind-element/index.cjs +1 -1
  99. package/dist/shared/tailwind-element/index.js +1 -1
  100. package/dist/{state-DPXXwNMf.js → state-DJBtqv5G.js} +1 -1
  101. package/dist/{state-DXBdLH-W.cjs → state-De1ciDiG.cjs} +1 -1
  102. package/dist/{style-map-CXXmrGLe.js → style-map-BXvyZNeB.js} +1 -1
  103. package/dist/{style-map-BFG88xg5.cjs → style-map-BjMzqR4L.cjs} +1 -1
  104. package/dist/{unsafe-html-C4RqiLkE.js → unsafe-html-Bs5tNJGm.js} +1 -1
  105. package/dist/{unsafe-html-CxwvRvgp.cjs → unsafe-html-D9Z4CuNa.cjs} +1 -1
  106. package/dist/vitest.config.d.ts.map +1 -1
  107. package/package.json +1 -1
  108. package/tailwind.config.cjs +14 -1
  109. package/LICENSE +0 -21
  110. package/README.md +0 -146
@@ -1,6 +1,6 @@
1
- import { T as TailwindStyledElement, E, x } from '../../index-BWp0TAbf.js';
2
- import { n, t } from '../../property-DkFGx5Fg.js';
3
- import { r } from '../../state-DPXXwNMf.js';
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-3 for heading levels
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 before = value.slice(0, s);
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 foundMatch = false;
975
- const searchText = value.slice(
976
- Math.max(0, s - 100),
977
- Math.min(value.length, e + 100)
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 matchStart = searchOffset + match.index;
983
- const matchEnd = searchOffset + match.index + match[0].length;
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 = searchOffset + match.index + spanOpenTag.length;
986
- const contentEnd = matchEnd - 7;
987
- if (contentStart <= s && e <= contentEnd) {
988
- const beforeContent = value.slice(contentStart, s);
989
- const afterContent = value.slice(e, contentEnd);
990
- const newContent = beforeContent + selected + afterContent;
991
- this.value = value.slice(0, matchStart) + newContent + value.slice(matchEnd);
992
- textarea.value = value.slice(0, matchStart) + newContent + value.slice(matchEnd);
993
- const selStart = matchStart + beforeContent.length;
994
- const selEnd = selStart + selected.length;
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(selStart, selEnd);
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
- foundMatch = true;
1001
- break;
1195
+ return;
1002
1196
  }
1003
- match = fullColorRegex.exec(searchText);
1004
1197
  }
1005
- if (!foundMatch) {
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) return false;
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) return false;
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
- requestAnimationFrame(() => {
1134
- textarea.setSelectionRange(newCursor, newCursor);
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
- let nextNumber = parseInt(numberStr, 10) + 1;
1159
- const beforeText = value.slice(0, lineStart);
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
- const newValue = before + prefix + after;
1180
- const renumberedValue = this.renumberOrderedListItems(
1181
- newValue,
1182
- start + prefix.length,
1183
- indent
1184
- );
1185
- this.value = renumberedValue;
1186
- textarea.value = renumberedValue;
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
- requestAnimationFrame(() => {
1189
- textarea.setSelectionRange(newCursor, newCursor);
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) return false;
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) return false;
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
- newLine = `${currentIndent}${indent}1. ${content}`;
1235
- newCursorOffset = indent.length;
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
- const newValue = before + newLine + after;
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
- requestAnimationFrame(() => {
1245
- textarea.setSelectionRange(newCursor, newCursor);
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
- if (cursorPositionInLine === markerEndPosition && !hasContent) {
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
- lineEnd === value.length ? lineEnd : lineEnd + 1
1461
- );
1462
- let newValue = before + after;
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
- newValue = this.renumberOrderedListItems(
1466
- newValue,
1467
- before.length,
1468
- indent
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") && before.length > 1) {
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);