Avoid keyboard-height padding inside setup dialogues

This commit is contained in:
vorotamoroz committed 2026-10-30 09:41:12 +00:00
1 parent b6de3969ac
commit b205b14c5f
4 files changed
+47 -1

No files matched your search

@@ -67,7 +67,7 @@
gap: 0.5em; gap: 0.5em;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding-bottom: var(--keyboard-height, 0px); padding-bottom: 0;
user-select: text; user-select: text;
-webkit-user-select: text; -webkit-user-select: text;
} }
+2
View File
@@ -50,6 +50,8 @@ Set `showVerboseLog: true` only in isolated plug-in data when a focused investig
Collect evidence before cleanup, and keep process, Vault, profile, and remote-fixture cleanup in `finally`. After `app.emulateMobile(true)`, use the active CDP renderer for fixture operations because Obsidian may remove desktop-only CLI commands. Visually inspect screenshots before copying selected images into user documentation; a passing locator assertion does not establish that a dialogue is readable or unobstructed. Collect evidence before cleanup, and keep process, Vault, profile, and remote-fixture cleanup in `finally`. After `app.emulateMobile(true)`, use the active CDP renderer for fixture operations because Obsidian may remove desktop-only CLI commands. Visually inspect screenshots before copying selected images into user documentation; a passing locator assertion does not establish that a dialogue is readable or unobstructed.
The dialogue scenario simulates the host keyboard-height variable while the mobile CouchDB setup dialogue is open. It verifies that the space after the final action does not grow with the keyboard height and restores the original variable and scroll position afterwards. This layout fixture does not open a physical software keyboard.
## Local Setup ## Local Setup
Set `OBSIDIAN_BINARY` when Obsidian is not installed in a standard location. Set `OBSIDIAN_CLI` as well when its companion executable is outside the built-in discovery paths. Set `OBSIDIAN_BINARY` when Obsidian is not installed in a standard location. Set `OBSIDIAN_CLI` as well when its companion executable is outside the built-in discovery paths.
@@ -431,6 +431,47 @@ async function assertDialogueActionAlignment(modal: Locator, mode: DialogueMode,
} }
} }
async function assertNoExtraKeyboardSpace(page: Page, modal: Locator): Promise<void> {
const original = await page.evaluate(() => ({
value: document.body.style.getPropertyValue("--keyboard-height"),
priority: document.body.style.getPropertyPriority("--keyboard-height"),
}));
const originalScroll = await modal.locator(".modal-content").evaluate((element) => element.scrollTop);
const keyboardHeight = await page.evaluate(() => Math.round(innerHeight * 0.4));
let baseline: number | undefined;
try {
for (const height of [0, keyboardHeight, 0]) {
await page.evaluate((value) => document.body.style.setProperty("--keyboard-height", `${value}px`), height);
await modal.locator(".modal-content").evaluate((element) => {
element.scrollTop = element.scrollHeight;
});
const gap = await modal.locator(".dialog-host").evaluate((host) => {
const buttons = Array.from(host.querySelectorAll("button")).filter(
(button) => button.getClientRects().length > 0
);
const last = buttons[buttons.length - 1];
if (last === undefined) throw new Error("The dialogue has no action button.");
return host.getBoundingClientRect().bottom - last.getBoundingClientRect().bottom;
});
console.log(JSON.stringify({ event: "dialogue-keyboard-spacing", height, gap, baseline }));
baseline ??= gap;
if (Math.abs(gap - baseline) > 1) {
throw new Error(
`Expected the keyboard not to add blank content after the final action: ${JSON.stringify({ height, gap, baseline })}`
);
}
}
} finally {
await page.evaluate(({ value, priority }) => {
if (value === "") document.body.style.removeProperty("--keyboard-height");
else document.body.style.setProperty("--keyboard-height", value, priority);
}, original);
await modal.locator(".modal-content").evaluate((element, top) => {
element.scrollTop = top;
}, originalScroll);
}
}
async function verifyRemoteSelectionDialogue(mode: DialogueMode): Promise<string> { async function verifyRemoteSelectionDialogue(mode: DialogueMode): Promise<string> {
await openRemoteSelectionDialogue(); await openRemoteSelectionDialogue();
const screenshotPath = await captureObsidianDialogue( const screenshotPath = await captureObsidianDialogue(
@@ -561,6 +602,7 @@ async function verifyCouchDBSettingsDialogue(mode: DialogueMode): Promise<string
await assertDialogueActionAlignment(modal, mode, "CouchDB settings dialogue"); await assertDialogueActionAlignment(modal, mode, "CouchDB settings dialogue");
if (mode === "mobile") { if (mode === "mobile") {
await assertMobileDialogueLayout(page, modal, "CouchDB settings dialogue"); await assertMobileDialogueLayout(page, modal, "CouchDB settings dialogue");
await assertNoExtraKeyboardSpace(page, modal);
} }
} }
); );
+2
View File
@@ -16,6 +16,8 @@ Earlier releases remain available in the 1.0 release history, the 1.0 preview hi
- Buttons in confirmation and setup dialogues now align with the content above them. Confirmation dialogue buttons also have space for keyboard focus outlines. - Buttons in confirmation and setup dialogues now align with the content above them. Confirmation dialogue buttons also have space for keyboard focus outlines.
- Setup dialogues no longer add a large blank area below their buttons when the software keyboard is open.
- A new Join or scheduled Fetch asks for data-handling choices again, even after a previous Fetch changed the local database suffix. - A new Join or scheduled Fetch asks for data-handling choices again, even after a previous Fetch changed the local database suffix.
- Fast Setup retains interrupted choices in an editable Markdown code block in the fetch flag. On restart, we confirm the current remote and saved choices, choose again, or cancel; a remaining flag never reapplies choices silently. - Fast Setup retains interrupted choices in an editable Markdown code block in the fetch flag. On restart, we confirm the current remote and saved choices, choose again, or cancel; a remaining flag never reapplies choices silently.
- If the saved selection cannot be read, we can choose new options for that attempt without repairing or rewriting the flag. Completing or cancelling the operation removes the whole flag. - If the saved selection cannot be read, we can choose new options for that attempt without repairing or rewriting the flag. Completing or cancelling the operation removes the whole flag.