kempo 2.7.1 → 2.7.3

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{toTitleCase}from"../utils/string.js";export default class Table extends Component{constructor(e=!1,t=!1,r={before:[],after:[]}){super(),this.registerProps({fields:[],records:[],controls:{before:[],after:[]}}),e&&this.setData(e,t,r)}async render(e){return!!await super.render(e)&&(this.renderFields(),this.renderRecords(),!0)}renderFields(){const e=this.controls.before?.length?"<th></th>":"",t=this.controls.after?.length?"<th></th>":"";this.shadowRoot.getElementById("fields").innerHTML=`${e}${this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}${t}`}renderRecords(){this.shadowRoot.getElementById("records").innerHTML=this.records.map((e=>`<tr>${this.renderControls(this.controls.before,e)}${this.fields.map((({name:t})=>{let r=e[t]||"";return Array.isArray(r)&&(r=r.join(", ")),`<td>${r}</td>`})).join("")}${this.renderControls(this.controls.after,e)}</tr>`)).join("")}renderControls(e=[],t){return 0===e.length?"":`<td>${e.map((({html:e,icon:r,action:s,render:n})=>{if(e)return e;if(n&&"function"==typeof n)return n(t,this);{const e=document.createElement("button");e.appendChild(new Icon(r)),s&&e.addEventListener("click",(()=>s(t,this)))}return button.outerHTML})).join("")}</td>`}setData(e,t=!1,r={before:[],after:[]}){this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),this.controls=r,this.renderFields(),this.renderRecords(),this.renderControls()}get shadowTemplate(){return`\n ${super.shadowTemplate}\n <div class="responsive-table">\n <table>\n <thead id="fields"></thead>\n <tbody id="records"></tbody>\n </table>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n margin-bottom: var(--spacer);\n }\n `}static extractFieldsFromRecords(e,t=100){const r=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>r.add(e)))})),[...r].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{toTitleCase}from"../utils/string.js";export default class Table extends Component{constructor(e=!1,t=!1,o={before:[],after:[],top:[],bottom:[]}){super(),this.registerProps({fields:[],records:[],controls:{before:[],after:[],top:[],bottom:[]}}),e&&this.setData(e,t,o)}async render(e){return!!await super.render(e)&&(this.renderControls(this.controls.top,"top"),this.renderFields(),this.renderRecords(),this.renderControls(this.controls.bottom,"bottom"),!0)}renderFields(){const e=this.controls?.before?.length?"<th></th>":"",t=this.controls?.after?.length?"<th></th>":"";this.shadowRoot.getElementById("fields").innerHTML=`${e}${this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}${t}`}renderRecords(){const e=this.shadowRoot.getElementById("records");e.innerHTML="",this.records.forEach((t=>{const o=document.createElement("tr");this.controls?.before?.length&&o.appendChild(this.renderRowControls(this.controls.before,t)),this.fields.forEach((({name:e})=>{const n=document.createElement("td");let r=t[e]||"";Array.isArray(r)&&(r=r.join(", ")),n.innerHTML=r,o.appendChild(n)})),this.controls?.after?.length&&o.appendChild(this.renderRowControls(this.controls.after,t)),e.appendChild(o)}))}renderRowControls(e=[],t){const o=document.createElement("td");return e.forEach((({html:e,icon:n,action:r,render:s})=>{if(e)o.appendChild(document.createRange().createContextualFragment(e));else if(s&&"function"==typeof s){const e=s(this,t);e instanceof HTMLElement?o.appendChild(e):"string"==typeof e&&o.appendChild(document.createRange().createContextualFragment(e))}else if(n){const e=document.createElement("button");e.appendChild(new Icon(n)),r&&e.addEventListener("click",(()=>r(this,t))),o.appendChild(e)}})),o}renderControls(e=[],t){const o=document.createElement("div");e.forEach((({html:e,icon:t,action:n,render:r})=>{if(e)o.appendChild(document.createRange().createContextualFragment(e));else if(r&&"function"==typeof r){const e=r(this);e instanceof HTMLElement?o.appendChild(e):"string"==typeof e&&o.appendChild(document.createRange().createContextualFragment(e))}else if(t){const e=document.createElement("button");e.appendChild(new Icon(t)),n&&e.addEventListener("click",(()=>n(this))),o.appendChild(e)}})),this.shadowRoot.getElementById(t).innerHTML="",this.shadowRoot.getElementById(t).appendChild(o)}setData(e,t=!1,o={before:[],after:[],top:[],bottom:[]}){this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),this.controls=o,this.renderControls(this.controls.top,"top"),this.renderFields(),this.renderRecords(),this.renderControls(this.controls.bottom,"bottom")}get shadowTemplate(){return`\n ${super.shadowTemplate}\n <div class="responsive-table">\n <div id="top"></div>\n <table>\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 }\n `}static extractFieldsFromRecords(e,t=100){const o=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>o.add(e)))})),[...o].map((e=>({name:e,label:toTitleCase(e)})))}}window.customElements.define("k-table",Table);
@@ -22,6 +22,7 @@
22
22
  <a href="#requirements">Requirements</a><br />
23
23
  <a href="#properties">Properties</a><br />
24
24
  <a href="#methods">Methods</a><br />
25
+ <a href="#controls">Row Controls</a><br />
25
26
  </div>
26
27
  </details>
27
28
 
@@ -107,6 +108,59 @@
107
108
  ]);
108
109
  </script>
109
110
 
111
+ <h3 id="controls"><a href="#controls" class="no-link">Row Controls</a></h3>
112
+ <p>The table component can display controls before or after each row. Each control is defined by an icon name, a callback function, and optionally an HTML string or a render function. All controls are combined into a single <code>&lt;td&gt;</code> with each control being a button.</p>
113
+
114
+
115
+ <k-table id="contacts2"></k-table>
116
+ <script type="module">
117
+ document.getElementById('contacts2').setData([
118
+ {
119
+ name: "Dustin",
120
+ phoneNumber: "(111) 111-1111",
121
+ emailAddress: "dustin@mailserver.com",
122
+ gender: "Male"
123
+ },
124
+ {
125
+ name: "Kayla",
126
+ phoneNumber: "(222) 222-2222",
127
+ emailAddress: "kayla@mailserver.com",
128
+ gender: "Female"
129
+ }
130
+ ], false, {
131
+ before: [
132
+ {
133
+ icon: 'edit',
134
+ action: (table, record) => console.log('Edit', table, record)
135
+ }
136
+ ],
137
+ after: [
138
+ {
139
+ icon: 'delete',
140
+ action: (table, record) => console.log('Delete', table, record)
141
+ },
142
+ {
143
+ html: '<span>Custom HTML</span>'
144
+ },
145
+ {
146
+ render: (table, record) => `<a href="mailto:${record.emailAddress}">Email</a>`
147
+ }
148
+ ],
149
+ top: [
150
+ {
151
+ icon: 'add',
152
+ action: (table) => console.log('Add', table)
153
+ }
154
+ ],
155
+ bottom: [
156
+ {
157
+ icon: 'refresh',
158
+ action: (table) => console.log('Refresh', table)
159
+ }
160
+ ]
161
+ });
162
+ </script>
163
+
110
164
  <h3 id="constructor"><a href="#consttructor" class="no-link">Constructor</a></h3>
111
165
  <h6>Extends <a href="./component.html">Component</a></h6>
112
166
  <h5>
@@ -150,11 +204,10 @@
150
204
  action: (record, table) => console.log('Delete', record, table)
151
205
  },
152
206
  {
153
- html: '<span>Custom HTML</span>',
154
- action: (record, table) => console.log('Custom Action', record, table)
207
+ html: '<span>Custom HTML</span>'
155
208
  },
156
209
  {
157
- render: (record, table) => `<button onclick="console.log('Rendered Action', ${record}, ${table})">Rendered Button</button>`
210
+ render: (record, table) => `&lt;button onclick="console.log('Rendered Action', ${record}, ${table})">Rendered Button&lt;/button>`
158
211
  }
159
212
  ]
160
213
  }</code></pre>
@@ -1 +1 @@
1
- import Component from"./Component.js";import Icon from"./Icon.js";import{toTitleCase}from"../utils/string.js";export default class Table extends Component{constructor(e=!1,t=!1,r={before:[],after:[]}){super(),this.registerProps({fields:[],records:[],controls:{before:[],after:[]}}),e&&this.setData(e,t,r)}async render(e){return!!await super.render(e)&&(this.renderFields(),this.renderRecords(),!0)}renderFields(){const e=this.controls.before?.length?"<th></th>":"",t=this.controls.after?.length?"<th></th>":"";this.shadowRoot.getElementById("fields").innerHTML=`${e}${this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}${t}`}renderRecords(){this.shadowRoot.getElementById("records").innerHTML=this.records.map((e=>`<tr>${this.renderControls(this.controls.before,e)}${this.fields.map((({name:t})=>{let r=e[t]||"";return Array.isArray(r)&&(r=r.join(", ")),`<td>${r}</td>`})).join("")}${this.renderControls(this.controls.after,e)}</tr>`)).join("")}renderControls(e=[],t){return 0===e.length?"":`<td>${e.map((({html:e,icon:r,action:s,render:n})=>{if(e)return e;if(n&&"function"==typeof n)return n(t,this);{const e=document.createElement("button");e.appendChild(new Icon(r)),s&&e.addEventListener("click",(()=>s(t,this)))}return button.outerHTML})).join("")}</td>`}setData(e,t=!1,r={before:[],after:[]}){this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),this.controls=r,this.renderFields(),this.renderRecords(),this.renderControls()}get shadowTemplate(){return`\n ${super.shadowTemplate}\n <div class="responsive-table">\n <table>\n <thead id="fields"></thead>\n <tbody id="records"></tbody>\n </table>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n margin-bottom: var(--spacer);\n }\n `}static extractFieldsFromRecords(e,t=100){const r=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>r.add(e)))})),[...r].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{toTitleCase}from"../utils/string.js";export default class Table extends Component{constructor(e=!1,t=!1,o={before:[],after:[],top:[],bottom:[]}){super(),this.registerProps({fields:[],records:[],controls:{before:[],after:[],top:[],bottom:[]}}),e&&this.setData(e,t,o)}async render(e){return!!await super.render(e)&&(this.renderControls(this.controls.top,"top"),this.renderFields(),this.renderRecords(),this.renderControls(this.controls.bottom,"bottom"),!0)}renderFields(){const e=this.controls?.before?.length?"<th></th>":"",t=this.controls?.after?.length?"<th></th>":"";this.shadowRoot.getElementById("fields").innerHTML=`${e}${this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}${t}`}renderRecords(){const e=this.shadowRoot.getElementById("records");e.innerHTML="",this.records.forEach((t=>{const o=document.createElement("tr");this.controls?.before?.length&&o.appendChild(this.renderRowControls(this.controls.before,t)),this.fields.forEach((({name:e})=>{const n=document.createElement("td");let r=t[e]||"";Array.isArray(r)&&(r=r.join(", ")),n.innerHTML=r,o.appendChild(n)})),this.controls?.after?.length&&o.appendChild(this.renderRowControls(this.controls.after,t)),e.appendChild(o)}))}renderRowControls(e=[],t){const o=document.createElement("td");return e.forEach((({html:e,icon:n,action:r,render:s})=>{if(e)o.appendChild(document.createRange().createContextualFragment(e));else if(s&&"function"==typeof s){const e=s(this,t);e instanceof HTMLElement?o.appendChild(e):"string"==typeof e&&o.appendChild(document.createRange().createContextualFragment(e))}else if(n){const e=document.createElement("button");e.appendChild(new Icon(n)),r&&e.addEventListener("click",(()=>r(this,t))),o.appendChild(e)}})),o}renderControls(e=[],t){const o=document.createElement("div");e.forEach((({html:e,icon:t,action:n,render:r})=>{if(e)o.appendChild(document.createRange().createContextualFragment(e));else if(r&&"function"==typeof r){const e=r(this);e instanceof HTMLElement?o.appendChild(e):"string"==typeof e&&o.appendChild(document.createRange().createContextualFragment(e))}else if(t){const e=document.createElement("button");e.appendChild(new Icon(t)),n&&e.addEventListener("click",(()=>n(this))),o.appendChild(e)}})),this.shadowRoot.getElementById(t).innerHTML="",this.shadowRoot.getElementById(t).appendChild(o)}setData(e,t=!1,o={before:[],after:[],top:[],bottom:[]}){this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),this.controls=o,this.renderControls(this.controls.top,"top"),this.renderFields(),this.renderRecords(),this.renderControls(this.controls.bottom,"bottom")}get shadowTemplate(){return`\n ${super.shadowTemplate}\n <div class="responsive-table">\n <div id="top"></div>\n <table>\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 }\n `}static extractFieldsFromRecords(e,t=100){const o=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>o.add(e)))})),[...o].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.7.1",
3
+ "version": "2.7.3",
4
4
  "type": "module",
5
5
  "description": "A web component library",
6
6
  "main": "dist/index.js",
@@ -3,13 +3,13 @@ import Icon from './Icon.js'; // Import Icon component
3
3
  import { toTitleCase } from '../utils/string.js';
4
4
 
5
5
  export default class Table extends Component {
6
- constructor(data = false, fields = false, controls = { before: [], after: [] }){
6
+ constructor(data = false, fields = false, controls = { before: [], after: [], top: [], bottom: [] }){
7
7
  super();
8
8
 
9
9
  this.registerProps({
10
10
  fields: [],
11
11
  records: [],
12
- controls: { before: [], after: [] }
12
+ controls: { before: [], after: [], top: [], bottom: [] }
13
13
  });
14
14
 
15
15
  /* Init */
@@ -19,64 +19,112 @@ export default class Table extends Component {
19
19
  }
20
20
  async render(force){
21
21
  if(await super.render(force)){
22
+ this.renderControls(this.controls.top, 'top');
22
23
  this.renderFields();
23
24
  this.renderRecords();
25
+ this.renderControls(this.controls.bottom, 'bottom');
24
26
  return true;
25
27
  }
26
28
  return false;
27
29
  }
28
30
  renderFields(){
29
- const beforeControls = this.controls.before?.length ? '<th></th>' : '';
30
- const afterControls = this.controls.after?.length ? '<th></th>' : '';
31
+ const beforeControls = this.controls?.before?.length ? '<th></th>' : '';
32
+ const afterControls = this.controls?.after?.length ? '<th></th>' : '';
31
33
  this.shadowRoot.getElementById('fields').innerHTML = `${beforeControls}${this.fields.map(({label})=>`<th>${label}</th>`).join('')}${afterControls}`;
32
34
  }
33
35
  renderRecords(){
34
- this.shadowRoot.getElementById('records').innerHTML = this.records.map((record) => {
35
- return `<tr>${this.renderControls(this.controls.before, record)}${this.fields.map(({name}) => {
36
+ const $records = this.shadowRoot.getElementById('records');
37
+ $records.innerHTML = '';
38
+ this.records.forEach((record) => {
39
+ const $tr = document.createElement('tr');
40
+ if(this.controls?.before?.length){
41
+ $tr.appendChild(this.renderRowControls(this.controls.before, record));
42
+ }
43
+ this.fields.forEach(({name}) => {
44
+ const $td = document.createElement('td');
36
45
  let value = record[name] || '';
37
46
  if (Array.isArray(value)) {
38
47
  value = value.join(', ');
39
48
  }
40
- return `<td>${value}</td>`;
41
- }).join('')}${this.renderControls(this.controls.after, record)}</tr>`;
42
- }).join('');
49
+ $td.innerHTML = value;
50
+ $tr.appendChild($td);
51
+ });
52
+ if(this.controls?.after?.length){
53
+ $tr.appendChild(this.renderRowControls(this.controls.after, record));
54
+ }
55
+ $records.appendChild($tr);
56
+ });
43
57
  }
44
58
 
45
- renderControls(controls = [], record) {
46
- if (controls.length === 0) return '';
47
- return `<td>${controls.map(({ html, icon, action, render }) => {
59
+ renderRowControls(controls = [], record) {
60
+ const $td = document.createElement('td');
61
+ controls.forEach(({ html, icon, action, render }) => {
62
+ if(html){
63
+ $td.appendChild(document.createRange().createContextualFragment(html));
64
+ } else if(render && typeof(render) === 'function'){
65
+ const rendered = render(this, record);
66
+ if(rendered instanceof HTMLElement){
67
+ $td.appendChild(rendered);
68
+ } else if(typeof(rendered) === 'string'){
69
+ $td.appendChild(document.createRange().createContextualFragment(rendered));
70
+ }
71
+ } else if(icon){
72
+ const $button = document.createElement('button');
73
+ $button.appendChild(new Icon(icon));
74
+ if (action) {
75
+ $button.addEventListener('click', () => action(this, record));
76
+ }
77
+ $td.appendChild($button);
78
+ }
79
+ });
80
+ return $td;
81
+ }
82
+
83
+ renderControls(controls = [], position) {
84
+ const $container = document.createElement('div');
85
+ controls.forEach(({ html, icon, action, render }) => {
48
86
  if(html){
49
- return html;
87
+ $container.appendChild(document.createRange().createContextualFragment(html));
50
88
  } else if(render && typeof(render) === 'function'){
51
- return render(record, this);
52
- } else {
89
+ const rendered = render(this);
90
+ if(rendered instanceof HTMLElement){
91
+ $container.appendChild(rendered);
92
+ } else if(typeof(rendered) === 'string'){
93
+ $container.appendChild(document.createRange().createContextualFragment(rendered));
94
+ }
95
+ } else if(icon){
53
96
  const $button = document.createElement('button');
54
97
  $button.appendChild(new Icon(icon));
55
98
  if (action) {
56
- $button.addEventListener('click', () => action(record, this));
99
+ $button.addEventListener('click', () => action(this));
57
100
  }
101
+ $container.appendChild($button);
58
102
  }
59
- return button.outerHTML;
60
- }).join('')}</td>`;
103
+ });
104
+ this.shadowRoot.getElementById(position).innerHTML = '';
105
+ this.shadowRoot.getElementById(position).appendChild($container);
61
106
  }
62
107
 
63
- setData(records, fields = false, controls = { before: [], after: [] }){
108
+ setData(records, fields = false, controls = { before: [], after: [], top: [], bottom: [] }){
64
109
  this.records = records;
65
110
  this.fields = fields || Table.extractFieldsFromRecords(this.records);
66
111
  this.controls = controls;
112
+ this.renderControls(this.controls.top, 'top');
67
113
  this.renderFields();
68
114
  this.renderRecords();
69
- this.renderControls();
115
+ this.renderControls(this.controls.bottom, 'bottom');
70
116
  }
71
117
 
72
118
  get shadowTemplate(){
73
119
  return /*html*/`
74
120
  ${super.shadowTemplate}
75
121
  <div class="responsive-table">
122
+ <div id="top"></div>
76
123
  <table>
77
124
  <thead id="fields"></thead>
78
125
  <tbody id="records"></tbody>
79
126
  </table>
127
+ <div id="bottom"></div>
80
128
  </div>
81
129
  `;
82
130
  }