@idds/js 1.2.5 → 1.6.1

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 +1177 -436
  2. package/dist/index.js +838 -383
  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,28 +1303,41 @@ 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`);
1264
1319
  input.placeholder = this.container.getAttribute("placeholder") || "Select time";
1265
1320
  if (this.options.disabled) input.disabled = true;
1266
1321
  if (this.options.readonly) input.readOnly = true;
1267
- else input.readOnly = true;
1268
1322
  wrapper.appendChild(input);
1269
1323
  if (this.options.allowClear) {
1270
- clearBtn = document.createElement("div");
1324
+ clearBtn = document.createElement("button");
1325
+ clearBtn.type = "button";
1271
1326
  clearBtn.className = `${PREFIX}-time-picker__clear-button`;
1327
+ clearBtn.setAttribute("aria-label", "Hapus waktu");
1272
1328
  clearBtn.innerHTML = this.createIcon("x");
1273
1329
  clearBtn.style.display = "none";
1274
1330
  wrapper.appendChild(clearBtn);
1275
1331
  }
1276
1332
  this.container.appendChild(wrapper);
1333
+ } else {
1334
+ wrapper.setAttribute("role", "combobox");
1335
+ wrapper.setAttribute("aria-haspopup", "listbox");
1336
+ wrapper.setAttribute("aria-expanded", "false");
1337
+ if (input && !input.id) input.id = this.inputId;
1338
+ if (clearBtn && !clearBtn.hasAttribute("aria-label")) {
1339
+ clearBtn.setAttribute("aria-label", "Hapus waktu");
1340
+ }
1277
1341
  }
1278
1342
  this.elements.wrapper = wrapper;
1279
1343
  this.elements.input = input;
@@ -1354,24 +1418,24 @@ var TimePicker = class {
1354
1418
  }
1355
1419
  }
1356
1420
  generateOptions(type) {
1357
- const options2 = [];
1421
+ const options = [];
1358
1422
  const { use12Hours, hourStep, minuteStep, secondStep } = this.options;
1359
1423
  let limit = type === "hour" ? use12Hours ? 12 : 24 : 60;
1360
1424
  let step = type === "hour" ? hourStep : type === "minute" ? minuteStep : secondStep;
1361
1425
  if (limit === 12) {
1362
1426
  for (let i = type === "hour" ? 1 : 0; i <= (type === "hour" ? 12 : 59); i += step) {
1363
- options2.push(i);
1427
+ options.push(i);
1364
1428
  }
1365
1429
  } else if (limit === 24) {
1366
1430
  for (let i = 0; i <= 23; i += step) {
1367
- options2.push(i);
1431
+ options.push(i);
1368
1432
  }
1369
1433
  } else {
1370
1434
  for (let i = 0; i <= 59; i += step) {
1371
- options2.push(i);
1435
+ options.push(i);
1372
1436
  }
1373
1437
  }
1374
- return options2;
1438
+ return options;
1375
1439
  }
1376
1440
  renderColumn(type, optionsArr) {
1377
1441
  const column = document.createElement("div");
@@ -1381,7 +1445,7 @@ var TimePicker = class {
1381
1445
  column.appendChild(colContent);
1382
1446
  const { use12Hours } = this.options;
1383
1447
  const { currentTime } = this.state;
1384
- optionsArr.forEach((optValue) => {
1448
+ optionsArr.forEach((optValue, index) => {
1385
1449
  const option = document.createElement("div");
1386
1450
  option.className = `${PREFIX}-time-picker__option`;
1387
1451
  let isSelected = false;
@@ -1427,9 +1491,9 @@ var TimePicker = class {
1427
1491
  option.classList.add(`${PREFIX}-time-picker__option--disabled`);
1428
1492
  option.setAttribute("role", "option");
1429
1493
  option.setAttribute("aria-selected", isSelected.toString());
1430
- const isFirstFocusable = index === 0 && !options.some((opt) => {
1494
+ const isFirstFocusable = index === 0 && !optionsArr.some((opt) => {
1431
1495
  if (type === "hour") {
1432
- return use12Hours ? (currentTime.hours === 0 ? 12 : currentTime.hours) === opt : currentTime.hours === opt;
1496
+ return (use12Hours && currentTime.hours === 0 ? 12 : currentTime.hours) === opt;
1433
1497
  } else if (type === "minute") {
1434
1498
  return currentTime.minutes === opt;
1435
1499
  } else if (type === "second") {
@@ -1547,6 +1611,7 @@ var TimePicker = class {
1547
1611
  this.state.isOpen = true;
1548
1612
  this.container.classList.add(`${PREFIX}-time-picker--open`);
1549
1613
  this.elements.panel.style.display = "block";
1614
+ this.elements.wrapper.setAttribute("aria-expanded", "true");
1550
1615
  this.state.currentTime = this.parseTime(this.elements.input.value);
1551
1616
  this.buildPanel();
1552
1617
  document.dispatchEvent(
@@ -1559,6 +1624,7 @@ var TimePicker = class {
1559
1624
  this.state.isOpen = false;
1560
1625
  this.container.classList.remove(`${PREFIX}-time-picker--open`);
1561
1626
  this.elements.panel.style.display = "none";
1627
+ this.elements.wrapper.setAttribute("aria-expanded", "false");
1562
1628
  }
1563
1629
  toggle() {
1564
1630
  if (this.state.isOpen) this.close();
@@ -1567,20 +1633,50 @@ var TimePicker = class {
1567
1633
  bindEvents() {
1568
1634
  this.elements.wrapper.addEventListener("click", (e) => {
1569
1635
  e.stopPropagation();
1570
- this.toggle();
1636
+ const target = e.target;
1637
+ if (target === this.elements.wrapper || target.classList.contains(`${PREFIX}-time-picker__suffix-icon`) || target.classList.contains(`${PREFIX}-time-picker__prefix-icon`)) {
1638
+ this.toggle();
1639
+ }
1571
1640
  });
1572
- if (this.elements.clearBtn && this.options.allowClear) {
1641
+ this.elements.input.addEventListener("input", (e) => {
1642
+ const val = e.target.value;
1643
+ this.state.internalValue = val;
1644
+ const timeRegex = this.options.use12Hours ? /^(\d{1,2}):(\d{2})(?::(\d{2}))?\s?(AM|PM|am|pm)?$/ : /^(\d{1,2}):(\d{2})(?::(\d{2}))?$/;
1645
+ if (timeRegex.test(val)) {
1646
+ this.state.currentTime = this.parseTime(val);
1647
+ if (this.state.isOpen) this.buildPanel();
1648
+ }
1649
+ if (this.elements.clearBtn && this.options.allowClear) {
1650
+ this.elements.clearBtn.style.display = val && !this.options.disabled ? "flex" : "none";
1651
+ }
1652
+ if (typeof this.options.onChange === "function") {
1653
+ this.options.onChange(val);
1654
+ }
1655
+ });
1656
+ this.elements.input.addEventListener("click", (e) => {
1657
+ e.stopPropagation();
1658
+ this.open();
1659
+ });
1660
+ this.elements.input.addEventListener("focus", () => {
1661
+ this.open();
1662
+ });
1663
+ this.elements.input.addEventListener("keydown", (e) => {
1664
+ if (e.key === "Enter") {
1665
+ e.preventDefault();
1666
+ if (this.state.internalValue) {
1667
+ this.close();
1668
+ } else {
1669
+ this.toggle();
1670
+ }
1671
+ } else if (e.key === "Escape") {
1672
+ if (this.state.isOpen) this.close();
1673
+ }
1674
+ });
1675
+ if (this.elements.clearBtn) {
1573
1676
  this.elements.clearBtn.addEventListener("click", (e) => {
1574
1677
  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
- this.container.dataset.value = "";
1583
1678
  this.state.internalValue = "";
1679
+ this.elements.input.value = "";
1584
1680
  this.elements.clearBtn.style.display = "none";
1585
1681
  this.elements.input.dispatchEvent(
1586
1682
  new Event("change", { bubbles: true })
@@ -1589,6 +1685,12 @@ var TimePicker = class {
1589
1685
  this.options.onChange("");
1590
1686
  }
1591
1687
  });
1688
+ this.elements.clearBtn.addEventListener("keydown", (e) => {
1689
+ if (e.key === "Enter" || e.key === " ") {
1690
+ e.preventDefault();
1691
+ this.elements.clearBtn.click();
1692
+ }
1693
+ });
1592
1694
  }
1593
1695
  document.addEventListener("click", (e) => {
1594
1696
  if (!this.container.contains(e.target)) this.close();
@@ -1602,11 +1704,11 @@ var TimePicker = class {
1602
1704
  return this.state.internalValue;
1603
1705
  }
1604
1706
  };
1605
- function initTimepicker(selectorOrElement, options2 = {}) {
1707
+ function initTimepicker(selectorOrElement, options = {}) {
1606
1708
  const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-time-picker`);
1607
1709
  const instances = [];
1608
1710
  elements.forEach((container) => {
1609
- const instance = new TimePicker(container, options2);
1711
+ const instance = new TimePicker(container, options);
1610
1712
  container.__timepickerAPI = instance;
1611
1713
  instances.push(instance);
1612
1714
  });
@@ -1649,6 +1751,17 @@ function openModal(modalEl) {
1649
1751
  modalEl.style.display = "flex";
1650
1752
  document.body.style.overflow = "hidden";
1651
1753
  modalEl.setAttribute("aria-hidden", "false");
1754
+ modalEl.setAttribute("tabindex", "-1");
1755
+ if (!modalEl.hasAttribute("role")) {
1756
+ modalEl.setAttribute("role", "dialog");
1757
+ }
1758
+ if (!modalEl.hasAttribute("aria-modal")) {
1759
+ modalEl.setAttribute("aria-modal", "true");
1760
+ }
1761
+ const closeBtn = modalEl.querySelector(`.${PREFIX}-modal__close-button`);
1762
+ if (closeBtn && !closeBtn.hasAttribute("aria-label")) {
1763
+ closeBtn.setAttribute("aria-label", "Tutup dialog");
1764
+ }
1652
1765
  modalEl.classList.remove(
1653
1766
  `${PREFIX}-modal--exit`,
1654
1767
  `${PREFIX}-modal--exit-active`
@@ -1747,6 +1860,19 @@ function initDrawer(rootSelector = `.${PREFIX2}-drawer`) {
1747
1860
  if (!drawer) return;
1748
1861
  drawer.style.display = "flex";
1749
1862
  document.body.style.overflow = "hidden";
1863
+ drawer.setAttribute("aria-hidden", "false");
1864
+ drawer.setAttribute("tabindex", "-1");
1865
+ if (!drawer.hasAttribute("role")) {
1866
+ drawer.setAttribute("role", "complementary");
1867
+ }
1868
+ if (!drawer.hasAttribute("aria-modal")) {
1869
+ drawer.setAttribute("aria-modal", "true");
1870
+ }
1871
+ const panel = drawer.querySelector(`.${PREFIX2}-drawer__panel`) || drawer.querySelector(`.${PREFIX2}-drawer__content`) || drawer;
1872
+ const closeBtn = panel.querySelector(`.${PREFIX2}-drawer__close-button`);
1873
+ if (closeBtn && !closeBtn.hasAttribute("aria-label")) {
1874
+ closeBtn.setAttribute("aria-label", "Tutup panel");
1875
+ }
1750
1876
  drawer.offsetHeight;
1751
1877
  drawer.classList.add(`${PREFIX2}-drawer--open`);
1752
1878
  drawer.dispatchEvent(new CustomEvent("drawer:open"));
@@ -1911,9 +2037,20 @@ function setDropdownState(root, newState) {
1911
2037
  if (newState.isOpen !== void 0) {
1912
2038
  root.setAttribute("data-state", newState.isOpen ? "open" : "closed");
1913
2039
  const trigger = root.querySelector(`.${PREFIX4}-select-dropdown__trigger`);
1914
- if (trigger) trigger.setAttribute("aria-expanded", newState.isOpen);
2040
+ if (trigger) {
2041
+ trigger.setAttribute("aria-expanded", newState.isOpen);
2042
+ if (!trigger.hasAttribute("aria-haspopup")) {
2043
+ trigger.setAttribute("aria-haspopup", "listbox");
2044
+ }
2045
+ }
1915
2046
  const panel = root.querySelector(`.${PREFIX4}-select-dropdown__panel`);
1916
2047
  if (panel) {
2048
+ if (!panel.hasAttribute("role")) {
2049
+ panel.setAttribute("role", "listbox");
2050
+ }
2051
+ if (newState.isMultiple) {
2052
+ panel.setAttribute("aria-multiselectable", "true");
2053
+ }
1917
2054
  if (newState.isOpen) {
1918
2055
  panel.style.removeProperty("display");
1919
2056
  } else {
@@ -1940,9 +2077,9 @@ function updateTriggerUI(root, values, isMultiple) {
1940
2077
  `.${PREFIX4}-select-dropdown__trigger-text`
1941
2078
  );
1942
2079
  const placeholder = input ? input.getAttribute("placeholder") : textSpan ? textSpan.getAttribute("data-placeholder") : "Select...";
1943
- const options2 = root.querySelectorAll(`.${PREFIX4}-select-dropdown__option`);
2080
+ const options = root.querySelectorAll(`.${PREFIX4}-select-dropdown__option`);
1944
2081
  const getLabel = (val) => {
1945
- const opt = Array.from(options2).find(
2082
+ const opt = Array.from(options).find(
1946
2083
  (o) => o.getAttribute("data-value") === val
1947
2084
  );
1948
2085
  return opt ? opt.textContent.trim() : val;
@@ -1968,7 +2105,7 @@ function updateTriggerUI(root, values, isMultiple) {
1968
2105
  values.length === 0
1969
2106
  );
1970
2107
  }
1971
- options2.forEach((opt) => {
2108
+ options.forEach((opt) => {
1972
2109
  const val = opt.getAttribute("data-value");
1973
2110
  const isSelected = values.includes(val);
1974
2111
  if (isMultiple) {
@@ -1990,6 +2127,10 @@ function updateTriggerUI(root, values, isMultiple) {
1990
2127
  isSelected
1991
2128
  );
1992
2129
  }
2130
+ if (!opt.hasAttribute("role")) {
2131
+ opt.setAttribute("role", "option");
2132
+ }
2133
+ opt.setAttribute("aria-selected", isSelected);
1993
2134
  });
1994
2135
  }
1995
2136
  function initSelectDropdown() {
@@ -2048,13 +2189,13 @@ function initSelectDropdown() {
2048
2189
  const root = e.target.closest(`.${PREFIX4}-select-dropdown`);
2049
2190
  if (root) {
2050
2191
  const term = e.target.value.toLowerCase();
2051
- const options2 = root.querySelectorAll(
2192
+ const options = root.querySelectorAll(
2052
2193
  `.${PREFIX4}-select-dropdown__option`
2053
2194
  );
2054
2195
  if (root.getAttribute("data-state") !== "open") {
2055
2196
  setDropdownState(root, { isOpen: true });
2056
2197
  }
2057
- options2.forEach((opt) => {
2198
+ options.forEach((opt) => {
2058
2199
  const text = opt.textContent.trim().toLowerCase();
2059
2200
  opt.style.display = text.includes(term) ? "" : "none";
2060
2201
  });
@@ -2128,20 +2269,20 @@ function initStepper() {
2128
2269
  `;
2129
2270
  const updateUI = () => {
2130
2271
  stepper.dataset.currentStep = currentStep;
2131
- items.forEach((item, index2) => {
2272
+ items.forEach((item, index) => {
2132
2273
  const iconWrapper = item.querySelector(
2133
2274
  `.${PREFIX}-stepper__icon-wrapper`
2134
2275
  );
2135
- const itemNumber = index2 + 1;
2276
+ const itemNumber = index + 1;
2136
2277
  item.classList.remove(
2137
2278
  `${PREFIX}-stepper__item--completed`,
2138
2279
  `${PREFIX}-stepper__item--active`
2139
2280
  );
2140
2281
  if (iconWrapper) iconWrapper.innerHTML = "";
2141
- if (index2 < currentStep) {
2282
+ if (index < currentStep) {
2142
2283
  item.classList.add(`${PREFIX}-stepper__item--completed`);
2143
2284
  if (iconWrapper) iconWrapper.innerHTML = checkIcon;
2144
- } else if (index2 === currentStep) {
2285
+ } else if (index === currentStep) {
2145
2286
  item.classList.add(`${PREFIX}-stepper__item--active`);
2146
2287
  if (iconWrapper)
2147
2288
  iconWrapper.innerHTML = `<span class="${PREFIX}-stepper__step-number">${itemNumber}</span>`;
@@ -2150,8 +2291,8 @@ function initStepper() {
2150
2291
  iconWrapper.innerHTML = `<span class="${PREFIX}-stepper__step-number">${itemNumber}</span>`;
2151
2292
  }
2152
2293
  });
2153
- separators.forEach((separator, index2) => {
2154
- if (index2 < currentStep) {
2294
+ separators.forEach((separator, index) => {
2295
+ if (index < currentStep) {
2155
2296
  separator.classList.add(`${PREFIX}-stepper__separator--completed`);
2156
2297
  } else {
2157
2298
  separator.classList.remove(`${PREFIX}-stepper__separator--completed`);
@@ -2197,11 +2338,11 @@ function initStepper() {
2197
2338
  }
2198
2339
  });
2199
2340
  });
2200
- items.forEach((item, index2) => {
2341
+ items.forEach((item, index) => {
2201
2342
  if (item.classList.contains(`${PREFIX}-stepper__item--clickable`) || item.hasAttribute("data-clickable")) {
2202
2343
  item.addEventListener("click", () => {
2203
2344
  if (!item.classList.contains(`${PREFIX}-stepper__item--disabled`)) {
2204
- currentStep = index2;
2345
+ currentStep = index;
2205
2346
  updateUI();
2206
2347
  }
2207
2348
  });
@@ -2275,7 +2416,7 @@ function initFileUpload(rootSelector = `.${PREFIX}-file-upload`) {
2275
2416
  } else {
2276
2417
  filesContainer.style.display = "none";
2277
2418
  }
2278
- uploadedFiles.forEach((f, index2) => {
2419
+ uploadedFiles.forEach((f, index) => {
2279
2420
  const fileEl = document.createElement("div");
2280
2421
  fileEl.className = `${PREFIX}-file-upload__file`;
2281
2422
  let statusClass = "";
@@ -3099,281 +3240,6 @@ function initRangeDatepicker() {
3099
3240
  });
3100
3241
  }
3101
3242
 
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
3243
  // src/js/components/stateful/pagination.js
3378
3244
  function initPagination() {
3379
3245
  document.querySelectorAll(`.${PREFIX}-pagination`).forEach((container) => {
@@ -3596,6 +3462,573 @@ function initPagination() {
3596
3462
  });
3597
3463
  }
3598
3464
 
3465
+ // src/js/utils/countries.js
3466
+ var COUNTRIES = [
3467
+ { code: "ID", name: "Indonesia", dialCode: "+62" },
3468
+ { code: "AF", name: "Afghanistan", dialCode: "+93" },
3469
+ { code: "AL", name: "Albania", dialCode: "+355" },
3470
+ { code: "DZ", name: "Algeria", dialCode: "+213" },
3471
+ { code: "AS", name: "American Samoa", dialCode: "+1684" },
3472
+ { code: "AD", name: "Andorra", dialCode: "+376" },
3473
+ { code: "AO", name: "Angola", dialCode: "+244" },
3474
+ { code: "AI", name: "Anguilla", dialCode: "+1264" },
3475
+ { code: "AG", name: "Antigua and Barbuda", dialCode: "+1268" },
3476
+ { code: "AR", name: "Argentina", dialCode: "+54" },
3477
+ { code: "AM", name: "Armenia", dialCode: "+374" },
3478
+ { code: "AW", name: "Aruba", dialCode: "+297" },
3479
+ { code: "AU", name: "Australia", dialCode: "+61" },
3480
+ { code: "AT", name: "Austria", dialCode: "+43" },
3481
+ { code: "AZ", name: "Azerbaijan", dialCode: "+994" },
3482
+ { code: "BS", name: "Bahamas", dialCode: "+1242" },
3483
+ { code: "BH", name: "Bahrain", dialCode: "+973" },
3484
+ { code: "BD", name: "Bangladesh", dialCode: "+880" },
3485
+ { code: "BB", name: "Barbados", dialCode: "+1246" },
3486
+ { code: "BY", name: "Belarus", dialCode: "+375" },
3487
+ { code: "BE", name: "Belgium", dialCode: "+32" },
3488
+ { code: "BZ", name: "Belize", dialCode: "+501" },
3489
+ { code: "BJ", name: "Benin", dialCode: "+229" },
3490
+ { code: "BM", name: "Bermuda", dialCode: "+1441" },
3491
+ { code: "BT", name: "Bhutan", dialCode: "+975" },
3492
+ { code: "BO", name: "Bolivia", dialCode: "+591" },
3493
+ { code: "BA", name: "Bosnia and Herzegovina", dialCode: "+387" },
3494
+ { code: "BW", name: "Botswana", dialCode: "+267" },
3495
+ { code: "BR", name: "Brazil", dialCode: "+55" },
3496
+ { code: "IO", name: "British Indian Ocean Territory", dialCode: "+246" },
3497
+ { code: "BN", name: "Brunei Darussalam", dialCode: "+673" },
3498
+ { code: "BG", name: "Bulgaria", dialCode: "+359" },
3499
+ { code: "BF", name: "Burkina Faso", dialCode: "+226" },
3500
+ { code: "BI", name: "Burundi", dialCode: "+257" },
3501
+ { code: "KH", name: "Cambodia", dialCode: "+855" },
3502
+ { code: "CM", name: "Cameroon", dialCode: "+237" },
3503
+ { code: "CA", name: "Canada", dialCode: "+1" },
3504
+ { code: "CV", name: "Cape Verde", dialCode: "+238" },
3505
+ { code: "KY", name: "Cayman Islands", dialCode: "+1345" },
3506
+ { code: "CF", name: "Central African Republic", dialCode: "+236" },
3507
+ { code: "TD", name: "Chad", dialCode: "+235" },
3508
+ { code: "CL", name: "Chile", dialCode: "+56" },
3509
+ { code: "CN", name: "China", dialCode: "+86" },
3510
+ { code: "CX", name: "Christmas Island", dialCode: "+61" },
3511
+ { code: "CC", name: "Cocos (Keeling) Islands", dialCode: "+61" },
3512
+ { code: "CO", name: "Colombia", dialCode: "+57" },
3513
+ { code: "KM", name: "Comoros", dialCode: "+269" },
3514
+ { code: "CG", name: "Congo", dialCode: "+242" },
3515
+ { code: "CD", name: "Congo, Democratic Republic of the", dialCode: "+243" },
3516
+ { code: "CK", name: "Cook Islands", dialCode: "+682" },
3517
+ { code: "CR", name: "Costa Rica", dialCode: "+506" },
3518
+ { code: "CI", name: "Cote d'Ivoire", dialCode: "+225" },
3519
+ { code: "HR", name: "Croatia", dialCode: "+385" },
3520
+ { code: "CU", name: "Cuba", dialCode: "+53" },
3521
+ { code: "CY", name: "Cyprus", dialCode: "+357" },
3522
+ { code: "CZ", name: "Czech Republic", dialCode: "+420" },
3523
+ { code: "DK", name: "Denmark", dialCode: "+45" },
3524
+ { code: "DJ", name: "Djibouti", dialCode: "+253" },
3525
+ { code: "DM", name: "Dominica", dialCode: "+1767" },
3526
+ { code: "DO", name: "Dominican Republic", dialCode: "+1" },
3527
+ { code: "EC", name: "Ecuador", dialCode: "+593" },
3528
+ { code: "EG", name: "Egypt", dialCode: "+20" },
3529
+ { code: "SV", name: "El Salvador", dialCode: "+503" },
3530
+ { code: "GQ", name: "Equatorial Guinea", dialCode: "+240" },
3531
+ { code: "ER", name: "Eritrea", dialCode: "+291" },
3532
+ { code: "EE", name: "Estonia", dialCode: "+372" },
3533
+ { code: "ET", name: "Ethiopia", dialCode: "+251" },
3534
+ { code: "FK", name: "Falkland Islands (Malvinas)", dialCode: "+500" },
3535
+ { code: "FO", name: "Faroe Islands", dialCode: "+298" },
3536
+ { code: "FJ", name: "Fiji", dialCode: "+679" },
3537
+ { code: "FI", name: "Finland", dialCode: "+358" },
3538
+ { code: "FR", name: "France", dialCode: "+33" },
3539
+ { code: "GF", name: "French Guiana", dialCode: "+594" },
3540
+ { code: "PF", name: "French Polynesia", dialCode: "+689" },
3541
+ { code: "GA", name: "Gabon", dialCode: "+241" },
3542
+ { code: "GM", name: "Gambia", dialCode: "+220" },
3543
+ { code: "GE", name: "Georgia", dialCode: "+995" },
3544
+ { code: "DE", name: "Germany", dialCode: "+49" },
3545
+ { code: "GH", name: "Ghana", dialCode: "+233" },
3546
+ { code: "GI", name: "Gibraltar", dialCode: "+350" },
3547
+ { code: "GR", name: "Greece", dialCode: "+30" },
3548
+ { code: "GL", name: "Greenland", dialCode: "+299" },
3549
+ { code: "GD", name: "Grenada", dialCode: "+1473" },
3550
+ { code: "GP", name: "Guadeloupe", dialCode: "+590" },
3551
+ { code: "GU", name: "Guam", dialCode: "+1671" },
3552
+ { code: "GT", name: "Guatemala", dialCode: "+502" },
3553
+ { code: "GG", name: "Guernsey", dialCode: "+44" },
3554
+ { code: "GN", name: "Guinea", dialCode: "+224" },
3555
+ { code: "GW", name: "Guinea-Bissau", dialCode: "+245" },
3556
+ { code: "GY", name: "Guyana", dialCode: "+592" },
3557
+ { code: "HT", name: "Haiti", dialCode: "+509" },
3558
+ { code: "VA", name: "Holy See (Vatican City State)", dialCode: "+379" },
3559
+ { code: "HN", name: "Honduras", dialCode: "+504" },
3560
+ { code: "HK", name: "Hong Kong", dialCode: "+852" },
3561
+ { code: "HU", name: "Hungary", dialCode: "+36" },
3562
+ { code: "IS", name: "Iceland", dialCode: "+354" },
3563
+ { code: "IN", name: "India", dialCode: "+91" },
3564
+ { code: "IR", name: "Iran, Islamic Republic of", dialCode: "+98" },
3565
+ { code: "IQ", name: "Iraq", dialCode: "+964" },
3566
+ { code: "IE", name: "Ireland", dialCode: "+353" },
3567
+ { code: "IM", name: "Isle of Man", dialCode: "+44" },
3568
+ { code: "IL", name: "Israel", dialCode: "+972" },
3569
+ { code: "IT", name: "Italy", dialCode: "+39" },
3570
+ { code: "JM", name: "Jamaica", dialCode: "+1876" },
3571
+ { code: "JP", name: "Japan", dialCode: "+81" },
3572
+ { code: "JE", name: "Jersey", dialCode: "+44" },
3573
+ { code: "JO", name: "Jordan", dialCode: "+962" },
3574
+ { code: "KZ", name: "Kazakhstan", dialCode: "+7" },
3575
+ { code: "KE", name: "Kenya", dialCode: "+254" },
3576
+ { code: "KI", name: "Kiribati", dialCode: "+686" },
3577
+ { code: "KP", name: "Korea, Democratic People's Republic of", dialCode: "+850" },
3578
+ { code: "KR", name: "Korea, Republic of", dialCode: "+82" },
3579
+ { code: "KW", name: "Kuwait", dialCode: "+965" },
3580
+ { code: "KG", name: "Kyrgyzstan", dialCode: "+996" },
3581
+ { code: "LA", name: "Laos", dialCode: "+856" },
3582
+ { code: "LV", name: "Latvia", dialCode: "+371" },
3583
+ { code: "LB", name: "Lebanon", dialCode: "+961" },
3584
+ { code: "LS", name: "Lesotho", dialCode: "+266" },
3585
+ { code: "LR", name: "Liberia", dialCode: "+231" },
3586
+ { code: "LY", name: "Libyan Arab Jamahiriya", dialCode: "+218" },
3587
+ { code: "LI", name: "Liechtenstein", dialCode: "+423" },
3588
+ { code: "LT", name: "Lithuania", dialCode: "+370" },
3589
+ { code: "LU", name: "Luxembourg", dialCode: "+352" },
3590
+ { code: "MO", name: "Macao", dialCode: "+853" },
3591
+ { code: "MK", name: "Macedonia, the Former Yugoslav Republic of", dialCode: "+389" },
3592
+ { code: "MG", name: "Madagascar", dialCode: "+261" },
3593
+ { code: "MW", name: "Malawi", dialCode: "+265" },
3594
+ { code: "MY", name: "Malaysia", dialCode: "+60" },
3595
+ { code: "MV", name: "Maldives", dialCode: "+960" },
3596
+ { code: "ML", name: "Mali", dialCode: "+223" },
3597
+ { code: "MT", name: "Malta", dialCode: "+356" },
3598
+ { code: "MH", name: "Marshall Islands", dialCode: "+692" },
3599
+ { code: "MQ", name: "Martinique", dialCode: "+596" },
3600
+ { code: "MR", name: "Mauritania", dialCode: "+222" },
3601
+ { code: "MU", name: "Mauritius", dialCode: "+230" },
3602
+ { code: "YT", name: "Mayotte", dialCode: "+262" },
3603
+ { code: "MX", name: "Mexico", dialCode: "+52" },
3604
+ { code: "FM", name: "Micronesia, Federated States of", dialCode: "+691" },
3605
+ { code: "MD", name: "Moldova, Republic of", dialCode: "+373" },
3606
+ { code: "MC", name: "Monaco", dialCode: "+377" },
3607
+ { code: "MN", name: "Mongolia", dialCode: "+976" },
3608
+ { code: "ME", name: "Montenegro", dialCode: "+382" },
3609
+ { code: "MS", name: "Montserrat", dialCode: "+1664" },
3610
+ { code: "MA", name: "Morocco", dialCode: "+212" },
3611
+ { code: "MZ", name: "Mozambique", dialCode: "+258" },
3612
+ { code: "MM", name: "Myanmar", dialCode: "+95" },
3613
+ { code: "NA", name: "Namibia", dialCode: "+264" },
3614
+ { code: "NR", name: "Nauru", dialCode: "+674" },
3615
+ { code: "NP", name: "Nepal", dialCode: "+977" },
3616
+ { code: "NL", name: "Netherlands", dialCode: "+31" },
3617
+ { code: "NC", name: "New Caledonia", dialCode: "+687" },
3618
+ { code: "NZ", name: "New Zealand", dialCode: "+64" },
3619
+ { code: "NI", name: "Nicaragua", dialCode: "+505" },
3620
+ { code: "NE", name: "Niger", dialCode: "+227" },
3621
+ { code: "NG", name: "Nigeria", dialCode: "+234" },
3622
+ { code: "NU", name: "Niue", dialCode: "+683" },
3623
+ { code: "NF", name: "Norfolk Island", dialCode: "+672" },
3624
+ { code: "MP", name: "Northern Mariana Islands", dialCode: "+1670" },
3625
+ { code: "NO", name: "Norway", dialCode: "+47" },
3626
+ { code: "OM", name: "Oman", dialCode: "+968" },
3627
+ { code: "PK", name: "Pakistan", dialCode: "+92" },
3628
+ { code: "PW", name: "Palau", dialCode: "+680" },
3629
+ { code: "PS", name: "Palestine", dialCode: "+970" },
3630
+ { code: "PA", name: "Panama", dialCode: "+507" },
3631
+ { code: "PG", name: "Papua New Guinea", dialCode: "+675" },
3632
+ { code: "PY", name: "Paraguay", dialCode: "+595" },
3633
+ { code: "PE", name: "Peru", dialCode: "+51" },
3634
+ { code: "PH", name: "Philippines", dialCode: "+63" },
3635
+ { code: "PN", name: "Pitcairn", dialCode: "+870" },
3636
+ { code: "PL", name: "Poland", dialCode: "+48" },
3637
+ { code: "PT", name: "Portugal", dialCode: "+351" },
3638
+ { code: "PR", name: "Puerto Rico", dialCode: "+1939" },
3639
+ { code: "QA", name: "Qatar", dialCode: "+974" },
3640
+ { code: "RE", name: "Reunion", dialCode: "+262" },
3641
+ { code: "RO", name: "Romania", dialCode: "+40" },
3642
+ { code: "RU", name: "Russian Federation", dialCode: "+7" },
3643
+ { code: "RW", name: "Rwanda", dialCode: "+250" },
3644
+ { code: "BL", name: "Saint Barthelemy", dialCode: "+590" },
3645
+ { code: "SH", name: "Saint Helena", dialCode: "+290" },
3646
+ { code: "KN", name: "Saint Kitts and Nevis", dialCode: "+1869" },
3647
+ { code: "LC", name: "Saint Lucia", dialCode: "+1758" },
3648
+ { code: "MF", name: "Saint Martin", dialCode: "+590" },
3649
+ { code: "PM", name: "Saint Pierre and Miquelon", dialCode: "+508" },
3650
+ { code: "VC", name: "Saint Vincent and the Grenadines", dialCode: "+1784" },
3651
+ { code: "WS", name: "Samoa", dialCode: "+685" },
3652
+ { code: "SM", name: "San Marino", dialCode: "+378" },
3653
+ { code: "ST", name: "Sao Tome and Principe", dialCode: "+239" },
3654
+ { code: "SA", name: "Saudi Arabia", dialCode: "+966" },
3655
+ { code: "SN", name: "Senegal", dialCode: "+221" },
3656
+ { code: "RS", name: "Serbia", dialCode: "+381" },
3657
+ { code: "SC", name: "Seychelles", dialCode: "+248" },
3658
+ { code: "SL", name: "Sierra Leone", dialCode: "+232" },
3659
+ { code: "SG", name: "Singapore", dialCode: "+65" },
3660
+ { code: "SK", name: "Slovakia", dialCode: "+421" },
3661
+ { code: "SI", name: "Slovenia", dialCode: "+386" },
3662
+ { code: "SB", name: "Solomon Islands", dialCode: "+677" },
3663
+ { code: "SO", name: "Somalia", dialCode: "+252" },
3664
+ { code: "ZA", name: "South Africa", dialCode: "+27" },
3665
+ { code: "GS", name: "South Georgia and the South Sandwich Islands", dialCode: "+500" },
3666
+ { code: "ES", name: "Spain", dialCode: "+34" },
3667
+ { code: "LK", name: "Sri Lanka", dialCode: "+94" },
3668
+ { code: "SD", name: "Sudan", dialCode: "+249" },
3669
+ { code: "SR", name: "Suriname", dialCode: "+597" },
3670
+ { code: "SJ", name: "Svalbard and Jan Mayen", dialCode: "+47" },
3671
+ { code: "SZ", name: "Swaziland", dialCode: "+268" },
3672
+ { code: "SE", name: "Sweden", dialCode: "+46" },
3673
+ { code: "CH", name: "Switzerland", dialCode: "+41" },
3674
+ { code: "SY", name: "Syrian Arab Republic", dialCode: "+963" },
3675
+ { code: "TW", name: "Taiwan, Province of China", dialCode: "+886" },
3676
+ { code: "TJ", name: "Tajikistan", dialCode: "+992" },
3677
+ { code: "TZ", name: "Tanzania, United Republic of", dialCode: "+255" },
3678
+ { code: "TH", name: "Thailand", dialCode: "+66" },
3679
+ { code: "TL", name: "Timor-Leste", dialCode: "+670" },
3680
+ { code: "TG", name: "Togo", dialCode: "+228" },
3681
+ { code: "TK", name: "Tokelau", dialCode: "+690" },
3682
+ { code: "TO", name: "Tonga", dialCode: "+676" },
3683
+ { code: "TT", name: "Trinidad and Tobago", dialCode: "+1868" },
3684
+ { code: "TN", name: "Tunisia", dialCode: "+216" },
3685
+ { code: "TR", name: "Turkey", dialCode: "+90" },
3686
+ { code: "TM", name: "Turkmenistan", dialCode: "+993" },
3687
+ { code: "TC", name: "Turks and Caicos Islands", dialCode: "+1649" },
3688
+ { code: "TV", name: "Tuvalu", dialCode: "+688" },
3689
+ { code: "UG", name: "Uganda", dialCode: "+256" },
3690
+ { code: "UA", name: "Ukraine", dialCode: "+380" },
3691
+ { code: "AE", name: "United Arab Emirates", dialCode: "+971" },
3692
+ { code: "GB", name: "United Kingdom", dialCode: "+44" },
3693
+ { code: "US", name: "United States", dialCode: "+1" },
3694
+ { code: "UY", name: "Uruguay", dialCode: "+598" },
3695
+ { code: "UZ", name: "Uzbekistan", dialCode: "+998" },
3696
+ { code: "VU", name: "Vanuatu", dialCode: "+678" },
3697
+ { code: "VE", name: "Venezuela", dialCode: "+58" },
3698
+ { code: "VN", name: "Vietnam", dialCode: "+84" },
3699
+ { code: "VG", name: "Virgin Islands, British", dialCode: "+1284" },
3700
+ { code: "VI", name: "Virgin Islands, U.S.", dialCode: "+1340" },
3701
+ { code: "WF", name: "Wallis and Futuna", dialCode: "+681" },
3702
+ { code: "EH", name: "Western Sahara", dialCode: "+212" },
3703
+ { code: "YE", name: "Yemen", dialCode: "+967" },
3704
+ { code: "ZM", name: "Zambia", dialCode: "+260" },
3705
+ { code: "ZW", name: "Zimbabwe", dialCode: "+263" }
3706
+ ];
3707
+
3708
+ // src/js/utils/flags.js
3709
+ var flagCache = {};
3710
+ var getFlag = async (code) => {
3711
+ if (flagCache[code]) {
3712
+ return flagCache[code];
3713
+ }
3714
+ try {
3715
+ const flag = await import(`@idds/styles/assets/flags/${code.toLowerCase()}.svg`);
3716
+ flagCache[code] = flag.default;
3717
+ return flag.default;
3718
+ } catch (error) {
3719
+ console.error(`[IDDS PhoneInput] Failed to load flag for: ${code}`, error);
3720
+ return "";
3721
+ }
3722
+ };
3723
+
3724
+ // src/js/components/stateful/phone-input.js
3725
+ var PhoneInput = class {
3726
+ constructor(selectorOrElement, options = {}) {
3727
+ this.container = typeof selectorOrElement === "string" ? document.querySelector(selectorOrElement) : selectorOrElement;
3728
+ if (!this.container) {
3729
+ console.warn("[IDDS PhoneInput] Container not found:", selectorOrElement);
3730
+ return;
3731
+ }
3732
+ if (this.container.dataset.initialized === "true") {
3733
+ return;
3734
+ }
3735
+ this.container.dataset.initialized = "true";
3736
+ this.options = {
3737
+ modelValue: this.container.dataset.value || "",
3738
+ label: this.container.dataset.label || "",
3739
+ placeholder: this.container.getAttribute("placeholder") || "812-3456-7890",
3740
+ size: this.container.dataset.size || "md",
3741
+ status: this.container.dataset.status || "neutral",
3742
+ disabled: this.container.hasAttribute("disabled") || false,
3743
+ readonly: this.container.hasAttribute("readonly") || false,
3744
+ required: this.container.hasAttribute("required") || false,
3745
+ defaultCountry: this.container.dataset.defaultCountry || "ID",
3746
+ allowClear: this.container.dataset.allowClear !== "false",
3747
+ countries: COUNTRIES,
3748
+ onChange: null,
3749
+ ...options
3750
+ };
3751
+ this.state = {
3752
+ isOpen: false,
3753
+ countrySearch: "",
3754
+ selectedCountry: this.options.countries.find((c) => c.code === this.options.defaultCountry) || this.options.countries[0],
3755
+ phoneNumber: ""
3756
+ };
3757
+ this.elements = {};
3758
+ this.inputId = `phone-input-${Math.random().toString(36).substr(2, 9)}`;
3759
+ this.init();
3760
+ }
3761
+ async init() {
3762
+ this.initDOM();
3763
+ this.initEvents();
3764
+ this.syncValueFromOptions();
3765
+ await this.updateFlag();
3766
+ }
3767
+ initDOM() {
3768
+ if (this.options.label) {
3769
+ const label = document.createElement("label");
3770
+ label.className = `${PREFIX}-phone-input__label`;
3771
+ label.setAttribute("for", this.inputId);
3772
+ label.textContent = this.options.label;
3773
+ if (this.options.required) {
3774
+ const asterisk = document.createElement("span");
3775
+ asterisk.className = `${PREFIX}-phone-input__required`;
3776
+ asterisk.textContent = "*";
3777
+ label.appendChild(asterisk);
3778
+ }
3779
+ this.container.appendChild(label);
3780
+ }
3781
+ const wrapper = document.createElement("div");
3782
+ wrapper.className = `${PREFIX}-phone-input__wrapper ${PREFIX}-phone-input__wrapper--size-${this.options.size}`;
3783
+ if (this.options.status !== "neutral") {
3784
+ wrapper.classList.add(`${PREFIX}-phone-input__wrapper--status-${this.options.status}`);
3785
+ }
3786
+ if (this.options.disabled) {
3787
+ wrapper.classList.add(`${PREFIX}-phone-input__wrapper--disabled`);
3788
+ }
3789
+ const selector = document.createElement("div");
3790
+ selector.className = `${PREFIX}-phone-input__country-selector`;
3791
+ const countryBtn = document.createElement("button");
3792
+ countryBtn.type = "button";
3793
+ countryBtn.className = `${PREFIX}-phone-input__country-button`;
3794
+ countryBtn.setAttribute("aria-label", "Pilih negara");
3795
+ countryBtn.setAttribute("aria-haspopup", "listbox");
3796
+ countryBtn.setAttribute("aria-expanded", "false");
3797
+ if (this.options.disabled || this.options.readonly) countryBtn.disabled = true;
3798
+ const flagImg = document.createElement("img");
3799
+ flagImg.className = `${PREFIX}-phone-input__country-flag-img`;
3800
+ flagImg.width = 24;
3801
+ flagImg.height = 18;
3802
+ flagImg.alt = "";
3803
+ const dialCode = document.createElement("span");
3804
+ dialCode.className = `${PREFIX}-phone-input__country-code`;
3805
+ dialCode.textContent = this.state.selectedCountry.dialCode;
3806
+ const chevron = document.createElement("div");
3807
+ 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">
3808
+ <path d="M6 9L12 15L18 9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3809
+ </svg>`;
3810
+ countryBtn.appendChild(flagImg);
3811
+ countryBtn.appendChild(dialCode);
3812
+ countryBtn.appendChild(chevron.firstChild);
3813
+ selector.appendChild(countryBtn);
3814
+ wrapper.appendChild(selector);
3815
+ const divider = document.createElement("div");
3816
+ divider.className = `${PREFIX}-phone-input__divider`;
3817
+ wrapper.appendChild(divider);
3818
+ const input = document.createElement("input");
3819
+ input.type = "tel";
3820
+ input.id = this.inputId;
3821
+ input.placeholder = this.options.placeholder;
3822
+ input.className = `${PREFIX}-phone-input__input`;
3823
+ if (this.options.disabled) input.disabled = true;
3824
+ if (this.options.readonly) input.readOnly = true;
3825
+ wrapper.appendChild(input);
3826
+ if (this.options.allowClear) {
3827
+ const clearBtn = document.createElement("button");
3828
+ clearBtn.type = "button";
3829
+ clearBtn.className = `${PREFIX}-phone-input__clear-button`;
3830
+ clearBtn.setAttribute("aria-label", "Hapus nomor telepon");
3831
+ 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">
3832
+ <line x1="18" y1="6" x2="6" y2="18"></line>
3833
+ <line x1="6" y1="6" x2="18" y2="18"></line>
3834
+ </svg>`;
3835
+ clearBtn.style.display = "none";
3836
+ wrapper.appendChild(clearBtn);
3837
+ this.elements.clearBtn = clearBtn;
3838
+ }
3839
+ this.container.appendChild(wrapper);
3840
+ const panel = document.createElement("div");
3841
+ panel.className = `${PREFIX}-phone-input__country-dropdown`;
3842
+ panel.style.display = "none";
3843
+ const searchDiv = document.createElement("div");
3844
+ searchDiv.className = `${PREFIX}-phone-input__country-search`;
3845
+ const searchInput = document.createElement("input");
3846
+ searchInput.type = "text";
3847
+ searchInput.placeholder = "Cari";
3848
+ searchInput.className = `${PREFIX}-phone-input__country-search-input`;
3849
+ searchDiv.appendChild(searchInput);
3850
+ panel.appendChild(searchDiv);
3851
+ const list = document.createElement("div");
3852
+ list.className = `${PREFIX}-phone-input__country-list`;
3853
+ list.setAttribute("role", "listbox");
3854
+ panel.appendChild(list);
3855
+ selector.appendChild(panel);
3856
+ this.elements.wrapper = wrapper;
3857
+ this.elements.countryBtn = countryBtn;
3858
+ this.elements.flagImg = flagImg;
3859
+ this.elements.dialCode = dialCode;
3860
+ this.elements.input = input;
3861
+ this.elements.panel = panel;
3862
+ this.elements.searchInput = searchInput;
3863
+ this.elements.list = list;
3864
+ this.elements.chevron = selector.querySelector(`.${PREFIX}-phone-input__country-chevron`);
3865
+ }
3866
+ initEvents() {
3867
+ this.elements.countryBtn.addEventListener("click", (e) => {
3868
+ e.stopPropagation();
3869
+ this.toggleDropdown();
3870
+ });
3871
+ this.elements.searchInput.addEventListener("input", (e) => {
3872
+ this.state.countrySearch = e.target.value;
3873
+ this.renderCountryList();
3874
+ });
3875
+ this.elements.input.addEventListener("input", (e) => {
3876
+ this.handleInput(e);
3877
+ });
3878
+ if (this.elements.clearBtn) {
3879
+ this.elements.clearBtn.addEventListener("click", () => {
3880
+ this.clear();
3881
+ });
3882
+ this.elements.clearBtn.addEventListener("keydown", (e) => {
3883
+ if (e.key === "Enter" || e.key === " ") {
3884
+ e.preventDefault();
3885
+ this.clear();
3886
+ }
3887
+ });
3888
+ }
3889
+ document.addEventListener("click", (e) => {
3890
+ if (!this.elements.wrapper.contains(e.target)) {
3891
+ this.closeDropdown();
3892
+ }
3893
+ });
3894
+ }
3895
+ async updateFlag() {
3896
+ const url = await getFlag(this.state.selectedCountry.code);
3897
+ this.elements.flagImg.src = url;
3898
+ this.elements.flagImg.alt = this.state.selectedCountry.name;
3899
+ this.elements.dialCode.textContent = this.state.selectedCountry.dialCode;
3900
+ }
3901
+ toggleDropdown() {
3902
+ if (this.state.isOpen) {
3903
+ this.closeDropdown();
3904
+ } else {
3905
+ this.openDropdown();
3906
+ }
3907
+ }
3908
+ openDropdown() {
3909
+ this.state.isOpen = true;
3910
+ this.elements.panel.style.display = "flex";
3911
+ this.elements.countryBtn.setAttribute("aria-expanded", "true");
3912
+ this.elements.chevron.classList.add(`${PREFIX}-phone-input__country-chevron--open`);
3913
+ this.state.countrySearch = "";
3914
+ this.elements.searchInput.value = "";
3915
+ this.renderCountryList();
3916
+ setTimeout(() => this.elements.searchInput.focus(), 0);
3917
+ }
3918
+ closeDropdown() {
3919
+ this.state.isOpen = false;
3920
+ this.elements.panel.style.display = "none";
3921
+ this.elements.countryBtn.setAttribute("aria-expanded", "false");
3922
+ this.elements.chevron.classList.remove(`${PREFIX}-phone-input__country-chevron--open`);
3923
+ }
3924
+ renderCountryList() {
3925
+ const list = this.elements.list;
3926
+ list.innerHTML = "";
3927
+ const filtered = this.options.countries.filter(
3928
+ (c) => c.name.toLowerCase().includes(this.state.countrySearch.toLowerCase()) || c.dialCode.includes(this.state.countrySearch) || c.code.toLowerCase().includes(this.state.countrySearch.toLowerCase())
3929
+ );
3930
+ filtered.forEach(async (country) => {
3931
+ const option = document.createElement("button");
3932
+ option.type = "button";
3933
+ option.className = `${PREFIX}-phone-input__country-option`;
3934
+ if (country.code === this.state.selectedCountry.code) {
3935
+ option.classList.add(`${PREFIX}-phone-input__country-option--selected`);
3936
+ }
3937
+ option.setAttribute("role", "option");
3938
+ option.setAttribute("aria-selected", country.code === this.state.selectedCountry.code ? "true" : "false");
3939
+ const flag = document.createElement("img");
3940
+ flag.className = `${PREFIX}-phone-input__country-flag-img`;
3941
+ flag.width = 20;
3942
+ flag.height = 15;
3943
+ getFlag(country.code).then((url) => flag.src = url);
3944
+ const name = document.createElement("span");
3945
+ name.className = `${PREFIX}-phone-input__country-name`;
3946
+ name.textContent = `${country.name} (${country.code})`;
3947
+ const code = document.createElement("span");
3948
+ code.className = `${PREFIX}-phone-input__country-dial-code`;
3949
+ code.textContent = country.dialCode;
3950
+ option.appendChild(flag);
3951
+ option.appendChild(name);
3952
+ option.appendChild(code);
3953
+ option.addEventListener("click", () => {
3954
+ this.selectCountry(country);
3955
+ });
3956
+ list.appendChild(option);
3957
+ });
3958
+ }
3959
+ selectCountry(country) {
3960
+ this.state.selectedCountry = country;
3961
+ this.updateFlag();
3962
+ this.closeDropdown();
3963
+ this.elements.input.focus();
3964
+ this.triggerChange();
3965
+ }
3966
+ formatPhoneNumber(value) {
3967
+ const clean = value.replace(/\D/g, "");
3968
+ if (clean.length > 7) {
3969
+ return clean.replace(/^(\d{3})(\d{4})(.*)/, "$1-$2-$3");
3970
+ } else if (clean.length > 3) {
3971
+ return clean.replace(/^(\d{3})(.*)/, "$1-$2");
3972
+ }
3973
+ return clean;
3974
+ }
3975
+ handleInput(e) {
3976
+ const value = e.target.value;
3977
+ const formatted = this.formatPhoneNumber(value);
3978
+ e.target.value = formatted;
3979
+ this.state.phoneNumber = formatted;
3980
+ if (this.elements.clearBtn) {
3981
+ this.elements.clearBtn.style.display = formatted ? "flex" : "none";
3982
+ }
3983
+ this.triggerChange();
3984
+ }
3985
+ clear() {
3986
+ this.state.phoneNumber = "";
3987
+ this.elements.input.value = "";
3988
+ if (this.elements.clearBtn) {
3989
+ this.elements.clearBtn.style.display = "none";
3990
+ }
3991
+ this.elements.input.focus();
3992
+ this.triggerChange();
3993
+ }
3994
+ syncValueFromOptions() {
3995
+ if (this.options.modelValue) {
3996
+ let val = this.options.modelValue;
3997
+ const dial = this.state.selectedCountry.dialCode;
3998
+ if (val.startsWith(dial)) {
3999
+ val = val.substring(dial.length);
4000
+ }
4001
+ this.state.phoneNumber = this.formatPhoneNumber(val);
4002
+ this.elements.input.value = this.state.phoneNumber;
4003
+ if (this.elements.clearBtn && this.state.phoneNumber) {
4004
+ this.elements.clearBtn.style.display = "flex";
4005
+ }
4006
+ }
4007
+ }
4008
+ triggerChange() {
4009
+ const cleanLocal = this.state.phoneNumber.replace(/\D/g, "");
4010
+ const cleanNoZero = cleanLocal.startsWith("0") ? cleanLocal.substring(1) : cleanLocal;
4011
+ const fullValue = `${this.state.selectedCountry.dialCode}${cleanNoZero}`;
4012
+ if (this.options.onChange) {
4013
+ this.options.onChange(fullValue);
4014
+ }
4015
+ this.container.dispatchEvent(new CustomEvent("change", {
4016
+ detail: { value: fullValue, country: this.state.selectedCountry }
4017
+ }));
4018
+ }
4019
+ };
4020
+ function initPhoneInput(selectorOrElement, options = {}) {
4021
+ const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-phone-input`);
4022
+ const instances = [];
4023
+ elements.forEach((container) => {
4024
+ const instance = new PhoneInput(container, options);
4025
+ container.__phoneInputAPI = instance;
4026
+ instances.push(instance);
4027
+ });
4028
+ if (instances.length === 0) return null;
4029
+ return instances.length === 1 ? instances[0] : instances;
4030
+ }
4031
+
3599
4032
  // src/js/components/stateful/tab-vertical.js
3600
4033
  function initTabVertical() {
3601
4034
  const tabs = document.querySelectorAll(`.${PREFIX}-tab-vertical`);
@@ -3708,7 +4141,7 @@ function initTabHorizontal() {
3708
4141
 
3709
4142
  // src/js/components/stateful/table.js
3710
4143
  var Table = class {
3711
- constructor(selectorOrElement, options2 = {}) {
4144
+ constructor(selectorOrElement, options = {}) {
3712
4145
  this.container = typeof selectorOrElement === "string" ? document.querySelector(selectorOrElement) : selectorOrElement;
3713
4146
  if (!this.container) {
3714
4147
  console.warn("[IDDS Table] Container not found:", selectorOrElement);
@@ -3740,7 +4173,7 @@ var Table = class {
3740
4173
  searchContainer: null,
3741
4174
  searchButton: null,
3742
4175
  onSearch: null,
3743
- ...options2
4176
+ ...options
3744
4177
  };
3745
4178
  this.state = {
3746
4179
  currentPage: this.options.initialPage,
@@ -3859,34 +4292,43 @@ var Table = class {
3859
4292
  if (col.sortable && col.accessor) {
3860
4293
  th.classList.add(`${PREFIX}-table__header-cell--sortable`);
3861
4294
  th.setAttribute("data-sort", col.accessor);
4295
+ let sortLabel = `Urutkan ${col.header}`;
4296
+ let currentSort = "none";
4297
+ if (this.state.sortField === field) {
4298
+ currentSort = this.state.sortOrder === "asc" ? "ascending" : "descending";
4299
+ }
4300
+ th.setAttribute("aria-sort", currentSort);
3862
4301
  let sortControlsHtml = `
3863
4302
  <div class="${PREFIX}-table__sort-controls">
3864
4303
  ${col.header}
3865
4304
  <div class="${PREFIX}-table__sort-icon">
3866
- <div class="${PREFIX}-table__sort-button" data-order="asc">
4305
+ <div class="${PREFIX}-table__sort-button" data-order="asc" role="button" aria-label="Urutkan ${col.header} menaik">
3867
4306
  <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
4307
  </div>
3869
- <div class="${PREFIX}-table__sort-button ${PREFIX}-table__sort-button-right" data-order="desc">
4308
+ <div class="${PREFIX}-table__sort-button ${PREFIX}-table__sort-button-right" data-order="desc" role="button" aria-label="Urutkan ${col.header} menurun">
3870
4309
  <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
4310
  </div>
3872
4311
  </div>
3873
4312
  </div>
3874
4313
  `;
3875
4314
  th.innerHTML = sortControlsHtml;
4315
+ const ascBtn = th.querySelector('[data-order="asc"]');
4316
+ const descBtn = th.querySelector('[data-order="desc"]');
4317
+ ascBtn.addEventListener("click", (e) => {
4318
+ e.stopPropagation();
4319
+ this.handleHeaderSort(col, "asc");
4320
+ });
4321
+ descBtn.addEventListener("click", (e) => {
4322
+ e.stopPropagation();
4323
+ this.handleHeaderSort(col, "desc");
4324
+ });
3876
4325
  th.addEventListener("click", () => {
3877
- const field = col.accessor;
4326
+ let nextOrder = "asc";
3878
4327
  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";
4328
+ if (this.state.sortOrder === "asc") nextOrder = "desc";
4329
+ else nextOrder = null;
3887
4330
  }
3888
- this.state.currentPage = 1;
3889
- this.loadData();
4331
+ this.handleHeaderSort(col, nextOrder);
3890
4332
  });
3891
4333
  } else {
3892
4334
  th.textContent = col.header;
@@ -3945,7 +4387,7 @@ var Table = class {
3945
4387
  this.updateSelectAllState();
3946
4388
  return;
3947
4389
  }
3948
- rowData.forEach((row, index2) => {
4390
+ rowData.forEach((row, index) => {
3949
4391
  const tr = document.createElement("tr");
3950
4392
  tr.className = `${PREFIX}-table__row`;
3951
4393
  if (this.options.rowClickable) {
@@ -3956,11 +4398,11 @@ var Table = class {
3956
4398
  return;
3957
4399
  }
3958
4400
  if (typeof this.options.onRowClick === "function") {
3959
- this.options.onRowClick(row, index2);
4401
+ this.options.onRowClick(row, index);
3960
4402
  }
3961
4403
  });
3962
4404
  }
3963
- const rowKeyStr = String(row[this.options.rowKey] || index2);
4405
+ const rowKeyStr = String(row[this.options.rowKey] || index);
3964
4406
  if (this.options.selectable) {
3965
4407
  const td = document.createElement("td");
3966
4408
  td.className = `${PREFIX}-table__cell`;
@@ -3986,7 +4428,7 @@ var Table = class {
3986
4428
  const td = document.createElement("td");
3987
4429
  td.className = `${PREFIX}-table__cell`;
3988
4430
  if (typeof col.render === "function") {
3989
- const content = col.render(row, index2);
4431
+ const content = col.render(row, index);
3990
4432
  if (typeof content === "string") {
3991
4433
  td.innerHTML = content;
3992
4434
  } else if (content instanceof HTMLElement) {
@@ -4132,6 +4574,13 @@ var Table = class {
4132
4574
  }
4133
4575
  );
4134
4576
  }
4577
+ handleHeaderSort(col, order) {
4578
+ const field2 = col.accessor;
4579
+ this.state.sortField = field2 ? order === null ? null : field2 : null;
4580
+ this.state.sortOrder = order;
4581
+ this.state.currentPage = 1;
4582
+ this.loadData();
4583
+ }
4135
4584
  updateSortIndicators() {
4136
4585
  const btns = this.elements.theadTr.querySelectorAll(
4137
4586
  `.${PREFIX}-table__sort-button`
@@ -4139,10 +4588,15 @@ var Table = class {
4139
4588
  btns.forEach((btn) => {
4140
4589
  const th = btn.closest("th");
4141
4590
  if (!th) return;
4142
- const field = th.getAttribute("data-sort");
4591
+ const field2 = th.getAttribute("data-sort");
4143
4592
  const order = btn.getAttribute("data-order");
4144
- const active = this.state.sortField === field && this.state.sortOrder === order;
4593
+ const active = this.state.sortField === field2 && this.state.sortOrder === order;
4145
4594
  btn.classList.toggle(`${PREFIX}-table__sort-button--active`, active);
4595
+ let currentSort = "none";
4596
+ if (this.state.sortField === field2) {
4597
+ currentSort = this.state.sortOrder === "asc" ? "ascending" : "descending";
4598
+ }
4599
+ th.setAttribute("aria-sort", currentSort);
4146
4600
  });
4147
4601
  }
4148
4602
  async loadData() {
@@ -4220,8 +4674,8 @@ var Table = class {
4220
4674
  this.triggerSelectionChange();
4221
4675
  }
4222
4676
  toggleAllSelection(checked) {
4223
- this.state.currentData.forEach((row, index2) => {
4224
- const keyStr = String(row[this.options.rowKey] || index2);
4677
+ this.state.currentData.forEach((row, index) => {
4678
+ const keyStr = String(row[this.options.rowKey] || index);
4225
4679
  if (checked) {
4226
4680
  this.state.selectedKeys.add(keyStr);
4227
4681
  this.state.selectedRows.set(keyStr, row);
@@ -4302,11 +4756,11 @@ var Table = class {
4302
4756
  };
4303
4757
  }
4304
4758
  };
4305
- function initTable(selectorOrElement, options2 = {}) {
4759
+ function initTable(selectorOrElement, options = {}) {
4306
4760
  const elements = typeof selectorOrElement === "string" ? document.querySelectorAll(selectorOrElement) : selectorOrElement ? typeof selectorOrElement.length !== "undefined" ? selectorOrElement : [selectorOrElement] : document.querySelectorAll(`.${PREFIX}-table`);
4307
4761
  const instances = [];
4308
4762
  elements.forEach((container) => {
4309
- const instance = new Table(container, options2);
4763
+ const instance = new Table(container, options);
4310
4764
  container.__tableAPI = instance;
4311
4765
  instances.push(instance);
4312
4766
  });
@@ -4340,17 +4794,17 @@ function initMonthPicker(rootSelector = `.${PREFIX}-month-picker`) {
4340
4794
  const trigger = container.querySelector(`.${PREFIX}-month-picker__trigger`);
4341
4795
  const panel = container.querySelector(`.${PREFIX}-month-picker__panel`);
4342
4796
  const grid = container.querySelector(`.${PREFIX}-month-picker__grid`);
4343
- const options2 = grid ? Array.from(
4797
+ const options = grid ? Array.from(
4344
4798
  grid.querySelectorAll(`.${PREFIX}-month-picker__month-option`)
4345
4799
  ) : [];
4346
- if (!trigger || !panel || !grid || options2.length === 0) return;
4800
+ if (!trigger || !panel || !grid || options.length === 0) return;
4347
4801
  let isPickerOpen = false;
4348
4802
  const updateText = () => {
4349
4803
  const textEl = trigger.querySelector(
4350
4804
  `.${PREFIX}-month-picker__trigger-text`
4351
4805
  );
4352
4806
  if (textEl) textEl.textContent = MONTHS_SHORT_ID[currentMonthIdx];
4353
- options2.forEach((opt, idx) => {
4807
+ options.forEach((opt, idx) => {
4354
4808
  if (idx === currentMonthIdx) {
4355
4809
  opt.classList.add(`${PREFIX}-month-picker__month-option--selected`);
4356
4810
  opt.setAttribute("aria-selected", "true");
@@ -4371,7 +4825,7 @@ function initMonthPicker(rootSelector = `.${PREFIX}-month-picker`) {
4371
4825
  panel.classList.add(`${PREFIX}-month-picker__panel--open`);
4372
4826
  trigger.setAttribute("aria-expanded", "true");
4373
4827
  setTimeout(() => {
4374
- const selectedOpt = options2.find((o) => o.tabIndex === 0);
4828
+ const selectedOpt = options.find((o) => o.tabIndex === 0);
4375
4829
  if (selectedOpt) selectedOpt.focus();
4376
4830
  }, 0);
4377
4831
  } else {
@@ -4395,7 +4849,7 @@ function initMonthPicker(rootSelector = `.${PREFIX}-month-picker`) {
4395
4849
  document.addEventListener("click", (e) => {
4396
4850
  if (!container.contains(e.target)) togglePicker(false);
4397
4851
  });
4398
- options2.forEach((btn, idx) => {
4852
+ options.forEach((btn, idx) => {
4399
4853
  btn.setAttribute("role", "option");
4400
4854
  btn.addEventListener("click", (e) => {
4401
4855
  if (disabled || readonly) return;
@@ -4438,8 +4892,8 @@ function initMonthPicker(rootSelector = `.${PREFIX}-month-picker`) {
4438
4892
  else if (e.key === "ArrowDown")
4439
4893
  nextIndex += 3;
4440
4894
  else if (e.key === "ArrowUp") nextIndex -= 3;
4441
- if (options2[nextIndex]) {
4442
- options2[nextIndex].focus();
4895
+ if (options[nextIndex]) {
4896
+ options[nextIndex].focus();
4443
4897
  }
4444
4898
  }
4445
4899
  });
@@ -4540,12 +4994,12 @@ function initYearPicker(rootSelector = `.${PREFIX}-year-picker`) {
4540
4994
  } else if (["ArrowRight", "ArrowLeft", "ArrowDown", "ArrowUp"].includes(e.key)) {
4541
4995
  e.preventDefault();
4542
4996
  e.stopPropagation();
4543
- const options2 = Array.from(
4997
+ const options = Array.from(
4544
4998
  grid.querySelectorAll(
4545
4999
  `.${PREFIX}-year-picker__year-option:not(:disabled)`
4546
5000
  )
4547
5001
  );
4548
- const currentIndex = options2.indexOf(btn);
5002
+ const currentIndex = options.indexOf(btn);
4549
5003
  if (currentIndex === -1) return;
4550
5004
  let nextIndex = currentIndex;
4551
5005
  if (e.key === "ArrowRight") nextIndex += 1;
@@ -4553,8 +5007,8 @@ function initYearPicker(rootSelector = `.${PREFIX}-year-picker`) {
4553
5007
  else if (e.key === "ArrowDown")
4554
5008
  nextIndex += 4;
4555
5009
  else if (e.key === "ArrowUp") nextIndex -= 4;
4556
- if (options2[nextIndex]) {
4557
- options2[nextIndex].focus();
5010
+ if (options[nextIndex]) {
5011
+ options[nextIndex].focus();
4558
5012
  } else {
4559
5013
  }
4560
5014
  }
@@ -4681,7 +5135,7 @@ function createToastElement({ title, message, state, style, actionHtml }) {
4681
5135
  return { toastItem, toast };
4682
5136
  }
4683
5137
  function showToast(optionsOrMessage, variant = "default", duration = 5e3) {
4684
- const options2 = typeof optionsOrMessage === "string" ? {
5138
+ const options = typeof optionsOrMessage === "string" ? {
4685
5139
  message: optionsOrMessage,
4686
5140
  state: variant,
4687
5141
  duration
@@ -4694,7 +5148,7 @@ function showToast(optionsOrMessage, variant = "default", duration = 5e3) {
4694
5148
  duration: autoCloseDuration = 5e3,
4695
5149
  position = "top-right",
4696
5150
  actionHtml = ""
4697
- } = options2;
5151
+ } = options;
4698
5152
  const container = getOrCreateContainer(position);
4699
5153
  const { toastItem, toast } = createToastElement({
4700
5154
  title,
@@ -4755,7 +5209,6 @@ function setBrandTheme(brandName) {
4755
5209
  var PREFIX = "ina";
4756
5210
  function initAll() {
4757
5211
  initAccordion();
4758
- initBanner();
4759
5212
  initButtonGroup();
4760
5213
  initCheckbox();
4761
5214
  initDatepicker();
@@ -4776,6 +5229,7 @@ function initAll() {
4776
5229
  initTab();
4777
5230
  initToggle();
4778
5231
  initPagination();
5232
+ initPhoneInput();
4779
5233
  initChip();
4780
5234
  initTabVertical();
4781
5235
  initTabHorizontal();
@@ -4786,6 +5240,7 @@ function initAll() {
4786
5240
  export {
4787
5241
  DatePicker,
4788
5242
  PREFIX,
5243
+ PhoneInput,
4789
5244
  Table,
4790
5245
  TimePicker,
4791
5246
  initAll,