mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
🐛 Fix resize cursor when selection has mixed values (#12229)
* 🐛 Fix resize cursor when selection has mixed values * 📎 PR changes * ✨ Add test
This commit is contained in:
parent
21ecfb67b7
commit
d800b893bc
@ -133,7 +133,7 @@ test("BUG 10001: Negative margins are allowed on the numeric input", async ({
|
||||
});
|
||||
|
||||
await expect(verticalMarginInput).toBeVisible();
|
||||
|
||||
|
||||
await verticalMarginInput.fill("-10");
|
||||
await verticalMarginInput.press("Enter");
|
||||
await expect(verticalMarginInput).toHaveValue("-10");
|
||||
@ -230,3 +230,54 @@ test("BUG 10638 - Invalid padding input on multi-selection must not persist stri
|
||||
expect(seenLayoutValues).not.toEqual([]);
|
||||
expect(badLayoutValues).toEqual([]);
|
||||
});
|
||||
|
||||
test("BUG 12227: Numeric inputs only show the scrub cursor when they hold a single value", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspacePage = new WasmWorkspacePage(page);
|
||||
await workspacePage.setupEmptyFile(page);
|
||||
await workspacePage.mockRPC(
|
||||
/get\-file\?/,
|
||||
"workspace/get-file-copy-paste.json",
|
||||
);
|
||||
await workspacePage.mockRPC(
|
||||
"get-file-fragment?file-id=*&fragment-id=*",
|
||||
"workspace/get-file-copy-paste-fragment.json",
|
||||
);
|
||||
|
||||
await workspacePage.goToWorkspace({
|
||||
fileId: "870f9f10-87b5-8137-8005-934804124660",
|
||||
pageId: "870f9f10-87b5-8137-8005-934804124661",
|
||||
});
|
||||
|
||||
await page.getByTestId("layer-item").getByRole("button").first().click();
|
||||
await workspacePage.layers.getByTestId("layer-row").nth(0).click();
|
||||
|
||||
const measuresSection = workspacePage.rightSidebar.getByRole("region", {
|
||||
name: "shape-measures-section",
|
||||
});
|
||||
await expect(measuresSection).toBeVisible();
|
||||
|
||||
const widthInput = measuresSection.getByRole("textbox", {
|
||||
name: "Width",
|
||||
exact: true,
|
||||
});
|
||||
await expect(widthInput).toHaveValue("360");
|
||||
|
||||
// The wrapper around the input is the element that carries the cursor.
|
||||
const widthWrapper = measuresSection
|
||||
.getByTestId("numeric-input-wrapper")
|
||||
.filter({ has: page.getByRole("textbox", { name: "Width", exact: true }) });
|
||||
|
||||
// A single committed value can be scrubbed.
|
||||
await expect(widthWrapper).toHaveCSS("cursor", "ew-resize");
|
||||
|
||||
// Selecting a second shape with a different width mixes the values.
|
||||
// The field then has no single value, so it must not look scrubbable.
|
||||
await workspacePage.layers
|
||||
.getByTestId("layer-row")
|
||||
.nth(1)
|
||||
.click({ modifiers: ["Shift"] });
|
||||
await expect(widthInput).toHaveAttribute("placeholder", "Mixed");
|
||||
await expect(widthWrapper).not.toHaveCSS("cursor", "ew-resize");
|
||||
});
|
||||
|
||||
@ -245,6 +245,10 @@
|
||||
is-token-applied? (and (some? token-applied-name)
|
||||
(not= :multiple token-applied-name))
|
||||
|
||||
scrubbable? (and (some? value)
|
||||
(not disabled)
|
||||
(not is-token-applied?))
|
||||
|
||||
focused-id* (mf/use-state nil)
|
||||
focused-id (deref focused-id*)
|
||||
|
||||
@ -572,24 +576,22 @@
|
||||
|
||||
on-scrub-pointer-down
|
||||
(mf/use-fn
|
||||
(mf/deps disabled is-open is-multiple? ref min max nillable default is-token-applied?)
|
||||
(mf/deps is-open ref min max nillable default scrubbable?)
|
||||
(fn [event]
|
||||
(when-not (or disabled is-open is-multiple? is-token-applied?)
|
||||
(let [has-token (some? (deref token-applied-name*))]
|
||||
(when-not has-token
|
||||
(let [client-x (.-clientX event)
|
||||
parsed (parse-value (str/trim (mf/ref-val raw-value*)) (mf/ref-val last-value*) min max nillable)
|
||||
start-val (or parsed default 0)]
|
||||
(mf/set-ref-val! drag-state* :maybe-dragging)
|
||||
(mf/set-ref-val! drag-start-x* client-x)
|
||||
(mf/set-ref-val! drag-start-val* start-val)
|
||||
(dom/capture-pointer event)))))))
|
||||
(when (and (not is-open) scrubbable?)
|
||||
(let [client-x (.-clientX event)
|
||||
parsed (parse-value (str/trim (mf/ref-val raw-value*)) (mf/ref-val last-value*) min max nillable)
|
||||
start-val (or parsed default 0)]
|
||||
(mf/set-ref-val! drag-state* :maybe-dragging)
|
||||
(mf/set-ref-val! drag-start-x* client-x)
|
||||
(mf/set-ref-val! drag-start-val* start-val)
|
||||
(dom/capture-pointer event)))))
|
||||
|
||||
on-scrub-pointer-move
|
||||
(mf/use-fn
|
||||
(mf/deps apply-value update-input step min max on-change-start is-token-applied?)
|
||||
(mf/deps apply-value update-input step min max on-change-start scrubbable?)
|
||||
(fn [event]
|
||||
(when-not is-token-applied?
|
||||
(when scrubbable?
|
||||
(let [state (mf/ref-val drag-state*)]
|
||||
(when (or (= state :maybe-dragging) (= state :dragging))
|
||||
(let [client-x (.-clientX event)
|
||||
@ -857,9 +859,9 @@
|
||||
(mf/with-effect [handle-unmount] handle-unmount)
|
||||
|
||||
[:div {:class [class (stl/css-case :input-wrapper true
|
||||
:resizable (and (not is-token-applied?)
|
||||
(not disabled)))]
|
||||
:scrubbable scrubbable?)]
|
||||
:ref wrapper-ref
|
||||
:data-testid "numeric-input-wrapper"
|
||||
:on-pointer-down on-scrub-pointer-down
|
||||
:on-pointer-move on-scrub-pointer-move
|
||||
:on-pointer-up on-scrub-pointer-up
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
inline-size: 100%;
|
||||
position: relative;
|
||||
|
||||
&.resizable {
|
||||
&.scrubbable {
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user