Skip to content

Commit

Permalink
frint-router-component-handlers (#327)
Browse files Browse the repository at this point in the history
* #290 Create `frint-router-component-handlers`

* #290 Add README.md for `frint-router-component-handlers`

* #290 Add tests for `frint-router-component-handlers`

* #290 Update `frint-router-component-handlers` dependencies to 3.0.1

* Update frint-router-react dependencies

* Add links to frint-router-component-handlers in docs
  • Loading branch information
viacheslaff authored Oct 4, 2017
1 parent bb1bd61 commit 3cb8104
Show file tree
Hide file tree
Showing 23 changed files with 838 additions and 162 deletions.
40 changes: 22 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,25 @@ Find more examples [here](https://github.com/Travix-International/frint/tree/mas

The framework is a collection of these packages, which can be composed together on demand:

| Package | Status | Description |
|-----------------------------|------------------------------------------------------------------------|-------------|
| [frint] | [![frint-status]][frint-package] | Base for creating Apps |
| [frint-store] | [![frint-store-status]][frint-store-package] | State management with reactive stores |
| [frint-data] | [![frint-data-status]][frint-data-package] | Reactive data modelling |
| [frint-react] | [![frint-react-status]][frint-react-package] | React.js integration |
| [frint-react-server] | [![frint-react-server-status]][frint-react-server-package] | Server-side rendering of Apps |
| [frint-router] | [![frint-router-status]][frint-router-package] | Router services for building Single Page Applications |
| [frint-router-react] | [![frint-router-react-status]][frint-router-react-package] | React components for building SPAs |
| [frint-cli] | [![frint-cli-status]][frint-cli-package] | CLI runner |
| [frint-compat] | [![frint-compat-status]][frint-compat-package] | Backwards compatibility for older versions |
| [frint-model] | [![frint-model-status]][frint-model-package] | Use `frint-data` instead |
| **For library developers:** | | |
| [frint-component-utils] | [![frint-component-utils-status]][frint-component-utils-package] | Utils for reactive Components |
| [frint-component-handlers] | [![frint-component-handlers-status]][frint-component-handlers-package] | Handlers for integrating with other rendering libraries |
| **Internally used:** | | |
| [frint-test-utils] | [![frint-test-utils-status]][frint-test-utils-package] | Internally used test utilities |
| [frint-config] | [![frint-config-status]][frint-config-package] | Common config for your Apps |
| Package | Status | Description |
|------------------------------------|--------------------------------------------------------------------------------------|-------------|
| [frint] | [![frint-status]][frint-package] | Base for creating Apps |
| [frint-store] | [![frint-store-status]][frint-store-package] | State management with reactive stores |
| [frint-data] | [![frint-data-status]][frint-data-package] | Reactive data modelling |
| [frint-react] | [![frint-react-status]][frint-react-package] | React.js integration |
| [frint-react-server] | [![frint-react-server-status]][frint-react-server-package] | Server-side rendering of Apps |
| [frint-router] | [![frint-router-status]][frint-router-package] | Router services for building Single Page Applications |
| [frint-router-react] | [![frint-router-react-status]][frint-router-react-package] | React components for building SPAs |
| [frint-cli] | [![frint-cli-status]][frint-cli-package] | CLI runner |
| [frint-compat] | [![frint-compat-status]][frint-compat-package] | Backwards compatibility for older versions |
| [frint-model] | [![frint-model-status]][frint-model-package] | Use `frint-data` instead |
| **For library developers:** | | |
| [frint-component-utils] | [![frint-component-utils-status]][frint-component-utils-package] | Utils for reactive Components |
| [frint-component-handlers] | [![frint-component-handlers-status]][frint-component-handlers-package] | Handlers for integrating with other rendering libraries |
| [frint-router-component-handlers] | [![frint-router-component-handlers-status]][frint-router-component-handlers-package] | Handlers for integrating `frint-router` with other rendering libraries |
| **Internally used:** | | |
| [frint-test-utils] | [![frint-test-utils-status]][frint-test-utils-package] | Internally used test utilities |
| [frint-config] | [![frint-config-status]][frint-config-package] | Common config for your Apps |

[frint]: https://frint.js.org/docs/packages/frint
[frint-store]: https://frint.js.org/docs/packages/frint-store
Expand All @@ -73,6 +74,7 @@ The framework is a collection of these packages, which can be composed together
[frint-compat]: https://frint.js.org/docs/packages/frint-compat
[frint-component-utils]: https://frint.js.org/docs/packages/frint-component-utils
[frint-component-handlers]: https://frint.js.org/docs/packages/frint-component-handlers
[frint-router-component-handlers]: https://frint.js.org/docs/packages/frint-router-component-handlers
[frint-test-utils]: https://frint.js.org/docs/packages/frint-test-utils
[frint-config]: https://frint.js.org/docs/packages/frint-config

Expand All @@ -88,6 +90,7 @@ The framework is a collection of these packages, which can be composed together
[frint-compat-status]: https://img.shields.io/npm/v/frint-compat.svg
[frint-component-utils-status]: https://img.shields.io/npm/v/frint-component-utils.svg
[frint-component-handlers-status]: https://img.shields.io/npm/v/frint-component-handlers.svg
[frint-router-component-handlers-status]: https://img.shields.io/npm/v/frint-router-component-handlers.svg
[frint-test-utils-status]: https://img.shields.io/npm/v/frint-test-utils.svg
[frint-config-status]: https://img.shields.io/npm/v/frint-config.svg

Expand All @@ -103,6 +106,7 @@ The framework is a collection of these packages, which can be composed together
[frint-compat-package]: https://npmjs.com/package/frint-compat
[frint-component-utils-package]: https://npmjs.com/package/frint-component-utils
[frint-component-handlers-package]: https://npmjs.com/package/frint-component-handlers
[frint-router-component-handlers-package]: https://npmjs.com/package/frint-router-component-handlers
[frint-test-utils-package]: https://npmjs.com/package/frint-test-utils
[frint-config-package]: https://npmjs.com/package/frint-config

Expand Down
1 change: 1 addition & 0 deletions packages/frint-router-component-handlers/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/*.js
5 changes: 5 additions & 0 deletions packages/frint-router-component-handlers/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
src
test
coverage
node_modules
.nyc_output
73 changes: 73 additions & 0 deletions packages/frint-router-component-handlers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# frint-router-component-handlers

[![npm](https://img.shields.io/npm/v/frint-router-component-handlers.svg)](https://www.npmjs.com/package/frint-router-component-handlers)

> Router component handlers package of Frint
<!-- MarkdownTOC autolink=true bracket=round -->

- [Guide](#guide)
- [Installation](#installation)
- [API](#api)
- [createLinkHandler](#createlinkhandler)
- [createRouteHandler](#createroutehandler)
- [createSwitchHandler](#createswitchhandler)

<!-- /MarkdownTOC -->

---

# Guide

This package is aimed at enabling other reactive rendering/templating libraries integrate with FrintJS router, and not to be used directly by developers in their applications.

For example, take a look at `frint-router-react` for its implementation using this package internally.

## Installation

With [npm](https://www.npmjs.com/):

```
$ npm install --save frint-router-component-handlers
```

# API


## createLinkHandler

> createLinkHandler(ComponentHandler, app, component)
Method for creating handler for `Link` component.

#### Arguments

1. `ComponentHandler` (`Object`): framework specific component handler implementing common API to work with `component`
2. `app` (`Object`): app instance
3. `component` (`Object`): `Link` component instance


## createRouteHandler

> createRouteHandler(ComponentHandler, app, component)
Method for creating handler for `Route` component.

#### Arguments

1. `ComponentHandler` (`Object`): framework specific component handler implementing common API to work with `component`
2. `app` (`Object`): app instance
3. `component` (`Object`): `Route` component instance


## createSwitchHandler

> createSwitchHandler(ComponentHandler, app, component)
Method for creating handler for `Switch` component.

#### Arguments

1. `ComponentHandler` (`Object`): framework specific component handler implementing common API to work with `component`
2. `app` (`Object`): app instance
3. `component` (`Object`): `Switch` component instance
42 changes: 42 additions & 0 deletions packages/frint-router-component-handlers/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "frint-router-component-handlers",
"version": "3.0.1",
"description": "Router component handlers package for Frint",
"main": "lib/index.js",
"homepage": "https://github.com/Travix-International/frint/tree/master/packages/frint-router-component-handlers",
"scripts": {
"lint": "cross-env ../../node_modules/.bin/eslint --color '{src,test}/**/*.js'",
"transpile": "cross-env ../../node_modules/.bin/babel src --out-dir lib",
"test": "cross-env ../../node_modules/.bin/mocha --colors --compilers js:babel-register --recursive ./src/**/*.spec.js",
"cover:run": "cross-env ../../node_modules/.bin/nyc --reporter=json --require babel-register ../../node_modules/.bin/mocha --colors --compilers js:babel-register --recursive ./src/**/*.spec.js",
"cover:report": "cross-env ../../node_modules/.bin/nyc report",
"cover": "npm run cover:run && npm run cover:report",
"dist:lib": "cross-env ../../node_modules/.bin/webpack --config ./webpack.config.js",
"dist:min": "cross-env DIST_MIN=1 ../../node_modules/.bin/webpack --config ./webpack.config.js",
"dist": "npm run dist:lib && npm run dist:min",
"prepublish": "npm run transpile"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Travix-International/frint.git"
},
"author": {
"name": "Travix International B.V.",
"url": "https://travix.com"
},
"keywords": [
"frint"
],
"dependencies": {
"frint-component-utils": "^3.0.1"
},
"devDependencies": {
"cross-env": "^5.0.5",
"frint-router": "^3.0.1",
"frint": "^3.0.1"
},
"bugs": {
"url": "https://github.com/Travix-International/frint/issues"
},
"license": "MIT"
}
74 changes: 74 additions & 0 deletions packages/frint-router-component-handlers/src/createLinkHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { composeHandlers } from 'frint-component-utils';

const LinkHandler = {
_routerSubscription: null,

getInitialData() {
return {
active: false,
};
},

beforeMount() {
this._resubscribeToRouter(this.getProps());
},

propsChange(nextProps, toChanged, exactChanged) {
this._resubscribeToRouter(nextProps, toChanged, exactChanged);
},

beforeDestroy() {
this._unsubscribeFromRouter();
},

handleClick() {
const router = this._getRouter();
const to = this.getProp('to');

if (router.getMatch(to, router.getHistory(), { exact: true }) === null) {
router.push(to);
}
},

_getRouter() {
return this.app.get('router');
},

_resubscribeToRouter(nextProps, toChanged = false, exactChanged = false) {
const { activeClassName, to, exact } = nextProps;

this._unsubscribeFromRouter();

if (typeof activeClassName === 'string') {
if (!this._routerSubscription || toChanged || exactChanged) {
this._routerSubscription = this._getRouter()
.getMatch$(to, { exact })
.subscribe((matched) => {
if (!matched) {
return this.setData('active', false);
}

return this.setData('active', true);
});
}
}
},

_unsubscribeFromRouter() {
if (this._routerSubscription) {
this._routerSubscription.unsubscribe();
this._routerSubscription = null;
}
},
};

export default function createLinkHandler(ComponentHandler, app, component) {
return composeHandlers(
LinkHandler,
ComponentHandler,
{
app,
component
},
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/* eslint-disable import/no-extraneous-dependencies, func-names, no-unused-expressions */
/* global describe, it */
import { expect } from 'chai';

import { MemoryRouterService } from 'frint-router';
import createLinkHandler from './createLinkHandler';
import { ComponentHandler, createTestAppInstance, createComponent } from './testHelpers';

describe('frint-router-component-handlers › createLinkHandler', function () {
it('creates a handler with getInitialData, beforeMount, propsChange, handleClick, beforeDestroy methods', function () {
const handler = createLinkHandler(
ComponentHandler,
createTestAppInstance(new MemoryRouterService()),
createComponent()
);

expect(handler).to.include.all.keys('getInitialData', 'beforeMount', 'propsChange', 'handleClick', 'beforeDestroy');
});

describe('LinkHandler functions properly throughout lifecycle', function () {
const router = new MemoryRouterService();

const component = createComponent();
component.props.to = '/about';
component.props.exact = false;
component.props.activeClassName = 'active-link';

const handler = createLinkHandler(
ComponentHandler,
createTestAppInstance(router),
component
);

it('when getInitialData() called, it returns object with active key', function () {
component.data = handler.getInitialData();
expect(component.data).to.have.all.keys({ active: false });
});

it('when beforeMount() called, subscribes to router and changes active data accordingly', function () {
handler.beforeMount();
expect(component.data.active).to.be.false;

router.push('/about');

expect(component.data.active).to.be.true;
});

it('when props change and propsChange() called, it resubscribes to router and changes active data accordingly', function () {
component.props.to = '/contact';
handler.propsChange(component.props, true, false);

expect(component.data.active).to.be.false;

router.push('/contact/us');
expect(component.data.active).to.be.true;
});

it('when handleClick() is called, it changes router url', function () {
expect(router.getLocation().pathname).to.equal('/contact/us');

handler.handleClick();

expect(router.getLocation().pathname).to.equal('/contact');
});

it('when beforeDestroy() is called, unsubscribes from router and doesn\'t change active data anymore', function () {
expect(component.data.active).to.be.true;

handler.beforeDestroy();
router.push('/random');
expect(component.data.active).to.be.true;
});
});
});
Loading

0 comments on commit 3cb8104

Please sign in to comment.