kempo 2.15.0 → 2.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Tabs.js +1 -1
- package/docs/components/tabs.html +56 -14
- package/docs/kempo/components/Tabs.js +1 -1
- package/package.json +1 -1
- package/src/components/Tabs.js +94 -16
package/dist/components/Tabs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import Component from"./Component.js";import{dispatchEvent}from"../utils/element.js";const clickHandler=Symbol();export class Tab extends Component{constructor(){super(),this[clickHandler]=()=>{this.active||(this.tabs.active=this.for)},this.slot="tabs",this.registerAttribute("active",!1)}connectedCallback(){super.connectedCallback(),this.shadowRoot.getElementById("button").addEventListener("click",this[clickHandler])}get for(){const t=this.getAttribute("for");return t||this?.tabs.tabs.indexOf(this)}set for(t){t?this.setAttribute("for",t):this.removeAttribute("for")}get tabs(){return"K-TABS"===this.parentElement.tagName?this.parentElement:null}get shadowTemplate(){return`\n <button id="button">\n ${super.shadowTemplate}\n </button>\n `}get shadowStyles(){return"\n :host {\n margin-bottom: -1px;\n }\n #button {\n padding: var(--spacer_h);\n background-color: transparent;\n border: none;\n cursor: inherit;\n box-shadow: none;\n color: inherit;\n }\n :host(:not([active])) #button {\n cursor: pointer;\n }\n :host([active]){\n border-bottom: 2px solid var(--c_primary);\n margin-bottom: -1px;\n }\n :host([active]) #button {\n color: var(--tc_primary);\n }\n "}}window.customElements.define("k-tab",Tab);export class TabContent extends Component{constructor(){super(),this.registerAttribute("active",!1)}get tabs(){return"K-TABS"===this.parentElement.tagName?this.parentElement:null}get name(){const t=this.getAttribute("name");return t||this?.tabs.contents.indexOf(this)}set name(t){t?this.setAttribute("name",t):this.removeAttribute("name")}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n height: 100%;\n max-height: 100%;\n flex: 1 1 auto;\n overflow: hidden;\n }\n :host([active]) {\n display: block;\n }\n :host(:not([active])) {\n display: none;\n }\n `}}window.customElements.define("k-tab-content",TabContent);export class Tabs extends Component{constructor(){super(),this.registerAttribute("active","")}async connectedCallback(){await super.connectedCallback(),this.active||(this.active=`${this.querySelectorAll("k-tab-content")[0].name}`)}attributeChangedCallback(t,e,n){if("active"===t){const t=this.getActiveTab();t&&(t.active=!1);const e=this.getActiveContent();e&&(e.active=!1);const
|
|
1
|
+
import Component from"./Component.js";import{dispatchEvent}from"../utils/element.js";const clickHandler=Symbol();export class Tab extends Component{constructor(){super(),this[clickHandler]=()=>{this.active||(this.tabs.active=this.for)},this.slot="tabs",this.registerAttribute("active",!1)}connectedCallback(){super.connectedCallback(),this.shadowRoot.getElementById("button").addEventListener("click",this[clickHandler])}get for(){const t=this.getAttribute("for");return t||this?.tabs.tabs.indexOf(this)}set for(t){t?this.setAttribute("for",t):this.removeAttribute("for")}get tabs(){return"K-TABS"===this.parentElement.tagName?this.parentElement:null}get shadowTemplate(){return`\n <button id="button">\n ${super.shadowTemplate}\n </button>\n `}get shadowStyles(){return"\n :host {\n margin-bottom: -1px;\n flex: 0 0 auto; /* Important: prevent shrinking and growing */\n }\n #button {\n padding: var(--spacer_h);\n background-color: transparent;\n border: none;\n cursor: inherit;\n box-shadow: none;\n color: inherit;\n white-space: nowrap; /* Prevent text wrapping */\n }\n :host(:not([active])) #button {\n cursor: pointer;\n }\n :host([active]){\n border-bottom: 2px solid var(--c_primary);\n margin-bottom: -1px;\n }\n :host([active]) #button {\n color: var(--tc_primary);\n }\n "}}window.customElements.define("k-tab",Tab);export class TabContent extends Component{constructor(){super(),this.registerAttribute("active",!1)}get tabs(){return"K-TABS"===this.parentElement.tagName?this.parentElement:null}get name(){const t=this.getAttribute("name");return t||this?.tabs.contents.indexOf(this)}set name(t){t?this.setAttribute("name",t):this.removeAttribute("name")}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n height: 100%;\n max-height: 100%;\n flex: 1 1 auto;\n overflow: hidden;\n }\n :host([active]) {\n display: block;\n }\n :host(:not([active])) {\n display: none;\n }\n `}}window.customElements.define("k-tab-content",TabContent);export class Tabs extends Component{constructor(){super(),this.registerAttribute("active","")}async connectedCallback(){await super.connectedCallback(),this.active||(this.active=`${this.querySelectorAll("k-tab-content")[0].name}`);const t=this.shadowRoot.getElementById("tabs");t.addEventListener("scroll",this.updateScrollIndicators.bind(this)),this.updateScrollIndicators(),new ResizeObserver((()=>this.updateScrollIndicators())).observe(t);const e=this.shadowRoot.getElementById("scroll-left"),n=this.shadowRoot.getElementById("scroll-right");e.addEventListener("click",(()=>{t.scrollBy({left:-200,behavior:"smooth"})})),n.addEventListener("click",(()=>{t.scrollBy({left:200,behavior:"smooth"})}))}updateScrollIndicators(){const t=this.shadowRoot.getElementById("tabs"),e=this.shadowRoot.getElementById("scroll-left"),n=this.shadowRoot.getElementById("scroll-right"),o=t.scrollLeft>0,s=t.scrollLeft<t.scrollWidth-t.clientWidth;e.classList.toggle("visible",o),n.classList.toggle("visible",s)}attributeChangedCallback(t,e,n){if("active"===t){const t=this.getActiveTab();t&&(t.active=!1);const e=this.getActiveContent();e&&(e.active=!1);const o=this.getTab(n);o&&(o.active=!0);const s=this.getContent(n);s&&(s.active=!0),dispatchEvent(this,"tab",{tab:n})}}get contents(){return[...this.querySelectorAll(":scope > k-tab-content")]}get tabs(){return[...this.querySelectorAll(":scope > k-tab")]}getTab(t){let e;if("string"==typeof t&&(e=this.querySelector(`k-tab[for="${t}"]`)),!e){let n=parseInt(t);n||(n=0),e=this.querySelectorAll("k-tab")[n]}return e}getActiveTab(){return this.querySelector(':scope > k-tab[active="true"]')}getContent(t){let e;if("string"==typeof t&&(e=this.querySelector(`k-tab-content[name="${t}"]`)),!e){let n=parseInt(t);n||(n=0),e=this.querySelectorAll("k-tab-content")[n]}return e}getActiveContent(){return this.querySelector(':scope > k-tab-content[active="true"]')}get shadowTemplate(){return`\n <div id="wrapper">\n <div id="tabs-container">\n <div id="scroll-left" class="scroll-indicator">\n <svg class="arrow" width="20" height="20" viewBox="0 0 20 20" fill="none">\n <path d="M12 15L7 10L12 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>\n </svg>\n </div>\n <div id="tabs">\n <slot name="tabs"></slot>\n </div>\n <div id="scroll-right" class="scroll-indicator">\n <svg class="arrow" width="20" height="20" viewBox="0 0 20 20" fill="none">\n <path d="M8 15L13 10L8 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>\n </svg>\n </div>\n </div>\n <div id="contents">\n ${super.shadowTemplate}\n </div>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n width: 100%;\n }\n #wrapper {\n display: flex;\n flex-direction: column;\n width: 100%;\n min-width: 0;\n }\n #tabs-container {\n position: relative;\n border-bottom: 1px solid var(--c_border);\n }\n #tabs {\n display: flex;\n overflow-x: auto;\n overflow-y: hidden;\n }\n #tabs ::slotted(*) {\n flex: 0 0 auto;\n }\n .scroll-indicator {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 72px;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.2s;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n padding-bottom: 2px;\n }\n .scroll-indicator .arrow {\n color: var(--tc_base);\n z-index: 1;\n }\n .scroll-indicator.visible {\n opacity: 1;\n }\n #scroll-left {\n left: 0;\n background: linear-gradient(90deg, \n var(--c_bg) 0%,\n var(--c_bg) 30%,\n transparent 100%\n );\n }\n #scroll-right {\n right: 0;\n justify-content: flex-end;\n background: linear-gradient(-90deg, \n var(--c_bg) 0%,\n var(--c_bg) 30%,\n transparent 100%\n );\n }\n `}static observedAttributes=[...super.observedAttributes,"active"]}window.customElements.define("k-tabs",Tabs);export class TabSpacer extends Component{constructor(){super(),this.slot="tabs"}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n flex: 1 1 auto;\n height: 1px;\n }\n `}}window.customElements.define("k-tab-spacer",TabSpacer);export default{Tab:Tab,TabContent:TabContent,Tabs:Tabs,TabSpacer:TabSpacer};
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
<h6>Examples</h6>
|
|
24
24
|
<a href="#basicUsage">Basic Usage</a><br />
|
|
25
25
|
<a href="#tabSpacers">Tab Spacers</a><br />
|
|
26
|
+
<a href="#scrollingTabs">Scrolling Tabs</a><br />
|
|
26
27
|
|
|
27
28
|
<h6 class="mt">JavaScript Reference</h6>
|
|
28
29
|
<a href="#constructor">Constructor</a><br />
|
|
@@ -62,36 +63,77 @@
|
|
|
62
63
|
</k-tab-content>
|
|
63
64
|
</k-tabs>
|
|
64
65
|
|
|
65
|
-
<
|
|
66
|
+
<h3 id="scrollingTabs"><a href="#scrollingTabs" class="no-link">Scrolling Tabs</a></h3>
|
|
67
|
+
<p>When there are many tabs, they will scroll horizontally with gradient indicators showing when more tabs are available.</p>
|
|
68
|
+
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">k-tabs</span>></span>
|
|
69
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tab1"</span>></span>Tab 1<span class="hljs-tag"></<span class="hljs-name">k-tab</span>></span>
|
|
70
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tab2"</span>></span>Tab 2<span class="hljs-tag"></<span class="hljs-name">k-tab</span>></span>
|
|
71
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tab3"</span>></span>Tab 3<span class="hljs-tag"></<span class="hljs-name">k-tab</span>></span>
|
|
72
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tab4"</span>></span>Tab 4<span class="hljs-tag"></<span class="hljs-name">k-tab</span>></span>
|
|
73
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tab5"</span>></span>Tab 5<span class="hljs-tag"></<span class="hljs-name">k-tab</span>></span>
|
|
74
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tab6"</span>></span>Tab 6<span class="hljs-tag"></<span class="hljs-name">k-tab</span>></span>
|
|
75
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tab7"</span>></span>Tab 7<span class="hljs-tag"></<span class="hljs-name">k-tab</span>></span>
|
|
76
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tab8"</span>></span>Tab 8<span class="hljs-tag"></<span class="hljs-name">k-tab</span>></span>
|
|
77
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tab9"</span>></span>Tab 9<span class="hljs-tag"></<span class="hljs-name">k-tab</span>></span>
|
|
78
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"tab10"</span>></span>Tab 10<span class="hljs-tag"></<span class="hljs-name">k-tab</span>></span>
|
|
79
|
+
<span class="hljs-comment"><!-- Tab Contents --></span>
|
|
80
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab-content</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tab1"</span>></span>Content 1<span class="hljs-tag"></<span class="hljs-name">k-tab-content</span>></span>
|
|
81
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab-content</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tab2"</span>></span>Content 2<span class="hljs-tag"></<span class="hljs-name">k-tab-content</span>></span>
|
|
82
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab-content</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tab3"</span>></span>Content 3<span class="hljs-tag"></<span class="hljs-name">k-tab-content</span>></span>
|
|
83
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab-content</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tab4"</span>></span>Content 4<span class="hljs-tag"></<span class="hljs-name">k-tab-content</span>></span>
|
|
84
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab-content</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tab5"</span>></span>Content 5<span class="hljs-tag"></<span class="hljs-name">k-tab-content</span>></span>
|
|
85
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab-content</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tab6"</span>></span>Content 6<span class="hljs-tag"></<span class="hljs-name">k-tab-content</span>></span>
|
|
86
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab-content</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tab7"</span>></span>Content 7<span class="hljs-tag"></<span class="hljs-name">k-tab-content</span>></span>
|
|
87
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab-content</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tab8"</span>></span>Content 8<span class="hljs-tag"></<span class="hljs-name">k-tab-content</span>></span>
|
|
88
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab-content</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tab9"</span>></span>Content 9<span class="hljs-tag"></<span class="hljs-name">k-tab-content</span>></span>
|
|
89
|
+
<span class="hljs-tag"><<span class="hljs-name">k-tab-content</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"tab10"</span>></span>Content 10<span class="hljs-tag"></<span class="hljs-name">k-tab-content</span>></span>
|
|
90
|
+
<span class="hljs-tag"></<span class="hljs-name">k-tabs</span>></span></code></pre>
|
|
91
|
+
<k-tabs>
|
|
92
|
+
<k-tab for="tab1">Long Tab Name 1</k-tab>
|
|
93
|
+
<k-tab for="tab2">Long Tab Name 2</k-tab>
|
|
94
|
+
<k-tab for="tab3">Long Tab Name 3</k-tab>
|
|
95
|
+
<k-tab for="tab4">Long Tab Name 4</k-tab>
|
|
96
|
+
<k-tab for="tab5">Long Tab Name 5</k-tab>
|
|
97
|
+
<k-tab for="tab6">Long Tab Name 6</k-tab>
|
|
98
|
+
<k-tab for="tab7">Long Tab Name 7</k-tab>
|
|
99
|
+
<k-tab for="tab8">Long Tab Name 8</k-tab>
|
|
100
|
+
<k-tab for="tab9">Long Tab Name 9</k-tab>
|
|
101
|
+
<k-tab for="tab10">Long Tab Name 10</k-tab>
|
|
102
|
+
<k-tab-content name="tab1"><p>Content 1</p></k-tab-content>
|
|
103
|
+
<k-tab-content name="tab2"><p>Content 2</p></k-tab-content>
|
|
104
|
+
<k-tab-content name="tab3"><p>Content 3</p></k-tab-content>
|
|
105
|
+
<k-tab-content name="tab4"><p>Content 4</p></k-tab-content>
|
|
106
|
+
<k-tab-content name="tab5"><p>Content 5</p></k-tab-content>
|
|
107
|
+
<k-tab-content name="tab6"><p>Content 6</p></k-tab-content>
|
|
108
|
+
<k-tab-content name="tab7"><p>Content 7</p></k-tab-content>
|
|
109
|
+
<k-tab-content name="tab8"><p>Content 8</p></k-tab-content>
|
|
110
|
+
<k-tab-content name="tab9"><p>Content 9</p></k-tab-content>
|
|
111
|
+
<k-tab-content name="tab10"><p>Content 10</p></k-tab-content>
|
|
112
|
+
</k-tabs>
|
|
66
113
|
|
|
114
|
+
<h2 id="jsRef">JavaScript Reference</h2>
|
|
67
115
|
<h3 id="constructor"><a href="#constructor" class="no-link">Constructor</a></h3>
|
|
68
116
|
<h6>Extends <a href="./component.html">Component</a></h6>
|
|
69
|
-
<h5>
|
|
70
|
-
<code>new Tabs()</code>
|
|
71
|
-
</h5>
|
|
72
|
-
|
|
117
|
+
<h5><code>new Tabs()</code></h5>
|
|
73
118
|
<h3 id="requirements"><a href="#requirements" class="no-link">Requirements</a></h3>
|
|
74
119
|
<ul>
|
|
75
120
|
<li><a href="./component.html">Component</a></li>
|
|
76
121
|
</ul>
|
|
77
|
-
|
|
78
122
|
<h3 id="attributes"><a href="#attributes" class="no-link">Attributes</a></h3>
|
|
79
123
|
<h5><code>active<i>: string</i></code></h5>
|
|
80
124
|
<p>The name of the active tab.</p>
|
|
81
|
-
|
|
82
125
|
<h3 id="methods"><a href="#methods" class="no-link">Methods</a></h3>
|
|
83
|
-
<h5><code>getTab(id)<i>: Tab</i></code></h5>
|
|
84
|
-
<p>Returns the tab with the specified id.</p>
|
|
85
126
|
<h5><code>getActiveTab()<i>: Tab</i></code></h5>
|
|
86
127
|
<p>Returns the currently active tab.</p>
|
|
87
|
-
<h5><code>
|
|
88
|
-
<p>Returns the tab
|
|
128
|
+
<h5><code>getTab(id)<i>: Tab</i></code></h5>
|
|
129
|
+
<p>Returns the tab with the specified id.</p>
|
|
89
130
|
<h5><code>getActiveContent()<i>: TabContent</i></code></h5>
|
|
90
131
|
<p>Returns the currently active tab content.</p>
|
|
91
|
-
|
|
132
|
+
<h5><code>getContent(id)<i>: TabContent</i></code></h5>
|
|
133
|
+
<p>Returns the tab content with the specified id.</p>
|
|
92
134
|
</main>
|
|
93
135
|
<div style="height:33vh"></div>
|
|
94
|
-
<script type="module" src="../kempo/components/
|
|
95
|
-
<script type="module" src="../kempo/components/
|
|
136
|
+
<script type="module" src="../kempo/components/Tabs.js"></script>
|
|
137
|
+
<script type="module" src="../kempo/components/Import.js"></script>
|
|
96
138
|
</body>
|
|
97
139
|
</html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import Component from"./Component.js";import{dispatchEvent}from"../utils/element.js";const clickHandler=Symbol();export class Tab extends Component{constructor(){super(),this[clickHandler]=()=>{this.active||(this.tabs.active=this.for)},this.slot="tabs",this.registerAttribute("active",!1)}connectedCallback(){super.connectedCallback(),this.shadowRoot.getElementById("button").addEventListener("click",this[clickHandler])}get for(){const t=this.getAttribute("for");return t||this?.tabs.tabs.indexOf(this)}set for(t){t?this.setAttribute("for",t):this.removeAttribute("for")}get tabs(){return"K-TABS"===this.parentElement.tagName?this.parentElement:null}get shadowTemplate(){return`\n <button id="button">\n ${super.shadowTemplate}\n </button>\n `}get shadowStyles(){return"\n :host {\n margin-bottom: -1px;\n }\n #button {\n padding: var(--spacer_h);\n background-color: transparent;\n border: none;\n cursor: inherit;\n box-shadow: none;\n color: inherit;\n }\n :host(:not([active])) #button {\n cursor: pointer;\n }\n :host([active]){\n border-bottom: 2px solid var(--c_primary);\n margin-bottom: -1px;\n }\n :host([active]) #button {\n color: var(--tc_primary);\n }\n "}}window.customElements.define("k-tab",Tab);export class TabContent extends Component{constructor(){super(),this.registerAttribute("active",!1)}get tabs(){return"K-TABS"===this.parentElement.tagName?this.parentElement:null}get name(){const t=this.getAttribute("name");return t||this?.tabs.contents.indexOf(this)}set name(t){t?this.setAttribute("name",t):this.removeAttribute("name")}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n height: 100%;\n max-height: 100%;\n flex: 1 1 auto;\n overflow: hidden;\n }\n :host([active]) {\n display: block;\n }\n :host(:not([active])) {\n display: none;\n }\n `}}window.customElements.define("k-tab-content",TabContent);export class Tabs extends Component{constructor(){super(),this.registerAttribute("active","")}async connectedCallback(){await super.connectedCallback(),this.active||(this.active=`${this.querySelectorAll("k-tab-content")[0].name}`)}attributeChangedCallback(t,e,n){if("active"===t){const t=this.getActiveTab();t&&(t.active=!1);const e=this.getActiveContent();e&&(e.active=!1);const
|
|
1
|
+
import Component from"./Component.js";import{dispatchEvent}from"../utils/element.js";const clickHandler=Symbol();export class Tab extends Component{constructor(){super(),this[clickHandler]=()=>{this.active||(this.tabs.active=this.for)},this.slot="tabs",this.registerAttribute("active",!1)}connectedCallback(){super.connectedCallback(),this.shadowRoot.getElementById("button").addEventListener("click",this[clickHandler])}get for(){const t=this.getAttribute("for");return t||this?.tabs.tabs.indexOf(this)}set for(t){t?this.setAttribute("for",t):this.removeAttribute("for")}get tabs(){return"K-TABS"===this.parentElement.tagName?this.parentElement:null}get shadowTemplate(){return`\n <button id="button">\n ${super.shadowTemplate}\n </button>\n `}get shadowStyles(){return"\n :host {\n margin-bottom: -1px;\n flex: 0 0 auto; /* Important: prevent shrinking and growing */\n }\n #button {\n padding: var(--spacer_h);\n background-color: transparent;\n border: none;\n cursor: inherit;\n box-shadow: none;\n color: inherit;\n white-space: nowrap; /* Prevent text wrapping */\n }\n :host(:not([active])) #button {\n cursor: pointer;\n }\n :host([active]){\n border-bottom: 2px solid var(--c_primary);\n margin-bottom: -1px;\n }\n :host([active]) #button {\n color: var(--tc_primary);\n }\n "}}window.customElements.define("k-tab",Tab);export class TabContent extends Component{constructor(){super(),this.registerAttribute("active",!1)}get tabs(){return"K-TABS"===this.parentElement.tagName?this.parentElement:null}get name(){const t=this.getAttribute("name");return t||this?.tabs.contents.indexOf(this)}set name(t){t?this.setAttribute("name",t):this.removeAttribute("name")}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n height: 100%;\n max-height: 100%;\n flex: 1 1 auto;\n overflow: hidden;\n }\n :host([active]) {\n display: block;\n }\n :host(:not([active])) {\n display: none;\n }\n `}}window.customElements.define("k-tab-content",TabContent);export class Tabs extends Component{constructor(){super(),this.registerAttribute("active","")}async connectedCallback(){await super.connectedCallback(),this.active||(this.active=`${this.querySelectorAll("k-tab-content")[0].name}`);const t=this.shadowRoot.getElementById("tabs");t.addEventListener("scroll",this.updateScrollIndicators.bind(this)),this.updateScrollIndicators(),new ResizeObserver((()=>this.updateScrollIndicators())).observe(t);const e=this.shadowRoot.getElementById("scroll-left"),n=this.shadowRoot.getElementById("scroll-right");e.addEventListener("click",(()=>{t.scrollBy({left:-200,behavior:"smooth"})})),n.addEventListener("click",(()=>{t.scrollBy({left:200,behavior:"smooth"})}))}updateScrollIndicators(){const t=this.shadowRoot.getElementById("tabs"),e=this.shadowRoot.getElementById("scroll-left"),n=this.shadowRoot.getElementById("scroll-right"),o=t.scrollLeft>0,s=t.scrollLeft<t.scrollWidth-t.clientWidth;e.classList.toggle("visible",o),n.classList.toggle("visible",s)}attributeChangedCallback(t,e,n){if("active"===t){const t=this.getActiveTab();t&&(t.active=!1);const e=this.getActiveContent();e&&(e.active=!1);const o=this.getTab(n);o&&(o.active=!0);const s=this.getContent(n);s&&(s.active=!0),dispatchEvent(this,"tab",{tab:n})}}get contents(){return[...this.querySelectorAll(":scope > k-tab-content")]}get tabs(){return[...this.querySelectorAll(":scope > k-tab")]}getTab(t){let e;if("string"==typeof t&&(e=this.querySelector(`k-tab[for="${t}"]`)),!e){let n=parseInt(t);n||(n=0),e=this.querySelectorAll("k-tab")[n]}return e}getActiveTab(){return this.querySelector(':scope > k-tab[active="true"]')}getContent(t){let e;if("string"==typeof t&&(e=this.querySelector(`k-tab-content[name="${t}"]`)),!e){let n=parseInt(t);n||(n=0),e=this.querySelectorAll("k-tab-content")[n]}return e}getActiveContent(){return this.querySelector(':scope > k-tab-content[active="true"]')}get shadowTemplate(){return`\n <div id="wrapper">\n <div id="tabs-container">\n <div id="scroll-left" class="scroll-indicator">\n <svg class="arrow" width="20" height="20" viewBox="0 0 20 20" fill="none">\n <path d="M12 15L7 10L12 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>\n </svg>\n </div>\n <div id="tabs">\n <slot name="tabs"></slot>\n </div>\n <div id="scroll-right" class="scroll-indicator">\n <svg class="arrow" width="20" height="20" viewBox="0 0 20 20" fill="none">\n <path d="M8 15L13 10L8 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>\n </svg>\n </div>\n </div>\n <div id="contents">\n ${super.shadowTemplate}\n </div>\n </div>\n `}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n display: block;\n width: 100%;\n }\n #wrapper {\n display: flex;\n flex-direction: column;\n width: 100%;\n min-width: 0;\n }\n #tabs-container {\n position: relative;\n border-bottom: 1px solid var(--c_border);\n }\n #tabs {\n display: flex;\n overflow-x: auto;\n overflow-y: hidden;\n }\n #tabs ::slotted(*) {\n flex: 0 0 auto;\n }\n .scroll-indicator {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 72px;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.2s;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n padding-bottom: 2px;\n }\n .scroll-indicator .arrow {\n color: var(--tc_base);\n z-index: 1;\n }\n .scroll-indicator.visible {\n opacity: 1;\n }\n #scroll-left {\n left: 0;\n background: linear-gradient(90deg, \n var(--c_bg) 0%,\n var(--c_bg) 30%,\n transparent 100%\n );\n }\n #scroll-right {\n right: 0;\n justify-content: flex-end;\n background: linear-gradient(-90deg, \n var(--c_bg) 0%,\n var(--c_bg) 30%,\n transparent 100%\n );\n }\n `}static observedAttributes=[...super.observedAttributes,"active"]}window.customElements.define("k-tabs",Tabs);export class TabSpacer extends Component{constructor(){super(),this.slot="tabs"}get shadowStyles(){return`\n ${super.shadowStyles}\n :host {\n flex: 1 1 auto;\n height: 1px;\n }\n `}}window.customElements.define("k-tab-spacer",TabSpacer);export default{Tab:Tab,TabContent:TabContent,Tabs:Tabs,TabSpacer:TabSpacer};
|
package/package.json
CHANGED
package/src/components/Tabs.js
CHANGED
|
@@ -53,6 +53,7 @@ export class Tab extends Component {
|
|
|
53
53
|
return /*css*/`
|
|
54
54
|
:host {
|
|
55
55
|
margin-bottom: -1px;
|
|
56
|
+
flex: 0 0 auto; /* Important: prevent shrinking and growing */
|
|
56
57
|
}
|
|
57
58
|
#button {
|
|
58
59
|
padding: var(--spacer_h);
|
|
@@ -61,6 +62,7 @@ export class Tab extends Component {
|
|
|
61
62
|
cursor: inherit;
|
|
62
63
|
box-shadow: none;
|
|
63
64
|
color: inherit;
|
|
65
|
+
white-space: nowrap; /* Prevent text wrapping */
|
|
64
66
|
}
|
|
65
67
|
:host(:not([active])) #button {
|
|
66
68
|
cursor: pointer;
|
|
@@ -133,7 +135,38 @@ export class Tabs extends Component {
|
|
|
133
135
|
if(!this.active){
|
|
134
136
|
this.active = `${this.querySelectorAll('k-tab-content')[0].name}`;
|
|
135
137
|
}
|
|
138
|
+
|
|
139
|
+
// Add scroll listeners for indicators
|
|
140
|
+
const tabsContainer = this.shadowRoot.getElementById('tabs');
|
|
141
|
+
tabsContainer.addEventListener('scroll', this.updateScrollIndicators.bind(this));
|
|
142
|
+
this.updateScrollIndicators();
|
|
143
|
+
|
|
144
|
+
// Update indicators on resize
|
|
145
|
+
new ResizeObserver(() => this.updateScrollIndicators()).observe(tabsContainer);
|
|
146
|
+
|
|
147
|
+
const leftButton = this.shadowRoot.getElementById('scroll-left');
|
|
148
|
+
const rightButton = this.shadowRoot.getElementById('scroll-right');
|
|
149
|
+
|
|
150
|
+
leftButton.addEventListener('click', () => {
|
|
151
|
+
tabsContainer.scrollBy({ left: -200, behavior: 'smooth' });
|
|
152
|
+
});
|
|
153
|
+
rightButton.addEventListener('click', () => {
|
|
154
|
+
tabsContainer.scrollBy({ left: 200, behavior: 'smooth' });
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
updateScrollIndicators() {
|
|
159
|
+
const tabsContainer = this.shadowRoot.getElementById('tabs');
|
|
160
|
+
const leftIndicator = this.shadowRoot.getElementById('scroll-left');
|
|
161
|
+
const rightIndicator = this.shadowRoot.getElementById('scroll-right');
|
|
162
|
+
|
|
163
|
+
const hasLeftScroll = tabsContainer.scrollLeft > 0;
|
|
164
|
+
const hasRightScroll = tabsContainer.scrollLeft < (tabsContainer.scrollWidth - tabsContainer.clientWidth);
|
|
165
|
+
|
|
166
|
+
leftIndicator.classList.toggle('visible', hasLeftScroll);
|
|
167
|
+
rightIndicator.classList.toggle('visible', hasRightScroll);
|
|
136
168
|
}
|
|
169
|
+
|
|
137
170
|
attributeChangedCallback(n, oV, nV){
|
|
138
171
|
if(n === 'active'){
|
|
139
172
|
const $activeTab = this.getActiveTab();
|
|
@@ -190,14 +223,25 @@ export class Tabs extends Component {
|
|
|
190
223
|
get shadowTemplate(){
|
|
191
224
|
return /*html*/`
|
|
192
225
|
<div id="wrapper">
|
|
193
|
-
<div id="tabs">
|
|
194
|
-
<
|
|
226
|
+
<div id="tabs-container">
|
|
227
|
+
<div id="scroll-left" class="scroll-indicator">
|
|
228
|
+
<svg class="arrow" width="20" height="20" viewBox="0 0 20 20" fill="none">
|
|
229
|
+
<path d="M12 15L7 10L12 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
230
|
+
</svg>
|
|
231
|
+
</div>
|
|
232
|
+
<div id="tabs">
|
|
233
|
+
<slot name="tabs"></slot>
|
|
234
|
+
</div>
|
|
235
|
+
<div id="scroll-right" class="scroll-indicator">
|
|
236
|
+
<svg class="arrow" width="20" height="20" viewBox="0 0 20 20" fill="none">
|
|
237
|
+
<path d="M8 15L13 10L8 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
238
|
+
</svg>
|
|
239
|
+
</div>
|
|
195
240
|
</div>
|
|
196
241
|
<div id="contents">
|
|
197
242
|
${super.shadowTemplate}
|
|
198
243
|
</div>
|
|
199
244
|
</div>
|
|
200
|
-
|
|
201
245
|
`;
|
|
202
246
|
}
|
|
203
247
|
get shadowStyles(){
|
|
@@ -205,28 +249,62 @@ export class Tabs extends Component {
|
|
|
205
249
|
${super.shadowStyles}
|
|
206
250
|
:host {
|
|
207
251
|
display: block;
|
|
208
|
-
|
|
252
|
+
width: 100%;
|
|
209
253
|
}
|
|
210
254
|
#wrapper {
|
|
211
255
|
display: flex;
|
|
212
256
|
flex-direction: column;
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
257
|
+
width: 100%;
|
|
258
|
+
min-width: 0;
|
|
259
|
+
}
|
|
260
|
+
#tabs-container {
|
|
261
|
+
position: relative;
|
|
262
|
+
border-bottom: 1px solid var(--c_border);
|
|
216
263
|
}
|
|
217
264
|
#tabs {
|
|
218
265
|
display: flex;
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
margin-top: calc(0 - var(--spacer));
|
|
222
|
-
align-items: flex-start;
|
|
266
|
+
overflow-x: auto;
|
|
267
|
+
overflow-y: hidden;
|
|
223
268
|
}
|
|
224
|
-
#
|
|
269
|
+
#tabs ::slotted(*) {
|
|
270
|
+
flex: 0 0 auto;
|
|
271
|
+
}
|
|
272
|
+
.scroll-indicator {
|
|
273
|
+
position: absolute;
|
|
274
|
+
top: 0;
|
|
275
|
+
bottom: 0;
|
|
276
|
+
width: 72px;
|
|
277
|
+
pointer-events: none;
|
|
278
|
+
opacity: 0;
|
|
279
|
+
transition: opacity 0.2s;
|
|
225
280
|
display: flex;
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
281
|
+
align-items: center;
|
|
282
|
+
justify-content: flex-start;
|
|
283
|
+
padding-bottom: 2px;
|
|
284
|
+
}
|
|
285
|
+
.scroll-indicator .arrow {
|
|
286
|
+
color: var(--tc_base);
|
|
287
|
+
z-index: 1;
|
|
288
|
+
}
|
|
289
|
+
.scroll-indicator.visible {
|
|
290
|
+
opacity: 1;
|
|
291
|
+
}
|
|
292
|
+
#scroll-left {
|
|
293
|
+
left: 0;
|
|
294
|
+
background: linear-gradient(90deg,
|
|
295
|
+
var(--c_bg) 0%,
|
|
296
|
+
var(--c_bg) 30%,
|
|
297
|
+
transparent 100%
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
#scroll-right {
|
|
301
|
+
right: 0;
|
|
302
|
+
justify-content: flex-end;
|
|
303
|
+
background: linear-gradient(-90deg,
|
|
304
|
+
var(--c_bg) 0%,
|
|
305
|
+
var(--c_bg) 30%,
|
|
306
|
+
transparent 100%
|
|
307
|
+
);
|
|
230
308
|
}
|
|
231
309
|
`;
|
|
232
310
|
}
|