caldom

    1.0.7 • Public • Published

    CalDOM JS Logo

    An agnostic, reactive & minimalist (3kb) JavaScript UI library with direct access to native DOM.

    Instead of pulling you into a library-specific magical world, CalDOM let you fully access the DOM directly while keeping the reactivity 💥. So you could take full advantage of native APIs & mix it with other libraries to gain superior performance & flexibility in the development process.

    In essence, CalDOM is just a wrapper around the native Node/Element. The overall performance drop is about 0.04x compared to vanilla/pure JavaScript. This is based on averaged unit level benchmarks in handling single & multiple-element instances: View Benchmark Results against Vanilla JS, jQuery, React JS, Vue & more.

    Official site: caldom.org

    Documentation: caldom.org/docs/

    Basic Syntax

    Hello World!

    Use it as a chainable DOM traverser and a manipulator, a lightweight jQuery alternative.

    _("#output-1")
        .append(
            _("+h1").text("Hello World!")
        );
    
    //Short append
    _( "#output-1", _("+p", "This is CalDOM.") );

    Hello World - Reactive

    Build reactive components. Use it as a lightweight React JS/Vue JS alternative. Not using classes, similar to React Hooks, but simpler.

    var app = _().react(
        {},
        {
            render: state =>
                _( "+h1", `Hello ${state.name}` ) //This is XSS safe by design
        }
    )
    
    _("#output-2", app );
    
    //Edit below line to update state
    app.state.name = "World Reactively 💥";

    Hello World - Reactive (ES6)

    Also works as an extended ES6 class.

    class HelloWorld extends _.Component{
     
        constructor(state){
            super();
       
            this.react(state);
        }
     
        render(state){
            return _("+div", [ //Can pass children as an array too
                _( "+h1", "Hello " + state.name ),
                
                _( "+p", ["The time is: ", state.time] )
            ]);
        }
    
        tick(){
            this.state.time = new Date().toTimeString().substr(0, 8);
        }
    
        didMount(){
            setInterval( () => this.tick(), 1000);
        }
     
    }
    
    var app = new HelloWorld( { name: "World!", time: "" } );
    
    _("#output-3", app);

    Reactive Native DOM Elements

    Native DOM Node is a first-class citizen. Also, a CalDOM instance is just a wrapper around them. This agnostic interoperability allows for an infinite amount of powerful integrations.

    var app = _().react(
        {},
        {
            render: state =>{
                let div = document.createElement("div");
    
                let heading = document.createElement("h1");
                heading.textContent = `I'm a reactive ${state.name}`;
    
                div.appendChild(heading);
    
                //.elem gives you the direct Element
                div.appendChild( _("+h2", "💥💥💥").elem ) 
    
                return div;
            }
        }
    )
    
    _("#output-3-1", app );
    
    app.state.name = "native DOM Element. 🙀";

    Make existing HTML reactive

    Not a fan of rendering & virtual-DOM thingies? Use CalDOM to update() pre-defined HTML content reactively. CalDOM's API is inspired by jQuery.

    var person_one = _("#person-1").react(
        {},
    
        {
            update: function(state, person){
                person.find(".name").text( state.name );
                person.find(".age").text( state.age );
            }
        }
    )
    
    //CalDOM batches these 2 state updates to only render once.
    person_one.state.name = "Jane Doe";
    person_one.state.age = 22;                 

    Summon the power of both worlds!

    Efficiently update() the DOM directly and/or proceed to virtual-DOM render if it's more suitable. Use this.$ to hold direct DOM Node references. CalDOM keeps them in sync even when render() drastically alter the DOM structure.

    class Person extends _.Component{
        constructor(){
            super();
    
            this.react({ name: "John", likes: ["SpongeBob"] });
        }
    
        render(state){
            return _("+div", [
                //Saving a reference to the direct DOM Element
                this.$.title = _( "+h1", `I'm ${state.name}` ).elem,
                
                _( "+p", "I like " + state.likes.join(" & ") )       
            ]);
        }
    
        update(state, person, changed_keys, changes_count){
            
            if( changes_count != 1 || !("name" in changed_keys) )
                // Too complex to update, proceed to render.
                return true;
                
            else //Update name directly using the DOM reference
                this.$.title
                    .textContent = `I'm ${state.name} Directly. 🦄`;
        }
    }
    
    var user = new Person();
    _("#output-4", user );
    
    user.state.likes.push( "Hulk" ); //This is handled by render()
    
    setTimeout( () => 
        user.state.name = "Jane" //This is handled by update()
    , 1000);

    You can even make jQuery reactive

    Basic building box of CalDOM is just native Node/Element. Thus, making it compatible with almost any DOM library on the web.

    class HelloJquery extends _.Component{
    
        constructor(){
            super();
    
            this.react({ prompt: "" });
        }
    
        render(state){
            //Creating element & attaching click event using jQuery
            return $("<h1></h1>")
                .text( state.prompt )
                .click( () => state.prompt = "Hello from jQuery!")[0];
        }
    }
    
    let app = new HelloJquery();
    _("#output-6", app);
    
    app.state.prompt = "Click Me!" 

    CalDOM also runs on Node JS

    You can use a library like JS-DOM to implement a browser context on the server.

    const { JSDOM } = require("jsdom"); 
    
    //Set window in the global scope
    window = new JSDOM().window;
    
    const _ = require("caldom");
    
    class ServerApp extends _.Component{
    
        constructor(){
            super();
    
            this.react( { msg: "" } );
        }
    
        render(state){
            return _("+p", state.msg)
                .css("color", "#199646")
        }
    }
    
    let app = new ServerApp();
    _("body", app);
    
    app.react( { msg: "Hello from NodeJS " + process.version  } );
    
    //Saving generated HTML by the component to a file
    require("fs").writeFileSync(
        "static_content.html", 
        window.document.body.innerHTML 
    );

    Visit caldom.org to experiment with many live code examples.


    Get Started

    CDN

    <script src="https://unpkg.com/caldom"></script>

    Download

    • Minified versions are at dist
    • Source code is at src

    Use it as a Module

    CalDOM is not attaching anything to the global environment when used as a module.

    npm install caldom
    //CalDOM also runs on Node JS with js-dom
    const _ = require('caldom');
    //RequireJS
    requirejs( ["caldom"], function(_){} );
    //ES6 Module
    import _ from "./dist/caldom.min.mjs.js";

    Contributing

    Your contributions are very welcome and thank you in advance. Please make sure to unit-test after changes.

    Key Principles

    • Performance, being agnostic(interoperability with native DOM) & minimalism is prioritized above all.
    • The richness in short-hand methods and features is secondary.
    • Supporting legacy browsers is not a priority.

    To-Do

    • Implement tests

      • Need to expand the variety of tests to different use cases. (Currently, it's biased towards my personal coding style).
    • A beginner-friendly documentation/guide. Current one is too technical.

    • Implement helpful debug outputs for the development version.

    • Thorough browser version tests.

    • Further optimize virtual DOM diffing algorithm. See benchmark here

      • The diffing algorithm is just 140+ lines of code.
      • I believe there is so much room for improvement if some bright minds look at it from a fresh angle.
    • Need to benchmark bigger implementations (Like in a spreadsheet where each cell is a sub-component?)

    Building

    Currently, the entire source code is in one file. So there isn't a huge build process other than using uglify-js to minify it.

    This simply build the .min.js & .min.mjs.js & related .map files in the ./dist/ folder.

    # Install dev dependencies
    npm install
    
    # Build
    npm run build

    Unit Testing & Benchmarking

    Tests and benchmarks sources are at the ./tests_and_benchmarks. CalDOM is using a brand new unit-testing & benchmarking framework called pFreak. Which was created as a side project of CalDOM.

    Unit test results for the latest build is available at caldom.org/tests/

    Initiate pFreak after installation to set sym links properly

    pfreak init ./tests_and_benchmarks/internal/
    pfreak init ./tests_and_benchmarks/external/

    Unit Tests

    npm test

    or

    pfreak test ./tests_and_benchmarks/internal/

    Run benchmarks against other libraries (This takes a lot of time, you can run tasks selectively using flags.)

    cd ./tests_and_benchmarks/external/
    pfreak benchmark

    refer pFreak's help for details

    pfreak --help

    Install

    npm i caldom

    Homepage

    caldom.org

    DownloadsWeekly Downloads

    23

    Version

    1.0.7

    License

    MIT

    Unpacked Size

    277 kB

    Total Files

    11

    Last publish

    Collaborators

    • dumi.jay