Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <title>Sample Mixin-Based Component</title>
  <!-- See "CSS" tab for styles -->
  <script>
    // This sample demonstrates how component behavior may be factored into
    // separate mixins. In this sample, three separate mixins handle input,
    // abstract semantics, and output, respectively. The three can be combined
    // to produce give a custom element very rudimentary selection support.
    //
    // These particular mixins are overly simplistic in order to focus just on
    // the way the mixins communicate. Real implementations of these would be
    // more complex in order to handle Shadow DOM distribution, events, issues
    // in older browsers, etc.
    //
    // This sample currently requires Google Chrome or Safari Technology Preview.
    
    
    // Simplistic mixin mapping click input to selection semantics.
    const ClickSelectionMixin = (base) => class ClickSelection extends base {
      constructor() {
        super();
        // When a child is clicked, set the selectedItem.
        this.addEventListener('click', event => {
          this.selectedItem = event.target;
          event.stopPropagation();
        });
      }
    }
    
    // Simplistic mixin for single selection.
    // This can remember which of the component's children is selected.
    // This also maps component selection semantics (which item is selected)
    // to item selection semantics (is an individual item selected or not).
    const selectedItemSymbol = Symbol('selectedItem');
    const SingleSelectionMixin = (base) => class SingleSelection extends base {
      
      // Turn the selection state of an individual item on or off.
      // The exact semantics of that can be defined elsewhere.
      // Note: To simplify inspection of this sample in the debugger, this
      // method has a string name. In practice, this internal method would
      // be referenced via a Symbol key instead to avoid exposing it in the
      // component's public API.
      applySelection(item, selected) {
        if (super.applySelection) { super.applySelection(item, selected); }
        // By default, nothing happens when something is selected.
      }
      
      // The item (child) which is currently selected.
      get selectedItem() {
        return this[selectedItemSymbol];
      }
      set selectedItem(item) {
        
        // Remember which item has now become selected.
        const previousSelectedItem = this[selectedItemSymbol];
        this[selectedItemSymbol] = item;
        
        // Invoke super in case other mixins implement this property.
        // Note: we detect whether the property is defined further up the
        // prototype chain by inspecting `in base.prototype`, since `in super`
        // is not valid, and just accessing `super.selectedItem` would actually
        // return the current value of that base class property if it existed.
        if ('selectedItem' in base.prototype) { super.selectedItem = item; }
        
        if (previousSelectedItem !== item) {
          // The selected item changed.
          if (previousSelectedItem) {
            // Remove selection from previous item.
            this.applySelection(previousSelectedItem, false);
          }
          // Apply selection to new item.
          this.applySelection(item, true);
        }
      }
      
    }
    
    // Simplistic mixin mapping item selection to a `selected` CSS class.
    const SelectionClassMixin = (base) => class SelectionClass extends base {
      
      applySelection(item, selected) {
        if (super.applySelection) { super.applySelection(item, selected); }
        item.classList.toggle('selected', selected);
      }
      
    }
    
    // Define a custom element using the above mixins.
    // Significantly, the order of mixin application doesn't matter.
    class TestElement extends 
        ClickSelectionMixin(SelectionClassMixin(SingleSelectionMixin(HTMLElement))) {}
    customElements.define('test-element', TestElement);
  </script>
</head>
<body>
  <p>
    Click an item to select it:
  </p>
  <test-element>
    <div>One</div>
    <div>Two</div>
    <div>Three</div>
    <div>Four</div>
    <div>Five</div>
  </test-element>
</body>
</html>
 
body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 15px;
  margin: 0;
  padding: 25px;
}
test-element {
  cursor: default;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
test-element > * {
  align-items: center;
  border: 1px solid lightgray;
  display: inline-flex;
  height: 50px;
  justify-content: center;
  padding: 0.25em;
  width: 50px;
}
test-element > .selected {
  background-color: highlight;
  color: highlighttext;
}
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
JanMiksovskypro
0viewers