Skip to content

Commit

Permalink
SSR-4153: Improve the Tabs component
Browse files Browse the repository at this point in the history
  • Loading branch information
h000780 committed Dec 4, 2024
1 parent 369f6ba commit 876707d
Show file tree
Hide file tree
Showing 8 changed files with 452 additions and 14 deletions.
6 changes: 5 additions & 1 deletion docs/document/docs/components/desktop/tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Here is a list of properties that can be used for modifying the component:

| Name | Type | Default | Description | Remark |
| :--- | :--- | :--- | :--- | :--- |
| allowScroll | boolean | false | Enable/Disable the tab list scrolling | |
| allowScrollButtons | boolean | false | Show/Hide the scroll buttons | |
| className | string | "" | Component class name | |
| id | string | "" | Component id name | |
| value | string | "" | Selected value | <li>If the `value` is matched in the `items`, the tab will be displayed even if it’s disabled</li><li>The first visible tab will be displayed in the following cases:<ul><li>If the `value` is not matched in the `items`</li><li>If the `value` is matched in the `items`, but the tab is not visible</li></ul></li><li>Will result an error if the `value` is not string type</li> |
Expand Down Expand Up @@ -127,7 +129,9 @@ const tabs = new Kuc.Tabs({
className: 'options-class',
id: 'options-id',
visible: true,
borderVisible: true
borderVisible: true,
allowScroll: true,
allowScrollButtons: false
});
space.appendChild(tabs);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { TabsComponent } from "@site/static/js/samples/desktop/tabs.jsx"

| Name | Type | Default | Description | Remark |
| :--- | :--- | :--- | :--- | :--- |
| allowScroll | boolean | false | タブリストのスクロール可/不可設定 | |
| allowScrollButtons | boolean | false | スクロールボタンの表示/非表示設定 | |
| className | string | "" | コンポーネントの class 名 ||
| id | string | "" | コンポーネントの id 名 ||
| value | string | "" | 選択されているタブ | <li>items 内に一致する value がある場合、disabled でもそのタブが表示される</li><li>以下の場合は最初の visible タブが表示される<ul><li>items 内に一致する value がない場合</li><li>items 内に一致する value があるが、そのタブが visible ではない場合</li></ul></li><li>value が文字列以外の場合、エラーを出力する</li> |
Expand Down Expand Up @@ -126,7 +128,9 @@ const tabs = new Kuc.Tabs({
className: 'options-class',
id: 'options-id',
visible: true,
borderVisible: true
borderVisible: true,
allowScroll: true,
allowScrollButtons: false
});
space.appendChild(tabs);

Expand Down
30 changes: 30 additions & 0 deletions src/tabs/index.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ Base.args = {
borderVisible: true,
className: "kuc-tabs-class",
id: "sample-id",
allowScroll: true,
allowScrollButtons: true,
items: [
{
label: "Tab1",
Expand All @@ -112,6 +114,34 @@ Base.args = {
visible: true,
content: thirdContent,
},
{
label: "Tab4",
value: "tab4",
disabled: false,
visible: true,
content: "Tab4 Content",
},
{
label: "Tab5",
value: "tab5",
disabled: false,
visible: true,
content: "Tab5 Content",
},
{
label: "Tab6",
value: "tab6",
disabled: false,
visible: true,
content: `
`,
},
],
value: "tab1",
visible: true,
Expand Down
125 changes: 114 additions & 11 deletions src/tabs/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { html, PropertyValues } from "lit";
import { property, queryAll, state } from "lit/decorators.js";
import { html, PropertyValues, svg } from "lit";
import { property, query, queryAll, state } from "lit/decorators.js";

import { ERROR_MESSAGE } from "../base/constant";
import { unsafeHTMLConverter, visiblePropConverter } from "../base/converter";
Expand All @@ -26,6 +26,8 @@ let exportTabs;
return;
}
class KucTabs extends KucBase {
@property({ type: Boolean }) allowScroll = false;
@property({ type: Boolean }) allowScrollButtons = false;
@property({ type: String, reflect: true, attribute: "class" }) className =
"";
@property({ type: String, reflect: true, attribute: "id" }) id = "";
Expand All @@ -42,6 +44,10 @@ let exportTabs;

@queryAll(".kuc-tabs__group__tab-list__tab__button")
private _tabButtons!: HTMLButtonElement[];
@query(".kuc-tabs__group__tab-list-container")
private _tabListContainer!: HTMLDivElement;
@query(".kuc-tabs__group")
private _tabGroup!: HTMLDivElement;

private _GUID: string;
private _selectedValue: string = "";
Expand Down Expand Up @@ -95,15 +101,33 @@ let exportTabs;
render() {
return html`
<div class="kuc-tabs__group">
<ul
class="kuc-tabs__group__tab-list"
role="tablist"
@blur="${this._handleBlur}"
>
${this.items.map((item, index) =>
this._getTabTemplate(item, index),
)}
</ul>
<div class="kuc-tabs__group__tabs-list__root">
<div
class="kuc-tabs__group__tab-pre-button"
@click="${this._handleClickPrevButton}"
?hidden="${!this.allowScroll || !this.allowScrollButtons}"
>
${this._getPrevButtonSvgTemplate()}
</div>
<div class="kuc-tabs__group__tab-list-container">
<ul
class="kuc-tabs__group__tab-list"
role="tablist"
@blur="${this._handleBlur}"
>
${this.items.map((item, index) =>
this._getTabTemplate(item, index),
)}
</ul>
</div>
<div
class="kuc-tabs__group__tab-next-button"
@click="${this._handleClickNextButton}"
?hidden="${!this.allowScroll || !this.allowScrollButtons}"
>
${this._getNextButtonSvgTemplate()}
</div>
</div>
<div
class="kuc-tabs__group__tab-panel"
?border-visible="${this.borderVisible}"
Expand All @@ -115,6 +139,17 @@ let exportTabs;
</div>
`;
}
protected updated() {
this._tabGroup.parentElement &&
this._tabGroup.parentElement.style.setProperty(
"width",
this.allowScroll ? "100%" : "auto",
);
this._tabListContainer.style.setProperty(
"overflow-x",
this.allowScroll ? "auto" : "visible",
);
}

private _getTabTemplate(item: TabsItem, index: number) {
const isSelected = item.value === this._selectedValue;
Expand Down Expand Up @@ -157,6 +192,32 @@ let exportTabs;
</div>`;
}

private _getScrollSize() {
const containerSize = this._tabListContainer.offsetWidth;
let totalSize = 0;
this._tabButtons.forEach((tab, i) => {
if (totalSize + tab.offsetWidth > containerSize) {
// If the first tab is already larger than the container, set the total size to the container size
if (i === 0) {
totalSize = containerSize;
}
return;
}
totalSize += tab.offsetWidth;
});
return totalSize;
}

private _handleClickPrevButton(event: MouseEvent) {
const totalSize = this._getScrollSize();
this._tabListContainer.scrollLeft -= totalSize;
}

private _handleClickNextButton(event: MouseEvent) {
const totalSize = this._getScrollSize();
this._tabListContainer.scrollLeft += totalSize;
}

private _handleMouseDown(event: Event) {
this._isClick = true;
}
Expand Down Expand Up @@ -263,6 +324,9 @@ let exportTabs;
),
);
this._tabButtons[this._getCurrentTabIndex(this.value)].focus();
this._tabButtons[this._getCurrentTabIndex(this.value)].scrollIntoView(
{ behavior: "smooth", block: "nearest", inline: "nearest" },
);
break;
}
index += increment;
Expand Down Expand Up @@ -300,12 +364,51 @@ let exportTabs;
),
);
this._tabButtons[this._getCurrentTabIndex(this.value)].focus();
this._tabButtons[this._getCurrentTabIndex(this.value)].scrollIntoView(
{ behavior: "smooth", block: "nearest", inline: "nearest" },
);
break;
}
index += increment;
}
}

private _getPrevButtonSvgTemplate() {
return svg`
<svg
width="9"
height="15"
viewBox="0 0 9 15"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M1.99061 7.5L9 0.0604158L7.06632 0L0 7.5L7.06632 15L9 14.9396L1.99061 7.5Z"
fill="var(--kuc-tabs-tab-color, #888888)"
/>
</svg>
`;
}

private _getNextButtonSvgTemplate() {
return svg`
<svg
width="9"
height="15"
viewBox="0 0 9 15"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M7.00939 7.5L0 0.0604158L1.93368 0L9 7.5L1.93368 15L0 14.9396L7.00939 7.5Z"
fill="var(--kuc-tabs-tab-color, #888888)"
/>
</svg>
`;
}

private _generateEventDetail(newValue: string) {
const oldValue = this.value;
this.value = newValue;
Expand Down
55 changes: 54 additions & 1 deletion src/tabs/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,66 @@ export const TABS_CSS = `
kuc-tabs[hidden] {
display: none;
}
.kuc-tabs__group__tabs-list__root {
display: flex;
padding: 0;
align-items: center;
padding-top: 16px;
}
.kuc-tabs__group__tab-pre-button {
display: flex;
align-items: center;
justify-content: center;
padding: 0;
margin: 0;
border: none;
background-color: var(--kuc-tabs-tab-background-color, #d4d7d7);
cursor: pointer;
height: var(--kuc-tabs-tab-height, 48px);
width: 24px;
min-width: 24px;
margin-right: 1px;
}
.kuc-tabs__group__tab-pre-button[hidden] {
visibility: hidden;
}
.kuc-tabs__group__tab-next-button {
display: flex;
align-items: center;
justify-content: center;
padding: 0;
margin: 0;
border: none;
background-color: var(--kuc-tabs-tab-background-color, #d4d7d7);
cursor: pointer;
height: var(--kuc-tabs-tab-height, 48px);
width: 24px;
min-width: 24px;
margin-left: 1px;
}
.kuc-tabs__group__tab-next-button[hidden] {
visibility: hidden;
}
.kuc-tabs__group__tab-list-container {
display: flex;
flex-direction: row;
padding: 0;
overflow-y: hidden;
}
.kuc-tabs__group__tab-list {
display: flex;
flex: 1;
padding: 16px 16px 0 16px;
margin: 0;
padding: 0px;
list-style: none;
}
.kuc-tabs__group__tab-list-container {
scrollbar-width: none; /* Firefox */
}
.kuc-tabs__group__tab-list-container::-webkit-scrollbar {
width: 0; /* Safari and Chrome */
display: none
}
.kuc-tabs__group__tab-list__tab {
min-height: var(--kuc-tabs-tab-height, 48px);
height: var(--kuc-tabs-tab-height, 48px);
Expand Down
Loading

0 comments on commit 876707d

Please sign in to comment.