Skip to content

Commit 308a587

Browse files
author
DavidQ
committed
Refine snap colors point style controls and angled square cap rendering - PR_26133_076-snap-angle-disabled-colors-and-point-style-refinement
1 parent 540549f commit 308a587

6 files changed

Lines changed: 163 additions & 55 deletions

File tree

docs/dev/reports/playwright_v8_coverage_report.md

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

3-
PR: PR_26133_075-shape-geometry-rounding-and-terminology-normalization
3+
PR: PR_26133_076-snap-angle-disabled-colors-and-point-style-refinement
44

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

@@ -22,7 +22,7 @@ Source: docs/dev/reports/playwright_v8_coverage_report.txt generated by the late
2222
## Changed Runtime JS Files Covered
2323

2424
- (83%) tools/object-vector-studio-v2/js/bootstrap.js - executed lines 109/109; executed functions 5/6
25-
- (96%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 6825/6825; executed functions 688/719
25+
- (96%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 6855/6855; executed functions 689/720
2626

2727
## Changed JS Files Considered
2828

docs/dev/reports/playwright_workspace_v2_results.md

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

3-
PR: PR_26133_075-shape-geometry-rounding-and-terminology-normalization
3+
PR: PR_26133_076-snap-angle-disabled-colors-and-point-style-refinement
44

55
## Validation
66

77
- PASS: npm run test:workspace-v2
88
- Result: 54 passed
9-
- Runtime: 5.3m
9+
- Runtime: 4.6m
1010
- Browser project: playwright
1111
- Workers: 1
1212

1313
## Targeted Checks Covered
1414

15-
- Object Vector Studio V2 UI and tests use Shape Geometry terminology instead of Object Geometry.
16-
- Palette no longer exposes the old End stroke control; stroke width remains in Palette.
17-
- Shape Geometry renders Point Style for closed cornered shapes and Start/End Point Style for open-ended shapes.
18-
- Closed shape point style changes update rendered joins, and open-ended line styles render separate start/end point cap markers.
19-
- Group summary remains below the point-style controls in Shape Geometry.
20-
- Existing polygon/polyline creation, Enter completion, and runtime error coverage remain green.
15+
- Snap control naming uses Snap Angle, including title, button text, aria label, and status log output.
16+
- Inactive Shape/Tools and Snap Angle icons share one disabled/inactive color; Snap None uses the same color.
17+
- Snap Point button color matches visible point snap target circles.
18+
- Shape Geometry Point Style UI renders Start, Joints, and End controls, with line/arc joints disabled and polyline joints wired.
19+
- Angled square line caps render as rotated markers aligned to the line angle instead of detached axis-aligned rectangles.
20+
- Palette accordion/content sizing collapses to the control content without the old empty bottom space.
2121

2222
## Console/Runtime Errors
2323

tests/playwright/tools/WorkspaceManagerV2.spec.mjs

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,10 @@ test.describe("Workspace Manager V2 bootstrap", () => {
15201520
render: icon("#objectVectorStudioV2GridRenderButton"),
15211521
snap: icon("#objectVectorStudioV2SnapModeButton")
15221522
},
1523+
inactiveIconColors: {
1524+
inactiveRectangle: getComputedStyle(document.querySelector("[data-shape-tool='rectangle'] .object-vector-studio-v2__shape-icon")).color,
1525+
snapAngle: getComputedStyle(document.querySelector("#objectVectorStudioV2AngleSnapButton")).color
1526+
},
15231527
modeButtons: {
15241528
paint: {
15251529
iconOrder: getComputedStyle(document.querySelector("#objectVectorStudioV2PaintModeButton"), "::before").order,
@@ -1684,20 +1688,22 @@ test.describe("Workspace Manager V2 bootstrap", () => {
16841688
expect(iconStyleState.viewportIcons.zoomOut.iconName).toBe("nf-oct-zoom_out");
16851689
expect(iconStyleState.titles).toEqual({
16861690
add: "Add a schema-valid object to the loaded payload",
1687-
angle: "Angle Snap is wired to Object Transform Rotate. Enable it before pressing Rotate to round the entered rotation delta to 15 degree increments.",
1691+
angle: "Snap Angle is wired to Object Transform Rotate. Enable it before pressing Rotate to round the entered rotation delta to 15 degree increments.",
16881692
grid: "Show or hide the preview grid",
16891693
polygon: "Create a polygon shape on the selected object. Click to add points.\n\nDouble-click to finish.",
16901694
polyline: "Create a polyline shape on the selected object. Click to add points.\n\nDouble-click to finish.",
16911695
rename: "Disabled until a schema-valid object is selected.",
16921696
shape: "Create a rectangle shape on the selected object",
16931697
zoomIn: "Zoom the work surface in"
16941698
});
1699+
expect(new Set(Object.values(iconStyleState.inactiveIconColors)).size).toBe(1);
1700+
await expect(page.locator("#objectVectorStudioV2AngleSnapButton")).toHaveText("Snap Angle");
16951701
await page.locator("#objectVectorStudioV2AngleSnapButton").click();
16961702
await expect(page.locator("#objectVectorStudioV2AngleSnapButton")).toHaveAttribute("aria-pressed", "true");
1697-
await expect(page.locator("#statusLog")).toHaveValue(/OK Angle snap enabled: Rotate action rounds entered rotation delta to 15 degree increments\./);
1703+
await expect(page.locator("#statusLog")).toHaveValue(/OK Snap angle enabled: Rotate action rounds entered rotation delta to 15 degree increments\./);
16981704
await page.locator("#objectVectorStudioV2AngleSnapButton").click();
16991705
await expect(page.locator("#objectVectorStudioV2AngleSnapButton")).toHaveAttribute("aria-pressed", "false");
1700-
await expect(page.locator("#statusLog")).toHaveValue(/OK Angle snap disabled: Rotate action uses raw entered rotation delta\./);
1706+
await expect(page.locator("#statusLog")).toHaveValue(/OK Snap angle disabled: Rotate action uses raw entered rotation delta\./);
17011707

17021708
await drawDefaultObjectVectorShape(page, "rectangle");
17031709
await expect(page.locator('[data-shape-tool="rectangle"]')).toHaveAttribute("aria-pressed", "true");
@@ -2225,8 +2231,10 @@ test.describe("Workspace Manager V2 bootstrap", () => {
22252231
noApplyButton: !details.querySelector("#objectVectorStudioV2ApplyGeometryButton"),
22262232
noHelperText: !details.textContent.includes("Editable fields below"),
22272233
noSelectedShapeText: !details.textContent.includes("Selected Shape"),
2234+
pointStyleHeading: details.querySelector(".object-vector-studio-v2__point-style-heading")?.textContent.trim() || "",
22282235
pointStyleBeforeGroup: Boolean(pointStyleControls && groupSummary && (pointStyleControls.compareDocumentPosition(groupSummary) & Node.DOCUMENT_POSITION_FOLLOWING)),
22292236
pointStyleControls: Array.from(details.querySelectorAll("[data-shape-point-style-field]")).map((control) => ({
2237+
disabled: control.disabled,
22302238
label: control.closest("label").querySelector("span").textContent.trim(),
22312239
value: control.value
22322240
})),
@@ -2237,15 +2245,16 @@ test.describe("Workspace Manager V2 bootstrap", () => {
22372245
expect(shapeGeometryOrder.noApplyButton).toBe(true);
22382246
expect(shapeGeometryOrder.noHelperText).toBe(true);
22392247
expect(shapeGeometryOrder.noSelectedShapeText).toBe(true);
2248+
expect(shapeGeometryOrder.pointStyleHeading).toBe("Point Style:");
22402249
expect(shapeGeometryOrder.pointStyleBeforeGroup).toBe(true);
2241-
expect(shapeGeometryOrder.pointStyleControls).toEqual([{ label: "Point Style", value: "round" }]);
2250+
expect(shapeGeometryOrder.pointStyleControls).toEqual([{ disabled: false, label: "Joints", value: "round" }]);
22422251
expect(shapeGeometryOrder.summaryItems).toEqual([
22432252
"Rectangle Geometry",
22442253
"Group",
22452254
"None"
22462255
]);
22472256
await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-shape-point-style-field='pointStyle']").selectOption("square");
2248-
await expect(page.locator("#statusLog")).toHaveValue(/OK Updated Point Style to square for shape row 0\./);
2257+
await expect(page.locator("#statusLog")).toHaveValue(/OK Updated Joints to square for shape row 0\./);
22492258
const rectanglePointStyleRender = await page.locator("#objectVectorStudioV2RenderSurface [data-shape-index='0']").evaluate((shape) => ({
22502259
pointStyle: shape.dataset.pointStyle,
22512260
strokeLinejoin: shape.getAttribute("stroke-linejoin")
@@ -3685,6 +3694,11 @@ test.describe("Workspace Manager V2 bootstrap", () => {
36853694
await expect(page.locator("#objectVectorStudioV2SnapModeButton")).toHaveAttribute("data-snap-mode", "point");
36863695
await expect(page.locator("#objectVectorStudioV2SnapModeButton")).toHaveAttribute("aria-pressed", "true");
36873696
await expect(page.locator("#objectVectorStudioV2RenderSurface .object-vector-studio-v2__snap-target")).not.toHaveCount(0);
3697+
const snapPointColorState = await page.evaluate(() => ({
3698+
buttonColor: getComputedStyle(document.querySelector("#objectVectorStudioV2SnapModeButton")).color,
3699+
targetStroke: getComputedStyle(document.querySelector("#objectVectorStudioV2RenderSurface .object-vector-studio-v2__snap-target")).stroke
3700+
}));
3701+
expect(snapPointColorState.buttonColor).toBe(snapPointColorState.targetStroke);
36883702
await drawObjectVectorShape(page, "line", [{ x: 1.3, y: 2.2 }, { x: 4.2, y: 4.1 }]);
36893703
const pointSnappedLine = await page.evaluate(() => window.__objectVectorStudioV2App.selectedShape().geometry);
36903704
expect(pointSnappedLine).toEqual({ point1: { x: 1, y: 2 }, point2: { x: 4, y: 4 } });
@@ -3693,6 +3707,11 @@ test.describe("Workspace Manager V2 bootstrap", () => {
36933707
await expect(page.locator("#objectVectorStudioV2SnapModeButton")).toHaveText("Snap None");
36943708
await expect(page.locator("#objectVectorStudioV2SnapModeButton")).toHaveAttribute("data-snap-mode", "none");
36953709
await expect(page.locator("#objectVectorStudioV2SnapModeButton")).toHaveAttribute("aria-pressed", "false");
3710+
const snapNoneColorState = await page.evaluate(() => ({
3711+
disabledIconColor: getComputedStyle(document.querySelector("#objectVectorStudioV2AngleSnapButton")).color,
3712+
snapNoneColor: getComputedStyle(document.querySelector("#objectVectorStudioV2SnapModeButton")).color
3713+
}));
3714+
expect(snapNoneColorState.snapNoneColor).toBe(snapNoneColorState.disabledIconColor);
36963715
await drawObjectVectorShape(page, "line", [{ x: 5.25, y: 6.5 }, { x: 7.75, y: 8.25 }]);
36973716
const unsnappedLine = await page.evaluate(() => window.__objectVectorStudioV2App.selectedShape().geometry);
36983717
expect(unsnappedLine).toEqual({ point1: { x: 5.25, y: 6.5 }, point2: { x: 7.75, y: 8.25 } });
@@ -3732,7 +3751,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
37323751
await page.locator("#objectVectorStudioV2StrokeWidth").dispatchEvent("change");
37333752
await page.locator('[data-shape-tool="line"]').click();
37343753
await clickObjectVectorLogicalPoint(page, -40, -50);
3735-
await moveObjectVectorLogicalPoint(page, { x: -10, y: -50 });
3754+
await moveObjectVectorLogicalPoint(page, { x: -10, y: -30 });
37363755
const wideStrokePreview = await page.locator("#objectVectorStudioV2RenderSurface .object-vector-studio-v2__drawing-preview").evaluate((preview) => ({
37373756
dash: preview.style.strokeDasharray,
37383757
strokeLinecap: preview.style.strokeLinecap,
@@ -3745,7 +3764,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
37453764
expect(wideStrokeDash[0]).toBeGreaterThan(5);
37463765
expect(wideStrokeDash[0]).toBeLessThan(220);
37473766
expect(wideStrokeDash[1]).toBeGreaterThan(4);
3748-
await clickObjectVectorLogicalPoint(page, -10, -50);
3767+
await clickObjectVectorLogicalPoint(page, -10, -30);
37493768
const wideStrokeLine = await page.evaluate(() => {
37503769
const app = window.__objectVectorStudioV2App;
37513770
return {
@@ -3760,15 +3779,17 @@ test.describe("Workspace Manager V2 bootstrap", () => {
37603779
strokeWidth: 20
37613780
});
37623781
const openPointStyleControls = await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-shape-point-style-field]").evaluateAll((controls) => controls.map((control) => ({
3782+
disabled: control.disabled,
37633783
label: control.closest("label").querySelector("span").textContent.trim(),
37643784
value: control.value
37653785
})));
37663786
expect(openPointStyleControls).toEqual([
3767-
{ label: "Start Point Style", value: "round" },
3768-
{ label: "End Point Style", value: "round" }
3787+
{ disabled: false, label: "Start", value: "round" },
3788+
{ disabled: true, label: "Joints", value: "round" },
3789+
{ disabled: false, label: "End", value: "round" }
37693790
]);
37703791
await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-shape-point-style-field='endPointStyle']").selectOption("square");
3771-
await expect(page.locator("#statusLog")).toHaveValue(/OK Updated End Point Style to square for shape row \d+\./);
3792+
await expect(page.locator("#statusLog")).toHaveValue(/OK Updated End to square for shape row \d+\./);
37723793
const wideStrokeLineAfterPointStyle = await page.evaluate(() => {
37733794
const app = window.__objectVectorStudioV2App;
37743795
return JSON.parse(JSON.stringify(app.selectedShape().style));
@@ -3790,12 +3811,26 @@ test.describe("Workspace Manager V2 bootstrap", () => {
37903811
const splitPointCaps = await page.locator(`#objectVectorStudioV2RenderSurface [data-point-style-caps='line'] [data-point-style-cap]`).evaluateAll((caps) => caps.map((cap) => ({
37913812
endpoint: cap.dataset.pointStyleCap,
37923813
pointStyle: cap.dataset.pointStyle,
3793-
tag: cap.tagName.toLowerCase()
3814+
tag: cap.tagName.toLowerCase(),
3815+
transform: cap.getAttribute("transform") || ""
37943816
})));
3795-
expect(splitPointCaps).toEqual([
3796-
{ endpoint: "start", pointStyle: "round", tag: "circle" },
3797-
{ endpoint: "end", pointStyle: "square", tag: "rect" }
3798-
]);
3817+
expect(splitPointCaps[0]).toMatchObject({ endpoint: "start", pointStyle: "round", tag: "circle", transform: "" });
3818+
expect(splitPointCaps[1]).toMatchObject({ endpoint: "end", pointStyle: "square", tag: "rect" });
3819+
expect(splitPointCaps[1].transform).toMatch(/^rotate\((?!0(?:\\.0+)? )/);
3820+
3821+
await page.locator('[data-shape-tool="polyline"]').click();
3822+
await clickObjectVectorLogicalPoint(page, 10, -40);
3823+
await clickObjectVectorLogicalPoint(page, 20, -20);
3824+
await clickObjectVectorLogicalPoint(page, 40, -40);
3825+
await page.keyboard.press("Enter");
3826+
await expect(page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-shape-point-style-field]")).toHaveCount(3);
3827+
await page.locator("#objectVectorStudioV2ShapeGeometryDetails [data-shape-point-style-field='pointStyle']").selectOption("square");
3828+
await expect(page.locator("#statusLog")).toHaveValue(/OK Updated Joints to square for shape row \d+\./);
3829+
const polylineJoinStyle = await page.locator(`#objectVectorStudioV2RenderSurface [data-shape-index="${await page.evaluate(() => window.__objectVectorStudioV2App.selectedShapeIndex)}"]`).evaluate((shape) => ({
3830+
jointStyle: shape.dataset.pointStyle || "",
3831+
strokeLinejoin: shape.getAttribute("stroke-linejoin")
3832+
}));
3833+
expect(polylineJoinStyle).toEqual({ jointStyle: "square", strokeLinejoin: "miter" });
37993834

38003835
await page.locator('[data-shape-tool="text"]').click();
38013836
await clickObjectVectorLogicalPoint(page, 70, 60);

tools/object-vector-studio-v2/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ <h2 class="tools-platform-frame__eyebrow">First-Class Tools Surface V2</h2>
269269
<hr class="object-vector-studio-v2__separator">
270270
<div class="object-vector-studio-v2__snap-actions" aria-label="Snap controls">
271271
<button id="objectVectorStudioV2SnapModeButton" type="button" aria-pressed="true" title="Snap drawing and point dragging to grid intersections">Snap Grid</button>
272-
<button id="objectVectorStudioV2AngleSnapButton" type="button" aria-pressed="false" title="Angle Snap is wired to Object Transform Rotate. Enable it before pressing Rotate to round the entered rotation delta to 15 degree increments.">Angle Snap</button>
272+
<button id="objectVectorStudioV2AngleSnapButton" type="button" aria-pressed="false" title="Snap Angle is wired to Object Transform Rotate. Enable it before pressing Rotate to round the entered rotation delta to 15 degree increments.">Snap Angle</button>
273273
<button id="objectVectorStudioV2GridRenderButton" type="button" aria-pressed="false" title="Show or hide the preview grid">Grid</button>
274274
<button id="objectVectorStudioV2ToolLabelModeButton" type="button" aria-pressed="false" title="Toggle shape tool labels between icon-only and icon plus text">Icon/Text</button>
275275
</div>

0 commit comments

Comments
 (0)