Spiel client is a flexible and light frontend framework to make easier create a complex and modern applications for the client side. It joins two light but powerful libraries: Ultradom and Navigo.
import {IConfigRouters} from "spiel-client";
import {genericHooks, hooks} from "./hooks";
import {page1, page2, page3, page4, notFound} from './Pages'
export const configSettings: IConfigRouters = {
default: "/home",
defaultProps: "default",
genericHooks,
hash: "#!",
notFound: true,
notFoundPath: "/not-found",
rootPath: "http://localhost:9876/",
routers: [{
page: Page1,
path: "/home",
routers: [{
alias: "child",
hooks,
page: Page2,
path: "/child/:number",
routers: [{
alias: "grandchild",
page: Page3,
path: "/child2/:word",
}],
}, {
defaultProps: "my own prop",
page: Page4,
path: "/brother",
}],
},
{
page: notFound,
path: "/not-found",
}],
useHash: true,
};
srouter.setRouters(configDefault).resolve();
srouter.setRouters();
const router = srouter.router;
router.on({
'/user/:id': {
as: 'user', uses: (params, query) => {
Object.assign(page2.state, params);
render(page2.view, page2.state);
}
}
});
router.resolve();
const configDefault: IConfigRouters = {
routers: [{
alias: 'user'
default: '/user'
page: page1,
path: '/user/:id',
}]
};
srouter.setRouters(configDefault).resolve();
const router = srouter.router;
console.log(router.generate('user', {id: 4})); // #/user/4
You can pass object with srouter.go
and recover it with lastState
state property:
export class TestPage4 {
public state = {
title: "Hello brother",
};
public view(state: State): JSXElements {
return (
<div>
<h1>{state.title}</h1>
<h2>{state.lastState}</h2>
<button
onclick ={() => {
state.title = "Yes brother";
srouter.go("/home/brother", {title: state.title});
render(testPage4.view, state);
}}
>Change Title</button>
<a href="/home" data-navigo>go to root</a>
</div>
);
}
}
export const genericHooks: IGenericHooks = {
after: (params: Params) => {
if (params && params.number) {
params.number = +params.number + 2;
}
},
before: (done: (suppress?: boolean) => void, params: Params) => {
if (params && params.number) {
params.number = +params.number + 2;
}
done();
},
};
export const hooks: IHooks = {
after: (params: Params) => {
if (params) {
params.number = +params.number + 2;
}
},
already: (params: Params) => {
if (params) {
params.number = +params.number + 2;
}
},
before: (done: (suppress?: boolean) => void, params: Params) => {
if (params) {
params.number = +params.number + 2;
}
done();
},
leave: (params: Params) => {
if (params) {
params.number = +params.number + 2;
}
},
};
import { Children, h, IPage, JSXElements, srouter, State, VNode } from "../../../src";
interface IShow {
value: string;
onGo: () => void;
}
export class Page5 implements IPage {
public state = {
text: "This is a component",
};
public view(state: State): JSXElements {
return(
<Show value={state.text} onGo={() => srouter.go("/")}>
<span>And this is its child</span>
</Show>
);
}
}
function Show({value, onGo}: IShow, children: Children) {
return (
<div>
<span>{value}</span>
<div id="child">{children}</div>
<button id="go-parent" onclick={() => srouter.go("/")}></button>
</div>
);
}
export const page5 = new page5();
Note: you need to export the singleton of the class and always import h
to render the views
To know more about the views see more in ultradom.
All the ultradom functionalities like patch
, h
etc... are available in spiel-client
This is a tsconfig example:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"sourceMap": true,
"strict": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"declaration": true,
"outDir": "./lib",
"rootDir": ".",
"jsx": "react",
"jsxFactory": "h"
},
"include": [
"./src",
"./example"
],
"exclude": [
"node_modules"
]
}
Remember always to put h
in the jsxFactory
option.
Create your mocks:
import { Children, h, IPage, JSXElements, State, VNode } from "../../src";
interface IShow {
value: string;
}
export class ComponentTest implements IPage {
public state = {
text: "This is a component",
};
public view(state: State): JSXElements {
return(
<Show value={state.text}>
<span>And this is its child</span>
</Show>
);
}
}
function Show({value}: IShow, children: Children) {
return (
<div>
<span>{value}</span>
<div id="child">{children}</div>
</div>
);
}
export const componentTest = new ComponentTest();
and your file spec:
import { assert, expect } from "chai";
import { h, patch, VNode} from "../../src";
import {componentTest} from "./mocks";
describe("Component", () => {
let nodes: VNode<any>;
before(() => {
nodes = h(componentTest.view, componentTest.state);
});
it("has to be created", () => {
const text: any = nodes.children.find((node: any) => node.nodeName === "span");
expect(text.children[0]).has.to.be.equal("This is a component");
});
it("has to exist its children", () => {
const child: any = nodes.children.find((node: any) => node.nodeName === "div");
const text: any = child.children.find((node: any) => node.nodeName === "span");
expect(text.children[0]).has.to.be.equal("And this is its child");
});
});
tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"sourceMap": true,
"strict": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"declaration": true,
"outDir": "./lib",
"rootDir": ".",
"jsx": "react",
"jsxFactory": "h"
},
"include": [
"./src",
"./example"
],
"exclude": [
"node_modules"
]
}
In your code:
import 'es6-shim'; // or every polyfill which you need
import { srouter, IConfigRouters } from 'spiel-client';
npm test
Spiel Client is MIT licensed. See license