Web UI framework and utilities.
It was originally created for MusicCloud.
And of cource MusicCloud (GitHub repo)
buildDOM.ts- View and DOM builderview.ts- The core of Viewpackages/utils- Utilitiesi18n- Internationalization (i18n) helper
views/- Some built-in Views and helpersBasicsListViewDialogMenuOverlayToastLoadingIndicatorSection
style.css- CSS for the built-in viewsdist/- Bundleswebfx.js- UMD bundle for browsers (+.min.jsversion)webfxcore.min.js- UMD bundle without the viewlib and stylewebfx.esm.js- ESM bundle
Install the module locally using npm:
npm install @yuuza/webfxImport from ES modules:
import{View,ButtonView}from"@yuuza/webfx";Add webfx to your web page:
<scriptsrc="https://cdn.jsdelivr.net/npm/@yuuza/webfx@1.9.12/dist/webfx.min.js"></script>Or if you don't need the viewlib:
<scriptsrc="https://cdn.jsdelivr.net/npm/@yuuza/webfx@1.9.12/dist/webfxcore.min.js"></script>Then the module can be accessed from global variable webfx:
const{ View, ButtonView, mountView }=webfx;// Define a very basic view classclassHelloextendsView{createDom(){// Returns a DOM expression object for rendering.return{tag: "p.text.bold#hello",text: "hello webfx",};}}// Create an instance of the view and mount it onto the <body>.mountView(document.body,newHello());Renders:
<pclass="text bold" id="hello">hello webfx</p>Note: You can omit the createDom() can be omited if you want an empty <div>.
A DOM Expression is an object of type BuildDomNode, or a View object, a string, a number, or a function that returns a string or number.
typeBuildDomNode={tag?: BuildDomTag;// A string that indicates a DOM tag name, class names, and id, similar to a CSS selector.child?: BuildDomExpr[]|BuildDomExpr;// One or more DOM expressions as the children.text?: FuncOrVal<string>;// A shortcut for `textContent`. It can be a function, see below.hidden?: FuncOrVal<boolean>;// The `hidden` property, but can be a function, see below.init?: Action<HTMLElement>;// A callback that is called when the DOM is created.update?: Action<HTMLElement>;// A callback that is called when the view is updated.// ...internal properties omitted...};The text and hidden callbacks will be called in updateDom().
Webfx does not have states; they are just properties.
You can use the child key in the DOM expression for child elements.
// Inject Webfx CSS.webfx.injectWebfxCss();classCounterextendsView{constructor(){super();this.count=0;}createDom(){return{tag: "div.counter",child: ["Count: ",()=>this.count,{tag: "br"},newButtonView({text: "Click me",onActive: ()=>{this.updateWith({count: this.count+1});},}),],};}}// Mount the view onto the body element.mountView(document.body,newCounter());Renders:
<divclass="counter">
Count: 9
<br/><divclass="btn" tabindex="0">Click me</div></div>Webfx provides two hook methods:
postCreateDom(): called when the DOM is just created.updateDom(): called afterpostCreateDom(). Can also be called manually byupdateDom().
updateWith() is a shortcut for changing properties and calling updateDom().
Note: When overriding these methods, call the super method.
webfx.injectWebfxCss();classCounterextendsView{constructor(){super();this.count=0;}createDom(){return{tag: "div.counter",child: ["Count: ",{tag: "span",text: ()=>this.count,init: (dom)=>{console.info("the <span> DOM is created",dom);},update: (dom)=>{dom.style.fontSize=`${14+this.count}px`;},},{tag: "br"},newButtonView({text: "Click me",onActive: ()=>{this.updateWith({count: this.count+1});},}),],};}postCreateDom(){super.postCreateDom();console.info("the counter DOM is created",this.dom);}updateDom(){super.updateDom();console.info("the counter DOM is updated",this.dom);}}// Mount the view onto the body element.mountView(document.body,newCounter());(TBD)
Before using JSX/TSX, make sure to set jsx() as the JSX factory in the transpiler.
You can do this in one of two ways:
- Set
"jsxFactory": "jsx"intsconfig.json. - Use
/** @jsx jsx */in your source code.
/** @jsx jsx */import{View,ButtonView,jsx}from"@yuuza/webfx";webfx.injectWebfxCss();classCounterextendsView{constructor(){super();this.count=0;}createDom(){return(<divclass="counter">
Count: {()=>this.count}<br/><ButtonViewonActive={()=>{this.updateWith({count: this.count+1});}}>
Click me
</ButtonView></div>);}}// Mount the view onto the body element.mountView(document.body,newCounter());- Implement functional DOM tree updating.
- Add React-like function components with hooks.
(TBD)