@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 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
- style: { zIndex: zIndex + 1 },
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;
@@ -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
- style: { zIndex: zIndex + 1 },
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
- inset: 0;
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.2",
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",