@localnerve/editable-object 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/editable-object.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
:host{--eo-min-width:300px;--eo-bg-color:#fafafa;--eo-border-radius:4px;--eo-border-focused-color:#444;--eo-border-defocused-color:#aaa;--eo-item-selected-bg-color:#999;--eo-item-selected-color:#222;--eo-item-selected-border-radius:4px;--eo-item-hover-border-width:1px;--eo-item-hover-border-color:#ddd;--eo-item-hover-border-radius:4px;--eo-icon-color:#444;--eo-add-new-icon-color:#444;--eo-input-focus-outline-color:#26b;--eo-input-focus-outline-width:1px;--eo-input-focus-outline-style:auto;--eo-input-border-color:#bbb;--eo-input-bg-color:#444;--eo-input-color:#eee;--eo-input-font-family:sans-serif;--eo-input-placeholder-color:#aaa}:host(.disabled){pointer-events:none}.editable-object{background:var(--eo-bg-color);border
|
|
1
|
+
:host{--eo-min-width:300px;--eo-bg-color:#fafafa;--eo-border-radius:4px;--eo-border-focused-color:#444;--eo-border-defocused-color:#aaa;--eo-item-selected-bg-color:#999;--eo-item-selected-color:#222;--eo-item-selected-border-radius:4px;--eo-item-hover-border-width:1px;--eo-item-hover-border-color:#ddd;--eo-item-hover-border-radius:4px;--eo-icon-color:#444;--eo-add-new-icon-color:#444;--eo-input-focus-outline-color:#26b;--eo-input-focus-outline-width:1px;--eo-input-focus-outline-style:auto;--eo-input-border-color:#bbb;--eo-input-bg-color:#444;--eo-input-color:#eee;--eo-input-font-family:sans-serif;--eo-input-placeholder-color:#aaa}:host(.disabled){pointer-events:none}.editable-object{background:var(--eo-bg-color);border-radius:var(--eo-border-radius);min-width:var(--eo-min-width);display:flex;flex-flow:column nowrap;justify-content:center;align-items:center}@media (min-width:360px){.editable-object{padding:0 .5rem}}@media (min-width:464px){.editable-object{border:1px solid var(--eo-border-focused-color);padding:1rem}.editable-object.defocused{border:1px solid var(--eo-border-defocused-color)}}ul{padding:0;margin:0;width:100%}li{line-height:2;list-style:none;cursor:default;padding:.5rem}input{padding:6px 8px;border-radius:4px;line-height:1.5;border:1px solid var(--eo-input-border-color);color:var(--eo-input-color);background:var(--eo-input-bg-color);font-family:var(--eo-input-font-family)}input:focus-visible{outline:var(--eo-input-focus-outline-color) var(--eo-input-focus-outline-style) var(--eo-input-focus-outline-width)}input::placeholder{color:var(--eo-input-placeholder-color)}.editable-object.defocused input{opacity:.7}.editable-object:not(.defocused) li.selected{background:var(--eo-item-selected-bg-color);color:var(--eo-item-selected-color);border-radius:var(--eo-item-selected-border-radius)}div>div,li{display:flex;align-items:center;justify-content:space-around}.editable-object:not(.defocused,.touch) li:hover{border:var(--eo-item-hover-border-width) solid var(--eo-item-hover-border-color);border-radius:var(--eo-item-hover-border-radius)}.property-wrapper{display:flex;flex-flow:row wrap;flex-grow:1;align-items:baseline;min-width:10em}.property-wrapper label{flex:1 1 100%;min-width:8em;max-width:100%}.property-wrapper input{flex:1;min-width:10em}@media (min-width:41.69em){.property-wrapper label{flex-basis:auto;max-width:45%;min-width:15em;padding-right:.5rem}.property-wrapper input{flex:1 1;min-width:16em}}.toolbar{display:flex;gap:1.5rem;padding-left:1.5rem}.editable-object.defocused .toolbar,li:not(.selected) .toolbar{opacity:0;pointer-events:none}.toolbar button{position:relative;fill:var(--eo-icon-color)}.editable-object-add-property.icon{fill:var(--eo-add-new-icon-color)}.toolbar button:hover:before{content:"";position:absolute;width:24px;height:24px;background:rgba(0,0,0,.1);left:-4px;top:-4px;border-radius:50%}.icon{background-color:transparent;border:none;cursor:pointer;font-size:0;fill:var(--eo-icon-color);padding:0}.icon svg{width:1rem;height:1rem}.new-object-property{margin-top:2rem;width:100%}.add-new-object-property-input{min-width:18em;flex:1}.add-new-object-property-input.error,.property-wrapper input.error{outline:red auto 1px}.hide{display:none}
|
package/dist/editable-object.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! editable-object@0.3.
|
|
2
|
-
class e extends HTMLElement{#e=null;#t=!1;#o=[];#r=[];#i=[];static#s=["object","add-property-placeholder","disable-edit"];static#n={object:{},"add-property-placeholder":"Add new property in key:value format","disabled-edit":!1};static get observedAttributes(){return this.#s}constructor(){super(),this.attachShadow({mode:"open",delegatesFocus:!0})}#l(t){if(this.hasAttribute(t)){const e=this.getAttribute(t);return/^\s*(?:true|false)\s*$/i.test(e)?"false"!==e:e}return e.#n[t]}#d(e){if("string"==typeof e||"number"==typeof e||"boolean"==typeof e||null===e)return e;if(void 0===e||"function"==typeof e||"symbol"==typeof e)return null;if("bigint"==typeof e)return`${e}n`;"[object RegExp]"===Object.prototype.toString.call(e)&&(e={__pattern:e.source,flags:e.flags});let t=JSON.stringify(e);return"{"===t[0]&&(t=t.replaceAll('"',"'")),t}#a(e,t=null){const o=e.trim();let r=parseFloat(o);if(r)return r;if(/\d+n$/.test(o))return BigInt(o.slice(0,-1));if("false"===o.toLowerCase())return!1;if("true"===o.toLowerCase())return!0;if("null"===o.toLowerCase())return null;let i,s=!1;try{let e=o;"{"===e[0]&&(s=!0,e=e.replaceAll("'",'"'));const t=JSON.parse(e);i=Object.keys(t).includes("__pattern")?new RegExp(t.__pattern,t.flags):t}catch{if(s&&t)throw t.classList.add("error"),new Error("Bad object input");i=o}return i}#c(e,t){return`\n <div class="property-wrapper">\n <label for="eo-${e}-value">${e}</label>\n <input readonly="true" id="eo-${e}-value" type="text" value="${t}" />\n </div>\n <div class="toolbar">\n <button class="editable-object-up-property icon" title="Move up">\n <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">\n <path d="m5 9 1.41 1.41L11 5.83V22h2V5.83l4.59 4.59L19 9l-7-7-7 7z"></path>\n </svg>\n </button>\n <button class="editable-object-down-property icon" title="Move down">\n <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">\n <path d="m19 15-1.41-1.41L13 18.17V2h-2v16.17l-4.59-4.59L5 15l7 7 7-7z"></path>\n </svg>\n </button>\n <button class="editable-object-remove-property icon" title="Remove">\n <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">\n <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path>\n </svg>\n </button>\n </div>\n `}#p(){const e=this.shadowRoot.querySelectorAll(".editable-object-up-property"),t=this.shadowRoot.querySelectorAll(".editable-object-down-property"),o=e.length;for(let r=0;r<o;r++)e[r].style.visibility=0==r?"hidden":"visible",t[r].style.visibility=r==o-1?"hidden":"visible";this.#t&&this.shadowRoot.querySelectorAll(".editable-object-remove-property").forEach((e=>e.classList.add("hide")))}#h(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)}#u(e){for(;"LI"!==e.tagName;)e=e.parentNode;return e}#b(e){this.#y();const t=this.#u(e.target);t.classList.toggle("selected",!0),[...t.querySelectorAll("button")].forEach((e=>{e.tabIndex=0})),t.querySelector("input").focus()}#v(e){return new CustomEvent("change",{bubbles:!0,cancelable:!1,composed:!0,detail:e})}#w(e){"INPUT"!==e.target.nodeName||e.target.classList.contains("error")||"Enter"!==e.key&&" "!==e.key||e.target.click()}#f(e){if(this._editing)return;this._editing=!0;const t=this.#u(e.target).querySelector(".property-wrapper > input");t.readOnly=!1,t._value=t.value;const o=this.#g.bind(this),r=this.#g.bind(this);t.addEventListener("blur",o,!1),this.#i.push({host:t,type:"blur",listener:o}),t.addEventListener("keypress",r,!1),this.#i.push({host:t,type:"keypress",listener:r}),t.focus()}#g(e){if(this._editing&&(e instanceof KeyboardEvent&&"Enter"===e.key||!(e instanceof KeyboardEvent))){e.preventDefault();const t=this.#u(e.target),o=t.querySelector(".property-wrapper > label").innerText,r=t.querySelector(".property-wrapper > input"),i=r._value,s=r.value;let n;this._editing=!1,r.readOnly=!0;let l=!1;try{n=this.#a(s,r)}catch{l=!0}this.#i.forEach((e=>{e.host.removeEventListener(e.type,e.listener)})),this.#i.length=0,l||(this.#e[o]=n,this.dispatchEvent(this.#v({action:"edit",key:o,previous:this.#a(i),new:n})))}}#m(e){const t=e.previousElementSibling;return!!t&&(e.parentNode.insertBefore(e,t),this.#p(),e.querySelector(".editable-object-up-property").focus(),!0)}#x(e){const t=e.nextElementSibling;return!!t&&(e.parentNode.insertBefore(t,e),this.#p(),e.querySelector(".editable-object-down-property").focus(),!0)}#j(e){e.remove(),this.#p()}#k(e){e.stopPropagation();const t=this.#u(e.target),o=t.querySelector(".property-wrapper > label").innerText.trim(),r=t.querySelector(".property-wrapper > input").value.trim();this.#j(t),delete this.#e[o],this.dispatchEvent(this.#v({action:"remove",key:o,previous:this.#a(r),new:null}))}#E(e){e.stopPropagation();const t=this.#u(e.target);this.#m(t)}#L(e){e.stopPropagation();const t=this.#u(e.target);this.#x(t)}#S(){let e,t=0;return function(o){const r=(new Date).getTime(),i=r-t;i<500&&i>0?(o.preventDefault(),this.#f(o)):e=setTimeout((()=>{clearTimeout(e)}),500),t=r}.bind(this)}#q(e){const t=this.#b.bind(this);e.forEach((e=>{e.addEventListener("click",t,!1),this.#r.push({host:e,type:"click",listener:t})}))}#A(e,t){const o=this.#h(),r=this.#S(),i=this.#f.bind(this),s=this.#w.bind(this);e.forEach((e=>{e.addEventListener("keypress",s,!1),this.#r.push({host:e,type:"keypress",listener:s}),this.#t||(e.addEventListener("dblclick",i,!1),this.#r.push({host:e,type:"dblclick",listener:i}),o&&(e.addEventListener("touchend",r),this.#r.push({host:e,type:"touchend",listener:r})))}));const n=this.#E.bind(this),l=this.#L.bind(this),d=this.#k.bind(this);t.up.forEach((e=>{e.addEventListener("click",n,!1),this.#r.push({host:e,type:"click",listener:n})})),t.down.forEach((e=>{e.addEventListener("click",l,!1),this.#r.push({host:e,type:"click",listener:l})})),this.#t||t.remove.forEach((e=>{e.addEventListener("click",d,!1),this.#r.push({host:e,type:"click",listener:d})}))}#O(e){e.composedPath().includes(this)||this.shadowRoot.querySelector(".editable-object").classList.add("defocused")}#R(){this.shadowRoot.querySelector(".editable-object").classList.remove("defocused")}#P(e){return e in this.#e}#y(){this.shadowRoot.querySelector(".add-new-object-property-input").classList.toggle("error",!1),[...this.shadowRoot.querySelectorAll("li")].forEach((e=>{e.querySelector(".property-wrapper > input").classList.toggle("error",!1),e.classList.toggle("selected",!1),[...e.querySelectorAll("button")].forEach((e=>{e.tabIndex=-1}))}))}#_(e){if(e instanceof KeyboardEvent&&"Enter"===e.key||!(e instanceof KeyboardEvent)){const e=this.shadowRoot.querySelector(".add-new-object-property-input"),t=e.value.trim();if(""!==t){const o=/^\s*(?<property>[^\s:]+)\s*:\s*(?<value>[^$]+)$/,r=t.match(o)?.groups,[i,s]=r?Object.values(r):["",""],n=i.trim(),l=s.trim();if(!n||!l||this.#P(n))return e.classList.add("error"),void e.focus();let d,a=!1;try{d=this.#a(l,e)}catch{a=!0}if(!a){const t={[n]:l};this.mergeObject(t),this.dispatchEvent(this.#v({action:"add",key:n,previous:null,new:d})),this.shadowRoot.querySelector(".object-properties").lastChild.click(),e.value=""}}}}get object(){return this.#e}set object(e){if(!e)return;this.#e&&Object.keys(this.#e).length>0&&[this.#r,this.#i].forEach((e=>{e.forEach((e=>{e.host.removeEventListener(e.type,e.listener)}))}));const t=this.shadowRoot.querySelector("#loading"),o=this.shadowRoot.querySelector(".object-properties");o.innerHTML="";const r=[],i=[],s={up:[],down:[],remove:[]};for(const[t,n]of Object.entries(e)){const e=document.createElement("li");e.innerHTML=this.#c(t,this.#d(n)),o.appendChild(e),r.push(e),i.push(e.querySelector(".property-wrapper")),s.up.push(e.querySelector(".editable-object-up-property")),s.down.push(e.querySelector(".editable-object-down-property")),s.remove.push(e.querySelector(".editable-object-remove-property"))}this.#q(r),this.#A(i,s),this.#p(),t.classList.add("hide"),this.#e=e}get addPropertyPlaceholder(){return this.#l("add-property-placeholder")}set addPropertyPlaceholder(t){const o="add-property-placeholder",r=this.shadowRoot.querySelector(".add-new-object-property-input");t?(this.setAttribute(o,t),r.placeholder=t):(this.removeAttribute(o),r.placeholder=e.#n[o])}set disableEdit(e){this.#t=!!e}get disableEdit(){return this.#t}mergeObject(e){this.object={...this.#e,...e}}connectedCallback(){const{shadowRoot:e}=this;e.innerHTML='<style>:host{--eo-min-width:300px;--eo-bg-color:#fafafa;--eo-border-radius:4px;--eo-border-focused-color:#444;--eo-border-defocused-color:#aaa;--eo-item-selected-bg-color:#999;--eo-item-selected-color:#222;--eo-item-selected-border-radius:4px;--eo-item-hover-border-width:1px;--eo-item-hover-border-color:#ddd;--eo-item-hover-border-radius:4px;--eo-icon-color:#444;--eo-add-new-icon-color:#444;--eo-input-focus-outline-color:#26b;--eo-input-focus-outline-width:1px;--eo-input-focus-outline-style:auto;--eo-input-border-color:#bbb;--eo-input-bg-color:#444;--eo-input-color:#eee;--eo-input-font-family:sans-serif;--eo-input-placeholder-color:#aaa}:host(.disabled){pointer-events:none}.editable-object{background:var(--eo-bg-color);border:1px solid var(--eo-border-focused-color);border-radius:var(--eo-border-radius);padding:1rem;min-width:var(--eo-min-width);display:flex;flex-flow:column nowrap;justify-content:center;align-items:center}.editable-object.defocused{border:1px solid var(--eo-border-defocused-color)}ul{padding:0;margin:0;width:100%}li{line-height:2;list-style:none;cursor:default;padding:.5rem}input{padding:6px 8px;border-radius:4px;line-height:1.5;border:1px solid var(--eo-input-border-color);color:var(--eo-input-color);background:var(--eo-input-bg-color);font-family:var(--eo-input-font-family)}input:focus-visible{outline:var(--eo-input-focus-outline-color) var(--eo-input-focus-outline-style) var(--eo-input-focus-outline-width)}input::placeholder{color:var(--eo-input-placeholder-color)}.editable-object.defocused input{opacity:.7}.editable-object:not(.defocused) li.selected{background:var(--eo-item-selected-bg-color);color:var(--eo-item-selected-color);border-radius:var(--eo-item-selected-border-radius)}div>div,li{display:flex;align-items:center;justify-content:space-around}.editable-object:not(.defocused,.touch) li:hover{border:var(--eo-item-hover-border-width) solid var(--eo-item-hover-border-color);border-radius:var(--eo-item-hover-border-radius)}.property-wrapper{display:flex;flex-flow:row wrap;flex-grow:1;align-items:baseline;min-width:10em}.property-wrapper label{flex:1 1 100%;min-width:8em;max-width:100%}.property-wrapper input{flex:1;min-width:10em}@media (min-width:41.69em){.property-wrapper label{flex-basis:auto;max-width:45%;min-width:15em;padding-right:.5rem}.property-wrapper input{flex:1 1;min-width:16em}}.toolbar{display:flex;gap:1.8rem;padding-left:1.5rem}.editable-object.defocused .toolbar,li:not(.selected) .toolbar{opacity:0;pointer-events:none}.toolbar button{position:relative;fill:var(--eo-icon-color)}.editable-object-add-property.icon{fill:var(--eo-add-new-icon-color)}.toolbar button:hover:before{content:"";position:absolute;width:24px;height:24px;background:rgba(0,0,0,.1);left:-4px;top:-4px;border-radius:50%}.icon{background-color:transparent;border:none;cursor:pointer;font-size:0;fill:var(--eo-icon-color);padding:0}.icon svg{width:1rem;height:1rem}.new-object-property{margin-top:2rem;width:100%}.add-new-object-property-input{min-width:18em;flex:1}.add-new-object-property-input.error,.property-wrapper input.error{outline:red auto 1px}.hide{display:none}</style><div class="editable-object defocused"><slot id=loading name=loading></slot><ul class=object-properties></ul><div class=new-object-property><input class=add-new-object-property-input type=text placeholder="Add new property in key:value format"><div class=toolbar><button class="editable-object-add-property icon" title=Add><svg version=1.1 xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink width=24 height=24 viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"></path></svg></button></div></div></div>';const t=this.getAttribute("object");this.object=JSON.parse(t);const o=this.getAttribute("disable-edit");this.#t="true"===o?.toLowerCase();const r=e.querySelector(".editable-object"),i=e.querySelector("#loading"),s=e.querySelector(".new-object-property"),n=e.querySelector(".add-new-object-property-input"),l=e.querySelector(".editable-object-add-property"),d=this.#h(),a=this.#O.bind(this),c=this.#R.bind(this);if(this.object&&i.classList.add("hide"),d&&r.classList.add("touch"),document.addEventListener("click",a,!1),this.#o.push({host:document,type:"click",listener:a}),r.addEventListener("click",c,!0),this.#o.push({host:r,type:"click",listener:c}),this.#t)s.classList.add("hide");else{const e=this.getAttribute("add-property-placeholder");this.addPropertyPlaceholder=e;const t=this.#y.bind(this);s.addEventListener("click",t,!0),this.#o.push({host:s,type:"click",listener:t});const o=this.#_.bind(this);n.addEventListener("keypress",o,!1),this.#o.push({host:n,type:"keypress",listener:o}),l.addEventListener("click",o,!1),this.#o.push({host:l,type:"click",listener:o})}}disconnectedCallback(){[this.#o,this.#r,this.#i].forEach((e=>{e.forEach((e=>{e.host.removeEventListener(e.type,e.listener)}))}))}attributeChangedCallback(e,t,o){o!==t&&(this[e]=this.getAttribute(e))}}customElements.define("editable-object",e);
|
|
1
|
+
/*! editable-object@0.3.2, Copyright (c) 2025 Alex Grant <alex@localnerve.com> (https://www.localnerve.com), LocalNerve LLC, BSD-3-Clause */
|
|
2
|
+
class e extends HTMLElement{#e=null;#t=!1;#o=[];#r=[];#i=[];static#s=["object","add-property-placeholder","disable-edit"];static#n={object:{},"add-property-placeholder":"Add new property in key:value format","disabled-edit":!1};static get observedAttributes(){return this.#s}constructor(){super(),this.attachShadow({mode:"open",delegatesFocus:!0})}#l(t){if(this.hasAttribute(t)){const e=this.getAttribute(t);return/^\s*(?:true|false)\s*$/i.test(e)?"false"!==e:e}return e.#n[t]}#d(e){if("string"==typeof e||"number"==typeof e||"boolean"==typeof e||null===e)return e;if(void 0===e||"function"==typeof e||"symbol"==typeof e)return null;if("bigint"==typeof e)return`${e}n`;"[object RegExp]"===Object.prototype.toString.call(e)&&(e={__pattern:e.source,flags:e.flags});let t=JSON.stringify(e);return"{"===t[0]&&(t=t.replaceAll('"',"'")),t}#a(e,t=null){const o=e.trim();let r=parseFloat(o);if(r)return r;if(/\d+n$/.test(o))return BigInt(o.slice(0,-1));if("false"===o.toLowerCase())return!1;if("true"===o.toLowerCase())return!0;if("null"===o.toLowerCase())return null;let i,s=!1;try{let e=o;"{"===e[0]&&(s=!0,e=e.replaceAll("'",'"'));const t=JSON.parse(e);i=Object.keys(t).includes("__pattern")?new RegExp(t.__pattern,t.flags):t}catch{if(s&&t)throw t.classList.add("error"),new Error("Bad object input");i=o}return i}#c(e,t){return`\n <div class="property-wrapper">\n <label for="eo-${e}-value">${e}</label>\n <input readonly="true" id="eo-${e}-value" type="text" value="${t}" />\n </div>\n <div class="toolbar">\n <button class="editable-object-up-property icon" title="Move up">\n <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">\n <path d="m5 9 1.41 1.41L11 5.83V22h2V5.83l4.59 4.59L19 9l-7-7-7 7z"></path>\n </svg>\n </button>\n <button class="editable-object-down-property icon" title="Move down">\n <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">\n <path d="m19 15-1.41-1.41L13 18.17V2h-2v16.17l-4.59-4.59L5 15l7 7 7-7z"></path>\n </svg>\n </button>\n <button class="editable-object-remove-property icon" title="Remove">\n <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">\n <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path>\n </svg>\n </button>\n </div>\n `}#p(){const e=this.shadowRoot.querySelectorAll(".editable-object-up-property"),t=this.shadowRoot.querySelectorAll(".editable-object-down-property"),o=e.length;for(let r=0;r<o;r++)e[r].style.visibility=0==r?"hidden":"visible",t[r].style.visibility=r==o-1?"hidden":"visible";this.#t&&this.shadowRoot.querySelectorAll(".editable-object-remove-property").forEach(e=>e.classList.add("hide"))}#h(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)}#u(e){for(;"LI"!==e.tagName;)e=e.parentNode;return e}#b(e){this.#y();const t=this.#u(e.target);t.classList.toggle("selected",!0),[...t.querySelectorAll("button")].forEach(e=>{e.tabIndex=0}),t.querySelector("input").focus()}#v(e){return new CustomEvent("change",{bubbles:!0,cancelable:!1,composed:!0,detail:e})}#w(e){"INPUT"!==e.target.nodeName||e.target.classList.contains("error")||"Enter"!==e.key&&" "!==e.key||e.target.click()}#f(e){if(this._editing)return;this._editing=!0;const t=this.#u(e.target).querySelector(".property-wrapper > input");t.readOnly=!1,t._value=t.value;const o=this.#g.bind(this),r=this.#g.bind(this);t.addEventListener("blur",o,!1),this.#i.push({host:t,type:"blur",listener:o}),t.addEventListener("keypress",r,!1),this.#i.push({host:t,type:"keypress",listener:r}),t.focus()}#g(e){if(this._editing&&(e instanceof KeyboardEvent&&"Enter"===e.key||!(e instanceof KeyboardEvent))){e.preventDefault();const t=this.#u(e.target),o=t.querySelector(".property-wrapper > label").innerText,r=t.querySelector(".property-wrapper > input"),i=r._value,s=r.value;let n;this._editing=!1,r.readOnly=!0;let l=!1;try{n=this.#a(s,r)}catch{l=!0}this.#i.forEach(e=>{e.host.removeEventListener(e.type,e.listener)}),this.#i.length=0,l||(this.#e[o]=n,this.dispatchEvent(this.#v({action:"edit",key:o,previous:this.#a(i),new:n})))}}#m(e){const t=e.previousElementSibling;return!!t&&(e.parentNode.insertBefore(e,t),this.#p(),e.querySelector(".editable-object-up-property").focus(),!0)}#x(e){const t=e.nextElementSibling;return!!t&&(e.parentNode.insertBefore(t,e),this.#p(),e.querySelector(".editable-object-down-property").focus(),!0)}#j(e){e.remove(),this.#p()}#k(e){e.stopPropagation();const t=this.#u(e.target),o=t.querySelector(".property-wrapper > label").innerText.trim(),r=t.querySelector(".property-wrapper > input").value.trim();this.#j(t),delete this.#e[o],this.dispatchEvent(this.#v({action:"remove",key:o,previous:this.#a(r),new:null}))}#E(e){e.stopPropagation();const t=this.#u(e.target);this.#m(t)}#L(e){e.stopPropagation();const t=this.#u(e.target);this.#x(t)}#S(){let e,t=0;return function(o){const r=(new Date).getTime(),i=r-t;i<500&&i>0?(o.preventDefault(),this.#f(o)):e=setTimeout(()=>{clearTimeout(e)},500),t=r}.bind(this)}#q(e){const t=this.#b.bind(this);e.forEach(e=>{e.addEventListener("click",t,!1),this.#r.push({host:e,type:"click",listener:t})})}#A(e,t){const o=this.#h(),r=this.#S(),i=this.#f.bind(this),s=this.#w.bind(this);e.forEach(e=>{e.addEventListener("keypress",s,!1),this.#r.push({host:e,type:"keypress",listener:s}),this.#t||(e.addEventListener("dblclick",i,!1),this.#r.push({host:e,type:"dblclick",listener:i}),o&&(e.addEventListener("touchend",r),this.#r.push({host:e,type:"touchend",listener:r})))});const n=this.#E.bind(this),l=this.#L.bind(this),d=this.#k.bind(this);t.up.forEach(e=>{e.addEventListener("click",n,!1),this.#r.push({host:e,type:"click",listener:n})}),t.down.forEach(e=>{e.addEventListener("click",l,!1),this.#r.push({host:e,type:"click",listener:l})}),this.#t||t.remove.forEach(e=>{e.addEventListener("click",d,!1),this.#r.push({host:e,type:"click",listener:d})})}#O(e){e.composedPath().includes(this)||this.shadowRoot.querySelector(".editable-object").classList.add("defocused")}#R(){this.shadowRoot.querySelector(".editable-object").classList.remove("defocused")}#P(e){return e in this.#e}#y(){this.shadowRoot.querySelector(".add-new-object-property-input").classList.toggle("error",!1),[...this.shadowRoot.querySelectorAll("li")].forEach(e=>{e.querySelector(".property-wrapper > input").classList.toggle("error",!1),e.classList.toggle("selected",!1),[...e.querySelectorAll("button")].forEach(e=>{e.tabIndex=-1})})}#_(e){if(e instanceof KeyboardEvent&&"Enter"===e.key||!(e instanceof KeyboardEvent)){const e=this.shadowRoot.querySelector(".add-new-object-property-input"),t=e.value.trim();if(""!==t){const o=/^\s*(?<property>[^\s:]+)\s*:\s*(?<value>[^$]+)$/,r=t.match(o)?.groups,[i,s]=r?Object.values(r):["",""],n=i.trim(),l=s.trim();if(!n||!l||this.#P(n))return e.classList.add("error"),void e.focus();let d,a=!1;try{d=this.#a(l,e)}catch{a=!0}if(!a){const t={[n]:l};this.mergeObject(t),this.dispatchEvent(this.#v({action:"add",key:n,previous:null,new:d})),this.shadowRoot.querySelector(".object-properties").lastChild.click(),e.value=""}}}}get object(){return this.#e}set object(e){if(!e)return;this.#e&&Object.keys(this.#e).length>0&&[this.#r,this.#i].forEach(e=>{e.forEach(e=>{e.host.removeEventListener(e.type,e.listener)})});const t=this.shadowRoot.querySelector("#loading"),o=this.shadowRoot.querySelector(".object-properties");o.innerHTML="";const r=[],i=[],s={up:[],down:[],remove:[]};for(const[t,n]of Object.entries(e)){const e=document.createElement("li");e.innerHTML=this.#c(t,this.#d(n)),o.appendChild(e),r.push(e),i.push(e.querySelector(".property-wrapper")),s.up.push(e.querySelector(".editable-object-up-property")),s.down.push(e.querySelector(".editable-object-down-property")),s.remove.push(e.querySelector(".editable-object-remove-property"))}this.#q(r),this.#A(i,s),this.#p(),t.classList.add("hide"),this.#e=e}get addPropertyPlaceholder(){return this.#l("add-property-placeholder")}set addPropertyPlaceholder(t){const o="add-property-placeholder",r=this.shadowRoot.querySelector(".add-new-object-property-input");t?(this.setAttribute(o,t),r.placeholder=t):(this.removeAttribute(o),r.placeholder=e.#n[o])}set disableEdit(e){this.#t=!!e}get disableEdit(){return this.#t}mergeObject(e){this.object={...this.#e,...e}}connectedCallback(){const{shadowRoot:e}=this;e.innerHTML='<style>:host{--eo-min-width:300px;--eo-bg-color:#fafafa;--eo-border-radius:4px;--eo-border-focused-color:#444;--eo-border-defocused-color:#aaa;--eo-item-selected-bg-color:#999;--eo-item-selected-color:#222;--eo-item-selected-border-radius:4px;--eo-item-hover-border-width:1px;--eo-item-hover-border-color:#ddd;--eo-item-hover-border-radius:4px;--eo-icon-color:#444;--eo-add-new-icon-color:#444;--eo-input-focus-outline-color:#26b;--eo-input-focus-outline-width:1px;--eo-input-focus-outline-style:auto;--eo-input-border-color:#bbb;--eo-input-bg-color:#444;--eo-input-color:#eee;--eo-input-font-family:sans-serif;--eo-input-placeholder-color:#aaa}:host(.disabled){pointer-events:none}.editable-object{background:var(--eo-bg-color);border-radius:var(--eo-border-radius);min-width:var(--eo-min-width);display:flex;flex-flow:column nowrap;justify-content:center;align-items:center}@media (min-width:360px){.editable-object{padding:0 .5rem}}@media (min-width:464px){.editable-object{border:1px solid var(--eo-border-focused-color);padding:1rem}.editable-object.defocused{border:1px solid var(--eo-border-defocused-color)}}ul{padding:0;margin:0;width:100%}li{line-height:2;list-style:none;cursor:default;padding:.5rem}input{padding:6px 8px;border-radius:4px;line-height:1.5;border:1px solid var(--eo-input-border-color);color:var(--eo-input-color);background:var(--eo-input-bg-color);font-family:var(--eo-input-font-family)}input:focus-visible{outline:var(--eo-input-focus-outline-color) var(--eo-input-focus-outline-style) var(--eo-input-focus-outline-width)}input::placeholder{color:var(--eo-input-placeholder-color)}.editable-object.defocused input{opacity:.7}.editable-object:not(.defocused) li.selected{background:var(--eo-item-selected-bg-color);color:var(--eo-item-selected-color);border-radius:var(--eo-item-selected-border-radius)}div>div,li{display:flex;align-items:center;justify-content:space-around}.editable-object:not(.defocused,.touch) li:hover{border:var(--eo-item-hover-border-width) solid var(--eo-item-hover-border-color);border-radius:var(--eo-item-hover-border-radius)}.property-wrapper{display:flex;flex-flow:row wrap;flex-grow:1;align-items:baseline;min-width:10em}.property-wrapper label{flex:1 1 100%;min-width:8em;max-width:100%}.property-wrapper input{flex:1;min-width:10em}@media (min-width:41.69em){.property-wrapper label{flex-basis:auto;max-width:45%;min-width:15em;padding-right:.5rem}.property-wrapper input{flex:1 1;min-width:16em}}.toolbar{display:flex;gap:1.5rem;padding-left:1.5rem}.editable-object.defocused .toolbar,li:not(.selected) .toolbar{opacity:0;pointer-events:none}.toolbar button{position:relative;fill:var(--eo-icon-color)}.editable-object-add-property.icon{fill:var(--eo-add-new-icon-color)}.toolbar button:hover:before{content:"";position:absolute;width:24px;height:24px;background:rgba(0,0,0,.1);left:-4px;top:-4px;border-radius:50%}.icon{background-color:transparent;border:none;cursor:pointer;font-size:0;fill:var(--eo-icon-color);padding:0}.icon svg{width:1rem;height:1rem}.new-object-property{margin-top:2rem;width:100%}.add-new-object-property-input{min-width:18em;flex:1}.add-new-object-property-input.error,.property-wrapper input.error{outline:red auto 1px}.hide{display:none}</style><div class="editable-object defocused"><slot id=loading name=loading></slot><ul class=object-properties></ul><div class=new-object-property><input class=add-new-object-property-input type=text placeholder="Add new property in key:value format"><div class=toolbar><button class="editable-object-add-property icon" title=Add><svg version=1.1 xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink width=24 height=24 viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"></path></svg></button></div></div></div>';const t=this.getAttribute("object");this.object=JSON.parse(t);const o=this.getAttribute("disable-edit");this.#t="true"===o?.toLowerCase();const r=e.querySelector(".editable-object"),i=e.querySelector("#loading"),s=e.querySelector(".new-object-property"),n=e.querySelector(".add-new-object-property-input"),l=e.querySelector(".editable-object-add-property"),d=this.#h(),a=this.#O.bind(this),c=this.#R.bind(this);if(this.object&&i.classList.add("hide"),d&&r.classList.add("touch"),document.addEventListener("click",a,!1),this.#o.push({host:document,type:"click",listener:a}),r.addEventListener("click",c,!0),this.#o.push({host:r,type:"click",listener:c}),this.#t)s.classList.add("hide");else{const e=this.getAttribute("add-property-placeholder");this.addPropertyPlaceholder=e;const t=this.#y.bind(this);s.addEventListener("click",t,!0),this.#o.push({host:s,type:"click",listener:t});const o=this.#_.bind(this);n.addEventListener("keypress",o,!1),this.#o.push({host:n,type:"keypress",listener:o}),l.addEventListener("click",o,!1),this.#o.push({host:l,type:"click",listener:o})}}disconnectedCallback(){[this.#o,this.#r,this.#i].forEach(e=>{e.forEach(e=>{e.host.removeEventListener(e.type,e.listener)})})}attributeChangedCallback(e,t,o){o!==t&&(this[e]=this.getAttribute(e))}}customElements.define("editable-object",e);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@localnerve/editable-object",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "A vanillajs editable-object web component for visual object display and editing",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"browser": "dist/editable-object.js",
|
|
@@ -14,12 +14,13 @@
|
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@eslint/js": "^9.29.0",
|
|
17
|
-
"@localnerve/web-component-build": "^1.
|
|
17
|
+
"@localnerve/web-component-build": "^1.12.1",
|
|
18
18
|
"babel-loader": "10.0.0",
|
|
19
19
|
"eslint": "^9.29.0",
|
|
20
20
|
"express": "5.1.0",
|
|
21
21
|
"globals": "^16.2.0",
|
|
22
|
-
"webpack-cli": "6.0.1"
|
|
22
|
+
"webpack-cli": "6.0.1",
|
|
23
|
+
"modern-normalize": "^3.0.1"
|
|
23
24
|
},
|
|
24
25
|
"files": [
|
|
25
26
|
"dist/**"
|