diff --git a/index.html b/index.html index 4543c5e..52d4055 100644 --- a/index.html +++ b/index.html @@ -1,96 +1,189 @@ + + + + + + + + X-Tag - Web Components Library + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +

X-Tag is a + lightweight, power-packed + Web Components library + that gets you there fast, and stays in its own lane.


@@ -99,627 +192,1256 @@

X-Tag is a
  • + - + + +

    Standard

    +
    Built on Web Components APIs
    +
  • + + + +

    Efficient

    +
    Powerful features in 3k min/gzip
    +
  • + + + +

    Pluggable

    +
    Plays nice with other libraries
    +
  • + + +
    + +

    What is X-Tag?

    + +

    Originally developed at Mozilla, now supported by devs at Microsoft, X-Tag is an open source JavaScript library that wraps the W3C standard Web Components family of APIs + to provide a compact, feature-rich interface for component development. While X-Tag makes it easy to leverage all the Web Components APIs + (Custom Elements, Shadow DOM, Templates, and HTML Imports), it only requires Custom Elements API support to operate. + In the absence of the native Custom Elements APIs, X-Tag uses the same polyfill + Google's Polymer framework relies on. You can view our package options in the Builds section

    + + +
    + + + +
    
    +
     xtag.create('x-clock', class extends XTagElement {
    +
       connectedCallback () {
    +
         this.start();
    +
       }
    +
       start (){
    +
         this.update();
    +
         this._interval = setInterval(() => this.update(), 1000);
    +
       }
    +
       stop (){
    +
         this._interval = clearInterval(this._data.interval);
    +
       }
    +
       update (){
    +
         this.textContent = new Date().toLocaleTimeString();
    +
       }
    +
       'tap::event' (){
    +
         if (this._interval) this.stop();
    +
         else this.start();
    +
       }
    +
     });
    -
    -
    +
    + +

    Browser Support

    +
    +
    + + + + Edge +
    + + + + Chrome (desktop and mobile) +
    + + + + Firefox (desktop and mobile) +
    + + + + Safari (Mac and iOS) +
    + + + + Opera (desktop and mobile) +
    + + + + Android Browser (OS version 5+) +
    +
    + +
    + +
    -

    Install from NPM:

    -

    npm install x-tag

    +

    Install from NPM:

    + +

    npm install x-tag

    + +

    - -
    +

    Download the build that works best for you:

    +
    + + + + +

    X-Tag
    +
    Polyfills

    +
    X-Tag + Custom Elements polyfill
    6k min/gzip
    +
    + + +

    Just X-Tag

    No Polyfills

    +
    Run it raw on native APIs
    3k min/gzip
    +
    +
    +
    -
    - -

    Getting Started

    +
    +

    Getting Started

    + The most important method in the X-Tag library is xtag.create(). The create function on the X-Tag object is what you'll use - to create new custom element definitions, which can include things like lifecycle callbacks, attribute-linked getters/setters (accessors), + + to create new custom element definitions that can be enhanced by using the built in lifecycle callbacks, attribute-linked getters/setters (accessors), rendering features, cached templating, + and event listeners. Here's what defining a simple custom element looks like with X-Tag: +

    -
    
    -const Frank = xtag.create('x-frankenstein', class extends XTagElement {
    +
    const Frank = xtag.create('x-frankenstein', class extends XTagElement {
    +
       constructor (){
    +
         alert("It's moving...it's alive!");
    +
       }
    -});
    -
    + +});
    + +

    + Notice the class definition extends the class XTagElement. If you are not extending from a previously defined Custom Element, + you must always extend from the XTagElement class for X-Tag to properly construct your Custom Element definition. The tag name argument (and subsequent automatic + element registration) is optional - here's what it looks like without it, and how to register your element with a tag name separately: +

    -
    
    -const Frank = xtag.create(class extends XTagElement {
    +
    +
    +
    const Frank = xtag.create(class extends XTagElement {
    +
       constructor (){
    +
         alert("Muhahaha!");
    +
       }
    +
     });
     
    +
    +
     xtag.register('x-frankenstein', Frank);
    +
     

    -

    A Word on Extensions and Pseudos

    -

    - In the next sections you're going to hear about a few features that are delivered via two different types of modular extensibility systems the - library offers for imbuing your elements with advanced functionality. These two systems are called extensions and pseudos. - Both are different in their intent, scope of effect, range of capabilities. You will use them frequently in your Custom Element class definition - blocks, here's what they look like: -

    -
    
    -xtag.create('x-foo', class extends XTagElement {
    -  'alert::foo' (){
     
    -  }
    -  'count:bar' (){
     
    -  }
    -  'send::attr:bar:zaz' (){
    -    
    -  }
    -});
    +
    +
    +

    Gettin' Jedi with Pseudos and Extensions

    + + + +

    + + Two advanced features of X-Tag you need to be aware of in detail are the pseudos and extensions API. + + Here are examples:

    + + + +

    Create your own Pseudo:

    + + + +

    + + Once you create a pseudo and add it to the main xtag.pseudos object, as shown below, + + you can then use it on any key of your custom element definition objects that has a + + function as its value. + +

    + + + +
    xtag.pseudos.foo = {
    +
    +  onParse: function(ctor, property, args, fn){
    +    /*
    +      Description:
    +
    +      onParse is called when the pseudos specified in a declaration are being 
    +
    +      compiled and wrapped around the function they are being applied to.
    +
    +      Parameters:
    +
    +      ctor: the Custom Element Class definition
    +
    +      property: property the pseudo is being applied to (ex: ping:foo, property = ping)
    +
    +      args: arguments from the pseudo definition (ex: prop:foo(1, 2), args = [1, 2])
    +
    +      fn: the function the pseudo is wrapping in the pseudo chain
    +    */
    +
    +  },
    +
    +  onInvoke: function(node, obj){
    +
    +    /*
    +      Description:
    +
    +      Invoke is called any time the pseudo-wrapped function is called. This is where 
    +
    +      you perform whatever action you desire on the node or object the pseudo targets.
    +
    +      Parameters:
    +
    +      node: the element
    +
    +      obj: object composed of these properties: { fn: fn, args: args, detail: detail } 
    +
    +    */
    +
    +  }
    +
    +};
    +
    +xtag.create("x-foo", class extends XTagElement{
    +
    +  "godzilla:foo"(){/* TODO APPLICATION LOGIC */}
    +
    +});
    +
     
    + +

    Create your own Extension

    + +

    + + Creating an extension and using them can be simple, but you can create complex relationships and bindings using this simple method + + to organize data and display it. + +

    + +
    // Lets create our X-Tag extension.
    +
    +xtag.extensions.gobble = {
    +  mixin: (base) => class extends base {
    +    connectedCallback(){ 
    +
    +      /* TODO APPLICATION LOGIC */
    +
    +    }
    +
    +    toGobble() { /* TODO APPLICATION LOGIC */ }
    +
    +    onGobbling() { /* TODO APPLICATION LOGIC */ }
    +
    +    onGobbled() { /* TODO APPLICATION LOGIC */ }
    +  }
    +};
    +
    +// Next we create our XTagElement using the extension method.
    +
    +xtag.create("x-gobble", class extends XTagElement.extensions("gobble"){
    +
    +  "toGobble::gobble"(){ /* TODO APPLICATION LOGIC */ }
    +
    +  "onGobbling::gobble"(){ /* TODO APPLICATION LOGIC */ }
    +
    +  "onGobbled::gobble"(){ /* TODO APPLICATION LOGIC */ }
    +
    +});
    + +

    + +


    + + +

    To an Extended Voyage

    +

    + X-Tag uses the standard Custom Elements mechanism for inheritance: ES6 class extension. The return value of the create method is an X-Tag compiled ES6 class, which + + can be itself extended either via generic ES6 class declaration, or by again passing it into create, if you wanted to add additional features to your new extended class + + using X-Tag APIs. + +

    + + + +
    const Foo = xtag.create('x-foo', class extends XTagElement {
    +
    +  set 'foo::attr' (){ /* Handle foo attribute change */ }
    +
    +});
    +
    +
    +
    +Bar extends Foo {
    +
    +  bar (){ }
    +
    +}
    +
    +
    +
    +const Zaz = xtag.create('x-zaz', class extends Bar {
    +
    +  'click::event' (){ /* do something when clicked */ }
    +
    +});
    +
    +
    + + + +

    + + In the next sections you're going to hear about a few features that are delivered via two different types of modular extensibility systems the + + library offers for imbuing your elements with advanced functionality. These two systems are called extensions and pseudos. + + Both are different in their intent, scope of effect, range of capabilities. You will use them frequently in your Custom Element class definition + + blocks, here's what they look like: + +

    + + + +
    
    +
    +xtag.create('x-foo', class extends XTagElement {
    +
    +  'alert::foo' (){
    +
    +
    +
    +  }
    +
    +  'count:bar' (){
    +
    +
    +
    +  }
    +
    +  'send::foo:bar:zaz' (){
    +
    +    
    +
    +  }
    +
    +});
    +
    +
    + + + +

    + Notice how the alert method has a ::foo attached to it - this is an extension. Extensions are little modules you can created that are called + into service by tagging a property with :: + the name of the extension. Extensions are a sizable API of their own that let's you manipulate + far more than just the property they are tagged to. You can only use one extension per property. +

    + +

    + The other API for adding custom functionality to components is called pseudos, which are seen above in the example property count:bar. When a pseudo is tagged to a property, the pseudo's + own function wraps the target function so that the pseudo is executed first, then the target, which receives its return value. You can chain pseudos, and - they are compiled from left to right so that they left most pseudo function wrapper fires first, passing each function's return value down to the next, until + + they are compiled from left to right so that the left most pseudo function wrapper fires first, passing each function's return value down to the next, until + finally the original target function is executed. You can see what this looks like in the above example property send::foo:bar:zaz. +

    + +

    + There are separate guides for extensions and pseudos that talk about how to create and use your own, but for now just be aware that they are one of + the primary means the X-Tag library delivers its own features. -

    + +


    + + + +

    Say Hello to Custom Attribute Accessors

    + +

    + Accessors are custom attributes linking to a corresponding pair of setters/getters, and X-Tag has a built-in extension that makes adding accessors to + + your custom element definition stupid simple. To use this extension, add an ::attr modifier to one of your class definition properties. + + This tells X-Tag to wire up a getter/setter to an HTML attribute of the same name. When attributes are linked to a getter/setter their gets, sets, and + + state changes will be synced without having to write any additional code. + +

    + +

    + In addition to binding attributes the ::attr extension also allow you to declare a specific data type. +

    + + +
    
    +
    +xtag.create('x-foo', class extends XTagElement {
    +
    +  set 'maxVolume::attr' (value){
    +
    +    // X-Tag automatically maps camel cased getter/setter names to their
    +
    +    // dashed attribute equivalents. In this example, the `maxVolume` 
    +
    +    // getter/setter pair maps to the `max-volume` attribute.
    +
    +  }
    +
    +});
    +
    +
    +
    +xtag.create('x-bar', class extends XTagElement {
    +
    +  '::template(true)' (){ return '<input />' }
    +
    +  set 'disabled::attr(boolean)' (value){
    +
    +    // The ::attr extended property links node.disabled to gets/sets of 
    +
    +    // the disabled="" attribute. Because it is declared as a boolean, 
    +
    +    // all values passed into its getter/setter will be a Boolean.
    +
    +    this.firstElementChild.disabled = value;
    +
    +  }
    +
    +});
    +
    +
    + +
    + + +

    Content is King

    + +

    + Many of the components you create will require child elements for structure and presentation. X-Tag includes a content templating + extension that makes this quick and easy. Simply add a ::template function to your component definition - and return a string or ES6 Template String. In the example below, notice the true parameter being passed to the extension. + + and return a string or ES6 Template String. In the example below, notice the true parameter being passed to the extension. + This tells the template extension to render the content immediately when an instance is created. If you don't want a template to render + automatically like this, don't pass anything to it. +

    +

    + + The XTagElement's `render()` method is the work horse of the `template` `extension`and makes it possible to create feature rich application + + parts. For more information regarding this check out the section. + +

    + + +
    
    +
     xtag.create('x-frankenstein', class extends XTagElement {
    +
       '::template(true)' (){
    +
         return `<h2>I am Frankenstein</h2>
    +
                 <span>I was created by a mad scientist</span>`
    +
       }
    +
     });
    +
     
    + +

    Manual Rendering of Templates

    + +

    + If you elect not to have your template automatically rendered when your component instances are created, you'll need to manually trigger render. +

    + +
    
    +
     const Frank = xtag.create('x-frankenstein', class extends XTagElement {
    +
       name (){ return 'Frankenstein'; }
    +
       '::template' (){
    +
         return `<h2>I am ${this.name()}</h2>
    +
                 <span>I was created by a mad scientist</span>`
    -  }
    -});
    +
    +  }});
    +
    +
     
     const FrankNode = new Frank();
    +
     FrankNode.render();
    +
     
    + +

    Multiple Templates

    + +

    + The template extension can be used multiple times within the same class definition block, which allows you to specify different templates + for use in the same component. The templates are cached and reference based on the property name you put in front of the ::template extension + token. To render your templates, simply pass the name of the template you want to use to the render function, as in the following example: +

    + +
    
    +
     const Frank = xtag.create('x-frankenstein', class extends XTagElement {
    +
       'foo::template(true)' (){
    +
         return `<h2>My name is Frankenstein</h2>
    +
                 <span>I work for a mad scientist</span>`
    +
       }
    +
       'bar::template' (){
    +
         return `<h2>My friends call me Frank</h2>
    +
                 <span>I work for a mad scientist</span>`
    +
       }
    +
     });
     
    +
    +
     const FrankNode = new Frank();
    +
     // Because the foo template indicated it was to be automatically rendered, its content is already present in your element instance.
    +
     FrankNode.render('bar');
    +
     // Calling the render function with the bar template name swaps out the current foo template content with the bar content.
    +
     
    -
    -

    Say Hello to Custom Attribute Accessors

    -

    - Accessors are custom attributes linking to a corresponding pair of setters/getters, and X-Tag has a built-in extension that makes adding accessors to - your custom element definition stupid simple. To use this extension, add an ::attr modifier to one of your class definition properties. - This tells X-Tag to wire up a getter/setter to an HTML attribute of the same name. When attributes are linked to a getter/setter their gets, sets, and - state changes will be synced without having to write any additional code. -

    +

    The Elements Render

    + +

    + + The XTagElement's render() method is the work horse of the template extension. It get's attached to every X-Tag element that you create and can be reused for your own extensions and pseudos. Below is an example of using an event to initiate a mode accessor. + +

    + -

    - You can also tell the accessor extension that type of accessor you are creating, and it will help by sanitizing values and modifying the gets/sets to - match the behavior of the type you declare. I

    
    -xtag.create('x-foo', class extends XTagElement {
    -  set 'maxVolume::attr' (value){
    -    // X-Tag automatically maps camel cased getter/setter names to their
    -    // dashed attribute equivalents. In this example, the `maxVolume` 
    -    // getter/setter pair maps to the `max-volume` attribute.
    +
    +var _rendered = xtag.create( "x-mode", class extends XTagElement {
    +
    +  set 'mode::attr'(_mode) {
    +
    +    this.render(_mode);
    +
    +    return _mode;
    +
       }
    -});
     
    -xtag.create('x-bar', class extends XTagElement {
    -  '::template(true)' (){ return '<input />' }
    -  set 'disabled::attr(boolean)' (value){
    -    // The ::attr extended property links node.disabled to gets/sets of 
    -    // the disabled="" attribute. Because it is declared as a boolean, 
    -    // all values passed into its getter/setter will be a Boolean.
    -    this.firstElementChild.disabled = value;
    +  get 'mode::attr'(){ 
    +
    +    return this.getAttribute("mode"); 
    +
       }
    -});
    -
    + + 'myModeSnippet::template'() { + + return "
    My creation has come to be,

    Rendered.

    "; + + } + + 'click::event'(e){ + + e.target.mode = e.target.mode; + + } + +} );
    + +
    + +

    The DL on Events

    +

    + X-Tag provides a powerful event system you'll use often in developing your components. + We'll cover the basics here, and leave the more advanced features for a special tutorial dedicated to the topic. -

    -

    - To add event listeners to your component (either native or custom events), you'll be using the event extension. To do so, add a property to your - Custom Element definition that matches the name of the event you want to listen for, plus the ::event extension flag. When your class definition - is processed by X-Tag's create method, the event extension will remove the property, add a listener using the supplied property name with the - function you supplied as the handler.

    -
    
    -xtag.register('x-foo', {
    -  'click::event': function(){
    -    // attaches a click listener that calls this function when
    -    // the user clicks an element inside the custom element
    -  },
    -  'focus::event': function(){
    -    // attaches a focus listener that calls this function when
    -    // something inside your custom element is focused.
    -  }
    -});
    -
    - -
    -

    Gettin' Jedi with Pseudos

    - One advanced feature of X-Tag you should be aware of right off the bat is the delegate pseudo. - X-Tag features a function modifier system called pseudos which allows you to seamlessly wrap - functions anywhere in your custom element defintion object (lifecycle callbacks, methods, accessors, and events) - to extend their functionality. The delegate pseudo enables you to quickly add event delegation - (filtering of event targets based on CSS expressions) to any event function you add to your component. Here's an example:

    -
    
    -xtag.register('x-foo', {
    -  content: '<input/>',
    -  events: {
    -    'tap:delegate(input)': function(){
    -      // Perform an action only when the user taps on an
    -      // <input/> element within your component.
    -    }
    -  }
    -});
    -
    + To add event listeners to your component (either native or custom events), you'll be using the event extension. To do so, add a property to your -

    Create your own Pseudo:

    + Custom Element definition that matches the name of the event you want to listen for, plus the ::event extension flag. When your class definition + + is processed by X-Tag's create method, the event extension will remove the property, add a listener using the supplied property name with the + + function you supplied as the handler. -

    - Once you create a pseudo and add it to the main xtag.pseudos object, as show below, - you can then use it on any key of your custom element definition objects that has a - function as its value.

    + +
    
    -xtag.pseudos.foo = {
    -  onParse: function(ctor, property, args, fn){
    -    /*
    -      Parse is called when the pseudos specified in a declaration are being 
    -      compiled and wrapped around the function they are being applied to.
     
    +xtag.register('x-foo', {
    +
    +  'click::event': function(){
    +
    +    // attaches a click listener that calls this function when
    +
    +    // the user clicks an element inside the custom element
     
    -      ctor: the Custom Element Class definition
    -      property: property the pseudo is being applied to (ex: ping:foo, property = ping)
    -      args: arguments from the pseudo definition (ex: prop:foo(1, 2), args = [1, 2])
    -      fn: the function the pseudo is wrapping in the pseud chain
    -    */
       },
    -  onInvoke: function(node, obj){
    -    /*
    -      Invoke is called any time the pseudo-wrapped function is called. This is where 
    -      you perform whatever action you desire on the node or object the pseudo targets.
     
    -      node: the element
    -      obj: object composed of these properties: { fn: fn, args: args, detail: detail } 
    -    */
    -  }
    -};
    -
    + 'focus::event': function(){ -
    + // attaches a focus listener that calls this function when -

    Inheritance

    + // something inside your custom element is focused. -

    - X-Tag uses the standard Custom Elements mechanism for inheritance: ES6 class extension. The return value of the create method is an X-Tag compiled ES6 class, which - can be itself extended either via generic ES6 class declaration, or by again passing it into create, if you wanted to add additional features to your new extended class - using X-Tag APIs. -

    + } -
    
    -const Foo = xtag.create('x-foo', class extends XTagElement {
    -  set 'foo::attr' (){ /* Handle foo attribute change */ }
     });
     
    -Bar extends Foo {
    -  bar (){ }
    -}
    +


    -const Zaz = xtag.create('x-zaz', class extends Bar { - 'click::event' (){ /* do something when clicked */ } -}); -
    -

    API Reference

    + +

    xtag.create(TAG_NAME, DEFINITION)

    + +

    + Create and (optionally) register a Custom Element definition for use as a new tag in HTML markup or via DOM APIS. +

    + + + + + + + + + + + + + + + + + +
    ArgumentTypeDescription
    TAG_NAME
    (optional)
    String + The tag name you want to use when using your Custom Element (must contain a dash). When + this argument is passed, the Custom Element definition is automatically added to the document's Custom Element registry. +
    DEFINITIONClassThe class definition block for your Custom Element
    + +
    
    +
     const Frank = xtag.create('x-frankenstein', class extends XTagElement {
    +
       constructor (){
    +
         alert("It's moving...it's alive!");
    +
       }
    +
     });
    +
     
    + +
    + +

    xtag.addEvent(ELEMENT, TYPE, HANDLER, CAPTURE)

    + +

    + Add a native, custom, or X-Tag library event listener to an element. The TYPE field also + accepts pseudo chains for even more powerful event handling. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentTypeDescription
    ELEMENTDOM element reference + The element you would like to attach an event listener to. +
    TYPEString + The event name, with any event pseudos you may want to chain. +
    HANDLERFunction + The event handler you want called when the event occurs. +
    CAPTUREFunction + Boolean argument you can pass if you want the event to use capturing vs bubbling. +
    + +
    
    +
     xtag.addEvent(myElement, 'tap:delegate(img)', function(event){
    +
       alert('An image element within myElement was just tapped');
    +
     });
    +
     
    + +
    + +

    xtag.addEvents(ELEMENT, OBJECT)

    + +

    + Add multiple native, custom, or X-Tag library event listeners to an element using one function. + Pseudo chains are avaliable for use in your event object keys. +

    + + + + + + + + + + + + + + + + + +
    ArgumentTypeDescription
    ELEMENTDOM element reference + The element you would like to attach the event listeners to. +
    OBJECTObject + An object composed of multiple events - keys are event names, and values are the event handlers. +
    + +
    
    +
     xtag.addEvents(myElement, {
    +
       'tap': function(event){
    +
         alert('myElement was just tapped');
    +
       },
    +
       'keypress:keypass(13)': function(event){
    +
         alert('The enter key was pressed, all other keys are blocked');
    +
       }
    +
     });
    +
     
    + +

    xtag.fireEvent(ELEMENT, NAME, OPTIONS)

    + +

    + Add a native, custom, or X-Tag library event listener to an element. The TYPE field also + accepts pseudo chains for even more powerful event handling. +

    + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentTypeDescription
    ELEMENTDOM element reference + The element you would like to attach an event listener to. +
    NAMEString + The event name you wish to fire on the target element. +
    OPTIONSObject + The event options you want to use in firing your event. These include: +
      +
    • detail allows passage of custom data via the detail property of the event
    • +
    • bubbles specify whether the event bubbles - defaults to true
    • +
    • cancelable specify whether the event is cancelable - defaults to true
    • +
    +
    + +
    
    +
     xtag.fireEvent(myElement, 'show', {
    +
       detail: {
    +
         x: 123,
    +
         y: 456
    +
       }
    +
     });
    +
     
    + +
    + +
    + + + + + + + + + + + - \ No newline at end of file + +