From 3058fcbc35f8b2863d4c3645485d419bbad1c57a Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 12 Jan 2023 09:18:17 +0000 Subject: [PATCH] Update pickers to use absolutely positioned root popover so that overflow does not matter --- packages/bbui/src/Actions/click_outside.js | 2 +- .../bbui/src/Actions/position_dropdown.js | 24 +- packages/bbui/src/Form/Core/Picker.svelte | 256 +++++++++--------- packages/bbui/src/Popover/Popover.svelte | 22 +- 4 files changed, 169 insertions(+), 135 deletions(-) diff --git a/packages/bbui/src/Actions/click_outside.js b/packages/bbui/src/Actions/click_outside.js index 3a08484635..9ea247f997 100644 --- a/packages/bbui/src/Actions/click_outside.js +++ b/packages/bbui/src/Actions/click_outside.js @@ -1,4 +1,4 @@ -const ignoredClasses = [".flatpickr-calendar", ".modal-container"] +const ignoredClasses = [".flatpickr-calendar"] let clickHandlers = [] /** diff --git a/packages/bbui/src/Actions/position_dropdown.js b/packages/bbui/src/Actions/position_dropdown.js index 7570a39c8c..88f8783633 100644 --- a/packages/bbui/src/Actions/position_dropdown.js +++ b/packages/bbui/src/Actions/position_dropdown.js @@ -1,6 +1,10 @@ -export default function positionDropdown(element, { anchor, align, maxWidth }) { +export default function positionDropdown( + element, + { anchor, align, maxWidth, useAnchorWidth } +) { let positionSide = "top" let maxHeight = 0 + let minWidth = 0 let dimensions = getDimensions(anchor) function getDimensions() { @@ -14,8 +18,7 @@ export default function positionDropdown(element, { anchor, align, maxWidth }) { const containerRect = element.getBoundingClientRect() let y - - if (spaceAbove > spaceBelow) { + if (window.innerHeight - bottom < 100) { positionSide = "bottom" maxHeight = spaceAbove - 20 y = window.innerHeight - spaceAbove + 5 @@ -25,6 +28,13 @@ export default function positionDropdown(element, { anchor, align, maxWidth }) { maxHeight = spaceBelow - 20 } + if (!maxWidth && useAnchorWidth) { + maxWidth = width + } + if (useAnchorWidth) { + minWidth = width + } + return { [positionSide]: y, left, @@ -36,9 +46,9 @@ export default function positionDropdown(element, { anchor, align, maxWidth }) { function calcLeftPosition() { let left - if (align == "right") { + if (align === "right") { left = dimensions.left + dimensions.width - dimensions.containerWidth - } else if (align == "right-side") { + } else if (align === "right-side") { left = dimensions.left + dimensions.width } else { left = dimensions.left @@ -52,7 +62,9 @@ export default function positionDropdown(element, { anchor, align, maxWidth }) { if (maxWidth) { element.style.maxWidth = `${maxWidth}px` } - element.style.minWidth = `${dimensions.width}px` + if (minWidth) { + element.style.minWidth = `${minWidth}px` + } element.style.maxHeight = `${maxHeight.toFixed(0)}px` element.style.transformOrigin = `center ${positionSide}` element.style[positionSide] = `${dimensions[positionSide]}px` diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index 63f07b7cd6..81348452c7 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -2,12 +2,12 @@ import "@spectrum-css/picker/dist/index-vars.css" import "@spectrum-css/popover/dist/index-vars.css" import "@spectrum-css/menu/dist/index-vars.css" - import { fly } from "svelte/transition" import { createEventDispatcher } from "svelte" import clickOutside from "../../Actions/click_outside" import Search from "./Search.svelte" import Icon from "../../Icon/Icon.svelte" import StatusLight from "../../StatusLight/StatusLight.svelte" + import Popover from "../../Popover/Popover.svelte" export let id = null export let disabled = false @@ -33,7 +33,10 @@ export let sort = false const dispatch = createEventDispatcher() + let searchTerm = null + let button + let popover $: sortedOptions = getSortedOptions(options, getOptionLabel, sort) $: filteredOptions = getFilteredOptions( @@ -76,77 +79,117 @@ } -
(open = false)}> - - {#if open} -
- {#if autocomplete} - (searchTerm = event.detail)} - {disabled} - placeholder="Search" - /> + {/if} + + + + (open = false)} + useAnchorWidth={!autoWidth} + maxWidth={autoWidth ? 400 : null} +> +
+ {#if autocomplete} + (searchTerm = event.detail)} + {disabled} + placeholder="Search" + /> + {/if} +
    + {#if placeholderOption} +
  • onSelectOption(null)} + > + {placeholderOption} + +
  • {/if} -
      - {#if placeholderOption} + {#if filteredOptions.length} + {#each filteredOptions as option, idx}
    • onSelectOption(null)} + on:click={() => onSelectOption(getOptionValue(option, idx))} + class:is-disabled={!isOptionEnabled(option)} > - {placeholderOption} + {#if getOptionIcon(option, idx)} + + + + {/if} + {#if getOptionColour(option, idx)} + + + + {/if} + + {getOptionLabel(option, idx)} +
    • - {/if} - {#if filteredOptions.length} - {#each filteredOptions as option, idx} -
    • onSelectOption(getOptionValue(option, idx))} - class:is-disabled={!isOptionEnabled(option)} - > - {#if getOptionIcon(option, idx)} - - - - {/if} - {#if getOptionColour(option, idx)} - - - - {/if} - - {getOptionLabel(option, idx)} - - -
    • - {/each} - {/if} -
    -
- {/if} -
+ {/each} + {/if} + +
+ diff --git a/packages/bbui/src/Popover/Popover.svelte b/packages/bbui/src/Popover/Popover.svelte index b81e76dc1f..191898578a 100644 --- a/packages/bbui/src/Popover/Popover.svelte +++ b/packages/bbui/src/Popover/Popover.svelte @@ -4,6 +4,7 @@ import { createEventDispatcher } from "svelte" import positionDropdown from "../Actions/position_dropdown" import clickOutside from "../Actions/click_outside" + import { fly } from "svelte/transition" const dispatch = createEventDispatcher() @@ -12,9 +13,10 @@ export let portalTarget export let dataCy export let maxWidth - export let direction = "bottom" export let showTip = false + export let open = false + export let useAnchorWidth = false let tipSvg = ' ' @@ -35,13 +37,22 @@ const handleOutsideClick = e => { if (open) { - e.stopPropagation() + // Stop propagation if the source is the anchor + let node = e.target + let fromAnchor = false + while (!fromAnchor && node && node.parentNode) { + fromAnchor = node === anchor + node = node.parentNode + } + if (fromAnchor) { + e.stopPropagation() + } + + // Hide the popover hide() } } - let open = null - function handleEscape(e) { if (open && e.key === "Escape") { hide() @@ -53,12 +64,13 @@