/*
* The MIT License (MIT)
*
* Copyright (c) 2015 - present Instructure, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import React from 'react'
import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
import type { PositionTheme } from '@instructure/shared-types'
import type {
PositionConstraint,
PositionMountNode,
PlacementPropValues,
ElementPosition
} from '../PositionPropTypes'
import type { WithDeterministicIdProps } from '@instructure/ui-react-utils'
import { Renderable } from '@instructure/shared-types'
type PositionOwnProps = {
/**
* The node to use as the position target
*/
renderTarget?: Renderable
/**
* The target to be used when not using `renderTarget`
*/
target?: PositionMountNode
/**
* The placement of the content in relation to the target
*/
placement?: PlacementPropValues
/**
* An element or a function returning an element to use as the mount node
* for the `` (defaults to `document.body`)
*/
mountNode?: PositionMountNode
/**
* Insert the element at the 'top' of the mountNode or at the 'bottom'
*/
insertAt?: 'bottom' | 'top'
/**
* The parent in which to constrain the placement.
* One of?: 'window', 'scroll-parent', 'parent', 'none', an element,
* or a function returning an element
*/
constrain?: PositionConstraint
/**
* The horizontal offset for the positioned content
*/
offsetX?: string | number
/**
* The vertical offset for the positioned content
*/
offsetY?: string | number
/**
* An id will be generated if not provided
*/
id?: string
/**
* Whether or not position of the target should be tracked or just set statically on render
*/
shouldTrackPosition?: boolean
/**
* Whether or not you want the content to position over the target
*/
shouldPositionOverTarget?: boolean
/**
* Callback fired when the position changes
*/
onPositionChanged?: (position: PositionObject) => void
/**
* Callback fired when `` content has been mounted and is initially positioned
*/
onPositioned?: (position: PositionObject) => void
/**
* The content to be positioned
*/
children?: React.ReactNode
/**
* Set the CSS `display` property on the outermost `` container element
*/
containerDisplay?: 'inline-block' | 'block'
/**
* Provides a reference to the underlying HTML root element (the target)
*/
elementRef?: (element: Element | null) => void
}
type PositionState = {
positioned: boolean
} & ElementPosition
type PositionStyle = ComponentStyle<'position' | 'zIndex'>
type PositionObject = ElementPosition['style'] & {
placement: ElementPosition['placement']
}
type PropKeys = keyof PositionOwnProps
type AllowedPropKeys = Readonly>
type PositionProps = PositionOwnProps &
WithStyleProps &
WithDeterministicIdProps
const allowedProps: AllowedPropKeys = [
'renderTarget',
'target',
'placement',
'mountNode',
'insertAt',
'constrain',
'offsetX',
'offsetY',
'id',
'shouldTrackPosition',
'shouldPositionOverTarget',
'onPositionChanged',
'onPositioned',
'children',
'containerDisplay',
'elementRef'
]
export type { PositionProps, PositionState, PositionStyle, PositionObject }
export { allowedProps }