# jigjs

> A front-end library

Latest version **0.0.0-pre-alpha.31** (published 2020-07-21) · MIT license · 0 weekly downloads

## Install

```sh
npm install jigjs
pnpm add jigjs
yarn add jigjs
bun add jigjs
```

Provides the commands `jigjs-build`, `jigjs-new-project`.

## Health

**Score 25/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities; high quality score.

Warnings: low downloads; no esm support; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.0.0-pre-alpha.31 |
| Published | 2020-07-21 |
| First published | 2020-05-17 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 10 |
| Unpacked size | 256.6 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 24 |
| Author | Carlos Maniero |
| Maintainers | carlosmaniero |
| Keywords | dom, template, literals, lightweight |

## Links

- npm: https://www.npmjs.com/package/jigjs
- Repository: https://github.com/carlosmaniero/jigjs
- Homepage: https://github.com/carlosmaniero/jigjs#readme
- Issues: https://github.com/carlosmaniero/jigjs/issues
- npm.io page: https://npm.io/package/jigjs

## Dependencies (10)

- [ncp](https://npm.io/package/ncp.md) ^2.0.0
- [chalk](https://npm.io/package/chalk.md) ^4.0.0
- [jsdom](https://npm.io/package/jsdom.md) ^16.2.2
- [express](https://npm.io/package/express.md) ^4.17.1
- [prompts](https://npm.io/package/prompts.md) ^2.3.2
- [ts-node](https://npm.io/package/ts-node.md) ^8.9.1
- [morphdom](https://npm.io/package/morphdom.md) ^2.6.1
- [ts-loader](https://npm.io/package/ts-loader.md) ^7.0.4
- [typescript](https://npm.io/package/typescript.md) ^3.9.6
- [route-parser](https://npm.io/package/route-parser.md) ^0.0.5

## Alternatives

- [babylon](https://npm.io/package/babylon.md) — 5.1M weekly downloads
- [csscolorparser](https://npm.io/package/csscolorparser.md) — 3.7M weekly downloads
- [expr-eval-fork](https://npm.io/package/expr-eval-fork.md) — 1.5M weekly downloads
- [@leeoniya/ufuzzy](https://npm.io/package/@leeoniya/ufuzzy.md) — 247.7K weekly downloads
- [xml-parser](https://npm.io/package/xml-parser.md) — 78.4K weekly downloads

## Recent versions

- 0.0.0-pre-alpha.31 (latest) — 2020-07-21
- 0.0.0-pre-alpha.30 — 2020-07-19
- 0.0.0-pre-alpha.29 — 2020-07-19
- 0.0.0-pre-alpha.28 — 2020-07-19
- 0.0.0-pre-alpha.27 — 2020-07-19
- 0.0.0-pre-alpha.26 — 2020-07-19
- 0.0.0-pre-alpha.25 — 2020-07-19
- 0.0.0-pre-alpha.24 — 2020-07-18
- 0.0.0-pre-alpha.23 — 2020-07-18
- 0.0.0-pre-alpha.22 — 2020-07-17
- 0.0.0-pre-alpha.21 — 2020-07-17
- 0.0.0-pre-alpha.20 — 2020-07-16
- 0.0.0-pre-alpha.19 — 2020-07-14
- 0.0.0-pre-alpha.18 — 2020-07-12
- 0.0.0-pre-alpha.17 — 2020-07-12
- … 17 more at https://npm.io/package/jigjs/versions

## README

<p align="center" style="color: #343a40">
  <p align="center" >
    <img src="jig/ghassets/logo.svg" alt="jigjs" align="center">
  </p>
  <h1 align="center">a front-end framework</h1>
</p>

![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)![Jig](https://github.com/carlosmaniero/jigjs/workflows/Jig/badge.svg) 
![npm version](https://badge.fury.io/js/jigjs.svg)
[![Coverage Status](https://codecov.io/gh/carlosmaniero/jigjs/branch/main/graph/badge.svg?flag=jigjs)](https://codecov.io/gh/carlosmaniero/jigjs) 
![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)

jigjs is a web library that combines reactiveness with OOP. Making it easy to react to
object side-effects.


```typescript
import {observable, observing, observe} from "jigjs/reactive";

@observable()
class Greater {
    @observing()
    private name;

    constructor(name: string) {
        this.name = name;
    }

    say() {
        return `Hello, ${this.name}!`
    }
    
    updateName(name: string) {
        this.name = name;
    }
}

const greater = new Greater("World!");

const subscription = observe(greater, () => {
    console.log(greater.say());   
});

greater.updateName('Universe'); // calls the observer and prints "Hello, Universe"
greater.updateName('Mars'); // calls the observer and prints "Hello, Mars"

subscription.unsubscribe();

greater.updateName('Earth'); // does not prints anything
``` 

## Installation

```bash
npm install -g jigjs 
```

## Components

A component is a small UI peace that manages its own state. Whenever the class fields
decorated with `@observing` changes the component is re-rendered.

```typescript
import {component, html} from "jigjs/components";
import {observing} from "jigjs/reactive";

@component()
export class CounterComponent {
    @observing()
    private number: number;

    constructor(initialCount = 0) {
        this.number = initialCount;
    }

    reset() {
       this.number = 0;
    }

    render() {
        return html`
            <button onclick="${() => { this.number++ }}">+</button>
            ${this.number}
            <button onclick="${() => { this.number-- }}">-</button>
        `;
    }
}
```
 
Using the component: 

```typescript
import {component, html, renderComponent} from "jigjs/components";

@component()
export class CounterPage {
    private readonly counter: CounterComponent;

    constructor() {
        this.counter = new CounterComponent();
    }

    render() {
        return html`
            <h1>Counter</h1>
        
            ${this.counter}

            <hr>
    
            <button onclick=${this.counter.reset()}>Reset counter</button>
        `;
    }
}

renderComponent(document.querySelector('#root'), new CounterPage());
```

In jigjs you control the component instance. There isn't a magic way to update a component props. The component props
is its state, and you update it by using class methods.

## Styling the component

There is a css-in-js module for jigjs.

Read more about jigcss [here](/jigcss).

## Creating an APP

As showed in the previous example, you can use jigjs as a simple library by using the `renderComponent` function.
However, it is also possible to use jigjs as a framework.

To start a jigjs project you can use the cli:

```bash
npm install -g jigjs
npx jigjs-new-project
``` 

![Installation demo](jig/ghassets/gif-fast.gif)

It comes with a `Router` system that enables `Single Page Applications`, Native `Server Side Rendering` and built-in 
`build system`.

### Routing

A router is composed by a `path`, a `name` and `handler`. 

- `path` is used to match the user request.
- `name` is used to reverse a route.
- `handler` is called when the path matches the user request.

```typescript
new Routes([
    {
        path: '/',
        name: 'index',
        handler(params, render) {
            render(new IndexPage());
        }
    },
    {
        path: '/hello/:name',
        name: 'hello',
        handler(params, render) {
            render(new HelloPage(params.name));
        }
    },
    {
        path: '/hello/?name=:name',
        name: 'hello:with-query',
        handler(params, render) {
            render(new HelloPage(params.name));
        }
    },
    {
        path: '/hello/#:name',
        name: 'hello:with-hash',
        handler(params, render) {
            render(new HelloPage(params.name));
        }
    }
]);
```

For more examples of router matchers: https://github.com/rcs/route-parser

### Navigation

To redirect users to a specific URL you can use the `Navigation` object.

```typescript
 const routerModule = new RouterModule(window, platform, new Routes([
    {
        path: '/',
        name: 'index',
        handler() {
            // ...
        }
    },
    {
        path: '/hello/:name',
        name: 'hello',
        handler() {
            // ...
        }
    }
]));

routerModule.navigation.navigateTo('hello', {name: 'world'});
routerModule.navigation.navigateTo('index');
```

### Async Handlers

When you need to process async functions in your components you can make your handler to return a promise.

```typescript
const routerModule = new RouterModule(window, platform, new Routes([
    {
        path: '/user/:id',
        name: 'show-user',
        async handler(params, render) {
            render(new PageLoadingComponent());
            const user = await fetchUser(params.id);
            render(new UserPage(user));
        }
    }
]));
```

The server will only release the request when the promise is resolved. You can call the `render` function as much as
you want, this is useful to render loading components that will be visible when the code is executed from the 
client-side.

### Custom Response

The handler receives the response object that can be used to add custom headers and status code.

There is no need to specify the response body since it will be always the render result.

```typescript
const routerModule = new RouterModule(window, platform, new Routes([
    {
        path: '/user/:id',
        name: 'show-user',
        async handler(params, render, transferState, response) {
            try {
                const user = await fetchUser(params.id);
                render(new UserPage(user));
            } catch(e) {
                response.statusCode = 404;
                response.headers['custom-error'] = 'User not found';

                render(new UserNotFoundPage());
            }
        }
    }
]));
```

### Transfer State

When you make a request to the jigjs server, it will pre-render the entire page and return it as raw HTML. Coming to 
browser, jigjs will execute the same code that had executed on server. It means that, any request you performed at the
server-side will be performed again.

To prevent this kind of behavior you must use `TransferState`. The`TransferState` is a key-value object that can 
be shared from server to browser. Once the server stores a value using `TransferState.setState` it will be available 
to browser thought the `TransferState.getState`.

```typescript
const routerModule = new RouterModule(window, platform, new Routes([
    {
        path: '/my-transfer-state-page',
        name: 'my-transfer-state-page',
        async handler(params, render, transferState) {
            if (transferState.hasState('page-title')) {
                render(new MyPage(transferState.getState('page-title')));
                return;
            }

            render(new PageLoadingComponent());
            const pageTitle = await asyncMethodThatReturnsANicePageTitle();
            transferState.setState('page-title', pageTitle);
            render(new MyPage(pageTitle));
        }
    }
]));
```

### SSR limitations

There is no global variable like `window` or `document` because global variables into a back-end application leads to concurrency
issues. If you want to access the `window` or `document` you can use the window injected into the `AppFactory`.

For third-party libraries you can use the `Platform` object to verify if the code is being executed from browser.

---
_Source: https://npm.io/package/jigjs · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
