Skip to content

Commit

Permalink
feat: add support for hover enter/leave delays and transition classes
Browse files Browse the repository at this point in the history
  • Loading branch information
NickDJM authored Jun 21, 2023
1 parent 155217f commit 46a583a
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 89 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
},
"homepage": "https://github.com/NickDJM/accessible-menu-bootstrap-5#readme",
"dependencies": {
"accessible-menu": "^4.0.0-beta.0"
"accessible-menu": "^4.0.0-beta.1"
},
"devDependencies": {
"@babel/core": "^7.12.3",
Expand Down
9 changes: 9 additions & 0 deletions src/bootstrap5DisclosureMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,13 @@ class Bootstrap5DisclosureMenu extends DisclosureMenu {
* @param {(HTMLElement|null)} [options.containerElement = null] - The element containing the menu in the DOM.
* @param {(string|string[]|null)} [options.openClass = show] - The class to apply when a menu is "open".
* @param {(string|string[]|null)} [options.closeClass = collapse] - The class to apply when a menu is "closed".
* @param {?(string|string[])} [options.transitionClass = transitioning] - The class to apply when a menu is transitioning between "open" and "closed" states.
* @param {boolean} [options.isTopLevel = false] - A flag to mark the root menu.
* @param {(Bootstrap5DisclosureMenu|null)} [options.parentMenu = null] - The parent menu to this menu.
* @param {string} [options.hoverType = off] - The type of hoverability a menu has.
* @param {number} [options.hoverDelay = 250] - The delay for closing menus if the menu is hoverable (in miliseconds).
* @param {number} [options.enterDelay = -1] - The delay for opening a menu if the menu is focusable (in miliseconds).
* @param {number} [options.leaveDelay = -1] - The delay for closing a menu if the menu is focusable (in miliseconds).
* @param {boolean} [options.optionalKeySupport = false] - A flag to add optional keyboard support (Arrow keys, Home, and End) to the menu.
* @param {boolean} [options.initialize = true] - A flag to initialize the menu immediately upon creation.
*/
Expand All @@ -69,10 +72,13 @@ class Bootstrap5DisclosureMenu extends DisclosureMenu {
containerElement = null,
openClass = "show",
closeClass = "collapse",
transitionClass = "transitioning",
isTopLevel = true,
parentMenu = null,
hoverType = "off",
hoverDelay = 250,
enterDelay = -1,
leaveDelay = -1,
optionalKeySupport = false,
initialize = true,
}) {
Expand All @@ -87,10 +93,13 @@ class Bootstrap5DisclosureMenu extends DisclosureMenu {
containerElement,
openClass,
closeClass,
transitionClass,
isTopLevel,
parentMenu,
hoverType,
hoverDelay,
enterDelay,
leaveDelay,
optionalKeySupport,
initialize: false,
});
Expand Down
69 changes: 47 additions & 22 deletions src/bootstrap5DisclosureMenuToggle.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable jsdoc/no-undefined-types */

import DisclosureMenuToggle from "accessible-menu/src/disclosureMenuToggle.js";
import { addClass, removeClass } from "accessible-menu/src/domHelpers.js";

/*
* A link or button that controls the visibility of a Bootstrap5DisclosureMenu.
Expand Down Expand Up @@ -84,17 +85,25 @@ class Bootstrap5DisclosureMenuToggle extends DisclosureMenuToggle {
* @param {boolean} [emit = true] - A toggle to emit the expand event once expanded.
*/
_expand(emit = true) {
const { openClass } = this.elements.controlledMenu;
const { openClass, transitionClass } = this.elements.controlledMenu;

this.dom.toggle.setAttribute("aria-expanded", "true");

// Add the open class
if (openClass !== "") {
if (typeof openClass === "string") {
this.dom.container.classList.add(openClass);
} else {
this.dom.container.classList.add(...openClass);
}
// If we're dealing with transition classes, then we need to utilize
// requestAnimationFrame to add the transition class, add the open class,
// and then remove the transition class.
if (transitionClass !== "") {
addClass(transitionClass, this.dom.container);

requestAnimationFrame(() => {
addClass(openClass, this.dom.container);

requestAnimationFrame(() => {
removeClass(transitionClass, this.dom.container);
});
});
} else if (openClass !== "") {
addClass(openClass, this.dom.container);
}

if (emit) {
Expand All @@ -110,25 +119,41 @@ class Bootstrap5DisclosureMenuToggle extends DisclosureMenuToggle {
* @param {boolean} [emit = true] - A toggle to emit the collapse event once collapsed.
*/
_collapse(emit = true) {
const { closeClass, openClass } = this.elements.controlledMenu;
const { closeClass, openClass, transitionClass } =
this.elements.controlledMenu;

this.dom.toggle.setAttribute("aria-expanded", "false");

// Add the close class
if (closeClass !== "") {
if (typeof closeClass === "string") {
this.dom.container.classList.add(closeClass);
} else {
this.dom.container.classList.add(...closeClass);
// If we're dealing with transition classes, then we need to utilize
// requestAnimationFrame to add the transition class, remove the open class,
// add the close class, and finally remove the transition class.
if (transitionClass !== "") {
addClass(transitionClass, this.dom.container);

requestAnimationFrame(() => {
if (openClass !== "") {
removeClass(openClass, this.dom.container);
}

requestAnimationFrame(() => {
if (closeClass !== "") {
addClass(closeClass, this.dom.container);
}

requestAnimationFrame(() => {
removeClass(transitionClass, this.dom.container);
});
});
});
} else {
// Add the close class
if (closeClass !== "") {
addClass(closeClass, this.dom.container);
}
}

// Remove the open class.
if (openClass !== "") {
if (typeof openClass === "string") {
this.dom.container.classList.remove(openClass);
} else {
this.dom.container.classList.remove(...openClass);
// Remove the open class.
if (openClass !== "") {
removeClass(openClass, this.dom.container);
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/bootstrap5Menubar.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@ class Bootstrap5Menubar extends Menubar {
* @param {(HTMLElement|null)} [options.containerElement = null] - The element containing the menu in the DOM.
* @param {(string|string[]|null)} [options.openClass = show] - The class to apply when a menu is "open".
* @param {(string|string[]|null)} [options.closeClass = collapse] - The class to apply when a menu is "closed".
* @param {?(string|string[])} [options.transitionClass = transitioning] - The class to apply when a menu is transitioning between "open" and "closed" states.
* @param {boolean} [options.isTopLevel = false] - A flag to mark the root menu.
* @param {(Bootstrap5Menubar|null)} [options.parentMenu = null] - The parent menu to this menu.
* @param {string} [options.hoverType = off] - The type of hoverability a menu has.
* @param {number} [options.hoverDelay = 250] - The delay for closing menus if the menu is hoverable (in miliseconds).
* @param {number} [options.enterDelay = -1] - The delay for opening a menu if the menu is focusable (in miliseconds).
* @param {number} [options.leaveDelay = -1] - The delay for closing a menu if the menu is focusable (in miliseconds).
* @param {boolean} [options.initialize = true] - A flag to initialize the menu immediately upon creation.
*/
constructor({
Expand All @@ -66,10 +69,13 @@ class Bootstrap5Menubar extends Menubar {
containerElement = null,
openClass = "show",
closeClass = "collapse",
transitionClass = "transitioning",
isTopLevel = true,
parentMenu = null,
hoverType = "off",
hoverDelay = 250,
enterDelay = -1,
leaveDelay = -1,
initialize = true,
}) {
super({
Expand All @@ -83,10 +89,13 @@ class Bootstrap5Menubar extends Menubar {
containerElement,
openClass,
closeClass,
transitionClass,
isTopLevel,
parentMenu,
hoverType,
hoverDelay,
enterDelay,
leaveDelay,
initialize: false,
});

Expand Down
69 changes: 47 additions & 22 deletions src/bootstrap5MenubarToggle.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable jsdoc/no-undefined-types */

import MenubarToggle from "accessible-menu/src/menubarToggle.js";
import { addClass, removeClass } from "accessible-menu/src/domHelpers.js";

/*
* A link or button that controls the visibility of a Bootstrap5Menubar.
Expand Down Expand Up @@ -84,17 +85,25 @@ class Bootstrap5MenubarToggle extends MenubarToggle {
* @param {boolean} [emit = true] - A toggle to emit the expand event once expanded.
*/
_expand(emit = true) {
const { openClass } = this.elements.controlledMenu;
const { openClass, transitionClass } = this.elements.controlledMenu;

this.dom.toggle.setAttribute("aria-expanded", "true");

// Add the open class
if (openClass !== "") {
if (typeof openClass === "string") {
this.dom.container.classList.add(openClass);
} else {
this.dom.container.classList.add(...openClass);
}
// If we're dealing with transition classes, then we need to utilize
// requestAnimationFrame to add the transition class, add the open class,
// and then remove the transition class.
if (transitionClass !== "") {
addClass(transitionClass, this.dom.container);

requestAnimationFrame(() => {
addClass(openClass, this.dom.container);

requestAnimationFrame(() => {
removeClass(transitionClass, this.dom.container);
});
});
} else if (openClass !== "") {
addClass(openClass, this.dom.container);
}

if (emit) {
Expand All @@ -110,25 +119,41 @@ class Bootstrap5MenubarToggle extends MenubarToggle {
* @param {boolean} [emit = true] - A toggle to emit the collapse event once collapsed.
*/
_collapse(emit = true) {
const { closeClass, openClass } = this.elements.controlledMenu;
const { closeClass, openClass, transitionClass } =
this.elements.controlledMenu;

this.dom.toggle.setAttribute("aria-expanded", "false");

// Add the close class
if (closeClass !== "") {
if (typeof closeClass === "string") {
this.dom.container.classList.add(closeClass);
} else {
this.dom.container.classList.add(...closeClass);
// If we're dealing with transition classes, then we need to utilize
// requestAnimationFrame to add the transition class, remove the open class,
// add the close class, and finally remove the transition class.
if (transitionClass !== "") {
addClass(transitionClass, this.dom.container);

requestAnimationFrame(() => {
if (openClass !== "") {
removeClass(openClass, this.dom.container);
}

requestAnimationFrame(() => {
if (closeClass !== "") {
addClass(closeClass, this.dom.container);
}

requestAnimationFrame(() => {
removeClass(transitionClass, this.dom.container);
});
});
});
} else {
// Add the close class
if (closeClass !== "") {
addClass(closeClass, this.dom.container);
}
}

// Remove the open class.
if (openClass !== "") {
if (typeof openClass === "string") {
this.dom.container.classList.remove(openClass);
} else {
this.dom.container.classList.remove(...openClass);
// Remove the open class.
if (openClass !== "") {
removeClass(openClass, this.dom.container);
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/bootstrap5TopLinkDisclosureMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,13 @@ class Bootstrap5TopLinkDisclosureMenu extends TopLinkDisclosureMenu {
* @param {(HTMLElement|null)} [options.containerElement = null] - The element containing the menu in the DOM.
* @param {(string|string[]|null)} [options.openClass = show] - The class to apply when a menu is "open".
* @param {(string|string[]|null)} [options.closeClass = collapse] - The class to apply when a menu is "closed".
* @param {?(string|string[])} [options.transitionClass = transitioning] - The class to apply when a menu is transitioning between "open" and "closed" states.
* @param {boolean} [options.isTopLevel = false] - A flag to mark the root menu.
* @param {(Bootstrap5TopLinkDisclosureMenu|null)} [options.parentMenu = null] - The parent menu to this menu.
* @param {string} [options.hoverType = off] - The type of hoverability a menu has.
* @param {number} [options.hoverDelay = 250] - The delay for closing menus if the menu is hoverable (in miliseconds).
* @param {number} [options.enterDelay = -1] - The delay for opening a menu if the menu is focusable (in miliseconds).
* @param {number} [options.leaveDelay = -1] - The delay for closing a menu if the menu is focusable (in miliseconds).
* @param {boolean} [options.optionalKeySupport = false] - A flag to add optional keyboard support (Arrow keys, Home, and End) to the menu.
* @param {boolean} [options.initialize = true] - A flag to initialize the menu immediately upon creation.
*/
Expand All @@ -71,10 +74,13 @@ class Bootstrap5TopLinkDisclosureMenu extends TopLinkDisclosureMenu {
containerElement = null,
openClass = "show",
closeClass = "collapse",
transitionClass = "transitioning",
isTopLevel = true,
parentMenu = null,
hoverType = "off",
hoverDelay = 250,
enterDelay = -1,
leaveDelay = -1,
optionalKeySupport = false,
initialize = true,
}) {
Expand All @@ -90,10 +96,13 @@ class Bootstrap5TopLinkDisclosureMenu extends TopLinkDisclosureMenu {
containerElement,
openClass,
closeClass,
transitionClass,
isTopLevel,
parentMenu,
hoverType,
hoverDelay,
enterDelay,
leaveDelay,
optionalKeySupport,
initialize: false,
});
Expand Down
Loading

0 comments on commit 46a583a

Please sign in to comment.