Merge pull request #15447 from Budibase/bbui-typing-1
Type Checkbox.svelte, CheckboxGroup.svelte, and Combobox.svelte.
This commit is contained in:
commit
a8c639687e
|
@ -8,27 +8,52 @@
|
||||||
|
|
||||||
// Strategies are defined as [Popover]To[Anchor].
|
// Strategies are defined as [Popover]To[Anchor].
|
||||||
// They can apply for both horizontal and vertical alignment.
|
// They can apply for both horizontal and vertical alignment.
|
||||||
const Strategies = {
|
type Strategy =
|
||||||
StartToStart: "StartToStart", // e.g. left alignment
|
| "StartToStart"
|
||||||
EndToEnd: "EndToEnd", // e.g. right alignment
|
| "EndToEnd"
|
||||||
StartToEnd: "StartToEnd", // e.g. right-outside alignment
|
| "StartToEnd"
|
||||||
EndToStart: "EndToStart", // e.g. left-outside alignment
|
| "EndToStart"
|
||||||
MidPoint: "MidPoint", // centers relative to midpoints
|
| "MidPoint"
|
||||||
ScreenEdge: "ScreenEdge", // locks to screen edge
|
| "ScreenEdge"
|
||||||
|
|
||||||
|
export interface Styles {
|
||||||
|
maxHeight?: number
|
||||||
|
minWidth?: number
|
||||||
|
maxWidth?: number
|
||||||
|
offset?: number
|
||||||
|
left: number
|
||||||
|
top: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function positionDropdown(element, opts) {
|
export type UpdateHandler = (
|
||||||
let resizeObserver
|
anchorBounds: DOMRect,
|
||||||
|
elementBounds: DOMRect,
|
||||||
|
styles: Styles
|
||||||
|
) => Styles
|
||||||
|
|
||||||
|
interface Opts {
|
||||||
|
anchor?: HTMLElement
|
||||||
|
align: string
|
||||||
|
maxHeight?: number
|
||||||
|
maxWidth?: number
|
||||||
|
minWidth?: number
|
||||||
|
useAnchorWidth: boolean
|
||||||
|
offset: number
|
||||||
|
customUpdate?: UpdateHandler
|
||||||
|
resizable: boolean
|
||||||
|
wrap: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function positionDropdown(element: HTMLElement, opts: Opts) {
|
||||||
|
let resizeObserver: ResizeObserver
|
||||||
let latestOpts = opts
|
let latestOpts = opts
|
||||||
|
|
||||||
// We need a static reference to this function so that we can properly
|
// We need a static reference to this function so that we can properly
|
||||||
// clean up the scroll listener.
|
// clean up the scroll listener.
|
||||||
const scrollUpdate = () => {
|
const scrollUpdate = () => updatePosition(latestOpts)
|
||||||
updatePosition(latestOpts)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updates the position of the dropdown
|
// Updates the position of the dropdown
|
||||||
const updatePosition = opts => {
|
const updatePosition = (opts: Opts) => {
|
||||||
const {
|
const {
|
||||||
anchor,
|
anchor,
|
||||||
align,
|
align,
|
||||||
|
@ -51,12 +76,12 @@ export default function positionDropdown(element, opts) {
|
||||||
const winWidth = window.innerWidth
|
const winWidth = window.innerWidth
|
||||||
const winHeight = window.innerHeight
|
const winHeight = window.innerHeight
|
||||||
const screenOffset = 8
|
const screenOffset = 8
|
||||||
let styles = {
|
let styles: Styles = {
|
||||||
maxHeight,
|
maxHeight,
|
||||||
minWidth: useAnchorWidth ? anchorBounds.width : minWidth,
|
minWidth: useAnchorWidth ? anchorBounds.width : minWidth,
|
||||||
maxWidth: useAnchorWidth ? anchorBounds.width : maxWidth,
|
maxWidth: useAnchorWidth ? anchorBounds.width : maxWidth,
|
||||||
left: null,
|
left: 0,
|
||||||
top: null,
|
top: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore all our logic for custom logic
|
// Ignore all our logic for custom logic
|
||||||
|
@ -81,67 +106,67 @@ export default function positionDropdown(element, opts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Applies a dynamic max height constraint if appropriate
|
// Applies a dynamic max height constraint if appropriate
|
||||||
const applyMaxHeight = height => {
|
const applyMaxHeight = (height: number) => {
|
||||||
if (!styles.maxHeight && resizable) {
|
if (!styles.maxHeight && resizable) {
|
||||||
styles.maxHeight = height
|
styles.maxHeight = height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Applies the X strategy to our styles
|
// Applies the X strategy to our styles
|
||||||
const applyXStrategy = strategy => {
|
const applyXStrategy = (strategy: Strategy) => {
|
||||||
switch (strategy) {
|
switch (strategy) {
|
||||||
case Strategies.StartToStart:
|
case "StartToStart":
|
||||||
default:
|
default:
|
||||||
styles.left = anchorBounds.left
|
styles.left = anchorBounds.left
|
||||||
break
|
break
|
||||||
case Strategies.EndToEnd:
|
case "EndToEnd":
|
||||||
styles.left = anchorBounds.right - elementBounds.width
|
styles.left = anchorBounds.right - elementBounds.width
|
||||||
break
|
break
|
||||||
case Strategies.StartToEnd:
|
case "StartToEnd":
|
||||||
styles.left = anchorBounds.right + offset
|
styles.left = anchorBounds.right + offset
|
||||||
break
|
break
|
||||||
case Strategies.EndToStart:
|
case "EndToStart":
|
||||||
styles.left = anchorBounds.left - elementBounds.width - offset
|
styles.left = anchorBounds.left - elementBounds.width - offset
|
||||||
break
|
break
|
||||||
case Strategies.MidPoint:
|
case "MidPoint":
|
||||||
styles.left =
|
styles.left =
|
||||||
anchorBounds.left +
|
anchorBounds.left +
|
||||||
anchorBounds.width / 2 -
|
anchorBounds.width / 2 -
|
||||||
elementBounds.width / 2
|
elementBounds.width / 2
|
||||||
break
|
break
|
||||||
case Strategies.ScreenEdge:
|
case "ScreenEdge":
|
||||||
styles.left = winWidth - elementBounds.width - screenOffset
|
styles.left = winWidth - elementBounds.width - screenOffset
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Applies the Y strategy to our styles
|
// Applies the Y strategy to our styles
|
||||||
const applyYStrategy = strategy => {
|
const applyYStrategy = (strategy: Strategy) => {
|
||||||
switch (strategy) {
|
switch (strategy) {
|
||||||
case Strategies.StartToStart:
|
case "StartToStart":
|
||||||
styles.top = anchorBounds.top
|
styles.top = anchorBounds.top
|
||||||
applyMaxHeight(winHeight - anchorBounds.top - screenOffset)
|
applyMaxHeight(winHeight - anchorBounds.top - screenOffset)
|
||||||
break
|
break
|
||||||
case Strategies.EndToEnd:
|
case "EndToEnd":
|
||||||
styles.top = anchorBounds.bottom - elementBounds.height
|
styles.top = anchorBounds.bottom - elementBounds.height
|
||||||
applyMaxHeight(anchorBounds.bottom - screenOffset)
|
applyMaxHeight(anchorBounds.bottom - screenOffset)
|
||||||
break
|
break
|
||||||
case Strategies.StartToEnd:
|
case "StartToEnd":
|
||||||
default:
|
default:
|
||||||
styles.top = anchorBounds.bottom + offset
|
styles.top = anchorBounds.bottom + offset
|
||||||
applyMaxHeight(winHeight - anchorBounds.bottom - screenOffset)
|
applyMaxHeight(winHeight - anchorBounds.bottom - screenOffset)
|
||||||
break
|
break
|
||||||
case Strategies.EndToStart:
|
case "EndToStart":
|
||||||
styles.top = anchorBounds.top - elementBounds.height - offset
|
styles.top = anchorBounds.top - elementBounds.height - offset
|
||||||
applyMaxHeight(anchorBounds.top - screenOffset)
|
applyMaxHeight(anchorBounds.top - screenOffset)
|
||||||
break
|
break
|
||||||
case Strategies.MidPoint:
|
case "MidPoint":
|
||||||
styles.top =
|
styles.top =
|
||||||
anchorBounds.top +
|
anchorBounds.top +
|
||||||
anchorBounds.height / 2 -
|
anchorBounds.height / 2 -
|
||||||
elementBounds.height / 2
|
elementBounds.height / 2
|
||||||
break
|
break
|
||||||
case Strategies.ScreenEdge:
|
case "ScreenEdge":
|
||||||
styles.top = winHeight - elementBounds.height - screenOffset
|
styles.top = winHeight - elementBounds.height - screenOffset
|
||||||
applyMaxHeight(winHeight - 2 * screenOffset)
|
applyMaxHeight(winHeight - 2 * screenOffset)
|
||||||
break
|
break
|
||||||
|
@ -150,81 +175,78 @@ export default function positionDropdown(element, opts) {
|
||||||
|
|
||||||
// Determine X strategy
|
// Determine X strategy
|
||||||
if (align === "right") {
|
if (align === "right") {
|
||||||
applyXStrategy(Strategies.EndToEnd)
|
applyXStrategy("EndToEnd")
|
||||||
} else if (align === "right-outside" || align === "right-context-menu") {
|
} else if (align === "right-outside" || align === "right-context-menu") {
|
||||||
applyXStrategy(Strategies.StartToEnd)
|
applyXStrategy("StartToEnd")
|
||||||
} else if (align === "left-outside" || align === "left-context-menu") {
|
} else if (align === "left-outside" || align === "left-context-menu") {
|
||||||
applyXStrategy(Strategies.EndToStart)
|
applyXStrategy("EndToStart")
|
||||||
} else if (align === "center") {
|
} else if (align === "center") {
|
||||||
applyXStrategy(Strategies.MidPoint)
|
applyXStrategy("MidPoint")
|
||||||
} else {
|
} else {
|
||||||
applyXStrategy(Strategies.StartToStart)
|
applyXStrategy("StartToStart")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine Y strategy
|
// Determine Y strategy
|
||||||
if (align === "right-outside" || align === "left-outside") {
|
if (align === "right-outside" || align === "left-outside") {
|
||||||
applyYStrategy(Strategies.MidPoint)
|
applyYStrategy("MidPoint")
|
||||||
} else if (
|
} else if (
|
||||||
align === "right-context-menu" ||
|
align === "right-context-menu" ||
|
||||||
align === "left-context-menu"
|
align === "left-context-menu"
|
||||||
) {
|
) {
|
||||||
applyYStrategy(Strategies.StartToStart)
|
applyYStrategy("StartToStart")
|
||||||
styles.top -= 5 // Manual adjustment for action menu padding
|
if (styles.top) {
|
||||||
|
styles.top -= 5 // Manual adjustment for action menu padding
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
applyYStrategy(Strategies.StartToEnd)
|
applyYStrategy("StartToEnd")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle screen overflow
|
// Handle screen overflow
|
||||||
if (doesXOverflow()) {
|
if (doesXOverflow()) {
|
||||||
// Swap left to right
|
// Swap left to right
|
||||||
if (align === "left") {
|
if (align === "left") {
|
||||||
applyXStrategy(Strategies.EndToEnd)
|
applyXStrategy("EndToEnd")
|
||||||
}
|
}
|
||||||
// Swap right-outside to left-outside
|
// Swap right-outside to left-outside
|
||||||
else if (align === "right-outside") {
|
else if (align === "right-outside") {
|
||||||
applyXStrategy(Strategies.EndToStart)
|
applyXStrategy("EndToStart")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (doesYOverflow()) {
|
if (doesYOverflow()) {
|
||||||
// If wrapping, lock to the bottom of the screen and also reposition to
|
// If wrapping, lock to the bottom of the screen and also reposition to
|
||||||
// the side to not block the anchor
|
// the side to not block the anchor
|
||||||
if (wrap) {
|
if (wrap) {
|
||||||
applyYStrategy(Strategies.MidPoint)
|
applyYStrategy("MidPoint")
|
||||||
if (doesYOverflow()) {
|
if (doesYOverflow()) {
|
||||||
applyYStrategy(Strategies.ScreenEdge)
|
applyYStrategy("ScreenEdge")
|
||||||
}
|
}
|
||||||
applyXStrategy(Strategies.StartToEnd)
|
applyXStrategy("StartToEnd")
|
||||||
if (doesXOverflow()) {
|
if (doesXOverflow()) {
|
||||||
applyXStrategy(Strategies.EndToStart)
|
applyXStrategy("EndToStart")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Othewise invert as normal
|
// Othewise invert as normal
|
||||||
else {
|
else {
|
||||||
// If using an outside strategy then lock to the bottom of the screen
|
// If using an outside strategy then lock to the bottom of the screen
|
||||||
if (align === "left-outside" || align === "right-outside") {
|
if (align === "left-outside" || align === "right-outside") {
|
||||||
applyYStrategy(Strategies.ScreenEdge)
|
applyYStrategy("ScreenEdge")
|
||||||
}
|
}
|
||||||
// Otherwise flip above
|
// Otherwise flip above
|
||||||
else {
|
else {
|
||||||
applyYStrategy(Strategies.EndToStart)
|
applyYStrategy("EndToStart")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply styles
|
for (const [key, value] of Object.entries(styles)) {
|
||||||
Object.entries(styles).forEach(([style, value]) => {
|
element.style.setProperty(key, value ? `${value}px` : null)
|
||||||
if (value != null) {
|
}
|
||||||
element.style[style] = `${value.toFixed(0)}px`
|
|
||||||
} else {
|
|
||||||
element.style[style] = null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The actual svelte action callback which creates observers on the relevant
|
// The actual svelte action callback which creates observers on the relevant
|
||||||
// DOM elements
|
// DOM elements
|
||||||
const update = newOpts => {
|
const update = (newOpts: Opts) => {
|
||||||
latestOpts = newOpts
|
latestOpts = newOpts
|
||||||
|
|
||||||
// Cleanup old state
|
// Cleanup old state
|
|
@ -1,22 +1,23 @@
|
||||||
<script>
|
<script lang="ts">
|
||||||
import "@spectrum-css/checkbox/dist/index-vars.css"
|
import "@spectrum-css/checkbox/dist/index-vars.css"
|
||||||
import "@spectrum-css/fieldgroup/dist/index-vars.css"
|
import "@spectrum-css/fieldgroup/dist/index-vars.css"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
|
import type { ChangeEventHandler } from "svelte/elements"
|
||||||
|
|
||||||
export let value = false
|
export let value = false
|
||||||
export let id = null
|
export let id: string | undefined = undefined
|
||||||
export let text = null
|
export let text: string | undefined = undefined
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let readonly = false
|
export let readonly = false
|
||||||
export let size
|
export let size: "S" | "M" | "L" | "XL" = "M"
|
||||||
export let indeterminate = false
|
export let indeterminate = false
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
const onChange = event => {
|
const onChange: ChangeEventHandler<HTMLInputElement> = event => {
|
||||||
dispatch("change", event.target.checked)
|
dispatch("change", event.currentTarget.checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
$: sizeClass = `spectrum-Checkbox--size${size || "M"}`
|
$: sizeClass = `spectrum-Checkbox--size${size}`
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<label
|
<label
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
<script>
|
<script lang="ts" context="module">
|
||||||
|
type O = any
|
||||||
|
type V = any
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" generics="O, V">
|
||||||
import "@spectrum-css/fieldgroup/dist/index-vars.css"
|
import "@spectrum-css/fieldgroup/dist/index-vars.css"
|
||||||
import "@spectrum-css/radio/dist/index-vars.css"
|
import "@spectrum-css/radio/dist/index-vars.css"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
export let direction = "vertical"
|
export let direction: "horizontal" | "vertical" = "vertical"
|
||||||
export let value = []
|
export let value: V[] = []
|
||||||
export let options = []
|
export let options: O[] = []
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let readonly = false
|
export let readonly = false
|
||||||
export let getOptionLabel = option => option
|
export let getOptionLabel = (option: O) => `${option}`
|
||||||
export let getOptionValue = option => option
|
export let getOptionValue = (option: O) => option as unknown as V
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher<{ change: V[] }>()
|
||||||
|
|
||||||
const onChange = optionValue => {
|
const onChange = (optionValue: V) => {
|
||||||
if (!value.includes(optionValue)) {
|
if (!value.includes(optionValue)) {
|
||||||
dispatch("change", [...value, optionValue])
|
dispatch("change", [...value, optionValue])
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
<script>
|
<script lang="ts" context="module">
|
||||||
|
type O = any
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" generics="O">
|
||||||
|
import type { ChangeEventHandler } from "svelte/elements"
|
||||||
|
|
||||||
import "@spectrum-css/inputgroup/dist/index-vars.css"
|
import "@spectrum-css/inputgroup/dist/index-vars.css"
|
||||||
import "@spectrum-css/popover/dist/index-vars.css"
|
import "@spectrum-css/popover/dist/index-vars.css"
|
||||||
import "@spectrum-css/menu/dist/index-vars.css"
|
import "@spectrum-css/menu/dist/index-vars.css"
|
||||||
|
@ -6,33 +12,38 @@
|
||||||
import clickOutside from "../../Actions/click_outside"
|
import clickOutside from "../../Actions/click_outside"
|
||||||
import Popover from "../../Popover/Popover.svelte"
|
import Popover from "../../Popover/Popover.svelte"
|
||||||
|
|
||||||
export let value = null
|
export let value: string | undefined = undefined
|
||||||
export let id = null
|
export let id: string | undefined = undefined
|
||||||
export let placeholder = "Choose an option or type"
|
export let placeholder = "Choose an option or type"
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let readonly = false
|
export let readonly = false
|
||||||
export let options = []
|
export let options: O[] = []
|
||||||
export let getOptionLabel = option => option
|
export let getOptionLabel = (option: O) => `${option}`
|
||||||
export let getOptionValue = option => option
|
export let getOptionValue = (option: O) => `${option}`
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher<{
|
||||||
|
change: string
|
||||||
|
blur: void
|
||||||
|
type: string
|
||||||
|
pick: string
|
||||||
|
}>()
|
||||||
|
|
||||||
let open = false
|
let open = false
|
||||||
let focus = false
|
let focus = false
|
||||||
let anchor
|
let anchor
|
||||||
|
|
||||||
const selectOption = value => {
|
const selectOption = (value: string) => {
|
||||||
dispatch("change", value)
|
dispatch("change", value)
|
||||||
open = false
|
open = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const onType = e => {
|
const onType: ChangeEventHandler<HTMLInputElement> = e => {
|
||||||
const value = e.target.value
|
const value = e.currentTarget.value
|
||||||
dispatch("type", value)
|
dispatch("type", value)
|
||||||
selectOption(value)
|
selectOption(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPick = value => {
|
const onPick = (value: string) => {
|
||||||
dispatch("pick", value)
|
dispatch("pick", value)
|
||||||
selectOption(value)
|
selectOption(value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,33 @@
|
||||||
<script>
|
<script lang="ts">
|
||||||
import "@spectrum-css/popover/dist/index-vars.css"
|
import "@spectrum-css/popover/dist/index-vars.css"
|
||||||
|
// @ts-expect-error no types for the version of svelte-portal we're on.
|
||||||
import Portal from "svelte-portal"
|
import Portal from "svelte-portal"
|
||||||
import { createEventDispatcher, getContext, onDestroy } from "svelte"
|
import { createEventDispatcher, getContext, onDestroy } from "svelte"
|
||||||
import positionDropdown from "../Actions/position_dropdown"
|
import positionDropdown, {
|
||||||
|
type UpdateHandler,
|
||||||
|
} from "../Actions/position_dropdown"
|
||||||
import clickOutside from "../Actions/click_outside"
|
import clickOutside from "../Actions/click_outside"
|
||||||
import { fly } from "svelte/transition"
|
import { fly } from "svelte/transition"
|
||||||
import Context from "../context"
|
import Context from "../context"
|
||||||
|
import type { KeyboardEventHandler } from "svelte/elements"
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher<{ open: void; close: void }>()
|
||||||
|
|
||||||
export let anchor
|
export let anchor: HTMLElement
|
||||||
export let align = "right"
|
export let align: "left" | "right" | "left-outside" | "right-outside" =
|
||||||
export let portalTarget
|
"right"
|
||||||
export let minWidth
|
export let portalTarget: string | undefined = undefined
|
||||||
export let maxWidth
|
export let minWidth: number | undefined = undefined
|
||||||
export let maxHeight
|
export let maxWidth: number | undefined = undefined
|
||||||
|
export let maxHeight: number | undefined = undefined
|
||||||
export let open = false
|
export let open = false
|
||||||
export let useAnchorWidth = false
|
export let useAnchorWidth = false
|
||||||
export let dismissible = true
|
export let dismissible = true
|
||||||
export let offset = 4
|
export let offset = 4
|
||||||
export let customHeight
|
export let customHeight: string | undefined = undefined
|
||||||
export let animate = true
|
export let animate = true
|
||||||
export let customZindex
|
export let customZindex: string | undefined = undefined
|
||||||
export let handlePostionUpdate
|
export let handlePostionUpdate: UpdateHandler | undefined = undefined
|
||||||
export let showPopover = true
|
export let showPopover = true
|
||||||
export let clickOutsideOverride = false
|
export let clickOutsideOverride = false
|
||||||
export let resizable = true
|
export let resizable = true
|
||||||
|
@ -30,7 +35,7 @@
|
||||||
|
|
||||||
const animationDuration = 260
|
const animationDuration = 260
|
||||||
|
|
||||||
let timeout
|
let timeout: ReturnType<typeof setTimeout>
|
||||||
let blockPointerEvents = false
|
let blockPointerEvents = false
|
||||||
|
|
||||||
$: target = portalTarget || getContext(Context.PopoverRoot) || ".spectrum"
|
$: target = portalTarget || getContext(Context.PopoverRoot) || ".spectrum"
|
||||||
|
@ -65,13 +70,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOutsideClick = e => {
|
const handleOutsideClick = (e: MouseEvent) => {
|
||||||
if (clickOutsideOverride) {
|
if (clickOutsideOverride) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (open) {
|
if (open) {
|
||||||
// Stop propagation if the source is the anchor
|
// Stop propagation if the source is the anchor
|
||||||
let node = e.target
|
let node = e.target as Node | null
|
||||||
let fromAnchor = false
|
let fromAnchor = false
|
||||||
while (!fromAnchor && node && node.parentNode) {
|
while (!fromAnchor && node && node.parentNode) {
|
||||||
fromAnchor = node === anchor
|
fromAnchor = node === anchor
|
||||||
|
@ -86,7 +91,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEscape(e) {
|
const handleEscape: KeyboardEventHandler<HTMLDivElement> = e => {
|
||||||
if (!clickOutsideOverride) {
|
if (!clickOutsideOverride) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue