diff --git a/main/blocklyinit.js b/main/blocklyinit.js index 36e4be98..42c544d4 100644 --- a/main/blocklyinit.js +++ b/main/blocklyinit.js @@ -1196,9 +1196,22 @@ export function initializeWorkspace() { workspaceSearch.preserveSelected ); }); + // Up/Down step through matches without leaving the search box; the plugin only binds Enter + const wsSearchArrowKeys = (e) => { + if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') return; + e.preventDefault(); + e.stopPropagation(); + if (!workspaceSearch.blocks?.length) return; + if (e.key === 'ArrowDown') workspaceSearch.next(); + else workspaceSearch.previous(); + }; + + workspaceSearch.inputElement?.addEventListener('keydown', wsSearchArrowKeys); + wsMobileInput.addEventListener('keydown', (e) => { if (e.key === 'Escape') workspaceSearch.close(); else if (e.key === 'Enter') e.shiftKey ? workspaceSearch.previous() : workspaceSearch.next(); + else wsSearchArrowKeys(e); }); wsMobilePrev.addEventListener('mousedown', (e) => e.preventDefault()); wsMobilePrev.addEventListener('click', () => workspaceSearch.previous()); @@ -1256,20 +1269,24 @@ export function initializeWorkspace() { block.getSvgRoot()?.classList.remove('ws-search-fade'); }); }; + // The current match is just the selected block, so Blockly renders it correctly for every block shape workspaceSearch.highlightCurrentSelection = function (block) { - const svg = block.getSvgRoot(); - if (svg) { - svg.classList.add('ws-search-current'); - let top = block; - while (top.getSurroundParent()) top = top.getSurroundParent(); - const topSvg = top.getSvgRoot(); - if (topSvg) topSvg.parentNode?.appendChild(topSvg); - } + block.select?.(); }; workspaceSearch.unhighlightCurrentSelection = function (block) { - block.getSvgRoot()?.classList.remove('ws-search-current'); + block.unselect?.(); }; + // Selecting a matched block makes it the current result, so search and selection stay in step + workspace.addChangeListener((event) => { + if (event.type !== Blockly.Events.SELECTED || !event.newElementId) return; + if (!blocklyDiv?.classList.contains('blockly-search-active')) return; + const index = workspaceSearch.blocks?.findIndex((b) => b.id === event.newElementId) ?? -1; + if (index >= 0 && index !== workspaceSearch.currentBlockIndex) { + workspaceSearch.setCurrentBlock(index); + } + }); + // Override the workspace centering for workspace search as it jumps all over the place by default! const originalCenter = workspace.centerOnBlock.bind(workspace); diff --git a/style/blockly.css b/style/blockly.css index 161bfbf7..3f5cbea7 100644 --- a/style/blockly.css +++ b/style/blockly.css @@ -246,9 +246,10 @@ body[data-theme='low-vision'] { transition: opacity 0.15s ease; } -/* Non-current matches get a pale yellow background (desktop only) */ +/* Matches get a pale yellow background (desktop only); the current match is the selected block. + .blocklyPathSelected shares the blocklyPath class; filling it makes the selection glow filter flood the block. */ @media (min-width: 769px) { - #blocklyDiv.blockly-search-active .ws-search-match:not(.ws-search-current) > path.blocklyPath { + #blocklyDiv.blockly-search-active .ws-search-match > path.blocklyPath:not(.blocklyPathSelected) { fill: rgba(255, 242, 0, 0.3) !important; } } @@ -256,8 +257,8 @@ body[data-theme='low-vision'] { /* Low-vision: replace fill with a dashed white stroke for better contrast */ [data-theme='low-vision'] #blocklyDiv.blockly-search-active - .ws-search-match:not(.ws-search-current) - > path.blocklyPath { + .ws-search-match + > path.blocklyPath:not(.blocklyPathSelected) { fill: revert !important; stroke: #ffffff !important; stroke-width: 10px !important; @@ -265,18 +266,6 @@ body[data-theme='low-vision'] { paint-order: stroke fill; } -/* Current match gets a yellow outline */ -#blocklyDiv.blockly-search-active .ws-search-current > path.blocklyPath { - stroke: var(--block-outline-focus) !important; - stroke-width: 10px !important; - paint-order: stroke fill; -} - -/* Suppress the Zelos selection glow path when the search outline is already showing */ -#blocklyDiv.blockly-search-active .ws-search-current > path.blocklyPathSelected { - display: none; -} - @media (min-width: 769px) { .blocklyTreeRow { flex-direction: row;