Skip to content

hstd-dev/hstd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

429 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HyperStandard Main Image

HyperStandard

Fast. Interactive. Web Interface.


Open in StackBlitz NPM version NPM package minimized gzipped size

import { $, h as html, on } from "hstd"


const Component = () => {

    const count = $(0);

    return html`
        <h1>Count is ${count}</h1>
        <button ${{ [on.click]: () => count.$++ }}>
            Add more!
        </button>
    `;
}


document.body[html] = Component();

hstd = HyperStandard is a minimal JavaScript library to build fast, interactive, extensible web interface. Visit live demo.



Getting Started

npm create hstd my-app
cd my-app
npm install
npm run dev

Use --ts for TypeScript with @hstd/ts IntelliSense:

npm create hstd my-app --ts

Install

Scaffold with Vite

npm create hstd my-app

NPM

npm i @hstd/std

HTTP

import { $, h as html } from "https://hstd.io";

ImportMap

{
    "imports": {
        "@hstd/std": "https://hstd.io"
    }
}

Examples

Class-model

import { $, h as html, on, css } from "@hstd/std"

const buttonClass = $((alertText) => ({
    [css]: {
        color: "white",
        backgroundColor: "blue",
    },
    [on.click]: () => alert(alertText)
}))

const Main = () => {

    const count = $(0);

    return html`
        <button ${{ [on.click]: () => count.$++, [buttonClass]: "hi" }}>
            I'm styled ${count}!
        </button>
    `
}

Interactive binding

import { $, h as html, io } from "@hstd/std"

const Linked = () => {

    const valueHolder = $(0)

    return html`
        <h1>these are linked!</h1>
        <input ${{ [io.value]: valueHolder, type: "range" }}>
        <input ${{ [io.value]: valueHolder, type: "range" }}>
        <label>value is ${valueHolder}</label>
    `
}

Post-processing

const Canvas = () => {

    const colorSwitch = $(true);

    return html`
        <canvas ${{ id: "color", [on.click]: () => colorSwitch.switch() }}></canvas>

    `.on(({ color }) => {

        const ctx = color.getContext("2d");
        colorSwitch.into($ => $ ? "red" : "blue").watch($ => {
            ctx.fillStyle = $;
            ctx.fillRect(0, 0, 100, 100);
        });
    })
}

Works with Async Iterator

import { $, h as html, io } from "@hstd/std";


const Iterated = async function*() {

    const
        user = $(''),
        { promise, resolve } = Promise.withResolvers()
    ;

    yield html`
        <label>Show user <input ${{ [io.value]: user }}/></label>
        <button ${{ [on.click]: resolve }}>submit</button>
    `;

    await promise;

    yield html`
        <label>Loading...</label>
    `;

    const { name, age, link } = await fetch(`/api/user/${user.$}`).then(res => res.json());

    yield html`
        <div>
            <label>${name}</label>
            <label>${age}</label>
            <label>${link}</label>
        </div>
    `;

}


document.body[html] = Iterated();

Reactive Arrays

import { $, h as html, on, io } from "@hstd/std"

const TodoApp = () => {

    const todos = $(["Buy milk", "Walk dog"]);
    const input = $('');

    return html`
        <ul>${todos.into(item => html`<li>${item}</li>`)}</ul>
        <input ${{ [io.value]: input }}>
        <button ${{ [on.click]: () => { todos.push(input.$); input.$ = ''; } }}>
            Add
        </button>
    `
}

$([...]) creates an ArrayPointer that tracks mutations (push, pop, shift, unshift, splice, sort, reverse, swap, set) and updates the DOM automatically. Derived queries like find, includes, some, every, reduce return reactive Pointers.

Template Literal Pointer

import { $, h as html, css } from "@hstd/std"

const Animated = () => {

    const rotation = $(0);
    const scale = $(1);
    const transform = $`rotate(${rotation}deg) scale(${scale})`;

    return html`
        <div ${{ [css.transform]: transform }}>Hello</div>
    `
}

$`...` creates a Pointer that interpolates reactive values into a string. When any interpolated Pointer changes, the string updates automatically.

Property Bundle Reference

import { $, h as html, css } from "@hstd/std"

const Themed = () => {

    const primary = $("royalblue");

    return html`
        <div ${{
            [css]: {
                backgroundColor: primary,
                color: $.this.backgroundColor,
                borderColor: $.this.color,
                border: "2px solid",
            }
        }}>
            color follows backgroundColor
        </div>
    `
}

$.this.propertyName creates a DeferredPointer that references another property within the same attribute object. The reference is resolved at render time.

Derived Pointers

import { $, h as html, io } from "@hstd/std"

const Dashboard = () => {

    const query = $('');
    const debounced = query.timeout(300);
    const status = debounced.into(q => q ? `Searching: ${q}` : "Type to search");

    return html`
        <input ${{ [io.value]: query, placeholder: "Search..." }}>
        <p>${status}</p>
    `
}

Pointers support chained derivations: .into(fn), .not(), .bool(), .isit(ifTrue, ifFalse), .timeout(ms), .until(value), .sum(n), .sub(n), .mul(n), .div(n), .mod(n), .is(v), .seq(v), .or(v), .and(v).

Runtime Validation

hstd validates bindings at runtime and throws descriptive errors for common mistakes:

// Position mismatch
html`<div>${{ color: "red" }}</div>`      // Error: Object literal in body position
html`<div ${"hello"}>text</div>`          // Error: string in attribute position

// Type mismatch
html`<div ${{ [on.click]: "str" }}>...`   // Error: on.click requires a function
html`<div ${{ [css.color]: () => {} }}>…` // Error: css.color requires a string, number, or Pointer
html`<input ${{ [io.value]: "str" }}>…`   // Error: io.value requires a Pointer

// Element mismatch
html`<div ${{ [io.value]: ptr }}>…`       // Error: io requires input/textarea/select/contenteditable

Packages

HyperStandard standard library — reactive primitives ($, Pointer, ArrayPointer), DOM templating (h), and declarative bindings (on, css, io).

TypeScript language service plugin for HyperStandard. Editor-agnostic IntelliSense that works with VS Code, vim, neovim, Helix, Zed, and any TypeScript-compatible editor:

  • HTML element completion inside h/html tagged templates
  • CSS property completion after css. and inside [css]: { }
  • DOM event completion after on. and inside [on]: { }
  • IO property completion after io.
  • $.this property completion with sibling property suggestions
  • Static diagnostics for type mismatches, position mismatches, and invalid io element targets
// tsconfig.json
{
    "compilerOptions": {
        "plugins": [{ "name": "@hstd/ts" }]
    }
}

HyperStandard-to-WebComponents adapter.

Scaffold a Vite + HyperStandard project with function components, css bindings, HMR, and light/dark theme support.

npm create hstd my-app        # JavaScript
npm create hstd my-app --ts   # TypeScript + @hstd/ts

Syntax Highlighting

TextMate grammars (VS Code, Sublime Text) and Tree-sitter queries (neovim, Helix, Zed) are available in pkg/vscode and pkg/tree-sitter-hstd.

License

hstd is MIT licensed.

About

HyperStandard - Fast. Interactive. Web Interface.

Resources

License

Stars

Watchers

Forks

Contributors