JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • 0
  • Score
    100M100P100Q29133F

Super concise chained call UI library

Package Exports

  • link-dom
  • link-dom/link-dom.es.min.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (link-dom) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Link Dom

Super concise chained call UI library

Introduction

Link-dom is an extremely concise imperative UI library with chained call features and no third-party dependencies. Its minimum size is only 7.7kb.

Link-dom provides the createStore method for simple state management.

In tool library projects that require UI development, if native js is used to write UI, it will be difficult to manage and maintain, and the code volume will be large. And introducing UI libraries such as Vue and React will greatly increase the package size and even be a bit of overkill. The birth of link-dom is precisely to meet such scenarios of small-scale UI usage. UI is described by JS imperative and componentized UI management is achieved.

Feature

  1. Imperative UI, supports chained calls and has no third-party dependencies.
  2. Has friendly type declaration support, covering attributes, styles, Dom tags, etc.
  3. Has good css-in-js support and supports nested rules similar to less.
  4. Supports state management.

Install

npm i link-dom

Usage

Dom

Dom is a layer of encapsulation of dom elements, and all operations on the dom are handled inside IUIEle. Chaining and friendly type hints are also implemented in Dom

Generate an Dom element with dom.xxx

import {mount, dom} from 'link-dom';

const hello = dom.div.text('Hello');
mount(hello, 'body');

Dom declaration

export declare class Dom {
    el: HTMLElement;
    constructor(key: (keyof HTMLElementTagNameMap) | HTMLElement);
    private _ur;
    class(): string;
    class(val: string): this;
    id(): string;
    id(val: string): this;
    addClass(name: string): this;
    removeClass(name: string): this;
    hasClass(name: string): boolean;
    toggleClass(name: string, force?: boolean): boolean;
    remove(): this;
    text(): string;
    text(val: string | number | IReactive): this;
    private __mounted?;
    mounted(v: (el: Dom) => void): this;
    attr(name: {
        [prop in IAttrKey]?: any;
    } | Record<string, any>): this;
    attr(name: IAttrKey): string;
    attr(name: string): string;
    attr(name: IAttrKey, value: any): this;
    attr(name: string, value: any): this;
    removeAttr(key: string): this;
    private __xr_funcs;
    func(k: string): (...args: any[]) => any;
    func(k: string, v: (...args: any[]) => any): this;
    data(name: Record<string, any>): this;
    data(name: string): any | null;
    data(name: string, value: any): this;
    style(name: IStyle | Record<string, any>): this;
    style(name: IStyleKey | string): string;
    style<T extends IStyleKey>(name: T, value: IStyle[T]): this;
    value(): string;
    value(val: string | number): this;
    html(): string;
    html(val: string | number): this;
    outerHtml(): string;
    outerHtml(val: string | number): this;
    child(i: number): Dom | null;
    children(): Dom[];
    click(value: IEventObject): this;
    event(name: Partial<Record<IEventKey, IEventObject>>): this;
    event(name: IEventKey, value?: IEventObject): this;
    append(...doms: IChild[]): this;
    ref(v: Dom): this;
    hide(): this;
    show(display?: string): this;
    setVisible(visible?: boolean, display?: string): this;
    query(selector: string, one: true): Dom;
    query(selector: string, one?: false): Dom[];
    src(): string;
    src(v: string): this;
    parent(): HTMLElement | null;
    empty(): this;
    name(): string;
    name(v: string): this;
    find(name: string): Dom;
    type(name: "text" | "number" | "password" | "checkbox" | "radio" | "color" | "range" | "submit" | "reset" | "input" | "date" | "email" | "tel"): this;
    bind(v: any): this;
}

style

import {style} from 'link-dom';

style({
    '.parent': {
        fontSize: '12px',
        '*': {color: '#000'},
        '.child': {
            color: '#444',
            '&.active': {color: '#f44'}
        },
    }
})

event

import {mount, dom} from 'link-dom';
function Main(){
    return dom.div.text('Hello World!')
        .event('click', ()=>{
            console.log('Hello')
        });
}
mount(Main(), 'body');

Use a decorator

import {mount, dom} from 'link-dom';
function Main(){
    return dom.div.text('Hello World!')
        .event('click', {
            stop: true,
            listener: ()=>{
                console.log('Hello')
            }
        });
}
mount(Main(), 'body');

mounted

import {mount, dom} from 'link-dom';
mount(dom.div.mounted(el=>{
    console.log('mounted', el);
}), 'body');

collectRef

import {collectRef, mount, dom} from 'link-dom';
function Main(){
    const refs = collectRef('hello');
    return dom.div.ref(refs.hello)
        .click(()=>{console.log(refs.hello.text())})
        .text('Hello World!');
}
mount(Main(), 'body');

State management

A simple state management and related APIs to use

import {createStore, react, mount} from 'link-dom';
function Counter () {
    const store = createStore({
        count: 0,
    });
    const increase = () => {
        store.count += 1;
    };
    const unsub = store.$sub('count', (v, pv) => {
        console.log(`Subscribe Count Change value=,`, v, `; prevValue=`, pv);
    });
    return dom.div.append(
        dom.input.type('number').bind(store.count),
        dom.span.text(react`count=${store.count}`),
        dom.button.text('addCount').click(increase),
        dom.button.text('UnSubscribe').click(unsub)
    );
}

mount(Counter(), 'body');

createStore

Create a state store

const store = createStore({
    count: 0,
});

react

The react method is used to concatenate a piece of responsive data

import {react} from 'link-dom';

const reactive = react`count=${store.count}`;
// You can also just pass one piece of data, you don't need to use a template string, you can just call the function
const reactive = react(store.count);

raw

The raw method is used to annotate a static data in React

import {react, raw} from 'link-dom';
const StaticName = 'count';
const reactive = react`${raw(StaticName)}=${store.count}`;

Dom.bind

Used for bidirectional binding of input type elements, the data inside the bind method does not need to be wrapped using react

const input = dom.input.bind(store.count)

Store.$sub

Subscribe to reactive data changes, which returns an unsubscribe

const unsub = store.$sub('count', (value, prevValue)=>{
    console.log(value, prevValue);
});
// Call unsub can unsubscribe

Store.$unsub

Cancel Subscribe

let handler = (value, prevValue)=>{
    console.log(value, prevValue);
}
store.$sub('count', handler);
store.$unsub('count', handler);
store.$unsub('count'); // 不传入第二个参数可以取消指定状态的所有订阅

Samples

List

import {dom, collectRef, UIEle, mount} from 'link-dom';

function List () {
    const refs = collectRef('list');
    const list = ['1', '2', '3'];

    const SingleChild = (children: UIEle|string|number) => {
        return dom.span.append(children);
    };
    let index = 0;
    return dom.div.ref(refs.list).append(
        dom.button.text('add').click(() => {
            index ++;
            list.push(`${index}`);
            refs.list.append(SingleChild(index));
        }),
        list.map(item => SingleChild(item))
    );
}

mount(List(), 'body');

Counter

import {createStore, react, mount} from 'link-dom';
function Counter () {
    const store = createStore({
        count: 0,
    });
    const increase = () => {
        store.count += 1;
    };
    const unsub = store.$sub('count', (v, pv) => {
        console.log(`Subscribe Count Change value=,`, v, `; prevValue=`, pv);
    });
    return dom.div.append(
        dom.input.type('number').bind(store.count),
        dom.span.text(react`count=${store.count}`),
        dom.button.text('addCount').click(increase),
        dom.button.text('UnSubscribe').click(unsub)
    );
}

mount(Counter(), 'body');