Skip to content

Commit d75290d

Browse files
author
DavidQ
committed
Fix Shape Geometry point rounding to one independent checkbox per point - PR_26133_078-point-rounding-checkbox-correction
1 parent c6845bf commit d75290d

5 files changed

Lines changed: 89 additions & 46 deletions

File tree

docs/dev/reports/playwright_v8_coverage_report.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Playwright V8 Coverage Report
22

3-
PR: PR_26133_077-point-rounding-snap-icon-color-and-snap-angle-wiring
3+
PR: PR_26133_078-point-rounding-checkbox-correction
44

55
Source: docs/dev/reports/playwright_v8_coverage_report.txt generated by the latest npm run test:workspace-v2 run.
66

@@ -21,9 +21,9 @@ Source: docs/dev/reports/playwright_v8_coverage_report.txt generated by the late
2121

2222
## Changed Runtime JS Files Covered
2323

24-
- (96%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 6933/6933; executed functions 712/745
24+
- (95%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 6968/6968; executed functions 717/751
2525

2626
## Changed JS Files Considered
2727

28-
- (96%) tools/object-vector-studio-v2/js/ToolStarterApp.js - changed runtime JS file with browser V8 coverage
28+
- (95%) tools/object-vector-studio-v2/js/ToolStarterApp.js - changed runtime JS file with browser V8 coverage
2929
- (0%) tests/playwright/tools/WorkspaceManagerV2.spec.mjs - Playwright test file, not collected as browser runtime coverage

docs/dev/reports/playwright_workspace_v2_results.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Playwright Workspace V2 Results
22

3-
PR: PR_26133_077-point-rounding-snap-icon-color-and-snap-angle-wiring
3+
PR: PR_26133_078-point-rounding-checkbox-correction
44

55
## Validation
66

@@ -12,12 +12,12 @@ PR: PR_26133_077-point-rounding-snap-icon-color-and-snap-angle-wiring
1212

1313
## Targeted Checks Covered
1414

15-
- Shape Geometry point rows render Round checkboxes and no longer render the prior Start/Joints/End dropdown model.
16-
- Point rows default square; checked point rows persist `style.pointRounding` and render round joins/markers.
17-
- Polygon/polyline point lists size naturally without an internal scrollbar.
18-
- Snap color behavior is scoped to Snap button glyphs: Snap None uses the red disabled tone, Snap Point matches point snap circles, and non-Snap icons keep default colors.
19-
- Future notes include spline as a tracked possible geometry addition.
20-
- Snap Angle rotate application is logged visibly as active or disabled, and enabled Snap Angle constrains Rotate to the snap increment.
15+
- Shape Geometry point rows now render exactly one checkbox per row.
16+
- The remaining checkbox is the Round control; unchecked rows render square and checked rows render round.
17+
- The old second point-selection checkbox was removed from polygon/polyline/triangle point rows.
18+
- Add/Delete point row targeting now uses row selection state instead of an extra checkbox.
19+
- No global Start/Joints/End or Joints point-style controls remain.
20+
- Independent per-point rounding coverage remains in place for open and closed multi-point geometry.
2121

2222
## Console/Runtime Errors
2323

tests/playwright/tools/WorkspaceManagerV2.spec.mjs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3982,7 +3982,8 @@ test.describe("Workspace Manager V2 bootstrap", () => {
39823982
expect(polygonPointListLayout).toEqual({ headingMarginBottom: 0, headingMarginTop: 0, listGap: 5, maxHeight: "none", overflowY: "visible", sectionGap: 5 });
39833983
await expect(page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-side-action]")).toHaveText(["Add Point", "Delete Point(s)"]);
39843984
await expect(page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-point-round='true']")).toHaveCount(4);
3985-
await expect(page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-point-select='true']")).toHaveCount(4);
3985+
await expect(page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-point-select='true']")).toHaveCount(0);
3986+
await expect.poll(() => page.locator("#objectVectorStudioV2ShapeGeometryDetails .object-vector-studio-v2__polygon-point-field").evaluateAll((rows) => rows.map((row) => row.querySelectorAll("input[type='checkbox']").length))).toEqual([1, 1, 1, 1]);
39863987
await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-point-round='true'][data-polygon-point-index='1']").check();
39873988
await expect(page.locator("#statusLog")).toHaveValue(/OK Updated point 2 rounding to round for shape row 0\./);
39883989
const roundedPointRender = await page.locator("#objectVectorStudioV2RenderSurface").evaluate((surface) => {
@@ -4001,14 +4002,14 @@ test.describe("Workspace Manager V2 bootstrap", () => {
40014002
pointRounding: [false, true, false, false],
40024003
strokeLinejoin: "miter"
40034004
});
4004-
await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-point-select='true'][data-polygon-point-index='1']").check();
4005+
await page.locator("#objectVectorStudioV2ShapeGeometryDetails .object-vector-studio-v2__polygon-point-label").nth(1).click();
40054006
await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-side-action='add']").click();
40064007
await expect.poll(() => page.locator("#objectVectorStudioV2ShapeGeometryDetails .object-vector-studio-v2__polygon-point-field").evaluateAll((rows) => rows.map((row) => ({
40074008
label: row.querySelector(".object-vector-studio-v2__polygon-point-label").textContent.trim(),
40084009
rounded: row.querySelector("[data-polygon-point-round='true']").checked,
40094010
x: row.querySelector("[data-polygon-point-axis='x']").value,
40104011
y: row.querySelector("[data-polygon-point-axis='y']").value,
4011-
selected: row.querySelector("[data-polygon-point-select='true']").checked
4012+
selected: row.dataset.polygonPointActionSelected === "true"
40124013
})))).toEqual([
40134014
{ label: "Point 1", rounded: false, x: "0", y: "-18", selected: false },
40144015
{ label: "Point 2", rounded: true, x: "14", y: "16", selected: false },
@@ -4019,10 +4020,10 @@ test.describe("Workspace Manager V2 bootstrap", () => {
40194020
await expect(page.locator("#statusLog")).toHaveValue(/OK Added point to shape row 0\./);
40204021
await expect.poll(() => page.evaluate(() => window.__objectVectorStudioV2App.selectedShape().geometry.points.length)).toBe(5);
40214022
await expect.poll(() => page.evaluate(() => window.__objectVectorStudioV2App.schemaService.validatePayload(window.__objectVectorStudioV2App.currentPayload).ok)).toBe(true);
4022-
await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-point-select='true'][data-polygon-point-index='2']").check();
4023+
await page.locator("#objectVectorStudioV2ShapeGeometryDetails .object-vector-studio-v2__polygon-point-label").nth(2).click();
40234024
await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-side-action='delete']").click();
40244025
await expect(page.locator("#objectVectorStudioV2ShapeGeometryDetails .object-vector-studio-v2__polygon-point-field")).toHaveCount(4);
4025-
await expect.poll(() => page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-point-select='true']").evaluateAll((checkboxes) => checkboxes.every((checkbox) => !checkbox.checked))).toBe(true);
4026+
await expect.poll(() => page.locator("#objectVectorStudioV2ShapeGeometryDetails .object-vector-studio-v2__polygon-point-field").evaluateAll((rows) => rows.every((row) => row.dataset.polygonPointActionSelected !== "true"))).toBe(true);
40264027
await expect(page.locator("#statusLog")).toHaveValue(/OK Deleted 1 point from shape row 0\./);
40274028
await expect.poll(() => page.evaluate(() => window.__objectVectorStudioV2App.selectedShape().geometry.points.length)).toBe(4);
40284029
await expect.poll(() => page.evaluate(() => window.__objectVectorStudioV2App.schemaService.validatePayload(window.__objectVectorStudioV2App.currentPayload).ok)).toBe(true);
@@ -4171,12 +4172,12 @@ test.describe("Workspace Manager V2 bootstrap", () => {
41714172
expect(resizedPreviewScale.pointsOnVisibleGridLines).toBe(true);
41724173
await page.locator("#objectVectorStudioV2ResetViewButton").click();
41734174
await expect(page.locator("#objectVectorStudioV2RenderSurface")).toHaveAttribute("viewBox", "-1600 -1100 3200 2200");
4174-
await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-point-select='true'][data-polygon-point-index='0']").check();
4175-
await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-point-select='true'][data-polygon-point-index='1']").check();
4175+
await page.locator("#objectVectorStudioV2ShapeGeometryDetails .object-vector-studio-v2__polygon-point-label").nth(0).click({ modifiers: ["Control"] });
4176+
await page.locator("#objectVectorStudioV2ShapeGeometryDetails .object-vector-studio-v2__polygon-point-label").nth(1).click({ modifiers: ["Control"] });
41764177
await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-side-action='delete']").click();
41774178
await expect(page.locator("#objectVectorStudioV2ShapeGeometryDetails .object-vector-studio-v2__polygon-point-field")).toHaveCount(4);
41784179
await expect(page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-side-action='delete']")).toHaveAttribute("aria-invalid", "true");
4179-
await expect.poll(() => page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-point-select='true']").evaluateAll((checkboxes) => checkboxes.every((checkbox) => !checkbox.checked))).toBe(true);
4180+
await expect.poll(() => page.locator("#objectVectorStudioV2ShapeGeometryDetails .object-vector-studio-v2__polygon-point-field").evaluateAll((rows) => rows.every((row) => row.dataset.polygonPointActionSelected !== "true"))).toBe(true);
41804181
await expect(page.locator("#statusLog")).toHaveValue(/FAIL Delete point rejected for shape row 0: polygon must keep at least 4 points\./);
41814182

41824183
expect(pageErrors).toEqual([]);
@@ -4361,6 +4362,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
43614362
await expect(page.locator("#objectVectorStudioV2ShapeGeometryDetails")).not.toContainText(/Shape\s*polygon-\d+ \(triangle\)/);
43624363
await expect(page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-side-action]")).toHaveCount(0);
43634364
await expect(page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-polygon-point-select='true']")).toHaveCount(0);
4365+
await expect.poll(() => page.locator("#objectVectorStudioV2ShapeGeometryDetails .object-vector-studio-v2__polygon-point-field").evaluateAll((rows) => rows.map((row) => row.querySelectorAll("input[type='checkbox']").length))).toEqual([1, 1, 1]);
43644366

43654367
expect(pageErrors).toEqual([]);
43664368
expect(consoleErrors).toEqual([]);

tools/object-vector-studio-v2/js/ToolStarterApp.js

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2292,6 +2292,21 @@ export class ToolStarterApp {
22922292
createPolygonPointRow(point, index, { rounded = false, selectable = true } = {}) {
22932293
const row = document.createElement("div");
22942294
row.className = "object-vector-studio-v2__polygon-point-field";
2295+
row.dataset.polygonPointIndex = String(index);
2296+
if (selectable) {
2297+
row.dataset.polygonPointSelectable = "true";
2298+
row.setAttribute("role", "button");
2299+
row.setAttribute("tabindex", "0");
2300+
row.setAttribute("aria-pressed", "false");
2301+
row.title = "Select this point row for Add Point or Delete Point(s).";
2302+
row.addEventListener("click", (event) => this.handlePolygonPointRowSelection(event, row));
2303+
row.addEventListener("keydown", (event) => {
2304+
if (event.key === "Enter" || event.key === " ") {
2305+
event.preventDefault();
2306+
this.togglePolygonPointRowSelection(row, event);
2307+
}
2308+
});
2309+
}
22952310
const caption = document.createElement("span");
22962311
caption.className = "object-vector-studio-v2__polygon-point-label";
22972312
caption.textContent = `Point ${index + 1}`;
@@ -2325,20 +2340,10 @@ export class ToolStarterApp {
23252340
roundCheckbox.dataset.polygonPointRound = "true";
23262341
roundCheckbox.dataset.polygonPointIndex = String(index);
23272342
roundCheckbox.setAttribute("aria-label", `Round point ${index + 1}`);
2343+
roundCheckbox.addEventListener("click", (event) => event.stopPropagation());
23282344
roundCheckbox.addEventListener("change", () => this.updateSelectedShapePointRounding(index, roundCheckbox.checked));
23292345
roundLabel.append(roundCaption, roundCheckbox);
23302346
row.append(roundLabel);
2331-
if (selectable) {
2332-
const selectLabel = document.createElement("label");
2333-
selectLabel.className = "object-vector-studio-v2__polygon-point-toggle";
2334-
const checkbox = document.createElement("input");
2335-
checkbox.type = "checkbox";
2336-
checkbox.dataset.polygonPointSelect = "true";
2337-
checkbox.dataset.polygonPointIndex = String(index);
2338-
checkbox.setAttribute("aria-label", `Select point ${index + 1}`);
2339-
selectLabel.append(checkbox);
2340-
row.append(selectLabel);
2341-
}
23422347
return row;
23432348
}
23442349

@@ -2360,6 +2365,39 @@ export class ToolStarterApp {
23602365
return actions;
23612366
}
23622367

2368+
handlePolygonPointRowSelection(event, row) {
2369+
if (event.target.closest("input, button, select, textarea, label")) {
2370+
return;
2371+
}
2372+
this.togglePolygonPointRowSelection(row, event);
2373+
}
2374+
2375+
togglePolygonPointRowSelection(row, event = null) {
2376+
if (!row?.dataset || row.dataset.polygonPointSelectable !== "true") {
2377+
return;
2378+
}
2379+
const shouldExtend = Boolean(event?.ctrlKey || event?.metaKey || event?.shiftKey);
2380+
if (!shouldExtend) {
2381+
this.elements.shapeGeometryDetails.querySelectorAll("[data-polygon-point-action-selected='true']").forEach((candidate) => {
2382+
if (candidate !== row) {
2383+
delete candidate.dataset.polygonPointActionSelected;
2384+
candidate.classList.remove("is-action-selected");
2385+
candidate.setAttribute("aria-pressed", "false");
2386+
}
2387+
});
2388+
}
2389+
const isSelected = row.dataset.polygonPointActionSelected === "true";
2390+
if (isSelected) {
2391+
delete row.dataset.polygonPointActionSelected;
2392+
row.classList.remove("is-action-selected");
2393+
row.setAttribute("aria-pressed", "false");
2394+
return;
2395+
}
2396+
row.dataset.polygonPointActionSelected = "true";
2397+
row.classList.add("is-action-selected");
2398+
row.setAttribute("aria-pressed", "true");
2399+
}
2400+
23632401
createShapeTransformControls(shape) {
23642402
const section = document.createElement("section");
23652403
section.className = "object-vector-studio-v2__edit-panel object-vector-studio-v2__edit-panel--transform";
@@ -6172,14 +6210,16 @@ export class ToolStarterApp {
61726210
}
61736211

61746212
checkedPolygonPointIndexes() {
6175-
return Array.from(this.elements.shapeGeometryDetails.querySelectorAll("[data-polygon-point-select='true']"))
6176-
.map((checkbox) => checkbox.checked ? Number(checkbox.dataset.polygonPointIndex) : null)
6213+
return Array.from(this.elements.shapeGeometryDetails.querySelectorAll("[data-polygon-point-action-selected='true']"))
6214+
.map((row) => Number(row.dataset.polygonPointIndex))
61776215
.filter((index) => Number.isInteger(index));
61786216
}
61796217

61806218
clearPolygonPointSelections() {
6181-
this.elements.shapeGeometryDetails.querySelectorAll("[data-polygon-point-select='true']").forEach((checkbox) => {
6182-
checkbox.checked = false;
6219+
this.elements.shapeGeometryDetails.querySelectorAll("[data-polygon-point-action-selected='true']").forEach((row) => {
6220+
delete row.dataset.polygonPointActionSelected;
6221+
row.classList.remove("is-action-selected");
6222+
row.setAttribute("aria-pressed", "false");
61836223
});
61846224
}
61856225

@@ -6256,14 +6296,11 @@ export class ToolStarterApp {
62566296
row.querySelectorAll("[data-polygon-point-index]").forEach((input) => {
62576297
input.dataset.polygonPointIndex = String(index);
62586298
});
6299+
row.dataset.polygonPointIndex = String(index);
62596300
const roundCheckbox = row.querySelector("[data-polygon-point-round='true']");
62606301
if (roundCheckbox) {
62616302
roundCheckbox.setAttribute("aria-label", `Round point ${index + 1}`);
62626303
}
6263-
const checkbox = row.querySelector("[data-polygon-point-select='true']");
6264-
if (checkbox) {
6265-
checkbox.setAttribute("aria-label", `Select point ${index + 1}`);
6266-
}
62676304
});
62686305
}
62696306

tools/object-vector-studio-v2/styles/toolStarter.css

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,11 +1674,22 @@ textarea:hover {
16741674

16751675
.object-vector-studio-v2__polygon-point-field {
16761676
display: grid;
1677-
grid-template-columns: 62px minmax(0, 1fr) minmax(0, 1fr) max-content 22px;
1677+
grid-template-columns: 62px minmax(0, 1fr) minmax(0, 1fr) max-content;
16781678
align-items: center;
16791679
gap: 6px;
16801680
}
16811681

1682+
.object-vector-studio-v2__polygon-point-field[data-polygon-point-selectable="true"] {
1683+
cursor: pointer;
1684+
border-radius: 6px;
1685+
}
1686+
1687+
.object-vector-studio-v2__polygon-point-field.is-action-selected {
1688+
background: color-mix(in srgb, var(--tool-starter-accent) 16%, transparent);
1689+
outline: 1px solid color-mix(in srgb, var(--tool-starter-accent) 48%, transparent);
1690+
outline-offset: 2px;
1691+
}
1692+
16821693
.object-vector-studio-v2__polygon-point-label {
16831694
color: var(--tool-starter-muted);
16841695
font-size: 0.82rem;
@@ -1713,12 +1724,6 @@ textarea:hover {
17131724
padding: 5px 7px;
17141725
}
17151726

1716-
.object-vector-studio-v2__polygon-point-toggle {
1717-
display: inline-grid;
1718-
place-items: center;
1719-
min-width: 0;
1720-
}
1721-
17221727
.object-vector-studio-v2__polygon-point-rounding {
17231728
display: inline-grid;
17241729
grid-template-columns: max-content 14px;
@@ -1729,8 +1734,7 @@ textarea:hover {
17291734
font-weight: 800;
17301735
}
17311736

1732-
.object-vector-studio-v2__polygon-point-rounding input,
1733-
.object-vector-studio-v2__polygon-point-toggle input {
1737+
.object-vector-studio-v2__polygon-point-rounding input {
17341738
width: 14px;
17351739
height: 14px;
17361740
margin: 0;

0 commit comments

Comments
 (0)