import * as React from 'react'; import { DirectionalHint } from '../../common/DirectionalHint'; import type { IStyle, ITheme } from '../../Styling'; import type { IRectangle, IStyleFunctionOrObject } from '../../Utilities'; import type { ICalloutPositionedInfo } from '../../Positioning'; import type { ILayerProps } from '../../Layer'; import type { IPopupProps } from '../../Popup'; import type { Target } from '@fluentui/react-hooks'; import type { IPopupRestoreFocusParams } from '../../Popup'; /** * {@docCategory Callout} */ export interface ICalloutProps extends React.HTMLAttributes, React.RefAttributes { /** * The target that the Callout should try to position itself based on. * It can be an element, a query selector string of a valid element, * or a `MouseEvent`. If a `MouseEvent` is given, the origin point of the event will be used. */ target?: Target; /** * How the element should be positioned * @defaultvalue DirectionalHint.BottomAutoEdge */ directionalHint?: DirectionalHint; /** * How the element should be positioned in RTL layouts. * If not specified, a mirror of the `directionalHint` alignment edge will be used instead. * This means that `DirectionalHint.BottomLeft` will change to `DirectionalHint.BottomRight` but * `DirectionalHint.LeftAuto` will not change. */ directionalHintForRTL?: DirectionalHint; /** * The gap between the Callout and the target, specified as number of pixels * @defaultvalue 0 */ gapSpace?: number; /** * The width of the beak. * @defaultvalue 16 */ beakWidth?: number; /** * Custom width for callout including borders. If value is 0, no width is applied. * @defaultvalue 0 */ calloutWidth?: number; /** * Maximum width for callout including borders. If value is 0, no width is applied. * @defaultvalue 0 */ calloutMaxWidth?: number; /** * Minimum width for callout including borders. If value is 0, no width is applied. * @defaultvalue 0 */ calloutMinWidth?: number; /** * The background color of the Callout in hex format ie. #ffffff. * @defaultvalue $ms-color-white */ backgroundColor?: string; /** * The bounding rectangle the callout can appear in (or callback that returns a rectangle). */ bounds?: IRectangle | ((target?: Target, targetWindow?: Window) => IRectangle | undefined); /** * The minimum distance the callout will be away from the edge of the screen. * @defaultvalue 8 */ minPagePadding?: number; /** * Whether the beak is visible. * @defaultvalue true */ isBeakVisible?: boolean; /** * If true then the callout will not dismiss on scroll * @defaultvalue false * @deprecated use preventDismissOnEvent callback instead */ preventDismissOnScroll?: boolean; /** * If true then the callout will not dismiss on resize * @defaultvalue false * @deprecated use preventDismissOnEvent callback instead */ preventDismissOnResize?: boolean; /** * If true then the callout will not dismiss when it loses focus * @defaultvalue false * @deprecated use preventDismissOnEvent callback instead */ preventDismissOnLostFocus?: boolean; /** * If true then the callout will dismiss when the target element is clicked * @defaultvalue false */ dismissOnTargetClick?: boolean; /** * If defined, then takes priority over `preventDismissOnLostFocus`, `preventDismissOnResize`, * and `preventDismissOnScroll`. * If it returns true, the callout will not dismiss for this event. * If not defined or returns false, the callout can dismiss for this event. */ preventDismissOnEvent?: (ev: Event | React.FocusEvent | React.KeyboardEvent | React.MouseEvent) => boolean; /** * If true, callout will dismiss when the window gets focus. * @defaultvalue false */ shouldDismissOnWindowFocus?: boolean; /** * If true, the callout element will be positioned to cover the target. * If false, it will position next to the target. * @defaultvalue false */ coverTarget?: boolean; /** * If true the positioning logic will prefer to flip edges rather than to nudge the rectangle to fit within bounds, * thus making sure the element aligns perfectly with target's alignment edge. */ alignTargetEdge?: boolean; /** * Aria role assigned to the callout (e.g. `dialog`, `alertdialog`). */ role?: string; /** * Accessible label text for callout. */ ariaLabel?: string; /** * ID of the element which contains label text for the callout. */ ariaLabelledBy?: string; /** * ID of the element which contains the description for the callout. */ ariaDescribedBy?: string; /** * CSS class to apply to the callout. * @defaultvalue null */ className?: string; /** * CSS style to apply to the callout. * * If you set `overflowY` in this object, it provides a performance optimization by preventing * Popup (underlying component of Callout) from calculating whether it needs a scroll bar. */ style?: React.CSSProperties; /** * Optional callback when the layer content has mounted. */ onLayerMounted?: () => void; /** * Optional props to pass to the Layer component hosting the callout. */ layerProps?: ILayerProps; /** * Optional props to pass the Popup component that the callout uses. */ popupProps?: IPopupProps; /** * Optional callback that is called once the callout has been correctly positioned. * @param positions - Gives the user information about how the callout is positioned such as the * final edge of the target that it positioned against, the beak position, and the beak's relationship to the * edges of the callout. */ onPositioned?: (positions?: ICalloutPositionedInfo) => void; /** * Callback when the Callout tries to close. */ onDismiss?: (ev?: Event | React.MouseEvent | React.KeyboardEvent) => void; /** * If true, do not render on a new layer. If false, render on a new layer. */ doNotLayer?: boolean; /** * If true the position will not change sides in an attempt to fit the callout within bounds. * It will still attempt to align it to whatever bounds are given. * @defaultvalue false */ directionalHintFixed?: boolean; /** * Specify the final height of the content. * To be used when expanding the content dynamically so that callout can adjust its position. */ finalHeight?: number; /** * Manually set `overflowYHidden` style prop to true on `calloutMain` element. * A variety of callout load animations will need this to hide the scollbar that can appear. */ hideOverflow?: boolean; /** * If true, then the callout will attempt to focus the first focusable element that it contains. * If it doesn't find a focusable element, no focus will be set. */ setInitialFocus?: boolean; /** * Set max height of callout. * When not set, the callout will expand with contents up to the bottom of the screen. */ calloutMaxHeight?: number; /** * Callback when the Callout body is scrolled. */ onScroll?: () => void; /** * Optional theme for component */ theme?: ITheme; /** * Optional styles for the component. */ styles?: IStyleFunctionOrObject; /** * If specified, renders the Callout in a hidden state. * Use this flag, rather than rendering a callout conditionally based on visibility, * to improve rendering performance when it becomes visible. * Note: When callout is hidden its content will not be rendered. It will only render * once the callout is visible. */ hidden?: boolean; /** * If true, the component will be updated even when `hidden` is true. * Note that this would consume resources to update even though nothing is being shown to the user. * This might be helpful though if your updates are small and you want the * callout to be revealed quickly to the user when `hidden` is set to false. */ shouldUpdateWhenHidden?: boolean; /** * If specified, determines whether the underlying {@link Popup} component should try to restore * focus when it is dismissed. When set to false, the Popup won't try to restore focus to * the last focused element. * @defaultvalue true * @deprecated use `onRestoreFocus` instead */ shouldRestoreFocus?: boolean; /** * Called when the component is unmounting, and focus needs to be restored. If this is provided, * focus will not be restored automatically, and you'll need to call `params.originalElement.focus()`. */ onRestoreFocus?: (params: IPopupRestoreFocusParams) => void; /** * The minimum height, in pixels, that the callout will scroll-resize down to on top/bottom edges * before repositioning to a new edge. * * Note: this prop has no effect if `directionalHintFixed=true`. * * Note: if `preferScrollResizing=false`, this prop will have no effect because the callout will not scroll-resize. * * Note: if `hideOverflow = true`, or if the computed callout style `overflowY` is `hidden` or `clip`, * the callout will not scroll-resize. * * @defaultvalue 200 */ minimumScrollResizeHeight?: number; /** * If true, the callout will scroll-resize when positioning on top / bottom edges, * rather than repositioning to a new edge. * * Example: if `directionalHint=DirectionalHint.bottomAutoEdge`, and the callout content height exceeds * the vertical space below the callout, the callout will position itself on the bottom edge of the target * (rather than repositioning to a new edge with more available vertical space), * and the callout will scroll-resize down to the available space. * * Use `minimumScrollResizeHeight` to change the minimum height the callout will resize down to * before repositioning to another edge (default 200px). * * Note: this prop has no effect if `directionalHintFixed=true`. * * Note: if `hideOverflow = true`, or if the computed callout style `overflowY` is `hidden` or `clip`, * the callout will not prefer scroll-resized positions (i.e. this prop will be ignored) * @defaultvalue false */ preferScrollResizePositioning?: boolean; } /** * {@docCategory Callout} */ export interface ICalloutContentStyleProps { /** * Theme to apply to the callout content. */ theme: ITheme; /** * Width for callout including borders. */ calloutWidth?: number; /** * CSS class to apply to the callout. */ className?: string; /** * Callout positioning data */ positions?: ICalloutPositionedInfo; /** * Whether or not to clip content of the callout, if it overflows vertically. */ overflowYHidden?: boolean; /** * Background color for the beak and callout. */ backgroundColor?: string; /** * Width of Callout beak */ beakWidth?: number; /** * Max width for callout including borders. */ calloutMaxWidth?: number; /** * Min width for callout including borders. */ calloutMinWidth?: number; /** * If true, a z-index should be set on the root element (since the Callout will not be rendered on a new layer). */ doNotLayer?: boolean; } /** * {@docCategory Callout} */ export interface ICalloutContentStyles { /** * Style for wrapper of Callout component. */ container: IStyle; /** * Style for callout container root element. */ root: IStyle; /** * Style for callout beak. */ beak: IStyle; /** * Style for callout beak curtain. */ beakCurtain: IStyle; /** * Style for content component of the callout. */ calloutMain: IStyle; } export type { Target };