Automatically adjust dialog position when the virtual keyboard is displayed, and allow input from the virtual keyboard to update value bindings in Svelte textfields.
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
import TextField from "@smui/textfield";
|
import TextField from "@smui/textfield";
|
||||||
import MessageDialog from "$dialogs/MessageDialog.svelte";
|
import MessageDialog from "$dialogs/MessageDialog.svelte";
|
||||||
import * as api from "$lib/api";
|
import * as api from "$lib/api";
|
||||||
|
import { virtualKeyboardChangeHelper } from "$lib/customActions";
|
||||||
|
|
||||||
// https://man7.org/linux/man-pages/man7/hostname.7.html
|
// https://man7.org/linux/man-pages/man7/hostname.7.html
|
||||||
//
|
//
|
||||||
@@ -72,15 +73,12 @@
|
|||||||
<Content id="change-hostname-dialog-content">
|
<Content id="change-hostname-dialog-content">
|
||||||
<TextField
|
<TextField
|
||||||
bind:value={hostname}
|
bind:value={hostname}
|
||||||
|
use={[[virtualKeyboardChangeHelper, (newValue) => (hostname = newValue)]]}
|
||||||
label="New Hostname"
|
label="New Hostname"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
style="width: 100%;"
|
style="width: 100%;"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<p>
|
|
||||||
<em>Clicking Confirm will reboot the controller to apply the change.</em>
|
|
||||||
</p>
|
|
||||||
</Content>
|
</Content>
|
||||||
|
|
||||||
<Actions>
|
<Actions>
|
||||||
|
|||||||
@@ -135,6 +135,67 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { onMount, onDestroy } from "svelte";
|
||||||
|
|
||||||
|
let bodyObserver: MutationObserver;
|
||||||
|
let keyboardObserver: MutationObserver;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
bodyObserver = new MutationObserver(() => {
|
||||||
|
const virtualKeyboard = document.getElementById(
|
||||||
|
"virtualKeyboardChromeExtension"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (virtualKeyboard) {
|
||||||
|
bodyObserver.disconnect();
|
||||||
|
bodyObserver = undefined;
|
||||||
|
|
||||||
|
const virtualKeyboardOverlay = document.getElementById(
|
||||||
|
"virtualKeyboardChromeExtensionOverlayScrollExtend"
|
||||||
|
);
|
||||||
|
|
||||||
|
keyboardObserver = new MutationObserver(() => {
|
||||||
|
const open = virtualKeyboard.getAttribute("_state") === "open";
|
||||||
|
const keyboardHeight = Number.parseFloat(
|
||||||
|
virtualKeyboardOverlay.style.height
|
||||||
|
);
|
||||||
|
|
||||||
|
const dialogContainers = document.querySelectorAll<HTMLDivElement>(
|
||||||
|
".mdc-dialog .mdc-dialog__container"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let dialogContainer of dialogContainers) {
|
||||||
|
dialogContainer.style["marginBottom"] = open
|
||||||
|
? `${keyboardHeight}px`
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
keyboardObserver.observe(virtualKeyboard, { attributes: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bodyObserver.observe(document.querySelector("body"), {
|
||||||
|
subtree: false,
|
||||||
|
childList: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if (bodyObserver) {
|
||||||
|
bodyObserver.disconnect();
|
||||||
|
bodyObserver = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyboardObserver) {
|
||||||
|
keyboardObserver.disconnect();
|
||||||
|
keyboardObserver = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<HomeMachineDialog {...$HomeMachineDialogProps} />
|
<HomeMachineDialog {...$HomeMachineDialogProps} />
|
||||||
<ProbeDialog {...$ProbeDialogProps} />
|
<ProbeDialog {...$ProbeDialogProps} />
|
||||||
<ScreenRotationDialog {...$ScreenRotationDialogProps} />
|
<ScreenRotationDialog {...$ScreenRotationDialogProps} />
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import TextField from "@smui/textfield";
|
import TextField from "@smui/textfield";
|
||||||
import Button, { Label } from "@smui/button";
|
import Button, { Label } from "@smui/button";
|
||||||
import { ControllerMethods } from "$lib/RegisterControllerMethods";
|
import { ControllerMethods } from "$lib/RegisterControllerMethods";
|
||||||
|
import { virtualKeyboardChangeHelper } from "$lib/customActions";
|
||||||
|
|
||||||
export let open: boolean;
|
export let open: boolean;
|
||||||
export let axis = "";
|
export let axis = "";
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
label="Absolute"
|
label="Absolute"
|
||||||
type="number"
|
type="number"
|
||||||
bind:value
|
bind:value
|
||||||
|
use={[[virtualKeyboardChangeHelper, (newValue) => (value = newValue)]]}
|
||||||
variant="filled"
|
variant="filled"
|
||||||
style="width: 100%;"
|
style="width: 100%;"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import TextField from "@smui/textfield";
|
import TextField from "@smui/textfield";
|
||||||
import Button, { Label } from "@smui/button";
|
import Button, { Label } from "@smui/button";
|
||||||
import { ControllerMethods } from "$lib/RegisterControllerMethods";
|
import { ControllerMethods } from "$lib/RegisterControllerMethods";
|
||||||
|
import { virtualKeyboardChangeHelper } from "$lib/customActions";
|
||||||
|
|
||||||
export let open: boolean;
|
export let open: boolean;
|
||||||
export let axis = "";
|
export let axis = "";
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
label="Position"
|
label="Position"
|
||||||
type="number"
|
type="number"
|
||||||
bind:value
|
bind:value
|
||||||
|
use={[[virtualKeyboardChangeHelper, (newValue) => (value = newValue)]]}
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
style="width: 100%;"
|
style="width: 100%;"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
import CircularProgress from "@smui/circular-progress";
|
import CircularProgress from "@smui/circular-progress";
|
||||||
import VirtualList from "svelte-tiny-virtual-list";
|
import VirtualList from "svelte-tiny-virtual-list";
|
||||||
import * as api from "$lib/api";
|
import * as api from "$lib/api";
|
||||||
|
import { virtualKeyboardChangeHelper } from "$lib/customActions";
|
||||||
|
|
||||||
const itemHeight = 35;
|
const itemHeight = 35;
|
||||||
|
|
||||||
@@ -153,6 +154,9 @@
|
|||||||
<Label>Date & Time</Label>
|
<Label>Date & Time</Label>
|
||||||
<TextField
|
<TextField
|
||||||
bind:value
|
bind:value
|
||||||
|
use={[
|
||||||
|
[virtualKeyboardChangeHelper, (newValue) => (value = newValue)],
|
||||||
|
]}
|
||||||
label="Time"
|
label="Time"
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
import MessageDialog from "$dialogs/MessageDialog.svelte";
|
import MessageDialog from "$dialogs/MessageDialog.svelte";
|
||||||
import type { WifiNetwork } from "$lib/NetworkInfo";
|
import type { WifiNetwork } from "$lib/NetworkInfo";
|
||||||
import * as api from "$lib/api";
|
import * as api from "$lib/api";
|
||||||
|
import { virtualKeyboardChangeHelper } from "$lib/customActions";
|
||||||
|
|
||||||
export let open = false;
|
export let open = false;
|
||||||
export let network: WifiNetwork;
|
export let network: WifiNetwork;
|
||||||
@@ -56,6 +57,7 @@
|
|||||||
{#if needPassword}
|
{#if needPassword}
|
||||||
<TextField
|
<TextField
|
||||||
bind:value={password}
|
bind:value={password}
|
||||||
|
use={[[virtualKeyboardChangeHelper, (newValue) => (password = newValue)]]}
|
||||||
label="Password"
|
label="Password"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
|
|||||||
4
src/svelte-components/src/lib/customActions.ts
Normal file
4
src/svelte-components/src/lib/customActions.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export function virtualKeyboardChangeHelper(node: HTMLElement, cb: (value: any) => void) {
|
||||||
|
const input = node.querySelector("input");
|
||||||
|
input.addEventListener("keyup", () => cb(input.value));
|
||||||
|
}
|
||||||
@@ -20,6 +20,10 @@
|
|||||||
:root {
|
:root {
|
||||||
--mdc-theme-text-primary-on-background: #777;
|
--mdc-theme-text-primary-on-background: #777;
|
||||||
|
|
||||||
|
.mdc-dialog .mdc-dialog__container {
|
||||||
|
transition: margin-bottom 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
.mdc-dialog .mdc-dialog__content {
|
.mdc-dialog .mdc-dialog__content {
|
||||||
color: #777;
|
color: #777;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user