How can I have a popup menu arrow that transitions between pointing left and right on both hover and click?

182 views Asked by At

I have a popup menu that should be hidden by default and appear to the left of the trigger button (the red circle) on both mouse hover and click, like so:

screenshot

Here's the code:

// HTML
<li id="daily-muster-statuses">
    <div id="daily-muster-statuses-menu" class="lpx-context-menu pb-0">
        <div class="lpx-user-ctx-body">
            <ul id="muster-status-list" class="lpx-nav-menu ps">
                <li id="muster-status-list-header" class="m-0 mb-2 outer-menu-item p-0">
                    <span id="muster-status-list-header-icon" class="lpx-menu-item-icon">
                        <i class="lpx-icon bi bi-card-checklist"></i>
                    </span>
                    <span class="lpx-menu-item-text">Daily Muster</span>
                </li>
            </ul>
        </div>
    </div>
    <ul id="daily-muster-statuses-rollup" class="lpx-nav-menu">
        <li class="m-0 outer-menu-item">
            <a class="d-block lpx-menu-item-link text-center">
                <i class="dd-icon bi bi-chevron-left" aria-hidden="true"></i>
                <i id="roll-up-status" class="fa fa-circle bg-rollup-waiting"></i>
            </a>
        </li>
    </ul>
</li>

// CSS
#daily-muster-statuses-menu {
    opacity: 0;
    visibility: hidden;
}

#daily-muster-statuses:hover > #daily-muster-statuses-menu {
    opacity: 1;
    visibility: visible;
}

.dd-icon {
    bottom: 2.5px;
    left: 12px;
    opacity: 1;
    transition: transform 0.1s linear;
}

.outer-menu-item:hover .dd-icon {
    transform: rotate(180deg);
}

.show + #daily-muster-statuses-rollup .dd-icon {
    transform: none;
}

// JS
const musterStatusesRollup = $('#daily-muster-statuses-rollup');
const musterStatusesMenu = $('#daily-muster-statuses-menu');
const musterStatusesChevron = musterStatusesRollup.find('.dd-icon');

let menuIsShown = false;

const hideDailyMusterStatusesMenu = () => {
    musterStatusesChevron.removeClass('bi-chevron-right').
        addClass('bi-chevron-left');
    musterStatusesMenu.removeClass('show');
    return (menuIsShown = false);
};

const initialiseDailyMusterStatusesMenu = () => {
    // Open the daily muster statuses context menu upon clicking its rollup icon in the
    // right sidebar, then collapse it when clicking it again or clicking anywhere else
    musterStatusesRollup.on('click', e => {
        if (menuIsShown) {
            return hideDailyMusterStatusesMenu();
        }

        e.stopPropagation();

        musterStatusesChevron.removeClass('bi-chevron-left').
            addClass('bi-chevron-right');
        musterStatusesMenu.addClass('show');
        menuIsShown = true;

        $(document).one('click', hideDailyMusterStatusesMenu);
    });
};

It almost works, but when you click the trigger li, the chevron moves around while the associated JS is run. I want it so that on mouse down, the browser starts to behave as if the CSS transition rule never existed but keeps the right-pointing chevron until after mouse up and another full click, with any amount of mouse movement in between. Then, after the second click, the chevron should transition back to the left.

I've seen this kind of behaviour on so many dropdown and popup menus across the web that it seems like I'm over-complicating the code, so any help with this would be very much appreciated.

EDIT: I've made a short video that demonstrates the problem

1

There are 1 answers

7
Exempt On

to change it to hidden you need to use display: none; to do the onclick to show it you need to use function demo { document.getElementById("").style.display = "block"; } but to keep it there try

function toggleVisibility() {
  var div = document.getElementById("myDIV");
  if (div.style.visibility === "hidden") {
    div.style.visibility = "visible";
  } else {
    div.style.visibility = "hidden";
  }
}
#myDIV {
  width: 200px;
  height: 100px;
  background-color: lightblue;
  border: 1px solid black;
}
<button onclick="toggleVisibility()">Toggle Visibility</button>
<div id="myDIV" style="visibility: hidden;">This is my DIV element.</div>