various asynchronous signal based html first client side library
npm install virst/fɜrst/ ("technically" pun of first /fɜrst/ and burst /bɜrst/);@html_first/simple_signal;solidJS signal based reactivitysimple_signal will be discontinued effective immediately;reactive(and if necessary, declarative) SPA web app, including functionalities such as:routing (using query parameter with our DefineQRouter);signal based asyncrhonous reactivity, which supports:dataOnly;attributeName="...attributeValues;");WebComponent Instance;Lifecycle Instance with:html onConnectedOptions to modify element innerHTML;DefinePageTemplate attributeName template on other page with swapattributeName to track the element lifecycle, using our Lifecyle class api:HATEOAS (like htmx) client side library, to interprete returned htmlString which have certain attributeName;static site generated exports/publish such as:bootstrap studio;pinegrow;WYSIWYG web builder;SSG software;window["virst"]["QUnique"] and window["virst"]["QFIFO"] so any library that, targets client side bundled and, are written using virst Lifecycle will share the same queue handler;asyncQueue handler in the background;async processes;typed with jsdoc:readme, you can allways rely on your IDE intellisenserepo/lib only serves for api-documentation purposes;example on how to use on different useCase refer to html-first-virstshell
npm i virst
// or
bun i virst
// or any js package manager with npm capability
`
v0.^9.x
- drop supports for Animation
> - it's better to use more dedicated library like animeJS
v0.^12.x
- drop supports for Component
- uses native web component instead using WebComponent class
- it's a fix for Lifecycle behaviour and simple WebComponent generation class
v0.^15.x
- fixed Lifecycle scope mechanism
- added class attributeSelector to dynamically proportional binding conditionally by using signal value;
v0.^16.x
- semantics and fixes for onViewPort;
>- onViewPort will no longer be exported to virst main module;
exported-api-and-type-list
- Lifecycle
- Ping
- Q
- QueuedBlock
- $
- Derived
- Let
- List
- _
- App
- CRUD
- DefinePageTemplate
- DefineQRouter
- DefineShortCuts
- DefineStorage
- Event_
- For
- FSsrc
- helper
- ShortCut
- Try_
- virst
- WebComponent
- WorkerMainThread
- WorkerThread
Lifecycle
- helper class to track connected/disconnected/attributeChanged of an element;
- instead of manually assigning whether
attributeName should be global or not, outOffScoped attributeName will produce warning in the runtime;
> - you can ignore it, as the most local Lifecycle will take priority, and when there are no other scope, the most global will take place, the warning is only to notify that you can still optimize your code further by renaming the conflicting attributeName by abiding more to the semantics;
Ping
trigger based callback integrated to the internal library queue handler;
can be created using class instantiation;
Q
helper methods for creating Promise to block execution code that return { resume } to allow subsequent calls to proceed;
`js
const { resume } = await Q.fifo(); // or Q.unique(id)
// code
resume(); // before return
`
QueuedBlock
function wrapper that turns callback into queued calls;
$
generate side effect for
signal based reactivity such as for:
- Let
`js
const letExample = new Let('')
new $(async(first)=>{
const value = test.value;
if(first){
return;
// return early if you want to opt out from handling the effect immediately,
// also by doing this you can make the $ slightly more performance 1) when dealing with async await on hydration,
// such as data fetching;
}
// handle value
})
// 1) and when all of the effects is registered, you can call letExample.call$ to call for effect in parallel;
`
- Derived
`js
// bassically the same with Let but use new Derived
`
Derived
- this class is extended from
Let Let
- signal based reactivity, wich value are derived from reacting to Let effects that are called in the asyncCallback this class instantiation;
`js
// @ts-check
const letSingle = new Let(1);
const doubleExample = new Derived(async()=>{
const value = letSingle.value; // autoscubscribed to letSingle value changes;
return value * 2; // returned value are to be derivedValue
});
`
- dataOnly:
`js
const dataOnlyExample = Derived.dataOnly(asyncCallback);
`
> - this will automatically opt you out from domReflector;
- make sure to check argument documentation in your IDE typeHint;
Let
signal based reactivity;
assigning newValue to Let insance:
- dataOnly:
`js
const dataOnlyExample = Let.dataOnly(args0);
`
- with domReflector;
`js
const letSingle = new Let(1, ...args);
letSingle.value++; // 2;
letSingle.value = 3 // 3;
`
> - the domReflector will automatically synchronise the value with the element on the dom;
`html
`
> - selector can be attributeName or propertyName:
> > - special selector value: will automatically bind the value with oninput event;
> > - special selector class: will dynamically add/remove classes, must be formated like this {class: "strings of HTMLClassNames separated by space"}
List
- helper class to create list that satisfy
Array
`js
const listExample = new List([
{key1: "test", ...keys},
{key1: "test3", ...keys},
])
`
- usefull for loops;
- instance method: 'push'|'unshift'|'slice'|'splice'|'swap'|'modify'|'shift', serves as helper to mutate, and notify for signal for effects:
> - slice uses splice in the background, you don't need to manually reindex when using it;
_
- auto
attributeName assign for signal based reactifity stored in static Method of class _;
- if you use our Component class, use this class static method, instead of their respective class, for generating attributeName to watch, which then you can use it's attr returned value to mark the element
`js
// on Component scope
onConnected(async()=>{
const data = _.l('test');
html
})
`
App
App starter helper for module environtment:
- the sole purpose is just to auto import the necessary global file in your main js file;
- if it's elementScoped instances/statics methods, it will be better to just leave it for the parentModule to import it accordingly;
`js
/**
* @typedef {Object} constructorOptions
* - for efficiency, only fill this options when you intent to use the library as sole View part of your stack;
* - the inputed root component must manually fills attr option argument, to target root element on the real dom;
* @property {(import("../lifecycle/Lifecycle.mjs").Lifecycle)[]} [options.lifecycles]
* @property {(import("./For.mjs").For)[]} [options.forS]
* @property {import('./DefineShortCuts.mjs').DefineShortCuts} [options.defineShortcuts]
* @property {import('./DefineQRouter.mjs').DefineQRouter} [options.defineQRouter]
* @property {import('./DefinePageTemplate.mjs').DefinePageTemplate} [options.definePageTemplate]
* @property {number} [options.pingDebounce]
* in ms;
* @property {import('./DefineStorage.mjs').DefineStorage} [options.defineStorage]
* @property {typeof helper["webComponentGlobalStyles"]} [options.webComponentGlobalStyles]
* @property {import('./FSsrc.mjs')} [options.defineFSSourceMapper]
* use custom encoding(eg. base64) to replace original file's source path;
* usefull when using web-app as View stack for desktop-app, mobile-app or other bundle target, removing the need to setup http server to display the file on the browser;
*/
`
CRUD
CRUD wrapper class;
-
signal will be updated from returned value of read;
- read will be called after calling thisInstance.create/update/delete_ that have true updateRead;
/**
@template V
DefinePageTemplate
- instantiate this class to opt in page templating, by saving html template string on a html document page;
- html implementation:
`html
// main page
// mode = 'inner' | 'outer'
`
- templateName of head & body are reserved for document.body and document.body of the template document, you can use it without adding targetAttribute="head" or targetAttribute="body" on the respective element;
`html
// template document
`
- how it works:
> - the class itself register a Lifecycle for templateName, which then upon connected, it will fetch the path then selects targetAttribute="selector" as template that then replace main page innerHTML with selected element innerHTML from template;
> - fetched page will be then be cached, along with any [targetAttribute] on that page
DefineQRouter
allow the usage of search query based router through class instantiation;
- register by
App.constructorOptions.defineQRouter
DefineShortCuts
create shortcuts through class instantiation;
- register by
App.constructorOptions.defineShortcuts
DefineStorage
create named storage (
localStorage or sessionStorage) through class instantiation;
- register by putting import this instance on your js main file
Event_
use this instead of normal
eventListener declaration for:
- creating autoqueued listener;
- autoScope _ static methods, inside Component scope;
`js
// @ts-check
someObject.addEventListener('click', Event_.listener( (event) => {
// code
}))
`
For
- assign element to loop through 'List' as data to render child element using class instantiation;
- loped childElement:
> - must have
HTMLElement as first children;
> - only first children will be used to loop through List, all other children will be deleted from the dom before onConnected event of parentElement;
- use ListInstance method helpers to mutate the data;
FSsrc
- use custom encoding(eg. base64) to replace original file's source path;
- usefull when using
web-app as View stack for desktop-app, mobile-app or other bundle target, removing the need to setup http server to display the file on the browser;
- register by App.constructorOptions.defineFSSourceMapper
helper
shared statics
ShortCut
- helper class to create
ShortCut through class instantiation;
- call thisInstance.ping to manually trigger action
Try_
error as value helper;
method(s):
- async;
- sync;
virst
centralized virst object for lib making
WebComponent
- native web component creation helper;
- you can add global css rules by inputing
urls to AppInstantiation arg0.globalStyles;
WorkerMainThread
helper class for registering and postMessage to webWorker
`js
const worker = new WorkerMainThread(options);
worker.postMessage(message);
`
WorkerThread
helper class to define web worker thread;
`js
new WorkerThread({
onMessage: ({ event, postMessage }) => {
const message = undefined;
// code to handle the message
postMessage(message);
},
});
``