@rezahasani78/sheet-router 0.1.0
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 +364 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +45 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +358 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +54 -0
- package/package.json +56 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
9
|
+
|
|
10
|
+
// src/lib/sheet-stack-manager.ts
|
|
11
|
+
var SheetStackManager = class {
|
|
12
|
+
constructor() {
|
|
13
|
+
__publicField(this, "stack", []);
|
|
14
|
+
__publicField(this, "listeners", /* @__PURE__ */ new Set());
|
|
15
|
+
__publicField(this, "snapshot", []);
|
|
16
|
+
}
|
|
17
|
+
push(entry) {
|
|
18
|
+
this.stack.push(entry);
|
|
19
|
+
this.updateSnapshot();
|
|
20
|
+
this.notify();
|
|
21
|
+
}
|
|
22
|
+
pop() {
|
|
23
|
+
const entry = this.stack.pop();
|
|
24
|
+
if (entry) {
|
|
25
|
+
this.updateSnapshot();
|
|
26
|
+
this.notify();
|
|
27
|
+
}
|
|
28
|
+
return entry;
|
|
29
|
+
}
|
|
30
|
+
popAll() {
|
|
31
|
+
if (this.stack.length === 0) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
this.stack.length = 0;
|
|
35
|
+
this.updateSnapshot();
|
|
36
|
+
this.notify();
|
|
37
|
+
}
|
|
38
|
+
peek() {
|
|
39
|
+
return this.stack[this.stack.length - 1];
|
|
40
|
+
}
|
|
41
|
+
getSnapshot() {
|
|
42
|
+
return this.snapshot;
|
|
43
|
+
}
|
|
44
|
+
get size() {
|
|
45
|
+
return this.stack.length;
|
|
46
|
+
}
|
|
47
|
+
get isEmpty() {
|
|
48
|
+
return this.stack.length === 0;
|
|
49
|
+
}
|
|
50
|
+
hasPath(path) {
|
|
51
|
+
return this.stack.some((entry) => entry.path === path);
|
|
52
|
+
}
|
|
53
|
+
subscribe(listener) {
|
|
54
|
+
this.listeners.add(listener);
|
|
55
|
+
return () => {
|
|
56
|
+
this.listeners.delete(listener);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
updateSnapshot() {
|
|
60
|
+
this.snapshot = [...this.stack];
|
|
61
|
+
}
|
|
62
|
+
notify() {
|
|
63
|
+
this.listeners.forEach((listener) => listener());
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// src/lib/history-manager.ts
|
|
68
|
+
function isSheetHistoryState(state) {
|
|
69
|
+
return typeof state === "object" && state !== null && "__sheetRouter" in state && state.__sheetRouter === true;
|
|
70
|
+
}
|
|
71
|
+
var HistoryManager = class {
|
|
72
|
+
constructor() {
|
|
73
|
+
__publicField(this, "subscribers", /* @__PURE__ */ new Set());
|
|
74
|
+
__publicField(this, "handlePopState");
|
|
75
|
+
this.handlePopState = (event) => {
|
|
76
|
+
if (isSheetHistoryState(event.state)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.notifyBack();
|
|
80
|
+
};
|
|
81
|
+
window.addEventListener("popstate", this.handlePopState);
|
|
82
|
+
}
|
|
83
|
+
pushState(entryId) {
|
|
84
|
+
const state = { __sheetRouter: true, entryId };
|
|
85
|
+
window.history.pushState(state, "", window.location.href);
|
|
86
|
+
}
|
|
87
|
+
goBack(count = 1) {
|
|
88
|
+
if (count > 0) {
|
|
89
|
+
window.history.go(-count);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
subscribe(onBack) {
|
|
93
|
+
this.subscribers.add(onBack);
|
|
94
|
+
return () => {
|
|
95
|
+
this.subscribers.delete(onBack);
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
destroy() {
|
|
99
|
+
window.removeEventListener("popstate", this.handlePopState);
|
|
100
|
+
this.subscribers.clear();
|
|
101
|
+
}
|
|
102
|
+
notifyBack() {
|
|
103
|
+
this.subscribers.forEach((handler) => handler());
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// src/lib/back-navigation-mediator.ts
|
|
108
|
+
var idCounter = 0;
|
|
109
|
+
function generateEntryId() {
|
|
110
|
+
idCounter += 1;
|
|
111
|
+
return `sheet-${idCounter}-${Date.now()}`;
|
|
112
|
+
}
|
|
113
|
+
var BackNavigationMediator = class {
|
|
114
|
+
constructor(sheetStack, historyManager) {
|
|
115
|
+
__publicField(this, "sheetStack");
|
|
116
|
+
__publicField(this, "historyManager");
|
|
117
|
+
__publicField(this, "unsubscribeHistory");
|
|
118
|
+
__publicField(this, "programmaticNavigation", 0);
|
|
119
|
+
this.sheetStack = sheetStack;
|
|
120
|
+
this.historyManager = historyManager;
|
|
121
|
+
this.unsubscribeHistory = this.historyManager.subscribe(() => {
|
|
122
|
+
this.handleBack();
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
open(path, params = {}) {
|
|
126
|
+
const entry = {
|
|
127
|
+
id: generateEntryId(),
|
|
128
|
+
path,
|
|
129
|
+
params
|
|
130
|
+
};
|
|
131
|
+
this.sheetStack.push(entry);
|
|
132
|
+
this.historyManager.pushState(entry.id);
|
|
133
|
+
}
|
|
134
|
+
back() {
|
|
135
|
+
if (this.sheetStack.isEmpty) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this.sheetStack.pop();
|
|
139
|
+
this.programmaticNavigation += 1;
|
|
140
|
+
this.historyManager.goBack(1);
|
|
141
|
+
}
|
|
142
|
+
backAll() {
|
|
143
|
+
const count = this.sheetStack.size;
|
|
144
|
+
if (count === 0) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
this.sheetStack.popAll();
|
|
148
|
+
this.programmaticNavigation += 1;
|
|
149
|
+
this.historyManager.goBack(count);
|
|
150
|
+
}
|
|
151
|
+
isOpen(path) {
|
|
152
|
+
return this.sheetStack.hasPath(path);
|
|
153
|
+
}
|
|
154
|
+
get stack() {
|
|
155
|
+
return this.sheetStack;
|
|
156
|
+
}
|
|
157
|
+
destroy() {
|
|
158
|
+
this.unsubscribeHistory();
|
|
159
|
+
this.historyManager.destroy();
|
|
160
|
+
}
|
|
161
|
+
handleBack() {
|
|
162
|
+
if (this.programmaticNavigation > 0) {
|
|
163
|
+
this.programmaticNavigation -= 1;
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
this.sheetStack.pop();
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
var SheetRouterContext = react.createContext(null);
|
|
170
|
+
function useSheetRouterContext() {
|
|
171
|
+
const context = react.useContext(SheetRouterContext);
|
|
172
|
+
if (!context) {
|
|
173
|
+
throw new Error(
|
|
174
|
+
"Sheet router hooks must be used within a <SheetRouter> provider."
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
return context;
|
|
178
|
+
}
|
|
179
|
+
var SheetParamsContext = react.createContext(null);
|
|
180
|
+
function useSheetParamsContext() {
|
|
181
|
+
const context = react.useContext(SheetParamsContext);
|
|
182
|
+
if (!context) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
"useSheetParams must be used inside a sheet rendered by <SheetRouter>."
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
return context;
|
|
188
|
+
}
|
|
189
|
+
function BottomSheet({
|
|
190
|
+
open,
|
|
191
|
+
behind,
|
|
192
|
+
zIndex,
|
|
193
|
+
onClose,
|
|
194
|
+
title,
|
|
195
|
+
children
|
|
196
|
+
}) {
|
|
197
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
198
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
199
|
+
"div",
|
|
200
|
+
{
|
|
201
|
+
className: "sr-backdrop",
|
|
202
|
+
"data-open": open,
|
|
203
|
+
style: { zIndex },
|
|
204
|
+
onClick: onClose,
|
|
205
|
+
role: "presentation"
|
|
206
|
+
}
|
|
207
|
+
),
|
|
208
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
209
|
+
"div",
|
|
210
|
+
{
|
|
211
|
+
className: "sr-sheet",
|
|
212
|
+
"data-open": open,
|
|
213
|
+
"data-behind": behind,
|
|
214
|
+
style: { zIndex: zIndex + 1 },
|
|
215
|
+
role: "dialog",
|
|
216
|
+
"aria-modal": "true",
|
|
217
|
+
"aria-label": title,
|
|
218
|
+
children: [
|
|
219
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sr-handle", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sr-handle-bar" }) }),
|
|
220
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sr-content", children })
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
)
|
|
224
|
+
] });
|
|
225
|
+
}
|
|
226
|
+
var BASE_Z_INDEX = 1e3;
|
|
227
|
+
function SheetOutlet() {
|
|
228
|
+
const { stack, routes, mediator } = useSheetRouterContext();
|
|
229
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: stack.map((entry, index) => {
|
|
230
|
+
const route = routes.get(entry.path);
|
|
231
|
+
if (!route) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
const isTop = index === stack.length - 1;
|
|
235
|
+
const isBehind = !isTop;
|
|
236
|
+
const zIndex = BASE_Z_INDEX + index * 2;
|
|
237
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
238
|
+
BottomSheet,
|
|
239
|
+
{
|
|
240
|
+
open: true,
|
|
241
|
+
behind: isBehind,
|
|
242
|
+
zIndex,
|
|
243
|
+
onClose: () => mediator.back(),
|
|
244
|
+
title: route.title ?? route.path,
|
|
245
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
246
|
+
SheetParamsContext.Provider,
|
|
247
|
+
{
|
|
248
|
+
value: { path: entry.path, params: entry.params },
|
|
249
|
+
children: react.createElement(route.component)
|
|
250
|
+
}
|
|
251
|
+
)
|
|
252
|
+
},
|
|
253
|
+
entry.id
|
|
254
|
+
);
|
|
255
|
+
}) });
|
|
256
|
+
}
|
|
257
|
+
function isSheetRouteElement(child) {
|
|
258
|
+
return react.isValidElement(child) && typeof child.type === "function" && "__isSheetRoute" in child.type;
|
|
259
|
+
}
|
|
260
|
+
function collectRoutes(children) {
|
|
261
|
+
const routes = /* @__PURE__ */ new Map();
|
|
262
|
+
react.Children.forEach(children, (child) => {
|
|
263
|
+
if (isSheetRouteElement(child)) {
|
|
264
|
+
const { path, component, title } = child.props;
|
|
265
|
+
routes.set(path, { path, component, title });
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
return routes;
|
|
269
|
+
}
|
|
270
|
+
function collectBaseContent(children) {
|
|
271
|
+
const base = [];
|
|
272
|
+
react.Children.forEach(children, (child) => {
|
|
273
|
+
if (!isSheetRouteElement(child)) {
|
|
274
|
+
base.push(child);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
return base;
|
|
278
|
+
}
|
|
279
|
+
function SheetRouter({ children }) {
|
|
280
|
+
const mediator = react.useMemo(() => {
|
|
281
|
+
const stack2 = new SheetStackManager();
|
|
282
|
+
const history = new HistoryManager();
|
|
283
|
+
return new BackNavigationMediator(stack2, history);
|
|
284
|
+
}, []);
|
|
285
|
+
react.useEffect(() => {
|
|
286
|
+
return () => {
|
|
287
|
+
mediator.destroy();
|
|
288
|
+
};
|
|
289
|
+
}, [mediator]);
|
|
290
|
+
const routes = react.useMemo(() => collectRoutes(children), [children]);
|
|
291
|
+
const baseContent = react.useMemo(() => collectBaseContent(children), [children]);
|
|
292
|
+
const stack = react.useSyncExternalStore(
|
|
293
|
+
(callback) => mediator.stack.subscribe(callback),
|
|
294
|
+
() => mediator.stack.getSnapshot()
|
|
295
|
+
);
|
|
296
|
+
const contextValue = react.useMemo(
|
|
297
|
+
() => ({ mediator, routes, stack }),
|
|
298
|
+
[mediator, routes, stack]
|
|
299
|
+
);
|
|
300
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(SheetRouterContext.Provider, { value: contextValue, children: [
|
|
301
|
+
baseContent,
|
|
302
|
+
/* @__PURE__ */ jsxRuntime.jsx(SheetOutlet, {})
|
|
303
|
+
] });
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// src/components/sheet-route.tsx
|
|
307
|
+
function SheetRoute(_props) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
SheetRoute.__isSheetRoute = true;
|
|
311
|
+
function useSheetNavigate() {
|
|
312
|
+
const { mediator } = useSheetRouterContext();
|
|
313
|
+
const open = react.useCallback(
|
|
314
|
+
(path, params) => {
|
|
315
|
+
mediator.open(path, params);
|
|
316
|
+
},
|
|
317
|
+
[mediator]
|
|
318
|
+
);
|
|
319
|
+
const back = react.useCallback(() => {
|
|
320
|
+
mediator.back();
|
|
321
|
+
}, [mediator]);
|
|
322
|
+
const backAll = react.useCallback(() => {
|
|
323
|
+
mediator.backAll();
|
|
324
|
+
}, [mediator]);
|
|
325
|
+
const isOpen = react.useCallback(
|
|
326
|
+
(path) => mediator.isOpen(path),
|
|
327
|
+
[mediator]
|
|
328
|
+
);
|
|
329
|
+
return react.useMemo(
|
|
330
|
+
() => ({ open, back, backAll, isOpen }),
|
|
331
|
+
[open, back, backAll, isOpen]
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/hooks/use-sheet-params.ts
|
|
336
|
+
function useSheetParams() {
|
|
337
|
+
const context = useSheetParamsContext();
|
|
338
|
+
return {
|
|
339
|
+
path: context.path,
|
|
340
|
+
params: context.params
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
function useBeforeUnload(enabled) {
|
|
344
|
+
react.useEffect(() => {
|
|
345
|
+
if (!enabled) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const handler = (event) => {
|
|
349
|
+
event.preventDefault();
|
|
350
|
+
};
|
|
351
|
+
window.addEventListener("beforeunload", handler);
|
|
352
|
+
return () => {
|
|
353
|
+
window.removeEventListener("beforeunload", handler);
|
|
354
|
+
};
|
|
355
|
+
}, [enabled]);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
exports.SheetRoute = SheetRoute;
|
|
359
|
+
exports.SheetRouter = SheetRouter;
|
|
360
|
+
exports.useBeforeUnload = useBeforeUnload;
|
|
361
|
+
exports.useSheetNavigate = useSheetNavigate;
|
|
362
|
+
exports.useSheetParams = useSheetParams;
|
|
363
|
+
//# sourceMappingURL=index.cjs.map
|
|
364
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/sheet-stack-manager.ts","../src/lib/history-manager.ts","../src/lib/back-navigation-mediator.ts","../src/context/sheet-router-context.ts","../src/context/sheet-params-context.ts","../src/components/bottom-sheet/index.tsx","../src/components/sheet-outlet.tsx","../src/components/sheet-router.tsx","../src/components/sheet-route.tsx","../src/hooks/use-sheet-navigate.ts","../src/hooks/use-sheet-params.ts","../src/hooks/use-before-unload.ts"],"names":["createContext","useContext","jsxs","Fragment","jsx","createElement","isValidElement","Children","useMemo","stack","useEffect","useSyncExternalStore","useCallback"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { StackEntry, Listener } from \"../types\";\n\nclass SheetStackManager {\n private stack: StackEntry[] = [];\n private listeners = new Set<Listener>();\n private snapshot: readonly StackEntry[] = [];\n\n push(entry: StackEntry): void {\n this.stack.push(entry);\n this.updateSnapshot();\n this.notify();\n }\n\n pop(): StackEntry | undefined {\n const entry = this.stack.pop();\n if (entry) {\n this.updateSnapshot();\n this.notify();\n }\n return entry;\n }\n\n popAll(): void {\n if (this.stack.length === 0) {\n return;\n }\n this.stack.length = 0;\n this.updateSnapshot();\n this.notify();\n }\n\n peek(): StackEntry | undefined {\n return this.stack[this.stack.length - 1];\n }\n\n getSnapshot(): readonly StackEntry[] {\n return this.snapshot;\n }\n\n get size(): number {\n return this.stack.length;\n }\n\n get isEmpty(): boolean {\n return this.stack.length === 0;\n }\n\n hasPath(path: string): boolean {\n return this.stack.some((entry) => entry.path === path);\n }\n\n subscribe(listener: Listener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private updateSnapshot(): void {\n this.snapshot = [...this.stack];\n }\n\n private notify(): void {\n this.listeners.forEach((listener) => listener());\n }\n}\n\nexport { SheetStackManager };\n","import type { BackHandler } from \"../types\";\n\ninterface SheetHistoryState {\n __sheetRouter: true;\n entryId: string;\n}\n\nfunction isSheetHistoryState(state: unknown): state is SheetHistoryState {\n return (\n typeof state === \"object\" &&\n state !== null &&\n \"__sheetRouter\" in state &&\n (state as SheetHistoryState).__sheetRouter === true\n );\n}\n\nclass HistoryManager {\n private subscribers = new Set<BackHandler>();\n private handlePopState: (event: PopStateEvent) => void;\n\n constructor() {\n this.handlePopState = (event: PopStateEvent) => {\n if (isSheetHistoryState(event.state)) {\n return;\n }\n this.notifyBack();\n };\n window.addEventListener(\"popstate\", this.handlePopState);\n }\n\n pushState(entryId: string): void {\n const state: SheetHistoryState = { __sheetRouter: true, entryId };\n window.history.pushState(state, \"\", window.location.href);\n }\n\n goBack(count: number = 1): void {\n if (count > 0) {\n window.history.go(-count);\n }\n }\n\n subscribe(onBack: BackHandler): () => void {\n this.subscribers.add(onBack);\n return () => {\n this.subscribers.delete(onBack);\n };\n }\n\n destroy(): void {\n window.removeEventListener(\"popstate\", this.handlePopState);\n this.subscribers.clear();\n }\n\n private notifyBack(): void {\n this.subscribers.forEach((handler) => handler());\n }\n}\n\nexport { HistoryManager };\n","import type { StackEntry } from \"../types\";\nimport { SheetStackManager } from \"./sheet-stack-manager\";\nimport { HistoryManager } from \"./history-manager\";\n\nlet idCounter = 0;\n\nfunction generateEntryId(): string {\n idCounter += 1;\n return `sheet-${idCounter}-${Date.now()}`;\n}\n\nclass BackNavigationMediator {\n private sheetStack: SheetStackManager;\n private historyManager: HistoryManager;\n private unsubscribeHistory: () => void;\n private programmaticNavigation = 0;\n\n constructor(\n sheetStack: SheetStackManager,\n historyManager: HistoryManager,\n ) {\n this.sheetStack = sheetStack;\n this.historyManager = historyManager;\n\n this.unsubscribeHistory = this.historyManager.subscribe(() => {\n this.handleBack();\n });\n }\n\n open(path: string, params: Record<string, unknown> = {}): void {\n const entry: StackEntry = {\n id: generateEntryId(),\n path,\n params,\n };\n this.sheetStack.push(entry);\n this.historyManager.pushState(entry.id);\n }\n\n back(): void {\n if (this.sheetStack.isEmpty) {\n return;\n }\n this.sheetStack.pop();\n this.programmaticNavigation += 1;\n this.historyManager.goBack(1);\n }\n\n backAll(): void {\n const count = this.sheetStack.size;\n if (count === 0) {\n return;\n }\n this.sheetStack.popAll();\n this.programmaticNavigation += 1;\n this.historyManager.goBack(count);\n }\n\n isOpen(path: string): boolean {\n return this.sheetStack.hasPath(path);\n }\n\n get stack(): SheetStackManager {\n return this.sheetStack;\n }\n\n destroy(): void {\n this.unsubscribeHistory();\n this.historyManager.destroy();\n }\n\n private handleBack(): void {\n if (this.programmaticNavigation > 0) {\n this.programmaticNavigation -= 1;\n return;\n }\n this.sheetStack.pop();\n }\n}\n\nexport { BackNavigationMediator };\n","import { createContext, useContext } from \"react\";\nimport type { RouteDefinition, StackEntry } from \"../types\";\nimport type { BackNavigationMediator } from \"../lib/back-navigation-mediator\";\n\ninterface SheetRouterContextValue {\n mediator: BackNavigationMediator;\n routes: Map<string, RouteDefinition>;\n stack: readonly StackEntry[];\n}\n\nconst SheetRouterContext = createContext<SheetRouterContextValue | null>(null);\n\nfunction useSheetRouterContext(): SheetRouterContextValue {\n const context = useContext(SheetRouterContext);\n if (!context) {\n throw new Error(\n \"Sheet router hooks must be used within a <SheetRouter> provider.\",\n );\n }\n return context;\n}\n\nexport { SheetRouterContext, useSheetRouterContext };\nexport type { SheetRouterContextValue };\n","import { createContext, useContext } from \"react\";\n\ninterface SheetParamsContextValue {\n path: string;\n params: Record<string, unknown>;\n}\n\nconst SheetParamsContext = createContext<SheetParamsContextValue | null>(null);\n\nfunction useSheetParamsContext(): SheetParamsContextValue {\n const context = useContext(SheetParamsContext);\n if (!context) {\n throw new Error(\n \"useSheetParams must be used inside a sheet rendered by <SheetRouter>.\",\n );\n }\n return context;\n}\n\nexport { SheetParamsContext, useSheetParamsContext };\nexport type { SheetParamsContextValue };\n","import type { ReactNode } from \"react\";\n\ninterface BottomSheetProps {\n open: boolean;\n behind: boolean;\n zIndex: number;\n onClose: () => void;\n title: string;\n children: ReactNode;\n}\n\nfunction BottomSheet({\n open,\n behind,\n zIndex,\n onClose,\n title,\n children,\n}: BottomSheetProps) {\n return (\n <>\n <div\n className=\"sr-backdrop\"\n data-open={open}\n style={{ zIndex }}\n onClick={onClose}\n role=\"presentation\"\n />\n <div\n className=\"sr-sheet\"\n data-open={open}\n data-behind={behind}\n style={{ zIndex: zIndex + 1 }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div className=\"sr-handle\">\n <div className=\"sr-handle-bar\" />\n </div>\n <div className=\"sr-content\">{children}</div>\n </div>\n </>\n );\n}\n\nexport { BottomSheet };\nexport type { BottomSheetProps };\n","import { createElement } from \"react\";\nimport { useSheetRouterContext } from \"../context/sheet-router-context\";\nimport { SheetParamsContext } from \"../context/sheet-params-context\";\nimport { BottomSheet } from \"./bottom-sheet\";\n\nconst BASE_Z_INDEX = 1000;\n\nfunction SheetOutlet() {\n const { stack, routes, mediator } = useSheetRouterContext();\n\n return (\n <>\n {stack.map((entry, index) => {\n const route = routes.get(entry.path);\n if (!route) {\n return null;\n }\n\n const isTop = index === stack.length - 1;\n const isBehind = !isTop;\n const zIndex = BASE_Z_INDEX + index * 2;\n\n return (\n <BottomSheet\n key={entry.id}\n open={true}\n behind={isBehind}\n zIndex={zIndex}\n onClose={() => mediator.back()}\n title={route.title ?? route.path}\n >\n <SheetParamsContext.Provider\n value={{ path: entry.path, params: entry.params }}\n >\n {createElement(route.component)}\n </SheetParamsContext.Provider>\n </BottomSheet>\n );\n })}\n </>\n );\n}\n\nexport { SheetOutlet };\n","import {\n Children,\n isValidElement,\n useEffect,\n useMemo,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\";\nimport type { RouteDefinition, SheetRouteProps, StackEntry } from \"../types\";\nimport { SheetStackManager } from \"../lib/sheet-stack-manager\";\nimport { HistoryManager } from \"../lib/history-manager\";\nimport { BackNavigationMediator } from \"../lib/back-navigation-mediator\";\nimport { SheetRouterContext } from \"../context/sheet-router-context\";\nimport { SheetOutlet } from \"./sheet-outlet\";\n\ninterface SheetRouterProps {\n children: ReactNode;\n}\n\nfunction isSheetRouteElement(\n child: ReactNode,\n): child is React.ReactElement<SheetRouteProps> {\n return (\n isValidElement(child) &&\n typeof child.type === \"function\" &&\n \"__isSheetRoute\" in child.type\n );\n}\n\nfunction collectRoutes(children: ReactNode): Map<string, RouteDefinition> {\n const routes = new Map<string, RouteDefinition>();\n\n Children.forEach(children, (child) => {\n if (isSheetRouteElement(child)) {\n const { path, component, title } = child.props;\n routes.set(path, { path, component, title });\n }\n });\n\n return routes;\n}\n\nfunction collectBaseContent(children: ReactNode): ReactNode[] {\n const base: ReactNode[] = [];\n\n Children.forEach(children, (child) => {\n if (!isSheetRouteElement(child)) {\n base.push(child);\n }\n });\n\n return base;\n}\n\nfunction SheetRouter({ children }: SheetRouterProps) {\n const mediator = useMemo(() => {\n const stack = new SheetStackManager();\n const history = new HistoryManager();\n return new BackNavigationMediator(stack, history);\n }, []);\n\n useEffect(() => {\n return () => {\n mediator.destroy();\n };\n }, [mediator]);\n\n const routes = useMemo(() => collectRoutes(children), [children]);\n const baseContent = useMemo(() => collectBaseContent(children), [children]);\n\n const stack: readonly StackEntry[] = useSyncExternalStore(\n (callback) => mediator.stack.subscribe(callback),\n () => mediator.stack.getSnapshot(),\n );\n\n const contextValue = useMemo(\n () => ({ mediator, routes, stack }),\n [mediator, routes, stack],\n );\n\n return (\n <SheetRouterContext.Provider value={contextValue}>\n {baseContent}\n <SheetOutlet />\n </SheetRouterContext.Provider>\n );\n}\n\nexport { SheetRouter };\n","import type { SheetRouteProps } from \"../types\";\n\nfunction SheetRoute(_props: SheetRouteProps): null {\n return null;\n}\n\nSheetRoute.__isSheetRoute = true;\n\nexport { SheetRoute };\n","import { useCallback, useMemo } from \"react\";\nimport type { SheetNavigator } from \"../types\";\nimport { useSheetRouterContext } from \"../context/sheet-router-context\";\n\nfunction useSheetNavigate(): SheetNavigator {\n const { mediator } = useSheetRouterContext();\n\n const open = useCallback(\n (path: string, params?: Record<string, unknown>) => {\n mediator.open(path, params);\n },\n [mediator],\n );\n\n const back = useCallback(() => {\n mediator.back();\n }, [mediator]);\n\n const backAll = useCallback(() => {\n mediator.backAll();\n }, [mediator]);\n\n const isOpen = useCallback(\n (path: string) => mediator.isOpen(path),\n [mediator],\n );\n\n return useMemo(\n () => ({ open, back, backAll, isOpen }),\n [open, back, backAll, isOpen],\n );\n}\n\nexport { useSheetNavigate };\n","import { useSheetParamsContext } from \"../context/sheet-params-context\";\n\nfunction useSheetParams<\n T extends Record<string, unknown> = Record<string, unknown>,\n>(): { path: string; params: T } {\n const context = useSheetParamsContext();\n return {\n path: context.path,\n params: context.params as T,\n };\n}\n\nexport { useSheetParams };\n","import { useEffect } from \"react\";\n\nfunction useBeforeUnload(enabled: boolean) {\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n const handler = (event: BeforeUnloadEvent) => {\n event.preventDefault();\n };\n\n window.addEventListener(\"beforeunload\", handler);\n return () => {\n window.removeEventListener(\"beforeunload\", handler);\n };\n }, [enabled]);\n}\n\nexport { useBeforeUnload };\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, ComponentType } from 'react';
|
|
3
|
+
|
|
4
|
+
interface SheetRouterProps {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
declare function SheetRouter({ children }: SheetRouterProps): react_jsx_runtime.JSX.Element;
|
|
8
|
+
|
|
9
|
+
interface StackEntry {
|
|
10
|
+
id: string;
|
|
11
|
+
path: string;
|
|
12
|
+
params: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
interface RouteDefinition {
|
|
15
|
+
path: string;
|
|
16
|
+
component: ComponentType;
|
|
17
|
+
title?: string;
|
|
18
|
+
}
|
|
19
|
+
interface SheetNavigator {
|
|
20
|
+
open: (path: string, params?: Record<string, unknown>) => void;
|
|
21
|
+
back: () => void;
|
|
22
|
+
backAll: () => void;
|
|
23
|
+
isOpen: (path: string) => boolean;
|
|
24
|
+
}
|
|
25
|
+
interface SheetRouteProps {
|
|
26
|
+
path: string;
|
|
27
|
+
component: ComponentType;
|
|
28
|
+
title?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare function SheetRoute(_props: SheetRouteProps): null;
|
|
32
|
+
declare namespace SheetRoute {
|
|
33
|
+
var __isSheetRoute: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
declare function useSheetNavigate(): SheetNavigator;
|
|
37
|
+
|
|
38
|
+
declare function useSheetParams<T extends Record<string, unknown> = Record<string, unknown>>(): {
|
|
39
|
+
path: string;
|
|
40
|
+
params: T;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
declare function useBeforeUnload(enabled: boolean): void;
|
|
44
|
+
|
|
45
|
+
export { type RouteDefinition, type SheetNavigator, SheetRoute, type SheetRouteProps, SheetRouter, type StackEntry, useBeforeUnload, useSheetNavigate, useSheetParams };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, ComponentType } from 'react';
|
|
3
|
+
|
|
4
|
+
interface SheetRouterProps {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
declare function SheetRouter({ children }: SheetRouterProps): react_jsx_runtime.JSX.Element;
|
|
8
|
+
|
|
9
|
+
interface StackEntry {
|
|
10
|
+
id: string;
|
|
11
|
+
path: string;
|
|
12
|
+
params: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
interface RouteDefinition {
|
|
15
|
+
path: string;
|
|
16
|
+
component: ComponentType;
|
|
17
|
+
title?: string;
|
|
18
|
+
}
|
|
19
|
+
interface SheetNavigator {
|
|
20
|
+
open: (path: string, params?: Record<string, unknown>) => void;
|
|
21
|
+
back: () => void;
|
|
22
|
+
backAll: () => void;
|
|
23
|
+
isOpen: (path: string) => boolean;
|
|
24
|
+
}
|
|
25
|
+
interface SheetRouteProps {
|
|
26
|
+
path: string;
|
|
27
|
+
component: ComponentType;
|
|
28
|
+
title?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare function SheetRoute(_props: SheetRouteProps): null;
|
|
32
|
+
declare namespace SheetRoute {
|
|
33
|
+
var __isSheetRoute: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
declare function useSheetNavigate(): SheetNavigator;
|
|
37
|
+
|
|
38
|
+
declare function useSheetParams<T extends Record<string, unknown> = Record<string, unknown>>(): {
|
|
39
|
+
path: string;
|
|
40
|
+
params: T;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
declare function useBeforeUnload(enabled: boolean): void;
|
|
44
|
+
|
|
45
|
+
export { type RouteDefinition, type SheetNavigator, SheetRoute, type SheetRouteProps, SheetRouter, type StackEntry, useBeforeUnload, useSheetNavigate, useSheetParams };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { createContext, useMemo, useEffect, useSyncExternalStore, useCallback, Children, createElement, useContext, isValidElement } from 'react';
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
|
+
|
|
8
|
+
// src/lib/sheet-stack-manager.ts
|
|
9
|
+
var SheetStackManager = class {
|
|
10
|
+
constructor() {
|
|
11
|
+
__publicField(this, "stack", []);
|
|
12
|
+
__publicField(this, "listeners", /* @__PURE__ */ new Set());
|
|
13
|
+
__publicField(this, "snapshot", []);
|
|
14
|
+
}
|
|
15
|
+
push(entry) {
|
|
16
|
+
this.stack.push(entry);
|
|
17
|
+
this.updateSnapshot();
|
|
18
|
+
this.notify();
|
|
19
|
+
}
|
|
20
|
+
pop() {
|
|
21
|
+
const entry = this.stack.pop();
|
|
22
|
+
if (entry) {
|
|
23
|
+
this.updateSnapshot();
|
|
24
|
+
this.notify();
|
|
25
|
+
}
|
|
26
|
+
return entry;
|
|
27
|
+
}
|
|
28
|
+
popAll() {
|
|
29
|
+
if (this.stack.length === 0) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
this.stack.length = 0;
|
|
33
|
+
this.updateSnapshot();
|
|
34
|
+
this.notify();
|
|
35
|
+
}
|
|
36
|
+
peek() {
|
|
37
|
+
return this.stack[this.stack.length - 1];
|
|
38
|
+
}
|
|
39
|
+
getSnapshot() {
|
|
40
|
+
return this.snapshot;
|
|
41
|
+
}
|
|
42
|
+
get size() {
|
|
43
|
+
return this.stack.length;
|
|
44
|
+
}
|
|
45
|
+
get isEmpty() {
|
|
46
|
+
return this.stack.length === 0;
|
|
47
|
+
}
|
|
48
|
+
hasPath(path) {
|
|
49
|
+
return this.stack.some((entry) => entry.path === path);
|
|
50
|
+
}
|
|
51
|
+
subscribe(listener) {
|
|
52
|
+
this.listeners.add(listener);
|
|
53
|
+
return () => {
|
|
54
|
+
this.listeners.delete(listener);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
updateSnapshot() {
|
|
58
|
+
this.snapshot = [...this.stack];
|
|
59
|
+
}
|
|
60
|
+
notify() {
|
|
61
|
+
this.listeners.forEach((listener) => listener());
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/lib/history-manager.ts
|
|
66
|
+
function isSheetHistoryState(state) {
|
|
67
|
+
return typeof state === "object" && state !== null && "__sheetRouter" in state && state.__sheetRouter === true;
|
|
68
|
+
}
|
|
69
|
+
var HistoryManager = class {
|
|
70
|
+
constructor() {
|
|
71
|
+
__publicField(this, "subscribers", /* @__PURE__ */ new Set());
|
|
72
|
+
__publicField(this, "handlePopState");
|
|
73
|
+
this.handlePopState = (event) => {
|
|
74
|
+
if (isSheetHistoryState(event.state)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.notifyBack();
|
|
78
|
+
};
|
|
79
|
+
window.addEventListener("popstate", this.handlePopState);
|
|
80
|
+
}
|
|
81
|
+
pushState(entryId) {
|
|
82
|
+
const state = { __sheetRouter: true, entryId };
|
|
83
|
+
window.history.pushState(state, "", window.location.href);
|
|
84
|
+
}
|
|
85
|
+
goBack(count = 1) {
|
|
86
|
+
if (count > 0) {
|
|
87
|
+
window.history.go(-count);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
subscribe(onBack) {
|
|
91
|
+
this.subscribers.add(onBack);
|
|
92
|
+
return () => {
|
|
93
|
+
this.subscribers.delete(onBack);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
destroy() {
|
|
97
|
+
window.removeEventListener("popstate", this.handlePopState);
|
|
98
|
+
this.subscribers.clear();
|
|
99
|
+
}
|
|
100
|
+
notifyBack() {
|
|
101
|
+
this.subscribers.forEach((handler) => handler());
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// src/lib/back-navigation-mediator.ts
|
|
106
|
+
var idCounter = 0;
|
|
107
|
+
function generateEntryId() {
|
|
108
|
+
idCounter += 1;
|
|
109
|
+
return `sheet-${idCounter}-${Date.now()}`;
|
|
110
|
+
}
|
|
111
|
+
var BackNavigationMediator = class {
|
|
112
|
+
constructor(sheetStack, historyManager) {
|
|
113
|
+
__publicField(this, "sheetStack");
|
|
114
|
+
__publicField(this, "historyManager");
|
|
115
|
+
__publicField(this, "unsubscribeHistory");
|
|
116
|
+
__publicField(this, "programmaticNavigation", 0);
|
|
117
|
+
this.sheetStack = sheetStack;
|
|
118
|
+
this.historyManager = historyManager;
|
|
119
|
+
this.unsubscribeHistory = this.historyManager.subscribe(() => {
|
|
120
|
+
this.handleBack();
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
open(path, params = {}) {
|
|
124
|
+
const entry = {
|
|
125
|
+
id: generateEntryId(),
|
|
126
|
+
path,
|
|
127
|
+
params
|
|
128
|
+
};
|
|
129
|
+
this.sheetStack.push(entry);
|
|
130
|
+
this.historyManager.pushState(entry.id);
|
|
131
|
+
}
|
|
132
|
+
back() {
|
|
133
|
+
if (this.sheetStack.isEmpty) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
this.sheetStack.pop();
|
|
137
|
+
this.programmaticNavigation += 1;
|
|
138
|
+
this.historyManager.goBack(1);
|
|
139
|
+
}
|
|
140
|
+
backAll() {
|
|
141
|
+
const count = this.sheetStack.size;
|
|
142
|
+
if (count === 0) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
this.sheetStack.popAll();
|
|
146
|
+
this.programmaticNavigation += 1;
|
|
147
|
+
this.historyManager.goBack(count);
|
|
148
|
+
}
|
|
149
|
+
isOpen(path) {
|
|
150
|
+
return this.sheetStack.hasPath(path);
|
|
151
|
+
}
|
|
152
|
+
get stack() {
|
|
153
|
+
return this.sheetStack;
|
|
154
|
+
}
|
|
155
|
+
destroy() {
|
|
156
|
+
this.unsubscribeHistory();
|
|
157
|
+
this.historyManager.destroy();
|
|
158
|
+
}
|
|
159
|
+
handleBack() {
|
|
160
|
+
if (this.programmaticNavigation > 0) {
|
|
161
|
+
this.programmaticNavigation -= 1;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
this.sheetStack.pop();
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
var SheetRouterContext = createContext(null);
|
|
168
|
+
function useSheetRouterContext() {
|
|
169
|
+
const context = useContext(SheetRouterContext);
|
|
170
|
+
if (!context) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
"Sheet router hooks must be used within a <SheetRouter> provider."
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
return context;
|
|
176
|
+
}
|
|
177
|
+
var SheetParamsContext = createContext(null);
|
|
178
|
+
function useSheetParamsContext() {
|
|
179
|
+
const context = useContext(SheetParamsContext);
|
|
180
|
+
if (!context) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
"useSheetParams must be used inside a sheet rendered by <SheetRouter>."
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
return context;
|
|
186
|
+
}
|
|
187
|
+
function BottomSheet({
|
|
188
|
+
open,
|
|
189
|
+
behind,
|
|
190
|
+
zIndex,
|
|
191
|
+
onClose,
|
|
192
|
+
title,
|
|
193
|
+
children
|
|
194
|
+
}) {
|
|
195
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
196
|
+
/* @__PURE__ */ jsx(
|
|
197
|
+
"div",
|
|
198
|
+
{
|
|
199
|
+
className: "sr-backdrop",
|
|
200
|
+
"data-open": open,
|
|
201
|
+
style: { zIndex },
|
|
202
|
+
onClick: onClose,
|
|
203
|
+
role: "presentation"
|
|
204
|
+
}
|
|
205
|
+
),
|
|
206
|
+
/* @__PURE__ */ jsxs(
|
|
207
|
+
"div",
|
|
208
|
+
{
|
|
209
|
+
className: "sr-sheet",
|
|
210
|
+
"data-open": open,
|
|
211
|
+
"data-behind": behind,
|
|
212
|
+
style: { zIndex: zIndex + 1 },
|
|
213
|
+
role: "dialog",
|
|
214
|
+
"aria-modal": "true",
|
|
215
|
+
"aria-label": title,
|
|
216
|
+
children: [
|
|
217
|
+
/* @__PURE__ */ jsx("div", { className: "sr-handle", children: /* @__PURE__ */ jsx("div", { className: "sr-handle-bar" }) }),
|
|
218
|
+
/* @__PURE__ */ jsx("div", { className: "sr-content", children })
|
|
219
|
+
]
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
] });
|
|
223
|
+
}
|
|
224
|
+
var BASE_Z_INDEX = 1e3;
|
|
225
|
+
function SheetOutlet() {
|
|
226
|
+
const { stack, routes, mediator } = useSheetRouterContext();
|
|
227
|
+
return /* @__PURE__ */ jsx(Fragment, { children: stack.map((entry, index) => {
|
|
228
|
+
const route = routes.get(entry.path);
|
|
229
|
+
if (!route) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
const isTop = index === stack.length - 1;
|
|
233
|
+
const isBehind = !isTop;
|
|
234
|
+
const zIndex = BASE_Z_INDEX + index * 2;
|
|
235
|
+
return /* @__PURE__ */ jsx(
|
|
236
|
+
BottomSheet,
|
|
237
|
+
{
|
|
238
|
+
open: true,
|
|
239
|
+
behind: isBehind,
|
|
240
|
+
zIndex,
|
|
241
|
+
onClose: () => mediator.back(),
|
|
242
|
+
title: route.title ?? route.path,
|
|
243
|
+
children: /* @__PURE__ */ jsx(
|
|
244
|
+
SheetParamsContext.Provider,
|
|
245
|
+
{
|
|
246
|
+
value: { path: entry.path, params: entry.params },
|
|
247
|
+
children: createElement(route.component)
|
|
248
|
+
}
|
|
249
|
+
)
|
|
250
|
+
},
|
|
251
|
+
entry.id
|
|
252
|
+
);
|
|
253
|
+
}) });
|
|
254
|
+
}
|
|
255
|
+
function isSheetRouteElement(child) {
|
|
256
|
+
return isValidElement(child) && typeof child.type === "function" && "__isSheetRoute" in child.type;
|
|
257
|
+
}
|
|
258
|
+
function collectRoutes(children) {
|
|
259
|
+
const routes = /* @__PURE__ */ new Map();
|
|
260
|
+
Children.forEach(children, (child) => {
|
|
261
|
+
if (isSheetRouteElement(child)) {
|
|
262
|
+
const { path, component, title } = child.props;
|
|
263
|
+
routes.set(path, { path, component, title });
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
return routes;
|
|
267
|
+
}
|
|
268
|
+
function collectBaseContent(children) {
|
|
269
|
+
const base = [];
|
|
270
|
+
Children.forEach(children, (child) => {
|
|
271
|
+
if (!isSheetRouteElement(child)) {
|
|
272
|
+
base.push(child);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
return base;
|
|
276
|
+
}
|
|
277
|
+
function SheetRouter({ children }) {
|
|
278
|
+
const mediator = useMemo(() => {
|
|
279
|
+
const stack2 = new SheetStackManager();
|
|
280
|
+
const history = new HistoryManager();
|
|
281
|
+
return new BackNavigationMediator(stack2, history);
|
|
282
|
+
}, []);
|
|
283
|
+
useEffect(() => {
|
|
284
|
+
return () => {
|
|
285
|
+
mediator.destroy();
|
|
286
|
+
};
|
|
287
|
+
}, [mediator]);
|
|
288
|
+
const routes = useMemo(() => collectRoutes(children), [children]);
|
|
289
|
+
const baseContent = useMemo(() => collectBaseContent(children), [children]);
|
|
290
|
+
const stack = useSyncExternalStore(
|
|
291
|
+
(callback) => mediator.stack.subscribe(callback),
|
|
292
|
+
() => mediator.stack.getSnapshot()
|
|
293
|
+
);
|
|
294
|
+
const contextValue = useMemo(
|
|
295
|
+
() => ({ mediator, routes, stack }),
|
|
296
|
+
[mediator, routes, stack]
|
|
297
|
+
);
|
|
298
|
+
return /* @__PURE__ */ jsxs(SheetRouterContext.Provider, { value: contextValue, children: [
|
|
299
|
+
baseContent,
|
|
300
|
+
/* @__PURE__ */ jsx(SheetOutlet, {})
|
|
301
|
+
] });
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/components/sheet-route.tsx
|
|
305
|
+
function SheetRoute(_props) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
SheetRoute.__isSheetRoute = true;
|
|
309
|
+
function useSheetNavigate() {
|
|
310
|
+
const { mediator } = useSheetRouterContext();
|
|
311
|
+
const open = useCallback(
|
|
312
|
+
(path, params) => {
|
|
313
|
+
mediator.open(path, params);
|
|
314
|
+
},
|
|
315
|
+
[mediator]
|
|
316
|
+
);
|
|
317
|
+
const back = useCallback(() => {
|
|
318
|
+
mediator.back();
|
|
319
|
+
}, [mediator]);
|
|
320
|
+
const backAll = useCallback(() => {
|
|
321
|
+
mediator.backAll();
|
|
322
|
+
}, [mediator]);
|
|
323
|
+
const isOpen = useCallback(
|
|
324
|
+
(path) => mediator.isOpen(path),
|
|
325
|
+
[mediator]
|
|
326
|
+
);
|
|
327
|
+
return useMemo(
|
|
328
|
+
() => ({ open, back, backAll, isOpen }),
|
|
329
|
+
[open, back, backAll, isOpen]
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// src/hooks/use-sheet-params.ts
|
|
334
|
+
function useSheetParams() {
|
|
335
|
+
const context = useSheetParamsContext();
|
|
336
|
+
return {
|
|
337
|
+
path: context.path,
|
|
338
|
+
params: context.params
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function useBeforeUnload(enabled) {
|
|
342
|
+
useEffect(() => {
|
|
343
|
+
if (!enabled) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const handler = (event) => {
|
|
347
|
+
event.preventDefault();
|
|
348
|
+
};
|
|
349
|
+
window.addEventListener("beforeunload", handler);
|
|
350
|
+
return () => {
|
|
351
|
+
window.removeEventListener("beforeunload", handler);
|
|
352
|
+
};
|
|
353
|
+
}, [enabled]);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export { SheetRoute, SheetRouter, useBeforeUnload, useSheetNavigate, useSheetParams };
|
|
357
|
+
//# sourceMappingURL=index.js.map
|
|
358
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/sheet-stack-manager.ts","../src/lib/history-manager.ts","../src/lib/back-navigation-mediator.ts","../src/context/sheet-router-context.ts","../src/context/sheet-params-context.ts","../src/components/bottom-sheet/index.tsx","../src/components/sheet-outlet.tsx","../src/components/sheet-router.tsx","../src/components/sheet-route.tsx","../src/hooks/use-sheet-navigate.ts","../src/hooks/use-sheet-params.ts","../src/hooks/use-before-unload.ts"],"names":["createContext","useContext","jsx","Fragment","stack","jsxs","useMemo","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import type { StackEntry, Listener } from \"../types\";\n\nclass SheetStackManager {\n private stack: StackEntry[] = [];\n private listeners = new Set<Listener>();\n private snapshot: readonly StackEntry[] = [];\n\n push(entry: StackEntry): void {\n this.stack.push(entry);\n this.updateSnapshot();\n this.notify();\n }\n\n pop(): StackEntry | undefined {\n const entry = this.stack.pop();\n if (entry) {\n this.updateSnapshot();\n this.notify();\n }\n return entry;\n }\n\n popAll(): void {\n if (this.stack.length === 0) {\n return;\n }\n this.stack.length = 0;\n this.updateSnapshot();\n this.notify();\n }\n\n peek(): StackEntry | undefined {\n return this.stack[this.stack.length - 1];\n }\n\n getSnapshot(): readonly StackEntry[] {\n return this.snapshot;\n }\n\n get size(): number {\n return this.stack.length;\n }\n\n get isEmpty(): boolean {\n return this.stack.length === 0;\n }\n\n hasPath(path: string): boolean {\n return this.stack.some((entry) => entry.path === path);\n }\n\n subscribe(listener: Listener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private updateSnapshot(): void {\n this.snapshot = [...this.stack];\n }\n\n private notify(): void {\n this.listeners.forEach((listener) => listener());\n }\n}\n\nexport { SheetStackManager };\n","import type { BackHandler } from \"../types\";\n\ninterface SheetHistoryState {\n __sheetRouter: true;\n entryId: string;\n}\n\nfunction isSheetHistoryState(state: unknown): state is SheetHistoryState {\n return (\n typeof state === \"object\" &&\n state !== null &&\n \"__sheetRouter\" in state &&\n (state as SheetHistoryState).__sheetRouter === true\n );\n}\n\nclass HistoryManager {\n private subscribers = new Set<BackHandler>();\n private handlePopState: (event: PopStateEvent) => void;\n\n constructor() {\n this.handlePopState = (event: PopStateEvent) => {\n if (isSheetHistoryState(event.state)) {\n return;\n }\n this.notifyBack();\n };\n window.addEventListener(\"popstate\", this.handlePopState);\n }\n\n pushState(entryId: string): void {\n const state: SheetHistoryState = { __sheetRouter: true, entryId };\n window.history.pushState(state, \"\", window.location.href);\n }\n\n goBack(count: number = 1): void {\n if (count > 0) {\n window.history.go(-count);\n }\n }\n\n subscribe(onBack: BackHandler): () => void {\n this.subscribers.add(onBack);\n return () => {\n this.subscribers.delete(onBack);\n };\n }\n\n destroy(): void {\n window.removeEventListener(\"popstate\", this.handlePopState);\n this.subscribers.clear();\n }\n\n private notifyBack(): void {\n this.subscribers.forEach((handler) => handler());\n }\n}\n\nexport { HistoryManager };\n","import type { StackEntry } from \"../types\";\nimport { SheetStackManager } from \"./sheet-stack-manager\";\nimport { HistoryManager } from \"./history-manager\";\n\nlet idCounter = 0;\n\nfunction generateEntryId(): string {\n idCounter += 1;\n return `sheet-${idCounter}-${Date.now()}`;\n}\n\nclass BackNavigationMediator {\n private sheetStack: SheetStackManager;\n private historyManager: HistoryManager;\n private unsubscribeHistory: () => void;\n private programmaticNavigation = 0;\n\n constructor(\n sheetStack: SheetStackManager,\n historyManager: HistoryManager,\n ) {\n this.sheetStack = sheetStack;\n this.historyManager = historyManager;\n\n this.unsubscribeHistory = this.historyManager.subscribe(() => {\n this.handleBack();\n });\n }\n\n open(path: string, params: Record<string, unknown> = {}): void {\n const entry: StackEntry = {\n id: generateEntryId(),\n path,\n params,\n };\n this.sheetStack.push(entry);\n this.historyManager.pushState(entry.id);\n }\n\n back(): void {\n if (this.sheetStack.isEmpty) {\n return;\n }\n this.sheetStack.pop();\n this.programmaticNavigation += 1;\n this.historyManager.goBack(1);\n }\n\n backAll(): void {\n const count = this.sheetStack.size;\n if (count === 0) {\n return;\n }\n this.sheetStack.popAll();\n this.programmaticNavigation += 1;\n this.historyManager.goBack(count);\n }\n\n isOpen(path: string): boolean {\n return this.sheetStack.hasPath(path);\n }\n\n get stack(): SheetStackManager {\n return this.sheetStack;\n }\n\n destroy(): void {\n this.unsubscribeHistory();\n this.historyManager.destroy();\n }\n\n private handleBack(): void {\n if (this.programmaticNavigation > 0) {\n this.programmaticNavigation -= 1;\n return;\n }\n this.sheetStack.pop();\n }\n}\n\nexport { BackNavigationMediator };\n","import { createContext, useContext } from \"react\";\nimport type { RouteDefinition, StackEntry } from \"../types\";\nimport type { BackNavigationMediator } from \"../lib/back-navigation-mediator\";\n\ninterface SheetRouterContextValue {\n mediator: BackNavigationMediator;\n routes: Map<string, RouteDefinition>;\n stack: readonly StackEntry[];\n}\n\nconst SheetRouterContext = createContext<SheetRouterContextValue | null>(null);\n\nfunction useSheetRouterContext(): SheetRouterContextValue {\n const context = useContext(SheetRouterContext);\n if (!context) {\n throw new Error(\n \"Sheet router hooks must be used within a <SheetRouter> provider.\",\n );\n }\n return context;\n}\n\nexport { SheetRouterContext, useSheetRouterContext };\nexport type { SheetRouterContextValue };\n","import { createContext, useContext } from \"react\";\n\ninterface SheetParamsContextValue {\n path: string;\n params: Record<string, unknown>;\n}\n\nconst SheetParamsContext = createContext<SheetParamsContextValue | null>(null);\n\nfunction useSheetParamsContext(): SheetParamsContextValue {\n const context = useContext(SheetParamsContext);\n if (!context) {\n throw new Error(\n \"useSheetParams must be used inside a sheet rendered by <SheetRouter>.\",\n );\n }\n return context;\n}\n\nexport { SheetParamsContext, useSheetParamsContext };\nexport type { SheetParamsContextValue };\n","import type { ReactNode } from \"react\";\n\ninterface BottomSheetProps {\n open: boolean;\n behind: boolean;\n zIndex: number;\n onClose: () => void;\n title: string;\n children: ReactNode;\n}\n\nfunction BottomSheet({\n open,\n behind,\n zIndex,\n onClose,\n title,\n children,\n}: BottomSheetProps) {\n return (\n <>\n <div\n className=\"sr-backdrop\"\n data-open={open}\n style={{ zIndex }}\n onClick={onClose}\n role=\"presentation\"\n />\n <div\n className=\"sr-sheet\"\n data-open={open}\n data-behind={behind}\n style={{ zIndex: zIndex + 1 }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div className=\"sr-handle\">\n <div className=\"sr-handle-bar\" />\n </div>\n <div className=\"sr-content\">{children}</div>\n </div>\n </>\n );\n}\n\nexport { BottomSheet };\nexport type { BottomSheetProps };\n","import { createElement } from \"react\";\nimport { useSheetRouterContext } from \"../context/sheet-router-context\";\nimport { SheetParamsContext } from \"../context/sheet-params-context\";\nimport { BottomSheet } from \"./bottom-sheet\";\n\nconst BASE_Z_INDEX = 1000;\n\nfunction SheetOutlet() {\n const { stack, routes, mediator } = useSheetRouterContext();\n\n return (\n <>\n {stack.map((entry, index) => {\n const route = routes.get(entry.path);\n if (!route) {\n return null;\n }\n\n const isTop = index === stack.length - 1;\n const isBehind = !isTop;\n const zIndex = BASE_Z_INDEX + index * 2;\n\n return (\n <BottomSheet\n key={entry.id}\n open={true}\n behind={isBehind}\n zIndex={zIndex}\n onClose={() => mediator.back()}\n title={route.title ?? route.path}\n >\n <SheetParamsContext.Provider\n value={{ path: entry.path, params: entry.params }}\n >\n {createElement(route.component)}\n </SheetParamsContext.Provider>\n </BottomSheet>\n );\n })}\n </>\n );\n}\n\nexport { SheetOutlet };\n","import {\n Children,\n isValidElement,\n useEffect,\n useMemo,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\";\nimport type { RouteDefinition, SheetRouteProps, StackEntry } from \"../types\";\nimport { SheetStackManager } from \"../lib/sheet-stack-manager\";\nimport { HistoryManager } from \"../lib/history-manager\";\nimport { BackNavigationMediator } from \"../lib/back-navigation-mediator\";\nimport { SheetRouterContext } from \"../context/sheet-router-context\";\nimport { SheetOutlet } from \"./sheet-outlet\";\n\ninterface SheetRouterProps {\n children: ReactNode;\n}\n\nfunction isSheetRouteElement(\n child: ReactNode,\n): child is React.ReactElement<SheetRouteProps> {\n return (\n isValidElement(child) &&\n typeof child.type === \"function\" &&\n \"__isSheetRoute\" in child.type\n );\n}\n\nfunction collectRoutes(children: ReactNode): Map<string, RouteDefinition> {\n const routes = new Map<string, RouteDefinition>();\n\n Children.forEach(children, (child) => {\n if (isSheetRouteElement(child)) {\n const { path, component, title } = child.props;\n routes.set(path, { path, component, title });\n }\n });\n\n return routes;\n}\n\nfunction collectBaseContent(children: ReactNode): ReactNode[] {\n const base: ReactNode[] = [];\n\n Children.forEach(children, (child) => {\n if (!isSheetRouteElement(child)) {\n base.push(child);\n }\n });\n\n return base;\n}\n\nfunction SheetRouter({ children }: SheetRouterProps) {\n const mediator = useMemo(() => {\n const stack = new SheetStackManager();\n const history = new HistoryManager();\n return new BackNavigationMediator(stack, history);\n }, []);\n\n useEffect(() => {\n return () => {\n mediator.destroy();\n };\n }, [mediator]);\n\n const routes = useMemo(() => collectRoutes(children), [children]);\n const baseContent = useMemo(() => collectBaseContent(children), [children]);\n\n const stack: readonly StackEntry[] = useSyncExternalStore(\n (callback) => mediator.stack.subscribe(callback),\n () => mediator.stack.getSnapshot(),\n );\n\n const contextValue = useMemo(\n () => ({ mediator, routes, stack }),\n [mediator, routes, stack],\n );\n\n return (\n <SheetRouterContext.Provider value={contextValue}>\n {baseContent}\n <SheetOutlet />\n </SheetRouterContext.Provider>\n );\n}\n\nexport { SheetRouter };\n","import type { SheetRouteProps } from \"../types\";\n\nfunction SheetRoute(_props: SheetRouteProps): null {\n return null;\n}\n\nSheetRoute.__isSheetRoute = true;\n\nexport { SheetRoute };\n","import { useCallback, useMemo } from \"react\";\nimport type { SheetNavigator } from \"../types\";\nimport { useSheetRouterContext } from \"../context/sheet-router-context\";\n\nfunction useSheetNavigate(): SheetNavigator {\n const { mediator } = useSheetRouterContext();\n\n const open = useCallback(\n (path: string, params?: Record<string, unknown>) => {\n mediator.open(path, params);\n },\n [mediator],\n );\n\n const back = useCallback(() => {\n mediator.back();\n }, [mediator]);\n\n const backAll = useCallback(() => {\n mediator.backAll();\n }, [mediator]);\n\n const isOpen = useCallback(\n (path: string) => mediator.isOpen(path),\n [mediator],\n );\n\n return useMemo(\n () => ({ open, back, backAll, isOpen }),\n [open, back, backAll, isOpen],\n );\n}\n\nexport { useSheetNavigate };\n","import { useSheetParamsContext } from \"../context/sheet-params-context\";\n\nfunction useSheetParams<\n T extends Record<string, unknown> = Record<string, unknown>,\n>(): { path: string; params: T } {\n const context = useSheetParamsContext();\n return {\n path: context.path,\n params: context.params as T,\n };\n}\n\nexport { useSheetParams };\n","import { useEffect } from \"react\";\n\nfunction useBeforeUnload(enabled: boolean) {\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n const handler = (event: BeforeUnloadEvent) => {\n event.preventDefault();\n };\n\n window.addEventListener(\"beforeunload\", handler);\n return () => {\n window.removeEventListener(\"beforeunload\", handler);\n };\n }, [enabled]);\n}\n\nexport { useBeforeUnload };\n"]}
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
.sr-backdrop {
|
|
2
|
+
position: fixed;
|
|
3
|
+
inset: 0;
|
|
4
|
+
background: rgba(0, 0, 0, 0.5);
|
|
5
|
+
opacity: 0;
|
|
6
|
+
pointer-events: none;
|
|
7
|
+
transition: opacity 0.3s ease;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.sr-backdrop[data-open="true"] {
|
|
11
|
+
opacity: 1;
|
|
12
|
+
pointer-events: auto;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.sr-sheet {
|
|
16
|
+
position: fixed;
|
|
17
|
+
inset: 0;
|
|
18
|
+
background: #ffffff;
|
|
19
|
+
border-radius: 0;
|
|
20
|
+
overflow-y: auto;
|
|
21
|
+
transform: translateY(100%);
|
|
22
|
+
transition:
|
|
23
|
+
transform 0.35s cubic-bezier(0.32, 0.72, 0, 1),
|
|
24
|
+
scale 0.35s cubic-bezier(0.32, 0.72, 0, 1);
|
|
25
|
+
will-change: transform;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.sr-sheet[data-open="true"] {
|
|
29
|
+
transform: translateY(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.sr-sheet[data-behind="true"] {
|
|
33
|
+
transform: translateY(0);
|
|
34
|
+
scale: 0.95;
|
|
35
|
+
border-radius: 12px;
|
|
36
|
+
pointer-events: none;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.sr-handle {
|
|
40
|
+
display: flex;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
padding: 12px 0 4px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.sr-handle-bar {
|
|
46
|
+
width: 36px;
|
|
47
|
+
height: 4px;
|
|
48
|
+
border-radius: 2px;
|
|
49
|
+
background: #d1d5db;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.sr-content {
|
|
53
|
+
padding: 8px 24px 32px;
|
|
54
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rezahasani78/sheet-router",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A declarative, router-like bottom sheet stack for React. Handles Android/browser back button with unlimited stacked sheets.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"./styles.css": "./dist/styles.css"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"sideEffects": [
|
|
26
|
+
"**/*.css"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsup && cp src/components/bottom-sheet/styles.css dist/styles.css",
|
|
30
|
+
"dev": "tsup --watch",
|
|
31
|
+
"type-check": "tsc --noEmit"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"react": ">=18.0.0",
|
|
35
|
+
"react-dom": ">=18.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/react": "^18.3.12",
|
|
39
|
+
"@types/react-dom": "^18.3.1",
|
|
40
|
+
"react": "^18.3.1",
|
|
41
|
+
"react-dom": "^18.3.1",
|
|
42
|
+
"tsup": "^8.3.5",
|
|
43
|
+
"typescript": "^5.6.3"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"react",
|
|
47
|
+
"bottom-sheet",
|
|
48
|
+
"router",
|
|
49
|
+
"back-button",
|
|
50
|
+
"pwa",
|
|
51
|
+
"android",
|
|
52
|
+
"sheet-stack",
|
|
53
|
+
"navigation"
|
|
54
|
+
],
|
|
55
|
+
"license": "MIT"
|
|
56
|
+
}
|