kempo 2.5.1 → 2.6.1

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";const cache={},getIconByPath=async t=>(cache[t]||(cache[t]=new Promise((async(e,n)=>{try{const n=await fetch(t);200===n.status&&e(await n.text())}catch(t){}return n()}))),await cache[t]),getIconByName=t=>{const e=async e=>getIconByPath(`${e}/${t}.svg`);return new Promise((async(t,n)=>{let s;for(let t=0;t<Icon.pathToIcons.length&&!s;t++)s=await e(Icon.pathToIcons[t]);s?t(s):n("Icon not found")}))};export default class Icon extends Component{constructor(){super(),this.registerAttributes({src:"",name:""})}connectedCallback(){}async render(t){if(await super.render(t)){if(this.src){const t=await getIconByPath(this.src);t?(this.innerHTML=t,this.fixSVG()):this.innerHTML.length||(this.innerHTML=Icon.fallback)}else if(this.name){const t=await getIconByName(this.name);t?(this.innerHTML=t,this.fixSVG()):this.innerHTML.length||(this.innerHTML=Icon.fallback)}else this.rendered=!1,this.innerHTML.length||(this.innerHTML=Icon.fallback);return!0}return!1}attributeChangedCallback(t,e,n){super.attributeChangedCallback(t,e,n),["src","name"].includes(t)&&n&&this.render(!0)}fixSVG(){const t=this.querySelector("svg");t.removeAttribute("width"),t.removeAttribute("height"),t.querySelectorAll("path, rect, circle").forEach((t=>{t.setAttribute("fill","currentColor")}))}get shadowStyles(){return"\n :host {\n display: inline-block;\n vertical-align: bottom;\n }\n ::slotted(svg){\n height: 1.35em;\n vertical-align: middle;\n }\n "}static observedAttributes=["name","src"];static pathToIcons=["/icons"];static fallback='\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currnetColor" d="M480-79q-16 0-30.5-6T423-102L102-423q-11-12-17-26.5T79-480q0-16 6-31t17-26l321-321q12-12 26.5-17.5T480-881q16 0 31 5.5t26 17.5l321 321q12 11 17.5 26t5.5 31q0 16-5.5 30.5T858-423L537-102q-11 11-26 17t-31 6Zm0-80 321-321-321-321-321 321 321 321Zm-40-281h80v-240h-80v240Zm40 120q17 0 28.5-11.5T520-360q0-17-11.5-28.5T480-400q-17 0-28.5 11.5T440-360q0 17 11.5 28.5T480-320Zm0-160Z"/></svg>\n '}window.customElements.define("k-icon",Icon);
1
+ import Component from"./Component.js";const cache={},getIconByPath=async t=>(cache[t]||(cache[t]=new Promise((async(e,n)=>{try{const n=await fetch(t);200===n.status&&e(await n.text())}catch(t){}return n()}))),await cache[t]),getIconByName=t=>{const e=async e=>getIconByPath(`${e}/${t}.svg`);return new Promise((async(t,n)=>{let s;for(let t=0;t<Icon.pathToIcons.length&&!s;t++)s=await e(Icon.pathToIcons[t]);s?t(s):n("Icon not found")}))};export default class Icon extends Component{constructor(t=""){super(),this.registerAttributes({src:"",name:t})}connectedCallback(){}async render(t){if(await super.render(t)){if(this.src){const t=await getIconByPath(this.src);t?(this.innerHTML=t,this.fixSVG()):this.innerHTML.length||(this.innerHTML=Icon.fallback)}else if(this.name){const t=await getIconByName(this.name);t?(this.innerHTML=t,this.fixSVG()):this.innerHTML.length||(this.innerHTML=Icon.fallback)}else this.rendered=!1,this.innerHTML.length||(this.innerHTML=Icon.fallback);return!0}return!1}attributeChangedCallback(t,e,n){super.attributeChangedCallback(t,e,n),["src","name"].includes(t)&&n&&this.render(!0)}fixSVG(){const t=this.querySelector("svg");t.removeAttribute("width"),t.removeAttribute("height"),t.querySelectorAll("path, rect, circle").forEach((t=>{t.setAttribute("fill","currentColor")}))}get shadowStyles(){return"\n :host {\n display: inline-block;\n vertical-align: bottom;\n }\n ::slotted(svg){\n height: 1.35em;\n vertical-align: middle;\n }\n "}static observedAttributes=["name","src"];static pathToIcons=["/icons"];static fallback='\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currnetColor" d="M480-79q-16 0-30.5-6T423-102L102-423q-11-12-17-26.5T79-480q0-16 6-31t17-26l321-321q12-12 26.5-17.5T480-881q16 0 31 5.5t26 17.5l321 321q12 11 17.5 26t5.5 31q0 16-5.5 30.5T858-423L537-102q-11 11-26 17t-31 6Zm0-80 321-321-321-321-321 321 321 321Zm-40-281h80v-240h-80v240Zm40 120q17 0 28.5-11.5T520-360q0-17-11.5-28.5T480-400q-17 0-28.5 11.5T440-360q0 17 11.5 28.5T480-320Zm0-160Z"/></svg>\n '}window.customElements.define("k-icon",Icon);
@@ -1 +1 @@
1
- import Component from"./Component.js";import{toTitleCase}from"../utils/string.js";export default class Table extends Component{constructor(e=!1,t=!1){super(),this.registerProps({fields:[],records:[]}),e&&this.setData(e,t)}async render(e){return!!await super.render(e)&&(this.renderFields(),this.renderRecords(),!0)}renderFields(){this.shadowRoot.getElementById("fields").innerHTML=this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}renderRecords(){this.shadowRoot.getElementById("records").innerHTML=this.records.map((e=>`<tr>${this.fields.map((({name:t})=>`<td>${e[t]||""}</td>`)).join("")}</tr>`)).join("")}setData(e,t=!1){this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),this.renderFields(),this.renderRecords()}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 s=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>s.add(e)))})),[...s].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,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((({icon:e,action:r})=>{const s=document.createElement("button"),o=new Icon(e);return s.appendChild(o),s.addEventListener("click",(()=>r(t,this))),s.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()}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);
@@ -22,14 +22,16 @@
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="#arrays">Displaying Arrays</a><br />
26
+ <a href="#controls">Row Controls</a><br />
25
27
  </div>
26
28
  </details>
27
29
 
28
30
  <h3>Description</h3>
29
- <p>The <code>&lt;k-table></code> component is used to render data into a <code>&lt;table></code> using JavaScript.</p>
31
+ <p>The <code>&lt;k-table&gt;</code> component is used to render data into a <code>&lt;table&gt;</code> using JavaScript.</p>
30
32
 
31
33
  <h3 id="basicUsage"><a href="#basicUsage" class="no-link">Basic Usage</a></h3>
32
- <p>In HTML create a <code>&lt;k-table></code>, and then in JavaScript call the <code>setData</code> method passing in an array of objects containing your data.</p>
34
+ <p>In HTML create a <code>&lt;k-table&gt;</code>, and then in JavaScript call the <code>setData</code> method passing in an array of objects containing your data.</p>
33
35
 
34
36
  <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">"contacts"</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-built_in">document</span>.getElementById(<span class="hljs-string">'contacts'</span>).setData([<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Dustin"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(111) 111-1111"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"dustin@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Male"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Kayla"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(222) 222-2222"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"kayla@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Female"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Alexander"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(333) 333-33333"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"alex@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Male"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Amelia"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(444) 444-44444"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"amelia@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Female"</span><br /> },<br /> ]);<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
35
37
  <script type="module" src="../kempo/components/Table.js"></script>
@@ -59,7 +61,7 @@
59
61
  phoneNumber: "(444) 444-44444",
60
62
  emailAddress: "amelia@mailserver.com",
61
63
  gender: "Female"
62
- },
64
+ }
63
65
  ]);
64
66
  </script>
65
67
 
@@ -107,20 +109,75 @@
107
109
  ]);
108
110
  </script>
109
111
 
110
- <h3 id="constructor"><a href="#consttructor" class="no-link">Constructor</a></h3>
112
+ <h3 id="arrays"><a href="#arrays" class="no-link">Displaying Arrays</a></h3>
113
+ <p>The table component can display arrays of strings or numbers by joining them with a comma and a space.</p>
114
+ <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">"hobbies"</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-built_in">document</span>.getElementById(<span class="hljs-string">'hobbies'</span>).setData([<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Dustin"</span>,<br /> <span class="hljs-attr">hobbies</span>: [<span class="hljs-string">"Reading"</span>, <span class="hljs-string">"Hiking"</span>, <span class="hljs-string">"Gaming"</span>]<br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Kayla"</span>,<br /> <span class="hljs-attr">hobbies</span>: [<span class="hljs-string">"Cooking"</span>, <span class="hljs-string">"Traveling"</span>]<br /> }<br /> ]);<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
115
+ <k-table id="hobbies"></k-table>
116
+ <script type="module">
117
+ document.getElementById('hobbies').setData([
118
+ {
119
+ name: "Dustin",
120
+ hobbies: ["Reading", "Hiking", "Gaming"]
121
+ },
122
+ {
123
+ name: "Kayla",
124
+ hobbies: ["Cooking", "Traveling"]
125
+ }
126
+ ]);
127
+ </script>
128
+
129
+ <h3 id="controls"><a href="#controls" class="no-link">Row Controls</a></h3>
130
+ <p>The table component can display controls before or after each row. Each control is defined by an icon name and a callback function. All controls are combined into a single <code>&lt;td&gt;</code> with each control being a button.</p>
131
+ <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">"contacts"</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-built_in">document</span>.getElementById(<span class="hljs-string">'contacts'</span>).setData([<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Dustin"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(111) 111-1111"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"dustin@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Male"</span><br /> },<br /> {<br /> <span class="hljs-attr">name</span>: <span class="hljs-string">"Kayla"</span>,<br /> <span class="hljs-attr">phoneNumber</span>: <span class="hljs-string">"(222) 222-2222"</span>,<br /> <span class="hljs-attr">emailAddress</span>: <span class="hljs-string">"kayla@mailserver.com"</span>,<br /> <span class="hljs-attr">gender</span>: <span class="hljs-string">"Female"</span><br /> }<br /> ], false, {<br /> before: [<br /> {<br /> icon: 'edit',<br /> action: (record, table) => console.log('Edit', record, table)<br /> }<br /> ],<br /> after: [<br /> {<br /> icon: 'delete',<br /> action: (record, table) => console.log('Delete', record, table)<br /> }<br /> ]<br /> });<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
132
+ <k-table id="contacts2"></k-table>
133
+ <script type="module">
134
+ document.getElementById('contacts2').setData([
135
+ {
136
+ name: "Dustin",
137
+ phoneNumber: "(111) 111-1111",
138
+ emailAddress: "dustin@mailserver.com",
139
+ gender: "Male"
140
+ },
141
+ {
142
+ name: "Kayla",
143
+ phoneNumber: "(222) 222-2222",
144
+ emailAddress: "kayla@mailserver.com",
145
+ gender: "Female"
146
+ }
147
+ ], false, {
148
+ before: [
149
+ {
150
+ icon: 'edit',
151
+ action: (record, table) => console.log('Edit', record, table)
152
+ }
153
+ ],
154
+ after: [
155
+ {
156
+ icon: 'delete',
157
+ action: (record, table) => console.log('Delete', record, table)
158
+ }
159
+ ]
160
+ });
161
+ </script>
162
+
163
+ <h3 id="constructor"><a href="#constructor" class="no-link">Constructor</a></h3>
111
164
  <h6>Extends <a href="./component.html">Component</a></h6>
112
165
  <h5>
113
166
  <code>new Table()</code><br />
114
167
  <code>new Table(<i>&lt;Array>object</i> records)</code><br />
115
- <code>new Table(<i>&lt;Array>object</i> records, <i>&lt;Array>object</i> fields)</code>
168
+ <code>new Table(<i>&lt;Array>object</i> records, <i>&lt;Array>object</i> fields)</code><br />
169
+ <code>new Table(<i>&lt;Array>object</i> records, <i>&lt;Array>object</i> fields, <i>object</i> controls)</code>
116
170
  </h5>
117
171
 
118
- <h4>Paramters</h4>
172
+ <h4>Parameters</h4>
119
173
  <h5><code><i>&lt;Array>object</i> records</code></h5>
120
174
  <p>An array of objects that represent the records to be shown in the table.</p>
121
175
 
122
176
  <h5><code><i>&lt;Array>object</i> fields</code></h5>
123
- <p>An array of objects that represents the feilds of the table, each object must contain a <code>name</code> and a <code>label</code>. If this parameter is ommitted the fields will be automatically generated from the first 100 records.</p>
177
+ <p>An array of objects that represents the fields of the table, each object must contain a <code>name</code> and a <code>label</code>. If this parameter is omitted, the fields will be automatically generated from the first 100 records.</p>
178
+
179
+ <h5><code><i>object</i> controls</code></h5>
180
+ <p>An object containing arrays of controls to be displayed before and/or after each row. Each control is defined by an icon name and a callback function. The <code>controls</code> object can only contain the <code>before</code> and <code>after</code> properties, which are arrays of objects containing the <code>icon</code> (string) and <code>action</code> (function).</p>
124
181
 
125
182
  <h3 id="requirements"><a href="#requirements" class="no-link">Requirements</a></h3>
126
183
  <ul>
@@ -134,6 +191,24 @@
134
191
  <h5><code>records<i>: &lt;Array>object</i></code></h5>
135
192
  <p>An array of objects containing the data that will be the records of the table, where the object keys match the field names.</p>
136
193
 
194
+ <h5><code>controls<i>: object</i></code></h5>
195
+ <p>An object containing arrays of controls to be displayed before and/or after each row. Each control is defined by an icon name and a callback function. The <code>controls</code> object can only contain the <code>before</code> and <code>after</code> properties, which are arrays of objects containing the <code>icon</code> (string) and <code>action</code> (function).</p>
196
+ <p>Example:</p>
197
+ <pre><code class="hljs javascript">{
198
+ before: [
199
+ {
200
+ icon: 'edit',
201
+ action: (record, table) => console.log('Edit', record, table)
202
+ }
203
+ ],
204
+ after: [
205
+ {
206
+ icon: 'delete',
207
+ action: (record, table) => console.log('Delete', record, table)
208
+ }
209
+ ]
210
+ }</code></pre>
211
+
137
212
  <h3 id="methods"><a href="#methods" class="no-link">Methods</a></h3>
138
213
 
139
214
  <h5><code>setData(<i>&lt;Array>object</i> records, <i>&lt;Array>object</i> fields)<i>: undefined</i></code></h5>
@@ -143,7 +218,10 @@
143
218
  <p>Renders the fields as table headers, this is called automatically by setData, you should never have to call it.</p>
144
219
 
145
220
  <h5><code>renderRecords()<i>: undefined</i></code></h5>
146
- <p>Renders the records as table row, this is called automatically by setData, you should never have to call it.</p>
221
+ <p>Renders the records as table rows, this is called automatically by setData, you should never have to call it.</p>
222
+
223
+ <h5><code>renderControls(<i>&lt;Array>object</i> controls, <i>object</i> record)<i>: string</i></code></h5>
224
+ <p>Renders the controls as table cells. Each control is defined by an icon name and a callback function. This is called automatically by renderRecords, you should never have to call it.</p>
147
225
 
148
226
  </main>
149
227
  <div style="height: 33.333vh"></div>
@@ -1 +1 @@
1
- import Component from"./Component.js";const cache={},getIconByPath=async t=>(cache[t]||(cache[t]=new Promise((async(e,n)=>{try{const n=await fetch(t);200===n.status&&e(await n.text())}catch(t){}return n()}))),await cache[t]),getIconByName=t=>{const e=async e=>getIconByPath(`${e}/${t}.svg`);return new Promise((async(t,n)=>{let s;for(let t=0;t<Icon.pathToIcons.length&&!s;t++)s=await e(Icon.pathToIcons[t]);s?t(s):n("Icon not found")}))};export default class Icon extends Component{constructor(){super(),this.registerAttributes({src:"",name:""})}connectedCallback(){}async render(t){if(await super.render(t)){if(this.src){const t=await getIconByPath(this.src);t?(this.innerHTML=t,this.fixSVG()):this.innerHTML.length||(this.innerHTML=Icon.fallback)}else if(this.name){const t=await getIconByName(this.name);t?(this.innerHTML=t,this.fixSVG()):this.innerHTML.length||(this.innerHTML=Icon.fallback)}else this.rendered=!1,this.innerHTML.length||(this.innerHTML=Icon.fallback);return!0}return!1}attributeChangedCallback(t,e,n){super.attributeChangedCallback(t,e,n),["src","name"].includes(t)&&n&&this.render(!0)}fixSVG(){const t=this.querySelector("svg");t.removeAttribute("width"),t.removeAttribute("height"),t.querySelectorAll("path, rect, circle").forEach((t=>{t.setAttribute("fill","currentColor")}))}get shadowStyles(){return"\n :host {\n display: inline-block;\n vertical-align: bottom;\n }\n ::slotted(svg){\n height: 1.35em;\n vertical-align: middle;\n }\n "}static observedAttributes=["name","src"];static pathToIcons=["/icons"];static fallback='\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currnetColor" d="M480-79q-16 0-30.5-6T423-102L102-423q-11-12-17-26.5T79-480q0-16 6-31t17-26l321-321q12-12 26.5-17.5T480-881q16 0 31 5.5t26 17.5l321 321q12 11 17.5 26t5.5 31q0 16-5.5 30.5T858-423L537-102q-11 11-26 17t-31 6Zm0-80 321-321-321-321-321 321 321 321Zm-40-281h80v-240h-80v240Zm40 120q17 0 28.5-11.5T520-360q0-17-11.5-28.5T480-400q-17 0-28.5 11.5T440-360q0 17 11.5 28.5T480-320Zm0-160Z"/></svg>\n '}window.customElements.define("k-icon",Icon);
1
+ import Component from"./Component.js";const cache={},getIconByPath=async t=>(cache[t]||(cache[t]=new Promise((async(e,n)=>{try{const n=await fetch(t);200===n.status&&e(await n.text())}catch(t){}return n()}))),await cache[t]),getIconByName=t=>{const e=async e=>getIconByPath(`${e}/${t}.svg`);return new Promise((async(t,n)=>{let s;for(let t=0;t<Icon.pathToIcons.length&&!s;t++)s=await e(Icon.pathToIcons[t]);s?t(s):n("Icon not found")}))};export default class Icon extends Component{constructor(t=""){super(),this.registerAttributes({src:"",name:t})}connectedCallback(){}async render(t){if(await super.render(t)){if(this.src){const t=await getIconByPath(this.src);t?(this.innerHTML=t,this.fixSVG()):this.innerHTML.length||(this.innerHTML=Icon.fallback)}else if(this.name){const t=await getIconByName(this.name);t?(this.innerHTML=t,this.fixSVG()):this.innerHTML.length||(this.innerHTML=Icon.fallback)}else this.rendered=!1,this.innerHTML.length||(this.innerHTML=Icon.fallback);return!0}return!1}attributeChangedCallback(t,e,n){super.attributeChangedCallback(t,e,n),["src","name"].includes(t)&&n&&this.render(!0)}fixSVG(){const t=this.querySelector("svg");t.removeAttribute("width"),t.removeAttribute("height"),t.querySelectorAll("path, rect, circle").forEach((t=>{t.setAttribute("fill","currentColor")}))}get shadowStyles(){return"\n :host {\n display: inline-block;\n vertical-align: bottom;\n }\n ::slotted(svg){\n height: 1.35em;\n vertical-align: middle;\n }\n "}static observedAttributes=["name","src"];static pathToIcons=["/icons"];static fallback='\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currnetColor" d="M480-79q-16 0-30.5-6T423-102L102-423q-11-12-17-26.5T79-480q0-16 6-31t17-26l321-321q12-12 26.5-17.5T480-881q16 0 31 5.5t26 17.5l321 321q12 11 17.5 26t5.5 31q0 16-5.5 30.5T858-423L537-102q-11 11-26 17t-31 6Zm0-80 321-321-321-321-321 321 321 321Zm-40-281h80v-240h-80v240Zm40 120q17 0 28.5-11.5T520-360q0-17-11.5-28.5T480-400q-17 0-28.5 11.5T440-360q0 17 11.5 28.5T480-320Zm0-160Z"/></svg>\n '}window.customElements.define("k-icon",Icon);
@@ -1 +1 @@
1
- import Component from"./Component.js";import{toTitleCase}from"../utils/string.js";export default class Table extends Component{constructor(e=!1,t=!1){super(),this.registerProps({fields:[],records:[]}),e&&this.setData(e,t)}async render(e){return!!await super.render(e)&&(this.renderFields(),this.renderRecords(),!0)}renderFields(){this.shadowRoot.getElementById("fields").innerHTML=this.fields.map((({label:e})=>`<th>${e}</th>`)).join("")}renderRecords(){this.shadowRoot.getElementById("records").innerHTML=this.records.map((e=>`<tr>${this.fields.map((({name:t})=>`<td>${e[t]||""}</td>`)).join("")}</tr>`)).join("")}setData(e,t=!1){this.records=e,this.fields=t||Table.extractFieldsFromRecords(this.records),this.renderFields(),this.renderRecords()}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 s=new Set;return e.slice(0,t).forEach((e=>{Object.keys(e).forEach((e=>s.add(e)))})),[...s].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,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((({icon:e,action:r})=>{const s=document.createElement("button"),o=new Icon(e);return s.appendChild(o),s.addEventListener("click",(()=>r(t,this))),s.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()}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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kempo",
3
- "version": "2.5.1",
3
+ "version": "2.6.1",
4
4
  "type": "module",
5
5
  "description": "A web component library",
6
6
  "main": "dist/index.js",
@@ -8,7 +8,7 @@ const getIconByPath = async (path) => {
8
8
  try {
9
9
  const response = await fetch(path);
10
10
  if(response.status === 200) resolve(await (response).text());
11
- } catch(e){ }
11
+ } catch(e){ }
12
12
  return reject();
13
13
  });
14
14
  }
@@ -31,11 +31,11 @@ const getIconByName = (name) => {
31
31
  }
32
32
 
33
33
  export default class Icon extends Component {
34
- constructor(){
34
+ constructor(name = ''){
35
35
  super();
36
36
  this.registerAttributes({
37
37
  src: '',
38
- name: ''
38
+ name: name
39
39
  });
40
40
  }
41
41
  connectedCallback(){
@@ -1,18 +1,20 @@
1
1
  import Component from './Component.js';
2
+ import Icon from './Icon.js'; // Import Icon component
2
3
  import { toTitleCase } from '../utils/string.js';
3
4
 
4
5
  export default class Table extends Component {
5
- constructor(data = false, fields = false){
6
+ constructor(data = false, fields = false, controls = { before: [], after: [] }){
6
7
  super();
7
8
 
8
9
  this.registerProps({
9
10
  fields: [],
10
- records: []
11
+ records: [],
12
+ controls: { before: [], after: [] }
11
13
  });
12
14
 
13
15
  /* Init */
14
16
  if(data){
15
- this.setData(data, fields);
17
+ this.setData(data, fields, controls);
16
18
  }
17
19
  }
18
20
  async render(force){
@@ -24,17 +26,37 @@ export default class Table extends Component {
24
26
  return false;
25
27
  }
26
28
  renderFields(){
27
- this.shadowRoot.getElementById('fields').innerHTML = this.fields.map(({label})=>`<th>${label}</th>`).join('');
29
+ const beforeControls = this.controls.before.length ? '<th></th>' : '';
30
+ const afterControls = this.controls.after.length ? '<th></th>' : '';
31
+ this.shadowRoot.getElementById('fields').innerHTML = `${beforeControls}${this.fields.map(({label})=>`<th>${label}</th>`).join('')}${afterControls}`;
28
32
  }
29
33
  renderRecords(){
30
34
  this.shadowRoot.getElementById('records').innerHTML = this.records.map((record) => {
31
- return `<tr>${this.fields.map(({name})=>`<td>${record[name] || ''}</td>`).join('')}</tr>`;
35
+ return `<tr>${this.renderControls(this.controls.before, record)}${this.fields.map(({name}) => {
36
+ let value = record[name] || '';
37
+ if (Array.isArray(value)) {
38
+ value = value.join(', ');
39
+ }
40
+ return `<td>${value}</td>`;
41
+ }).join('')}${this.renderControls(this.controls.after, record)}</tr>`;
32
42
  }).join('');
33
43
  }
34
44
 
35
- setData(records, fields = false){
45
+ renderControls(controls, record) {
46
+ if (controls.length === 0) return '';
47
+ return `<td>${controls.map(({ icon, action }) => {
48
+ const button = document.createElement('button');
49
+ const iconElement = new Icon(icon); // Pass icon name as parameter
50
+ button.appendChild(iconElement);
51
+ button.addEventListener('click', () => action(record, this));
52
+ return button.outerHTML;
53
+ }).join('')}</td>`;
54
+ }
55
+
56
+ setData(records, fields = false, controls = { before: [], after: [] }){
36
57
  this.records = records;
37
58
  this.fields = fields || Table.extractFieldsFromRecords(this.records);
59
+ this.controls = controls;
38
60
  this.renderFields();
39
61
  this.renderRecords();
40
62
  }