virst
v0.17.2
Published
various asynchronous signal based html first client side library
Maintainers
Readme
about virst
virst is:
- pronounced
/fɜrst/("technically" pun of first/fɜrst/and burst/bɜrst/); - new repo/library based on
@html_first/simple_signal;
- which itself are inspired by
solidJSsignalbasedreactivity
- which then
simple_signalwill be discontinued effective immediately;
- collections of library for creating:
reactive(and if necessary,declarative)SPA web app, including functionalities such as:
- client side
routing(using query parameter with ourDefineQRouter);signalbased asyncrhonous reactivity, which supports:
dataOnly;- with "dom reflector" (using
attributeName="...attributeValues;");
- templating using:
- native web component with
WebComponentInstance;LifecycleInstance with:
htmlonConnectedOptionsto modify elementinnerHTML;DefinePageTemplateattributeNametemplate on other page withswap
- client side JS library that are relying on
attributeNameto track the element lifecycle, using ourLifecyleclass api:
- you can use it to create your own
HATEOAS(likehtmx) client side library, to interprete returnedhtmlStringwhich have certainattributeName;- handle non editable
static site generatedexports/publish such as:
bootstrap studio;pinegrow;WYSIWYG web builder;- or bassically any kind of
SSGsoftware;
- added globals in window object
window["virst"]["QUnique"]andwindow["virst"]["QFIFO"]so any library that, targets client side bundled and, are written usingvirstLifecyclewill share the same queue handler;
- comes with
asyncQueuehandler in the background;
- no need to scratch your head too much for
asyncprocesses;
- all of our class api are
typedwithjsdoc:
- if you cannot find the documentation in this
readme, you can allways rely on yourIDE intellisense
about this readme
- this
repo/libonly serves forapi-documentationpurposes; - as for
exampleon how to use on differentuseCaserefer to html-first-virst
how to install
npm i virst
// or
bun i virst
// or any js package manager with npm capabilityv0.^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
WebComponentclass - it's a fix for
Lifecyclebehaviour and simpleWebComponentgeneration class
v0.^15.x
- fixed
Lifecyclescope mechanism - added
classattributeSelectorto dynamically proportional binding conditionally by usingsignalvalue;
v0.^16.x
- semantics and fixes for
onViewPort;
onViewPortwill no longer be exported tovirstmain 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
- helper class to track connected/disconnected/attributeChanged of an element;
- instead of manually assigning whether
attributeNameshould beglobalor not,outOffScopedattributeNamewill 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
attributeNameby abiding more to the semantics;
trigger based callback integrated to the internal library queue handler; can be created using class instantiation;
helper methods for creating Promise to block execution code that return { resume } to allow subsequent calls to proceed;
const { resume } = await Q.fifo(); // or Q.unique(id)
// code
resume(); // before returnfunction wrapper that turns callback into queued calls;
generate side effect for signal based reactivity such as for:
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;// bassically the same with `Let` but use `new Derived`- this class is extended from
LetLet signalbased reactivity, wich value are derived from reacting toLet<T>.valueeffects that are called in theasyncCallbackthis class instantiation;
// @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:
const dataOnlyExample = Derived.dataOnly(asyncCallback);
- this will automatically opt you out from
domReflector;
- make sure to check
argumentdocumentation in yourIDEtypeHint;
signal based reactivity;
assigning newValue to Let insance:
dataOnly:
const dataOnlyExample = Let.dataOnly(args0);- with
domReflector;
const letSingle = new Let(1, ...args);
letSingle.value++; // 2;
letSingle.value = 3 // 3;
- the
domReflectorwill automatically synchronise the value with the element on the dom;
<div attributeName="...selectorsSeparatedBySemicolon"></div>
- selector can be
attributeNameorpropertyName:
- special selector
value: will automatically bind the value withoninputevent;- special selector
class: will dynamically add/removeclasses, must be formated like this{class: "strings of HTMLClassNames separated by space"}
- helper class to create list that satisfy
Array<Record<string, string>>
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
signalforeffects:
sliceusessplicein the background, you don't need to manually reindex when using it;
- auto
attributeNameassign forsignalbased reactifity stored in static Method of class_; - if you use our
Componentclass, use this class static method, instead of their respective class, for generatingattributeNameto watch, which then you can use it'sattrreturned value to mark the element
// on Component scope
onConnected(async()=>{
const data = _.l('test');
html`<div ${data.attr}="innerText"></div>`
})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
elementScopedinstances/statics methods, it will be better to just leave it for theparentModuleto import it accordingly;
/**
* @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 wrapper class;
signalwill be updated from returned value ofread;readwill be called after callingthisInstance.create/update/delete_that havetrueupdateRead; /** @template V
- instantiate this class to opt in page templating, by saving html template string on a html document page;
- html implementation:
// main page
<div ${templateName}="${path};${templateName};${mode}"></div>
// mode = 'inner' | 'outer'templateNameofhead&bodyare reserved fordocument.bodyanddocument.bodyof the templatedocument, you can use it without addingtargetAttribute="head"ortargetAttribute="body"on the respective element;
// template document
<div ${targetAttribute}="${selector}"></div>- how it works:
- the class itself register a
LifecyclefortemplateName, which then upon connected, it will fetch thepaththen selectstargetAttribute="selector" as template that then replace main pageinnerHTMLwith selected elementinnerHTMLfrom template;- fetched page will be then be cached, along with any
[targetAttribute]on that page
allow the usage of search query based router through class instantiation;
- register by
App.constructorOptions.defineQRouter
create shortcuts through class instantiation;
- register by
App.constructorOptions.defineShortcuts
create named storage (localStorage or sessionStorage) through class instantiation;
- register by putting import this instance on your js
main file
use this instead of normal eventListener declaration for:
- creating
autoqueuedlistener; autoScope_static methods, insideComponentscope;
// @ts-check
someObject.addEventListener('click', Event_.listener( (event) => {
// code
}))- assign element to loop through 'List' as data to render child element using class instantiation;
- loped childElement:
- must have
HTMLElementas first children;- only first children will be used to loop through
List, all other children will be deleted from the dom beforeonConnectedevent of parentElement;
- use
ListInstancemethodhelpers to mutate the data;
- use custom encoding(eg. base64) to replace original file's source path;
- usefull when using
web-appasViewstack fordesktop-app,mobile-appor other bundle target, removing the need to setup http server to display the file on thebrowser; - register by
App.constructorOptions.defineFSSourceMapper
shared statics
- helper class to create
ShortCutthrough class instantiation; - call
thisInstance.pingto manually trigger action
error as value helper; method(s):
- async;
- sync;
centralized virst object for lib making
- native web component creation helper;
- you can add global css rules by inputing
urlstoAppInstantiationarg0.globalStyles;
helper class for registering and postMessage to webWorker
const worker = new WorkerMainThread(options);
worker.postMessage(message);helper class to define web worker thread;
new WorkerThread({
onMessage: ({ event, postMessage }) => {
const message = undefined;
// code to handle the message
postMessage(message);
},
});