diff --git a/src/index.html b/src/index.html index 0b7d180..95ede83 100644 --- a/src/index.html +++ b/src/index.html @@ -14077,27 +14077,39 @@ setTimeout(() => { delete el.dataset.dragMoved; }, 0); } else if (textTarget && wasSoleSelected) { // Click without drag on a text layer that was already the lone - // selection → drop into edit mode. Focus the contenteditable and - // place the caret at the click position so the user can start - // selecting / typing immediately. This is the standard "select - // once, click again to edit" pattern from PowerPoint / Keynote. - textTarget.focus(); + // selection → drop into edit mode. Two subtleties: + // 1. The click event still has to fire on .freeLayer after this + // pointerup, and that handler ends up clobbering the focus. + // So defer with setTimeout(0) to run after the click chain. + // 2. The selection change may have triggered a re-render that + // detaches the original textTarget. Look the layer's .textLayer + // up by id when the deferred handler runs, so we always focus + // the live DOM node and not a stale reference. + const layerId = layer.id; const cx = (upEvent && typeof upEvent.clientX === 'number') ? upEvent.clientX : startX; const cy = (upEvent && typeof upEvent.clientY === 'number') ? upEvent.clientY : startY; - try { - let range = null; - if (typeof document.caretRangeFromPoint === 'function') { - range = document.caretRangeFromPoint(cx, cy); - } else if (typeof document.caretPositionFromPoint === 'function') { - const pos = document.caretPositionFromPoint(cx, cy); - if (pos) { range = document.createRange(); range.setStart(pos.offsetNode, pos.offset); range.collapse(true); } - } - if (range) { - const sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - } - } catch (e) {} + setTimeout(() => { + const live = document.querySelector(`.freeLayer[data-layer-id="${layerId}"] .textLayer`); + if (!live) return; + live.focus(); + try { + let range = null; + if (typeof document.caretRangeFromPoint === 'function') { + range = document.caretRangeFromPoint(cx, cy); + } else if (typeof document.caretPositionFromPoint === 'function') { + const pos = document.caretPositionFromPoint(cx, cy); + if (pos) { range = document.createRange(); range.setStart(pos.offsetNode, pos.offset); range.collapse(true); } + } + // Only use the caret position if it's inside the live editable + // — caretRangeFromPoint can return a position in the previous + // (now detached) .textLayer. + if (range && live.contains(range.startContainer)) { + const sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + } + } catch (e) {} + }, 0); } localStorage.setItem('case-cover-template-maker-autosave', JSON.stringify(state)); };