@idds/js 1.0.60 → 1.0.62

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 +145 -145
  2. package/dist/index.js +583 -126
  3. package/package.json +1 -1
@@ -829,150 +829,6 @@ var InaUI = (() => {
829
829
  });
830
830
  }
831
831
 
832
- // src/js/components/stateful/dropdown.js
833
- function initDropdown(rootSelector = `.${PREFIX}-dropdown`) {
834
- document.querySelectorAll(rootSelector).forEach((dropdown) => {
835
- const trigger = dropdown.querySelector(`.${PREFIX}-dropdown__trigger`);
836
- const input = dropdown.querySelector(`.${PREFIX}-dropdown__input`);
837
- const menu = dropdown.querySelector(`.${PREFIX}-dropdown__menu`);
838
- const menuItems = menu.querySelectorAll("li[role='option']");
839
- const menuId = menu.id;
840
- let activeIndex = -1;
841
- menuItems.forEach((item, index) => {
842
- item.id = `${menuId}-item-${index}`;
843
- });
844
- const toggleMenu = (show) => {
845
- const isCurrentlyShown = dropdown.classList.contains("show");
846
- const isShown = show !== void 0 ? show : !isCurrentlyShown;
847
- if (isShown === isCurrentlyShown) {
848
- return;
849
- }
850
- dropdown.classList.toggle("show", isShown);
851
- trigger.setAttribute("aria-expanded", isShown);
852
- if (isShown) {
853
- input.focus();
854
- } else {
855
- input.blur();
856
- removeHighlight();
857
- activeIndex = -1;
858
- input.removeAttribute("aria-activedescendant");
859
- }
860
- };
861
- const filterItems = () => {
862
- const filterValue = input.value.toLowerCase();
863
- let hasVisibleItems = false;
864
- activeIndex = -1;
865
- removeHighlight();
866
- input.removeAttribute("aria-activedescendant");
867
- const activeItem = menu.querySelector("li[role='option'].selected");
868
- if (activeItem && input.value !== activeItem.textContent.trim()) {
869
- activeItem.classList.remove("selected");
870
- }
871
- menuItems.forEach((item) => {
872
- const itemText = item.textContent.toLowerCase();
873
- const isMatch = itemText.includes(filterValue);
874
- item.classList.toggle("hidden", !isMatch);
875
- if (isMatch) hasVisibleItems = true;
876
- });
877
- if (!dropdown.classList.contains("show") && hasVisibleItems) {
878
- toggleMenu(true);
879
- }
880
- };
881
- const selectItem = (item) => {
882
- const itemText = item.textContent.trim();
883
- input.value = itemText;
884
- menuItems.forEach((li) => {
885
- li.classList.remove("selected");
886
- });
887
- if (item) {
888
- item.classList.add("selected");
889
- dropdown.dispatchEvent(
890
- new CustomEvent("dropdown:changed", {
891
- detail: { value: itemText }
892
- })
893
- );
894
- }
895
- toggleMenu(false);
896
- };
897
- const setHighlight = (index) => {
898
- removeHighlight();
899
- const visibleItems = menu.querySelectorAll(
900
- "li[role='option']:not(.hidden)"
901
- );
902
- if (visibleItems.length === 0) return;
903
- if (index < 0) index = 0;
904
- else if (index >= visibleItems.length) index = visibleItems.length - 1;
905
- const itemToHighlight = visibleItems[index];
906
- if (itemToHighlight) {
907
- itemToHighlight.classList.add("highlighted");
908
- input.setAttribute("aria-activedescendant", itemToHighlight.id);
909
- itemToHighlight.scrollIntoView({
910
- behavior: "smooth",
911
- block: "nearest"
912
- });
913
- activeIndex = index;
914
- }
915
- };
916
- const removeHighlight = () => {
917
- menuItems.forEach((item) => item.classList.remove("highlighted"));
918
- };
919
- trigger.addEventListener("click", () => {
920
- toggleMenu();
921
- });
922
- input.addEventListener("input", filterItems);
923
- menu.addEventListener("click", (e) => {
924
- const option = e.target.closest("li[role='option']");
925
- if (option) {
926
- e.preventDefault();
927
- selectItem(option);
928
- }
929
- });
930
- document.addEventListener("click", (e) => {
931
- if (!dropdown.contains(e.target)) {
932
- toggleMenu(false);
933
- }
934
- });
935
- input.addEventListener("keydown", (e) => {
936
- const { key } = e;
937
- const isMenuOpen = dropdown.classList.contains("show");
938
- switch (key) {
939
- case "ArrowDown":
940
- e.preventDefault();
941
- if (!isMenuOpen) {
942
- toggleMenu(true);
943
- }
944
- setHighlight(activeIndex + 1);
945
- break;
946
- case "ArrowUp":
947
- e.preventDefault();
948
- if (isMenuOpen) {
949
- setHighlight(activeIndex - 1);
950
- }
951
- break;
952
- case "Enter":
953
- e.preventDefault();
954
- const firstVisible = menu.querySelector(
955
- "li[role='option']:not(.hidden)"
956
- );
957
- const activeItem = menu.querySelector(".highlighted");
958
- if (isMenuOpen && activeItem) {
959
- selectItem(activeItem);
960
- } else if (isMenuOpen && firstVisible) {
961
- toggleMenu(false);
962
- }
963
- break;
964
- case "Escape":
965
- e.preventDefault();
966
- toggleMenu(false);
967
- break;
968
- case "Tab":
969
- toggleMenu(false);
970
- break;
971
- }
972
- });
973
- });
974
- }
975
-
976
832
  // src/js/components/stateful/file-upload.js
977
833
  var ICONS = {
978
834
  upload: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"></path><polyline points="16 6 12 2 8 6"></polyline><line x1="12" y1="2" x2="12" y2="16"></line></svg>`,
@@ -1208,7 +1064,7 @@ var InaUI = (() => {
1208
1064
  `.${PREFIX}-single-file-upload__description`
1209
1065
  );
1210
1066
  const initialTitle = titleEl ? titleEl.textContent : "Unggah File";
1211
- const initialDescription = descriptionEl ? descriptionEl.textContent : "Unggah atau seret dan lepas ke sini";
1067
+ const initialDescription = descriptionEl && descriptionEl.textContent.trim() ? descriptionEl.textContent : "Unggah atau seret dan lepas ke sini";
1212
1068
  const maxSize = parseInt(container.getAttribute("data-max-size")) || 0;
1213
1069
  const allowedExtensions = (container.getAttribute("data-allowed-extensions") || "").toLowerCase().split(",").map((ext) => ext.trim()).filter(Boolean);
1214
1070
  let status = "idle";
@@ -1781,6 +1637,150 @@ var InaUI = (() => {
1781
1637
  });
1782
1638
  }
1783
1639
 
1640
+ // src/js/components/stateful/dropdown.js
1641
+ function initDropdown(rootSelector = `.${PREFIX}-dropdown`) {
1642
+ document.querySelectorAll(rootSelector).forEach((dropdown) => {
1643
+ const trigger = dropdown.querySelector(`.${PREFIX}-dropdown__trigger`);
1644
+ const input = dropdown.querySelector(`.${PREFIX}-dropdown__input`);
1645
+ const menu = dropdown.querySelector(`.${PREFIX}-dropdown__menu`);
1646
+ const menuItems = menu.querySelectorAll("li[role='option']");
1647
+ const menuId = menu.id;
1648
+ let activeIndex = -1;
1649
+ menuItems.forEach((item, index) => {
1650
+ item.id = `${menuId}-item-${index}`;
1651
+ });
1652
+ const toggleMenu = (show) => {
1653
+ const isCurrentlyShown = dropdown.classList.contains("show");
1654
+ const isShown = show !== void 0 ? show : !isCurrentlyShown;
1655
+ if (isShown === isCurrentlyShown) {
1656
+ return;
1657
+ }
1658
+ dropdown.classList.toggle("show", isShown);
1659
+ trigger.setAttribute("aria-expanded", isShown);
1660
+ if (isShown) {
1661
+ input.focus();
1662
+ } else {
1663
+ input.blur();
1664
+ removeHighlight();
1665
+ activeIndex = -1;
1666
+ input.removeAttribute("aria-activedescendant");
1667
+ }
1668
+ };
1669
+ const filterItems = () => {
1670
+ const filterValue = input.value.toLowerCase();
1671
+ let hasVisibleItems = false;
1672
+ activeIndex = -1;
1673
+ removeHighlight();
1674
+ input.removeAttribute("aria-activedescendant");
1675
+ const activeItem = menu.querySelector("li[role='option'].selected");
1676
+ if (activeItem && input.value !== activeItem.textContent.trim()) {
1677
+ activeItem.classList.remove("selected");
1678
+ }
1679
+ menuItems.forEach((item) => {
1680
+ const itemText = item.textContent.toLowerCase();
1681
+ const isMatch = itemText.includes(filterValue);
1682
+ item.classList.toggle("hidden", !isMatch);
1683
+ if (isMatch) hasVisibleItems = true;
1684
+ });
1685
+ if (!dropdown.classList.contains("show") && hasVisibleItems) {
1686
+ toggleMenu(true);
1687
+ }
1688
+ };
1689
+ const selectItem = (item) => {
1690
+ const itemText = item.textContent.trim();
1691
+ input.value = itemText;
1692
+ menuItems.forEach((li) => {
1693
+ li.classList.remove("selected");
1694
+ });
1695
+ if (item) {
1696
+ item.classList.add("selected");
1697
+ dropdown.dispatchEvent(
1698
+ new CustomEvent("dropdown:changed", {
1699
+ detail: { value: itemText }
1700
+ })
1701
+ );
1702
+ }
1703
+ toggleMenu(false);
1704
+ };
1705
+ const setHighlight = (index) => {
1706
+ removeHighlight();
1707
+ const visibleItems = menu.querySelectorAll(
1708
+ "li[role='option']:not(.hidden)"
1709
+ );
1710
+ if (visibleItems.length === 0) return;
1711
+ if (index < 0) index = 0;
1712
+ else if (index >= visibleItems.length) index = visibleItems.length - 1;
1713
+ const itemToHighlight = visibleItems[index];
1714
+ if (itemToHighlight) {
1715
+ itemToHighlight.classList.add("highlighted");
1716
+ input.setAttribute("aria-activedescendant", itemToHighlight.id);
1717
+ itemToHighlight.scrollIntoView({
1718
+ behavior: "smooth",
1719
+ block: "nearest"
1720
+ });
1721
+ activeIndex = index;
1722
+ }
1723
+ };
1724
+ const removeHighlight = () => {
1725
+ menuItems.forEach((item) => item.classList.remove("highlighted"));
1726
+ };
1727
+ trigger.addEventListener("click", () => {
1728
+ toggleMenu();
1729
+ });
1730
+ input.addEventListener("input", filterItems);
1731
+ menu.addEventListener("click", (e) => {
1732
+ const option = e.target.closest("li[role='option']");
1733
+ if (option) {
1734
+ e.preventDefault();
1735
+ selectItem(option);
1736
+ }
1737
+ });
1738
+ document.addEventListener("click", (e) => {
1739
+ if (!dropdown.contains(e.target)) {
1740
+ toggleMenu(false);
1741
+ }
1742
+ });
1743
+ input.addEventListener("keydown", (e) => {
1744
+ const { key } = e;
1745
+ const isMenuOpen = dropdown.classList.contains("show");
1746
+ switch (key) {
1747
+ case "ArrowDown":
1748
+ e.preventDefault();
1749
+ if (!isMenuOpen) {
1750
+ toggleMenu(true);
1751
+ }
1752
+ setHighlight(activeIndex + 1);
1753
+ break;
1754
+ case "ArrowUp":
1755
+ e.preventDefault();
1756
+ if (isMenuOpen) {
1757
+ setHighlight(activeIndex - 1);
1758
+ }
1759
+ break;
1760
+ case "Enter":
1761
+ e.preventDefault();
1762
+ const firstVisible = menu.querySelector(
1763
+ "li[role='option']:not(.hidden)"
1764
+ );
1765
+ const activeItem = menu.querySelector(".highlighted");
1766
+ if (isMenuOpen && activeItem) {
1767
+ selectItem(activeItem);
1768
+ } else if (isMenuOpen && firstVisible) {
1769
+ toggleMenu(false);
1770
+ }
1771
+ break;
1772
+ case "Escape":
1773
+ e.preventDefault();
1774
+ toggleMenu(false);
1775
+ break;
1776
+ case "Tab":
1777
+ toggleMenu(false);
1778
+ break;
1779
+ }
1780
+ });
1781
+ });
1782
+ }
1783
+
1784
1784
  // src/js/components/stateful/range-datepicker.js
1785
1785
  function initRangeDatepicker() {
1786
1786
  document.querySelectorAll(".ina-ss-range-datepicker").forEach((rangeDatepicker) => {
package/dist/index.js CHANGED
@@ -832,147 +832,348 @@ function initModal(rootSelector = `.${PREFIX}-modal`) {
832
832
  });
833
833
  }
834
834
 
835
- // src/js/components/stateful/dropdown.js
836
- function initDropdown(rootSelector = `.${PREFIX}-dropdown`) {
837
- document.querySelectorAll(rootSelector).forEach((dropdown) => {
838
- const trigger = dropdown.querySelector(`.${PREFIX}-dropdown__trigger`);
839
- const input = dropdown.querySelector(`.${PREFIX}-dropdown__input`);
840
- const menu = dropdown.querySelector(`.${PREFIX}-dropdown__menu`);
841
- const menuItems = menu.querySelectorAll("li[role='option']");
842
- const menuId = menu.id;
843
- let activeIndex = -1;
844
- menuItems.forEach((item, index) => {
845
- item.id = `${menuId}-item-${index}`;
835
+ // src/js/components/stateless/drawer.js
836
+ function initDrawer(rootSelector = `.${PREFIX}-drawer`) {
837
+ const drawers = document.querySelectorAll(rootSelector);
838
+ const closeDrawer = (drawer) => {
839
+ if (!drawer) return;
840
+ drawer.classList.add(`${PREFIX}-drawer--closing`);
841
+ const onAnimationEnd = () => {
842
+ drawer.classList.remove(`${PREFIX}-drawer--closing`);
843
+ drawer.style.display = "none";
844
+ document.body.style.overflow = "";
845
+ drawer.removeEventListener("animationend", onAnimationEnd);
846
+ };
847
+ drawer.addEventListener("animationend", onAnimationEnd, { once: true });
848
+ };
849
+ const openDrawer = (drawer) => {
850
+ if (!drawer) return;
851
+ drawer.style.display = "flex";
852
+ document.body.style.overflow = "hidden";
853
+ drawer.dispatchEvent(new CustomEvent("drawer:open"));
854
+ };
855
+ drawers.forEach((drawer) => {
856
+ if (drawer.__inaDrawerInitialized) return;
857
+ const isPersistent = drawer.getAttribute("data-persistent") === "true";
858
+ const closeBtns = drawer.querySelectorAll(
859
+ `.${PREFIX}-drawer__close-button`
860
+ );
861
+ closeBtns.forEach((btn) => {
862
+ btn.addEventListener("click", () => closeDrawer(drawer));
846
863
  });
847
- const toggleMenu = (show) => {
848
- const isCurrentlyShown = dropdown.classList.contains("show");
849
- const isShown = show !== void 0 ? show : !isCurrentlyShown;
850
- if (isShown === isCurrentlyShown) {
851
- return;
864
+ const backdrop = drawer.querySelector(`.${PREFIX}-drawer__backdrop`);
865
+ if (backdrop) {
866
+ backdrop.addEventListener("click", (e) => {
867
+ if (!isPersistent) {
868
+ closeDrawer(drawer);
869
+ }
870
+ });
871
+ }
872
+ document.addEventListener("keydown", (e) => {
873
+ if (e.key === "Escape" && drawer.style.display === "flex" && !isPersistent) {
874
+ closeDrawer(drawer);
852
875
  }
853
- dropdown.classList.toggle("show", isShown);
854
- trigger.setAttribute("aria-expanded", isShown);
855
- if (isShown) {
856
- input.focus();
876
+ });
877
+ drawer.__inaDrawerInitialized = true;
878
+ });
879
+ document.body.addEventListener("click", (e) => {
880
+ const trigger = e.target.closest('[data-trigger="drawer"]');
881
+ if (trigger) {
882
+ const targetId = trigger.getAttribute("data-target");
883
+ if (targetId) {
884
+ const targetDrawer = document.querySelector(targetId);
885
+ if (targetDrawer) {
886
+ openDrawer(targetDrawer);
887
+ }
888
+ }
889
+ }
890
+ const closeTrigger = e.target.closest('[data-dismiss="drawer"]');
891
+ if (closeTrigger) {
892
+ const targetId = closeTrigger.getAttribute("data-target");
893
+ let targetDrawer;
894
+ if (targetId) {
895
+ targetDrawer = document.querySelector(targetId);
857
896
  } else {
858
- input.blur();
859
- removeHighlight();
860
- activeIndex = -1;
861
- input.removeAttribute("aria-activedescendant");
897
+ targetDrawer = closeTrigger.closest(`.${PREFIX}-drawer`);
862
898
  }
863
- };
864
- const filterItems = () => {
865
- const filterValue = input.value.toLowerCase();
866
- let hasVisibleItems = false;
867
- activeIndex = -1;
868
- removeHighlight();
869
- input.removeAttribute("aria-activedescendant");
870
- const activeItem = menu.querySelector("li[role='option'].selected");
871
- if (activeItem && input.value !== activeItem.textContent.trim()) {
872
- activeItem.classList.remove("selected");
899
+ if (targetDrawer) {
900
+ closeDrawer(targetDrawer);
873
901
  }
874
- menuItems.forEach((item) => {
875
- const itemText = item.textContent.toLowerCase();
876
- const isMatch = itemText.includes(filterValue);
877
- item.classList.toggle("hidden", !isMatch);
878
- if (isMatch) hasVisibleItems = true;
879
- });
880
- if (!dropdown.classList.contains("show") && hasVisibleItems) {
881
- toggleMenu(true);
902
+ }
903
+ });
904
+ }
905
+
906
+ // src/js/components/stateful/basic-dropdown.js
907
+ var handleDropdownLogic = (rootSelector, triggerSelector, panelSelector, activeClass) => {
908
+ const dropdowns = document.querySelectorAll(rootSelector);
909
+ dropdowns.forEach((dropdown) => {
910
+ if (dropdown.__inaDropdownInitialized) return;
911
+ const trigger = dropdown.querySelector(triggerSelector);
912
+ const panel = dropdown.querySelector(panelSelector);
913
+ if (!trigger || !panel) return;
914
+ const toggle = (force) => {
915
+ const isExpanded = trigger.getAttribute("aria-expanded") === "true";
916
+ const shouldExpand = force !== void 0 ? force : !isExpanded;
917
+ trigger.setAttribute("aria-expanded", shouldExpand);
918
+ if (shouldExpand) {
919
+ panel.classList.add(activeClass);
920
+ panel.style.display = "block";
921
+ if (activeClass) panel.classList.add(activeClass);
922
+ if (rootSelector.includes("basic")) {
923
+ const btn = trigger.querySelector(
924
+ `.${PREFIX}-basic-dropdown__trigger-button`
925
+ );
926
+ if (btn)
927
+ btn.classList.add(`${PREFIX}-basic-dropdown__trigger-button--open`);
928
+ } else {
929
+ trigger.classList.add(`${PREFIX}-action-dropdown__trigger--open`);
930
+ }
931
+ } else {
932
+ if (activeClass) panel.classList.remove(activeClass);
933
+ panel.style.display = "none";
934
+ if (rootSelector.includes("basic")) {
935
+ const btn = trigger.querySelector(
936
+ `.${PREFIX}-basic-dropdown__trigger-button`
937
+ );
938
+ if (btn)
939
+ btn.classList.remove(
940
+ `${PREFIX}-basic-dropdown__trigger-button--open`
941
+ );
942
+ } else {
943
+ trigger.classList.remove(`${PREFIX}-action-dropdown__trigger--open`);
944
+ }
882
945
  }
883
946
  };
884
- const selectItem = (item) => {
885
- const itemText = item.textContent.trim();
886
- input.value = itemText;
887
- menuItems.forEach((li) => {
888
- li.classList.remove("selected");
947
+ panel.style.display = "none";
948
+ trigger.addEventListener("click", (e) => {
949
+ e.stopPropagation();
950
+ toggle();
951
+ });
952
+ document.addEventListener("click", (e) => {
953
+ if (!dropdown.contains(e.target)) {
954
+ toggle(false);
955
+ }
956
+ });
957
+ dropdown.addEventListener("keydown", (e) => {
958
+ if (e.key === "Escape") {
959
+ toggle(false);
960
+ }
961
+ });
962
+ if (rootSelector.includes("action")) {
963
+ panel.addEventListener("click", (e) => {
964
+ const item = e.target.closest(`.${PREFIX}-action-dropdown__item`);
965
+ if (item && !item.disabled) {
966
+ toggle(false);
967
+ }
889
968
  });
890
- if (item) {
891
- item.classList.add("selected");
892
- dropdown.dispatchEvent(
893
- new CustomEvent("dropdown:changed", {
894
- detail: { value: itemText }
895
- })
896
- );
969
+ }
970
+ dropdown.__inaDropdownInitialized = true;
971
+ });
972
+ };
973
+ function initBasicDropdown() {
974
+ handleDropdownLogic(
975
+ `.${PREFIX}-basic-dropdown`,
976
+ `.${PREFIX}-basic-dropdown__trigger`,
977
+ `.${PREFIX}-basic-dropdown__panel`
978
+ );
979
+ }
980
+ function initActionDropdown() {
981
+ handleDropdownLogic(
982
+ `.${PREFIX}-action-dropdown`,
983
+ `.${PREFIX}-action-dropdown__trigger`,
984
+ `.${PREFIX}-action-dropdown__menu`,
985
+ `${PREFIX}-action-dropdown__menu--visible`
986
+ );
987
+ }
988
+
989
+ // src/js/components/stateful/select-dropdown.js
990
+ function initSelectDropdown(rootSelector = `.${PREFIX}-select-dropdown`) {
991
+ document.querySelectorAll(rootSelector).forEach((dropdown) => {
992
+ if (dropdown.__inaSelectDropdownInitialized) return;
993
+ const isMultiple = dropdown.getAttribute("data-multiple") === "true";
994
+ const isSearchable = dropdown.getAttribute("data-searchable") !== "false";
995
+ const trigger = dropdown.querySelector(
996
+ `.${PREFIX}-select-dropdown__trigger`
997
+ );
998
+ const input = dropdown.querySelector(
999
+ `.${PREFIX}-select-dropdown__trigger-input`
1000
+ );
1001
+ const panel = dropdown.querySelector(`.${PREFIX}-select-dropdown__panel`);
1002
+ const optionsContainer = dropdown.querySelector(
1003
+ `.${PREFIX}-select-dropdown__options`
1004
+ );
1005
+ if (!trigger || !panel) return;
1006
+ let isOpen = false;
1007
+ let selectedValues = [];
1008
+ const options = panel.querySelectorAll(
1009
+ `.${PREFIX}-select-dropdown__option`
1010
+ );
1011
+ options.forEach((opt) => {
1012
+ if (opt.classList.contains(
1013
+ `${PREFIX}-select-dropdown__option--selected-single`
1014
+ ) || opt.classList.contains(
1015
+ `${PREFIX}-select-dropdown__option--selected-multiple`
1016
+ )) {
1017
+ const val = getOptionValue(opt);
1018
+ if (val) selectedValues.push(val);
1019
+ }
1020
+ });
1021
+ const toggle = (force) => {
1022
+ const shouldOpen = force !== void 0 ? force : !isOpen;
1023
+ if (shouldOpen === isOpen) return;
1024
+ isOpen = shouldOpen;
1025
+ trigger.setAttribute("aria-expanded", isOpen);
1026
+ if (isOpen) {
1027
+ panel.style.display = "block";
1028
+ if (input) input.focus();
1029
+ } else {
1030
+ panel.style.display = "none";
897
1031
  }
898
- toggleMenu(false);
899
1032
  };
900
- const setHighlight = (index) => {
901
- removeHighlight();
902
- const visibleItems = menu.querySelectorAll(
903
- "li[role='option']:not(.hidden)"
1033
+ panel.style.display = "none";
1034
+ function getOptionValue(option) {
1035
+ return option.getAttribute("data-value");
1036
+ }
1037
+ function getOptionLabel(option) {
1038
+ return option.textContent.trim();
1039
+ }
1040
+ function updateTriggerUI() {
1041
+ const triggerText = trigger.querySelector(
1042
+ `.${PREFIX}-select-dropdown__trigger-text`
904
1043
  );
905
- if (visibleItems.length === 0) return;
906
- if (index < 0) index = 0;
907
- else if (index >= visibleItems.length) index = visibleItems.length - 1;
908
- const itemToHighlight = visibleItems[index];
909
- if (itemToHighlight) {
910
- itemToHighlight.classList.add("highlighted");
911
- input.setAttribute("aria-activedescendant", itemToHighlight.id);
912
- itemToHighlight.scrollIntoView({
913
- behavior: "smooth",
914
- block: "nearest"
1044
+ if (isMultiple) {
1045
+ let label = "";
1046
+ if (selectedValues.length === 0) {
1047
+ label = input ? input.getAttribute("placeholder") : triggerText ? triggerText.getAttribute("data-placeholder") : "Select...";
1048
+ } else if (selectedValues.length > 3) {
1049
+ label = `${selectedValues.length} data terpilih`;
1050
+ } else {
1051
+ const labels = [];
1052
+ selectedValues.forEach((val) => {
1053
+ const opt = Array.from(options).find(
1054
+ (o) => getOptionValue(o) === val
1055
+ );
1056
+ if (opt) labels.push(getOptionLabel(opt));
1057
+ else labels.push(val);
1058
+ });
1059
+ label = labels.join(", ");
1060
+ }
1061
+ if (input) {
1062
+ input.value = "";
1063
+ input.placeholder = label;
1064
+ } else if (triggerText) {
1065
+ triggerText.textContent = label;
1066
+ triggerText.classList.toggle(
1067
+ `${PREFIX}-select-dropdown__trigger-text--placeholder`,
1068
+ selectedValues.length === 0
1069
+ );
1070
+ }
1071
+ } else {
1072
+ const val = selectedValues[0];
1073
+ let label = "";
1074
+ if (val) {
1075
+ const opt = Array.from(options).find(
1076
+ (o) => getOptionValue(o) === val
1077
+ );
1078
+ label = opt ? getOptionLabel(opt) : val;
1079
+ } else {
1080
+ label = input ? input.getAttribute("placeholder") : triggerText ? triggerText.getAttribute("data-placeholder") : "Select...";
1081
+ }
1082
+ if (input) {
1083
+ if (!isOpen) input.value = label;
1084
+ } else if (triggerText) {
1085
+ triggerText.textContent = label;
1086
+ triggerText.classList.toggle(
1087
+ `${PREFIX}-select-dropdown__trigger-text--placeholder`,
1088
+ !val
1089
+ );
1090
+ }
1091
+ }
1092
+ }
1093
+ function selectOption(option) {
1094
+ if (option.hasAttribute("disabled")) return;
1095
+ const val = getOptionValue(option);
1096
+ if (isMultiple) {
1097
+ const idx = selectedValues.indexOf(val);
1098
+ if (idx > -1) {
1099
+ selectedValues.splice(idx, 1);
1100
+ option.classList.remove(
1101
+ `${PREFIX}-select-dropdown__option--selected-multiple`
1102
+ );
1103
+ const checkbox = option.querySelector(
1104
+ `.${PREFIX}-select-dropdown__option-checkbox`
1105
+ );
1106
+ if (checkbox)
1107
+ checkbox.classList.remove(
1108
+ `${PREFIX}-select-dropdown__option-checkbox--checked`
1109
+ );
1110
+ } else {
1111
+ selectedValues.push(val);
1112
+ option.classList.add(
1113
+ `${PREFIX}-select-dropdown__option--selected-multiple`
1114
+ );
1115
+ const checkbox = option.querySelector(
1116
+ `.${PREFIX}-select-dropdown__option-checkbox`
1117
+ );
1118
+ if (checkbox)
1119
+ checkbox.classList.add(
1120
+ `${PREFIX}-select-dropdown__option-checkbox--checked`
1121
+ );
1122
+ }
1123
+ } else {
1124
+ selectedValues = [val];
1125
+ options.forEach((o) => {
1126
+ o.classList.remove(
1127
+ `${PREFIX}-select-dropdown__option--selected-single`
1128
+ );
915
1129
  });
916
- activeIndex = index;
1130
+ option.classList.add(
1131
+ `${PREFIX}-select-dropdown__option--selected-single`
1132
+ );
1133
+ toggle(false);
917
1134
  }
918
- };
919
- const removeHighlight = () => {
920
- menuItems.forEach((item) => item.classList.remove("highlighted"));
921
- };
922
- trigger.addEventListener("click", () => {
923
- toggleMenu();
924
- });
925
- input.addEventListener("input", filterItems);
926
- menu.addEventListener("click", (e) => {
927
- const option = e.target.closest("li[role='option']");
928
- if (option) {
929
- e.preventDefault();
930
- selectItem(option);
1135
+ updateTriggerUI();
1136
+ dropdown.dispatchEvent(
1137
+ new CustomEvent("change", {
1138
+ detail: { value: isMultiple ? selectedValues : selectedValues[0] }
1139
+ })
1140
+ );
1141
+ }
1142
+ trigger.addEventListener("click", (e) => {
1143
+ if (e.target !== input) {
1144
+ toggle();
1145
+ } else if (!isOpen) {
1146
+ toggle(true);
931
1147
  }
932
1148
  });
933
- document.addEventListener("click", (e) => {
934
- if (!dropdown.contains(e.target)) {
935
- toggleMenu(false);
936
- }
1149
+ if (input) {
1150
+ input.addEventListener("input", (e) => {
1151
+ const term = e.target.value.toLowerCase();
1152
+ if (!isOpen) toggle(true);
1153
+ options.forEach((opt) => {
1154
+ const label = getOptionLabel(opt).toLowerCase();
1155
+ const match = label.includes(term);
1156
+ opt.style.display = match ? "" : "none";
1157
+ });
1158
+ });
1159
+ }
1160
+ options.forEach((opt) => {
1161
+ opt.addEventListener("click", (e) => {
1162
+ e.stopPropagation();
1163
+ selectOption(opt);
1164
+ });
937
1165
  });
938
- input.addEventListener("keydown", (e) => {
939
- const { key } = e;
940
- const isMenuOpen = dropdown.classList.contains("show");
941
- switch (key) {
942
- case "ArrowDown":
943
- e.preventDefault();
944
- if (!isMenuOpen) {
945
- toggleMenu(true);
946
- }
947
- setHighlight(activeIndex + 1);
948
- break;
949
- case "ArrowUp":
950
- e.preventDefault();
951
- if (isMenuOpen) {
952
- setHighlight(activeIndex - 1);
953
- }
954
- break;
955
- case "Enter":
956
- e.preventDefault();
957
- const firstVisible = menu.querySelector(
958
- "li[role='option']:not(.hidden)"
959
- );
960
- const activeItem = menu.querySelector(".highlighted");
961
- if (isMenuOpen && activeItem) {
962
- selectItem(activeItem);
963
- } else if (isMenuOpen && firstVisible) {
964
- toggleMenu(false);
965
- }
966
- break;
967
- case "Escape":
968
- e.preventDefault();
969
- toggleMenu(false);
970
- break;
971
- case "Tab":
972
- toggleMenu(false);
973
- break;
974
- }
1166
+ document.addEventListener("click", (e) => {
1167
+ if (!dropdown.contains(e.target)) toggle(false);
975
1168
  });
1169
+ if (optionsContainer) {
1170
+ optionsContainer.addEventListener("scroll", () => {
1171
+ if (optionsContainer.scrollTop + optionsContainer.clientHeight >= optionsContainer.scrollHeight - 20) {
1172
+ dropdown.dispatchEvent(new CustomEvent("scroll-end"));
1173
+ }
1174
+ });
1175
+ }
1176
+ dropdown.__inaSelectDropdownInitialized = true;
976
1177
  });
977
1178
  }
978
1179
 
@@ -1211,7 +1412,7 @@ function initSingleFileUpload(rootSelector = `.${PREFIX}-single-file-upload`) {
1211
1412
  `.${PREFIX}-single-file-upload__description`
1212
1413
  );
1213
1414
  const initialTitle = titleEl ? titleEl.textContent : "Unggah File";
1214
- const initialDescription = descriptionEl ? descriptionEl.textContent : "Unggah atau seret dan lepas ke sini";
1415
+ const initialDescription = descriptionEl && descriptionEl.textContent.trim() ? descriptionEl.textContent : "Unggah atau seret dan lepas ke sini";
1215
1416
  const maxSize = parseInt(container.getAttribute("data-max-size")) || 0;
1216
1417
  const allowedExtensions = (container.getAttribute("data-allowed-extensions") || "").toLowerCase().split(",").map((ext) => ext.trim()).filter(Boolean);
1217
1418
  let status = "idle";
@@ -1499,6 +1700,150 @@ function initFileUploadItem(rootSelector = `.${PREFIX}-file-item`) {
1499
1700
  });
1500
1701
  }
1501
1702
 
1703
+ // src/js/components/stateful/dropdown.js
1704
+ function initDropdown(rootSelector = `.${PREFIX}-dropdown`) {
1705
+ document.querySelectorAll(rootSelector).forEach((dropdown) => {
1706
+ const trigger = dropdown.querySelector(`.${PREFIX}-dropdown__trigger`);
1707
+ const input = dropdown.querySelector(`.${PREFIX}-dropdown__input`);
1708
+ const menu = dropdown.querySelector(`.${PREFIX}-dropdown__menu`);
1709
+ const menuItems = menu.querySelectorAll("li[role='option']");
1710
+ const menuId = menu.id;
1711
+ let activeIndex = -1;
1712
+ menuItems.forEach((item, index) => {
1713
+ item.id = `${menuId}-item-${index}`;
1714
+ });
1715
+ const toggleMenu = (show) => {
1716
+ const isCurrentlyShown = dropdown.classList.contains("show");
1717
+ const isShown = show !== void 0 ? show : !isCurrentlyShown;
1718
+ if (isShown === isCurrentlyShown) {
1719
+ return;
1720
+ }
1721
+ dropdown.classList.toggle("show", isShown);
1722
+ trigger.setAttribute("aria-expanded", isShown);
1723
+ if (isShown) {
1724
+ input.focus();
1725
+ } else {
1726
+ input.blur();
1727
+ removeHighlight();
1728
+ activeIndex = -1;
1729
+ input.removeAttribute("aria-activedescendant");
1730
+ }
1731
+ };
1732
+ const filterItems = () => {
1733
+ const filterValue = input.value.toLowerCase();
1734
+ let hasVisibleItems = false;
1735
+ activeIndex = -1;
1736
+ removeHighlight();
1737
+ input.removeAttribute("aria-activedescendant");
1738
+ const activeItem = menu.querySelector("li[role='option'].selected");
1739
+ if (activeItem && input.value !== activeItem.textContent.trim()) {
1740
+ activeItem.classList.remove("selected");
1741
+ }
1742
+ menuItems.forEach((item) => {
1743
+ const itemText = item.textContent.toLowerCase();
1744
+ const isMatch = itemText.includes(filterValue);
1745
+ item.classList.toggle("hidden", !isMatch);
1746
+ if (isMatch) hasVisibleItems = true;
1747
+ });
1748
+ if (!dropdown.classList.contains("show") && hasVisibleItems) {
1749
+ toggleMenu(true);
1750
+ }
1751
+ };
1752
+ const selectItem = (item) => {
1753
+ const itemText = item.textContent.trim();
1754
+ input.value = itemText;
1755
+ menuItems.forEach((li) => {
1756
+ li.classList.remove("selected");
1757
+ });
1758
+ if (item) {
1759
+ item.classList.add("selected");
1760
+ dropdown.dispatchEvent(
1761
+ new CustomEvent("dropdown:changed", {
1762
+ detail: { value: itemText }
1763
+ })
1764
+ );
1765
+ }
1766
+ toggleMenu(false);
1767
+ };
1768
+ const setHighlight = (index) => {
1769
+ removeHighlight();
1770
+ const visibleItems = menu.querySelectorAll(
1771
+ "li[role='option']:not(.hidden)"
1772
+ );
1773
+ if (visibleItems.length === 0) return;
1774
+ if (index < 0) index = 0;
1775
+ else if (index >= visibleItems.length) index = visibleItems.length - 1;
1776
+ const itemToHighlight = visibleItems[index];
1777
+ if (itemToHighlight) {
1778
+ itemToHighlight.classList.add("highlighted");
1779
+ input.setAttribute("aria-activedescendant", itemToHighlight.id);
1780
+ itemToHighlight.scrollIntoView({
1781
+ behavior: "smooth",
1782
+ block: "nearest"
1783
+ });
1784
+ activeIndex = index;
1785
+ }
1786
+ };
1787
+ const removeHighlight = () => {
1788
+ menuItems.forEach((item) => item.classList.remove("highlighted"));
1789
+ };
1790
+ trigger.addEventListener("click", () => {
1791
+ toggleMenu();
1792
+ });
1793
+ input.addEventListener("input", filterItems);
1794
+ menu.addEventListener("click", (e) => {
1795
+ const option = e.target.closest("li[role='option']");
1796
+ if (option) {
1797
+ e.preventDefault();
1798
+ selectItem(option);
1799
+ }
1800
+ });
1801
+ document.addEventListener("click", (e) => {
1802
+ if (!dropdown.contains(e.target)) {
1803
+ toggleMenu(false);
1804
+ }
1805
+ });
1806
+ input.addEventListener("keydown", (e) => {
1807
+ const { key } = e;
1808
+ const isMenuOpen = dropdown.classList.contains("show");
1809
+ switch (key) {
1810
+ case "ArrowDown":
1811
+ e.preventDefault();
1812
+ if (!isMenuOpen) {
1813
+ toggleMenu(true);
1814
+ }
1815
+ setHighlight(activeIndex + 1);
1816
+ break;
1817
+ case "ArrowUp":
1818
+ e.preventDefault();
1819
+ if (isMenuOpen) {
1820
+ setHighlight(activeIndex - 1);
1821
+ }
1822
+ break;
1823
+ case "Enter":
1824
+ e.preventDefault();
1825
+ const firstVisible = menu.querySelector(
1826
+ "li[role='option']:not(.hidden)"
1827
+ );
1828
+ const activeItem = menu.querySelector(".highlighted");
1829
+ if (isMenuOpen && activeItem) {
1830
+ selectItem(activeItem);
1831
+ } else if (isMenuOpen && firstVisible) {
1832
+ toggleMenu(false);
1833
+ }
1834
+ break;
1835
+ case "Escape":
1836
+ e.preventDefault();
1837
+ toggleMenu(false);
1838
+ break;
1839
+ case "Tab":
1840
+ toggleMenu(false);
1841
+ break;
1842
+ }
1843
+ });
1844
+ });
1845
+ }
1846
+
1502
1847
  // src/js/components/stateful/range-datepicker.js
1503
1848
  function initRangeDatepicker() {
1504
1849
  document.querySelectorAll(".ina-ss-range-datepicker").forEach((rangeDatepicker) => {
@@ -2124,6 +2469,114 @@ if (typeof window !== void 0) {
2124
2469
  });
2125
2470
  }
2126
2471
 
2472
+ // src/js/components/stateful/chip.js
2473
+ function initChip(rootSelector = `.${PREFIX}-chip`) {
2474
+ const chips = document.querySelectorAll(rootSelector);
2475
+ chips.forEach((container) => {
2476
+ if (container.__inaChipInitialized) return;
2477
+ const showCustomization = container.getAttribute("data-show-customization") === "true";
2478
+ const customizationLabel = container.getAttribute("data-customization-label") || "Kustomisasi";
2479
+ let selectedValue = container.getAttribute("data-selected") || "";
2480
+ const list = container.querySelector(`.${PREFIX}-chip__list`);
2481
+ const items = list ? list.querySelectorAll(`.${PREFIX}-chip__item`) : [];
2482
+ let customFieldContainer = container.querySelector(
2483
+ `.${PREFIX}-chip__custom-field`
2484
+ );
2485
+ const updateUI = () => {
2486
+ items.forEach((item) => {
2487
+ const itemValue = item.getAttribute("data-value");
2488
+ const isSelected = itemValue === selectedValue;
2489
+ if (isSelected) {
2490
+ item.classList.add(`${PREFIX}-chip__item--selected`);
2491
+ } else {
2492
+ item.classList.remove(`${PREFIX}-chip__item--selected`);
2493
+ }
2494
+ });
2495
+ if (showCustomization) {
2496
+ const isCustomToggleSelected = selectedValue === customizationLabel;
2497
+ let isStandard = false;
2498
+ items.forEach((item) => {
2499
+ if (item.getAttribute("data-value") === selectedValue && item.textContent.trim() !== customizationLabel) {
2500
+ isStandard = true;
2501
+ }
2502
+ });
2503
+ const toggleBtn = Array.from(items).find(
2504
+ (i) => i.textContent.trim() === customizationLabel
2505
+ );
2506
+ const showInput = toggleBtn && selectedValue === toggleBtn.getAttribute("data-value") || !isStandard && selectedValue !== "";
2507
+ if (showInput) {
2508
+ if (!customFieldContainer) {
2509
+ customFieldContainer = document.createElement("div");
2510
+ customFieldContainer.className = `${PREFIX}-chip__custom-field`;
2511
+ container.appendChild(customFieldContainer);
2512
+ }
2513
+ let input = customFieldContainer.querySelector(
2514
+ `.${PREFIX}-chip__input`
2515
+ );
2516
+ if (!input) {
2517
+ customFieldContainer.innerHTML = `
2518
+ <div class="${PREFIX}-text-field ${PREFIX}-text-field--size-medium ${PREFIX}-text-field--variant-outline ${PREFIX}-chip__input">
2519
+ <div class="${PREFIX}-text-field__wrapper">
2520
+ <input type="text" class="${PREFIX}-text-field__input" placeholder="Masukkan data yang Anda inginkan" value="${!isStandard ? selectedValue : ""}" />
2521
+ </div>
2522
+ </div>
2523
+ `;
2524
+ input = customFieldContainer.querySelector("input");
2525
+ input.addEventListener("blur", (e) => {
2526
+ const val = e.target.value;
2527
+ if (val.trim()) {
2528
+ handleSelect(val);
2529
+ } else {
2530
+ handleSelect("");
2531
+ }
2532
+ });
2533
+ input.addEventListener("keydown", (e) => {
2534
+ if (e.key === "Enter") {
2535
+ handleSelect(e.target.value);
2536
+ e.target.blur();
2537
+ }
2538
+ });
2539
+ } else {
2540
+ const inputEl = customFieldContainer.querySelector("input");
2541
+ if (inputEl && document.activeElement !== inputEl) {
2542
+ inputEl.value = !isStandard ? selectedValue : "";
2543
+ }
2544
+ }
2545
+ customFieldContainer.style.display = "block";
2546
+ } else {
2547
+ if (customFieldContainer) {
2548
+ customFieldContainer.style.display = "none";
2549
+ }
2550
+ }
2551
+ }
2552
+ };
2553
+ const handleSelect = (val) => {
2554
+ selectedValue = val;
2555
+ container.setAttribute("data-selected", val);
2556
+ updateUI();
2557
+ container.dispatchEvent(
2558
+ new CustomEvent("chip:select", {
2559
+ detail: { value: val },
2560
+ bubbles: true
2561
+ })
2562
+ );
2563
+ };
2564
+ items.forEach((item) => {
2565
+ item.addEventListener("click", (e) => {
2566
+ const val = item.getAttribute("data-value");
2567
+ const label = item.textContent.trim();
2568
+ if (showCustomization && label === customizationLabel) {
2569
+ handleSelect(val);
2570
+ } else {
2571
+ handleSelect(val);
2572
+ }
2573
+ });
2574
+ });
2575
+ updateUI();
2576
+ container.__inaChipInitialized = true;
2577
+ });
2578
+ }
2579
+
2127
2580
  // src/js/index.js
2128
2581
  var PREFIX = "ina";
2129
2582
  function initAll() {
@@ -2132,7 +2585,10 @@ function initAll() {
2132
2585
  initButtonGroup();
2133
2586
  initCheckbox();
2134
2587
  initDatepicker();
2135
- initDropdown();
2588
+ initDrawer();
2589
+ initBasicDropdown();
2590
+ initActionDropdown();
2591
+ initSelectDropdown();
2136
2592
  initFileUpload();
2137
2593
  initSingleFileUpload();
2138
2594
  initFileUploadBase();
@@ -2143,6 +2599,7 @@ function initAll() {
2143
2599
  initTab();
2144
2600
  initToggle();
2145
2601
  initTimepicker();
2602
+ initChip();
2146
2603
  }
2147
2604
  export {
2148
2605
  PREFIX,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idds/js",
3
- "version": "1.0.60",
3
+ "version": "1.0.62",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },