kempo 2.9.1 → 2.9.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.
@@ -1 +1 @@
1
- import Component from"./Component.js";import Icon from"./Icon.js";import SelectCount from"./tableControls/SelectCount.js";import PageSelect from"./tableControls/PageSelect.js";import PageSize from"./tableControls/PageSize.js";import DeleteSelected from"./tableControls/DeleteSelected.js";import{toTitleCase}from"../utils/string.js";import{onEvent,dispatchEvent}from"../utils/element.js";export default class Table extends Component{static controls={prevPage:{render:e=>{const t=document.createElement("button");return t.classList.add("pq","no-btn"),t.appendChild(new Icon("chevron-left")),onEvent(t,"click",(()=>e.prevPage())),onEvent(e,"pageChange",(()=>{t.disabled=1===e.getCurrentPage()})),t}},nextPage:{render:e=>{const t=document.createElement("button");return t.classList.add("pq","no-btn"),t.appendChild(new Icon("chevron-right")),onEvent(t,"click",(()=>e.nextPage())),onEvent(e,"pageChange",(()=>{t.disabled=e.getCurrentPage()===e.getTotalPages()})),t}},pageSelect:{render:e=>new PageSelect(e)},pageSize:{render:e=>new PageSize(e)},selectCount:{render:e=>new SelectCount(e)},deleteSelected:{render:e=>new DeleteSelected(e)},spacer:{html:'<div class="flex"></div>'}};constructor({records:e=[],fields:t=[],controls:n={before:[],after:[],top:[],bottom:[]},pageSize:s=100,pageSizeOptions:r=[10,25,50,100,500],currentPage:i=1,enableSelection:o=!1}={}){super(),this.registerProps({fields:t,records:e,controls:n,pageSize:s,pageSizeOptions:r,currentPage:i,enableSelection:o,selectedIndexes:[]})}async render(e){return!!await super.render(e)&&(this.setData({records:this.records,fields:this.fields,controls:this.controls,pageSize:this.pageSize,pageSizeOptions:this.pageSizeOptions,currentPage:this.currentPage}),!0)}renderFields(){if(!this.rendered)return;const e=this.controls?.before?.length?"<th></th>":"",t=this.controls?.after?.length?"<th></th>":"",n=this.enableSelection?'<th class="selection"><input type="checkbox" id="select-all"></th>':"";if(this.shadowRoot.getElementById("fields").innerHTML=`${n}${e}${this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}${t}`,this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e.addEventListener("change",(()=>{e.checked?this.selectAllOnPage():this.deselectAllOnPage()})),onEvent(this,"selectionChange pageChange",(()=>{this.allOnPageSelected()?e.checked=!0:e.checked=!1}))}}renderRecords(){if(!this.rendered)return;const e=this.shadowRoot.getElementById("records");e.innerHTML="";const t=(this.currentPage-1)*this.pageSize,n=t+this.pageSize;this.records.slice(t,n).forEach(((s,r)=>{const i=document.createElement("tr");if(this.enableSelection){const e=document.createElement("td");e.classList.add("selection");const n=document.createElement("input");n.type="checkbox",n.checked=this.selectedIndexes.includes(t+r),n.addEventListener("change",(()=>{n.checked?this.selectedIndexes.push(t+r):this.selectedIndexes=this.selectedIndexes.filter((e=>e!==t+r)),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})})),e.appendChild(n),i.appendChild(e)}this.controls?.before?.length&&i.appendChild(this.renderRowControls(this.controls.before,s,t+r)),this.fields.forEach((({name:e,formatter:r,calculator:o})=>{const d=document.createElement("td");if(null===s)d.innerHTML="Loading...",dispatchEvent(this,"fetchRecords",{start:t,end:n});else{let t;o?t=o(s,this):(t=s[e]||"",Array.isArray(t)?t=r?t.map(r).join(", "):t.join(", "):r&&(t=r(t))),d.innerHTML=t}i.appendChild(d)})),this.controls?.after?.length&&i.appendChild(this.renderRowControls(this.controls.after,s,t+r)),e.appendChild(i)}))}renderRowControls(e=[],t,n){if(!this.rendered)return;const s=document.createElement("td");return e.forEach((({html:e,icon:r,action:i,render:o})=>{if(e)s.appendChild(document.createRange().createContextualFragment(e));else if(o&&"function"==typeof o){const e=o(this,t,n);e instanceof HTMLElement?s.appendChild(e):"string"==typeof e&&s.appendChild(document.createRange().createContextualFragment(e))}else if(r){const e=document.createElement("button");e.classList.add("pq","no-btn"),e.appendChild(new Icon(r)),i&&onEvent(e,"click",(()=>i(this,t,n))),s.appendChild(e)}})),s}renderControls(e=[],t){if(!this.rendered)return;const n=this.shadowRoot.getElementById(t);n.innerHTML="",e.forEach((({html:e,icon:t,action:s,render:r})=>{if(e)n.appendChild(document.createRange().createContextualFragment(e));else if(r&&"function"==typeof r){const e=r(this);e instanceof HTMLElement?n.appendChild(e):"string"==typeof e&&n.appendChild(document.createRange().createContextualFragment(e))}else if(t){const e=document.createElement("button");e.classList.add("pq","no-btn"),e.appendChild(new Icon(t)),s&&onEvent(e,"click",(()=>s(this))),n.appendChild(e)}}))}getCurrentPage(){return this.currentPage}getTotalPages(){return Math.ceil(this.records.length/this.pageSize)}setPage(e){e<1||e>this.getTotalPages()||(this.currentPage=e,this.renderRecords(),dispatchEvent(this,"pageChange"))}nextPage(){this.currentPage<this.getTotalPages()&&this.setPage(this.currentPage+1)}prevPage(){this.currentPage>1&&this.setPage(this.currentPage-1)}setPageSize(e){this.pageSize=e,this.currentPage=1,this.renderRecords(),dispatchEvent(this,"pageSizeChange")}setData({records:e=!1,fields:t=!1,controls:n=!1,pageSize:s=!1,pageSizeOptions:r=!1,currentPage:i=!1,enableSelection:o=!1}={}){let d=!1,c=!1;e&&(this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),d=!0),s&&(this.pageSize=s,d=!0),r&&(this.pageSizeOptions=r),n&&(this.controls=n,c=!0),i&&(this.currentPage=i,d=!0),void 0!==o&&(this.enableSelection=o,d=!0),d&&(this.renderFields(),this.renderRecords()),c&&(this.renderControls(this.controls.top,"top"),this.renderControls(this.controls.bottom,"bottom"))}setRecords(e){this.records=e,this.currentPage=1,this.renderRecords(),dispatchEvent(this,"recordsSet",{records:e})}setupFetchRecords(e,t){const n=this.records.length;n<e&&(this.records.length=e,this.records.fill(null,n)),onEvent(this,"fetchRecords",(async e=>{const{start:n,end:s}=e.detail,r=await t(n,s-n);this.records.splice(n,r.length,...r),this.renderRecords()}))}addRecord(e){this.records.push(e),this.renderRecords(),dispatchEvent(this,"recordAdded",{record:e})}updateRecord(e,t){this.records[e]=t;const n=(this.currentPage-1)*this.pageSize,s=n+this.pageSize;e>=n&&e<s&&this.renderRecords()}deleteRecord(e){e>=0&&e<this.records.length&&(this.selectedIndexes=this.selectedIndexes.filter((t=>t!==e)),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes}),this.records.splice(e,1),this.renderRecords(),dispatchEvent(this,"recordDeleted",{index:e}))}getSelectedRecords(){return this.selectedIndexes.map((e=>this.records[e]))}selectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let n=e;n<t;n++)this.selectedIndexes.includes(n)||this.selectedIndexes.push(n);this.renderRecords(),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})}deselectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);this.selectedIndexes=this.selectedIndexes.filter((n=>n<e||n>=t)),this.renderRecords(),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})}allOnPageSelected(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let n=e;n<t;n++)if(!this.selectedIndexes.includes(n))return!1;return!0}get shadowTemplate(){return`\n ${super.shadowTemplate}\n <div class="responsive-table">\n <div id="top"></div>\n <table class="b0">\n <thead id="fields"></thead>\n <tbody id="records"></tbody>\n </table>\n <div id="bottom"></div>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n margin-bottom: var(--spacer);\n border: 1px solid var(--c_border);\n border-radius: var(--radius);\n }\n #top, #bottom {\n display: flex;\n }\n th {\n border-top: none;\n }\n tr:last-child td:first-child {\n border-bottom-left-radius: 0;\n }\n tr:last-child td:last-child {\n border-bottom-right-radius: 0;\n }\n tr:last-child td {\n border-bottom: none;\n }\n th:first-child, td:first-child {\n border-left: none;\n }\n th:last-child, td:last-child {\n border-right: none;\n }\n #top:not(:empty) {\n border-bottom: 1px solid var(--c_border);\n }\n #bottom:not(:empty) {\n border-top: 1px solid var(--c_border);\n }\n th.selection, td.selection {\n width: 50px;\n }\n th.selection input,\n td.selection input {\n margin: 0;\n width: 1.35rem;\n height: 1.35rem;\n }\n `}static extractFieldsFromRecords(e,t=100){const n=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>n.add(e)))})),[...n].map((e=>({name:e,label:toTitleCase(e)})))}}window.customElements.define("k-table",Table);
1
+ import Component from"./Component.js";import Icon from"./Icon.js";import SelectCount from"./tableControls/SelectCount.js";import PageSelect from"./tableControls/PageSelect.js";import PageSize from"./tableControls/PageSize.js";import DeleteSelected from"./tableControls/DeleteSelected.js";import{toTitleCase}from"../utils/string.js";import{onEvent,dispatchEvent}from"../utils/element.js";export default class Table extends Component{static controls={prevPage:{render:e=>{const t=document.createElement("button");return t.classList.add("pq","no-btn"),t.appendChild(new Icon("chevron-left")),onEvent(t,"click",(()=>e.prevPage())),onEvent(e,"pageChange",(()=>{t.disabled=1===e.getCurrentPage()})),t}},nextPage:{render:e=>{const t=document.createElement("button");return t.classList.add("pq","no-btn"),t.appendChild(new Icon("chevron-right")),onEvent(t,"click",(()=>e.nextPage())),onEvent(e,"pageChange",(()=>{t.disabled=e.getCurrentPage()===e.getTotalPages()})),t}},pageSelect:{render:e=>new PageSelect(e)},pageSize:{render:e=>new PageSize(e)},selectCount:{render:e=>new SelectCount(e)},deleteSelected:{render:e=>new DeleteSelected(e)},spacer:{html:'<div class="flex"></div>'}};constructor({records:e=[],fields:t=[],controls:n={before:[],after:[],top:[],bottom:[]},pageSize:s=100,pageSizeOptions:r=[10,25,50,100,500],currentPage:i=1,enableSelection:o=!1}={}){super(),this.registerProps({fields:t,records:e,controls:n,pageSize:s,pageSizeOptions:r,currentPage:i,enableSelection:o,selectedIndexes:[]})}async render(e){return!!await super.render(e)&&(this.setData({records:this.records,fields:this.fields,controls:this.controls,pageSize:this.pageSize,pageSizeOptions:this.pageSizeOptions,currentPage:this.currentPage}),!0)}renderFields(){if(!this.rendered)return;const e=this.controls?.before?.length?"<th></th>":"",t=this.controls?.after?.length?"<th></th>":"",n=this.enableSelection?'<th class="selection"><input type="checkbox" id="select-all"></th>':"";if(this.shadowRoot.getElementById("fields").innerHTML=`${n}${e}${this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}${t}`,this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e.addEventListener("change",(()=>{e.checked?this.selectAllOnPage():this.deselectAllOnPage()})),onEvent(this,"selectionChange pageChange",(()=>{this.allOnPageSelected()?e.checked=!0:e.checked=!1}))}}renderRecords(){if(!this.rendered)return;const e=this.shadowRoot.getElementById("records");e.innerHTML="";const t=(this.currentPage-1)*this.pageSize,n=t+this.pageSize,s=this.records.slice(t,n);let r=!1;s.forEach(((n,s)=>{const i=document.createElement("tr");if(this.enableSelection){const e=document.createElement("td");e.classList.add("selection");const n=document.createElement("input");n.type="checkbox",n.checked=this.selectedIndexes.includes(t+s),n.addEventListener("change",(()=>{n.checked?this.selectedIndexes.push(t+s):this.selectedIndexes=this.selectedIndexes.filter((e=>e!==t+s)),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})})),e.appendChild(n),i.appendChild(e)}if(this.controls?.before?.length&&i.appendChild(this.renderRowControls(this.controls.before,n,t+s)),null===n){const e=document.createElement("td");e.colSpan=this.fields.length,e.innerHTML="<i>Loading...</i>",r=!0,i.appendChild(e)}else this.fields.forEach((({name:e,formatter:t,calculator:s},r)=>{const o=document.createElement("td");let d;s?d=s(n,this):(d=n[e]||"",Array.isArray(d)?d=t?d.map(t).join(", "):d.join(", "):t&&(d=t(d))),o.innerHTML=d,i.appendChild(o)}));this.controls?.after?.length&&i.appendChild(this.renderRowControls(this.controls.after,n,t+s)),e.appendChild(i)})),r&&dispatchEvent(this,"fetchRecords",{start:t,end:n})}renderRowControls(e=[],t,n){if(!this.rendered)return;const s=document.createElement("td");return e.forEach((({html:e,icon:r,action:i,render:o})=>{if(e)s.appendChild(document.createRange().createContextualFragment(e));else if(o&&"function"==typeof o){const e=o(this,t,n);e instanceof HTMLElement?s.appendChild(e):"string"==typeof e&&s.appendChild(document.createRange().createContextualFragment(e))}else if(r){const e=document.createElement("button");e.classList.add("pq","no-btn"),e.appendChild(new Icon(r)),i&&onEvent(e,"click",(()=>i(this,t,n))),s.appendChild(e)}})),s}renderControls(e=[],t){if(!this.rendered)return;const n=this.shadowRoot.getElementById(t);n.innerHTML="",e.forEach((({html:e,icon:t,action:s,render:r})=>{if(e)n.appendChild(document.createRange().createContextualFragment(e));else if(r&&"function"==typeof r){const e=r(this);e instanceof HTMLElement?n.appendChild(e):"string"==typeof e&&n.appendChild(document.createRange().createContextualFragment(e))}else if(t){const e=document.createElement("button");e.classList.add("pq","no-btn"),e.appendChild(new Icon(t)),s&&onEvent(e,"click",(()=>s(this))),n.appendChild(e)}}))}getCurrentPage(){return this.currentPage}getTotalPages(){return Math.ceil(this.records.length/this.pageSize)}setPage(e){e<1||e>this.getTotalPages()||(this.currentPage=e,this.renderRecords(),dispatchEvent(this,"pageChange"))}nextPage(){this.currentPage<this.getTotalPages()&&this.setPage(this.currentPage+1)}prevPage(){this.currentPage>1&&this.setPage(this.currentPage-1)}setPageSize(e){this.pageSize=e,this.currentPage=1,this.renderRecords(),dispatchEvent(this,"pageSizeChange")}setData({records:e=!1,fields:t=!1,controls:n=!1,pageSize:s=!1,pageSizeOptions:r=!1,currentPage:i=!1,enableSelection:o=!1}={}){let d=!1,c=!1;e&&(this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),d=!0),s&&(this.pageSize=s,d=!0),r&&(this.pageSizeOptions=r),n&&(this.controls=n,c=!0),i&&(this.currentPage=i,d=!0),void 0!==o&&(this.enableSelection=o,d=!0),d&&(this.renderFields(),this.renderRecords()),c&&(this.renderControls(this.controls.top,"top"),this.renderControls(this.controls.bottom,"bottom"))}setRecords(e){this.records=e,this.currentPage=1,this.renderRecords(),dispatchEvent(this,"recordsSet",{records:e})}setupFetchRecords(e,t){const n=this.records.length;n<e&&(this.records.length=e,this.records.fill(null,n)),onEvent(this,"fetchRecords",(async e=>{const{start:n,end:s}=e.detail,r=await t(n,s-n);this.records.splice(n,r.length,...r),this.renderRecords()}))}addRecord(e){this.records.push(e),this.renderRecords(),dispatchEvent(this,"recordAdded",{record:e})}updateRecord(e,t){this.records[e]=t;const n=(this.currentPage-1)*this.pageSize,s=n+this.pageSize;e>=n&&e<s&&this.renderRecords()}deleteRecord(e){e>=0&&e<this.records.length&&(this.selectedIndexes=this.selectedIndexes.filter((t=>t!==e)),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes}),this.records.splice(e,1),this.renderRecords(),dispatchEvent(this,"recordDeleted",{index:e}))}getSelectedRecords(){return this.selectedIndexes.map((e=>this.records[e]))}selectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let n=e;n<t;n++)this.selectedIndexes.includes(n)||this.selectedIndexes.push(n);this.renderRecords(),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})}deselectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);this.selectedIndexes=this.selectedIndexes.filter((n=>n<e||n>=t)),this.renderRecords(),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})}allOnPageSelected(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let n=e;n<t;n++)if(!this.selectedIndexes.includes(n))return!1;return!0}get shadowTemplate(){return`\n ${super.shadowTemplate}\n <div class="responsive-table">\n <div id="top"></div>\n <table class="b0">\n <thead id="fields"></thead>\n <tbody id="records"></tbody>\n </table>\n <div id="bottom"></div>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n margin-bottom: var(--spacer);\n border: 1px solid var(--c_border);\n border-radius: var(--radius);\n }\n #top, #bottom {\n display: flex;\n }\n th {\n border-top: none;\n }\n tr:last-child td:first-child {\n border-bottom-left-radius: 0;\n }\n tr:last-child td:last-child {\n border-bottom-right-radius: 0;\n }\n tr:last-child td {\n border-bottom: none;\n }\n th:first-child, td:first-child {\n border-left: none;\n }\n th:last-child, td:last-child {\n border-right: none;\n }\n #top:not(:empty) {\n border-bottom: 1px solid var(--c_border);\n }\n #bottom:not(:empty) {\n border-top: 1px solid var(--c_border);\n }\n th.selection, td.selection {\n width: 50px;\n }\n th.selection input,\n td.selection input {\n margin: 0;\n width: 1.35rem;\n height: 1.35rem;\n }\n `}static extractFieldsFromRecords(e,t=100){const n=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>n.add(e)))})),[...n].map((e=>({name:e,label:toTitleCase(e)})))}}window.customElements.define("k-table",Table);
@@ -255,28 +255,36 @@
255
255
  });
256
256
  </script>
257
257
 
258
- <h3 id="recordSelection"><a href="#recordSelection" class="no-link">Record Selection</a></h3>
259
- <p>The table component supports record selection. You can enable record selection by setting the <code>enableSelection</code> property to <code>true</code>.</p>
260
- <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"recordSelectionExample"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-table</span>&gt;</span><br /><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript"><br /> <span class="hljs-keyword">import</span> Table <span class="hljs-keyword">from</span> <span class="hljs-string">'../kempo/components/Table.js'</span>;<br /><br /> <span class="hljs-keyword">const</span> $recordSelectionExample = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'recordSelectionExample'</span>);<br /> $recordSelectionExample.setData({<br /> <span class="hljs-attr">records</span>: contacts,<br /> <span class="hljs-attr">enableSelection</span>: <span class="hljs-literal">true</span>,<br /> <span class="hljs-attr">controls</span>: {<br /> <span class="hljs-attr">bottom</span>: [<br /> Table.controls.prevPage,<br /> Table.controls.nextPage,<br /> Table.controls.spacer,<br /> Table.controls.selectCount,<br /> Table.controls.deleteSelected<br /> ]<br /> },<br /> <span class="hljs-attr">pageSize</span>: <span class="hljs-number">10</span><br /> });<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
261
- <k-table id="recordSelectionExample"></k-table>
258
+ <h3 id="fetchRecords"><a href="#fetchRecords" class="no-link">Fetch Records</a></h3>
259
+ <p>The table component supports fetching records dynamically. You can set up the fetch records feature by using the <code>setupFetchRecords</code> method.</p>
260
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"fetchRecordsExample"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-table</span>&gt;</span><br /><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript"><br /> <span class="hljs-keyword">import</span> Table <span class="hljs-keyword">from</span> <span class="hljs-string">'../kempo/components/Table.js'</span>;<br /><br /> <span class="hljs-keyword">const</span> $fetchRecordsExample = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'fetchRecordsExample'</span>);<br /> <span class="hljs-keyword">const</span> totalRecords = <span class="hljs-number">100</span>;<br /> $fetchRecordsExample.setData({<br /> <span class="hljs-attr">pageSize</span>: <span class="hljs-number">10</span>,<br /> <span class="hljs-attr">records</span>: contacts.slice(<span class="hljs-number">0</span>, <span class="hljs-number">10</span>),<br /> <span class="hljs-attr">controls</span>: {<br /> <span class="hljs-attr">bottom</span>: [<br /> Table.controls.prevPage,<br /> Table.controls.nextPage,<br /> Table.controls.pageSelect,<br /> Table.controls.spacer,<br /> Table.controls.pageSize<br /> ]<br /> }<br /> });<br /> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mockFetchRecords</span>(<span class="hljs-params">start, count</span>) </span>{<br /> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> {<br /> setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {<br /> resolve(contacts.slice(start, start + count));<br /> }, <span class="hljs-number">1000</span>);<br /> });<br /> }<br /> $fetchRecordsExample.setupFetchRecords(totalRecords, mockFetchRecords);<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
261
+ <k-table id="fetchRecordsExample"></k-table>
262
262
  <script type="module">
263
263
  import Table from '../kempo/components/Table.js';
264
264
 
265
- const $recordSelectionExample = document.getElementById('recordSelectionExample');
266
- $recordSelectionExample.setData({
267
- records: contacts,
268
- enableSelection: true,
265
+ const $fetchRecordsExample = document.getElementById('fetchRecordsExample');
266
+ const totalRecords = 100;
267
+ $fetchRecordsExample.setData({
268
+ pageSize: 10,
269
+ records: contacts.slice(0, 10),
269
270
  controls: {
270
271
  bottom: [
271
272
  Table.controls.prevPage,
272
273
  Table.controls.nextPage,
274
+ Table.controls.pageSelect,
273
275
  Table.controls.spacer,
274
- Table.controls.selectCount,
275
- Table.controls.deleteSelected
276
+ Table.controls.pageSize
276
277
  ]
277
- },
278
- pageSize: 10
278
+ }
279
279
  });
280
+ function mockFetchRecords(start, count) {
281
+ return new Promise((resolve) => {
282
+ setTimeout(() => {
283
+ resolve(contacts.slice(start, start + count));
284
+ }, 1000);
285
+ });
286
+ }
287
+ $fetchRecordsExample.setupFetchRecords(totalRecords, mockFetchRecords);
280
288
  </script>
281
289
 
282
290
  <h2>JavaScript Reference</h2>
@@ -1 +1 @@
1
- import Component from"./Component.js";import Icon from"./Icon.js";import SelectCount from"./tableControls/SelectCount.js";import PageSelect from"./tableControls/PageSelect.js";import PageSize from"./tableControls/PageSize.js";import DeleteSelected from"./tableControls/DeleteSelected.js";import{toTitleCase}from"../utils/string.js";import{onEvent,dispatchEvent}from"../utils/element.js";export default class Table extends Component{static controls={prevPage:{render:e=>{const t=document.createElement("button");return t.classList.add("pq","no-btn"),t.appendChild(new Icon("chevron-left")),onEvent(t,"click",(()=>e.prevPage())),onEvent(e,"pageChange",(()=>{t.disabled=1===e.getCurrentPage()})),t}},nextPage:{render:e=>{const t=document.createElement("button");return t.classList.add("pq","no-btn"),t.appendChild(new Icon("chevron-right")),onEvent(t,"click",(()=>e.nextPage())),onEvent(e,"pageChange",(()=>{t.disabled=e.getCurrentPage()===e.getTotalPages()})),t}},pageSelect:{render:e=>new PageSelect(e)},pageSize:{render:e=>new PageSize(e)},selectCount:{render:e=>new SelectCount(e)},deleteSelected:{render:e=>new DeleteSelected(e)},spacer:{html:'<div class="flex"></div>'}};constructor({records:e=[],fields:t=[],controls:n={before:[],after:[],top:[],bottom:[]},pageSize:s=100,pageSizeOptions:r=[10,25,50,100,500],currentPage:i=1,enableSelection:o=!1}={}){super(),this.registerProps({fields:t,records:e,controls:n,pageSize:s,pageSizeOptions:r,currentPage:i,enableSelection:o,selectedIndexes:[]})}async render(e){return!!await super.render(e)&&(this.setData({records:this.records,fields:this.fields,controls:this.controls,pageSize:this.pageSize,pageSizeOptions:this.pageSizeOptions,currentPage:this.currentPage}),!0)}renderFields(){if(!this.rendered)return;const e=this.controls?.before?.length?"<th></th>":"",t=this.controls?.after?.length?"<th></th>":"",n=this.enableSelection?'<th class="selection"><input type="checkbox" id="select-all"></th>':"";if(this.shadowRoot.getElementById("fields").innerHTML=`${n}${e}${this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}${t}`,this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e.addEventListener("change",(()=>{e.checked?this.selectAllOnPage():this.deselectAllOnPage()})),onEvent(this,"selectionChange pageChange",(()=>{this.allOnPageSelected()?e.checked=!0:e.checked=!1}))}}renderRecords(){if(!this.rendered)return;const e=this.shadowRoot.getElementById("records");e.innerHTML="";const t=(this.currentPage-1)*this.pageSize,n=t+this.pageSize;this.records.slice(t,n).forEach(((s,r)=>{const i=document.createElement("tr");if(this.enableSelection){const e=document.createElement("td");e.classList.add("selection");const n=document.createElement("input");n.type="checkbox",n.checked=this.selectedIndexes.includes(t+r),n.addEventListener("change",(()=>{n.checked?this.selectedIndexes.push(t+r):this.selectedIndexes=this.selectedIndexes.filter((e=>e!==t+r)),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})})),e.appendChild(n),i.appendChild(e)}this.controls?.before?.length&&i.appendChild(this.renderRowControls(this.controls.before,s,t+r)),this.fields.forEach((({name:e,formatter:r,calculator:o})=>{const d=document.createElement("td");if(null===s)d.innerHTML="Loading...",dispatchEvent(this,"fetchRecords",{start:t,end:n});else{let t;o?t=o(s,this):(t=s[e]||"",Array.isArray(t)?t=r?t.map(r).join(", "):t.join(", "):r&&(t=r(t))),d.innerHTML=t}i.appendChild(d)})),this.controls?.after?.length&&i.appendChild(this.renderRowControls(this.controls.after,s,t+r)),e.appendChild(i)}))}renderRowControls(e=[],t,n){if(!this.rendered)return;const s=document.createElement("td");return e.forEach((({html:e,icon:r,action:i,render:o})=>{if(e)s.appendChild(document.createRange().createContextualFragment(e));else if(o&&"function"==typeof o){const e=o(this,t,n);e instanceof HTMLElement?s.appendChild(e):"string"==typeof e&&s.appendChild(document.createRange().createContextualFragment(e))}else if(r){const e=document.createElement("button");e.classList.add("pq","no-btn"),e.appendChild(new Icon(r)),i&&onEvent(e,"click",(()=>i(this,t,n))),s.appendChild(e)}})),s}renderControls(e=[],t){if(!this.rendered)return;const n=this.shadowRoot.getElementById(t);n.innerHTML="",e.forEach((({html:e,icon:t,action:s,render:r})=>{if(e)n.appendChild(document.createRange().createContextualFragment(e));else if(r&&"function"==typeof r){const e=r(this);e instanceof HTMLElement?n.appendChild(e):"string"==typeof e&&n.appendChild(document.createRange().createContextualFragment(e))}else if(t){const e=document.createElement("button");e.classList.add("pq","no-btn"),e.appendChild(new Icon(t)),s&&onEvent(e,"click",(()=>s(this))),n.appendChild(e)}}))}getCurrentPage(){return this.currentPage}getTotalPages(){return Math.ceil(this.records.length/this.pageSize)}setPage(e){e<1||e>this.getTotalPages()||(this.currentPage=e,this.renderRecords(),dispatchEvent(this,"pageChange"))}nextPage(){this.currentPage<this.getTotalPages()&&this.setPage(this.currentPage+1)}prevPage(){this.currentPage>1&&this.setPage(this.currentPage-1)}setPageSize(e){this.pageSize=e,this.currentPage=1,this.renderRecords(),dispatchEvent(this,"pageSizeChange")}setData({records:e=!1,fields:t=!1,controls:n=!1,pageSize:s=!1,pageSizeOptions:r=!1,currentPage:i=!1,enableSelection:o=!1}={}){let d=!1,c=!1;e&&(this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),d=!0),s&&(this.pageSize=s,d=!0),r&&(this.pageSizeOptions=r),n&&(this.controls=n,c=!0),i&&(this.currentPage=i,d=!0),void 0!==o&&(this.enableSelection=o,d=!0),d&&(this.renderFields(),this.renderRecords()),c&&(this.renderControls(this.controls.top,"top"),this.renderControls(this.controls.bottom,"bottom"))}setRecords(e){this.records=e,this.currentPage=1,this.renderRecords(),dispatchEvent(this,"recordsSet",{records:e})}setupFetchRecords(e,t){const n=this.records.length;n<e&&(this.records.length=e,this.records.fill(null,n)),onEvent(this,"fetchRecords",(async e=>{const{start:n,end:s}=e.detail,r=await t(n,s-n);this.records.splice(n,r.length,...r),this.renderRecords()}))}addRecord(e){this.records.push(e),this.renderRecords(),dispatchEvent(this,"recordAdded",{record:e})}updateRecord(e,t){this.records[e]=t;const n=(this.currentPage-1)*this.pageSize,s=n+this.pageSize;e>=n&&e<s&&this.renderRecords()}deleteRecord(e){e>=0&&e<this.records.length&&(this.selectedIndexes=this.selectedIndexes.filter((t=>t!==e)),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes}),this.records.splice(e,1),this.renderRecords(),dispatchEvent(this,"recordDeleted",{index:e}))}getSelectedRecords(){return this.selectedIndexes.map((e=>this.records[e]))}selectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let n=e;n<t;n++)this.selectedIndexes.includes(n)||this.selectedIndexes.push(n);this.renderRecords(),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})}deselectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);this.selectedIndexes=this.selectedIndexes.filter((n=>n<e||n>=t)),this.renderRecords(),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})}allOnPageSelected(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let n=e;n<t;n++)if(!this.selectedIndexes.includes(n))return!1;return!0}get shadowTemplate(){return`\n ${super.shadowTemplate}\n <div class="responsive-table">\n <div id="top"></div>\n <table class="b0">\n <thead id="fields"></thead>\n <tbody id="records"></tbody>\n </table>\n <div id="bottom"></div>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n margin-bottom: var(--spacer);\n border: 1px solid var(--c_border);\n border-radius: var(--radius);\n }\n #top, #bottom {\n display: flex;\n }\n th {\n border-top: none;\n }\n tr:last-child td:first-child {\n border-bottom-left-radius: 0;\n }\n tr:last-child td:last-child {\n border-bottom-right-radius: 0;\n }\n tr:last-child td {\n border-bottom: none;\n }\n th:first-child, td:first-child {\n border-left: none;\n }\n th:last-child, td:last-child {\n border-right: none;\n }\n #top:not(:empty) {\n border-bottom: 1px solid var(--c_border);\n }\n #bottom:not(:empty) {\n border-top: 1px solid var(--c_border);\n }\n th.selection, td.selection {\n width: 50px;\n }\n th.selection input,\n td.selection input {\n margin: 0;\n width: 1.35rem;\n height: 1.35rem;\n }\n `}static extractFieldsFromRecords(e,t=100){const n=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>n.add(e)))})),[...n].map((e=>({name:e,label:toTitleCase(e)})))}}window.customElements.define("k-table",Table);
1
+ import Component from"./Component.js";import Icon from"./Icon.js";import SelectCount from"./tableControls/SelectCount.js";import PageSelect from"./tableControls/PageSelect.js";import PageSize from"./tableControls/PageSize.js";import DeleteSelected from"./tableControls/DeleteSelected.js";import{toTitleCase}from"../utils/string.js";import{onEvent,dispatchEvent}from"../utils/element.js";export default class Table extends Component{static controls={prevPage:{render:e=>{const t=document.createElement("button");return t.classList.add("pq","no-btn"),t.appendChild(new Icon("chevron-left")),onEvent(t,"click",(()=>e.prevPage())),onEvent(e,"pageChange",(()=>{t.disabled=1===e.getCurrentPage()})),t}},nextPage:{render:e=>{const t=document.createElement("button");return t.classList.add("pq","no-btn"),t.appendChild(new Icon("chevron-right")),onEvent(t,"click",(()=>e.nextPage())),onEvent(e,"pageChange",(()=>{t.disabled=e.getCurrentPage()===e.getTotalPages()})),t}},pageSelect:{render:e=>new PageSelect(e)},pageSize:{render:e=>new PageSize(e)},selectCount:{render:e=>new SelectCount(e)},deleteSelected:{render:e=>new DeleteSelected(e)},spacer:{html:'<div class="flex"></div>'}};constructor({records:e=[],fields:t=[],controls:n={before:[],after:[],top:[],bottom:[]},pageSize:s=100,pageSizeOptions:r=[10,25,50,100,500],currentPage:i=1,enableSelection:o=!1}={}){super(),this.registerProps({fields:t,records:e,controls:n,pageSize:s,pageSizeOptions:r,currentPage:i,enableSelection:o,selectedIndexes:[]})}async render(e){return!!await super.render(e)&&(this.setData({records:this.records,fields:this.fields,controls:this.controls,pageSize:this.pageSize,pageSizeOptions:this.pageSizeOptions,currentPage:this.currentPage}),!0)}renderFields(){if(!this.rendered)return;const e=this.controls?.before?.length?"<th></th>":"",t=this.controls?.after?.length?"<th></th>":"",n=this.enableSelection?'<th class="selection"><input type="checkbox" id="select-all"></th>':"";if(this.shadowRoot.getElementById("fields").innerHTML=`${n}${e}${this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}${t}`,this.enableSelection){const e=this.shadowRoot.getElementById("select-all");e.addEventListener("change",(()=>{e.checked?this.selectAllOnPage():this.deselectAllOnPage()})),onEvent(this,"selectionChange pageChange",(()=>{this.allOnPageSelected()?e.checked=!0:e.checked=!1}))}}renderRecords(){if(!this.rendered)return;const e=this.shadowRoot.getElementById("records");e.innerHTML="";const t=(this.currentPage-1)*this.pageSize,n=t+this.pageSize,s=this.records.slice(t,n);let r=!1;s.forEach(((n,s)=>{const i=document.createElement("tr");if(this.enableSelection){const e=document.createElement("td");e.classList.add("selection");const n=document.createElement("input");n.type="checkbox",n.checked=this.selectedIndexes.includes(t+s),n.addEventListener("change",(()=>{n.checked?this.selectedIndexes.push(t+s):this.selectedIndexes=this.selectedIndexes.filter((e=>e!==t+s)),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})})),e.appendChild(n),i.appendChild(e)}if(this.controls?.before?.length&&i.appendChild(this.renderRowControls(this.controls.before,n,t+s)),null===n){const e=document.createElement("td");e.colSpan=this.fields.length,e.innerHTML="<i>Loading...</i>",r=!0,i.appendChild(e)}else this.fields.forEach((({name:e,formatter:t,calculator:s},r)=>{const o=document.createElement("td");let d;s?d=s(n,this):(d=n[e]||"",Array.isArray(d)?d=t?d.map(t).join(", "):d.join(", "):t&&(d=t(d))),o.innerHTML=d,i.appendChild(o)}));this.controls?.after?.length&&i.appendChild(this.renderRowControls(this.controls.after,n,t+s)),e.appendChild(i)})),r&&dispatchEvent(this,"fetchRecords",{start:t,end:n})}renderRowControls(e=[],t,n){if(!this.rendered)return;const s=document.createElement("td");return e.forEach((({html:e,icon:r,action:i,render:o})=>{if(e)s.appendChild(document.createRange().createContextualFragment(e));else if(o&&"function"==typeof o){const e=o(this,t,n);e instanceof HTMLElement?s.appendChild(e):"string"==typeof e&&s.appendChild(document.createRange().createContextualFragment(e))}else if(r){const e=document.createElement("button");e.classList.add("pq","no-btn"),e.appendChild(new Icon(r)),i&&onEvent(e,"click",(()=>i(this,t,n))),s.appendChild(e)}})),s}renderControls(e=[],t){if(!this.rendered)return;const n=this.shadowRoot.getElementById(t);n.innerHTML="",e.forEach((({html:e,icon:t,action:s,render:r})=>{if(e)n.appendChild(document.createRange().createContextualFragment(e));else if(r&&"function"==typeof r){const e=r(this);e instanceof HTMLElement?n.appendChild(e):"string"==typeof e&&n.appendChild(document.createRange().createContextualFragment(e))}else if(t){const e=document.createElement("button");e.classList.add("pq","no-btn"),e.appendChild(new Icon(t)),s&&onEvent(e,"click",(()=>s(this))),n.appendChild(e)}}))}getCurrentPage(){return this.currentPage}getTotalPages(){return Math.ceil(this.records.length/this.pageSize)}setPage(e){e<1||e>this.getTotalPages()||(this.currentPage=e,this.renderRecords(),dispatchEvent(this,"pageChange"))}nextPage(){this.currentPage<this.getTotalPages()&&this.setPage(this.currentPage+1)}prevPage(){this.currentPage>1&&this.setPage(this.currentPage-1)}setPageSize(e){this.pageSize=e,this.currentPage=1,this.renderRecords(),dispatchEvent(this,"pageSizeChange")}setData({records:e=!1,fields:t=!1,controls:n=!1,pageSize:s=!1,pageSizeOptions:r=!1,currentPage:i=!1,enableSelection:o=!1}={}){let d=!1,c=!1;e&&(this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),d=!0),s&&(this.pageSize=s,d=!0),r&&(this.pageSizeOptions=r),n&&(this.controls=n,c=!0),i&&(this.currentPage=i,d=!0),void 0!==o&&(this.enableSelection=o,d=!0),d&&(this.renderFields(),this.renderRecords()),c&&(this.renderControls(this.controls.top,"top"),this.renderControls(this.controls.bottom,"bottom"))}setRecords(e){this.records=e,this.currentPage=1,this.renderRecords(),dispatchEvent(this,"recordsSet",{records:e})}setupFetchRecords(e,t){const n=this.records.length;n<e&&(this.records.length=e,this.records.fill(null,n)),onEvent(this,"fetchRecords",(async e=>{const{start:n,end:s}=e.detail,r=await t(n,s-n);this.records.splice(n,r.length,...r),this.renderRecords()}))}addRecord(e){this.records.push(e),this.renderRecords(),dispatchEvent(this,"recordAdded",{record:e})}updateRecord(e,t){this.records[e]=t;const n=(this.currentPage-1)*this.pageSize,s=n+this.pageSize;e>=n&&e<s&&this.renderRecords()}deleteRecord(e){e>=0&&e<this.records.length&&(this.selectedIndexes=this.selectedIndexes.filter((t=>t!==e)),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes}),this.records.splice(e,1),this.renderRecords(),dispatchEvent(this,"recordDeleted",{index:e}))}getSelectedRecords(){return this.selectedIndexes.map((e=>this.records[e]))}selectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let n=e;n<t;n++)this.selectedIndexes.includes(n)||this.selectedIndexes.push(n);this.renderRecords(),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})}deselectAllOnPage(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);this.selectedIndexes=this.selectedIndexes.filter((n=>n<e||n>=t)),this.renderRecords(),dispatchEvent(this,"selectionChange",{selectedIndexes:this.selectedIndexes})}allOnPageSelected(){const e=(this.currentPage-1)*this.pageSize,t=Math.min(e+this.pageSize,this.records.length);for(let n=e;n<t;n++)if(!this.selectedIndexes.includes(n))return!1;return!0}get shadowTemplate(){return`\n ${super.shadowTemplate}\n <div class="responsive-table">\n <div id="top"></div>\n <table class="b0">\n <thead id="fields"></thead>\n <tbody id="records"></tbody>\n </table>\n <div id="bottom"></div>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n margin-bottom: var(--spacer);\n border: 1px solid var(--c_border);\n border-radius: var(--radius);\n }\n #top, #bottom {\n display: flex;\n }\n th {\n border-top: none;\n }\n tr:last-child td:first-child {\n border-bottom-left-radius: 0;\n }\n tr:last-child td:last-child {\n border-bottom-right-radius: 0;\n }\n tr:last-child td {\n border-bottom: none;\n }\n th:first-child, td:first-child {\n border-left: none;\n }\n th:last-child, td:last-child {\n border-right: none;\n }\n #top:not(:empty) {\n border-bottom: 1px solid var(--c_border);\n }\n #bottom:not(:empty) {\n border-top: 1px solid var(--c_border);\n }\n th.selection, td.selection {\n width: 50px;\n }\n th.selection input,\n td.selection input {\n margin: 0;\n width: 1.35rem;\n height: 1.35rem;\n }\n `}static extractFieldsFromRecords(e,t=100){const n=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>n.add(e)))})),[...n].map((e=>({name:e,label:toTitleCase(e)})))}}window.customElements.define("k-table",Table);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kempo",
3
- "version": "2.9.1",
3
+ "version": "2.9.2",
4
4
  "type": "module",
5
5
  "description": "A web component library",
6
6
  "main": "dist/index.js",
@@ -127,6 +127,7 @@ export default class Table extends Component {
127
127
  const start = (this.currentPage - 1) * this.pageSize;
128
128
  const end = start + this.pageSize;
129
129
  const paginatedRecords = this.records.slice(start, end);
130
+ let fetchRecords = false;
130
131
  paginatedRecords.forEach((record, index) => {
131
132
  const $tr = document.createElement('tr');
132
133
  if (this.enableSelection) {
@@ -149,12 +150,15 @@ export default class Table extends Component {
149
150
  if(this.controls?.before?.length){
150
151
  $tr.appendChild(this.renderRowControls(this.controls.before, record, start + index));
151
152
  }
152
- this.fields.forEach(({name, formatter, calculator}) => {
153
+ if(record === null){
153
154
  const $td = document.createElement('td');
154
- if (record === null) {
155
- $td.innerHTML = 'Loading...';
156
- dispatchEvent(this, 'fetchRecords', { start, end });
157
- } else {
155
+ $td.colSpan = this.fields.length;
156
+ $td.innerHTML = '<i>Loading...</i>';
157
+ fetchRecords = true;
158
+ $tr.appendChild($td);
159
+ } else {
160
+ this.fields.forEach(({name, formatter, calculator}, index) => {
161
+ const $td = document.createElement('td');
158
162
  let value;
159
163
  if(calculator){
160
164
  value = calculator(record, this);
@@ -173,14 +177,17 @@ export default class Table extends Component {
173
177
  }
174
178
  }
175
179
  $td.innerHTML = value;
176
- }
177
- $tr.appendChild($td);
178
- });
180
+ $tr.appendChild($td);
181
+ });
182
+ }
179
183
  if(this.controls?.after?.length){
180
184
  $tr.appendChild(this.renderRowControls(this.controls.after, record, start + index));
181
185
  }
182
186
  $records.appendChild($tr);
183
187
  });
188
+ if(fetchRecords){
189
+ dispatchEvent(this, 'fetchRecords', { start, end });
190
+ }
184
191
  }
185
192
 
186
193
  renderRowControls(controls = [], record, index) {