@liedekef/ftable 1.1.50 → 1.1.52

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 (38) hide show
  1. package/ftable.esm.js +132 -12
  2. package/ftable.js +132 -12
  3. package/ftable.min.js +2 -2
  4. package/ftable.umd.js +132 -12
  5. package/package.json +1 -1
  6. package/themes/basic/ftable_basic.css +5 -2
  7. package/themes/basic/ftable_basic.min.css +1 -1
  8. package/themes/ftable_theme_base.less +6 -2
  9. package/themes/lightcolor/blue/ftable.css +5 -2
  10. package/themes/lightcolor/blue/ftable.min.css +1 -1
  11. package/themes/lightcolor/gray/ftable.css +5 -2
  12. package/themes/lightcolor/gray/ftable.min.css +1 -1
  13. package/themes/lightcolor/green/ftable.css +5 -2
  14. package/themes/lightcolor/green/ftable.min.css +1 -1
  15. package/themes/lightcolor/orange/ftable.css +5 -2
  16. package/themes/lightcolor/orange/ftable.min.css +1 -1
  17. package/themes/lightcolor/red/ftable.css +5 -2
  18. package/themes/lightcolor/red/ftable.min.css +1 -1
  19. package/themes/metro/blue/ftable.css +5 -2
  20. package/themes/metro/blue/ftable.min.css +1 -1
  21. package/themes/metro/brown/ftable.css +5 -2
  22. package/themes/metro/brown/ftable.min.css +1 -1
  23. package/themes/metro/crimson/ftable.css +5 -2
  24. package/themes/metro/crimson/ftable.min.css +1 -1
  25. package/themes/metro/darkgray/ftable.css +5 -2
  26. package/themes/metro/darkgray/ftable.min.css +1 -1
  27. package/themes/metro/darkorange/ftable.css +5 -2
  28. package/themes/metro/darkorange/ftable.min.css +1 -1
  29. package/themes/metro/green/ftable.css +5 -2
  30. package/themes/metro/green/ftable.min.css +1 -1
  31. package/themes/metro/lightgray/ftable.css +5 -2
  32. package/themes/metro/lightgray/ftable.min.css +1 -1
  33. package/themes/metro/pink/ftable.css +5 -2
  34. package/themes/metro/pink/ftable.min.css +1 -1
  35. package/themes/metro/purple/ftable.css +5 -2
  36. package/themes/metro/purple/ftable.min.css +1 -1
  37. package/themes/metro/red/ftable.css +5 -2
  38. package/themes/metro/red/ftable.min.css +1 -1
package/ftable.esm.js CHANGED
@@ -1429,7 +1429,10 @@ class FTableFormBuilder {
1429
1429
  // Create display area
1430
1430
  const display = FTableDOMHelper.create('div', {
1431
1431
  className: 'ftable-multiselect-display',
1432
- parent: container
1432
+ parent: container,
1433
+ attributes: {
1434
+ tabindex: '0' // Makes it focusable and in tab order
1435
+ }
1433
1436
  });
1434
1437
 
1435
1438
  const selectedDisplay = FTableDOMHelper.create('div', {
@@ -1449,7 +1452,10 @@ class FTableFormBuilder {
1449
1452
  type: 'button',
1450
1453
  className: 'ftable-multiselect-toggle',
1451
1454
  innerHTML: '▼',
1452
- parent: display
1455
+ parent: display,
1456
+ attributes: {
1457
+ tabindex: '-1' // this skips regular focus when tabbing
1458
+ }
1453
1459
  });
1454
1460
 
1455
1461
  // Dropdown and overlay will be created on demand and appended to body
@@ -1524,6 +1530,7 @@ class FTableFormBuilder {
1524
1530
 
1525
1531
  // Function to close dropdown
1526
1532
  const closeDropdown = () => {
1533
+ display.focus(); // Return focus to the trigger
1527
1534
  if (dropdown) {
1528
1535
  dropdown.remove();
1529
1536
  dropdown = null;
@@ -1558,7 +1565,7 @@ class FTableFormBuilder {
1558
1565
  dropdown.style.zIndex = '10000';
1559
1566
 
1560
1567
  // Adjust horizontal position if needed
1561
- const dropdownRect = dropdown.getBoundingClientRect();
1568
+ const dropdownRect = dropdown.getBoundingClientRect();
1562
1569
  const viewportWidth = window.innerWidth;
1563
1570
  if (dropdownRect.right > viewportWidth) {
1564
1571
  left = Math.max(10, viewportWidth - dropdownRect.width - 10);
@@ -1643,7 +1650,12 @@ class FTableFormBuilder {
1643
1650
  // Create dropdown
1644
1651
  dropdown = FTableDOMHelper.create('div', {
1645
1652
  className: 'ftable-multiselect-dropdown',
1646
- parent: document.body
1653
+ parent: document.body,
1654
+ attributes: {
1655
+ tabindex: '-1',
1656
+ role: 'listbox',
1657
+ 'aria-multiselectable': 'true'
1658
+ }
1647
1659
  });
1648
1660
 
1649
1661
  // Populate options
@@ -1652,6 +1664,37 @@ class FTableFormBuilder {
1652
1664
  // Position dropdown
1653
1665
  positionDropdown();
1654
1666
 
1667
+ // dropdown focus
1668
+ dropdown.focus();
1669
+
1670
+ // Add keyboard navigation
1671
+ dropdown.addEventListener('keydown', (e) => {
1672
+ if (e.key === 'Escape') {
1673
+ closeDropdown();
1674
+ } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
1675
+ e.preventDefault();
1676
+ // Navigate between options
1677
+ const checkboxes = Array.from(dropdown.querySelectorAll('.ftable-multiselect-checkbox'));
1678
+ const current = document.activeElement;
1679
+ const currentIndex = checkboxes.indexOf(current);
1680
+
1681
+ let nextIndex;
1682
+ if (e.key === 'ArrowDown') {
1683
+ nextIndex = currentIndex < checkboxes.length - 1 ? currentIndex + 1 : 0;
1684
+ } else {
1685
+ nextIndex = currentIndex > 0 ? currentIndex - 1 : checkboxes.length - 1;
1686
+ }
1687
+
1688
+ checkboxes[nextIndex].focus();
1689
+ } else if (e.key === ' ' || e.key === 'Enter') {
1690
+ e.preventDefault();
1691
+ // Toggle the focused checkbox
1692
+ if (document.activeElement.classList.contains('ftable-multiselect-checkbox')) {
1693
+ document.activeElement.click();
1694
+ }
1695
+ }
1696
+ });
1697
+
1655
1698
  // Handle clicks outside
1656
1699
  dropdownOverlay.addEventListener('click', (event) => {
1657
1700
  if (event.target === dropdownOverlay) {
@@ -1661,19 +1704,36 @@ class FTableFormBuilder {
1661
1704
 
1662
1705
  // Reposition on scroll/resize
1663
1706
  const repositionHandler = () => positionDropdown();
1664
- window.addEventListener('scroll', repositionHandler, true);
1707
+ const scrollHandler = (e) => {
1708
+ if (dropdown && dropdown.contains(e.target)) {
1709
+ return; // Allow scrolling inside dropdown
1710
+ }
1711
+ positionDropdown();
1712
+ };
1713
+ const selectedResizeObserver = new ResizeObserver(() => {
1714
+ positionDropdown();
1715
+ });
1716
+ window.addEventListener('scroll', scrollHandler, true);
1665
1717
  window.addEventListener('resize', repositionHandler);
1718
+ selectedResizeObserver.observe(selectedDisplay);
1666
1719
 
1667
1720
  // Store cleanup function
1668
1721
  container._cleanupHandlers = () => {
1669
- window.removeEventListener('scroll', repositionHandler, true);
1722
+ window.removeEventListener('scroll', scrollHandler, true);
1670
1723
  window.removeEventListener('resize', repositionHandler);
1724
+ selectedResizeObserver.disconnect();
1671
1725
  };
1672
1726
  }
1673
1727
  };
1674
1728
 
1675
1729
  display.addEventListener('click', toggleDropdown);
1676
1730
  toggleBtn.addEventListener('click', toggleDropdown);
1731
+ display.addEventListener('keydown', (e) => {
1732
+ if (e.key === 'ArrowDown' || e.key === 'Enter') {
1733
+ e.preventDefault();
1734
+ toggleDropdown();
1735
+ }
1736
+ });
1677
1737
 
1678
1738
  // Clean up when container is removed from DOM
1679
1739
  const observer = new MutationObserver((mutations) => {
@@ -2732,7 +2792,10 @@ class FTable extends FTableEventEmitter {
2732
2792
  // Create display area
2733
2793
  const display = FTableDOMHelper.create('div', {
2734
2794
  className: 'ftable-multiselect-display',
2735
- parent: container
2795
+ parent: container,
2796
+ attributes: {
2797
+ tabindex: '0' // Makes it focusable and in tab order
2798
+ }
2736
2799
  });
2737
2800
 
2738
2801
  const selectedDisplay = FTableDOMHelper.create('div', {
@@ -2752,7 +2815,10 @@ class FTable extends FTableEventEmitter {
2752
2815
  type: 'button',
2753
2816
  className: 'ftable-multiselect-toggle',
2754
2817
  innerHTML: '▼',
2755
- parent: display
2818
+ parent: display,
2819
+ attributes: {
2820
+ tabindex: '-1' // this skips regular focus when tabbing
2821
+ }
2756
2822
  });
2757
2823
 
2758
2824
  // Dropdown and overlay will be created on demand and appended to body
@@ -2826,6 +2892,7 @@ class FTable extends FTableEventEmitter {
2826
2892
 
2827
2893
  // Function to close dropdown
2828
2894
  const closeDropdown = () => {
2895
+ display.focus(); // Return focus to the trigger
2829
2896
  if (dropdown) {
2830
2897
  dropdown.remove();
2831
2898
  dropdown = null;
@@ -2860,7 +2927,7 @@ class FTable extends FTableEventEmitter {
2860
2927
  dropdown.style.zIndex = '10000';
2861
2928
 
2862
2929
  // Adjust horizontal position if needed
2863
- const dropdownRect = dropdown.getBoundingClientRect();
2930
+ const dropdownRect = dropdown.getBoundingClientRect();
2864
2931
  const viewportWidth = window.innerWidth;
2865
2932
  if (dropdownRect.right > viewportWidth) {
2866
2933
  left = Math.max(10, viewportWidth - dropdownRect.width - 10);
@@ -2957,7 +3024,12 @@ class FTable extends FTableEventEmitter {
2957
3024
  // Create dropdown
2958
3025
  dropdown = FTableDOMHelper.create('div', {
2959
3026
  className: 'ftable-multiselect-dropdown',
2960
- parent: document.body
3027
+ parent: document.body,
3028
+ attributes: {
3029
+ tabindex: '-1',
3030
+ role: 'listbox',
3031
+ 'aria-multiselectable': 'true'
3032
+ }
2961
3033
  });
2962
3034
 
2963
3035
  // Populate options
@@ -2966,6 +3038,37 @@ class FTable extends FTableEventEmitter {
2966
3038
  // Position dropdown
2967
3039
  positionDropdown();
2968
3040
 
3041
+ // dropdown focus
3042
+ dropdown.focus();
3043
+
3044
+ // Add keyboard navigation
3045
+ dropdown.addEventListener('keydown', (e) => {
3046
+ if (e.key === 'Escape') {
3047
+ closeDropdown();
3048
+ } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
3049
+ e.preventDefault();
3050
+ // Navigate between options
3051
+ const checkboxes = Array.from(dropdown.querySelectorAll('.ftable-multiselect-checkbox'));
3052
+ const current = document.activeElement;
3053
+ const currentIndex = checkboxes.indexOf(current);
3054
+
3055
+ let nextIndex;
3056
+ if (e.key === 'ArrowDown') {
3057
+ nextIndex = currentIndex < checkboxes.length - 1 ? currentIndex + 1 : 0;
3058
+ } else {
3059
+ nextIndex = currentIndex > 0 ? currentIndex - 1 : checkboxes.length - 1;
3060
+ }
3061
+
3062
+ checkboxes[nextIndex].focus();
3063
+ } else if (e.key === ' ' || e.key === 'Enter') {
3064
+ e.preventDefault();
3065
+ // Toggle the focused checkbox
3066
+ if (document.activeElement.classList.contains('ftable-multiselect-checkbox')) {
3067
+ document.activeElement.click();
3068
+ }
3069
+ }
3070
+ });
3071
+
2969
3072
  // Handle clicks outside
2970
3073
  dropdownOverlay.addEventListener('click', (event) => {
2971
3074
  if (event.target === dropdownOverlay) {
@@ -2975,19 +3078,36 @@ class FTable extends FTableEventEmitter {
2975
3078
 
2976
3079
  // Reposition on scroll/resize
2977
3080
  const repositionHandler = () => positionDropdown();
2978
- window.addEventListener('scroll', repositionHandler, true);
3081
+ const scrollHandler = (e) => {
3082
+ if (dropdown && dropdown.contains(e.target)) {
3083
+ return; // Allow scrolling inside dropdown
3084
+ }
3085
+ positionDropdown();
3086
+ };
3087
+ const selectedResizeObserver = new ResizeObserver(() => {
3088
+ positionDropdown();
3089
+ });
3090
+ window.addEventListener('scroll', scrollHandler, true);
2979
3091
  window.addEventListener('resize', repositionHandler);
3092
+ selectedResizeObserver.observe(selectedDisplay);
2980
3093
 
2981
3094
  // Store cleanup function
2982
3095
  container._cleanupHandlers = () => {
2983
- window.removeEventListener('scroll', repositionHandler, true);
3096
+ window.removeEventListener('scroll', scrollHandler, true);
2984
3097
  window.removeEventListener('resize', repositionHandler);
3098
+ selectedResizeObserver.disconnect();
2985
3099
  };
2986
3100
  }
2987
3101
  };
2988
3102
 
2989
3103
  display.addEventListener('click', toggleDropdown);
2990
3104
  toggleBtn.addEventListener('click', toggleDropdown);
3105
+ display.addEventListener('keydown', (e) => {
3106
+ if (e.key === 'ArrowDown' || e.key === 'Enter') {
3107
+ e.preventDefault();
3108
+ toggleDropdown();
3109
+ }
3110
+ });
2991
3111
 
2992
3112
  // Add reset method to container
2993
3113
  container.resetMultiSelect = () => {
package/ftable.js CHANGED
@@ -1430,7 +1430,10 @@ class FTableFormBuilder {
1430
1430
  // Create display area
1431
1431
  const display = FTableDOMHelper.create('div', {
1432
1432
  className: 'ftable-multiselect-display',
1433
- parent: container
1433
+ parent: container,
1434
+ attributes: {
1435
+ tabindex: '0' // Makes it focusable and in tab order
1436
+ }
1434
1437
  });
1435
1438
 
1436
1439
  const selectedDisplay = FTableDOMHelper.create('div', {
@@ -1450,7 +1453,10 @@ class FTableFormBuilder {
1450
1453
  type: 'button',
1451
1454
  className: 'ftable-multiselect-toggle',
1452
1455
  innerHTML: '▼',
1453
- parent: display
1456
+ parent: display,
1457
+ attributes: {
1458
+ tabindex: '-1' // this skips regular focus when tabbing
1459
+ }
1454
1460
  });
1455
1461
 
1456
1462
  // Dropdown and overlay will be created on demand and appended to body
@@ -1525,6 +1531,7 @@ class FTableFormBuilder {
1525
1531
 
1526
1532
  // Function to close dropdown
1527
1533
  const closeDropdown = () => {
1534
+ display.focus(); // Return focus to the trigger
1528
1535
  if (dropdown) {
1529
1536
  dropdown.remove();
1530
1537
  dropdown = null;
@@ -1559,7 +1566,7 @@ class FTableFormBuilder {
1559
1566
  dropdown.style.zIndex = '10000';
1560
1567
 
1561
1568
  // Adjust horizontal position if needed
1562
- const dropdownRect = dropdown.getBoundingClientRect();
1569
+ const dropdownRect = dropdown.getBoundingClientRect();
1563
1570
  const viewportWidth = window.innerWidth;
1564
1571
  if (dropdownRect.right > viewportWidth) {
1565
1572
  left = Math.max(10, viewportWidth - dropdownRect.width - 10);
@@ -1644,7 +1651,12 @@ class FTableFormBuilder {
1644
1651
  // Create dropdown
1645
1652
  dropdown = FTableDOMHelper.create('div', {
1646
1653
  className: 'ftable-multiselect-dropdown',
1647
- parent: document.body
1654
+ parent: document.body,
1655
+ attributes: {
1656
+ tabindex: '-1',
1657
+ role: 'listbox',
1658
+ 'aria-multiselectable': 'true'
1659
+ }
1648
1660
  });
1649
1661
 
1650
1662
  // Populate options
@@ -1653,6 +1665,37 @@ class FTableFormBuilder {
1653
1665
  // Position dropdown
1654
1666
  positionDropdown();
1655
1667
 
1668
+ // dropdown focus
1669
+ dropdown.focus();
1670
+
1671
+ // Add keyboard navigation
1672
+ dropdown.addEventListener('keydown', (e) => {
1673
+ if (e.key === 'Escape') {
1674
+ closeDropdown();
1675
+ } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
1676
+ e.preventDefault();
1677
+ // Navigate between options
1678
+ const checkboxes = Array.from(dropdown.querySelectorAll('.ftable-multiselect-checkbox'));
1679
+ const current = document.activeElement;
1680
+ const currentIndex = checkboxes.indexOf(current);
1681
+
1682
+ let nextIndex;
1683
+ if (e.key === 'ArrowDown') {
1684
+ nextIndex = currentIndex < checkboxes.length - 1 ? currentIndex + 1 : 0;
1685
+ } else {
1686
+ nextIndex = currentIndex > 0 ? currentIndex - 1 : checkboxes.length - 1;
1687
+ }
1688
+
1689
+ checkboxes[nextIndex].focus();
1690
+ } else if (e.key === ' ' || e.key === 'Enter') {
1691
+ e.preventDefault();
1692
+ // Toggle the focused checkbox
1693
+ if (document.activeElement.classList.contains('ftable-multiselect-checkbox')) {
1694
+ document.activeElement.click();
1695
+ }
1696
+ }
1697
+ });
1698
+
1656
1699
  // Handle clicks outside
1657
1700
  dropdownOverlay.addEventListener('click', (event) => {
1658
1701
  if (event.target === dropdownOverlay) {
@@ -1662,19 +1705,36 @@ class FTableFormBuilder {
1662
1705
 
1663
1706
  // Reposition on scroll/resize
1664
1707
  const repositionHandler = () => positionDropdown();
1665
- window.addEventListener('scroll', repositionHandler, true);
1708
+ const scrollHandler = (e) => {
1709
+ if (dropdown && dropdown.contains(e.target)) {
1710
+ return; // Allow scrolling inside dropdown
1711
+ }
1712
+ positionDropdown();
1713
+ };
1714
+ const selectedResizeObserver = new ResizeObserver(() => {
1715
+ positionDropdown();
1716
+ });
1717
+ window.addEventListener('scroll', scrollHandler, true);
1666
1718
  window.addEventListener('resize', repositionHandler);
1719
+ selectedResizeObserver.observe(selectedDisplay);
1667
1720
 
1668
1721
  // Store cleanup function
1669
1722
  container._cleanupHandlers = () => {
1670
- window.removeEventListener('scroll', repositionHandler, true);
1723
+ window.removeEventListener('scroll', scrollHandler, true);
1671
1724
  window.removeEventListener('resize', repositionHandler);
1725
+ selectedResizeObserver.disconnect();
1672
1726
  };
1673
1727
  }
1674
1728
  };
1675
1729
 
1676
1730
  display.addEventListener('click', toggleDropdown);
1677
1731
  toggleBtn.addEventListener('click', toggleDropdown);
1732
+ display.addEventListener('keydown', (e) => {
1733
+ if (e.key === 'ArrowDown' || e.key === 'Enter') {
1734
+ e.preventDefault();
1735
+ toggleDropdown();
1736
+ }
1737
+ });
1678
1738
 
1679
1739
  // Clean up when container is removed from DOM
1680
1740
  const observer = new MutationObserver((mutations) => {
@@ -2733,7 +2793,10 @@ class FTable extends FTableEventEmitter {
2733
2793
  // Create display area
2734
2794
  const display = FTableDOMHelper.create('div', {
2735
2795
  className: 'ftable-multiselect-display',
2736
- parent: container
2796
+ parent: container,
2797
+ attributes: {
2798
+ tabindex: '0' // Makes it focusable and in tab order
2799
+ }
2737
2800
  });
2738
2801
 
2739
2802
  const selectedDisplay = FTableDOMHelper.create('div', {
@@ -2753,7 +2816,10 @@ class FTable extends FTableEventEmitter {
2753
2816
  type: 'button',
2754
2817
  className: 'ftable-multiselect-toggle',
2755
2818
  innerHTML: '▼',
2756
- parent: display
2819
+ parent: display,
2820
+ attributes: {
2821
+ tabindex: '-1' // this skips regular focus when tabbing
2822
+ }
2757
2823
  });
2758
2824
 
2759
2825
  // Dropdown and overlay will be created on demand and appended to body
@@ -2827,6 +2893,7 @@ class FTable extends FTableEventEmitter {
2827
2893
 
2828
2894
  // Function to close dropdown
2829
2895
  const closeDropdown = () => {
2896
+ display.focus(); // Return focus to the trigger
2830
2897
  if (dropdown) {
2831
2898
  dropdown.remove();
2832
2899
  dropdown = null;
@@ -2861,7 +2928,7 @@ class FTable extends FTableEventEmitter {
2861
2928
  dropdown.style.zIndex = '10000';
2862
2929
 
2863
2930
  // Adjust horizontal position if needed
2864
- const dropdownRect = dropdown.getBoundingClientRect();
2931
+ const dropdownRect = dropdown.getBoundingClientRect();
2865
2932
  const viewportWidth = window.innerWidth;
2866
2933
  if (dropdownRect.right > viewportWidth) {
2867
2934
  left = Math.max(10, viewportWidth - dropdownRect.width - 10);
@@ -2958,7 +3025,12 @@ class FTable extends FTableEventEmitter {
2958
3025
  // Create dropdown
2959
3026
  dropdown = FTableDOMHelper.create('div', {
2960
3027
  className: 'ftable-multiselect-dropdown',
2961
- parent: document.body
3028
+ parent: document.body,
3029
+ attributes: {
3030
+ tabindex: '-1',
3031
+ role: 'listbox',
3032
+ 'aria-multiselectable': 'true'
3033
+ }
2962
3034
  });
2963
3035
 
2964
3036
  // Populate options
@@ -2967,6 +3039,37 @@ class FTable extends FTableEventEmitter {
2967
3039
  // Position dropdown
2968
3040
  positionDropdown();
2969
3041
 
3042
+ // dropdown focus
3043
+ dropdown.focus();
3044
+
3045
+ // Add keyboard navigation
3046
+ dropdown.addEventListener('keydown', (e) => {
3047
+ if (e.key === 'Escape') {
3048
+ closeDropdown();
3049
+ } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
3050
+ e.preventDefault();
3051
+ // Navigate between options
3052
+ const checkboxes = Array.from(dropdown.querySelectorAll('.ftable-multiselect-checkbox'));
3053
+ const current = document.activeElement;
3054
+ const currentIndex = checkboxes.indexOf(current);
3055
+
3056
+ let nextIndex;
3057
+ if (e.key === 'ArrowDown') {
3058
+ nextIndex = currentIndex < checkboxes.length - 1 ? currentIndex + 1 : 0;
3059
+ } else {
3060
+ nextIndex = currentIndex > 0 ? currentIndex - 1 : checkboxes.length - 1;
3061
+ }
3062
+
3063
+ checkboxes[nextIndex].focus();
3064
+ } else if (e.key === ' ' || e.key === 'Enter') {
3065
+ e.preventDefault();
3066
+ // Toggle the focused checkbox
3067
+ if (document.activeElement.classList.contains('ftable-multiselect-checkbox')) {
3068
+ document.activeElement.click();
3069
+ }
3070
+ }
3071
+ });
3072
+
2970
3073
  // Handle clicks outside
2971
3074
  dropdownOverlay.addEventListener('click', (event) => {
2972
3075
  if (event.target === dropdownOverlay) {
@@ -2976,19 +3079,36 @@ class FTable extends FTableEventEmitter {
2976
3079
 
2977
3080
  // Reposition on scroll/resize
2978
3081
  const repositionHandler = () => positionDropdown();
2979
- window.addEventListener('scroll', repositionHandler, true);
3082
+ const scrollHandler = (e) => {
3083
+ if (dropdown && dropdown.contains(e.target)) {
3084
+ return; // Allow scrolling inside dropdown
3085
+ }
3086
+ positionDropdown();
3087
+ };
3088
+ const selectedResizeObserver = new ResizeObserver(() => {
3089
+ positionDropdown();
3090
+ });
3091
+ window.addEventListener('scroll', scrollHandler, true);
2980
3092
  window.addEventListener('resize', repositionHandler);
3093
+ selectedResizeObserver.observe(selectedDisplay);
2981
3094
 
2982
3095
  // Store cleanup function
2983
3096
  container._cleanupHandlers = () => {
2984
- window.removeEventListener('scroll', repositionHandler, true);
3097
+ window.removeEventListener('scroll', scrollHandler, true);
2985
3098
  window.removeEventListener('resize', repositionHandler);
3099
+ selectedResizeObserver.disconnect();
2986
3100
  };
2987
3101
  }
2988
3102
  };
2989
3103
 
2990
3104
  display.addEventListener('click', toggleDropdown);
2991
3105
  toggleBtn.addEventListener('click', toggleDropdown);
3106
+ display.addEventListener('keydown', (e) => {
3107
+ if (e.key === 'ArrowDown' || e.key === 'Enter') {
3108
+ e.preventDefault();
3109
+ toggleDropdown();
3110
+ }
3111
+ });
2992
3112
 
2993
3113
  // Add reset method to container
2994
3114
  container.resetMultiSelect = () => {