diff --git a/demo/demo.css b/demo/demo.css
index ff0c798..87f5300 100644
--- a/demo/demo.css
+++ b/demo/demo.css
@@ -1,160 +1 @@
-/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
-html {
- line-height: 1.15;
- -webkit-text-size-adjust: 100%;
-}
-
-body {
- margin: 0;
-}
-
-main {
- display: block;
-}
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-hr {
- box-sizing: content-box;
- height: 0;
- overflow: visible;
-}
-
-pre {
- font-family: monospace, monospace;
- font-size: 1em;
-}
-
-a {
- background-color: transparent;
-}
-
-abbr[title] {
- border-bottom: none;
- text-decoration: underline;
- -webkit-text-decoration: underline dotted;
- text-decoration: underline dotted;
-}
-
-b, strong {
- font-weight: bolder;
-}
-
-code, kbd, samp {
- font-family: monospace, monospace;
- font-size: 1em;
-}
-
-small {
- font-size: 80%;
-}
-
-sub, sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-sup {
- top: -0.5em;
-}
-
-img {
- border-style: none;
-}
-
-button, input, optgroup, select, textarea {
- font-family: inherit;
- font-size: 100%;
- line-height: 1.15;
- margin: 0;
-}
-
-button, input {
- overflow: visible;
-}
-
-button, select {
- text-transform: none;
-}
-
-[type=button], [type=reset], [type=submit], button {
- -webkit-appearance: button;
-}
-
-[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {
- border-style: none;
- padding: 0;
-}
-
-[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {
- outline: 1px dotted ButtonText;
-}
-
-fieldset {
- padding: 0.35em 0.75em 0.625em;
-}
-
-legend {
- box-sizing: border-box;
- color: inherit;
- display: table;
- max-width: 100%;
- padding: 0;
- white-space: normal;
-}
-
-progress {
- vertical-align: baseline;
-}
-
-textarea {
- overflow: auto;
-}
-
-[type=checkbox], [type=radio] {
- box-sizing: border-box;
- padding: 0;
-}
-
-[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {
- height: auto;
-}
-
-[type=search] {
- -webkit-appearance: textfield;
- outline-offset: -2px;
-}
-
-[type=search]::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-::-webkit-file-upload-button {
- -webkit-appearance: button;
- font: inherit;
-}
-
-details {
- display: block;
-}
-
-summary {
- display: list-item;
-}
-
-template {
- display: none;
-}
-
-[hidden] {
- display: none;
-}
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}
diff --git a/demo/demo.js b/demo/demo.js
index f5535be..23b577a 100644
--- a/demo/demo.js
+++ b/demo/demo.js
@@ -1,3038 +1,6 @@
-/******/ (() => { // webpackBootstrap
-/******/ var __webpack_modules__ = ({
-
-/***/ "./src/field-error.riot":
-/*!******************************!*\
- !*** ./src/field-error.riot ***!
- \******************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "default": () => __WEBPACK_DEFAULT_EXPORT__
-/* harmony export */ });
-/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
- 'css': null,
-
- 'exports': {
- state: {
- errors: [
-
- ],
- },
-
- onMounted(props, state) {
-
- const parent = this.root.closest('.field')
- const element = document.querySelector('[name="' + props.name + '"]')
- const form = element.closest('form')
-
- // element and form set
- if (element && form) {
- element.addEventListener('keyup', function(event) {
-
- const fieldUpdateEvent = new CustomEvent('field-update', {
- 'detail': {
- 'name': props.name,
- 'value': this.value
- }
- })
-
- form.dispatchEvent(fieldUpdateEvent)
- })
- }
-
- // add custom event to listen to form-validation
- this.root.addEventListener('form-validation', (event) => {
-
- // if detail is set with element name, get errors
- if (event.detail) {
- this.state.errors = event.detail
- parent.classList.add('field--error')
- parent.classList.remove('field--valid')
- } else {
- this.state.errors = []
- parent.classList.remove('field--error')
- parent.classList.add('field--valid')
- }
-
- this.update()
- })
- }
- },
-
- 'template': function(
- template,
- expressionTypes,
- bindingTypes,
- getComponent
- ) {
- return template(
- '
',
- [
- {
- 'type': bindingTypes.IF,
-
- 'evaluate': function(
- scope
- ) {
- return scope.state.errors.length > 0;
- },
-
- 'redundantAttribute': 'expr0',
- 'selector': '[expr0]',
-
- 'template': template(
- '',
- [
- {
- 'type': bindingTypes.EACH,
- 'getKey': null,
- 'condition': null,
-
- 'template': template(
- ' ',
- [
- {
- 'expressions': [
- {
- 'type': expressionTypes.TEXT,
- 'childNodeIndex': 0,
-
- 'evaluate': function(
- scope
- ) {
- return [
- scope.error
- ].join(
- ''
- );
- }
- }
- ]
- }
- ]
- ),
-
- 'redundantAttribute': 'expr1',
- 'selector': '[expr1]',
- 'itemName': 'error',
- 'indexName': null,
-
- 'evaluate': function(
- scope
- ) {
- return scope.state.errors;
- }
- }
- ]
- )
- }
- ]
- );
- },
-
- 'name': 'field-error'
-});
-
-/***/ }),
-
-/***/ "./src/FormValidator.js":
-/*!******************************!*\
- !*** ./src/FormValidator.js ***!
- \******************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "default": () => __WEBPACK_DEFAULT_EXPORT__
-/* harmony export */ });
-/* harmony import */ var validate_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! validate.js */ "./node_modules/validate.js/validate.js");
-/* harmony import */ var validate_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(validate_js__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var form_serialize__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! form-serialize */ "./node_modules/form-serialize/index.js");
-/* harmony import */ var form_serialize__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(form_serialize__WEBPACK_IMPORTED_MODULE_1__);
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
-
-function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
-
-
-
-/**
- *
- *
- *
- */
-
-var FormValidator = /*#__PURE__*/function () {
- /**
- *
- * @param {[type]} formSelector [description]
- * @param {[type]} constraits [description]
- */
- function FormValidator(formSelector, constraits) {
- var _this = this;
-
- _classCallCheck(this, FormValidator);
-
- this.errors = []; // getting selector to find form-element
-
- this.formSelector = formSelector; // constraits for validate.js
-
- this.constraits = constraits; // get form and elements
-
- this.form = document.querySelector(this.formSelector);
- this.elements = this.form.querySelectorAll('field-error'); // adding submit event
-
- this.form.addEventListener('submit', function (event) {
- _this.onSubmit(event);
- }); // adding event if a element is updated
-
- this.form.addEventListener('field-update', function (event) {
- _this.onFieldUpdate(event);
- });
- }
- /**
- *
- * @param {[type]} name [description]
- * @return {[type]} [description]
- */
-
-
- _createClass(FormValidator, [{
- key: "findElementByName",
- value: function findElementByName(name) {
- var result;
- this.elements.forEach(function (element) {
- if (element.attributes.name.nodeValue == name) {
- result = element;
- return false;
- }
- });
- return result;
- }
- /**
- *
- * @param {[type]} event [description]
- * @return {[type]} [description]
- */
-
- }, {
- key: "onSubmit",
- value: function onSubmit(event) {
- var _this2 = this;
-
- var errors = validate_js__WEBPACK_IMPORTED_MODULE_0___default()(form_serialize__WEBPACK_IMPORTED_MODULE_1___default()(event.target, {
- hash: true
- }), this.constraits);
-
- if (errors) {
- event.preventDefault();
- this.elements.forEach(function (element) {
- var elementErrors = false;
-
- if (errors[element.attributes.name.nodeValue]) {
- elementErrors = errors[element.attributes.name.nodeValue];
- }
-
- _this2.dispatchCustomEvent(elementErrors, element);
- });
- }
- }
- /**
- *
- * @param {[type]} event [description]
- * @return {[type]} [description]
- */
-
- }, {
- key: "onFieldUpdate",
- value: function onFieldUpdate(event) {
- var errors = validate_js__WEBPACK_IMPORTED_MODULE_0___default().single(event.detail.value, this.constraits[event.detail.name]);
- var element = this.findElementByName(event.detail.name);
- this.dispatchCustomEvent(errors, element);
- }
- /**
- *
- * @param {[type]} errors [description]
- * @param {[type]} element [description]
- * @return {[type]} [description]
- */
-
- }, {
- key: "dispatchCustomEvent",
- value: function dispatchCustomEvent(errors, element) {
- var detail = false;
-
- if (errors) {
- detail = errors;
- }
-
- var formValidationEvent = new CustomEvent('form-validation', {
- 'detail': detail
- });
- element.dispatchEvent(formValidationEvent);
- }
- }]);
-
- return FormValidator;
-}();
-
-/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (FormValidator);
-
-/***/ }),
-
-/***/ "./src/demo/demo.js":
-/*!**************************!*\
- !*** ./src/demo/demo.js ***!
- \**************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony import */ var riot__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! riot */ "./node_modules/riot/riot.esm.js");
-/* harmony import */ var _FormValidator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./../FormValidator */ "./src/FormValidator.js");
-/* harmony import */ var _field_error_riot__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./../field-error.riot */ "./src/field-error.riot");
-
-
-
-riot__WEBPACK_IMPORTED_MODULE_2__.register('field-error', _field_error_riot__WEBPACK_IMPORTED_MODULE_1__.default);
-riot__WEBPACK_IMPORTED_MODULE_2__.mount('field-error');
-var formValidation = new _FormValidator__WEBPACK_IMPORTED_MODULE_0__.default('form', {
- 'email': {
- 'presence': true,
- 'email': true
- },
- 'password': {
- 'presence': true
- }
-});
-
-/***/ }),
-
-/***/ "./node_modules/form-serialize/index.js":
-/*!**********************************************!*\
- !*** ./node_modules/form-serialize/index.js ***!
- \**********************************************/
-/***/ ((module) => {
-
-// get successful control from form and assemble into object
-// http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2
-
-// types which indicate a submit action and are not successful controls
-// these will be ignored
-var k_r_submitter = /^(?:submit|button|image|reset|file)$/i;
-
-// node names which could be successful controls
-var k_r_success_contrls = /^(?:input|select|textarea|keygen)/i;
-
-// Matches bracket notation.
-var brackets = /(\[[^\[\]]*\])/g;
-
-// serializes form fields
-// @param form MUST be an HTMLForm element
-// @param options is an optional argument to configure the serialization. Default output
-// with no options specified is a url encoded string
-// - hash: [true | false] Configure the output type. If true, the output will
-// be a js object.
-// - serializer: [function] Optional serializer function to override the default one.
-// The function takes 3 arguments (result, key, value) and should return new result
-// hash and url encoded str serializers are provided with this module
-// - disabled: [true | false]. If true serialize disabled fields.
-// - empty: [true | false]. If true serialize empty fields
-function serialize(form, options) {
- if (typeof options != 'object') {
- options = { hash: !!options };
- }
- else if (options.hash === undefined) {
- options.hash = true;
- }
-
- var result = (options.hash) ? {} : '';
- var serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize);
-
- var elements = form && form.elements ? form.elements : [];
-
- //Object store each radio and set if it's empty or not
- var radio_store = Object.create(null);
-
- for (var i=0 ; i {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-// extracted by mini-css-extract-plugin
-
-
-/***/ }),
-
-/***/ "./node_modules/riot/riot.esm.js":
-/*!***************************************!*\
- !*** ./node_modules/riot/riot.esm.js ***!
- \***************************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */ "__": () => /* binding */ __,
-/* harmony export */ "component": () => /* binding */ component,
-/* harmony export */ "install": () => /* binding */ install,
-/* harmony export */ "mount": () => /* binding */ mount,
-/* harmony export */ "pure": () => /* binding */ pure,
-/* harmony export */ "register": () => /* binding */ register,
-/* harmony export */ "uninstall": () => /* binding */ uninstall,
-/* harmony export */ "unmount": () => /* binding */ unmount,
-/* harmony export */ "unregister": () => /* binding */ unregister,
-/* harmony export */ "version": () => /* binding */ version
-/* harmony export */ });
+(()=>{var t={2:(t,e,n)=>{"use strict";function r(t){return t.replace(/-(\w)/g,((t,e)=>e.toUpperCase()))}function i(t,e){t.firstChild&&(e.appendChild(t.firstChild),i(t,e))}function s(t){Array.from(t).forEach(o)}const o=t=>t&&t.parentNode&&t.parentNode.removeChild(t),a=(t,e)=>e&&e.parentNode&&e.parentNode.insertBefore(t,e),u=new Map,l=Symbol("riot-component"),c=new Set,f="is",d="mount",h="update",p="unmount",m="shouldUpdate",g="onBeforeMount",v="onMounted",b="onBeforeUpdate",y="onUpdated",E="onBeforeUnmount",x="onUnmounted",O="props",N="state",w="slots",T="root",j=Symbol.for("pure"),A=Symbol("parent"),S=Symbol("attributes"),M=Symbol("template");var _=Object.freeze({__proto__:null,COMPONENTS_IMPLEMENTATION_MAP:u,DOM_COMPONENT_INSTANCE_PROPERTY:l,PLUGINS_SET:c,IS_DIRECTIVE:f,VALUE_ATTRIBUTE:"value",MOUNT_METHOD_KEY:d,UPDATE_METHOD_KEY:h,UNMOUNT_METHOD_KEY:p,SHOULD_UPDATE_KEY:m,ON_BEFORE_MOUNT_KEY:g,ON_MOUNTED_KEY:v,ON_BEFORE_UPDATE_KEY:b,ON_UPDATED_KEY:y,ON_BEFORE_UNMOUNT_KEY:E,ON_UNMOUNTED_KEY:x,PROPS_KEY:O,STATE_KEY:N,SLOTS_KEY:w,ROOT_KEY:T,IS_PURE_SYMBOL:j,PARENT_KEY_SYMBOL:A,ATTRIBUTES_KEY_SYMBOL:S,TEMPLATE_KEY_SYMBOL:M});var D={EACH:0,IF:1,SIMPLE:2,TAG:3,SLOT:4};var P={ATTRIBUTE:0,EVENT:1,TEXT:2,VALUE:3};function k(t,e){return typeof t===e}function C(t){const e=t.ownerSVGElement;return!!e||null===e}function L(t){return!R(t.content)}function U(t){return k(t,"function")}function I(t){return!R(t)&&k(t,"object")}function R(t){return null==t}const z=Symbol("unmount"),V={nodes:[],mount(t,e){return this.update(t,e)},update(t,e){const{placeholder:n,nodes:r,childrenMap:i}=this,s=t===z?null:this.evaluate(t),u=s?Array.from(s):[],{newChildrenMap:l,batches:c,futureNodes:f}=(n.parentNode,function(t,e,n,r){const{condition:i,template:s,childrenMap:o,itemName:a,getKey:u,indexName:l,root:c,isTemplateTag:f}=r,d=new Map,h=[],p=[];return t.forEach(((t,r)=>{const m=function(t,e){let{itemName:n,indexName:r,index:i,item:s}=e;t[n]=s,r&&(t[r]=i);return t}(Object.create(e),{itemName:a,indexName:l,index:r,item:t}),g=u?u(m):r,v=o.get(g);if(function(t,e){return!!t&&!1===Boolean(t(e))}(i,m))return;const b=v?v.template:s.clone(),y=v?b.el:c.cloneNode(),E=!v,x=f&&E?function(t){const e=t.dom.cloneNode(!0);return{avoidDOMInjection:!0,fragment:e,children:Array.from(e.childNodes)}}(b):{};if(E?h.push((()=>b.mount(y,m,n,x))):h.push((()=>b.update(m,n))),f){const t=x.children||b.children;p.push(...t)}else p.push(y);o.delete(g),d.set(g,{template:b,context:m,index:r})})),{newChildrenMap:d,batches:h,futureNodes:p}}(u,t,e,this));return((t,e,n,r,i)=>{const s=n.length;let u=e.length,l=s,c=0,f=0,d=null;for(;ct-f){const i=r(e[c],0);for(;f{if(r<0){const n=t.pop();if(n){const{template:t,context:r}=n;t.unmount(r,e,null)}}return n}}(Array.from(i.values()),e),n),c.forEach((t=>t())),this.childrenMap=l,this.nodes=f,this},unmount(t,e){return this.update(z,e),this}};const F={mount(t,e){return this.update(t,e)},update(t,e){const n=!!this.evaluate(t),r=!this.value&&n,i=this.value&&!n,s=()=>{const n=this.node.cloneNode();a(n,this.placeholder),this.template=this.template.clone(),this.template.mount(n,t,e)};switch(!0){case r:s();break;case i:this.unmount(t);break;default:n&&this.template.update(t,e)}return this.value=n,this},unmount(t,e){return this.template.unmount(t,e,!0),this}};function B(t){throw new Error(t)}function K(t){return t.reduce(((t,e)=>{const{value:n,type:i}=e;switch(!0){case!e.name&&0===i:return Object.assign({},t,n);case 3===i:t.value=e.value;break;default:t[r(e.name)]=e.value}return t}),{})}const Y="removeAttribute",$="setAttribute",q="undefined"==typeof Element?{}:Element.prototype,H=function(t){const e=new Map,n=n=>(e.has(n)||e.set(n,t.call(this,n)))&&e.get(n);return n.cache=e,n}((t=>q.hasOwnProperty(t)));function G(t,e,n,r){let{name:i}=e;if(!i)return r&&function(t,e,n){const r=e?Object.keys(e):[];Object.keys(n).filter((t=>!r.includes(t))).forEach((e=>t.removeAttribute(e)))}(t,n,r),void(n&&function(t,e){Object.entries(e).forEach((e=>{let[n,r]=e;return G(t,{name:n},r)}))}(t,n));!H(i)&&(function(t){return k(t,"boolean")}(n)||I(n)||U(n))&&(t[i]=n),t[function(t){return R(t)||!1===t||""===t||I(t)||U(t)?Y:$}(n)](i,function(t,e){return!0===e?t:e}(i,n))}const X=/^on/,J={handleEvent(t){this[t.type](t)}},Z=new WeakMap;function W(t){return R(t)?"":t}const Q=(t,e)=>{const n=t.childNodes[e];if(n.nodeType===Node.COMMENT_NODE){const e=document.createTextNode("");return t.replaceChild(e,n),e}return n};var tt={0:G,1:function(t,e,n){let{name:r}=e;const i=r.replace(X,""),s=Z.get(t)||(t=>{const e=Object.create(J);return Z.set(t,e),e})(t),[o,a]=(t=>Array.isArray(t)?t:[t,!1])(n),u=s[i],l=o&&!u;u&&!o&&t.removeEventListener(i,s),l&&t.addEventListener(i,s,a),s[i]=o},2:function(t,e,n){t.data=W(n)},3:function(t,e,n){t.value=W(n)}};const et={mount(t){return this.value=this.evaluate(t),nt(this,this.value),this},update(t){const e=this.evaluate(t);return this.value!==e&&(nt(this,e),this.value=e),this},unmount(){return 1===this.type&&nt(this,null),this}};function nt(t,e){return tt[t.type](t.node,t,e,t.value)}function rt(t,e){return Object.assign({},et,e,{node:2===e.type?Q(t,e.childNodeIndex):t})}const it=(t,e)=>t[A]||e,st={attributes:[],getTemplateScope(t,e){return function(t,e,n){if(!t||!t.length)return n;const r=t.map((t=>Object.assign({},t,{value:t.evaluate(e)})));return Object.assign(Object.create(n||null),K(r))}(this.attributes,t,e)},mount(t,e){const n=!!t.slots&&t.slots.find((t=>{let{id:e}=t;return e===this.name})),{parentNode:r}=this.node,i=it(t,e);return this.template=n&&mt(n.html,n.bindings).createDOM(r),this.template&&(this.template.mount(this.node,this.getTemplateScope(t,i),i),this.template.children=Array.from(this.node.childNodes),ot(this.node)),o(this.node),this},update(t,e){if(this.template){const n=it(t,e);this.template.update(this.getTemplateScope(t,n),n)}return this},unmount(t,e,n){return this.template&&this.template.unmount(this.getTemplateScope(t,e),null,n),this}};function ot(t){const e=t&&t.firstChild;e&&(a(e,t),ot(t))}function at(t){return t.reduce(((t,e)=>{let{bindings:n}=e;return t.concat(n)}),[])}const ut={mount(t){return this.update(t)},update(t,e){const n=this.evaluate(t);return n===this.name?this.tag.update(t):(this.unmount(t,e,!0),this.name=n,this.tag=function(t,e,n){return void 0===e&&(e=[]),void 0===n&&(n=[]),t?t({slots:e,attributes:n}):mt(function(t){return t.reduce(((t,e)=>t+e.html),"")}(e),[...at(e),{expressions:n.map((t=>Object.assign({type:0},t)))}])}(this.getComponent(n),this.slots,this.attributes),this.tag.mount(this.node,t)),this},unmount(t,e,n){return this.tag&&this.tag.unmount(n),this}};var lt={1:function(t,e){let{evaluate:n,template:r}=e;const i=document.createTextNode("");return a(i,t),o(t),Object.assign({},F,{node:t,evaluate:n,placeholder:i,template:r.createDOM(t)})},2:function(t,e){let{expressions:n}=e;return Object.assign({},(r=n.map((e=>rt(t,e))),["mount","update","unmount"].reduce(((t,e)=>Object.assign({},t,{[e]:t=>r.map((n=>n[e](t)))&&i})),{})));var r,i},0:function(t,e){let{evaluate:n,condition:r,itemName:i,indexName:s,getKey:u,template:l}=e;const c=document.createTextNode(""),f=t.cloneNode();return a(c,t),o(t),Object.assign({},V,{childrenMap:new Map,node:t,root:f,condition:r,evaluate:n,isTemplateTag:L(f),template:l.createDOM(t),getKey:u,indexName:s,itemName:i,placeholder:c})},3:function(t,e){let{evaluate:n,getComponent:r,slots:i,attributes:s}=e;return Object.assign({},ut,{node:t,evaluate:n,slots:i,attributes:s,getComponent:r})},4:function(t,e){let{name:n,attributes:r}=e;return Object.assign({},st,{attributes:r,node:t,name:n})}};function ct(t,e){return t.map((t=>2===t.type?Object.assign({},t,{childNodeIndex:t.childNodeIndex+e}):t))}function ft(t,e,n){const{selector:r,type:i,redundantAttribute:s,expressions:o}=e,a=r?t.querySelector(r):t;s&&a.removeAttribute(s);const u=o||[];return(lt[i]||lt[2])(a,Object.assign({},e,{expressions:n&&!r?ct(u,n):u}))}function dt(t,e){return C(t)?function(t,e){return e.ownerDocument.importNode((new window.DOMParser).parseFromString(``,"application/xml").documentElement,!0)}(e,t):function(t,e){const n=L(e)?e:document.createElement("template");return n.innerHTML=t,n.content}(e,t)}function ht(t,e){switch(!0){case C(t):i(e,t);break;case L(t):t.parentNode.replaceChild(e,t);break;default:t.appendChild(e)}}const pt=Object.freeze({createDOM(t){return this.dom=this.dom||function(t,e){return e&&("string"==typeof e?dt(t,e):e)}(t,this.html),this},mount(t,e,n,r){if(void 0===r&&(r={}),!t)throw new Error("Please provide DOM node to mount properly your template");this.el&&this.unmount(e);const{fragment:i,children:s,avoidDOMInjection:o}=r,{parentNode:a}=s?s[0]:t,u=L(t),l=u?Math.max(Array.from(a.childNodes).indexOf(t),0):null;return this.isTemplateTag=u,this.createDOM(t),this.dom&&(this.fragment=i||this.dom.cloneNode(!0)),this.el=this.isTemplateTag?a:t,this.children=this.isTemplateTag?s||Array.from(this.fragment.childNodes):null,!o&&this.fragment&&ht(t,this.fragment),this.bindings=this.bindingsData.map((t=>ft(this.el,t,l))),this.bindings.forEach((t=>t.mount(e,n))),this},update(t,e){return this.bindings.forEach((n=>n.update(t,e))),this},unmount(t,e,n){if(this.el){switch(this.bindings.forEach((r=>r.unmount(t,e,n))),!0){case this.el[j]:break;case this.children&&null!==n:s(this.children);break;case!0===n:o(this.el);break;case null!==n:s(this.el.childNodes)}this.el=null}return this},clone(){return Object.assign({},this,{el:null})}});function mt(t,e){return void 0===e&&(e=[]),Object.assign({},pt,{html:t,bindingsData:e})}function gt(){return this}function vt(t){return U(t)?t.prototype&&t.prototype.constructor?new t:t():t}function bt(t,e,n,r){return void 0===r&&(r={}),Object.defineProperty(t,e,Object.assign({value:n,enumerable:!1,writable:!1,configurable:!0},r)),t}function yt(t,e,n){return Object.entries(e).forEach((e=>{let[r,i]=e;bt(t,r,i,n)})),t}function Et(t,e){return Object.entries(e).forEach((e=>{let[n,r]=e;t[n]||(t[n]=r)})),t}function xt(t){return Array.isArray(t)?t:/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(t))&&"number"==typeof t.length?Array.from(t):[t]}function Ot(t,e){return xt("string"==typeof t?(e||document).querySelectorAll(t):t)}const Nt=t=>1===t.length?t[0]:t;function wt(t,e,n){const r="object"==typeof e?e:{[e]:n},i=Object.keys(r);return xt(t).forEach((t=>{i.forEach((e=>t.setAttribute(e,r[e])))})),t}function Tt(t,e){return function(t,e,n){const r="string"==typeof e?[e]:e;return Nt(xt(t).map((t=>Nt(r.map((e=>t[n](e)))))))}(t,e,"getAttribute")}const jt=new Map,At=()=>St||(wt(St=Ot("style[riot]")[0]||document.createElement("style"),"type","text/css"),St.parentNode||document.head.appendChild(St),St);var St,Mt={CSS_BY_NAME:jt,add(t,e){return jt.has(t)||(jt.set(t,e),this.inject()),this},inject(){return At().innerHTML=[...jt.values()].join("\n"),this},remove(t){return jt.has(t)&&(jt.delete(t),this.inject()),this}};function _t(t){for(var e=arguments.length,n=new Array(e>1?e-1:0),r=1;r(t[r(e.name)]=e.value,t)),{})}(t),vt(e))}const It=(t,e)=>t[l]=e;function Rt(t){return[d,h,p].reduce(((e,n)=>(e[n]=t(n),e)),{})}function zt(t){let{css:e,template:n,exports:r,name:i}=t;const s=n?function(t,e){return t(mt,P,D,(t=>e[t]||u.get(t)))}(n,r?function(t){void 0===t&&(t={});return Object.entries(vt(t)).reduce(((t,e)=>{let[n,r]=e;
/* Riot v5.1.2, @license MIT */
-/**
- * Convert a string from camel case to dash-case
- * @param {string} string - probably a component tag name
- * @returns {string} component name normalized
- */
-function camelToDashCase(string) {
- return string.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
-}
-/**
- * Convert a string containing dashes to camel case
- * @param {string} string - input string
- * @returns {string} my-string -> myString
- */
-
-function dashToCamelCase(string) {
- return string.replace(/-(\w)/g, (_, c) => c.toUpperCase());
-}
-
-/**
- * Get all the element attributes as object
- * @param {HTMLElement} element - DOM node we want to parse
- * @returns {Object} all the attributes found as a key value pairs
- */
-
-function DOMattributesToObject(element) {
- return Array.from(element.attributes).reduce((acc, attribute) => {
- acc[dashToCamelCase(attribute.name)] = attribute.value;
- return acc;
- }, {});
-}
-/**
- * Move all the child nodes from a source tag to another
- * @param {HTMLElement} source - source node
- * @param {HTMLElement} target - target node
- * @returns {undefined} it's a void method ¯\_(ツ)_/¯
- */
-// Ignore this helper because it's needed only for svg tags
-
-function moveChildren(source, target) {
- if (source.firstChild) {
- target.appendChild(source.firstChild);
- moveChildren(source, target);
- }
-}
-/**
- * Remove the child nodes from any DOM node
- * @param {HTMLElement} node - target node
- * @returns {undefined}
- */
-
-function cleanNode(node) {
- clearChildren(node.childNodes);
-}
-/**
- * Clear multiple children in a node
- * @param {HTMLElement[]} children - direct children nodes
- * @returns {undefined}
- */
-
-function clearChildren(children) {
- Array.from(children).forEach(removeChild);
-}
-/**
- * Remove a node
- * @param {HTMLElement}node - node to remove
- * @returns {undefined}
- */
-
-const removeChild = node => node && node.parentNode && node.parentNode.removeChild(node);
-/**
- * Insert before a node
- * @param {HTMLElement} newNode - node to insert
- * @param {HTMLElement} refNode - ref child
- * @returns {undefined}
- */
-
-const insertBefore = (newNode, refNode) => refNode && refNode.parentNode && refNode.parentNode.insertBefore(newNode, refNode);
-/**
- * Replace a node
- * @param {HTMLElement} newNode - new node to add to the DOM
- * @param {HTMLElement} replaced - node to replace
- * @returns {undefined}
- */
-
-const replaceChild = (newNode, replaced) => replaced && replaced.parentNode && replaced.parentNode.replaceChild(newNode, replaced);
-
-// Riot.js constants that can be used accross more modules
-const COMPONENTS_IMPLEMENTATION_MAP = new Map(),
- DOM_COMPONENT_INSTANCE_PROPERTY = Symbol('riot-component'),
- PLUGINS_SET = new Set(),
- IS_DIRECTIVE = 'is',
- VALUE_ATTRIBUTE = 'value',
- MOUNT_METHOD_KEY = 'mount',
- UPDATE_METHOD_KEY = 'update',
- UNMOUNT_METHOD_KEY = 'unmount',
- SHOULD_UPDATE_KEY = 'shouldUpdate',
- ON_BEFORE_MOUNT_KEY = 'onBeforeMount',
- ON_MOUNTED_KEY = 'onMounted',
- ON_BEFORE_UPDATE_KEY = 'onBeforeUpdate',
- ON_UPDATED_KEY = 'onUpdated',
- ON_BEFORE_UNMOUNT_KEY = 'onBeforeUnmount',
- ON_UNMOUNTED_KEY = 'onUnmounted',
- PROPS_KEY = 'props',
- STATE_KEY = 'state',
- SLOTS_KEY = 'slots',
- ROOT_KEY = 'root',
- IS_PURE_SYMBOL = Symbol.for('pure'),
- PARENT_KEY_SYMBOL = Symbol('parent'),
- ATTRIBUTES_KEY_SYMBOL = Symbol('attributes'),
- TEMPLATE_KEY_SYMBOL = Symbol('template');
-
-var globals = /*#__PURE__*/Object.freeze({
- __proto__: null,
- COMPONENTS_IMPLEMENTATION_MAP: COMPONENTS_IMPLEMENTATION_MAP,
- DOM_COMPONENT_INSTANCE_PROPERTY: DOM_COMPONENT_INSTANCE_PROPERTY,
- PLUGINS_SET: PLUGINS_SET,
- IS_DIRECTIVE: IS_DIRECTIVE,
- VALUE_ATTRIBUTE: VALUE_ATTRIBUTE,
- MOUNT_METHOD_KEY: MOUNT_METHOD_KEY,
- UPDATE_METHOD_KEY: UPDATE_METHOD_KEY,
- UNMOUNT_METHOD_KEY: UNMOUNT_METHOD_KEY,
- SHOULD_UPDATE_KEY: SHOULD_UPDATE_KEY,
- ON_BEFORE_MOUNT_KEY: ON_BEFORE_MOUNT_KEY,
- ON_MOUNTED_KEY: ON_MOUNTED_KEY,
- ON_BEFORE_UPDATE_KEY: ON_BEFORE_UPDATE_KEY,
- ON_UPDATED_KEY: ON_UPDATED_KEY,
- ON_BEFORE_UNMOUNT_KEY: ON_BEFORE_UNMOUNT_KEY,
- ON_UNMOUNTED_KEY: ON_UNMOUNTED_KEY,
- PROPS_KEY: PROPS_KEY,
- STATE_KEY: STATE_KEY,
- SLOTS_KEY: SLOTS_KEY,
- ROOT_KEY: ROOT_KEY,
- IS_PURE_SYMBOL: IS_PURE_SYMBOL,
- PARENT_KEY_SYMBOL: PARENT_KEY_SYMBOL,
- ATTRIBUTES_KEY_SYMBOL: ATTRIBUTES_KEY_SYMBOL,
- TEMPLATE_KEY_SYMBOL: TEMPLATE_KEY_SYMBOL
-});
-
-const EACH = 0;
-const IF = 1;
-const SIMPLE = 2;
-const TAG = 3;
-const SLOT = 4;
-var bindingTypes = {
- EACH,
- IF,
- SIMPLE,
- TAG,
- SLOT
-};
-
-const ATTRIBUTE = 0;
-const EVENT = 1;
-const TEXT = 2;
-const VALUE = 3;
-var expressionTypes = {
- ATTRIBUTE,
- EVENT,
- TEXT,
- VALUE
-};
-
-/**
- * Create the template meta object in case of fragments
- * @param {TemplateChunk} componentTemplate - template chunk object
- * @returns {Object} the meta property that will be passed to the mount function of the TemplateChunk
- */
-function createTemplateMeta(componentTemplate) {
- const fragment = componentTemplate.dom.cloneNode(true);
- return {
- avoidDOMInjection: true,
- fragment,
- children: Array.from(fragment.childNodes)
- };
-}
-
-/**
- * Quick type checking
- * @param {*} element - anything
- * @param {string} type - type definition
- * @returns {boolean} true if the type corresponds
- */
-function checkType(element, type) {
- return typeof element === type;
-}
-/**
- * Check if an element is part of an svg
- * @param {HTMLElement} el - element to check
- * @returns {boolean} true if we are in an svg context
- */
-
-function isSvg(el) {
- const owner = el.ownerSVGElement;
- return !!owner || owner === null;
-}
-/**
- * Check if an element is a template tag
- * @param {HTMLElement} el - element to check
- * @returns {boolean} true if it's a
- */
-
-function isTemplate(el) {
- return !isNil(el.content);
-}
-/**
- * Check that will be passed if its argument is a function
- * @param {*} value - value to check
- * @returns {boolean} - true if the value is a function
- */
-
-function isFunction(value) {
- return checkType(value, 'function');
-}
-/**
- * Check if a value is a Boolean
- * @param {*} value - anything
- * @returns {boolean} true only for the value is a boolean
- */
-
-function isBoolean(value) {
- return checkType(value, 'boolean');
-}
-/**
- * Check if a value is an Object
- * @param {*} value - anything
- * @returns {boolean} true only for the value is an object
- */
-
-function isObject(value) {
- return !isNil(value) && checkType(value, 'object');
-}
-/**
- * Check if a value is null or undefined
- * @param {*} value - anything
- * @returns {boolean} true only for the 'undefined' and 'null' types
- */
-
-function isNil(value) {
- return value === null || value === undefined;
-}
-
-/**
- * ISC License
- *
- * Copyright (c) 2020, Andrea Giammarchi, @WebReflection
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-// fork of https://github.com/WebReflection/udomdiff version 1.1.0
-// due to https://github.com/WebReflection/udomdiff/pull/2
-
-/* eslint-disable */
-
-/**
- * @param {Node} parentNode The container where children live
- * @param {Node[]} a The list of current/live children
- * @param {Node[]} b The list of future children
- * @param {(entry: Node, action: number) => Node} get
- * The callback invoked per each entry related DOM operation.
- * @param {Node} [before] The optional node used as anchor to insert before.
- * @returns {Node[]} The same list of future children.
- */
-
-var udomdiff = ((parentNode, a, b, get, before) => {
- const bLength = b.length;
- let aEnd = a.length;
- let bEnd = bLength;
- let aStart = 0;
- let bStart = 0;
- let map = null;
-
- while (aStart < aEnd || bStart < bEnd) {
- // append head, tail, or nodes in between: fast path
- if (aEnd === aStart) {
- // we could be in a situation where the rest of nodes that
- // need to be added are not at the end, and in such case
- // the node to `insertBefore`, if the index is more than 0
- // must be retrieved, otherwise it's gonna be the first item.
- const node = bEnd < bLength ? bStart ? get(b[bStart - 1], -0).nextSibling : get(b[bEnd - bStart], 0) : before;
-
- while (bStart < bEnd) insertBefore(get(b[bStart++], 1), node);
- } // remove head or tail: fast path
- else if (bEnd === bStart) {
- while (aStart < aEnd) {
- // remove the node only if it's unknown or not live
- if (!map || !map.has(a[aStart])) removeChild(get(a[aStart], -1));
- aStart++;
- }
- } // same node: fast path
- else if (a[aStart] === b[bStart]) {
- aStart++;
- bStart++;
- } // same tail: fast path
- else if (a[aEnd - 1] === b[bEnd - 1]) {
- aEnd--;
- bEnd--;
- } // The once here single last swap "fast path" has been removed in v1.1.0
- // https://github.com/WebReflection/udomdiff/blob/single-final-swap/esm/index.js#L69-L85
- // reverse swap: also fast path
- else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {
- // this is a "shrink" operation that could happen in these cases:
- // [1, 2, 3, 4, 5]
- // [1, 4, 3, 2, 5]
- // or asymmetric too
- // [1, 2, 3, 4, 5]
- // [1, 2, 3, 5, 6, 4]
- const node = get(a[--aEnd], -1).nextSibling;
- insertBefore(get(b[bStart++], 1), get(a[aStart++], -1).nextSibling);
- insertBefore(get(b[--bEnd], 1), node); // mark the future index as identical (yeah, it's dirty, but cheap 👍)
- // The main reason to do this, is that when a[aEnd] will be reached,
- // the loop will likely be on the fast path, as identical to b[bEnd].
- // In the best case scenario, the next loop will skip the tail,
- // but in the worst one, this node will be considered as already
- // processed, bailing out pretty quickly from the map index check
-
- a[aEnd] = b[bEnd];
- } // map based fallback, "slow" path
- else {
- // the map requires an O(bEnd - bStart) operation once
- // to store all future nodes indexes for later purposes.
- // In the worst case scenario, this is a full O(N) cost,
- // and such scenario happens at least when all nodes are different,
- // but also if both first and last items of the lists are different
- if (!map) {
- map = new Map();
- let i = bStart;
-
- while (i < bEnd) map.set(b[i], i++);
- } // if it's a future node, hence it needs some handling
-
-
- if (map.has(a[aStart])) {
- // grab the index of such node, 'cause it might have been processed
- const index = map.get(a[aStart]); // if it's not already processed, look on demand for the next LCS
-
- if (bStart < index && index < bEnd) {
- let i = aStart; // counts the amount of nodes that are the same in the future
-
- let sequence = 1;
-
- while (++i < aEnd && i < bEnd && map.get(a[i]) === index + sequence) sequence++; // effort decision here: if the sequence is longer than replaces
- // needed to reach such sequence, which would brings again this loop
- // to the fast path, prepend the difference before a sequence,
- // and move only the future list index forward, so that aStart
- // and bStart will be aligned again, hence on the fast path.
- // An example considering aStart and bStart are both 0:
- // a: [1, 2, 3, 4]
- // b: [7, 1, 2, 3, 6]
- // this would place 7 before 1 and, from that time on, 1, 2, and 3
- // will be processed at zero cost
-
-
- if (sequence > index - bStart) {
- const node = get(a[aStart], 0);
-
- while (bStart < index) insertBefore(get(b[bStart++], 1), node);
- } // if the effort wasn't good enough, fallback to a replace,
- // moving both source and target indexes forward, hoping that some
- // similar node will be found later on, to go back to the fast path
- else {
- replaceChild(get(b[bStart++], 1), get(a[aStart++], -1));
- }
- } // otherwise move the source forward, 'cause there's nothing to do
- else aStart++;
- } // this node has no meaning in the future list, so it's more than safe
- // to remove it, and check the next live node out instead, meaning
- // that only the live list index should be forwarded
- else removeChild(get(a[aStart++], -1));
- }
- }
-
- return b;
-});
-
-const UNMOUNT_SCOPE = Symbol('unmount');
-const EachBinding = {
- // dynamic binding properties
- // childrenMap: null,
- // node: null,
- // root: null,
- // condition: null,
- // evaluate: null,
- // template: null,
- // isTemplateTag: false,
- nodes: [],
-
- // getKey: null,
- // indexName: null,
- // itemName: null,
- // afterPlaceholder: null,
- // placeholder: null,
- // API methods
- mount(scope, parentScope) {
- return this.update(scope, parentScope);
- },
-
- update(scope, parentScope) {
- const {
- placeholder,
- nodes,
- childrenMap
- } = this;
- const collection = scope === UNMOUNT_SCOPE ? null : this.evaluate(scope);
- const items = collection ? Array.from(collection) : [];
- const parent = placeholder.parentNode; // prepare the diffing
-
- const {
- newChildrenMap,
- batches,
- futureNodes
- } = createPatch(items, scope, parentScope, this); // patch the DOM only if there are new nodes
-
- udomdiff(parent, nodes, futureNodes, patch(Array.from(childrenMap.values()), parentScope), placeholder); // trigger the mounts and the updates
-
- batches.forEach(fn => fn()); // update the children map
-
- this.childrenMap = newChildrenMap;
- this.nodes = futureNodes;
- return this;
- },
-
- unmount(scope, parentScope) {
- this.update(UNMOUNT_SCOPE, parentScope);
- return this;
- }
-
-};
-/**
- * Patch the DOM while diffing
- * @param {TemplateChunk[]} redundant - redundant tepmplate chunks
- * @param {*} parentScope - scope of the parent template
- * @returns {Function} patch function used by domdiff
- */
-
-function patch(redundant, parentScope) {
- return (item, info) => {
- if (info < 0) {
- const element = redundant.pop();
-
- if (element) {
- const {
- template,
- context
- } = element; // notice that we pass null as last argument because
- // the root node and its children will be removed by domdiff
-
- template.unmount(context, parentScope, null);
- }
- }
-
- return item;
- };
-}
-/**
- * Check whether a template must be filtered from a loop
- * @param {Function} condition - filter function
- * @param {Object} context - argument passed to the filter function
- * @returns {boolean} true if this item should be skipped
- */
-
-
-function mustFilterItem(condition, context) {
- return condition ? Boolean(condition(context)) === false : false;
-}
-/**
- * Extend the scope of the looped template
- * @param {Object} scope - current template scope
- * @param {string} options.itemName - key to identify the looped item in the new context
- * @param {string} options.indexName - key to identify the index of the looped item
- * @param {number} options.index - current index
- * @param {*} options.item - collection item looped
- * @returns {Object} enhanced scope object
- */
-
-
-function extendScope(scope, _ref) {
- let {
- itemName,
- indexName,
- index,
- item
- } = _ref;
- scope[itemName] = item;
- if (indexName) scope[indexName] = index;
- return scope;
-}
-/**
- * Loop the current template items
- * @param {Array} items - expression collection value
- * @param {*} scope - template scope
- * @param {*} parentScope - scope of the parent template
- * @param {EeachBinding} binding - each binding object instance
- * @returns {Object} data
- * @returns {Map} data.newChildrenMap - a Map containing the new children template structure
- * @returns {Array} data.batches - array containing the template lifecycle functions to trigger
- * @returns {Array} data.futureNodes - array containing the nodes we need to diff
- */
-
-
-function createPatch(items, scope, parentScope, binding) {
- const {
- condition,
- template,
- childrenMap,
- itemName,
- getKey,
- indexName,
- root,
- isTemplateTag
- } = binding;
- const newChildrenMap = new Map();
- const batches = [];
- const futureNodes = [];
- items.forEach((item, index) => {
- const context = extendScope(Object.create(scope), {
- itemName,
- indexName,
- index,
- item
- });
- const key = getKey ? getKey(context) : index;
- const oldItem = childrenMap.get(key);
-
- if (mustFilterItem(condition, context)) {
- return;
- }
-
- const componentTemplate = oldItem ? oldItem.template : template.clone();
- const el = oldItem ? componentTemplate.el : root.cloneNode();
- const mustMount = !oldItem;
- const meta = isTemplateTag && mustMount ? createTemplateMeta(componentTemplate) : {};
-
- if (mustMount) {
- batches.push(() => componentTemplate.mount(el, context, parentScope, meta));
- } else {
- batches.push(() => componentTemplate.update(context, parentScope));
- } // create the collection of nodes to update or to add
- // in case of template tags we need to add all its children nodes
-
-
- if (isTemplateTag) {
- const children = meta.children || componentTemplate.children;
- futureNodes.push(...children);
- } else {
- futureNodes.push(el);
- } // delete the old item from the children map
-
-
- childrenMap.delete(key); // update the children map
-
- newChildrenMap.set(key, {
- template: componentTemplate,
- context,
- index
- });
- });
- return {
- newChildrenMap,
- batches,
- futureNodes
- };
-}
-
-function create(node, _ref2) {
- let {
- evaluate,
- condition,
- itemName,
- indexName,
- getKey,
- template
- } = _ref2;
- const placeholder = document.createTextNode('');
- const root = node.cloneNode();
- insertBefore(placeholder, node);
- removeChild(node);
- return Object.assign({}, EachBinding, {
- childrenMap: new Map(),
- node,
- root,
- condition,
- evaluate,
- isTemplateTag: isTemplate(root),
- template: template.createDOM(node),
- getKey,
- indexName,
- itemName,
- placeholder
- });
-}
-
-/**
- * Binding responsible for the `if` directive
- */
-
-const IfBinding = {
- // dynamic binding properties
- // node: null,
- // evaluate: null,
- // isTemplateTag: false,
- // placeholder: null,
- // template: null,
- // API methods
- mount(scope, parentScope) {
- return this.update(scope, parentScope);
- },
-
- update(scope, parentScope) {
- const value = !!this.evaluate(scope);
- const mustMount = !this.value && value;
- const mustUnmount = this.value && !value;
-
- const mount = () => {
- const pristine = this.node.cloneNode();
- insertBefore(pristine, this.placeholder);
- this.template = this.template.clone();
- this.template.mount(pristine, scope, parentScope);
- };
-
- switch (true) {
- case mustMount:
- mount();
- break;
-
- case mustUnmount:
- this.unmount(scope);
- break;
-
- default:
- if (value) this.template.update(scope, parentScope);
- }
-
- this.value = value;
- return this;
- },
-
- unmount(scope, parentScope) {
- this.template.unmount(scope, parentScope, true);
- return this;
- }
-
-};
-function create$1(node, _ref) {
- let {
- evaluate,
- template
- } = _ref;
- const placeholder = document.createTextNode('');
- insertBefore(placeholder, node);
- removeChild(node);
- return Object.assign({}, IfBinding, {
- node,
- evaluate,
- placeholder,
- template: template.createDOM(node)
- });
-}
-
-/**
- * Throw an error with a descriptive message
- * @param { string } message - error message
- * @returns { undefined } hoppla.. at this point the program should stop working
- */
-
-function panic(message) {
- throw new Error(message);
-}
-/**
- * Returns the memoized (cached) function.
- * // borrowed from https://www.30secondsofcode.org/js/s/memoize
- * @param {Function} fn - function to memoize
- * @returns {Function} memoize function
- */
-
-function memoize(fn) {
- const cache = new Map();
-
- const cached = val => {
- return cache.has(val) ? cache.get(val) : cache.set(val, fn.call(this, val)) && cache.get(val);
- };
-
- cached.cache = cache;
- return cached;
-}
-/**
- * Evaluate a list of attribute expressions
- * @param {Array} attributes - attribute expressions generated by the riot compiler
- * @returns {Object} key value pairs with the result of the computation
- */
-
-function evaluateAttributeExpressions(attributes) {
- return attributes.reduce((acc, attribute) => {
- const {
- value,
- type
- } = attribute;
-
- switch (true) {
- // spread attribute
- case !attribute.name && type === ATTRIBUTE:
- return Object.assign({}, acc, value);
- // value attribute
-
- case type === VALUE:
- acc.value = attribute.value;
- break;
- // normal attributes
-
- default:
- acc[dashToCamelCase(attribute.name)] = attribute.value;
- }
-
- return acc;
- }, {});
-}
-
-const REMOVE_ATTRIBUTE = 'removeAttribute';
-const SET_ATTIBUTE = 'setAttribute';
-const ElementProto = typeof Element === 'undefined' ? {} : Element.prototype;
-const isNativeHtmlProperty = memoize(name => ElementProto.hasOwnProperty(name)); // eslint-disable-line
-
-/**
- * Add all the attributes provided
- * @param {HTMLElement} node - target node
- * @param {Object} attributes - object containing the attributes names and values
- * @returns {undefined} sorry it's a void function :(
- */
-
-function setAllAttributes(node, attributes) {
- Object.entries(attributes).forEach((_ref) => {
- let [name, value] = _ref;
- return attributeExpression(node, {
- name
- }, value);
- });
-}
-/**
- * Remove all the attributes provided
- * @param {HTMLElement} node - target node
- * @param {Object} newAttributes - object containing all the new attribute names
- * @param {Object} oldAttributes - object containing all the old attribute names
- * @returns {undefined} sorry it's a void function :(
- */
-
-
-function removeAllAttributes(node, newAttributes, oldAttributes) {
- const newKeys = newAttributes ? Object.keys(newAttributes) : [];
- Object.keys(oldAttributes).filter(name => !newKeys.includes(name)).forEach(attribute => node.removeAttribute(attribute));
-}
-/**
- * This methods handles the DOM attributes updates
- * @param {HTMLElement} node - target node
- * @param {Object} expression - expression object
- * @param {string} expression.name - attribute name
- * @param {*} value - new expression value
- * @param {*} oldValue - the old expression cached value
- * @returns {undefined}
- */
-
-
-function attributeExpression(node, _ref2, value, oldValue) {
- let {
- name
- } = _ref2;
-
- // is it a spread operator? {...attributes}
- if (!name) {
- if (oldValue) {
- // remove all the old attributes
- removeAllAttributes(node, value, oldValue);
- } // is the value still truthy?
-
-
- if (value) {
- setAllAttributes(node, value);
- }
-
- return;
- } // handle boolean attributes
-
-
- if (!isNativeHtmlProperty(name) && (isBoolean(value) || isObject(value) || isFunction(value))) {
- node[name] = value;
- }
-
- node[getMethod(value)](name, normalizeValue(name, value));
-}
-/**
- * Get the attribute modifier method
- * @param {*} value - if truthy we return `setAttribute` othewise `removeAttribute`
- * @returns {string} the node attribute modifier method name
- */
-
-function getMethod(value) {
- return isNil(value) || value === false || value === '' || isObject(value) || isFunction(value) ? REMOVE_ATTRIBUTE : SET_ATTIBUTE;
-}
-/**
- * Get the value as string
- * @param {string} name - attribute name
- * @param {*} value - user input value
- * @returns {string} input value as string
- */
-
-
-function normalizeValue(name, value) {
- // be sure that expressions like selected={ true } will be always rendered as selected='selected'
- if (value === true) return name;
- return value;
-}
-
-const RE_EVENTS_PREFIX = /^on/;
-
-const getCallbackAndOptions = value => Array.isArray(value) ? value : [value, false]; // see also https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38
-
-
-const EventListener = {
- handleEvent(event) {
- this[event.type](event);
- }
-
-};
-const ListenersWeakMap = new WeakMap();
-
-const createListener = node => {
- const listener = Object.create(EventListener);
- ListenersWeakMap.set(node, listener);
- return listener;
-};
-/**
- * Set a new event listener
- * @param {HTMLElement} node - target node
- * @param {Object} expression - expression object
- * @param {string} expression.name - event name
- * @param {*} value - new expression value
- * @returns {value} the callback just received
- */
-
-
-function eventExpression(node, _ref, value) {
- let {
- name
- } = _ref;
- const normalizedEventName = name.replace(RE_EVENTS_PREFIX, '');
- const eventListener = ListenersWeakMap.get(node) || createListener(node);
- const [callback, options] = getCallbackAndOptions(value);
- const handler = eventListener[normalizedEventName];
- const mustRemoveEvent = handler && !callback;
- const mustAddEvent = callback && !handler;
-
- if (mustRemoveEvent) {
- node.removeEventListener(normalizedEventName, eventListener);
- }
-
- if (mustAddEvent) {
- node.addEventListener(normalizedEventName, eventListener, options);
- }
-
- eventListener[normalizedEventName] = callback;
-}
-
-/**
- * Normalize the user value in order to render a empty string in case of falsy values
- * @param {*} value - user input value
- * @returns {string} hopefully a string
- */
-
-function normalizeStringValue(value) {
- return isNil(value) ? '' : value;
-}
-
-/**
- * Get the the target text node to update or create one from of a comment node
- * @param {HTMLElement} node - any html element containing childNodes
- * @param {number} childNodeIndex - index of the text node in the childNodes list
- * @returns {HTMLTextNode} the text node to update
- */
-
-const getTextNode = (node, childNodeIndex) => {
- const target = node.childNodes[childNodeIndex];
-
- if (target.nodeType === Node.COMMENT_NODE) {
- const textNode = document.createTextNode('');
- node.replaceChild(textNode, target);
- return textNode;
- }
-
- return target;
-};
-/**
- * This methods handles a simple text expression update
- * @param {HTMLElement} node - target node
- * @param {Object} data - expression object
- * @param {*} value - new expression value
- * @returns {undefined}
- */
-
-function textExpression(node, data, value) {
- node.data = normalizeStringValue(value);
-}
-
-/**
- * This methods handles the input fileds value updates
- * @param {HTMLElement} node - target node
- * @param {Object} expression - expression object
- * @param {*} value - new expression value
- * @returns {undefined}
- */
-
-function valueExpression(node, expression, value) {
- node.value = normalizeStringValue(value);
-}
-
-var expressions = {
- [ATTRIBUTE]: attributeExpression,
- [EVENT]: eventExpression,
- [TEXT]: textExpression,
- [VALUE]: valueExpression
-};
-
-const Expression = {
- // Static props
- // node: null,
- // value: null,
- // API methods
-
- /**
- * Mount the expression evaluating its initial value
- * @param {*} scope - argument passed to the expression to evaluate its current values
- * @returns {Expression} self
- */
- mount(scope) {
- // hopefully a pure function
- this.value = this.evaluate(scope); // IO() DOM updates
-
- apply(this, this.value);
- return this;
- },
-
- /**
- * Update the expression if its value changed
- * @param {*} scope - argument passed to the expression to evaluate its current values
- * @returns {Expression} self
- */
- update(scope) {
- // pure function
- const value = this.evaluate(scope);
-
- if (this.value !== value) {
- // IO() DOM updates
- apply(this, value);
- this.value = value;
- }
-
- return this;
- },
-
- /**
- * Expression teardown method
- * @returns {Expression} self
- */
- unmount() {
- // unmount only the event handling expressions
- if (this.type === EVENT) apply(this, null);
- return this;
- }
-
-};
-/**
- * IO() function to handle the DOM updates
- * @param {Expression} expression - expression object
- * @param {*} value - current expression value
- * @returns {undefined}
- */
-
-function apply(expression, value) {
- return expressions[expression.type](expression.node, expression, value, expression.value);
-}
-
-function create$2(node, data) {
- return Object.assign({}, Expression, data, {
- node: data.type === TEXT ? getTextNode(node, data.childNodeIndex) : node
- });
-}
-
-/**
- * Create a flat object having as keys a list of methods that if dispatched will propagate
- * on the whole collection
- * @param {Array} collection - collection to iterate
- * @param {Array} methods - methods to execute on each item of the collection
- * @param {*} context - context returned by the new methods created
- * @returns {Object} a new object to simplify the the nested methods dispatching
- */
-function flattenCollectionMethods(collection, methods, context) {
- return methods.reduce((acc, method) => {
- return Object.assign({}, acc, {
- [method]: scope => {
- return collection.map(item => item[method](scope)) && context;
- }
- });
- }, {});
-}
-
-function create$3(node, _ref) {
- let {
- expressions
- } = _ref;
- return Object.assign({}, flattenCollectionMethods(expressions.map(expression => create$2(node, expression)), ['mount', 'update', 'unmount']));
-}
-
-function extendParentScope(attributes, scope, parentScope) {
- if (!attributes || !attributes.length) return parentScope;
- const expressions = attributes.map(attr => Object.assign({}, attr, {
- value: attr.evaluate(scope)
- }));
- return Object.assign(Object.create(parentScope || null), evaluateAttributeExpressions(expressions));
-} // this function is only meant to fix an edge case
-// https://github.com/riot/riot/issues/2842
-
-
-const getRealParent = (scope, parentScope) => scope[PARENT_KEY_SYMBOL] || parentScope;
-
-const SlotBinding = {
- // dynamic binding properties
- // node: null,
- // name: null,
- attributes: [],
-
- // template: null,
- getTemplateScope(scope, parentScope) {
- return extendParentScope(this.attributes, scope, parentScope);
- },
-
- // API methods
- mount(scope, parentScope) {
- const templateData = scope.slots ? scope.slots.find((_ref) => {
- let {
- id
- } = _ref;
- return id === this.name;
- }) : false;
- const {
- parentNode
- } = this.node;
- const realParent = getRealParent(scope, parentScope);
- this.template = templateData && create$6(templateData.html, templateData.bindings).createDOM(parentNode);
-
- if (this.template) {
- this.template.mount(this.node, this.getTemplateScope(scope, realParent), realParent);
- this.template.children = Array.from(this.node.childNodes);
- moveSlotInnerContent(this.node);
- }
-
- removeChild(this.node);
- return this;
- },
-
- update(scope, parentScope) {
- if (this.template) {
- const realParent = getRealParent(scope, parentScope);
- this.template.update(this.getTemplateScope(scope, realParent), realParent);
- }
-
- return this;
- },
-
- unmount(scope, parentScope, mustRemoveRoot) {
- if (this.template) {
- this.template.unmount(this.getTemplateScope(scope, parentScope), null, mustRemoveRoot);
- }
-
- return this;
- }
-
-};
-/**
- * Move the inner content of the slots outside of them
- * @param {HTMLElement} slot - slot node
- * @returns {undefined} it's a void method ¯\_(ツ)_/¯
- */
-
-function moveSlotInnerContent(slot) {
- const child = slot && slot.firstChild;
- if (!child) return;
- insertBefore(child, slot);
- moveSlotInnerContent(slot);
-}
-/**
- * Create a single slot binding
- * @param {HTMLElement} node - slot node
- * @param {string} options.name - slot id
- * @returns {Object} Slot binding object
- */
-
-
-function createSlot(node, _ref2) {
- let {
- name,
- attributes
- } = _ref2;
- return Object.assign({}, SlotBinding, {
- attributes,
- node,
- name
- });
-}
-
-/**
- * Create a new tag object if it was registered before, otherwise fallback to the simple
- * template chunk
- * @param {Function} component - component factory function
- * @param {Array