Noble Programming Mantra

    @yuuza/webfx
    TypeScript icon, indicating that this package has built-in type declarations

    1.10.1 • Public • Published

    Webfx

    Web UI framework and utilities.

    It was originally created for MusicCloud.

    npm

    Demos

    Project Structure

    • utils.ts - Utilities
    • i18n.ts - Internationalization (i18n) helper
    • buildDOM.ts - View and DOM builder
    • view.ts - The core of View
    • views/ - Some built-in Views and helpers
      • Basics
      • ListView
      • Dialog
      • Menu
      • Overlay
      • Toast
      • LoadingIndicator
      • Section
    • style.css - CSS for the built-in views
    • dist/ - Bundles
      • webfx.js - UMD bundle for browsers (+ .min.js version)
      • webfxcore.min.js - UMD bundle without the viewlib and style
      • webfx.esm.js - ESM bundle

    Installation

    Import from modules

    Install the module locally using npm:

    npm install @yuuza/webfx

    Import from ES modules:

    import { View, ButtonView } from "@yuuza/webfx";

    Load into the browser directly

    Add webfx to your web page:

    <script src="https://cdn.jsdelivr.net/npm/@yuuza/webfx@1.9.12/dist/webfx.min.js"></script>

    Or if you don't need the viewlib:

    <script src="https://cdn.jsdelivr.net/npm/@yuuza/webfx@1.9.12/dist/webfxcore.min.js"></script>

    Then the module can be accessed from global variable webfx:

    const { View, ButtonView, mountView } = webfx;

    Usage

    A basic view component

    // Define a very basic view class
    class Hello extends View {
      createDom() {
        // Returns a so-called "DOM expression" object.
        return {
          tag: 'p.text.bold#hello',
          text: 'hello webfx'
        }
      }
    }
    
    // Create a instance of the view and mount it on <body>.
    mountView(document.body, new Hello());

    Renders:

    <p class="text bold" id="hello">hello webfx</p>

    Note: createDom() can be omited, then the DOM will be an empty <div>.

    DOM Expression

    A DOM Expression is a BuildDomNode object, View object, string, number or function (which returns string/number only).

    type BuildDomNode = {
        tag?: BuildDomTag;  // A string indicates DOM tag name, class names and id, similar to CSS seletor.
        child?: BuildDomExpr[] | BuildDomExpr;  // One or more DOM expressions as the children.
        text?: FuncOrVal<string>;  // Shortcut for `textContent`, can be a function, see below.
        hidden?: FuncOrVal<boolean>;  // `hidden` but can be a function, see below.
        init?: Action<HTMLElement>;  // A callback that is called on the DOM created.
        update?: Action<HTMLElement>;  // A callback that is called on the View updated.
        // ...omited internal properties...
    }

    The text and hidden callbacks will be called in updateDom().

    Properties and Child Elements

    There are no states in webfx. They're just properties.

    Use the child key in DOM expression for child elements.

    webfx.injectWebfxCss();
    class Counter extends View {
      constructor() {
        super();
        this.count = 0;
      }
      createDom() {
        return {
          tag: 'div.counter',
          child: [
            'Count: ', () => this.count, {tag: 'br'},
            new ButtonView({ text: 'Click me', onActive: () => {
              this.updateWith({count: this.count + 1});
            }})
          ]
        }
      }
    }
    mountView(document.body, new Counter());

    Renders:

    <div class="counter">
      Count: 9<br>
      <div class="btn" tabindex="0">Click me</div>
    </div>

    Hook methods

    postCreateDom() is called when the DOM is just created.

    updateDom() is called after postCreateDom(), also be called manually by updateDom().

    updateWith() is a shortcut for changing properties and calling updateDom().

    Note: Remember to call the super method when overriding these methods.

    webfx.injectWebfxCss();
    class Counter extends View {
      constructor() {
        super();
        this.count = 0;
      }
      createDom() {
        return {
          tag: 'div.counter',
          child: [
            'Count: ',
            {
              tag: 'span',
              text: () => this.count,
              init: (dom) => { console.info('the <span> DOM is created', dom); },
              update: (dom) => { dom.style.fontSize = `${14 + this.count}px`; }
            },
            {tag: 'br'},
    
            new ButtonView({text: 'Click me', onActive: () => {
              this.updateWith({count: this.count + 1});
            }})
          ]
        }
      }
      postCreateDom() {
        super.postCreateDom();
        console.info('the counter DOM is created', this.dom);
      }
      updateDom() {
        super.updateDom();
        console.info('the counter DOM is updated', this.dom);
      }
    }
    mountView(document.body, new Counter());

    ListView

    (TBD)

    JSX/TSX

    Some configuration is required to make the JSX/TSX compiler use the correct JSX factory. Set "jsxFactory": "jsx" in tsconfig.json or use /** @jsx jsx */.

    /** @jsx jsx */
    import { View, jsx } from "@yuuza/webfx";
    
    webfx.injectWebfxCss();
    class Counter extends View {
      constructor() {
        super();
        this.count = 0;
      }
      createDom() {
        return (
          <div class="counter">
            Count: {() => this.count}<br/>
            <ButtonView onActive={() => {
              this.updateWith({count: this.count + 1});
            }}>
                Click me
            </ButtonView>
          </div>
        );
      }
    }
    mountView(document.body, new Counter());

    I18n Helper

    Using the tagged templates feature, the i18n is very easy.

    This feature is also available as a standalone package @yuuza/i18n.

    import { i18n, I } from "@yuuza/webfx";
    
    i18n.add2dArray([
        ['en', 'zh'],
        ['Hello!', '你好!'],
        ['My name is {0}.', '我的名字是 {0}。']
    ]);
    
    function sayHello(name) {
        console.log(I`Hello!`);
        console.log(I`My name is ${name}.`);
    }
    
    i18n.curLang = 'en';
    sayHello('Yuuza');
    // Hello!
    // My name is Yuuza.
    
    i18n.curLang = 'zh';
    sayHello('Yuuza');
    // 你好!
    // 我的名字是 Yuuza。

    Todos

    • [ ] Functional DOM tree updating
    • [ ] React-like function components with hooks

    (TBD)

    Keywords

    none

    Install

    npm i @yuuza/webfx

    DownloadsWeekly Downloads

    2

    Version

    1.10.1

    License

    MIT

    Unpacked Size

    739 kB

    Total Files

    33

    Last publish

    Collaborators

    • lideming