diff --git a/CHANGELOG.md b/CHANGELOG.md
index ed384a33..caf26f29 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
# Changelog
+## v5.2.2-holistics.2
+
+### 🩹 Fixes
+
+ - Add `fixDiagonalSubmenuProblem` prop, fix [#916](https://github.com/Akryum/floating-vue/issues/916)
+
+### ❤️ Contributors
+
+- Cuong Vuong ([@cuong-vuong-holistics](https://github.com/cuong-vuong-holistics))
+
## v5.2.2-holistics.1
### 🚀 Performance Improvements
diff --git a/README.md b/README.md
index e087205c..b44f0f39 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
This fork has the `@holistics/floating-vue` package that tries to fix the following issues:
- **[Performance]** Disable toggling CSS class of `
`: this makes the entire page reflow whenever some floating elements are shown/all are hidden ([PR #1019](https://github.com/Akryum/floating-vue/pull/1019)). Can be re-enabled via `toggleBodyClass` prop.
+- **[Fix]** Properly fix diagonal submenu problem ([#916](https://github.com/Akryum/floating-vue/issues/916)) via `fixDiagonalSubmenuProblem` prop
### 📦️ Versioning and syncing
diff --git a/packages/floating-vue/README.md b/packages/floating-vue/README.md
index d582b430..e1181698 100644
--- a/packages/floating-vue/README.md
+++ b/packages/floating-vue/README.md
@@ -5,6 +5,7 @@
This fork has the `@holistics/floating-vue` package that tries to fix the following issues:
- **[Performance]** Disable toggling CSS class of ``: this makes the entire page reflow whenever some floating elements are shown/all are hidden ([PR #1019](https://github.com/Akryum/floating-vue/pull/1019)). Can be re-enabled via `toggleBodyClass` prop.
+- **[Fix]** Properly fix diagonal submenu problem ([#916](https://github.com/Akryum/floating-vue/issues/916)) via `fixDiagonalSubmenuProblem` prop
### 📦️ Versioning and syncing
diff --git a/packages/floating-vue/package.json b/packages/floating-vue/package.json
index b051a733..0a8d00ca 100644
--- a/packages/floating-vue/package.json
+++ b/packages/floating-vue/package.json
@@ -1,6 +1,6 @@
{
"name": "@holistics/floating-vue",
- "version": "5.2.2-holistics.1",
+ "version": "5.2.2-holistics.2",
"description": "Holistics fork of Floating Vue - Easy Vue tooltips, dropdowns, menus & popovers using floating-ui",
"contributors": [
"Guillaume Chau ",
diff --git a/packages/floating-vue/src/components/Popper.ts b/packages/floating-vue/src/components/Popper.ts
index b0655a72..ef2fa31f 100644
--- a/packages/floating-vue/src/components/Popper.ts
+++ b/packages/floating-vue/src/components/Popper.ts
@@ -49,6 +49,17 @@ function defaultPropFactory (prop: string) {
const PROVIDE_KEY = '__floating-vue__popper'
+function normalizeTriggers (
+ commonTriggers: string[],
+ customTriggers?: string[] | ((commonTriggers: string[]) => string[]),
+) {
+ if (customTriggers != null) {
+ return typeof customTriggers === 'function' ? customTriggers(commonTriggers) : customTriggers
+ }
+
+ return commonTriggers
+}
+
const createPopper = () => defineComponent({
name: 'VPopper',
@@ -282,6 +293,11 @@ const createPopper = () => defineComponent({
type: Boolean,
default: undefined,
},
+
+ fixDiagonalSubmenuProblem: {
+ type: [Boolean, Number],
+ default: undefined,
+ },
},
emits: {
@@ -362,7 +378,18 @@ const createPopper = () => defineComponent({
return this[PROVIDE_KEY]?.parentPopper
},
- hasPopperShowTriggerHover () {
+ shouldFixDiagonalSubmenuProblem () {
+ return this.fixDiagonalSubmenuProblem === true || typeof this.fixDiagonalSubmenuProblem === 'number'
+ },
+
+ hasHoverableTrigger () {
+ if (this.shouldFixDiagonalSubmenuProblem) {
+ const showTriggers = normalizeTriggers(this.triggers, this.showTriggers)
+ const popperShowTriggers = normalizeTriggers(this.popperTriggers, this.popperShowTriggers)
+
+ return showTriggers.includes('hover') && popperShowTriggers.includes('hover')
+ }
+
return this.popperTriggers?.includes('hover') || this.popperShowTriggers?.includes('hover')
},
},
@@ -468,16 +495,24 @@ const createPopper = () => defineComponent({
}
// Abort if aiming for the popper
- if (this.hasPopperShowTriggerHover && this.$_isAimingPopper()) {
+ if (this.hasHoverableTrigger && this.$_isAimingPopper()) {
if (this.parentPopper) {
this.parentPopper.lockedChild = this
clearTimeout(this.parentPopper.lockedChildTimer)
+
+ let timeout = 1000
+ if (this.fixDiagonalSubmenuProblem === true) {
+ timeout = 250
+ } else if (typeof this.fixDiagonalSubmenuProblem === 'number') {
+ timeout = this.fixDiagonalSubmenuProblem
+ }
+
this.parentPopper.lockedChildTimer = setTimeout(() => {
if (this.parentPopper.lockedChild === this) {
this.parentPopper.lockedChild.hide({ skipDelay })
this.parentPopper.lockedChild = null
}
- }, 1000)
+ }, timeout)
}
return
}
@@ -492,6 +527,12 @@ const createPopper = () => defineComponent({
this.$emit('update:shown', false)
},
+ handlePopperNodeHovered () {
+ if (this.parentPopper?.lockedChild === this) {
+ this.parentPopper.lockedChild = null
+ }
+ },
+
init () {
if (!this.isDisposed) return
this.isDisposed = false
@@ -904,8 +945,17 @@ const createPopper = () => defineComponent({
!this.$_preventShow && this.show({ event })
}
- this.$_registerTriggerListeners(this.$_targetNodes, SHOW_EVENT_MAP, this.triggers, this.showTriggers, handleShow)
- this.$_registerTriggerListeners([this.$_popperNode], SHOW_EVENT_MAP, this.popperTriggers, this.popperShowTriggers, handleShow)
+ const showTriggers = normalizeTriggers(this.triggers, this.showTriggers)
+ const hideTriggers = normalizeTriggers(this.triggers, this.hideTriggers)
+ const popperShowTriggers = normalizeTriggers(this.popperTriggers, this.popperShowTriggers)
+ const popperHideTriggers = normalizeTriggers(this.popperTriggers, this.popperHideTriggers)
+
+ this.$_registerTriggerListeners(this.$_targetNodes, SHOW_EVENT_MAP, showTriggers, handleShow)
+ this.$_registerTriggerListeners([this.$_popperNode], SHOW_EVENT_MAP, popperShowTriggers, handleShow)
+
+ if (this.shouldFixDiagonalSubmenuProblem && this.hasHoverableTrigger) {
+ this.$_registerTriggerListeners([this.$_popperNode], SHOW_EVENT_MAP, popperShowTriggers, this.handlePopperNodeHovered)
+ }
// Add trigger hide events
@@ -916,8 +966,8 @@ const createPopper = () => defineComponent({
this.hide({ event })
}
- this.$_registerTriggerListeners(this.$_targetNodes, HIDE_EVENT_MAP, this.triggers, this.hideTriggers, handleHide)
- this.$_registerTriggerListeners([this.$_popperNode], HIDE_EVENT_MAP, this.popperTriggers, this.popperHideTriggers, handleHide)
+ this.$_registerTriggerListeners(this.$_targetNodes, HIDE_EVENT_MAP, hideTriggers, handleHide)
+ this.$_registerTriggerListeners([this.$_popperNode], HIDE_EVENT_MAP, popperHideTriggers, handleHide)
},
$_registerEventListeners (targetNodes: Element[], eventType: string, handler: (event: Event) => void) {
@@ -929,13 +979,7 @@ const createPopper = () => defineComponent({
: undefined))
},
- $_registerTriggerListeners (targetNodes: Element[], eventMap: Record, commonTriggers, customTrigger, handler: (event: Event) => void) {
- let triggers = commonTriggers
-
- if (customTrigger != null) {
- triggers = typeof customTrigger === 'function' ? customTrigger(triggers) : customTrigger
- }
-
+ $_registerTriggerListeners (targetNodes: Element[], eventMap: Record, triggers: string[], handler: (event: Event) => void) {
triggers.forEach(trigger => {
const eventType = eventMap[trigger]
if (eventType) {
diff --git a/packages/floating-vue/src/components/PopperWrapper.vue b/packages/floating-vue/src/components/PopperWrapper.vue
index 764885a6..18ec8d59 100644
--- a/packages/floating-vue/src/components/PopperWrapper.vue
+++ b/packages/floating-vue/src/components/PopperWrapper.vue
@@ -294,6 +294,11 @@ export default defineComponent({
type: Boolean,
default: undefined,
},
+
+ fixDiagonalSubmenuProblem: {
+ type: [Boolean, Number],
+ default: undefined,
+ },
},
emits: {