chore(vue): add eslint and prettier (#26635)

This commit is contained in:
Liam DeBeasi
2023-01-18 18:29:25 -05:00
committed by GitHub
parent 6d4c52aa5b
commit dc27736bd5
25 changed files with 5693 additions and 574 deletions

View File

@ -1,3 +1,11 @@
import type { AnimationBuilder } from "@ionic/core/components";
import {
LIFECYCLE_DID_ENTER,
LIFECYCLE_DID_LEAVE,
LIFECYCLE_WILL_ENTER,
LIFECYCLE_WILL_LEAVE,
} from "@ionic/core/components";
import { defineCustomElement } from "@ionic/core/components/ion-router-outlet.js";
import {
h,
defineComponent,
@ -7,24 +15,25 @@ import {
provide,
watch,
shallowRef,
InjectionKey,
onUnmounted,
Ref
} from 'vue';
import { AnimationBuilder, LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE } from '@ionic/core/components';
import { defineCustomElement } from '@ionic/core/components/ion-router-outlet.js';
import { matchedRouteKey, routeLocationKey, useRoute } from 'vue-router';
import { fireLifecycle, generateId, getConfig } from '../utils';
} from "vue";
import type { InjectionKey, Ref } from "vue";
import { matchedRouteKey, routeLocationKey, useRoute } from "vue-router";
import { fireLifecycle, generateId, getConfig } from "../utils";
// TODO(FW-2969): types
const isViewVisible = (enteringEl: HTMLElement) => {
return !enteringEl.classList.contains('ion-page-hidden') && !enteringEl.classList.contains('ion-page-invisible');
}
return (
!enteringEl.classList.contains("ion-page-hidden") &&
!enteringEl.classList.contains("ion-page-invisible")
);
};
let viewDepthKey: InjectionKey<0> = Symbol(0);
const viewDepthKey: InjectionKey<0> = Symbol(0);
export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
name: 'IonRouterOutlet',
name: "IonRouterOutlet",
setup() {
defineCustomElement();
@ -35,14 +44,14 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
let previousMatchedRouteRef: Ref | undefined;
let previousMatchedPath: string | undefined;
provide(viewDepthKey, depth + 1)
provide(viewDepthKey, depth + 1);
provide(matchedRouteKey, matchedRouteRef);
const ionRouterOutlet = ref();
const id = generateId('ion-router-outlet');
const id = generateId("ion-router-outlet");
const ionRouter: any = inject('navManager');
const viewStacks: any = inject('viewStacks');
const ionRouter: any = inject("navManager");
const viewStacks: any = inject("viewStacks");
const components = shallowRef([]);
@ -57,57 +66,63 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
* So going from /page/1 to /page/2 would not fire this callback if we
* only listened for changes to matchedRouteRef.
*/
watch(() => [route, matchedRouteRef.value], ([currentRoute, currentMatchedRouteRef]) => {
/**
* This callback checks whether or not a router outlet
* needs to respond to a change in the matched route.
* It handles a few cases:
* 1. The matched route is undefined. This means that
* the matched route is not applicable to this outlet.
* For example, a /settings route is not applicable
* to a /tabs/... route.
*
* Note: When going back to a tabs outlet from a non-tabs outlet,
* the tabs outlet should NOT attempt a page transition from the
* previous tab to the active tab. To do this we compare the current
* route with the previous route. Unfortunately, we cannot rely on the
* previous value provided by Vue in the watch callback. This is because
* when coming back to the tabs context, the previous matched route will
* be undefined (because nothing in the tabs context matches /settings)
* but the current matched route will be defined and so a transition
* will always occur.
*
* 2. The matched route is defined and is different than
* the previously matched route. This is the most
* common case such as when you go from /page1 to /page2.
*
* 3. The matched route is the same but the parameters are different.
* This is a special case for parameterized routes (i.e. /page/:id).
* When going from /page/1 to /page/2, the matched route object will
* be the same, but we still need to perform a page transition. To do this
* we check if the parameters are different (i.e. 1 vs 2). To avoid enumerating
* all of the keys in the params object, we check the url path to
* see if they are different after ensuring we are in a parameterized route.
*/
if (currentMatchedRouteRef !== undefined) {
const matchedDifferentRoutes = currentMatchedRouteRef !== previousMatchedRouteRef;
const matchedDifferentParameterRoutes = (
currentRoute.matched[currentRoute.matched.length - 1] === currentMatchedRouteRef &&
currentRoute.path !== previousMatchedPath
);
watch(
() => [route, matchedRouteRef.value],
([currentRoute, currentMatchedRouteRef]) => {
/**
* This callback checks whether or not a router outlet
* needs to respond to a change in the matched route.
* It handles a few cases:
* 1. The matched route is undefined. This means that
* the matched route is not applicable to this outlet.
* For example, a /settings route is not applicable
* to a /tabs/... route.
*
* Note: When going back to a tabs outlet from a non-tabs outlet,
* the tabs outlet should NOT attempt a page transition from the
* previous tab to the active tab. To do this we compare the current
* route with the previous route. Unfortunately, we cannot rely on the
* previous value provided by Vue in the watch callback. This is because
* when coming back to the tabs context, the previous matched route will
* be undefined (because nothing in the tabs context matches /settings)
* but the current matched route will be defined and so a transition
* will always occur.
*
* 2. The matched route is defined and is different than
* the previously matched route. This is the most
* common case such as when you go from /page1 to /page2.
*
* 3. The matched route is the same but the parameters are different.
* This is a special case for parameterized routes (i.e. /page/:id).
* When going from /page/1 to /page/2, the matched route object will
* be the same, but we still need to perform a page transition. To do this
* we check if the parameters are different (i.e. 1 vs 2). To avoid enumerating
* all of the keys in the params object, we check the url path to
* see if they are different after ensuring we are in a parameterized route.
*/
if (currentMatchedRouteRef !== undefined) {
const matchedDifferentRoutes =
currentMatchedRouteRef !== previousMatchedRouteRef;
const matchedDifferentParameterRoutes =
currentRoute.matched[currentRoute.matched.length - 1] ===
currentMatchedRouteRef &&
currentRoute.path !== previousMatchedPath;
if (matchedDifferentRoutes || matchedDifferentParameterRoutes) {
setupViewItem(matchedRouteRef);
if (matchedDifferentRoutes || matchedDifferentParameterRoutes) {
setupViewItem(matchedRouteRef);
}
}
}
previousMatchedRouteRef = currentMatchedRouteRef;
previousMatchedPath = currentRoute.path;
});
previousMatchedRouteRef = currentMatchedRouteRef;
previousMatchedPath = currentRoute.path;
}
);
const canStart = () => {
const config = getConfig();
const swipeEnabled = config && config.get('swipeBackEnabled', ionRouterOutlet.value.mode === 'ios');
const swipeEnabled =
config &&
config.get("swipeBackEnabled", ionRouterOutlet.value.mode === "ios");
if (!swipeEnabled) return false;
const stack = viewStacks.getViewStack(id);
@ -119,14 +134,20 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
* to make sure the view is in the outlet we want.
*/
const routeInfo = ionRouter.getLeavingRouteInfo();
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id);
const enteringViewItem = viewStacks.findViewItemByRouteInfo(
{ pathname: routeInfo.pushedByRoute || "" },
id
);
return !!enteringViewItem;
}
};
const onStart = async () => {
const routeInfo = ionRouter.getLeavingRouteInfo();
const { routerAnimation } = routeInfo;
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id);
const enteringViewItem = viewStacks.findViewItemByRouteInfo(
{ pathname: routeInfo.pushedByRoute || "" },
id
);
const leavingViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id);
if (leavingViewItem) {
@ -135,17 +156,14 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
const leavingEl = leavingViewItem.ionPageElement;
/**
* If we are going back from a page that
* was presented using a custom animation
* we should default to using that
* unless the developer explicitly
* provided another animation.
*/
* If we are going back from a page that
* was presented using a custom animation
* we should default to using that
* unless the developer explicitly
* provided another animation.
*/
const customAnimation = enteringViewItem.routerAnimation;
if (
animationBuilder === undefined &&
customAnimation !== undefined
) {
if (animationBuilder === undefined && customAnimation !== undefined) {
animationBuilder = customAnimation;
}
@ -154,7 +172,7 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
await transition(
enteringEl,
leavingEl,
'back',
"back",
ionRouter.canGoBack(2),
true,
animationBuilder
@ -162,7 +180,7 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
}
return Promise.resolve();
}
};
const onEnd = (shouldContinue: boolean) => {
if (shouldContinue) {
@ -181,18 +199,21 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
* re-hide the page that was going to enter.
*/
const routeInfo = ionRouter.getCurrentRouteInfo();
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id);
enteringViewItem.ionPageElement.setAttribute('aria-hidden', 'true');
enteringViewItem.ionPageElement.classList.add('ion-page-hidden');
const enteringViewItem = viewStacks.findViewItemByRouteInfo(
{ pathname: routeInfo.pushedByRoute || "" },
id
);
enteringViewItem.ionPageElement.setAttribute("aria-hidden", "true");
enteringViewItem.ionPageElement.classList.add("ion-page-hidden");
}
}
};
watch(ionRouterOutlet, () => {
ionRouterOutlet.value.swipeHandler = {
canStart,
onStart,
onEnd
}
onEnd,
};
});
const transition = (
@ -203,7 +224,7 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
progressAnimation: boolean,
animationBuilder?: AnimationBuilder
) => {
return new Promise(resolve => {
return new Promise((resolve) => {
if (skipTransition) {
skipTransition = false;
return resolve(false);
@ -215,38 +236,60 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
requestAnimationFrame(() => {
requestAnimationFrame(async () => {
enteringEl.classList.add('ion-page-invisible');
enteringEl.classList.add("ion-page-invisible");
const hasRootDirection = direction === undefined || direction === 'root' || direction === 'none';
const result = await ionRouterOutlet.value.commit(enteringEl, leavingEl, {
deepWait: true,
/**
* replace operations result in a direction of none.
* These typically do not have need animations, so we set
* the duration to 0. However, if a developer explicitly
* passes an animationBuilder, we should assume that
* they want an animation to be played even
* though it is a replace operation.
*/
duration: hasRootDirection && animationBuilder === undefined ? 0 : undefined,
direction,
showGoBack,
progressAnimation,
animationBuilder
});
const hasRootDirection =
direction === undefined ||
direction === "root" ||
direction === "none";
const result = await ionRouterOutlet.value.commit(
enteringEl,
leavingEl,
{
deepWait: true,
/**
* replace operations result in a direction of none.
* These typically do not have need animations, so we set
* the duration to 0. However, if a developer explicitly
* passes an animationBuilder, we should assume that
* they want an animation to be played even
* though it is a replace operation.
*/
duration:
hasRootDirection && animationBuilder === undefined
? 0
: undefined,
direction,
showGoBack,
progressAnimation,
animationBuilder,
}
);
return resolve(result);
});
});
});
}
};
const handlePageTransition = async () => {
const routeInfo = ionRouter.getCurrentRouteInfo();
const { routerDirection, routerAction, routerAnimation, prevRouteLastPathname, delta } = routeInfo;
const {
routerDirection,
routerAction,
routerAnimation,
prevRouteLastPathname,
delta,
} = routeInfo;
const enteringViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id);
let leavingViewItem = viewStacks.findLeavingViewItemByRouteInfo(routeInfo, id);
const enteringViewItem = viewStacks.findViewItemByRouteInfo(
routeInfo,
id
);
let leavingViewItem = viewStacks.findLeavingViewItemByRouteInfo(
routeInfo,
id
);
const enteringEl = enteringViewItem.ionPageElement;
/**
@ -262,7 +305,10 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information.
if (enteringViewItem === leavingViewItem) return;
if (!leavingViewItem && prevRouteLastPathname) {
leavingViewItem = viewStacks.findViewItemByPathname(prevRouteLastPathname, id);
leavingViewItem = viewStacks.findViewItemByPathname(
prevRouteLastPathname,
id
);
}
/**
@ -284,29 +330,44 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information.
* return early for swipe to go back when
* going from a non-tabs page to a tabs page.
*/
if (isViewVisible(enteringEl) && leavingViewItem?.ionPageElement !== undefined && !isViewVisible(leavingViewItem.ionPageElement)) {
if (
isViewVisible(enteringEl) &&
leavingViewItem?.ionPageElement !== undefined &&
!isViewVisible(leavingViewItem.ionPageElement)
) {
return;
}
fireLifecycle(enteringViewItem.vueComponent, enteringViewItem.vueComponentRef, LIFECYCLE_WILL_ENTER);
fireLifecycle(
enteringViewItem.vueComponent,
enteringViewItem.vueComponentRef,
LIFECYCLE_WILL_ENTER
);
if (leavingViewItem?.ionPageElement && enteringViewItem !== leavingViewItem) {
if (
leavingViewItem?.ionPageElement &&
enteringViewItem !== leavingViewItem
) {
let animationBuilder = routerAnimation;
const leavingEl = leavingViewItem.ionPageElement;
fireLifecycle(leavingViewItem.vueComponent, leavingViewItem.vueComponentRef, LIFECYCLE_WILL_LEAVE);
fireLifecycle(
leavingViewItem.vueComponent,
leavingViewItem.vueComponentRef,
LIFECYCLE_WILL_LEAVE
);
/**
* If we are going back from a page that
* was presented using a custom animation
* we should default to using that
* unless the developer explicitly
* provided another animation.
*/
* If we are going back from a page that
* was presented using a custom animation
* we should default to using that
* unless the developer explicitly
* provided another animation.
*/
const customAnimation = enteringViewItem.routerAnimation;
if (
animationBuilder === undefined &&
routerDirection === 'back' &&
routerDirection === "back" &&
customAnimation !== undefined
) {
animationBuilder = customAnimation;
@ -323,17 +384,22 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information.
animationBuilder
);
leavingEl.classList.add('ion-page-hidden');
leavingEl.setAttribute('aria-hidden', 'true');
leavingEl.classList.add("ion-page-hidden");
leavingEl.setAttribute("aria-hidden", "true");
const usingLinearNavigation = viewStacks.size() === 1;
if (routerAction === 'replace') {
if (routerAction === "replace") {
leavingViewItem.mount = false;
leavingViewItem.ionPageElement = undefined;
leavingViewItem.ionRoute = false;
} else if (!(routerAction === 'push' && routerDirection === 'forward')) {
const shouldLeavingViewBeRemoved = routerDirection !== 'none' && leavingViewItem && (enteringViewItem !== leavingViewItem);
} else if (
!(routerAction === "push" && routerDirection === "forward")
) {
const shouldLeavingViewBeRemoved =
routerDirection !== "none" &&
leavingViewItem &&
enteringViewItem !== leavingViewItem;
if (shouldLeavingViewBeRemoved) {
leavingViewItem.mount = false;
leavingViewItem.ionPageElement = undefined;
@ -353,7 +419,11 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information.
viewStacks.mountIntermediaryViews(id, leavingViewItem, delta);
}
fireLifecycle(leavingViewItem.vueComponent, leavingViewItem.vueComponentRef, LIFECYCLE_DID_LEAVE);
fireLifecycle(
leavingViewItem.vueComponent,
leavingViewItem.vueComponentRef,
LIFECYCLE_DID_LEAVE
);
} else {
/**
* If there is no leaving element, just show
@ -361,13 +431,19 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information.
* in case ion-content's fullscreen callback
* is running. Otherwise we'd have a flicker.
*/
requestAnimationFrame(() => enteringEl.classList.remove('ion-page-invisible'));
requestAnimationFrame(() =>
enteringEl.classList.remove("ion-page-invisible")
);
}
fireLifecycle(enteringViewItem.vueComponent, enteringViewItem.vueComponentRef, LIFECYCLE_DID_ENTER);
fireLifecycle(
enteringViewItem.vueComponent,
enteringViewItem.vueComponentRef,
LIFECYCLE_DID_ENTER
);
components.value = viewStacks.getChildrenToRender(id);
}
};
const setupViewItem = (matchedRouteRef: any) => {
const firstMatchedRoute = route.matched[0];
@ -387,16 +463,25 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information.
*/
if (
!matchedRouteRef.value ||
(matchedRouteRef.value !== firstMatchedRoute && firstMatchedRoute.path !== parentOutletPath)
(matchedRouteRef.value !== firstMatchedRoute &&
firstMatchedRoute.path !== parentOutletPath)
) {
return;
return;
}
const currentRoute = ionRouter.getCurrentRouteInfo();
let enteringViewItem = viewStacks.findViewItemByRouteInfo(currentRoute, id);
let enteringViewItem = viewStacks.findViewItemByRouteInfo(
currentRoute,
id
);
if (!enteringViewItem) {
enteringViewItem = viewStacks.createViewItem(id, matchedRouteRef.value.components.default, matchedRouteRef.value, currentRoute);
enteringViewItem = viewStacks.createViewItem(
id,
matchedRouteRef.value.components.default,
matchedRouteRef.value,
currentRoute
);
viewStacks.add(enteringViewItem);
}
@ -405,13 +490,13 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information.
enteringViewItem.registerCallback = () => {
handlePageTransition();
enteringViewItem.registerCallback = undefined;
}
};
} else {
handlePageTransition();
}
components.value = viewStacks.getChildrenToRender(id);
}
};
if (matchedRouteRef.value) {
setupViewItem(matchedRouteRef);
@ -439,88 +524,90 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information.
* Page should be hidden initially
* to avoid flickering.
*/
ionPageEl.classList.add('ion-page-invisible');
ionPageEl.classList.add("ion-page-invisible");
viewItem.registerCallback();
/**
* If there is no registerCallback, then
* this component is likely being re-registered
* as a result of a hot module replacement.
* We need to see if the oldIonPageEl has
* .ion-page-invisible. If it does not then we
* need to remove it from the new ionPageEl otherwise
* the page will be hidden when it is replaced.
*/
} else if (oldIonPageEl && !oldIonPageEl.classList.contains('ion-page-invisible')) {
ionPageEl.classList.remove('ion-page-invisible');
/**
* If there is no registerCallback, then
* this component is likely being re-registered
* as a result of a hot module replacement.
* We need to see if the oldIonPageEl has
* .ion-page-invisible. If it does not then we
* need to remove it from the new ionPageEl otherwise
* the page will be hidden when it is replaced.
*/
} else if (
oldIonPageEl &&
!oldIonPageEl.classList.contains("ion-page-invisible")
) {
ionPageEl.classList.remove("ion-page-invisible");
}
};
};
return {
id,
components,
injectedRoute,
ionRouterOutlet,
registerIonPage
}
registerIonPage,
};
},
render() {
const { components, registerIonPage, injectedRoute } = this;
return h(
'ion-router-outlet',
{ ref: 'ionRouterOutlet' },
components && components.map((c: any) => {
let props = {
ref: c.vueComponentRef,
key: c.pathname,
registerIonPage: (ionPageEl: HTMLElement) => registerIonPage(c, ionPageEl)
}
"ion-router-outlet",
{ ref: "ionRouterOutlet" },
components &&
components.map((c: any) => {
let props = {
ref: c.vueComponentRef,
key: c.pathname,
registerIonPage: (ionPageEl: HTMLElement) =>
registerIonPage(c, ionPageEl),
};
/**
* IonRouterOutlet does not support named outlets.
*/
const routePropsOption = c.matchedRoute?.props?.default;
/**
* IonRouterOutlet does not support named outlets.
*/
const routePropsOption = c.matchedRoute?.props?.default;
/**
* Since IonRouterOutlet renders multiple components,
* each render will cause all props functions to be
* called again. As a result, we need to cache the function
* result and provide it on each render so that the props
* are not lost when navigating from and back to a page.
* When a component is destroyed and re-created, the
* function is called again.
*/
const getPropsFunctionResult = () => {
const cachedPropsResult = c.vueComponentData?.propsFunctionResult;
if (cachedPropsResult) {
return cachedPropsResult;
} else {
const propsFunctionResult = routePropsOption(injectedRoute);
c.vueComponentData = {
...c.vueComponentData,
propsFunctionResult
};
return propsFunctionResult;
}
}
const routeProps = routePropsOption
? routePropsOption === true
? c.params
: typeof routePropsOption === 'function'
? getPropsFunctionResult()
: routePropsOption
: null
/**
* Since IonRouterOutlet renders multiple components,
* each render will cause all props functions to be
* called again. As a result, we need to cache the function
* result and provide it on each render so that the props
* are not lost when navigating from and back to a page.
* When a component is destroyed and re-created, the
* function is called again.
*/
const getPropsFunctionResult = () => {
const cachedPropsResult = c.vueComponentData?.propsFunctionResult;
if (cachedPropsResult) {
return cachedPropsResult;
} else {
const propsFunctionResult = routePropsOption(injectedRoute);
c.vueComponentData = {
...c.vueComponentData,
propsFunctionResult,
};
return propsFunctionResult;
}
};
const routeProps = routePropsOption
? routePropsOption === true
? c.params
: typeof routePropsOption === "function"
? getPropsFunctionResult()
: routePropsOption
: null;
props = {
...props,
...routeProps
}
props = {
...props,
...routeProps,
};
return h(
c.vueComponent,
props
);
})
)
}
return h(c.vueComponent, props);
})
);
},
});