@rezahasani78/sheet-router 0.1.2 → 0.2.1
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/README.md +262 -0
- package/dist/index.cjs +11 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/dist/styles.css +9 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# @rezahasani78/sheet-router
|
|
2
|
+
|
|
3
|
+
A declarative, router-like bottom sheet stack for React.
|
|
4
|
+
Handles Android/browser back button with unlimited stacked sheets.
|
|
5
|
+
|
|
6
|
+
**[Live Demo](https://sheet-router-nextjs.vercel.app/)**
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Stacked sheets** — open unlimited sheets on top of each other, each with its own params
|
|
13
|
+
- **Back-button support** — browser back button and Android hardware back close sheets one by one
|
|
14
|
+
- **Configurable height** — `50%`, `80%`, `100%`, or any CSS value per sheet
|
|
15
|
+
- **State persistence** — survives page refresh via `sessionStorage` (default) or a custom storage provider
|
|
16
|
+
- **SSR-safe** — works with Next.js, Remix, and any server-rendered React app
|
|
17
|
+
- **Tiny** — no dependencies beyond React
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @rezahasani78/sheet-router
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { SheetRouter, SheetRoute, useSheetNavigate } from "@rezahasani78/sheet-router";
|
|
29
|
+
import "@rezahasani78/sheet-router/styles.css";
|
|
30
|
+
|
|
31
|
+
function App() {
|
|
32
|
+
return (
|
|
33
|
+
<SheetRouter>
|
|
34
|
+
<HomePage />
|
|
35
|
+
<SheetRoute path="sheet-a" component={SheetA} height="50%" />
|
|
36
|
+
<SheetRoute path="sheet-b" component={SheetB} height="80%" />
|
|
37
|
+
<SheetRoute path="sheet-c" component={SheetC} />
|
|
38
|
+
</SheetRouter>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function HomePage() {
|
|
43
|
+
const { open } = useSheetNavigate();
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div>
|
|
47
|
+
<button onClick={() => open("sheet-a")}>Open Sheet A (50%)</button>
|
|
48
|
+
<button onClick={() => open("sheet-b")}>Open Sheet B (80%)</button>
|
|
49
|
+
<button onClick={() => open("sheet-c")}>Open Sheet C (full screen)</button>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function SheetA() {
|
|
55
|
+
const { open, back } = useSheetNavigate();
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div>
|
|
59
|
+
<h2>Sheet A</h2>
|
|
60
|
+
<button onClick={() => open("sheet-b")}>Stack Sheet B on top</button>
|
|
61
|
+
<button onClick={back}>Close</button>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function SheetB() {
|
|
67
|
+
const { back, backAll } = useSheetNavigate();
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<div>
|
|
71
|
+
<h2>Sheet B</h2>
|
|
72
|
+
<button onClick={back}>Back</button>
|
|
73
|
+
<button onClick={backAll}>Close All</button>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function SheetC() {
|
|
79
|
+
const { back } = useSheetNavigate();
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div>
|
|
83
|
+
<h2>Sheet C (full screen)</h2>
|
|
84
|
+
<button onClick={back}>Back</button>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## API
|
|
91
|
+
|
|
92
|
+
### `<SheetRouter>`
|
|
93
|
+
|
|
94
|
+
The root provider. Wrap your app content and `<SheetRoute>` declarations inside it.
|
|
95
|
+
|
|
96
|
+
| Prop | Type | Default | Description |
|
|
97
|
+
|---|---|---|---|
|
|
98
|
+
| `children` | `ReactNode` | — | Base content + `<SheetRoute>` elements |
|
|
99
|
+
| `persist` | `boolean` | `true` | Persist sheet stack across page refreshes |
|
|
100
|
+
| `storageProvider` | `StorageProvider` | `sessionStorage` | Custom storage backend (Redux, Zustand, etc.) |
|
|
101
|
+
|
|
102
|
+
### `<SheetRoute>`
|
|
103
|
+
|
|
104
|
+
Declares a sheet. Renders nothing by itself — the sheet opens when navigated to.
|
|
105
|
+
|
|
106
|
+
| Prop | Type | Required | Description |
|
|
107
|
+
|---|---|---|---|
|
|
108
|
+
| `path` | `string` | yes | Unique identifier for this sheet |
|
|
109
|
+
| `component` | `ComponentType` | yes | React component rendered inside the sheet |
|
|
110
|
+
| `title` | `string` | no | Accessible label for the dialog |
|
|
111
|
+
| `height` | `string` | no | CSS height value (`"50%"`, `"80%"`, etc.). Omit for full screen |
|
|
112
|
+
|
|
113
|
+
### `useSheetNavigate()`
|
|
114
|
+
|
|
115
|
+
Returns a `SheetNavigator` object with navigation methods.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const { open, back, backAll, isOpen } = useSheetNavigate();
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
| Method | Signature | Description |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| `open` | `(path: string, params?: Record<string, unknown>) => void` | Opens a sheet by path, optionally passing params |
|
|
124
|
+
| `back` | `() => void` | Closes the top sheet |
|
|
125
|
+
| `backAll` | `() => void` | Closes all sheets at once |
|
|
126
|
+
| `isOpen` | `(path: string) => boolean` | Checks if a sheet with the given path is in the stack |
|
|
127
|
+
|
|
128
|
+
### `useSheetParams<T>()`
|
|
129
|
+
|
|
130
|
+
Access the current sheet's path and params. Use inside a sheet component.
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
function UserSheet() {
|
|
134
|
+
const { path, params } = useSheetParams<{ userId: string }>();
|
|
135
|
+
return <p>User: {params.userId}</p>;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `useBeforeUnload(enabled: boolean)`
|
|
140
|
+
|
|
141
|
+
Shows a browser confirmation dialog when the user tries to close/reload the tab.
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
useBeforeUnload(true); // enable the prompt
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### `StorageProvider` interface
|
|
148
|
+
|
|
149
|
+
Implement this to use a custom storage backend.
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
interface StorageProvider {
|
|
153
|
+
save: (stack: readonly StackEntry[]) => void;
|
|
154
|
+
load: () => StackEntry[];
|
|
155
|
+
clear: () => void;
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### Example: Redux storage provider
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
import type { StorageProvider, StackEntry } from "@rezahasani78/sheet-router";
|
|
163
|
+
import { store } from "./store";
|
|
164
|
+
import { setStack, clearStack } from "./sheet-slice";
|
|
165
|
+
|
|
166
|
+
export function createReduxStorageProvider(): StorageProvider {
|
|
167
|
+
return {
|
|
168
|
+
save(stack) {
|
|
169
|
+
store.dispatch(setStack([...stack]));
|
|
170
|
+
},
|
|
171
|
+
load() {
|
|
172
|
+
return store.getState().sheet.stack;
|
|
173
|
+
},
|
|
174
|
+
clear() {
|
|
175
|
+
store.dispatch(clearStack());
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Disabling persistence
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
<SheetRouter persist={false}>
|
|
185
|
+
{/* sheets reset on refresh */}
|
|
186
|
+
</SheetRouter>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Design Patterns
|
|
192
|
+
|
|
193
|
+
This library is built on four design patterns:
|
|
194
|
+
|
|
195
|
+
### Stack
|
|
196
|
+
|
|
197
|
+
`SheetStackManager` manages sheets as a **LIFO stack**. Each `open()` pushes a new entry, `back()` pops the top, `backAll()` clears the stack. The stack drives the rendering order — earlier entries appear behind newer ones.
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
open("A") → [A]
|
|
201
|
+
open("B") → [A, B]
|
|
202
|
+
open("C") → [A, B, C]
|
|
203
|
+
back() → [A, B]
|
|
204
|
+
backAll() → []
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Observer
|
|
208
|
+
|
|
209
|
+
Both `SheetStackManager` and `HistoryManager` implement the **Observer pattern** using a `subscribe(listener)` / `notify()` mechanism. React subscribes via `useSyncExternalStore` so the UI re-renders only when the stack actually changes — no unnecessary renders.
|
|
210
|
+
|
|
211
|
+
### Mediator
|
|
212
|
+
|
|
213
|
+
`BackNavigationMediator` sits between the stack and the History API, **coordinating** them so they never fall out of sync. When the user presses the browser back button, the mediator pops the stack. When `back()` is called programmatically, it pops the stack _and_ calls `history.go(-1)`. A `programmaticNavigation` guard prevents double-pops.
|
|
214
|
+
|
|
215
|
+
### Provider (React Context)
|
|
216
|
+
|
|
217
|
+
`SheetRouterContext` and `SheetParamsContext` use the **Provider pattern** to distribute the mediator, route map, and current stack to any descendant via hooks (`useSheetNavigate`, `useSheetParams`) — without prop drilling.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Architecture
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
┌─────────────────────────────────────────────┐
|
|
225
|
+
│ SheetRouter │
|
|
226
|
+
│ (collects routes, renders base + outlet) │
|
|
227
|
+
├─────────────────────────────────────────────┤
|
|
228
|
+
│ SheetRouterContext │
|
|
229
|
+
│ ┌──────────────┐ ┌────────────────────┐ │
|
|
230
|
+
│ │ SheetOutlet │ │ useSheetNavigate │ │
|
|
231
|
+
│ │ (renders │ │ useSheetParams │ │
|
|
232
|
+
│ │ BottomSheet │ │ (hooks for │ │
|
|
233
|
+
│ │ per entry) │ │ components) │ │
|
|
234
|
+
│ └──────┬───────┘ └────────────────────┘ │
|
|
235
|
+
├─────────┼───────────────────────────────────┤
|
|
236
|
+
│ ▼ │
|
|
237
|
+
│ BackNavigationMediator (Mediator) │
|
|
238
|
+
│ ┌──────────────────┐ ┌─────────────────┐ │
|
|
239
|
+
│ │ SheetStackManager │ │ HistoryManager │ │
|
|
240
|
+
│ │ (Stack+Observer) │ │ (Observer) │ │
|
|
241
|
+
│ └────────┬─────────┘ └───────┬─────────┘ │
|
|
242
|
+
│ ▼ ▼ │
|
|
243
|
+
│ StorageProvider History API │
|
|
244
|
+
│ (sessionStorage/Redux) (pushState/ │
|
|
245
|
+
│ popstate) │
|
|
246
|
+
└─────────────────────────────────────────────┘
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Browser Support
|
|
252
|
+
|
|
253
|
+
Works in all modern browsers that support the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API):
|
|
254
|
+
|
|
255
|
+
- Chrome / Edge 80+
|
|
256
|
+
- Firefox 80+
|
|
257
|
+
- Safari 14+
|
|
258
|
+
- Android WebView / Chrome for Android
|
|
259
|
+
|
|
260
|
+
## License
|
|
261
|
+
|
|
262
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -300,8 +300,10 @@ function BottomSheet({
|
|
|
300
300
|
zIndex,
|
|
301
301
|
onClose,
|
|
302
302
|
title,
|
|
303
|
-
children
|
|
303
|
+
children,
|
|
304
|
+
height
|
|
304
305
|
}) {
|
|
306
|
+
const isFullScreen = !height || height === "100%";
|
|
305
307
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
306
308
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
307
309
|
"div",
|
|
@@ -319,7 +321,11 @@ function BottomSheet({
|
|
|
319
321
|
className: "sr-sheet",
|
|
320
322
|
"data-open": open,
|
|
321
323
|
"data-behind": behind,
|
|
322
|
-
|
|
324
|
+
"data-full": isFullScreen,
|
|
325
|
+
style: {
|
|
326
|
+
zIndex: zIndex + 1,
|
|
327
|
+
...height ? { height } : {}
|
|
328
|
+
},
|
|
323
329
|
role: "dialog",
|
|
324
330
|
"aria-modal": "true",
|
|
325
331
|
"aria-label": title,
|
|
@@ -350,6 +356,7 @@ function SheetOutlet() {
|
|
|
350
356
|
zIndex,
|
|
351
357
|
onClose: () => mediator.back(),
|
|
352
358
|
title: route.title ?? route.path,
|
|
359
|
+
height: route.height,
|
|
353
360
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
354
361
|
SheetParamsContext.Provider,
|
|
355
362
|
{
|
|
@@ -370,8 +377,8 @@ function collectRoutes(children) {
|
|
|
370
377
|
const routes = /* @__PURE__ */ new Map();
|
|
371
378
|
react.Children.forEach(children, (child) => {
|
|
372
379
|
if (isSheetRouteElement(child)) {
|
|
373
|
-
const { path, component, title } = child.props;
|
|
374
|
-
routes.set(path, { path, component, title });
|
|
380
|
+
const { path, component, title, height } = child.props;
|
|
381
|
+
routes.set(path, { path, component, title, height });
|
|
375
382
|
}
|
|
376
383
|
});
|
|
377
384
|
return routes;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/sheet-stack-manager.ts","../src/lib/history-manager.ts","../src/lib/back-navigation-mediator.ts","../src/lib/session-storage.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":["isBrowser","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, StorageProvider } from \"../types\";\n\nclass SheetStackManager {\n private stack: StackEntry[] = [];\n private listeners = new Set<Listener>();\n private snapshot: readonly StackEntry[] = [];\n private storage: StorageProvider | null;\n\n constructor(storage: StorageProvider | null) {\n this.storage = storage;\n\n if (this.storage) {\n const restored = this.storage.load();\n if (restored.length > 0) {\n this.stack = restored.map((entry) => ({ ...entry }));\n this.updateSnapshot();\n }\n }\n }\n\n push(entry: StackEntry): void {\n this.stack.push(entry);\n this.persist();\n this.updateSnapshot();\n this.notify();\n }\n\n pop(): StackEntry | undefined {\n const entry = this.stack.pop();\n if (entry) {\n this.persist();\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.persist();\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 persist(): void {\n this.storage?.save(this.stack);\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\nconst isBrowser = typeof window !== \"undefined\";\n\ninterface SheetHistoryState {\n __sheetRouter: true;\n entryId: string;\n depth: number;\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) | null = null;\n private depth = 0;\n\n constructor() {\n if (!isBrowser) {\n return;\n }\n\n this.handlePopState = (event: PopStateEvent) => {\n const targetDepth = isSheetHistoryState(event.state)\n ? event.state.depth\n : 0;\n\n if (targetDepth < this.depth) {\n this.depth = targetDepth;\n this.notifyBack();\n } else {\n this.depth = targetDepth;\n }\n };\n window.addEventListener(\"popstate\", this.handlePopState);\n }\n\n restoreEntries(entryIds: string[]): void {\n if (!isBrowser) {\n return;\n }\n if (isSheetHistoryState(window.history.state)) {\n window.history.replaceState(null, \"\", window.location.href);\n }\n for (const entryId of entryIds) {\n this.depth += 1;\n const state: SheetHistoryState = {\n __sheetRouter: true,\n entryId,\n depth: this.depth,\n };\n window.history.pushState(state, \"\", window.location.href);\n }\n }\n\n pushState(entryId: string): void {\n if (!isBrowser) {\n return;\n }\n this.depth += 1;\n const state: SheetHistoryState = {\n __sheetRouter: true,\n entryId,\n depth: this.depth,\n };\n window.history.pushState(state, \"\", window.location.href);\n }\n\n goBack(count: number = 1): void {\n if (!isBrowser) {\n return;\n }\n if (count > 0) {\n this.depth = Math.max(0, this.depth - count);\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 if (isBrowser && this.handlePopState) {\n window.removeEventListener(\"popstate\", this.handlePopState);\n }\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 const restoredEntries = this.sheetStack.getSnapshot();\n if (restoredEntries.length > 0) {\n this.historyManager.restoreEntries(\n restoredEntries.map((entry) => entry.id),\n );\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 type { StackEntry, StorageProvider } from \"../types\";\n\nconst STORAGE_KEY = \"__sheetRouter_stack\";\nconst isBrowser = typeof window !== \"undefined\";\n\nfunction validateEntries(parsed: unknown): StackEntry[] {\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter(\n (entry): entry is StackEntry =>\n typeof entry === \"object\" &&\n entry !== null &&\n typeof entry.id === \"string\" &&\n typeof entry.path === \"string\" &&\n typeof entry.params === \"object\",\n );\n}\n\nfunction createSessionStorageProvider(): StorageProvider {\n return {\n save(stack: readonly StackEntry[]): void {\n if (!isBrowser) {\n return;\n }\n try {\n sessionStorage.setItem(STORAGE_KEY, JSON.stringify(stack));\n } catch {\n // quota exceeded or private browsing\n }\n },\n\n load(): StackEntry[] {\n if (!isBrowser) {\n return [];\n }\n try {\n const raw = sessionStorage.getItem(STORAGE_KEY);\n if (!raw) {\n return [];\n }\n return validateEntries(JSON.parse(raw));\n } catch {\n return [];\n }\n },\n\n clear(): void {\n if (!isBrowser) {\n return;\n }\n try {\n sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n // ignore\n }\n },\n };\n}\n\nexport { createSessionStorageProvider };\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, StorageProvider } from \"../types\";\nimport { SheetStackManager } from \"../lib/sheet-stack-manager\";\nimport { HistoryManager } from \"../lib/history-manager\";\nimport { BackNavigationMediator } from \"../lib/back-navigation-mediator\";\nimport { createSessionStorageProvider } from \"../lib/session-storage\";\nimport { SheetRouterContext } from \"../context/sheet-router-context\";\nimport { SheetOutlet } from \"./sheet-outlet\";\n\ninterface SheetRouterProps {\n children: ReactNode;\n persist?: boolean;\n storageProvider?: StorageProvider;\n}\n\nconst EMPTY_STACK: readonly StackEntry[] = [];\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, persist = true, storageProvider }: SheetRouterProps) {\n const mediator = useMemo(() => {\n const storage = persist\n ? (storageProvider ?? createSessionStorageProvider())\n : null;\n const stack = new SheetStackManager(storage);\n const history = new HistoryManager();\n return new BackNavigationMediator(stack, history);\n // eslint-disable-next-line react-hooks/exhaustive-deps\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 () => EMPTY_STACK,\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/sheet-stack-manager.ts","../src/lib/history-manager.ts","../src/lib/back-navigation-mediator.ts","../src/lib/session-storage.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":["isBrowser","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, StorageProvider } from \"../types\";\n\nclass SheetStackManager {\n private stack: StackEntry[] = [];\n private listeners = new Set<Listener>();\n private snapshot: readonly StackEntry[] = [];\n private storage: StorageProvider | null;\n\n constructor(storage: StorageProvider | null) {\n this.storage = storage;\n\n if (this.storage) {\n const restored = this.storage.load();\n if (restored.length > 0) {\n this.stack = restored.map((entry) => ({ ...entry }));\n this.updateSnapshot();\n }\n }\n }\n\n push(entry: StackEntry): void {\n this.stack.push(entry);\n this.persist();\n this.updateSnapshot();\n this.notify();\n }\n\n pop(): StackEntry | undefined {\n const entry = this.stack.pop();\n if (entry) {\n this.persist();\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.persist();\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 persist(): void {\n this.storage?.save(this.stack);\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\nconst isBrowser = typeof window !== \"undefined\";\n\ninterface SheetHistoryState {\n __sheetRouter: true;\n entryId: string;\n depth: number;\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) | null = null;\n private depth = 0;\n\n constructor() {\n if (!isBrowser) {\n return;\n }\n\n this.handlePopState = (event: PopStateEvent) => {\n const targetDepth = isSheetHistoryState(event.state)\n ? event.state.depth\n : 0;\n\n if (targetDepth < this.depth) {\n this.depth = targetDepth;\n this.notifyBack();\n } else {\n this.depth = targetDepth;\n }\n };\n window.addEventListener(\"popstate\", this.handlePopState);\n }\n\n restoreEntries(entryIds: string[]): void {\n if (!isBrowser) {\n return;\n }\n if (isSheetHistoryState(window.history.state)) {\n window.history.replaceState(null, \"\", window.location.href);\n }\n for (const entryId of entryIds) {\n this.depth += 1;\n const state: SheetHistoryState = {\n __sheetRouter: true,\n entryId,\n depth: this.depth,\n };\n window.history.pushState(state, \"\", window.location.href);\n }\n }\n\n pushState(entryId: string): void {\n if (!isBrowser) {\n return;\n }\n this.depth += 1;\n const state: SheetHistoryState = {\n __sheetRouter: true,\n entryId,\n depth: this.depth,\n };\n window.history.pushState(state, \"\", window.location.href);\n }\n\n goBack(count: number = 1): void {\n if (!isBrowser) {\n return;\n }\n if (count > 0) {\n this.depth = Math.max(0, this.depth - count);\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 if (isBrowser && this.handlePopState) {\n window.removeEventListener(\"popstate\", this.handlePopState);\n }\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 const restoredEntries = this.sheetStack.getSnapshot();\n if (restoredEntries.length > 0) {\n this.historyManager.restoreEntries(\n restoredEntries.map((entry) => entry.id),\n );\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 type { StackEntry, StorageProvider } from \"../types\";\n\nconst STORAGE_KEY = \"__sheetRouter_stack\";\nconst isBrowser = typeof window !== \"undefined\";\n\nfunction validateEntries(parsed: unknown): StackEntry[] {\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter(\n (entry): entry is StackEntry =>\n typeof entry === \"object\" &&\n entry !== null &&\n typeof entry.id === \"string\" &&\n typeof entry.path === \"string\" &&\n typeof entry.params === \"object\",\n );\n}\n\nfunction createSessionStorageProvider(): StorageProvider {\n return {\n save(stack: readonly StackEntry[]): void {\n if (!isBrowser) {\n return;\n }\n try {\n sessionStorage.setItem(STORAGE_KEY, JSON.stringify(stack));\n } catch {\n // quota exceeded or private browsing\n }\n },\n\n load(): StackEntry[] {\n if (!isBrowser) {\n return [];\n }\n try {\n const raw = sessionStorage.getItem(STORAGE_KEY);\n if (!raw) {\n return [];\n }\n return validateEntries(JSON.parse(raw));\n } catch {\n return [];\n }\n },\n\n clear(): void {\n if (!isBrowser) {\n return;\n }\n try {\n sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n // ignore\n }\n },\n };\n}\n\nexport { createSessionStorageProvider };\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 height?: string;\n}\n\nfunction BottomSheet({\n open,\n behind,\n zIndex,\n onClose,\n title,\n children,\n height,\n}: BottomSheetProps) {\n const isFullScreen = !height || height === \"100%\";\n\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 data-full={isFullScreen}\n style={{\n zIndex: zIndex + 1,\n ...(height ? { height } : {}),\n }}\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 height={route.height}\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, StorageProvider } from \"../types\";\nimport { SheetStackManager } from \"../lib/sheet-stack-manager\";\nimport { HistoryManager } from \"../lib/history-manager\";\nimport { BackNavigationMediator } from \"../lib/back-navigation-mediator\";\nimport { createSessionStorageProvider } from \"../lib/session-storage\";\nimport { SheetRouterContext } from \"../context/sheet-router-context\";\nimport { SheetOutlet } from \"./sheet-outlet\";\n\ninterface SheetRouterProps {\n children: ReactNode;\n persist?: boolean;\n storageProvider?: StorageProvider;\n}\n\nconst EMPTY_STACK: readonly StackEntry[] = [];\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, height } = child.props;\n routes.set(path, { path, component, title, height });\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, persist = true, storageProvider }: SheetRouterProps) {\n const mediator = useMemo(() => {\n const storage = persist\n ? (storageProvider ?? createSessionStorageProvider())\n : null;\n const stack = new SheetStackManager(storage);\n const history = new HistoryManager();\n return new BackNavigationMediator(stack, history);\n // eslint-disable-next-line react-hooks/exhaustive-deps\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 () => EMPTY_STACK,\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
CHANGED
|
@@ -10,6 +10,7 @@ interface RouteDefinition {
|
|
|
10
10
|
path: string;
|
|
11
11
|
component: ComponentType;
|
|
12
12
|
title?: string;
|
|
13
|
+
height?: string;
|
|
13
14
|
}
|
|
14
15
|
interface SheetNavigator {
|
|
15
16
|
open: (path: string, params?: Record<string, unknown>) => void;
|
|
@@ -21,6 +22,7 @@ interface SheetRouteProps {
|
|
|
21
22
|
path: string;
|
|
22
23
|
component: ComponentType;
|
|
23
24
|
title?: string;
|
|
25
|
+
height?: string;
|
|
24
26
|
}
|
|
25
27
|
interface StorageProvider {
|
|
26
28
|
save: (stack: readonly StackEntry[]) => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ interface RouteDefinition {
|
|
|
10
10
|
path: string;
|
|
11
11
|
component: ComponentType;
|
|
12
12
|
title?: string;
|
|
13
|
+
height?: string;
|
|
13
14
|
}
|
|
14
15
|
interface SheetNavigator {
|
|
15
16
|
open: (path: string, params?: Record<string, unknown>) => void;
|
|
@@ -21,6 +22,7 @@ interface SheetRouteProps {
|
|
|
21
22
|
path: string;
|
|
22
23
|
component: ComponentType;
|
|
23
24
|
title?: string;
|
|
25
|
+
height?: string;
|
|
24
26
|
}
|
|
25
27
|
interface StorageProvider {
|
|
26
28
|
save: (stack: readonly StackEntry[]) => void;
|
package/dist/index.js
CHANGED
|
@@ -298,8 +298,10 @@ function BottomSheet({
|
|
|
298
298
|
zIndex,
|
|
299
299
|
onClose,
|
|
300
300
|
title,
|
|
301
|
-
children
|
|
301
|
+
children,
|
|
302
|
+
height
|
|
302
303
|
}) {
|
|
304
|
+
const isFullScreen = !height || height === "100%";
|
|
303
305
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
304
306
|
/* @__PURE__ */ jsx(
|
|
305
307
|
"div",
|
|
@@ -317,7 +319,11 @@ function BottomSheet({
|
|
|
317
319
|
className: "sr-sheet",
|
|
318
320
|
"data-open": open,
|
|
319
321
|
"data-behind": behind,
|
|
320
|
-
|
|
322
|
+
"data-full": isFullScreen,
|
|
323
|
+
style: {
|
|
324
|
+
zIndex: zIndex + 1,
|
|
325
|
+
...height ? { height } : {}
|
|
326
|
+
},
|
|
321
327
|
role: "dialog",
|
|
322
328
|
"aria-modal": "true",
|
|
323
329
|
"aria-label": title,
|
|
@@ -348,6 +354,7 @@ function SheetOutlet() {
|
|
|
348
354
|
zIndex,
|
|
349
355
|
onClose: () => mediator.back(),
|
|
350
356
|
title: route.title ?? route.path,
|
|
357
|
+
height: route.height,
|
|
351
358
|
children: /* @__PURE__ */ jsx(
|
|
352
359
|
SheetParamsContext.Provider,
|
|
353
360
|
{
|
|
@@ -368,8 +375,8 @@ function collectRoutes(children) {
|
|
|
368
375
|
const routes = /* @__PURE__ */ new Map();
|
|
369
376
|
Children.forEach(children, (child) => {
|
|
370
377
|
if (isSheetRouteElement(child)) {
|
|
371
|
-
const { path, component, title } = child.props;
|
|
372
|
-
routes.set(path, { path, component, title });
|
|
378
|
+
const { path, component, title, height } = child.props;
|
|
379
|
+
routes.set(path, { path, component, title, height });
|
|
373
380
|
}
|
|
374
381
|
});
|
|
375
382
|
return routes;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/sheet-stack-manager.ts","../src/lib/history-manager.ts","../src/lib/back-navigation-mediator.ts","../src/lib/session-storage.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":["isBrowser","createContext","useContext","jsx","Fragment","stack","jsxs","useMemo","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import type { StackEntry, Listener, StorageProvider } from \"../types\";\n\nclass SheetStackManager {\n private stack: StackEntry[] = [];\n private listeners = new Set<Listener>();\n private snapshot: readonly StackEntry[] = [];\n private storage: StorageProvider | null;\n\n constructor(storage: StorageProvider | null) {\n this.storage = storage;\n\n if (this.storage) {\n const restored = this.storage.load();\n if (restored.length > 0) {\n this.stack = restored.map((entry) => ({ ...entry }));\n this.updateSnapshot();\n }\n }\n }\n\n push(entry: StackEntry): void {\n this.stack.push(entry);\n this.persist();\n this.updateSnapshot();\n this.notify();\n }\n\n pop(): StackEntry | undefined {\n const entry = this.stack.pop();\n if (entry) {\n this.persist();\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.persist();\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 persist(): void {\n this.storage?.save(this.stack);\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\nconst isBrowser = typeof window !== \"undefined\";\n\ninterface SheetHistoryState {\n __sheetRouter: true;\n entryId: string;\n depth: number;\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) | null = null;\n private depth = 0;\n\n constructor() {\n if (!isBrowser) {\n return;\n }\n\n this.handlePopState = (event: PopStateEvent) => {\n const targetDepth = isSheetHistoryState(event.state)\n ? event.state.depth\n : 0;\n\n if (targetDepth < this.depth) {\n this.depth = targetDepth;\n this.notifyBack();\n } else {\n this.depth = targetDepth;\n }\n };\n window.addEventListener(\"popstate\", this.handlePopState);\n }\n\n restoreEntries(entryIds: string[]): void {\n if (!isBrowser) {\n return;\n }\n if (isSheetHistoryState(window.history.state)) {\n window.history.replaceState(null, \"\", window.location.href);\n }\n for (const entryId of entryIds) {\n this.depth += 1;\n const state: SheetHistoryState = {\n __sheetRouter: true,\n entryId,\n depth: this.depth,\n };\n window.history.pushState(state, \"\", window.location.href);\n }\n }\n\n pushState(entryId: string): void {\n if (!isBrowser) {\n return;\n }\n this.depth += 1;\n const state: SheetHistoryState = {\n __sheetRouter: true,\n entryId,\n depth: this.depth,\n };\n window.history.pushState(state, \"\", window.location.href);\n }\n\n goBack(count: number = 1): void {\n if (!isBrowser) {\n return;\n }\n if (count > 0) {\n this.depth = Math.max(0, this.depth - count);\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 if (isBrowser && this.handlePopState) {\n window.removeEventListener(\"popstate\", this.handlePopState);\n }\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 const restoredEntries = this.sheetStack.getSnapshot();\n if (restoredEntries.length > 0) {\n this.historyManager.restoreEntries(\n restoredEntries.map((entry) => entry.id),\n );\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 type { StackEntry, StorageProvider } from \"../types\";\n\nconst STORAGE_KEY = \"__sheetRouter_stack\";\nconst isBrowser = typeof window !== \"undefined\";\n\nfunction validateEntries(parsed: unknown): StackEntry[] {\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter(\n (entry): entry is StackEntry =>\n typeof entry === \"object\" &&\n entry !== null &&\n typeof entry.id === \"string\" &&\n typeof entry.path === \"string\" &&\n typeof entry.params === \"object\",\n );\n}\n\nfunction createSessionStorageProvider(): StorageProvider {\n return {\n save(stack: readonly StackEntry[]): void {\n if (!isBrowser) {\n return;\n }\n try {\n sessionStorage.setItem(STORAGE_KEY, JSON.stringify(stack));\n } catch {\n // quota exceeded or private browsing\n }\n },\n\n load(): StackEntry[] {\n if (!isBrowser) {\n return [];\n }\n try {\n const raw = sessionStorage.getItem(STORAGE_KEY);\n if (!raw) {\n return [];\n }\n return validateEntries(JSON.parse(raw));\n } catch {\n return [];\n }\n },\n\n clear(): void {\n if (!isBrowser) {\n return;\n }\n try {\n sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n // ignore\n }\n },\n };\n}\n\nexport { createSessionStorageProvider };\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, StorageProvider } from \"../types\";\nimport { SheetStackManager } from \"../lib/sheet-stack-manager\";\nimport { HistoryManager } from \"../lib/history-manager\";\nimport { BackNavigationMediator } from \"../lib/back-navigation-mediator\";\nimport { createSessionStorageProvider } from \"../lib/session-storage\";\nimport { SheetRouterContext } from \"../context/sheet-router-context\";\nimport { SheetOutlet } from \"./sheet-outlet\";\n\ninterface SheetRouterProps {\n children: ReactNode;\n persist?: boolean;\n storageProvider?: StorageProvider;\n}\n\nconst EMPTY_STACK: readonly StackEntry[] = [];\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, persist = true, storageProvider }: SheetRouterProps) {\n const mediator = useMemo(() => {\n const storage = persist\n ? (storageProvider ?? createSessionStorageProvider())\n : null;\n const stack = new SheetStackManager(storage);\n const history = new HistoryManager();\n return new BackNavigationMediator(stack, history);\n // eslint-disable-next-line react-hooks/exhaustive-deps\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 () => EMPTY_STACK,\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/sheet-stack-manager.ts","../src/lib/history-manager.ts","../src/lib/back-navigation-mediator.ts","../src/lib/session-storage.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":["isBrowser","createContext","useContext","jsx","Fragment","stack","jsxs","useMemo","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import type { StackEntry, Listener, StorageProvider } from \"../types\";\n\nclass SheetStackManager {\n private stack: StackEntry[] = [];\n private listeners = new Set<Listener>();\n private snapshot: readonly StackEntry[] = [];\n private storage: StorageProvider | null;\n\n constructor(storage: StorageProvider | null) {\n this.storage = storage;\n\n if (this.storage) {\n const restored = this.storage.load();\n if (restored.length > 0) {\n this.stack = restored.map((entry) => ({ ...entry }));\n this.updateSnapshot();\n }\n }\n }\n\n push(entry: StackEntry): void {\n this.stack.push(entry);\n this.persist();\n this.updateSnapshot();\n this.notify();\n }\n\n pop(): StackEntry | undefined {\n const entry = this.stack.pop();\n if (entry) {\n this.persist();\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.persist();\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 persist(): void {\n this.storage?.save(this.stack);\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\nconst isBrowser = typeof window !== \"undefined\";\n\ninterface SheetHistoryState {\n __sheetRouter: true;\n entryId: string;\n depth: number;\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) | null = null;\n private depth = 0;\n\n constructor() {\n if (!isBrowser) {\n return;\n }\n\n this.handlePopState = (event: PopStateEvent) => {\n const targetDepth = isSheetHistoryState(event.state)\n ? event.state.depth\n : 0;\n\n if (targetDepth < this.depth) {\n this.depth = targetDepth;\n this.notifyBack();\n } else {\n this.depth = targetDepth;\n }\n };\n window.addEventListener(\"popstate\", this.handlePopState);\n }\n\n restoreEntries(entryIds: string[]): void {\n if (!isBrowser) {\n return;\n }\n if (isSheetHistoryState(window.history.state)) {\n window.history.replaceState(null, \"\", window.location.href);\n }\n for (const entryId of entryIds) {\n this.depth += 1;\n const state: SheetHistoryState = {\n __sheetRouter: true,\n entryId,\n depth: this.depth,\n };\n window.history.pushState(state, \"\", window.location.href);\n }\n }\n\n pushState(entryId: string): void {\n if (!isBrowser) {\n return;\n }\n this.depth += 1;\n const state: SheetHistoryState = {\n __sheetRouter: true,\n entryId,\n depth: this.depth,\n };\n window.history.pushState(state, \"\", window.location.href);\n }\n\n goBack(count: number = 1): void {\n if (!isBrowser) {\n return;\n }\n if (count > 0) {\n this.depth = Math.max(0, this.depth - count);\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 if (isBrowser && this.handlePopState) {\n window.removeEventListener(\"popstate\", this.handlePopState);\n }\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 const restoredEntries = this.sheetStack.getSnapshot();\n if (restoredEntries.length > 0) {\n this.historyManager.restoreEntries(\n restoredEntries.map((entry) => entry.id),\n );\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 type { StackEntry, StorageProvider } from \"../types\";\n\nconst STORAGE_KEY = \"__sheetRouter_stack\";\nconst isBrowser = typeof window !== \"undefined\";\n\nfunction validateEntries(parsed: unknown): StackEntry[] {\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter(\n (entry): entry is StackEntry =>\n typeof entry === \"object\" &&\n entry !== null &&\n typeof entry.id === \"string\" &&\n typeof entry.path === \"string\" &&\n typeof entry.params === \"object\",\n );\n}\n\nfunction createSessionStorageProvider(): StorageProvider {\n return {\n save(stack: readonly StackEntry[]): void {\n if (!isBrowser) {\n return;\n }\n try {\n sessionStorage.setItem(STORAGE_KEY, JSON.stringify(stack));\n } catch {\n // quota exceeded or private browsing\n }\n },\n\n load(): StackEntry[] {\n if (!isBrowser) {\n return [];\n }\n try {\n const raw = sessionStorage.getItem(STORAGE_KEY);\n if (!raw) {\n return [];\n }\n return validateEntries(JSON.parse(raw));\n } catch {\n return [];\n }\n },\n\n clear(): void {\n if (!isBrowser) {\n return;\n }\n try {\n sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n // ignore\n }\n },\n };\n}\n\nexport { createSessionStorageProvider };\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 height?: string;\n}\n\nfunction BottomSheet({\n open,\n behind,\n zIndex,\n onClose,\n title,\n children,\n height,\n}: BottomSheetProps) {\n const isFullScreen = !height || height === \"100%\";\n\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 data-full={isFullScreen}\n style={{\n zIndex: zIndex + 1,\n ...(height ? { height } : {}),\n }}\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 height={route.height}\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, StorageProvider } from \"../types\";\nimport { SheetStackManager } from \"../lib/sheet-stack-manager\";\nimport { HistoryManager } from \"../lib/history-manager\";\nimport { BackNavigationMediator } from \"../lib/back-navigation-mediator\";\nimport { createSessionStorageProvider } from \"../lib/session-storage\";\nimport { SheetRouterContext } from \"../context/sheet-router-context\";\nimport { SheetOutlet } from \"./sheet-outlet\";\n\ninterface SheetRouterProps {\n children: ReactNode;\n persist?: boolean;\n storageProvider?: StorageProvider;\n}\n\nconst EMPTY_STACK: readonly StackEntry[] = [];\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, height } = child.props;\n routes.set(path, { path, component, title, height });\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, persist = true, storageProvider }: SheetRouterProps) {\n const mediator = useMemo(() => {\n const storage = persist\n ? (storageProvider ?? createSessionStorageProvider())\n : null;\n const stack = new SheetStackManager(storage);\n const history = new HistoryManager();\n return new BackNavigationMediator(stack, history);\n // eslint-disable-next-line react-hooks/exhaustive-deps\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 () => EMPTY_STACK,\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
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
background: rgba(0, 0, 0, 0.5);
|
|
5
5
|
opacity: 0;
|
|
6
6
|
pointer-events: none;
|
|
7
|
+
transition: opacity 0.3s ease;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
.sr-backdrop[data-open="true"] {
|
|
@@ -13,7 +14,10 @@
|
|
|
13
14
|
|
|
14
15
|
.sr-sheet {
|
|
15
16
|
position: fixed;
|
|
16
|
-
|
|
17
|
+
left: 0;
|
|
18
|
+
right: 0;
|
|
19
|
+
bottom: 0;
|
|
20
|
+
height: 100%;
|
|
17
21
|
background: #ffffff;
|
|
18
22
|
border-radius: 0;
|
|
19
23
|
overflow-y: auto;
|
|
@@ -26,6 +30,10 @@
|
|
|
26
30
|
animation: sr-slide-up 0.35s cubic-bezier(0.32, 0.72, 0, 1);
|
|
27
31
|
}
|
|
28
32
|
|
|
33
|
+
.sr-sheet[data-open="true"]:not([data-full="true"]) {
|
|
34
|
+
border-radius: 16px 16px 0 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
29
37
|
.sr-sheet[data-behind="true"] {
|
|
30
38
|
transform: translateY(0);
|
|
31
39
|
scale: 0.95;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rezahasani78/sheet-router",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "A declarative, router-like bottom sheet stack for React. Handles Android/browser back button with unlimited stacked sheets.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|