nom, please more

    turbopug

    1.0.5 • Public • Published

    TURBOPUG

    No-junk JS component library with insignificant weight. If you're 17.5% too weak or 11.4% too unwilling to use heavy-weight component frameworks, but still want all the stuff in one mush:

    • Web-Components
    • Localization
    • Templates
    • Routing
    • Reactive binding
    • Debounce
    • Unique IDs
    • PSW hashing

    Plus 133.7% of all the quickility.

    KEEPING IT SIMPLE SINCE 1903

    Handmade master craftsmanship gives you the full-bodied low-fat experience you expect from a component framework:

    • No inheritance
    • No bundler
    • No build-step
    • No TypeScript
    • No junk

    All the folding chair comfort you ever hoped for.

    REQUIREMENTS

    Because TURBOPUG is so bare bones, your customer's browser almost needs to be from the JavaScript-future:

    • modules & imports
    • template literals
    • Web Components
    • All the words: let, const, ...

    Yes: That's all the browsers, since a couple of years.

    GET OVER YOUR SPEED-ANGST

    Running in an up-to-date browsers your SPA doesn't need all the vanity junk. Just use a server that doesn't crack on HTML/2 push and gzipped response compression.

    Real quickility comes with not doing stuff. And thats what TURBOPUG does: not doing stuff. If you want wing chair comfort and a nurse giving you a hand, don't use TURBOPUG. If you know your JavaScript, get cracking.

    FRIENDLY TO CARBONS OUT OF THE BOX

    TURBOPUG is hertz-saving for computers. So somewhere someone doesn't need to burn fatty non-renewables. But keep in mind: what you do is up to you: Run your stuff on a Windows-11-VM through 5 VPNs and 6 SSH-tunnels if you like to roll like a coaler.

    Docs

    TURBOPUG happened while writing an SPA in vanilla JavaScript in a reactive, event-driven design by factoring out the accidental complexity.

    Component Example

    import Comp from '../turbo/comp.js';
    import Store from '../turbo/store.js';
    
    export class MyCounter extends Comp {
        #store;
    
        static get observedAttributes() {
            return ['label'];
        }
    
        constructor() {
            super();
    
            this.#store = new Store({
                label: (value = '', event) => {
                    switch (event.type) {
                        case 'set':
                            return event.value;
                        default:
                            return value;
                    }
                },
                counter: (value = 0, event) => {
                    switch (event) {
                        case 'incremented':
                            return value + 1;
                        case 'decremented':
                            return value - 1;
                        default:
                            return value;
                    }
                },
            });
    
            this.#store.merge({
                label: null,
                counter: 1,
            });
        }
    
        attributeChangedCallback(name, _, value) {
            switch (name) {
                case 'label':
                    this.#store.send.label({type: 'set', value});
                    break;
                default:
                    break;
            }
        }
    
        get label() {
            return this.#store.state.label;
        }
        set label(value) {
            this.#store.send.label({type: 'set', value});
        }
    
        render() {
            return /*html*/`
                <div>
                    <span class="label">${this.#store.state.label}</span>
                    <span class="counter">${this.#store.state.counter}</span>
                </div>
                <button class="decrement">Decrement</button>
                <button class="increment">Increment</button>
            `;
        }
    
        bind(valElem, decBtn, incBtn) {
            const labelElem = valElem.querySelector('.label');
            this.#store.on.label((_, value) => {
                labelElem.innerText = value;
            });
            const counterElem = valElem.querySelector('.counter');
            this.#store.on.counter((_, value) => {
                counterElem.innerText = value;
            });
            decBtn.addEventListener('click', () => {
                this.#store.send.counter('decremented');
            });
            incBtn.addEventListener('click', () => {
                this.#store.send.counter('incremented');
            });
        }
    }
    
    customElements.define('my-counter', MyCounter);
    • An TURBOPUG component is defined by extending the class Comp.
    • For state management a Store is initialized and assigned onto a private variable #store. Stores are inspired by redux und made of variables that can be changed by sending events and reacting to them via reducers.
    • The 2 methods static get observedAttributes() and attributeChangedCallback(name, _, value) are part of the web-components specification.
    • A component can have a render-method which must return a rendered HTML-string. JS template strings are used for that.
    • After such a HTML-string is turned into DOM elements the bind-method is called. In which event-listeners from the DOM are attached and changes coming from the store are inserted into the DOM.

    Components are state machines

    How to program with TURBOPUG

    An TURBOPUG comp is a state machine. Programming is done via variable changes over time. I.e. setting one variable through user-input, reacting to a change, setting another variable and reacting to the change, until one change is reflected in HTML via a binding or triggers an outside variable-change-handler.

    Localization/i18n bindings

    lcz-prop and lcz-attr are used to bind to localization keys from the translations file. Syntax is:

    [<attrib-or-prop-name>=]<LOCALIZATION_KEY>

    Example:

    <p lcz-prop="textContent=LOCALIZABLE_KEY:Fallback Translation"></p>
    <input lcz-attr="value=LOCALIZABLE_KEY:Fallback Translation" type="text">

    The name of the prop or attrib to set the localization on. Can be omitted, defaults to textContent.

    <LOCALIZATION_KEY>

    The localization key to use to retrieve the value from the translations file. Fallback is value of <attrib-or-prop-name> if not found, default value textContent included.

    Localization/i18n setup

    insig must rely on script loading order to make translations available ASAP during page-loading. Translations file and LCZ-module must be setup as follows:

    <!doctype html>
    <html lang="en">
    
    <head>
        <script src="/translations.js"></script> <!-- TRANSLATIONS FILE IS FIRST JS-FILE LOADED -->
        <!-- OTHER SCRIPT AFTERWARDS ... -->
    </head>
    
    <body>
        <!-- CONTENT COMES HERE -->
        <script src="/insig/lcz.js" type="module"></script> <!-- LCZ MODULE LOADED DIRECTLY AFTER CONTENT -->
    </body>
    
    </html>

    The localizations file must set a the property localizations on the window object. If you only need one central localizations file, use the simple object notation in which each language locale is a key, i.e. de for german or "de-CH" for swiss german:

    window.localizations = {
        de: {
            DOGS: 'Hunde',
            CATS: 'Katzen',
            DOG: 'Hund',
            CAT: 'Katze',
            DONE: 'Fertig'
        }
    };

    If you want to use several localization files, use the array notation in which each entry is one of the above. Use the following terse notation per file to automatically extend a previously loaded definition:

    window.localizations = (l => [...l, {
        de: {
            DOGS: 'Hunde',
            CATS: 'Katzen',
            DOG: 'Hund',
            CAT: 'Katze',
            DONE: 'Fertig'
        }
    }])(window.localizations || []);

    The actual translations objects are merged in this case. The order in which the files are loaded in the HTML is significant: Files loaded later overwrite translation-keys from a file loaded earlier, so you can extend on base localizations.

    Install

    npm i turbopug

    DownloadsWeekly Downloads

    0

    Version

    1.0.5

    License

    LicenseRef-LICENSE

    Unpacked Size

    35.8 kB

    Total Files

    17

    Last publish

    Collaborators

    • jaqmol