Skip to content

@tma.js/solid-router-integration

Telegram Mini Apps Navigator integration for @solidjs/router.

Installation

bash
pnpm i @tma.js/solid-router-integration
pnpm i @tma.js/solid-router-integration
bash
npm i @tma.js/solid-router-integration
npm i @tma.js/solid-router-integration
bash
yarn add @tma.js/solid-router-integration
yarn add @tma.js/solid-router-integration

Usage

At the moment, this package provides the only 1 function, which creates the integration for @solidjs/router Router - createIntegration.

Here is how it could be used:

jsx
import {
  Routes,
  Route,
  Navigate,
  Router,
} from '@solidjs/router';
import { HashNavigator } from '@tma.js/sdk';
import { createIntegration } from '@tma.js/solid-router-integration';

import { IndexPage } from './IndexPage.js';

function App() {
  // We should create navigator to pass it to integration creation.
  const navigator = new HashNavigator([{}], 0);

  // Then, to allow this navigator update current browser history, 
  // we should attach it. Otherwise, it will work in memory mode.
  void navigator.attach();

  return (
    <Router source={createIntegration(() => navigator)}>
      <Routes>
        <Route path={'/'} component={IndexPage}/>
        <Route path={'*'} element={<Navigate href={'/'}/>}/>
      </Routes>
    </Router>
  );
}
import {
  Routes,
  Route,
  Navigate,
  Router,
} from '@solidjs/router';
import { HashNavigator } from '@tma.js/sdk';
import { createIntegration } from '@tma.js/solid-router-integration';

import { IndexPage } from './IndexPage.js';

function App() {
  // We should create navigator to pass it to integration creation.
  const navigator = new HashNavigator([{}], 0);

  // Then, to allow this navigator update current browser history, 
  // we should attach it. Otherwise, it will work in memory mode.
  void navigator.attach();

  return (
    <Router source={createIntegration(() => navigator)}>
      <Routes>
        <Route path={'/'} component={IndexPage}/>
        <Route path={'*'} element={<Navigate href={'/'}/>}/>
      </Routes>
    </Router>
  );
}

And also a bit more complex example with navigation state restoration:

jsx
import {
  Routes,
  Route,
  Navigate,
  Router,
} from '@solidjs/router';
import { HashNavigator } from '@tma.js/sdk';

import { createNavigator } from './createNavigator.js';
import { IndexPage } from './IndexPage.js';

function App() {
  // We should create navigator to pass it to integration creation.
  const navigator = createNavigator();

  // Then, to allow this navigator update current browser history, 
  // we should attach it. Otherwise, it will work in memory mode.
  void navigator.attach();

  return (
    <Router source={createIntegration(() => navigator)}>
      <Routes>
        <Route path={'/'} component={IndexPage}/>
        <Route path={'*'} element={<Navigate href={'/'}/>}/>
      </Routes>
    </Router>
  );
}
import {
  Routes,
  Route,
  Navigate,
  Router,
} from '@solidjs/router';
import { HashNavigator } from '@tma.js/sdk';

import { createNavigator } from './createNavigator.js';
import { IndexPage } from './IndexPage.js';

function App() {
  // We should create navigator to pass it to integration creation.
  const navigator = createNavigator();

  // Then, to allow this navigator update current browser history, 
  // we should attach it. Otherwise, it will work in memory mode.
  void navigator.attach();

  return (
    <Router source={createIntegration(() => navigator)}>
      <Routes>
        <Route path={'/'} component={IndexPage}/>
        <Route path={'*'} element={<Navigate href={'/'}/>}/>
      </Routes>
    </Router>
  );
}
typescript
import {
  isPageReload,
  HashNavigator,
  type HashNavigatorOptions,
} from '@tma.js/sdk';

export function createNavigator(): HashNavigator {
  let navigator: HashNavigator | undefined;
  const navigatorOptions: HashNavigatorOptions = {
    debug: true,
  };

  // If page was reloaded, we assume that navigator had to previously save
  // its state in the session storage.
  if (isPageReload()) {
    const stateRaw = sessionStorage.getItem('hash-navigator-state');
    if (stateRaw) {
      try {
        const { cursor, entries } = JSON.parse(stateRaw);
        navigator = new HashNavigator(entries, cursor, navigatorOptions);
      } catch (e) {
        console.error('Unable to restore hash navigator state.', e);
      }
    }
  }

  // In case, we could not restore its state, or it is the fresh start, we
  // can create empty navigator.
  if (!navigator) {
    navigator = new HashNavigator([{}], 0, navigatorOptions);
  }

  const saveState = (nav: HashNavigator) => {
    sessionStorage.setItem('hash-navigator-state', JSON.stringify({
      cursor: nav.cursor,
      entries: nav.getEntries(),
    }));
  }

  // Whenever navigator changes its state, we save it in the session storage.
  navigator.on('change', ({ navigator: nav }) => saveState(nav));

  // Save initial state to make sure nothing will break when page will
  // be reloaded.
  saveState(navigator);

  return navigator;
}
import {
  isPageReload,
  HashNavigator,
  type HashNavigatorOptions,
} from '@tma.js/sdk';

export function createNavigator(): HashNavigator {
  let navigator: HashNavigator | undefined;
  const navigatorOptions: HashNavigatorOptions = {
    debug: true,
  };

  // If page was reloaded, we assume that navigator had to previously save
  // its state in the session storage.
  if (isPageReload()) {
    const stateRaw = sessionStorage.getItem('hash-navigator-state');
    if (stateRaw) {
      try {
        const { cursor, entries } = JSON.parse(stateRaw);
        navigator = new HashNavigator(entries, cursor, navigatorOptions);
      } catch (e) {
        console.error('Unable to restore hash navigator state.', e);
      }
    }
  }

  // In case, we could not restore its state, or it is the fresh start, we
  // can create empty navigator.
  if (!navigator) {
    navigator = new HashNavigator([{}], 0, navigatorOptions);
  }

  const saveState = (nav: HashNavigator) => {
    sessionStorage.setItem('hash-navigator-state', JSON.stringify({
      cursor: nav.cursor,
      entries: nav.getEntries(),
    }));
  }

  // Whenever navigator changes its state, we save it in the session storage.
  navigator.on('change', ({ navigator: nav }) => saveState(nav));

  // Save initial state to make sure nothing will break when page will
  // be reloaded.
  saveState(navigator);

  return navigator;
}

Template

We have already created a template for Solid JS that utilizes the current package, so you can use it.

Released under the MIT License.