npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

tsui

v0.0.1

Published

Front-end framework for typescript projects

Downloads

5

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 constructed
  • onMount: Your component has been mounted to the DOM
  • onUpdate: Your component state has been updated
  • onDestroy: 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*/);
	}
}

Examples