1
0
Fork 0
mirror of synced 2024-09-11 15:08:05 +12:00

Fix certain types of popover not working inside modals or side panels (#9424)

This commit is contained in:
Andrew Kingston 2023-01-27 14:38:31 +00:00 committed by GitHub
parent 3ba6b134fc
commit 2211becdba
2 changed files with 21 additions and 8 deletions

View file

@ -1,4 +1,4 @@
const ignoredClasses = [".flatpickr-calendar"] const ignoredClasses = [".flatpickr-calendar", ".spectrum-Popover"]
let clickHandlers = [] let clickHandlers = []
/** /**
@ -19,7 +19,7 @@ const handleClick = event => {
} }
// Ignore clicks for modals, unless the handler is registered from a modal // Ignore clicks for modals, unless the handler is registered from a modal
const sourceInModal = handler.element.closest(".spectrum-Modal") != null const sourceInModal = handler.anchor.closest(".spectrum-Modal") != null
const clickInModal = event.target.closest(".spectrum-Modal") != null const clickInModal = event.target.closest(".spectrum-Modal") != null
if (clickInModal && !sourceInModal) { if (clickInModal && !sourceInModal) {
return return
@ -33,10 +33,10 @@ document.documentElement.addEventListener("click", handleClick, true)
/** /**
* Adds or updates a click handler * Adds or updates a click handler
*/ */
const updateHandler = (id, element, callback) => { const updateHandler = (id, element, anchor, callback) => {
let existingHandler = clickHandlers.find(x => x.id === id) let existingHandler = clickHandlers.find(x => x.id === id)
if (!existingHandler) { if (!existingHandler) {
clickHandlers.push({ id, element, callback }) clickHandlers.push({ id, element, anchor, callback })
} else { } else {
existingHandler.callback = callback existingHandler.callback = callback
} }
@ -51,12 +51,22 @@ const removeHandler = id => {
/** /**
* Svelte action to apply a click outside handler for a certain element * Svelte action to apply a click outside handler for a certain element
* opts.anchor is an optional param specifying the real root source of the
* component being observed. This is required for things like popovers, where
* the element using the clickoutside action is the popover, but the popover is
* rendered at the root of the DOM somewhere, whereas the popover anchor is the
* element we actually want to consider when determining the source component.
*/ */
export default (element, callback) => { export default (element, opts) => {
const id = Math.random() const id = Math.random()
updateHandler(id, element, callback) const update = newOpts => {
const callback = newOpts?.callback || newOpts
const anchor = newOpts?.anchor || element
updateHandler(id, element, anchor, callback)
}
update(opts)
return { return {
update: newCallback => updateHandler(id, element, newCallback), update,
destroy: () => removeHandler(id), destroy: () => removeHandler(id),
} }
} }

View file

@ -68,7 +68,10 @@
<div <div
tabindex="0" tabindex="0"
use:positionDropdown={{ anchor, align, maxWidth, useAnchorWidth }} use:positionDropdown={{ anchor, align, maxWidth, useAnchorWidth }}
use:clickOutside={handleOutsideClick} use:clickOutside={{
callback: handleOutsideClick,
anchor,
}}
on:keydown={handleEscape} on:keydown={handleEscape}
class={"spectrum-Popover is-open " + (tooltipClasses || "")} class={"spectrum-Popover is-open " + (tooltipClasses || "")}
role="presentation" role="presentation"