Package Exports
- @zapstra/core-router
Readme
@zapstra/core-router
Query-preserving router and navigation utilities for Zapstra platform apps.
Features
- Query parameter preservation during navigation (essential for Shopify apps)
- Built-in loading states and progress indicators
- React context for navigation state management
- TypeScript support with full type safety
- Customizable loading spinner with gradient design
- Path matching utilities for active state detection
Installation
npm install @zapstra/core-router
Usage
Basic Setup
import { AppRouterProvider } from '@zapstra/core-router';
export default function App() {
return (
<AppRouterProvider>
{/* Your app content */}
</AppRouterProvider>
);
}
Navigation with Query Preservation
import { useAppRouter } from '@zapstra/core-router';
function NavigationComponent() {
const { route, isNavigating } = useAppRouter();
const handleNavigate = () => {
// Automatically preserves ?host, ?shop, and other query params
route('/app/settings');
};
return (
<button
onClick={handleNavigate}
disabled={isNavigating}
>
Go to Settings
</button>
);
}
Direct Navigation Utilities
import { useNavigateWithQuery, useQueryParams, useIsPathActive } from '@zapstra/core-router';
function MyComponent() {
const navigate = useNavigateWithQuery();
const queryParams = useQueryParams();
const isActive = useIsPathActive();
// Navigate preserving query params
const goToHome = () => navigate('/app');
// Access current query parameters
const shopDomain = queryParams.shop;
const host = queryParams.host;
// Check if path is active
const isSettingsActive = isActive('/app/settings');
const isExactHome = isActive('/app', true); // exact match
return (
<div>
<button onClick={goToHome}>Home</button>
<p>Current shop: {shopDomain}</p>
<p>Settings active: {isSettingsActive}</p>
</div>
);
}
Custom Loading Spinner
import { AppRouterProvider } from '@zapstra/core-router';
export default function App() {
return (
<AppRouterProvider
showLoadingSpinner={true}
spinnerProps={{
size: 100,
strokeWidth: 6
}}
>
{/* Your app */}
</AppRouterProvider>
);
}
Without Built-in Spinner
import { AppRouterProvider, useAppRouter, GradientProgressSpinner } from '@zapstra/core-router';
function CustomLoadingWrapper({ children }) {
const { isNavigating } = useAppRouter();
return (
<>
{isNavigating && <div>Custom loading...</div>}
{children}
</>
);
}
export default function App() {
return (
<AppRouterProvider showLoadingSpinner={false}>
<CustomLoadingWrapper>
{/* Your app */}
</CustomLoadingWrapper>
</AppRouterProvider>
);
}
Higher-Order Component
import { withAppRouter } from '@zapstra/core-router';
function MyApp() {
return <div>My App Content</div>;
}
export default withAppRouter(MyApp, {
showLoadingSpinner: true,
spinnerProps: { size: 80 }
});
Why Query Preservation?
Shopify apps run in embedded iframes and require specific query parameters like ?host
and ?shop
to function correctly. Standard navigation can lose these parameters, breaking the app. This router automatically preserves all query parameters during navigation.
// Without @zapstra/core-router - BREAKS SHOPIFY APPS
navigate('/app/settings'); // Loses ?host=... and ?shop=...
// With @zapstra/core-router - WORKS CORRECTLY
const { route } = useAppRouter();
route('/app/settings'); // Preserves ?host=... and ?shop=...
API Reference
Components
AppRouterProvider
Main provider component that wraps your app.
Props:
children: ReactNode
- Your app contentshowLoadingSpinner?: boolean
- Show built-in loading spinner (default: true)spinnerProps?: object
- Customize spinner appearance
GradientProgressSpinner
Standalone loading spinner component.
Props:
isLoading: boolean
- Whether to show spinnersize?: number
- Spinner size in pixels (default: 80)strokeWidth?: number
- Stroke width (default: 4)
Hooks
useAppRouter()
Main navigation hook.
Returns:
route: (path: string) => void
- Navigate function with query preservationisNavigating: boolean
- Current navigation state
useNavigateWithQuery()
Low-level navigation hook.
Returns:
(path: string) => void
- Navigate function with query preservation
useQueryParams()
Get current query parameters as object.
Returns:
Record<string, string>
- Current query parameters
useIsPathActive()
Check if paths are active.
Returns:
(path: string, exact?: boolean) => boolean
- Path matching function
Utilities
navigateWithQuery(navigate, path, search)
Navigate while preserving query parameters.
withAppRouter(Component, options?)
Higher-order component to wrap apps with router provider.