@sequent-org/moodboard 1.2.42 → 1.2.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -473,6 +473,10 @@ export class SelectTool extends BaseTool {
|
|
|
473
473
|
type: 'text',
|
|
474
474
|
position: posData.position,
|
|
475
475
|
properties: { content: textContent },
|
|
476
|
+
caretClick: {
|
|
477
|
+
clientX: event?.originalEvent?.clientX,
|
|
478
|
+
clientY: event?.originalEvent?.clientY
|
|
479
|
+
},
|
|
476
480
|
create: false
|
|
477
481
|
});
|
|
478
482
|
return;
|
|
@@ -1990,7 +1994,7 @@ export class SelectTool extends BaseTool {
|
|
|
1990
1994
|
];
|
|
1991
1995
|
} else {
|
|
1992
1996
|
// Для обычного текста используем стандартное позиционирование
|
|
1993
|
-
// Динамически компенсируем внутренние отступы textarea
|
|
1997
|
+
// Динамически компенсируем внутренние отступы textarea для точного совпадения со статичным текстом
|
|
1994
1998
|
let padTop = 0;
|
|
1995
1999
|
let padLeft = 0;
|
|
1996
2000
|
let lineHeightPx = 0;
|
|
@@ -2011,8 +2015,27 @@ export class SelectTool extends BaseTool {
|
|
|
2011
2015
|
if (r && isFinite(r.height)) lineHeightPx = r.height;
|
|
2012
2016
|
} catch (_) {}
|
|
2013
2017
|
}
|
|
2014
|
-
|
|
2015
|
-
|
|
2018
|
+
|
|
2019
|
+
// Базовая точка позиционирования: для редактирования берём точные координаты статичного HTML-текста,
|
|
2020
|
+
// для создания — используем рассчитанные screenPos
|
|
2021
|
+
let baseLeftPx = screenPos.x;
|
|
2022
|
+
let baseTopPx = screenPos.y;
|
|
2023
|
+
try {
|
|
2024
|
+
if (!create && objectId && typeof window !== 'undefined' && window.moodboardHtmlTextLayer) {
|
|
2025
|
+
const el = window.moodboardHtmlTextLayer.idToEl.get(objectId);
|
|
2026
|
+
if (el) {
|
|
2027
|
+
const cssLeft = parseFloat(el.style.left || 'NaN');
|
|
2028
|
+
const cssTop = parseFloat(el.style.top || 'NaN');
|
|
2029
|
+
if (isFinite(cssLeft)) baseLeftPx = cssLeft;
|
|
2030
|
+
if (isFinite(cssTop)) baseTopPx = cssTop;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
} catch (_) {}
|
|
2034
|
+
|
|
2035
|
+
const leftPx = Math.round(baseLeftPx - padLeft);
|
|
2036
|
+
const topPx = create
|
|
2037
|
+
? Math.round(baseTopPx - padTop - (lineHeightPx / 2)) // по клику совмещаем центр строки с точкой клика
|
|
2038
|
+
: Math.round(baseTopPx - padTop); // при редактировании совмещаем верх контента
|
|
2016
2039
|
wrapper.style.left = `${leftPx}px`;
|
|
2017
2040
|
wrapper.style.top = `${topPx}px`;
|
|
2018
2041
|
// Сохраняем CSS-позицию редактора для точной синхронизации при закрытии
|
|
@@ -2023,6 +2046,7 @@ export class SelectTool extends BaseTool {
|
|
|
2023
2046
|
console.log('🧭 Text input', {
|
|
2024
2047
|
input: { left: leftPx, top: topPx },
|
|
2025
2048
|
screenPos,
|
|
2049
|
+
baseFromStatic: (!create && objectId) ? { left: baseLeftPx, top: baseTopPx } : null,
|
|
2026
2050
|
padding: { top: padTop, left: padLeft },
|
|
2027
2051
|
lineHeightPx,
|
|
2028
2052
|
caretCenterY: create ? (topPx + padTop + (lineHeightPx / 2)) : topPx,
|
|
@@ -2160,6 +2184,59 @@ export class SelectTool extends BaseTool {
|
|
|
2160
2184
|
document.head.appendChild(styleEl);
|
|
2161
2185
|
this.textEditor = { active: true, objectId, textarea, wrapper, world: this.textEditor.world, position, properties: { fontSize }, objectType, _phStyle: styleEl };
|
|
2162
2186
|
|
|
2187
|
+
// Если переходим в редактирование существующего текста по двойному клику,
|
|
2188
|
+
// устанавливаем каретку по координате клика между буквами
|
|
2189
|
+
try {
|
|
2190
|
+
const click = (object && object.caretClick) ? object.caretClick : null;
|
|
2191
|
+
if (!create && objectId && click && typeof window !== 'undefined') {
|
|
2192
|
+
setTimeout(() => {
|
|
2193
|
+
try {
|
|
2194
|
+
const el = window.moodboardHtmlTextLayer ? window.moodboardHtmlTextLayer.idToEl.get(objectId) : null;
|
|
2195
|
+
const fullText = (typeof textarea.value === 'string') ? textarea.value : '';
|
|
2196
|
+
if (!el || !fullText || !el.firstChild) return;
|
|
2197
|
+
const textNode = el.firstChild;
|
|
2198
|
+
const len = textNode.textContent.length;
|
|
2199
|
+
if (len === 0) {
|
|
2200
|
+
textarea.selectionStart = textarea.selectionEnd = 0;
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
2203
|
+
const doc = el.ownerDocument || document;
|
|
2204
|
+
let bestIdx = 0;
|
|
2205
|
+
let bestDist = Infinity;
|
|
2206
|
+
for (let i = 0; i <= len; i++) {
|
|
2207
|
+
const range = doc.createRange();
|
|
2208
|
+
range.setStart(textNode, i);
|
|
2209
|
+
range.setEnd(textNode, i);
|
|
2210
|
+
const rects = range.getClientRects();
|
|
2211
|
+
const rect = rects && rects.length > 0 ? rects[0] : range.getBoundingClientRect();
|
|
2212
|
+
if (rect && isFinite(rect.left) && isFinite(rect.top)) {
|
|
2213
|
+
if (click.clientX >= rect.left && click.clientX <= rect.right &&
|
|
2214
|
+
click.clientY >= rect.top && click.clientY <= rect.bottom) {
|
|
2215
|
+
bestIdx = i;
|
|
2216
|
+
bestDist = 0;
|
|
2217
|
+
break;
|
|
2218
|
+
}
|
|
2219
|
+
const cx = Math.max(rect.left, Math.min(click.clientX, rect.right));
|
|
2220
|
+
const cy = Math.max(rect.top, Math.min(click.clientY, rect.bottom));
|
|
2221
|
+
const dx = click.clientX - cx;
|
|
2222
|
+
const dy = click.clientY - cy;
|
|
2223
|
+
const d2 = dx * dx + dy * dy;
|
|
2224
|
+
if (d2 < bestDist) {
|
|
2225
|
+
bestDist = d2;
|
|
2226
|
+
bestIdx = i;
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
2231
|
+
const caret = clamp(bestIdx, 0, fullText.length);
|
|
2232
|
+
textarea.selectionStart = textarea.selectionEnd = caret;
|
|
2233
|
+
if (typeof textarea.scrollTop === 'number') textarea.scrollTop = 0;
|
|
2234
|
+
console.log('🧭 Text caret set', { objectId, caret, len: fullText.length });
|
|
2235
|
+
} catch (_) {}
|
|
2236
|
+
}, 0);
|
|
2237
|
+
}
|
|
2238
|
+
} catch (_) {}
|
|
2239
|
+
|
|
2163
2240
|
// Если редактируем записку — скрываем PIXI-текст записки (чтобы не было дублирования)
|
|
2164
2241
|
if (objectType === 'note' && objectId) {
|
|
2165
2242
|
try {
|