@sequent-org/moodboard 1.4.56 → 1.4.57

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.
@@ -206,10 +206,27 @@
206
206
  height: 36px;
207
207
  }
208
208
 
209
+ .text-properties-panel.is-locked {
210
+ min-width: 0;
211
+ padding: 0 6px;
212
+ gap: 4px;
213
+ }
214
+
209
215
  .text-properties-panel * {
210
216
  max-height: 36px;
211
217
  }
212
218
 
219
+ .text-properties-panel [id^="tpp-color-dropdown"],
220
+ .text-properties-panel [id^="tpp-color-dropdown"] *,
221
+ .text-properties-panel [id^="tpp-bgcolor-dropdown"],
222
+ .text-properties-panel [id^="tpp-bgcolor-dropdown"] *,
223
+ .text-properties-panel [id^="tpp-highlight-dropdown"],
224
+ .text-properties-panel [id^="tpp-highlight-dropdown"] *,
225
+ .text-properties-panel .tpp-more-dropdown,
226
+ .text-properties-panel .tpp-more-dropdown * {
227
+ max-height: none;
228
+ }
229
+
213
230
  /* Frame properties toolbar — mirror image toolbar look */
214
231
  .frame-properties-panel {
215
232
  position: absolute;
@@ -615,10 +632,10 @@
615
632
 
616
633
  .text-properties-panel .font-select {
617
634
  box-sizing: border-box;
618
- min-width: 90px;
619
- width: 90px;
635
+ min-width: 70px;
636
+ width: 70px;
620
637
  height: 38px;
621
- padding: 4px 8px;
638
+ padding: 4px 0px;
622
639
  font-size: 13px;
623
640
  background-color: #fff;
624
641
  border: none;
@@ -741,12 +758,12 @@
741
758
  border: none;
742
759
  padding: 0;
743
760
  cursor: pointer;
744
- color: #666;
761
+ color: #6B7280;
745
762
  }
746
763
 
747
764
  .text-properties-panel .font-size-stepper:hover {
748
765
  background: #f5f5f5;
749
- color: #333;
766
+ color: #111827;
750
767
  }
751
768
 
752
769
  .text-properties-panel .font-size-stepper--down {
@@ -754,11 +771,10 @@
754
771
  margin-top: -2px;
755
772
  }
756
773
 
757
- .text-properties-panel .current-color-button,
758
774
  .text-properties-panel .current-bgcolor-button {
759
- width: 28px;
760
- height: 28px;
761
- border: 1px solid #ddd;
775
+ width: 20px;
776
+ height: 20px;
777
+ border: none;
762
778
  border-radius: 50%;
763
779
  background-color: #000;
764
780
  cursor: pointer;
@@ -769,6 +785,54 @@
769
785
  position: relative;
770
786
  }
771
787
 
788
+ .text-properties-panel .current-color-button {
789
+ width: 28px;
790
+ height: 28px;
791
+ border: 1px solid transparent;
792
+ border-radius: 4px;
793
+ background-color: transparent;
794
+ cursor: pointer;
795
+ margin: 0;
796
+ padding: 0;
797
+ display: flex;
798
+ flex-direction: column;
799
+ align-items: center;
800
+ justify-content: center;
801
+ box-sizing: border-box;
802
+ position: relative;
803
+ transition: background 0.15s;
804
+ color: #6B7280;
805
+ }
806
+
807
+ .text-properties-panel .current-color-button:hover {
808
+ background: #f0f0f0;
809
+ color: #111827;
810
+ }
811
+
812
+ .text-properties-panel .current-highlight-button {
813
+ width: 28px;
814
+ height: 28px;
815
+ border: 1px solid transparent;
816
+ border-radius: 4px;
817
+ background-color: transparent;
818
+ cursor: pointer;
819
+ margin: 0;
820
+ padding: 0;
821
+ display: flex;
822
+ flex-direction: column;
823
+ align-items: center;
824
+ justify-content: center;
825
+ box-sizing: border-box;
826
+ position: relative;
827
+ transition: background 0.15s;
828
+ color: #6B7280;
829
+ }
830
+
831
+ .text-properties-panel .current-highlight-button:hover {
832
+ background: #f0f0f0;
833
+ color: #111827;
834
+ }
835
+
772
836
  .text-properties-panel .tpp-format-btn {
773
837
  height: 28px;
774
838
  min-width: 28px;
@@ -780,17 +844,29 @@
780
844
  display: inline-flex;
781
845
  align-items: center;
782
846
  justify-content: center;
783
- color: #444;
847
+ color: #6B7280;
784
848
  flex-shrink: 0;
785
- transition: background 0.15s;
849
+ transition: background 0.15s, color 0.15s;
786
850
  }
787
- .text-properties-panel .tpp-format-btn:hover { background: #f0f0f0; }
851
+ .text-properties-panel .tpp-format-btn:hover { background: #f0f0f0; color: #111827; }
788
852
  .text-properties-panel .tpp-format-btn.is-active {
789
853
  background: #e8eaff;
790
854
  border-color: #6155F5;
791
855
  color: #6155F5;
792
856
  }
793
857
 
858
+ .text-properties-panel .tpp-format-btns-wrapper {
859
+ width: 24px;
860
+ height: 24px;
861
+ }
862
+
863
+ .text-properties-panel .tpp-format-btn.tpp-format-trigger {
864
+ width: 24px;
865
+ min-width: 24px;
866
+ height: 24px;
867
+ padding: 0;
868
+ }
869
+
794
870
  .text-properties-panel .tpp-list-btns {
795
871
  display: flex;
796
872
  gap: 2px;
@@ -817,6 +893,21 @@
817
893
  z-index: 4000;
818
894
  }
819
895
 
896
+ .text-properties-panel .tpp-format-modal {
897
+ max-height: none;
898
+ position: absolute;
899
+ top: calc(100% + 4px);
900
+ left: 0;
901
+ flex-direction: row;
902
+ gap: 2px;
903
+ background: #ffffff;
904
+ border: 1px solid #E5E7EB;
905
+ border-radius: 6px;
906
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.06);
907
+ padding: 4px;
908
+ z-index: 4000;
909
+ }
910
+
820
911
  .text-properties-panel .tpp-list-modal-option {
821
912
  display: flex;
822
913
  align-items: center;
@@ -833,6 +924,26 @@
833
924
  flex-shrink: 0;
834
925
  }
835
926
 
927
+ .text-properties-panel .tpp-format-modal-option {
928
+ display: flex;
929
+ align-items: center;
930
+ justify-content: center;
931
+ width: 28px;
932
+ height: 28px;
933
+ padding: 0;
934
+ border: none;
935
+ background: transparent;
936
+ border-radius: 4px;
937
+ cursor: pointer;
938
+ color: #374151;
939
+ transition: background 0.1s;
940
+ flex-shrink: 0;
941
+ }
942
+
943
+ .text-properties-panel .tpp-format-modal-option:hover {
944
+ background: #f3f4f6;
945
+ }
946
+
836
947
  .text-properties-panel .tpp-list-modal-option:hover {
837
948
  background: #f3f4f6;
838
949
  }
@@ -887,6 +998,34 @@
887
998
  background: #f3f4f6;
888
999
  }
889
1000
 
1001
+ .text-properties-panel .tpp-lh-control {
1002
+ display: flex;
1003
+ align-items: center;
1004
+ position: relative;
1005
+ }
1006
+
1007
+ .text-properties-panel .tpp-lh-control svg {
1008
+ width: 22px;
1009
+ height: 22px;
1010
+ }
1011
+
1012
+ .text-properties-panel .tpp-lh-modal {
1013
+ max-height: none;
1014
+ position: absolute;
1015
+ top: calc(100% + 4px);
1016
+ left: 50%;
1017
+ transform: translateX(-50%);
1018
+ flex-direction: row;
1019
+ align-items: center;
1020
+ justify-content: center;
1021
+ background: #ffffff;
1022
+ border: 1px solid #E5E7EB;
1023
+ border-radius: 6px;
1024
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.06);
1025
+ padding: 8px 12px;
1026
+ z-index: 4000;
1027
+ }
1028
+
890
1029
  .text-properties-panel .tpp-lh-slider {
891
1030
  width: 68px;
892
1031
  accent-color: #6155F5;
@@ -1091,7 +1230,7 @@
1091
1230
  }
1092
1231
 
1093
1232
  /* More Dropdown */
1094
- .ipp-more-dropdown {
1233
+ .ipp-more-dropdown, .tpp-more-dropdown {
1095
1234
  position: absolute;
1096
1235
  top: calc(100% + 6px);
1097
1236
  right: 0;
@@ -1106,11 +1245,15 @@
1106
1245
  z-index: 1001;
1107
1246
  }
1108
1247
 
1109
- .ipp-more-dropdown.is-open {
1248
+ .ipp-more-dropdown.is-open, .tpp-more-dropdown.is-open {
1110
1249
  display: flex;
1250
+ position: fixed;
1251
+ min-width: 0;
1252
+ max-width: 214px;
1253
+ width: 214px;
1111
1254
  }
1112
1255
 
1113
- .ipp-dropdown-item {
1256
+ .ipp-dropdown-item, .tpp-dropdown-item {
1114
1257
  display: flex;
1115
1258
  align-items: center;
1116
1259
  padding: 6px 8px;
@@ -1127,7 +1270,7 @@
1127
1270
  width: 100%;
1128
1271
  }
1129
1272
 
1130
- .ipp-dropdown-item:hover {
1273
+ .ipp-dropdown-item:hover, .tpp-dropdown-item:hover {
1131
1274
  background: #F3F4F6;
1132
1275
  }
1133
1276
 
@@ -1137,19 +1280,19 @@
1137
1280
  font-size: 12px;
1138
1281
  }
1139
1282
 
1140
- .ipp-dropdown-item-shortcut {
1283
+ .ipp-dropdown-item-shortcut, .tpp-dropdown-item-shortcut {
1141
1284
  margin-left: auto;
1142
1285
  color: #9CA3AF;
1143
1286
  font-size: 12px;
1144
1287
  }
1145
1288
 
1146
- .ipp-dropdown-divider {
1289
+ .ipp-dropdown-divider, .tpp-dropdown-divider {
1147
1290
  height: 1px;
1148
1291
  background: #E5E7EB;
1149
1292
  margin: 4px 2px;
1150
1293
  }
1151
1294
 
1152
- .ipp-dropdown-icon {
1295
+ .ipp-dropdown-icon, .tpp-dropdown-icon {
1153
1296
  width: 16px;
1154
1297
  height: 16px;
1155
1298
  display: inline-flex;
@@ -1585,3 +1728,81 @@
1585
1728
  opacity: 1;
1586
1729
  }
1587
1730
 
1731
+ /* ── Кнопка «Ссылка» в панели свойств текста ────────────────── */
1732
+ .tpp-link-btn:disabled,
1733
+ .tpp-link-btn--disabled {
1734
+ opacity: 0.35;
1735
+ cursor: not-allowed;
1736
+ pointer-events: none;
1737
+ }
1738
+
1739
+ /* ── Форма ввода URL ─────────────────────────────────────────── */
1740
+ .tpp-link-form {
1741
+ position: fixed;
1742
+ z-index: 10010;
1743
+ display: flex;
1744
+ flex-direction: column;
1745
+ gap: 6px;
1746
+ background: #ffffff;
1747
+ border: 1px solid #E5E7EB;
1748
+ border-radius: 10px;
1749
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.07);
1750
+ padding: 10px 12px;
1751
+ min-width: 260px;
1752
+ max-width: 340px;
1753
+ }
1754
+
1755
+ .tpp-link-form-label {
1756
+ font-size: 11px;
1757
+ color: #6B7280;
1758
+ white-space: nowrap;
1759
+ overflow: hidden;
1760
+ text-overflow: ellipsis;
1761
+ max-width: 100%;
1762
+ }
1763
+
1764
+ .tpp-link-form-row {
1765
+ display: flex;
1766
+ gap: 6px;
1767
+ align-items: center;
1768
+ }
1769
+
1770
+ .tpp-link-input {
1771
+ flex: 1;
1772
+ height: 30px;
1773
+ padding: 0 8px;
1774
+ border: 1px solid #D1D5DB;
1775
+ border-radius: 6px;
1776
+ font-size: 13px;
1777
+ font-family: inherit;
1778
+ outline: none;
1779
+ color: #111827;
1780
+ transition: border-color 0.15s;
1781
+ }
1782
+
1783
+ .tpp-link-input:focus {
1784
+ border-color: #6366F1;
1785
+ }
1786
+
1787
+ .tpp-link-input--error {
1788
+ border-color: #EF4444;
1789
+ }
1790
+
1791
+ .tpp-link-form-ok {
1792
+ height: 30px;
1793
+ padding: 0 12px;
1794
+ background: #6366F1;
1795
+ color: #ffffff;
1796
+ border: none;
1797
+ border-radius: 6px;
1798
+ font-size: 13px;
1799
+ font-family: inherit;
1800
+ cursor: pointer;
1801
+ flex-shrink: 0;
1802
+ transition: background 0.15s;
1803
+ }
1804
+
1805
+ .tpp-link-form-ok:hover {
1806
+ background: #4F46E5;
1807
+ }
1808
+
@@ -288,7 +288,7 @@
288
288
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
289
289
  font-size: 13px;
290
290
  font-family: 'Roboto', Arial, sans-serif;
291
- min-width: 320px;
291
+ min-width: auto;
292
292
  height: 36px;
293
293
  }
294
294
 
@@ -321,6 +321,21 @@
321
321
  letter-spacing: normal;
322
322
  }
323
323
 
324
+ /* Веб-ссылка внутри текстового объекта. pointer-events: auto переопределяет
325
+ pointer-events: none у родительского .mb-text и .moodboard-html-layer,
326
+ чтобы по ссылке можно было реально перейти. */
327
+ .mb-text-link {
328
+ color: #2563EB;
329
+ text-decoration: underline;
330
+ text-underline-offset: 2px;
331
+ pointer-events: auto;
332
+ cursor: pointer;
333
+ }
334
+
335
+ .mb-text-link:hover {
336
+ color: #1D4ED8;
337
+ }
338
+
324
339
  /* Markdown-режим текстового объекта: блочный рендер, перенос по словам */
325
340
  .mb-text--md {
326
341
  white-space: normal;
@@ -688,9 +703,6 @@
688
703
 
689
704
  .text-properties-panel .current-color-button,
690
705
  .text-properties-panel .current-bgcolor-button {
691
- width: 28px;
692
- height: 20px;
693
- border: 1px solid #ddd;
694
706
  border-radius: 4px;
695
707
  background-color: #000;
696
708
  cursor: pointer;
@@ -700,6 +712,18 @@
700
712
  box-sizing: border-box;
701
713
  position: relative;
702
714
  }
715
+
716
+ .text-properties-panel .current-color-button {
717
+ width: 20px;
718
+ height: 20px;
719
+ border: 1px solid #ddd;
720
+ }
721
+
722
+ .text-properties-panel .current-bgcolor-button {
723
+ width: 20px;
724
+ height: 20px;
725
+ border: none;
726
+ }
703
727
  /* MoodBoard Workspace Styles */
704
728
 
705
729
  /* Основные контейнеры */
@@ -1548,8 +1572,8 @@
1548
1572
  transition: all 0.2s ease;
1549
1573
  outline: none;
1550
1574
  outline-offset: 0;
1551
- padding-top: 5px;
1552
- padding-bottom: 5px;
1575
+ padding-top: 1px;
1576
+ padding-bottom: 1px;
1553
1577
  }
1554
1578
 
1555
1579
  .moodboard-text-input:focus {
@@ -6,10 +6,11 @@ import {
6
6
  } from './TextPropertiesPanelMapper.js';
7
7
 
8
8
  // Статичные SVG-строки (lucide-style). innerHTML допустим — это доверенные константы, не пользовательский ввод.
9
- const SVG_BOLD = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/><path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/></svg>';
10
- const SVG_ITALIC = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/></svg>';
11
- const SVG_UNDERLINE = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4v6a6 6 0 0 0 12 0V4"/><line x1="4" y1="20" x2="20" y2="20"/></svg>';
12
- const SVG_STRIKE = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 4H9a3 3 0 0 0-2.83 4"/><path d="M14 12a4 4 0 0 1 0 8H6"/><line x1="4" y1="12" x2="20" y2="12"/></svg>';
9
+ const SVG_TEXT_FORMAT = '<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" type="text-format" size="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M7.54459 15.3341C7.52012 15.4823 7.52819 15.634 7.56823 15.7787C7.60828 15.9234 7.67935 16.0576 7.77651 16.1721C7.87366 16.2866 7.99458 16.3786 8.13085 16.4416C8.26712 16.5047 8.41548 16.5373 8.56563 16.5372H11.9587C12.8918 16.5372 13.6811 16.3966 14.3277 16.1141C14.9742 15.8286 15.4822 15.4417 15.8505 14.9566C16.2229 14.4662 16.4608 13.9138 16.5674 13.2993C16.6656 12.6755 16.6242 12.1469 16.4432 11.7124C16.2632 11.2779 16.0005 10.9417 15.657 10.7069C15.3354 10.4746 14.9536 10.3399 14.5574 10.319L14.5801 10.201C14.9567 10.1079 15.3146 9.9569 15.656 9.74897C15.9974 9.54207 16.287 9.2669 16.526 8.92552C16.7691 8.58414 16.9315 8.16414 17.0142 7.66241C17.1156 7.06655 17.0691 6.53172 16.8725 6.05793C16.676 5.58 16.3201 5.20138 15.8029 4.9231C15.2898 4.64069 14.607 4.5 13.7515 4.5H10.2208C9.97593 4.50011 9.73904 4.58708 9.55227 4.74544C9.3655 4.9038 9.24096 5.12328 9.2008 5.36483L7.54563 15.3341H7.54459ZM12.0415 14.9803H9.42011L10.0667 11.1238H12.7522C13.2384 11.1238 13.6418 11.2179 13.9625 11.4062C14.2884 11.5945 14.5201 11.8469 14.6567 12.1645C14.7974 12.4821 14.8387 12.8307 14.7808 13.2114C14.6898 13.7162 14.428 14.1372 13.9925 14.4745C13.5622 14.8117 12.9115 14.9803 12.0415 14.9803ZM12.7346 9.70759H10.3077L10.9077 6.04552H13.3874C14.1042 6.04552 14.608 6.21414 14.8977 6.55138C15.1915 6.88448 15.296 7.30138 15.2091 7.8031C15.1511 8.1869 15.0022 8.52207 14.7632 8.80862C14.5274 9.09414 14.2315 9.31552 13.8756 9.47276C13.5229 9.62897 13.1422 9.70759 12.7346 9.70759ZM6.56908 17.9483C6.3633 17.9483 6.16596 18.03 6.02046 18.1755C5.87496 18.321 5.79321 18.5184 5.79321 18.7241C5.79321 18.9299 5.87496 19.1273 6.02046 19.2728C6.16596 19.4183 6.3633 19.5 6.56908 19.5H17.4311C17.6369 19.5 17.8343 19.4183 17.9798 19.2728C18.1253 19.1273 18.207 18.9299 18.207 18.7241C18.207 18.5184 18.1253 18.321 17.9798 18.1755C17.8343 18.03 17.6369 17.9483 17.4311 17.9483H6.56908Z"></path></svg>';
10
+ const SVG_BOLD = '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6.92188 12H13.1719C14.8978 12 16.2969 10.6009 16.2969 8.875C16.2969 7.14911 14.8978 5.75 13.1719 5.75H6.92188V12ZM6.92188 12H13.9531C15.679 12 17.0781 13.3991 17.0781 15.125C17.0781 16.8509 15.679 18.25 13.9531 18.25H6.92188V12Z"></path></svg>';
11
+ const SVG_ITALIC = '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M17.4688 5.75H10.4375M13.5625 18.25H6.53125M14.3438 5.75L9.65625 18.25"></path></svg>';
12
+ const SVG_UNDERLINE = '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4v6a6 6 0 0 0 12 0V4"/><line x1="4" y1="20" x2="20" y2="20"/></svg>';
13
+ const SVG_STRIKE = '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M7.3125 15.125C7.3125 16.8509 8.71161 18.25 10.4375 18.25H13.5625C15.2884 18.25 16.6875 16.8509 16.6875 15.125C16.6875 13.3991 15.2884 12 13.5625 12M16.6875 8.875C16.6875 7.14911 15.2884 5.75 13.5625 5.75H10.4375C8.71161 5.75 7.3125 7.14911 7.3125 8.875M4.96875 12H19.0312"></path></svg>';
13
14
 
14
15
  const SVG_ALIGN_LEFT = '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><path d="M4.75 5.73633H19.25"/><path d="M4.75 18.2637H13.25"/><path d="M4.75 14.0879H19.25"/><path d="M4.75 9.91211L13.25 9.91211"/></svg>';
15
16
  const SVG_ALIGN_CENTER = '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><path d="M4.75 5.73633H19.25"/><path d="M7.75 18.2637H16.25"/><path d="M4.75 14.0879H19.25"/><path d="M7.75 9.91211L16.25 9.91211"/></svg>';
@@ -19,6 +20,7 @@ const SVG_ALIGN_JUSTIFY = '<svg width="24" height="24" viewBox="0 0 24 24" fill=
19
20
  const SVG_LIST_BULLET = '<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8.28516 5.49609H19.2852M8.28516 11H19.2852M8.28516 16.4961H19.2852M4.21484 17.25C4.62906 17.25 4.96484 16.9142 4.96484 16.5C4.96484 16.0858 4.62906 15.75 4.21484 15.75C3.80063 15.75 3.46484 16.0858 3.46484 16.5C3.46484 16.9142 3.80063 17.25 4.21484 17.25ZM4.21484 11.75C4.62906 11.75 4.96484 11.4142 4.96484 11C4.96484 10.5858 4.62906 10.25 4.21484 10.25C3.80063 10.25 3.46484 10.5858 3.46484 11C3.46484 11.4142 3.80063 11.75 4.21484 11.75ZM4.21484 6.24609C4.62906 6.24609 4.96484 5.91031 4.96484 5.49609C4.96484 5.08188 4.62906 4.74609 4.21484 4.74609C3.80063 4.74609 3.46484 5.08188 3.46484 5.49609C3.46484 5.91031 3.80063 6.24609 4.21484 6.24609Z"/></svg>';
20
21
  const SVG_LIST_NUMBERED = '<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M8.28516 5.49505H19.2852M8.28516 10.999H19.2852M8.28516 16.4951H19.2852M3.30078 5.32812L4.67578 4.64062V9.45312M3.39531 13.2839C3.45867 13.1269 3.55438 12.9853 3.67622 12.8678C3.79808 12.7505 3.9433 12.6602 4.10242 12.6027C4.26156 12.5453 4.43101 12.5221 4.59972 12.5345C4.76844 12.547 4.93262 12.595 5.08156 12.6752C5.23049 12.7555 5.36082 12.8662 5.46407 13.0002C5.56729 13.1343 5.6411 13.2885 5.68067 13.453C5.72022 13.6175 5.72466 13.7885 5.69366 13.9549C5.66266 14.1211 5.59693 14.279 5.50078 14.4182L3.30078 17.3573H5.70703"/></svg>';
21
22
  const SVG_LIST_CHECK = '<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M8.28516 5.49609H19.2852M8.28516 11H19.2852M8.28516 16.4961H19.2852M2.9 5.2L3.9 6.2L5.7 4.2M2.9 10.7L3.9 11.7L5.7 9.7M2.9 16.2L3.9 17.2L5.7 15.2"/></svg>';
23
+ const SVG_LINE_HEIGHT = '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" type="line-height-2" size="24"><path d="M6.02009 5.35419V18.6459M6.02009 5.35419L8.77156 8.10419M6.02009 5.35419L3.27156 8.10419M6.02009 18.6459L3.26862 15.8959M6.02009 18.6459L8.76862 15.8959" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"></path><path d="M13.6112 13.2205H18.9513M11.8311 17.481L15.633 7.47121C15.839 6.92904 15.9419 6.65795 16.0846 6.57385C16.2086 6.50077 16.3539 6.50077 16.4779 6.57385C16.6206 6.65795 16.7235 6.92904 16.9295 7.47121L20.7314 17.481" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
22
24
 
23
25
  function makeSep() {
24
26
  const d = document.createElement('div');
@@ -57,6 +59,7 @@ function makeListButtons() {
57
59
  triggerBtn.innerHTML = SVG_LIST_BULLET;
58
60
 
59
61
  const modal = document.createElement('div');
62
+ modal.id = `tpp-list-modal-${Date.now()}-${Math.floor(Math.random() * 10000)}`;
60
63
  modal.className = 'tpp-list-modal';
61
64
  modal.style.display = 'none';
62
65
 
@@ -161,6 +164,7 @@ function makeAlignButtons() {
161
164
 
162
165
  // Модальный попап
163
166
  const modal = document.createElement('div');
167
+ modal.id = `tpp-align-modal-${Date.now()}-${Math.floor(Math.random() * 10000)}`;
164
168
  modal.className = 'tpp-align-modal';
165
169
  modal.style.display = 'none';
166
170
 
@@ -248,33 +252,86 @@ function makeAlignButtons() {
248
252
  return proxy;
249
253
  }
250
254
 
251
- export function createTextFormatControls(panelInstance, panel) {
252
- panel.appendChild(makeSep());
255
+ function makeFormatButtons(panelInstance) {
256
+ const container = document.createElement('div');
257
+ container.className = 'tpp-format-btns-wrapper';
258
+ container.style.position = 'relative';
259
+ container.style.display = 'flex';
260
+
261
+ const triggerBtn = document.createElement('button');
262
+ triggerBtn.type = 'button';
263
+ triggerBtn.title = 'Форматирование текста';
264
+ triggerBtn.className = 'tpp-format-btn tpp-format-trigger';
265
+ triggerBtn.innerHTML = SVG_TEXT_FORMAT;
266
+
267
+ const modal = document.createElement('div');
268
+ modal.id = `tpp-format-modal-${Date.now()}-${Math.floor(Math.random() * 10000)}`;
269
+ modal.className = 'tpp-format-modal';
270
+ modal.style.display = 'none';
253
271
 
254
272
  panelInstance.boldBtn = makeToggleBtn(SVG_BOLD, 'Жирный', 'bold');
255
273
  panelInstance.italicBtn = makeToggleBtn(SVG_ITALIC, 'Курсив', 'italic');
256
274
  panelInstance.underlineBtn = makeToggleBtn(SVG_UNDERLINE, 'Подчёркнутый', 'underline');
257
275
  panelInstance.strikethroughBtn = makeToggleBtn(SVG_STRIKE, 'Зачёркнутый', 'strikethrough');
258
276
 
259
- [panelInstance.boldBtn, panelInstance.italicBtn, panelInstance.underlineBtn, panelInstance.strikethroughBtn].forEach(
260
- (btn) => panel.appendChild(btn),
261
- );
277
+ const btns = [
278
+ panelInstance.boldBtn,
279
+ panelInstance.italicBtn,
280
+ panelInstance.underlineBtn,
281
+ panelInstance.strikethroughBtn
282
+ ];
262
283
 
263
- panel.appendChild(makeSep());
284
+ btns.forEach((btn) => {
285
+ btn.classList.add('tpp-format-modal-option');
286
+ modal.appendChild(btn);
287
+ });
264
288
 
265
- panelInstance.alignControl = makeAlignButtons();
266
- panel.appendChild(panelInstance.alignControl._container);
289
+ container.appendChild(triggerBtn);
290
+ container.appendChild(modal);
267
291
 
268
- panelInstance.listControl = makeListButtons();
269
- panel.appendChild(panelInstance.listControl._container);
292
+ function openModal() {
293
+ modal.style.display = 'flex';
294
+ setTimeout(() => {
295
+ document.addEventListener('click', closeOnOutside);
296
+ }, 0);
297
+ }
270
298
 
271
- panel.appendChild(makeSep());
299
+ function closeModal() {
300
+ modal.style.display = 'none';
301
+ document.removeEventListener('click', closeOnOutside);
302
+ }
303
+
304
+ function closeOnOutside(e) {
305
+ if (!container.contains(e.target)) {
306
+ closeModal();
307
+ }
308
+ }
309
+
310
+ triggerBtn.addEventListener('click', (e) => {
311
+ e.stopPropagation();
312
+ if (modal.style.display === 'none') {
313
+ openModal();
314
+ } else {
315
+ closeModal();
316
+ }
317
+ });
318
+
319
+ return container;
320
+ }
321
+
322
+ function makeLineHeightControl(panelInstance) {
323
+ const container = document.createElement('div');
324
+ container.className = 'tpp-lh-control';
325
+
326
+ const triggerBtn = document.createElement('button');
327
+ triggerBtn.type = 'button';
328
+ triggerBtn.title = 'Межстрочный интервал';
329
+ triggerBtn.className = 'tpp-format-btn';
330
+ triggerBtn.innerHTML = SVG_LINE_HEIGHT;
272
331
 
273
- const lhLabel = document.createElement('span');
274
- lhLabel.className = 'tpp-label';
275
- lhLabel.title = 'Межстрочный интервал';
276
- lhLabel.textContent = '↕';
277
- panel.appendChild(lhLabel);
332
+ const modal = document.createElement('div');
333
+ modal.className = 'tpp-lh-modal';
334
+ modal.style.display = 'none';
278
335
 
279
336
  panelInstance.lineHeightSlider = document.createElement('input');
280
337
  panelInstance.lineHeightSlider.type = 'range';
@@ -283,5 +340,59 @@ export function createTextFormatControls(panelInstance, panel) {
283
340
  panelInstance.lineHeightSlider.max = String(LINE_HEIGHT_MAX);
284
341
  panelInstance.lineHeightSlider.step = String(LINE_HEIGHT_STEP);
285
342
  panelInstance.lineHeightSlider.value = String(LINE_HEIGHT_DEFAULT);
286
- panel.appendChild(panelInstance.lineHeightSlider);
343
+
344
+ modal.appendChild(panelInstance.lineHeightSlider);
345
+ container.appendChild(triggerBtn);
346
+ container.appendChild(modal);
347
+
348
+ function openModal() {
349
+ modal.style.display = 'flex';
350
+ triggerBtn.classList.add('is-active');
351
+ setTimeout(() => {
352
+ document.addEventListener('click', closeOnOutside);
353
+ }, 0);
354
+ }
355
+
356
+ function closeModal() {
357
+ modal.style.display = 'none';
358
+ triggerBtn.classList.remove('is-active');
359
+ document.removeEventListener('click', closeOnOutside);
360
+ }
361
+
362
+ function closeOnOutside(e) {
363
+ if (!container.contains(e.target)) {
364
+ closeModal();
365
+ }
366
+ }
367
+
368
+ triggerBtn.addEventListener('click', (e) => {
369
+ e.stopPropagation();
370
+ if (modal.style.display === 'none') {
371
+ openModal();
372
+ } else {
373
+ closeModal();
374
+ }
375
+ });
376
+
377
+ return container;
378
+ }
379
+
380
+ export function createTextFormatControls(panelInstance, panel) {
381
+ panel.appendChild(makeSep());
382
+
383
+ const formatButtonsWrapper = makeFormatButtons(panelInstance);
384
+ panel.appendChild(formatButtonsWrapper);
385
+
386
+ panelInstance.alignControl = makeAlignButtons();
387
+ panel.appendChild(panelInstance.alignControl._container);
388
+
389
+ panelInstance.listControl = makeListButtons();
390
+ panel.appendChild(panelInstance.listControl._container);
391
+
392
+ panel.appendChild(makeSep());
393
+
394
+ const lhControl = makeLineHeightControl(panelInstance);
395
+ panel.appendChild(lhControl);
396
+
397
+ panel.appendChild(makeSep());
287
398
  }