@modastar/z-router 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +366 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -19
- package/dist/index.d.ts +39 -19
- package/dist/index.js +361 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -22,8 +22,13 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
DefaultTransitionDuration: () => DefaultTransitionDuration,
|
|
24
24
|
LocationContext: () => LocationContext,
|
|
25
|
+
LocationProvider: () => LocationProvider,
|
|
26
|
+
PageRenderer: () => PageRenderer,
|
|
27
|
+
RouteComponent: () => RouteComponent,
|
|
25
28
|
RouteContext: () => RouteContext,
|
|
26
29
|
RouterContext: () => RouterContext,
|
|
30
|
+
RouterProvider: () => RouterProvider,
|
|
31
|
+
Stack: () => Stack,
|
|
27
32
|
createRouter: () => createRouter,
|
|
28
33
|
matchRoute: () => matchRoute,
|
|
29
34
|
matchUrl: () => matchUrl,
|
|
@@ -36,6 +41,69 @@ __export(index_exports, {
|
|
|
36
41
|
});
|
|
37
42
|
module.exports = __toCommonJS(index_exports);
|
|
38
43
|
|
|
44
|
+
// src/context/locationContext.ts
|
|
45
|
+
var import_react = require("react");
|
|
46
|
+
var LocationContext = (0, import_react.createContext)(null);
|
|
47
|
+
|
|
48
|
+
// src/components/locationProvider.tsx
|
|
49
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
50
|
+
var LocationProvider = ({
|
|
51
|
+
location,
|
|
52
|
+
children
|
|
53
|
+
}) => {
|
|
54
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationContext.Provider, { value: location, children });
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// src/components/routeComponent.tsx
|
|
58
|
+
var import_react4 = require("react");
|
|
59
|
+
|
|
60
|
+
// src/hooks/useRouter.ts
|
|
61
|
+
var import_react3 = require("react");
|
|
62
|
+
|
|
63
|
+
// src/context/routerContext.ts
|
|
64
|
+
var import_react2 = require("react");
|
|
65
|
+
var RouterContext = (0, import_react2.createContext)(null);
|
|
66
|
+
|
|
67
|
+
// src/hooks/useRouter.ts
|
|
68
|
+
var useRouter = () => {
|
|
69
|
+
const router = (0, import_react3.useContext)(RouterContext);
|
|
70
|
+
if (router === null) {
|
|
71
|
+
throw new Error("useRouter must be used within a Stack");
|
|
72
|
+
}
|
|
73
|
+
return router;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// src/components/routeComponent.tsx
|
|
77
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
78
|
+
var RouteComponent = ({
|
|
79
|
+
route,
|
|
80
|
+
children
|
|
81
|
+
}) => {
|
|
82
|
+
const router = useRouter();
|
|
83
|
+
const [pending, setPending] = (0, import_react4.useState)(!!route.beforeLoad);
|
|
84
|
+
(0, import_react4.useEffect)(() => {
|
|
85
|
+
if (route.beforeLoad) {
|
|
86
|
+
route.beforeLoad({ location: router.location }).catch((error) => {
|
|
87
|
+
if (error instanceof Error && typeof error.cause === "object" && error.cause !== null && "to" in error.cause) {
|
|
88
|
+
router.navigate({
|
|
89
|
+
to: error.cause.to,
|
|
90
|
+
replace: error.cause.replace
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}).finally(() => setPending(false));
|
|
94
|
+
}
|
|
95
|
+
}, []);
|
|
96
|
+
if (pending) {
|
|
97
|
+
const PendingComponent = route.pendingComponent;
|
|
98
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PendingComponent, {});
|
|
99
|
+
}
|
|
100
|
+
const Component = route.component;
|
|
101
|
+
return Component ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Component, { children }) : children;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// src/components/routerProvider.tsx
|
|
105
|
+
var import_react5 = require("react");
|
|
106
|
+
|
|
39
107
|
// src/utils.ts
|
|
40
108
|
var DefaultTransitionDuration = 300;
|
|
41
109
|
var redirect = (options) => {
|
|
@@ -117,22 +185,156 @@ var createRouter = (options) => {
|
|
|
117
185
|
return options;
|
|
118
186
|
};
|
|
119
187
|
|
|
120
|
-
// src/
|
|
121
|
-
var
|
|
122
|
-
var
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
188
|
+
// src/components/routerProvider.tsx
|
|
189
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
190
|
+
var RouterProvider = ({
|
|
191
|
+
router,
|
|
192
|
+
children
|
|
193
|
+
}) => {
|
|
194
|
+
const [history, setHistory] = (0, import_react5.useState)([]);
|
|
195
|
+
const [currentLocationIndex, setCurrentLocationIndex] = (0, import_react5.useState)(-1);
|
|
196
|
+
const [isTransitioning, setIsTransitioning] = (0, import_react5.useState)(false);
|
|
197
|
+
const [transitionDuration, setTransitionDuration] = (0, import_react5.useState)(
|
|
198
|
+
DefaultTransitionDuration
|
|
199
|
+
);
|
|
200
|
+
const [transitioningToIndex, setTransitioningToIndex] = (0, import_react5.useState)(null);
|
|
201
|
+
const navigate = (0, import_react5.useCallback)(
|
|
202
|
+
({
|
|
203
|
+
to,
|
|
204
|
+
replace,
|
|
205
|
+
transition,
|
|
206
|
+
duration,
|
|
207
|
+
updateHistory,
|
|
208
|
+
onFinish,
|
|
209
|
+
...locationOptions
|
|
210
|
+
}) => {
|
|
211
|
+
if (isTransitioning) return;
|
|
212
|
+
const newLocationIndex = replace ? currentLocationIndex : currentLocationIndex + 1;
|
|
213
|
+
const newLocation = {
|
|
214
|
+
index: newLocationIndex,
|
|
215
|
+
params: {},
|
|
216
|
+
query: {},
|
|
217
|
+
state: /* @__PURE__ */ new Map(),
|
|
218
|
+
pathname: to,
|
|
219
|
+
...locationOptions
|
|
220
|
+
};
|
|
221
|
+
if (newLocationIndex === history.length) {
|
|
222
|
+
setHistory([...history, newLocation]);
|
|
223
|
+
} else {
|
|
224
|
+
setHistory((prevHistory) => {
|
|
225
|
+
const newHistory = [...prevHistory];
|
|
226
|
+
newHistory[newLocationIndex] = newLocation;
|
|
227
|
+
return newHistory.slice(0, currentLocationIndex + 2);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
if (!replace && currentLocationIndex >= 0 && (transition ?? router.defaultViewTransition?.(
|
|
231
|
+
history.at(currentLocationIndex),
|
|
232
|
+
history.at(newLocationIndex)
|
|
233
|
+
))) {
|
|
234
|
+
const currentDuration = duration ?? DefaultTransitionDuration;
|
|
235
|
+
setIsTransitioning(true);
|
|
236
|
+
setTransitionDuration(currentDuration);
|
|
237
|
+
setTransitioningToIndex(newLocationIndex);
|
|
238
|
+
setTimeout(() => {
|
|
239
|
+
setIsTransitioning(false);
|
|
240
|
+
setTransitioningToIndex(null);
|
|
241
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
242
|
+
onFinish?.();
|
|
243
|
+
if (updateHistory) {
|
|
244
|
+
window.history.pushState({}, "", to);
|
|
245
|
+
}
|
|
246
|
+
}, currentDuration);
|
|
247
|
+
} else if (!replace) {
|
|
248
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
249
|
+
if (updateHistory) {
|
|
250
|
+
window.history.pushState({}, "", to);
|
|
251
|
+
}
|
|
252
|
+
} else if (updateHistory) {
|
|
253
|
+
window.history.replaceState({}, "", to);
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
[currentLocationIndex, history, isTransitioning, router]
|
|
257
|
+
);
|
|
258
|
+
(0, import_react5.useEffect)(() => {
|
|
259
|
+
console.log("Navigate: History updated:", history);
|
|
260
|
+
}, [history]);
|
|
261
|
+
const back = (0, import_react5.useCallback)(
|
|
262
|
+
(options) => {
|
|
263
|
+
if (isTransitioning) return;
|
|
264
|
+
const newLocationIndex = currentLocationIndex - (options?.depth ?? 1);
|
|
265
|
+
if (currentLocationIndex > 0 && (options?.transition ?? router.defaultViewTransition?.(
|
|
266
|
+
history.at(currentLocationIndex),
|
|
267
|
+
history.at(newLocationIndex)
|
|
268
|
+
))) {
|
|
269
|
+
const currentDuration = options?.duration ?? DefaultTransitionDuration;
|
|
270
|
+
setIsTransitioning(true);
|
|
271
|
+
setTransitionDuration(currentDuration);
|
|
272
|
+
setTransitioningToIndex(newLocationIndex);
|
|
273
|
+
setTimeout(() => {
|
|
274
|
+
setIsTransitioning(false);
|
|
275
|
+
setTransitioningToIndex(null);
|
|
276
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
277
|
+
options?.onFinish?.();
|
|
278
|
+
}, currentDuration);
|
|
279
|
+
} else {
|
|
280
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
[currentLocationIndex, history, isTransitioning, router]
|
|
284
|
+
);
|
|
285
|
+
const forward = (0, import_react5.useCallback)(
|
|
286
|
+
(options) => {
|
|
287
|
+
if (isTransitioning) return;
|
|
288
|
+
const newLocationIndex = currentLocationIndex + 1;
|
|
289
|
+
if (newLocationIndex < history.length && (options?.transition ?? router.defaultViewTransition?.(
|
|
290
|
+
history.at(currentLocationIndex),
|
|
291
|
+
history.at(newLocationIndex)
|
|
292
|
+
))) {
|
|
293
|
+
const duration = options?.duration ?? DefaultTransitionDuration;
|
|
294
|
+
setIsTransitioning(true);
|
|
295
|
+
setTransitionDuration(duration);
|
|
296
|
+
setTransitioningToIndex(newLocationIndex);
|
|
297
|
+
setTimeout(() => {
|
|
298
|
+
setIsTransitioning(false);
|
|
299
|
+
setTransitioningToIndex(null);
|
|
300
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
301
|
+
options?.onFinish?.();
|
|
302
|
+
}, duration);
|
|
303
|
+
} else {
|
|
304
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
[currentLocationIndex, history, isTransitioning, router]
|
|
308
|
+
);
|
|
309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
310
|
+
RouterContext.Provider,
|
|
311
|
+
{
|
|
312
|
+
value: {
|
|
313
|
+
options: router,
|
|
314
|
+
history,
|
|
315
|
+
currentLocationIndex,
|
|
316
|
+
location: history.at(currentLocationIndex) || null,
|
|
317
|
+
canGoBack: currentLocationIndex > 0,
|
|
318
|
+
canGoForward: currentLocationIndex < history.length - 1,
|
|
319
|
+
isTransitioning,
|
|
320
|
+
transitionDuration,
|
|
321
|
+
transitioningToIndex,
|
|
322
|
+
navigate,
|
|
323
|
+
back,
|
|
324
|
+
forward
|
|
325
|
+
},
|
|
326
|
+
children
|
|
327
|
+
}
|
|
328
|
+
);
|
|
329
|
+
};
|
|
127
330
|
|
|
128
|
-
// src/
|
|
129
|
-
var
|
|
130
|
-
var RouterContext = (0, import_react3.createContext)(null);
|
|
331
|
+
// src/components/stack.tsx
|
|
332
|
+
var import_react10 = require("react");
|
|
131
333
|
|
|
132
334
|
// src/hooks/useLocation.ts
|
|
133
|
-
var
|
|
335
|
+
var import_react6 = require("react");
|
|
134
336
|
var useLocation = () => {
|
|
135
|
-
const context = (0,
|
|
337
|
+
const context = (0, import_react6.useContext)(LocationContext);
|
|
136
338
|
if (context === null) {
|
|
137
339
|
throw new Error("useLocation must be used within a LocationProvider");
|
|
138
340
|
}
|
|
@@ -140,9 +342,15 @@ var useLocation = () => {
|
|
|
140
342
|
};
|
|
141
343
|
|
|
142
344
|
// src/hooks/useRoute.ts
|
|
143
|
-
var
|
|
345
|
+
var import_react8 = require("react");
|
|
346
|
+
|
|
347
|
+
// src/context/routeContext.ts
|
|
348
|
+
var import_react7 = require("react");
|
|
349
|
+
var RouteContext = (0, import_react7.createContext)(null);
|
|
350
|
+
|
|
351
|
+
// src/hooks/useRoute.ts
|
|
144
352
|
var useRoute = () => {
|
|
145
|
-
const route = (0,
|
|
353
|
+
const route = (0, import_react8.useContext)(RouteContext);
|
|
146
354
|
if (route === null) {
|
|
147
355
|
throw new Error("useRoute must be used within a RouteProvider");
|
|
148
356
|
}
|
|
@@ -157,21 +365,158 @@ var useMatches = () => {
|
|
|
157
365
|
return matchRoute(route, location.pathname)?.matches || [];
|
|
158
366
|
};
|
|
159
367
|
|
|
160
|
-
// src/
|
|
161
|
-
var
|
|
162
|
-
var
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
368
|
+
// src/components/routeProvider.tsx
|
|
369
|
+
var import_react9 = require("react");
|
|
370
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
371
|
+
var RouteProvider = ({
|
|
372
|
+
rootRoute,
|
|
373
|
+
children
|
|
374
|
+
}) => {
|
|
375
|
+
const router = useRouter();
|
|
376
|
+
(0, import_react9.useEffect)(() => {
|
|
377
|
+
const currentLocation = parseLocationFromHref(
|
|
378
|
+
rootRoute,
|
|
379
|
+
window.location.href
|
|
380
|
+
);
|
|
381
|
+
if (!currentLocation) return;
|
|
382
|
+
router.navigate({
|
|
383
|
+
to: currentLocation.pathname,
|
|
384
|
+
params: currentLocation.params,
|
|
385
|
+
query: currentLocation.query
|
|
386
|
+
});
|
|
387
|
+
return () => {
|
|
388
|
+
router.back();
|
|
389
|
+
};
|
|
390
|
+
}, []);
|
|
391
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RouteContext.Provider, { value: rootRoute, children });
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// src/components/stack.tsx
|
|
395
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
396
|
+
var PageRenderer = () => {
|
|
397
|
+
const route = useRoute();
|
|
398
|
+
const matches = useMatches();
|
|
399
|
+
if (!matches || matches.length === 0) {
|
|
400
|
+
const NotFoundComponent = route.notFoundComponent;
|
|
401
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(NotFoundComponent, {});
|
|
166
402
|
}
|
|
167
|
-
|
|
403
|
+
let content = null;
|
|
404
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
405
|
+
const route2 = matches[i];
|
|
406
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RouteComponent, { route: route2, children: content });
|
|
407
|
+
}
|
|
408
|
+
return content;
|
|
409
|
+
};
|
|
410
|
+
var StackComponent = () => {
|
|
411
|
+
const {
|
|
412
|
+
history,
|
|
413
|
+
currentLocationIndex,
|
|
414
|
+
canGoBack,
|
|
415
|
+
canGoForward,
|
|
416
|
+
isTransitioning,
|
|
417
|
+
transitioningToIndex,
|
|
418
|
+
transitionDuration,
|
|
419
|
+
back,
|
|
420
|
+
forward
|
|
421
|
+
} = useRouter();
|
|
422
|
+
const [isDragging, setIsDragging] = (0, import_react10.useState)(false);
|
|
423
|
+
const [startX, setStartX] = (0, import_react10.useState)(0);
|
|
424
|
+
const [dragOffset, setDragOffset] = (0, import_react10.useState)(0);
|
|
425
|
+
const [isCanceling, setIsCanceling] = (0, import_react10.useState)(false);
|
|
426
|
+
const [isTransitionStarted, setIsTransitionStarted] = (0, import_react10.useState)(false);
|
|
427
|
+
(0, import_react10.useEffect)(() => {
|
|
428
|
+
if (!isTransitioning || transitioningToIndex === null) return;
|
|
429
|
+
setIsTransitionStarted(true);
|
|
430
|
+
setTimeout(() => {
|
|
431
|
+
setIsTransitionStarted(false);
|
|
432
|
+
}, transitionDuration);
|
|
433
|
+
}, [isTransitioning, transitioningToIndex]);
|
|
434
|
+
const reset = () => {
|
|
435
|
+
setIsDragging(false);
|
|
436
|
+
setDragOffset(0);
|
|
437
|
+
setIsCanceling(false);
|
|
438
|
+
};
|
|
439
|
+
const handleTouchStart = (e) => {
|
|
440
|
+
if (isTransitioning || !canGoForward && !canGoBack) return;
|
|
441
|
+
setIsDragging(true);
|
|
442
|
+
setStartX(e.touches[0].clientX);
|
|
443
|
+
};
|
|
444
|
+
const handleTouchMove = (e) => {
|
|
445
|
+
if (!isDragging) return;
|
|
446
|
+
const offset = e.touches[0].clientX - startX;
|
|
447
|
+
if (offset > 0 && currentLocationIndex === 0 || offset < 0 && currentLocationIndex + 1 === history.length) {
|
|
448
|
+
setDragOffset(0);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
setDragOffset(Math.min(window.innerWidth, offset));
|
|
452
|
+
};
|
|
453
|
+
const handleTouchEnd = () => {
|
|
454
|
+
if (!isDragging) return;
|
|
455
|
+
if (dragOffset > window.innerWidth * 0.3 && canGoBack) {
|
|
456
|
+
back({
|
|
457
|
+
onFinish: reset
|
|
458
|
+
});
|
|
459
|
+
} else if (dragOffset < -window.innerWidth * 0.3 && canGoForward) {
|
|
460
|
+
forward({
|
|
461
|
+
onFinish: reset
|
|
462
|
+
});
|
|
463
|
+
} else {
|
|
464
|
+
setIsCanceling(true);
|
|
465
|
+
setTimeout(reset, transitionDuration);
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative inset-0 h-full w-full overflow-hidden", children: [
|
|
469
|
+
currentLocationIndex >= 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "absolute inset-0 -z-10", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LocationProvider, { location: history.at(currentLocationIndex - 1), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PageRenderer, {}, currentLocationIndex - 1) }) }),
|
|
470
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
471
|
+
"div",
|
|
472
|
+
{
|
|
473
|
+
className: "bg-background absolute inset-0 overflow-hidden",
|
|
474
|
+
style: {
|
|
475
|
+
transform: isTransitioning && transitioningToIndex !== null && transitioningToIndex < currentLocationIndex ? `translateX(100%)` : isDragging && dragOffset > 0 && !isCanceling ? `translateX(${dragOffset}px)` : "translateX(0px)",
|
|
476
|
+
transition: isCanceling || isTransitioning && transitioningToIndex !== null && transitioningToIndex < currentLocationIndex ? `transform ${transitionDuration}ms ease-out` : "",
|
|
477
|
+
boxShadow: isDragging && dragOffset > 0 ? "-4px 0 8px rgba(0,0,0,0.1)" : "none"
|
|
478
|
+
},
|
|
479
|
+
onTouchStart: handleTouchStart,
|
|
480
|
+
onTouchMove: handleTouchMove,
|
|
481
|
+
onTouchEnd: handleTouchEnd,
|
|
482
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LocationProvider, { location: history.at(currentLocationIndex), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PageRenderer, {}, currentLocationIndex) })
|
|
483
|
+
},
|
|
484
|
+
currentLocationIndex
|
|
485
|
+
),
|
|
486
|
+
(isDragging && dragOffset < 0 || isTransitioning && transitioningToIndex !== null && currentLocationIndex < transitioningToIndex) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
487
|
+
"div",
|
|
488
|
+
{
|
|
489
|
+
className: "bg-background absolute inset-0 z-10 overflow-hidden transition-transform ease-in",
|
|
490
|
+
style: {
|
|
491
|
+
transform: isTransitionStarted ? `translateX(0px)` : isDragging && !isCanceling ? `translateX(${window.innerWidth + dragOffset}px)` : "translateX(100%)",
|
|
492
|
+
transitionDuration: isTransitioning || isCanceling ? `${transitionDuration}ms` : "0ms"
|
|
493
|
+
},
|
|
494
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
495
|
+
LocationProvider,
|
|
496
|
+
{
|
|
497
|
+
location: isDragging ? history.at(currentLocationIndex + 1) : history.at(transitioningToIndex),
|
|
498
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PageRenderer, {}, transitioningToIndex)
|
|
499
|
+
}
|
|
500
|
+
)
|
|
501
|
+
},
|
|
502
|
+
transitioningToIndex
|
|
503
|
+
)
|
|
504
|
+
] });
|
|
505
|
+
};
|
|
506
|
+
var Stack = ({ rootRoute }) => {
|
|
507
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RouteProvider, { rootRoute, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StackComponent, {}) });
|
|
168
508
|
};
|
|
169
509
|
// Annotate the CommonJS export names for ESM import in node:
|
|
170
510
|
0 && (module.exports = {
|
|
171
511
|
DefaultTransitionDuration,
|
|
172
512
|
LocationContext,
|
|
513
|
+
LocationProvider,
|
|
514
|
+
PageRenderer,
|
|
515
|
+
RouteComponent,
|
|
173
516
|
RouteContext,
|
|
174
517
|
RouterContext,
|
|
518
|
+
RouterProvider,
|
|
519
|
+
Stack,
|
|
175
520
|
createRouter,
|
|
176
521
|
matchRoute,
|
|
177
522
|
matchUrl,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/context/locationContext.ts","../src/context/routeContext.ts","../src/context/routerContext.ts","../src/hooks/useLocation.ts","../src/hooks/useRoute.ts","../src/hooks/useMatches.ts","../src/hooks/useRouter.ts"],"sourcesContent":["export * from \"./utils.js\";\n\nexport * from \"./context/index.js\";\nexport * from \"./hooks/index.js\";\n","import type { Location, RootRoute, Route, RouterOptions } from \"./types.js\";\n\nexport const DefaultTransitionDuration = 300;\n\nexport const redirect = (options: { to: string; replace?: boolean }) => {\n return new Error(\"\", { cause: options });\n};\n\nexport const matchUrl = (\n pattern: string,\n url: string\n): { params: Record<string, string>; query: Record<string, string> } | null => {\n try {\n // 解析 URL\n let pathname, searchParams;\n\n if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {\n const urlObj = new URL(url);\n pathname = urlObj.pathname;\n searchParams = urlObj.searchParams;\n } else {\n // 處理相對路徑\n const [path, queryString] = url.split(\"?\");\n if (!path) {\n return null;\n }\n pathname = path;\n searchParams = new URLSearchParams(queryString || \"\");\n }\n\n // 移除路徑首尾的斜線以便比較\n const cleanPath = pathname.replaceAll(/^\\/|\\/$/g, \"\");\n const cleanPattern = pattern.replaceAll(/^\\/|\\/$/g, \"\");\n\n // 分割路徑段\n const pathSegments = cleanPath.split(\"/\");\n const patternSegments = cleanPattern.split(\"/\");\n\n // 路徑段數量不同則不匹配\n if (pathSegments.length !== patternSegments.length) {\n return null;\n }\n\n // 提取路徑參數\n const params: Record<string, string> = {};\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSegment = patternSegments[i];\n const pathSegment = pathSegments[i];\n\n if (patternSegment.startsWith(\":\")) {\n // 動態參數\n const paramName = patternSegment.slice(1);\n params[paramName] = decodeURIComponent(pathSegment);\n } else if (patternSegment !== pathSegment) {\n // 靜態段不匹配\n return null;\n }\n }\n\n // 提取查詢參數\n const query = Object.fromEntries(searchParams.entries());\n\n return { params, query };\n } catch {\n return null;\n }\n};\n\nexport const matchRoute = (\n rootRoute: RootRoute,\n url: string\n): {\n matches: Route[];\n params: Record<string, string>;\n query: Record<string, string>;\n} | null => {\n const _matchRoute = (\n matches: Route[],\n route: Route\n ): {\n matches: Route[];\n params: Record<string, string>;\n query: Record<string, string>;\n } | null => {\n if (route.children) {\n for (const childRoute of route.children) {\n const matchesResult = _matchRoute([...matches, childRoute], childRoute);\n if (matchesResult) {\n return matchesResult;\n }\n }\n return null;\n }\n\n let pattern = \"\";\n for (const match of matches) {\n if (match.pathname === undefined) continue;\n pattern += `/${match.pathname}`;\n }\n const result = matchUrl(pattern, url);\n if (result) {\n return { matches, ...result };\n }\n return null;\n };\n\n return _matchRoute([], rootRoute);\n};\n\nexport const parseLocationFromHref = (\n rootRoute: RootRoute,\n to: string\n): Pick<Location, \"pathname\" | \"params\" | \"query\"> | null => {\n const result = matchRoute(rootRoute, to);\n if (!result) return null;\n return {\n pathname: to,\n params: result.params,\n query: result.query,\n };\n};\n\nexport const createRouter = (options: RouterOptions): RouterOptions => {\n return options;\n};\n","import { createContext } from \"react\";\n\nimport type { Location } from \"@/types.js\";\n\nexport const LocationContext = createContext<Location | null>(null);\n","import { createContext } from \"react\";\n\nimport type { RootRoute } from \"@/types.js\";\n\nexport const RouteContext = createContext<RootRoute | null>(null);\n","import { createContext } from \"react\";\n\nimport type {\n BackOptions,\n ForwardOptions,\n Location,\n NavigateOptions,\n RouterOptions,\n} from \"@/types.js\";\n\nexport interface RouterContextType {\n // Router Config\n options: RouterOptions;\n\n // Navigation State\n history: Location[];\n currentLocationIndex: number;\n location: Location | null;\n canGoBack: boolean;\n canGoForward: boolean;\n\n // Transition state\n isTransitioning: boolean;\n transitionDuration: number;\n transitioningToIndex: number | null;\n\n // Actions\n navigate: (options: NavigateOptions) => void;\n back: (options: BackOptions) => void;\n forward: (options: ForwardOptions) => void;\n}\n\nexport const RouterContext = createContext<RouterContextType | null>(null);\n","import { useContext } from \"react\";\n\nimport { LocationContext } from \"@/context/locationContext.js\";\n\nexport const useLocation = () => {\n const context = useContext(LocationContext);\n if (context === null) {\n throw new Error(\"useLocation must be used within a LocationProvider\");\n }\n return context;\n};\n","import { useContext } from \"react\";\n\nimport { RouteContext } from \"@/context/routeContext.js\";\n\nexport const useRoute = () => {\n const route = useContext(RouteContext);\n if (route === null) {\n throw new Error(\"useRoute must be used within a RouteProvider\");\n }\n return route;\n};\n","import { matchRoute } from \"@/utils.js\";\n\nimport { useLocation } from \"./useLocation.js\";\nimport { useRoute } from \"./useRoute.js\";\n\nexport const useMatches = () => {\n const route = useRoute();\n const location = useLocation();\n if (!location) return [];\n return matchRoute(route, location.pathname)?.matches || [];\n};\n","import { useContext } from \"react\";\n\nimport { RouterContext } from \"@/context/routerContext.js\";\n\nexport const useRouter = () => {\n const router = useContext(RouterContext);\n if (router === null) {\n throw new Error(\"useRouter must be used within a Stack\");\n }\n return router;\n};\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/context/locationContext.ts","../src/components/locationProvider.tsx","../src/components/routeComponent.tsx","../src/hooks/useRouter.ts","../src/context/routerContext.ts","../src/components/routerProvider.tsx","../src/utils.ts","../src/components/stack.tsx","../src/hooks/useLocation.ts","../src/hooks/useRoute.ts","../src/context/routeContext.ts","../src/hooks/useMatches.ts","../src/components/routeProvider.tsx"],"sourcesContent":["export * from \"./components/index.js\";\nexport * from \"./context/index.js\";\nexport * from \"./hooks/index.js\";\nexport * from \"./utils.js\";\n","import { createContext } from \"react\";\n\nimport type { Location } from \"@/types.js\";\n\nexport const LocationContext = createContext<Location | null>(null);\n","import { LocationContext } from \"@/context/locationContext.js\";\nimport type { Location } from \"@/types.js\";\n\nexport const LocationProvider = ({\n location,\n children,\n}: {\n location: Location;\n children: React.ReactNode;\n}) => {\n return (\n <LocationContext.Provider value={location}>\n {children}\n </LocationContext.Provider>\n );\n};\n","import { useEffect, useState } from \"react\";\n\nimport { useRouter } from \"@/hooks/useRouter.js\";\nimport type { Route } from \"@/types.js\";\n\nexport const RouteComponent = ({\n route,\n children,\n}: {\n route: Route;\n children?: React.ReactNode;\n}) => {\n const router = useRouter();\n const [pending, setPending] = useState(!!route.beforeLoad);\n\n useEffect(() => {\n if (route.beforeLoad) {\n route\n .beforeLoad({ location: router.location! })\n .catch((error: unknown) => {\n if (\n error instanceof Error &&\n typeof error.cause === \"object\" &&\n error.cause !== null &&\n \"to\" in error.cause\n ) {\n router.navigate({\n to: (error.cause as any).to,\n replace: (error.cause as any).replace,\n });\n }\n })\n .finally(() => setPending(false));\n }\n }, []);\n\n if (pending) {\n const PendingComponent = route.pendingComponent!;\n return <PendingComponent />;\n }\n\n const Component = route.component;\n return Component ? <Component>{children}</Component> : children;\n};\n","import { useContext } from \"react\";\n\nimport { RouterContext } from \"@/context/routerContext.js\";\n\nexport const useRouter = () => {\n const router = useContext(RouterContext);\n if (router === null) {\n throw new Error(\"useRouter must be used within a Stack\");\n }\n return router;\n};\n","import { createContext } from \"react\";\n\nimport type {\n BackOptions,\n ForwardOptions,\n Location,\n NavigateOptions,\n RouterOptions,\n} from \"@/types.js\";\n\nexport interface RouterContextType {\n // Router Config\n options: RouterOptions;\n\n // Navigation State\n history: Location[];\n currentLocationIndex: number;\n location: Location | null;\n canGoBack: boolean;\n canGoForward: boolean;\n\n // Transition state\n isTransitioning: boolean;\n transitionDuration: number;\n transitioningToIndex: number | null;\n\n // Actions\n navigate: (options: NavigateOptions) => void;\n back: (options: BackOptions) => void;\n forward: (options: ForwardOptions) => void;\n}\n\nexport const RouterContext = createContext<RouterContextType | null>(null);\n","import { useCallback, useEffect, useState } from \"react\";\n\nimport { RouterContext } from \"@/context/routerContext.js\";\nimport type {\n BackOptions,\n ForwardOptions,\n Location,\n NavigateOptions,\n RouterOptions,\n} from \"@/types.js\";\nimport { DefaultTransitionDuration } from \"@/utils.js\";\n\nexport const RouterProvider = ({\n router,\n children,\n}: {\n router: RouterOptions;\n children: React.ReactNode;\n}) => {\n const [history, setHistory] = useState<Location[]>([]);\n const [currentLocationIndex, setCurrentLocationIndex] = useState<number>(-1);\n const [isTransitioning, setIsTransitioning] = useState<boolean>(false);\n const [transitionDuration, setTransitionDuration] = useState<number>(\n DefaultTransitionDuration\n );\n const [transitioningToIndex, setTransitioningToIndex] = useState<\n number | null\n >(null);\n\n const navigate = useCallback(\n ({\n to,\n replace,\n transition,\n duration,\n updateHistory,\n onFinish,\n ...locationOptions\n }: NavigateOptions) => {\n if (isTransitioning) return;\n const newLocationIndex = replace\n ? currentLocationIndex\n : currentLocationIndex + 1;\n const newLocation: Location = {\n index: newLocationIndex,\n params: {},\n query: {},\n state: new Map(),\n pathname: to,\n ...locationOptions,\n };\n if (newLocationIndex === history.length) {\n setHistory([...history, newLocation]);\n } else {\n setHistory((prevHistory) => {\n const newHistory = [...prevHistory];\n newHistory[newLocationIndex] = newLocation;\n return newHistory.slice(0, currentLocationIndex + 2);\n });\n }\n if (\n !replace &&\n currentLocationIndex >= 0 &&\n (transition ??\n router.defaultViewTransition?.(\n history.at(currentLocationIndex),\n history.at(newLocationIndex)\n ))\n ) {\n const currentDuration = duration ?? DefaultTransitionDuration;\n setIsTransitioning(true);\n setTransitionDuration(currentDuration);\n setTransitioningToIndex(newLocationIndex);\n setTimeout(() => {\n setIsTransitioning(false);\n setTransitioningToIndex(null);\n setCurrentLocationIndex(newLocationIndex);\n onFinish?.();\n if (updateHistory) {\n window.history.pushState({}, \"\", to);\n }\n }, currentDuration);\n } else if (!replace) {\n setCurrentLocationIndex(newLocationIndex);\n if (updateHistory) {\n window.history.pushState({}, \"\", to);\n }\n } else if (updateHistory) {\n window.history.replaceState({}, \"\", to);\n }\n },\n [currentLocationIndex, history, isTransitioning, router]\n );\n\n useEffect(() => {\n console.log(\"Navigate: History updated:\", history);\n }, [history]);\n\n const back = useCallback(\n (options: BackOptions) => {\n if (isTransitioning) return;\n const newLocationIndex = currentLocationIndex - (options?.depth ?? 1);\n if (\n currentLocationIndex > 0 &&\n (options?.transition ??\n router.defaultViewTransition?.(\n history.at(currentLocationIndex),\n history.at(newLocationIndex)\n ))\n ) {\n const currentDuration = options?.duration ?? DefaultTransitionDuration;\n setIsTransitioning(true);\n setTransitionDuration(currentDuration);\n setTransitioningToIndex(newLocationIndex);\n setTimeout(() => {\n setIsTransitioning(false);\n setTransitioningToIndex(null);\n setCurrentLocationIndex(newLocationIndex);\n options?.onFinish?.();\n }, currentDuration);\n } else {\n setCurrentLocationIndex(newLocationIndex);\n }\n },\n [currentLocationIndex, history, isTransitioning, router]\n );\n\n const forward = useCallback(\n (options: ForwardOptions) => {\n if (isTransitioning) return;\n const newLocationIndex = currentLocationIndex + 1;\n if (\n newLocationIndex < history.length &&\n (options?.transition ??\n router.defaultViewTransition?.(\n history.at(currentLocationIndex),\n history.at(newLocationIndex)\n ))\n ) {\n const duration = options?.duration ?? DefaultTransitionDuration;\n setIsTransitioning(true);\n setTransitionDuration(duration);\n setTransitioningToIndex(newLocationIndex);\n setTimeout(() => {\n setIsTransitioning(false);\n setTransitioningToIndex(null);\n setCurrentLocationIndex(newLocationIndex);\n options?.onFinish?.();\n }, duration);\n } else {\n setCurrentLocationIndex(newLocationIndex);\n }\n },\n [currentLocationIndex, history, isTransitioning, router]\n );\n\n return (\n <RouterContext.Provider\n value={{\n options: router,\n\n history,\n currentLocationIndex,\n location: history.at(currentLocationIndex) || null,\n canGoBack: currentLocationIndex > 0,\n canGoForward: currentLocationIndex < history.length - 1,\n\n isTransitioning,\n transitionDuration,\n transitioningToIndex,\n\n navigate,\n back,\n forward,\n }}\n >\n {children}\n </RouterContext.Provider>\n );\n};\n","import type { Location, RootRoute, Route, RouterOptions } from \"./types.js\";\n\nexport const DefaultTransitionDuration = 300;\n\nexport const redirect = (options: { to: string; replace?: boolean }) => {\n return new Error(\"\", { cause: options });\n};\n\nexport const matchUrl = (\n pattern: string,\n url: string\n): { params: Record<string, string>; query: Record<string, string> } | null => {\n try {\n // 解析 URL\n let pathname, searchParams;\n\n if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {\n const urlObj = new URL(url);\n pathname = urlObj.pathname;\n searchParams = urlObj.searchParams;\n } else {\n // 處理相對路徑\n const [path, queryString] = url.split(\"?\");\n if (!path) {\n return null;\n }\n pathname = path;\n searchParams = new URLSearchParams(queryString || \"\");\n }\n\n // 移除路徑首尾的斜線以便比較\n const cleanPath = pathname.replaceAll(/^\\/|\\/$/g, \"\");\n const cleanPattern = pattern.replaceAll(/^\\/|\\/$/g, \"\");\n\n // 分割路徑段\n const pathSegments = cleanPath.split(\"/\");\n const patternSegments = cleanPattern.split(\"/\");\n\n // 路徑段數量不同則不匹配\n if (pathSegments.length !== patternSegments.length) {\n return null;\n }\n\n // 提取路徑參數\n const params: Record<string, string> = {};\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSegment = patternSegments[i];\n const pathSegment = pathSegments[i];\n\n if (patternSegment.startsWith(\":\")) {\n // 動態參數\n const paramName = patternSegment.slice(1);\n params[paramName] = decodeURIComponent(pathSegment);\n } else if (patternSegment !== pathSegment) {\n // 靜態段不匹配\n return null;\n }\n }\n\n // 提取查詢參數\n const query = Object.fromEntries(searchParams.entries());\n\n return { params, query };\n } catch {\n return null;\n }\n};\n\nexport const matchRoute = (\n rootRoute: RootRoute,\n url: string\n): {\n matches: Route[];\n params: Record<string, string>;\n query: Record<string, string>;\n} | null => {\n const _matchRoute = (\n matches: Route[],\n route: Route\n ): {\n matches: Route[];\n params: Record<string, string>;\n query: Record<string, string>;\n } | null => {\n if (route.children) {\n for (const childRoute of route.children) {\n const matchesResult = _matchRoute([...matches, childRoute], childRoute);\n if (matchesResult) {\n return matchesResult;\n }\n }\n return null;\n }\n\n let pattern = \"\";\n for (const match of matches) {\n if (match.pathname === undefined) continue;\n pattern += `/${match.pathname}`;\n }\n const result = matchUrl(pattern, url);\n if (result) {\n return { matches, ...result };\n }\n return null;\n };\n\n return _matchRoute([], rootRoute);\n};\n\nexport const parseLocationFromHref = (\n rootRoute: RootRoute,\n to: string\n): Pick<Location, \"pathname\" | \"params\" | \"query\"> | null => {\n const result = matchRoute(rootRoute, to);\n if (!result) return null;\n return {\n pathname: to,\n params: result.params,\n query: result.query,\n };\n};\n\nexport const createRouter = (options: RouterOptions): RouterOptions => {\n return options;\n};\n","import { useEffect, useState } from \"react\";\n\nimport { useMatches } from \"@/hooks/useMatches.js\";\nimport { useRoute } from \"@/hooks/useRoute.js\";\nimport { useRouter } from \"@/hooks/useRouter.js\";\nimport type { RootRoute } from \"@/types.js\";\n\nimport { LocationProvider } from \"./locationProvider.js\";\nimport { RouteComponent } from \"./routeComponent.js\";\nimport { RouteProvider } from \"./routeProvider.js\";\n\nexport const PageRenderer = () => {\n const route = useRoute();\n const matches = useMatches();\n if (!matches || matches.length === 0) {\n const NotFoundComponent = route.notFoundComponent!;\n return <NotFoundComponent />;\n }\n let content: React.ReactNode = null;\n for (let i = matches.length - 1; i >= 0; i--) {\n const route = matches[i];\n content = <RouteComponent route={route}>{content}</RouteComponent>;\n }\n return content;\n};\n\nconst StackComponent = () => {\n const {\n history,\n currentLocationIndex,\n canGoBack,\n canGoForward,\n isTransitioning,\n transitioningToIndex,\n transitionDuration,\n back,\n forward,\n } = useRouter();\n\n const [isDragging, setIsDragging] = useState(false);\n const [startX, setStartX] = useState(0);\n const [dragOffset, setDragOffset] = useState(0);\n const [isCanceling, setIsCanceling] = useState(false);\n const [isTransitionStarted, setIsTransitionStarted] = useState(false);\n\n useEffect(() => {\n if (!isTransitioning || transitioningToIndex === null) return;\n setIsTransitionStarted(true);\n setTimeout(() => {\n setIsTransitionStarted(false);\n }, transitionDuration);\n }, [isTransitioning, transitioningToIndex]);\n\n const reset = () => {\n setIsDragging(false);\n setDragOffset(0);\n setIsCanceling(false);\n };\n\n const handleTouchStart = (e: React.TouchEvent) => {\n if (isTransitioning || (!canGoForward && !canGoBack)) return;\n setIsDragging(true);\n setStartX(e.touches[0].clientX);\n };\n\n const handleTouchMove = (e: React.TouchEvent) => {\n if (!isDragging) return;\n const offset = e.touches[0].clientX - startX;\n if (\n (offset > 0 && currentLocationIndex === 0) ||\n (offset < 0 && currentLocationIndex + 1 === history.length)\n ) {\n setDragOffset(0);\n return;\n }\n setDragOffset(Math.min(window.innerWidth, offset));\n };\n\n const handleTouchEnd = () => {\n if (!isDragging) return;\n\n if (dragOffset > window.innerWidth * 0.3 && canGoBack) {\n back({\n onFinish: reset,\n });\n } else if (dragOffset < -window.innerWidth * 0.3 && canGoForward) {\n forward({\n onFinish: reset,\n });\n } else {\n setIsCanceling(true);\n setTimeout(reset, transitionDuration);\n }\n };\n\n return (\n <div className=\"relative inset-0 h-full w-full overflow-hidden\">\n {currentLocationIndex >= 1 && (\n <div className=\"absolute inset-0 -z-10\">\n <LocationProvider location={history.at(currentLocationIndex - 1)!}>\n <PageRenderer key={currentLocationIndex - 1} />\n </LocationProvider>\n </div>\n )}\n <div\n key={currentLocationIndex}\n className=\"bg-background absolute inset-0 overflow-hidden\"\n style={{\n transform:\n isTransitioning &&\n transitioningToIndex !== null &&\n transitioningToIndex < currentLocationIndex\n ? `translateX(100%)`\n : isDragging && dragOffset > 0 && !isCanceling\n ? `translateX(${dragOffset}px)`\n : \"translateX(0px)\",\n transition:\n isCanceling ||\n (isTransitioning &&\n transitioningToIndex !== null &&\n transitioningToIndex < currentLocationIndex)\n ? `transform ${transitionDuration}ms ease-out`\n : \"\",\n boxShadow:\n isDragging && dragOffset > 0\n ? \"-4px 0 8px rgba(0,0,0,0.1)\"\n : \"none\",\n }}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n <LocationProvider location={history.at(currentLocationIndex)!}>\n <PageRenderer key={currentLocationIndex} />\n </LocationProvider>\n </div>\n {((isDragging && dragOffset < 0) ||\n (isTransitioning &&\n transitioningToIndex !== null &&\n currentLocationIndex < transitioningToIndex)) && (\n <div\n key={transitioningToIndex}\n className=\"bg-background absolute inset-0 z-10 overflow-hidden transition-transform ease-in\"\n style={{\n transform: isTransitionStarted\n ? `translateX(0px)`\n : isDragging && !isCanceling\n ? `translateX(${window.innerWidth + dragOffset}px)`\n : \"translateX(100%)\",\n transitionDuration:\n isTransitioning || isCanceling\n ? `${transitionDuration}ms`\n : \"0ms\",\n }}\n >\n <LocationProvider\n location={\n isDragging\n ? history.at(currentLocationIndex + 1)!\n : history.at(transitioningToIndex!)!\n }\n >\n <PageRenderer key={transitioningToIndex} />\n </LocationProvider>\n </div>\n )}\n </div>\n );\n};\n\nexport const Stack = ({ rootRoute }: { rootRoute: RootRoute }) => {\n return (\n <RouteProvider rootRoute={rootRoute}>\n <StackComponent />\n </RouteProvider>\n );\n};\n","import { useContext } from \"react\";\n\nimport { LocationContext } from \"@/context/locationContext.js\";\n\nexport const useLocation = () => {\n const context = useContext(LocationContext);\n if (context === null) {\n throw new Error(\"useLocation must be used within a LocationProvider\");\n }\n return context;\n};\n","import { useContext } from \"react\";\n\nimport { RouteContext } from \"@/context/routeContext.js\";\n\nexport const useRoute = () => {\n const route = useContext(RouteContext);\n if (route === null) {\n throw new Error(\"useRoute must be used within a RouteProvider\");\n }\n return route;\n};\n","import { createContext } from \"react\";\n\nimport type { RootRoute } from \"@/types.js\";\n\nexport const RouteContext = createContext<RootRoute | null>(null);\n","import { matchRoute } from \"@/utils.js\";\n\nimport { useLocation } from \"./useLocation.js\";\nimport { useRoute } from \"./useRoute.js\";\n\nexport const useMatches = () => {\n const route = useRoute();\n const location = useLocation();\n if (!location) return [];\n return matchRoute(route, location.pathname)?.matches || [];\n};\n","import { useEffect } from \"react\";\n\nimport { RouteContext } from \"@/context/routeContext.js\";\nimport { useRouter } from \"@/hooks/useRouter.js\";\nimport type { RootRoute } from \"@/types.js\";\nimport { parseLocationFromHref } from \"@/utils.js\";\n\nexport const RouteProvider = ({\n rootRoute,\n children,\n}: {\n rootRoute: RootRoute;\n children: React.ReactNode;\n}) => {\n const router = useRouter();\n\n useEffect(() => {\n const currentLocation = parseLocationFromHref(\n rootRoute,\n window.location.href\n );\n if (!currentLocation) return;\n router.navigate({\n to: currentLocation.pathname,\n params: currentLocation.params,\n query: currentLocation.query,\n });\n return () => {\n router.back();\n };\n }, []);\n\n return (\n <RouteContext.Provider value={rootRoute}>{children}</RouteContext.Provider>\n );\n};\n"],"mappings":"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","names":["import_react","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_react","import_react","import_react","import_react","import_jsx_runtime","import_jsx_runtime","route"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
|
|
4
4
|
interface Route {
|
|
@@ -16,7 +16,7 @@ interface RootRoute extends Route {
|
|
|
16
16
|
|
|
17
17
|
interface Location {
|
|
18
18
|
index: number;
|
|
19
|
-
pathname:
|
|
19
|
+
pathname: string;
|
|
20
20
|
params: any;
|
|
21
21
|
query: any;
|
|
22
22
|
state?: Map<string, any>;
|
|
@@ -55,22 +55,25 @@ type ForwardOptions =
|
|
|
55
55
|
})
|
|
56
56
|
| void;
|
|
57
57
|
|
|
58
|
-
declare const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
declare const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
} | null;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
declare const
|
|
58
|
+
declare const LocationProvider: ({ location, children, }: {
|
|
59
|
+
location: Location;
|
|
60
|
+
children: React.ReactNode;
|
|
61
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
62
|
+
|
|
63
|
+
declare const RouteComponent: ({ route, children, }: {
|
|
64
|
+
route: Route;
|
|
65
|
+
children?: React.ReactNode;
|
|
66
|
+
}) => string | number | bigint | boolean | Iterable<react.ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<react.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
|
|
67
|
+
|
|
68
|
+
declare const RouterProvider: ({ router, children, }: {
|
|
69
|
+
router: RouterOptions;
|
|
70
|
+
children: React.ReactNode;
|
|
71
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
72
|
+
|
|
73
|
+
declare const PageRenderer: () => react_jsx_runtime.JSX.Element | null;
|
|
74
|
+
declare const Stack: ({ rootRoute }: {
|
|
75
|
+
rootRoute: RootRoute;
|
|
76
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
74
77
|
|
|
75
78
|
declare const LocationContext: react.Context<Location | null>;
|
|
76
79
|
|
|
@@ -100,4 +103,21 @@ declare const useRoute: () => RootRoute;
|
|
|
100
103
|
|
|
101
104
|
declare const useRouter: () => RouterContextType;
|
|
102
105
|
|
|
103
|
-
|
|
106
|
+
declare const DefaultTransitionDuration = 300;
|
|
107
|
+
declare const redirect: (options: {
|
|
108
|
+
to: string;
|
|
109
|
+
replace?: boolean;
|
|
110
|
+
}) => Error;
|
|
111
|
+
declare const matchUrl: (pattern: string, url: string) => {
|
|
112
|
+
params: Record<string, string>;
|
|
113
|
+
query: Record<string, string>;
|
|
114
|
+
} | null;
|
|
115
|
+
declare const matchRoute: (rootRoute: RootRoute, url: string) => {
|
|
116
|
+
matches: Route[];
|
|
117
|
+
params: Record<string, string>;
|
|
118
|
+
query: Record<string, string>;
|
|
119
|
+
} | null;
|
|
120
|
+
declare const parseLocationFromHref: (rootRoute: RootRoute, to: string) => Pick<Location, "pathname" | "params" | "query"> | null;
|
|
121
|
+
declare const createRouter: (options: RouterOptions) => RouterOptions;
|
|
122
|
+
|
|
123
|
+
export { DefaultTransitionDuration, LocationContext, LocationProvider, PageRenderer, RouteComponent, RouteContext, RouterContext, type RouterContextType, RouterProvider, Stack, createRouter, matchRoute, matchUrl, parseLocationFromHref, redirect, useLocation, useMatches, useRoute, useRouter };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
|
|
4
4
|
interface Route {
|
|
@@ -16,7 +16,7 @@ interface RootRoute extends Route {
|
|
|
16
16
|
|
|
17
17
|
interface Location {
|
|
18
18
|
index: number;
|
|
19
|
-
pathname:
|
|
19
|
+
pathname: string;
|
|
20
20
|
params: any;
|
|
21
21
|
query: any;
|
|
22
22
|
state?: Map<string, any>;
|
|
@@ -55,22 +55,25 @@ type ForwardOptions =
|
|
|
55
55
|
})
|
|
56
56
|
| void;
|
|
57
57
|
|
|
58
|
-
declare const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
declare const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
} | null;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
declare const
|
|
58
|
+
declare const LocationProvider: ({ location, children, }: {
|
|
59
|
+
location: Location;
|
|
60
|
+
children: React.ReactNode;
|
|
61
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
62
|
+
|
|
63
|
+
declare const RouteComponent: ({ route, children, }: {
|
|
64
|
+
route: Route;
|
|
65
|
+
children?: React.ReactNode;
|
|
66
|
+
}) => string | number | bigint | boolean | Iterable<react.ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<react.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
|
|
67
|
+
|
|
68
|
+
declare const RouterProvider: ({ router, children, }: {
|
|
69
|
+
router: RouterOptions;
|
|
70
|
+
children: React.ReactNode;
|
|
71
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
72
|
+
|
|
73
|
+
declare const PageRenderer: () => react_jsx_runtime.JSX.Element | null;
|
|
74
|
+
declare const Stack: ({ rootRoute }: {
|
|
75
|
+
rootRoute: RootRoute;
|
|
76
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
74
77
|
|
|
75
78
|
declare const LocationContext: react.Context<Location | null>;
|
|
76
79
|
|
|
@@ -100,4 +103,21 @@ declare const useRoute: () => RootRoute;
|
|
|
100
103
|
|
|
101
104
|
declare const useRouter: () => RouterContextType;
|
|
102
105
|
|
|
103
|
-
|
|
106
|
+
declare const DefaultTransitionDuration = 300;
|
|
107
|
+
declare const redirect: (options: {
|
|
108
|
+
to: string;
|
|
109
|
+
replace?: boolean;
|
|
110
|
+
}) => Error;
|
|
111
|
+
declare const matchUrl: (pattern: string, url: string) => {
|
|
112
|
+
params: Record<string, string>;
|
|
113
|
+
query: Record<string, string>;
|
|
114
|
+
} | null;
|
|
115
|
+
declare const matchRoute: (rootRoute: RootRoute, url: string) => {
|
|
116
|
+
matches: Route[];
|
|
117
|
+
params: Record<string, string>;
|
|
118
|
+
query: Record<string, string>;
|
|
119
|
+
} | null;
|
|
120
|
+
declare const parseLocationFromHref: (rootRoute: RootRoute, to: string) => Pick<Location, "pathname" | "params" | "query"> | null;
|
|
121
|
+
declare const createRouter: (options: RouterOptions) => RouterOptions;
|
|
122
|
+
|
|
123
|
+
export { DefaultTransitionDuration, LocationContext, LocationProvider, PageRenderer, RouteComponent, RouteContext, RouterContext, type RouterContextType, RouterProvider, Stack, createRouter, matchRoute, matchUrl, parseLocationFromHref, redirect, useLocation, useMatches, useRoute, useRouter };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,66 @@
|
|
|
1
|
+
// src/context/locationContext.ts
|
|
2
|
+
import { createContext } from "react";
|
|
3
|
+
var LocationContext = createContext(null);
|
|
4
|
+
|
|
5
|
+
// src/components/locationProvider.tsx
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
var LocationProvider = ({
|
|
8
|
+
location,
|
|
9
|
+
children
|
|
10
|
+
}) => {
|
|
11
|
+
return /* @__PURE__ */ jsx(LocationContext.Provider, { value: location, children });
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// src/components/routeComponent.tsx
|
|
15
|
+
import { useEffect, useState } from "react";
|
|
16
|
+
|
|
17
|
+
// src/hooks/useRouter.ts
|
|
18
|
+
import { useContext } from "react";
|
|
19
|
+
|
|
20
|
+
// src/context/routerContext.ts
|
|
21
|
+
import { createContext as createContext2 } from "react";
|
|
22
|
+
var RouterContext = createContext2(null);
|
|
23
|
+
|
|
24
|
+
// src/hooks/useRouter.ts
|
|
25
|
+
var useRouter = () => {
|
|
26
|
+
const router = useContext(RouterContext);
|
|
27
|
+
if (router === null) {
|
|
28
|
+
throw new Error("useRouter must be used within a Stack");
|
|
29
|
+
}
|
|
30
|
+
return router;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// src/components/routeComponent.tsx
|
|
34
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
35
|
+
var RouteComponent = ({
|
|
36
|
+
route,
|
|
37
|
+
children
|
|
38
|
+
}) => {
|
|
39
|
+
const router = useRouter();
|
|
40
|
+
const [pending, setPending] = useState(!!route.beforeLoad);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (route.beforeLoad) {
|
|
43
|
+
route.beforeLoad({ location: router.location }).catch((error) => {
|
|
44
|
+
if (error instanceof Error && typeof error.cause === "object" && error.cause !== null && "to" in error.cause) {
|
|
45
|
+
router.navigate({
|
|
46
|
+
to: error.cause.to,
|
|
47
|
+
replace: error.cause.replace
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}).finally(() => setPending(false));
|
|
51
|
+
}
|
|
52
|
+
}, []);
|
|
53
|
+
if (pending) {
|
|
54
|
+
const PendingComponent = route.pendingComponent;
|
|
55
|
+
return /* @__PURE__ */ jsx2(PendingComponent, {});
|
|
56
|
+
}
|
|
57
|
+
const Component = route.component;
|
|
58
|
+
return Component ? /* @__PURE__ */ jsx2(Component, { children }) : children;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// src/components/routerProvider.tsx
|
|
62
|
+
import { useCallback, useEffect as useEffect2, useState as useState2 } from "react";
|
|
63
|
+
|
|
1
64
|
// src/utils.ts
|
|
2
65
|
var DefaultTransitionDuration = 300;
|
|
3
66
|
var redirect = (options) => {
|
|
@@ -79,22 +142,156 @@ var createRouter = (options) => {
|
|
|
79
142
|
return options;
|
|
80
143
|
};
|
|
81
144
|
|
|
82
|
-
// src/
|
|
83
|
-
import {
|
|
84
|
-
var
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
145
|
+
// src/components/routerProvider.tsx
|
|
146
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
147
|
+
var RouterProvider = ({
|
|
148
|
+
router,
|
|
149
|
+
children
|
|
150
|
+
}) => {
|
|
151
|
+
const [history, setHistory] = useState2([]);
|
|
152
|
+
const [currentLocationIndex, setCurrentLocationIndex] = useState2(-1);
|
|
153
|
+
const [isTransitioning, setIsTransitioning] = useState2(false);
|
|
154
|
+
const [transitionDuration, setTransitionDuration] = useState2(
|
|
155
|
+
DefaultTransitionDuration
|
|
156
|
+
);
|
|
157
|
+
const [transitioningToIndex, setTransitioningToIndex] = useState2(null);
|
|
158
|
+
const navigate = useCallback(
|
|
159
|
+
({
|
|
160
|
+
to,
|
|
161
|
+
replace,
|
|
162
|
+
transition,
|
|
163
|
+
duration,
|
|
164
|
+
updateHistory,
|
|
165
|
+
onFinish,
|
|
166
|
+
...locationOptions
|
|
167
|
+
}) => {
|
|
168
|
+
if (isTransitioning) return;
|
|
169
|
+
const newLocationIndex = replace ? currentLocationIndex : currentLocationIndex + 1;
|
|
170
|
+
const newLocation = {
|
|
171
|
+
index: newLocationIndex,
|
|
172
|
+
params: {},
|
|
173
|
+
query: {},
|
|
174
|
+
state: /* @__PURE__ */ new Map(),
|
|
175
|
+
pathname: to,
|
|
176
|
+
...locationOptions
|
|
177
|
+
};
|
|
178
|
+
if (newLocationIndex === history.length) {
|
|
179
|
+
setHistory([...history, newLocation]);
|
|
180
|
+
} else {
|
|
181
|
+
setHistory((prevHistory) => {
|
|
182
|
+
const newHistory = [...prevHistory];
|
|
183
|
+
newHistory[newLocationIndex] = newLocation;
|
|
184
|
+
return newHistory.slice(0, currentLocationIndex + 2);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if (!replace && currentLocationIndex >= 0 && (transition ?? router.defaultViewTransition?.(
|
|
188
|
+
history.at(currentLocationIndex),
|
|
189
|
+
history.at(newLocationIndex)
|
|
190
|
+
))) {
|
|
191
|
+
const currentDuration = duration ?? DefaultTransitionDuration;
|
|
192
|
+
setIsTransitioning(true);
|
|
193
|
+
setTransitionDuration(currentDuration);
|
|
194
|
+
setTransitioningToIndex(newLocationIndex);
|
|
195
|
+
setTimeout(() => {
|
|
196
|
+
setIsTransitioning(false);
|
|
197
|
+
setTransitioningToIndex(null);
|
|
198
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
199
|
+
onFinish?.();
|
|
200
|
+
if (updateHistory) {
|
|
201
|
+
window.history.pushState({}, "", to);
|
|
202
|
+
}
|
|
203
|
+
}, currentDuration);
|
|
204
|
+
} else if (!replace) {
|
|
205
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
206
|
+
if (updateHistory) {
|
|
207
|
+
window.history.pushState({}, "", to);
|
|
208
|
+
}
|
|
209
|
+
} else if (updateHistory) {
|
|
210
|
+
window.history.replaceState({}, "", to);
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
[currentLocationIndex, history, isTransitioning, router]
|
|
214
|
+
);
|
|
215
|
+
useEffect2(() => {
|
|
216
|
+
console.log("Navigate: History updated:", history);
|
|
217
|
+
}, [history]);
|
|
218
|
+
const back = useCallback(
|
|
219
|
+
(options) => {
|
|
220
|
+
if (isTransitioning) return;
|
|
221
|
+
const newLocationIndex = currentLocationIndex - (options?.depth ?? 1);
|
|
222
|
+
if (currentLocationIndex > 0 && (options?.transition ?? router.defaultViewTransition?.(
|
|
223
|
+
history.at(currentLocationIndex),
|
|
224
|
+
history.at(newLocationIndex)
|
|
225
|
+
))) {
|
|
226
|
+
const currentDuration = options?.duration ?? DefaultTransitionDuration;
|
|
227
|
+
setIsTransitioning(true);
|
|
228
|
+
setTransitionDuration(currentDuration);
|
|
229
|
+
setTransitioningToIndex(newLocationIndex);
|
|
230
|
+
setTimeout(() => {
|
|
231
|
+
setIsTransitioning(false);
|
|
232
|
+
setTransitioningToIndex(null);
|
|
233
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
234
|
+
options?.onFinish?.();
|
|
235
|
+
}, currentDuration);
|
|
236
|
+
} else {
|
|
237
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
[currentLocationIndex, history, isTransitioning, router]
|
|
241
|
+
);
|
|
242
|
+
const forward = useCallback(
|
|
243
|
+
(options) => {
|
|
244
|
+
if (isTransitioning) return;
|
|
245
|
+
const newLocationIndex = currentLocationIndex + 1;
|
|
246
|
+
if (newLocationIndex < history.length && (options?.transition ?? router.defaultViewTransition?.(
|
|
247
|
+
history.at(currentLocationIndex),
|
|
248
|
+
history.at(newLocationIndex)
|
|
249
|
+
))) {
|
|
250
|
+
const duration = options?.duration ?? DefaultTransitionDuration;
|
|
251
|
+
setIsTransitioning(true);
|
|
252
|
+
setTransitionDuration(duration);
|
|
253
|
+
setTransitioningToIndex(newLocationIndex);
|
|
254
|
+
setTimeout(() => {
|
|
255
|
+
setIsTransitioning(false);
|
|
256
|
+
setTransitioningToIndex(null);
|
|
257
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
258
|
+
options?.onFinish?.();
|
|
259
|
+
}, duration);
|
|
260
|
+
} else {
|
|
261
|
+
setCurrentLocationIndex(newLocationIndex);
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
[currentLocationIndex, history, isTransitioning, router]
|
|
265
|
+
);
|
|
266
|
+
return /* @__PURE__ */ jsx3(
|
|
267
|
+
RouterContext.Provider,
|
|
268
|
+
{
|
|
269
|
+
value: {
|
|
270
|
+
options: router,
|
|
271
|
+
history,
|
|
272
|
+
currentLocationIndex,
|
|
273
|
+
location: history.at(currentLocationIndex) || null,
|
|
274
|
+
canGoBack: currentLocationIndex > 0,
|
|
275
|
+
canGoForward: currentLocationIndex < history.length - 1,
|
|
276
|
+
isTransitioning,
|
|
277
|
+
transitionDuration,
|
|
278
|
+
transitioningToIndex,
|
|
279
|
+
navigate,
|
|
280
|
+
back,
|
|
281
|
+
forward
|
|
282
|
+
},
|
|
283
|
+
children
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
};
|
|
89
287
|
|
|
90
|
-
// src/
|
|
91
|
-
import {
|
|
92
|
-
var RouterContext = createContext3(null);
|
|
288
|
+
// src/components/stack.tsx
|
|
289
|
+
import { useEffect as useEffect4, useState as useState3 } from "react";
|
|
93
290
|
|
|
94
291
|
// src/hooks/useLocation.ts
|
|
95
|
-
import { useContext } from "react";
|
|
292
|
+
import { useContext as useContext2 } from "react";
|
|
96
293
|
var useLocation = () => {
|
|
97
|
-
const context =
|
|
294
|
+
const context = useContext2(LocationContext);
|
|
98
295
|
if (context === null) {
|
|
99
296
|
throw new Error("useLocation must be used within a LocationProvider");
|
|
100
297
|
}
|
|
@@ -102,9 +299,15 @@ var useLocation = () => {
|
|
|
102
299
|
};
|
|
103
300
|
|
|
104
301
|
// src/hooks/useRoute.ts
|
|
105
|
-
import { useContext as
|
|
302
|
+
import { useContext as useContext3 } from "react";
|
|
303
|
+
|
|
304
|
+
// src/context/routeContext.ts
|
|
305
|
+
import { createContext as createContext3 } from "react";
|
|
306
|
+
var RouteContext = createContext3(null);
|
|
307
|
+
|
|
308
|
+
// src/hooks/useRoute.ts
|
|
106
309
|
var useRoute = () => {
|
|
107
|
-
const route =
|
|
310
|
+
const route = useContext3(RouteContext);
|
|
108
311
|
if (route === null) {
|
|
109
312
|
throw new Error("useRoute must be used within a RouteProvider");
|
|
110
313
|
}
|
|
@@ -119,20 +322,157 @@ var useMatches = () => {
|
|
|
119
322
|
return matchRoute(route, location.pathname)?.matches || [];
|
|
120
323
|
};
|
|
121
324
|
|
|
122
|
-
// src/
|
|
123
|
-
import {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
325
|
+
// src/components/routeProvider.tsx
|
|
326
|
+
import { useEffect as useEffect3 } from "react";
|
|
327
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
328
|
+
var RouteProvider = ({
|
|
329
|
+
rootRoute,
|
|
330
|
+
children
|
|
331
|
+
}) => {
|
|
332
|
+
const router = useRouter();
|
|
333
|
+
useEffect3(() => {
|
|
334
|
+
const currentLocation = parseLocationFromHref(
|
|
335
|
+
rootRoute,
|
|
336
|
+
window.location.href
|
|
337
|
+
);
|
|
338
|
+
if (!currentLocation) return;
|
|
339
|
+
router.navigate({
|
|
340
|
+
to: currentLocation.pathname,
|
|
341
|
+
params: currentLocation.params,
|
|
342
|
+
query: currentLocation.query
|
|
343
|
+
});
|
|
344
|
+
return () => {
|
|
345
|
+
router.back();
|
|
346
|
+
};
|
|
347
|
+
}, []);
|
|
348
|
+
return /* @__PURE__ */ jsx4(RouteContext.Provider, { value: rootRoute, children });
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// src/components/stack.tsx
|
|
352
|
+
import { jsx as jsx5, jsxs } from "react/jsx-runtime";
|
|
353
|
+
var PageRenderer = () => {
|
|
354
|
+
const route = useRoute();
|
|
355
|
+
const matches = useMatches();
|
|
356
|
+
if (!matches || matches.length === 0) {
|
|
357
|
+
const NotFoundComponent = route.notFoundComponent;
|
|
358
|
+
return /* @__PURE__ */ jsx5(NotFoundComponent, {});
|
|
128
359
|
}
|
|
129
|
-
|
|
360
|
+
let content = null;
|
|
361
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
362
|
+
const route2 = matches[i];
|
|
363
|
+
content = /* @__PURE__ */ jsx5(RouteComponent, { route: route2, children: content });
|
|
364
|
+
}
|
|
365
|
+
return content;
|
|
366
|
+
};
|
|
367
|
+
var StackComponent = () => {
|
|
368
|
+
const {
|
|
369
|
+
history,
|
|
370
|
+
currentLocationIndex,
|
|
371
|
+
canGoBack,
|
|
372
|
+
canGoForward,
|
|
373
|
+
isTransitioning,
|
|
374
|
+
transitioningToIndex,
|
|
375
|
+
transitionDuration,
|
|
376
|
+
back,
|
|
377
|
+
forward
|
|
378
|
+
} = useRouter();
|
|
379
|
+
const [isDragging, setIsDragging] = useState3(false);
|
|
380
|
+
const [startX, setStartX] = useState3(0);
|
|
381
|
+
const [dragOffset, setDragOffset] = useState3(0);
|
|
382
|
+
const [isCanceling, setIsCanceling] = useState3(false);
|
|
383
|
+
const [isTransitionStarted, setIsTransitionStarted] = useState3(false);
|
|
384
|
+
useEffect4(() => {
|
|
385
|
+
if (!isTransitioning || transitioningToIndex === null) return;
|
|
386
|
+
setIsTransitionStarted(true);
|
|
387
|
+
setTimeout(() => {
|
|
388
|
+
setIsTransitionStarted(false);
|
|
389
|
+
}, transitionDuration);
|
|
390
|
+
}, [isTransitioning, transitioningToIndex]);
|
|
391
|
+
const reset = () => {
|
|
392
|
+
setIsDragging(false);
|
|
393
|
+
setDragOffset(0);
|
|
394
|
+
setIsCanceling(false);
|
|
395
|
+
};
|
|
396
|
+
const handleTouchStart = (e) => {
|
|
397
|
+
if (isTransitioning || !canGoForward && !canGoBack) return;
|
|
398
|
+
setIsDragging(true);
|
|
399
|
+
setStartX(e.touches[0].clientX);
|
|
400
|
+
};
|
|
401
|
+
const handleTouchMove = (e) => {
|
|
402
|
+
if (!isDragging) return;
|
|
403
|
+
const offset = e.touches[0].clientX - startX;
|
|
404
|
+
if (offset > 0 && currentLocationIndex === 0 || offset < 0 && currentLocationIndex + 1 === history.length) {
|
|
405
|
+
setDragOffset(0);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
setDragOffset(Math.min(window.innerWidth, offset));
|
|
409
|
+
};
|
|
410
|
+
const handleTouchEnd = () => {
|
|
411
|
+
if (!isDragging) return;
|
|
412
|
+
if (dragOffset > window.innerWidth * 0.3 && canGoBack) {
|
|
413
|
+
back({
|
|
414
|
+
onFinish: reset
|
|
415
|
+
});
|
|
416
|
+
} else if (dragOffset < -window.innerWidth * 0.3 && canGoForward) {
|
|
417
|
+
forward({
|
|
418
|
+
onFinish: reset
|
|
419
|
+
});
|
|
420
|
+
} else {
|
|
421
|
+
setIsCanceling(true);
|
|
422
|
+
setTimeout(reset, transitionDuration);
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative inset-0 h-full w-full overflow-hidden", children: [
|
|
426
|
+
currentLocationIndex >= 1 && /* @__PURE__ */ jsx5("div", { className: "absolute inset-0 -z-10", children: /* @__PURE__ */ jsx5(LocationProvider, { location: history.at(currentLocationIndex - 1), children: /* @__PURE__ */ jsx5(PageRenderer, {}, currentLocationIndex - 1) }) }),
|
|
427
|
+
/* @__PURE__ */ jsx5(
|
|
428
|
+
"div",
|
|
429
|
+
{
|
|
430
|
+
className: "bg-background absolute inset-0 overflow-hidden",
|
|
431
|
+
style: {
|
|
432
|
+
transform: isTransitioning && transitioningToIndex !== null && transitioningToIndex < currentLocationIndex ? `translateX(100%)` : isDragging && dragOffset > 0 && !isCanceling ? `translateX(${dragOffset}px)` : "translateX(0px)",
|
|
433
|
+
transition: isCanceling || isTransitioning && transitioningToIndex !== null && transitioningToIndex < currentLocationIndex ? `transform ${transitionDuration}ms ease-out` : "",
|
|
434
|
+
boxShadow: isDragging && dragOffset > 0 ? "-4px 0 8px rgba(0,0,0,0.1)" : "none"
|
|
435
|
+
},
|
|
436
|
+
onTouchStart: handleTouchStart,
|
|
437
|
+
onTouchMove: handleTouchMove,
|
|
438
|
+
onTouchEnd: handleTouchEnd,
|
|
439
|
+
children: /* @__PURE__ */ jsx5(LocationProvider, { location: history.at(currentLocationIndex), children: /* @__PURE__ */ jsx5(PageRenderer, {}, currentLocationIndex) })
|
|
440
|
+
},
|
|
441
|
+
currentLocationIndex
|
|
442
|
+
),
|
|
443
|
+
(isDragging && dragOffset < 0 || isTransitioning && transitioningToIndex !== null && currentLocationIndex < transitioningToIndex) && /* @__PURE__ */ jsx5(
|
|
444
|
+
"div",
|
|
445
|
+
{
|
|
446
|
+
className: "bg-background absolute inset-0 z-10 overflow-hidden transition-transform ease-in",
|
|
447
|
+
style: {
|
|
448
|
+
transform: isTransitionStarted ? `translateX(0px)` : isDragging && !isCanceling ? `translateX(${window.innerWidth + dragOffset}px)` : "translateX(100%)",
|
|
449
|
+
transitionDuration: isTransitioning || isCanceling ? `${transitionDuration}ms` : "0ms"
|
|
450
|
+
},
|
|
451
|
+
children: /* @__PURE__ */ jsx5(
|
|
452
|
+
LocationProvider,
|
|
453
|
+
{
|
|
454
|
+
location: isDragging ? history.at(currentLocationIndex + 1) : history.at(transitioningToIndex),
|
|
455
|
+
children: /* @__PURE__ */ jsx5(PageRenderer, {}, transitioningToIndex)
|
|
456
|
+
}
|
|
457
|
+
)
|
|
458
|
+
},
|
|
459
|
+
transitioningToIndex
|
|
460
|
+
)
|
|
461
|
+
] });
|
|
462
|
+
};
|
|
463
|
+
var Stack = ({ rootRoute }) => {
|
|
464
|
+
return /* @__PURE__ */ jsx5(RouteProvider, { rootRoute, children: /* @__PURE__ */ jsx5(StackComponent, {}) });
|
|
130
465
|
};
|
|
131
466
|
export {
|
|
132
467
|
DefaultTransitionDuration,
|
|
133
468
|
LocationContext,
|
|
469
|
+
LocationProvider,
|
|
470
|
+
PageRenderer,
|
|
471
|
+
RouteComponent,
|
|
134
472
|
RouteContext,
|
|
135
473
|
RouterContext,
|
|
474
|
+
RouterProvider,
|
|
475
|
+
Stack,
|
|
136
476
|
createRouter,
|
|
137
477
|
matchRoute,
|
|
138
478
|
matchUrl,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts","../src/context/locationContext.ts","../src/context/routeContext.ts","../src/context/routerContext.ts","../src/hooks/useLocation.ts","../src/hooks/useRoute.ts","../src/hooks/useMatches.ts","../src/hooks/useRouter.ts"],"sourcesContent":["import type { Location, RootRoute, Route, RouterOptions } from \"./types.js\";\n\nexport const DefaultTransitionDuration = 300;\n\nexport const redirect = (options: { to: string; replace?: boolean }) => {\n return new Error(\"\", { cause: options });\n};\n\nexport const matchUrl = (\n pattern: string,\n url: string\n): { params: Record<string, string>; query: Record<string, string> } | null => {\n try {\n // 解析 URL\n let pathname, searchParams;\n\n if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {\n const urlObj = new URL(url);\n pathname = urlObj.pathname;\n searchParams = urlObj.searchParams;\n } else {\n // 處理相對路徑\n const [path, queryString] = url.split(\"?\");\n if (!path) {\n return null;\n }\n pathname = path;\n searchParams = new URLSearchParams(queryString || \"\");\n }\n\n // 移除路徑首尾的斜線以便比較\n const cleanPath = pathname.replaceAll(/^\\/|\\/$/g, \"\");\n const cleanPattern = pattern.replaceAll(/^\\/|\\/$/g, \"\");\n\n // 分割路徑段\n const pathSegments = cleanPath.split(\"/\");\n const patternSegments = cleanPattern.split(\"/\");\n\n // 路徑段數量不同則不匹配\n if (pathSegments.length !== patternSegments.length) {\n return null;\n }\n\n // 提取路徑參數\n const params: Record<string, string> = {};\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSegment = patternSegments[i];\n const pathSegment = pathSegments[i];\n\n if (patternSegment.startsWith(\":\")) {\n // 動態參數\n const paramName = patternSegment.slice(1);\n params[paramName] = decodeURIComponent(pathSegment);\n } else if (patternSegment !== pathSegment) {\n // 靜態段不匹配\n return null;\n }\n }\n\n // 提取查詢參數\n const query = Object.fromEntries(searchParams.entries());\n\n return { params, query };\n } catch {\n return null;\n }\n};\n\nexport const matchRoute = (\n rootRoute: RootRoute,\n url: string\n): {\n matches: Route[];\n params: Record<string, string>;\n query: Record<string, string>;\n} | null => {\n const _matchRoute = (\n matches: Route[],\n route: Route\n ): {\n matches: Route[];\n params: Record<string, string>;\n query: Record<string, string>;\n } | null => {\n if (route.children) {\n for (const childRoute of route.children) {\n const matchesResult = _matchRoute([...matches, childRoute], childRoute);\n if (matchesResult) {\n return matchesResult;\n }\n }\n return null;\n }\n\n let pattern = \"\";\n for (const match of matches) {\n if (match.pathname === undefined) continue;\n pattern += `/${match.pathname}`;\n }\n const result = matchUrl(pattern, url);\n if (result) {\n return { matches, ...result };\n }\n return null;\n };\n\n return _matchRoute([], rootRoute);\n};\n\nexport const parseLocationFromHref = (\n rootRoute: RootRoute,\n to: string\n): Pick<Location, \"pathname\" | \"params\" | \"query\"> | null => {\n const result = matchRoute(rootRoute, to);\n if (!result) return null;\n return {\n pathname: to,\n params: result.params,\n query: result.query,\n };\n};\n\nexport const createRouter = (options: RouterOptions): RouterOptions => {\n return options;\n};\n","import { createContext } from \"react\";\n\nimport type { Location } from \"@/types.js\";\n\nexport const LocationContext = createContext<Location | null>(null);\n","import { createContext } from \"react\";\n\nimport type { RootRoute } from \"@/types.js\";\n\nexport const RouteContext = createContext<RootRoute | null>(null);\n","import { createContext } from \"react\";\n\nimport type {\n BackOptions,\n ForwardOptions,\n Location,\n NavigateOptions,\n RouterOptions,\n} from \"@/types.js\";\n\nexport interface RouterContextType {\n // Router Config\n options: RouterOptions;\n\n // Navigation State\n history: Location[];\n currentLocationIndex: number;\n location: Location | null;\n canGoBack: boolean;\n canGoForward: boolean;\n\n // Transition state\n isTransitioning: boolean;\n transitionDuration: number;\n transitioningToIndex: number | null;\n\n // Actions\n navigate: (options: NavigateOptions) => void;\n back: (options: BackOptions) => void;\n forward: (options: ForwardOptions) => void;\n}\n\nexport const RouterContext = createContext<RouterContextType | null>(null);\n","import { useContext } from \"react\";\n\nimport { LocationContext } from \"@/context/locationContext.js\";\n\nexport const useLocation = () => {\n const context = useContext(LocationContext);\n if (context === null) {\n throw new Error(\"useLocation must be used within a LocationProvider\");\n }\n return context;\n};\n","import { useContext } from \"react\";\n\nimport { RouteContext } from \"@/context/routeContext.js\";\n\nexport const useRoute = () => {\n const route = useContext(RouteContext);\n if (route === null) {\n throw new Error(\"useRoute must be used within a RouteProvider\");\n }\n return route;\n};\n","import { matchRoute } from \"@/utils.js\";\n\nimport { useLocation } from \"./useLocation.js\";\nimport { useRoute } from \"./useRoute.js\";\n\nexport const useMatches = () => {\n const route = useRoute();\n const location = useLocation();\n if (!location) return [];\n return matchRoute(route, location.pathname)?.matches || [];\n};\n","import { useContext } from \"react\";\n\nimport { RouterContext } from \"@/context/routerContext.js\";\n\nexport const useRouter = () => {\n const router = useContext(RouterContext);\n if (router === null) {\n throw new Error(\"useRouter must be used within a Stack\");\n }\n return router;\n};\n"],"mappings":"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","names":["createContext","createContext","useContext","useContext","useContext","useContext"]}
|
|
1
|
+
{"version":3,"sources":["../src/context/locationContext.ts","../src/components/locationProvider.tsx","../src/components/routeComponent.tsx","../src/hooks/useRouter.ts","../src/context/routerContext.ts","../src/components/routerProvider.tsx","../src/utils.ts","../src/components/stack.tsx","../src/hooks/useLocation.ts","../src/hooks/useRoute.ts","../src/context/routeContext.ts","../src/hooks/useMatches.ts","../src/components/routeProvider.tsx"],"sourcesContent":["import { createContext } from \"react\";\n\nimport type { Location } from \"@/types.js\";\n\nexport const LocationContext = createContext<Location | null>(null);\n","import { LocationContext } from \"@/context/locationContext.js\";\nimport type { Location } from \"@/types.js\";\n\nexport const LocationProvider = ({\n location,\n children,\n}: {\n location: Location;\n children: React.ReactNode;\n}) => {\n return (\n <LocationContext.Provider value={location}>\n {children}\n </LocationContext.Provider>\n );\n};\n","import { useEffect, useState } from \"react\";\n\nimport { useRouter } from \"@/hooks/useRouter.js\";\nimport type { Route } from \"@/types.js\";\n\nexport const RouteComponent = ({\n route,\n children,\n}: {\n route: Route;\n children?: React.ReactNode;\n}) => {\n const router = useRouter();\n const [pending, setPending] = useState(!!route.beforeLoad);\n\n useEffect(() => {\n if (route.beforeLoad) {\n route\n .beforeLoad({ location: router.location! })\n .catch((error: unknown) => {\n if (\n error instanceof Error &&\n typeof error.cause === \"object\" &&\n error.cause !== null &&\n \"to\" in error.cause\n ) {\n router.navigate({\n to: (error.cause as any).to,\n replace: (error.cause as any).replace,\n });\n }\n })\n .finally(() => setPending(false));\n }\n }, []);\n\n if (pending) {\n const PendingComponent = route.pendingComponent!;\n return <PendingComponent />;\n }\n\n const Component = route.component;\n return Component ? <Component>{children}</Component> : children;\n};\n","import { useContext } from \"react\";\n\nimport { RouterContext } from \"@/context/routerContext.js\";\n\nexport const useRouter = () => {\n const router = useContext(RouterContext);\n if (router === null) {\n throw new Error(\"useRouter must be used within a Stack\");\n }\n return router;\n};\n","import { createContext } from \"react\";\n\nimport type {\n BackOptions,\n ForwardOptions,\n Location,\n NavigateOptions,\n RouterOptions,\n} from \"@/types.js\";\n\nexport interface RouterContextType {\n // Router Config\n options: RouterOptions;\n\n // Navigation State\n history: Location[];\n currentLocationIndex: number;\n location: Location | null;\n canGoBack: boolean;\n canGoForward: boolean;\n\n // Transition state\n isTransitioning: boolean;\n transitionDuration: number;\n transitioningToIndex: number | null;\n\n // Actions\n navigate: (options: NavigateOptions) => void;\n back: (options: BackOptions) => void;\n forward: (options: ForwardOptions) => void;\n}\n\nexport const RouterContext = createContext<RouterContextType | null>(null);\n","import { useCallback, useEffect, useState } from \"react\";\n\nimport { RouterContext } from \"@/context/routerContext.js\";\nimport type {\n BackOptions,\n ForwardOptions,\n Location,\n NavigateOptions,\n RouterOptions,\n} from \"@/types.js\";\nimport { DefaultTransitionDuration } from \"@/utils.js\";\n\nexport const RouterProvider = ({\n router,\n children,\n}: {\n router: RouterOptions;\n children: React.ReactNode;\n}) => {\n const [history, setHistory] = useState<Location[]>([]);\n const [currentLocationIndex, setCurrentLocationIndex] = useState<number>(-1);\n const [isTransitioning, setIsTransitioning] = useState<boolean>(false);\n const [transitionDuration, setTransitionDuration] = useState<number>(\n DefaultTransitionDuration\n );\n const [transitioningToIndex, setTransitioningToIndex] = useState<\n number | null\n >(null);\n\n const navigate = useCallback(\n ({\n to,\n replace,\n transition,\n duration,\n updateHistory,\n onFinish,\n ...locationOptions\n }: NavigateOptions) => {\n if (isTransitioning) return;\n const newLocationIndex = replace\n ? currentLocationIndex\n : currentLocationIndex + 1;\n const newLocation: Location = {\n index: newLocationIndex,\n params: {},\n query: {},\n state: new Map(),\n pathname: to,\n ...locationOptions,\n };\n if (newLocationIndex === history.length) {\n setHistory([...history, newLocation]);\n } else {\n setHistory((prevHistory) => {\n const newHistory = [...prevHistory];\n newHistory[newLocationIndex] = newLocation;\n return newHistory.slice(0, currentLocationIndex + 2);\n });\n }\n if (\n !replace &&\n currentLocationIndex >= 0 &&\n (transition ??\n router.defaultViewTransition?.(\n history.at(currentLocationIndex),\n history.at(newLocationIndex)\n ))\n ) {\n const currentDuration = duration ?? DefaultTransitionDuration;\n setIsTransitioning(true);\n setTransitionDuration(currentDuration);\n setTransitioningToIndex(newLocationIndex);\n setTimeout(() => {\n setIsTransitioning(false);\n setTransitioningToIndex(null);\n setCurrentLocationIndex(newLocationIndex);\n onFinish?.();\n if (updateHistory) {\n window.history.pushState({}, \"\", to);\n }\n }, currentDuration);\n } else if (!replace) {\n setCurrentLocationIndex(newLocationIndex);\n if (updateHistory) {\n window.history.pushState({}, \"\", to);\n }\n } else if (updateHistory) {\n window.history.replaceState({}, \"\", to);\n }\n },\n [currentLocationIndex, history, isTransitioning, router]\n );\n\n useEffect(() => {\n console.log(\"Navigate: History updated:\", history);\n }, [history]);\n\n const back = useCallback(\n (options: BackOptions) => {\n if (isTransitioning) return;\n const newLocationIndex = currentLocationIndex - (options?.depth ?? 1);\n if (\n currentLocationIndex > 0 &&\n (options?.transition ??\n router.defaultViewTransition?.(\n history.at(currentLocationIndex),\n history.at(newLocationIndex)\n ))\n ) {\n const currentDuration = options?.duration ?? DefaultTransitionDuration;\n setIsTransitioning(true);\n setTransitionDuration(currentDuration);\n setTransitioningToIndex(newLocationIndex);\n setTimeout(() => {\n setIsTransitioning(false);\n setTransitioningToIndex(null);\n setCurrentLocationIndex(newLocationIndex);\n options?.onFinish?.();\n }, currentDuration);\n } else {\n setCurrentLocationIndex(newLocationIndex);\n }\n },\n [currentLocationIndex, history, isTransitioning, router]\n );\n\n const forward = useCallback(\n (options: ForwardOptions) => {\n if (isTransitioning) return;\n const newLocationIndex = currentLocationIndex + 1;\n if (\n newLocationIndex < history.length &&\n (options?.transition ??\n router.defaultViewTransition?.(\n history.at(currentLocationIndex),\n history.at(newLocationIndex)\n ))\n ) {\n const duration = options?.duration ?? DefaultTransitionDuration;\n setIsTransitioning(true);\n setTransitionDuration(duration);\n setTransitioningToIndex(newLocationIndex);\n setTimeout(() => {\n setIsTransitioning(false);\n setTransitioningToIndex(null);\n setCurrentLocationIndex(newLocationIndex);\n options?.onFinish?.();\n }, duration);\n } else {\n setCurrentLocationIndex(newLocationIndex);\n }\n },\n [currentLocationIndex, history, isTransitioning, router]\n );\n\n return (\n <RouterContext.Provider\n value={{\n options: router,\n\n history,\n currentLocationIndex,\n location: history.at(currentLocationIndex) || null,\n canGoBack: currentLocationIndex > 0,\n canGoForward: currentLocationIndex < history.length - 1,\n\n isTransitioning,\n transitionDuration,\n transitioningToIndex,\n\n navigate,\n back,\n forward,\n }}\n >\n {children}\n </RouterContext.Provider>\n );\n};\n","import type { Location, RootRoute, Route, RouterOptions } from \"./types.js\";\n\nexport const DefaultTransitionDuration = 300;\n\nexport const redirect = (options: { to: string; replace?: boolean }) => {\n return new Error(\"\", { cause: options });\n};\n\nexport const matchUrl = (\n pattern: string,\n url: string\n): { params: Record<string, string>; query: Record<string, string> } | null => {\n try {\n // 解析 URL\n let pathname, searchParams;\n\n if (url.startsWith(\"http://\") || url.startsWith(\"https://\")) {\n const urlObj = new URL(url);\n pathname = urlObj.pathname;\n searchParams = urlObj.searchParams;\n } else {\n // 處理相對路徑\n const [path, queryString] = url.split(\"?\");\n if (!path) {\n return null;\n }\n pathname = path;\n searchParams = new URLSearchParams(queryString || \"\");\n }\n\n // 移除路徑首尾的斜線以便比較\n const cleanPath = pathname.replaceAll(/^\\/|\\/$/g, \"\");\n const cleanPattern = pattern.replaceAll(/^\\/|\\/$/g, \"\");\n\n // 分割路徑段\n const pathSegments = cleanPath.split(\"/\");\n const patternSegments = cleanPattern.split(\"/\");\n\n // 路徑段數量不同則不匹配\n if (pathSegments.length !== patternSegments.length) {\n return null;\n }\n\n // 提取路徑參數\n const params: Record<string, string> = {};\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSegment = patternSegments[i];\n const pathSegment = pathSegments[i];\n\n if (patternSegment.startsWith(\":\")) {\n // 動態參數\n const paramName = patternSegment.slice(1);\n params[paramName] = decodeURIComponent(pathSegment);\n } else if (patternSegment !== pathSegment) {\n // 靜態段不匹配\n return null;\n }\n }\n\n // 提取查詢參數\n const query = Object.fromEntries(searchParams.entries());\n\n return { params, query };\n } catch {\n return null;\n }\n};\n\nexport const matchRoute = (\n rootRoute: RootRoute,\n url: string\n): {\n matches: Route[];\n params: Record<string, string>;\n query: Record<string, string>;\n} | null => {\n const _matchRoute = (\n matches: Route[],\n route: Route\n ): {\n matches: Route[];\n params: Record<string, string>;\n query: Record<string, string>;\n } | null => {\n if (route.children) {\n for (const childRoute of route.children) {\n const matchesResult = _matchRoute([...matches, childRoute], childRoute);\n if (matchesResult) {\n return matchesResult;\n }\n }\n return null;\n }\n\n let pattern = \"\";\n for (const match of matches) {\n if (match.pathname === undefined) continue;\n pattern += `/${match.pathname}`;\n }\n const result = matchUrl(pattern, url);\n if (result) {\n return { matches, ...result };\n }\n return null;\n };\n\n return _matchRoute([], rootRoute);\n};\n\nexport const parseLocationFromHref = (\n rootRoute: RootRoute,\n to: string\n): Pick<Location, \"pathname\" | \"params\" | \"query\"> | null => {\n const result = matchRoute(rootRoute, to);\n if (!result) return null;\n return {\n pathname: to,\n params: result.params,\n query: result.query,\n };\n};\n\nexport const createRouter = (options: RouterOptions): RouterOptions => {\n return options;\n};\n","import { useEffect, useState } from \"react\";\n\nimport { useMatches } from \"@/hooks/useMatches.js\";\nimport { useRoute } from \"@/hooks/useRoute.js\";\nimport { useRouter } from \"@/hooks/useRouter.js\";\nimport type { RootRoute } from \"@/types.js\";\n\nimport { LocationProvider } from \"./locationProvider.js\";\nimport { RouteComponent } from \"./routeComponent.js\";\nimport { RouteProvider } from \"./routeProvider.js\";\n\nexport const PageRenderer = () => {\n const route = useRoute();\n const matches = useMatches();\n if (!matches || matches.length === 0) {\n const NotFoundComponent = route.notFoundComponent!;\n return <NotFoundComponent />;\n }\n let content: React.ReactNode = null;\n for (let i = matches.length - 1; i >= 0; i--) {\n const route = matches[i];\n content = <RouteComponent route={route}>{content}</RouteComponent>;\n }\n return content;\n};\n\nconst StackComponent = () => {\n const {\n history,\n currentLocationIndex,\n canGoBack,\n canGoForward,\n isTransitioning,\n transitioningToIndex,\n transitionDuration,\n back,\n forward,\n } = useRouter();\n\n const [isDragging, setIsDragging] = useState(false);\n const [startX, setStartX] = useState(0);\n const [dragOffset, setDragOffset] = useState(0);\n const [isCanceling, setIsCanceling] = useState(false);\n const [isTransitionStarted, setIsTransitionStarted] = useState(false);\n\n useEffect(() => {\n if (!isTransitioning || transitioningToIndex === null) return;\n setIsTransitionStarted(true);\n setTimeout(() => {\n setIsTransitionStarted(false);\n }, transitionDuration);\n }, [isTransitioning, transitioningToIndex]);\n\n const reset = () => {\n setIsDragging(false);\n setDragOffset(0);\n setIsCanceling(false);\n };\n\n const handleTouchStart = (e: React.TouchEvent) => {\n if (isTransitioning || (!canGoForward && !canGoBack)) return;\n setIsDragging(true);\n setStartX(e.touches[0].clientX);\n };\n\n const handleTouchMove = (e: React.TouchEvent) => {\n if (!isDragging) return;\n const offset = e.touches[0].clientX - startX;\n if (\n (offset > 0 && currentLocationIndex === 0) ||\n (offset < 0 && currentLocationIndex + 1 === history.length)\n ) {\n setDragOffset(0);\n return;\n }\n setDragOffset(Math.min(window.innerWidth, offset));\n };\n\n const handleTouchEnd = () => {\n if (!isDragging) return;\n\n if (dragOffset > window.innerWidth * 0.3 && canGoBack) {\n back({\n onFinish: reset,\n });\n } else if (dragOffset < -window.innerWidth * 0.3 && canGoForward) {\n forward({\n onFinish: reset,\n });\n } else {\n setIsCanceling(true);\n setTimeout(reset, transitionDuration);\n }\n };\n\n return (\n <div className=\"relative inset-0 h-full w-full overflow-hidden\">\n {currentLocationIndex >= 1 && (\n <div className=\"absolute inset-0 -z-10\">\n <LocationProvider location={history.at(currentLocationIndex - 1)!}>\n <PageRenderer key={currentLocationIndex - 1} />\n </LocationProvider>\n </div>\n )}\n <div\n key={currentLocationIndex}\n className=\"bg-background absolute inset-0 overflow-hidden\"\n style={{\n transform:\n isTransitioning &&\n transitioningToIndex !== null &&\n transitioningToIndex < currentLocationIndex\n ? `translateX(100%)`\n : isDragging && dragOffset > 0 && !isCanceling\n ? `translateX(${dragOffset}px)`\n : \"translateX(0px)\",\n transition:\n isCanceling ||\n (isTransitioning &&\n transitioningToIndex !== null &&\n transitioningToIndex < currentLocationIndex)\n ? `transform ${transitionDuration}ms ease-out`\n : \"\",\n boxShadow:\n isDragging && dragOffset > 0\n ? \"-4px 0 8px rgba(0,0,0,0.1)\"\n : \"none\",\n }}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n <LocationProvider location={history.at(currentLocationIndex)!}>\n <PageRenderer key={currentLocationIndex} />\n </LocationProvider>\n </div>\n {((isDragging && dragOffset < 0) ||\n (isTransitioning &&\n transitioningToIndex !== null &&\n currentLocationIndex < transitioningToIndex)) && (\n <div\n key={transitioningToIndex}\n className=\"bg-background absolute inset-0 z-10 overflow-hidden transition-transform ease-in\"\n style={{\n transform: isTransitionStarted\n ? `translateX(0px)`\n : isDragging && !isCanceling\n ? `translateX(${window.innerWidth + dragOffset}px)`\n : \"translateX(100%)\",\n transitionDuration:\n isTransitioning || isCanceling\n ? `${transitionDuration}ms`\n : \"0ms\",\n }}\n >\n <LocationProvider\n location={\n isDragging\n ? history.at(currentLocationIndex + 1)!\n : history.at(transitioningToIndex!)!\n }\n >\n <PageRenderer key={transitioningToIndex} />\n </LocationProvider>\n </div>\n )}\n </div>\n );\n};\n\nexport const Stack = ({ rootRoute }: { rootRoute: RootRoute }) => {\n return (\n <RouteProvider rootRoute={rootRoute}>\n <StackComponent />\n </RouteProvider>\n );\n};\n","import { useContext } from \"react\";\n\nimport { LocationContext } from \"@/context/locationContext.js\";\n\nexport const useLocation = () => {\n const context = useContext(LocationContext);\n if (context === null) {\n throw new Error(\"useLocation must be used within a LocationProvider\");\n }\n return context;\n};\n","import { useContext } from \"react\";\n\nimport { RouteContext } from \"@/context/routeContext.js\";\n\nexport const useRoute = () => {\n const route = useContext(RouteContext);\n if (route === null) {\n throw new Error(\"useRoute must be used within a RouteProvider\");\n }\n return route;\n};\n","import { createContext } from \"react\";\n\nimport type { RootRoute } from \"@/types.js\";\n\nexport const RouteContext = createContext<RootRoute | null>(null);\n","import { matchRoute } from \"@/utils.js\";\n\nimport { useLocation } from \"./useLocation.js\";\nimport { useRoute } from \"./useRoute.js\";\n\nexport const useMatches = () => {\n const route = useRoute();\n const location = useLocation();\n if (!location) return [];\n return matchRoute(route, location.pathname)?.matches || [];\n};\n","import { useEffect } from \"react\";\n\nimport { RouteContext } from \"@/context/routeContext.js\";\nimport { useRouter } from \"@/hooks/useRouter.js\";\nimport type { RootRoute } from \"@/types.js\";\nimport { parseLocationFromHref } from \"@/utils.js\";\n\nexport const RouteProvider = ({\n rootRoute,\n children,\n}: {\n rootRoute: RootRoute;\n children: React.ReactNode;\n}) => {\n const router = useRouter();\n\n useEffect(() => {\n const currentLocation = parseLocationFromHref(\n rootRoute,\n window.location.href\n );\n if (!currentLocation) return;\n router.navigate({\n to: currentLocation.pathname,\n params: currentLocation.params,\n query: currentLocation.query,\n });\n return () => {\n router.back();\n };\n }, []);\n\n return (\n <RouteContext.Provider value={rootRoute}>{children}</RouteContext.Provider>\n );\n};\n"],"mappings":"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","names":["createContext","jsx","useEffect","useState","jsx","useState","useEffect","useEffect","useState","useContext","useContext","useContext","createContext","useContext","useEffect","jsx","useEffect","jsx","route","useState","useEffect"]}
|