-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(Dialog): "esc" key close dialogs in wrong order (#5021)
* fix(Dialog): "esc" close dialogs in wrong order Related items: #5019 * proposal to discuss * last bits * added password component to comment esc key handling approach * add esc key handling to cascade select * add esc key handling to split button + fix error in overlay panel * fix: add speed dial to common esc handling approach * fix: prop naming * fix: format --------- Co-authored-by: Melloware <[email protected]>
- Loading branch information
Showing
17 changed files
with
300 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import * as React from 'react'; | ||
import { UniqueComponentId } from '../utils/Utils'; | ||
|
||
const groupToDisplayedElements = {}; | ||
|
||
export const useDisplayOrder = (group, isVisible = true) => { | ||
const [uid] = React.useState(() => UniqueComponentId()); | ||
|
||
const [displayOrder, setDisplayOrder] = React.useState(); | ||
|
||
React.useEffect(() => { | ||
if (isVisible) { | ||
if (!(group in groupToDisplayedElements)) { | ||
groupToDisplayedElements[group] = []; | ||
} | ||
|
||
const newDisplayOrder = groupToDisplayedElements[group].length; | ||
|
||
groupToDisplayedElements[group].push(uid); | ||
setDisplayOrder(newDisplayOrder); | ||
|
||
return () => { | ||
delete groupToDisplayedElements[group][newDisplayOrder]; | ||
const lastOrder = groupToDisplayedElements[group].findLastIndex((el) => el !== undefined); | ||
|
||
// Reduce array length, by removing undefined elements at the end of array: | ||
groupToDisplayedElements[group].splice(lastOrder + 1); | ||
|
||
setDisplayOrder(undefined); | ||
}; | ||
} | ||
}, [group, uid, isVisible]); | ||
|
||
return displayOrder; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { DomHandler } from '../utils/Utils'; | ||
import { useEffect } from 'react'; | ||
|
||
/** | ||
* Priorities of different components (bigger number handled first) | ||
*/ | ||
export const ESC_KEY_HANDLING_PRIORITIES = { | ||
SIDEBAR: 100, | ||
SLIDE_MENU: 200, | ||
DIALOG: 300, | ||
IMAGE: 400, | ||
MENU: 500, | ||
OVERLAY_PANEL: 600, | ||
PASSWORD: 700, | ||
CASCADE_SELECT: 800, | ||
SPLIT_BUTTON: 900, | ||
SPEED_DIAL: 1000 | ||
}; | ||
|
||
/** | ||
* Object, that manages global escape key handling logic | ||
*/ | ||
const globalEscKeyHandlingLogic = { | ||
/** | ||
* Mapping from ESC_KEY_HANDLING_PRIORITY to array of related listeners, grouped by priority | ||
* @example | ||
* Map<{ | ||
* [ESC_KEY_HANDLING_PRIORITIES.SIDEBAR]: Map<{ | ||
* 1: () => {...}, | ||
* 2: () => {...} | ||
* }>, | ||
* [ESC_KEY_HANDLING_PRIORITIES.DIALOG]: Map<{ | ||
* 1: () => {...}, | ||
* 2: () => {...} | ||
* }> | ||
* }>; | ||
*/ | ||
escKeyListeners: new Map(), | ||
|
||
/** | ||
* Keydown handler (attached to any keydown) | ||
*/ | ||
onGlobalKeyDown(event) { | ||
// Do nothing if not an "esc" key is pressed: | ||
if (event.key !== 'Esc' && event.key !== 'Escape') return; | ||
|
||
const escKeyListeners = globalEscKeyHandlingLogic.escKeyListeners; | ||
const maxPrimaryPriority = Math.max(...escKeyListeners.keys()); | ||
|
||
const theMostImportantEscHandlersSet = escKeyListeners.get(maxPrimaryPriority); | ||
|
||
const maxSecondaryPriority = Math.max(...theMostImportantEscHandlersSet.keys()); | ||
const theMostImportantEscHandler = theMostImportantEscHandlersSet.get(maxSecondaryPriority); | ||
|
||
theMostImportantEscHandler(event); | ||
}, | ||
|
||
/** | ||
* Attach global keydown listener if there are any "esc" key handlers assigned, | ||
* otherwise detach. | ||
*/ | ||
refreshGlobalKeyDownListener() { | ||
const document = DomHandler.getTargetElement('document'); | ||
|
||
if (this.escKeyListeners.size > 0) { | ||
document.addEventListener('keydown', this.onGlobalKeyDown); | ||
} else { | ||
document.removeEventListener('keydown', this.onGlobalKeyDown); | ||
} | ||
}, | ||
|
||
/** | ||
* Add "Esc" key handler | ||
*/ | ||
addListener(callback, [primaryPriority, secondaryPriority]) { | ||
const escKeyListeners = this.escKeyListeners; | ||
|
||
if (!escKeyListeners.has(primaryPriority)) { | ||
escKeyListeners.set(primaryPriority, new Map()); | ||
} | ||
|
||
const primaryPriorityListeners = escKeyListeners.get(primaryPriority); | ||
|
||
// To prevent unexpected override of callback: | ||
if (primaryPriorityListeners.has(secondaryPriority)) { | ||
throw new Error(`Unexpected: global esc key listener with priority [${primaryPriority}, ${secondaryPriority}] already exists.`); | ||
} | ||
|
||
primaryPriorityListeners.set(secondaryPriority, callback); | ||
this.refreshGlobalKeyDownListener(); | ||
|
||
return () => { | ||
primaryPriorityListeners.delete(secondaryPriority); | ||
|
||
if (primaryPriorityListeners.size === 0) { | ||
escKeyListeners.delete(primaryPriority); | ||
} | ||
|
||
this.refreshGlobalKeyDownListener(); | ||
}; | ||
} | ||
}; | ||
|
||
export const useGlobalOnEscapeKey = ({ callback, when, priority }) => { | ||
useEffect(() => { | ||
if (!when) return; | ||
|
||
return globalEscKeyHandlingLogic.addListener(callback, priority); | ||
}, [when, callback, priority]); | ||
}; |
Oops, something went wrong.