@abydahana/aksara-ui 1.2.3 → 1.2.4
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/aksara.css +22 -0
- package/dist/aksara.d.ts +3 -1
- package/dist/aksara.esm.js +106 -6
- package/dist/aksara.js +106 -6
- package/dist/aksara.min.css +1 -1
- package/dist/aksara.min.js +1 -1
- package/dist/components/navigation/tabs.d.ts +2 -0
- package/dist/components/navigation/tabs.js +7 -5
- package/package.json +1 -1
package/dist/aksara.css
CHANGED
|
@@ -24271,6 +24271,28 @@ img,svg,video {
|
|
|
24271
24271
|
.tab-panel {
|
|
24272
24272
|
padding:1rem 0
|
|
24273
24273
|
}
|
|
24274
|
+
.tabs-slider {
|
|
24275
|
+
position:relative;
|
|
24276
|
+
overflow:hidden;
|
|
24277
|
+
width:100%
|
|
24278
|
+
}
|
|
24279
|
+
.tabs-slider-track {
|
|
24280
|
+
display:flex;
|
|
24281
|
+
flex-direction:row;
|
|
24282
|
+
flex-wrap:nowrap;
|
|
24283
|
+
width:100%;
|
|
24284
|
+
will-change:transform;
|
|
24285
|
+
touch-action:pan-y pinch-zoom;
|
|
24286
|
+
transition:transform .3s cubic-bezier(.25,1,.5,1)
|
|
24287
|
+
}
|
|
24288
|
+
.tabs-slider-track > .tab-panel,.tabs-slider-track > .tab-pane {
|
|
24289
|
+
flex:0 0 100%;
|
|
24290
|
+
min-width:100%;
|
|
24291
|
+
max-width:100%;
|
|
24292
|
+
width:100%;
|
|
24293
|
+
box-sizing:border-box;
|
|
24294
|
+
display:block !important
|
|
24295
|
+
}
|
|
24274
24296
|
.tab[aria-selected="true"] {
|
|
24275
24297
|
background:var(--aksara-bg-subtle);
|
|
24276
24298
|
color:var(--aksara-text-body)
|
package/dist/aksara.d.ts
CHANGED
|
@@ -189,7 +189,9 @@ export declare class Tabs extends Component {
|
|
|
189
189
|
constructor(element: HTMLElement, options?: TabsOptions);
|
|
190
190
|
updateOptions(options?: TabsOptions): this;
|
|
191
191
|
activateInitial(): void;
|
|
192
|
-
|
|
192
|
+
getSliderTrack(): HTMLElement | null;
|
|
193
|
+
bindSliderGestures(): void;
|
|
194
|
+
show(tab: HTMLElement, animate?: boolean): this;
|
|
193
195
|
}
|
|
194
196
|
export declare class Toast extends Component {
|
|
195
197
|
static componentName: string;
|
package/dist/aksara.esm.js
CHANGED
|
@@ -990,6 +990,7 @@ export class Tabs extends Component {
|
|
|
990
990
|
this.show(next);
|
|
991
991
|
}
|
|
992
992
|
});
|
|
993
|
+
this.bindSliderGestures();
|
|
993
994
|
this.activateInitial();
|
|
994
995
|
}
|
|
995
996
|
updateOptions(options = {}) {
|
|
@@ -1029,29 +1030,128 @@ export class Tabs extends Component {
|
|
|
1029
1030
|
if (initial)
|
|
1030
1031
|
this.show(initial);
|
|
1031
1032
|
}
|
|
1032
|
-
|
|
1033
|
+
getSliderTrack() {
|
|
1034
|
+
const wrapper = this.element.closest(".tabs-wrapper") ||
|
|
1035
|
+
this.element.closest(".feed-main-col, main, .page-container, [data-tabs-wrapper]") ||
|
|
1036
|
+
this.element.parentElement;
|
|
1037
|
+
return (wrapper?.querySelector(".tabs-slider-track, [data-tabs-slider]") ||
|
|
1038
|
+
document.querySelector(".tabs-slider-track, [data-tabs-slider]"));
|
|
1039
|
+
}
|
|
1040
|
+
bindSliderGestures() {
|
|
1041
|
+
const track = this.getSliderTrack();
|
|
1042
|
+
if (!track || track.__sliderGesturesBound)
|
|
1043
|
+
return;
|
|
1044
|
+
track.__sliderGesturesBound = true;
|
|
1045
|
+
let startX = 0;
|
|
1046
|
+
let startY = 0;
|
|
1047
|
+
let deltaX = 0;
|
|
1048
|
+
let deltaY = 0;
|
|
1049
|
+
let isSwiping = false;
|
|
1050
|
+
let isVertical = false;
|
|
1051
|
+
track.addEventListener("touchstart", (e) => {
|
|
1052
|
+
if (e.touches.length !== 1)
|
|
1053
|
+
return;
|
|
1054
|
+
const target = e.target;
|
|
1055
|
+
if (target?.closest("input, textarea, select, [contenteditable='true'], video, audio, .carousel, .bento-carousel, .media-grid-scroll, .map-canvas-container, [data-prevent-swipe]")) {
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
const touch = e.touches[0];
|
|
1059
|
+
startX = touch.clientX;
|
|
1060
|
+
startY = touch.clientY;
|
|
1061
|
+
deltaX = 0;
|
|
1062
|
+
deltaY = 0;
|
|
1063
|
+
isSwiping = false;
|
|
1064
|
+
isVertical = false;
|
|
1065
|
+
}, { passive: true });
|
|
1066
|
+
track.addEventListener("touchmove", (e) => {
|
|
1067
|
+
if (e.touches.length !== 1 || isVertical)
|
|
1068
|
+
return;
|
|
1069
|
+
const touch = e.touches[0];
|
|
1070
|
+
deltaX = touch.clientX - startX;
|
|
1071
|
+
deltaY = touch.clientY - startY;
|
|
1072
|
+
if (!isSwiping) {
|
|
1073
|
+
if (Math.abs(deltaY) > 8 && Math.abs(deltaY) > Math.abs(deltaX)) {
|
|
1074
|
+
isVertical = true;
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
if (Math.abs(deltaX) > 8 && Math.abs(deltaX) > Math.abs(deltaY)) {
|
|
1078
|
+
isSwiping = true;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
if (isSwiping) {
|
|
1082
|
+
if (e.cancelable)
|
|
1083
|
+
e.preventDefault();
|
|
1084
|
+
const tabs = Array.from(this.element.querySelectorAll(this.tabSelector));
|
|
1085
|
+
const maxIdx = Math.max(0, tabs.length - 1);
|
|
1086
|
+
let currentDelta = deltaX;
|
|
1087
|
+
const currentIdx = tabs.findIndex((t) => t.classList.contains("active"));
|
|
1088
|
+
const safeIdx = currentIdx >= 0 ? currentIdx : 0;
|
|
1089
|
+
if ((safeIdx === 0 && currentDelta > 0) || (safeIdx === maxIdx && currentDelta < 0)) {
|
|
1090
|
+
currentDelta = currentDelta * 0.3;
|
|
1091
|
+
}
|
|
1092
|
+
track.style.transition = "none";
|
|
1093
|
+
track.style.transform = `translate3d(calc(-${safeIdx * 100}% + ${currentDelta}px), 0, 0)`;
|
|
1094
|
+
}
|
|
1095
|
+
}, { passive: false });
|
|
1096
|
+
const onTouchEnd = () => {
|
|
1097
|
+
if (!isSwiping)
|
|
1098
|
+
return;
|
|
1099
|
+
isSwiping = false;
|
|
1100
|
+
const tabs = Array.from(this.element.querySelectorAll(this.tabSelector));
|
|
1101
|
+
const maxIdx = Math.max(0, tabs.length - 1);
|
|
1102
|
+
const currentIdx = tabs.findIndex((t) => t.classList.contains("active"));
|
|
1103
|
+
const safeIdx = currentIdx >= 0 ? currentIdx : 0;
|
|
1104
|
+
track.style.transition = "transform 0.3s cubic-bezier(0.25, 1, 0.5, 1)";
|
|
1105
|
+
if (deltaX < -50 && safeIdx < maxIdx) {
|
|
1106
|
+
this.show(tabs[safeIdx + 1]);
|
|
1107
|
+
}
|
|
1108
|
+
else if (deltaX > 50 && safeIdx > 0) {
|
|
1109
|
+
this.show(tabs[safeIdx - 1]);
|
|
1110
|
+
}
|
|
1111
|
+
else {
|
|
1112
|
+
track.style.transform = `translate3d(-${safeIdx * 100}%, 0, 0)`;
|
|
1113
|
+
}
|
|
1114
|
+
};
|
|
1115
|
+
track.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
1116
|
+
track.addEventListener("touchcancel", onTouchEnd, { passive: true });
|
|
1117
|
+
}
|
|
1118
|
+
show(tab, animate = true) {
|
|
1033
1119
|
const selector = tab.getAttribute("data-tabs");
|
|
1034
1120
|
const panel = selector ? document.querySelector(selector) : null;
|
|
1035
1121
|
if (!panel)
|
|
1036
1122
|
return this;
|
|
1037
|
-
this.element.querySelectorAll(this.tabSelector)
|
|
1123
|
+
const tabs = Array.from(this.element.querySelectorAll(this.tabSelector));
|
|
1124
|
+
const targetIndex = tabs.indexOf(tab);
|
|
1125
|
+
const track = this.getSliderTrack();
|
|
1126
|
+
const isSlider = Boolean(track && track.contains(panel));
|
|
1127
|
+
tabs.forEach((item) => {
|
|
1038
1128
|
const selected = item === tab;
|
|
1039
1129
|
item.setAttribute("role", item.getAttribute("role") || "tab");
|
|
1040
1130
|
item.setAttribute("aria-selected", String(selected));
|
|
1131
|
+
item.classList.toggle("active", selected);
|
|
1041
1132
|
item.tabIndex = selected ? 0 : -1;
|
|
1042
1133
|
const targetSelector = item.getAttribute("data-tabs");
|
|
1043
1134
|
const target = targetSelector ? document.querySelector(targetSelector) : null;
|
|
1044
|
-
if (target)
|
|
1045
|
-
target.
|
|
1135
|
+
if (target) {
|
|
1136
|
+
target.classList.toggle("active", selected);
|
|
1137
|
+
if (!isSlider) {
|
|
1138
|
+
target.hidden = !selected;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1046
1141
|
});
|
|
1047
|
-
if (this.panelSelector) {
|
|
1142
|
+
if (this.panelSelector && !isSlider) {
|
|
1048
1143
|
document.querySelectorAll(this.panelSelector).forEach((item) => {
|
|
1049
1144
|
if (item !== panel)
|
|
1050
1145
|
item.hidden = true;
|
|
1051
1146
|
});
|
|
1052
1147
|
}
|
|
1053
1148
|
panel.setAttribute("role", panel.getAttribute("role") || "tabpanel");
|
|
1054
|
-
|
|
1149
|
+
if (isSlider && track && targetIndex >= 0) {
|
|
1150
|
+
track.style.transition = animate ? "transform 0.3s cubic-bezier(0.25, 1, 0.5, 1)" : "none";
|
|
1151
|
+
track.style.transform = `translate3d(-${targetIndex * 100}%, 0, 0)`;
|
|
1152
|
+
}
|
|
1153
|
+
tab.scrollIntoView({ behavior: "smooth", inline: "center", block: "nearest" });
|
|
1154
|
+
emit(this.element, "tabs:show", { tab, panel, index: targetIndex, instance: this });
|
|
1055
1155
|
return this;
|
|
1056
1156
|
}
|
|
1057
1157
|
}
|
package/dist/aksara.js
CHANGED
|
@@ -991,6 +991,7 @@ class Tabs extends Component {
|
|
|
991
991
|
this.show(next);
|
|
992
992
|
}
|
|
993
993
|
});
|
|
994
|
+
this.bindSliderGestures();
|
|
994
995
|
this.activateInitial();
|
|
995
996
|
}
|
|
996
997
|
updateOptions(options = {}) {
|
|
@@ -1030,29 +1031,128 @@ class Tabs extends Component {
|
|
|
1030
1031
|
if (initial)
|
|
1031
1032
|
this.show(initial);
|
|
1032
1033
|
}
|
|
1033
|
-
|
|
1034
|
+
getSliderTrack() {
|
|
1035
|
+
const wrapper = this.element.closest(".tabs-wrapper") ||
|
|
1036
|
+
this.element.closest(".feed-main-col, main, .page-container, [data-tabs-wrapper]") ||
|
|
1037
|
+
this.element.parentElement;
|
|
1038
|
+
return (wrapper?.querySelector(".tabs-slider-track, [data-tabs-slider]") ||
|
|
1039
|
+
document.querySelector(".tabs-slider-track, [data-tabs-slider]"));
|
|
1040
|
+
}
|
|
1041
|
+
bindSliderGestures() {
|
|
1042
|
+
const track = this.getSliderTrack();
|
|
1043
|
+
if (!track || track.__sliderGesturesBound)
|
|
1044
|
+
return;
|
|
1045
|
+
track.__sliderGesturesBound = true;
|
|
1046
|
+
let startX = 0;
|
|
1047
|
+
let startY = 0;
|
|
1048
|
+
let deltaX = 0;
|
|
1049
|
+
let deltaY = 0;
|
|
1050
|
+
let isSwiping = false;
|
|
1051
|
+
let isVertical = false;
|
|
1052
|
+
track.addEventListener("touchstart", (e) => {
|
|
1053
|
+
if (e.touches.length !== 1)
|
|
1054
|
+
return;
|
|
1055
|
+
const target = e.target;
|
|
1056
|
+
if (target?.closest("input, textarea, select, [contenteditable='true'], video, audio, .carousel, .bento-carousel, .media-grid-scroll, .map-canvas-container, [data-prevent-swipe]")) {
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
const touch = e.touches[0];
|
|
1060
|
+
startX = touch.clientX;
|
|
1061
|
+
startY = touch.clientY;
|
|
1062
|
+
deltaX = 0;
|
|
1063
|
+
deltaY = 0;
|
|
1064
|
+
isSwiping = false;
|
|
1065
|
+
isVertical = false;
|
|
1066
|
+
}, { passive: true });
|
|
1067
|
+
track.addEventListener("touchmove", (e) => {
|
|
1068
|
+
if (e.touches.length !== 1 || isVertical)
|
|
1069
|
+
return;
|
|
1070
|
+
const touch = e.touches[0];
|
|
1071
|
+
deltaX = touch.clientX - startX;
|
|
1072
|
+
deltaY = touch.clientY - startY;
|
|
1073
|
+
if (!isSwiping) {
|
|
1074
|
+
if (Math.abs(deltaY) > 8 && Math.abs(deltaY) > Math.abs(deltaX)) {
|
|
1075
|
+
isVertical = true;
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
if (Math.abs(deltaX) > 8 && Math.abs(deltaX) > Math.abs(deltaY)) {
|
|
1079
|
+
isSwiping = true;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
if (isSwiping) {
|
|
1083
|
+
if (e.cancelable)
|
|
1084
|
+
e.preventDefault();
|
|
1085
|
+
const tabs = Array.from(this.element.querySelectorAll(this.tabSelector));
|
|
1086
|
+
const maxIdx = Math.max(0, tabs.length - 1);
|
|
1087
|
+
let currentDelta = deltaX;
|
|
1088
|
+
const currentIdx = tabs.findIndex((t) => t.classList.contains("active"));
|
|
1089
|
+
const safeIdx = currentIdx >= 0 ? currentIdx : 0;
|
|
1090
|
+
if ((safeIdx === 0 && currentDelta > 0) || (safeIdx === maxIdx && currentDelta < 0)) {
|
|
1091
|
+
currentDelta = currentDelta * 0.3;
|
|
1092
|
+
}
|
|
1093
|
+
track.style.transition = "none";
|
|
1094
|
+
track.style.transform = `translate3d(calc(-${safeIdx * 100}% + ${currentDelta}px), 0, 0)`;
|
|
1095
|
+
}
|
|
1096
|
+
}, { passive: false });
|
|
1097
|
+
const onTouchEnd = () => {
|
|
1098
|
+
if (!isSwiping)
|
|
1099
|
+
return;
|
|
1100
|
+
isSwiping = false;
|
|
1101
|
+
const tabs = Array.from(this.element.querySelectorAll(this.tabSelector));
|
|
1102
|
+
const maxIdx = Math.max(0, tabs.length - 1);
|
|
1103
|
+
const currentIdx = tabs.findIndex((t) => t.classList.contains("active"));
|
|
1104
|
+
const safeIdx = currentIdx >= 0 ? currentIdx : 0;
|
|
1105
|
+
track.style.transition = "transform 0.3s cubic-bezier(0.25, 1, 0.5, 1)";
|
|
1106
|
+
if (deltaX < -50 && safeIdx < maxIdx) {
|
|
1107
|
+
this.show(tabs[safeIdx + 1]);
|
|
1108
|
+
}
|
|
1109
|
+
else if (deltaX > 50 && safeIdx > 0) {
|
|
1110
|
+
this.show(tabs[safeIdx - 1]);
|
|
1111
|
+
}
|
|
1112
|
+
else {
|
|
1113
|
+
track.style.transform = `translate3d(-${safeIdx * 100}%, 0, 0)`;
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1116
|
+
track.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
1117
|
+
track.addEventListener("touchcancel", onTouchEnd, { passive: true });
|
|
1118
|
+
}
|
|
1119
|
+
show(tab, animate = true) {
|
|
1034
1120
|
const selector = tab.getAttribute("data-tabs");
|
|
1035
1121
|
const panel = selector ? document.querySelector(selector) : null;
|
|
1036
1122
|
if (!panel)
|
|
1037
1123
|
return this;
|
|
1038
|
-
this.element.querySelectorAll(this.tabSelector)
|
|
1124
|
+
const tabs = Array.from(this.element.querySelectorAll(this.tabSelector));
|
|
1125
|
+
const targetIndex = tabs.indexOf(tab);
|
|
1126
|
+
const track = this.getSliderTrack();
|
|
1127
|
+
const isSlider = Boolean(track && track.contains(panel));
|
|
1128
|
+
tabs.forEach((item) => {
|
|
1039
1129
|
const selected = item === tab;
|
|
1040
1130
|
item.setAttribute("role", item.getAttribute("role") || "tab");
|
|
1041
1131
|
item.setAttribute("aria-selected", String(selected));
|
|
1132
|
+
item.classList.toggle("active", selected);
|
|
1042
1133
|
item.tabIndex = selected ? 0 : -1;
|
|
1043
1134
|
const targetSelector = item.getAttribute("data-tabs");
|
|
1044
1135
|
const target = targetSelector ? document.querySelector(targetSelector) : null;
|
|
1045
|
-
if (target)
|
|
1046
|
-
target.
|
|
1136
|
+
if (target) {
|
|
1137
|
+
target.classList.toggle("active", selected);
|
|
1138
|
+
if (!isSlider) {
|
|
1139
|
+
target.hidden = !selected;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1047
1142
|
});
|
|
1048
|
-
if (this.panelSelector) {
|
|
1143
|
+
if (this.panelSelector && !isSlider) {
|
|
1049
1144
|
document.querySelectorAll(this.panelSelector).forEach((item) => {
|
|
1050
1145
|
if (item !== panel)
|
|
1051
1146
|
item.hidden = true;
|
|
1052
1147
|
});
|
|
1053
1148
|
}
|
|
1054
1149
|
panel.setAttribute("role", panel.getAttribute("role") || "tabpanel");
|
|
1055
|
-
|
|
1150
|
+
if (isSlider && track && targetIndex >= 0) {
|
|
1151
|
+
track.style.transition = animate ? "transform 0.3s cubic-bezier(0.25, 1, 0.5, 1)" : "none";
|
|
1152
|
+
track.style.transform = `translate3d(-${targetIndex * 100}%, 0, 0)`;
|
|
1153
|
+
}
|
|
1154
|
+
tab.scrollIntoView({ behavior: "smooth", inline: "center", block: "nearest" });
|
|
1155
|
+
emit(this.element, "tabs:show", { tab, panel, index: targetIndex, instance: this });
|
|
1056
1156
|
return this;
|
|
1057
1157
|
}
|
|
1058
1158
|
}
|