@idds/js 1.2.4 → 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
package/dist/index.js CHANGED
@@ -6,6 +6,12 @@ function initButtonGroup(rootSelector = `.${PREFIX}-button-group`) {
6
6
  const buttons = buttonGroup.querySelectorAll(
7
7
  `.${PREFIX}-button-group__button`
8
8
  );
9
+ if (!buttonGroup.hasAttribute("role")) {
10
+ buttonGroup.setAttribute("role", "group");
11
+ }
12
+ if (!buttonGroup.hasAttribute("aria-label")) {
13
+ buttonGroup.setAttribute("aria-label", "Grup tombol");
14
+ }
9
15
  const updateState = (clickedButton) => {
10
16
  const isDisabled = clickedButton.hasAttribute("disabled") || clickedButton.classList.contains(
11
17
  `${PREFIX}-button-group__button--disabled`
@@ -29,7 +35,7 @@ function initButtonGroup(rootSelector = `.${PREFIX}-button-group`) {
29
35
  })
30
36
  );
31
37
  };
32
- buttons.forEach((button, index2) => {
38
+ buttons.forEach((button, index) => {
33
39
  button.addEventListener("click", (e) => {
34
40
  if (button.type !== "submit") {
35
41
  e.preventDefault();
@@ -44,19 +50,19 @@ function initButtonGroup(rootSelector = `.${PREFIX}-button-group`) {
44
50
  updateState(button);
45
51
  } else if (e.key === "ArrowRight" || e.key === "ArrowDown") {
46
52
  e.preventDefault();
47
- let nextIndex = (index2 + 1) % buttons.length;
53
+ let nextIndex = (index + 1) % buttons.length;
48
54
  while ((buttons[nextIndex].hasAttribute("disabled") || buttons[nextIndex].classList.contains(
49
55
  `${PREFIX}-button-group__button--disabled`
50
- )) && nextIndex !== index2) {
56
+ )) && nextIndex !== index) {
51
57
  nextIndex = (nextIndex + 1) % buttons.length;
52
58
  }
53
59
  buttons[nextIndex]?.focus();
54
60
  } else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
55
61
  e.preventDefault();
56
- let prevIndex = (index2 - 1 + buttons.length) % buttons.length;
62
+ let prevIndex = (index - 1 + buttons.length) % buttons.length;
57
63
  while ((buttons[prevIndex].hasAttribute("disabled") || buttons[prevIndex].classList.contains(
58
64
  `${PREFIX}-button-group__button--disabled`
59
- )) && prevIndex !== index2) {
65
+ )) && prevIndex !== index) {
60
66
  prevIndex = (prevIndex - 1 + buttons.length) % buttons.length;
61
67
  }
62
68
  buttons[prevIndex]?.focus();
@@ -117,18 +123,18 @@ function initTab(rootSelector = `.${PREFIX}-tab`) {
117
123
  const tabItem = tab.querySelectorAll(`.${PREFIX}-tab-item`);
118
124
  tabItem.forEach((tabButton) => {
119
125
  function updateState() {
120
- const index2 = Array.from(tabItem).indexOf(tabButton);
126
+ const index = Array.from(tabItem).indexOf(tabButton);
121
127
  tabItem.forEach((tabButton2, i) => {
122
128
  tabButton2.classList.remove("active");
123
129
  tabButton2.setAttribute("aria-selected", "false");
124
- if (i === index2) {
130
+ if (i === index) {
125
131
  tabButton2.classList.add("active");
126
132
  tabButton2.setAttribute("aria-selected", "true");
127
133
  }
128
134
  });
129
135
  tab.dispatchEvent(
130
136
  new CustomEvent("tab:change", {
131
- detail: { activeIndex: index2 },
137
+ detail: { activeIndex: index },
132
138
  bubbles: true,
133
139
  composed: true
134
140
  })
@@ -223,28 +229,28 @@ var AccordionGroup = class {
223
229
  this.element.__inaAccordionGroup = this;
224
230
  }
225
231
  registerItem(item) {
226
- const index2 = this.items.size;
227
- this.items.set(item.id, index2);
232
+ const index = this.items.size;
233
+ this.items.set(item.id, index);
228
234
  this.itemsArray.push(item);
229
235
  if (item.defaultOpen) {
230
236
  if (this.isMultiple) {
231
- if (!this.openIndexes.includes(index2)) {
232
- this.openIndexes.push(index2);
237
+ if (!this.openIndexes.includes(index)) {
238
+ this.openIndexes.push(index);
233
239
  }
234
240
  } else {
235
241
  if (this.openIndexes.length === 0) {
236
- this.openIndexes.push(index2);
242
+ this.openIndexes.push(index);
237
243
  }
238
244
  }
239
245
  }
240
- return index2;
246
+ return index;
241
247
  }
242
248
  unregisterItem(item) {
243
- const index2 = this.items.get(item.id);
244
- if (index2 !== void 0) {
249
+ const index = this.items.get(item.id);
250
+ if (index !== void 0) {
245
251
  this.items.delete(item.id);
246
252
  this.itemsArray = this.itemsArray.filter((i) => i !== item);
247
- this.openIndexes = this.openIndexes.filter((idx) => idx !== index2).map((idx) => idx > index2 ? idx - 1 : idx);
253
+ this.openIndexes = this.openIndexes.filter((idx) => idx !== index).map((idx) => idx > index ? idx - 1 : idx);
248
254
  const newMap = /* @__PURE__ */ new Map();
249
255
  this.itemsArray.forEach((itm, newIdx) => {
250
256
  newMap.set(itm.id, newIdx);
@@ -252,22 +258,22 @@ var AccordionGroup = class {
252
258
  this.items = newMap;
253
259
  }
254
260
  }
255
- handleItemToggle(index2, isOpen) {
261
+ handleItemToggle(index, isOpen) {
256
262
  const prevIndexes = [...this.openIndexes];
257
263
  let nextIndexes = [];
258
264
  if (this.isMultiple) {
259
265
  if (isOpen) {
260
- if (!prevIndexes.includes(index2)) {
261
- nextIndexes = [...prevIndexes, index2];
266
+ if (!prevIndexes.includes(index)) {
267
+ nextIndexes = [...prevIndexes, index];
262
268
  } else {
263
269
  nextIndexes = prevIndexes;
264
270
  }
265
271
  } else {
266
- nextIndexes = prevIndexes.filter((idx) => idx !== index2);
272
+ nextIndexes = prevIndexes.filter((idx) => idx !== index);
267
273
  }
268
274
  } else {
269
275
  if (isOpen) {
270
- nextIndexes = [index2];
276
+ nextIndexes = [index];
271
277
  } else {
272
278
  nextIndexes = [];
273
279
  }
@@ -275,16 +281,16 @@ var AccordionGroup = class {
275
281
  this.openIndexes = nextIndexes;
276
282
  this.notifyItems();
277
283
  }
278
- isItemOpen(index2) {
279
- return this.openIndexes.includes(index2);
284
+ isItemOpen(index) {
285
+ return this.openIndexes.includes(index);
280
286
  }
281
287
  getItemIndex(itemId) {
282
288
  return this.items.get(itemId);
283
289
  }
284
290
  // Notify all children to update their visual state based on new openIndexes
285
291
  notifyItems() {
286
- this.itemsArray.forEach((item, index2) => {
287
- const isOpen = this.openIndexes.includes(index2);
292
+ this.itemsArray.forEach((item, index) => {
293
+ const isOpen = this.openIndexes.includes(index);
288
294
  item.setOpenState(isOpen);
289
295
  });
290
296
  }
@@ -393,7 +399,7 @@ function initAccordion(rootSelector = `.${PREFIX}-accordion-group`) {
393
399
 
394
400
  // src/js/components/stateful/date-picker.js
395
401
  var DatePicker = class {
396
- constructor(selectorOrElement, options2 = {}) {
402
+ constructor(selectorOrElement, options = {}) {
397
403
  this.container = typeof selectorOrElement === "string" ? document.querySelector(selectorOrElement) : selectorOrElement;
398
404
  if (!this.container) {
399
405
  console.warn("[IDDS DatePicker] Container not found:", selectorOrElement);
@@ -419,7 +425,11 @@ var DatePicker = class {
419
425
  onChange: null,
420
426
  triggerWidth: "",
421
427
  panelMaxHeight: "",
422
- ...options2
428
+ allowClear: true,
429
+ // Added allowClear option
430
+ className: "",
431
+ // Added className option
432
+ ...options
423
433
  };
424
434
  this.state = {
425
435
  viewDate: /* @__PURE__ */ new Date(),
@@ -573,6 +583,18 @@ var DatePicker = class {
573
583
  }
574
584
  this.renderPanel();
575
585
  }
586
+ getFullDayName(shortName) {
587
+ const map = {
588
+ Min: "Minggu",
589
+ Sen: "Senin",
590
+ Sel: "Selasa",
591
+ Rab: "Rabu",
592
+ Kam: "Kamis",
593
+ Jum: "Jumat",
594
+ Sab: "Sabtu"
595
+ };
596
+ return map[shortName] || shortName;
597
+ }
576
598
  initDOM() {
577
599
  if (!this.container.classList.contains(`${PREFIX}-date-picker`)) {
578
600
  this.container.classList.add(`${PREFIX}-date-picker`);
@@ -588,6 +610,9 @@ var DatePicker = class {
588
610
  if (this.options.triggerWidth) {
589
611
  trigger.style.width = typeof this.options.triggerWidth === "number" ? `${this.options.triggerWidth}px` : this.options.triggerWidth;
590
612
  }
613
+ trigger.setAttribute("aria-haspopup", "dialog");
614
+ trigger.setAttribute("aria-expanded", "false");
615
+ trigger.setAttribute("aria-label", "Pilih Tanggal");
591
616
  const textWrapper = document.createElement("span");
592
617
  textWrapper.className = `${PREFIX}-date-picker__trigger-text ${PREFIX}-date-picker__trigger-text--placeholder`;
593
618
  textWrapper.textContent = "Pilih Tanggal";
@@ -597,6 +622,26 @@ var DatePicker = class {
597
622
  trigger.appendChild(textWrapper);
598
623
  trigger.appendChild(iconWrapper);
599
624
  this.container.appendChild(trigger);
625
+ } else if (trigger) {
626
+ if (!trigger.hasAttribute("aria-haspopup"))
627
+ trigger.setAttribute("aria-haspopup", "dialog");
628
+ if (!trigger.hasAttribute("aria-expanded"))
629
+ trigger.setAttribute("aria-expanded", "false");
630
+ if (!trigger.hasAttribute("aria-label"))
631
+ trigger.setAttribute("aria-label", "Pilih Tanggal");
632
+ }
633
+ if (this.options.allowClear && !this.options.panelOnly) {
634
+ let clearBtn = this.container.querySelector(`.${PREFIX}-date-picker__clear-button`);
635
+ if (!clearBtn) {
636
+ clearBtn = document.createElement("button");
637
+ clearBtn.type = "button";
638
+ clearBtn.className = `${PREFIX}-date-picker__clear-button`;
639
+ clearBtn.setAttribute("aria-label", "Hapus tanggal terpilih");
640
+ clearBtn.innerHTML = this.createIcon("x");
641
+ clearBtn.style.display = "none";
642
+ this.container.appendChild(clearBtn);
643
+ }
644
+ this.elements.clearBtn = clearBtn;
600
645
  }
601
646
  this.elements.trigger = trigger;
602
647
  if (trigger) {
@@ -891,10 +936,13 @@ var DatePicker = class {
891
936
  header.appendChild(nextBtn);
892
937
  const grid = document.createElement("div");
893
938
  grid.className = `${PREFIX}-date-picker__calendar-grid`;
939
+ grid.setAttribute("role", "grid");
894
940
  this.DAYS_SHORT.forEach((d) => {
895
941
  const dh = document.createElement("div");
896
942
  dh.className = `${PREFIX}-date-picker__day-header`;
897
943
  dh.textContent = d;
944
+ dh.setAttribute("role", "columnheader");
945
+ dh.setAttribute("aria-label", this.getFullDayName(d));
898
946
  grid.appendChild(dh);
899
947
  });
900
948
  const firstDayOfMonth = new Date(year, month, 1).getDay();
@@ -1039,6 +1087,7 @@ var DatePicker = class {
1039
1087
  this.state.isOpen = true;
1040
1088
  this.elements.panel.classList.add(`${PREFIX}-date-picker__panel--open`);
1041
1089
  this.elements.panel.style.display = "block";
1090
+ if (this.elements.trigger) this.elements.trigger.setAttribute("aria-expanded", "true");
1042
1091
  this.renderPanel();
1043
1092
  }
1044
1093
  close() {
@@ -1046,6 +1095,7 @@ var DatePicker = class {
1046
1095
  this.state.isOpen = false;
1047
1096
  this.elements.panel.classList.remove(`${PREFIX}-date-picker__panel--open`);
1048
1097
  this.elements.panel.style.display = "none";
1098
+ if (this.elements.trigger) this.elements.trigger.setAttribute("aria-expanded", "false");
1049
1099
  }
1050
1100
  toggle() {
1051
1101
  if (this.state.isOpen) this.close();
@@ -1090,11 +1140,11 @@ var DatePicker = class {
1090
1140
  return this.state.rangeDate;
1091
1141
  }
1092
1142
  };
1093
- function initDatepicker(selectorOrElement, options2 = {}) {
1143
+ function initDatepicker(selectorOrElement, options = {}) {
1094
1144
  const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-date-picker`);
1095
1145
  const instances = [];
1096
1146
  elements.forEach((container) => {
1097
- const instance = new DatePicker(container, options2);
1147
+ const instance = new DatePicker(container, options);
1098
1148
  container.__datepickerAPI = instance;
1099
1149
  instances.push(instance);
1100
1150
  });
@@ -1104,7 +1154,7 @@ function initDatepicker(selectorOrElement, options2 = {}) {
1104
1154
 
1105
1155
  // src/js/components/stateful/time-picker.js
1106
1156
  var TimePicker = class {
1107
- constructor(selectorOrElement, options2 = {}) {
1157
+ constructor(selectorOrElement, options = {}) {
1108
1158
  this.container = typeof selectorOrElement === "string" ? document.querySelector(selectorOrElement) : selectorOrElement;
1109
1159
  if (!this.container) {
1110
1160
  console.warn("[IDDS TimePicker] Container not found:", selectorOrElement);
@@ -1137,7 +1187,7 @@ var TimePicker = class {
1137
1187
  secondStep: 1,
1138
1188
  onChange: null,
1139
1189
  size: this.container.dataset.size || "md",
1140
- ...options2
1190
+ ...options
1141
1191
  };
1142
1192
  this.state = {
1143
1193
  isOpen: false,
@@ -1145,6 +1195,7 @@ var TimePicker = class {
1145
1195
  internalValue: ""
1146
1196
  };
1147
1197
  this.elements = {};
1198
+ this.inputId = this.container.id || `time-picker-${Math.random().toString(36).substr(2, 9)}`;
1148
1199
  this.initDOM();
1149
1200
  this.bindEvents();
1150
1201
  if (this.elements.input && this.elements.input.value) {
@@ -1252,12 +1303,16 @@ var TimePicker = class {
1252
1303
  if (!wrapper) {
1253
1304
  wrapper = document.createElement("div");
1254
1305
  wrapper.className = `${PREFIX}-time-picker__wrapper`;
1306
+ wrapper.setAttribute("role", "combobox");
1307
+ wrapper.setAttribute("aria-haspopup", "listbox");
1308
+ wrapper.setAttribute("aria-expanded", "false");
1255
1309
  const prefixIcon = document.createElement("div");
1256
1310
  prefixIcon.className = `${PREFIX}-time-picker__prefix-icon`;
1257
1311
  prefixIcon.innerHTML = this.createIcon("clock");
1258
1312
  wrapper.appendChild(prefixIcon);
1259
1313
  input = document.createElement("input");
1260
1314
  input.type = "text";
1315
+ input.id = this.inputId;
1261
1316
  input.className = `${PREFIX}-time-picker__input ${PREFIX}-time-picker__input--size-${this.options.size} ${PREFIX}-time-picker__input--with-prefix`;
1262
1317
  if (this.options.allowClear)
1263
1318
  input.classList.add(`${PREFIX}-time-picker__input--with-suffix`);
@@ -1267,13 +1322,23 @@ var TimePicker = class {
1267
1322
  else input.readOnly = true;
1268
1323
  wrapper.appendChild(input);
1269
1324
  if (this.options.allowClear) {
1270
- clearBtn = document.createElement("div");
1325
+ clearBtn = document.createElement("button");
1326
+ clearBtn.type = "button";
1271
1327
  clearBtn.className = `${PREFIX}-time-picker__clear-button`;
1328
+ clearBtn.setAttribute("aria-label", "Hapus waktu");
1272
1329
  clearBtn.innerHTML = this.createIcon("x");
1273
1330
  clearBtn.style.display = "none";
1274
1331
  wrapper.appendChild(clearBtn);
1275
1332
  }
1276
1333
  this.container.appendChild(wrapper);
1334
+ } else {
1335
+ wrapper.setAttribute("role", "combobox");
1336
+ wrapper.setAttribute("aria-haspopup", "listbox");
1337
+ wrapper.setAttribute("aria-expanded", "false");
1338
+ if (input && !input.id) input.id = this.inputId;
1339
+ if (clearBtn && !clearBtn.hasAttribute("aria-label")) {
1340
+ clearBtn.setAttribute("aria-label", "Hapus waktu");
1341
+ }
1277
1342
  }
1278
1343
  this.elements.wrapper = wrapper;
1279
1344
  this.elements.input = input;
@@ -1354,24 +1419,24 @@ var TimePicker = class {
1354
1419
  }
1355
1420
  }
1356
1421
  generateOptions(type) {
1357
- const options2 = [];
1422
+ const options = [];
1358
1423
  const { use12Hours, hourStep, minuteStep, secondStep } = this.options;
1359
1424
  let limit = type === "hour" ? use12Hours ? 12 : 24 : 60;
1360
1425
  let step = type === "hour" ? hourStep : type === "minute" ? minuteStep : secondStep;
1361
1426
  if (limit === 12) {
1362
1427
  for (let i = type === "hour" ? 1 : 0; i <= (type === "hour" ? 12 : 59); i += step) {
1363
- options2.push(i);
1428
+ options.push(i);
1364
1429
  }
1365
1430
  } else if (limit === 24) {
1366
1431
  for (let i = 0; i <= 23; i += step) {
1367
- options2.push(i);
1432
+ options.push(i);
1368
1433
  }
1369
1434
  } else {
1370
1435
  for (let i = 0; i <= 59; i += step) {
1371
- options2.push(i);
1436
+ options.push(i);
1372
1437
  }
1373
1438
  }
1374
- return options2;
1439
+ return options;
1375
1440
  }
1376
1441
  renderColumn(type, optionsArr) {
1377
1442
  const column = document.createElement("div");
@@ -1381,7 +1446,7 @@ var TimePicker = class {
1381
1446
  column.appendChild(colContent);
1382
1447
  const { use12Hours } = this.options;
1383
1448
  const { currentTime } = this.state;
1384
- optionsArr.forEach((optValue) => {
1449
+ optionsArr.forEach((optValue, index) => {
1385
1450
  const option = document.createElement("div");
1386
1451
  option.className = `${PREFIX}-time-picker__option`;
1387
1452
  let isSelected = false;
@@ -1427,9 +1492,9 @@ var TimePicker = class {
1427
1492
  option.classList.add(`${PREFIX}-time-picker__option--disabled`);
1428
1493
  option.setAttribute("role", "option");
1429
1494
  option.setAttribute("aria-selected", isSelected.toString());
1430
- const isFirstFocusable = index === 0 && !options.some((opt) => {
1495
+ const isFirstFocusable = index === 0 && !optionsArr.some((opt) => {
1431
1496
  if (type === "hour") {
1432
- return use12Hours ? (currentTime.hours === 0 ? 12 : currentTime.hours) === opt : currentTime.hours === opt;
1497
+ return (use12Hours && currentTime.hours === 0 ? 12 : currentTime.hours) === opt;
1433
1498
  } else if (type === "minute") {
1434
1499
  return currentTime.minutes === opt;
1435
1500
  } else if (type === "second") {
@@ -1547,6 +1612,7 @@ var TimePicker = class {
1547
1612
  this.state.isOpen = true;
1548
1613
  this.container.classList.add(`${PREFIX}-time-picker--open`);
1549
1614
  this.elements.panel.style.display = "block";
1615
+ this.elements.wrapper.setAttribute("aria-expanded", "true");
1550
1616
  this.state.currentTime = this.parseTime(this.elements.input.value);
1551
1617
  this.buildPanel();
1552
1618
  document.dispatchEvent(
@@ -1559,6 +1625,7 @@ var TimePicker = class {
1559
1625
  this.state.isOpen = false;
1560
1626
  this.container.classList.remove(`${PREFIX}-time-picker--open`);
1561
1627
  this.elements.panel.style.display = "none";
1628
+ this.elements.wrapper.setAttribute("aria-expanded", "false");
1562
1629
  }
1563
1630
  toggle() {
1564
1631
  if (this.state.isOpen) this.close();
@@ -1569,16 +1636,9 @@ var TimePicker = class {
1569
1636
  e.stopPropagation();
1570
1637
  this.toggle();
1571
1638
  });
1572
- if (this.elements.clearBtn && this.options.allowClear) {
1639
+ if (this.elements.clearBtn) {
1573
1640
  this.elements.clearBtn.addEventListener("click", (e) => {
1574
1641
  e.stopPropagation();
1575
- this.elements.input.value = "";
1576
- this.state.currentTime = {
1577
- hours: 0,
1578
- minutes: 0,
1579
- seconds: 0,
1580
- period: "AM"
1581
- };
1582
1642
  this.container.dataset.value = "";
1583
1643
  this.state.internalValue = "";
1584
1644
  this.elements.clearBtn.style.display = "none";
@@ -1602,11 +1662,11 @@ var TimePicker = class {
1602
1662
  return this.state.internalValue;
1603
1663
  }
1604
1664
  };
1605
- function initTimepicker(selectorOrElement, options2 = {}) {
1665
+ function initTimepicker(selectorOrElement, options = {}) {
1606
1666
  const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-time-picker`);
1607
1667
  const instances = [];
1608
1668
  elements.forEach((container) => {
1609
- const instance = new TimePicker(container, options2);
1669
+ const instance = new TimePicker(container, options);
1610
1670
  container.__timepickerAPI = instance;
1611
1671
  instances.push(instance);
1612
1672
  });
@@ -1649,6 +1709,17 @@ function openModal(modalEl) {
1649
1709
  modalEl.style.display = "flex";
1650
1710
  document.body.style.overflow = "hidden";
1651
1711
  modalEl.setAttribute("aria-hidden", "false");
1712
+ modalEl.setAttribute("tabindex", "-1");
1713
+ if (!modalEl.hasAttribute("role")) {
1714
+ modalEl.setAttribute("role", "dialog");
1715
+ }
1716
+ if (!modalEl.hasAttribute("aria-modal")) {
1717
+ modalEl.setAttribute("aria-modal", "true");
1718
+ }
1719
+ const closeBtn = modalEl.querySelector(`.${PREFIX}-modal__close-button`);
1720
+ if (closeBtn && !closeBtn.hasAttribute("aria-label")) {
1721
+ closeBtn.setAttribute("aria-label", "Tutup dialog");
1722
+ }
1652
1723
  modalEl.classList.remove(
1653
1724
  `${PREFIX}-modal--exit`,
1654
1725
  `${PREFIX}-modal--exit-active`
@@ -1747,6 +1818,19 @@ function initDrawer(rootSelector = `.${PREFIX2}-drawer`) {
1747
1818
  if (!drawer) return;
1748
1819
  drawer.style.display = "flex";
1749
1820
  document.body.style.overflow = "hidden";
1821
+ drawer.setAttribute("aria-hidden", "false");
1822
+ drawer.setAttribute("tabindex", "-1");
1823
+ if (!drawer.hasAttribute("role")) {
1824
+ drawer.setAttribute("role", "complementary");
1825
+ }
1826
+ if (!drawer.hasAttribute("aria-modal")) {
1827
+ drawer.setAttribute("aria-modal", "true");
1828
+ }
1829
+ const panel = drawer.querySelector(`.${PREFIX2}-drawer__panel`) || drawer.querySelector(`.${PREFIX2}-drawer__content`) || drawer;
1830
+ const closeBtn = panel.querySelector(`.${PREFIX2}-drawer__close-button`);
1831
+ if (closeBtn && !closeBtn.hasAttribute("aria-label")) {
1832
+ closeBtn.setAttribute("aria-label", "Tutup panel");
1833
+ }
1750
1834
  drawer.offsetHeight;
1751
1835
  drawer.classList.add(`${PREFIX2}-drawer--open`);
1752
1836
  drawer.dispatchEvent(new CustomEvent("drawer:open"));
@@ -1911,9 +1995,20 @@ function setDropdownState(root, newState) {
1911
1995
  if (newState.isOpen !== void 0) {
1912
1996
  root.setAttribute("data-state", newState.isOpen ? "open" : "closed");
1913
1997
  const trigger = root.querySelector(`.${PREFIX4}-select-dropdown__trigger`);
1914
- if (trigger) trigger.setAttribute("aria-expanded", newState.isOpen);
1998
+ if (trigger) {
1999
+ trigger.setAttribute("aria-expanded", newState.isOpen);
2000
+ if (!trigger.hasAttribute("aria-haspopup")) {
2001
+ trigger.setAttribute("aria-haspopup", "listbox");
2002
+ }
2003
+ }
1915
2004
  const panel = root.querySelector(`.${PREFIX4}-select-dropdown__panel`);
1916
2005
  if (panel) {
2006
+ if (!panel.hasAttribute("role")) {
2007
+ panel.setAttribute("role", "listbox");
2008
+ }
2009
+ if (newState.isMultiple) {
2010
+ panel.setAttribute("aria-multiselectable", "true");
2011
+ }
1917
2012
  if (newState.isOpen) {
1918
2013
  panel.style.removeProperty("display");
1919
2014
  } else {
@@ -1940,9 +2035,9 @@ function updateTriggerUI(root, values, isMultiple) {
1940
2035
  `.${PREFIX4}-select-dropdown__trigger-text`
1941
2036
  );
1942
2037
  const placeholder = input ? input.getAttribute("placeholder") : textSpan ? textSpan.getAttribute("data-placeholder") : "Select...";
1943
- const options2 = root.querySelectorAll(`.${PREFIX4}-select-dropdown__option`);
2038
+ const options = root.querySelectorAll(`.${PREFIX4}-select-dropdown__option`);
1944
2039
  const getLabel = (val) => {
1945
- const opt = Array.from(options2).find(
2040
+ const opt = Array.from(options).find(
1946
2041
  (o) => o.getAttribute("data-value") === val
1947
2042
  );
1948
2043
  return opt ? opt.textContent.trim() : val;
@@ -1968,7 +2063,7 @@ function updateTriggerUI(root, values, isMultiple) {
1968
2063
  values.length === 0
1969
2064
  );
1970
2065
  }
1971
- options2.forEach((opt) => {
2066
+ options.forEach((opt) => {
1972
2067
  const val = opt.getAttribute("data-value");
1973
2068
  const isSelected = values.includes(val);
1974
2069
  if (isMultiple) {
@@ -1990,6 +2085,10 @@ function updateTriggerUI(root, values, isMultiple) {
1990
2085
  isSelected
1991
2086
  );
1992
2087
  }
2088
+ if (!opt.hasAttribute("role")) {
2089
+ opt.setAttribute("role", "option");
2090
+ }
2091
+ opt.setAttribute("aria-selected", isSelected);
1993
2092
  });
1994
2093
  }
1995
2094
  function initSelectDropdown() {
@@ -2048,13 +2147,13 @@ function initSelectDropdown() {
2048
2147
  const root = e.target.closest(`.${PREFIX4}-select-dropdown`);
2049
2148
  if (root) {
2050
2149
  const term = e.target.value.toLowerCase();
2051
- const options2 = root.querySelectorAll(
2150
+ const options = root.querySelectorAll(
2052
2151
  `.${PREFIX4}-select-dropdown__option`
2053
2152
  );
2054
2153
  if (root.getAttribute("data-state") !== "open") {
2055
2154
  setDropdownState(root, { isOpen: true });
2056
2155
  }
2057
- options2.forEach((opt) => {
2156
+ options.forEach((opt) => {
2058
2157
  const text = opt.textContent.trim().toLowerCase();
2059
2158
  opt.style.display = text.includes(term) ? "" : "none";
2060
2159
  });
@@ -2128,20 +2227,20 @@ function initStepper() {
2128
2227
  `;
2129
2228
  const updateUI = () => {
2130
2229
  stepper.dataset.currentStep = currentStep;
2131
- items.forEach((item, index2) => {
2230
+ items.forEach((item, index) => {
2132
2231
  const iconWrapper = item.querySelector(
2133
2232
  `.${PREFIX}-stepper__icon-wrapper`
2134
2233
  );
2135
- const itemNumber = index2 + 1;
2234
+ const itemNumber = index + 1;
2136
2235
  item.classList.remove(
2137
2236
  `${PREFIX}-stepper__item--completed`,
2138
2237
  `${PREFIX}-stepper__item--active`
2139
2238
  );
2140
2239
  if (iconWrapper) iconWrapper.innerHTML = "";
2141
- if (index2 < currentStep) {
2240
+ if (index < currentStep) {
2142
2241
  item.classList.add(`${PREFIX}-stepper__item--completed`);
2143
2242
  if (iconWrapper) iconWrapper.innerHTML = checkIcon;
2144
- } else if (index2 === currentStep) {
2243
+ } else if (index === currentStep) {
2145
2244
  item.classList.add(`${PREFIX}-stepper__item--active`);
2146
2245
  if (iconWrapper)
2147
2246
  iconWrapper.innerHTML = `<span class="${PREFIX}-stepper__step-number">${itemNumber}</span>`;
@@ -2150,8 +2249,8 @@ function initStepper() {
2150
2249
  iconWrapper.innerHTML = `<span class="${PREFIX}-stepper__step-number">${itemNumber}</span>`;
2151
2250
  }
2152
2251
  });
2153
- separators.forEach((separator, index2) => {
2154
- if (index2 < currentStep) {
2252
+ separators.forEach((separator, index) => {
2253
+ if (index < currentStep) {
2155
2254
  separator.classList.add(`${PREFIX}-stepper__separator--completed`);
2156
2255
  } else {
2157
2256
  separator.classList.remove(`${PREFIX}-stepper__separator--completed`);
@@ -2197,11 +2296,11 @@ function initStepper() {
2197
2296
  }
2198
2297
  });
2199
2298
  });
2200
- items.forEach((item, index2) => {
2299
+ items.forEach((item, index) => {
2201
2300
  if (item.classList.contains(`${PREFIX}-stepper__item--clickable`) || item.hasAttribute("data-clickable")) {
2202
2301
  item.addEventListener("click", () => {
2203
2302
  if (!item.classList.contains(`${PREFIX}-stepper__item--disabled`)) {
2204
- currentStep = index2;
2303
+ currentStep = index;
2205
2304
  updateUI();
2206
2305
  }
2207
2306
  });
@@ -2275,7 +2374,7 @@ function initFileUpload(rootSelector = `.${PREFIX}-file-upload`) {
2275
2374
  } else {
2276
2375
  filesContainer.style.display = "none";
2277
2376
  }
2278
- uploadedFiles.forEach((f, index2) => {
2377
+ uploadedFiles.forEach((f, index) => {
2279
2378
  const fileEl = document.createElement("div");
2280
2379
  fileEl.className = `${PREFIX}-file-upload__file`;
2281
2380
  let statusClass = "";
@@ -3099,281 +3198,6 @@ function initRangeDatepicker() {
3099
3198
  });
3100
3199
  }
3101
3200
 
3102
- // src/js/components/stateless/img-compare.js
3103
- function initImgCompare(rootSelector = `.${PREFIX}-img-compare`) {
3104
- document.querySelectorAll(rootSelector).forEach((imgCompare) => {
3105
- const sliderEl = document.createElement("input");
3106
- sliderEl.type = "range";
3107
- sliderEl.min = "0";
3108
- sliderEl.max = "100";
3109
- sliderEl.value = "50";
3110
- sliderEl.setAttribute("aria-label", "Percentage of the image to show");
3111
- sliderEl.setAttribute("aria-valuenow", "50");
3112
- sliderEl.setAttribute("aria-valuemin", "0");
3113
- sliderEl.setAttribute("aria-valuemax", "100");
3114
- sliderEl.classList.add("ina-ss-img__slider");
3115
- sliderEl.addEventListener("input", () => {
3116
- imgCompare.style.setProperty(
3117
- `--${PREFIX}-position`,
3118
- `${sliderEl.value}%`
3119
- );
3120
- });
3121
- const sliderLineEl = document.createElement("div");
3122
- sliderLineEl.classList.add("ina-ss-img__slider-line");
3123
- const sliderButtonEl = document.createElement("button");
3124
- sliderButtonEl.classList.add("ina-ss-img__slider-button");
3125
- imgCompare.appendChild(sliderEl);
3126
- imgCompare.appendChild(sliderLineEl);
3127
- imgCompare.appendChild(sliderButtonEl);
3128
- });
3129
- }
3130
-
3131
- // src/js/components/stateful/chip.js
3132
- var PREFIX5 = "ina";
3133
- function initChip(rootSelector = `.${PREFIX5}-chip`) {
3134
- const chips = document.querySelectorAll(rootSelector);
3135
- chips.forEach((container) => {
3136
- if (container.__inaChipInitialized) return;
3137
- const showCustomization = container.getAttribute("data-show-customization") === "true";
3138
- const customizationLabel = container.getAttribute("data-customization-label") || "Kustomisasi";
3139
- const isMultiple = container.getAttribute("data-multiple") === "true";
3140
- let selectedValue = container.getAttribute("data-selected") || "";
3141
- const list = container.querySelector(`.${PREFIX5}-chip__list`);
3142
- const items = list ? list.querySelectorAll(`.${PREFIX5}-chip__item`) : [];
3143
- let customFieldContainer = container.querySelector(
3144
- `.${PREFIX5}-chip__custom-field`
3145
- );
3146
- const getNormalizedSelected = () => {
3147
- if (!selectedValue) return [];
3148
- return isMultiple ? selectedValue.split(",").map((s) => s.trim()).filter(Boolean) : [selectedValue];
3149
- };
3150
- const updateUI = () => {
3151
- const normSelected = getNormalizedSelected();
3152
- const getInitialFocusIndex = () => {
3153
- if (normSelected.length > 0) {
3154
- const standardValues = Array.from(items).filter((item) => item.textContent.trim() !== customizationLabel).map((item) => item.getAttribute("data-value"));
3155
- const hasCustomVal = normSelected.some(
3156
- (val) => !standardValues.includes(val) && val !== ""
3157
- );
3158
- if (hasCustomVal && showCustomization) {
3159
- return items.length - 1;
3160
- }
3161
- const firstSelectedIndex = Array.from(items).findIndex(
3162
- (opt) => normSelected.includes(opt.getAttribute("data-value"))
3163
- );
3164
- if (firstSelectedIndex !== -1) return firstSelectedIndex;
3165
- }
3166
- return 0;
3167
- };
3168
- const focusedIndex = getInitialFocusIndex();
3169
- items.forEach((item, index2) => {
3170
- const itemValue = item.getAttribute("data-value");
3171
- const isSelected = normSelected.includes(itemValue) || showCustomization && item.textContent.trim() === customizationLabel && normSelected.some(
3172
- (val) => !Array.from(items).filter((i) => i.textContent.trim() !== customizationLabel).map((i) => i.getAttribute("data-value")).includes(val) && val !== ""
3173
- );
3174
- const isDisabled = item.hasAttribute("disabled");
3175
- if (isSelected) {
3176
- item.classList.add(`${PREFIX5}-chip__item--selected`);
3177
- } else {
3178
- item.classList.remove(`${PREFIX5}-chip__item--selected`);
3179
- }
3180
- if (isDisabled) {
3181
- item.classList.add(`${PREFIX5}-chip__item--disabled`);
3182
- }
3183
- item.setAttribute(
3184
- "tabindex",
3185
- index2 === focusedIndex && !isDisabled ? "0" : "-1"
3186
- );
3187
- });
3188
- if (showCustomization) {
3189
- const isToggleBtn2 = (i) => i.hasAttribute("data-customization-toggle") || i.textContent.trim() === customizationLabel;
3190
- const standardValues = Array.from(items).filter((item) => !isToggleBtn2(item)).map((item) => item.getAttribute("data-value"));
3191
- const customValues = normSelected.filter(
3192
- (val) => !standardValues.includes(val) && val !== ""
3193
- );
3194
- const isStandard = customValues.length === 0;
3195
- const primaryCustomValue = customValues[customValues.length - 1] || "";
3196
- const toggleBtn = Array.from(items).find(isToggleBtn2);
3197
- const showInput = toggleBtn && normSelected.includes(toggleBtn.getAttribute("data-value")) || !isStandard && normSelected.length > 0;
3198
- if (showInput) {
3199
- if (!customFieldContainer) {
3200
- customFieldContainer = document.createElement("div");
3201
- customFieldContainer.className = `${PREFIX5}-chip__custom-field`;
3202
- container.appendChild(customFieldContainer);
3203
- }
3204
- let input = customFieldContainer.querySelector(
3205
- `.${PREFIX5}-chip__input`
3206
- );
3207
- if (!input) {
3208
- customFieldContainer.innerHTML = `
3209
- <div class="${PREFIX5}-chip__input-wrapper">
3210
- <input type="text" class="${PREFIX5}-chip__input" placeholder="Masukkan data yang Anda inginkan" value="${!isStandard ? primaryCustomValue : ""}" />
3211
- <button type="button" class="${PREFIX5}-chip__clear-button" aria-label="Clear input" style="display: ${!isStandard && primaryCustomValue ? "inline-flex" : "none"};">
3212
- <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="${PREFIX5}-chip__clear-icon">
3213
- <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
3214
- <path d="M18 6l-12 12"></path>
3215
- <path d="M6 6l12 12"></path>
3216
- </svg>
3217
- </button>
3218
- </div>
3219
- `;
3220
- input = customFieldContainer.querySelector("input");
3221
- const clearBtn = customFieldContainer.querySelector(
3222
- ".ina-chip__clear-button"
3223
- );
3224
- input.addEventListener("input", (e) => {
3225
- clearBtn.style.display = e.target.value ? "inline-flex" : "none";
3226
- });
3227
- clearBtn.addEventListener("click", () => {
3228
- input.value = "";
3229
- clearBtn.style.display = "none";
3230
- commitCustomValue(input);
3231
- });
3232
- input.addEventListener("blur", (e) => {
3233
- commitCustomValue(e.target);
3234
- });
3235
- input.addEventListener("keydown", (e) => {
3236
- if (e.key === "Enter") {
3237
- commitCustomValue(e.target);
3238
- e.target.blur();
3239
- }
3240
- });
3241
- } else {
3242
- const inputEl = customFieldContainer.querySelector("input");
3243
- if (inputEl && document.activeElement !== inputEl) {
3244
- inputEl.value = !isStandard ? primaryCustomValue : "";
3245
- }
3246
- }
3247
- customFieldContainer.style.display = "block";
3248
- } else {
3249
- if (customFieldContainer) {
3250
- customFieldContainer.style.display = "none";
3251
- }
3252
- }
3253
- }
3254
- };
3255
- const handleSelect = (val) => {
3256
- if (!val) return;
3257
- let finalVal = val;
3258
- if (isMultiple) {
3259
- const normSelected = getNormalizedSelected();
3260
- let newSelected;
3261
- if (normSelected.includes(val)) {
3262
- newSelected = normSelected.filter((v) => v !== val);
3263
- } else {
3264
- newSelected = [...normSelected, val];
3265
- }
3266
- finalVal = newSelected;
3267
- selectedValue = newSelected.join(",");
3268
- } else {
3269
- const normSelected = getNormalizedSelected();
3270
- if (normSelected.includes(val)) {
3271
- selectedValue = "";
3272
- finalVal = "";
3273
- } else {
3274
- selectedValue = val;
3275
- }
3276
- }
3277
- container.setAttribute("data-selected", selectedValue);
3278
- updateUI();
3279
- container.dispatchEvent(
3280
- new CustomEvent("chip:select", {
3281
- detail: { value: finalVal },
3282
- bubbles: true
3283
- })
3284
- );
3285
- };
3286
- let currentFocusedIndex = -1;
3287
- const setItemFocus = (index2) => {
3288
- items.forEach((item, i) => {
3289
- item.setAttribute("tabindex", i === index2 ? "0" : "-1");
3290
- });
3291
- if (items[index2]) {
3292
- items[index2].focus();
3293
- currentFocusedIndex = index2;
3294
- }
3295
- };
3296
- const commitCustomValue = (inputEl) => {
3297
- const finalValue = inputEl.value.trim();
3298
- let normSelected = getNormalizedSelected();
3299
- const toggleBtn = Array.from(items).find(isToggleBtn);
3300
- const toggleVal = toggleBtn ? toggleBtn.getAttribute("data-value") : null;
3301
- const standardValues = Array.from(items).filter((i) => !isToggleBtn(i)).map((i) => i.getAttribute("data-value"));
3302
- const customValues = normSelected.filter(
3303
- (val) => !standardValues.includes(val) && val !== "" && val !== toggleVal
3304
- );
3305
- const primaryCustomValue = customValues[customValues.length - 1];
3306
- if (primaryCustomValue) {
3307
- normSelected = normSelected.filter((v) => v !== primaryCustomValue);
3308
- }
3309
- if (finalValue !== "") {
3310
- if (!normSelected.includes(finalValue)) {
3311
- normSelected.push(finalValue);
3312
- }
3313
- } else {
3314
- if (toggleVal) {
3315
- normSelected = normSelected.filter((v) => v !== toggleVal);
3316
- }
3317
- }
3318
- if (isMultiple) {
3319
- selectedValue = normSelected.join(",");
3320
- } else {
3321
- selectedValue = finalValue;
3322
- }
3323
- updateUI();
3324
- const changeEvent = new CustomEvent(`${PREFIX5}-chip:change`, {
3325
- detail: { value: isMultiple ? getNormalizedSelected() : selectedValue },
3326
- bubbles: true
3327
- });
3328
- container.dispatchEvent(changeEvent);
3329
- };
3330
- items.forEach((item, index2) => {
3331
- item.addEventListener("click", (e) => {
3332
- if (item.hasAttribute("disabled")) return;
3333
- currentFocusedIndex = index2;
3334
- const val = item.getAttribute("data-value");
3335
- if (showCustomization && isToggleBtn(item)) {
3336
- const normSelected = getNormalizedSelected();
3337
- const standardValues = Array.from(items).filter((i) => !isToggleBtn(i)).map((i) => i.getAttribute("data-value"));
3338
- const customValues = normSelected.filter(
3339
- (v) => !standardValues.includes(v) && v !== "" && v !== val
3340
- );
3341
- const isInputVisible = normSelected.includes(val) || customValues.length > 0;
3342
- if (!isInputVisible) {
3343
- handleSelect(val);
3344
- }
3345
- } else {
3346
- handleSelect(val);
3347
- }
3348
- });
3349
- item.addEventListener("keydown", (e) => {
3350
- if (item.hasAttribute("disabled")) return;
3351
- if (e.key === "ArrowRight" || e.key === "ArrowDown") {
3352
- e.preventDefault();
3353
- let nextIndex = (index2 + 1) % items.length;
3354
- while (items[nextIndex].hasAttribute("disabled") && nextIndex !== index2) {
3355
- nextIndex = (nextIndex + 1) % items.length;
3356
- }
3357
- setItemFocus(nextIndex);
3358
- } else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
3359
- e.preventDefault();
3360
- let prevIndex = (index2 - 1 + items.length) % items.length;
3361
- while (items[prevIndex].hasAttribute("disabled") && prevIndex !== index2) {
3362
- prevIndex = (prevIndex - 1 + items.length) % items.length;
3363
- }
3364
- setItemFocus(prevIndex);
3365
- }
3366
- if (e.key === " " || e.key === "Enter") {
3367
- e.preventDefault();
3368
- item.click();
3369
- }
3370
- });
3371
- });
3372
- updateUI();
3373
- container.__inaChipInitialized = true;
3374
- });
3375
- }
3376
-
3377
3201
  // src/js/components/stateful/pagination.js
3378
3202
  function initPagination() {
3379
3203
  document.querySelectorAll(`.${PREFIX}-pagination`).forEach((container) => {
@@ -3596,6 +3420,567 @@ function initPagination() {
3596
3420
  });
3597
3421
  }
3598
3422
 
3423
+ // src/js/utils/countries.js
3424
+ var COUNTRIES = [
3425
+ { code: "ID", name: "Indonesia", dialCode: "+62" },
3426
+ { code: "AF", name: "Afghanistan", dialCode: "+93" },
3427
+ { code: "AL", name: "Albania", dialCode: "+355" },
3428
+ { code: "DZ", name: "Algeria", dialCode: "+213" },
3429
+ { code: "AS", name: "American Samoa", dialCode: "+1684" },
3430
+ { code: "AD", name: "Andorra", dialCode: "+376" },
3431
+ { code: "AO", name: "Angola", dialCode: "+244" },
3432
+ { code: "AI", name: "Anguilla", dialCode: "+1264" },
3433
+ { code: "AG", name: "Antigua and Barbuda", dialCode: "+1268" },
3434
+ { code: "AR", name: "Argentina", dialCode: "+54" },
3435
+ { code: "AM", name: "Armenia", dialCode: "+374" },
3436
+ { code: "AW", name: "Aruba", dialCode: "+297" },
3437
+ { code: "AU", name: "Australia", dialCode: "+61" },
3438
+ { code: "AT", name: "Austria", dialCode: "+43" },
3439
+ { code: "AZ", name: "Azerbaijan", dialCode: "+994" },
3440
+ { code: "BS", name: "Bahamas", dialCode: "+1242" },
3441
+ { code: "BH", name: "Bahrain", dialCode: "+973" },
3442
+ { code: "BD", name: "Bangladesh", dialCode: "+880" },
3443
+ { code: "BB", name: "Barbados", dialCode: "+1246" },
3444
+ { code: "BY", name: "Belarus", dialCode: "+375" },
3445
+ { code: "BE", name: "Belgium", dialCode: "+32" },
3446
+ { code: "BZ", name: "Belize", dialCode: "+501" },
3447
+ { code: "BJ", name: "Benin", dialCode: "+229" },
3448
+ { code: "BM", name: "Bermuda", dialCode: "+1441" },
3449
+ { code: "BT", name: "Bhutan", dialCode: "+975" },
3450
+ { code: "BO", name: "Bolivia", dialCode: "+591" },
3451
+ { code: "BA", name: "Bosnia and Herzegovina", dialCode: "+387" },
3452
+ { code: "BW", name: "Botswana", dialCode: "+267" },
3453
+ { code: "BR", name: "Brazil", dialCode: "+55" },
3454
+ { code: "IO", name: "British Indian Ocean Territory", dialCode: "+246" },
3455
+ { code: "BN", name: "Brunei Darussalam", dialCode: "+673" },
3456
+ { code: "BG", name: "Bulgaria", dialCode: "+359" },
3457
+ { code: "BF", name: "Burkina Faso", dialCode: "+226" },
3458
+ { code: "BI", name: "Burundi", dialCode: "+257" },
3459
+ { code: "KH", name: "Cambodia", dialCode: "+855" },
3460
+ { code: "CM", name: "Cameroon", dialCode: "+237" },
3461
+ { code: "CA", name: "Canada", dialCode: "+1" },
3462
+ { code: "CV", name: "Cape Verde", dialCode: "+238" },
3463
+ { code: "KY", name: "Cayman Islands", dialCode: "+1345" },
3464
+ { code: "CF", name: "Central African Republic", dialCode: "+236" },
3465
+ { code: "TD", name: "Chad", dialCode: "+235" },
3466
+ { code: "CL", name: "Chile", dialCode: "+56" },
3467
+ { code: "CN", name: "China", dialCode: "+86" },
3468
+ { code: "CX", name: "Christmas Island", dialCode: "+61" },
3469
+ { code: "CC", name: "Cocos (Keeling) Islands", dialCode: "+61" },
3470
+ { code: "CO", name: "Colombia", dialCode: "+57" },
3471
+ { code: "KM", name: "Comoros", dialCode: "+269" },
3472
+ { code: "CG", name: "Congo", dialCode: "+242" },
3473
+ { code: "CD", name: "Congo, Democratic Republic of the", dialCode: "+243" },
3474
+ { code: "CK", name: "Cook Islands", dialCode: "+682" },
3475
+ { code: "CR", name: "Costa Rica", dialCode: "+506" },
3476
+ { code: "CI", name: "Cote d'Ivoire", dialCode: "+225" },
3477
+ { code: "HR", name: "Croatia", dialCode: "+385" },
3478
+ { code: "CU", name: "Cuba", dialCode: "+53" },
3479
+ { code: "CY", name: "Cyprus", dialCode: "+357" },
3480
+ { code: "CZ", name: "Czech Republic", dialCode: "+420" },
3481
+ { code: "DK", name: "Denmark", dialCode: "+45" },
3482
+ { code: "DJ", name: "Djibouti", dialCode: "+253" },
3483
+ { code: "DM", name: "Dominica", dialCode: "+1767" },
3484
+ { code: "DO", name: "Dominican Republic", dialCode: "+1" },
3485
+ { code: "EC", name: "Ecuador", dialCode: "+593" },
3486
+ { code: "EG", name: "Egypt", dialCode: "+20" },
3487
+ { code: "SV", name: "El Salvador", dialCode: "+503" },
3488
+ { code: "GQ", name: "Equatorial Guinea", dialCode: "+240" },
3489
+ { code: "ER", name: "Eritrea", dialCode: "+291" },
3490
+ { code: "EE", name: "Estonia", dialCode: "+372" },
3491
+ { code: "ET", name: "Ethiopia", dialCode: "+251" },
3492
+ { code: "FK", name: "Falkland Islands (Malvinas)", dialCode: "+500" },
3493
+ { code: "FO", name: "Faroe Islands", dialCode: "+298" },
3494
+ { code: "FJ", name: "Fiji", dialCode: "+679" },
3495
+ { code: "FI", name: "Finland", dialCode: "+358" },
3496
+ { code: "FR", name: "France", dialCode: "+33" },
3497
+ { code: "GF", name: "French Guiana", dialCode: "+594" },
3498
+ { code: "PF", name: "French Polynesia", dialCode: "+689" },
3499
+ { code: "GA", name: "Gabon", dialCode: "+241" },
3500
+ { code: "GM", name: "Gambia", dialCode: "+220" },
3501
+ { code: "GE", name: "Georgia", dialCode: "+995" },
3502
+ { code: "DE", name: "Germany", dialCode: "+49" },
3503
+ { code: "GH", name: "Ghana", dialCode: "+233" },
3504
+ { code: "GI", name: "Gibraltar", dialCode: "+350" },
3505
+ { code: "GR", name: "Greece", dialCode: "+30" },
3506
+ { code: "GL", name: "Greenland", dialCode: "+299" },
3507
+ { code: "GD", name: "Grenada", dialCode: "+1473" },
3508
+ { code: "GP", name: "Guadeloupe", dialCode: "+590" },
3509
+ { code: "GU", name: "Guam", dialCode: "+1671" },
3510
+ { code: "GT", name: "Guatemala", dialCode: "+502" },
3511
+ { code: "GG", name: "Guernsey", dialCode: "+44" },
3512
+ { code: "GN", name: "Guinea", dialCode: "+224" },
3513
+ { code: "GW", name: "Guinea-Bissau", dialCode: "+245" },
3514
+ { code: "GY", name: "Guyana", dialCode: "+592" },
3515
+ { code: "HT", name: "Haiti", dialCode: "+509" },
3516
+ { code: "VA", name: "Holy See (Vatican City State)", dialCode: "+379" },
3517
+ { code: "HN", name: "Honduras", dialCode: "+504" },
3518
+ { code: "HK", name: "Hong Kong", dialCode: "+852" },
3519
+ { code: "HU", name: "Hungary", dialCode: "+36" },
3520
+ { code: "IS", name: "Iceland", dialCode: "+354" },
3521
+ { code: "IN", name: "India", dialCode: "+91" },
3522
+ { code: "IR", name: "Iran, Islamic Republic of", dialCode: "+98" },
3523
+ { code: "IQ", name: "Iraq", dialCode: "+964" },
3524
+ { code: "IE", name: "Ireland", dialCode: "+353" },
3525
+ { code: "IM", name: "Isle of Man", dialCode: "+44" },
3526
+ { code: "IL", name: "Israel", dialCode: "+972" },
3527
+ { code: "IT", name: "Italy", dialCode: "+39" },
3528
+ { code: "JM", name: "Jamaica", dialCode: "+1876" },
3529
+ { code: "JP", name: "Japan", dialCode: "+81" },
3530
+ { code: "JE", name: "Jersey", dialCode: "+44" },
3531
+ { code: "JO", name: "Jordan", dialCode: "+962" },
3532
+ { code: "KZ", name: "Kazakhstan", dialCode: "+7" },
3533
+ { code: "KE", name: "Kenya", dialCode: "+254" },
3534
+ { code: "KI", name: "Kiribati", dialCode: "+686" },
3535
+ { code: "KP", name: "Korea, Democratic People's Republic of", dialCode: "+850" },
3536
+ { code: "KR", name: "Korea, Republic of", dialCode: "+82" },
3537
+ { code: "KW", name: "Kuwait", dialCode: "+965" },
3538
+ { code: "KG", name: "Kyrgyzstan", dialCode: "+996" },
3539
+ { code: "LA", name: "Laos", dialCode: "+856" },
3540
+ { code: "LV", name: "Latvia", dialCode: "+371" },
3541
+ { code: "LB", name: "Lebanon", dialCode: "+961" },
3542
+ { code: "LS", name: "Lesotho", dialCode: "+266" },
3543
+ { code: "LR", name: "Liberia", dialCode: "+231" },
3544
+ { code: "LY", name: "Libyan Arab Jamahiriya", dialCode: "+218" },
3545
+ { code: "LI", name: "Liechtenstein", dialCode: "+423" },
3546
+ { code: "LT", name: "Lithuania", dialCode: "+370" },
3547
+ { code: "LU", name: "Luxembourg", dialCode: "+352" },
3548
+ { code: "MO", name: "Macao", dialCode: "+853" },
3549
+ { code: "MK", name: "Macedonia, the Former Yugoslav Republic of", dialCode: "+389" },
3550
+ { code: "MG", name: "Madagascar", dialCode: "+261" },
3551
+ { code: "MW", name: "Malawi", dialCode: "+265" },
3552
+ { code: "MY", name: "Malaysia", dialCode: "+60" },
3553
+ { code: "MV", name: "Maldives", dialCode: "+960" },
3554
+ { code: "ML", name: "Mali", dialCode: "+223" },
3555
+ { code: "MT", name: "Malta", dialCode: "+356" },
3556
+ { code: "MH", name: "Marshall Islands", dialCode: "+692" },
3557
+ { code: "MQ", name: "Martinique", dialCode: "+596" },
3558
+ { code: "MR", name: "Mauritania", dialCode: "+222" },
3559
+ { code: "MU", name: "Mauritius", dialCode: "+230" },
3560
+ { code: "YT", name: "Mayotte", dialCode: "+262" },
3561
+ { code: "MX", name: "Mexico", dialCode: "+52" },
3562
+ { code: "FM", name: "Micronesia, Federated States of", dialCode: "+691" },
3563
+ { code: "MD", name: "Moldova, Republic of", dialCode: "+373" },
3564
+ { code: "MC", name: "Monaco", dialCode: "+377" },
3565
+ { code: "MN", name: "Mongolia", dialCode: "+976" },
3566
+ { code: "ME", name: "Montenegro", dialCode: "+382" },
3567
+ { code: "MS", name: "Montserrat", dialCode: "+1664" },
3568
+ { code: "MA", name: "Morocco", dialCode: "+212" },
3569
+ { code: "MZ", name: "Mozambique", dialCode: "+258" },
3570
+ { code: "MM", name: "Myanmar", dialCode: "+95" },
3571
+ { code: "NA", name: "Namibia", dialCode: "+264" },
3572
+ { code: "NR", name: "Nauru", dialCode: "+674" },
3573
+ { code: "NP", name: "Nepal", dialCode: "+977" },
3574
+ { code: "NL", name: "Netherlands", dialCode: "+31" },
3575
+ { code: "NC", name: "New Caledonia", dialCode: "+687" },
3576
+ { code: "NZ", name: "New Zealand", dialCode: "+64" },
3577
+ { code: "NI", name: "Nicaragua", dialCode: "+505" },
3578
+ { code: "NE", name: "Niger", dialCode: "+227" },
3579
+ { code: "NG", name: "Nigeria", dialCode: "+234" },
3580
+ { code: "NU", name: "Niue", dialCode: "+683" },
3581
+ { code: "NF", name: "Norfolk Island", dialCode: "+672" },
3582
+ { code: "MP", name: "Northern Mariana Islands", dialCode: "+1670" },
3583
+ { code: "NO", name: "Norway", dialCode: "+47" },
3584
+ { code: "OM", name: "Oman", dialCode: "+968" },
3585
+ { code: "PK", name: "Pakistan", dialCode: "+92" },
3586
+ { code: "PW", name: "Palau", dialCode: "+680" },
3587
+ { code: "PS", name: "Palestine", dialCode: "+970" },
3588
+ { code: "PA", name: "Panama", dialCode: "+507" },
3589
+ { code: "PG", name: "Papua New Guinea", dialCode: "+675" },
3590
+ { code: "PY", name: "Paraguay", dialCode: "+595" },
3591
+ { code: "PE", name: "Peru", dialCode: "+51" },
3592
+ { code: "PH", name: "Philippines", dialCode: "+63" },
3593
+ { code: "PN", name: "Pitcairn", dialCode: "+870" },
3594
+ { code: "PL", name: "Poland", dialCode: "+48" },
3595
+ { code: "PT", name: "Portugal", dialCode: "+351" },
3596
+ { code: "PR", name: "Puerto Rico", dialCode: "+1939" },
3597
+ { code: "QA", name: "Qatar", dialCode: "+974" },
3598
+ { code: "RE", name: "Reunion", dialCode: "+262" },
3599
+ { code: "RO", name: "Romania", dialCode: "+40" },
3600
+ { code: "RU", name: "Russian Federation", dialCode: "+7" },
3601
+ { code: "RW", name: "Rwanda", dialCode: "+250" },
3602
+ { code: "BL", name: "Saint Barthelemy", dialCode: "+590" },
3603
+ { code: "SH", name: "Saint Helena", dialCode: "+290" },
3604
+ { code: "KN", name: "Saint Kitts and Nevis", dialCode: "+1869" },
3605
+ { code: "LC", name: "Saint Lucia", dialCode: "+1758" },
3606
+ { code: "MF", name: "Saint Martin", dialCode: "+590" },
3607
+ { code: "PM", name: "Saint Pierre and Miquelon", dialCode: "+508" },
3608
+ { code: "VC", name: "Saint Vincent and the Grenadines", dialCode: "+1784" },
3609
+ { code: "WS", name: "Samoa", dialCode: "+685" },
3610
+ { code: "SM", name: "San Marino", dialCode: "+378" },
3611
+ { code: "ST", name: "Sao Tome and Principe", dialCode: "+239" },
3612
+ { code: "SA", name: "Saudi Arabia", dialCode: "+966" },
3613
+ { code: "SN", name: "Senegal", dialCode: "+221" },
3614
+ { code: "RS", name: "Serbia", dialCode: "+381" },
3615
+ { code: "SC", name: "Seychelles", dialCode: "+248" },
3616
+ { code: "SL", name: "Sierra Leone", dialCode: "+232" },
3617
+ { code: "SG", name: "Singapore", dialCode: "+65" },
3618
+ { code: "SK", name: "Slovakia", dialCode: "+421" },
3619
+ { code: "SI", name: "Slovenia", dialCode: "+386" },
3620
+ { code: "SB", name: "Solomon Islands", dialCode: "+677" },
3621
+ { code: "SO", name: "Somalia", dialCode: "+252" },
3622
+ { code: "ZA", name: "South Africa", dialCode: "+27" },
3623
+ { code: "GS", name: "South Georgia and the South Sandwich Islands", dialCode: "+500" },
3624
+ { code: "ES", name: "Spain", dialCode: "+34" },
3625
+ { code: "LK", name: "Sri Lanka", dialCode: "+94" },
3626
+ { code: "SD", name: "Sudan", dialCode: "+249" },
3627
+ { code: "SR", name: "Suriname", dialCode: "+597" },
3628
+ { code: "SJ", name: "Svalbard and Jan Mayen", dialCode: "+47" },
3629
+ { code: "SZ", name: "Swaziland", dialCode: "+268" },
3630
+ { code: "SE", name: "Sweden", dialCode: "+46" },
3631
+ { code: "CH", name: "Switzerland", dialCode: "+41" },
3632
+ { code: "SY", name: "Syrian Arab Republic", dialCode: "+963" },
3633
+ { code: "TW", name: "Taiwan, Province of China", dialCode: "+886" },
3634
+ { code: "TJ", name: "Tajikistan", dialCode: "+992" },
3635
+ { code: "TZ", name: "Tanzania, United Republic of", dialCode: "+255" },
3636
+ { code: "TH", name: "Thailand", dialCode: "+66" },
3637
+ { code: "TL", name: "Timor-Leste", dialCode: "+670" },
3638
+ { code: "TG", name: "Togo", dialCode: "+228" },
3639
+ { code: "TK", name: "Tokelau", dialCode: "+690" },
3640
+ { code: "TO", name: "Tonga", dialCode: "+676" },
3641
+ { code: "TT", name: "Trinidad and Tobago", dialCode: "+1868" },
3642
+ { code: "TN", name: "Tunisia", dialCode: "+216" },
3643
+ { code: "TR", name: "Turkey", dialCode: "+90" },
3644
+ { code: "TM", name: "Turkmenistan", dialCode: "+993" },
3645
+ { code: "TC", name: "Turks and Caicos Islands", dialCode: "+1649" },
3646
+ { code: "TV", name: "Tuvalu", dialCode: "+688" },
3647
+ { code: "UG", name: "Uganda", dialCode: "+256" },
3648
+ { code: "UA", name: "Ukraine", dialCode: "+380" },
3649
+ { code: "AE", name: "United Arab Emirates", dialCode: "+971" },
3650
+ { code: "GB", name: "United Kingdom", dialCode: "+44" },
3651
+ { code: "US", name: "United States", dialCode: "+1" },
3652
+ { code: "UY", name: "Uruguay", dialCode: "+598" },
3653
+ { code: "UZ", name: "Uzbekistan", dialCode: "+998" },
3654
+ { code: "VU", name: "Vanuatu", dialCode: "+678" },
3655
+ { code: "VE", name: "Venezuela", dialCode: "+58" },
3656
+ { code: "VN", name: "Vietnam", dialCode: "+84" },
3657
+ { code: "VG", name: "Virgin Islands, British", dialCode: "+1284" },
3658
+ { code: "VI", name: "Virgin Islands, U.S.", dialCode: "+1340" },
3659
+ { code: "WF", name: "Wallis and Futuna", dialCode: "+681" },
3660
+ { code: "EH", name: "Western Sahara", dialCode: "+212" },
3661
+ { code: "YE", name: "Yemen", dialCode: "+967" },
3662
+ { code: "ZM", name: "Zambia", dialCode: "+260" },
3663
+ { code: "ZW", name: "Zimbabwe", dialCode: "+263" }
3664
+ ];
3665
+
3666
+ // src/js/utils/flags.js
3667
+ var flagCache = {};
3668
+ var getFlag = async (code) => {
3669
+ if (flagCache[code]) {
3670
+ return flagCache[code];
3671
+ }
3672
+ try {
3673
+ const flag = await import(`@idds/styles/assets/flags/${code.toLowerCase()}.svg`);
3674
+ flagCache[code] = flag.default;
3675
+ return flag.default;
3676
+ } catch (error) {
3677
+ console.error(`[IDDS PhoneInput] Failed to load flag for: ${code}`, error);
3678
+ return "";
3679
+ }
3680
+ };
3681
+
3682
+ // src/js/components/stateful/phone-input.js
3683
+ var PhoneInput = class {
3684
+ constructor(selectorOrElement, options = {}) {
3685
+ this.container = typeof selectorOrElement === "string" ? document.querySelector(selectorOrElement) : selectorOrElement;
3686
+ if (!this.container) {
3687
+ console.warn("[IDDS PhoneInput] Container not found:", selectorOrElement);
3688
+ return;
3689
+ }
3690
+ if (this.container.dataset.initialized === "true") {
3691
+ return;
3692
+ }
3693
+ this.container.dataset.initialized = "true";
3694
+ this.options = {
3695
+ modelValue: this.container.dataset.value || "",
3696
+ label: this.container.dataset.label || "",
3697
+ placeholder: this.container.getAttribute("placeholder") || "812-3456-7890",
3698
+ size: this.container.dataset.size || "md",
3699
+ status: this.container.dataset.status || "neutral",
3700
+ disabled: this.container.hasAttribute("disabled") || false,
3701
+ readonly: this.container.hasAttribute("readonly") || false,
3702
+ required: this.container.hasAttribute("required") || false,
3703
+ defaultCountry: this.container.dataset.defaultCountry || "ID",
3704
+ allowClear: this.container.dataset.allowClear !== "false",
3705
+ countries: COUNTRIES,
3706
+ onChange: null,
3707
+ ...options
3708
+ };
3709
+ this.state = {
3710
+ isOpen: false,
3711
+ countrySearch: "",
3712
+ selectedCountry: this.options.countries.find((c) => c.code === this.options.defaultCountry) || this.options.countries[0],
3713
+ phoneNumber: ""
3714
+ };
3715
+ this.elements = {};
3716
+ this.inputId = `phone-input-${Math.random().toString(36).substr(2, 9)}`;
3717
+ this.init();
3718
+ }
3719
+ async init() {
3720
+ this.initDOM();
3721
+ this.initEvents();
3722
+ this.syncValueFromOptions();
3723
+ await this.updateFlag();
3724
+ }
3725
+ initDOM() {
3726
+ if (this.options.label) {
3727
+ const label = document.createElement("label");
3728
+ label.className = `${PREFIX}-phone-input__label`;
3729
+ label.setAttribute("for", this.inputId);
3730
+ label.textContent = this.options.label;
3731
+ if (this.options.required) {
3732
+ const asterisk = document.createElement("span");
3733
+ asterisk.className = `${PREFIX}-phone-input__required`;
3734
+ asterisk.textContent = "*";
3735
+ label.appendChild(asterisk);
3736
+ }
3737
+ this.container.appendChild(label);
3738
+ }
3739
+ const wrapper = document.createElement("div");
3740
+ wrapper.className = `${PREFIX}-phone-input__wrapper ${PREFIX}-phone-input__wrapper--size-${this.options.size}`;
3741
+ if (this.options.status !== "neutral") {
3742
+ wrapper.classList.add(`${PREFIX}-phone-input__wrapper--status-${this.options.status}`);
3743
+ }
3744
+ if (this.options.disabled) {
3745
+ wrapper.classList.add(`${PREFIX}-phone-input__wrapper--disabled`);
3746
+ }
3747
+ const selector = document.createElement("div");
3748
+ selector.className = `${PREFIX}-phone-input__country-selector`;
3749
+ const countryBtn = document.createElement("button");
3750
+ countryBtn.type = "button";
3751
+ countryBtn.className = `${PREFIX}-phone-input__country-button`;
3752
+ countryBtn.setAttribute("aria-label", "Pilih negara");
3753
+ countryBtn.setAttribute("aria-haspopup", "listbox");
3754
+ countryBtn.setAttribute("aria-expanded", "false");
3755
+ if (this.options.disabled || this.options.readonly) countryBtn.disabled = true;
3756
+ const flagImg = document.createElement("img");
3757
+ flagImg.className = `${PREFIX}-phone-input__country-flag-img`;
3758
+ flagImg.width = 24;
3759
+ flagImg.height = 18;
3760
+ flagImg.alt = "";
3761
+ const dialCode = document.createElement("span");
3762
+ dialCode.className = `${PREFIX}-phone-input__country-code`;
3763
+ dialCode.textContent = this.state.selectedCountry.dialCode;
3764
+ const chevron = document.createElement("div");
3765
+ 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">
3766
+ <path d="M6 9L12 15L18 9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3767
+ </svg>`;
3768
+ countryBtn.appendChild(flagImg);
3769
+ countryBtn.appendChild(dialCode);
3770
+ countryBtn.appendChild(chevron.firstChild);
3771
+ selector.appendChild(countryBtn);
3772
+ wrapper.appendChild(selector);
3773
+ const divider = document.createElement("div");
3774
+ divider.className = `${PREFIX}-phone-input__divider`;
3775
+ wrapper.appendChild(divider);
3776
+ const input = document.createElement("input");
3777
+ input.type = "tel";
3778
+ input.id = this.inputId;
3779
+ input.placeholder = this.options.placeholder;
3780
+ input.className = `${PREFIX}-phone-input__input`;
3781
+ if (this.options.disabled) input.disabled = true;
3782
+ if (this.options.readonly) input.readOnly = true;
3783
+ wrapper.appendChild(input);
3784
+ if (this.options.allowClear) {
3785
+ const clearBtn = document.createElement("button");
3786
+ clearBtn.type = "button";
3787
+ clearBtn.className = `${PREFIX}-phone-input__clear-button`;
3788
+ clearBtn.setAttribute("aria-label", "Hapus nomor telepon");
3789
+ 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">
3790
+ <line x1="18" y1="6" x2="6" y2="18"></line>
3791
+ <line x1="6" y1="6" x2="18" y2="18"></line>
3792
+ </svg>`;
3793
+ clearBtn.style.display = "none";
3794
+ wrapper.appendChild(clearBtn);
3795
+ this.elements.clearBtn = clearBtn;
3796
+ }
3797
+ this.container.appendChild(wrapper);
3798
+ const panel = document.createElement("div");
3799
+ panel.className = `${PREFIX}-phone-input__country-dropdown`;
3800
+ panel.style.display = "none";
3801
+ const searchDiv = document.createElement("div");
3802
+ searchDiv.className = `${PREFIX}-phone-input__country-search`;
3803
+ const searchInput = document.createElement("input");
3804
+ searchInput.type = "text";
3805
+ searchInput.placeholder = "Cari";
3806
+ searchInput.className = `${PREFIX}-phone-input__country-search-input`;
3807
+ searchDiv.appendChild(searchInput);
3808
+ panel.appendChild(searchDiv);
3809
+ const list = document.createElement("div");
3810
+ list.className = `${PREFIX}-phone-input__country-list`;
3811
+ list.setAttribute("role", "listbox");
3812
+ panel.appendChild(list);
3813
+ selector.appendChild(panel);
3814
+ this.elements.wrapper = wrapper;
3815
+ this.elements.countryBtn = countryBtn;
3816
+ this.elements.flagImg = flagImg;
3817
+ this.elements.dialCode = dialCode;
3818
+ this.elements.input = input;
3819
+ this.elements.panel = panel;
3820
+ this.elements.searchInput = searchInput;
3821
+ this.elements.list = list;
3822
+ this.elements.chevron = selector.querySelector(`.${PREFIX}-phone-input__country-chevron`);
3823
+ }
3824
+ initEvents() {
3825
+ this.elements.countryBtn.addEventListener("click", (e) => {
3826
+ e.stopPropagation();
3827
+ this.toggleDropdown();
3828
+ });
3829
+ this.elements.searchInput.addEventListener("input", (e) => {
3830
+ this.state.countrySearch = e.target.value;
3831
+ this.renderCountryList();
3832
+ });
3833
+ this.elements.input.addEventListener("input", (e) => {
3834
+ this.handleInput(e);
3835
+ });
3836
+ if (this.elements.clearBtn) {
3837
+ this.elements.clearBtn.addEventListener("click", () => {
3838
+ this.clear();
3839
+ });
3840
+ }
3841
+ document.addEventListener("click", (e) => {
3842
+ if (!this.elements.wrapper.contains(e.target)) {
3843
+ this.closeDropdown();
3844
+ }
3845
+ });
3846
+ }
3847
+ async updateFlag() {
3848
+ const url = await getFlag(this.state.selectedCountry.code);
3849
+ this.elements.flagImg.src = url;
3850
+ this.elements.flagImg.alt = this.state.selectedCountry.name;
3851
+ this.elements.dialCode.textContent = this.state.selectedCountry.dialCode;
3852
+ }
3853
+ toggleDropdown() {
3854
+ if (this.state.isOpen) {
3855
+ this.closeDropdown();
3856
+ } else {
3857
+ this.openDropdown();
3858
+ }
3859
+ }
3860
+ openDropdown() {
3861
+ this.state.isOpen = true;
3862
+ this.elements.panel.style.display = "flex";
3863
+ this.elements.countryBtn.setAttribute("aria-expanded", "true");
3864
+ this.elements.chevron.classList.add(`${PREFIX}-phone-input__country-chevron--open`);
3865
+ this.state.countrySearch = "";
3866
+ this.elements.searchInput.value = "";
3867
+ this.renderCountryList();
3868
+ setTimeout(() => this.elements.searchInput.focus(), 0);
3869
+ }
3870
+ closeDropdown() {
3871
+ this.state.isOpen = false;
3872
+ this.elements.panel.style.display = "none";
3873
+ this.elements.countryBtn.setAttribute("aria-expanded", "false");
3874
+ this.elements.chevron.classList.remove(`${PREFIX}-phone-input__country-chevron--open`);
3875
+ }
3876
+ renderCountryList() {
3877
+ const list = this.elements.list;
3878
+ list.innerHTML = "";
3879
+ const filtered = this.options.countries.filter(
3880
+ (c) => c.name.toLowerCase().includes(this.state.countrySearch.toLowerCase()) || c.dialCode.includes(this.state.countrySearch) || c.code.toLowerCase().includes(this.state.countrySearch.toLowerCase())
3881
+ );
3882
+ filtered.forEach(async (country) => {
3883
+ const option = document.createElement("button");
3884
+ option.type = "button";
3885
+ option.className = `${PREFIX}-phone-input__country-option`;
3886
+ if (country.code === this.state.selectedCountry.code) {
3887
+ option.classList.add(`${PREFIX}-phone-input__country-option--selected`);
3888
+ }
3889
+ option.setAttribute("role", "option");
3890
+ option.setAttribute("aria-selected", country.code === this.state.selectedCountry.code ? "true" : "false");
3891
+ const flag = document.createElement("img");
3892
+ flag.className = `${PREFIX}-phone-input__country-flag-img`;
3893
+ flag.width = 20;
3894
+ flag.height = 15;
3895
+ getFlag(country.code).then((url) => flag.src = url);
3896
+ const name = document.createElement("span");
3897
+ name.className = `${PREFIX}-phone-input__country-name`;
3898
+ name.textContent = `${country.name} (${country.code})`;
3899
+ const code = document.createElement("span");
3900
+ code.className = `${PREFIX}-phone-input__country-dial-code`;
3901
+ code.textContent = country.dialCode;
3902
+ option.appendChild(flag);
3903
+ option.appendChild(name);
3904
+ option.appendChild(code);
3905
+ option.addEventListener("click", () => {
3906
+ this.selectCountry(country);
3907
+ });
3908
+ list.appendChild(option);
3909
+ });
3910
+ }
3911
+ selectCountry(country) {
3912
+ this.state.selectedCountry = country;
3913
+ this.updateFlag();
3914
+ this.closeDropdown();
3915
+ this.elements.input.focus();
3916
+ this.triggerChange();
3917
+ }
3918
+ formatPhoneNumber(value) {
3919
+ const clean = value.replace(/\D/g, "");
3920
+ if (clean.length > 7) {
3921
+ return clean.replace(/^(\d{3})(\d{4})(.*)/, "$1-$2-$3");
3922
+ } else if (clean.length > 3) {
3923
+ return clean.replace(/^(\d{3})(.*)/, "$1-$2");
3924
+ }
3925
+ return clean;
3926
+ }
3927
+ handleInput(e) {
3928
+ const value = e.target.value;
3929
+ const formatted = this.formatPhoneNumber(value);
3930
+ e.target.value = formatted;
3931
+ this.state.phoneNumber = formatted;
3932
+ if (this.elements.clearBtn) {
3933
+ this.elements.clearBtn.style.display = formatted ? "flex" : "none";
3934
+ }
3935
+ this.triggerChange();
3936
+ }
3937
+ clear() {
3938
+ this.state.phoneNumber = "";
3939
+ this.elements.input.value = "";
3940
+ if (this.elements.clearBtn) {
3941
+ this.elements.clearBtn.style.display = "none";
3942
+ }
3943
+ this.elements.input.focus();
3944
+ this.triggerChange();
3945
+ }
3946
+ syncValueFromOptions() {
3947
+ if (this.options.modelValue) {
3948
+ let val = this.options.modelValue;
3949
+ const dial = this.state.selectedCountry.dialCode;
3950
+ if (val.startsWith(dial)) {
3951
+ val = val.substring(dial.length);
3952
+ }
3953
+ this.state.phoneNumber = this.formatPhoneNumber(val);
3954
+ this.elements.input.value = this.state.phoneNumber;
3955
+ if (this.elements.clearBtn && this.state.phoneNumber) {
3956
+ this.elements.clearBtn.style.display = "flex";
3957
+ }
3958
+ }
3959
+ }
3960
+ triggerChange() {
3961
+ const cleanLocal = this.state.phoneNumber.replace(/\D/g, "");
3962
+ const cleanNoZero = cleanLocal.startsWith("0") ? cleanLocal.substring(1) : cleanLocal;
3963
+ const fullValue = `${this.state.selectedCountry.dialCode}${cleanNoZero}`;
3964
+ if (this.options.onChange) {
3965
+ this.options.onChange(fullValue);
3966
+ }
3967
+ this.container.dispatchEvent(new CustomEvent("change", {
3968
+ detail: { value: fullValue, country: this.state.selectedCountry }
3969
+ }));
3970
+ }
3971
+ };
3972
+ function initPhoneInput(selectorOrElement, options = {}) {
3973
+ const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-phone-input`);
3974
+ const instances = [];
3975
+ elements.forEach((container) => {
3976
+ const instance = new PhoneInput(container, options);
3977
+ container.__phoneInputAPI = instance;
3978
+ instances.push(instance);
3979
+ });
3980
+ if (instances.length === 0) return null;
3981
+ return instances.length === 1 ? instances[0] : instances;
3982
+ }
3983
+
3599
3984
  // src/js/components/stateful/tab-vertical.js
3600
3985
  function initTabVertical() {
3601
3986
  const tabs = document.querySelectorAll(`.${PREFIX}-tab-vertical`);
@@ -3708,7 +4093,7 @@ function initTabHorizontal() {
3708
4093
 
3709
4094
  // src/js/components/stateful/table.js
3710
4095
  var Table = class {
3711
- constructor(selectorOrElement, options2 = {}) {
4096
+ constructor(selectorOrElement, options = {}) {
3712
4097
  this.container = typeof selectorOrElement === "string" ? document.querySelector(selectorOrElement) : selectorOrElement;
3713
4098
  if (!this.container) {
3714
4099
  console.warn("[IDDS Table] Container not found:", selectorOrElement);
@@ -3740,7 +4125,7 @@ var Table = class {
3740
4125
  searchContainer: null,
3741
4126
  searchButton: null,
3742
4127
  onSearch: null,
3743
- ...options2
4128
+ ...options
3744
4129
  };
3745
4130
  this.state = {
3746
4131
  currentPage: this.options.initialPage,
@@ -3859,34 +4244,43 @@ var Table = class {
3859
4244
  if (col.sortable && col.accessor) {
3860
4245
  th.classList.add(`${PREFIX}-table__header-cell--sortable`);
3861
4246
  th.setAttribute("data-sort", col.accessor);
4247
+ let sortLabel = `Urutkan ${col.header}`;
4248
+ let currentSort = "none";
4249
+ if (this.state.sortField === field) {
4250
+ currentSort = this.state.sortOrder === "asc" ? "ascending" : "descending";
4251
+ }
4252
+ th.setAttribute("aria-sort", currentSort);
3862
4253
  let sortControlsHtml = `
3863
4254
  <div class="${PREFIX}-table__sort-controls">
3864
4255
  ${col.header}
3865
4256
  <div class="${PREFIX}-table__sort-icon">
3866
- <div class="${PREFIX}-table__sort-button" data-order="asc">
4257
+ <div class="${PREFIX}-table__sort-button" data-order="asc" role="button" aria-label="Urutkan ${col.header} menaik">
3867
4258
  <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>
3868
4259
  </div>
3869
- <div class="${PREFIX}-table__sort-button ${PREFIX}-table__sort-button-right" data-order="desc">
4260
+ <div class="${PREFIX}-table__sort-button ${PREFIX}-table__sort-button-right" data-order="desc" role="button" aria-label="Urutkan ${col.header} menurun">
3870
4261
  <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>
3871
4262
  </div>
3872
4263
  </div>
3873
4264
  </div>
3874
4265
  `;
3875
4266
  th.innerHTML = sortControlsHtml;
4267
+ const ascBtn = th.querySelector('[data-order="asc"]');
4268
+ const descBtn = th.querySelector('[data-order="desc"]');
4269
+ ascBtn.addEventListener("click", (e) => {
4270
+ e.stopPropagation();
4271
+ this.handleHeaderSort(col, "asc");
4272
+ });
4273
+ descBtn.addEventListener("click", (e) => {
4274
+ e.stopPropagation();
4275
+ this.handleHeaderSort(col, "desc");
4276
+ });
3876
4277
  th.addEventListener("click", () => {
3877
- const field = col.accessor;
4278
+ let nextOrder = "asc";
3878
4279
  if (this.state.sortField === field) {
3879
- if (this.state.sortOrder === "asc") this.state.sortOrder = "desc";
3880
- else {
3881
- this.state.sortField = null;
3882
- this.state.sortOrder = null;
3883
- }
3884
- } else {
3885
- this.state.sortField = field;
3886
- this.state.sortOrder = "asc";
4280
+ if (this.state.sortOrder === "asc") nextOrder = "desc";
4281
+ else nextOrder = null;
3887
4282
  }
3888
- this.state.currentPage = 1;
3889
- this.loadData();
4283
+ this.handleHeaderSort(col, nextOrder);
3890
4284
  });
3891
4285
  } else {
3892
4286
  th.textContent = col.header;
@@ -3945,7 +4339,7 @@ var Table = class {
3945
4339
  this.updateSelectAllState();
3946
4340
  return;
3947
4341
  }
3948
- rowData.forEach((row, index2) => {
4342
+ rowData.forEach((row, index) => {
3949
4343
  const tr = document.createElement("tr");
3950
4344
  tr.className = `${PREFIX}-table__row`;
3951
4345
  if (this.options.rowClickable) {
@@ -3956,11 +4350,11 @@ var Table = class {
3956
4350
  return;
3957
4351
  }
3958
4352
  if (typeof this.options.onRowClick === "function") {
3959
- this.options.onRowClick(row, index2);
4353
+ this.options.onRowClick(row, index);
3960
4354
  }
3961
4355
  });
3962
4356
  }
3963
- const rowKeyStr = String(row[this.options.rowKey] || index2);
4357
+ const rowKeyStr = String(row[this.options.rowKey] || index);
3964
4358
  if (this.options.selectable) {
3965
4359
  const td = document.createElement("td");
3966
4360
  td.className = `${PREFIX}-table__cell`;
@@ -3986,7 +4380,7 @@ var Table = class {
3986
4380
  const td = document.createElement("td");
3987
4381
  td.className = `${PREFIX}-table__cell`;
3988
4382
  if (typeof col.render === "function") {
3989
- const content = col.render(row, index2);
4383
+ const content = col.render(row, index);
3990
4384
  if (typeof content === "string") {
3991
4385
  td.innerHTML = content;
3992
4386
  } else if (content instanceof HTMLElement) {
@@ -4132,6 +4526,13 @@ var Table = class {
4132
4526
  }
4133
4527
  );
4134
4528
  }
4529
+ handleHeaderSort(col, order) {
4530
+ const field2 = col.accessor;
4531
+ this.state.sortField = field2 ? order === null ? null : field2 : null;
4532
+ this.state.sortOrder = order;
4533
+ this.state.currentPage = 1;
4534
+ this.loadData();
4535
+ }
4135
4536
  updateSortIndicators() {
4136
4537
  const btns = this.elements.theadTr.querySelectorAll(
4137
4538
  `.${PREFIX}-table__sort-button`
@@ -4139,10 +4540,15 @@ var Table = class {
4139
4540
  btns.forEach((btn) => {
4140
4541
  const th = btn.closest("th");
4141
4542
  if (!th) return;
4142
- const field = th.getAttribute("data-sort");
4543
+ const field2 = th.getAttribute("data-sort");
4143
4544
  const order = btn.getAttribute("data-order");
4144
- const active = this.state.sortField === field && this.state.sortOrder === order;
4545
+ const active = this.state.sortField === field2 && this.state.sortOrder === order;
4145
4546
  btn.classList.toggle(`${PREFIX}-table__sort-button--active`, active);
4547
+ let currentSort = "none";
4548
+ if (this.state.sortField === field2) {
4549
+ currentSort = this.state.sortOrder === "asc" ? "ascending" : "descending";
4550
+ }
4551
+ th.setAttribute("aria-sort", currentSort);
4146
4552
  });
4147
4553
  }
4148
4554
  async loadData() {
@@ -4220,8 +4626,8 @@ var Table = class {
4220
4626
  this.triggerSelectionChange();
4221
4627
  }
4222
4628
  toggleAllSelection(checked) {
4223
- this.state.currentData.forEach((row, index2) => {
4224
- const keyStr = String(row[this.options.rowKey] || index2);
4629
+ this.state.currentData.forEach((row, index) => {
4630
+ const keyStr = String(row[this.options.rowKey] || index);
4225
4631
  if (checked) {
4226
4632
  this.state.selectedKeys.add(keyStr);
4227
4633
  this.state.selectedRows.set(keyStr, row);
@@ -4302,11 +4708,11 @@ var Table = class {
4302
4708
  };
4303
4709
  }
4304
4710
  };
4305
- function initTable(selectorOrElement, options2 = {}) {
4711
+ function initTable(selectorOrElement, options = {}) {
4306
4712
  const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-table`);
4307
4713
  const instances = [];
4308
4714
  elements.forEach((container) => {
4309
- const instance = new Table(container, options2);
4715
+ const instance = new Table(container, options);
4310
4716
  container.__tableAPI = instance;
4311
4717
  instances.push(instance);
4312
4718
  });
@@ -4340,17 +4746,17 @@ function initMonthPicker(rootSelector = `.${PREFIX}-month-picker`) {
4340
4746
  const trigger = container.querySelector(`.${PREFIX}-month-picker__trigger`);
4341
4747
  const panel = container.querySelector(`.${PREFIX}-month-picker__panel`);
4342
4748
  const grid = container.querySelector(`.${PREFIX}-month-picker__grid`);
4343
- const options2 = grid ? Array.from(
4749
+ const options = grid ? Array.from(
4344
4750
  grid.querySelectorAll(`.${PREFIX}-month-picker__month-option`)
4345
4751
  ) : [];
4346
- if (!trigger || !panel || !grid || options2.length === 0) return;
4752
+ if (!trigger || !panel || !grid || options.length === 0) return;
4347
4753
  let isPickerOpen = false;
4348
4754
  const updateText = () => {
4349
4755
  const textEl = trigger.querySelector(
4350
4756
  `.${PREFIX}-month-picker__trigger-text`
4351
4757
  );
4352
4758
  if (textEl) textEl.textContent = MONTHS_SHORT_ID[currentMonthIdx];
4353
- options2.forEach((opt, idx) => {
4759
+ options.forEach((opt, idx) => {
4354
4760
  if (idx === currentMonthIdx) {
4355
4761
  opt.classList.add(`${PREFIX}-month-picker__month-option--selected`);
4356
4762
  opt.setAttribute("aria-selected", "true");
@@ -4371,7 +4777,7 @@ function initMonthPicker(rootSelector = `.${PREFIX}-month-picker`) {
4371
4777
  panel.classList.add(`${PREFIX}-month-picker__panel--open`);
4372
4778
  trigger.setAttribute("aria-expanded", "true");
4373
4779
  setTimeout(() => {
4374
- const selectedOpt = options2.find((o) => o.tabIndex === 0);
4780
+ const selectedOpt = options.find((o) => o.tabIndex === 0);
4375
4781
  if (selectedOpt) selectedOpt.focus();
4376
4782
  }, 0);
4377
4783
  } else {
@@ -4395,7 +4801,7 @@ function initMonthPicker(rootSelector = `.${PREFIX}-month-picker`) {
4395
4801
  document.addEventListener("click", (e) => {
4396
4802
  if (!container.contains(e.target)) togglePicker(false);
4397
4803
  });
4398
- options2.forEach((btn, idx) => {
4804
+ options.forEach((btn, idx) => {
4399
4805
  btn.setAttribute("role", "option");
4400
4806
  btn.addEventListener("click", (e) => {
4401
4807
  if (disabled || readonly) return;
@@ -4438,8 +4844,8 @@ function initMonthPicker(rootSelector = `.${PREFIX}-month-picker`) {
4438
4844
  else if (e.key === "ArrowDown")
4439
4845
  nextIndex += 3;
4440
4846
  else if (e.key === "ArrowUp") nextIndex -= 3;
4441
- if (options2[nextIndex]) {
4442
- options2[nextIndex].focus();
4847
+ if (options[nextIndex]) {
4848
+ options[nextIndex].focus();
4443
4849
  }
4444
4850
  }
4445
4851
  });
@@ -4540,12 +4946,12 @@ function initYearPicker(rootSelector = `.${PREFIX}-year-picker`) {
4540
4946
  } else if (["ArrowRight", "ArrowLeft", "ArrowDown", "ArrowUp"].includes(e.key)) {
4541
4947
  e.preventDefault();
4542
4948
  e.stopPropagation();
4543
- const options2 = Array.from(
4949
+ const options = Array.from(
4544
4950
  grid.querySelectorAll(
4545
4951
  `.${PREFIX}-year-picker__year-option:not(:disabled)`
4546
4952
  )
4547
4953
  );
4548
- const currentIndex = options2.indexOf(btn);
4954
+ const currentIndex = options.indexOf(btn);
4549
4955
  if (currentIndex === -1) return;
4550
4956
  let nextIndex = currentIndex;
4551
4957
  if (e.key === "ArrowRight") nextIndex += 1;
@@ -4553,8 +4959,8 @@ function initYearPicker(rootSelector = `.${PREFIX}-year-picker`) {
4553
4959
  else if (e.key === "ArrowDown")
4554
4960
  nextIndex += 4;
4555
4961
  else if (e.key === "ArrowUp") nextIndex -= 4;
4556
- if (options2[nextIndex]) {
4557
- options2[nextIndex].focus();
4962
+ if (options[nextIndex]) {
4963
+ options[nextIndex].focus();
4558
4964
  } else {
4559
4965
  }
4560
4966
  }
@@ -4681,7 +5087,7 @@ function createToastElement({ title, message, state, style, actionHtml }) {
4681
5087
  return { toastItem, toast };
4682
5088
  }
4683
5089
  function showToast(optionsOrMessage, variant = "default", duration = 5e3) {
4684
- const options2 = typeof optionsOrMessage === "string" ? {
5090
+ const options = typeof optionsOrMessage === "string" ? {
4685
5091
  message: optionsOrMessage,
4686
5092
  state: variant,
4687
5093
  duration
@@ -4694,7 +5100,7 @@ function showToast(optionsOrMessage, variant = "default", duration = 5e3) {
4694
5100
  duration: autoCloseDuration = 5e3,
4695
5101
  position = "top-right",
4696
5102
  actionHtml = ""
4697
- } = options2;
5103
+ } = options;
4698
5104
  const container = getOrCreateContainer(position);
4699
5105
  const { toastItem, toast } = createToastElement({
4700
5106
  title,
@@ -4755,7 +5161,6 @@ function setBrandTheme(brandName) {
4755
5161
  var PREFIX = "ina";
4756
5162
  function initAll() {
4757
5163
  initAccordion();
4758
- initBanner();
4759
5164
  initButtonGroup();
4760
5165
  initCheckbox();
4761
5166
  initDatepicker();
@@ -4776,6 +5181,7 @@ function initAll() {
4776
5181
  initTab();
4777
5182
  initToggle();
4778
5183
  initPagination();
5184
+ initPhoneInput();
4779
5185
  initChip();
4780
5186
  initTabVertical();
4781
5187
  initTabHorizontal();
@@ -4786,6 +5192,7 @@ function initAll() {
4786
5192
  export {
4787
5193
  DatePicker,
4788
5194
  PREFIX,
5195
+ PhoneInput,
4789
5196
  Table,
4790
5197
  TimePicker,
4791
5198
  initAll,