UNPKG

joicomponents

Version:

Design patterns to build native web components

95 lines (85 loc) 2.36 kB
<script> function excludeBranches(nodes, branchPoints) { return Array.from(nodes).filter(function (node) { for (let i = 0; i < branchPoints.length; i++) { if (branchPoints[i].contains(node)) return false; } return true; }); } class MySelect extends HTMLElement { constructor() { super(); this.addEventListener("option-selected", this.optionSelected.bind(this)); } optionSelected(e) { e.stopPropagation(); const options = excludeBranches(this.querySelectorAll("my-option[selected]"), this.querySelectorAll("my-select")); for (let i = 0; i < options.length; i++) { let option = options[i]; option !== e.target && option.removeAttribute("selected"); } } } class MyOption extends HTMLElement { constructor() { super(); this.addEventListener("click", this.clickSelect.bind(this)); } static get observedAttributes() { return ["selected"]; } attributeChangedCallback(name, oldValue, newValue) { if (name === "selected" && newValue !== null && oldValue === null) { this.dispatchEvent(new CustomEvent("option-selected", {bubbles: true})); } } clickSelect(e) { e.stopPropagation(); this.hasAttribute("selected") ? this.removeAttribute("selected") : this.setAttribute("selected", ""); } } customElements.define("my-select", MySelect); customElements.define("my-option", MyOption); </script> <style> my-select { display: block; border: 2px solid grey; margin-left: 10px; } my-option { display: block; margin: 0 10px; } [selected] { border-left: 4px solid red; } #inner [selected] { border-left: 4px solid blue; } </style> <my-select> <my-option>click <my-option>to <my-option selected>select <my-option>between</my-option> <my-option>us</my-option> </my-option> </my-option> </my-option> <my-option> Inner select <my-select id="inner"> <my-option>click</my-option> <my-option>to</my-option> <my-option selected>select</my-option> <my-option>between</my-option> <my-option>us</my-option> </my-select> </my-option> <my-option>so</my-option> <my-option>many</my-option> <my-option>options..</my-option> </my-select>