feat(vue): extend useIonRouter hook for programmatic navigation with animation control (#23499)

resolves #23450
This commit is contained in:
Liam DeBeasi
2021-06-28 10:33:32 -04:00
committed by GitHub
parent 79e3a26499
commit fc9e1b4b36
10 changed files with 456 additions and 132 deletions

View File

@ -0,0 +1,15 @@
import { BackButtonEvent } from '@ionic/core/components';
type Handler = (processNextHandler: () => void) => Promise<any> | void | null;
export interface UseBackButtonResult {
unregister: () => void;
}
export const useBackButton = (priority: number, handler: Handler): UseBackButtonResult => {
const callback = (ev: BackButtonEvent) => ev.detail.register(priority, handler);
const unregister = () => document.removeEventListener('ionBackButton', callback);
document.addEventListener('ionBackButton', callback);
return { unregister };
}

View File

@ -0,0 +1,40 @@
import { ref, Ref } from 'vue';
export interface UseKeyboardResult {
isOpen: Ref<boolean>;
keyboardHeight: Ref<number>;
unregister: () => void
}
export const useKeyboard = (): UseKeyboardResult => {
let isOpen = ref(false);
let keyboardHeight = ref(0);
const showCallback = (ev: CustomEvent) => {
isOpen.value = true;
keyboardHeight.value = ev.detail.keyboardHeight;
}
const hideCallback = () => {
isOpen.value = false;
keyboardHeight.value = 0;
}
const unregister = () => {
if (typeof (window as any) !== 'undefined') {
window.removeEventListener('ionKeyboardDidShow', showCallback);
window.removeEventListener('ionKeyboardDidHide', hideCallback);
}
}
if (typeof (window as any) !== 'undefined') {
window.addEventListener('ionKeyboardDidShow', showCallback);
window.addEventListener('ionKeyboardDidHide', hideCallback);
}
return {
isOpen,
keyboardHeight,
unregister
}
}

View File

@ -0,0 +1,37 @@
import { LifecycleHooks } from '../utils';
import { ComponentInternalInstance, getCurrentInstance } from 'vue';
/**
* Creates an returns a function that
* can be used to provide a lifecycle hook.
*/
const injectHook = (lifecycleType: LifecycleHooks, hook: Function, component: ComponentInternalInstance | null): Function | undefined => {
if (component) {
// Add to public instance so it is accessible to IonRouterOutlet
const target = component as any;
const hooks = target.proxy[lifecycleType] || (target.proxy[lifecycleType] = []);
const wrappedHook = (...args: unknown[]) => {
if (target.isUnmounted) {
return;
}
return args ? hook(...args) : hook();
};
hooks.push(wrappedHook);
return wrappedHook;
} else {
console.warn('[@ionic/vue]: Ionic Lifecycle Hooks can only be used during execution of setup().');
}
}
const createHook = <T extends Function = () => any>(lifecycle: LifecycleHooks) => {
return (hook: T, target: ComponentInternalInstance | null = getCurrentInstance()) => injectHook(lifecycle, hook, target);
}
export const onIonViewWillEnter = createHook(LifecycleHooks.WillEnter);
export const onIonViewDidEnter = createHook(LifecycleHooks.DidEnter);
export const onIonViewWillLeave = createHook(LifecycleHooks.WillLeave);
export const onIonViewDidLeave = createHook(LifecycleHooks.DidLeave);

View File

@ -0,0 +1,69 @@
import { inject } from 'vue';
import { AnimationBuilder } from '../';
export type RouteAction = 'push' | 'pop' | 'replace';
export type RouteDirection = 'forward' | 'back' | 'root' | 'none';
export interface UseIonRouterResult {
/**
* The location parameter is really of type 'RouteLocationRaw'
* imported from vue-router, but the @ionic/vue package should
* not have a hard dependency on vue-router, so we just use 'any'.
*/
canGoBack: (deep?: number) => boolean;
push: (location: any, routerAnimation?: AnimationBuilder) => void;
replace: (location: any, routerAnimation?: AnimationBuilder) => void;
back: (routerAnimation?: AnimationBuilder) => void;
forward: (routerAnimation?: AnimationBuilder) => void;
navigate: (
location: any,
routerDirection?: RouteDirection,
routerAction?: RouteAction,
routerAnimation?: AnimationBuilder
) => void;
}
/**
* Used to navigate within Vue Router
* while controlling the animation.
*/
export const useIonRouter = (): UseIonRouterResult => {
const { canGoBack, goBack, goForward, handleNavigate } = inject('navManager') as any;
const navigate = (
location: any,
routerDirection?: RouteDirection,
routerAction?: RouteAction,
routerAnimation?: AnimationBuilder
) => handleNavigate(location, routerAction, routerDirection, routerAnimation);
const push = (
location: any,
routerAnimation?: AnimationBuilder
) => navigate(location, 'forward', 'push', routerAnimation);
const replace = (
location: any,
routerAnimation?: AnimationBuilder
) => navigate(location, 'root', 'replace', routerAnimation);
const back = (
routerAnimation?: AnimationBuilder
) => goBack(routerAnimation);
const forward = (
routerAnimation?: AnimationBuilder
) => goForward(routerAnimation);
return {
canGoBack,
push,
replace,
back,
forward,
navigate
} as UseIonRouterResult
}