@sigmela/router 0.0.15 → 0.0.17

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 CHANGED
@@ -1,25 +1,42 @@
1
- # Router for React Native
1
+ # React Native Router
2
2
 
3
- [![npm version](https://badge.fury.io/js/%40sigmela%2Frouter.svg)](https://www.npmjs.com/package/@sigmela/router)
3
+ Modern, predictable navigation for React Native and Web built on top of react-native-screens. Simple class-based stacks, optional bottom tabs, global modals, typed URL params, and first-class web History API support.
4
4
 
5
- Lightweight, predictable navigation for React Native built on top of react-native-screens. It provides:
6
- - Stack navigation with URL-like paths and typed params
7
- - Bottom tab navigation via a simple builder API
8
- - A global overlay stack (e.g., auth modal) rendered above tabs/root
9
- - An imperative API with idempotent navigation and O(1) per-stack updates
5
+ Features
6
+ - Simple, chainable API: `new NavigationStack().addScreen('/users/:id', User)`
7
+ - Bottom tab bar with native and web renderers; supports custom tab bars
8
+ - Global stack for modals/overlays on top of root/tabs
9
+ - URL-first navigation: navigate using path strings; typed `useParams` and `useQueryParams`
10
+ - Works on web: integrates with pushState/replaceState/popstate and supports deep links
11
+ - Appearance control for headers, screens, and tab bar
10
12
 
11
13
  Installation
12
-
13
14
  ```bash
14
15
  yarn add @sigmela/router react-native-screens
16
+ # or
17
+ npm i @sigmela/router react-native-screens
15
18
  ```
16
19
 
17
- Make sure react-native-screens is properly installed and configured in your app.
20
+ Peer requirements
21
+ - react-native-screens >= 4.16.0
22
+ - react and react-native (versions matching your app)
18
23
 
19
- Quick start (single stack)
24
+ Web CSS
25
+ - Import the bundled stylesheet once in your web entry to enable transitions and default tab styles:
26
+ ```ts
27
+ import '@sigmela/router/styles.css';
28
+ ```
20
29
 
30
+ Quick start (single stack)
21
31
  ```tsx
22
- import { NavigationStack, Router, Navigation, useRouter, useParams, useQueryParams } from '@sigmela/router';
32
+ import {
33
+ NavigationStack,
34
+ Router,
35
+ Navigation,
36
+ useRouter,
37
+ useParams,
38
+ useQueryParams,
39
+ } from '@sigmela/router';
23
40
 
24
41
  function HomeScreen() {
25
42
  const router = useRouter();
@@ -49,27 +66,37 @@ export default function App() {
49
66
  ```
50
67
 
51
68
  Quick start (tabs + global stack)
52
-
53
69
  ```tsx
54
70
  import { NavigationStack, Router, Navigation, TabBar } from '@sigmela/router';
55
71
 
56
- const homeStack = new NavigationStack()
57
- .addScreen('/', HomeScreen, { header: { title: 'Home' } });
72
+ const homeStack = new NavigationStack().addScreen('/', HomeScreen, {
73
+ header: { title: 'Home' },
74
+ });
58
75
 
59
76
  const catalogStack = new NavigationStack()
60
77
  .addScreen('/catalog', CatalogScreen, { header: { title: 'Catalog' } })
61
- .addScreen('/catalog/products/:productId', ProductScreen, {
62
- header: { title: 'Product' }
78
+ .addScreen('/catalog/products/:productId', ProductScreen, {
79
+ header: { title: 'Product' },
63
80
  });
64
81
 
65
- const globalStack = new NavigationStack()
66
- .addModal('/auth', AuthScreen, {
67
- header: { title: 'Sign in' },
68
- });
82
+ const globalStack = new NavigationStack().addModal('/auth', AuthScreen, {
83
+ header: { title: 'Sign in' },
84
+ });
69
85
 
70
- const tabBar = new TabBar({ labeled: true })
71
- .addTab({ stack: homeStack, title: 'Home', icon: { sfSymbol: 'house' } })
72
- .addTab({ stack: catalogStack, title: 'Catalog', icon: { sfSymbol: 'bag' } });
86
+ const tabBar = new TabBar()
87
+ .addTab({
88
+ key: 'home',
89
+ stack: homeStack,
90
+ title: 'Home',
91
+ // iOS: SF Symbols, Android/Web: image source
92
+ icon: { sfSymbolName: 'house' },
93
+ })
94
+ .addTab({
95
+ key: 'catalog',
96
+ stack: catalogStack,
97
+ title: 'Catalog',
98
+ icon: { sfSymbolName: 'bag' },
99
+ });
73
100
 
74
101
  const router = new Router({ root: tabBar, global: globalStack });
75
102
 
@@ -78,40 +105,43 @@ export default function App() {
78
105
  }
79
106
  ```
80
107
 
81
- ## Navigation Appearance
108
+ Custom tab bar (optional)
109
+ ```tsx
110
+ import { TabBar, type TabBarProps } from '@sigmela/router';
82
111
 
83
- You can customize the navigation appearance using the `appearance` prop:
112
+ function MyTabBar({ tabs, activeIndex, onTabPress }: TabBarProps) {
113
+ return (
114
+ <div className="my-tabs">
115
+ {tabs.map((t, i) => (
116
+ <button key={t.tabKey} onClick={() => onTabPress(i)} aria-pressed={i === activeIndex}>
117
+ {t.title}
118
+ </button>
119
+ ))}
120
+ </div>
121
+ );
122
+ }
123
+
124
+ const tabBar = new TabBar({ component: MyTabBar })
125
+ .addTab({ key: 'home', stack: homeStack, title: 'Home' })
126
+ .addTab({ key: 'catalog', stack: catalogStack, title: 'Catalog' });
127
+ ```
84
128
 
129
+ Appearance
130
+ Pass `appearance` to `Navigation` to style headers, screens, and the tab bar.
85
131
  ```tsx
86
- import { Navigation, NavigationAppearance } from '@sigmela/router';
132
+ import type { NavigationAppearance } from '@sigmela/router';
87
133
 
88
134
  const appearance: NavigationAppearance = {
89
135
  tabBar: {
90
- // Android-specific
91
- backgroundColor: '#ffffff',
92
- tabBarItemStyle: {
93
- titleFontColor: '#999999',
94
- titleFontColorActive: '#007AFF',
95
- titleFontSize: 12,
96
- titleFontWeight: '600',
97
- iconColor: '#999999',
98
- iconColorActive: '#007AFF',
99
- rippleColor: '#00000020',
100
- activeIndicatorColor: '#007AFF',
101
- },
102
- // iOS-specific
103
- tintColor: '#007AFF',
104
- standardAppearance: {
105
- tabBarBackgroundColor: '#ffffff',
106
- tabBarShadowColor: 'transparent',
107
- },
108
- scrollEdgeAppearance: {
109
- tabBarBackgroundColor: 'rgba(255,255,255,0.9)',
110
- tabBarShadowColor: 'transparent',
111
- },
136
+ backgroundColor: '#fff',
137
+ iconColor: '#8e8e93',
138
+ iconColorActive: '#000',
139
+ title: { fontSize: 11, color: '#555', activeColor: '#000' },
140
+ // Android-only options:
141
+ androidRippleColor: 'rgba(0,0,0,0.1)',
112
142
  },
113
- screenStyle: {
114
- backgroundColor: '#ffffff',
143
+ header: {
144
+ backgroundColor: '#fff',
115
145
  },
116
146
  };
117
147
 
@@ -120,227 +150,98 @@ export default function App() {
120
150
  }
121
151
  ```
122
152
 
123
- Core concepts
124
-
125
- - Router: central coordinator. Holds slices (histories) per stack, active tab index, and the visible route.
126
- - NavigationStack: define stack routes with path patterns using path-to-regexp.
127
- - TabBar: builder for bottom tabs; each tab may reference a stack or a single screen.
128
- - Global stack: a separate stack rendered above tabs/root, ideal for modals like auth.
129
- - Navigation component: renders current root layer (tabs or root stack) and the global overlay.
130
-
131
- API reference
132
-
133
- NavigationStack
134
-
135
- - constructor(idOrOptions?, maybeOptions?)
136
- - Overloads:
137
- - new NavigationStack()
138
- - new NavigationStack(id: string)
139
- - new NavigationStack(defaultOptions: ScreenOptions)
140
- - new NavigationStack(id: string, defaultOptions: ScreenOptions)
141
- - addScreen(path: string, component: React.ComponentType, options?: ScreenOptions): this
142
- - addModal(path: string, component: React.ComponentType, options?: ScreenOptions): this
143
- - Convenience method that automatically sets `stackPresentation: 'modal'`
144
- - getId(): string
145
- - getDefaultOptions(): ScreenOptions | undefined
146
-
147
- Router
148
-
149
- - constructor({ root, global?, screenOptions? })
150
- - root: TabBar | NavigationStack
151
- - global: optional NavigationStack rendered on top (modal layer)
152
- - screenOptions: global ScreenOptions overrides merged into each screen
153
- - navigate(path: string): void
154
- - Matches a route by pathname, switches tab if needed, pushes a new history item
155
- - Duplicate navigate to the same top screen with the same params is ignored
156
- - replace(path: string): void
157
- - Replaces the top history item. If the top stack changes, both stack slices are updated incrementally to avoid stale entries [[memory:6631860]].
158
- - goBack(): void
159
- - Pops from the highest priority layer that can pop: global → current tab → root
160
- - “Seed” screens (the very first screen of a stack) are protected from popping
161
- - setRoot(nextRoot: TabBar | NavigationStack, options?: { transition?: ScreenOptions['stackAnimation'] }): void
162
- - Switch between auth flow and main app, etc.; reseeds the new root
163
- - transition is applied to the root layer when changing
164
- - onTabIndexChange(index: number): void and setActiveTabIndex(index: number): void
165
- - ensureTabSeed(index: number): void
166
- - Ensures the first screen of a tab stack is seeded when the tab becomes active
167
- - getVisibleRoute(): {
168
- routeId: string; stackId?: string; tabIndex?: number; scope: 'global' | 'tab' | 'root'; params?; query?; path?; pattern?
169
- } | null
170
- - subscribe(listener): unsubscribe
171
- - subscribeStack(stackId, listener): unsubscribe
172
- - subscribeActiveTab(listener): unsubscribe
173
- - getStackHistory(stackId): HistoryItem[] (useful for debugging/analytics)
174
- - hasTabBar(): boolean, getRootStackId(): string | undefined, getGlobalStackId(): string | undefined, getRootTransition(): ScreenOptions['stackAnimation'] | undefined
175
-
176
- Components
177
-
178
- - Navigation: top-level view that renders the root layer and the global overlay. Usage: `<Navigation router={router} appearance={appearance} />`.
179
- - StackRenderer: renders a single `NavigationStack` (advanced use, usually not needed directly).
180
-
181
- Hooks
182
-
183
- - useRouter(): Router
184
- - useCurrentRoute(): VisibleRoute
185
- - useParams<TParams>(): TParams
186
- - useQueryParams<TQuery>(): TQuery
187
- - useRoute(): { params, query, pattern?, path? }
188
-
189
- TabBar builder
190
-
191
- ```ts
192
- new TabBar({
193
- sidebarAdaptable?: boolean,
194
- disablePageAnimations?: boolean,
195
- hapticFeedbackEnabled?: boolean,
196
- scrollEdgeAppearance?: 'default' | 'opaque' | 'transparent',
197
- minimizeBehavior?: 'automatic' | 'onScrollDown' | 'onScrollUp' | 'never',
198
- })
199
- .addTab({
200
- stack?: NavigationStack,
201
- screen?: React.ComponentType,
202
- title?: string,
203
- badge?: string,
204
- icon?: ImageSource | AppleIcon | (({ focused }: { focused: boolean }) => ImageSource | AppleIcon),
205
- activeTintColor?: ColorValue,
206
- hidden?: boolean,
207
- testID?: string,
208
- role?: 'search',
209
- freezeOnBlur?: boolean,
210
- lazy?: boolean,
211
- iconInsets?: { top?: number; bottom?: number; left?: number; right?: number },
212
- })
213
- ```
214
-
215
- You can update badges at runtime via:
216
- - setBadge(tabIndex, badge: string | null)
217
- - setTabBarConfig(partial)
218
-
219
- For styling, use the `appearance` prop on the Navigation component instead.
153
+ API Reference
154
+ - Classes
155
+ - NavigationStack
156
+ - `constructor(idOrOptions?: string | ScreenOptions, defaults?: ScreenOptions)`
157
+ - `addScreen(path: string, component: Component | { component, controller? }, options?: ScreenOptions)`
158
+ - `addModal(path: string, component: Component | { component, controller? }, options?: ScreenOptions)`
159
+ - TabBar
160
+ - `constructor(config?: { component?: ComponentType<TabBarProps> })`
161
+ - `addTab({ key: string, stack?: NavigationStack, screen?: Component, title?: string, icon?: ImageSource | { sfSymbolName | imageSource | templateSource } })`
162
+ - `setBadge(index: number, badge: string | null)`
163
+ - Router
164
+ - `constructor({ root: TabBar | NavigationStack, global?: NavigationStack, screenOptions?: ScreenOptions })`
165
+ - `navigate(path: string)` — push a route (e.g. `/catalog/products/42?ref=home`)
166
+ - `replace(path: string, dedupe?: boolean)` — replace top route; `dedupe` avoids no-op replaces on web
167
+ - `goBack()` — pop a single screen within the active stack (or global)
168
+ - `setRoot(nextRoot: TabBar | NavigationStack, options?: { transition?: ScreenOptions['stackAnimation'] })`
169
+ - `getVisibleRoute()` — returns `{ scope, path, params, query, ... } | null`
170
+
171
+ - Components
172
+ - `Navigation` — the renderer. Props: `{ router: Router; appearance?: NavigationAppearance }`
173
+
174
+ - Hooks
175
+ - `useRouter()` access the router instance
176
+ - `useCurrentRoute()` — subscribe to the currently visible route
177
+ - `useParams<T>()` — typed path params
178
+ - `useQueryParams<T>()` — typed query params
179
+ - `useRoute()` — raw route context `{ presentation, params, query, pattern, path }`
180
+ - `useTabBar()` — access the current `TabBar` (inside a tab screen)
181
+
182
+ - Utilities
183
+ - `createController<TParams, TQuery>(controller)` — build controllers for guarded navigation
184
+
185
+ - Types
186
+ - `ScreenOptions` subset of `react-native-screens` Screen props plus `{ header?, tabBarIcon? }`
187
+ - `NavigationAppearance` `{ tabBar?, screen?, header? }`
188
+ - `TabBarProps` — props passed to a custom tab bar component
220
189
 
221
190
  Screen options
191
+ - `header`: `ScreenStackHeaderConfigProps` (from react-native-screens). If `title` is falsy, the header is hidden.
192
+ - `stackPresentation`: `'push' | 'modal' | ...'` (react-native-screens)
193
+ - `stackAnimation`: `'slide_from_right' | 'fade' | ...'` (react-native-screens)
194
+ - `tabBarIcon` (web helper): string or `{ sfSymbolName?: string }` for default web icon rendering
222
195
 
223
- ScreenOptions map directly to props of react-native-screens `ScreenStackItem` (e.g., header, stackPresentation, stackAnimation, gestureEnabled, etc.).
224
- - **header**: controls the navigation header. If not specified, the header is hidden by default.
225
- - Per-screen options come from `addScreen(path, component, options)`
226
- - Per-stack defaults via `new NavigationStack(defaultOptions)`
227
- - Global overrides via `new Router({ screenOptions })`
228
- The effective options are merged in this order: stack defaults → per-screen → router overrides.
229
-
230
- Header configuration:
231
- ```tsx
232
- // Header with title (visible)
233
- { header: { title: 'My Screen' } }
234
-
235
- // Hidden header (explicit)
236
- { header: { hidden: true } }
237
-
238
- // No header specified = hidden by default
239
- { /* header will be hidden automatically */ }
240
-
241
- // Custom header with background color
242
- { header: { title: 'Settings', backgroundColor: '#007AFF' } }
243
- ```
244
-
245
- Modal screens:
196
+ Controllers (guarded/async navigation)
197
+ Controllers run before a screen is presented. Call `present(passProps?)` when you're ready to show the screen. Useful for auth checks, data prefetch, or conditional redirects.
246
198
  ```tsx
247
- // Using addModal - automatically sets stackPresentation: 'modal'
248
- const stack = new NavigationStack()
249
- .addModal('/auth', AuthScreen, {
250
- header: { title: 'Sign In' }
251
- })
252
- .addModal('/settings', SettingsScreen, {
253
- header: { title: 'Settings' }
254
- });
255
-
256
- // Equivalent to using addScreen with explicit modal presentation
257
- const stack = new NavigationStack()
258
- .addScreen('/auth', AuthScreen, {
259
- stackPresentation: 'modal',
260
- header: { title: 'Sign In' }
261
- });
262
- ```
263
-
264
- Paths, params and query
265
-
266
- - Paths use path-to-regexp under the hood. Examples:
267
- - `/users/:userId`
268
- - `/orders/:year/:month`
269
- - Params are exposed via `useParams()`; query params via `useQueryParams()` and are parsed with query-string.
270
- - When you call `router.navigate('/users/123?tab=posts')`, your screen receives `{ userId: '123' }` as params and `{ tab: 'posts' }` as query.
271
-
272
- ### Controllers: delay screen presentation and pass props
273
-
274
- You can attach a controller to a route to perform checks or async work before the screen is shown. If a controller is present, the screen is NOT pushed until the controller calls `present(passProps)`.
275
-
276
- Definition:
277
-
278
- ```ts
279
199
  import { createController } from '@sigmela/router';
280
200
 
281
- type ProductParams = { productId: string };
282
- type ProductQuery = { coupon?: string };
283
-
284
- export const ProductController = createController<ProductParams, ProductQuery>((input, present) => {
285
- // input.params and input.query are typed
286
- // Do any sync/async work here (auth, data prefetch, A/B logic, etc.)
287
- setTimeout(() => {
288
- present({ preloadedTitle: 'From controller' }); // props passed to the screen
289
- }, 300);
290
- });
291
- ```
292
-
293
- Attach to a route:
201
+ const Details = {
202
+ component: DetailsScreen,
203
+ controller: createController<{ id: string }, { from?: string }>(async ({ params }, present) => {
204
+ const isSignedIn = await auth.check();
205
+ if (!isSignedIn) {
206
+ router.navigate('/auth');
207
+ return;
208
+ }
209
+ present({ fetched: await api.load(params.id) });
210
+ }),
211
+ };
294
212
 
295
- ```ts
296
- new NavigationStack()
297
- .addScreen('/catalog/products/:productId', {
298
- controller: ProductController,
299
- component: ProductScreen,
300
- }, {
301
- header: { title: 'Product' },
302
- });
213
+ new NavigationStack().addScreen('/details/:id', Details);
303
214
  ```
304
215
 
305
- In your screen you can receive `passProps` from the controller alongside route params/query:
216
+ Web behavior
217
+ - On web, the router listens to `pushState`, `replaceState`, and `popstate`. You can navigate by calling `router.navigate('/path')` or by updating `window.history` yourself; the router will stay in sync.
218
+ - Initial load deep links are expanded into a stack chain: `/a/b/c` seeds the stack with `/a` → `/a/b` → `/a/b/c` if those routes exist in the same stack.
219
+ - `goBack()` pops within the active stack (or global). The router avoids creating duplicate entries when switching tabs by using `replace` under the hood in the web tab bar.
306
220
 
221
+ Root switching (auth flows)
222
+ Switch between a login stack and the main tab bar at runtime. Optionally pass a transition for the change.
307
223
  ```tsx
308
- type ProductScreenProps = { preloadedTitle?: string };
309
-
310
- function ProductScreen(props: ProductScreenProps) {
311
- const { productId } = useParams<ProductParams>();
312
- const { coupon } = useQueryParams<ProductQuery>();
313
- return <Text>{props.preloadedTitle} #{productId} coupon={coupon ?? '—'}</Text>;
314
- }
224
+ router.setRoot(loggedIn ? mainTabs : authStack, { transition: 'fade' });
315
225
  ```
316
226
 
317
- Notes:
318
- - `navigate()` and `replace()` both respect controllers.
319
- - If the controller never calls `present()`, the screen will not be shown (useful for redirects).
320
- - Props passed to `present()` are injected into the route component as regular props.
321
-
322
- Behavior highlights (verified by tests)
323
-
324
- - Initial seeding: the first screen of the active tab (or root stack) is pushed automatically.
325
- - Duplicate navigate to the same top screen with the same params is ignored.
326
- - goBack pops from the global stack first (if any), then from the current tab’s stack, then from the root stack; seed screens are protected.
327
- - Navigating to a route inside a tab switches the active tab and seeds it if needed.
328
- - setRoot switches between TabBar and NavigationStack, applies an optional transition, rebuilds the registry, and reseeds the new root; subscribers to `subscribeRoot` are notified.
329
- - replace updates old/new stack slices atomically to avoid stale entries and keeps per-stack updates O(1) [[memory:6631860]].
330
-
331
- TypeScript
227
+ Badges and programmatic tab control
228
+ ```ts
229
+ // Show a badge on the second tab
230
+ tabBar.setBadge(1, '3');
332
231
 
333
- Helpful exports:
334
- - Types: `TabConfig`, `TabBarConfig`, `NavigationProps`, `NavigationAppearance`, `HistoryItem`
335
- - Components: `Navigation`, `StackRenderer`, `TabBar`
336
- - Hooks: `useRouter`, `useCurrentRoute`, `useParams`, `useQueryParams`
337
- - Core classes: `Router`, `NavigationStack`
232
+ // Switch active tab (e.g., from a screen)
233
+ useRouter().onTabIndexChange(2);
234
+ ```
338
235
 
339
- Requirements
236
+ Example app
237
+ - This repo contains an `example` app demonstrating tabs, stacks, and appearance.
340
238
 
341
- - React 18+
342
- - React Native (with react-native-screens)
239
+ Tips
240
+ - Prefer path-based navigation throughout your app: it keeps web and native in sync.
241
+ - Type your params and query with `useParams<T>()` and `useQueryParams<T>()` to get end-to-end type safety.
242
+ - On the web, remember to import `@sigmela/router/styles.css` once.
343
243
 
344
244
  License
245
+ MIT
246
+
345
247
 
346
- MIT
@@ -1,25 +1,3 @@
1
-
2
-
3
- :root {
4
- --tabs-transition: .2s ease-in-out;
5
- --transition-standard-easing: cubic-bezier(.4, .0, .2, 1);
6
- --transition-standard-in-time: .3s;
7
- --transition-standard-out-time: .25s;
8
-
9
- --transition-standard-in: var(--transition-standard-in-time) var(--transition-standard-easing);
10
- --transition-standard-out: var(--transition-standard-out-time) var(--transition-standard-easing);
11
-
12
- --background-color-true: #181818;
13
-
14
- --background-color: var(--background-color-true);
15
- }
16
-
17
-
18
- body {
19
- margin: 0;
20
- padding: 0;
21
- }
22
-
23
1
  .screen-stack {
24
2
  min-width: 100%;
25
3
  width: 100%;
@@ -43,19 +21,19 @@ body {
43
21
  }
44
22
 
45
23
  .screen-stack[data-animation="navigation"].animating > .screen-stack-item {
46
- transition: transform var(--transition-standard-in), filter var(--transition-standard-in);
24
+ transition: transform .3s cubic-bezier(.4, .0, .2, 1), filter .3s cubic-bezier(.4, .0, .2, 1)
47
25
  }
48
26
 
49
27
  .screen-stack[data-animation="navigation"].animating.backwards > .screen-stack-item {
50
- transition: transform var(--transition-standard-out), filter var(--transition-standard-out);
28
+ transition: transform .25s cubic-bezier(.4, .0, .2, 1), filter .25s cubic-bezier(.4, .0, .2, 1);
51
29
  }
52
30
 
53
31
  .screen-stack[data-animation="modal"].animating > .screen-stack-item {
54
- transition: transform var(--transition-standard-in), filter var(--transition-standard-in);
32
+ transition: transform .3s cubic-bezier(.4, .0, .2, 1), filter .3s cubic-bezier(.4, .0, .2, 1)
55
33
  }
56
34
 
57
35
  .screen-stack[data-animation="modal"].animating.backwards > .screen-stack-item {
58
- transition: transform var(--transition-standard-out), filter var(--transition-standard-out);
36
+ transition: transform .25s cubic-bezier(.4, .0, .2, 1), filter .25s cubic-bezier(.4, .0, .2, 1);
59
37
  }
60
38
 
61
39
  .tab-stacks-container {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigmela/router",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "React Native Router",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -11,7 +11,10 @@
11
11
  "default": "./lib/module/index.js"
12
12
  },
13
13
  "./package.json": "./package.json",
14
- "./styles.css": "./src/styles.css"
14
+ "./styles.css": {
15
+ "source": "./src/styles.css",
16
+ "default": "./lib/module/styles.css"
17
+ }
15
18
  },
16
19
  "files": [
17
20
  "lib",