Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Resumability JavaScript Framework

License

NotificationsYou must be signed in to change notification settings

async-framework/async-framework

Repository files navigation

A lightweight, signal-based framework for building reactive web applications with custom elements and async handlers.

Async Framework

Core Concepts

  1. Signals: Reactive state management
  2. Custom Elements: Web components with async capabilities
  3. Event Handlers: Async event handling with dynamic imports
  4. JSX Support: Optional JSX/TSX support for component creation

Stability Status

ComponentStatusDescription
AsyncLoaderStable-ishCore async loading functionality for handlers and modules
HandlerRegistryStable-ishEvent handler registration and management system
Framework CoreUnstableCore framework features and utilities
JSX RuntimeUnstableJSX/TSX support and rendering (under development)
SignalsExperimentalReactive state management (API may change)
Signal-ListExperimentalA signal-list primitive to optimize rendering lists
Signal-TableExperimentalA signal-table primitive to optimize rendering tables
Custom ElementsExperimentalWeb Components integration and lifecycle management
TemplatesExperimentalHTML template handling and instantiation
QwikLoaderExperimentalReplace QwikLoader with AsyncLoader

Basic Usage

1. Signals

Signals are reactive state containers that automatically track dependencies and update subscribers:

import{signal,computed}from'@async/framework';// Create a basic signalconstcount=signal(0);// Read and write to signalconsole.log(count.value);// 0count.value=1;// Create a computed signalconstdoubled=computed(()=>count.value*2);

2. Custom Elements

Create reactive web components using signals:

// counter-element.jsimport{signal}from'@async/framework';exportclassCounterElementextendsHTMLElement{constructor(){super();this.count=signal(0);}connectedCallback(){this.innerHTML=/*html*/`       <button on:click="./handlers/increment.js">Count:${this.count.value}</button>     `;// Auto-update view when signal changesconstbuttonEl=this.querySelector('button');this.count.subscribe(newValue=>{buttonEl.textContent=`Count:${newValue}`;});}}// in maincustomElements.define('counter-element',CounterElement);

3. Async Event Handlers

Event handlers can be loaded asynchronously and chained:

HTML:

<!-- Multiple handlers separated by commas --><buttonon:click="./handlers/validate.js, ./handlers/submit.js">   Submit</button><!-- Handler with specific export --><divon:dragover="./handlers/drag.js#onDragover">   Drag here</div>

Handler files:

// handlers/validate.jsexportfunctionhandler(context){const{ event, element}=context;if(!element.value){context.break();// Prevents next handlers from executingreturnfalse;}}// handlers/submit.jsexportasyncfunctionhandler(context){const{ event, element}=context;constresult=awaitsubmitData(element.value);returnresult;}

4. JSX Components

Create components using JSX/TSX:

// Counter.tsximport{signal}from'@async/framework';exportfunctionCounter(){constcount=signal(0);return(<div><h1>Count:{count}</h1><buttonon:click={()=>count.value++}>         Increment</button></div>);}

Complete Example

Here's a complete example combining all features:

index.html:

<!DOCTYPE html><htmllang="en"><head><title>Async Framework Demo</title></head><body><divdata-container="root"><todo-app></todo-app></div><scripttype="module">import{render}from"@async/framework";import{TotoApp}from"./TodoApp.js";// Register the custom elementcustomElements.define("todo-app",TotoApp);// Render the component into the containerrender(document.querySelector("todo-app"){root:document.querySelector('[data-container="root"]'),// events in the appevents:["click","keyup"],},);</script></body></html>

TodoApp.js:

import{ContextWrapper,html,signal,each,wrapContext}from"@async/framework";exportclassTodoAppextendsHTMLElement{privatewrapper:ContextWrapper;privatetodos;privateinputValue;constructor(){super();this.wrapper=wrapContext(this,()=>{this.todos=signal<string[]>([]);this.inputValue=signal("");});}createTemplate(){consttemplate=html`<divclass="p-6 bg-white rounded-lg shadow-md"><divclass="mb-4 flex gap-2"><inputtype="text"class="flex-1 px-4 py-2 border rounded"value="${this.inputValue}"on:keyup="./handlers/input.js"><buttonclass="px-4 py-2 bg-indigo-600 text-white rounded"on:click="./handlers/add-todo.js, ./handlers/clear-input.js">            Add Todo</button></div><ulclass="space-y-2">${each(this.todos,(todo)=>html`<liclass="flex items-center justify-between p-2 border rounded"><span>${todo}</span><buttonclass="px-2 py-1 bg-red-500 text-white rounded"on:click="./handlers/remove-todo.js">                Remove</button></li>          `)}</ul></div>    `;returntemplate;}connectedCallback(){this.wrapper.render(()=>this.createTemplate());}disconnectedCallback(){this.wrapper.cleanup();}}

Handlers:

// handlers/input.jsexportfunctionhandler(context){const{ element}=context;constcomponent=element.closest("todo-app");component.inputValue.value=element.value;}// handlers/add-todo.jsexportfunctionhandler(context){const{ element}=context;constcomponent=element.closest("todo-app");constnewTodo=component.inputValue.value.trim();if(newTodo){component.todos.value=[...component.todos.value,newTodo];}}// handlers/clear-input.jsexportfunctionhandler(context){const{ element}=context;constcomponent=element.closest("todo-app");component.inputValue.value='';context.element.querySelector('input').value='';}

Key Features

  • 🔄 Reactive signals for state management
  • ⚡ Async event handlers with dynamic imports
  • 🧩 Web Components integration
  • ⚛️ Optional JSX support
  • 🔌 Pluggable architecture
  • 📦 No build step required
  • 🪶 Lightweight and performant

Best Practices

  1. Keep handlers small and focused
  2. Use signals for shared state
  3. Leverage async handlers for complex operations
  4. Break down components into smaller, reusable pieces
  5. Use computed signals for derived state

Project Structure

packages/  examples/                # Example applications  async-loader/            # Core async loading functionality  dev/                     # Development server  custom-element-signals/  # Custom element integration

Getting Started

  1. Clone the repository
  2. Install Deno if not already installed
  3. Run example apps:deno task start

Visithttp://localhost:8000 to see the examples in action.

Framework Prompt

Use this prompt to help AI assistants understand how to work with this framework:

I'm using a custom web framework with the following characteristics:

  1. It's built for Deno and uses TypeScript/JavaScript
  2. Components should preferably be created using JSX/TSX (though Custom Elements are supported)
  3. State management uses Signals (reactive state containers)
  4. Event handling uses async handlers loaded dynamically

BASIC SETUP:

  • Create an index.html with this structure:
<!DOCTYPE html><html><head><title>App</title></head><body><divid="app"></div><scripttype="module">import{render}from'@async/framework';import{App}from'./App.tsx';// Bootstrap the applicationrender(<App/>,document.getElementById('app'));</script></body></html>

JSX COMPONENTS (Preferred Method):

  • Create components in .tsx files
  • Use signals for state management

Example App.tsx:

import{signal}from'@async/framework';exportfunctionApp(){constcount=signal(0);return(<div><h1>Count:{count}</h1><buttonon:click="./handlers/increment.js">Add</button></div>);}

EVENT HANDLING:

  • Events are handled using file paths in on: attributes
  • Multiple handlers can be chained with commas
  • Handlers receive a context object with:
{event,// Original DOM eventelement,// Target elementdispatch(),// Dispatch custom eventsvalue,// Passed between chained handlers// helperseventName,// Name of the eventattrValue,// Original attribute valuehandlers,// Handler registrysignals,// Signal registrytemplates,// Tenplate registrycontainer,// Container element// TODO: component,       // Component refmodule,// Module file instance of the handlercanceled,// If we canceled the chained handlersbreak(),// break out of chained handlers//  mimic EventpreventDefault(),stopPropagation(),target,}

Handler Patterns:

  1. Default Export:
// handlers/submit.js// typeof module.default === 'function'exportdefaultfunction(context){// Used when no specific method is referenced}
  1. Named Event Handler:
// handlers/form.js// "submit" -> "on" + capitalize("submit")exportfunctiononSubmit(context){// Automatically matched when event name is "submit"}
  1. Hash-Referenced Export:
// handlers/drag.jsexportfunctionmyCustomNamedHandler(context){}exportfunctiononDragend(context){}// Use hash to target specific export<divon:drag="./handlers/drag.js#myCustomNamedHandler"/>// dragend will resolve to onDragend<divon:dragend="./handlers/drag.js"/>
  1. Inline Function (JSX):
<buttononClick={(context)=>{console.log('Clicked!',context);}}>

Examples:

<!-- Chain multiple handler files --><buttonon:click="./handlers/validate.js, ./handlers/submit.js">   Submit</button><!-- Target specific export with hash --><divon:dragover="./handlers/drag.js#onDragover">   Drop Zone</div><!-- Use event-named export --><formon:submit="./handlers/form.js"><!-- handler will use onSubmit export --></form>

Handler Context:

{event,// Original DOM eventelement,// Target elementdispatch(),// Dispatch custom eventsvalue,// Passed between chained handlers// helperseventName,// Name of the eventattrValue,// Original attribute valuehandlers,// Handler registrysignals,// Signal registrytemplates,// Tenplate registrycontainer,// Container element// TODO: component,       // Component refmodule,// Module file instance of the handlercanceled,// If we canceled the chained handlersbreak(),// break out of chained handlers//  mimic EventpreventDefault(),stopPropagation(),target,}

Control Flow:

  • Invoke context.break() to stop handler chain (rarely needed)
  • Return values are passed to next handler via context.value

SIGNALS:

  • Used for reactive state management
  • Created using signal(initialValue)
  • Access value with .value
  • Can be computed using computed(() => ...)
  • Separating get and set using createSignal(initialValue)
  • Access value with [get, set] = createSignal()Example:
constcount=signal(0);count.value++;// Updates all subscribersconstdoubled=computed(()=>count.value*2);// passing around get and setconst[getCount,setCount]=createSignal(0);setCount(getCount()+1);// Updates all subscribersconstdoubled=computed(()=>getCount*2);

FILE STRUCTURE:

project/  ├── index.html  ├── App.tsx  ├── components/  │   └── Counter.tsx  └── handlers/      ├── increment.js      └── submit.js

When working with this framework, please follow these conventions and patterns. The framework emphasizes clean separation of concerns, reactive state management, and async event handling.

END PROMPT

About

Resumability JavaScript Framework

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors2

  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp