New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@pinnacle0/react-stack-router

Package Overview
Dependencies
Maintainers
5
Versions
63
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@pinnacle0/react-stack-router - npm Package Compare versions

Comparing version 0.1.3-beta.4 to 0.1.3-beta.5

4

lib/component/Stack/index.d.ts

@@ -0,1 +1,2 @@

import type { CSSProperties } from "react";
import type { StackRouter } from "../../stackRouter";

@@ -5,5 +6,6 @@ interface StackProps {

className?: string;
style?: CSSProperties;
}
export declare function Stack({ router, className }: StackProps): import("react/jsx-runtime").JSX.Element;
export declare function Stack({ router, className, style }: StackProps): import("react/jsx-runtime").JSX.Element;
export {};
//# sourceMappingURL=index.d.ts.map

@@ -22,8 +22,8 @@ import { jsx as _jsx } from "react/jsx-runtime";

};
export function Stack({ router, className }) {
export function Stack({ router, className, style }) {
const [screens, setScreens] = useState([]);
useEffect(() => router.subscribe(_ => setScreens([..._])), [router]);
useEffect(() => router.attachSafariEdgeSwipeDetector(), [router]);
return (_jsx("div", { className: classNames("g-stack-router", className), style: routerStyle, children: _jsx(AnimatePresence, { children: screens.map(screen => (_jsx(ScreenComponent, { className: "g-stack-router-screen", style: screenStyle, screen: screen }, screen.history.location.key))) }) }));
return (_jsx("div", { className: classNames("g-stack-router", className), style: { ...style, ...routerStyle }, children: _jsx(AnimatePresence, { children: screens.map(screen => (_jsx(ScreenComponent, { className: "g-stack-router-screen", style: screenStyle, screen: screen }, screen.history.location.key))) }) }));
}
//# sourceMappingURL=index.js.map
import { jsx as _jsx } from "react/jsx-runtime";
import React, { useEffect, useMemo } from "react";
import React, { useEffect, useMemo, useState } from "react";
import { createBrowserHistory } from "history";

@@ -10,3 +10,3 @@ import { invariant } from "./invariant";

import { StackRouter } from "./stackRouter";
const createChildrenRoute = (children, parentPaths = [], route = new Route()) => {
const createChildrenRoute = (children, parentPattern, route = new Route()) => {
React.Children.forEach(children, element => {

@@ -16,9 +16,15 @@ invariant(React.isValidElement(element), `${element} is not valid element`);

const props = element.props;
const paths = [...parentPaths];
paths.push(props.path);
const patterns = [];
let parent = parentPattern;
while (parent) {
patterns.unshift(parent.pattern);
parent = parent.parent;
}
const pattern = { pattern: props.path, parent: parentPattern, hasComponent: false };
if ("component" in props) {
route.insert(paths.join("/"), { component: props.component, singlePageOnload: props.singlePageOnload ?? false });
pattern.hasComponent = true;
route.insert([...patterns, props.path].join("/"), { pattern, component: props.component });
}
if (props.children) {
createChildrenRoute(props.children, paths, route);
createChildrenRoute(props.children, pattern, route);
}

@@ -36,8 +42,11 @@ });

const Root = ({ children }) => {
const route = useMemo(() => createChildrenRoute(children), [children]);
const route = useMemo(() => createChildrenRoute(children, null), [children]);
const [initialized, setInitialized] = useState(false);
const historyRef = React.useRef(internalHistory);
historyRef.current = internalHistory;
router.updateRoute(route);
useEffect(() => router.initialize(), []);
return (_jsx(RouterContext.Provider, { value: { history: historyRef.current, push, pop, replace, reset }, children: _jsx(Stack, { router: router }) }));
useEffect(() => {
router.initialize().then(() => setInitialized(true));
}, []);
return (_jsx(RouterContext.Provider, { value: { history: historyRef.current, push, pop, replace, reset }, children: _jsx(Stack, { router: router, style: { visibility: initialized ? "visible" : "hidden" } }) }));
};

@@ -44,0 +53,0 @@ return {

@@ -11,6 +11,2 @@ export interface RouteNode<T> {

}
export interface Parent<T> {
payload: T | null;
matchedSegment: string;
}
export interface Match<T> {

@@ -21,3 +17,4 @@ params: {

payload: T;
parents: Parent<T>[];
matchedSegments: string[];
fallback: boolean;
}

@@ -37,3 +34,4 @@ /**

}
export declare function pathToSegments(path: string): string[];
export declare function formatPath(path: string): string;
//# sourceMappingURL=index.d.ts.map

@@ -11,4 +11,3 @@ import { invariant } from "../invariant";

this.cache.clear();
const formattedPath = formatPath(path);
const segments = formattedPath === "/" ? ["/"] : formattedPath.split("/");
const segments = pathToSegments(path);
let currentNode = this.root;

@@ -40,7 +39,6 @@ for (const segment of segments) {

freshLookup(path) {
const formattedPath = formatPath(path);
const segments = formattedPath === "/" ? ["/"] : formattedPath.split("/");
const segments = pathToSegments(path);
let params = {};
let nextNode = this.root;
const parents = [];
const matchedSegments = [];
for (const segment of segments) {

@@ -70,3 +68,3 @@ const childNode = nextNode.children.get(segment);

}
parents.push({ payload: nextNode.payload, matchedSegment: segment });
matchedSegments.push(segment);
}

@@ -84,6 +82,6 @@ // if matched node do not have payload, lookup parent wildcard

// removed matched node itself
parents.pop();
return this.createMatch(nextNode.payload, params, parents);
matchedSegments.pop();
return this.createMatch(nextNode.payload, params, matchedSegments);
}
createMatch(payload, params, parents) {
createMatch(payload, params, matchedSegments, fallback = false) {
return payload

@@ -93,3 +91,4 @@ ? {

params,
parents,
matchedSegments,
fallback,
}

@@ -99,3 +98,3 @@ : null;

matchFallbackRoute() {
return this.createMatch(this.root.fallbackNode?.payload ?? null, {}, []);
return this.createMatch(this.root.fallbackNode?.payload ?? null, {}, [], true);
}

@@ -127,2 +126,11 @@ createNode(segment, currentNode) {

}
export function pathToSegments(path) {
const formattedPath = formatPath(path);
if (formattedPath === "/") {
return ["/"];
}
else {
return formattedPath.split("/");
}
}
export function formatPath(path) {

@@ -129,0 +137,0 @@ let formatted = path.replaceAll(/[/]+/g, "/");

@@ -7,5 +7,10 @@ import { Route } from "../route";

export type Subscriber = (screens: Screen[]) => void;
export type StackRoutePattern = {
pattern: string;
parent: StackRoutePattern | null;
hasComponent: boolean;
};
export type StackRoutePayload = {
component: React.ComponentType<any>;
singlePageOnload: boolean;
pattern: StackRoutePattern;
};

@@ -22,3 +27,3 @@ export declare class StackRouter {

constructor(history: History);
initialize(): void;
initialize(): Promise<void[] | undefined>;
updateRoute(route: Route<StackRoutePayload>): void;

@@ -25,0 +30,0 @@ attachSafariEdgeSwipeDetector(): () => void;

import { Action } from "history";
import { Route } from "../route";
import { Route, formatPath } from "../route";
import { Screen } from "../screen";

@@ -14,4 +14,4 @@ import { invariant } from "../invariant";

safariEdgeSwipeDetector = createSafariEdgeSwipeDetector();
pushOption = new BurnAfterRead();
resolve = new BurnAfterRead();
pushOption = new Snapshot();
resolve = new Snapshot();
constructor(history) {

@@ -21,21 +21,28 @@ this.stackHistory = createStackHistory(history);

}
initialize() {
async initialize() {
if (this.initialized)
return;
this.initialized = true;
const { hash, search, pathname } = window.location;
const { pathname, hash, search } = window.location;
const matched = this.matchRoute(pathname);
if (matched.payload.singlePageOnload) {
this.replace({ pathname, search, hash }, { transition: "none" });
return;
let numOfParentComponent = 0;
let parentPattern = matched.payload.pattern.parent;
while (parentPattern) {
if (parentPattern.hasComponent) {
numOfParentComponent++;
}
parentPattern = parentPattern.parent;
}
const stackPaths = matched.parents.reduce((paths, curr) => {
if (curr.payload) {
return [...paths, (paths[paths.length - 1] ?? "") + "/" + curr.matchedSegment];
const stack = [{ pathname, hash, search }];
const segments = ["/", ...matched.matchedSegments];
while (numOfParentComponent !== 0 && segments.length !== 0) {
const pathname = formatPath(segments.join("/"));
const matched = this.route.lookup(pathname);
if (!matched?.fallback) {
stack.unshift(pathname);
numOfParentComponent--;
}
return paths;
}, []);
stackPaths.push({ hash, search, pathname });
this.replace("/");
stackPaths.forEach(to => this.push(to, { transition: "exiting" }));
segments.pop();
}
return Promise.all(stack.map((to, index) => (index === 0 ? this.replace(to) : this.push(to, { transition: "exiting" }))));
}

@@ -57,4 +64,4 @@ updateRoute(route) {

return;
const wait = new Promise(resolve => this.resolve.set(resolve));
this.pushOption.set(option ?? null);
const wait = new Promise(resolve => (this.resolve.value = resolve));
this.pushOption.value = option ?? null;
this.stackHistory.push(to, option?.state);

@@ -64,3 +71,3 @@ return wait;

async pop() {
const wait = new Promise(resolve => this.resolve.set(resolve));
const wait = new Promise(resolve => (this.resolve.value = resolve));
this.stackHistory.pop();

@@ -72,3 +79,3 @@ return wait;

return;
const wait = new Promise(resolve => this.resolve.set(resolve));
const wait = new Promise(resolve => (this.resolve.value = resolve));
this.stackHistory.replace(to, state);

@@ -108,4 +115,4 @@ return wait;

pushScreen(location, transition) {
const option = this.pushOption.get();
const resolve = this.resolve.get();
const option = this.pushOption.value;
const resolve = this.resolve.value;
const screen = this.createScreen(location, option?.transition ?? transition);

@@ -121,3 +128,3 @@ if (!screen) {

popScreen(transition) {
const resolve = this.resolve.get();
const resolve = this.resolve.value;
const top = this.getTopScreen();

@@ -130,3 +137,3 @@ top?.transition.update(transition);

replaceScreen(location) {
const resolve = this.resolve.get();
const resolve = this.resolve.value;
const top = this.getTopScreen();

@@ -158,16 +165,17 @@ top?.transition.update("none");

}
class BurnAfterRead {
value;
constructor(value = null) {
this.value = value;
// Turn value to null after read
class Snapshot {
_value;
constructor(_value = null) {
this._value = _value;
}
set(newValue) {
this.value = newValue;
}
get() {
const current = this.value;
this.value = null;
get value() {
const current = this._value;
this._value = null;
return current;
}
set value(newValue) {
this._value = newValue;
}
}
//# sourceMappingURL=index.js.map
/**
* Aim at detect popstate event tirggered by Safari edge swipe gesture
* for left edge swipe (back): clientX of touchend event is always be a native value
* Aim at detect popstate event triggered by Safari edge swipe gesture
* for left edge swipe (back): clientX of touchend event is always be a negative value
* for right edge swipe (forward): popstate event fired with only touchstart triggered

@@ -5,0 +5,0 @@ * therefore, if there are any popstate event fired within 300ms after above scenarios, it recognized as a native swipe back pop event

/**
* Aim at detect popstate event tirggered by Safari edge swipe gesture
* for left edge swipe (back): clientX of touchend event is always be a native value
* Aim at detect popstate event triggered by Safari edge swipe gesture
* for left edge swipe (back): clientX of touchend event is always be a negative value
* for right edge swipe (forward): popstate event fired with only touchstart triggered

@@ -8,7 +8,7 @@ * therefore, if there are any popstate event fired within 300ms after above scenarios, it recognized as a native swipe back pop event

export function createSafariEdgeSwipeDetector() {
let isForwordSwipe = false;
let isForwardSwipe = false;
const isBackwardSwipe = new TimeoutFalseValue(200);
return {
get isForwardPop() {
return isForwordSwipe;
return isForwardSwipe;
},

@@ -21,6 +21,6 @@ get isBackwardPop() {

if (Array.from(event.changedTouches).some(touch => window.innerWidth - touch.clientX < 20))
isForwordSwipe = true;
isForwardSwipe = true;
};
const end = (event) => {
isForwordSwipe = false;
isForwardSwipe = false;
if (Array.from(event.changedTouches).some(touch => touch.clientX < 0))

@@ -30,3 +30,3 @@ isBackwardSwipe.value = true;

const cancel = () => {
isForwordSwipe = false;
isForwardSwipe = false;
isBackwardSwipe.value = false;

@@ -60,3 +60,3 @@ };

this.bool = true;
setTimeout(() => (this.bool = false), this.timeout);
window.setTimeout(() => (this.bool = false), this.timeout);
}

@@ -63,0 +63,0 @@ else {

{
"name": "@pinnacle0/react-stack-router",
"version": "0.1.3-beta.4",
"version": "0.1.3-beta.5",
"author": "Pinnacle",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -15,11 +15,7 @@ import {invariant} from "../invariant";

export interface Parent<T> {
payload: T | null;
matchedSegment: string;
}
export interface Match<T> {
params: {[key: string]: string};
payload: T;
parents: Parent<T>[];
matchedSegments: string[];
fallback: boolean;
}

@@ -36,4 +32,3 @@

this.cache.clear();
const formattedPath = formatPath(path);
const segments = formattedPath === "/" ? ["/"] : formattedPath.split("/");
const segments = pathToSegments(path);

@@ -67,8 +62,6 @@ let currentNode: RouteNode<T> = this.root;

private freshLookup(path: string): Match<T> | null {
const formattedPath = formatPath(path);
const segments = formattedPath === "/" ? ["/"] : formattedPath.split("/");
const segments = pathToSegments(path);
let params: Record<string, string> = {};
let nextNode: RouteNode<T> = this.root;
const parents: Parent<T>[] = [];
const matchedSegments: string[] = [];

@@ -97,3 +90,3 @@ for (const segment of segments) {

}
parents.push({payload: nextNode.payload, matchedSegment: segment});
matchedSegments.push(segment);
}

@@ -114,8 +107,8 @@

// removed matched node itself
parents.pop();
matchedSegments.pop();
return this.createMatch(nextNode.payload, params, parents);
return this.createMatch(nextNode.payload, params, matchedSegments);
}
private createMatch(payload: T | null, params: Record<string, string>, parents: Parent<T>[]): Match<T> | null {
private createMatch(payload: T | null, params: Record<string, string>, matchedSegments: string[], fallback = false): Match<T> | null {
return payload

@@ -125,3 +118,4 @@ ? {

params,
parents,
matchedSegments,
fallback,
}

@@ -132,3 +126,3 @@ : null;

private matchFallbackRoute(): Match<T> | null {
return this.createMatch(this.root.fallbackNode?.payload ?? null, {}, []);
return this.createMatch(this.root.fallbackNode?.payload ?? null, {}, [], true);
}

@@ -163,2 +157,12 @@

export function pathToSegments(path: string): string[] {
const formattedPath = formatPath(path);
if (formattedPath === "/") {
return ["/"];
} else {
return formattedPath.split("/");
}
}
export function formatPath(path: string): string {

@@ -165,0 +169,0 @@ let formatted = path.replaceAll(/[/]+/g, "/");

import {Action} from "history";
import type {Match} from "../route";
import {Route} from "../route";
import {Route, formatPath} from "../route";
import {Screen} from "../screen";

@@ -16,5 +16,11 @@ import {invariant} from "../invariant";

export type StackRoutePattern = {
pattern: string;
parent: StackRoutePattern | null;
hasComponent: boolean;
};
export type StackRoutePayload = {
component: React.ComponentType<any>;
singlePageOnload: boolean;
pattern: StackRoutePattern;
};

@@ -30,4 +36,4 @@

private pushOption = new BurnAfterRead<PushOption>();
private resolve = new BurnAfterRead<() => void>();
private pushOption = new Snapshot<PushOption>();
private resolve = new Snapshot<() => void>();

@@ -39,24 +45,32 @@ constructor(history: History) {

initialize() {
async initialize() {
if (this.initialized) return;
this.initialized = true;
const {hash, search, pathname} = window.location;
const {pathname, hash, search} = window.location;
const matched = this.matchRoute(pathname);
if (matched.payload.singlePageOnload) {
this.replace({pathname, search, hash}, {transition: "none"});
return;
let numOfParentComponent = 0;
let parentPattern: StackRoutePattern | null = matched.payload.pattern.parent;
while (parentPattern) {
if (parentPattern.hasComponent) {
numOfParentComponent++;
}
parentPattern = parentPattern.parent;
}
const stackPaths = matched.parents.reduce((paths, curr) => {
if (curr.payload) {
return [...paths, (paths[paths.length - 1] ?? "") + "/" + curr.matchedSegment];
const stack: To[] = [{pathname, hash, search}];
const segments = ["/", ...matched.matchedSegments];
while (numOfParentComponent !== 0 && segments.length !== 0) {
const pathname = formatPath(segments.join("/"));
const matched = this.route.lookup(pathname);
if (!matched?.fallback) {
stack.unshift(pathname);
numOfParentComponent--;
}
return paths;
}, [] as To[]);
segments.pop();
}
stackPaths.push({hash, search, pathname});
this.replace("/");
stackPaths.forEach(to => this.push(to, {transition: "exiting"}));
return Promise.all(stack.map((to, index) => (index === 0 ? this.replace(to) : this.push(to, {transition: "exiting"}))));
}

@@ -82,4 +96,4 @@

const wait = new Promise<void>(resolve => this.resolve.set(resolve));
this.pushOption.set(option ?? null);
const wait = new Promise<void>(resolve => (this.resolve.value = resolve));
this.pushOption.value = option ?? null;
this.stackHistory.push(to, option?.state);

@@ -91,3 +105,3 @@

async pop(): Promise<void> {
const wait = new Promise<void>(resolve => this.resolve.set(resolve));
const wait = new Promise<void>(resolve => (this.resolve.value = resolve));
this.stackHistory.pop();

@@ -100,3 +114,3 @@ return wait;

const wait = new Promise<void>(resolve => this.resolve.set(resolve));
const wait = new Promise<void>(resolve => (this.resolve.value = resolve));
this.stackHistory.replace(to, state);

@@ -141,4 +155,4 @@ return wait;

private pushScreen(location: Location, transition: TransitionType): void {
const option = this.pushOption.get();
const resolve = this.resolve.get();
const option = this.pushOption.value;
const resolve = this.resolve.value;

@@ -157,3 +171,3 @@ const screen = this.createScreen(location, option?.transition ?? transition);

private popScreen(transition: TransitionType) {
const resolve = this.resolve.get();
const resolve = this.resolve.value;
const top = this.getTopScreen();

@@ -168,3 +182,3 @@

private replaceScreen(location: Location) {
const resolve = this.resolve.get();
const resolve = this.resolve.value;
const top = this.getTopScreen();

@@ -201,14 +215,15 @@

class BurnAfterRead<T> {
constructor(private value: T | null = null) {}
// Turn value to null after read
class Snapshot<T> {
constructor(private _value: T | null = null) {}
set(newValue: T | null) {
this.value = newValue;
get value() {
const current = this._value;
this._value = null;
return current;
}
get(): T | null {
const current = this.value;
this.value = null;
return current;
set value(newValue: T | null) {
this._value = newValue;
}
}
/**
* Aim at detect popstate event tirggered by Safari edge swipe gesture
* for left edge swipe (back): clientX of touchend event is always be a native value
* Aim at detect popstate event triggered by Safari edge swipe gesture
* for left edge swipe (back): clientX of touchend event is always be a negative value
* for right edge swipe (forward): popstate event fired with only touchstart triggered

@@ -8,3 +8,3 @@ * therefore, if there are any popstate event fired within 300ms after above scenarios, it recognized as a native swipe back pop event

export function createSafariEdgeSwipeDetector() {
let isForwordSwipe = false;
let isForwardSwipe = false;
const isBackwardSwipe = new TimeoutFalseValue(200);

@@ -14,3 +14,3 @@

get isForwardPop(): boolean {
return isForwordSwipe;
return isForwardSwipe;
},

@@ -24,6 +24,6 @@

const start = (event: TouchEvent) => {
if (Array.from(event.changedTouches).some(touch => window.innerWidth - touch.clientX < 20)) isForwordSwipe = true;
if (Array.from(event.changedTouches).some(touch => window.innerWidth - touch.clientX < 20)) isForwardSwipe = true;
};
const end = (event: TouchEvent) => {
isForwordSwipe = false;
isForwardSwipe = false;
if (Array.from(event.changedTouches).some(touch => touch.clientX < 0)) isBackwardSwipe.value = true;

@@ -33,3 +33,3 @@ };

const cancel = () => {
isForwordSwipe = false;
isForwardSwipe = false;
isBackwardSwipe.value = false;

@@ -65,3 +65,3 @@ };

this.bool = true;
setTimeout(() => (this.bool = false), this.timeout);
window.setTimeout(() => (this.bool = false), this.timeout);
} else {

@@ -68,0 +68,0 @@ this.bool = false;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc