vuetify-editable-data-grid
Version:
A highly customizable and interactive editable data table component built with Vue 3 and Vuetify 3. This component supports inline editing, undo/redo functionality, column visibility filters, drag-to-fill (like Excel), and more.
2 lines (1 loc) • 12.2 kB
JavaScript
(function(V,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(V=typeof globalThis<"u"?globalThis:V||self,e(V.VueCopyToClipboard={},V.Vue))})(this,function(V,e){"use strict";function P(i,h={}){const{deep:b=!1,capacity:f=1/0,clone:C=p=>JSON.parse(JSON.stringify(p))}=h,k=e.ref([]),u=e.ref(-1),D=e.ref(!1),O=e.ref(!1),R=e.ref(!1),S=()=>{O.value=u.value>0,R.value=u.value<k.value.length-1},T=p=>{const x=C(p);u.value<k.value.length-1&&k.value.splice(u.value+1),k.value.push(x),u.value++,k.value.length>f&&(k.value.shift(),u.value--),S()},d=()=>{O.value&&(i.value=C(k.value[u.value]),u.value--,i.value=C(k.value[u.value]),D.value=!1,S())},m=()=>{R.value&&(D.value=!0,u.value++,i.value=C(k.value[u.value]),D.value=!1,S())};return e.watch(i,p=>{if(D.value)return;const x=JSON.stringify(p),B=JSON.stringify(k.value[u.value]);x!==B&&T(p)},{deep:b,immediate:!0}),{history:k,pointer:u,canUndo:O,canRedo:R,undo:d,redo:m}}function Y(i,h={}){const{minimumFractionDigits:b=0,maximumFractionDigits:f=2}=h,C=typeof i=="string"?parseFloat(i):i;return new Intl.NumberFormat(void 0,{minimumFractionDigits:b,maximumFractionDigits:f}).format(C)}const Q=(i,h)=>{const b=i.__vccOpts||i;for(const[f,C]of h)b[f]=C;return b},W=["id","data-row","data-col","onClick","onDblclick"],ee={key:0,class:"error-caret"},z=Q({__name:"DataGrid",props:e.mergeModels({headers:{type:Array,default:()=>[]}},{modelValue:{type:Array,default:()=>[],required:!0},modelModifiers:{}}),emits:["update:modelValue"],setup(i,{expose:h}){const b=e.useModel(i,"modelValue"),f=e.ref([]),C=e.useTemplateRef("formRef");e.watch(()=>i.headers,o=>{f.value.length===0&&o.length>0&&(f.value=o.map(n=>n.key))},{immediate:!0});const k=e.computed(()=>i.headers.length===f.value.length),u=e.computed(()=>i.headers.filter(o=>f.value.includes(o.key))),D=o=>{f.value.includes(o.key)?f.value=f.value.filter(n=>n!==o.key):f.value=[...f.value,o.key]},{canUndo:O,canRedo:R,undo:S,redo:T}=P(b,{deep:!0}),d=b,m=e.ref(null),p=e.ref(null),x=e.ref(!1),B=e.ref({row:null,key:null}),F=e.ref(""),M=e.computed(()=>F.value?d.value.filter(o=>Object.values(o).some(n=>String(n).toLowerCase().includes(F.value.toLowerCase()))):d.value);function $(o){var n;return(n=i.headers.find(l=>l.key===o))==null?void 0:n.type}function oe(o){switch($(o)){case"string":return"v-text-field";case"number":case"currency":return"v-number-input";case"select":return"v-autocomplete";case"checkbox":return"v-checkbox";default:return null}}function I(o,n){m.value={row:o,key:n}}function U(o,n){var l,a;return((l=m.value)==null?void 0:l.row)===o&&((a=m.value)==null?void 0:a.key)===n}function K(o,n){var l,a;return((l=B.value)==null?void 0:l.row)===o&&((a=B.value)==null?void 0:a.key)===n}function ne(o,n){$(n)&&(B.value={row:o,key:n})}const L=e.ref({});function H(o,n){var a;const l=(a=o.target)==null?void 0:a.id;l&&C.value.errors.find(r=>{if(r.id===l)return L.value[n]=r.errorMessages[0],!0}),B.value={row:null,key:null}}function j(){return!m.value||!p.value?null:m.value.row!==p.value.row?"vertical":m.value.key!==p.value.key?"horizontal":null}function le(o,n){if(!m.value||!p.value)return!1;const l=j();if(!l)return!1;if(l==="vertical"&&n===m.value.key){const[a,r]=[m.value.row,p.value.row];return a<r&&o>a&&o<=r||a>r&&o<a&&o>=r}if(l==="horizontal"&&o===m.value.row){const a=i.headers.map(w=>w.key),[r,g]=[a.indexOf(m.value.key),a.indexOf(p.value.key)].sort((w,N)=>w-N),s=a.indexOf(n);return s>r&&s<=g}return!1}function A(){x.value=!0}function G(o){var a;if(!x.value||!m.value)return;const n=document.elementFromPoint(o.clientX,o.clientY),l=(a=n==null?void 0:n.closest)==null?void 0:a.call(n,"[data-row][data-col]");l&&(p.value={row:Number(l.dataset.row),key:l.dataset.col})}function J(){x.value&&m.value&&p.value&&ae(),x.value=!1,p.value=null}function ae(){const o=m.value,n=p.value,l=j();if(l){if(l==="vertical"){const a=o.key,r=d.value.indexOf(M.value[o.row]),g=d.value.indexOf(M.value[n.row]);if(r===-1||g===-1)return;const s=d.value[r][a],[w,N]=[o.row,n.row].sort((y,v)=>y-v);for(let y=w;y<=N;y++){const v=d.value.indexOf(M.value[y]);v!==-1&&(d.value[v][a]=s)}}if(l==="horizontal"){const a=o.row,r=d.value.indexOf(M.value[a]);if(r===-1)return;const g=d.value[r][o.key],s=i.headers.map(y=>y.key),[w,N]=[s.indexOf(o.key),s.indexOf(n.key)].sort((y,v)=>y-v);for(let y=w+1;y<=N;y++){const v=s[y];d.value[r][v]=g}}}}function q(o){if(!m.value||B.value.row!==null)return;const{row:n,key:l}=m.value,a=M.value.length,r=u.value.map(s=>s.key),g=r.indexOf(l);if(o.key==="ArrowDown"){const s=Math.min(n+1,a-1);I(s,l)}else if(o.key==="ArrowUp"){const s=Math.max(n-1,0);I(s,l)}else if(o.key==="ArrowRight"){const s=Math.min(g+1,r.length-1),w=r[s];I(n,r[s]),Z(n,w)}else if(o.key==="ArrowLeft"){const s=Math.max(g-1,0),w=r[s];I(n,r[s]),Z(n,w)}}function Z(o,n){const l=document.getElementById(`cell-${o}-${n}`);l&&l.scrollIntoView({behavior:"smooth",inline:"nearest",block:"nearest"})}return console.time("Total Mounting time"),e.onMounted(()=>{window.addEventListener("mousemove",G),window.addEventListener("mouseup",J),window.addEventListener("keydown",q),window.addEventListener("keydown",o=>{(o.ctrlKey||o.metaKey)&&o.key==="z"&&S(),(o.ctrlKey||o.metaKey)&&o.key==="y"&&T()}),console.timeEnd("Total Mounting time")}),e.onBeforeUnmount(()=>{window.removeEventListener("mousemove",G),window.removeEventListener("mouseup",J),window.removeEventListener("keydown",q)}),h({formRef:C}),(o,n)=>{const l=e.resolveComponent("v-col"),a=e.resolveComponent("v-text-field"),r=e.resolveComponent("v-btn"),g=e.resolveComponent("v-icon"),s=e.resolveComponent("v-badge"),w=e.resolveComponent("v-list-subheader"),N=e.resolveComponent("v-checkbox-btn"),y=e.resolveComponent("v-list-item-action"),v=e.resolveComponent("v-list-item"),re=e.resolveComponent("v-list"),ce=e.resolveComponent("v-menu"),ie=e.resolveComponent("v-row"),se=e.resolveComponent("v-tooltip"),de=e.resolveComponent("v-checkbox"),me=e.resolveComponent("v-select"),fe=e.resolveComponent("AppPriceDisplay"),ue=e.resolveComponent("v-data-table"),pe=e.resolveComponent("v-form"),ye=e.resolveComponent("v-container"),X=e.resolveDirective("tooltip");return e.openBlock(),e.createBlock(ye,{fluid:"",class:"pa-0"},{default:e.withCtx(()=>[e.createVNode(ie,null,{default:e.withCtx(()=>[e.createVNode(l,{cols:"6",class:"d-flex align-center"},{default:e.withCtx(()=>[e.renderSlot(o.$slots,"header",{},void 0,!0)]),_:3}),e.createVNode(l,{cols:"6",class:"d-flex justify-end"},{default:e.withCtx(()=>[e.renderSlot(o.$slots,"controls",{},()=>[e.createVNode(a,{modelValue:F.value,"onUpdate:modelValue":n[0]||(n[0]=t=>F.value=t),label:"Search",density:"compact","hide-details":"",class:"my-2",style:{"max-width":"300px"}},null,8,["modelValue"]),e.withDirectives(e.createVNode(r,{disabled:!e.unref(O),variant:"text",icon:"mdi-undo",onClick:e.unref(S)},null,8,["disabled","onClick"]),[[X,"Undo","bottom"]]),e.withDirectives(e.createVNode(r,{variant:"text",icon:"mdi-redo",disabled:!e.unref(R),onClick:e.unref(T)},null,8,["disabled","onClick"]),[[X,"Redo","bottom"]]),e.createVNode(ce,{"offset-y":"","close-on-content-click":!1,contained:"",height:"400"},{activator:e.withCtx(({props:t})=>[e.createVNode(r,e.mergeProps(t,{icon:"",variant:"text"}),{default:e.withCtx(()=>[e.createVNode(s,{"model-value":!k.value,dot:"",color:"mpBlue"},{default:e.withCtx(()=>[e.createVNode(g,null,{default:e.withCtx(()=>n[2]||(n[2]=[e.createTextVNode("mdi-filter-variant")])),_:1})]),_:1},8,["model-value"])]),_:2},1040)]),default:e.withCtx(()=>[e.createVNode(re,{selected:f.value,"onUpdate:selected":n[1]||(n[1]=t=>f.value=t),"select-strategy":"leaf"},{default:e.withCtx(()=>[e.createVNode(w,{class:"font-weight-large"},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(o.$t("products.create.bulk-edit.filter-btn")),1)]),_:1}),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(i.headers,t=>(e.openBlock(),e.createBlock(v,{key:t.key,title:t.title,value:t.key,disabled:t.permanent},{prepend:e.withCtx(({isSelected:E})=>[e.createVNode(y,{start:""},{default:e.withCtx(()=>[e.createVNode(N,{"model-value":E,onClick:e.withModifiers(c=>D(t),["stop"])},null,8,["model-value","onClick"])]),_:2},1024)]),_:2},1032,["title","value","disabled"]))),128))]),_:1},8,["selected"])]),_:1})],!0)]),_:3})]),_:3}),e.renderSlot(o.$slots,"prepend",{},void 0,!0),e.createVNode(pe,{ref_key:"formRef",ref:C},{default:e.withCtx(()=>[e.createVNode(ue,{headers:u.value,items:M.value,class:"custom-grid elevation-2 mt-4","hide-default-footer":"",density:"compact"},e.createSlots({_:2},[e.renderList(u.value,t=>({name:`item.${t.key}`,fn:e.withCtx(({item:E,index:c})=>[e.createElementVNode("div",{id:`cell-${c}-${t.key}`,class:e.normalizeClass(["cell",{selected:U(c,t.key),fillZone:le(c,t.key),nonEditable:!$(t.key),[`text-${t.align||"center"}`]:!0}]),"data-row":c,"data-col":t.key,onClick:_=>I(c,t.key),onDblclick:_=>ne(c,t.key)},[L.value[`${c}-${t.key}`]?(e.openBlock(),e.createBlock(se,{key:0,activator:"parent",location:"top","content-class":"error-tooltip"},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(L.value[`${c}-${t.key}`]),1)]),_:2},1024)):e.createCommentVNode("",!0),t.type==="checkbox"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createVNode(de,e.mergeProps({modelValue:e.unref(d)[c][t.key],"onUpdate:modelValue":_=>e.unref(d)[c][t.key]=_,"hide-details":"",variant:"plain",density:"compact",class:"d-flex justify-center align-center edit-input",autofocus:""},t.props),null,16,["modelValue","onUpdate:modelValue"]),!t.hideHandle&&U(c,t.key)&&$(t.key)?(e.openBlock(),e.createElementBlock("div",{key:0,class:"handle",onMousedown:e.withModifiers(A,["stop","prevent"])},null,32)):e.createCommentVNode("",!0)],64)):t.type==="select"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:2},[e.createVNode(me,e.mergeProps({modelValue:e.unref(d)[c][t.key],"onUpdate:modelValue":_=>e.unref(d)[c][t.key]=_,items:t.items,"item-title":t.itemTitle,"item-value":t.itemValue,"hide-details":"",variant:"plain",density:"compact"},t.props),null,16,["modelValue","onUpdate:modelValue","items","item-title","item-value"]),!t.hideHandle&&U(c,t.key)&&$(t.key)?(e.openBlock(),e.createElementBlock("div",{key:0,class:"handle",onMousedown:e.withModifiers(A,["stop","prevent"])},null,32)):e.createCommentVNode("",!0)],64)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:3},[e.withDirectives(e.createElementVNode("div",{class:e.normalizeClass(["w-100",{show:K(c,t.key)}])},[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(oe(t.key)),e.mergeProps({modelValue:e.unref(d)[c][t.key],"onUpdate:modelValue":_=>e.unref(d)[c][t.key]=_,class:"edit-input",variant:"plain",density:"compact",autofocus:"","hide-details":""},t.props,{onBlur:_=>H(_,`${c}-${t.key}`),onKeydown:e.withKeys(_=>H(_,`${c}-${t.key}`),["enter"])}),{append:e.withCtx(({isValid:_})=>[_.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",ee))]),_:2},1040,["modelValue","onUpdate:modelValue","onBlur","onKeydown"]))],2),[[e.vShow,K(c,t.key)]]),K(c,t.key)?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[t.type==="number"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createTextVNode(e.toDisplayString(t.prefix)+" "+e.toDisplayString(E[t.key]?e.unref(Y)(E[t.key]):E[t.key])+" "+e.toDisplayString(t.suffix),1)],64)):t.type==="currency"?(e.openBlock(),e.createBlock(fe,{key:1,price:E[t.key],currency:t.currency_code,class:"text-no-wrap"},null,8,["price","currency"])):(e.openBlock(),e.createElementBlock(e.Fragment,{key:2},[e.createTextVNode(e.toDisplayString(t.prefix)+" "+e.toDisplayString(E[t.key])+" "+e.toDisplayString(t.suffix),1)],64)),!t.hideHandle&&U(c,t.key)&&$(t.key)?(e.openBlock(),e.createElementBlock("div",{key:3,class:"handle",onMousedown:e.withModifiers(A,["stop","prevent"])},null,32)):e.createCommentVNode("",!0)],64))],64))],42,W)])}))]),1032,["headers","items"])]),_:1},512)]),_:3})}}},[["__scopeId","data-v-6cc7b667"]]),te={install(i){i.component("EditableDataGrid",z)}};V.EditableDataGrid=z,V.default=te,V.useRefHistory=P,Object.defineProperties(V,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});