impr(animated modal): add option to automatically focus and select on show

This commit is contained in:
Miodec 2024-03-14 17:02:28 +01:00
parent 9c73697b37
commit b6b22b3cf5
4 changed files with 41 additions and 37 deletions

View file

@ -6,7 +6,7 @@ import AnimatedModal from "../utils/animated-modal";
export function show(): void {
void modal.show({
focusFirstInput: true,
focusFirstInput: "focusAndSelect",
beforeAnimation: async (modalEl) => {
(
modalEl.querySelector("input") as HTMLInputElement

View file

@ -17,6 +17,7 @@ export function show(mode: "import" | "export", config?: string): void {
state.value = config ?? "";
void modal.show({
focusFirstInput: "focusAndSelect",
beforeAnimation: async (modal) => {
(modal.querySelector("input") as HTMLInputElement).value = state.value;
if (state.mode === "export") {
@ -27,14 +28,6 @@ export function show(mode: "import" | "export", config?: string): void {
modal.querySelector("input")?.removeAttribute("readonly");
}
},
afterAnimation: async (modal) => {
const inputEl = modal.querySelector("input");
if (state.mode === "import") {
inputEl?.focus();
} else if (state.mode === "export") {
inputEl?.select();
}
},
});
}

View file

@ -62,26 +62,11 @@ async function copy(): Promise<void> {
duration: 5,
}
);
await modal.hide({
animationMode: "modalOnly",
animationDurationMs: 62.5,
});
void urlModal.show({
animationMode: "modalOnly",
animationDurationMs: 62.5,
beforeAnimation: async (modal) => {
const input = modal.querySelector("input") as HTMLInputElement;
input.value = url;
//focus and select input
setTimeout(() => {
input.focus();
input.select();
}, 0);
},
afterAnimation: async (modal) => {
const input = modal.querySelector("input") as HTMLInputElement;
input.focus();
input.select();
modalChain: modal,
focusFirstInput: "focusAndSelect",
beforeAnimation: async (m) => {
(m.querySelector("input") as HTMLInputElement).value = url;
},
});
}
@ -98,4 +83,20 @@ const modal = new AnimatedModal("shareCustomThemeModal", "popups", undefined, {
},
});
const urlModal = new AnimatedModal("shareCustomThemeUrlModal", "popups");
const urlModal = new AnimatedModal(
"shareCustomThemeUrlModal",
"popups",
undefined,
{
customEscapeHandler: async (): Promise<void> => {
await urlModal.hide({
clearModalChain: true,
});
},
customWrapperClickHandler: async (): Promise<void> => {
await urlModal.hide({
clearModalChain: true,
});
},
}
);

View file

@ -27,7 +27,7 @@ type ShowHideOptions = {
};
export type ShowOptions = ShowHideOptions & {
focusFirstInput?: boolean;
focusFirstInput?: true | "focusAndSelect";
modalChain?: AnimatedModal;
};
@ -146,6 +146,19 @@ export default class AnimatedModal {
isOpen(): boolean {
return this.open;
}
focusFirstInput(setting: true | "focusAndSelect" | undefined): void {
if (setting === true) {
this.modalEl.querySelector("input")?.focus();
} else if (setting === "focusAndSelect") {
const input = this.modalEl.querySelector("input") as HTMLInputElement;
input.focus();
input.select();
} else {
this.wrapperEl.focus();
}
}
async show(options?: ShowOptions): Promise<void> {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve) => {
@ -181,13 +194,9 @@ export default class AnimatedModal {
//wait until the next event loop to allow the dialog to start animating
setTimeout(async () => {
if (options?.focusFirstInput) {
this.modalEl.querySelector("input")?.focus();
} else {
this.wrapperEl.focus();
}
this.focusFirstInput(options?.focusFirstInput);
await options?.beforeAnimation?.(this.modalEl);
}, 0);
}, 1);
const modalAnimation =
options?.customAnimation?.modal ?? this.customShowAnimations?.modal;
@ -231,6 +240,7 @@ export default class AnimatedModal {
animationMode === "none" ? 0 : wrapperAnimationDuration,
wrapperAnimation.easing ?? "swing",
async () => {
this.focusFirstInput(options?.focusFirstInput);
await options?.afterAnimation?.(this.modalEl);
resolve();
}
@ -248,7 +258,7 @@ export default class AnimatedModal {
modalAnimationDuration,
modalAnimation?.easing ?? "swing",
async () => {
this.wrapperEl.focus();
this.focusFirstInput(options?.focusFirstInput);
await options?.afterAnimation?.(this.modalEl);
resolve();
}