Skip to content

Commit

Permalink
feat: rename hatch to route (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeysova authored Jun 17, 2022
2 parents 86fa314 + a3b6862 commit f8fcf97
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 70 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ jobs:

- name: Build
run: yarn build

- name: Test
run: yarn test
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,31 @@ forward({

```ts
// some-page/contract.ts
import { createHatch } from 'bypath';
import { createRoute } from 'bypath';

import { navigationDomain } from 'entities/navigation';

export const hatch = createHatch(navigationDomain);
export const route = createRoute(navigationDomain);
// domain is optional
// for debug/logging
```

```ts
// some-page/index.tsx
import { guard, createDomain } from 'effector';
import { withHatch } from 'bypath';
import { sample, createDomain } from 'effector';
import { withRoute } from 'bypath';

import { historyPush } from 'entities/navigation';
import { $isAuthenticated } from 'entities/session';

import { hatch } from './contract';
import { route } from './contract';

export const Page = withHatch(hatch, () => {
export const Page = withRoute(route, () => {
//...
});

guard({
source: hatch.enter,
sample({
source: route.enter,
filter: $isAuthenticated.map((is) => !is),
target: historyPush.prepend(() => '/login')
});
Expand Down
28 changes: 14 additions & 14 deletions src/browser-application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Domain, Event, combine, forward, guard } from 'effector';
import { RouteConfig, matchRoutes } from 'react-router-config';
import { splitMap } from 'patronum/split-map';

import { HatchParams, getHatch } from './hatch';
import { RouteParams, getRoute } from './routing';
import { createNavigation } from './navigation';
import { defaultDomain } from './default-domain';

Expand Down Expand Up @@ -54,15 +54,15 @@ export function createBrowserApplication(config: {
},
});

const hatchEnter = domain.createEvent<HatchParams>({ name: `hatchEnter:${path}` });
const hatchUpdate = domain.createEvent<HatchParams>({ name: `hatchUpdate:${path}` });
const hatchExit = domain.createEvent<void>({ name: `hatchExit:${path}` });
const pageRouteEnter = domain.createEvent<RouteParams>({ name: `routeEnter:${path}` });
const pageRouteUpdate = domain.createEvent<RouteParams>({ name: `routeUpdate:${path}` });
const pageRouteExit = domain.createEvent<void>({ name: `routeExit:${path}` });

const componentHatch = getHatch(component);
if (componentHatch) {
forward({ from: hatchEnter, to: componentHatch.enter });
forward({ from: hatchUpdate, to: componentHatch.update });
forward({ from: hatchExit, to: componentHatch.exit });
const pageRoute = getRoute(component);
if (pageRoute) {
forward({ from: pageRouteEnter, to: pageRoute.enter });
forward({ from: pageRouteUpdate, to: pageRoute.update });
forward({ from: pageRouteExit, to: pageRoute.exit });
}

// Shows that user is on the route
Expand All @@ -78,16 +78,16 @@ export function createBrowserApplication(config: {
guard({
clock: routeMatched,
filter: $onPage,
target: hatchUpdate,
target: pageRouteUpdate,
});

guard({
clock: routeMatched,
filter: combine($onPage, $onRoute, (page, route) => !page && route),
target: hatchEnter,
target: pageRouteEnter,
});

$onPage.on(hatchEnter, () => true);
$onPage.on(pageRouteEnter, () => true);
//#endregion route matched

//#region NOT matched
Expand All @@ -96,10 +96,10 @@ export function createBrowserApplication(config: {
guard({
clock: notMatched,
filter: $onPage,
target: hatchExit,
target: pageRouteExit,
});

$onPage.on(hatchExit, () => false);
$onPage.on(pageRouteExit, () => false);
//#endregion NOT matched
}

Expand Down
2 changes: 1 addition & 1 deletion src/default-domain.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { createDomain } from 'effector';

export const defaultDomain = createDomain('framework/default');
export const defaultDomain = createDomain('bypath/default');
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import loadable from '@loadable/component';
import { RouteConfig, renderRoutes } from 'react-router-config';

export { createBrowserApplication } from './browser-application';
export { createHatch, getHatch, withHatch, lookupHatch } from './hatch';
export type { Hatch, HatchParams } from './hatch';
export { createRoute, getRoute, withRoute, lookupRoute } from './routing';
export type { Route, RouteParams } from './routing';

export { contract } from './contract';

Expand Down
48 changes: 24 additions & 24 deletions src/hatch.ts → src/routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,32 @@ import { MatchedRoute } from 'react-router-config';

import { defaultDomain } from './default-domain';

const HATCH = 'framework/page-hatch';
const ROUTE_PROPERTY = 'bypath/page-route';

export interface HatchParams {
export interface RouteParams {
params: Record<string, string>;
query: Record<string, string>;
}

/**
* Hatch is like a Gate, but just for models
* Route is like a Gate, but just for models
*/
export interface Hatch {
export interface Route {
// Called by history from withHatch
enter: Event<HatchParams>;
update: Event<HatchParams>;
enter: Event<RouteParams>;
update: Event<RouteParams>;
exit: Event<void>;

$opened: Store<boolean>;
$params: Store<Record<string, string>>;
$query: Store<Record<string, string>>;

$props: Store<HatchParams>;
$props: Store<RouteParams>;
}

interface Config {
enter: Event<HatchParams>;
update: Event<HatchParams>;
enter: Event<RouteParams>;
update: Event<RouteParams>;
exit: Event<void>;
domain?: Domain;
}
Expand All @@ -39,7 +39,7 @@ interface Config {
* Stores is derived from this events and holds specific parameters
* `$opened` holds current state of page, if user visited page but not left, it is `true`
*/
export function createHatch(config_: Config | Domain = defaultDomain): Hatch {
export function createRoute(config_: Config | Domain = defaultDomain): Route {
let domain;
let config: Partial<Config>;
if (is.domain(config_)) {
Expand All @@ -57,41 +57,41 @@ export function createHatch(config_: Config | Domain = defaultDomain): Hatch {
const $params = domain.createStore<Record<string, string>>({});
const $query = domain.createStore<Record<string, string>>({});

const hatch = {
enter: config.enter ?? domain.createEvent<HatchParams>(),
update: config.update ?? domain.createEvent<HatchParams>(),
const route = {
enter: config.enter ?? domain.createEvent<RouteParams>(),
update: config.update ?? domain.createEvent<RouteParams>(),
exit: config.exit ?? domain.createEvent<void>(),
$opened,
$params,
$query,
$props: combine({ params: $params, query: $query }),
};

$params.on([hatch.enter, hatch.update], (_, { params }) => params);
$query.on([hatch.enter, hatch.update], (_, { query }) => query);
$params.on([route.enter, route.update], (_, { params }) => params);
$query.on([route.enter, route.update], (_, { query }) => query);

hatch.$opened.on(hatch.enter, () => Boolean(true)).reset(hatch.exit);
route.$opened.on(route.enter, () => Boolean(true)).reset(route.exit);
// Developer may want to read props when user leaves the page
// if $opened store will reset on hatch.exit, data will be deleted
// if $opened store will reset on route.exit, data will be deleted

return hatch;
return route;
}

export function withHatch<C extends React.ComponentType>(hatch: Hatch, component: C): C {
export function withRoute<C extends React.ComponentType>(hatch: Route, component: C): C {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(component as any)[HATCH] = hatch;
(component as any)[ROUTE_PROPERTY] = hatch;
return component;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getHatch<T extends React.ComponentType<any>>(component: T): Hatch | undefined {
export function getRoute<T extends React.ComponentType<any>>(component: T): Route | undefined {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (component as any)[HATCH];
return (component as any)[ROUTE_PROPERTY];
}

export function lookupHatch<P>(match: MatchedRoute<P>): Hatch | undefined {
export function lookupRoute<P>(match: MatchedRoute<P>): Route | undefined {
if (match.route.component) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return getHatch(match.route.component as any);
return getRoute(match.route.component as any);
}
}
2 changes: 1 addition & 1 deletion src/server-application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { createNavigation } from './navigation';
import { defaultDomain } from './default-domain';

export function createServerApplication(config: { routes: RouteConfig[]; domain?: Domain }) {
const debug = createDebug('framework-server');
const debug = createDebug('bypath/server');
const domain = config.domain || defaultDomain;
const navigation = createNavigation(domain, { emitHistory: false, trackRedirects: true });

Expand Down
8 changes: 4 additions & 4 deletions tests/browser/fixtures/page-another.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import React from 'react';
import { sample } from 'effector';

import { createHatch, withHatch } from '../../../src';
import { createRoute, withRoute } from '../../../src';
import { pageNameSet, root } from './internal';

const hatch = createHatch(root);
const route = createRoute(root);

const PageAnother = withHatch(hatch, () => {
const PageAnother = withRoute(route, () => {
return <div>For example just another page</div>;
});

export default PageAnother;

sample({
source: hatch.enter,
source: route.enter,
fn: () => 'page-another',
target: pageNameSet,
});
10 changes: 5 additions & 5 deletions tests/browser/fixtures/page1.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import React from 'react';
import { sample } from 'effector';

import { createHatch, withHatch } from '../../../src';
import { createRoute, withRoute } from '../../../src';
import { pageNameSet, root } from './internal';

const hatch = createHatch(root);
const route = createRoute(root);

hatch.enter.watch((e) => console.info('PAGE1 Hatch Enter', e));
route.enter.watch((e) => console.info('PAGE1 Hatch Enter', e));

const Page1 = withHatch(hatch, () => {
const Page1 = withRoute(route, () => {
return <div>For example first page</div>;
});

export default Page1;

sample({
source: hatch.enter,
source: route.enter,
fn: () => 'page1',
target: pageNameSet,
});
2 changes: 1 addition & 1 deletion tests/browser/routing-with-chunks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { allSettled, fork } from 'effector';
import { $pageName, root } from './fixtures/internal';
import { createBrowserApplication, loadable } from '../../src';

test.skip('triggering hatch loaded from chunk', async () => {
test.skip('triggering route loaded from chunk', async () => {
const routes = [
{
path: '/page1',
Expand Down
20 changes: 10 additions & 10 deletions tests/browser/routing.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React from 'react';
import { Effect, Event, Store, createEvent } from 'effector';

import { createBrowserApplication, createHatch, withHatch } from '../../src';
import { createBrowserApplication, createRoute, withRoute } from '../../src';

test('check triggering hatch without binding to domain', () => {
const homePageHatch = createHatch();
const HomePage = withHatch(homePageHatch, () => <div>Home page</div>);
test('check triggering route without binding to domain', () => {
const homePageHatch = createRoute();
const HomePage = withRoute(homePageHatch, () => <div>Home page</div>);

const notFoundPageHatch = createHatch();
const NotFoundPage = withHatch(notFoundPageHatch, () => <span>Not found</span>);
const notFoundPageHatch = createRoute();
const NotFoundPage = withRoute(notFoundPageHatch, () => <span>Not found</span>);
const routes = [
{
path: '/',
Expand Down Expand Up @@ -48,11 +48,11 @@ test('check triggering hatch without binding to domain', () => {
});

test('trigger hatch on enter and leave', () => {
const hatchHomePage = createHatch();
const HomePage = withHatch(hatchHomePage, () => <div>Home page</div>);
const hatchHomePage = createRoute();
const HomePage = withRoute(hatchHomePage, () => <div>Home page</div>);

const hatchNotFoundPage = createHatch();
const NotFoundPage = withHatch(hatchNotFoundPage, () => <span>Not found</span>);
const hatchNotFoundPage = createRoute();
const NotFoundPage = withRoute(hatchNotFoundPage, () => <span>Not found</span>);
const routes = [
{
path: '/',
Expand Down

0 comments on commit f8fcf97

Please sign in to comment.