Improve matching component look and feel - #1323
Conversation
Visual redesign of the matching component: - Draw connections as S-curved bezier paths with rounded caps instead of straight lines, and mark the attachment points with port dots on the inner edge of each box so the connect-a-line affordance is visible. - Tighten the workspace (780px) so the two columns sit closer together; boxes in a column share a uniform width and premises are left-aligned. - Softer box styling (theme background, 1px border, radius, subtle shadow) with hover states, replacing the gray heavy-border look. - Show graded results on the boxes themselves (green/red fill via the parsons theme variables) in addition to coloring the lines. - Replace the debug-style score readout with a score badge plus a 'N correct / N incorrect / N missing' summary line, and only render the feedback block when the author actually provided feedback text. - Give the empty connections panel a helpful hint instead of a bare 'Connections:' header. Interaction fixes made along the way: - Releasing a drag on empty space no longer throws (the old code dereferenced endBox.dataset unconditionally), which also leaked the document-level pointer listeners it failed to remove. - matching_connection events are only logged when a connection is actually created, and the leftover console.log is gone. - Connecting two boxes in the same column flashes the boxes and reports the problem via the aria-live region instead of a blocking alert(). - Stale correct/incorrect marks are cleared when the user changes their connections after grading. - Removed the always-true (e.ctrlKey || e.metaKey || true) condition and the CSS rules that leaked out of the component (bare button, body, h2, and * selectors). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Thanks for this! I'll check it out today or tomorrow. |
There was a problem hiding this comment.
Pull request overview
This PR refreshes the Runestone matching component’s UI (curved connector paths, ports, layout, and results display) while also addressing several interaction/logging bugs during connection creation and grading feedback rendering.
Changes:
- Switch connector rendering from straight SVG
<line>elements to curved<path>beziers, with updated styling and a “temp” drag state. - Improve UX and accessibility: visible ports, empty-state messaging, non-blocking invalid-connection feedback (flash + aria-live), and a more compact score display.
- Fix interaction issues: prevent logging “matching_connection” on failed/invalid connections and clear stale grading marks when connections change.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| bases/rsptx/interactives/runestone/matching/js/matching.js | Refactors connection creation/rendering (paths + endpoints), improves invalid/empty states, adjusts grading visuals, and tightens event logging/cleanup. |
| bases/rsptx/interactives/runestone/matching/css/matching.css | Restyles the component (scoped rules, ports, curved line styling, results badge, and control button scoping) and adds responsive tweaks. |
Comments suppressed due to low confidence (1)
bases/rsptx/interactives/runestone/matching/js/matching.js:672
updateTempLinealso hard-codesgetRightBoxCenter(this.startBox), so the drag line continues to come from the wrong edge when starting from a right-column (role="drop") box. This should use the same port-selection logic as permanent lines (left edge for drop, right edge for drag).
e.preventDefault();
if (!this.startBox || !this.tempLine) return;
const from = this.getRightBoxCenter(this.startBox);
const containerRect = this.workspace.getBoundingClientRect();
const to = {
x: e.clientX - containerRect.left,
y: e.clientY - containerRect.top,
};
this.setLineEndpoints(this.tempLine, from, to);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| e.preventDefault(); | ||
| this.startBox = box; | ||
| const from = this.getRightBoxCenter(this.startBox); | ||
| this.tempLine = this.createLineElement(from, from); | ||
| this.tempLine.classList.add("temp"); | ||
| this.svg.appendChild(this.tempLine); |
There was a problem hiding this comment.
Not due to your PR, it looks like it has been in place for a while. But it would be worth fixing.
|
If I select a box on the left, I have to tab through all of the connectors before I get to the boxes on the right. I wonder if we could position the next selected object to be the top box on the right after something is selected. If nothing is selected on the left then we should still tab through connectors as the user may want to delete one. |
- Anchor the temporary drag line to the box's port edge (left edge for right-column boxes) via a new getPortCenter helper, instead of always using the right edge. The bezier control points now also pull toward the other endpoint, so a line dragged leftward curves correctly. - When a box is selected with Enter, move focus to the top box of the opposite column so the user doesn't tab through the rest of the column and every connection line to reach a match; with nothing selected, natural tab order still visits the lines so they can be deleted. Escape cancels a selection and returns focus to the selected box. - Update the help modal and aria-live announcements to describe the new keyboard flow. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Thanks! Here are the updates: The temp line now anchors to the port edge of whichever box the drag starts from. For keyboard use: selecting a box with Enter now moves focus to the top of the opposite column, requiring fewer tabs; escape cancels a selection. Help screen also updated. |
What this does
Enhances the look and feel of the matching component and addresses several interaction bugs found along the way. No changes to grading logic, event logging semantics, or the stored answer format.
Visual changes
<line>elements, and each box shows a small port dot on its inner edge, making the "draw a line from here to there" affordance discoverable.Score/Correct/Incorrect/Missingdebug-style block is now a score badge plus a one-line "N correct · N incorrect · N missing" summary. The feedback block only renders when the author actually supplied feedback text (previously an empty red band appeared for exercises with<feedback></feedback>).:root.dark-modeand[data-theme="dark"]variable sets.Bug fixes
TypeError(the old code dereferencedendBox.datasetunconditionally). Because the throw happened before cleanup, the document-levelpointermove/pointeruplisteners also leaked. Now guarded, and cleanup always runs.matching_connectionevents were logged even when no connection was made (release on empty space, duplicate connection, same-column attempt).createPermanentLinenow returns a boolean and the event is logged only on success.alert(). It now flashes the boxes briefly and announces the problem via the existing aria-live region.console.log, the always-trueif (e.ctrlKey || e.metaKey || true)wrapper, and CSS that leaked outside the component (barebutton,body,h2, and*selectors — thebuttonrules were restyling unrelated buttons on the page).Screenshots
Testing
timed_matching.jsonly touchesconnList.style.display, unaffected by the refactor.