hta
Version:
The tiny framework for building Hyper Text Application with ease
210 lines (160 loc) • 6.29 kB
Markdown
# HTA
The tiny framework for building Hyper Text Application with ease
## Why HTA ?
- Write less do more
- No compiler or bundler needed
- Easy to convert HTML template to HTA
- Extremely fast DOM updating
- Built-in store and router
## Installation
```
npm install hta --save
```
## Comparison with Other Frameworks
### Syntax
Let's create simple counter app
### HTA
```js
import { $, render } from "hta";
const initialState = { count: 0 };
const Increase = ({ count }) => ({ count: count + 1 });
const CounterValue = (props, select) => $`<h1>${select("count")}</h1>`;
const CounterAction = () =>
$`<button ${{ onclick: [Increase] }}>Increase</button>`;
const App = () => $`
${CounterValue}
${CounterAction}`;
render(App, { state: initialState });
```
### React + Redux Toolkit
```jsx
import React from "react";
import { render } from "react-dom";
import { connect, Provider } from "react-redux";
import { configureStore, createAction, createReducer } from "@reduxjs/toolkit";
const increment = createAction("INCREMENT");
const reducer = createReducer(0, {
[increment.type]: (state) => state + 1,
});
const store = configureStore({ reducer });
const CounterValue = connect((state) => ({ count: state }))(({ count }) => (
<h1>{count}</h1>
));
const CounterAction = connect(null, { increment })(({ increment }) => (
<button onClick={increment}>Increase</button>
));
const App = () => (
<>
<Provider store={store}>
<CounterValue />
<CounterAction />
</Provider>
</>
);
render(<App />, document.body);
```
## Features
| Feature | HTA | React | Vue | Angular |
| :------------------------ | :-----: | :-----: | :-----: | :-----: |
| Compiler / Bundler needed | | ☑ | ☑ | ☑ |
| Async Rendering | ☑ | | | |
| Two Way Binding | ☑ | | ☑ | ☑ |
| SVG Supported | ☑ | | ☑ | ☑ |
| Directive | ☑ | | ☑ | ☑ |
| Built-in Router | ☑ | | | ☑ |
| Built-in Store | ☑ | | | |
| Suspense | ☑ | ☑ | | |
| Declarative | ☑ | ☑ | | |
| Component | ☑ | ☑ | ☑ | ☑ |
| Functional Hooks | ☑ | ☑ | ☑ | |
| Lazy Component | ☑ | ☑ | ☑ | ☑ |
| Shared Context | ☑ | ☑ | ☑ | ☑ |
## Basic Usages
### Render simple HTML
```js
import { $, render } from "hta";
render($`<h1>Hello World</h1>`);
```
### Using substitutions
```js
import { $, render } from "hta";
render($`<h1>It is ${new Date().toLocaleTimeString()}.</h1>`);
```
If the substitution is:
- **string/number/Date**: It will be rendered as text node
- **boolean/undefined/null**: It will not be rendered
- **Function**: HTA understands the function is component and render the component content/result
- **Tuple \[Function, object\]**: HTA renders component with specified props (the second item of tuple)
- Promise/Plain object: By default HTA renders these text node, and the node value is toString() result,
but you can add extras (please refer JSON tag extras) to handle plain object rendering.
### Using element binding
```js
import { $, render } from "hta";
render(
// add style attribute and textContent property bindings to DIV element
$`<div ${{ style: "font-weight: bold", textContent: "Hello World" }}></div>`
);
```
The binding must be placed in open tag. You can bind any element property / attribute.
#### Handling element event
```js
import { $, render } from "hta";
render($`<button ${{ onclick: () => alert("Hello World") }}>Click me</button>`);
```
> HTA treats the binding which starts with on\*\*\* as event handler.
> If you want to bind some element property/attribute which starts with on\*\*\* ?
> Using { attr: { attrName: value } } for attribute binding and { prop: { propName: value } } for property binding
#### Updating element text
There are 2 ways to update element text
1. Using text / textContent binding
1. Using substitution is more flexible than above
```js
import { $, render } from "hta";
render($`
<button ${{ text: "Button 1" }}></button>
<button ${{ textContext: "Button 2" }}></button>
<button>${"Button 3"} ${"Other text"}</button>
`);
```
#### Updating element HTML
There are 2 ways to update element HTML
1. Using text / textContent binding
1. Using substitution is more flexible than above
```js
import { $, render } from "hta";
render($`
<button ${{ html: "<strong>Button 1</strong>" }}></button>
<button ${{ innerHTML: "<strong>Button 2</strong>" }}></button>
<button>${$`<strong>Button 3</strong>`} ${$("Other HTML")}</button>
`);
```
### Component
HTA component is pure function, that receives component props and return component content
```js
function MyComponent(props) {
return $`<h2>Hello ${props.name}</h2>`;
}
function App() {
return $`
<h1>Component Demo</h1>
<!-- passing tuple to substitution to render MyComponent with specified props -->
${[MyComponent, { name: "World" }]}
`;
}
render(App);
```
> Component content is anything, it is the same as substitution
## Advanced Usages
## Examples
- [Todo MVC(140 lines of code)](https://codesandbox.io/s/hta-todomvc-76dib?file=/src/index.js)
- [Todo App (4000 todos)](https://codesandbox.io/s/hta-todo-performance-forked-1xmx5?file=/src/index.js)
- [Crypto Search (5600 coins)](https://codesandbox.io/s/hta-crypto-search-rv39j?file=/src/hta/index.js)
- [Silky Smooth (Fast enough to render over 500 elements at 60fps)](https://codesandbox.io/s/hta-silky-smooth-2-s3l3r?file=/src/index.js)
- Performance testing
- [hta](https://codesandbox.io/s/hta-v1-performance-b3dou?file=/src/index.js)
- [react + redux](https://codesandbox.io/s/redux-performance-hbit7)
- SVG Animation
- [hta](https://codesandbox.io/s/hta-v1-balls-anim-90v1j?file=/src/index.js)
- [d3js](http://tommykrueger.com/projects/d3tests/performance-test.php)
- (more examples)[https://github.com/linq2js/hta/tree/master/examples]
## API references