kempo 2.1.1 → 2.3.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.
Files changed (38) hide show
  1. package/dist/components/ContentSlider.js +1 -0
  2. package/dist/components/DirectoryViewer.js +1 -1
  3. package/dist/components/ShowMore.js +1 -1
  4. package/dist/components/ThemeSwitcher.js +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/kempo-hljs.css +1 -1
  7. package/dist/utils/element.js +1 -1
  8. package/docs/components/_template.html +2 -0
  9. package/docs/components/content-slider.html +185 -0
  10. package/docs/components/{directoryviewer.html → directory-viewer.html} +9 -4
  11. package/docs/components/show-more.html +1 -2
  12. package/docs/kempo/components/ContentSlider.js +1 -0
  13. package/docs/kempo/components/DirectoryViewer.js +1 -1
  14. package/docs/kempo/components/ShowMore.js +1 -1
  15. package/docs/kempo/components/ThemeSwitcher.js +1 -1
  16. package/docs/kempo/index.js +1 -1
  17. package/docs/kempo/kempo-hljs.css +1 -1
  18. package/docs/kempo/utils/element.js +1 -1
  19. package/docs/nav-1.inc.html +3 -2
  20. package/docs/nav.inc.html +3 -4
  21. package/docs/search.json +9 -1
  22. package/icons/cards.svg +1 -0
  23. package/icons/chevron-left.svg +1 -0
  24. package/icons/chevron-right.svg +1 -0
  25. package/icons/label-add.svg +1 -0
  26. package/icons/label.svg +1 -0
  27. package/icons/mode-auto.svg +1 -0
  28. package/icons/tag.svg +1 -0
  29. package/package.json +1 -1
  30. package/src/components/ContentSlider.js +192 -0
  31. package/src/components/DirectoryViewer.js +64 -15
  32. package/src/components/ShowMore.js +23 -3
  33. package/src/components/ThemeSwitcher.js +21 -3
  34. package/src/kempo-hljs.css +1 -0
  35. package/src/utils/element.js +5 -2
  36. /package/docs/components/{lazycomponent.html → lazy-component.html} +0 -0
  37. /package/icons/{dark-mode.svg → mode-dark.svg} +0 -0
  38. /package/icons/{light-mode.svg → mode-light.svg} +0 -0
@@ -0,0 +1 @@
1
+ import LazyComponent from"./LazyComponent.js";import{onEvent,offEvent,dispatchEvent}from"../utils/element.js";const content=Symbol(),prevClickHandler=Symbol(),nextClickHandler=Symbol(),keydownHandler=Symbol();export default class ContentSlider extends LazyComponent{constructor(n=[],{index:t=0,controls:e=!0,globalControls:o=!1,keyboardControls:s=!0,loop:i=!1}={}){super(),this[content]=[...n],this[prevClickHandler]=()=>this.previous(),this[nextClickHandler]=()=>this.next(),this[keydownHandler]=n=>{"ArrowLeft"===n.code?(n.preventDefault(),dispatchEvent(this,"keyleft"),this.previous()):"ArrowRight"===n.code&&(n.preventDefault(),dispatchEvent(this,"keyright"),this.next())},this.registerAttributes({index:t,controls:e,keyboardControls:s,globalControls:o,loop:i}),this.tabIndex=0}connectedCallback(){super.connectedCallback(),this[content]=[...this.querySelectorAll(":scope > *")]}async render(n){return!!await super.render(n)&&(this.keyboardControls&&(this.globalControls?onEvent(window,"keydown",this[keydownHandler]):(onEvent(this,"keydown",this[keydownHandler]),onEvent(this.shadowRoot,"keydown",this[keydownHandler]))),onEvent(this.shadowRoot.getElementById("prev"),"click",this[prevClickHandler]),onEvent(this.shadowRoot.getElementById("next"),"click",this[nextClickHandler]),this.renderContent(),!0)}attributeChangedCallback(n,t,e){if(super.attributeChangedCallback(n,t,e),"index"===n&&t!==e){const n=parseInt(e),t=Math.max(Math.min(this[content].length-1,n),0);n!==t?this.index=t:(dispatchEvent(this,"change",{index:t}),this.renderContent())}else"keyboard-controls"===n&&t!==e&&(this.keyboardControls?this.globalControls?onEvent(window,"keydown",this[keydownHandler]):(onEvent(this,"keydown",this[keydownHandler]),onEvent(this.shadowRoot,"keydown",this[keydownHandler])):offEvent(this.globalControls?window:this.shadowRoot,"keydown",this[keydownHandler]))}renderContent(){this.innerHTML="",this.appendChild(this[content][this.index])}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("prev"),"click",this[prevClickHandler]),offEvent(this.shadowRoot.getElementById("next"),"click",this[nextClickHandler]),offEvent(window,"keydown",this[keydownHandler]),offEvent(this.shadowRoot,"keydown",this[keydownHandler]),offEvent(this,"keydown",this[keydownHandler])}previous(){let n=this.index-1;this.loop&&n<0&&(n=this[content].length-1),dispatchEvent(this,"previous",{index:n}),this.index=n}next(){let n=this.index+1;this.loop&&n>=this[content].length&&(n=0),dispatchEvent(this,"next",{index:n}),this.index=n}goto(n){dispatchEvent(this,"goto",{index:n}),this.index=n}get shadowTemplate(){return`\n <div id="content">\n ${super.shadowTemplate}\n </div>\n <div id="controls">\n <button\n id="prev"\n class="no-btn"\n >\n <slot name="prev">\n <k-icon name="chevron-left"></k-icon>\n </slot>\n </button>\n <button\n id="next"\n class="no-btn"\n >\n <slot name="next">\n <k-icon name="chevron-right"></k-icon>\n </slot>\n </button>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n position: relative;\n outline: none;\n }\n #prev,\n #next {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n font-size: 2rem;\n }\n #next {\n right: 0;\n }\n :host(:not([controls="true"])) #controls {\n display: none;\n }\n `}static observedAttributes=[...LazyComponent.observedAttributes,"index","keyboard-controls","global-controls"]}window.customElements.define("k-content-slider",ContentSlider);
@@ -1 +1 @@
1
- import LazyComponent from"./LazyComponent.js";import Component from"./Component.js";import"./Icon.js";import{onEvent,offEvent}from"../utils/element.js";import watchDirectoryHandle from"../utils/watchDirectoryHandle.js";const handle=Symbol(),selectDirectoryClickHandler=Symbol(),openToggleClickHandler=Symbol(),fileSelectedHandler=Symbol(),watchId=Symbol(),changeCallback=Symbol();export default class DirectoryViewer extends LazyComponent{constructor(e=!1){super(),this[handle]=e,this[selectDirectoryClickHandler]=()=>this.selectDirectory(),this[openToggleClickHandler]=()=>{this.root?this.clearDirectoryHandle():this.toggleOpen()},this[changeCallback]=()=>{this.updateContents()},this.slot="content",this.registerAttributes({root:!e,hasHandle:!!e,opened:!e}),this[watchId]=!1}async render(e){return!!await super.render(e)&&(onEvent(this.shadowRoot,"fileselected",this[fileSelectedHandler]),onEvent(this.shadowRoot.getElementById("selectDirectory"),"click",this[selectDirectoryClickHandler]),onEvent(this.shadowRoot.getElementById("openToggle"),"click",this[openToggleClickHandler]),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.opened||this.root){for await(const e of this[handle].values())"directory"===e.kind&&this.appendChild(new DirectoryViewer(e,!1));for await(const e of this[handle].values())"file"===e.kind&&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("selectDirectory"),"click",this[selectDirectoryClickHandler]),offEvent(this.shadowRoot.getElementById("openToggle"),"click",this[openToggleClickHandler])}attributeChangedCallback(e,t,n){"opened"===e&&t!==n&&(!n&&this.root?this.opened=!0:this.renderContents())}async selectDirectory(){window.showDirectoryPicker&&(this[handle]=await window.showDirectoryPicker(),this[handle]&&(this.hasHandle=!0,this.renderDirectory()))}open(){this.opened=!0}close(){this.root||(this.opened=!1)}toggleOpen(){this.root||(this.opened=!this.opened)}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)}get shadowTemplate(){return`\n <button\n id="selectDirectory"\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]) #selectDirectory,\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 `}static observedAttributes=[...LazyComponent.observedAttributes,"opened"];static watchInterval=1e3}window.customElements.define("k-directory-viewer",DirectoryViewer);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])}select(){const e=this.closest("k-directory-viewer[root]").querySelector("k-directory-viewer-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
+ 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(),openToggleClickHandler=Symbol(),fileSelectedHandler=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.slot="content",this.registerAttributes({root:!e,hasHandle:!!e,opened:!e,selected:!1})}async render(e){return!!await super.render(e)&&(onEvent(this.shadowRoot,"fileselected",this[fileSelectedHandler]),onEvent(this.shadowRoot.getElementById("loadDirectory"),"click",this[loadDirectoryClickHandler]),onEvent(this.shadowRoot.getElementById("openToggle"),"click",this[openToggleClickHandler]),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()))}open(){this.opened=!0}close(){this.root||(this.opened=!1)}toggleOpen(){this.root||(this.opened=!this.opened)}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.closest("k-directory-viewer[root]").querySelector("k-directory-viewer[selected], k-directory-viewer-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);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])}select(){const e=this.closest("k-directory-viewer[root]").querySelector("k-directory-viewer[selected], k-directory-viewer-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 LazyComponent from"./LazyComponent.js";import"./Icon.js";import{onEvent,offEvent,dispatchEvent}from"../utils/element.js";export default class ShowMore extends LazyComponent{constructor(){super(),this.registerAttribute("opened",!1),this.registerProp("_toggleClickHandler",(()=>this.toggle()))}async render(n){await super.render(n),onEvent(this.shadowRoot.getElementById("toggle"),"click",this._toggleClickHandler)}more(){this.opened=!0}less(){this.opened=!1}toggle(){this.opened?this.less():this.more()}get shadowTemplate(){return`\n <div id="wrapper">\n <div id="content">\n ${super.shadowTemplate}\n </div>\n <button\n id="toggle"\n class="no-btn"\n >\n <span id="more">\n <slot name="more">Show More <k-icon name="arrow-down-double"></k-icon></slot>\n </span>\n <span id="less">\n <slot name="less">Show Less <k-icon name="arrow-up-double"></k-icon></slot>\n </span>\n </button>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n --closed_height: 7rem;\n \n display: block;\n }\n :host(:not([opened])) #content{\n height: var(--closed_height);\n overflow-y: hidden;\n }\n :host(:not([opened])) #content {\n margin-bottom: calc(var(--closed_height) * -0.9);\n }\n :host(:not([opened])) #toggle {\n padding-top: calc(var(--closed_height) - 2rem);\n background: linear-gradient(to bottom, transparent 0%, var(--c_bg) 95%);\n }\n #toggle {\n width: 100%;\n padding: var(--spacer_h);\n text-align: center;\n background: var(--c_bg);\n }\n :host([opened]) #more,\n :host(:not([opened])) #less {\n display: none;\n }\n `}}window.customElements.define("k-show-more",ShowMore);
1
+ import LazyComponent from"./LazyComponent.js";import"./Icon.js";import{onEvent,offEvent,dispatchEvent}from"../utils/element.js";const toggleClickHandler=Symbol();export default class ShowMore extends LazyComponent{constructor(){super(),this[toggleClickHandler]=()=>this.toggle(),this.registerAttribute("opened",!1)}async render(e){await super.render(e),onEvent(this.shadowRoot.getElementById("toggle"),"click",this[toggleClickHandler])}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("toggle"),"click",this[toggleClickHandler])}attributeChangedCallback(e,n,t){super.attributeChangedCallback(e,n,t),"opened"===e&&n!==t&&(this.opened?dispatchEvent(this,"change opened"):dispatchEvent(this,"change closed"))}more(){this.opened=!0}less(){this.opened=!1}toggle(){this.opened=!this.opened}get shadowTemplate(){return`\n <div id="wrapper">\n <div id="content">\n ${super.shadowTemplate}\n </div>\n <button\n id="toggle"\n class="no-btn"\n >\n <span id="more">\n <slot name="more">Show More <k-icon name="arrow-down-double"></k-icon></slot>\n </span>\n <span id="less">\n <slot name="less">Show Less <k-icon name="arrow-up-double"></k-icon></slot>\n </span>\n </button>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n --closed_height: 7rem;\n \n display: block;\n }\n :host(:not([opened])) #content{\n height: var(--closed_height);\n overflow-y: hidden;\n }\n :host(:not([opened])) #content {\n margin-bottom: calc(var(--closed_height) * -0.9);\n }\n :host(:not([opened])) #toggle {\n padding-top: calc(var(--closed_height) - 2rem);\n background: linear-gradient(to bottom, transparent 0%, var(--c_bg) 95%);\n }\n #toggle {\n width: 100%;\n padding: var(--spacer_h);\n text-align: center;\n background: var(--c_bg);\n }\n :host([opened]) #more,\n :host(:not([opened])) #less {\n display: none;\n }\n `}}window.customElements.define("k-show-more",ShowMore);
@@ -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]=()=>{ThemeSwitcher.setTheme("light"===ThemeSwitcher.getCurrentTheme()?"dark":"light")},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)}get shadowTemplate(){return'\n <button\n id="toggle"\n class="no-btn"\n >\n <k-icon\n id="lightMode"\n name="light-mode"\n ></k-icon>\n <k-icon\n id="darkMode"\n name="dark-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 :host([current-theme="dark"]) #darkMode,\n :host([current-theme="light"]) #lightMode {\n display: none;\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);
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-mode"\n class="mode"\n ></k-icon>\n <k-icon\n id="darkMode"\n name="dark-mode"\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/dist/index.js CHANGED
@@ -1 +1 @@
1
- import Card from"./components/Card.js";import Component from"./components/Component.js";import Dialog from"./components/Dialog.js";import DirectoryViewer from"./components/DirectoryViewer.js";import FocusCapture from"./components/FocusCapture.js";import Icon from"./components/Icon.js";import Import from"./components/Import.js";import LazyComponent from"./components/LazyComponent.js";import ReactiveComponent from"./components/ReactiveComponent.js";import ReactiveLazyComponent from"./components/ReactiveLazyComponent.js";import Resize from"./components/Resize.js";import Search from"./components/Search.js";import ShowMore from"./components/ShowMore.js";import SideMenu from"./components/SideMenu.js";import Split from"./components/Split.js";import Table from"./components/Table.js";import Tabs from"./components/Tabs.js";import Tags from"./components/Tags.js";import ThemeSwitcher from"./components/ThemeSwitcher.js";import Timestamp from"./components/Timestamp.js";import Toggle from"./components/Toggle.js";import cli from"./utils/cli.js";import cookie from"./utils/cookie.js";import debounce from"./utils/debounce.js";import drag from"./utils/drag.js";import element from"./utils/element.js";import files from"./utils/files.js";import formatTimestamp from"./utils/formatTimestamp.js";import fuzzyMatch from"./utils/fuzzyMatch.js";import getPreferredTheme from"./utils/getPreferredTheme.js";import loadCss from"./utils/loadCss.js";import loadScript from"./utils/loadScript.js";import object from"./utils/object.js";import string from"./utils/string.js";import toFunction from"./utils/toFunction.js";import type from"./utils/type.js";import waitFrames from"./utils/waitFrames.js";import watchDirectoryHandle from"./utils/watchDirectoryHandle.js";export default{Card:Card,Component:Component,Dialog:Dialog,DirectoryViewer:DirectoryViewer,FocusCapture:FocusCapture,Icon:Icon,Import:Import,LazyComponent:LazyComponent,ReactiveComponent:ReactiveComponent,ReactiveLazyComponent:ReactiveLazyComponent,Resize:Resize,Search:Search,ShowMore:ShowMore,SideMenu:SideMenu,Split:Split,Table:Table,Tabs:Tabs,Tags:Tags,ThemeSwitcher:ThemeSwitcher,Timestamp:Timestamp,Toggle:Toggle,cli:cli,cookie:cookie,debounce:debounce,drag:drag,element:element,files:files,formatTimestamp:formatTimestamp,fuzzyMatch:fuzzyMatch,getPreferredTheme:getPreferredTheme,loadCss:loadCss,loadScript:loadScript,object:object,string:string,toFunction:toFunction,type:type,waitFrames:waitFrames,watchDirectoryHandle:watchDirectoryHandle};
1
+ import Card from"./components/Card.js";import Component from"./components/Component.js";import ContentSlider from"./components/ContentSlider.js";import Dialog from"./components/Dialog.js";import DirectoryViewer from"./components/DirectoryViewer.js";import FocusCapture from"./components/FocusCapture.js";import Icon from"./components/Icon.js";import Import from"./components/Import.js";import LazyComponent from"./components/LazyComponent.js";import ReactiveComponent from"./components/ReactiveComponent.js";import ReactiveLazyComponent from"./components/ReactiveLazyComponent.js";import Resize from"./components/Resize.js";import Search from"./components/Search.js";import ShowMore from"./components/ShowMore.js";import SideMenu from"./components/SideMenu.js";import Split from"./components/Split.js";import Table from"./components/Table.js";import Tabs from"./components/Tabs.js";import Tags from"./components/Tags.js";import ThemeSwitcher from"./components/ThemeSwitcher.js";import Timestamp from"./components/Timestamp.js";import Toggle from"./components/Toggle.js";import cli from"./utils/cli.js";import cookie from"./utils/cookie.js";import debounce from"./utils/debounce.js";import drag from"./utils/drag.js";import element from"./utils/element.js";import files from"./utils/files.js";import formatTimestamp from"./utils/formatTimestamp.js";import fuzzyMatch from"./utils/fuzzyMatch.js";import getPreferredTheme from"./utils/getPreferredTheme.js";import loadCss from"./utils/loadCss.js";import loadScript from"./utils/loadScript.js";import object from"./utils/object.js";import string from"./utils/string.js";import toFunction from"./utils/toFunction.js";import type from"./utils/type.js";import waitFrames from"./utils/waitFrames.js";import watchDirectoryHandle from"./utils/watchDirectoryHandle.js";export default{Card:Card,Component:Component,ContentSlider:ContentSlider,Dialog:Dialog,DirectoryViewer:DirectoryViewer,FocusCapture:FocusCapture,Icon:Icon,Import:Import,LazyComponent:LazyComponent,ReactiveComponent:ReactiveComponent,ReactiveLazyComponent:ReactiveLazyComponent,Resize:Resize,Search:Search,ShowMore:ShowMore,SideMenu:SideMenu,Split:Split,Table:Table,Tabs:Tabs,Tags:Tags,ThemeSwitcher:ThemeSwitcher,Timestamp:Timestamp,Toggle:Toggle,cli:cli,cookie:cookie,debounce:debounce,drag:drag,element:element,files:files,formatTimestamp:formatTimestamp,fuzzyMatch:fuzzyMatch,getPreferredTheme:getPreferredTheme,loadCss:loadCss,loadScript:loadScript,object:object,string:string,toFunction:toFunction,type:type,waitFrames:waitFrames,watchDirectoryHandle:watchDirectoryHandle};
@@ -1 +1 @@
1
- :root,[theme="light"]{--c_text:#000000;--c_keyword:#0000ff;--c_builtin:#00b0e8;--c_number:#709756;--c_string:#a31515;--c_regex:#914525;--c_function:inherit;--c_comment:#008000;--c_doc:#808080;--c_tag:#7d7d7d;--c_var:#b436bf;--c_attr:#ff0000;--c_section:#a31515;--c_selector:#0000ff;--c_addition:#a31515;--c_deletion:#2b91af;--c_caret:black}[theme="dark"]{--c_text:#DCDCDC;--c_keyword:#569CD6;--c_builtin:#4EC9B0;--c_number:#B8D7A3;--c_string:#D69D85;--c_regex:#9A5334;--c_function:inehrit;--c_comment:#57A64A;--c_doc:#608B4E;--c_tag:#9B9B9B;--c_var:#BD63C5;--c_attr:#9CDCFE;--c_section:#ffd700;--c_selector:#569CD6;--c_addition:#144212;--c_deletion:#600;--c_caret:white}.hljs{display:block;overflow-x:auto;color:var(--c_text)}.hljs-keyword,.hljs-literal,.hljs-symbol,.hljs-name,.hljs-link{color:var(--c_keyword)}.hljs-link{text-decoration:underline}.hljs-built_in,.hljs-type{color:var(--c_builtin)}.hljs-number,.hljs-class{color:var(--c_number)}.hljs-string,.hljs-meta-string{color:var(--c_string)}.hljs-regexp,.hljs-template-tag{color:var(--c_regex)}.hljs-subst,.hljs-function,.hljs-title,.hljs-params,.hljs-formula{color:var(--c_function)}.hljs-comment,.hljs-quote{color:var(--c_comment);font-style:italic}.hljs-doctag{color:var(--c_doc)}.hljs-meta,.hljs-meta-keyword,.hljs-tag{color:var(--c_tag)}.hljs-variable,.hljs-template-variable{color:var(--c_var)}.hljs-attr,.hljs-attribute,.hljs-builtin-name{color:var(--c_attr)}.hljs-section{color:var(--c_section)}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}.hljs-bullet,.hljs-selector-tag,.hljs-selector-id,.hljs-selector-class,.hljs-selector-attr,.hljs-selector-pseudo{color:var(--c_selector)}.hljs-addition{background-color:var(--c_addition);display:inline-block;width:100%}.hljs-deletion{background-color:var(--c_deletion);display:inline-block;width:100%}
1
+ :root,[theme="light"]{--c_text:#000000;--c_keyword:#0000ff;--c_builtin:#00b0e8;--c_number:#709756;--c_string:#a31515;--c_regex:#914525;--c_function:inherit;--c_comment:#008000;--c_doc:#808080;--c_tag:#7d7d7d;--c_var:#b436bf;--c_attr:#ff0000;--c_section:#a31515;--c_selector:#0000ff;--c_addition:#a31515;--c_deletion:#2b91af;--c_caret:black}[auto-theme="dark"]:not([theme="light"]),[theme="dark"]{--c_text:#DCDCDC;--c_keyword:#569CD6;--c_builtin:#4EC9B0;--c_number:#B8D7A3;--c_string:#D69D85;--c_regex:#9A5334;--c_function:inehrit;--c_comment:#57A64A;--c_doc:#608B4E;--c_tag:#9B9B9B;--c_var:#BD63C5;--c_attr:#9CDCFE;--c_section:#ffd700;--c_selector:#569CD6;--c_addition:#144212;--c_deletion:#600;--c_caret:white}.hljs{display:block;overflow-x:auto;color:var(--c_text)}.hljs-keyword,.hljs-literal,.hljs-symbol,.hljs-name,.hljs-link{color:var(--c_keyword)}.hljs-link{text-decoration:underline}.hljs-built_in,.hljs-type{color:var(--c_builtin)}.hljs-number,.hljs-class{color:var(--c_number)}.hljs-string,.hljs-meta-string{color:var(--c_string)}.hljs-regexp,.hljs-template-tag{color:var(--c_regex)}.hljs-subst,.hljs-function,.hljs-title,.hljs-params,.hljs-formula{color:var(--c_function)}.hljs-comment,.hljs-quote{color:var(--c_comment);font-style:italic}.hljs-doctag{color:var(--c_doc)}.hljs-meta,.hljs-meta-keyword,.hljs-tag{color:var(--c_tag)}.hljs-variable,.hljs-template-variable{color:var(--c_var)}.hljs-attr,.hljs-attribute,.hljs-builtin-name{color:var(--c_attr)}.hljs-section{color:var(--c_section)}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}.hljs-bullet,.hljs-selector-tag,.hljs-selector-id,.hljs-selector-class,.hljs-selector-attr,.hljs-selector-pseudo{color:var(--c_selector)}.hljs-addition{background-color:var(--c_addition);display:inline-block;width:100%}.hljs-deletion{background-color:var(--c_deletion);display:inline-block;width:100%}
@@ -1 +1 @@
1
- import waitFrames from"./waitFrames.js";export const onEvent=(t,e,n,o=document)=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.addEventListener(e,n)})):t instanceof NodeList||t instanceof Array?t.forEach((t=>onEvent(t,e,n))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>onEvent(t,e,n)))};export const offEvent=(t,e,n,o=document)=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.removeEventListener(e,n)})):t instanceof NodeList||t instanceof Array?t.forEach((t=>offEvent(t,e,n))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>offEvent(t,e,n)))};export const dispatchEvent=(t,e,n,o=document)=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.dispatchEvent(new CustomEvent(e,{detail:n}))})):t instanceof NodeList||t instanceof Array?t.forEach((t=>dispatchEvent(t,e,handler))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>dispatchEvent(t,e,handler)))};export const isInView=async t=>{await waitFrames(2);const e=t.getBoundingClientRect(),n=window.innerHeight||document.documentElement.clientHeight,o=window.innerWidth||document.documentElement.clientWidth;if(e.bottom<0||e.top>n||e.right<0||e.left>o)return!1;for(;t;){const e=getComputedStyle(t);if("none"===e.display||"hidden"===e.visibility)return!1;t=t.parentElement}return!0};export const firstFocusable=t=>t.querySelector('a[href]:not([disabled]), button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])');export const setProp=(t,e,n,o=document)=>{t instanceof HTMLElement?t[e]=n:t instanceof NodeList||t instanceof Array?[...t].forEach((t=>dispatchEvent(t,e,n))):"string"==typeof t&&dispatchEvent(o.querySelectorAll(t),e,n)};export default{onEvent:onEvent,offEvent:offEvent,dispatchEvent:dispatchEvent,isInView:isInView,firstFocusable:firstFocusable,setProp:setProp};
1
+ import waitFrames from"./waitFrames.js";export const onEvent=(t,e,n,o=document)=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.addEventListener(e,n)})):t instanceof NodeList||t instanceof Array?t.forEach((t=>onEvent(t,e,n))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>onEvent(t,e,n)))};export const offEvent=(t,e,n,o=document)=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.removeEventListener(e,n)})):t instanceof NodeList||t instanceof Array?t.forEach((t=>offEvent(t,e,n))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>offEvent(t,e,n)))};export const dispatchEvent=(t,e,n,{scope:o=document,bubbles:i=!1}={})=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.dispatchEvent(new CustomEvent(e,{bubbles:i,detail:n}))})):t instanceof NodeList||t instanceof Array?t.forEach((t=>dispatchEvent(t,e,handler))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>dispatchEvent(t,e,handler)))};export const isInView=async t=>{await waitFrames(2);const e=t.getBoundingClientRect(),n=window.innerHeight||document.documentElement.clientHeight,o=window.innerWidth||document.documentElement.clientWidth;if(e.bottom<0||e.top>n||e.right<0||e.left>o)return!1;for(;t;){const e=getComputedStyle(t);if("none"===e.display||"hidden"===e.visibility)return!1;t=t.parentElement}return!0};export const firstFocusable=t=>t.querySelector('a[href]:not([disabled]), button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])');export const setProp=(t,e,n,o=document)=>{t instanceof HTMLElement?t[e]=n:t instanceof NodeList||t instanceof Array?[...t].forEach((t=>dispatchEvent(t,e,n))):"string"==typeof t&&dispatchEvent(o.querySelectorAll(t),e,n)};export default{onEvent:onEvent,offEvent:offEvent,dispatchEvent:dispatchEvent,isInView:isInView,firstFocusable:firstFocusable,setProp:setProp};
@@ -30,6 +30,8 @@
30
30
 
31
31
  <h3 id="basicUsage"><a href="#basicUsage" class="no-link">Basic Usage</a></h3>
32
32
 
33
+ <h2 id="jsRef">JavaScript Refrerence</h2>
34
+
33
35
  <h3 id="constructor"><a href="#constructor" class="no-link">Constructor</a></h3>
34
36
  <h6>Extends <a href="./component.html">Component</a></h6>
35
37
  <h5>
@@ -0,0 +1,185 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Content Slider - Components - Kempo Docs - A Web Components Solution</title>
7
+ <link rel="stylesheet" href="../kempo/kempo-vars.css" /><link rel="stylesheet" href="../kempo/kempo-styles.css" />
8
+ <link rel="stylesheet" href="../kempo/kempo-hljs.css" />
9
+ </head>
10
+ <body>
11
+ <k-import src="../nav-1.inc.html"></k-import>
12
+ <h1 class="ta-center">Content Slider</h1>
13
+ <main>
14
+ <details
15
+ class="b r mb"
16
+ >
17
+ <summary class="p">Table of Contents</summary>
18
+ <div class="m mt0 pl">
19
+ <a href="#basicUsage">Basic Usage</a><br />
20
+ <a href="#keyboardControls">Keyboard Controls</a><br />
21
+ <a href="#globalControls">Global Controls</a><br />
22
+ <a href="#controls">Controls</a><br />
23
+ <a href="#loop">Loop</a><br />
24
+ <a href="#constructor">Constructor</a><br />
25
+ <a href="#requirements">Requirements</a><br />
26
+ <a href="#attributes">Attributes</a><br />
27
+ <a href="#properties">Properties</a><br />
28
+ <a href="#methods">Methods</a><br />
29
+ </div>
30
+ </details>
31
+
32
+ <h3>Description</h3>
33
+ <p>description</p>
34
+
35
+ <h3 id="basicUsage"><a href="#basicUsage" class="no-link">Basic Usage</a></h3>
36
+ <div class="row -mx">
37
+ <div class="col d-span-6 t-span-6 m-spane-12 p">
38
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-content-slider</span><br /> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-alt"</span><br /> <span class="hljs-attr">style</span>=<span class="hljs-string">"height: 10rem"</span><br />&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 1<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 2<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 3<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 4<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /><span class="hljs-tag">&lt;/<span class="hljs-name">k-content-slider</span>&gt;</span></code></pre>
39
+ </div>
40
+ <div class="col d-span-6 t-span-6 m-spane-12 p">
41
+ <k-content-slider
42
+ class="bg-alt"
43
+ style="height: 10rem"
44
+ >
45
+ <div><p>Slide 1</p></div>
46
+ <div><p>Slide 2</p></div>
47
+ <div><p>Slide 3</p></div>
48
+ <div><p>Slide 4</p></div>
49
+ </k-content-slider>
50
+ </div>
51
+ </div>
52
+
53
+ <h3 id="keyboardControls"><a href="#keyboardControls" class="no-link">Keyboard Controls</a></h3>
54
+ <p>By default the <code>keyboard-controls</code> attribute is set to <code>"true"</code>, which allows the left and right keyboard buttons to change the slides when the component is focused. Set it to <code>"false"</code> to disable this functionality.</p>
55
+ <div class="row -mx">
56
+ <div class="col d-span-6 t-span-6 m-spane-12 p">
57
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-content-slider</span><br /> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-alt"</span><br /> <span class="hljs-attr">style</span>=<span class="hljs-string">"height: 10rem"</span><br /> <span class="hljs-attr">keyboard-controls</span>=<span class="hljs-string">"false"</span><br />&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 1<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 2<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 3<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 4<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /><span class="hljs-tag">&lt;/<span class="hljs-name">k-content-slider</span>&gt;</span></code></pre>
58
+ </div>
59
+ <div class="col d-span-6 t-span-6 m-spane-12 p">
60
+ <k-content-slider
61
+ class="bg-alt"
62
+ style="height: 10rem"
63
+ keyboard-controls="false"
64
+ >
65
+ <div><p>Slide 1</p></div>
66
+ <div><p>Slide 2</p></div>
67
+ <div><p>Slide 3</p></div>
68
+ <div><p>Slide 4</p></div>
69
+ </k-content-slider>
70
+ </div>
71
+ </div>
72
+
73
+ <h3 id="globalControls"><a href="#globalControls" class="no-link">Global Controls</a></h3>
74
+ <p>Use the <code>global-controls="true"</code> attribute to enable global controls (next and back arrows) anywhere in the window, even when this component is not focused. This is suggested when there is only one content slider on a page and it is of prominance (large slider on top of the page).</p>
75
+ <div class="row -mx">
76
+ <div class="col d-span-6 t-span-6 m-spane-12 p">
77
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-content-slider</span><br /> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-alt"</span><br /> <span class="hljs-attr">style</span>=<span class="hljs-string">"height: 10rem"</span><br /> <span class="hljs-attr">global-controls</span>=<span class="hljs-string">"true"</span><br />&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 1<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 2<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 3<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 4<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /><span class="hljs-tag">&lt;/<span class="hljs-name">k-content-slider</span>&gt;</span></code></pre>
78
+ </div>
79
+ <div class="col d-span-6 t-span-6 m-spane-12 p">
80
+ <k-content-slider
81
+ class="bg-alt"
82
+ style="height: 10rem"
83
+ global-controls="true"
84
+ >
85
+ <div><p>Slide 1</p></div>
86
+ <div><p>Slide 2</p></div>
87
+ <div><p>Slide 3</p></div>
88
+ <div><p>Slide 4</p></div>
89
+ </k-content-slider>
90
+ </div>
91
+ </div>
92
+
93
+ <h3 id="controls"><a href="#controls" class="no-link">Controls</a></h3>
94
+ <p>By default the <code>controls</code> attribute is set to <code>"true"</code>, this shows the previous and next buttons. To hide them set <code>controls="false"</code>.</p>
95
+ <div class="row -mx">
96
+ <div class="col d-span-6 t-span-6 m-spane-12 p">
97
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-content-slider</span><br /> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-alt"</span><br /> <span class="hljs-attr">style</span>=<span class="hljs-string">"height: 10rem"</span><br /> <span class="hljs-attr">controls</span>=<span class="hljs-string">"false"</span><br />&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 1<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 2<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 3<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 4<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /><span class="hljs-tag">&lt;/<span class="hljs-name">k-content-slider</span>&gt;</span></code></pre>
98
+ </div>
99
+ <div class="col d-span-6 t-span-6 m-spane-12 p">
100
+ <k-content-slider
101
+ class="bg-alt"
102
+ style="height: 10rem"
103
+ controls="false"
104
+ >
105
+ <div><p>Slide 1</p></div>
106
+ <div><p>Slide 2</p></div>
107
+ <div><p>Slide 3</p></div>
108
+ <div><p>Slide 4</p></div>
109
+ </k-content-slider>
110
+ </div>
111
+ </div>
112
+
113
+ <h3 id="loop"><a href="#loop" class="no-link">Loop</a></h3>
114
+ <p>To make the slider loop (go back to the beginning after it hits the last slide) use the <code>loop="true"</code> attribute.</p>
115
+ <div class="row -mx">
116
+ <div class="col d-span-6 t-span-6 m-spane-12 p">
117
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-content-slider</span><br /> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-alt"</span><br /> <span class="hljs-attr">style</span>=<span class="hljs-string">"height: 10rem"</span><br /> <span class="hljs-attr">loop</span>=<span class="hljs-string">"true"</span><br />&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 1<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 2<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 3<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Slide 4<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br /><span class="hljs-tag">&lt;/<span class="hljs-name">k-content-slider</span>&gt;</span></code></pre>
118
+ </div>
119
+ <div class="col d-span-6 t-span-6 m-spane-12 p">
120
+ <k-content-slider
121
+ class="bg-alt"
122
+ style="height: 10rem"
123
+ loop="true"
124
+ >
125
+ <div><p>Slide 1</p></div>
126
+ <div><p>Slide 2</p></div>
127
+ <div><p>Slide 3</p></div>
128
+ <div><p>Slide 4</p></div>
129
+ </k-content-slider>
130
+ </div>
131
+ </div>
132
+
133
+ <h2 id="jsRef">JavaScript Refrerence</h2>
134
+
135
+ <h3 id="constructor"><a href="#constructor" class="no-link">Constructor</a></h3>
136
+ <h6>Extends <a href="./lazy-component.html">LazyComponent</a></h6>
137
+ <h5>
138
+ <code>new ContentSlider()</code><br />
139
+ <code>new ContentSlider(<i>&lt;Array>HTMLElement</i> content)</code><br/>
140
+ <code>new ContentSlider(<i>&lt;Array>HTMLElement</i> content, <i>Object</i> init_attrs)</code>
141
+ </h5>
142
+
143
+ <h4>Paramters</h4>
144
+ <h5><code>content<i>: &lt;Array>HTMLElement></i></code></h5>
145
+ <p>An array of <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement" target="_blank">HTMLElement</a>s that will be the contents of this slider.</p>
146
+ <h5><code>init_attrs<i>: Object</i></code></h5>
147
+ <p>An options object that may contain the initial values of the attributes (see attributes below).</p>
148
+
149
+ <h3 id="requirements"><a href="#requirements" class="no-link">Requirements</a></h3>
150
+ <ul>
151
+ <li><a href="">LazyComponent Class</a></li>
152
+ <li><a href="">elements.js Util</a></li>
153
+ </ul>
154
+
155
+ <h3 id="attributes"><a href="#attributes" class="no-link">Attributes</a></h3>
156
+ <h5><code>index<i>: number</i></code></h5>
157
+ <p>The index of the currently active slide (base <code>0</code>). The default value is <code>0</code>.</p>
158
+
159
+ <h5><code>controls<i>: boolean</i></code></h5>
160
+ <p>A boolean that indicates if the control buttons should be shown. The default value is <code>true</code>.</p>
161
+
162
+ <h5><code>keyboardControls<i>: boolean</i></code></h5>
163
+ <p>A boolean that indicates if the left and right arrows should be used to control the slider. The default value is <code>true</code>.</p>
164
+
165
+ <h5><code>globalControls<i>: boolean</i></code></h5>
166
+ <p>A boolean that indicates if the left and right arrows should be used to control the slider even when it is not focused (the listener is on the window). The default value is <code>false</code>.</p>
167
+
168
+ <h5><code>loop<i>: boolean</i></code></h5>
169
+ <p>A boolean that indicates index should loop. When true, after the last side it will go back to the first, and when on the first slide the previous slide will be the last. The default value is <code>false</code>.</p>
170
+
171
+ <h3 id="methods"><a href="#methods" class="no-link">Methods</a></h3>
172
+ <h5><code>previous()<i>: undefined</i></code></h5>
173
+ <p>Goes to the previous slide.</p>
174
+
175
+ <h5><code>next()<i>: undefined</i></code></h5>
176
+ <p>Goes to the next slide.</p>
177
+
178
+ <h5><code>goto(<i>number<i> index)<i>: undefined</i></code></h5>
179
+ <p>Goes to the specified slide. If the index is more than the number of slides the last side will be shown. If the index is below 0, the first slide will be shown.</p>
180
+
181
+ </main>
182
+ <script type="module" src="../kempo/components/Import.js"></script>
183
+ <script type="module" src="../kempo/components/ContentSlider.js"></script>
184
+ </body>
185
+ </html>
@@ -3,13 +3,13 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Template - Components - Kempo Docs - A Web Components Solution</title>
6
+ <title>Directory Viewer - Components - Kempo Docs - A Web Components Solution</title>
7
7
  <link rel="stylesheet" href="../kempo/kempo-vars.css" /><link rel="stylesheet" href="../kempo/kempo-styles.css" />
8
8
  <link rel="stylesheet" href="../kempo/kempo-hljs.css" />
9
9
  </head>
10
10
  <body>
11
11
  <k-import src="../nav-1.inc.html"></k-import>
12
- <h1 class="ta-center">DirectoryViewer</h1>
12
+ <h1 class="ta-center">Directory Viewer</h1>
13
13
  <main>
14
14
  <details
15
15
  class="b r mb"
@@ -34,14 +34,19 @@
34
34
  <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">k-directory-viewer</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">k-directory-viewer</span>&gt;</span></code></pre>
35
35
  </div>
36
36
  <div class="col d-span-6 t-span-6 m-span-12 px">
37
- <k-directory-viewer></k-directory-viewer>
37
+ <k-directory-viewer id="dv"></k-directory-viewer>
38
+ <script type="module">
39
+ await window.customElements.whenDefined('k-directory-viewer');
40
+ document.getElementById('dv').addFilter(({kind})=>kind!='file');
41
+ document.getElementById('dv').addFilter(({name})=>!name.startsWith('.')&&!name.startsWith('_'));
42
+ </script>
38
43
  </div>
39
44
  </div>
40
45
 
41
46
 
42
47
 
43
48
  <h3 id="constructor"><a href="#constructor" class="no-link">Constructor</a></h3>
44
- <h6>Extends <a href="./lazycomponent.html">LazyComponent</a></h6>
49
+ <h6>Extends <a href="./lazy-component.html">LazyComponent</a></h6>
45
50
  <h5>
46
51
  <code>new DirectoryViewer()</code><br />
47
52
  </h5>
@@ -69,7 +69,6 @@
69
69
  <div style="height:33vh"></div>
70
70
 
71
71
  <script type="module" src="../kempo/components/Import.js"></script>
72
- <script type="module" src="../kempo/components/ShowMore.js"></script>
73
- <script type="module" src="../kempo/components/WebSnippetEditor.js"></script>
72
+ <script type="module" src="../kempo/components/ShowMore.js"></script>
74
73
  </body>
75
74
  </html>
@@ -0,0 +1 @@
1
+ import LazyComponent from"./LazyComponent.js";import{onEvent,offEvent,dispatchEvent}from"../utils/element.js";const content=Symbol(),prevClickHandler=Symbol(),nextClickHandler=Symbol(),keydownHandler=Symbol();export default class ContentSlider extends LazyComponent{constructor(n=[],{index:t=0,controls:e=!0,globalControls:o=!1,keyboardControls:s=!0,loop:i=!1}={}){super(),this[content]=[...n],this[prevClickHandler]=()=>this.previous(),this[nextClickHandler]=()=>this.next(),this[keydownHandler]=n=>{"ArrowLeft"===n.code?(n.preventDefault(),dispatchEvent(this,"keyleft"),this.previous()):"ArrowRight"===n.code&&(n.preventDefault(),dispatchEvent(this,"keyright"),this.next())},this.registerAttributes({index:t,controls:e,keyboardControls:s,globalControls:o,loop:i}),this.tabIndex=0}connectedCallback(){super.connectedCallback(),this[content]=[...this.querySelectorAll(":scope > *")]}async render(n){return!!await super.render(n)&&(this.keyboardControls&&(this.globalControls?onEvent(window,"keydown",this[keydownHandler]):(onEvent(this,"keydown",this[keydownHandler]),onEvent(this.shadowRoot,"keydown",this[keydownHandler]))),onEvent(this.shadowRoot.getElementById("prev"),"click",this[prevClickHandler]),onEvent(this.shadowRoot.getElementById("next"),"click",this[nextClickHandler]),this.renderContent(),!0)}attributeChangedCallback(n,t,e){if(super.attributeChangedCallback(n,t,e),"index"===n&&t!==e){const n=parseInt(e),t=Math.max(Math.min(this[content].length-1,n),0);n!==t?this.index=t:(dispatchEvent(this,"change",{index:t}),this.renderContent())}else"keyboard-controls"===n&&t!==e&&(this.keyboardControls?this.globalControls?onEvent(window,"keydown",this[keydownHandler]):(onEvent(this,"keydown",this[keydownHandler]),onEvent(this.shadowRoot,"keydown",this[keydownHandler])):offEvent(this.globalControls?window:this.shadowRoot,"keydown",this[keydownHandler]))}renderContent(){this.innerHTML="",this.appendChild(this[content][this.index])}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("prev"),"click",this[prevClickHandler]),offEvent(this.shadowRoot.getElementById("next"),"click",this[nextClickHandler]),offEvent(window,"keydown",this[keydownHandler]),offEvent(this.shadowRoot,"keydown",this[keydownHandler]),offEvent(this,"keydown",this[keydownHandler])}previous(){let n=this.index-1;this.loop&&n<0&&(n=this[content].length-1),dispatchEvent(this,"previous",{index:n}),this.index=n}next(){let n=this.index+1;this.loop&&n>=this[content].length&&(n=0),dispatchEvent(this,"next",{index:n}),this.index=n}goto(n){dispatchEvent(this,"goto",{index:n}),this.index=n}get shadowTemplate(){return`\n <div id="content">\n ${super.shadowTemplate}\n </div>\n <div id="controls">\n <button\n id="prev"\n class="no-btn"\n >\n <slot name="prev">\n <k-icon name="chevron-left"></k-icon>\n </slot>\n </button>\n <button\n id="next"\n class="no-btn"\n >\n <slot name="next">\n <k-icon name="chevron-right"></k-icon>\n </slot>\n </button>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n position: relative;\n outline: none;\n }\n #prev,\n #next {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n font-size: 2rem;\n }\n #next {\n right: 0;\n }\n :host(:not([controls="true"])) #controls {\n display: none;\n }\n `}static observedAttributes=[...LazyComponent.observedAttributes,"index","keyboard-controls","global-controls"]}window.customElements.define("k-content-slider",ContentSlider);
@@ -1 +1 @@
1
- import LazyComponent from"./LazyComponent.js";import Component from"./Component.js";import"./Icon.js";import{onEvent,offEvent}from"../utils/element.js";import watchDirectoryHandle from"../utils/watchDirectoryHandle.js";const handle=Symbol(),selectDirectoryClickHandler=Symbol(),openToggleClickHandler=Symbol(),fileSelectedHandler=Symbol(),watchId=Symbol(),changeCallback=Symbol();export default class DirectoryViewer extends LazyComponent{constructor(e=!1){super(),this[handle]=e,this[selectDirectoryClickHandler]=()=>this.selectDirectory(),this[openToggleClickHandler]=()=>{this.root?this.clearDirectoryHandle():this.toggleOpen()},this[changeCallback]=()=>{this.updateContents()},this.slot="content",this.registerAttributes({root:!e,hasHandle:!!e,opened:!e}),this[watchId]=!1}async render(e){return!!await super.render(e)&&(onEvent(this.shadowRoot,"fileselected",this[fileSelectedHandler]),onEvent(this.shadowRoot.getElementById("selectDirectory"),"click",this[selectDirectoryClickHandler]),onEvent(this.shadowRoot.getElementById("openToggle"),"click",this[openToggleClickHandler]),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.opened||this.root){for await(const e of this[handle].values())"directory"===e.kind&&this.appendChild(new DirectoryViewer(e,!1));for await(const e of this[handle].values())"file"===e.kind&&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("selectDirectory"),"click",this[selectDirectoryClickHandler]),offEvent(this.shadowRoot.getElementById("openToggle"),"click",this[openToggleClickHandler])}attributeChangedCallback(e,t,n){"opened"===e&&t!==n&&(!n&&this.root?this.opened=!0:this.renderContents())}async selectDirectory(){window.showDirectoryPicker&&(this[handle]=await window.showDirectoryPicker(),this[handle]&&(this.hasHandle=!0,this.renderDirectory()))}open(){this.opened=!0}close(){this.root||(this.opened=!1)}toggleOpen(){this.root||(this.opened=!this.opened)}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)}get shadowTemplate(){return`\n <button\n id="selectDirectory"\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]) #selectDirectory,\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 `}static observedAttributes=[...LazyComponent.observedAttributes,"opened"];static watchInterval=1e3}window.customElements.define("k-directory-viewer",DirectoryViewer);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])}select(){const e=this.closest("k-directory-viewer[root]").querySelector("k-directory-viewer-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
+ 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(),openToggleClickHandler=Symbol(),fileSelectedHandler=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.slot="content",this.registerAttributes({root:!e,hasHandle:!!e,opened:!e,selected:!1})}async render(e){return!!await super.render(e)&&(onEvent(this.shadowRoot,"fileselected",this[fileSelectedHandler]),onEvent(this.shadowRoot.getElementById("loadDirectory"),"click",this[loadDirectoryClickHandler]),onEvent(this.shadowRoot.getElementById("openToggle"),"click",this[openToggleClickHandler]),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()))}open(){this.opened=!0}close(){this.root||(this.opened=!1)}toggleOpen(){this.root||(this.opened=!this.opened)}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.closest("k-directory-viewer[root]").querySelector("k-directory-viewer[selected], k-directory-viewer-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);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])}select(){const e=this.closest("k-directory-viewer[root]").querySelector("k-directory-viewer[selected], k-directory-viewer-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 LazyComponent from"./LazyComponent.js";import"./Icon.js";import{onEvent,offEvent,dispatchEvent}from"../utils/element.js";export default class ShowMore extends LazyComponent{constructor(){super(),this.registerAttribute("opened",!1),this.registerProp("_toggleClickHandler",(()=>this.toggle()))}async render(n){await super.render(n),onEvent(this.shadowRoot.getElementById("toggle"),"click",this._toggleClickHandler)}more(){this.opened=!0}less(){this.opened=!1}toggle(){this.opened?this.less():this.more()}get shadowTemplate(){return`\n <div id="wrapper">\n <div id="content">\n ${super.shadowTemplate}\n </div>\n <button\n id="toggle"\n class="no-btn"\n >\n <span id="more">\n <slot name="more">Show More <k-icon name="arrow-down-double"></k-icon></slot>\n </span>\n <span id="less">\n <slot name="less">Show Less <k-icon name="arrow-up-double"></k-icon></slot>\n </span>\n </button>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n --closed_height: 7rem;\n \n display: block;\n }\n :host(:not([opened])) #content{\n height: var(--closed_height);\n overflow-y: hidden;\n }\n :host(:not([opened])) #content {\n margin-bottom: calc(var(--closed_height) * -0.9);\n }\n :host(:not([opened])) #toggle {\n padding-top: calc(var(--closed_height) - 2rem);\n background: linear-gradient(to bottom, transparent 0%, var(--c_bg) 95%);\n }\n #toggle {\n width: 100%;\n padding: var(--spacer_h);\n text-align: center;\n background: var(--c_bg);\n }\n :host([opened]) #more,\n :host(:not([opened])) #less {\n display: none;\n }\n `}}window.customElements.define("k-show-more",ShowMore);
1
+ import LazyComponent from"./LazyComponent.js";import"./Icon.js";import{onEvent,offEvent,dispatchEvent}from"../utils/element.js";const toggleClickHandler=Symbol();export default class ShowMore extends LazyComponent{constructor(){super(),this[toggleClickHandler]=()=>this.toggle(),this.registerAttribute("opened",!1)}async render(e){await super.render(e),onEvent(this.shadowRoot.getElementById("toggle"),"click",this[toggleClickHandler])}disconnectedCallback(){super.disconnectedCallback(),offEvent(this.shadowRoot.getElementById("toggle"),"click",this[toggleClickHandler])}attributeChangedCallback(e,n,t){super.attributeChangedCallback(e,n,t),"opened"===e&&n!==t&&(this.opened?dispatchEvent(this,"change opened"):dispatchEvent(this,"change closed"))}more(){this.opened=!0}less(){this.opened=!1}toggle(){this.opened=!this.opened}get shadowTemplate(){return`\n <div id="wrapper">\n <div id="content">\n ${super.shadowTemplate}\n </div>\n <button\n id="toggle"\n class="no-btn"\n >\n <span id="more">\n <slot name="more">Show More <k-icon name="arrow-down-double"></k-icon></slot>\n </span>\n <span id="less">\n <slot name="less">Show Less <k-icon name="arrow-up-double"></k-icon></slot>\n </span>\n </button>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n --closed_height: 7rem;\n \n display: block;\n }\n :host(:not([opened])) #content{\n height: var(--closed_height);\n overflow-y: hidden;\n }\n :host(:not([opened])) #content {\n margin-bottom: calc(var(--closed_height) * -0.9);\n }\n :host(:not([opened])) #toggle {\n padding-top: calc(var(--closed_height) - 2rem);\n background: linear-gradient(to bottom, transparent 0%, var(--c_bg) 95%);\n }\n #toggle {\n width: 100%;\n padding: var(--spacer_h);\n text-align: center;\n background: var(--c_bg);\n }\n :host([opened]) #more,\n :host(:not([opened])) #less {\n display: none;\n }\n `}}window.customElements.define("k-show-more",ShowMore);
@@ -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]=()=>{ThemeSwitcher.setTheme("light"===ThemeSwitcher.getCurrentTheme()?"dark":"light")},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)}get shadowTemplate(){return'\n <button\n id="toggle"\n class="no-btn"\n >\n <k-icon\n id="lightMode"\n name="light-mode"\n ></k-icon>\n <k-icon\n id="darkMode"\n name="dark-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 :host([current-theme="dark"]) #darkMode,\n :host([current-theme="light"]) #lightMode {\n display: none;\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);
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-mode"\n class="mode"\n ></k-icon>\n <k-icon\n id="darkMode"\n name="dark-mode"\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);
@@ -1 +1 @@
1
- import Card from"./components/Card.js";import Component from"./components/Component.js";import Dialog from"./components/Dialog.js";import DirectoryViewer from"./components/DirectoryViewer.js";import FocusCapture from"./components/FocusCapture.js";import Icon from"./components/Icon.js";import Import from"./components/Import.js";import LazyComponent from"./components/LazyComponent.js";import ReactiveComponent from"./components/ReactiveComponent.js";import ReactiveLazyComponent from"./components/ReactiveLazyComponent.js";import Resize from"./components/Resize.js";import Search from"./components/Search.js";import ShowMore from"./components/ShowMore.js";import SideMenu from"./components/SideMenu.js";import Split from"./components/Split.js";import Table from"./components/Table.js";import Tabs from"./components/Tabs.js";import Tags from"./components/Tags.js";import ThemeSwitcher from"./components/ThemeSwitcher.js";import Timestamp from"./components/Timestamp.js";import Toggle from"./components/Toggle.js";import cli from"./utils/cli.js";import cookie from"./utils/cookie.js";import debounce from"./utils/debounce.js";import drag from"./utils/drag.js";import element from"./utils/element.js";import files from"./utils/files.js";import formatTimestamp from"./utils/formatTimestamp.js";import fuzzyMatch from"./utils/fuzzyMatch.js";import getPreferredTheme from"./utils/getPreferredTheme.js";import loadCss from"./utils/loadCss.js";import loadScript from"./utils/loadScript.js";import object from"./utils/object.js";import string from"./utils/string.js";import toFunction from"./utils/toFunction.js";import type from"./utils/type.js";import waitFrames from"./utils/waitFrames.js";import watchDirectoryHandle from"./utils/watchDirectoryHandle.js";export default{Card:Card,Component:Component,Dialog:Dialog,DirectoryViewer:DirectoryViewer,FocusCapture:FocusCapture,Icon:Icon,Import:Import,LazyComponent:LazyComponent,ReactiveComponent:ReactiveComponent,ReactiveLazyComponent:ReactiveLazyComponent,Resize:Resize,Search:Search,ShowMore:ShowMore,SideMenu:SideMenu,Split:Split,Table:Table,Tabs:Tabs,Tags:Tags,ThemeSwitcher:ThemeSwitcher,Timestamp:Timestamp,Toggle:Toggle,cli:cli,cookie:cookie,debounce:debounce,drag:drag,element:element,files:files,formatTimestamp:formatTimestamp,fuzzyMatch:fuzzyMatch,getPreferredTheme:getPreferredTheme,loadCss:loadCss,loadScript:loadScript,object:object,string:string,toFunction:toFunction,type:type,waitFrames:waitFrames,watchDirectoryHandle:watchDirectoryHandle};
1
+ import Card from"./components/Card.js";import Component from"./components/Component.js";import ContentSlider from"./components/ContentSlider.js";import Dialog from"./components/Dialog.js";import DirectoryViewer from"./components/DirectoryViewer.js";import FocusCapture from"./components/FocusCapture.js";import Icon from"./components/Icon.js";import Import from"./components/Import.js";import LazyComponent from"./components/LazyComponent.js";import ReactiveComponent from"./components/ReactiveComponent.js";import ReactiveLazyComponent from"./components/ReactiveLazyComponent.js";import Resize from"./components/Resize.js";import Search from"./components/Search.js";import ShowMore from"./components/ShowMore.js";import SideMenu from"./components/SideMenu.js";import Split from"./components/Split.js";import Table from"./components/Table.js";import Tabs from"./components/Tabs.js";import Tags from"./components/Tags.js";import ThemeSwitcher from"./components/ThemeSwitcher.js";import Timestamp from"./components/Timestamp.js";import Toggle from"./components/Toggle.js";import cli from"./utils/cli.js";import cookie from"./utils/cookie.js";import debounce from"./utils/debounce.js";import drag from"./utils/drag.js";import element from"./utils/element.js";import files from"./utils/files.js";import formatTimestamp from"./utils/formatTimestamp.js";import fuzzyMatch from"./utils/fuzzyMatch.js";import getPreferredTheme from"./utils/getPreferredTheme.js";import loadCss from"./utils/loadCss.js";import loadScript from"./utils/loadScript.js";import object from"./utils/object.js";import string from"./utils/string.js";import toFunction from"./utils/toFunction.js";import type from"./utils/type.js";import waitFrames from"./utils/waitFrames.js";import watchDirectoryHandle from"./utils/watchDirectoryHandle.js";export default{Card:Card,Component:Component,ContentSlider:ContentSlider,Dialog:Dialog,DirectoryViewer:DirectoryViewer,FocusCapture:FocusCapture,Icon:Icon,Import:Import,LazyComponent:LazyComponent,ReactiveComponent:ReactiveComponent,ReactiveLazyComponent:ReactiveLazyComponent,Resize:Resize,Search:Search,ShowMore:ShowMore,SideMenu:SideMenu,Split:Split,Table:Table,Tabs:Tabs,Tags:Tags,ThemeSwitcher:ThemeSwitcher,Timestamp:Timestamp,Toggle:Toggle,cli:cli,cookie:cookie,debounce:debounce,drag:drag,element:element,files:files,formatTimestamp:formatTimestamp,fuzzyMatch:fuzzyMatch,getPreferredTheme:getPreferredTheme,loadCss:loadCss,loadScript:loadScript,object:object,string:string,toFunction:toFunction,type:type,waitFrames:waitFrames,watchDirectoryHandle:watchDirectoryHandle};
@@ -1 +1 @@
1
- :root,[theme="light"]{--c_text:#000000;--c_keyword:#0000ff;--c_builtin:#00b0e8;--c_number:#709756;--c_string:#a31515;--c_regex:#914525;--c_function:inherit;--c_comment:#008000;--c_doc:#808080;--c_tag:#7d7d7d;--c_var:#b436bf;--c_attr:#ff0000;--c_section:#a31515;--c_selector:#0000ff;--c_addition:#a31515;--c_deletion:#2b91af;--c_caret:black}[theme="dark"]{--c_text:#DCDCDC;--c_keyword:#569CD6;--c_builtin:#4EC9B0;--c_number:#B8D7A3;--c_string:#D69D85;--c_regex:#9A5334;--c_function:inehrit;--c_comment:#57A64A;--c_doc:#608B4E;--c_tag:#9B9B9B;--c_var:#BD63C5;--c_attr:#9CDCFE;--c_section:#ffd700;--c_selector:#569CD6;--c_addition:#144212;--c_deletion:#600;--c_caret:white}.hljs{display:block;overflow-x:auto;color:var(--c_text)}.hljs-keyword,.hljs-literal,.hljs-symbol,.hljs-name,.hljs-link{color:var(--c_keyword)}.hljs-link{text-decoration:underline}.hljs-built_in,.hljs-type{color:var(--c_builtin)}.hljs-number,.hljs-class{color:var(--c_number)}.hljs-string,.hljs-meta-string{color:var(--c_string)}.hljs-regexp,.hljs-template-tag{color:var(--c_regex)}.hljs-subst,.hljs-function,.hljs-title,.hljs-params,.hljs-formula{color:var(--c_function)}.hljs-comment,.hljs-quote{color:var(--c_comment);font-style:italic}.hljs-doctag{color:var(--c_doc)}.hljs-meta,.hljs-meta-keyword,.hljs-tag{color:var(--c_tag)}.hljs-variable,.hljs-template-variable{color:var(--c_var)}.hljs-attr,.hljs-attribute,.hljs-builtin-name{color:var(--c_attr)}.hljs-section{color:var(--c_section)}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}.hljs-bullet,.hljs-selector-tag,.hljs-selector-id,.hljs-selector-class,.hljs-selector-attr,.hljs-selector-pseudo{color:var(--c_selector)}.hljs-addition{background-color:var(--c_addition);display:inline-block;width:100%}.hljs-deletion{background-color:var(--c_deletion);display:inline-block;width:100%}
1
+ :root,[theme="light"]{--c_text:#000000;--c_keyword:#0000ff;--c_builtin:#00b0e8;--c_number:#709756;--c_string:#a31515;--c_regex:#914525;--c_function:inherit;--c_comment:#008000;--c_doc:#808080;--c_tag:#7d7d7d;--c_var:#b436bf;--c_attr:#ff0000;--c_section:#a31515;--c_selector:#0000ff;--c_addition:#a31515;--c_deletion:#2b91af;--c_caret:black}[auto-theme="dark"]:not([theme="light"]),[theme="dark"]{--c_text:#DCDCDC;--c_keyword:#569CD6;--c_builtin:#4EC9B0;--c_number:#B8D7A3;--c_string:#D69D85;--c_regex:#9A5334;--c_function:inehrit;--c_comment:#57A64A;--c_doc:#608B4E;--c_tag:#9B9B9B;--c_var:#BD63C5;--c_attr:#9CDCFE;--c_section:#ffd700;--c_selector:#569CD6;--c_addition:#144212;--c_deletion:#600;--c_caret:white}.hljs{display:block;overflow-x:auto;color:var(--c_text)}.hljs-keyword,.hljs-literal,.hljs-symbol,.hljs-name,.hljs-link{color:var(--c_keyword)}.hljs-link{text-decoration:underline}.hljs-built_in,.hljs-type{color:var(--c_builtin)}.hljs-number,.hljs-class{color:var(--c_number)}.hljs-string,.hljs-meta-string{color:var(--c_string)}.hljs-regexp,.hljs-template-tag{color:var(--c_regex)}.hljs-subst,.hljs-function,.hljs-title,.hljs-params,.hljs-formula{color:var(--c_function)}.hljs-comment,.hljs-quote{color:var(--c_comment);font-style:italic}.hljs-doctag{color:var(--c_doc)}.hljs-meta,.hljs-meta-keyword,.hljs-tag{color:var(--c_tag)}.hljs-variable,.hljs-template-variable{color:var(--c_var)}.hljs-attr,.hljs-attribute,.hljs-builtin-name{color:var(--c_attr)}.hljs-section{color:var(--c_section)}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}.hljs-bullet,.hljs-selector-tag,.hljs-selector-id,.hljs-selector-class,.hljs-selector-attr,.hljs-selector-pseudo{color:var(--c_selector)}.hljs-addition{background-color:var(--c_addition);display:inline-block;width:100%}.hljs-deletion{background-color:var(--c_deletion);display:inline-block;width:100%}
@@ -1 +1 @@
1
- import waitFrames from"./waitFrames.js";export const onEvent=(t,e,n,o=document)=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.addEventListener(e,n)})):t instanceof NodeList||t instanceof Array?t.forEach((t=>onEvent(t,e,n))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>onEvent(t,e,n)))};export const offEvent=(t,e,n,o=document)=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.removeEventListener(e,n)})):t instanceof NodeList||t instanceof Array?t.forEach((t=>offEvent(t,e,n))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>offEvent(t,e,n)))};export const dispatchEvent=(t,e,n,o=document)=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.dispatchEvent(new CustomEvent(e,{detail:n}))})):t instanceof NodeList||t instanceof Array?t.forEach((t=>dispatchEvent(t,e,handler))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>dispatchEvent(t,e,handler)))};export const isInView=async t=>{await waitFrames(2);const e=t.getBoundingClientRect(),n=window.innerHeight||document.documentElement.clientHeight,o=window.innerWidth||document.documentElement.clientWidth;if(e.bottom<0||e.top>n||e.right<0||e.left>o)return!1;for(;t;){const e=getComputedStyle(t);if("none"===e.display||"hidden"===e.visibility)return!1;t=t.parentElement}return!0};export const firstFocusable=t=>t.querySelector('a[href]:not([disabled]), button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])');export const setProp=(t,e,n,o=document)=>{t instanceof HTMLElement?t[e]=n:t instanceof NodeList||t instanceof Array?[...t].forEach((t=>dispatchEvent(t,e,n))):"string"==typeof t&&dispatchEvent(o.querySelectorAll(t),e,n)};export default{onEvent:onEvent,offEvent:offEvent,dispatchEvent:dispatchEvent,isInView:isInView,firstFocusable:firstFocusable,setProp:setProp};
1
+ import waitFrames from"./waitFrames.js";export const onEvent=(t,e,n,o=document)=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.addEventListener(e,n)})):t instanceof NodeList||t instanceof Array?t.forEach((t=>onEvent(t,e,n))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>onEvent(t,e,n)))};export const offEvent=(t,e,n,o=document)=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.removeEventListener(e,n)})):t instanceof NodeList||t instanceof Array?t.forEach((t=>offEvent(t,e,n))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>offEvent(t,e,n)))};export const dispatchEvent=(t,e,n,{scope:o=document,bubbles:i=!1}={})=>{t instanceof EventTarget?e.toLowerCase().split(" ").forEach((e=>{t.dispatchEvent(new CustomEvent(e,{bubbles:i,detail:n}))})):t instanceof NodeList||t instanceof Array?t.forEach((t=>dispatchEvent(t,e,handler))):"string"==typeof t&&o.querySelectorAll(t).forEach((t=>dispatchEvent(t,e,handler)))};export const isInView=async t=>{await waitFrames(2);const e=t.getBoundingClientRect(),n=window.innerHeight||document.documentElement.clientHeight,o=window.innerWidth||document.documentElement.clientWidth;if(e.bottom<0||e.top>n||e.right<0||e.left>o)return!1;for(;t;){const e=getComputedStyle(t);if("none"===e.display||"hidden"===e.visibility)return!1;t=t.parentElement}return!0};export const firstFocusable=t=>t.querySelector('a[href]:not([disabled]), button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])');export const setProp=(t,e,n,o=document)=>{t instanceof HTMLElement?t[e]=n:t instanceof NodeList||t instanceof Array?[...t].forEach((t=>dispatchEvent(t,e,n))):"string"==typeof t&&dispatchEvent(o.querySelectorAll(t),e,n)};export default{onEvent:onEvent,offEvent:offEvent,dispatchEvent:dispatchEvent,isInView:isInView,firstFocusable:firstFocusable,setProp:setProp};
@@ -35,12 +35,13 @@
35
35
  <h5 class="mb0">Components</h5>
36
36
  <div class="pl mb">
37
37
  <a href="../components/component.html">Component</a>
38
- <a href="../components/lazycomponent.html">LazyComponent</a>
38
+ <a href="../components/lazy-component.html">LazyComponent</a>
39
39
  <a href="../components/reactivecomponent.html">ReactiveComponent</a>
40
- <a href="../components/reactivelazycomponent.html">ReactiveLazyComponent</a>
40
+ <a href="../components/reactivelazy-component.html">ReactiveLazyComponent</a>
41
41
  <a href="../components/focuscapture.html">FocusCapture</a>
42
42
  <hr />
43
43
  <a href="../components/card.html">Card</a>
44
+ <a href="../components/content-slider.html">Content Slider</a>
44
45
  <a href="../components/dialog.html">Dialog</a>
45
46
  <a href="../components/directory-viewer.html">Directory Viewer</a>
46
47
  <a href="../components/icon.html">Icon</a>
package/docs/nav.inc.html CHANGED
@@ -35,13 +35,13 @@
35
35
  <h5 class="mb0">Components</h5>
36
36
  <div class="pl mb">
37
37
  <a href="./components/component.html">Component</a>
38
- <a href="./components/lazycomponent.html">LazyComponent</a>
38
+ <a href="./components/lazy-component.html">LazyComponent</a>
39
39
  <a href="./components/reactivecomponent.html">ReactiveComponent</a>
40
- <a href="./components/reactivelazycomponent.html">ReactiveLazyComponent</a>
40
+ <a href="./components/reactivelazy-component.html">ReactiveLazyComponent</a>
41
41
  <a href="./components/focuscapture.html">FocusCapture</a>
42
42
  <hr />
43
- <a href="./components/codeeditor.html">Code Editor</a>
44
43
  <a href="./components/card.html">Card</a>
44
+ <a href="./components/content-slider.html">Content Slider</a>
45
45
  <a href="./components/dialog.html">Dialog</a>
46
46
  <a href="./components/directory-viewer.html">Directory Viewer</a>
47
47
  <a href="./components/icon.html">Icon</a>
@@ -53,7 +53,6 @@
53
53
  <a href="./components/table.html">Table</a>
54
54
  <a href="./components/tabs.html">Tabs</a>
55
55
  <a href="./components/toggle.html">Toggle</a>
56
- <a href="./components/websnippeteditor.html">Web Snippet Editor</a>
57
56
  </div>
58
57
  </menu>
59
58
  </k-side-menu>
package/docs/search.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "parent"
10
10
  ]
11
11
  },
12
- "/components/lazycomponent.html": {
12
+ "/components/lazy-component.html": {
13
13
  "name": "Components > LazyComponent",
14
14
  "terms": [
15
15
  "lazy",
@@ -20,6 +20,14 @@
20
20
  "parent"
21
21
  ]
22
22
  },
23
+ "/components/content-slider.html": {
24
+ "name": "Components > Content Slider",
25
+ "terms": [
26
+ "content",
27
+ "slider",
28
+ "photos"
29
+ ]
30
+ },
23
31
  "/components/directoryviewer.html": {
24
32
  "name": "Components > DirectoryViewer",
25
33
  "terms": [
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M240-500v-220h220v220H240Zm0 260v-220h220v220H240Zm260-260v-220h220v220H500Zm0 260v-220h220v220H500ZM320-580h60v-60h-60v60Zm260 0h60v-60h-60v60ZM320-320h60v-60h-60v60Zm260 0h60v-60h-60v60ZM380-580Zm200 0Zm0 200Zm-200 0ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M480-160v-80h120l180-240-180-240H160v200H80v-200q0-33 23.5-56.5T160-800h440q19 0 36 8.5t28 23.5l216 288-216 288q-11 15-28 23.5t-36 8.5H480Zm-10-320ZM200-120v-120H80v-80h120v-120h80v120h120v80H280v120h-80Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h440q19 0 36 8.5t28 23.5l216 288-216 288q-11 15-28 23.5t-36 8.5H160Zm0-80h440l180-240-180-240H160v480Zm220-240Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M 440 -920 L 440 -760 L 520 -760 L 520 -920 L 440 -920 z M 818.67969 -885.5332 L 583.66602 -651.38281 C 553.04363 -670.31258 518.55019 -680 480 -680 C 424.66678 -680 377.49992 -660.49992 338.5 -621.5 C 299.50008 -582.50008 280 -535.33322 280 -480 C 280 -441.71314 289.5643 -407.43184 308.23633 -376.96484 L 97.058594 -166.5625 L 168.59375 -92.332031 L 263.80078 -187.18945 C 267.09506 -183.63709 270.46257 -180.11555 273.9375 -176.64062 C 343.93736 -106.64077 428.9377 -71.640625 528.9375 -71.640625 C 628.9373 -71.640625 713.93764 -106.64077 783.9375 -176.64062 C 853.93736 -246.64049 888.9375 -331.64082 888.9375 -431.64062 C 888.9375 -440.97395 888.60417 -450.14064 887.9375 -459.14062 C 887.27083 -468.14062 886.27083 -476.97398 884.9375 -485.64062 C 865.60421 -458.30735 840.60411 -436.47393 809.9375 -420.14062 C 779.27089 -403.80733 745.60409 -395.64062 708.9375 -395.64062 C 648.93762 -395.64062 597.93742 -416.64072 555.9375 -458.64062 C 552.62172 -461.95641 549.47084 -465.3433 546.42188 -468.77344 L 890.21484 -811.30273 L 818.67969 -885.5332 z M 212 -806 L 155 -747 L 256 -650 L 308 -706 L 212 -806 z M 480 -600 C 495.83397 -600 510.50253 -597.28065 524.08008 -592.01562 L 367.83594 -436.34375 C 362.67843 -449.80488 360 -464.32853 360 -480 C 360 -513.33327 371.66671 -541.66671 395 -565 C 418.33329 -588.33329 446.66673 -600 480 -600 z M 40 -520 L 40 -440 L 200 -440 L 200 -520 L 40 -520 z M 489.73047 -412.28906 C 492.87534 -408.86757 496.09809 -405.48004 499.4375 -402.14062 C 557.10405 -344.47408 626.93766 -315.64062 708.9375 -315.64062 C 722.27081 -315.64062 735.60419 -316.64064 748.9375 -318.64062 C 762.27081 -320.64062 775.60419 -323.3073 788.9375 -326.64062 C 767.60421 -274.64074 733.60407 -232.4739 686.9375 -200.14062 C 640.27093 -167.80736 587.60405 -151.64062 528.9375 -151.64062 C 451.60432 -151.64062 385.60406 -178.97407 330.9375 -233.64062 C 327.48999 -237.08813 324.17746 -240.59082 320.95312 -244.13086 L 489.73047 -412.28906 z " /></svg>
package/icons/tag.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="m240-160 40-160H120l20-80h160l40-160H180l20-80h160l40-160h80l-40 160h160l40-160h80l-40 160h160l-20 80H660l-40 160h160l-20 80H600l-40 160h-80l40-160H360l-40 160h-80Zm140-240h160l40-160H420l-40 160Z"/></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kempo",
3
- "version": "2.1.1",
3
+ "version": "2.3.0",
4
4
  "type": "module",
5
5
  "description": "A web component library",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,192 @@
1
+ import LazyComponent from './LazyComponent.js';
2
+ import {
3
+ onEvent,
4
+ offEvent,
5
+ dispatchEvent
6
+ } from '../utils/element.js';
7
+
8
+ const content = Symbol(),
9
+ prevClickHandler = Symbol(),
10
+ nextClickHandler = Symbol(),
11
+ keydownHandler = Symbol();
12
+ export default class ContentSlider extends LazyComponent {
13
+ constructor(_content = [], {
14
+ index = 0,
15
+ controls = true,
16
+ globalControls = false,
17
+ keyboardControls = true,
18
+ loop = false
19
+ } = {}){
20
+ super();
21
+
22
+ /* Private Members */
23
+ this[content] = [..._content];
24
+
25
+ /* Private Methods */
26
+ this[prevClickHandler] = () => this.previous();
27
+ this[nextClickHandler] = () => this.next();
28
+ this[keydownHandler] = (event) => {
29
+ if(event.code === 'ArrowLeft'){
30
+ event.preventDefault();
31
+ dispatchEvent(this, 'keyleft');
32
+ this.previous();
33
+ } else if(event.code === 'ArrowRight'){
34
+ event.preventDefault();
35
+ dispatchEvent(this, 'keyright');
36
+ this.next();
37
+ }
38
+ }
39
+
40
+ /* Init */
41
+ this.registerAttributes({
42
+ index,
43
+ controls,
44
+ keyboardControls,
45
+ globalControls,
46
+ loop
47
+ });
48
+ this.tabIndex = 0;
49
+ }
50
+
51
+ /* Lifecycle Callback */
52
+ connectedCallback(){
53
+ super.connectedCallback();
54
+ this[content] = [...this.querySelectorAll(':scope > *')];
55
+ }
56
+ async render(force){
57
+ if(await super.render(force)){
58
+ if(this.keyboardControls){ // add keyboard controls
59
+ if(this.globalControls){
60
+ onEvent(window, 'keydown', this[keydownHandler]);
61
+ } else {
62
+ onEvent(this, 'keydown', this[keydownHandler]);
63
+ onEvent(this.shadowRoot, 'keydown', this[keydownHandler]);
64
+ }
65
+ }
66
+ onEvent(this.shadowRoot.getElementById('prev'), 'click', this[prevClickHandler]);
67
+ onEvent(this.shadowRoot.getElementById('next'), 'click', this[nextClickHandler]);
68
+ this.renderContent();
69
+ return true;
70
+ }
71
+ return false;
72
+ }
73
+ attributeChangedCallback(n, oV, nV){
74
+ super.attributeChangedCallback(n, oV, nV);
75
+ if(n === 'index' && oV !== nV){
76
+ const newIndex = parseInt(nV);
77
+ const validNew = Math.max(Math.min(this[content].length-1, newIndex), 0);
78
+ if(newIndex !== validNew){
79
+ this.index = validNew;
80
+ } else {
81
+ dispatchEvent(this, 'change', {
82
+ index: validNew
83
+ });
84
+ this.renderContent();
85
+ }
86
+ } else if(n === 'keyboard-controls' && oV !== nV){
87
+ if(this.keyboardControls){ // add keyboard controls
88
+ if(this.globalControls){
89
+ onEvent(window, 'keydown', this[keydownHandler]);
90
+ } else {
91
+ onEvent(this, 'keydown', this[keydownHandler]);
92
+ onEvent(this.shadowRoot, 'keydown', this[keydownHandler]);
93
+ }
94
+ } else { // remove keyboard controls
95
+ offEvent(this.globalControls?window:this.shadowRoot, 'keydown', this[keydownHandler]);
96
+ }
97
+ }
98
+ }
99
+ renderContent(){
100
+ this.innerHTML = '';
101
+ this.appendChild(this[content][this.index]);
102
+ }
103
+ disconnectedCallback(){
104
+ super.disconnectedCallback();
105
+ offEvent(this.shadowRoot.getElementById('prev'), 'click', this[prevClickHandler]);
106
+ offEvent(this.shadowRoot.getElementById('next'), 'click', this[nextClickHandler]);
107
+ offEvent(window, 'keydown', this[keydownHandler]);
108
+ offEvent(this.shadowRoot, 'keydown', this[keydownHandler]);
109
+ offEvent(this, 'keydown', this[keydownHandler]);
110
+ }
111
+
112
+ /* Public Methods */
113
+ previous(){
114
+ let newIndex = this.index - 1;
115
+ if(this.loop){
116
+ if(newIndex < 0) newIndex = this[content].length - 1;
117
+ }
118
+ dispatchEvent(this, 'previous', {index: newIndex});
119
+ this.index = newIndex;
120
+ }
121
+ next(){
122
+ let newIndex = this.index + 1;
123
+ if(this.loop){
124
+ if(newIndex >= this[content].length) newIndex = 0;
125
+ }
126
+ dispatchEvent(this, 'next', {index: newIndex});
127
+ this.index = newIndex;
128
+ }
129
+ goto(newIndex){
130
+ dispatchEvent(this, 'goto', {index: newIndex});
131
+ this.index = newIndex;
132
+ }
133
+
134
+ /* Shadow DOM */
135
+ get shadowTemplate(){
136
+ return /*html*/`
137
+ <div id="content">
138
+ ${super.shadowTemplate}
139
+ </div>
140
+ <div id="controls">
141
+ <button
142
+ id="prev"
143
+ class="no-btn"
144
+ >
145
+ <slot name="prev">
146
+ <k-icon name="chevron-left"></k-icon>
147
+ </slot>
148
+ </button>
149
+ <button
150
+ id="next"
151
+ class="no-btn"
152
+ >
153
+ <slot name="next">
154
+ <k-icon name="chevron-right"></k-icon>
155
+ </slot>
156
+ </button>
157
+ </div>
158
+ `;
159
+ }
160
+ get shadowStyles(){
161
+ return /*css*/`
162
+ ${super.shadowStyles}
163
+ :host {
164
+ display: block;
165
+ position: relative;
166
+ outline: none;
167
+ }
168
+ #prev,
169
+ #next {
170
+ position: absolute;
171
+ top: 50%;
172
+ transform: translateY(-50%);
173
+ font-size: 2rem;
174
+ }
175
+ #next {
176
+ right: 0;
177
+ }
178
+ :host(:not([controls="true"])) #controls {
179
+ display: none;
180
+ }
181
+ `;
182
+ }
183
+
184
+ /* Static Members */
185
+ static observedAttributes = [
186
+ ...LazyComponent.observedAttributes,
187
+ 'index',
188
+ 'keyboard-controls',
189
+ 'global-controls'
190
+ ];
191
+ }
192
+ window.customElements.define('k-content-slider', ContentSlider);
@@ -3,28 +3,33 @@ import Component from './Component.js';
3
3
  import './Icon.js';
4
4
  import {
5
5
  onEvent,
6
- offEvent
6
+ offEvent,
7
+ dispatchEvent
7
8
  } from '../utils/element.js';
8
9
  import watchDirectoryHandle from '../utils/watchDirectoryHandle.js';
9
10
 
10
11
  const handle = Symbol(),
11
- selectDirectoryClickHandler = Symbol(),
12
+ loadDirectoryClickHandler = Symbol(),
12
13
  openToggleClickHandler = Symbol(),
13
14
  fileSelectedHandler = Symbol(),
14
15
  watchId = Symbol(),
15
- changeCallback = Symbol();
16
+ changeCallback = Symbol(),
17
+ filters = Symbol();
16
18
  export default class DirectoryViewer extends LazyComponent {
17
19
  constructor(_handle = false){
18
20
  super();
19
21
 
20
22
  /* Private Members */
21
23
  this[handle] = _handle;
24
+ this[watchId] = false;
25
+ this[filters] = [];
22
26
 
23
27
  /* Private Methods */
24
- this[selectDirectoryClickHandler] = () => this.selectDirectory();
28
+ this[loadDirectoryClickHandler] = () => this.loadDirectory();
25
29
  this[openToggleClickHandler] = () => {
26
30
  if(!this.root){
27
31
  this.toggleOpen();
32
+ this.select();
28
33
  } else {
29
34
  this.clearDirectoryHandle();
30
35
  }
@@ -38,16 +43,16 @@ export default class DirectoryViewer extends LazyComponent {
38
43
  this.registerAttributes({
39
44
  root: !_handle,
40
45
  hasHandle: !!_handle,
41
- opened: !_handle
46
+ opened: !_handle,
47
+ selected: false
42
48
  });
43
- this[watchId] = false;
44
49
  }
45
50
 
46
51
  /* Lifecycle Callbacks */
47
52
  async render(force){
48
53
  if(await super.render(force)){
49
54
  onEvent(this.shadowRoot, 'fileselected', this[fileSelectedHandler]);
50
- onEvent(this.shadowRoot.getElementById('selectDirectory'), 'click', this[selectDirectoryClickHandler]);
55
+ onEvent(this.shadowRoot.getElementById('loadDirectory'), 'click', this[loadDirectoryClickHandler]);
51
56
  onEvent(this.shadowRoot.getElementById('openToggle'), 'click', this[openToggleClickHandler]);
52
57
  this.renderDirectory();
53
58
  return true;
@@ -61,15 +66,23 @@ export default class DirectoryViewer extends LazyComponent {
61
66
  }
62
67
  async renderContents(){
63
68
  this.querySelectorAll('[slot="content"]').forEach(e=>e.remove());
64
- if(this.opened || this.root){
69
+ if(
70
+ this.rendered &&
71
+ this[handle] &&
72
+ (this.opened || this.root)
73
+ ){
65
74
  for await(const entry of this[handle].values()){
66
75
  if(entry.kind === 'directory'){
67
- this.appendChild(new DirectoryViewer(entry, false));
76
+ if(this.filters.every(filter=>filter(entry))){
77
+ this.appendChild(new DirectoryViewer(entry, false));
78
+ }
68
79
  }
69
80
  }
70
81
  for await(const entry of this[handle].values()){
71
82
  if(entry.kind === 'file'){
72
- this.appendChild(new File(entry));
83
+ if(this.filters.every(filter=>filter(entry))){
84
+ this.appendChild(new File(entry));
85
+ }
73
86
  }
74
87
  }
75
88
  if(!this[watchId]) this[watchId] = watchDirectoryHandle(this[handle], this[changeCallback]);
@@ -83,7 +96,7 @@ export default class DirectoryViewer extends LazyComponent {
83
96
  disconnectedCallback(){
84
97
  super.disconnectedCallback();
85
98
  offEvent(this.shadowRoot, 'fileselected', this[fileSelectedHandler]);
86
- offEvent(this.shadowRoot.getElementById('selectDirectory'), 'click', this[selectDirectoryClickHandler]);
99
+ offEvent(this.shadowRoot.getElementById('loadDirectory'), 'click', this[loadDirectoryClickHandler]);
87
100
  offEvent(this.shadowRoot.getElementById('openToggle'), 'click', this[openToggleClickHandler]);
88
101
  }
89
102
  attributeChangedCallback(n, oV, nV){
@@ -96,13 +109,26 @@ export default class DirectoryViewer extends LazyComponent {
96
109
  }
97
110
  }
98
111
 
112
+ /* Protected Members */
113
+ get rootDir(){
114
+ if(this.root) return this;
115
+ else return this.closest('k-directory-viewer[root="true"]')
116
+ }
117
+ get filters(){
118
+ return this.rootDir[filters];
119
+ }
120
+
99
121
 
100
122
  /* Public Methods */
101
- async selectDirectory(){
123
+ async loadDirectory(){
102
124
  if(window.showDirectoryPicker){
103
125
  this[handle] = await window.showDirectoryPicker();
104
126
  if(this[handle]){
105
127
  this.hasHandle = true;
128
+ dispatchEvent(this, 'directoryloaded', {
129
+ dirHandle: this[handle],
130
+ dirComponent: this
131
+ });
106
132
  this.renderDirectory();
107
133
  }
108
134
  }
@@ -156,12 +182,30 @@ export default class DirectoryViewer extends LazyComponent {
156
182
  }
157
183
  }
158
184
  }
185
+ select(){
186
+ const $currentSelection = this.closest('k-directory-viewer[root]').querySelector('k-directory-viewer[selected], k-directory-viewer-file[selected]');
187
+ if($currentSelection === this) return;
188
+ if($currentSelection) $currentSelection.selected = false;
189
+ this.selected = true;
190
+ this.dispatchEvent(new CustomEvent('dirselected', {
191
+ detail: {
192
+ dirHandle: this[handle],
193
+ dirComponent: this
194
+ },
195
+ bubbles: true,
196
+ composed: true
197
+ }));
198
+ }
199
+ addFilter(filter){
200
+ this[filters].push(filter);
201
+ this.renderContents();
202
+ }
159
203
 
160
204
  /* Shadow DOM */
161
205
  get shadowTemplate(){
162
206
  return /*html*/`
163
207
  <button
164
- id="selectDirectory"
208
+ id="loadDirectory"
165
209
  >
166
210
  <slot name="selectButton">
167
211
  <k-icon name="folder-create"></k-icon> Select Directory
@@ -184,7 +228,7 @@ export default class DirectoryViewer extends LazyComponent {
184
228
  get shadowStyles(){
185
229
  return /*css*/`
186
230
  ${super.shadowStyles}
187
- :host([has-handle]) #selectDirectory,
231
+ :host([has-handle]) #loadDirectory,
188
232
  :host([opened]) #folder-closed,
189
233
  :host(:not([opened])) #folder-opened,
190
234
  :host(:not([has-handle])) #folder-closed,
@@ -208,6 +252,11 @@ export default class DirectoryViewer extends LazyComponent {
208
252
  #clearSelectedDirectory {
209
253
  flex: none;
210
254
  }
255
+ :host([selected]) #openToggle {
256
+ background-color: var(--c_primary);
257
+ color: var(--tc_on_primary);
258
+ border-radius: var(--raidus);
259
+ }
211
260
  `;
212
261
  }
213
262
 
@@ -263,7 +312,7 @@ export class File extends Component {
263
312
 
264
313
  /* Public Methods */
265
314
  select(){
266
- const $currentSelection = this.closest('k-directory-viewer[root]').querySelector('k-directory-viewer-file[selected]');
315
+ const $currentSelection = this.closest('k-directory-viewer[root]').querySelector('k-directory-viewer[selected], k-directory-viewer-file[selected]');
267
316
  if($currentSelection === this) return;
268
317
  if($currentSelection) $currentSelection.selected = false;
269
318
  this.selected = true;
@@ -6,17 +6,37 @@ import {
6
6
  dispatchEvent
7
7
  } from '../utils/element.js';
8
8
 
9
+ const toggleClickHandler = Symbol();
9
10
  export default class ShowMore extends LazyComponent {
10
11
  constructor(){
11
12
  super();
12
13
 
14
+ this[toggleClickHandler] = () => this.toggle();
15
+
13
16
  this.registerAttribute('opened', false);
14
- this.registerProp('_toggleClickHandler', () => this.toggle());
15
17
  }
18
+
19
+ /* Lifecycle Callbacks */
16
20
  async render(force){
17
21
  await super.render(force);
18
- onEvent(this.shadowRoot.getElementById('toggle'), 'click', this._toggleClickHandler);
22
+ onEvent(this.shadowRoot.getElementById('toggle'), 'click', this[toggleClickHandler]);
23
+ }
24
+ disconnectedCallback(){
25
+ super.disconnectedCallback();
26
+ offEvent(this.shadowRoot.getElementById('toggle'), 'click', this[toggleClickHandler]);
19
27
  }
28
+ attributeChangedCallback(n, oV, nV){
29
+ super.attributeChangedCallback(n, oV, nV);
30
+ if(n === 'opened' && oV !== nV){
31
+ if(this.opened){
32
+ dispatchEvent(this, 'change opened');
33
+ } else {
34
+ dispatchEvent(this, 'change closed');
35
+ }
36
+ }
37
+ }
38
+
39
+ /* Public Methods */
20
40
  more(){
21
41
  this.opened = true;
22
42
  }
@@ -24,7 +44,7 @@ export default class ShowMore extends LazyComponent {
24
44
  this.opened = false;
25
45
  }
26
46
  toggle(){
27
- this.opened?this.less():this.more();
47
+ this.opened = !this.opened;
28
48
  }
29
49
 
30
50
  get shadowTemplate(){
@@ -15,7 +15,10 @@ export default class ThemeSwitcher extends Component {
15
15
  this.currentTheme = ThemeSwitcher.getCurrentTheme();
16
16
  }
17
17
  this[clickHandler] = () => {
18
- ThemeSwitcher.setTheme(ThemeSwitcher.getCurrentTheme()==='light'?'dark':'light');
18
+ const current = ThemeSwitcher.getCurrentTheme();
19
+ if(current === 'auto') ThemeSwitcher.setTheme('light');
20
+ if(current === 'light') ThemeSwitcher.setTheme('dark');
21
+ if(current === 'dark') ThemeSwitcher.setTheme('auto');
19
22
  }
20
23
  this.registerAttribute('currentTheme', ThemeSwitcher.getCurrentTheme());
21
24
  }
@@ -27,6 +30,10 @@ export default class ThemeSwitcher extends Component {
27
30
  }
28
31
  return false;
29
32
  }
33
+ disconnectedCallback(){
34
+ super.disconnectedCallback();
35
+ offEvent(this.shadowRoot.getElementById('toggle'), 'click', this[clickHandler]);
36
+ }
30
37
 
31
38
  get shadowTemplate(){
32
39
  return /*html*/`
@@ -34,13 +41,20 @@ export default class ThemeSwitcher extends Component {
34
41
  id="toggle"
35
42
  class="no-btn"
36
43
  >
44
+ <k-icon
45
+ id="autoMode"
46
+ name="mode-auto"
47
+ class="mode"
48
+ ></k-icon>
37
49
  <k-icon
38
50
  id="lightMode"
39
51
  name="light-mode"
52
+ class="mode"
40
53
  ></k-icon>
41
54
  <k-icon
42
55
  id="darkMode"
43
56
  name="dark-mode"
57
+ class="mode"
44
58
  ></k-icon>
45
59
  </button>
46
60
  `;
@@ -55,10 +69,14 @@ export default class ThemeSwitcher extends Component {
55
69
  #toggle {
56
70
  padding: var(--padding);
57
71
  }
58
- :host([current-theme="dark"]) #darkMode,
59
- :host([current-theme="light"]) #lightMode {
72
+ .mode {
60
73
  display: none;
61
74
  }
75
+ :host([current-theme="auto"]) #autoMode,
76
+ :host([current-theme="light"]) #lightMode,
77
+ :host([current-theme="dark"]) #darkMode {
78
+ display: block;
79
+ }
62
80
  `;
63
81
  }
64
82
 
@@ -18,6 +18,7 @@
18
18
  --c_deletion: #2b91af;
19
19
  --c_caret: black;
20
20
  }
21
+ [auto-theme="dark"]:not([theme="light"]),
21
22
  [theme="dark"] {
22
23
  --c_text: #DCDCDC;
23
24
  --c_keyword: #569CD6;
@@ -22,10 +22,13 @@ export const offEvent = (element, events, handler, scope = document) => {
22
22
  scope.querySelectorAll(element).forEach( el => offEvent(el, events, handler));
23
23
  }
24
24
  }
25
- export const dispatchEvent = (element, events, detail, scope = document) => {
25
+ export const dispatchEvent = (element, events, detail, {
26
+ scope = document,
27
+ bubbles = false
28
+ }={}) => {
26
29
  if(element instanceof EventTarget){
27
30
  events.toLowerCase().split(' ').forEach( event => {
28
- element.dispatchEvent(new CustomEvent(event, { detail } ));
31
+ element.dispatchEvent(new CustomEvent(event, { bubbles, detail } ));
29
32
  });
30
33
  } else if(element instanceof NodeList || element instanceof Array){
31
34
  element.forEach( el => dispatchEvent(el, events, handler));
File without changes
File without changes