@sequent-org/moodboard 1.4.55 → 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.
@@ -6,10 +6,21 @@ 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>';
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>';
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>';
17
+ const SVG_ALIGN_RIGHT = '<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="M10.75 18.2637H19.25"/><path d="M4.75 14.0879H19.25"/><path d="M10.75 9.91211L19.25 9.91211"/></svg>';
18
+ const SVG_ALIGN_JUSTIFY = '<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 9.91211H19.25"/><path d="M4.75 14.0879H19.25"/><path d="M4.75 18.2637H19.25"/></svg>';
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>';
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>';
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>';
13
24
 
14
25
  function makeSep() {
15
26
  const d = document.createElement('div');
@@ -27,55 +38,300 @@ function makeToggleBtn(svgStr, title, prop) {
27
38
  return btn;
28
39
  }
29
40
 
30
- function makeSelect(className, options) {
31
- const sel = document.createElement('select');
32
- sel.className = className;
33
- options.forEach(({ value, label }) => {
34
- const opt = document.createElement('option');
35
- opt.value = value;
36
- opt.textContent = label;
37
- sel.appendChild(opt);
41
+ function makeListButtons() {
42
+ const container = document.createElement('div');
43
+ container.className = 'tpp-list-btns';
44
+
45
+ const listOptions = [
46
+ { value: 'bullet', title: 'Маркированный список', svg: SVG_LIST_BULLET },
47
+ { value: 'numbered', title: 'Нумерованный список', svg: SVG_LIST_NUMBERED },
48
+ { value: 'checkbox', title: 'Список с флажками', svg: SVG_LIST_CHECK },
49
+ ];
50
+
51
+ let currentValue = 'none';
52
+ const changeListeners = [];
53
+
54
+ // Кнопка-триггер: всегда показывает иконку bullet-list и открывает модальное окно
55
+ const triggerBtn = document.createElement('button');
56
+ triggerBtn.type = 'button';
57
+ triggerBtn.title = 'Список';
58
+ triggerBtn.className = 'tpp-format-btn tpp-list-trigger';
59
+ triggerBtn.innerHTML = SVG_LIST_BULLET;
60
+
61
+ const modal = document.createElement('div');
62
+ modal.id = `tpp-list-modal-${Date.now()}-${Math.floor(Math.random() * 10000)}`;
63
+ modal.className = 'tpp-list-modal';
64
+ modal.style.display = 'none';
65
+
66
+ listOptions.forEach(({ value, title, svg }) => {
67
+ const optBtn = document.createElement('button');
68
+ optBtn.type = 'button';
69
+ optBtn.title = title;
70
+ optBtn.className = 'tpp-list-modal-option';
71
+ optBtn.dataset.listValue = value;
72
+ optBtn.innerHTML = svg;
73
+ optBtn.addEventListener('click', (e) => {
74
+ e.stopPropagation();
75
+ // Клик по выбранному элементу снимает форматирование (none).
76
+ currentValue = currentValue === value ? 'none' : value;
77
+ closeModal();
78
+ updateActive();
79
+ changeListeners.forEach((cb) => cb({ target: proxy }));
80
+ });
81
+ modal.appendChild(optBtn);
82
+ });
83
+
84
+ container.appendChild(triggerBtn);
85
+ container.appendChild(modal);
86
+
87
+ function openModal() {
88
+ modal.style.display = 'flex';
89
+ updateModalActive();
90
+ setTimeout(() => {
91
+ document.addEventListener('click', closeOnOutside);
92
+ }, 0);
93
+ }
94
+
95
+ function closeModal() {
96
+ modal.style.display = 'none';
97
+ document.removeEventListener('click', closeOnOutside);
98
+ }
99
+
100
+ function closeOnOutside(e) {
101
+ if (!container.contains(e.target)) {
102
+ closeModal();
103
+ }
104
+ }
105
+
106
+ function updateActive() {
107
+ triggerBtn.classList.toggle('is-active', currentValue !== 'none');
108
+ updateModalActive();
109
+ }
110
+
111
+ function updateModalActive() {
112
+ modal.querySelectorAll('.tpp-list-modal-option').forEach((btn) => {
113
+ const isActive = btn.dataset.listValue === currentValue;
114
+ btn.style.color = isActive ? 'rgb(53, 56, 205)' : '';
115
+ });
116
+ }
117
+
118
+ triggerBtn.addEventListener('click', (e) => {
119
+ e.stopPropagation();
120
+ if (modal.style.display === 'none') {
121
+ openModal();
122
+ } else {
123
+ closeModal();
124
+ }
38
125
  });
39
- return sel;
126
+
127
+ const proxy = {
128
+ get value() {
129
+ return currentValue;
130
+ },
131
+ set value(v) {
132
+ currentValue = v || 'none';
133
+ updateActive();
134
+ },
135
+ addEventListener(event, cb) {
136
+ if (event === 'change') changeListeners.push(cb);
137
+ },
138
+ _container: container,
139
+ };
140
+
141
+ updateActive();
142
+ return proxy;
40
143
  }
41
144
 
42
- export function createTextFormatControls(panelInstance, panel) {
43
- panel.appendChild(makeSep());
145
+ function makeAlignButtons() {
146
+ const container = document.createElement('div');
147
+ container.className = 'tpp-align-btns';
148
+
149
+ const alignOptions = [
150
+ { value: 'left', title: 'По левому краю', svg: SVG_ALIGN_LEFT },
151
+ { value: 'center', title: 'По центру', svg: SVG_ALIGN_CENTER },
152
+ { value: 'right', title: 'По правому краю', svg: SVG_ALIGN_RIGHT },
153
+ { value: 'justify', title: 'По ширине', svg: SVG_ALIGN_JUSTIFY },
154
+ ];
155
+
156
+ let currentValue = 'left';
157
+ const changeListeners = [];
158
+
159
+ // Единственная кнопка — отображает текущее выравнивание и открывает модальное окно
160
+ const triggerBtn = document.createElement('button');
161
+ triggerBtn.type = 'button';
162
+ triggerBtn.className = 'tpp-format-btn tpp-align-btn tpp-align-trigger';
163
+ triggerBtn.dataset.alignValue = 'left';
164
+
165
+ // Модальный попап
166
+ const modal = document.createElement('div');
167
+ modal.id = `tpp-align-modal-${Date.now()}-${Math.floor(Math.random() * 10000)}`;
168
+ modal.className = 'tpp-align-modal';
169
+ modal.style.display = 'none';
170
+
171
+ alignOptions.forEach(({ value, title, svg }) => {
172
+ const optBtn = document.createElement('button');
173
+ optBtn.type = 'button';
174
+ optBtn.title = title;
175
+ optBtn.className = 'tpp-align-modal-option';
176
+ optBtn.dataset.alignValue = value;
177
+ optBtn.innerHTML = svg;
178
+ optBtn.addEventListener('click', (e) => {
179
+ e.stopPropagation();
180
+ currentValue = value;
181
+ closeModal();
182
+ updateActive();
183
+ changeListeners.forEach((cb) => cb({ target: proxy }));
184
+ });
185
+ modal.appendChild(optBtn);
186
+ });
187
+
188
+ container.appendChild(triggerBtn);
189
+ container.appendChild(modal);
190
+
191
+ function openModal() {
192
+ modal.style.display = 'flex';
193
+ updateModalActive();
194
+ // Закрытие по клику вне
195
+ setTimeout(() => {
196
+ document.addEventListener('click', closeOnOutside);
197
+ }, 0);
198
+ }
199
+
200
+ function closeModal() {
201
+ modal.style.display = 'none';
202
+ document.removeEventListener('click', closeOnOutside);
203
+ }
204
+
205
+ function closeOnOutside(e) {
206
+ if (!container.contains(e.target)) {
207
+ closeModal();
208
+ }
209
+ }
210
+
211
+ function updateActive() {
212
+ const opt = alignOptions.find((o) => o.value === currentValue);
213
+ if (opt) {
214
+ triggerBtn.innerHTML = opt.svg;
215
+ triggerBtn.title = opt.title;
216
+ triggerBtn.dataset.alignValue = currentValue;
217
+ }
218
+ updateModalActive();
219
+ }
220
+
221
+ function updateModalActive() {
222
+ modal.querySelectorAll('.tpp-align-modal-option').forEach((btn) => {
223
+ const isActive = btn.dataset.alignValue === currentValue;
224
+ btn.style.color = isActive ? 'rgb(53, 56, 205)' : '';
225
+ });
226
+ }
227
+
228
+ triggerBtn.addEventListener('click', (e) => {
229
+ e.stopPropagation();
230
+ if (modal.style.display === 'none') {
231
+ openModal();
232
+ } else {
233
+ closeModal();
234
+ }
235
+ });
236
+
237
+ const proxy = {
238
+ get value() {
239
+ return currentValue;
240
+ },
241
+ set value(v) {
242
+ currentValue = v;
243
+ updateActive();
244
+ },
245
+ addEventListener(event, cb) {
246
+ if (event === 'change') changeListeners.push(cb);
247
+ },
248
+ _container: container,
249
+ };
250
+
251
+ updateActive();
252
+ return proxy;
253
+ }
254
+
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';
44
271
 
45
272
  panelInstance.boldBtn = makeToggleBtn(SVG_BOLD, 'Жирный', 'bold');
46
273
  panelInstance.italicBtn = makeToggleBtn(SVG_ITALIC, 'Курсив', 'italic');
47
274
  panelInstance.underlineBtn = makeToggleBtn(SVG_UNDERLINE, 'Подчёркнутый', 'underline');
48
275
  panelInstance.strikethroughBtn = makeToggleBtn(SVG_STRIKE, 'Зачёркнутый', 'strikethrough');
49
276
 
50
- [panelInstance.boldBtn, panelInstance.italicBtn, panelInstance.underlineBtn, panelInstance.strikethroughBtn].forEach(
51
- (btn) => panel.appendChild(btn),
52
- );
277
+ const btns = [
278
+ panelInstance.boldBtn,
279
+ panelInstance.italicBtn,
280
+ panelInstance.underlineBtn,
281
+ panelInstance.strikethroughBtn
282
+ ];
53
283
 
54
- panel.appendChild(makeSep());
284
+ btns.forEach((btn) => {
285
+ btn.classList.add('tpp-format-modal-option');
286
+ modal.appendChild(btn);
287
+ });
55
288
 
56
- panelInstance.alignControl = makeSelect('tpp-align-select', [
57
- { value: 'left', label: '≡ Лево' },
58
- { value: 'center', label: '≡ Центр' },
59
- { value: 'right', label: '≡ Право' },
60
- { value: 'justify', label: '≡ По ширине' },
61
- ]);
62
- panel.appendChild(panelInstance.alignControl);
63
-
64
- panelInstance.listControl = makeSelect('tpp-list-select', [
65
- { value: 'none', label: 'Список: нет' },
66
- { value: 'bullet', label: '• Маркер' },
67
- { value: 'numbered', label: '1. Нумерация' },
68
- { value: 'checkbox', label: '☐ Флажки' },
69
- ]);
70
- panel.appendChild(panelInstance.listControl);
289
+ container.appendChild(triggerBtn);
290
+ container.appendChild(modal);
71
291
 
72
- panel.appendChild(makeSep());
292
+ function openModal() {
293
+ modal.style.display = 'flex';
294
+ setTimeout(() => {
295
+ document.addEventListener('click', closeOnOutside);
296
+ }, 0);
297
+ }
73
298
 
74
- const lhLabel = document.createElement('span');
75
- lhLabel.className = 'tpp-label';
76
- lhLabel.title = 'Межстрочный интервал';
77
- lhLabel.textContent = '↕';
78
- panel.appendChild(lhLabel);
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;
331
+
332
+ const modal = document.createElement('div');
333
+ modal.className = 'tpp-lh-modal';
334
+ modal.style.display = 'none';
79
335
 
80
336
  panelInstance.lineHeightSlider = document.createElement('input');
81
337
  panelInstance.lineHeightSlider.type = 'range';
@@ -84,5 +340,59 @@ export function createTextFormatControls(panelInstance, panel) {
84
340
  panelInstance.lineHeightSlider.max = String(LINE_HEIGHT_MAX);
85
341
  panelInstance.lineHeightSlider.step = String(LINE_HEIGHT_STEP);
86
342
  panelInstance.lineHeightSlider.value = String(LINE_HEIGHT_DEFAULT);
87
- 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());
88
398
  }