a.js Documentation

Welcome to the documentation for a.js, a lightweight JavaScript flexwork designed to empower developers with flexibility and transparency. This guide will walk you through the core concepts, features, and best practices of a.js.

Getting Started

a.js is easy to integrate into your projects. Follow these steps to get started:

1. Add a.js to Your Project

Include the a.js script in your HTML file:

<script src="path/to/a.js"></script>

Replace path/to/a.js with the actual path to the a.js file in your project.

2. Your First a.js Script

Create a basic a.js script using the <a-closure> tag. For example:

<div>
    <a-closure>
        <let>
            global watched g.message
        </let>
        g.message = "Hello, a.js!";
        {(<strong>${g.message}</strong>)}
    </a-closure>
</div>

This script declares a reactive variable g.message and renders it dynamically in the DOM.

3. Key Concepts in a.js

4. Learn as You Build

Start by experimenting with the examples in this guide, and refer to the sections below for deeper insights into specific features and functionalities.

Tip: You can mix a.js functionality with standard JavaScript and HTML seamlessly, giving you full control over your application.

Core Concepts

In this section, we explore the core concepts of a.js, starting with the building blocks that make it powerful and flexible.

Custom Elements and <a-tagDef>

At the heart of a.js is the ability to create and manage custom HTML elements with ease. The <a-tagDef> tag allows you to define reusable components with minimal effort. Here's a simple example:

<a-tagDef fortag="my-button">
    {(<button>Click Me!</button>)}
</a-tagDef>
<my-button></my-button>

In this example, <my-button> becomes a custom tag that renders a button element. You can use this tag anywhere in your HTML.

Template Literals and JSX-like Syntax

To make your custom elements dynamic, a.js leverages JavaScript template literals, which allow you to embed dynamic content. For example:

<a-tagDef fortag="interactive-message">
    <let>
        global watched g.text
    </let>
    g.text = "Hello, Dynamic World!";

    function updateMessage() {
        g.text = "Message Updated!";
    }

    {(<div>
        <p>${g.text}</p>
        <button onclick="updateMessage()">Update Message</button>
    </div>)}
</a-tagDef>
<interactive-message></interactive-message>

This example demonstrates how to:

When you click the button, the text in the paragraph will change instantly without the need for manually updating the DOM. This is the power of reactivity in a.js.

Tip: Use <a:tag> to avoid potential conflicts with native HTML tags when using template literals.

Reactivity

Reactivity is a core feature of a.js, enabling automatic updates to the DOM when variables change. This is achieved through the use of watched variables. In this section, we delve deeper into how reactivity works.

What Are Watched Variables?

Watched variables are special variables that a.js observes for changes. When their values are updated, any part of the DOM that depends on them is automatically refreshed. This eliminates the need for manual DOM manipulation.

Declaring Watched Variables

Watched variables are declared using the watched keyword inside a <let> block. For example:

<a-closure>
    <let>
        global watched g.counter
    </let>
    g.counter = 0;
</a-closure>

This code initializes a watched variable, g.counter, with a value of 0.

Using Watched Variables in the DOM

You can bind watched variables to the DOM using template literals. Here's an example:

<a-closure>
    <let>
        global watched g.counter
    </let>
    g.counter = 0;

    function incrementCounter() {
        g.counter++;
    }

    {(<div>
        <p>Counter: ${g.counter}</p>
        <button onclick="incrementCounter()">Increment</button>
    </div>)}
</a-closure>

In this example:

When you click the button, the counter value increases and the DOM updates seamlessly.

Scope of Watched Variables

Watched variables can be scoped globally, to namespaces, or to a parent-child relationship. The scope is defined by the namespace attribute of the <a-closure> tag. For example:

<a-closure namespace="myNamespace">
    <let>
        nsGlobal watched g.counter
    </let>
    g.counter = 10;
</a-closure>

This code declares a watched variable g.counter within the namespace myNamespace.

Types of <let> Declarations

The <let> block supports several keywords for declaring variables with specific scopes:

Tip: Use namespaces or local scopes to avoid naming collisions and to manage state effectively in larger applications.

State Management

Managing application state effectively is critical in dynamic applications. a.js provides powerful tools to save, restore, and manipulate application states with minimal effort.

Saving Application State

With a.js, you can save the current state of your application using A.dumpAllStates(). This function captures all reactive states in the application.

// Save the current state
let savedState = A.dumpAllStates();

This returns a serialized string representing the current state of all watched variables and reactive contexts.

Restoring Application State

To restore a previously saved state, use A.restoreAllStates(stateDump). This function takes a serialized state string as input and updates all watched variables to match the saved state.

// Restore a previously saved state
A.restoreAllStates(savedState);

Once the state is restored, the DOM automatically updates to reflect the restored values, demonstrating the seamless integration of reactivity and state management.

Practical Example

Here’s an improved example demonstrating state saving and restoration while ensuring that the application always has a meaningful state to revert to:

<a-closure>
    <let>
        global watched g.text
    </let>
    g.text = "Initial State";

    let stateHistory = [A.dumpAllStates()];

    function saveState() {
        stateHistory.push(A.dumpAllStates());
    }

    function restoreState() {
        if (stateHistory.length > 1) {
            stateHistory.pop();
            A.restoreAllStates(stateHistory[stateHistory.length - 1]);
        }
    }

    function updateText() {
        g.text = `Updated at ${new Date().toLocaleTimeString()}`;
        saveState();
    }

    {(<div>
        <p>${g.text}</p>
        <button onclick="restoreState()">Undo</button>
        <button onclick="updateText()">Update Text</button>
    </div>)}
</a-closure>

In this example:

With this approach, the application always has a meaningful state to revert to, ensuring a smooth user experience.

Tip: Use state history to implement advanced features like multi-level undo/redo or state snapshots for debugging.

Advanced Features

The advanced features of a.js empower developers with dynamic tools for building flexible, high-performance applications. These features include scoped contexts, redefinable custom elements, and dynamic templates, allowing fine-grained control and customization.

Scoped Contexts

Scoped contexts help organize and manage application state, preventing naming collisions and ensuring variables are accessible only where needed. The namespace attribute of the <a-closure> tag defines the active namespace for variables declared within it.

<a-closure namespace="exampleNamespace">
    <let>
        nsGlobal watched g.message
    </let>
    g.message = "Scoped to exampleNamespace";
    {(<p>${g.message}</p>)}
</a-closure>

Here, g.message belongs to the exampleNamespace, ensuring it does not conflict with similarly named variables in other contexts.

Redefinable Custom Elements

With a.js, you can redefine the behavior of custom elements dynamically. This feature is useful for updating components at runtime without needing a full reload.

<a-tagDef fortag="dynamic-element">
    {(<div>Original Element</div>)}
</a-tagDef>

<dynamic-element></dynamic-element>

<script>
// Initially defined behavior
setTimeout(() => {
    // Redefine the behavior dynamically
    A.tagDef({
        fortag: "dynamic-element",
        content: `{(<div>Redefined Element</div>)}`
    });
    A.replayCustomTagsByName("dynamic-element");
}, 3000); // Wait 3 seconds before redefinition
</script>

Initially, <dynamic-element> displays "Original Element." After 3 seconds, the component dynamically updates to "Redefined Element," showcasing runtime redefinition.

Dynamic Templates

Dynamic templates in a.js allow you to build responsive UIs that update seamlessly with changes to state or variables. Using template literals with reactive variables ensures efficient DOM updates.

<ul>
		<a-closure>
			<let>
				local watched g
			</let>
			g.arr = [1,2,3,4,5]
			let count = 6;
			{(<button onclick="g.arr.push(count++)">push</button>)}

			{(<button onclick="g.arr[1]--">--</button>)}
			
			{(<button onclick="g.arr.pop()">pop</button>)}
			
			{(<button onclick="g.arr.shift()">shift</button>)}
			<forEachOf g.arr="val">
				{(<li key="${forEach}">(${val}-${g.arr[forEach]})</li>)}
			</forEachOf>
		</a-closure>
</ul>

In this example:

Tip: Advanced features like scoped contexts and redefinable elements enable dynamic applications while maintaining modularity and reusability.
> Introduction