tsui
v0.0.1
Published
Front-end framework for typescript projects
Downloads
5
Maintainers
Readme
TSui
TypeScript user interface.
Installation
You should install it both globally (for command line usage) and locally.
npm i --save tsui && npm i -g tsui
Notice: The global installation will just act as an interface to listen to your command line inputs, while the local installation is the one responsible for compiling and providing dependencies. This way you can depend on a specific version of this framework regardless of the globally installed version.
Usage
This is not just a front end framework, I actually created as a solution for all the mess that I have to deal with while writing my application's front end. So a module bundler (rollup) and a transpiler (babel) is included.
Starting by writing your components, typically each component should be a class in a file with a render method
that returns a JSX object.
// file: component.tsx
import {Component} from 'tsui';
// the class should extend
// the Component class in the framework
export default class extends Component {
render(state) {
return (<p>My name is {state.name}</p>);
}
}
Then you application file import this class, create a new instance of it with an initial state and mount it to an element:
// file app.ts
import Component from "./component.tsx";
// instantiate
const component = Component({
// initial state
name:"Bond, James Bond"
});
// mount it
component.mount("element-id");
// then you can update the state like this:
component.update({
// new state
name:"Alex"
});
// HTML view will update automatically
Then you can compile your typescript code and component into a transpiled single file JavaScript using the tsui command
tsui app.ts
And you'll get a file (app.js
) will be generated that is consumable by the browser.
Component API
When instantiating a component the following methods and properties will be available to you:
Get the component state
The component state is the state
property of the initialized component:
import Component from "./component.tsx";
const component = Component({name:"Alex"});
component.mount("element-id");
console.log(component.state.name);
// > "Alex"
// Important:
// setting the name to "Dan" like the following:
component.state.name = "Dan";
// will not be reflected to the DOM unless you call the update method
component.update({});
// thus it's always better to just call the update
// method with any state change you'd like
// (below)
Update the component state
component.mount("element-id");
component.update({name:"Dan"});
Note an update must be carried out only after mounting the component to a parent element.
Mount and Destroy
The mount method must be given an element ID.
component.mount("element-id");
otherwise it will complain that it didn't find the element specified with the given ID.
Destroy component
Basically it will remove the component root element
component.destroy();
Observe state change
You can set a callback for a specific state changes in the component
component.observe("name",(oldVal,newVal) => {
console.log(oldVal,newVal);
});
Cancel observance
When observing a state change a unique identifier will be given to that observer, you can pass this unique identifier to the cancel
method and your callback method will not by called anymore.
const observer1 = component.observe("name",(oldVal,newVal) => {
console.log(oldVal,newVal);
});
component.update({name:"Alex"});
// callback will be called
component.cancel(observer1);
component.update({name:"James Bond"});
// callback will NOT be called
Life Cycle Events in the Components
There are 4 life cycle events for your component:
onInit
: Your component has been constructedonMount
: Your component has been mounted to the DOMonUpdate
: Your component state has been updatedonDestroy
: Your component has been destroyed/demounted from the DOM.
You can use those life cycle event in your component:
// file: component.tsx
import {Component} from 'tsui';
// the class should extend
// the Component class in the framework
export default class extends Component {
render(state) {
return (/*what ever*/);
}
onInit(state){
console.log(state);
}
onMount($parent,state){
console.log($parent,state)
}
onDestroy($parent,state){
console.log($parent,state)
}
onUpdate(newState,oldState){
console.log(newState,oldState)
}
}
DOM events
All vanilla javascript DOM events are supported like onclick
, onchange
, onDblClick
... etc But you have to capitalize the first letter.
// file: component.tsx
import {Component} from 'tsui';
export default class extends Component {
render(state) {
return (<button OnClick={handlers.click}>Click me, {state.name}</button>);
}
}
const handlers = {
click:function(){
// the context of event function is the DOM element
// so inside this function `this` refers to the DOM element
// just like vanilla javascript
console.log(this); // logs the DOM element in question
// However, all dom elements that has been created
// in this component has a `component` attribute that refers to
// this instance of the component
// so you can do the following:
this.component.update({name:"Alex"});
}
}
Custom events
A custom event can by anything, called anything, passed anything, triggered anywhere, and being listened to anywhere.
// In your application
import Component from "./component.tsx";
const component = Component({name:"Alex"});
component.mount("element-id");
// Once you started listening to a custom event
// you've practically created one:
// listen to: "myEvent":
component.on("myEvent",function(a,b,c){
console.log(a,b,c);
});
// trigger my event
component.trigger("myEvent",1,2,3);
// first argument: event name
// all other argument are callback arguments
// Multiple listeners can be set to a single custom event:
component.on("myEvent",function(a,b,c){
console.log(a*b*c) // 6
});
// file: component.tsx
import {Component} from 'tsui';
export default class extends Component {
render(state) {
return (<button OnClick={this.trigger("myEvent","hello","world")}>Click me, {state.name}</button>);
}
// register a listener from inside the component
onMyEvent:function(a,b){
console.log(a+" "+b) // hello world
}
}
Surely, a custom event can get listened to in your app.ts
and triggered inside your component.
Child components
A child component can be used in the render method and it's props will be considered as it's state:
// file: child.tsx
import {Component} from 'tsui';
export default class extends Component {
render(state) {
return (<span>name: {state.name}, age: {state.age}</span>);
}
}
// file: component.tsx
import {Component} from 'tsui';
import Child from "./child";
export default class extends Component {
render(state) {
return (
<div>
<Child name="alex" age={state.age}/>
</div>
);
}
}
Type definitions for your state
To get the full out of typescript definitions you can define your components constructor function and update method with a parameter and an interface, but remember to call the super methods.
import {Component} from 'tsui';
interface State {
name:string,
age:number
}
export default class extends Component {
constructor(state:State){
super(state);
}
update(state:State){
super.update(state)
}
render(state) {
return (/*anything*/);
}
}