StackedRouter: inject inline insets, fix #48
All checks were successful
/ depoly (push) Successful in 1m19s
All checks were successful
/ depoly (push) Successful in 1m19s
This commit is contained in:
parent
5ecba144f0
commit
6726ffe664
1 changed files with 73 additions and 0 deletions
|
@ -2,6 +2,7 @@ import { StaticRouter, type RouterProps } from "@solidjs/router";
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
createContext,
|
createContext,
|
||||||
|
createMemo,
|
||||||
createRenderEffect,
|
createRenderEffect,
|
||||||
createUniqueId,
|
createUniqueId,
|
||||||
Index,
|
Index,
|
||||||
|
@ -16,6 +17,7 @@ import "./StackedRouter.css";
|
||||||
import { animateSlideInFromRight, animateSlideOutToRight } from "./anim";
|
import { animateSlideInFromRight, animateSlideOutToRight } from "./anim";
|
||||||
import { ANIM_CURVE_DECELERATION, ANIM_CURVE_STD } from "../material/theme";
|
import { ANIM_CURVE_DECELERATION, ANIM_CURVE_STD } from "../material/theme";
|
||||||
import { makeEventListener } from "@solid-primitives/event-listener";
|
import { makeEventListener } from "@solid-primitives/event-listener";
|
||||||
|
import { useWindowSize } from "@solid-primitives/resize-observer";
|
||||||
|
|
||||||
export type StackedRouterProps = Omit<RouterProps, "url">;
|
export type StackedRouterProps = Omit<RouterProps, "url">;
|
||||||
|
|
||||||
|
@ -203,9 +205,46 @@ function serializableStack(stack: readonly StackFrame[]) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The router that stacks the pages.
|
* The router that stacks the pages.
|
||||||
|
*
|
||||||
|
* **Routes** The router accepts the {@link RouteProps} excluding the "url" field.
|
||||||
|
* You can seamlessly use the `<Route />` from `@solidjs/router`.
|
||||||
|
*
|
||||||
|
* Be advised that this component is not a drop-in replacement of that router.
|
||||||
|
* These primitives from `@solidjs/router` won't work correctly:
|
||||||
|
*
|
||||||
|
* - `<A />` component - use ~platform/A instead
|
||||||
|
* - `useLocation()` - see {@link useCurrentFrame}
|
||||||
|
* - `useNavigate()` - see {@link useNavigator}
|
||||||
|
*
|
||||||
|
* The other primitives may work, as long as they don't rely on the global location.
|
||||||
|
* This component uses `@solidjs/router` {@link StaticRouter} to route.
|
||||||
|
*
|
||||||
|
* **Injecting Safe Area Insets** The router calculate correct
|
||||||
|
* `--safe-area-inset-left` and `--safe-area-inset-right` from the window
|
||||||
|
* width and `--safe-area-inset-*` from the :root element. That means
|
||||||
|
* the injected insets do not reflects the overrides that are not on the :root.
|
||||||
|
*
|
||||||
|
* The recalculation is only performed when the window size changed.
|
||||||
|
*
|
||||||
|
* **Navigation Animation** The router provides default animation for
|
||||||
|
* navigation.
|
||||||
|
*
|
||||||
|
* If the default animation does not met your requirement,
|
||||||
|
* this component is also intergated with Web Animation API.
|
||||||
|
* You can provide {@link NewFrameOptions.animateOpen} and
|
||||||
|
* {@link NewFrameOptions.animateClose} to define custom animation.
|
||||||
|
*
|
||||||
|
* **Swipe to back** For the subpages (the pages stacked on the entry),
|
||||||
|
* swipe to back gesture is provided for user experience.
|
||||||
|
*
|
||||||
|
* Navigation animations (even the custom ones) will be played during
|
||||||
|
* swipe to back, please keep in mind when designing animations.
|
||||||
|
*
|
||||||
|
* The iOS default gesture is blocked on those pages.
|
||||||
*/
|
*/
|
||||||
const StackedRouter: Component<StackedRouterProps> = (oprops) => {
|
const StackedRouter: Component<StackedRouterProps> = (oprops) => {
|
||||||
const [stack, mutStack] = createStore([] as StackFrame[], { name: "stack" });
|
const [stack, mutStack] = createStore([] as StackFrame[], { name: "stack" });
|
||||||
|
const windowSize = useWindowSize();
|
||||||
|
|
||||||
const pushFrame = (path: string, opts?: Readonly<NewFrameOptions<any>>) =>
|
const pushFrame = (path: string, opts?: Readonly<NewFrameOptions<any>>) =>
|
||||||
untrack(() => {
|
untrack(() => {
|
||||||
|
@ -293,6 +332,39 @@ const StackedRouter: Component<StackedRouterProps> = (oprops) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const subInsets = createMemo(() => {
|
||||||
|
const SUBPAGE_MAX_WIDTH = 560;
|
||||||
|
const { width } = windowSize;
|
||||||
|
if (width <= SUBPAGE_MAX_WIDTH) {
|
||||||
|
// page width = 100vw, use the inset directly
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const computedStyle = window.getComputedStyle(
|
||||||
|
document.querySelector(":root")!,
|
||||||
|
);
|
||||||
|
const oinsetLeft = computedStyle
|
||||||
|
.getPropertyValue("--safe-area-inset-left")
|
||||||
|
.split("px", 1)[0];
|
||||||
|
const oinsetRight = computedStyle
|
||||||
|
.getPropertyValue("--safe-area-inset-right")
|
||||||
|
.split("px", 1)[0];
|
||||||
|
console.debug("insets-inline", oinsetLeft, oinsetRight);
|
||||||
|
const left = Number(oinsetLeft),
|
||||||
|
right = Number(oinsetRight.slice(0, oinsetRight.length - 2));
|
||||||
|
const totalWidth = SUBPAGE_MAX_WIDTH + left + right;
|
||||||
|
if (width >= totalWidth) {
|
||||||
|
return {
|
||||||
|
"--safe-area-inset-left": "0px",
|
||||||
|
"--safe-area-inset-right": "0px",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const ofs = (totalWidth - width) / 2;
|
||||||
|
return {
|
||||||
|
"--safe-area-inset-left": `${Math.max(left - ofs, 0)}px`,
|
||||||
|
"--safe-area-inset-right": `${Math.max(right - ofs, 0)}px`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
let reenterableAnimation: Animation | undefined;
|
let reenterableAnimation: Animation | undefined;
|
||||||
let origWidth = 0,
|
let origWidth = 0,
|
||||||
origFigX = 0,
|
origFigX = 0,
|
||||||
|
@ -435,6 +507,7 @@ const StackedRouter: Component<StackedRouterProps> = (oprops) => {
|
||||||
on:touchend={onDialogTouchEnd}
|
on:touchend={onDialogTouchEnd}
|
||||||
on:touchcancel={onDialogTouchCancel}
|
on:touchcancel={onDialogTouchCancel}
|
||||||
id={frame().rootId}
|
id={frame().rootId}
|
||||||
|
style={subInsets()}
|
||||||
>
|
>
|
||||||
<StaticRouter url={frame().path} {...oprops} />
|
<StaticRouter url={frame().path} {...oprops} />
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
Loading…
Reference in a new issue