@idds/js 1.2.5 → 1.6.0

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.
Files changed (3) hide show
  1. package/dist/index.iife.js +1138 -445
  2. package/dist/index.js +787 -380
  3. package/package.json +1 -1
@@ -21,19 +21,20 @@ var InaUI = (() => {
21
21
  var bundle_exports = {};
22
22
  __export(bundle_exports, {
23
23
  DatePicker: () => DatePicker,
24
+ PhoneInput: () => PhoneInput,
24
25
  Table: () => Table,
25
26
  TimePicker: () => TimePicker,
26
27
  initAccordion: () => initAccordion,
27
28
  initButtonGroup: () => initButtonGroup,
28
29
  initCheckbox: () => initCheckbox,
29
- initChip: () => initChip,
30
+ initChip: () => initChip2,
30
31
  initDatepicker: () => initDatepicker,
31
32
  initDrawer: () => initDrawer,
32
33
  initDropdown: () => initDropdown,
33
34
  initFileUpload: () => initFileUpload,
34
35
  initFileUploadBase: () => initFileUploadBase,
35
36
  initFileUploadItem: () => initFileUploadItem,
36
- initImgCompare: () => initImgCompare,
37
+ initImgCompare: () => initImgCompare2,
37
38
  initModal: () => initModal,
38
39
  initMonthPicker: () => initMonthPicker,
39
40
  initPagination: () => initPagination,
@@ -103,18 +104,18 @@ var InaUI = (() => {
103
104
  const tabItem = tab.querySelectorAll(`.${PREFIX}-tab-item`);
104
105
  tabItem.forEach((tabButton) => {
105
106
  function updateState() {
106
- const index2 = Array.from(tabItem).indexOf(tabButton);
107
+ const index = Array.from(tabItem).indexOf(tabButton);
107
108
  tabItem.forEach((tabButton2, i) => {
108
109
  tabButton2.classList.remove("active");
109
110
  tabButton2.setAttribute("aria-selected", "false");
110
- if (i === index2) {
111
+ if (i === index) {
111
112
  tabButton2.classList.add("active");
112
113
  tabButton2.setAttribute("aria-selected", "true");
113
114
  }
114
115
  });
115
116
  tab.dispatchEvent(
116
117
  new CustomEvent("tab:change", {
117
- detail: { activeIndex: index2 },
118
+ detail: { activeIndex: index },
118
119
  bubbles: true,
119
120
  composed: true
120
121
  })
@@ -209,28 +210,28 @@ var InaUI = (() => {
209
210
  this.element.__inaAccordionGroup = this;
210
211
  }
211
212
  registerItem(item) {
212
- const index2 = this.items.size;
213
- this.items.set(item.id, index2);
213
+ const index = this.items.size;
214
+ this.items.set(item.id, index);
214
215
  this.itemsArray.push(item);
215
216
  if (item.defaultOpen) {
216
217
  if (this.isMultiple) {
217
- if (!this.openIndexes.includes(index2)) {
218
- this.openIndexes.push(index2);
218
+ if (!this.openIndexes.includes(index)) {
219
+ this.openIndexes.push(index);
219
220
  }
220
221
  } else {
221
222
  if (this.openIndexes.length === 0) {
222
- this.openIndexes.push(index2);
223
+ this.openIndexes.push(index);
223
224
  }
224
225
  }
225
226
  }
226
- return index2;
227
+ return index;
227
228
  }
228
229
  unregisterItem(item) {
229
- const index2 = this.items.get(item.id);
230
- if (index2 !== void 0) {
230
+ const index = this.items.get(item.id);
231
+ if (index !== void 0) {
231
232
  this.items.delete(item.id);
232
233
  this.itemsArray = this.itemsArray.filter((i) => i !== item);
233
- this.openIndexes = this.openIndexes.filter((idx) => idx !== index2).map((idx) => idx > index2 ? idx - 1 : idx);
234
+ this.openIndexes = this.openIndexes.filter((idx) => idx !== index).map((idx) => idx > index ? idx - 1 : idx);
234
235
  const newMap = /* @__PURE__ */ new Map();
235
236
  this.itemsArray.forEach((itm, newIdx) => {
236
237
  newMap.set(itm.id, newIdx);
@@ -238,22 +239,22 @@ var InaUI = (() => {
238
239
  this.items = newMap;
239
240
  }
240
241
  }
241
- handleItemToggle(index2, isOpen) {
242
+ handleItemToggle(index, isOpen) {
242
243
  const prevIndexes = [...this.openIndexes];
243
244
  let nextIndexes = [];
244
245
  if (this.isMultiple) {
245
246
  if (isOpen) {
246
- if (!prevIndexes.includes(index2)) {
247
- nextIndexes = [...prevIndexes, index2];
247
+ if (!prevIndexes.includes(index)) {
248
+ nextIndexes = [...prevIndexes, index];
248
249
  } else {
249
250
  nextIndexes = prevIndexes;
250
251
  }
251
252
  } else {
252
- nextIndexes = prevIndexes.filter((idx) => idx !== index2);
253
+ nextIndexes = prevIndexes.filter((idx) => idx !== index);
253
254
  }
254
255
  } else {
255
256
  if (isOpen) {
256
- nextIndexes = [index2];
257
+ nextIndexes = [index];
257
258
  } else {
258
259
  nextIndexes = [];
259
260
  }
@@ -261,16 +262,16 @@ var InaUI = (() => {
261
262
  this.openIndexes = nextIndexes;
262
263
  this.notifyItems();
263
264
  }
264
- isItemOpen(index2) {
265
- return this.openIndexes.includes(index2);
265
+ isItemOpen(index) {
266
+ return this.openIndexes.includes(index);
266
267
  }
267
268
  getItemIndex(itemId) {
268
269
  return this.items.get(itemId);
269
270
  }
270
271
  // Notify all children to update their visual state based on new openIndexes
271
272
  notifyItems() {
272
- this.itemsArray.forEach((item, index2) => {
273
- const isOpen = this.openIndexes.includes(index2);
273
+ this.itemsArray.forEach((item, index) => {
274
+ const isOpen = this.openIndexes.includes(index);
274
275
  item.setOpenState(isOpen);
275
276
  });
276
277
  }
@@ -379,7 +380,7 @@ var InaUI = (() => {
379
380
 
380
381
  // src/js/components/stateful/date-picker.js
381
382
  var DatePicker = class {
382
- constructor(selectorOrElement, options2 = {}) {
383
+ constructor(selectorOrElement, options = {}) {
383
384
  this.container = typeof selectorOrElement === "string" ? document.querySelector(selectorOrElement) : selectorOrElement;
384
385
  if (!this.container) {
385
386
  console.warn("[IDDS DatePicker] Container not found:", selectorOrElement);
@@ -405,7 +406,11 @@ var InaUI = (() => {
405
406
  onChange: null,
406
407
  triggerWidth: "",
407
408
  panelMaxHeight: "",
408
- ...options2
409
+ allowClear: true,
410
+ // Added allowClear option
411
+ className: "",
412
+ // Added className option
413
+ ...options
409
414
  };
410
415
  this.state = {
411
416
  viewDate: /* @__PURE__ */ new Date(),
@@ -559,6 +564,18 @@ var InaUI = (() => {
559
564
  }
560
565
  this.renderPanel();
561
566
  }
567
+ getFullDayName(shortName) {
568
+ const map = {
569
+ Min: "Minggu",
570
+ Sen: "Senin",
571
+ Sel: "Selasa",
572
+ Rab: "Rabu",
573
+ Kam: "Kamis",
574
+ Jum: "Jumat",
575
+ Sab: "Sabtu"
576
+ };
577
+ return map[shortName] || shortName;
578
+ }
562
579
  initDOM() {
563
580
  if (!this.container.classList.contains(`${PREFIX}-date-picker`)) {
564
581
  this.container.classList.add(`${PREFIX}-date-picker`);
@@ -574,6 +591,9 @@ var InaUI = (() => {
574
591
  if (this.options.triggerWidth) {
575
592
  trigger.style.width = typeof this.options.triggerWidth === "number" ? `${this.options.triggerWidth}px` : this.options.triggerWidth;
576
593
  }
594
+ trigger.setAttribute("aria-haspopup", "dialog");
595
+ trigger.setAttribute("aria-expanded", "false");
596
+ trigger.setAttribute("aria-label", "Pilih Tanggal");
577
597
  const textWrapper = document.createElement("span");
578
598
  textWrapper.className = `${PREFIX}-date-picker__trigger-text ${PREFIX}-date-picker__trigger-text--placeholder`;
579
599
  textWrapper.textContent = "Pilih Tanggal";
@@ -583,6 +603,26 @@ var InaUI = (() => {
583
603
  trigger.appendChild(textWrapper);
584
604
  trigger.appendChild(iconWrapper);
585
605
  this.container.appendChild(trigger);
606
+ } else if (trigger) {
607
+ if (!trigger.hasAttribute("aria-haspopup"))
608
+ trigger.setAttribute("aria-haspopup", "dialog");
609
+ if (!trigger.hasAttribute("aria-expanded"))
610
+ trigger.setAttribute("aria-expanded", "false");
611
+ if (!trigger.hasAttribute("aria-label"))
612
+ trigger.setAttribute("aria-label", "Pilih Tanggal");
613
+ }
614
+ if (this.options.allowClear && !this.options.panelOnly) {
615
+ let clearBtn = this.container.querySelector(`.${PREFIX}-date-picker__clear-button`);
616
+ if (!clearBtn) {
617
+ clearBtn = document.createElement("button");
618
+ clearBtn.type = "button";
619
+ clearBtn.className = `${PREFIX}-date-picker__clear-button`;
620
+ clearBtn.setAttribute("aria-label", "Hapus tanggal terpilih");
621
+ clearBtn.innerHTML = this.createIcon("x");
622
+ clearBtn.style.display = "none";
623
+ this.container.appendChild(clearBtn);
624
+ }
625
+ this.elements.clearBtn = clearBtn;
586
626
  }
587
627
  this.elements.trigger = trigger;
588
628
  if (trigger) {
@@ -877,10 +917,13 @@ var InaUI = (() => {
877
917
  header.appendChild(nextBtn);
878
918
  const grid = document.createElement("div");
879
919
  grid.className = `${PREFIX}-date-picker__calendar-grid`;
920
+ grid.setAttribute("role", "grid");
880
921
  this.DAYS_SHORT.forEach((d) => {
881
922
  const dh = document.createElement("div");
882
923
  dh.className = `${PREFIX}-date-picker__day-header`;
883
924
  dh.textContent = d;
925
+ dh.setAttribute("role", "columnheader");
926
+ dh.setAttribute("aria-label", this.getFullDayName(d));
884
927
  grid.appendChild(dh);
885
928
  });
886
929
  const firstDayOfMonth = new Date(year, month, 1).getDay();
@@ -1025,6 +1068,7 @@ var InaUI = (() => {
1025
1068
  this.state.isOpen = true;
1026
1069
  this.elements.panel.classList.add(`${PREFIX}-date-picker__panel--open`);
1027
1070
  this.elements.panel.style.display = "block";
1071
+ if (this.elements.trigger) this.elements.trigger.setAttribute("aria-expanded", "true");
1028
1072
  this.renderPanel();
1029
1073
  }
1030
1074
  close() {
@@ -1032,6 +1076,7 @@ var InaUI = (() => {
1032
1076
  this.state.isOpen = false;
1033
1077
  this.elements.panel.classList.remove(`${PREFIX}-date-picker__panel--open`);
1034
1078
  this.elements.panel.style.display = "none";
1079
+ if (this.elements.trigger) this.elements.trigger.setAttribute("aria-expanded", "false");
1035
1080
  }
1036
1081
  toggle() {
1037
1082
  if (this.state.isOpen) this.close();
@@ -1076,11 +1121,11 @@ var InaUI = (() => {
1076
1121
  return this.state.rangeDate;
1077
1122
  }
1078
1123
  };
1079
- function initDatepicker(selectorOrElement, options2 = {}) {
1124
+ function initDatepicker(selectorOrElement, options = {}) {
1080
1125
  const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-date-picker`);
1081
1126
  const instances = [];
1082
1127
  elements.forEach((container) => {
1083
- const instance = new DatePicker(container, options2);
1128
+ const instance = new DatePicker(container, options);
1084
1129
  container.__datepickerAPI = instance;
1085
1130
  instances.push(instance);
1086
1131
  });
@@ -1090,7 +1135,7 @@ var InaUI = (() => {
1090
1135
 
1091
1136
  // src/js/components/stateful/time-picker.js
1092
1137
  var TimePicker = class {
1093
- constructor(selectorOrElement, options2 = {}) {
1138
+ constructor(selectorOrElement, options = {}) {
1094
1139
  this.container = typeof selectorOrElement === "string" ? document.querySelector(selectorOrElement) : selectorOrElement;
1095
1140
  if (!this.container) {
1096
1141
  console.warn("[IDDS TimePicker] Container not found:", selectorOrElement);
@@ -1123,7 +1168,7 @@ var InaUI = (() => {
1123
1168
  secondStep: 1,
1124
1169
  onChange: null,
1125
1170
  size: this.container.dataset.size || "md",
1126
- ...options2
1171
+ ...options
1127
1172
  };
1128
1173
  this.state = {
1129
1174
  isOpen: false,
@@ -1131,6 +1176,7 @@ var InaUI = (() => {
1131
1176
  internalValue: ""
1132
1177
  };
1133
1178
  this.elements = {};
1179
+ this.inputId = this.container.id || `time-picker-${Math.random().toString(36).substr(2, 9)}`;
1134
1180
  this.initDOM();
1135
1181
  this.bindEvents();
1136
1182
  if (this.elements.input && this.elements.input.value) {
@@ -1238,12 +1284,16 @@ var InaUI = (() => {
1238
1284
  if (!wrapper) {
1239
1285
  wrapper = document.createElement("div");
1240
1286
  wrapper.className = `${PREFIX}-time-picker__wrapper`;
1287
+ wrapper.setAttribute("role", "combobox");
1288
+ wrapper.setAttribute("aria-haspopup", "listbox");
1289
+ wrapper.setAttribute("aria-expanded", "false");
1241
1290
  const prefixIcon = document.createElement("div");
1242
1291
  prefixIcon.className = `${PREFIX}-time-picker__prefix-icon`;
1243
1292
  prefixIcon.innerHTML = this.createIcon("clock");
1244
1293
  wrapper.appendChild(prefixIcon);
1245
1294
  input = document.createElement("input");
1246
1295
  input.type = "text";
1296
+ input.id = this.inputId;
1247
1297
  input.className = `${PREFIX}-time-picker__input ${PREFIX}-time-picker__input--size-${this.options.size} ${PREFIX}-time-picker__input--with-prefix`;
1248
1298
  if (this.options.allowClear)
1249
1299
  input.classList.add(`${PREFIX}-time-picker__input--with-suffix`);
@@ -1253,13 +1303,23 @@ var InaUI = (() => {
1253
1303
  else input.readOnly = true;
1254
1304
  wrapper.appendChild(input);
1255
1305
  if (this.options.allowClear) {
1256
- clearBtn = document.createElement("div");
1306
+ clearBtn = document.createElement("button");
1307
+ clearBtn.type = "button";
1257
1308
  clearBtn.className = `${PREFIX}-time-picker__clear-button`;
1309
+ clearBtn.setAttribute("aria-label", "Hapus waktu");
1258
1310
  clearBtn.innerHTML = this.createIcon("x");
1259
1311
  clearBtn.style.display = "none";
1260
1312
  wrapper.appendChild(clearBtn);
1261
1313
  }
1262
1314
  this.container.appendChild(wrapper);
1315
+ } else {
1316
+ wrapper.setAttribute("role", "combobox");
1317
+ wrapper.setAttribute("aria-haspopup", "listbox");
1318
+ wrapper.setAttribute("aria-expanded", "false");
1319
+ if (input && !input.id) input.id = this.inputId;
1320
+ if (clearBtn && !clearBtn.hasAttribute("aria-label")) {
1321
+ clearBtn.setAttribute("aria-label", "Hapus waktu");
1322
+ }
1263
1323
  }
1264
1324
  this.elements.wrapper = wrapper;
1265
1325
  this.elements.input = input;
@@ -1340,24 +1400,24 @@ var InaUI = (() => {
1340
1400
  }
1341
1401
  }
1342
1402
  generateOptions(type) {
1343
- const options2 = [];
1403
+ const options = [];
1344
1404
  const { use12Hours, hourStep, minuteStep, secondStep } = this.options;
1345
1405
  let limit = type === "hour" ? use12Hours ? 12 : 24 : 60;
1346
1406
  let step = type === "hour" ? hourStep : type === "minute" ? minuteStep : secondStep;
1347
1407
  if (limit === 12) {
1348
1408
  for (let i = type === "hour" ? 1 : 0; i <= (type === "hour" ? 12 : 59); i += step) {
1349
- options2.push(i);
1409
+ options.push(i);
1350
1410
  }
1351
1411
  } else if (limit === 24) {
1352
1412
  for (let i = 0; i <= 23; i += step) {
1353
- options2.push(i);
1413
+ options.push(i);
1354
1414
  }
1355
1415
  } else {
1356
1416
  for (let i = 0; i <= 59; i += step) {
1357
- options2.push(i);
1417
+ options.push(i);
1358
1418
  }
1359
1419
  }
1360
- return options2;
1420
+ return options;
1361
1421
  }
1362
1422
  renderColumn(type, optionsArr) {
1363
1423
  const column = document.createElement("div");
@@ -1367,7 +1427,7 @@ var InaUI = (() => {
1367
1427
  column.appendChild(colContent);
1368
1428
  const { use12Hours } = this.options;
1369
1429
  const { currentTime } = this.state;
1370
- optionsArr.forEach((optValue) => {
1430
+ optionsArr.forEach((optValue, index) => {
1371
1431
  const option = document.createElement("div");
1372
1432
  option.className = `${PREFIX}-time-picker__option`;
1373
1433
  let isSelected = false;
@@ -1413,9 +1473,9 @@ var InaUI = (() => {
1413
1473
  option.classList.add(`${PREFIX}-time-picker__option--disabled`);
1414
1474
  option.setAttribute("role", "option");
1415
1475
  option.setAttribute("aria-selected", isSelected.toString());
1416
- const isFirstFocusable = index === 0 && !options.some((opt) => {
1476
+ const isFirstFocusable = index === 0 && !optionsArr.some((opt) => {
1417
1477
  if (type === "hour") {
1418
- return use12Hours ? (currentTime.hours === 0 ? 12 : currentTime.hours) === opt : currentTime.hours === opt;
1478
+ return (use12Hours && currentTime.hours === 0 ? 12 : currentTime.hours) === opt;
1419
1479
  } else if (type === "minute") {
1420
1480
  return currentTime.minutes === opt;
1421
1481
  } else if (type === "second") {
@@ -1533,6 +1593,7 @@ var InaUI = (() => {
1533
1593
  this.state.isOpen = true;
1534
1594
  this.container.classList.add(`${PREFIX}-time-picker--open`);
1535
1595
  this.elements.panel.style.display = "block";
1596
+ this.elements.wrapper.setAttribute("aria-expanded", "true");
1536
1597
  this.state.currentTime = this.parseTime(this.elements.input.value);
1537
1598
  this.buildPanel();
1538
1599
  document.dispatchEvent(
@@ -1545,6 +1606,7 @@ var InaUI = (() => {
1545
1606
  this.state.isOpen = false;
1546
1607
  this.container.classList.remove(`${PREFIX}-time-picker--open`);
1547
1608
  this.elements.panel.style.display = "none";
1609
+ this.elements.wrapper.setAttribute("aria-expanded", "false");
1548
1610
  }
1549
1611
  toggle() {
1550
1612
  if (this.state.isOpen) this.close();
@@ -1555,16 +1617,9 @@ var InaUI = (() => {
1555
1617
  e.stopPropagation();
1556
1618
  this.toggle();
1557
1619
  });
1558
- if (this.elements.clearBtn && this.options.allowClear) {
1620
+ if (this.elements.clearBtn) {
1559
1621
  this.elements.clearBtn.addEventListener("click", (e) => {
1560
1622
  e.stopPropagation();
1561
- this.elements.input.value = "";
1562
- this.state.currentTime = {
1563
- hours: 0,
1564
- minutes: 0,
1565
- seconds: 0,
1566
- period: "AM"
1567
- };
1568
1623
  this.container.dataset.value = "";
1569
1624
  this.state.internalValue = "";
1570
1625
  this.elements.clearBtn.style.display = "none";
@@ -1588,11 +1643,11 @@ var InaUI = (() => {
1588
1643
  return this.state.internalValue;
1589
1644
  }
1590
1645
  };
1591
- function initTimepicker(selectorOrElement, options2 = {}) {
1646
+ function initTimepicker(selectorOrElement, options = {}) {
1592
1647
  const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-time-picker`);
1593
1648
  const instances = [];
1594
1649
  elements.forEach((container) => {
1595
- const instance = new TimePicker(container, options2);
1650
+ const instance = new TimePicker(container, options);
1596
1651
  container.__timepickerAPI = instance;
1597
1652
  instances.push(instance);
1598
1653
  });
@@ -1635,6 +1690,17 @@ var InaUI = (() => {
1635
1690
  modalEl.style.display = "flex";
1636
1691
  document.body.style.overflow = "hidden";
1637
1692
  modalEl.setAttribute("aria-hidden", "false");
1693
+ modalEl.setAttribute("tabindex", "-1");
1694
+ if (!modalEl.hasAttribute("role")) {
1695
+ modalEl.setAttribute("role", "dialog");
1696
+ }
1697
+ if (!modalEl.hasAttribute("aria-modal")) {
1698
+ modalEl.setAttribute("aria-modal", "true");
1699
+ }
1700
+ const closeBtn = modalEl.querySelector(`.${PREFIX}-modal__close-button`);
1701
+ if (closeBtn && !closeBtn.hasAttribute("aria-label")) {
1702
+ closeBtn.setAttribute("aria-label", "Tutup dialog");
1703
+ }
1638
1704
  modalEl.classList.remove(
1639
1705
  `${PREFIX}-modal--exit`,
1640
1706
  `${PREFIX}-modal--exit-active`
@@ -1733,6 +1799,19 @@ var InaUI = (() => {
1733
1799
  if (!drawer) return;
1734
1800
  drawer.style.display = "flex";
1735
1801
  document.body.style.overflow = "hidden";
1802
+ drawer.setAttribute("aria-hidden", "false");
1803
+ drawer.setAttribute("tabindex", "-1");
1804
+ if (!drawer.hasAttribute("role")) {
1805
+ drawer.setAttribute("role", "complementary");
1806
+ }
1807
+ if (!drawer.hasAttribute("aria-modal")) {
1808
+ drawer.setAttribute("aria-modal", "true");
1809
+ }
1810
+ const panel = drawer.querySelector(`.${PREFIX2}-drawer__panel`) || drawer.querySelector(`.${PREFIX2}-drawer__content`) || drawer;
1811
+ const closeBtn = panel.querySelector(`.${PREFIX2}-drawer__close-button`);
1812
+ if (closeBtn && !closeBtn.hasAttribute("aria-label")) {
1813
+ closeBtn.setAttribute("aria-label", "Tutup panel");
1814
+ }
1736
1815
  drawer.offsetHeight;
1737
1816
  drawer.classList.add(`${PREFIX2}-drawer--open`);
1738
1817
  drawer.dispatchEvent(new CustomEvent("drawer:open"));
@@ -1805,9 +1884,20 @@ var InaUI = (() => {
1805
1884
  if (newState.isOpen !== void 0) {
1806
1885
  root.setAttribute("data-state", newState.isOpen ? "open" : "closed");
1807
1886
  const trigger = root.querySelector(`.${PREFIX3}-select-dropdown__trigger`);
1808
- if (trigger) trigger.setAttribute("aria-expanded", newState.isOpen);
1887
+ if (trigger) {
1888
+ trigger.setAttribute("aria-expanded", newState.isOpen);
1889
+ if (!trigger.hasAttribute("aria-haspopup")) {
1890
+ trigger.setAttribute("aria-haspopup", "listbox");
1891
+ }
1892
+ }
1809
1893
  const panel = root.querySelector(`.${PREFIX3}-select-dropdown__panel`);
1810
1894
  if (panel) {
1895
+ if (!panel.hasAttribute("role")) {
1896
+ panel.setAttribute("role", "listbox");
1897
+ }
1898
+ if (newState.isMultiple) {
1899
+ panel.setAttribute("aria-multiselectable", "true");
1900
+ }
1811
1901
  if (newState.isOpen) {
1812
1902
  panel.style.removeProperty("display");
1813
1903
  } else {
@@ -1834,9 +1924,9 @@ var InaUI = (() => {
1834
1924
  `.${PREFIX3}-select-dropdown__trigger-text`
1835
1925
  );
1836
1926
  const placeholder = input ? input.getAttribute("placeholder") : textSpan ? textSpan.getAttribute("data-placeholder") : "Select...";
1837
- const options2 = root.querySelectorAll(`.${PREFIX3}-select-dropdown__option`);
1927
+ const options = root.querySelectorAll(`.${PREFIX3}-select-dropdown__option`);
1838
1928
  const getLabel = (val) => {
1839
- const opt = Array.from(options2).find(
1929
+ const opt = Array.from(options).find(
1840
1930
  (o) => o.getAttribute("data-value") === val
1841
1931
  );
1842
1932
  return opt ? opt.textContent.trim() : val;
@@ -1862,7 +1952,7 @@ var InaUI = (() => {
1862
1952
  values.length === 0
1863
1953
  );
1864
1954
  }
1865
- options2.forEach((opt) => {
1955
+ options.forEach((opt) => {
1866
1956
  const val = opt.getAttribute("data-value");
1867
1957
  const isSelected = values.includes(val);
1868
1958
  if (isMultiple) {
@@ -1884,6 +1974,10 @@ var InaUI = (() => {
1884
1974
  isSelected
1885
1975
  );
1886
1976
  }
1977
+ if (!opt.hasAttribute("role")) {
1978
+ opt.setAttribute("role", "option");
1979
+ }
1980
+ opt.setAttribute("aria-selected", isSelected);
1887
1981
  });
1888
1982
  }
1889
1983
  function initSelectDropdown() {
@@ -1942,13 +2036,13 @@ var InaUI = (() => {
1942
2036
  const root = e.target.closest(`.${PREFIX3}-select-dropdown`);
1943
2037
  if (root) {
1944
2038
  const term = e.target.value.toLowerCase();
1945
- const options2 = root.querySelectorAll(
2039
+ const options = root.querySelectorAll(
1946
2040
  `.${PREFIX3}-select-dropdown__option`
1947
2041
  );
1948
2042
  if (root.getAttribute("data-state") !== "open") {
1949
2043
  setDropdownState(root, { isOpen: true });
1950
2044
  }
1951
- options2.forEach((opt) => {
2045
+ options.forEach((opt) => {
1952
2046
  const text = opt.textContent.trim().toLowerCase();
1953
2047
  opt.style.display = text.includes(term) ? "" : "none";
1954
2048
  });
@@ -2022,20 +2116,20 @@ var InaUI = (() => {
2022
2116
  `;
2023
2117
  const updateUI = () => {
2024
2118
  stepper.dataset.currentStep = currentStep;
2025
- items.forEach((item, index2) => {
2119
+ items.forEach((item, index) => {
2026
2120
  const iconWrapper = item.querySelector(
2027
2121
  `.${PREFIX}-stepper__icon-wrapper`
2028
2122
  );
2029
- const itemNumber = index2 + 1;
2123
+ const itemNumber = index + 1;
2030
2124
  item.classList.remove(
2031
2125
  `${PREFIX}-stepper__item--completed`,
2032
2126
  `${PREFIX}-stepper__item--active`
2033
2127
  );
2034
2128
  if (iconWrapper) iconWrapper.innerHTML = "";
2035
- if (index2 < currentStep) {
2129
+ if (index < currentStep) {
2036
2130
  item.classList.add(`${PREFIX}-stepper__item--completed`);
2037
2131
  if (iconWrapper) iconWrapper.innerHTML = checkIcon;
2038
- } else if (index2 === currentStep) {
2132
+ } else if (index === currentStep) {
2039
2133
  item.classList.add(`${PREFIX}-stepper__item--active`);
2040
2134
  if (iconWrapper)
2041
2135
  iconWrapper.innerHTML = `<span class="${PREFIX}-stepper__step-number">${itemNumber}</span>`;
@@ -2044,8 +2138,8 @@ var InaUI = (() => {
2044
2138
  iconWrapper.innerHTML = `<span class="${PREFIX}-stepper__step-number">${itemNumber}</span>`;
2045
2139
  }
2046
2140
  });
2047
- separators.forEach((separator, index2) => {
2048
- if (index2 < currentStep) {
2141
+ separators.forEach((separator, index) => {
2142
+ if (index < currentStep) {
2049
2143
  separator.classList.add(`${PREFIX}-stepper__separator--completed`);
2050
2144
  } else {
2051
2145
  separator.classList.remove(`${PREFIX}-stepper__separator--completed`);
@@ -2091,11 +2185,11 @@ var InaUI = (() => {
2091
2185
  }
2092
2186
  });
2093
2187
  });
2094
- items.forEach((item, index2) => {
2188
+ items.forEach((item, index) => {
2095
2189
  if (item.classList.contains(`${PREFIX}-stepper__item--clickable`) || item.hasAttribute("data-clickable")) {
2096
2190
  item.addEventListener("click", () => {
2097
2191
  if (!item.classList.contains(`${PREFIX}-stepper__item--disabled`)) {
2098
- currentStep = index2;
2192
+ currentStep = index;
2099
2193
  updateUI();
2100
2194
  }
2101
2195
  });
@@ -2169,7 +2263,7 @@ var InaUI = (() => {
2169
2263
  } else {
2170
2264
  filesContainer.style.display = "none";
2171
2265
  }
2172
- uploadedFiles.forEach((f, index2) => {
2266
+ uploadedFiles.forEach((f, index) => {
2173
2267
  const fileEl = document.createElement("div");
2174
2268
  fileEl.className = `${PREFIX}-file-upload__file`;
2175
2269
  let statusClass = "";
@@ -2993,342 +3087,67 @@ var InaUI = (() => {
2993
3087
  });
2994
3088
  }
2995
3089
 
2996
- // src/js/components/stateless/img-compare.js
2997
- function initImgCompare(rootSelector = `.${PREFIX}-img-compare`) {
2998
- document.querySelectorAll(rootSelector).forEach((imgCompare) => {
2999
- const sliderEl = document.createElement("input");
3000
- sliderEl.type = "range";
3001
- sliderEl.min = "0";
3002
- sliderEl.max = "100";
3003
- sliderEl.value = "50";
3004
- sliderEl.setAttribute("aria-label", "Percentage of the image to show");
3005
- sliderEl.setAttribute("aria-valuenow", "50");
3006
- sliderEl.setAttribute("aria-valuemin", "0");
3007
- sliderEl.setAttribute("aria-valuemax", "100");
3008
- sliderEl.classList.add("ina-ss-img__slider");
3009
- sliderEl.addEventListener("input", () => {
3010
- imgCompare.style.setProperty(
3011
- `--${PREFIX}-position`,
3012
- `${sliderEl.value}%`
3013
- );
3014
- });
3015
- const sliderLineEl = document.createElement("div");
3016
- sliderLineEl.classList.add("ina-ss-img__slider-line");
3017
- const sliderButtonEl = document.createElement("button");
3018
- sliderButtonEl.classList.add("ina-ss-img__slider-button");
3019
- imgCompare.appendChild(sliderEl);
3020
- imgCompare.appendChild(sliderLineEl);
3021
- imgCompare.appendChild(sliderButtonEl);
3022
- });
3023
- }
3024
-
3025
- // src/js/components/stateful/chip.js
3026
- var PREFIX4 = "ina";
3027
- function initChip(rootSelector = `.${PREFIX4}-chip`) {
3028
- const chips = document.querySelectorAll(rootSelector);
3029
- chips.forEach((container) => {
3030
- if (container.__inaChipInitialized) return;
3031
- const showCustomization = container.getAttribute("data-show-customization") === "true";
3032
- const customizationLabel = container.getAttribute("data-customization-label") || "Kustomisasi";
3033
- const isMultiple = container.getAttribute("data-multiple") === "true";
3034
- let selectedValue = container.getAttribute("data-selected") || "";
3035
- const list = container.querySelector(`.${PREFIX4}-chip__list`);
3036
- const items = list ? list.querySelectorAll(`.${PREFIX4}-chip__item`) : [];
3037
- let customFieldContainer = container.querySelector(
3038
- `.${PREFIX4}-chip__custom-field`
3090
+ // src/js/components/stateful/pagination.js
3091
+ function initPagination() {
3092
+ document.querySelectorAll(`.${PREFIX}-pagination`).forEach((container) => {
3093
+ if (container.dataset.initialized === "true") return;
3094
+ container.dataset.initialized = "true";
3095
+ const navButtonsContainer = container.querySelector(
3096
+ `.${PREFIX}-pagination__nav-buttons`
3039
3097
  );
3040
- const getNormalizedSelected = () => {
3041
- if (!selectedValue) return [];
3042
- return isMultiple ? selectedValue.split(",").map((s) => s.trim()).filter(Boolean) : [selectedValue];
3043
- };
3098
+ const pageInfo = container.querySelector(
3099
+ `.${PREFIX}-pagination__page-info`
3100
+ );
3101
+ const firstBtn = container.querySelector('[data-action="first"]');
3102
+ const prevBtn = container.querySelector('[data-action="prev"]');
3103
+ const nextBtn = container.querySelector('[data-action="next"]');
3104
+ const lastBtn = container.querySelector('[data-action="last"]');
3105
+ const pageSizeSelect = container.querySelector('[data-role="page-size"]');
3106
+ if (!navButtonsContainer || !pageInfo) return;
3107
+ let currentPage = parseInt(container.dataset.current || "1", 10);
3108
+ let totalPages = parseInt(container.dataset.total || "10", 10);
3109
+ let pageSize = parseInt(container.dataset.pageSize || "10", 10);
3110
+ let isDisabled = container.dataset.disabled === "true";
3111
+ let pageButtons = [];
3044
3112
  const updateUI = () => {
3045
- const normSelected = getNormalizedSelected();
3046
- const getInitialFocusIndex = () => {
3047
- if (normSelected.length > 0) {
3048
- const standardValues = Array.from(items).filter((item) => item.textContent.trim() !== customizationLabel).map((item) => item.getAttribute("data-value"));
3049
- const hasCustomVal = normSelected.some(
3050
- (val) => !standardValues.includes(val) && val !== ""
3051
- );
3052
- if (hasCustomVal && showCustomization) {
3053
- return items.length - 1;
3054
- }
3055
- const firstSelectedIndex = Array.from(items).findIndex(
3056
- (opt) => normSelected.includes(opt.getAttribute("data-value"))
3057
- );
3058
- if (firstSelectedIndex !== -1) return firstSelectedIndex;
3059
- }
3060
- return 0;
3061
- };
3062
- const focusedIndex = getInitialFocusIndex();
3063
- items.forEach((item, index2) => {
3064
- const itemValue = item.getAttribute("data-value");
3065
- const isSelected = normSelected.includes(itemValue) || showCustomization && item.textContent.trim() === customizationLabel && normSelected.some(
3066
- (val) => !Array.from(items).filter((i) => i.textContent.trim() !== customizationLabel).map((i) => i.getAttribute("data-value")).includes(val) && val !== ""
3067
- );
3068
- const isDisabled = item.hasAttribute("disabled");
3069
- if (isSelected) {
3070
- item.classList.add(`${PREFIX4}-chip__item--selected`);
3071
- } else {
3072
- item.classList.remove(`${PREFIX4}-chip__item--selected`);
3073
- }
3074
- if (isDisabled) {
3075
- item.classList.add(`${PREFIX4}-chip__item--disabled`);
3076
- }
3077
- item.setAttribute(
3078
- "tabindex",
3079
- index2 === focusedIndex && !isDisabled ? "0" : "-1"
3113
+ pageInfo.textContent = `Halaman ${currentPage} dari ${totalPages}`;
3114
+ const isFirst = currentPage === 1;
3115
+ if (firstBtn) {
3116
+ const disabled = isDisabled || isFirst;
3117
+ firstBtn.disabled = disabled;
3118
+ firstBtn.classList.toggle(
3119
+ `${PREFIX}-pagination__nav-button--disabled`,
3120
+ disabled
3080
3121
  );
3081
- });
3082
- if (showCustomization) {
3083
- const isToggleBtn2 = (i) => i.hasAttribute("data-customization-toggle") || i.textContent.trim() === customizationLabel;
3084
- const standardValues = Array.from(items).filter((item) => !isToggleBtn2(item)).map((item) => item.getAttribute("data-value"));
3085
- const customValues = normSelected.filter(
3086
- (val) => !standardValues.includes(val) && val !== ""
3122
+ firstBtn.classList.toggle(
3123
+ `${PREFIX}-pagination__nav-button--enabled`,
3124
+ !disabled
3087
3125
  );
3088
- const isStandard = customValues.length === 0;
3089
- const primaryCustomValue = customValues[customValues.length - 1] || "";
3090
- const toggleBtn = Array.from(items).find(isToggleBtn2);
3091
- const showInput = toggleBtn && normSelected.includes(toggleBtn.getAttribute("data-value")) || !isStandard && normSelected.length > 0;
3092
- if (showInput) {
3093
- if (!customFieldContainer) {
3094
- customFieldContainer = document.createElement("div");
3095
- customFieldContainer.className = `${PREFIX4}-chip__custom-field`;
3096
- container.appendChild(customFieldContainer);
3097
- }
3098
- let input = customFieldContainer.querySelector(
3099
- `.${PREFIX4}-chip__input`
3100
- );
3101
- if (!input) {
3102
- customFieldContainer.innerHTML = `
3103
- <div class="${PREFIX4}-chip__input-wrapper">
3104
- <input type="text" class="${PREFIX4}-chip__input" placeholder="Masukkan data yang Anda inginkan" value="${!isStandard ? primaryCustomValue : ""}" />
3105
- <button type="button" class="${PREFIX4}-chip__clear-button" aria-label="Clear input" style="display: ${!isStandard && primaryCustomValue ? "inline-flex" : "none"};">
3106
- <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="${PREFIX4}-chip__clear-icon">
3107
- <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
3108
- <path d="M18 6l-12 12"></path>
3109
- <path d="M6 6l12 12"></path>
3110
- </svg>
3111
- </button>
3112
- </div>
3113
- `;
3114
- input = customFieldContainer.querySelector("input");
3115
- const clearBtn = customFieldContainer.querySelector(
3116
- ".ina-chip__clear-button"
3117
- );
3118
- input.addEventListener("input", (e) => {
3119
- clearBtn.style.display = e.target.value ? "inline-flex" : "none";
3120
- });
3121
- clearBtn.addEventListener("click", () => {
3122
- input.value = "";
3123
- clearBtn.style.display = "none";
3124
- commitCustomValue(input);
3125
- });
3126
- input.addEventListener("blur", (e) => {
3127
- commitCustomValue(e.target);
3128
- });
3129
- input.addEventListener("keydown", (e) => {
3130
- if (e.key === "Enter") {
3131
- commitCustomValue(e.target);
3132
- e.target.blur();
3133
- }
3134
- });
3135
- } else {
3136
- const inputEl = customFieldContainer.querySelector("input");
3137
- if (inputEl && document.activeElement !== inputEl) {
3138
- inputEl.value = !isStandard ? primaryCustomValue : "";
3139
- }
3140
- }
3141
- customFieldContainer.style.display = "block";
3142
- } else {
3143
- if (customFieldContainer) {
3144
- customFieldContainer.style.display = "none";
3145
- }
3146
- }
3147
3126
  }
3148
- };
3149
- const handleSelect = (val) => {
3150
- if (!val) return;
3151
- let finalVal = val;
3152
- if (isMultiple) {
3153
- const normSelected = getNormalizedSelected();
3154
- let newSelected;
3155
- if (normSelected.includes(val)) {
3156
- newSelected = normSelected.filter((v) => v !== val);
3157
- } else {
3158
- newSelected = [...normSelected, val];
3159
- }
3160
- finalVal = newSelected;
3161
- selectedValue = newSelected.join(",");
3162
- } else {
3163
- const normSelected = getNormalizedSelected();
3164
- if (normSelected.includes(val)) {
3165
- selectedValue = "";
3166
- finalVal = "";
3167
- } else {
3168
- selectedValue = val;
3169
- }
3127
+ if (prevBtn) {
3128
+ const disabled = isDisabled || isFirst;
3129
+ prevBtn.disabled = disabled;
3130
+ prevBtn.classList.toggle(
3131
+ `${PREFIX}-pagination__nav-button--disabled`,
3132
+ disabled
3133
+ );
3134
+ prevBtn.classList.toggle(
3135
+ `${PREFIX}-pagination__nav-button--enabled`,
3136
+ !disabled
3137
+ );
3170
3138
  }
3171
- container.setAttribute("data-selected", selectedValue);
3172
- updateUI();
3173
- container.dispatchEvent(
3174
- new CustomEvent("chip:select", {
3175
- detail: { value: finalVal },
3176
- bubbles: true
3177
- })
3178
- );
3179
- };
3180
- let currentFocusedIndex = -1;
3181
- const setItemFocus = (index2) => {
3182
- items.forEach((item, i) => {
3183
- item.setAttribute("tabindex", i === index2 ? "0" : "-1");
3184
- });
3185
- if (items[index2]) {
3186
- items[index2].focus();
3187
- currentFocusedIndex = index2;
3188
- }
3189
- };
3190
- const commitCustomValue = (inputEl) => {
3191
- const finalValue = inputEl.value.trim();
3192
- let normSelected = getNormalizedSelected();
3193
- const toggleBtn = Array.from(items).find(isToggleBtn);
3194
- const toggleVal = toggleBtn ? toggleBtn.getAttribute("data-value") : null;
3195
- const standardValues = Array.from(items).filter((i) => !isToggleBtn(i)).map((i) => i.getAttribute("data-value"));
3196
- const customValues = normSelected.filter(
3197
- (val) => !standardValues.includes(val) && val !== "" && val !== toggleVal
3198
- );
3199
- const primaryCustomValue = customValues[customValues.length - 1];
3200
- if (primaryCustomValue) {
3201
- normSelected = normSelected.filter((v) => v !== primaryCustomValue);
3202
- }
3203
- if (finalValue !== "") {
3204
- if (!normSelected.includes(finalValue)) {
3205
- normSelected.push(finalValue);
3206
- }
3207
- } else {
3208
- if (toggleVal) {
3209
- normSelected = normSelected.filter((v) => v !== toggleVal);
3210
- }
3211
- }
3212
- if (isMultiple) {
3213
- selectedValue = normSelected.join(",");
3214
- } else {
3215
- selectedValue = finalValue;
3216
- }
3217
- updateUI();
3218
- const changeEvent = new CustomEvent(`${PREFIX4}-chip:change`, {
3219
- detail: { value: isMultiple ? getNormalizedSelected() : selectedValue },
3220
- bubbles: true
3221
- });
3222
- container.dispatchEvent(changeEvent);
3223
- };
3224
- items.forEach((item, index2) => {
3225
- item.addEventListener("click", (e) => {
3226
- if (item.hasAttribute("disabled")) return;
3227
- currentFocusedIndex = index2;
3228
- const val = item.getAttribute("data-value");
3229
- if (showCustomization && isToggleBtn(item)) {
3230
- const normSelected = getNormalizedSelected();
3231
- const standardValues = Array.from(items).filter((i) => !isToggleBtn(i)).map((i) => i.getAttribute("data-value"));
3232
- const customValues = normSelected.filter(
3233
- (v) => !standardValues.includes(v) && v !== "" && v !== val
3234
- );
3235
- const isInputVisible = normSelected.includes(val) || customValues.length > 0;
3236
- if (!isInputVisible) {
3237
- handleSelect(val);
3238
- }
3239
- } else {
3240
- handleSelect(val);
3241
- }
3242
- });
3243
- item.addEventListener("keydown", (e) => {
3244
- if (item.hasAttribute("disabled")) return;
3245
- if (e.key === "ArrowRight" || e.key === "ArrowDown") {
3246
- e.preventDefault();
3247
- let nextIndex = (index2 + 1) % items.length;
3248
- while (items[nextIndex].hasAttribute("disabled") && nextIndex !== index2) {
3249
- nextIndex = (nextIndex + 1) % items.length;
3250
- }
3251
- setItemFocus(nextIndex);
3252
- } else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
3253
- e.preventDefault();
3254
- let prevIndex = (index2 - 1 + items.length) % items.length;
3255
- while (items[prevIndex].hasAttribute("disabled") && prevIndex !== index2) {
3256
- prevIndex = (prevIndex - 1 + items.length) % items.length;
3257
- }
3258
- setItemFocus(prevIndex);
3259
- }
3260
- if (e.key === " " || e.key === "Enter") {
3261
- e.preventDefault();
3262
- item.click();
3263
- }
3264
- });
3265
- });
3266
- updateUI();
3267
- container.__inaChipInitialized = true;
3268
- });
3269
- }
3270
-
3271
- // src/js/components/stateful/pagination.js
3272
- function initPagination() {
3273
- document.querySelectorAll(`.${PREFIX}-pagination`).forEach((container) => {
3274
- if (container.dataset.initialized === "true") return;
3275
- container.dataset.initialized = "true";
3276
- const navButtonsContainer = container.querySelector(
3277
- `.${PREFIX}-pagination__nav-buttons`
3278
- );
3279
- const pageInfo = container.querySelector(
3280
- `.${PREFIX}-pagination__page-info`
3281
- );
3282
- const firstBtn = container.querySelector('[data-action="first"]');
3283
- const prevBtn = container.querySelector('[data-action="prev"]');
3284
- const nextBtn = container.querySelector('[data-action="next"]');
3285
- const lastBtn = container.querySelector('[data-action="last"]');
3286
- const pageSizeSelect = container.querySelector('[data-role="page-size"]');
3287
- if (!navButtonsContainer || !pageInfo) return;
3288
- let currentPage = parseInt(container.dataset.current || "1", 10);
3289
- let totalPages = parseInt(container.dataset.total || "10", 10);
3290
- let pageSize = parseInt(container.dataset.pageSize || "10", 10);
3291
- let isDisabled = container.dataset.disabled === "true";
3292
- let pageButtons = [];
3293
- const updateUI = () => {
3294
- pageInfo.textContent = `Halaman ${currentPage} dari ${totalPages}`;
3295
- const isFirst = currentPage === 1;
3296
- if (firstBtn) {
3297
- const disabled = isDisabled || isFirst;
3298
- firstBtn.disabled = disabled;
3299
- firstBtn.classList.toggle(
3300
- `${PREFIX}-pagination__nav-button--disabled`,
3301
- disabled
3302
- );
3303
- firstBtn.classList.toggle(
3304
- `${PREFIX}-pagination__nav-button--enabled`,
3305
- !disabled
3306
- );
3307
- }
3308
- if (prevBtn) {
3309
- const disabled = isDisabled || isFirst;
3310
- prevBtn.disabled = disabled;
3311
- prevBtn.classList.toggle(
3312
- `${PREFIX}-pagination__nav-button--disabled`,
3313
- disabled
3314
- );
3315
- prevBtn.classList.toggle(
3316
- `${PREFIX}-pagination__nav-button--enabled`,
3317
- !disabled
3318
- );
3319
- }
3320
- const isLast = currentPage === totalPages;
3321
- if (nextBtn) {
3322
- const disabled = isDisabled || isLast;
3323
- nextBtn.disabled = disabled;
3324
- nextBtn.classList.toggle(
3325
- `${PREFIX}-pagination__nav-button--disabled`,
3326
- disabled
3327
- );
3328
- nextBtn.classList.toggle(
3329
- `${PREFIX}-pagination__nav-button--enabled`,
3330
- !disabled
3331
- );
3139
+ const isLast = currentPage === totalPages;
3140
+ if (nextBtn) {
3141
+ const disabled = isDisabled || isLast;
3142
+ nextBtn.disabled = disabled;
3143
+ nextBtn.classList.toggle(
3144
+ `${PREFIX}-pagination__nav-button--disabled`,
3145
+ disabled
3146
+ );
3147
+ nextBtn.classList.toggle(
3148
+ `${PREFIX}-pagination__nav-button--enabled`,
3149
+ !disabled
3150
+ );
3332
3151
  }
3333
3152
  if (lastBtn) {
3334
3153
  const disabled = isDisabled || isLast;
@@ -3490,6 +3309,567 @@ var InaUI = (() => {
3490
3309
  });
3491
3310
  }
3492
3311
 
3312
+ // src/js/utils/countries.js
3313
+ var COUNTRIES = [
3314
+ { code: "ID", name: "Indonesia", dialCode: "+62" },
3315
+ { code: "AF", name: "Afghanistan", dialCode: "+93" },
3316
+ { code: "AL", name: "Albania", dialCode: "+355" },
3317
+ { code: "DZ", name: "Algeria", dialCode: "+213" },
3318
+ { code: "AS", name: "American Samoa", dialCode: "+1684" },
3319
+ { code: "AD", name: "Andorra", dialCode: "+376" },
3320
+ { code: "AO", name: "Angola", dialCode: "+244" },
3321
+ { code: "AI", name: "Anguilla", dialCode: "+1264" },
3322
+ { code: "AG", name: "Antigua and Barbuda", dialCode: "+1268" },
3323
+ { code: "AR", name: "Argentina", dialCode: "+54" },
3324
+ { code: "AM", name: "Armenia", dialCode: "+374" },
3325
+ { code: "AW", name: "Aruba", dialCode: "+297" },
3326
+ { code: "AU", name: "Australia", dialCode: "+61" },
3327
+ { code: "AT", name: "Austria", dialCode: "+43" },
3328
+ { code: "AZ", name: "Azerbaijan", dialCode: "+994" },
3329
+ { code: "BS", name: "Bahamas", dialCode: "+1242" },
3330
+ { code: "BH", name: "Bahrain", dialCode: "+973" },
3331
+ { code: "BD", name: "Bangladesh", dialCode: "+880" },
3332
+ { code: "BB", name: "Barbados", dialCode: "+1246" },
3333
+ { code: "BY", name: "Belarus", dialCode: "+375" },
3334
+ { code: "BE", name: "Belgium", dialCode: "+32" },
3335
+ { code: "BZ", name: "Belize", dialCode: "+501" },
3336
+ { code: "BJ", name: "Benin", dialCode: "+229" },
3337
+ { code: "BM", name: "Bermuda", dialCode: "+1441" },
3338
+ { code: "BT", name: "Bhutan", dialCode: "+975" },
3339
+ { code: "BO", name: "Bolivia", dialCode: "+591" },
3340
+ { code: "BA", name: "Bosnia and Herzegovina", dialCode: "+387" },
3341
+ { code: "BW", name: "Botswana", dialCode: "+267" },
3342
+ { code: "BR", name: "Brazil", dialCode: "+55" },
3343
+ { code: "IO", name: "British Indian Ocean Territory", dialCode: "+246" },
3344
+ { code: "BN", name: "Brunei Darussalam", dialCode: "+673" },
3345
+ { code: "BG", name: "Bulgaria", dialCode: "+359" },
3346
+ { code: "BF", name: "Burkina Faso", dialCode: "+226" },
3347
+ { code: "BI", name: "Burundi", dialCode: "+257" },
3348
+ { code: "KH", name: "Cambodia", dialCode: "+855" },
3349
+ { code: "CM", name: "Cameroon", dialCode: "+237" },
3350
+ { code: "CA", name: "Canada", dialCode: "+1" },
3351
+ { code: "CV", name: "Cape Verde", dialCode: "+238" },
3352
+ { code: "KY", name: "Cayman Islands", dialCode: "+1345" },
3353
+ { code: "CF", name: "Central African Republic", dialCode: "+236" },
3354
+ { code: "TD", name: "Chad", dialCode: "+235" },
3355
+ { code: "CL", name: "Chile", dialCode: "+56" },
3356
+ { code: "CN", name: "China", dialCode: "+86" },
3357
+ { code: "CX", name: "Christmas Island", dialCode: "+61" },
3358
+ { code: "CC", name: "Cocos (Keeling) Islands", dialCode: "+61" },
3359
+ { code: "CO", name: "Colombia", dialCode: "+57" },
3360
+ { code: "KM", name: "Comoros", dialCode: "+269" },
3361
+ { code: "CG", name: "Congo", dialCode: "+242" },
3362
+ { code: "CD", name: "Congo, Democratic Republic of the", dialCode: "+243" },
3363
+ { code: "CK", name: "Cook Islands", dialCode: "+682" },
3364
+ { code: "CR", name: "Costa Rica", dialCode: "+506" },
3365
+ { code: "CI", name: "Cote d'Ivoire", dialCode: "+225" },
3366
+ { code: "HR", name: "Croatia", dialCode: "+385" },
3367
+ { code: "CU", name: "Cuba", dialCode: "+53" },
3368
+ { code: "CY", name: "Cyprus", dialCode: "+357" },
3369
+ { code: "CZ", name: "Czech Republic", dialCode: "+420" },
3370
+ { code: "DK", name: "Denmark", dialCode: "+45" },
3371
+ { code: "DJ", name: "Djibouti", dialCode: "+253" },
3372
+ { code: "DM", name: "Dominica", dialCode: "+1767" },
3373
+ { code: "DO", name: "Dominican Republic", dialCode: "+1" },
3374
+ { code: "EC", name: "Ecuador", dialCode: "+593" },
3375
+ { code: "EG", name: "Egypt", dialCode: "+20" },
3376
+ { code: "SV", name: "El Salvador", dialCode: "+503" },
3377
+ { code: "GQ", name: "Equatorial Guinea", dialCode: "+240" },
3378
+ { code: "ER", name: "Eritrea", dialCode: "+291" },
3379
+ { code: "EE", name: "Estonia", dialCode: "+372" },
3380
+ { code: "ET", name: "Ethiopia", dialCode: "+251" },
3381
+ { code: "FK", name: "Falkland Islands (Malvinas)", dialCode: "+500" },
3382
+ { code: "FO", name: "Faroe Islands", dialCode: "+298" },
3383
+ { code: "FJ", name: "Fiji", dialCode: "+679" },
3384
+ { code: "FI", name: "Finland", dialCode: "+358" },
3385
+ { code: "FR", name: "France", dialCode: "+33" },
3386
+ { code: "GF", name: "French Guiana", dialCode: "+594" },
3387
+ { code: "PF", name: "French Polynesia", dialCode: "+689" },
3388
+ { code: "GA", name: "Gabon", dialCode: "+241" },
3389
+ { code: "GM", name: "Gambia", dialCode: "+220" },
3390
+ { code: "GE", name: "Georgia", dialCode: "+995" },
3391
+ { code: "DE", name: "Germany", dialCode: "+49" },
3392
+ { code: "GH", name: "Ghana", dialCode: "+233" },
3393
+ { code: "GI", name: "Gibraltar", dialCode: "+350" },
3394
+ { code: "GR", name: "Greece", dialCode: "+30" },
3395
+ { code: "GL", name: "Greenland", dialCode: "+299" },
3396
+ { code: "GD", name: "Grenada", dialCode: "+1473" },
3397
+ { code: "GP", name: "Guadeloupe", dialCode: "+590" },
3398
+ { code: "GU", name: "Guam", dialCode: "+1671" },
3399
+ { code: "GT", name: "Guatemala", dialCode: "+502" },
3400
+ { code: "GG", name: "Guernsey", dialCode: "+44" },
3401
+ { code: "GN", name: "Guinea", dialCode: "+224" },
3402
+ { code: "GW", name: "Guinea-Bissau", dialCode: "+245" },
3403
+ { code: "GY", name: "Guyana", dialCode: "+592" },
3404
+ { code: "HT", name: "Haiti", dialCode: "+509" },
3405
+ { code: "VA", name: "Holy See (Vatican City State)", dialCode: "+379" },
3406
+ { code: "HN", name: "Honduras", dialCode: "+504" },
3407
+ { code: "HK", name: "Hong Kong", dialCode: "+852" },
3408
+ { code: "HU", name: "Hungary", dialCode: "+36" },
3409
+ { code: "IS", name: "Iceland", dialCode: "+354" },
3410
+ { code: "IN", name: "India", dialCode: "+91" },
3411
+ { code: "IR", name: "Iran, Islamic Republic of", dialCode: "+98" },
3412
+ { code: "IQ", name: "Iraq", dialCode: "+964" },
3413
+ { code: "IE", name: "Ireland", dialCode: "+353" },
3414
+ { code: "IM", name: "Isle of Man", dialCode: "+44" },
3415
+ { code: "IL", name: "Israel", dialCode: "+972" },
3416
+ { code: "IT", name: "Italy", dialCode: "+39" },
3417
+ { code: "JM", name: "Jamaica", dialCode: "+1876" },
3418
+ { code: "JP", name: "Japan", dialCode: "+81" },
3419
+ { code: "JE", name: "Jersey", dialCode: "+44" },
3420
+ { code: "JO", name: "Jordan", dialCode: "+962" },
3421
+ { code: "KZ", name: "Kazakhstan", dialCode: "+7" },
3422
+ { code: "KE", name: "Kenya", dialCode: "+254" },
3423
+ { code: "KI", name: "Kiribati", dialCode: "+686" },
3424
+ { code: "KP", name: "Korea, Democratic People's Republic of", dialCode: "+850" },
3425
+ { code: "KR", name: "Korea, Republic of", dialCode: "+82" },
3426
+ { code: "KW", name: "Kuwait", dialCode: "+965" },
3427
+ { code: "KG", name: "Kyrgyzstan", dialCode: "+996" },
3428
+ { code: "LA", name: "Laos", dialCode: "+856" },
3429
+ { code: "LV", name: "Latvia", dialCode: "+371" },
3430
+ { code: "LB", name: "Lebanon", dialCode: "+961" },
3431
+ { code: "LS", name: "Lesotho", dialCode: "+266" },
3432
+ { code: "LR", name: "Liberia", dialCode: "+231" },
3433
+ { code: "LY", name: "Libyan Arab Jamahiriya", dialCode: "+218" },
3434
+ { code: "LI", name: "Liechtenstein", dialCode: "+423" },
3435
+ { code: "LT", name: "Lithuania", dialCode: "+370" },
3436
+ { code: "LU", name: "Luxembourg", dialCode: "+352" },
3437
+ { code: "MO", name: "Macao", dialCode: "+853" },
3438
+ { code: "MK", name: "Macedonia, the Former Yugoslav Republic of", dialCode: "+389" },
3439
+ { code: "MG", name: "Madagascar", dialCode: "+261" },
3440
+ { code: "MW", name: "Malawi", dialCode: "+265" },
3441
+ { code: "MY", name: "Malaysia", dialCode: "+60" },
3442
+ { code: "MV", name: "Maldives", dialCode: "+960" },
3443
+ { code: "ML", name: "Mali", dialCode: "+223" },
3444
+ { code: "MT", name: "Malta", dialCode: "+356" },
3445
+ { code: "MH", name: "Marshall Islands", dialCode: "+692" },
3446
+ { code: "MQ", name: "Martinique", dialCode: "+596" },
3447
+ { code: "MR", name: "Mauritania", dialCode: "+222" },
3448
+ { code: "MU", name: "Mauritius", dialCode: "+230" },
3449
+ { code: "YT", name: "Mayotte", dialCode: "+262" },
3450
+ { code: "MX", name: "Mexico", dialCode: "+52" },
3451
+ { code: "FM", name: "Micronesia, Federated States of", dialCode: "+691" },
3452
+ { code: "MD", name: "Moldova, Republic of", dialCode: "+373" },
3453
+ { code: "MC", name: "Monaco", dialCode: "+377" },
3454
+ { code: "MN", name: "Mongolia", dialCode: "+976" },
3455
+ { code: "ME", name: "Montenegro", dialCode: "+382" },
3456
+ { code: "MS", name: "Montserrat", dialCode: "+1664" },
3457
+ { code: "MA", name: "Morocco", dialCode: "+212" },
3458
+ { code: "MZ", name: "Mozambique", dialCode: "+258" },
3459
+ { code: "MM", name: "Myanmar", dialCode: "+95" },
3460
+ { code: "NA", name: "Namibia", dialCode: "+264" },
3461
+ { code: "NR", name: "Nauru", dialCode: "+674" },
3462
+ { code: "NP", name: "Nepal", dialCode: "+977" },
3463
+ { code: "NL", name: "Netherlands", dialCode: "+31" },
3464
+ { code: "NC", name: "New Caledonia", dialCode: "+687" },
3465
+ { code: "NZ", name: "New Zealand", dialCode: "+64" },
3466
+ { code: "NI", name: "Nicaragua", dialCode: "+505" },
3467
+ { code: "NE", name: "Niger", dialCode: "+227" },
3468
+ { code: "NG", name: "Nigeria", dialCode: "+234" },
3469
+ { code: "NU", name: "Niue", dialCode: "+683" },
3470
+ { code: "NF", name: "Norfolk Island", dialCode: "+672" },
3471
+ { code: "MP", name: "Northern Mariana Islands", dialCode: "+1670" },
3472
+ { code: "NO", name: "Norway", dialCode: "+47" },
3473
+ { code: "OM", name: "Oman", dialCode: "+968" },
3474
+ { code: "PK", name: "Pakistan", dialCode: "+92" },
3475
+ { code: "PW", name: "Palau", dialCode: "+680" },
3476
+ { code: "PS", name: "Palestine", dialCode: "+970" },
3477
+ { code: "PA", name: "Panama", dialCode: "+507" },
3478
+ { code: "PG", name: "Papua New Guinea", dialCode: "+675" },
3479
+ { code: "PY", name: "Paraguay", dialCode: "+595" },
3480
+ { code: "PE", name: "Peru", dialCode: "+51" },
3481
+ { code: "PH", name: "Philippines", dialCode: "+63" },
3482
+ { code: "PN", name: "Pitcairn", dialCode: "+870" },
3483
+ { code: "PL", name: "Poland", dialCode: "+48" },
3484
+ { code: "PT", name: "Portugal", dialCode: "+351" },
3485
+ { code: "PR", name: "Puerto Rico", dialCode: "+1939" },
3486
+ { code: "QA", name: "Qatar", dialCode: "+974" },
3487
+ { code: "RE", name: "Reunion", dialCode: "+262" },
3488
+ { code: "RO", name: "Romania", dialCode: "+40" },
3489
+ { code: "RU", name: "Russian Federation", dialCode: "+7" },
3490
+ { code: "RW", name: "Rwanda", dialCode: "+250" },
3491
+ { code: "BL", name: "Saint Barthelemy", dialCode: "+590" },
3492
+ { code: "SH", name: "Saint Helena", dialCode: "+290" },
3493
+ { code: "KN", name: "Saint Kitts and Nevis", dialCode: "+1869" },
3494
+ { code: "LC", name: "Saint Lucia", dialCode: "+1758" },
3495
+ { code: "MF", name: "Saint Martin", dialCode: "+590" },
3496
+ { code: "PM", name: "Saint Pierre and Miquelon", dialCode: "+508" },
3497
+ { code: "VC", name: "Saint Vincent and the Grenadines", dialCode: "+1784" },
3498
+ { code: "WS", name: "Samoa", dialCode: "+685" },
3499
+ { code: "SM", name: "San Marino", dialCode: "+378" },
3500
+ { code: "ST", name: "Sao Tome and Principe", dialCode: "+239" },
3501
+ { code: "SA", name: "Saudi Arabia", dialCode: "+966" },
3502
+ { code: "SN", name: "Senegal", dialCode: "+221" },
3503
+ { code: "RS", name: "Serbia", dialCode: "+381" },
3504
+ { code: "SC", name: "Seychelles", dialCode: "+248" },
3505
+ { code: "SL", name: "Sierra Leone", dialCode: "+232" },
3506
+ { code: "SG", name: "Singapore", dialCode: "+65" },
3507
+ { code: "SK", name: "Slovakia", dialCode: "+421" },
3508
+ { code: "SI", name: "Slovenia", dialCode: "+386" },
3509
+ { code: "SB", name: "Solomon Islands", dialCode: "+677" },
3510
+ { code: "SO", name: "Somalia", dialCode: "+252" },
3511
+ { code: "ZA", name: "South Africa", dialCode: "+27" },
3512
+ { code: "GS", name: "South Georgia and the South Sandwich Islands", dialCode: "+500" },
3513
+ { code: "ES", name: "Spain", dialCode: "+34" },
3514
+ { code: "LK", name: "Sri Lanka", dialCode: "+94" },
3515
+ { code: "SD", name: "Sudan", dialCode: "+249" },
3516
+ { code: "SR", name: "Suriname", dialCode: "+597" },
3517
+ { code: "SJ", name: "Svalbard and Jan Mayen", dialCode: "+47" },
3518
+ { code: "SZ", name: "Swaziland", dialCode: "+268" },
3519
+ { code: "SE", name: "Sweden", dialCode: "+46" },
3520
+ { code: "CH", name: "Switzerland", dialCode: "+41" },
3521
+ { code: "SY", name: "Syrian Arab Republic", dialCode: "+963" },
3522
+ { code: "TW", name: "Taiwan, Province of China", dialCode: "+886" },
3523
+ { code: "TJ", name: "Tajikistan", dialCode: "+992" },
3524
+ { code: "TZ", name: "Tanzania, United Republic of", dialCode: "+255" },
3525
+ { code: "TH", name: "Thailand", dialCode: "+66" },
3526
+ { code: "TL", name: "Timor-Leste", dialCode: "+670" },
3527
+ { code: "TG", name: "Togo", dialCode: "+228" },
3528
+ { code: "TK", name: "Tokelau", dialCode: "+690" },
3529
+ { code: "TO", name: "Tonga", dialCode: "+676" },
3530
+ { code: "TT", name: "Trinidad and Tobago", dialCode: "+1868" },
3531
+ { code: "TN", name: "Tunisia", dialCode: "+216" },
3532
+ { code: "TR", name: "Turkey", dialCode: "+90" },
3533
+ { code: "TM", name: "Turkmenistan", dialCode: "+993" },
3534
+ { code: "TC", name: "Turks and Caicos Islands", dialCode: "+1649" },
3535
+ { code: "TV", name: "Tuvalu", dialCode: "+688" },
3536
+ { code: "UG", name: "Uganda", dialCode: "+256" },
3537
+ { code: "UA", name: "Ukraine", dialCode: "+380" },
3538
+ { code: "AE", name: "United Arab Emirates", dialCode: "+971" },
3539
+ { code: "GB", name: "United Kingdom", dialCode: "+44" },
3540
+ { code: "US", name: "United States", dialCode: "+1" },
3541
+ { code: "UY", name: "Uruguay", dialCode: "+598" },
3542
+ { code: "UZ", name: "Uzbekistan", dialCode: "+998" },
3543
+ { code: "VU", name: "Vanuatu", dialCode: "+678" },
3544
+ { code: "VE", name: "Venezuela", dialCode: "+58" },
3545
+ { code: "VN", name: "Vietnam", dialCode: "+84" },
3546
+ { code: "VG", name: "Virgin Islands, British", dialCode: "+1284" },
3547
+ { code: "VI", name: "Virgin Islands, U.S.", dialCode: "+1340" },
3548
+ { code: "WF", name: "Wallis and Futuna", dialCode: "+681" },
3549
+ { code: "EH", name: "Western Sahara", dialCode: "+212" },
3550
+ { code: "YE", name: "Yemen", dialCode: "+967" },
3551
+ { code: "ZM", name: "Zambia", dialCode: "+260" },
3552
+ { code: "ZW", name: "Zimbabwe", dialCode: "+263" }
3553
+ ];
3554
+
3555
+ // src/js/utils/flags.js
3556
+ var flagCache = {};
3557
+ var getFlag = async (code) => {
3558
+ if (flagCache[code]) {
3559
+ return flagCache[code];
3560
+ }
3561
+ try {
3562
+ const flag = await import(`@idds/styles/assets/flags/${code.toLowerCase()}.svg`);
3563
+ flagCache[code] = flag.default;
3564
+ return flag.default;
3565
+ } catch (error) {
3566
+ console.error(`[IDDS PhoneInput] Failed to load flag for: ${code}`, error);
3567
+ return "";
3568
+ }
3569
+ };
3570
+
3571
+ // src/js/components/stateful/phone-input.js
3572
+ var PhoneInput = class {
3573
+ constructor(selectorOrElement, options = {}) {
3574
+ this.container = typeof selectorOrElement === "string" ? document.querySelector(selectorOrElement) : selectorOrElement;
3575
+ if (!this.container) {
3576
+ console.warn("[IDDS PhoneInput] Container not found:", selectorOrElement);
3577
+ return;
3578
+ }
3579
+ if (this.container.dataset.initialized === "true") {
3580
+ return;
3581
+ }
3582
+ this.container.dataset.initialized = "true";
3583
+ this.options = {
3584
+ modelValue: this.container.dataset.value || "",
3585
+ label: this.container.dataset.label || "",
3586
+ placeholder: this.container.getAttribute("placeholder") || "812-3456-7890",
3587
+ size: this.container.dataset.size || "md",
3588
+ status: this.container.dataset.status || "neutral",
3589
+ disabled: this.container.hasAttribute("disabled") || false,
3590
+ readonly: this.container.hasAttribute("readonly") || false,
3591
+ required: this.container.hasAttribute("required") || false,
3592
+ defaultCountry: this.container.dataset.defaultCountry || "ID",
3593
+ allowClear: this.container.dataset.allowClear !== "false",
3594
+ countries: COUNTRIES,
3595
+ onChange: null,
3596
+ ...options
3597
+ };
3598
+ this.state = {
3599
+ isOpen: false,
3600
+ countrySearch: "",
3601
+ selectedCountry: this.options.countries.find((c) => c.code === this.options.defaultCountry) || this.options.countries[0],
3602
+ phoneNumber: ""
3603
+ };
3604
+ this.elements = {};
3605
+ this.inputId = `phone-input-${Math.random().toString(36).substr(2, 9)}`;
3606
+ this.init();
3607
+ }
3608
+ async init() {
3609
+ this.initDOM();
3610
+ this.initEvents();
3611
+ this.syncValueFromOptions();
3612
+ await this.updateFlag();
3613
+ }
3614
+ initDOM() {
3615
+ if (this.options.label) {
3616
+ const label = document.createElement("label");
3617
+ label.className = `${PREFIX}-phone-input__label`;
3618
+ label.setAttribute("for", this.inputId);
3619
+ label.textContent = this.options.label;
3620
+ if (this.options.required) {
3621
+ const asterisk = document.createElement("span");
3622
+ asterisk.className = `${PREFIX}-phone-input__required`;
3623
+ asterisk.textContent = "*";
3624
+ label.appendChild(asterisk);
3625
+ }
3626
+ this.container.appendChild(label);
3627
+ }
3628
+ const wrapper = document.createElement("div");
3629
+ wrapper.className = `${PREFIX}-phone-input__wrapper ${PREFIX}-phone-input__wrapper--size-${this.options.size}`;
3630
+ if (this.options.status !== "neutral") {
3631
+ wrapper.classList.add(`${PREFIX}-phone-input__wrapper--status-${this.options.status}`);
3632
+ }
3633
+ if (this.options.disabled) {
3634
+ wrapper.classList.add(`${PREFIX}-phone-input__wrapper--disabled`);
3635
+ }
3636
+ const selector = document.createElement("div");
3637
+ selector.className = `${PREFIX}-phone-input__country-selector`;
3638
+ const countryBtn = document.createElement("button");
3639
+ countryBtn.type = "button";
3640
+ countryBtn.className = `${PREFIX}-phone-input__country-button`;
3641
+ countryBtn.setAttribute("aria-label", "Pilih negara");
3642
+ countryBtn.setAttribute("aria-haspopup", "listbox");
3643
+ countryBtn.setAttribute("aria-expanded", "false");
3644
+ if (this.options.disabled || this.options.readonly) countryBtn.disabled = true;
3645
+ const flagImg = document.createElement("img");
3646
+ flagImg.className = `${PREFIX}-phone-input__country-flag-img`;
3647
+ flagImg.width = 24;
3648
+ flagImg.height = 18;
3649
+ flagImg.alt = "";
3650
+ const dialCode = document.createElement("span");
3651
+ dialCode.className = `${PREFIX}-phone-input__country-code`;
3652
+ dialCode.textContent = this.state.selectedCountry.dialCode;
3653
+ const chevron = document.createElement("div");
3654
+ chevron.innerHTML = `<svg class="${PREFIX}-phone-input__country-chevron" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
3655
+ <path d="M6 9L12 15L18 9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3656
+ </svg>`;
3657
+ countryBtn.appendChild(flagImg);
3658
+ countryBtn.appendChild(dialCode);
3659
+ countryBtn.appendChild(chevron.firstChild);
3660
+ selector.appendChild(countryBtn);
3661
+ wrapper.appendChild(selector);
3662
+ const divider = document.createElement("div");
3663
+ divider.className = `${PREFIX}-phone-input__divider`;
3664
+ wrapper.appendChild(divider);
3665
+ const input = document.createElement("input");
3666
+ input.type = "tel";
3667
+ input.id = this.inputId;
3668
+ input.placeholder = this.options.placeholder;
3669
+ input.className = `${PREFIX}-phone-input__input`;
3670
+ if (this.options.disabled) input.disabled = true;
3671
+ if (this.options.readonly) input.readOnly = true;
3672
+ wrapper.appendChild(input);
3673
+ if (this.options.allowClear) {
3674
+ const clearBtn = document.createElement("button");
3675
+ clearBtn.type = "button";
3676
+ clearBtn.className = `${PREFIX}-phone-input__clear-button`;
3677
+ clearBtn.setAttribute("aria-label", "Hapus nomor telepon");
3678
+ clearBtn.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
3679
+ <line x1="18" y1="6" x2="6" y2="18"></line>
3680
+ <line x1="6" y1="6" x2="18" y2="18"></line>
3681
+ </svg>`;
3682
+ clearBtn.style.display = "none";
3683
+ wrapper.appendChild(clearBtn);
3684
+ this.elements.clearBtn = clearBtn;
3685
+ }
3686
+ this.container.appendChild(wrapper);
3687
+ const panel = document.createElement("div");
3688
+ panel.className = `${PREFIX}-phone-input__country-dropdown`;
3689
+ panel.style.display = "none";
3690
+ const searchDiv = document.createElement("div");
3691
+ searchDiv.className = `${PREFIX}-phone-input__country-search`;
3692
+ const searchInput = document.createElement("input");
3693
+ searchInput.type = "text";
3694
+ searchInput.placeholder = "Cari";
3695
+ searchInput.className = `${PREFIX}-phone-input__country-search-input`;
3696
+ searchDiv.appendChild(searchInput);
3697
+ panel.appendChild(searchDiv);
3698
+ const list = document.createElement("div");
3699
+ list.className = `${PREFIX}-phone-input__country-list`;
3700
+ list.setAttribute("role", "listbox");
3701
+ panel.appendChild(list);
3702
+ selector.appendChild(panel);
3703
+ this.elements.wrapper = wrapper;
3704
+ this.elements.countryBtn = countryBtn;
3705
+ this.elements.flagImg = flagImg;
3706
+ this.elements.dialCode = dialCode;
3707
+ this.elements.input = input;
3708
+ this.elements.panel = panel;
3709
+ this.elements.searchInput = searchInput;
3710
+ this.elements.list = list;
3711
+ this.elements.chevron = selector.querySelector(`.${PREFIX}-phone-input__country-chevron`);
3712
+ }
3713
+ initEvents() {
3714
+ this.elements.countryBtn.addEventListener("click", (e) => {
3715
+ e.stopPropagation();
3716
+ this.toggleDropdown();
3717
+ });
3718
+ this.elements.searchInput.addEventListener("input", (e) => {
3719
+ this.state.countrySearch = e.target.value;
3720
+ this.renderCountryList();
3721
+ });
3722
+ this.elements.input.addEventListener("input", (e) => {
3723
+ this.handleInput(e);
3724
+ });
3725
+ if (this.elements.clearBtn) {
3726
+ this.elements.clearBtn.addEventListener("click", () => {
3727
+ this.clear();
3728
+ });
3729
+ }
3730
+ document.addEventListener("click", (e) => {
3731
+ if (!this.elements.wrapper.contains(e.target)) {
3732
+ this.closeDropdown();
3733
+ }
3734
+ });
3735
+ }
3736
+ async updateFlag() {
3737
+ const url = await getFlag(this.state.selectedCountry.code);
3738
+ this.elements.flagImg.src = url;
3739
+ this.elements.flagImg.alt = this.state.selectedCountry.name;
3740
+ this.elements.dialCode.textContent = this.state.selectedCountry.dialCode;
3741
+ }
3742
+ toggleDropdown() {
3743
+ if (this.state.isOpen) {
3744
+ this.closeDropdown();
3745
+ } else {
3746
+ this.openDropdown();
3747
+ }
3748
+ }
3749
+ openDropdown() {
3750
+ this.state.isOpen = true;
3751
+ this.elements.panel.style.display = "flex";
3752
+ this.elements.countryBtn.setAttribute("aria-expanded", "true");
3753
+ this.elements.chevron.classList.add(`${PREFIX}-phone-input__country-chevron--open`);
3754
+ this.state.countrySearch = "";
3755
+ this.elements.searchInput.value = "";
3756
+ this.renderCountryList();
3757
+ setTimeout(() => this.elements.searchInput.focus(), 0);
3758
+ }
3759
+ closeDropdown() {
3760
+ this.state.isOpen = false;
3761
+ this.elements.panel.style.display = "none";
3762
+ this.elements.countryBtn.setAttribute("aria-expanded", "false");
3763
+ this.elements.chevron.classList.remove(`${PREFIX}-phone-input__country-chevron--open`);
3764
+ }
3765
+ renderCountryList() {
3766
+ const list = this.elements.list;
3767
+ list.innerHTML = "";
3768
+ const filtered = this.options.countries.filter(
3769
+ (c) => c.name.toLowerCase().includes(this.state.countrySearch.toLowerCase()) || c.dialCode.includes(this.state.countrySearch) || c.code.toLowerCase().includes(this.state.countrySearch.toLowerCase())
3770
+ );
3771
+ filtered.forEach(async (country) => {
3772
+ const option = document.createElement("button");
3773
+ option.type = "button";
3774
+ option.className = `${PREFIX}-phone-input__country-option`;
3775
+ if (country.code === this.state.selectedCountry.code) {
3776
+ option.classList.add(`${PREFIX}-phone-input__country-option--selected`);
3777
+ }
3778
+ option.setAttribute("role", "option");
3779
+ option.setAttribute("aria-selected", country.code === this.state.selectedCountry.code ? "true" : "false");
3780
+ const flag = document.createElement("img");
3781
+ flag.className = `${PREFIX}-phone-input__country-flag-img`;
3782
+ flag.width = 20;
3783
+ flag.height = 15;
3784
+ getFlag(country.code).then((url) => flag.src = url);
3785
+ const name = document.createElement("span");
3786
+ name.className = `${PREFIX}-phone-input__country-name`;
3787
+ name.textContent = `${country.name} (${country.code})`;
3788
+ const code = document.createElement("span");
3789
+ code.className = `${PREFIX}-phone-input__country-dial-code`;
3790
+ code.textContent = country.dialCode;
3791
+ option.appendChild(flag);
3792
+ option.appendChild(name);
3793
+ option.appendChild(code);
3794
+ option.addEventListener("click", () => {
3795
+ this.selectCountry(country);
3796
+ });
3797
+ list.appendChild(option);
3798
+ });
3799
+ }
3800
+ selectCountry(country) {
3801
+ this.state.selectedCountry = country;
3802
+ this.updateFlag();
3803
+ this.closeDropdown();
3804
+ this.elements.input.focus();
3805
+ this.triggerChange();
3806
+ }
3807
+ formatPhoneNumber(value) {
3808
+ const clean = value.replace(/\D/g, "");
3809
+ if (clean.length > 7) {
3810
+ return clean.replace(/^(\d{3})(\d{4})(.*)/, "$1-$2-$3");
3811
+ } else if (clean.length > 3) {
3812
+ return clean.replace(/^(\d{3})(.*)/, "$1-$2");
3813
+ }
3814
+ return clean;
3815
+ }
3816
+ handleInput(e) {
3817
+ const value = e.target.value;
3818
+ const formatted = this.formatPhoneNumber(value);
3819
+ e.target.value = formatted;
3820
+ this.state.phoneNumber = formatted;
3821
+ if (this.elements.clearBtn) {
3822
+ this.elements.clearBtn.style.display = formatted ? "flex" : "none";
3823
+ }
3824
+ this.triggerChange();
3825
+ }
3826
+ clear() {
3827
+ this.state.phoneNumber = "";
3828
+ this.elements.input.value = "";
3829
+ if (this.elements.clearBtn) {
3830
+ this.elements.clearBtn.style.display = "none";
3831
+ }
3832
+ this.elements.input.focus();
3833
+ this.triggerChange();
3834
+ }
3835
+ syncValueFromOptions() {
3836
+ if (this.options.modelValue) {
3837
+ let val = this.options.modelValue;
3838
+ const dial = this.state.selectedCountry.dialCode;
3839
+ if (val.startsWith(dial)) {
3840
+ val = val.substring(dial.length);
3841
+ }
3842
+ this.state.phoneNumber = this.formatPhoneNumber(val);
3843
+ this.elements.input.value = this.state.phoneNumber;
3844
+ if (this.elements.clearBtn && this.state.phoneNumber) {
3845
+ this.elements.clearBtn.style.display = "flex";
3846
+ }
3847
+ }
3848
+ }
3849
+ triggerChange() {
3850
+ const cleanLocal = this.state.phoneNumber.replace(/\D/g, "");
3851
+ const cleanNoZero = cleanLocal.startsWith("0") ? cleanLocal.substring(1) : cleanLocal;
3852
+ const fullValue = `${this.state.selectedCountry.dialCode}${cleanNoZero}`;
3853
+ if (this.options.onChange) {
3854
+ this.options.onChange(fullValue);
3855
+ }
3856
+ this.container.dispatchEvent(new CustomEvent("change", {
3857
+ detail: { value: fullValue, country: this.state.selectedCountry }
3858
+ }));
3859
+ }
3860
+ };
3861
+ function initPhoneInput(selectorOrElement, options = {}) {
3862
+ const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-phone-input`);
3863
+ const instances = [];
3864
+ elements.forEach((container) => {
3865
+ const instance = new PhoneInput(container, options);
3866
+ container.__phoneInputAPI = instance;
3867
+ instances.push(instance);
3868
+ });
3869
+ if (instances.length === 0) return null;
3870
+ return instances.length === 1 ? instances[0] : instances;
3871
+ }
3872
+
3493
3873
  // src/js/components/stateful/tab-vertical.js
3494
3874
  function initTabVertical() {
3495
3875
  const tabs = document.querySelectorAll(`.${PREFIX}-tab-vertical`);
@@ -3602,7 +3982,7 @@ var InaUI = (() => {
3602
3982
 
3603
3983
  // src/js/components/stateful/table.js
3604
3984
  var Table = class {
3605
- constructor(selectorOrElement, options2 = {}) {
3985
+ constructor(selectorOrElement, options = {}) {
3606
3986
  this.container = typeof selectorOrElement === "string" ? document.querySelector(selectorOrElement) : selectorOrElement;
3607
3987
  if (!this.container) {
3608
3988
  console.warn("[IDDS Table] Container not found:", selectorOrElement);
@@ -3634,7 +4014,7 @@ var InaUI = (() => {
3634
4014
  searchContainer: null,
3635
4015
  searchButton: null,
3636
4016
  onSearch: null,
3637
- ...options2
4017
+ ...options
3638
4018
  };
3639
4019
  this.state = {
3640
4020
  currentPage: this.options.initialPage,
@@ -3753,34 +4133,43 @@ var InaUI = (() => {
3753
4133
  if (col.sortable && col.accessor) {
3754
4134
  th.classList.add(`${PREFIX}-table__header-cell--sortable`);
3755
4135
  th.setAttribute("data-sort", col.accessor);
4136
+ let sortLabel = `Urutkan ${col.header}`;
4137
+ let currentSort = "none";
4138
+ if (this.state.sortField === field) {
4139
+ currentSort = this.state.sortOrder === "asc" ? "ascending" : "descending";
4140
+ }
4141
+ th.setAttribute("aria-sort", currentSort);
3756
4142
  let sortControlsHtml = `
3757
4143
  <div class="${PREFIX}-table__sort-controls">
3758
4144
  ${col.header}
3759
4145
  <div class="${PREFIX}-table__sort-icon">
3760
- <div class="${PREFIX}-table__sort-button" data-order="asc">
4146
+ <div class="${PREFIX}-table__sort-button" data-order="asc" role="button" aria-label="Urutkan ${col.header} menaik">
3761
4147
  <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 stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 5l0 14" /><path d="M16 9l-4 -4" /><path d="M8 9l4 -4" /></svg>
3762
4148
  </div>
3763
- <div class="${PREFIX}-table__sort-button ${PREFIX}-table__sort-button-right" data-order="desc">
4149
+ <div class="${PREFIX}-table__sort-button ${PREFIX}-table__sort-button-right" data-order="desc" role="button" aria-label="Urutkan ${col.header} menurun">
3764
4150
  <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 stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 5l0 14" /><path d="M16 15l-4 4" /><path d="M8 15l4 4" /></svg>
3765
4151
  </div>
3766
4152
  </div>
3767
4153
  </div>
3768
4154
  `;
3769
4155
  th.innerHTML = sortControlsHtml;
4156
+ const ascBtn = th.querySelector('[data-order="asc"]');
4157
+ const descBtn = th.querySelector('[data-order="desc"]');
4158
+ ascBtn.addEventListener("click", (e) => {
4159
+ e.stopPropagation();
4160
+ this.handleHeaderSort(col, "asc");
4161
+ });
4162
+ descBtn.addEventListener("click", (e) => {
4163
+ e.stopPropagation();
4164
+ this.handleHeaderSort(col, "desc");
4165
+ });
3770
4166
  th.addEventListener("click", () => {
3771
- const field = col.accessor;
4167
+ let nextOrder = "asc";
3772
4168
  if (this.state.sortField === field) {
3773
- if (this.state.sortOrder === "asc") this.state.sortOrder = "desc";
3774
- else {
3775
- this.state.sortField = null;
3776
- this.state.sortOrder = null;
3777
- }
3778
- } else {
3779
- this.state.sortField = field;
3780
- this.state.sortOrder = "asc";
4169
+ if (this.state.sortOrder === "asc") nextOrder = "desc";
4170
+ else nextOrder = null;
3781
4171
  }
3782
- this.state.currentPage = 1;
3783
- this.loadData();
4172
+ this.handleHeaderSort(col, nextOrder);
3784
4173
  });
3785
4174
  } else {
3786
4175
  th.textContent = col.header;
@@ -3839,7 +4228,7 @@ var InaUI = (() => {
3839
4228
  this.updateSelectAllState();
3840
4229
  return;
3841
4230
  }
3842
- rowData.forEach((row, index2) => {
4231
+ rowData.forEach((row, index) => {
3843
4232
  const tr = document.createElement("tr");
3844
4233
  tr.className = `${PREFIX}-table__row`;
3845
4234
  if (this.options.rowClickable) {
@@ -3850,11 +4239,11 @@ var InaUI = (() => {
3850
4239
  return;
3851
4240
  }
3852
4241
  if (typeof this.options.onRowClick === "function") {
3853
- this.options.onRowClick(row, index2);
4242
+ this.options.onRowClick(row, index);
3854
4243
  }
3855
4244
  });
3856
4245
  }
3857
- const rowKeyStr = String(row[this.options.rowKey] || index2);
4246
+ const rowKeyStr = String(row[this.options.rowKey] || index);
3858
4247
  if (this.options.selectable) {
3859
4248
  const td = document.createElement("td");
3860
4249
  td.className = `${PREFIX}-table__cell`;
@@ -3880,7 +4269,7 @@ var InaUI = (() => {
3880
4269
  const td = document.createElement("td");
3881
4270
  td.className = `${PREFIX}-table__cell`;
3882
4271
  if (typeof col.render === "function") {
3883
- const content = col.render(row, index2);
4272
+ const content = col.render(row, index);
3884
4273
  if (typeof content === "string") {
3885
4274
  td.innerHTML = content;
3886
4275
  } else if (content instanceof HTMLElement) {
@@ -4026,6 +4415,13 @@ var InaUI = (() => {
4026
4415
  }
4027
4416
  );
4028
4417
  }
4418
+ handleHeaderSort(col, order) {
4419
+ const field2 = col.accessor;
4420
+ this.state.sortField = field2 ? order === null ? null : field2 : null;
4421
+ this.state.sortOrder = order;
4422
+ this.state.currentPage = 1;
4423
+ this.loadData();
4424
+ }
4029
4425
  updateSortIndicators() {
4030
4426
  const btns = this.elements.theadTr.querySelectorAll(
4031
4427
  `.${PREFIX}-table__sort-button`
@@ -4033,10 +4429,15 @@ var InaUI = (() => {
4033
4429
  btns.forEach((btn) => {
4034
4430
  const th = btn.closest("th");
4035
4431
  if (!th) return;
4036
- const field = th.getAttribute("data-sort");
4432
+ const field2 = th.getAttribute("data-sort");
4037
4433
  const order = btn.getAttribute("data-order");
4038
- const active = this.state.sortField === field && this.state.sortOrder === order;
4434
+ const active = this.state.sortField === field2 && this.state.sortOrder === order;
4039
4435
  btn.classList.toggle(`${PREFIX}-table__sort-button--active`, active);
4436
+ let currentSort = "none";
4437
+ if (this.state.sortField === field2) {
4438
+ currentSort = this.state.sortOrder === "asc" ? "ascending" : "descending";
4439
+ }
4440
+ th.setAttribute("aria-sort", currentSort);
4040
4441
  });
4041
4442
  }
4042
4443
  async loadData() {
@@ -4114,8 +4515,8 @@ var InaUI = (() => {
4114
4515
  this.triggerSelectionChange();
4115
4516
  }
4116
4517
  toggleAllSelection(checked) {
4117
- this.state.currentData.forEach((row, index2) => {
4118
- const keyStr = String(row[this.options.rowKey] || index2);
4518
+ this.state.currentData.forEach((row, index) => {
4519
+ const keyStr = String(row[this.options.rowKey] || index);
4119
4520
  if (checked) {
4120
4521
  this.state.selectedKeys.add(keyStr);
4121
4522
  this.state.selectedRows.set(keyStr, row);
@@ -4196,11 +4597,11 @@ var InaUI = (() => {
4196
4597
  };
4197
4598
  }
4198
4599
  };
4199
- function initTable(selectorOrElement, options2 = {}) {
4600
+ function initTable(selectorOrElement, options = {}) {
4200
4601
  const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-table`);
4201
4602
  const instances = [];
4202
4603
  elements.forEach((container) => {
4203
- const instance = new Table(container, options2);
4604
+ const instance = new Table(container, options);
4204
4605
  container.__tableAPI = instance;
4205
4606
  instances.push(instance);
4206
4607
  });
@@ -4234,17 +4635,17 @@ var InaUI = (() => {
4234
4635
  const trigger = container.querySelector(`.${PREFIX}-month-picker__trigger`);
4235
4636
  const panel = container.querySelector(`.${PREFIX}-month-picker__panel`);
4236
4637
  const grid = container.querySelector(`.${PREFIX}-month-picker__grid`);
4237
- const options2 = grid ? Array.from(
4638
+ const options = grid ? Array.from(
4238
4639
  grid.querySelectorAll(`.${PREFIX}-month-picker__month-option`)
4239
4640
  ) : [];
4240
- if (!trigger || !panel || !grid || options2.length === 0) return;
4641
+ if (!trigger || !panel || !grid || options.length === 0) return;
4241
4642
  let isPickerOpen = false;
4242
4643
  const updateText = () => {
4243
4644
  const textEl = trigger.querySelector(
4244
4645
  `.${PREFIX}-month-picker__trigger-text`
4245
4646
  );
4246
4647
  if (textEl) textEl.textContent = MONTHS_SHORT_ID[currentMonthIdx];
4247
- options2.forEach((opt, idx) => {
4648
+ options.forEach((opt, idx) => {
4248
4649
  if (idx === currentMonthIdx) {
4249
4650
  opt.classList.add(`${PREFIX}-month-picker__month-option--selected`);
4250
4651
  opt.setAttribute("aria-selected", "true");
@@ -4265,7 +4666,7 @@ var InaUI = (() => {
4265
4666
  panel.classList.add(`${PREFIX}-month-picker__panel--open`);
4266
4667
  trigger.setAttribute("aria-expanded", "true");
4267
4668
  setTimeout(() => {
4268
- const selectedOpt = options2.find((o) => o.tabIndex === 0);
4669
+ const selectedOpt = options.find((o) => o.tabIndex === 0);
4269
4670
  if (selectedOpt) selectedOpt.focus();
4270
4671
  }, 0);
4271
4672
  } else {
@@ -4289,7 +4690,7 @@ var InaUI = (() => {
4289
4690
  document.addEventListener("click", (e) => {
4290
4691
  if (!container.contains(e.target)) togglePicker(false);
4291
4692
  });
4292
- options2.forEach((btn, idx) => {
4693
+ options.forEach((btn, idx) => {
4293
4694
  btn.setAttribute("role", "option");
4294
4695
  btn.addEventListener("click", (e) => {
4295
4696
  if (disabled || readonly) return;
@@ -4332,8 +4733,8 @@ var InaUI = (() => {
4332
4733
  else if (e.key === "ArrowDown")
4333
4734
  nextIndex += 3;
4334
4735
  else if (e.key === "ArrowUp") nextIndex -= 3;
4335
- if (options2[nextIndex]) {
4336
- options2[nextIndex].focus();
4736
+ if (options[nextIndex]) {
4737
+ options[nextIndex].focus();
4337
4738
  }
4338
4739
  }
4339
4740
  });
@@ -4434,12 +4835,12 @@ var InaUI = (() => {
4434
4835
  } else if (["ArrowRight", "ArrowLeft", "ArrowDown", "ArrowUp"].includes(e.key)) {
4435
4836
  e.preventDefault();
4436
4837
  e.stopPropagation();
4437
- const options2 = Array.from(
4838
+ const options = Array.from(
4438
4839
  grid.querySelectorAll(
4439
4840
  `.${PREFIX}-year-picker__year-option:not(:disabled)`
4440
4841
  )
4441
4842
  );
4442
- const currentIndex = options2.indexOf(btn);
4843
+ const currentIndex = options.indexOf(btn);
4443
4844
  if (currentIndex === -1) return;
4444
4845
  let nextIndex = currentIndex;
4445
4846
  if (e.key === "ArrowRight") nextIndex += 1;
@@ -4447,8 +4848,8 @@ var InaUI = (() => {
4447
4848
  else if (e.key === "ArrowDown")
4448
4849
  nextIndex += 4;
4449
4850
  else if (e.key === "ArrowUp") nextIndex -= 4;
4450
- if (options2[nextIndex]) {
4451
- options2[nextIndex].focus();
4851
+ if (options[nextIndex]) {
4852
+ options[nextIndex].focus();
4452
4853
  } else {
4453
4854
  }
4454
4855
  }
@@ -4575,7 +4976,7 @@ var InaUI = (() => {
4575
4976
  return { toastItem, toast };
4576
4977
  }
4577
4978
  function showToast(optionsOrMessage, variant = "default", duration = 5e3) {
4578
- const options2 = typeof optionsOrMessage === "string" ? {
4979
+ const options = typeof optionsOrMessage === "string" ? {
4579
4980
  message: optionsOrMessage,
4580
4981
  state: variant,
4581
4982
  duration
@@ -4588,7 +4989,7 @@ var InaUI = (() => {
4588
4989
  duration: autoCloseDuration = 5e3,
4589
4990
  position = "top-right",
4590
4991
  actionHtml = ""
4591
- } = options2;
4992
+ } = options;
4592
4993
  const container = getOrCreateContainer(position);
4593
4994
  const { toastItem, toast } = createToastElement({
4594
4995
  title,
@@ -4656,6 +5057,12 @@ var InaUI = (() => {
4656
5057
  const buttons = buttonGroup.querySelectorAll(
4657
5058
  `.${PREFIX}-button-group__button`
4658
5059
  );
5060
+ if (!buttonGroup.hasAttribute("role")) {
5061
+ buttonGroup.setAttribute("role", "group");
5062
+ }
5063
+ if (!buttonGroup.hasAttribute("aria-label")) {
5064
+ buttonGroup.setAttribute("aria-label", "Grup tombol");
5065
+ }
4659
5066
  const updateState = (clickedButton) => {
4660
5067
  const isDisabled = clickedButton.hasAttribute("disabled") || clickedButton.classList.contains(
4661
5068
  `${PREFIX}-button-group__button--disabled`
@@ -4679,7 +5086,7 @@ var InaUI = (() => {
4679
5086
  })
4680
5087
  );
4681
5088
  };
4682
- buttons.forEach((button, index2) => {
5089
+ buttons.forEach((button, index) => {
4683
5090
  button.addEventListener("click", (e) => {
4684
5091
  if (button.type !== "submit") {
4685
5092
  e.preventDefault();
@@ -4694,19 +5101,19 @@ var InaUI = (() => {
4694
5101
  updateState(button);
4695
5102
  } else if (e.key === "ArrowRight" || e.key === "ArrowDown") {
4696
5103
  e.preventDefault();
4697
- let nextIndex = (index2 + 1) % buttons.length;
5104
+ let nextIndex = (index + 1) % buttons.length;
4698
5105
  while ((buttons[nextIndex].hasAttribute("disabled") || buttons[nextIndex].classList.contains(
4699
5106
  `${PREFIX}-button-group__button--disabled`
4700
- )) && nextIndex !== index2) {
5107
+ )) && nextIndex !== index) {
4701
5108
  nextIndex = (nextIndex + 1) % buttons.length;
4702
5109
  }
4703
5110
  buttons[nextIndex]?.focus();
4704
5111
  } else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
4705
5112
  e.preventDefault();
4706
- let prevIndex = (index2 - 1 + buttons.length) % buttons.length;
5113
+ let prevIndex = (index - 1 + buttons.length) % buttons.length;
4707
5114
  while ((buttons[prevIndex].hasAttribute("disabled") || buttons[prevIndex].classList.contains(
4708
5115
  `${PREFIX}-button-group__button--disabled`
4709
- )) && prevIndex !== index2) {
5116
+ )) && prevIndex !== index) {
4710
5117
  prevIndex = (prevIndex - 1 + buttons.length) % buttons.length;
4711
5118
  }
4712
5119
  buttons[prevIndex]?.focus();
@@ -4726,8 +5133,8 @@ var InaUI = (() => {
4726
5133
  const menuItems = menu.querySelectorAll("li[role='option']");
4727
5134
  const menuId = menu.id;
4728
5135
  let activeIndex = -1;
4729
- menuItems.forEach((item, index2) => {
4730
- item.id = `${menuId}-item-${index2}`;
5136
+ menuItems.forEach((item, index) => {
5137
+ item.id = `${menuId}-item-${index}`;
4731
5138
  });
4732
5139
  const toggleMenu = (show) => {
4733
5140
  const isCurrentlyShown = dropdown.classList.contains("show");
@@ -4782,15 +5189,15 @@ var InaUI = (() => {
4782
5189
  }
4783
5190
  toggleMenu(false);
4784
5191
  };
4785
- const setHighlight = (index2) => {
5192
+ const setHighlight = (index) => {
4786
5193
  removeHighlight();
4787
5194
  const visibleItems = menu.querySelectorAll(
4788
5195
  "li[role='option']:not(.hidden)"
4789
5196
  );
4790
5197
  if (visibleItems.length === 0) return;
4791
- if (index2 < 0) index2 = 0;
4792
- else if (index2 >= visibleItems.length) index2 = visibleItems.length - 1;
4793
- const itemToHighlight = visibleItems[index2];
5198
+ if (index < 0) index = 0;
5199
+ else if (index >= visibleItems.length) index = visibleItems.length - 1;
5200
+ const itemToHighlight = visibleItems[index];
4794
5201
  if (itemToHighlight) {
4795
5202
  itemToHighlight.classList.add("highlighted");
4796
5203
  input.setAttribute("aria-activedescendant", itemToHighlight.id);
@@ -4798,7 +5205,7 @@ var InaUI = (() => {
4798
5205
  behavior: "smooth",
4799
5206
  block: "nearest"
4800
5207
  });
4801
- activeIndex = index2;
5208
+ activeIndex = index;
4802
5209
  }
4803
5210
  };
4804
5211
  const removeHighlight = () => {
@@ -4861,6 +5268,291 @@ var InaUI = (() => {
4861
5268
  });
4862
5269
  }
4863
5270
 
5271
+ // src/js/components/stateful/chip.js
5272
+ var PREFIX4 = "ina";
5273
+ function initChip2(rootSelector = `.${PREFIX4}-chip`) {
5274
+ const chips = document.querySelectorAll(rootSelector);
5275
+ chips.forEach((container) => {
5276
+ if (container.__inaChipInitialized) return;
5277
+ const showCustomization = container.getAttribute("data-show-customization") === "true";
5278
+ const customizationLabel = container.getAttribute("data-customization-label") || "Kustomisasi";
5279
+ const isMultiple = container.getAttribute("data-multiple") === "true";
5280
+ let selectedValue = container.getAttribute("data-selected") || "";
5281
+ const list = container.querySelector(`.${PREFIX4}-chip__list`);
5282
+ const items = list ? list.querySelectorAll(`.${PREFIX4}-chip__item`) : [];
5283
+ let customFieldContainer = container.querySelector(
5284
+ `.${PREFIX4}-chip__custom-field`
5285
+ );
5286
+ const getNormalizedSelected = () => {
5287
+ if (!selectedValue) return [];
5288
+ return isMultiple ? selectedValue.split(",").map((s) => s.trim()).filter(Boolean) : [selectedValue];
5289
+ };
5290
+ const updateUI = () => {
5291
+ const normSelected = getNormalizedSelected();
5292
+ const getInitialFocusIndex = () => {
5293
+ if (normSelected.length > 0) {
5294
+ const standardValues = Array.from(items).filter((item) => item.textContent.trim() !== customizationLabel).map((item) => item.getAttribute("data-value"));
5295
+ const hasCustomVal = normSelected.some(
5296
+ (val) => !standardValues.includes(val) && val !== ""
5297
+ );
5298
+ if (hasCustomVal && showCustomization) {
5299
+ return items.length - 1;
5300
+ }
5301
+ const firstSelectedIndex = Array.from(items).findIndex(
5302
+ (opt) => normSelected.includes(opt.getAttribute("data-value"))
5303
+ );
5304
+ if (firstSelectedIndex !== -1) return firstSelectedIndex;
5305
+ }
5306
+ return 0;
5307
+ };
5308
+ const focusedIndex = getInitialFocusIndex();
5309
+ items.forEach((item, index) => {
5310
+ const itemValue = item.getAttribute("data-value");
5311
+ const isSelected = normSelected.includes(itemValue) || showCustomization && item.textContent.trim() === customizationLabel && normSelected.some(
5312
+ (val) => !Array.from(items).filter((i) => i.textContent.trim() !== customizationLabel).map((i) => i.getAttribute("data-value")).includes(val) && val !== ""
5313
+ );
5314
+ const isDisabled = item.hasAttribute("disabled");
5315
+ if (isSelected) {
5316
+ item.classList.add(`${PREFIX4}-chip__item--selected`);
5317
+ } else {
5318
+ item.classList.remove(`${PREFIX4}-chip__item--selected`);
5319
+ }
5320
+ if (isDisabled) {
5321
+ item.classList.add(`${PREFIX4}-chip__item--disabled`);
5322
+ }
5323
+ if (!item.hasAttribute("role")) {
5324
+ item.setAttribute("role", "option");
5325
+ }
5326
+ item.setAttribute("aria-selected", isSelected);
5327
+ item.setAttribute(
5328
+ "tabindex",
5329
+ index === focusedIndex && !isDisabled ? "0" : "-1"
5330
+ );
5331
+ });
5332
+ if (showCustomization) {
5333
+ const isToggleBtn2 = (i) => i.hasAttribute("data-customization-toggle") || i.textContent.trim() === customizationLabel;
5334
+ const standardValues = Array.from(items).filter((item) => !isToggleBtn2(item)).map((item) => item.getAttribute("data-value"));
5335
+ const customValues = normSelected.filter(
5336
+ (val) => !standardValues.includes(val) && val !== ""
5337
+ );
5338
+ const isStandard = customValues.length === 0;
5339
+ const primaryCustomValue = customValues[customValues.length - 1] || "";
5340
+ const toggleBtn = Array.from(items).find(isToggleBtn2);
5341
+ const showInput = toggleBtn && normSelected.includes(toggleBtn.getAttribute("data-value")) || !isStandard && normSelected.length > 0;
5342
+ if (showInput) {
5343
+ if (!customFieldContainer) {
5344
+ customFieldContainer = document.createElement("div");
5345
+ customFieldContainer.className = `${PREFIX4}-chip__custom-field`;
5346
+ container.appendChild(customFieldContainer);
5347
+ }
5348
+ let input = customFieldContainer.querySelector(
5349
+ `.${PREFIX4}-chip__input`
5350
+ );
5351
+ if (!input) {
5352
+ customFieldContainer.innerHTML = `
5353
+ <div class="${PREFIX4}-chip__input-wrapper">
5354
+ <input type="text" class="${PREFIX4}-chip__input" placeholder="Masukkan data yang Anda inginkan" value="${!isStandard ? primaryCustomValue : ""}" />
5355
+ <button type="button" class="${PREFIX4}-chip__clear-button" aria-label="Hapus input" style="display: ${!isStandard && primaryCustomValue ? "inline-flex" : "none"};">
5356
+ <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="${PREFIX4}-chip__clear-icon">
5357
+ <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
5358
+ <path d="M18 6l-12 12"></path>
5359
+ <path d="M6 6l12 12"></path>
5360
+ </svg>
5361
+ </button>
5362
+ </div>
5363
+ `;
5364
+ input = customFieldContainer.querySelector("input");
5365
+ const clearBtn = customFieldContainer.querySelector(
5366
+ ".ina-chip__clear-button"
5367
+ );
5368
+ input.addEventListener("input", (e) => {
5369
+ clearBtn.style.display = e.target.value ? "inline-flex" : "none";
5370
+ });
5371
+ clearBtn.addEventListener("click", () => {
5372
+ input.value = "";
5373
+ clearBtn.style.display = "none";
5374
+ commitCustomValue(input);
5375
+ });
5376
+ input.addEventListener("blur", (e) => {
5377
+ commitCustomValue(e.target);
5378
+ });
5379
+ input.addEventListener("keydown", (e) => {
5380
+ if (e.key === "Enter") {
5381
+ commitCustomValue(e.target);
5382
+ e.target.blur();
5383
+ }
5384
+ });
5385
+ } else {
5386
+ const inputEl = customFieldContainer.querySelector("input");
5387
+ if (inputEl && document.activeElement !== inputEl) {
5388
+ inputEl.value = !isStandard ? primaryCustomValue : "";
5389
+ }
5390
+ }
5391
+ customFieldContainer.style.display = "block";
5392
+ } else {
5393
+ if (customFieldContainer) {
5394
+ customFieldContainer.style.display = "none";
5395
+ }
5396
+ }
5397
+ }
5398
+ };
5399
+ const handleSelect = (val) => {
5400
+ if (!val) return;
5401
+ let finalVal = val;
5402
+ if (isMultiple) {
5403
+ const normSelected = getNormalizedSelected();
5404
+ let newSelected;
5405
+ if (normSelected.includes(val)) {
5406
+ newSelected = normSelected.filter((v) => v !== val);
5407
+ } else {
5408
+ newSelected = [...normSelected, val];
5409
+ }
5410
+ finalVal = newSelected;
5411
+ selectedValue = newSelected.join(",");
5412
+ } else {
5413
+ const normSelected = getNormalizedSelected();
5414
+ if (normSelected.includes(val)) {
5415
+ selectedValue = "";
5416
+ finalVal = "";
5417
+ } else {
5418
+ selectedValue = val;
5419
+ }
5420
+ }
5421
+ container.setAttribute("data-selected", selectedValue);
5422
+ updateUI();
5423
+ container.dispatchEvent(
5424
+ new CustomEvent("chip:select", {
5425
+ detail: { value: finalVal },
5426
+ bubbles: true
5427
+ })
5428
+ );
5429
+ };
5430
+ let currentFocusedIndex = -1;
5431
+ const setItemFocus = (index) => {
5432
+ items.forEach((item, i) => {
5433
+ item.setAttribute("tabindex", i === index ? "0" : "-1");
5434
+ });
5435
+ if (items[index]) {
5436
+ items[index].focus();
5437
+ currentFocusedIndex = index;
5438
+ }
5439
+ };
5440
+ const commitCustomValue = (inputEl) => {
5441
+ const finalValue = inputEl.value.trim();
5442
+ let normSelected = getNormalizedSelected();
5443
+ const toggleBtn = Array.from(items).find(isToggleBtn);
5444
+ const toggleVal = toggleBtn ? toggleBtn.getAttribute("data-value") : null;
5445
+ const standardValues = Array.from(items).filter((i) => !isToggleBtn(i)).map((i) => i.getAttribute("data-value"));
5446
+ const customValues = normSelected.filter(
5447
+ (val) => !standardValues.includes(val) && val !== "" && val !== toggleVal
5448
+ );
5449
+ const primaryCustomValue = customValues[customValues.length - 1];
5450
+ if (primaryCustomValue) {
5451
+ normSelected = normSelected.filter((v) => v !== primaryCustomValue);
5452
+ }
5453
+ if (finalValue !== "") {
5454
+ if (!normSelected.includes(finalValue)) {
5455
+ normSelected.push(finalValue);
5456
+ }
5457
+ } else {
5458
+ if (toggleVal) {
5459
+ normSelected = normSelected.filter((v) => v !== toggleVal);
5460
+ }
5461
+ }
5462
+ if (isMultiple) {
5463
+ selectedValue = normSelected.join(",");
5464
+ } else {
5465
+ selectedValue = finalValue;
5466
+ }
5467
+ updateUI();
5468
+ const changeEvent = new CustomEvent(`${PREFIX4}-chip:change`, {
5469
+ detail: { value: isMultiple ? getNormalizedSelected() : selectedValue },
5470
+ bubbles: true
5471
+ });
5472
+ container.dispatchEvent(changeEvent);
5473
+ };
5474
+ items.forEach((item, index) => {
5475
+ item.addEventListener("click", (e) => {
5476
+ if (item.hasAttribute("disabled")) return;
5477
+ currentFocusedIndex = index;
5478
+ const val = item.getAttribute("data-value");
5479
+ if (showCustomization && isToggleBtn(item)) {
5480
+ const normSelected = getNormalizedSelected();
5481
+ const standardValues = Array.from(items).filter((i) => !isToggleBtn(i)).map((i) => i.getAttribute("data-value"));
5482
+ const customValues = normSelected.filter(
5483
+ (v) => !standardValues.includes(v) && v !== "" && v !== val
5484
+ );
5485
+ const isInputVisible = normSelected.includes(val) || customValues.length > 0;
5486
+ if (!isInputVisible) {
5487
+ handleSelect(val);
5488
+ }
5489
+ } else {
5490
+ handleSelect(val);
5491
+ }
5492
+ });
5493
+ item.addEventListener("keydown", (e) => {
5494
+ if (item.hasAttribute("disabled")) return;
5495
+ if (e.key === "ArrowRight" || e.key === "ArrowDown") {
5496
+ e.preventDefault();
5497
+ let nextIndex = (index + 1) % items.length;
5498
+ while (items[nextIndex].hasAttribute("disabled") && nextIndex !== index) {
5499
+ nextIndex = (nextIndex + 1) % items.length;
5500
+ }
5501
+ setItemFocus(nextIndex);
5502
+ } else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
5503
+ e.preventDefault();
5504
+ let prevIndex = (index - 1 + items.length) % items.length;
5505
+ while (items[prevIndex].hasAttribute("disabled") && prevIndex !== index) {
5506
+ prevIndex = (prevIndex - 1 + items.length) % items.length;
5507
+ }
5508
+ setItemFocus(prevIndex);
5509
+ }
5510
+ if (e.key === " " || e.key === "Enter") {
5511
+ e.preventDefault();
5512
+ item.click();
5513
+ }
5514
+ });
5515
+ });
5516
+ updateUI();
5517
+ if (list && !list.hasAttribute("role")) {
5518
+ list.setAttribute("role", "listbox");
5519
+ if (isMultiple) {
5520
+ list.setAttribute("aria-multiselectable", "true");
5521
+ }
5522
+ }
5523
+ container.__inaChipInitialized = true;
5524
+ });
5525
+ }
5526
+
5527
+ // src/js/components/stateless/img-compare.js
5528
+ function initImgCompare2(rootSelector = `.${PREFIX}-img-compare`) {
5529
+ document.querySelectorAll(rootSelector).forEach((imgCompare) => {
5530
+ const sliderEl = document.createElement("input");
5531
+ sliderEl.type = "range";
5532
+ sliderEl.min = "0";
5533
+ sliderEl.max = "100";
5534
+ sliderEl.value = "50";
5535
+ sliderEl.setAttribute("aria-label", "Percentage of the image to show");
5536
+ sliderEl.setAttribute("aria-valuenow", "50");
5537
+ sliderEl.setAttribute("aria-valuemin", "0");
5538
+ sliderEl.setAttribute("aria-valuemax", "100");
5539
+ sliderEl.classList.add("ina-ss-img__slider");
5540
+ sliderEl.addEventListener("input", () => {
5541
+ imgCompare.style.setProperty(
5542
+ `--${PREFIX}-position`,
5543
+ `${sliderEl.value}%`
5544
+ );
5545
+ });
5546
+ const sliderLineEl = document.createElement("div");
5547
+ sliderLineEl.classList.add("ina-ss-img__slider-line");
5548
+ const sliderButtonEl = document.createElement("button");
5549
+ sliderButtonEl.classList.add("ina-ss-img__slider-button");
5550
+ imgCompare.appendChild(sliderEl);
5551
+ imgCompare.appendChild(sliderLineEl);
5552
+ imgCompare.appendChild(sliderButtonEl);
5553
+ });
5554
+ }
5555
+
4864
5556
  // src/js/bundle.js
4865
5557
  if (typeof window !== void 0) {
4866
5558
  document.addEventListener("DOMContentLoaded", () => {
@@ -4875,7 +5567,7 @@ var InaUI = (() => {
4875
5567
  initSingleFileUpload();
4876
5568
  initFileUploadBase();
4877
5569
  initFileUploadItem();
4878
- initImgCompare();
5570
+ initImgCompare2();
4879
5571
  initModal();
4880
5572
  initRangeDatepicker();
4881
5573
  initRadioButton();
@@ -4884,12 +5576,13 @@ var InaUI = (() => {
4884
5576
  initToggle();
4885
5577
  initPagination();
4886
5578
  initSelectDropdown();
4887
- initChip();
5579
+ initChip2();
4888
5580
  initTabVertical();
4889
5581
  initTabHorizontal();
4890
5582
  initTable();
4891
5583
  initMonthPicker();
4892
5584
  initYearPicker();
5585
+ initPhoneInput();
4893
5586
  });
4894
5587
  }
4895
5588
  return __toCommonJS(bundle_exports);