Skip to content

SoEasy/trike

Repository files navigation

trike

A JavaScript routing library with easy navigation control and monitoring.

License: MIT TypeScript

Overview

trike is a browser history wrapper that solves common problems with the standard History API:

  • Detecting navigation direction (back/forward) on popstate events
  • Preventing users from leaving the site via the back button (canLeaveBack option)
  • Persisting and restoring navigation history on page refresh/tab restore
  • Full compatibility with react-router via the history package interface

Installation

# Using pnpm
pnpm add @trike/history

# Using npm
npm install @trike/history

# Using yarn
yarn add @trike/history

Available Packages

Quick Start

import {
  createTrikeHistory,
  createTrikeLocationController
} from '@trike/history';

// Create controller (manages navigation entries in memory)
const controller = createTrikeLocationController({
  canLeaveBack: false, // prevent leaving site via back button
});

// Create history instance
const history = createTrikeHistory(controller);

// Use like standard history
history.push('/dashboard');
history.replace('/settings');
history.back();

// Listen to navigation events with direction info
history.listenNavigation((event) => {
  console.log(event.direction); // 'forward' | 'back' | 'replace'
  console.log(event.source);    // 'programmatic' | 'browser'
  console.log(event.from.location, event.to.location);
});

Core Concepts

The Problem

Browser's popstate event doesn't indicate navigation direction. When user clicks back or forward button, you only get a POP action without knowing which way they went.

The Solution

Trike maintains a virtual stack of 1-3 entries in browser history with indices { index: 1 | 2 | 3 }. By tracking the current index, it determines navigation direction. The actual navigation history is stored in TrikeLocationController in memory and persisted to browser state.

Architecture

  • TrikeHistory — wrapper over window.history, implements History interface from the history package
  • TrikeLocationController — stores the full navigation stack in memory, handles back/forward logic

Examples

With React Router

import {createTrikeHistory, createTrikeLocationController} from '@trike/history';
import {Router} from 'react-router-dom';

const controller = createTrikeLocationController({canLeaveBack: false});
const history = createTrikeHistory(controller);

function App() {
  return (
    <Router history = {history} >
      {/* your routes */}
      < /Router>
  );
}

Navigation with Direction Detection

history.listenNavigation((event) => {
  if (event.direction === 'back' && event.source === 'browser') {
    // User clicked browser's back button
    analytics.track('browser_back_navigation');
  }
});

Blocking Navigation

// Block navigation with confirmation prompt
const unblock = history.blockV4('You have unsaved changes. Leave anyway?');

// Later, remove the block
unblock();

API Reference

History Package (@trike/history)

createTrikeLocationController(options?)

Creates a controller that manages navigation history in memory.

Option Type Default Description
canLeaveBack boolean false If false, prevents leaving the site via back button

createTrikeHistory(controller)

Creates a history instance. Returns ITrikeHistory which extends the standard History interface.

Navigation Methods:

  • push(path, state?) — navigate to a new location
  • replace(path, state?) — replace current location
  • back() / goBack() — go back (returns boolean indicating success)
  • forward() / goForward() — go forward (returns boolean)
  • go(n) — go n steps (returns boolean)

Listeners:

  • listen(listener) — standard history listener
  • listenNavigation(listener) — rich event listener with direction/source info

Other:

  • blockV4(prompt?) — block navigation with optional confirmation message
  • createHref(location) — create URL string from location
  • destroy() — cleanup listeners

TypeScript Support

trike is built with TypeScript and provides full type safety

Testing

Trike includes comprehensive tests using Vitest:

# Run all tests
pnpm test

# Run tests for specific package
pnpm --filter @trike/history test

# Watch mode
pnpm test:watch

Development

Monorepo Structure

trike/
├── packages/
│   └── history/                # History library
├── apps/
│   └── dev-app/                # Demo application (Preact)
├── configs/                    # Shared configurations
└── .changeset/                 # Changesets for versioning

Build and Development

# Install dependencies
pnpm install

# Build all packages
pnpm build

# Build specific package
pnpm --filter @trike/history build

# Run demo app
pnpm --filter dev-app dev

# Run linter
pnpm lint

# Type check
pnpm typecheck

# Format code
pnpm format

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests and linters: pnpm test && pnpm lint && pnpm typecheck
  5. Create a changeset: pnpm changeset
  6. Submit a pull request

Requirements

  • Node.js: >= 18
  • TypeScript: >= 5.0
  • Module format: ESM only
  • Target: ES5 (transpiled output)

Browser Compatibility

Trike works in all modern browsers.

License

MIT License - see LICENSE file for details.

Credits

Developed by Vladimir Sannikov

Links


Built with ❤️ using TypeScript

About

A JavaScript routing library with easy navigation control and monitoring

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors