@idds/js 1.0.84 → 1.0.85
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/index.iife.js +330 -0
- package/dist/index.js +329 -0
- package/package.json +1 -1
package/dist/index.iife.js
CHANGED
|
@@ -41,6 +41,7 @@ var InaUI = (() => {
|
|
|
41
41
|
initTab: () => initTab,
|
|
42
42
|
initTabHorizontal: () => initTabHorizontal,
|
|
43
43
|
initTabVertical: () => initTabVertical,
|
|
44
|
+
initTable: () => initTable,
|
|
44
45
|
initTimepicker: () => initTimepicker,
|
|
45
46
|
initToggle: () => initToggle,
|
|
46
47
|
setBrandTheme: () => setBrandTheme,
|
|
@@ -2902,6 +2903,334 @@ var InaUI = (() => {
|
|
|
2902
2903
|
});
|
|
2903
2904
|
}
|
|
2904
2905
|
|
|
2906
|
+
// src/js/components/stateful/table.js
|
|
2907
|
+
function initTable(selectorOrElement, options = {}) {
|
|
2908
|
+
const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? selectorOrElement.length ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-table`);
|
|
2909
|
+
elements.forEach((container) => {
|
|
2910
|
+
if (container.dataset.initialized === "true") return;
|
|
2911
|
+
container.dataset.initialized = "true";
|
|
2912
|
+
const {
|
|
2913
|
+
columns = [],
|
|
2914
|
+
fetchData = null,
|
|
2915
|
+
data = [],
|
|
2916
|
+
initialPageSize = 10,
|
|
2917
|
+
pageSizeOptions = [10, 20, 50],
|
|
2918
|
+
initialSortField = null,
|
|
2919
|
+
initialSortOrder = null,
|
|
2920
|
+
searchContainer = null,
|
|
2921
|
+
// External search input element or selector
|
|
2922
|
+
searchButton = null,
|
|
2923
|
+
// External search button element or selector
|
|
2924
|
+
onSearch = null
|
|
2925
|
+
// External search handler
|
|
2926
|
+
} = options;
|
|
2927
|
+
let currentPage = 1;
|
|
2928
|
+
let pageSize = initialPageSize;
|
|
2929
|
+
let totalPages = 1;
|
|
2930
|
+
let total = data.length;
|
|
2931
|
+
let sortField = initialSortField;
|
|
2932
|
+
let sortOrder = initialSortOrder;
|
|
2933
|
+
let searchTerm = "";
|
|
2934
|
+
let loading = false;
|
|
2935
|
+
let currentData = [...data];
|
|
2936
|
+
let tableEl = container.querySelector(`.${PREFIX}-table__container`);
|
|
2937
|
+
let theadEl = container.querySelector(`.${PREFIX}-table__header`);
|
|
2938
|
+
let tbodyEl = container.querySelector(`.${PREFIX}-table__body`);
|
|
2939
|
+
let paginationEl = container.querySelector(`.${PREFIX}-table__pagination`);
|
|
2940
|
+
let progressBarEl = container.querySelector(
|
|
2941
|
+
`.${PREFIX}-table__progress-bar`
|
|
2942
|
+
);
|
|
2943
|
+
let progressFillEl = container.querySelector(
|
|
2944
|
+
`.${PREFIX}-progress-bar__fill`
|
|
2945
|
+
);
|
|
2946
|
+
const searchInputEl = typeof searchContainer === "string" ? document.querySelector(searchContainer) : searchContainer;
|
|
2947
|
+
const searchBtnEl = typeof searchButton === "string" ? document.querySelector(searchButton) : searchButton;
|
|
2948
|
+
if (!tableEl) {
|
|
2949
|
+
container.innerHTML = `
|
|
2950
|
+
<div class="${PREFIX}-table__progress-bar" style="display: none;">
|
|
2951
|
+
<div class="${PREFIX}-progress-bar ${PREFIX}-progress-bar--variant-primary ${PREFIX}-progress-bar--height-sm">
|
|
2952
|
+
<div class="${PREFIX}-progress-bar__track">
|
|
2953
|
+
<div class="${PREFIX}-progress-bar__fill" style="width: 0%;"></div>
|
|
2954
|
+
</div>
|
|
2955
|
+
</div>
|
|
2956
|
+
</div>
|
|
2957
|
+
<table class="${PREFIX}-table__container">
|
|
2958
|
+
<thead class="${PREFIX}-table__header"><tr></tr></thead>
|
|
2959
|
+
<tbody class="${PREFIX}-table__body"></tbody>
|
|
2960
|
+
</table>
|
|
2961
|
+
<div class="${PREFIX}-table__pagination"></div>
|
|
2962
|
+
`;
|
|
2963
|
+
tableEl = container.querySelector(`.${PREFIX}-table__container`);
|
|
2964
|
+
theadEl = container.querySelector(`.${PREFIX}-table__header`);
|
|
2965
|
+
tbodyEl = container.querySelector(`.${PREFIX}-table__body`);
|
|
2966
|
+
paginationEl = container.querySelector(`.${PREFIX}-table__pagination`);
|
|
2967
|
+
progressBarEl = container.querySelector(`.${PREFIX}-table__progress-bar`);
|
|
2968
|
+
progressFillEl = container.querySelector(`.${PREFIX}-progress-bar__fill`);
|
|
2969
|
+
}
|
|
2970
|
+
const trHeader = theadEl.querySelector("tr") || document.createElement("tr");
|
|
2971
|
+
if (!theadEl.contains(trHeader)) theadEl.appendChild(trHeader);
|
|
2972
|
+
if (columns.length > 0) {
|
|
2973
|
+
trHeader.innerHTML = "";
|
|
2974
|
+
columns.forEach((col) => {
|
|
2975
|
+
const th = document.createElement("th");
|
|
2976
|
+
th.className = `${PREFIX}-table__header-cell`;
|
|
2977
|
+
if (col.sortable && col.accessor) {
|
|
2978
|
+
th.classList.add(`${PREFIX}-table__header-cell--sortable`);
|
|
2979
|
+
th.setAttribute("data-sort", col.accessor);
|
|
2980
|
+
th.innerHTML = `
|
|
2981
|
+
<div class="${PREFIX}-table__sort-controls">
|
|
2982
|
+
${col.header}
|
|
2983
|
+
<div class="${PREFIX}-table__sort-icon">
|
|
2984
|
+
<div class="${PREFIX}-table__sort-button" data-order="asc">
|
|
2985
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9L12 15L18 9"></path></svg>
|
|
2986
|
+
</div>
|
|
2987
|
+
<div class="${PREFIX}-table__sort-button ${PREFIX}-table__sort-button-right" data-order="desc">
|
|
2988
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 15L12 9L6 15"></path></svg>
|
|
2989
|
+
</div>
|
|
2990
|
+
</div>
|
|
2991
|
+
</div>
|
|
2992
|
+
`;
|
|
2993
|
+
th.addEventListener("click", () => {
|
|
2994
|
+
const field = col.accessor;
|
|
2995
|
+
if (sortField === field) {
|
|
2996
|
+
if (sortOrder === "asc") sortOrder = "desc";
|
|
2997
|
+
else if (sortOrder === "desc") {
|
|
2998
|
+
sortField = null;
|
|
2999
|
+
sortOrder = null;
|
|
3000
|
+
}
|
|
3001
|
+
} else {
|
|
3002
|
+
sortField = field;
|
|
3003
|
+
sortOrder = "asc";
|
|
3004
|
+
}
|
|
3005
|
+
currentPage = 1;
|
|
3006
|
+
loadData();
|
|
3007
|
+
});
|
|
3008
|
+
} else {
|
|
3009
|
+
th.textContent = col.header;
|
|
3010
|
+
}
|
|
3011
|
+
trHeader.appendChild(th);
|
|
3012
|
+
});
|
|
3013
|
+
}
|
|
3014
|
+
const sortButtons = theadEl.querySelectorAll(
|
|
3015
|
+
`.${PREFIX}-table__sort-button`
|
|
3016
|
+
);
|
|
3017
|
+
let loadingInterval;
|
|
3018
|
+
function setLoading(isLoading) {
|
|
3019
|
+
loading = isLoading;
|
|
3020
|
+
if (!progressBarEl || !progressFillEl) return;
|
|
3021
|
+
if (isLoading) {
|
|
3022
|
+
progressBarEl.style.display = "block";
|
|
3023
|
+
let progress = 0;
|
|
3024
|
+
clearInterval(loadingInterval);
|
|
3025
|
+
loadingInterval = setInterval(() => {
|
|
3026
|
+
if (progress >= 90 || !loading) {
|
|
3027
|
+
clearInterval(loadingInterval);
|
|
3028
|
+
if (!loading) {
|
|
3029
|
+
progress = 100;
|
|
3030
|
+
progressFillEl.style.width = "100%";
|
|
3031
|
+
setTimeout(() => {
|
|
3032
|
+
progressBarEl.style.display = "none";
|
|
3033
|
+
progressFillEl.style.width = "0%";
|
|
3034
|
+
}, 300);
|
|
3035
|
+
}
|
|
3036
|
+
return;
|
|
3037
|
+
}
|
|
3038
|
+
progress += Math.random() * 15;
|
|
3039
|
+
progressFillEl.style.width = progress + "%";
|
|
3040
|
+
}, 200);
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
function renderRows(rowData) {
|
|
3044
|
+
tbodyEl.innerHTML = "";
|
|
3045
|
+
if (rowData.length === 0) {
|
|
3046
|
+
const tr = document.createElement("tr");
|
|
3047
|
+
tr.innerHTML = `<td colspan="${columns.length || 1}" class="${PREFIX}-table__empty-cell">No data found</td>`;
|
|
3048
|
+
tbodyEl.appendChild(tr);
|
|
3049
|
+
return;
|
|
3050
|
+
}
|
|
3051
|
+
rowData.forEach((row, index) => {
|
|
3052
|
+
const tr = document.createElement("tr");
|
|
3053
|
+
tr.className = `${PREFIX}-table__row`;
|
|
3054
|
+
columns.forEach((col) => {
|
|
3055
|
+
const td = document.createElement("td");
|
|
3056
|
+
td.className = `${PREFIX}-table__cell`;
|
|
3057
|
+
if (typeof col.render === "function") {
|
|
3058
|
+
const content = col.render(row, index);
|
|
3059
|
+
if (typeof content === "string") {
|
|
3060
|
+
td.innerHTML = content;
|
|
3061
|
+
} else if (content instanceof HTMLElement) {
|
|
3062
|
+
td.appendChild(content);
|
|
3063
|
+
} else {
|
|
3064
|
+
td.textContent = content;
|
|
3065
|
+
}
|
|
3066
|
+
} else {
|
|
3067
|
+
td.textContent = row[col.accessor] !== void 0 ? row[col.accessor] : "";
|
|
3068
|
+
}
|
|
3069
|
+
tr.appendChild(td);
|
|
3070
|
+
});
|
|
3071
|
+
tbodyEl.appendChild(tr);
|
|
3072
|
+
});
|
|
3073
|
+
}
|
|
3074
|
+
function renderPagination() {
|
|
3075
|
+
if (!paginationEl) return;
|
|
3076
|
+
totalPages = Math.ceil(total / pageSize);
|
|
3077
|
+
if (totalPages < 1) totalPages = 1;
|
|
3078
|
+
paginationEl.innerHTML = `
|
|
3079
|
+
<div class="${PREFIX}-pagination">
|
|
3080
|
+
<div class="${PREFIX}-pagination__nav-container">
|
|
3081
|
+
<div class="${PREFIX}-pagination__page-info">Halaman ${currentPage} dari ${totalPages}</div>
|
|
3082
|
+
<div class="${PREFIX}-pagination__nav-buttons"></div>
|
|
3083
|
+
</div>
|
|
3084
|
+
<div class="${PREFIX}-pagination__page-size-container">
|
|
3085
|
+
<span class="${PREFIX}-pagination__page-size-label">Baris per halaman</span>
|
|
3086
|
+
<select class="${PREFIX}-pagination__page-size-select">
|
|
3087
|
+
${pageSizeOptions.map((opt) => `<option value="${opt}" ${pageSize === opt ? "selected" : ""}>${opt}</option>`).join("")}
|
|
3088
|
+
</select>
|
|
3089
|
+
</div>
|
|
3090
|
+
</div>
|
|
3091
|
+
`;
|
|
3092
|
+
const navButtonsContainer = paginationEl.querySelector(
|
|
3093
|
+
`.${PREFIX}-pagination__nav-buttons`
|
|
3094
|
+
);
|
|
3095
|
+
const pageSizeSelect = paginationEl.querySelector(
|
|
3096
|
+
`.${PREFIX}-pagination__page-size-select`
|
|
3097
|
+
);
|
|
3098
|
+
pageSizeSelect.addEventListener("change", (e) => {
|
|
3099
|
+
pageSize = parseInt(e.target.value);
|
|
3100
|
+
currentPage = 1;
|
|
3101
|
+
loadData();
|
|
3102
|
+
});
|
|
3103
|
+
const createButton = (isNav, enabled, content, onClick) => {
|
|
3104
|
+
const btn = document.createElement("button");
|
|
3105
|
+
btn.type = "button";
|
|
3106
|
+
const baseClass = isNav ? `${PREFIX}-pagination__nav-button` : `${PREFIX}-pagination__page-button`;
|
|
3107
|
+
const stateClass = isNav ? enabled ? `${baseClass}--enabled` : `${baseClass}--disabled` : enabled ? `${baseClass}--enabled` : `${baseClass}--active`;
|
|
3108
|
+
btn.className = `${baseClass} ${stateClass}`;
|
|
3109
|
+
btn.disabled = !enabled;
|
|
3110
|
+
if (typeof content === "string") btn.innerHTML = content;
|
|
3111
|
+
else btn.appendChild(content);
|
|
3112
|
+
btn.onclick = onClick;
|
|
3113
|
+
navButtonsContainer.appendChild(btn);
|
|
3114
|
+
};
|
|
3115
|
+
const iconPaths = {
|
|
3116
|
+
first: '<path d="M11 7l-5 5l5 5"></path><path d="M17 7l-5 5l5 5"></path>',
|
|
3117
|
+
prev: '<path d="M15 6l-6 6l6 6"></path>',
|
|
3118
|
+
next: '<path d="M9 6l6 6l-6 6"></path>',
|
|
3119
|
+
last: '<path d="M7 7l5 5l-5 5"></path><path d="M13 7l5 5l-5 5"></path>'
|
|
3120
|
+
};
|
|
3121
|
+
const getIcon = (type) => `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="${PREFIX}-pagination__nav-icon">${iconPaths[type]}</svg>`;
|
|
3122
|
+
createButton(true, currentPage > 1, getIcon("first"), () => {
|
|
3123
|
+
currentPage = 1;
|
|
3124
|
+
loadData();
|
|
3125
|
+
});
|
|
3126
|
+
createButton(true, currentPage > 1, getIcon("prev"), () => {
|
|
3127
|
+
currentPage--;
|
|
3128
|
+
loadData();
|
|
3129
|
+
});
|
|
3130
|
+
const maxVisible = 5;
|
|
3131
|
+
let startPage = Math.max(1, currentPage - Math.floor(maxVisible / 2));
|
|
3132
|
+
let endPage = Math.min(totalPages, startPage + maxVisible - 1);
|
|
3133
|
+
if (endPage - startPage < maxVisible - 1) {
|
|
3134
|
+
startPage = Math.max(1, endPage - maxVisible + 1);
|
|
3135
|
+
}
|
|
3136
|
+
for (let i = startPage; i <= endPage; i++) {
|
|
3137
|
+
createButton(false, i !== currentPage, String(i), () => {
|
|
3138
|
+
currentPage = i;
|
|
3139
|
+
loadData();
|
|
3140
|
+
});
|
|
3141
|
+
}
|
|
3142
|
+
createButton(true, currentPage < totalPages, getIcon("next"), () => {
|
|
3143
|
+
currentPage++;
|
|
3144
|
+
loadData();
|
|
3145
|
+
});
|
|
3146
|
+
createButton(true, currentPage < totalPages, getIcon("last"), () => {
|
|
3147
|
+
currentPage = totalPages;
|
|
3148
|
+
loadData();
|
|
3149
|
+
});
|
|
3150
|
+
}
|
|
3151
|
+
function updateSortIndicators() {
|
|
3152
|
+
sortButtons.forEach((btn) => {
|
|
3153
|
+
const headerCell = btn.closest("th");
|
|
3154
|
+
if (!headerCell) return;
|
|
3155
|
+
const field = headerCell.getAttribute("data-sort");
|
|
3156
|
+
const order = btn.getAttribute("data-order");
|
|
3157
|
+
const isActive = sortField === field && sortOrder === order;
|
|
3158
|
+
btn.classList.toggle(`${PREFIX}-table__sort-button--active`, isActive);
|
|
3159
|
+
});
|
|
3160
|
+
}
|
|
3161
|
+
async function loadData() {
|
|
3162
|
+
setLoading(true);
|
|
3163
|
+
try {
|
|
3164
|
+
if (typeof fetchData === "function") {
|
|
3165
|
+
const result = await fetchData({
|
|
3166
|
+
page: currentPage,
|
|
3167
|
+
pageSize,
|
|
3168
|
+
sortField,
|
|
3169
|
+
sortOrder,
|
|
3170
|
+
searchTerm
|
|
3171
|
+
});
|
|
3172
|
+
total = result.total;
|
|
3173
|
+
currentData = result.data;
|
|
3174
|
+
} else {
|
|
3175
|
+
let filteredData = [...data];
|
|
3176
|
+
if (searchTerm) {
|
|
3177
|
+
const lowerSearch = searchTerm.toLowerCase();
|
|
3178
|
+
filteredData = filteredData.filter(
|
|
3179
|
+
(item) => columns.some(
|
|
3180
|
+
(c) => String(item[c.accessor] || "").toLowerCase().includes(lowerSearch)
|
|
3181
|
+
)
|
|
3182
|
+
);
|
|
3183
|
+
}
|
|
3184
|
+
if (sortField && sortOrder) {
|
|
3185
|
+
filteredData.sort((a, b) => {
|
|
3186
|
+
const aVal = a[sortField];
|
|
3187
|
+
const bVal = b[sortField];
|
|
3188
|
+
if (aVal < bVal) return sortOrder === "asc" ? -1 : 1;
|
|
3189
|
+
if (aVal > bVal) return sortOrder === "asc" ? 1 : -1;
|
|
3190
|
+
return 0;
|
|
3191
|
+
});
|
|
3192
|
+
}
|
|
3193
|
+
total = filteredData.length;
|
|
3194
|
+
const skip = (currentPage - 1) * pageSize;
|
|
3195
|
+
currentData = filteredData.slice(skip, skip + pageSize);
|
|
3196
|
+
}
|
|
3197
|
+
renderRows(currentData);
|
|
3198
|
+
renderPagination();
|
|
3199
|
+
updateSortIndicators();
|
|
3200
|
+
} catch (error) {
|
|
3201
|
+
console.error("Table API Error:", error);
|
|
3202
|
+
} finally {
|
|
3203
|
+
setLoading(false);
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
if (searchInputEl && searchBtnEl) {
|
|
3207
|
+
const handleSearch = () => {
|
|
3208
|
+
searchTerm = searchInputEl.value.trim();
|
|
3209
|
+
currentPage = 1;
|
|
3210
|
+
loadData();
|
|
3211
|
+
if (typeof onSearch === "function") onSearch(searchTerm);
|
|
3212
|
+
};
|
|
3213
|
+
searchBtnEl.addEventListener("click", handleSearch);
|
|
3214
|
+
searchInputEl.addEventListener("keydown", (e) => {
|
|
3215
|
+
if (e.key === "Enter") handleSearch();
|
|
3216
|
+
});
|
|
3217
|
+
}
|
|
3218
|
+
loadData();
|
|
3219
|
+
container.__tableAPI = {
|
|
3220
|
+
reload: loadData,
|
|
3221
|
+
setSearchTerm: (term) => {
|
|
3222
|
+
searchTerm = term;
|
|
3223
|
+
currentPage = 1;
|
|
3224
|
+
loadData();
|
|
3225
|
+
},
|
|
3226
|
+
setPage: (page) => {
|
|
3227
|
+
currentPage = page;
|
|
3228
|
+
loadData();
|
|
3229
|
+
}
|
|
3230
|
+
};
|
|
3231
|
+
});
|
|
3232
|
+
}
|
|
3233
|
+
|
|
2905
3234
|
// src/js/components/stateless/toast.js
|
|
2906
3235
|
var ICONS3 = {
|
|
2907
3236
|
default: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>`,
|
|
@@ -3231,6 +3560,7 @@ var InaUI = (() => {
|
|
|
3231
3560
|
initChip();
|
|
3232
3561
|
initTabVertical();
|
|
3233
3562
|
initTabHorizontal();
|
|
3563
|
+
initTable();
|
|
3234
3564
|
});
|
|
3235
3565
|
}
|
|
3236
3566
|
return __toCommonJS(bundle_exports);
|
package/dist/index.js
CHANGED
|
@@ -2988,6 +2988,334 @@ function initTabHorizontal() {
|
|
|
2988
2988
|
});
|
|
2989
2989
|
}
|
|
2990
2990
|
|
|
2991
|
+
// src/js/components/stateful/table.js
|
|
2992
|
+
function initTable(selectorOrElement, options = {}) {
|
|
2993
|
+
const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? selectorOrElement.length ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-table`);
|
|
2994
|
+
elements.forEach((container) => {
|
|
2995
|
+
if (container.dataset.initialized === "true") return;
|
|
2996
|
+
container.dataset.initialized = "true";
|
|
2997
|
+
const {
|
|
2998
|
+
columns = [],
|
|
2999
|
+
fetchData = null,
|
|
3000
|
+
data = [],
|
|
3001
|
+
initialPageSize = 10,
|
|
3002
|
+
pageSizeOptions = [10, 20, 50],
|
|
3003
|
+
initialSortField = null,
|
|
3004
|
+
initialSortOrder = null,
|
|
3005
|
+
searchContainer = null,
|
|
3006
|
+
// External search input element or selector
|
|
3007
|
+
searchButton = null,
|
|
3008
|
+
// External search button element or selector
|
|
3009
|
+
onSearch = null
|
|
3010
|
+
// External search handler
|
|
3011
|
+
} = options;
|
|
3012
|
+
let currentPage = 1;
|
|
3013
|
+
let pageSize = initialPageSize;
|
|
3014
|
+
let totalPages = 1;
|
|
3015
|
+
let total = data.length;
|
|
3016
|
+
let sortField = initialSortField;
|
|
3017
|
+
let sortOrder = initialSortOrder;
|
|
3018
|
+
let searchTerm = "";
|
|
3019
|
+
let loading = false;
|
|
3020
|
+
let currentData = [...data];
|
|
3021
|
+
let tableEl = container.querySelector(`.${PREFIX}-table__container`);
|
|
3022
|
+
let theadEl = container.querySelector(`.${PREFIX}-table__header`);
|
|
3023
|
+
let tbodyEl = container.querySelector(`.${PREFIX}-table__body`);
|
|
3024
|
+
let paginationEl = container.querySelector(`.${PREFIX}-table__pagination`);
|
|
3025
|
+
let progressBarEl = container.querySelector(
|
|
3026
|
+
`.${PREFIX}-table__progress-bar`
|
|
3027
|
+
);
|
|
3028
|
+
let progressFillEl = container.querySelector(
|
|
3029
|
+
`.${PREFIX}-progress-bar__fill`
|
|
3030
|
+
);
|
|
3031
|
+
const searchInputEl = typeof searchContainer === "string" ? document.querySelector(searchContainer) : searchContainer;
|
|
3032
|
+
const searchBtnEl = typeof searchButton === "string" ? document.querySelector(searchButton) : searchButton;
|
|
3033
|
+
if (!tableEl) {
|
|
3034
|
+
container.innerHTML = `
|
|
3035
|
+
<div class="${PREFIX}-table__progress-bar" style="display: none;">
|
|
3036
|
+
<div class="${PREFIX}-progress-bar ${PREFIX}-progress-bar--variant-primary ${PREFIX}-progress-bar--height-sm">
|
|
3037
|
+
<div class="${PREFIX}-progress-bar__track">
|
|
3038
|
+
<div class="${PREFIX}-progress-bar__fill" style="width: 0%;"></div>
|
|
3039
|
+
</div>
|
|
3040
|
+
</div>
|
|
3041
|
+
</div>
|
|
3042
|
+
<table class="${PREFIX}-table__container">
|
|
3043
|
+
<thead class="${PREFIX}-table__header"><tr></tr></thead>
|
|
3044
|
+
<tbody class="${PREFIX}-table__body"></tbody>
|
|
3045
|
+
</table>
|
|
3046
|
+
<div class="${PREFIX}-table__pagination"></div>
|
|
3047
|
+
`;
|
|
3048
|
+
tableEl = container.querySelector(`.${PREFIX}-table__container`);
|
|
3049
|
+
theadEl = container.querySelector(`.${PREFIX}-table__header`);
|
|
3050
|
+
tbodyEl = container.querySelector(`.${PREFIX}-table__body`);
|
|
3051
|
+
paginationEl = container.querySelector(`.${PREFIX}-table__pagination`);
|
|
3052
|
+
progressBarEl = container.querySelector(`.${PREFIX}-table__progress-bar`);
|
|
3053
|
+
progressFillEl = container.querySelector(`.${PREFIX}-progress-bar__fill`);
|
|
3054
|
+
}
|
|
3055
|
+
const trHeader = theadEl.querySelector("tr") || document.createElement("tr");
|
|
3056
|
+
if (!theadEl.contains(trHeader)) theadEl.appendChild(trHeader);
|
|
3057
|
+
if (columns.length > 0) {
|
|
3058
|
+
trHeader.innerHTML = "";
|
|
3059
|
+
columns.forEach((col) => {
|
|
3060
|
+
const th = document.createElement("th");
|
|
3061
|
+
th.className = `${PREFIX}-table__header-cell`;
|
|
3062
|
+
if (col.sortable && col.accessor) {
|
|
3063
|
+
th.classList.add(`${PREFIX}-table__header-cell--sortable`);
|
|
3064
|
+
th.setAttribute("data-sort", col.accessor);
|
|
3065
|
+
th.innerHTML = `
|
|
3066
|
+
<div class="${PREFIX}-table__sort-controls">
|
|
3067
|
+
${col.header}
|
|
3068
|
+
<div class="${PREFIX}-table__sort-icon">
|
|
3069
|
+
<div class="${PREFIX}-table__sort-button" data-order="asc">
|
|
3070
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9L12 15L18 9"></path></svg>
|
|
3071
|
+
</div>
|
|
3072
|
+
<div class="${PREFIX}-table__sort-button ${PREFIX}-table__sort-button-right" data-order="desc">
|
|
3073
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 15L12 9L6 15"></path></svg>
|
|
3074
|
+
</div>
|
|
3075
|
+
</div>
|
|
3076
|
+
</div>
|
|
3077
|
+
`;
|
|
3078
|
+
th.addEventListener("click", () => {
|
|
3079
|
+
const field = col.accessor;
|
|
3080
|
+
if (sortField === field) {
|
|
3081
|
+
if (sortOrder === "asc") sortOrder = "desc";
|
|
3082
|
+
else if (sortOrder === "desc") {
|
|
3083
|
+
sortField = null;
|
|
3084
|
+
sortOrder = null;
|
|
3085
|
+
}
|
|
3086
|
+
} else {
|
|
3087
|
+
sortField = field;
|
|
3088
|
+
sortOrder = "asc";
|
|
3089
|
+
}
|
|
3090
|
+
currentPage = 1;
|
|
3091
|
+
loadData();
|
|
3092
|
+
});
|
|
3093
|
+
} else {
|
|
3094
|
+
th.textContent = col.header;
|
|
3095
|
+
}
|
|
3096
|
+
trHeader.appendChild(th);
|
|
3097
|
+
});
|
|
3098
|
+
}
|
|
3099
|
+
const sortButtons = theadEl.querySelectorAll(
|
|
3100
|
+
`.${PREFIX}-table__sort-button`
|
|
3101
|
+
);
|
|
3102
|
+
let loadingInterval;
|
|
3103
|
+
function setLoading(isLoading) {
|
|
3104
|
+
loading = isLoading;
|
|
3105
|
+
if (!progressBarEl || !progressFillEl) return;
|
|
3106
|
+
if (isLoading) {
|
|
3107
|
+
progressBarEl.style.display = "block";
|
|
3108
|
+
let progress = 0;
|
|
3109
|
+
clearInterval(loadingInterval);
|
|
3110
|
+
loadingInterval = setInterval(() => {
|
|
3111
|
+
if (progress >= 90 || !loading) {
|
|
3112
|
+
clearInterval(loadingInterval);
|
|
3113
|
+
if (!loading) {
|
|
3114
|
+
progress = 100;
|
|
3115
|
+
progressFillEl.style.width = "100%";
|
|
3116
|
+
setTimeout(() => {
|
|
3117
|
+
progressBarEl.style.display = "none";
|
|
3118
|
+
progressFillEl.style.width = "0%";
|
|
3119
|
+
}, 300);
|
|
3120
|
+
}
|
|
3121
|
+
return;
|
|
3122
|
+
}
|
|
3123
|
+
progress += Math.random() * 15;
|
|
3124
|
+
progressFillEl.style.width = progress + "%";
|
|
3125
|
+
}, 200);
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
function renderRows(rowData) {
|
|
3129
|
+
tbodyEl.innerHTML = "";
|
|
3130
|
+
if (rowData.length === 0) {
|
|
3131
|
+
const tr = document.createElement("tr");
|
|
3132
|
+
tr.innerHTML = `<td colspan="${columns.length || 1}" class="${PREFIX}-table__empty-cell">No data found</td>`;
|
|
3133
|
+
tbodyEl.appendChild(tr);
|
|
3134
|
+
return;
|
|
3135
|
+
}
|
|
3136
|
+
rowData.forEach((row, index) => {
|
|
3137
|
+
const tr = document.createElement("tr");
|
|
3138
|
+
tr.className = `${PREFIX}-table__row`;
|
|
3139
|
+
columns.forEach((col) => {
|
|
3140
|
+
const td = document.createElement("td");
|
|
3141
|
+
td.className = `${PREFIX}-table__cell`;
|
|
3142
|
+
if (typeof col.render === "function") {
|
|
3143
|
+
const content = col.render(row, index);
|
|
3144
|
+
if (typeof content === "string") {
|
|
3145
|
+
td.innerHTML = content;
|
|
3146
|
+
} else if (content instanceof HTMLElement) {
|
|
3147
|
+
td.appendChild(content);
|
|
3148
|
+
} else {
|
|
3149
|
+
td.textContent = content;
|
|
3150
|
+
}
|
|
3151
|
+
} else {
|
|
3152
|
+
td.textContent = row[col.accessor] !== void 0 ? row[col.accessor] : "";
|
|
3153
|
+
}
|
|
3154
|
+
tr.appendChild(td);
|
|
3155
|
+
});
|
|
3156
|
+
tbodyEl.appendChild(tr);
|
|
3157
|
+
});
|
|
3158
|
+
}
|
|
3159
|
+
function renderPagination() {
|
|
3160
|
+
if (!paginationEl) return;
|
|
3161
|
+
totalPages = Math.ceil(total / pageSize);
|
|
3162
|
+
if (totalPages < 1) totalPages = 1;
|
|
3163
|
+
paginationEl.innerHTML = `
|
|
3164
|
+
<div class="${PREFIX}-pagination">
|
|
3165
|
+
<div class="${PREFIX}-pagination__nav-container">
|
|
3166
|
+
<div class="${PREFIX}-pagination__page-info">Halaman ${currentPage} dari ${totalPages}</div>
|
|
3167
|
+
<div class="${PREFIX}-pagination__nav-buttons"></div>
|
|
3168
|
+
</div>
|
|
3169
|
+
<div class="${PREFIX}-pagination__page-size-container">
|
|
3170
|
+
<span class="${PREFIX}-pagination__page-size-label">Baris per halaman</span>
|
|
3171
|
+
<select class="${PREFIX}-pagination__page-size-select">
|
|
3172
|
+
${pageSizeOptions.map((opt) => `<option value="${opt}" ${pageSize === opt ? "selected" : ""}>${opt}</option>`).join("")}
|
|
3173
|
+
</select>
|
|
3174
|
+
</div>
|
|
3175
|
+
</div>
|
|
3176
|
+
`;
|
|
3177
|
+
const navButtonsContainer = paginationEl.querySelector(
|
|
3178
|
+
`.${PREFIX}-pagination__nav-buttons`
|
|
3179
|
+
);
|
|
3180
|
+
const pageSizeSelect = paginationEl.querySelector(
|
|
3181
|
+
`.${PREFIX}-pagination__page-size-select`
|
|
3182
|
+
);
|
|
3183
|
+
pageSizeSelect.addEventListener("change", (e) => {
|
|
3184
|
+
pageSize = parseInt(e.target.value);
|
|
3185
|
+
currentPage = 1;
|
|
3186
|
+
loadData();
|
|
3187
|
+
});
|
|
3188
|
+
const createButton = (isNav, enabled, content, onClick) => {
|
|
3189
|
+
const btn = document.createElement("button");
|
|
3190
|
+
btn.type = "button";
|
|
3191
|
+
const baseClass = isNav ? `${PREFIX}-pagination__nav-button` : `${PREFIX}-pagination__page-button`;
|
|
3192
|
+
const stateClass = isNav ? enabled ? `${baseClass}--enabled` : `${baseClass}--disabled` : enabled ? `${baseClass}--enabled` : `${baseClass}--active`;
|
|
3193
|
+
btn.className = `${baseClass} ${stateClass}`;
|
|
3194
|
+
btn.disabled = !enabled;
|
|
3195
|
+
if (typeof content === "string") btn.innerHTML = content;
|
|
3196
|
+
else btn.appendChild(content);
|
|
3197
|
+
btn.onclick = onClick;
|
|
3198
|
+
navButtonsContainer.appendChild(btn);
|
|
3199
|
+
};
|
|
3200
|
+
const iconPaths = {
|
|
3201
|
+
first: '<path d="M11 7l-5 5l5 5"></path><path d="M17 7l-5 5l5 5"></path>',
|
|
3202
|
+
prev: '<path d="M15 6l-6 6l6 6"></path>',
|
|
3203
|
+
next: '<path d="M9 6l6 6l-6 6"></path>',
|
|
3204
|
+
last: '<path d="M7 7l5 5l-5 5"></path><path d="M13 7l5 5l-5 5"></path>'
|
|
3205
|
+
};
|
|
3206
|
+
const getIcon = (type) => `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="${PREFIX}-pagination__nav-icon">${iconPaths[type]}</svg>`;
|
|
3207
|
+
createButton(true, currentPage > 1, getIcon("first"), () => {
|
|
3208
|
+
currentPage = 1;
|
|
3209
|
+
loadData();
|
|
3210
|
+
});
|
|
3211
|
+
createButton(true, currentPage > 1, getIcon("prev"), () => {
|
|
3212
|
+
currentPage--;
|
|
3213
|
+
loadData();
|
|
3214
|
+
});
|
|
3215
|
+
const maxVisible = 5;
|
|
3216
|
+
let startPage = Math.max(1, currentPage - Math.floor(maxVisible / 2));
|
|
3217
|
+
let endPage = Math.min(totalPages, startPage + maxVisible - 1);
|
|
3218
|
+
if (endPage - startPage < maxVisible - 1) {
|
|
3219
|
+
startPage = Math.max(1, endPage - maxVisible + 1);
|
|
3220
|
+
}
|
|
3221
|
+
for (let i = startPage; i <= endPage; i++) {
|
|
3222
|
+
createButton(false, i !== currentPage, String(i), () => {
|
|
3223
|
+
currentPage = i;
|
|
3224
|
+
loadData();
|
|
3225
|
+
});
|
|
3226
|
+
}
|
|
3227
|
+
createButton(true, currentPage < totalPages, getIcon("next"), () => {
|
|
3228
|
+
currentPage++;
|
|
3229
|
+
loadData();
|
|
3230
|
+
});
|
|
3231
|
+
createButton(true, currentPage < totalPages, getIcon("last"), () => {
|
|
3232
|
+
currentPage = totalPages;
|
|
3233
|
+
loadData();
|
|
3234
|
+
});
|
|
3235
|
+
}
|
|
3236
|
+
function updateSortIndicators() {
|
|
3237
|
+
sortButtons.forEach((btn) => {
|
|
3238
|
+
const headerCell = btn.closest("th");
|
|
3239
|
+
if (!headerCell) return;
|
|
3240
|
+
const field = headerCell.getAttribute("data-sort");
|
|
3241
|
+
const order = btn.getAttribute("data-order");
|
|
3242
|
+
const isActive = sortField === field && sortOrder === order;
|
|
3243
|
+
btn.classList.toggle(`${PREFIX}-table__sort-button--active`, isActive);
|
|
3244
|
+
});
|
|
3245
|
+
}
|
|
3246
|
+
async function loadData() {
|
|
3247
|
+
setLoading(true);
|
|
3248
|
+
try {
|
|
3249
|
+
if (typeof fetchData === "function") {
|
|
3250
|
+
const result = await fetchData({
|
|
3251
|
+
page: currentPage,
|
|
3252
|
+
pageSize,
|
|
3253
|
+
sortField,
|
|
3254
|
+
sortOrder,
|
|
3255
|
+
searchTerm
|
|
3256
|
+
});
|
|
3257
|
+
total = result.total;
|
|
3258
|
+
currentData = result.data;
|
|
3259
|
+
} else {
|
|
3260
|
+
let filteredData = [...data];
|
|
3261
|
+
if (searchTerm) {
|
|
3262
|
+
const lowerSearch = searchTerm.toLowerCase();
|
|
3263
|
+
filteredData = filteredData.filter(
|
|
3264
|
+
(item) => columns.some(
|
|
3265
|
+
(c) => String(item[c.accessor] || "").toLowerCase().includes(lowerSearch)
|
|
3266
|
+
)
|
|
3267
|
+
);
|
|
3268
|
+
}
|
|
3269
|
+
if (sortField && sortOrder) {
|
|
3270
|
+
filteredData.sort((a, b) => {
|
|
3271
|
+
const aVal = a[sortField];
|
|
3272
|
+
const bVal = b[sortField];
|
|
3273
|
+
if (aVal < bVal) return sortOrder === "asc" ? -1 : 1;
|
|
3274
|
+
if (aVal > bVal) return sortOrder === "asc" ? 1 : -1;
|
|
3275
|
+
return 0;
|
|
3276
|
+
});
|
|
3277
|
+
}
|
|
3278
|
+
total = filteredData.length;
|
|
3279
|
+
const skip = (currentPage - 1) * pageSize;
|
|
3280
|
+
currentData = filteredData.slice(skip, skip + pageSize);
|
|
3281
|
+
}
|
|
3282
|
+
renderRows(currentData);
|
|
3283
|
+
renderPagination();
|
|
3284
|
+
updateSortIndicators();
|
|
3285
|
+
} catch (error) {
|
|
3286
|
+
console.error("Table API Error:", error);
|
|
3287
|
+
} finally {
|
|
3288
|
+
setLoading(false);
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
if (searchInputEl && searchBtnEl) {
|
|
3292
|
+
const handleSearch = () => {
|
|
3293
|
+
searchTerm = searchInputEl.value.trim();
|
|
3294
|
+
currentPage = 1;
|
|
3295
|
+
loadData();
|
|
3296
|
+
if (typeof onSearch === "function") onSearch(searchTerm);
|
|
3297
|
+
};
|
|
3298
|
+
searchBtnEl.addEventListener("click", handleSearch);
|
|
3299
|
+
searchInputEl.addEventListener("keydown", (e) => {
|
|
3300
|
+
if (e.key === "Enter") handleSearch();
|
|
3301
|
+
});
|
|
3302
|
+
}
|
|
3303
|
+
loadData();
|
|
3304
|
+
container.__tableAPI = {
|
|
3305
|
+
reload: loadData,
|
|
3306
|
+
setSearchTerm: (term) => {
|
|
3307
|
+
searchTerm = term;
|
|
3308
|
+
currentPage = 1;
|
|
3309
|
+
loadData();
|
|
3310
|
+
},
|
|
3311
|
+
setPage: (page) => {
|
|
3312
|
+
currentPage = page;
|
|
3313
|
+
loadData();
|
|
3314
|
+
}
|
|
3315
|
+
};
|
|
3316
|
+
});
|
|
3317
|
+
}
|
|
3318
|
+
|
|
2991
3319
|
// src/js/components/stateless/toast.js
|
|
2992
3320
|
var ICONS3 = {
|
|
2993
3321
|
default: `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>`,
|
|
@@ -3129,6 +3457,7 @@ function initAll() {
|
|
|
3129
3457
|
initChip();
|
|
3130
3458
|
initTabVertical();
|
|
3131
3459
|
initTabHorizontal();
|
|
3460
|
+
initTable();
|
|
3132
3461
|
}
|
|
3133
3462
|
export {
|
|
3134
3463
|
PREFIX,
|