breadcrumbs.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. export default function initCollapsibleBreadcrumbs() {
  2. const breadcrumbsContainer = document.querySelector('[data-breadcrumb-next]');
  3. const breadcrumbsToggle = breadcrumbsContainer.querySelector(
  4. '[data-toggle-breadcrumbs]',
  5. );
  6. const breadcrumbItems = breadcrumbsContainer.querySelectorAll(
  7. '[data-breadcrumb-item]',
  8. );
  9. const cssClass = {
  10. maxWidth: 'w-max-w-4xl', // Setting this allows the breadcrumb to animate to this width
  11. };
  12. // Local state
  13. let open = false;
  14. let mouseExitedToggle = true;
  15. let keepOpen = false;
  16. let hideBreadcrumbsWithDelay;
  17. function hideBreadcrumbs() {
  18. breadcrumbItems.forEach((breadcrumb) => {
  19. breadcrumb.classList.remove(cssClass.maxWidth);
  20. // eslint-disable-next-line no-param-reassign
  21. breadcrumb.hidden = true;
  22. });
  23. breadcrumbsToggle.setAttribute('aria-expanded', 'false');
  24. // Change Icon to dots
  25. breadcrumbsToggle
  26. .querySelector('svg use')
  27. .setAttribute('href', '#icon-dots-horizontal');
  28. open = false;
  29. }
  30. function showBreadcrumbs() {
  31. breadcrumbItems.forEach((breadcrumb, index) => {
  32. setTimeout(() => {
  33. // eslint-disable-next-line no-param-reassign
  34. breadcrumb.hidden = false;
  35. setTimeout(() => {
  36. breadcrumb.classList.add(cssClass.maxWidth);
  37. }, 50);
  38. }, index * 10);
  39. });
  40. breadcrumbsToggle.setAttribute('aria-expanded', 'true');
  41. open = true;
  42. }
  43. // Events
  44. breadcrumbsToggle.addEventListener('click', () => {
  45. if (keepOpen) {
  46. mouseExitedToggle = false;
  47. hideBreadcrumbs();
  48. keepOpen = false;
  49. }
  50. if (open) {
  51. mouseExitedToggle = false;
  52. keepOpen = true;
  53. // Change Icon to cross
  54. breadcrumbsToggle
  55. .querySelector('svg use')
  56. .setAttribute('href', '#icon-cross');
  57. } else if (mouseExitedToggle) {
  58. showBreadcrumbs();
  59. }
  60. });
  61. breadcrumbsToggle.addEventListener('mouseenter', () => {
  62. // If menu is open or the mouse hasn't exited button zone do nothing
  63. if (open || !mouseExitedToggle) {
  64. return;
  65. }
  66. open = true;
  67. // Set mouse exited so mouseover doesn't restart until mouse leaves
  68. mouseExitedToggle = false;
  69. showBreadcrumbs();
  70. });
  71. breadcrumbsContainer.addEventListener('mouseleave', () => {
  72. if (!keepOpen) {
  73. hideBreadcrumbsWithDelay = setTimeout(() => {
  74. hideBreadcrumbs();
  75. // Give a little bit of time before closing in case the user changes their mind
  76. }, 500);
  77. }
  78. });
  79. breadcrumbsContainer.addEventListener('mouseenter', () => {
  80. clearTimeout(hideBreadcrumbsWithDelay);
  81. });
  82. breadcrumbsToggle.addEventListener('mouseleave', () => {
  83. mouseExitedToggle = true;
  84. });
  85. document.addEventListener('keydown', (e) => {
  86. if (e.key === 'Escape') {
  87. hideBreadcrumbs();
  88. }
  89. });
  90. }