Skip to content

Commit 5e6ee39

Browse files
author
DavidQ
committed
Unify shape creation flow and preserve stroke width on final commit - PR_26133_070-unified-click-preview-click-shape-creation
1 parent 7f7a8e7 commit 5e6ee39

4 files changed

Lines changed: 101 additions & 100 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 @@
1-
# Playwright V8 Coverage Report
1+
# Playwright V8 Coverage Report
22

3-
PR: PR_26133_069-object-preview-selection-style-and-snap-fixes
3+
PR: PR_26133_070-unified-click-preview-click-shape-creation
44

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

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

2222
## Changed Runtime JS Files Covered
2323

24-
- (95%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 6357/6357; executed functions 644/676
24+
- (95%) tools/object-vector-studio-v2/js/ToolStarterApp.js - executed lines 6352/6352; executed functions 645/676
2525

2626
## Changed JS Files Considered
2727

docs/dev/reports/playwright_workspace_v2_results.md

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

3-
PR: PR_26133_069-object-preview-selection-style-and-snap-fixes
3+
PR: PR_26133_070-unified-click-preview-click-shape-creation
44

55
## Validation
66

@@ -12,13 +12,12 @@ PR: PR_26133_069-object-preview-selection-style-and-snap-fixes
1212

1313
## Targeted Checks Covered
1414

15-
- New Object Vector Studio V2 shapes are committed stroke-only with transparent fill for line, polygon, polyline, rectangle, square, circle, ellipse, triangle, and text drawing flows.
16-
- Empty canvas click deselects the current shape and clicking inside another shape selects it.
17-
- Selected shape click-hold-drag movement updates live through the preview surface.
18-
- Circle selection handle resize updates circle geometry.
19-
- Snap Grid stores whole logical coordinates and Snap None preserves fractional coordinates.
20-
- Paint and Stroke stay independent; applying Stroke does not mutate Fill opacity and applying Paint does not mutate Stroke opacity.
21-
- Selecting Shape/Tools activates Stroke mode.
15+
- Simple/bounded Object Vector Studio V2 tools use click -> live preview -> click commit for line, rectangle, square, circle, ellipse, arc, text, and triangle.
16+
- Polygon and Polyline keep multi-point click behavior and still finish through Enter/double-click completion paths.
17+
- Drawing preview remains visible after first click and mouse move; Escape does not cancel Object Vector Studio V2 drawing.
18+
- Committed shapes capture active Stroke color, Stroke opacity, and Stroke Width consistently from drawing start through commit.
19+
- Newly committed shapes keep transparent fill unless Paint is applied later.
20+
- Snap Grid, Snap Point, and Snap None behaviors remain covered during drawing flows.
2221

2322
## Console/Runtime Errors
2423

tests/playwright/tools/WorkspaceManagerV2.spec.mjs

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -133,29 +133,30 @@ async function dragObjectVectorLogicalPoints(page, start, end) {
133133
}, { endPoint, startPoint });
134134
}
135135

136+
async function moveObjectVectorLogicalPoint(page, point) {
137+
const clientPoint = await objectVectorLogicalClientPoint(page, point.x, point.y);
138+
await page.evaluate((targetPoint) => {
139+
const pointerInit = {
140+
bubbles: true,
141+
button: 0,
142+
buttons: 0,
143+
cancelable: true,
144+
clientX: targetPoint.x,
145+
clientY: targetPoint.y,
146+
pointerId: 1,
147+
pointerType: "mouse"
148+
};
149+
window.dispatchEvent(new PointerEvent("pointermove", pointerInit));
150+
}, clientPoint);
151+
}
152+
136153
async function drawObjectVectorShape(page, tool, points) {
137154
await page.locator(`[data-shape-tool="${tool}"]`).click();
138-
if (["rectangle", "square", "circle", "ellipse", "arc", "triangle"].includes(tool)) {
139-
await dragObjectVectorLogicalPoints(page, points[0], points[1]);
140-
return;
141-
}
142-
if (tool === "line") {
155+
if (["line", "rectangle", "square", "circle", "ellipse", "arc", "text", "triangle"].includes(tool)) {
156+
const endPoint = points[1] || points[0];
143157
await clickObjectVectorLogicalPoint(page, points[0].x, points[0].y);
144-
const endPoint = await objectVectorLogicalClientPoint(page, points[1].x, points[1].y);
145-
await page.evaluate((point) => {
146-
const pointerInit = {
147-
bubbles: true,
148-
button: 0,
149-
buttons: 1,
150-
cancelable: true,
151-
clientX: point.x,
152-
clientY: point.y,
153-
pointerId: 1,
154-
pointerType: "mouse"
155-
};
156-
window.dispatchEvent(new PointerEvent("pointermove", pointerInit));
157-
}, endPoint);
158-
await clickObjectVectorLogicalPoint(page, points[1].x, points[1].y);
158+
await moveObjectVectorLogicalPoint(page, endPoint);
159+
await clickObjectVectorLogicalPoint(page, endPoint.x, endPoint.y);
159160
return;
160161
}
161162
if (tool === "polygon" || tool === "polyline") {
@@ -165,9 +166,6 @@ async function drawObjectVectorShape(page, tool, points) {
165166
await page.keyboard.press("Enter");
166167
return;
167168
}
168-
if (tool === "text") {
169-
await clickObjectVectorLogicalPoint(page, points[0].x, points[0].y);
170-
}
171169
}
172170

173171
async function drawDefaultObjectVectorShape(page, tool) {
@@ -180,7 +178,7 @@ async function drawDefaultObjectVectorShape(page, tool) {
180178
polyline: [{ x: -40, y: 0 }, { x: 0, y: -30 }, { x: 40, y: 0 }],
181179
rectangle: [{ x: -80, y: -30 }, { x: 0, y: 30 }],
182180
square: [{ x: -80, y: -30 }, { x: -20, y: 30 }],
183-
text: [{ x: -30, y: 40 }],
181+
text: [{ x: -35, y: 35 }, { x: -30, y: 40 }],
184182
triangle: [{ x: -40, y: -80 }, { x: 40, y: -10 }]
185183
};
186184
await drawObjectVectorShape(page, tool, defaults[tool]);
@@ -1661,7 +1659,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
16611659

16621660
await drawDefaultObjectVectorShape(page, "rectangle");
16631661
await expect(page.locator('[data-shape-tool="rectangle"]')).toHaveAttribute("aria-pressed", "true");
1664-
await expect(page.locator("#statusLog")).toHaveValue(/OK Drawing mode selected: Rectangle\. Use canvas pointer input to create geometry\. Select a schema-valid object before committing geometry\./);
1662+
await expect(page.locator("#statusLog")).toHaveValue(/OK Drawing mode selected: Rectangle\. Click once to start, move to preview, then click again to finish\. Select a schema-valid object before committing geometry\./);
16651663
const shapeToolLayout = await page.locator('[data-shape-tool="rectangle"]').evaluate((button) => {
16661664
const rect = button.getBoundingClientRect();
16671665
const gridButton = document.querySelector("#objectVectorStudioV2GridRenderButton");
@@ -2262,7 +2260,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
22622260
await expect(page.locator("#objectVectorStudioV2ShapeLockButton")).toHaveCount(0);
22632261
await expect(page.locator("#objectVectorStudioV2DuplicateShapeButton")).toHaveCount(0);
22642262
await expect(page.locator("#objectVectorStudioV2DeleteShapeButton")).toHaveCount(0);
2265-
await expect(page.locator("#statusLog")).toHaveValue(/OK Created rectangle shape on Asteroids Ship from canvas drag\./);
2263+
await expect(page.locator("#statusLog")).toHaveValue(/OK Created rectangle shape on Asteroids Ship from canvas click\./);
22662264
await expect(page.locator("#statusLog")).toHaveValue(/OK Render mode svg-work-surface: rendered Asteroids Ship with 1 visible shapes; capture mode none\./);
22672265
const createdRectangleSchemaDefaults = await page.evaluate(() => {
22682266
const app = window.__objectVectorStudioV2App;
@@ -2289,7 +2287,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
22892287
fillOpacity: createdRectangleSchemaDefaults.schemaStyle.fillOpacity,
22902288
stroke: "#ffffff",
22912289
strokeOpacity: createdRectangleSchemaDefaults.schemaStyle.strokeOpacity,
2292-
strokeWidth: createdRectangleSchemaDefaults.schemaStyle.strokeWidth
2290+
strokeWidth: 2
22932291
},
22942292
tool: "rectangle",
22952293
transform: {
@@ -3382,7 +3380,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
33823380
});
33833381

33843382
await drawDefaultObjectVectorShape(page, "square");
3385-
await expect(page.locator("#statusLog")).toHaveValue(/OK Created square shape on Square Tool Check from canvas drag\./);
3383+
await expect(page.locator("#statusLog")).toHaveValue(/OK Created square shape on Square Tool Check from canvas click\./);
33863384
await expect(page.locator("#objectVectorStudioV2ObjectDetails")).toContainText("Square Geometry");
33873385
await expect(page.locator(".object-vector-studio-v2__shape-select-label")).toHaveText("0. Square");
33883386
const createdSquare = await page.evaluate(() => {
@@ -3409,7 +3407,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
34093407
],
34103408
geometry: { height: 60, width: 60, x: -80, y: -30 },
34113409
schemaOk: true,
3412-
style: { fill: "#00000000", fillOpacity: 1, stroke: "#ffffff", strokeOpacity: 1, strokeWidth: 3 },
3410+
style: { fill: "#00000000", fillOpacity: 1, stroke: "#ffffff", strokeOpacity: 1, strokeWidth: 2 },
34133411
tool: "square"
34143412
});
34153413

@@ -3483,6 +3481,8 @@ test.describe("Workspace Manager V2 bootstrap", () => {
34833481
});
34843482
await page.locator("#objectVectorStudioV2StrokeModeButton").click();
34853483
await page.locator("[data-palette-color='#6fd3ff']").click();
3484+
await page.locator("#objectVectorStudioV2StrokeWidth").fill("4.5");
3485+
await page.locator("#objectVectorStudioV2StrokeWidth").dispatchEvent("change");
34863486

34873487
await page.locator('[data-shape-tool="polygon"]').click();
34883488
await expect(page.locator("#statusLog")).toHaveValue(/OK Drawing mode selected: Polygon\. Click to add points\.\n\nDouble-click to finish\./);
@@ -3492,9 +3492,13 @@ test.describe("Workspace Manager V2 bootstrap", () => {
34923492
await expect(page.locator('[data-shape-tool="rectangle"]')).toHaveAttribute("aria-pressed", "true");
34933493
await expect(page.locator("#objectVectorStudioV2RenderSurface")).toHaveClass(/is-drawing-mode/);
34943494
await expect(page.locator("#objectVectorStudioV2RenderSurface [data-shape-index]")).toHaveCount(0);
3495+
await clickObjectVectorLogicalPoint(page, -80, -30);
3496+
await moveObjectVectorLogicalPoint(page, { x: -20, y: 30 });
3497+
await expect(page.locator("#objectVectorStudioV2RenderSurface .object-vector-studio-v2__drawing-preview")).toHaveCount(1);
34953498
await page.keyboard.press("Escape");
34963499
await expect(page.locator("#objectVectorStudioV2RenderSurface")).toHaveClass(/is-drawing-mode/);
34973500
await expect(page.locator("#objectVectorStudioV2RenderSurface [data-shape-index]")).toHaveCount(0);
3501+
await expect(page.locator("#objectVectorStudioV2RenderSurface .object-vector-studio-v2__drawing-preview")).toHaveCount(1);
34983502
await page.locator('[data-shape-tool="select"]').click();
34993503
await expect(page.locator("#objectVectorStudioV2RenderSurface")).not.toHaveClass(/is-drawing-mode/);
35003504
await expect(page.locator("#objectVectorStudioV2RenderSurface [data-shape-index]")).toHaveCount(0);
@@ -3507,12 +3511,14 @@ test.describe("Workspace Manager V2 bootstrap", () => {
35073511
fill: shape.style.fill,
35083512
geometry: shape.geometry,
35093513
stroke: shape.style.stroke,
3514+
strokeOpacity: shape.style.strokeOpacity,
3515+
strokeWidth: shape.style.strokeWidth,
35103516
tool: shape.tool
35113517
})));
35123518
expect(pointDrawnShapes).toMatchObject([
3513-
{ fill: "#00000000", geometry: { point1: { x: -10, y: 0 }, point2: { x: 10, y: 0 } }, stroke: "#6fd3ff", tool: "line" },
3514-
{ fill: "#00000000", geometry: { points: [{ x: -10, y: -10 }, { x: 10, y: -10 }, { x: 10, y: 10 }, { x: -10, y: 10 }] }, stroke: "#6fd3ff", tool: "polygon" },
3515-
{ fill: "#00000000", geometry: { points: [{ x: -20, y: 20 }, { x: 0, y: 0 }, { x: 20, y: 20 }] }, stroke: "#6fd3ff", tool: "polyline" }
3519+
{ fill: "#00000000", geometry: { point1: { x: -10, y: 0 }, point2: { x: 10, y: 0 } }, stroke: "#6fd3ff", strokeOpacity: 1, strokeWidth: 4.5, tool: "line" },
3520+
{ fill: "#00000000", geometry: { points: [{ x: -10, y: -10 }, { x: 10, y: -10 }, { x: 10, y: 10 }, { x: -10, y: 10 }] }, stroke: "#6fd3ff", strokeOpacity: 1, strokeWidth: 4.5, tool: "polygon" },
3521+
{ fill: "#00000000", geometry: { points: [{ x: -20, y: 20 }, { x: 0, y: 0 }, { x: 20, y: 20 }] }, stroke: "#6fd3ff", strokeOpacity: 1, strokeWidth: 4.5, tool: "polyline" }
35163522
]);
35173523
const strokeOnlyPolygonBeforeSelection = await page.evaluate(() => {
35183524
const app = window.__objectVectorStudioV2App;
@@ -3604,16 +3610,17 @@ test.describe("Workspace Manager V2 bootstrap", () => {
36043610
fillOpacity: shape.style.fillOpacity,
36053611
stroke: shape.style.stroke,
36063612
strokeOpacity: shape.style.strokeOpacity,
3613+
strokeWidth: shape.style.strokeWidth,
36073614
tool: shape.tool
36083615
}));
36093616
});
36103617
expect(strokeOnlyCreatedShapes).toEqual([
3611-
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, tool: "rectangle" },
3612-
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, tool: "square" },
3613-
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, tool: "circle" },
3614-
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, tool: "ellipse" },
3615-
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, tool: "triangle" },
3616-
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, tool: "text" }
3618+
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, strokeWidth: 4.5, tool: "rectangle" },
3619+
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, strokeWidth: 4.5, tool: "square" },
3620+
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, strokeWidth: 4.5, tool: "circle" },
3621+
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, strokeWidth: 4.5, tool: "ellipse" },
3622+
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, strokeWidth: 4.5, tool: "triangle" },
3623+
{ fill: "#00000000", fillOpacity: 1, stroke: "#6fd3ff", strokeOpacity: 1, strokeWidth: 4.5, tool: "text" }
36173624
]);
36183625

36193626
expect(pageErrors).toEqual([]);
@@ -4631,7 +4638,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
46314638
await expect(page.locator('[data-object-thumbnail="object.authoring.ufo-template"] .object-vector-studio-v2__object-thumbnail-shape')).toHaveCount(2);
46324639
await expect(page.locator("#objectVectorStudioV2RenderSurface [data-object-bounds='object.authoring.ufo-template']")).toHaveCount(1);
46334640
await expect(page.locator('[data-object-id="object.authoring.ufo-template"] [data-object-tile-shape-index]')).toHaveCount(2);
4634-
await expect(page.locator("#statusLog")).toHaveValue(/OK Created ellipse shape on UFO Template from canvas drag\./);
4641+
await expect(page.locator("#statusLog")).toHaveValue(/OK Created ellipse shape on UFO Template from canvas click\./);
46354642
const ellipseGeometryLayout = await page.locator("#objectVectorStudioV2ObjectDetails .object-vector-studio-v2__edit-grid--ellipse").evaluate((grid) => {
46364643
const fields = Array.from(grid.querySelectorAll(".object-vector-studio-v2__edit-field"));
46374644
const fieldRects = fields.map((field) => field.getBoundingClientRect());

0 commit comments

Comments
 (0)