@idds/js 1.0.85 → 1.0.87
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 +539 -297
- package/dist/index.js +539 -297
- package/package.json +1 -1
package/dist/index.iife.js
CHANGED
|
@@ -20,6 +20,7 @@ var InaUI = (() => {
|
|
|
20
20
|
// src/js/bundle.js
|
|
21
21
|
var bundle_exports = {};
|
|
22
22
|
__export(bundle_exports, {
|
|
23
|
+
Table: () => Table,
|
|
23
24
|
initAccordion: () => initAccordion,
|
|
24
25
|
initButtonGroup: () => initButtonGroup,
|
|
25
26
|
initCheckbox: () => initCheckbox,
|
|
@@ -2904,331 +2905,572 @@ var InaUI = (() => {
|
|
|
2904
2905
|
}
|
|
2905
2906
|
|
|
2906
2907
|
// src/js/components/stateful/table.js
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
if (container
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2908
|
+
var Table = class {
|
|
2909
|
+
constructor(selectorOrElement, options = {}) {
|
|
2910
|
+
this.container = typeof selectorOrElement === "string" ? document.querySelector(selectorOrElement) : selectorOrElement;
|
|
2911
|
+
if (!this.container) {
|
|
2912
|
+
console.warn("[IDDS Table] Container not found:", selectorOrElement);
|
|
2913
|
+
return;
|
|
2914
|
+
}
|
|
2915
|
+
if (this.container.dataset.initialized === "true") {
|
|
2916
|
+
return;
|
|
2917
|
+
}
|
|
2918
|
+
this.container.dataset.initialized = "true";
|
|
2919
|
+
this.options = {
|
|
2920
|
+
columns: [],
|
|
2921
|
+
fetchData: null,
|
|
2922
|
+
data: [],
|
|
2923
|
+
initialPage: 1,
|
|
2924
|
+
initialPageSize: 10,
|
|
2925
|
+
pageSizeOptions: [10, 20, 50],
|
|
2926
|
+
initialSortField: null,
|
|
2927
|
+
initialSortOrder: null,
|
|
2928
|
+
searchPlaceholder: "Input pencarian",
|
|
2929
|
+
buttonSearchLabel: "Cari",
|
|
2930
|
+
selectable: false,
|
|
2931
|
+
onSelectionChange: null,
|
|
2932
|
+
rowKey: "id",
|
|
2933
|
+
showSearch: false,
|
|
2934
|
+
rowClickable: false,
|
|
2935
|
+
onRowClick: null,
|
|
2936
|
+
emptyState: "No data found",
|
|
2937
|
+
showPagination: true,
|
|
2938
|
+
searchContainer: null,
|
|
2939
|
+
searchButton: null,
|
|
2940
|
+
onSearch: null,
|
|
2941
|
+
...options
|
|
2942
|
+
};
|
|
2943
|
+
this.state = {
|
|
2944
|
+
currentPage: this.options.initialPage,
|
|
2945
|
+
pageSize: this.options.initialPageSize,
|
|
2946
|
+
totalPages: 1,
|
|
2947
|
+
total: this.options.data.length,
|
|
2948
|
+
sortField: this.options.initialSortField,
|
|
2949
|
+
sortOrder: this.options.initialSortOrder,
|
|
2950
|
+
searchTerm: "",
|
|
2951
|
+
loading: false,
|
|
2952
|
+
currentData: [...this.options.data],
|
|
2953
|
+
selectedKeys: /* @__PURE__ */ new Set(),
|
|
2954
|
+
selectedRows: /* @__PURE__ */ new Map()
|
|
2955
|
+
};
|
|
2956
|
+
this.elements = {};
|
|
2957
|
+
this.initDOM();
|
|
2958
|
+
this.bindEvents();
|
|
2959
|
+
this.loadData();
|
|
2960
|
+
}
|
|
2961
|
+
initDOM() {
|
|
2962
|
+
this.container.innerHTML = "";
|
|
2963
|
+
this.container.classList.add(`${PREFIX}-table-wrapper`);
|
|
2964
|
+
if (this.options.showSearch && !this.options.searchContainer) {
|
|
2965
|
+
const searchWrap = document.createElement("div");
|
|
2966
|
+
searchWrap.className = "flex items-center gap-2 mb-4";
|
|
2967
|
+
searchWrap.style.display = "flex";
|
|
2968
|
+
searchWrap.style.alignItems = "center";
|
|
2969
|
+
searchWrap.style.gap = "8px";
|
|
2970
|
+
searchWrap.style.marginBottom = "16px";
|
|
2971
|
+
searchWrap.innerHTML = `
|
|
2972
|
+
<div style="flex: 1;">
|
|
2973
|
+
<div class="${PREFIX}-text-field">
|
|
2974
|
+
<div class="${PREFIX}-text-field__wrapper ${PREFIX}-text-field__wrapper--size-md">
|
|
2975
|
+
<input type="text" class="${PREFIX}-text-field__input" placeholder="${this.options.searchPlaceholder}">
|
|
2954
2976
|
</div>
|
|
2955
2977
|
</div>
|
|
2956
2978
|
</div>
|
|
2957
|
-
<
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2979
|
+
<button type="button" class="${PREFIX}-button ${PREFIX}-button--primary ${PREFIX}-button--md">
|
|
2980
|
+
${this.options.buttonSearchLabel}
|
|
2981
|
+
</button>
|
|
2982
|
+
`;
|
|
2983
|
+
this.container.appendChild(searchWrap);
|
|
2984
|
+
this.elements.searchInput = searchWrap.querySelector("input");
|
|
2985
|
+
this.elements.searchButton = searchWrap.querySelector("button");
|
|
2986
|
+
} else {
|
|
2987
|
+
this.elements.searchInput = typeof this.options.searchContainer === "string" ? document.querySelector(this.options.searchContainer) : this.options.searchContainer;
|
|
2988
|
+
this.elements.searchButton = typeof this.options.searchButton === "string" ? document.querySelector(this.options.searchButton) : this.options.searchButton;
|
|
2989
|
+
}
|
|
2990
|
+
const tableDiv = document.createElement("div");
|
|
2991
|
+
tableDiv.className = `${PREFIX}-table`;
|
|
2992
|
+
const progressDiv = document.createElement("div");
|
|
2993
|
+
progressDiv.className = `${PREFIX}-table__progress-bar`;
|
|
2994
|
+
progressDiv.style.display = "none";
|
|
2995
|
+
progressDiv.innerHTML = `
|
|
2996
|
+
<div class="${PREFIX}-progress-bar ${PREFIX}-progress-bar--variant-primary ${PREFIX}-progress-bar--height-sm">
|
|
2997
|
+
<div class="${PREFIX}-progress-bar__track">
|
|
2998
|
+
<div class="${PREFIX}-progress-bar__fill" style="width: 0%;"></div>
|
|
2999
|
+
</div>
|
|
3000
|
+
</div>
|
|
3001
|
+
`;
|
|
3002
|
+
tableDiv.appendChild(progressDiv);
|
|
3003
|
+
const tableEl = document.createElement("table");
|
|
3004
|
+
tableEl.className = `${PREFIX}-table__container`;
|
|
3005
|
+
const theadEl = document.createElement("thead");
|
|
3006
|
+
theadEl.className = `${PREFIX}-table__header`;
|
|
3007
|
+
const trHeader = document.createElement("tr");
|
|
3008
|
+
theadEl.appendChild(trHeader);
|
|
3009
|
+
tableEl.appendChild(theadEl);
|
|
3010
|
+
const tbodyEl = document.createElement("tbody");
|
|
3011
|
+
tbodyEl.className = `${PREFIX}-table__body`;
|
|
3012
|
+
tableEl.appendChild(tbodyEl);
|
|
3013
|
+
tableDiv.appendChild(tableEl);
|
|
3014
|
+
const paginationEl = document.createElement("div");
|
|
3015
|
+
paginationEl.className = `${PREFIX}-table__pagination`;
|
|
3016
|
+
if (!this.options.showPagination) {
|
|
3017
|
+
paginationEl.style.display = "none";
|
|
3018
|
+
}
|
|
3019
|
+
tableDiv.appendChild(paginationEl);
|
|
3020
|
+
this.container.appendChild(tableDiv);
|
|
3021
|
+
this.elements.progressEl = progressDiv;
|
|
3022
|
+
this.elements.progressFillEl = progressDiv.querySelector(
|
|
3023
|
+
`.${PREFIX}-progress-bar__fill`
|
|
3024
|
+
);
|
|
3025
|
+
this.elements.theadTr = trHeader;
|
|
3026
|
+
this.elements.tbody = tbodyEl;
|
|
3027
|
+
this.elements.pagination = paginationEl;
|
|
3028
|
+
this.buildHeader();
|
|
3029
|
+
}
|
|
3030
|
+
buildHeader() {
|
|
3031
|
+
this.elements.theadTr.innerHTML = "";
|
|
3032
|
+
if (this.options.selectable) {
|
|
3033
|
+
const th = document.createElement("th");
|
|
3034
|
+
th.className = `${PREFIX}-table__header-cell`;
|
|
3035
|
+
th.style.width = "48px";
|
|
3036
|
+
const checkboxWrap = document.createElement("div");
|
|
3037
|
+
checkboxWrap.className = `${PREFIX}-checkbox`;
|
|
3038
|
+
checkboxWrap.innerHTML = `
|
|
3039
|
+
<label class="${PREFIX}-checkbox__label-wrapper">
|
|
3040
|
+
<input type="checkbox" class="${PREFIX}-checkbox__input" id="selectAll">
|
|
3041
|
+
<div class="${PREFIX}-checkbox__box ${PREFIX}-checkbox__box--unchecked"></div>
|
|
3042
|
+
</label>
|
|
2962
3043
|
`;
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
<div class="${PREFIX}-table__sort-
|
|
2984
|
-
<
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
<
|
|
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>
|
|
3044
|
+
th.appendChild(checkboxWrap);
|
|
3045
|
+
this.elements.theadTr.appendChild(th);
|
|
3046
|
+
this.elements.selectAllInput = checkboxWrap.querySelector("input");
|
|
3047
|
+
this.elements.selectAllBox = checkboxWrap.querySelector(
|
|
3048
|
+
`.${PREFIX}-checkbox__box`
|
|
3049
|
+
);
|
|
3050
|
+
this.elements.selectAllInput.addEventListener("change", (e) => {
|
|
3051
|
+
this.toggleAllSelection(e.target.checked);
|
|
3052
|
+
});
|
|
3053
|
+
}
|
|
3054
|
+
this.options.columns.forEach((col) => {
|
|
3055
|
+
const th = document.createElement("th");
|
|
3056
|
+
th.className = `${PREFIX}-table__header-cell`;
|
|
3057
|
+
if (col.sortable && col.accessor) {
|
|
3058
|
+
th.classList.add(`${PREFIX}-table__header-cell--sortable`);
|
|
3059
|
+
th.setAttribute("data-sort", col.accessor);
|
|
3060
|
+
let sortControlsHtml = `
|
|
3061
|
+
<div class="${PREFIX}-table__sort-controls">
|
|
3062
|
+
${col.header}
|
|
3063
|
+
<div class="${PREFIX}-table__sort-icon">
|
|
3064
|
+
<div class="${PREFIX}-table__sort-button" data-order="asc">
|
|
3065
|
+
<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>
|
|
3066
|
+
</div>
|
|
3067
|
+
<div class="${PREFIX}-table__sort-button ${PREFIX}-table__sort-button-right" data-order="desc">
|
|
3068
|
+
<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>
|
|
2990
3069
|
</div>
|
|
2991
3070
|
</div>
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
sortField = field;
|
|
3003
|
-
sortOrder = "asc";
|
|
3071
|
+
</div>
|
|
3072
|
+
`;
|
|
3073
|
+
th.innerHTML = sortControlsHtml;
|
|
3074
|
+
th.addEventListener("click", () => {
|
|
3075
|
+
const field = col.accessor;
|
|
3076
|
+
if (this.state.sortField === field) {
|
|
3077
|
+
if (this.state.sortOrder === "asc") this.state.sortOrder = "desc";
|
|
3078
|
+
else {
|
|
3079
|
+
this.state.sortField = null;
|
|
3080
|
+
this.state.sortOrder = null;
|
|
3004
3081
|
}
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3082
|
+
} else {
|
|
3083
|
+
this.state.sortField = field;
|
|
3084
|
+
this.state.sortOrder = "asc";
|
|
3085
|
+
}
|
|
3086
|
+
this.state.currentPage = 1;
|
|
3087
|
+
this.loadData();
|
|
3088
|
+
});
|
|
3089
|
+
} else {
|
|
3090
|
+
th.textContent = col.header;
|
|
3091
|
+
}
|
|
3092
|
+
this.elements.theadTr.appendChild(th);
|
|
3093
|
+
});
|
|
3094
|
+
}
|
|
3095
|
+
bindEvents() {
|
|
3096
|
+
if (this.elements.searchInput && this.elements.searchButton) {
|
|
3097
|
+
const handleSearch = () => {
|
|
3098
|
+
this.state.searchTerm = this.elements.searchInput.value.trim();
|
|
3099
|
+
this.state.currentPage = 1;
|
|
3100
|
+
this.loadData();
|
|
3101
|
+
if (typeof this.options.onSearch === "function") {
|
|
3102
|
+
this.options.onSearch(this.state.searchTerm);
|
|
3010
3103
|
}
|
|
3011
|
-
|
|
3104
|
+
};
|
|
3105
|
+
this.elements.searchButton.addEventListener("click", handleSearch);
|
|
3106
|
+
this.elements.searchInput.addEventListener("keydown", (e) => {
|
|
3107
|
+
if (e.key === "Enter") handleSearch();
|
|
3012
3108
|
});
|
|
3013
3109
|
}
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
progressFillEl.style.width = "
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3110
|
+
}
|
|
3111
|
+
setLoading(isLoading) {
|
|
3112
|
+
this.state.loading = isLoading;
|
|
3113
|
+
if (!this.elements.progressEl || !this.elements.progressFillEl) return;
|
|
3114
|
+
if (isLoading) {
|
|
3115
|
+
this.elements.progressEl.style.display = "block";
|
|
3116
|
+
let progress = 0;
|
|
3117
|
+
clearInterval(this.loadingInterval);
|
|
3118
|
+
this.loadingInterval = setInterval(() => {
|
|
3119
|
+
if (progress >= 90 || !this.state.loading) {
|
|
3120
|
+
clearInterval(this.loadingInterval);
|
|
3121
|
+
if (!this.state.loading) {
|
|
3122
|
+
progress = 100;
|
|
3123
|
+
this.elements.progressFillEl.style.width = "100%";
|
|
3124
|
+
setTimeout(() => {
|
|
3125
|
+
this.elements.progressEl.style.display = "none";
|
|
3126
|
+
this.elements.progressFillEl.style.width = "0%";
|
|
3127
|
+
}, 300);
|
|
3128
|
+
}
|
|
3129
|
+
return;
|
|
3130
|
+
}
|
|
3131
|
+
progress += Math.random() * 15;
|
|
3132
|
+
this.elements.progressFillEl.style.width = progress + "%";
|
|
3133
|
+
}, 200);
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
renderRows(rowData) {
|
|
3137
|
+
this.elements.tbody.innerHTML = "";
|
|
3138
|
+
if (rowData.length === 0) {
|
|
3139
|
+
const tr = document.createElement("tr");
|
|
3140
|
+
const colspan = this.options.columns.length + (this.options.selectable ? 1 : 0);
|
|
3141
|
+
tr.innerHTML = `<td colspan="${colspan}" class="${PREFIX}-table__empty-cell">${this.options.emptyState}</td>`;
|
|
3142
|
+
this.elements.tbody.appendChild(tr);
|
|
3143
|
+
this.updateSelectAllState();
|
|
3144
|
+
return;
|
|
3145
|
+
}
|
|
3146
|
+
rowData.forEach((row, index) => {
|
|
3147
|
+
const tr = document.createElement("tr");
|
|
3148
|
+
tr.className = `${PREFIX}-table__row`;
|
|
3149
|
+
if (this.options.rowClickable) {
|
|
3150
|
+
tr.style.cursor = "pointer";
|
|
3151
|
+
tr.classList.add(`${PREFIX}-table__row--clickable`);
|
|
3152
|
+
tr.addEventListener("click", (e) => {
|
|
3153
|
+
if (e.target.closest(`.${PREFIX}-checkbox`) && this.options.selectable) {
|
|
3036
3154
|
return;
|
|
3037
3155
|
}
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3156
|
+
if (typeof this.options.onRowClick === "function") {
|
|
3157
|
+
this.options.onRowClick(row, index);
|
|
3158
|
+
}
|
|
3159
|
+
});
|
|
3041
3160
|
}
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
const
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3161
|
+
const rowKeyStr = String(row[this.options.rowKey] || index);
|
|
3162
|
+
if (this.options.selectable) {
|
|
3163
|
+
const td = document.createElement("td");
|
|
3164
|
+
td.className = `${PREFIX}-table__cell`;
|
|
3165
|
+
const isChecked = this.state.selectedKeys.has(rowKeyStr);
|
|
3166
|
+
const checkboxWrap = document.createElement("div");
|
|
3167
|
+
checkboxWrap.className = `${PREFIX}-checkbox`;
|
|
3168
|
+
checkboxWrap.innerHTML = `
|
|
3169
|
+
<label class="${PREFIX}-checkbox__label-wrapper">
|
|
3170
|
+
<input type="checkbox" class="${PREFIX}-checkbox__input" ${isChecked ? "checked" : ""}>
|
|
3171
|
+
<div class="${PREFIX}-checkbox__box ${isChecked ? `${PREFIX}-checkbox__box--checked` : `${PREFIX}-checkbox__box--unchecked`}">
|
|
3172
|
+
${isChecked ? '<svg class="ina-checkbox__icon" 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="M5 12l5 5l10 -10"></path></svg>' : ""}
|
|
3173
|
+
</div>
|
|
3174
|
+
</label>
|
|
3175
|
+
`;
|
|
3176
|
+
td.appendChild(checkboxWrap);
|
|
3177
|
+
tr.appendChild(td);
|
|
3178
|
+
const rowInput = checkboxWrap.querySelector("input");
|
|
3179
|
+
rowInput.addEventListener("change", (e) => {
|
|
3180
|
+
this.toggleRowSelection(rowKeyStr, row, e.target.checked);
|
|
3181
|
+
});
|
|
3050
3182
|
}
|
|
3051
|
-
|
|
3052
|
-
const
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
const
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
td.innerHTML = content;
|
|
3061
|
-
} else if (content instanceof HTMLElement) {
|
|
3062
|
-
td.appendChild(content);
|
|
3063
|
-
} else {
|
|
3064
|
-
td.textContent = content;
|
|
3065
|
-
}
|
|
3183
|
+
this.options.columns.forEach((col) => {
|
|
3184
|
+
const td = document.createElement("td");
|
|
3185
|
+
td.className = `${PREFIX}-table__cell`;
|
|
3186
|
+
if (typeof col.render === "function") {
|
|
3187
|
+
const content = col.render(row, index);
|
|
3188
|
+
if (typeof content === "string") {
|
|
3189
|
+
td.innerHTML = content;
|
|
3190
|
+
} else if (content instanceof HTMLElement) {
|
|
3191
|
+
td.appendChild(content);
|
|
3066
3192
|
} else {
|
|
3067
|
-
td.textContent =
|
|
3193
|
+
td.textContent = content;
|
|
3068
3194
|
}
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3195
|
+
} else {
|
|
3196
|
+
td.textContent = row[col.accessor] !== void 0 && row[col.accessor] !== null ? row[col.accessor] : "";
|
|
3197
|
+
}
|
|
3198
|
+
tr.appendChild(td);
|
|
3072
3199
|
});
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
<div class="${PREFIX}-pagination__page-
|
|
3085
|
-
|
|
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>
|
|
3200
|
+
this.elements.tbody.appendChild(tr);
|
|
3201
|
+
});
|
|
3202
|
+
this.updateSelectAllState();
|
|
3203
|
+
}
|
|
3204
|
+
renderPagination() {
|
|
3205
|
+
if (!this.elements.pagination || !this.options.showPagination) return;
|
|
3206
|
+
this.state.totalPages = Math.ceil(this.state.total / this.state.pageSize);
|
|
3207
|
+
if (this.state.totalPages < 1) this.state.totalPages = 1;
|
|
3208
|
+
this.elements.pagination.innerHTML = `
|
|
3209
|
+
<div class="${PREFIX}-pagination">
|
|
3210
|
+
<div class="${PREFIX}-pagination__nav-container">
|
|
3211
|
+
<div class="${PREFIX}-pagination__page-info">Halaman ${this.state.currentPage} dari ${this.state.totalPages}</div>
|
|
3212
|
+
<div class="${PREFIX}-pagination__nav-buttons"></div>
|
|
3090
3213
|
</div>
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
}
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
const
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
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);
|
|
3214
|
+
<div class="${PREFIX}-pagination__page-size-container">
|
|
3215
|
+
<span class="${PREFIX}-pagination__page-size-label">Baris per halaman</span>
|
|
3216
|
+
<select class="${PREFIX}-pagination__page-size-select">
|
|
3217
|
+
${this.options.pageSizeOptions.map(
|
|
3218
|
+
(opt) => `<option value="${opt}" ${this.state.pageSize === opt ? "selected" : ""}>${opt}</option>`
|
|
3219
|
+
).join("")}
|
|
3220
|
+
</select>
|
|
3221
|
+
</div>
|
|
3222
|
+
</div>
|
|
3223
|
+
`;
|
|
3224
|
+
const navButtons = this.elements.pagination.querySelector(
|
|
3225
|
+
`.${PREFIX}-pagination__nav-buttons`
|
|
3226
|
+
);
|
|
3227
|
+
const pageSizeSelect = this.elements.pagination.querySelector(
|
|
3228
|
+
`.${PREFIX}-pagination__page-size-select`
|
|
3229
|
+
);
|
|
3230
|
+
pageSizeSelect.addEventListener("change", (e) => {
|
|
3231
|
+
this.state.pageSize = parseInt(e.target.value, 10);
|
|
3232
|
+
this.state.currentPage = 1;
|
|
3233
|
+
this.loadData();
|
|
3234
|
+
});
|
|
3235
|
+
const createBtn = (isNav, enabled, content, onClick) => {
|
|
3236
|
+
const btn = document.createElement("button");
|
|
3237
|
+
btn.type = "button";
|
|
3238
|
+
const baseCls = isNav ? `${PREFIX}-pagination__nav-button` : `${PREFIX}-pagination__page-button`;
|
|
3239
|
+
const stCls = isNav ? enabled ? `${baseCls}--enabled` : `${baseCls}--disabled` : enabled ? `${baseCls}--enabled` : `${baseCls}--active`;
|
|
3240
|
+
btn.className = `${baseCls} ${stCls}`;
|
|
3241
|
+
btn.disabled = !enabled;
|
|
3242
|
+
btn.innerHTML = content;
|
|
3243
|
+
btn.onclick = onClick;
|
|
3244
|
+
navButtons.appendChild(btn);
|
|
3245
|
+
};
|
|
3246
|
+
const SVG = {
|
|
3247
|
+
first: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="ina-pagination__nav-icon"><path d="M11 7l-5 5l5 5"></path><path d="M17 7l-5 5l5 5"></path></svg>',
|
|
3248
|
+
prev: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="ina-pagination__nav-icon"><path d="M15 6l-6 6l6 6"></path></svg>',
|
|
3249
|
+
next: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="ina-pagination__nav-icon"><path d="M9 6l6 6l-6 6"></path></svg>',
|
|
3250
|
+
last: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="ina-pagination__nav-icon"><path d="M7 7l5 5l-5 5"></path><path d="M13 7l5 5l-5 5"></path></svg>'
|
|
3251
|
+
};
|
|
3252
|
+
createBtn(true, this.state.currentPage > 1, SVG.first, () => {
|
|
3253
|
+
this.state.currentPage = 1;
|
|
3254
|
+
this.loadData();
|
|
3255
|
+
});
|
|
3256
|
+
createBtn(true, this.state.currentPage > 1, SVG.prev, () => {
|
|
3257
|
+
this.state.currentPage--;
|
|
3258
|
+
this.loadData();
|
|
3259
|
+
});
|
|
3260
|
+
const maxVisible = 5;
|
|
3261
|
+
let startPage = Math.max(
|
|
3262
|
+
1,
|
|
3263
|
+
this.state.currentPage - Math.floor(maxVisible / 2)
|
|
3264
|
+
);
|
|
3265
|
+
let endPage = Math.min(this.state.totalPages, startPage + maxVisible - 1);
|
|
3266
|
+
if (endPage - startPage < maxVisible - 1) {
|
|
3267
|
+
startPage = Math.max(1, endPage - maxVisible + 1);
|
|
3268
|
+
}
|
|
3269
|
+
for (let i = startPage; i <= endPage; i++) {
|
|
3270
|
+
createBtn(false, i !== this.state.currentPage, String(i), () => {
|
|
3271
|
+
this.state.currentPage = i;
|
|
3272
|
+
this.loadData();
|
|
3159
3273
|
});
|
|
3160
3274
|
}
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3275
|
+
createBtn(
|
|
3276
|
+
true,
|
|
3277
|
+
this.state.currentPage < this.state.totalPages,
|
|
3278
|
+
SVG.next,
|
|
3279
|
+
() => {
|
|
3280
|
+
this.state.currentPage++;
|
|
3281
|
+
this.loadData();
|
|
3282
|
+
}
|
|
3283
|
+
);
|
|
3284
|
+
createBtn(
|
|
3285
|
+
true,
|
|
3286
|
+
this.state.currentPage < this.state.totalPages,
|
|
3287
|
+
SVG.last,
|
|
3288
|
+
() => {
|
|
3289
|
+
this.state.currentPage = this.state.totalPages;
|
|
3290
|
+
this.loadData();
|
|
3291
|
+
}
|
|
3292
|
+
);
|
|
3293
|
+
}
|
|
3294
|
+
updateSortIndicators() {
|
|
3295
|
+
const btns = this.elements.theadTr.querySelectorAll(
|
|
3296
|
+
`.${PREFIX}-table__sort-button`
|
|
3297
|
+
);
|
|
3298
|
+
btns.forEach((btn) => {
|
|
3299
|
+
const th = btn.closest("th");
|
|
3300
|
+
if (!th) return;
|
|
3301
|
+
const field = th.getAttribute("data-sort");
|
|
3302
|
+
const order = btn.getAttribute("data-order");
|
|
3303
|
+
const active = this.state.sortField === field && this.state.sortOrder === order;
|
|
3304
|
+
btn.classList.toggle(`${PREFIX}-table__sort-button--active`, active);
|
|
3305
|
+
});
|
|
3306
|
+
}
|
|
3307
|
+
async loadData() {
|
|
3308
|
+
this.setLoading(true);
|
|
3309
|
+
try {
|
|
3310
|
+
if (typeof this.options.fetchData === "function") {
|
|
3311
|
+
const res = await this.options.fetchData({
|
|
3312
|
+
page: this.state.currentPage,
|
|
3313
|
+
pageSize: this.state.pageSize,
|
|
3314
|
+
sortField: this.state.sortField,
|
|
3315
|
+
sortOrder: this.state.sortOrder,
|
|
3316
|
+
searchTerm: this.state.searchTerm
|
|
3317
|
+
});
|
|
3318
|
+
this.state.total = res.total;
|
|
3319
|
+
this.state.currentData = res.data || [];
|
|
3320
|
+
} else {
|
|
3321
|
+
let filtered = [...this.options.data];
|
|
3322
|
+
if (this.state.searchTerm) {
|
|
3323
|
+
const lower = this.state.searchTerm.toLowerCase();
|
|
3324
|
+
filtered = filtered.filter(
|
|
3325
|
+
(row) => this.options.columns.some(
|
|
3326
|
+
(c) => String(row[c.accessor] || "").toLowerCase().includes(lower)
|
|
3327
|
+
)
|
|
3328
|
+
);
|
|
3329
|
+
}
|
|
3330
|
+
if (this.state.sortField && this.state.sortOrder) {
|
|
3331
|
+
filtered.sort((a, b) => {
|
|
3332
|
+
const aVal = a[this.state.sortField];
|
|
3333
|
+
const bVal = b[this.state.sortField];
|
|
3334
|
+
if (aVal < bVal) return this.state.sortOrder === "asc" ? -1 : 1;
|
|
3335
|
+
if (aVal > bVal) return this.state.sortOrder === "asc" ? 1 : -1;
|
|
3336
|
+
return 0;
|
|
3171
3337
|
});
|
|
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
3338
|
}
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
setLoading(false);
|
|
3339
|
+
this.state.total = filtered.length;
|
|
3340
|
+
const skip = (this.state.currentPage - 1) * this.state.pageSize;
|
|
3341
|
+
this.state.currentData = filtered.slice(
|
|
3342
|
+
skip,
|
|
3343
|
+
skip + this.state.pageSize
|
|
3344
|
+
);
|
|
3204
3345
|
}
|
|
3346
|
+
this.renderRows(this.state.currentData);
|
|
3347
|
+
this.renderPagination();
|
|
3348
|
+
this.updateSortIndicators();
|
|
3349
|
+
} catch (e) {
|
|
3350
|
+
console.error("Table API Error:", e);
|
|
3351
|
+
} finally {
|
|
3352
|
+
this.setLoading(false);
|
|
3205
3353
|
}
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
searchInputEl.addEventListener("keydown", (e) => {
|
|
3215
|
-
if (e.key === "Enter") handleSearch();
|
|
3216
|
-
});
|
|
3354
|
+
}
|
|
3355
|
+
toggleRowSelection(keyStr, row, checked) {
|
|
3356
|
+
if (checked) {
|
|
3357
|
+
this.state.selectedKeys.add(keyStr);
|
|
3358
|
+
this.state.selectedRows.set(keyStr, row);
|
|
3359
|
+
} else {
|
|
3360
|
+
this.state.selectedKeys.delete(keyStr);
|
|
3361
|
+
this.state.selectedRows.delete(keyStr);
|
|
3217
3362
|
}
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3363
|
+
const inputs = this.elements.tbody.querySelectorAll(
|
|
3364
|
+
`.${PREFIX}-checkbox__input`
|
|
3365
|
+
);
|
|
3366
|
+
inputs.forEach((input) => {
|
|
3367
|
+
const box = input.nextElementSibling;
|
|
3368
|
+
if (input.checked) {
|
|
3369
|
+
box.classList.remove(`${PREFIX}-checkbox__box--unchecked`);
|
|
3370
|
+
box.classList.add(`${PREFIX}-checkbox__box--checked`);
|
|
3371
|
+
box.innerHTML = '<svg class="ina-checkbox__icon" 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="M5 12l5 5l10 -10"></path></svg>';
|
|
3372
|
+
} else {
|
|
3373
|
+
box.classList.remove(`${PREFIX}-checkbox__box--checked`);
|
|
3374
|
+
box.classList.add(`${PREFIX}-checkbox__box--unchecked`);
|
|
3375
|
+
box.innerHTML = "";
|
|
3376
|
+
}
|
|
3377
|
+
});
|
|
3378
|
+
this.updateSelectAllState();
|
|
3379
|
+
this.triggerSelectionChange();
|
|
3380
|
+
}
|
|
3381
|
+
toggleAllSelection(checked) {
|
|
3382
|
+
this.state.currentData.forEach((row, index) => {
|
|
3383
|
+
const keyStr = String(row[this.options.rowKey] || index);
|
|
3384
|
+
if (checked) {
|
|
3385
|
+
this.state.selectedKeys.add(keyStr);
|
|
3386
|
+
this.state.selectedRows.set(keyStr, row);
|
|
3387
|
+
} else {
|
|
3388
|
+
this.state.selectedKeys.delete(keyStr);
|
|
3389
|
+
this.state.selectedRows.delete(keyStr);
|
|
3229
3390
|
}
|
|
3391
|
+
});
|
|
3392
|
+
this.renderRows(this.state.currentData);
|
|
3393
|
+
this.triggerSelectionChange();
|
|
3394
|
+
}
|
|
3395
|
+
updateSelectAllState() {
|
|
3396
|
+
if (!this.options.selectable || !this.elements.selectAllInput) return;
|
|
3397
|
+
const checkboxes = this.elements.tbody.querySelectorAll(
|
|
3398
|
+
'input[type="checkbox"]'
|
|
3399
|
+
);
|
|
3400
|
+
const checkedCount = Array.from(checkboxes).filter(
|
|
3401
|
+
(cb) => cb.checked
|
|
3402
|
+
).length;
|
|
3403
|
+
const totalCount = this.state.currentData.length;
|
|
3404
|
+
const box = this.elements.selectAllBox;
|
|
3405
|
+
box.innerHTML = "";
|
|
3406
|
+
if (totalCount === 0 || checkedCount === 0) {
|
|
3407
|
+
this.elements.selectAllInput.checked = false;
|
|
3408
|
+
this.elements.selectAllInput.indeterminate = false;
|
|
3409
|
+
box.classList.remove(
|
|
3410
|
+
`${PREFIX}-checkbox__box--checked`,
|
|
3411
|
+
`${PREFIX}-checkbox__box--indeterminate`
|
|
3412
|
+
);
|
|
3413
|
+
box.classList.add(`${PREFIX}-checkbox__box--unchecked`);
|
|
3414
|
+
} else if (checkedCount === totalCount) {
|
|
3415
|
+
this.elements.selectAllInput.checked = true;
|
|
3416
|
+
this.elements.selectAllInput.indeterminate = false;
|
|
3417
|
+
box.classList.remove(
|
|
3418
|
+
`${PREFIX}-checkbox__box--unchecked`,
|
|
3419
|
+
`${PREFIX}-checkbox__box--indeterminate`
|
|
3420
|
+
);
|
|
3421
|
+
box.classList.add(`${PREFIX}-checkbox__box--checked`);
|
|
3422
|
+
box.innerHTML = '<svg class="ina-checkbox__icon" 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="M5 12l5 5l10 -10"></path></svg>';
|
|
3423
|
+
} else {
|
|
3424
|
+
this.elements.selectAllInput.checked = false;
|
|
3425
|
+
this.elements.selectAllInput.indeterminate = true;
|
|
3426
|
+
box.classList.remove(
|
|
3427
|
+
`${PREFIX}-checkbox__box--unchecked`,
|
|
3428
|
+
`${PREFIX}-checkbox__box--checked`
|
|
3429
|
+
);
|
|
3430
|
+
box.classList.add(`${PREFIX}-checkbox__box--indeterminate`);
|
|
3431
|
+
box.innerHTML = '<svg class="ina-checkbox__icon" 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="M5 12h14"></path></svg>';
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
3434
|
+
triggerSelectionChange() {
|
|
3435
|
+
if (typeof this.options.onSelectionChange === "function") {
|
|
3436
|
+
const keys = Array.from(this.state.selectedKeys);
|
|
3437
|
+
const rows = Array.from(this.state.selectedRows.values());
|
|
3438
|
+
this.options.onSelectionChange(keys, rows);
|
|
3439
|
+
}
|
|
3440
|
+
}
|
|
3441
|
+
// API Methods
|
|
3442
|
+
reload() {
|
|
3443
|
+
this.loadData();
|
|
3444
|
+
}
|
|
3445
|
+
setSearchTerm(term) {
|
|
3446
|
+
this.state.searchTerm = term;
|
|
3447
|
+
this.state.currentPage = 1;
|
|
3448
|
+
if (this.elements.searchInput) {
|
|
3449
|
+
this.elements.searchInput.value = term;
|
|
3450
|
+
}
|
|
3451
|
+
this.loadData();
|
|
3452
|
+
}
|
|
3453
|
+
setPage(page) {
|
|
3454
|
+
this.state.currentPage = page;
|
|
3455
|
+
this.loadData();
|
|
3456
|
+
}
|
|
3457
|
+
getSelectedRows() {
|
|
3458
|
+
return {
|
|
3459
|
+
keys: Array.from(this.state.selectedKeys),
|
|
3460
|
+
rows: Array.from(this.state.selectedRows.values())
|
|
3230
3461
|
};
|
|
3462
|
+
}
|
|
3463
|
+
};
|
|
3464
|
+
function initTable(selectorOrElement, options = {}) {
|
|
3465
|
+
const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-table`);
|
|
3466
|
+
const instances = [];
|
|
3467
|
+
elements.forEach((container) => {
|
|
3468
|
+
const instance = new Table(container, options);
|
|
3469
|
+
container.__tableAPI = instance;
|
|
3470
|
+
instances.push(instance);
|
|
3231
3471
|
});
|
|
3472
|
+
if (instances.length === 0) return null;
|
|
3473
|
+
return instances.length === 1 ? instances[0] : instances;
|
|
3232
3474
|
}
|
|
3233
3475
|
|
|
3234
3476
|
// src/js/components/stateless/toast.js
|