kempo 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/DirectoryViewer.js +1 -1
- package/dist/components/Table.js +1 -1
- package/dist/components/ThemeSwitcher.js +1 -1
- package/docs/components/table.html +20 -2
- package/docs/kempo/components/DirectoryViewer.js +1 -1
- package/docs/kempo/components/Table.js +1 -1
- package/docs/kempo/components/ThemeSwitcher.js +1 -1
- package/package.json +1 -1
- package/src/components/DirectoryViewer.js +91 -20
- package/src/components/Table.js +7 -1
- package/src/components/ThemeSwitcher.js +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
import LazyComponent from"./LazyComponent.js";import Component from"./Component.js";import"./Icon.js";import{onEvent,offEvent,dispatchEvent}from"../utils/element.js";import watchDirectoryHandle from"../utils/watchDirectoryHandle.js";const handle=Symbol(),loadDirectoryClickHandler=Symbol(),
|
|
1
|
+
import LazyComponent from"./LazyComponent.js";import Component from"./Component.js";import"./Icon.js";import{onEvent,offEvent,dispatchEvent}from"../utils/element.js";import watchDirectoryHandle from"../utils/watchDirectoryHandle.js";const handle=Symbol(),loadDirectoryClickHandler=Symbol(),selectedHandler=Symbol(),watchId=Symbol(),changeCallback=Symbol(),filters=Symbol();export default class DirectoryViewer extends LazyComponent{constructor(e=!1){super(),this[handle]=e,this[watchId]=!1,this[filters]=[],this[loadDirectoryClickHandler]=()=>this.loadDirectory(),this[openToggleClickHandler]=()=>{this.root?this.clearDirectoryHandle():(this.toggleOpen(),this.select())},this[changeCallback]=()=>{this.updateContents()},this[selectedHandler]=e=>{},this.registerAttributes({hasHandle:!!e,selected:!1})}async render(e){return!!await super.render(e)&&(onEvent(this.shadowRoot,"fileSelected directorySelected",this[selectedHandler]),onEvent(this.shadowRoot.getElementById("loadDirectory"),"click",this[loadDirectoryClickHandler]),this.renderDirectory(),!0)}async renderDirectory(){this[handle]&&this.rendered&&(this.innerHTML=this[handle].name,this.renderContents())}async renderContents(){if(this.querySelectorAll('[slot="content"]').forEach((e=>e.remove())),this.rendered&&this[handle]&&(this.opened||this.root)){for await(const e of this[handle].values())"directory"===e.kind&&this.filters.every((t=>t(e)))&&this.appendChild(new DirectoryViewer(e,!1));for await(const e of this[handle].values())"file"===e.kind&&this.filters.every((t=>t(e)))&&this.appendChild(new File(e));this[watchId]||(this[watchId]=watchDirectoryHandle(this[handle],this[changeCallback]))}else this[watchId]&&(clearInterval(this[watchId]),this[watchId]=!1)}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot,"fileselected",this[fileSelectedHandler]),offEvent(this.shadowRoot.getElementById("loadDirectory"),"click",this[loadDirectoryClickHandler]),offEvent(this.shadowRoot.getElementById("openToggle"),"click",this[openToggleClickHandler])}attributeChangedCallback(e,t,n){"opened"===e&&t!==n&&(!n&&this.root?this.opened=!0:this.renderContents())}get rootDir(){return this.root?this:this.closest('k-directory-viewer[root="true"]')}get filters(){return this.rootDir[filters]}async loadDirectory(){window.showDirectoryPicker&&(this[handle]=await window.showDirectoryPicker(),this[handle]&&(this.hasHandle=!0,dispatchEvent(this,"directoryloaded",{dirHandle:this[handle],dirComponent:this}),this.renderDirectory()))}clearDirectoryHandle(){this[handle]=!1,this.hasHandle=!1,this.innerHTML=""}async updateContents(){if(this.opened||this.root){const e=new Set([...this.querySelectorAll("k-directory-viewer")]);for await(const t of this[handle].values())if("directory"===t.kind){const n=[...e].find((e=>t.isSameEntry(e[handle])&&t.name===e[handle].name));n?(this.appendChild(n),e.delete(n)):this.appendChild(new DirectoryViewer(t,!1))}e.forEach((e=>e.remove()));const t=new Set([...this.querySelectorAll("k-directory-viewer-file")]);for await(const e of this[handle].values())if("file"===e.kind){const n=[...t].find((t=>e.isSameEntry(t[handle])&&e.name===t[handle].name));n?(this.appendChild(n),t.delete(n)):this.appendChild(new File(e))}t.forEach((e=>e.remove())),this[watchId]||(this[watchId]=watchDirectoryHandle(this[handle],this[changeCallback]))}else this[watchId]&&(clearInterval(this[watchId]),this[watchId]=!1)}select(){const e=this.querySelector("k-directory[selected], k-file[selected]");e!==this&&(e&&(e.selected=!1),this.selected=!0,this.dispatchEvent(new CustomEvent("dirSelected",{detail:{dirHandle:this[handle],dirComponent:this},bubbles:!0,composed:!0})))}addFilter(e){this[filters].push(e),this.renderContents()}get shadowTemplate(){return`\n <button\n id="loadDirectory"\n >\n <slot name="selectButton">\n <k-icon name="folder-create"></k-icon> Select Directory\n </slot>\n </button>\n <button\n id="openToggle"\n class="no-btn"\n >\n <k-icon name="folder" id="folder-closed"></k-icon>\n <k-icon name="folder-open" id="folder-opened"></k-icon>\n <k-icon name="folder-clear" id="folder-clear"></k-icon>\n ${super.shadowTemplate}\n </button>\n <div id="tree">\n <slot name="content"></slot>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host([has-handle]) #loadDirectory,\n :host([opened]) #folder-closed,\n :host(:not([opened])) #folder-opened,\n :host(:not([has-handle])) #folder-closed,\n :host(:not([has-handle])) #folder-opened,\n :host(:not([has-handle])) #folder-clear,\n :host(:not([root])) #folder-clear,\n :host([root]) #folder-opened {\n display: none;\n }\n #openToggle {\n display: block;\n width: 100%;\n flex: 1 1 auto;\n }\n #tree {\n padding-left: var(--spacer);\n }\n #wrapper {\n display: flex;\n }\n #clearSelectedDirectory {\n flex: none;\n }\n :host([selected]) #openToggle {\n background-color: var(--c_primary);\n color: var(--tc_on_primary);\n border-radius: var(--raidus);\n }\n `}static observedAttributes=[...LazyComponent.observedAttributes,"opened"];static watchInterval=1e3}window.customElements.define("k-directory-viewer",DirectoryViewer);export class Directory extends Component{constructor(e=!1){super(),this[handle]=e,this[selectDirectoryClickHandler]=()=>this.select(),this.slot="content",this.registerAttribute("selected",!1)}async render(e){return!!await super.render(e)&&(this[handle]&&(this.innerHTML=this[handle].name,onEvent(this.shadowRoot.getElementById("selectDirectory"),"click",this[selectDirectoryClickHandler])),!0)}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("selectDirectory"),"click",this[selectDirectoryClickHandler])}get rootDir(){return this.closest("k-directory-viewer")}select(){const e=this.rootDir.querySelector("k-directory[selected], k-file[selected]");e!==this&&(e&&(e.selected=!1),this.selected=!0,this.dispatchEvent(new CustomEvent("directorySelected",{detail:{fileHandle:this[handle],fileComponent:this},bubbles:!0,composed:!0})))}get shadowTemplate(){return`\n <button\n id="selectDirectory"\n >\n <slot name="selectButton">\n <k-icon id="extIcon" name="file"></k-icon> ${this[handle].name}\n </slot>\n </button>\n ${super.shadowTemplate}\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host([selected]) #selectFile {\n background-color: var(--c_primary);\n color: var(--tc_on_primary);\n border-radius: var(--raidus);\n }\n `}}const selectFileClickHandler=Symbol();export class File extends Component{constructor(e=!1){super(),this[handle]=e,this[selectFileClickHandler]=()=>this.select(),this.slot="content",this.registerAttribute("selected",!1)}async render(e){if(await super.render(e)){if(this[handle]){this.innerHTML=this[handle].name;const e=this[handle].name.split(".").pop(),t=this.shadowRoot.getElementById("extIcon");["png","gif","jpeg","jpg","tif","webp"].includes(e)?t.name="image":["txt","rtf","js","css","html"].includes(e)?t.name="file-text":t.name="file",onEvent(this.shadowRoot.getElementById("selectFile"),"click",this[selectFileClickHandler])}return!0}return!1}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("selectFile"),"click",this[selectFileClickHandler])}get rootDir(){return this.closest("k-directory-viewer")}select(){const e=this.rootDir.querySelector("k-directory[selected], k-file[selected]");e!==this&&(e&&(e.selected=!1),this.selected=!0,this.dispatchEvent(new CustomEvent("fileSelected",{detail:{fileHandle:this[handle],fileComponent:this},bubbles:!0,composed:!0})))}get shadowTemplate(){return`\n <button\n id="selectFile"\n class="no-btn"\n >\n <k-icon\n id="extIcon"\n name=""\n ></k-icon>\n ${super.shadowTemplate}\n </button>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n width: 100%;\n }\n :host([selected]) {\n background-color: var(--c_primary);\n color: var(--tc_on_primary);\n border-radius: var(--raidus);\n }\n #selectFile {\n width: 100%;\n }\n `}}window.customElements.define("k-directory-viewer-file",File);
|
package/dist/components/Table.js
CHANGED
|
@@ -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})
|
|
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})=>{let s=e[t]||"";return Array.isArray(s)&&(s=s.join(", ")),`<td>${s}</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 +1 @@
|
|
|
1
|
-
import Component from"./Component.js";import{onEvent,dispatchEvent}from"../utils/element.js";import"./Icon.js";const storageWatcher=Symbol("storageWatcher"),clickHandler=Symbol("clickHandler");export default class ThemeSwitcher extends Component{constructor(){super(),this[storageWatcher]=()=>{this.currentTheme=ThemeSwitcher.getCurrentTheme()},this[clickHandler]=()=>{const e=ThemeSwitcher.getCurrentTheme();"auto"===e&&ThemeSwitcher.setTheme("light"),"light"===e&&ThemeSwitcher.setTheme("dark"),"dark"===e&&ThemeSwitcher.setTheme("auto")},this.registerAttribute("currentTheme",ThemeSwitcher.getCurrentTheme())}async render(e){return!!await super.render(e)&&(onEvent(window,"storage",this[storageWatcher]),onEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler]),!0)}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler])}get shadowTemplate(){return'\n <button\n id="toggle"\n class="no-btn"\n >\n <k-icon\n id="autoMode"\n name="mode-auto"\n class="mode"\n ></k-icon>\n <k-icon\n id="lightMode"\n name="light
|
|
1
|
+
import Component from"./Component.js";import{onEvent,dispatchEvent}from"../utils/element.js";import"./Icon.js";const storageWatcher=Symbol("storageWatcher"),clickHandler=Symbol("clickHandler");export default class ThemeSwitcher extends Component{constructor(){super(),this[storageWatcher]=()=>{this.currentTheme=ThemeSwitcher.getCurrentTheme()},this[clickHandler]=()=>{const e=ThemeSwitcher.getCurrentTheme();"auto"===e&&ThemeSwitcher.setTheme("light"),"light"===e&&ThemeSwitcher.setTheme("dark"),"dark"===e&&ThemeSwitcher.setTheme("auto")},this.registerAttribute("currentTheme",ThemeSwitcher.getCurrentTheme())}async render(e){return!!await super.render(e)&&(onEvent(window,"storage",this[storageWatcher]),onEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler]),!0)}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler])}get shadowTemplate(){return'\n <button\n id="toggle"\n class="no-btn"\n >\n <k-icon\n id="autoMode"\n name="mode-auto"\n class="mode"\n ></k-icon>\n <k-icon\n id="lightMode"\n name="mode-light"\n class="mode"\n ></k-icon>\n <k-icon\n id="darkMode"\n name="mode-dark"\n class="mode"\n ></k-icon>\n </button>\n '}get shadowStyles(){return'\n :host {\n --padding: var(--spacer);\n\n display: flex;\n }\n #toggle {\n padding: var(--padding);\n }\n .mode {\n display: none;\n }\n :host([current-theme="auto"]) #autoMode,\n :host([current-theme="light"]) #lightMode,\n :host([current-theme="dark"]) #darkMode {\n display: block;\n }\n '}static setTheme(e){localStorage.setItem("theme",e),document.documentElement.setAttribute("theme",e),dispatchEvent(window,"storage",{theme:e})}static getCurrentTheme(){let e=document.documentElement.getAttribute("theme");return e||(e=localStorage.getItem("theme")),e}}const colorSchemeQuery=window.matchMedia("(prefers-color-scheme: dark)"),colorSchemeChangeHandler=e=>document.documentElement.setAttribute("auto-theme",e.matches?"dark":"light");colorSchemeQuery.addEventListener("change",colorSchemeChangeHandler),colorSchemeChangeHandler(colorSchemeQuery),ThemeSwitcher.setTheme(ThemeSwitcher.getCurrentTheme()),window.customElements.define("k-theme-switcher",ThemeSwitcher);
|
|
@@ -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="#arrays">Displaying Arrays</a><br />
|
|
25
26
|
</div>
|
|
26
27
|
</details>
|
|
27
28
|
|
|
@@ -107,6 +108,23 @@
|
|
|
107
108
|
]);
|
|
108
109
|
</script>
|
|
109
110
|
|
|
111
|
+
<h3 id="arrays"><a href="#arrays" class="no-link">Displaying Arrays</a></h3>
|
|
112
|
+
<p>The table component can display arrays of strings or numbers by joining them with a comma and a space.</p>
|
|
113
|
+
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">k-table</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"hobbies"</span>></span><span class="hljs-tag"></<span class="hljs-name">k-table</span>></span><br /><span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>></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"></<span class="hljs-name">script</span>></span></code></pre>
|
|
114
|
+
<k-table id="hobbies"></k-table>
|
|
115
|
+
<script type="module">
|
|
116
|
+
document.getElementById('hobbies').setData([
|
|
117
|
+
{
|
|
118
|
+
name: "Dustin",
|
|
119
|
+
hobbies: ["Reading", "Hiking", "Gaming"]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "Kayla",
|
|
123
|
+
hobbies: ["Cooking", "Traveling"]
|
|
124
|
+
}
|
|
125
|
+
]);
|
|
126
|
+
</script>
|
|
127
|
+
|
|
110
128
|
<h3 id="constructor"><a href="#consttructor" class="no-link">Constructor</a></h3>
|
|
111
129
|
<h6>Extends <a href="./component.html">Component</a></h6>
|
|
112
130
|
<h5>
|
|
@@ -139,10 +157,10 @@
|
|
|
139
157
|
<h5><code>setData(<i><Array>object</i> records, <i><Array>object</i> fields)<i>: undefined</i></code></h5>
|
|
140
158
|
<p>Sets the records and the fields and renders the table, if no fields are provided then they will be automatically generated from the keys of the first 100 records.</p>
|
|
141
159
|
|
|
142
|
-
<h5><code>renderFields()<i>: undefined</i></
|
|
160
|
+
<h5><code>renderFields()<i>: undefined</i></h5>
|
|
143
161
|
<p>Renders the fields as table headers, this is called automatically by setData, you should never have to call it.</p>
|
|
144
162
|
|
|
145
|
-
<h5><code>renderRecords()<i>: undefined</i></
|
|
163
|
+
<h5><code>renderRecords()<i>: undefined</i></h5>
|
|
146
164
|
<p>Renders the records as table row, this is called automatically by setData, you should never have to call it.</p>
|
|
147
165
|
|
|
148
166
|
</main>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import LazyComponent from"./LazyComponent.js";import Component from"./Component.js";import"./Icon.js";import{onEvent,offEvent,dispatchEvent}from"../utils/element.js";import watchDirectoryHandle from"../utils/watchDirectoryHandle.js";const handle=Symbol(),loadDirectoryClickHandler=Symbol(),
|
|
1
|
+
import LazyComponent from"./LazyComponent.js";import Component from"./Component.js";import"./Icon.js";import{onEvent,offEvent,dispatchEvent}from"../utils/element.js";import watchDirectoryHandle from"../utils/watchDirectoryHandle.js";const handle=Symbol(),loadDirectoryClickHandler=Symbol(),selectedHandler=Symbol(),watchId=Symbol(),changeCallback=Symbol(),filters=Symbol();export default class DirectoryViewer extends LazyComponent{constructor(e=!1){super(),this[handle]=e,this[watchId]=!1,this[filters]=[],this[loadDirectoryClickHandler]=()=>this.loadDirectory(),this[openToggleClickHandler]=()=>{this.root?this.clearDirectoryHandle():(this.toggleOpen(),this.select())},this[changeCallback]=()=>{this.updateContents()},this[selectedHandler]=e=>{},this.registerAttributes({hasHandle:!!e,selected:!1})}async render(e){return!!await super.render(e)&&(onEvent(this.shadowRoot,"fileSelected directorySelected",this[selectedHandler]),onEvent(this.shadowRoot.getElementById("loadDirectory"),"click",this[loadDirectoryClickHandler]),this.renderDirectory(),!0)}async renderDirectory(){this[handle]&&this.rendered&&(this.innerHTML=this[handle].name,this.renderContents())}async renderContents(){if(this.querySelectorAll('[slot="content"]').forEach((e=>e.remove())),this.rendered&&this[handle]&&(this.opened||this.root)){for await(const e of this[handle].values())"directory"===e.kind&&this.filters.every((t=>t(e)))&&this.appendChild(new DirectoryViewer(e,!1));for await(const e of this[handle].values())"file"===e.kind&&this.filters.every((t=>t(e)))&&this.appendChild(new File(e));this[watchId]||(this[watchId]=watchDirectoryHandle(this[handle],this[changeCallback]))}else this[watchId]&&(clearInterval(this[watchId]),this[watchId]=!1)}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot,"fileselected",this[fileSelectedHandler]),offEvent(this.shadowRoot.getElementById("loadDirectory"),"click",this[loadDirectoryClickHandler]),offEvent(this.shadowRoot.getElementById("openToggle"),"click",this[openToggleClickHandler])}attributeChangedCallback(e,t,n){"opened"===e&&t!==n&&(!n&&this.root?this.opened=!0:this.renderContents())}get rootDir(){return this.root?this:this.closest('k-directory-viewer[root="true"]')}get filters(){return this.rootDir[filters]}async loadDirectory(){window.showDirectoryPicker&&(this[handle]=await window.showDirectoryPicker(),this[handle]&&(this.hasHandle=!0,dispatchEvent(this,"directoryloaded",{dirHandle:this[handle],dirComponent:this}),this.renderDirectory()))}clearDirectoryHandle(){this[handle]=!1,this.hasHandle=!1,this.innerHTML=""}async updateContents(){if(this.opened||this.root){const e=new Set([...this.querySelectorAll("k-directory-viewer")]);for await(const t of this[handle].values())if("directory"===t.kind){const n=[...e].find((e=>t.isSameEntry(e[handle])&&t.name===e[handle].name));n?(this.appendChild(n),e.delete(n)):this.appendChild(new DirectoryViewer(t,!1))}e.forEach((e=>e.remove()));const t=new Set([...this.querySelectorAll("k-directory-viewer-file")]);for await(const e of this[handle].values())if("file"===e.kind){const n=[...t].find((t=>e.isSameEntry(t[handle])&&e.name===t[handle].name));n?(this.appendChild(n),t.delete(n)):this.appendChild(new File(e))}t.forEach((e=>e.remove())),this[watchId]||(this[watchId]=watchDirectoryHandle(this[handle],this[changeCallback]))}else this[watchId]&&(clearInterval(this[watchId]),this[watchId]=!1)}select(){const e=this.querySelector("k-directory[selected], k-file[selected]");e!==this&&(e&&(e.selected=!1),this.selected=!0,this.dispatchEvent(new CustomEvent("dirSelected",{detail:{dirHandle:this[handle],dirComponent:this},bubbles:!0,composed:!0})))}addFilter(e){this[filters].push(e),this.renderContents()}get shadowTemplate(){return`\n <button\n id="loadDirectory"\n >\n <slot name="selectButton">\n <k-icon name="folder-create"></k-icon> Select Directory\n </slot>\n </button>\n <button\n id="openToggle"\n class="no-btn"\n >\n <k-icon name="folder" id="folder-closed"></k-icon>\n <k-icon name="folder-open" id="folder-opened"></k-icon>\n <k-icon name="folder-clear" id="folder-clear"></k-icon>\n ${super.shadowTemplate}\n </button>\n <div id="tree">\n <slot name="content"></slot>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host([has-handle]) #loadDirectory,\n :host([opened]) #folder-closed,\n :host(:not([opened])) #folder-opened,\n :host(:not([has-handle])) #folder-closed,\n :host(:not([has-handle])) #folder-opened,\n :host(:not([has-handle])) #folder-clear,\n :host(:not([root])) #folder-clear,\n :host([root]) #folder-opened {\n display: none;\n }\n #openToggle {\n display: block;\n width: 100%;\n flex: 1 1 auto;\n }\n #tree {\n padding-left: var(--spacer);\n }\n #wrapper {\n display: flex;\n }\n #clearSelectedDirectory {\n flex: none;\n }\n :host([selected]) #openToggle {\n background-color: var(--c_primary);\n color: var(--tc_on_primary);\n border-radius: var(--raidus);\n }\n `}static observedAttributes=[...LazyComponent.observedAttributes,"opened"];static watchInterval=1e3}window.customElements.define("k-directory-viewer",DirectoryViewer);export class Directory extends Component{constructor(e=!1){super(),this[handle]=e,this[selectDirectoryClickHandler]=()=>this.select(),this.slot="content",this.registerAttribute("selected",!1)}async render(e){return!!await super.render(e)&&(this[handle]&&(this.innerHTML=this[handle].name,onEvent(this.shadowRoot.getElementById("selectDirectory"),"click",this[selectDirectoryClickHandler])),!0)}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("selectDirectory"),"click",this[selectDirectoryClickHandler])}get rootDir(){return this.closest("k-directory-viewer")}select(){const e=this.rootDir.querySelector("k-directory[selected], k-file[selected]");e!==this&&(e&&(e.selected=!1),this.selected=!0,this.dispatchEvent(new CustomEvent("directorySelected",{detail:{fileHandle:this[handle],fileComponent:this},bubbles:!0,composed:!0})))}get shadowTemplate(){return`\n <button\n id="selectDirectory"\n >\n <slot name="selectButton">\n <k-icon id="extIcon" name="file"></k-icon> ${this[handle].name}\n </slot>\n </button>\n ${super.shadowTemplate}\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host([selected]) #selectFile {\n background-color: var(--c_primary);\n color: var(--tc_on_primary);\n border-radius: var(--raidus);\n }\n `}}const selectFileClickHandler=Symbol();export class File extends Component{constructor(e=!1){super(),this[handle]=e,this[selectFileClickHandler]=()=>this.select(),this.slot="content",this.registerAttribute("selected",!1)}async render(e){if(await super.render(e)){if(this[handle]){this.innerHTML=this[handle].name;const e=this[handle].name.split(".").pop(),t=this.shadowRoot.getElementById("extIcon");["png","gif","jpeg","jpg","tif","webp"].includes(e)?t.name="image":["txt","rtf","js","css","html"].includes(e)?t.name="file-text":t.name="file",onEvent(this.shadowRoot.getElementById("selectFile"),"click",this[selectFileClickHandler])}return!0}return!1}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("selectFile"),"click",this[selectFileClickHandler])}get rootDir(){return this.closest("k-directory-viewer")}select(){const e=this.rootDir.querySelector("k-directory[selected], k-file[selected]");e!==this&&(e&&(e.selected=!1),this.selected=!0,this.dispatchEvent(new CustomEvent("fileSelected",{detail:{fileHandle:this[handle],fileComponent:this},bubbles:!0,composed:!0})))}get shadowTemplate(){return`\n <button\n id="selectFile"\n class="no-btn"\n >\n <k-icon\n id="extIcon"\n name=""\n ></k-icon>\n ${super.shadowTemplate}\n </button>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n width: 100%;\n }\n :host([selected]) {\n background-color: var(--c_primary);\n color: var(--tc_on_primary);\n border-radius: var(--raidus);\n }\n #selectFile {\n width: 100%;\n }\n `}}window.customElements.define("k-directory-viewer-file",File);
|
|
@@ -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})
|
|
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})=>{let s=e[t]||"";return Array.isArray(s)&&(s=s.join(", ")),`<td>${s}</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 +1 @@
|
|
|
1
|
-
import Component from"./Component.js";import{onEvent,dispatchEvent}from"../utils/element.js";import"./Icon.js";const storageWatcher=Symbol("storageWatcher"),clickHandler=Symbol("clickHandler");export default class ThemeSwitcher extends Component{constructor(){super(),this[storageWatcher]=()=>{this.currentTheme=ThemeSwitcher.getCurrentTheme()},this[clickHandler]=()=>{const e=ThemeSwitcher.getCurrentTheme();"auto"===e&&ThemeSwitcher.setTheme("light"),"light"===e&&ThemeSwitcher.setTheme("dark"),"dark"===e&&ThemeSwitcher.setTheme("auto")},this.registerAttribute("currentTheme",ThemeSwitcher.getCurrentTheme())}async render(e){return!!await super.render(e)&&(onEvent(window,"storage",this[storageWatcher]),onEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler]),!0)}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler])}get shadowTemplate(){return'\n <button\n id="toggle"\n class="no-btn"\n >\n <k-icon\n id="autoMode"\n name="mode-auto"\n class="mode"\n ></k-icon>\n <k-icon\n id="lightMode"\n name="light
|
|
1
|
+
import Component from"./Component.js";import{onEvent,dispatchEvent}from"../utils/element.js";import"./Icon.js";const storageWatcher=Symbol("storageWatcher"),clickHandler=Symbol("clickHandler");export default class ThemeSwitcher extends Component{constructor(){super(),this[storageWatcher]=()=>{this.currentTheme=ThemeSwitcher.getCurrentTheme()},this[clickHandler]=()=>{const e=ThemeSwitcher.getCurrentTheme();"auto"===e&&ThemeSwitcher.setTheme("light"),"light"===e&&ThemeSwitcher.setTheme("dark"),"dark"===e&&ThemeSwitcher.setTheme("auto")},this.registerAttribute("currentTheme",ThemeSwitcher.getCurrentTheme())}async render(e){return!!await super.render(e)&&(onEvent(window,"storage",this[storageWatcher]),onEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler]),!0)}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("toggle"),"click",this[clickHandler])}get shadowTemplate(){return'\n <button\n id="toggle"\n class="no-btn"\n >\n <k-icon\n id="autoMode"\n name="mode-auto"\n class="mode"\n ></k-icon>\n <k-icon\n id="lightMode"\n name="mode-light"\n class="mode"\n ></k-icon>\n <k-icon\n id="darkMode"\n name="mode-dark"\n class="mode"\n ></k-icon>\n </button>\n '}get shadowStyles(){return'\n :host {\n --padding: var(--spacer);\n\n display: flex;\n }\n #toggle {\n padding: var(--padding);\n }\n .mode {\n display: none;\n }\n :host([current-theme="auto"]) #autoMode,\n :host([current-theme="light"]) #lightMode,\n :host([current-theme="dark"]) #darkMode {\n display: block;\n }\n '}static setTheme(e){localStorage.setItem("theme",e),document.documentElement.setAttribute("theme",e),dispatchEvent(window,"storage",{theme:e})}static getCurrentTheme(){let e=document.documentElement.getAttribute("theme");return e||(e=localStorage.getItem("theme")),e}}const colorSchemeQuery=window.matchMedia("(prefers-color-scheme: dark)"),colorSchemeChangeHandler=e=>document.documentElement.setAttribute("auto-theme",e.matches?"dark":"light");colorSchemeQuery.addEventListener("change",colorSchemeChangeHandler),colorSchemeChangeHandler(colorSchemeQuery),ThemeSwitcher.setTheme(ThemeSwitcher.getCurrentTheme()),window.customElements.define("k-theme-switcher",ThemeSwitcher);
|
package/package.json
CHANGED
|
@@ -10,8 +10,7 @@ import watchDirectoryHandle from '../utils/watchDirectoryHandle.js';
|
|
|
10
10
|
|
|
11
11
|
const handle = Symbol(),
|
|
12
12
|
loadDirectoryClickHandler = Symbol(),
|
|
13
|
-
|
|
14
|
-
fileSelectedHandler = Symbol(),
|
|
13
|
+
selectedHandler = Symbol(),
|
|
15
14
|
watchId = Symbol(),
|
|
16
15
|
changeCallback = Symbol(),
|
|
17
16
|
filters = Symbol();
|
|
@@ -37,13 +36,13 @@ export default class DirectoryViewer extends LazyComponent {
|
|
|
37
36
|
this[changeCallback] = () => {
|
|
38
37
|
this.updateContents();
|
|
39
38
|
}
|
|
39
|
+
this[selectedHandler] = (e) => {
|
|
40
|
+
|
|
41
|
+
}
|
|
40
42
|
|
|
41
43
|
/* Init */
|
|
42
|
-
this.slot = 'content';
|
|
43
44
|
this.registerAttributes({
|
|
44
|
-
root: !_handle,
|
|
45
45
|
hasHandle: !!_handle,
|
|
46
|
-
opened: !_handle,
|
|
47
46
|
selected: false
|
|
48
47
|
});
|
|
49
48
|
}
|
|
@@ -51,9 +50,8 @@ export default class DirectoryViewer extends LazyComponent {
|
|
|
51
50
|
/* Lifecycle Callbacks */
|
|
52
51
|
async render(force){
|
|
53
52
|
if(await super.render(force)){
|
|
54
|
-
onEvent(this.shadowRoot, '
|
|
53
|
+
onEvent(this.shadowRoot, 'fileSelected directorySelected', this[selectedHandler]);
|
|
55
54
|
onEvent(this.shadowRoot.getElementById('loadDirectory'), 'click', this[loadDirectoryClickHandler]);
|
|
56
|
-
onEvent(this.shadowRoot.getElementById('openToggle'), 'click', this[openToggleClickHandler]);
|
|
57
55
|
this.renderDirectory();
|
|
58
56
|
return true;
|
|
59
57
|
}
|
|
@@ -133,15 +131,6 @@ export default class DirectoryViewer extends LazyComponent {
|
|
|
133
131
|
}
|
|
134
132
|
}
|
|
135
133
|
}
|
|
136
|
-
open(){
|
|
137
|
-
this.opened = true;
|
|
138
|
-
}
|
|
139
|
-
close(){
|
|
140
|
-
if(!this.root) this.opened = false;
|
|
141
|
-
}
|
|
142
|
-
toggleOpen(){
|
|
143
|
-
if(!this.root) this.opened = !this.opened;
|
|
144
|
-
}
|
|
145
134
|
clearDirectoryHandle(){
|
|
146
135
|
this[handle] = false;
|
|
147
136
|
this.hasHandle = false;
|
|
@@ -183,11 +172,11 @@ export default class DirectoryViewer extends LazyComponent {
|
|
|
183
172
|
}
|
|
184
173
|
}
|
|
185
174
|
select(){
|
|
186
|
-
const $currentSelection = this.
|
|
175
|
+
const $currentSelection = this.querySelector('k-directory[selected], k-file[selected]');
|
|
187
176
|
if($currentSelection === this) return;
|
|
188
177
|
if($currentSelection) $currentSelection.selected = false;
|
|
189
178
|
this.selected = true;
|
|
190
|
-
this.dispatchEvent(new CustomEvent('
|
|
179
|
+
this.dispatchEvent(new CustomEvent('dirSelected', {
|
|
191
180
|
detail: {
|
|
192
181
|
dirHandle: this[handle],
|
|
193
182
|
dirComponent: this
|
|
@@ -269,6 +258,83 @@ export default class DirectoryViewer extends LazyComponent {
|
|
|
269
258
|
}
|
|
270
259
|
window.customElements.define('k-directory-viewer', DirectoryViewer);
|
|
271
260
|
|
|
261
|
+
export class Directory extends Component {
|
|
262
|
+
constructor(_handle = false){
|
|
263
|
+
super();
|
|
264
|
+
|
|
265
|
+
/* Private Members */
|
|
266
|
+
this[handle] = _handle;
|
|
267
|
+
|
|
268
|
+
/* Private Methods */
|
|
269
|
+
this[selectDirectoryClickHandler] = () => this.select();
|
|
270
|
+
|
|
271
|
+
/* Init */
|
|
272
|
+
this.slot = 'content';
|
|
273
|
+
this.registerAttribute('selected', false);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* Lifecycle Callbacks */
|
|
277
|
+
async render(force){
|
|
278
|
+
if(await super.render(force)){
|
|
279
|
+
if(this[handle]){
|
|
280
|
+
this.innerHTML = this[handle].name;
|
|
281
|
+
onEvent(this.shadowRoot.getElementById('selectDirectory'), 'click', this[selectDirectoryClickHandler]);
|
|
282
|
+
}
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
disconnectedCallback(){
|
|
288
|
+
super.disconnectedCallback();
|
|
289
|
+
offEvent(this.shadowRoot.getElementById('selectDirectory'), 'click', this[selectDirectoryClickHandler]);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* Protected Members */
|
|
293
|
+
get rootDir(){
|
|
294
|
+
return this.closest('k-directory-viewer')
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* Public Methods */
|
|
298
|
+
select(){
|
|
299
|
+
const $currentSelection = this.rootDir.querySelector('k-directory[selected], k-file[selected]');
|
|
300
|
+
if($currentSelection === this) return;
|
|
301
|
+
if($currentSelection) $currentSelection.selected = false;
|
|
302
|
+
this.selected = true;
|
|
303
|
+
this.dispatchEvent(new CustomEvent('directorySelected', {
|
|
304
|
+
detail: {
|
|
305
|
+
fileHandle: this[handle],
|
|
306
|
+
fileComponent: this
|
|
307
|
+
},
|
|
308
|
+
bubbles: true,
|
|
309
|
+
composed: true
|
|
310
|
+
}));
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/* Shadow DOM */
|
|
314
|
+
get shadowTemplate(){
|
|
315
|
+
return /*html*/`
|
|
316
|
+
<button
|
|
317
|
+
id="selectDirectory"
|
|
318
|
+
>
|
|
319
|
+
<slot name="selectButton">
|
|
320
|
+
<k-icon id="extIcon" name="file"></k-icon> ${this[handle].name}
|
|
321
|
+
</slot>
|
|
322
|
+
</button>
|
|
323
|
+
${super.shadowTemplate}
|
|
324
|
+
`;
|
|
325
|
+
}
|
|
326
|
+
get shadowStyles(){
|
|
327
|
+
return /*css*/`
|
|
328
|
+
${super.shadowStyles}
|
|
329
|
+
:host([selected]) #selectFile {
|
|
330
|
+
background-color: var(--c_primary);
|
|
331
|
+
color: var(--tc_on_primary);
|
|
332
|
+
border-radius: var(--raidus);
|
|
333
|
+
}
|
|
334
|
+
`;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
272
338
|
const selectFileClickHandler = Symbol();
|
|
273
339
|
export class File extends Component {
|
|
274
340
|
constructor(_handle = false){
|
|
@@ -310,13 +376,18 @@ export class File extends Component {
|
|
|
310
376
|
offEvent(this.shadowRoot.getElementById('selectFile'), 'click', this[selectFileClickHandler]);
|
|
311
377
|
}
|
|
312
378
|
|
|
379
|
+
/* Protected Members */
|
|
380
|
+
get rootDir(){
|
|
381
|
+
return this.closest('k-directory-viewer')
|
|
382
|
+
}
|
|
383
|
+
|
|
313
384
|
/* Public Methods */
|
|
314
385
|
select(){
|
|
315
|
-
const $currentSelection = this.
|
|
386
|
+
const $currentSelection = this.rootDir.querySelector('k-directory[selected], k-file[selected]');
|
|
316
387
|
if($currentSelection === this) return;
|
|
317
388
|
if($currentSelection) $currentSelection.selected = false;
|
|
318
389
|
this.selected = true;
|
|
319
|
-
this.dispatchEvent(new CustomEvent('
|
|
390
|
+
this.dispatchEvent(new CustomEvent('fileSelected', {
|
|
320
391
|
detail: {
|
|
321
392
|
fileHandle: this[handle],
|
|
322
393
|
fileComponent: this
|
package/src/components/Table.js
CHANGED
|
@@ -28,7 +28,13 @@ export default class Table extends Component {
|
|
|
28
28
|
}
|
|
29
29
|
renderRecords(){
|
|
30
30
|
this.shadowRoot.getElementById('records').innerHTML = this.records.map((record) => {
|
|
31
|
-
return `<tr>${this.fields.map(({name})
|
|
31
|
+
return `<tr>${this.fields.map(({name}) => {
|
|
32
|
+
let value = record[name] || '';
|
|
33
|
+
if (Array.isArray(value)) {
|
|
34
|
+
value = value.join(', ');
|
|
35
|
+
}
|
|
36
|
+
return `<td>${value}</td>`;
|
|
37
|
+
}).join('')}</tr>`;
|
|
32
38
|
}).join('');
|
|
33
39
|
}
|
|
34
40
|
|
|
@@ -48,12 +48,12 @@ export default class ThemeSwitcher extends Component {
|
|
|
48
48
|
></k-icon>
|
|
49
49
|
<k-icon
|
|
50
50
|
id="lightMode"
|
|
51
|
-
name="light
|
|
51
|
+
name="mode-light"
|
|
52
52
|
class="mode"
|
|
53
53
|
></k-icon>
|
|
54
54
|
<k-icon
|
|
55
55
|
id="darkMode"
|
|
56
|
-
name="dark
|
|
56
|
+
name="mode-dark"
|
|
57
57
|
class="mode"
|
|
58
58
|
></k-icon>
|
|
59
59
|
</button>
|