From 119b14e1d3f75f81883a1408de9a0edbdad0abba Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Wed, 27 May 2026 10:10:02 -0400 Subject: [PATCH] Editor UX: click background to deselect + strip selection chrome in print MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three small editor-UX fixes: 1. Click in the canvas gutter → deselect. The existing #sheet click handler only fired when the click landed inside .sheet; clicks in the area between the sheet edge and the previewShell edge ("sheetWrap" parent) hit no handler and the selection stuck. Added a #previewShell click handler that deselects when the click isn't on a .freeLayer and isn't on #sheet (which the existing handler still covers). Layer .freeLayer clicks already stopPropagation, so they don't bubble through. 2. Selection chrome no longer bleeds into PDF / JPEG-fallback output. The codebase had `body.exporting .freeLayer.selected { outline: none }` rules sitting dead — JS only ever toggles `body.export-print`. Renamed the CSS to match. Also added rules to hide .layerHandle (resize squares) and .layerSelectionBox (multi-select dashed box) under the same class. 3. The regular Print / Save PDF button (printWithCurrentFilename) wasn't adding any export class around window.print(), so selection chrome bled into single-sheet prints too. Added body.classList.add('export-print') before the print + the matching remove on afterprint. The JPEG-PDF-fallback flow (enterExportPrintMode) already added this class; now both flows benefit from the same CSS. Verified via CDP: clicking in the gutter outside the sheet now deselects ({selId:'', isSel:false}). Co-Authored-By: Claude Opus 4.7 --- src/index.html | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/index.html b/src/index.html index 5b59269..7a0acd8 100644 --- a/src/index.html +++ b/src/index.html @@ -2437,19 +2437,27 @@ body.exporting .jewelSlot::before, body.exporting .jewelSlot::after, body.exporting .jewelSpineGuide, body.exporting .foldLine, body.exporting .trimArea, body.exporting .bleedFill, - body.exporting .spineText, body.exporting .discSpineStrip { + /* `body.export-print` is added while the printBtn / JPEG-PDF flows are + generating output via window.print(). It strips editor chrome from + the snapshot so the PDF / JPEG-fallback doesn't include layer + selection outlines, resize handles, the spine guide labels, etc. */ + body.export-print .spineText, body.export-print .discSpineStrip { display: none !important; } - body.exporting .freeLayer.selected { + body.export-print .freeLayer.selected, + body.export-print .freeLayer.multiSelected { outline: none !important; + box-shadow: none !important; } - body.exporting .freeLayer { + body.export-print .layerHandle, + body.export-print .layerSelectionBox { display: none !important; } + body.export-print .freeLayer { pointer-events: none !important; } - body.exporting .sheet, - body.exporting .sheet *, - body.exporting .designerDiscWrap, - body.exporting .designerDiscWrap * { + body.export-print .sheet, + body.export-print .sheet *, + body.export-print .designerDiscWrap, + body.export-print .designerDiscWrap * { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; color-adjust: exact !important; @@ -14762,11 +14770,13 @@ function printWithCurrentFilename() { const previousTitle = document.title; const nextTitle = currentPdfTitle(); - const restoreTitle = () => { + document.body.classList.add('export-print'); + const restore = () => { document.title = previousTitle; - window.removeEventListener('afterprint', restoreTitle); + document.body.classList.remove('export-print'); + window.removeEventListener('afterprint', restore); }; - window.addEventListener('afterprint', restoreTitle); + window.addEventListener('afterprint', restore); document.title = nextTitle; render(); setTimeout(() => window.print(), 50); @@ -22028,6 +22038,16 @@ clearLayerSelection(); render(); }); + // Clicks in the gutter between the sheet edge and the previewShell + // edge also deselect — the existing #sheet handler misses those. + // Layer .freeLayer clicks stopPropagation so they don't bubble up + // through here. + $('previewShell')?.addEventListener('click', (event) => { + if (event.target.closest('.freeLayer')) return; + if (event.target.closest('#sheet')) return; // handled by the rule above + clearLayerSelection(); + render(); + }); $('layerName').addEventListener('input', (event) => updateSelectedLayer('name', event.target.value)); $('layerUrl').addEventListener('change', (event) => {