@amboss/design-system 4.4.6 → 4.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/components/RangePopover/RangePopover.d.ts +13 -7
- package/build/cjs/components/RangePopover/RangePopover.js +1 -1
- package/build/cjs/components/Toggletip/BasePopover.d.ts +1 -1
- package/build/cjs/components/Toggletip/BasePopover.js +1 -1
- package/build/cjs/components/Tooltip/BaseTooltip.d.ts +1 -1
- package/build/cjs/components/Tooltip/BaseTooltip.js +1 -1
- package/build/cjs/components/Tooltip/FloatingPositionedContext.d.ts +8 -0
- package/build/cjs/components/Tooltip/FloatingPositionedContext.js +1 -0
- package/build/cjs/components/Tooltip/TooltipContent.d.ts +6 -11
- package/build/cjs/components/Tooltip/TooltipContent.js +1 -1
- package/build/cjs/components/Tooltip/utils.d.ts +60 -16
- package/build/cjs/components/Tooltip/utils.js +1 -1
- package/build/cjs/components/Utilities/FloatingPosition/useFloatingPosition.d.ts +41 -6
- package/build/cjs/components/Utilities/FloatingPosition/useFloatingPosition.js +1 -1
- package/build/cjs/shared/FocusTrapWrapper.js +1 -1
- package/build/esm/components/RangePopover/RangePopover.d.ts +13 -7
- package/build/esm/components/RangePopover/RangePopover.js +1 -1
- package/build/esm/components/Toggletip/BasePopover.d.ts +1 -1
- package/build/esm/components/Toggletip/BasePopover.js +1 -1
- package/build/esm/components/Tooltip/BaseTooltip.d.ts +1 -1
- package/build/esm/components/Tooltip/BaseTooltip.js +1 -1
- package/build/esm/components/Tooltip/FloatingPositionedContext.d.ts +8 -0
- package/build/esm/components/Tooltip/FloatingPositionedContext.js +1 -0
- package/build/esm/components/Tooltip/TooltipContent.d.ts +6 -11
- package/build/esm/components/Tooltip/TooltipContent.js +1 -1
- package/build/esm/components/Tooltip/utils.d.ts +60 -16
- package/build/esm/components/Tooltip/utils.js +1 -1
- package/build/esm/components/Utilities/FloatingPosition/useFloatingPosition.d.ts +41 -6
- package/build/esm/components/Utilities/FloatingPosition/useFloatingPosition.js +1 -1
- package/build/esm/shared/FocusTrapWrapper.js +1 -1
- package/package.json +1 -1
- package/build/cjs/components/Tooltip/getSideTooltipStyle.d.ts +0 -14
- package/build/cjs/components/Tooltip/getSideTooltipStyle.js +0 -1
- package/build/esm/components/Tooltip/getSideTooltipStyle.d.ts +0 -14
- package/build/esm/components/Tooltip/getSideTooltipStyle.js +0 -1
|
@@ -10,6 +10,11 @@ export type RangePopoverProps = {
|
|
|
10
10
|
isVisible: boolean;
|
|
11
11
|
/** Called when the popover is dismissed by an outside click or the Escape key. */
|
|
12
12
|
onClose: () => void;
|
|
13
|
+
/**
|
|
14
|
+
* Controls whether the popover closes on an outside click. When false, only
|
|
15
|
+
* the Escape key dismisses it.
|
|
16
|
+
*/
|
|
17
|
+
dismissOnOutsideClick?: boolean;
|
|
13
18
|
/** Preferred placement relative to the range. */
|
|
14
19
|
placement?: RangePopoverPlacement;
|
|
15
20
|
/** Portal target; falls back to the document body when omitted. */
|
|
@@ -40,17 +45,18 @@ export type RangePopoverProps = {
|
|
|
40
45
|
* A click-dismissed popover anchored on a DOM {@link Range} rather than a
|
|
41
46
|
* trigger element.
|
|
42
47
|
*
|
|
43
|
-
* It pairs the design-system tooltip positioner — which
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
48
|
+
* It pairs the design-system tooltip positioner — which accepts a `Range` in
|
|
49
|
+
* `triggerRef` and anchors on it as a floating-ui virtual element — with the
|
|
50
|
+
* focus-trap dismissal model used by the design-system Popover. This lets it
|
|
51
|
+
* anchor on a painted text selection that has no DOM node of its own, the same
|
|
52
|
+
* way `UserHighlightTooltip` does, while opening and closing on explicit
|
|
53
|
+
* interaction instead of hover.
|
|
49
54
|
*
|
|
50
55
|
* @param content - The popover body.
|
|
51
56
|
* @param range - The range to anchor on.
|
|
52
57
|
* @param isVisible - Whether the popover is shown.
|
|
53
58
|
* @param onClose - Called when dismissed by an outside click or the Escape key.
|
|
59
|
+
* @param dismissOnOutsideClick - Whether an outside click dismisses the popover.
|
|
54
60
|
* @param placement - Preferred placement relative to the range.
|
|
55
61
|
* @param portalContainer - Portal target; falls back to the document body.
|
|
56
62
|
* @param contentPadding - Inner padding of the popover surface.
|
|
@@ -60,5 +66,5 @@ export type RangePopoverProps = {
|
|
|
60
66
|
* @param aria-label - Accessible name for the popover surface.
|
|
61
67
|
* @param disableInitialFocus - When true, does not move focus into the popover.
|
|
62
68
|
*/
|
|
63
|
-
export declare function RangePopover({ content, range, isVisible, onClose, placement, portalContainer, contentPadding, maxWidth, hideArrow, role, "aria-label": ariaLabel, disableInitialFocus, "data-e2e-test-id": dataE2eTestId, }: RangePopoverProps): React.ReactElement;
|
|
69
|
+
export declare function RangePopover({ content, range, isVisible, onClose, dismissOnOutsideClick, placement, portalContainer, contentPadding, maxWidth, hideArrow, role, "aria-label": ariaLabel, disableInitialFocus, "data-e2e-test-id": dataE2eTestId, }: RangePopoverProps): React.ReactElement;
|
|
64
70
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"RangePopover",{enumerable:!0,get:function(){return RangePopover}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_styled=/*#__PURE__*/_interop_require_default._(require("@emotion/styled")),_TooltipContent=require("../Tooltip/TooltipContent"),_FocusTrapWrapper=require("../../shared/FocusTrapWrapper"),StyledContent=(0,_styled.default)("div",{target:"
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"RangePopover",{enumerable:!0,get:function(){return RangePopover}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_styled=/*#__PURE__*/_interop_require_default._(require("@emotion/styled")),_TooltipContent=require("../Tooltip/TooltipContent"),_FocusTrapWrapper=require("../../shared/FocusTrapWrapper"),StyledContent=(0,_styled.default)("div",{target:"e1cdfvza0",label:"StyledContent"})(({theme,contentPadding})=>({padding:"m"===contentPadding?theme.variables.size.spacing.s:theme.variables.size.spacing.xxs}));function RangePopover({content,range,isVisible,onClose,dismissOnOutsideClick=!0,placement="top",portalContainer,contentPadding="s",maxWidth,hideArrow=!1,role="dialog","aria-label":ariaLabel,disableInitialFocus=!1,"data-e2e-test-id":dataE2eTestId}){let tooltipId=(0,_react.useId)(),rangeRef=(0,_react.useRef)(null);rangeRef.current=range;let contentRef=(0,_react.useRef)(null),trappedContent=_react.default.createElement(_FocusTrapWrapper.FocusTrapWrapper,{active:isVisible,focusTrapOptions:{allowOutsideClick:!0,clickOutsideDeactivates:dismissOnOutsideClick,escapeDeactivates:!0,fallbackFocus:()=>contentRef.current,initialFocus:!disableInitialFocus&&void 0,onPostDeactivate:onClose,preventScroll:!0,returnFocusOnDeactivate:!disableInitialFocus}},_react.default.createElement(StyledContent,{ref:contentRef,tabIndex:-1,contentPadding:contentPadding},content));return _react.default.createElement(_TooltipContent.TooltipContent,{"aria-label":ariaLabel,content:trappedContent,dataDSId:"RangePopover",dataE2eTestId:dataE2eTestId,hideArrow:hideArrow,isVisible:isVisible,maxWidth:maxWidth,placement:placement,portalContainer:portalContainer,role:role,tooltipId:tooltipId,triggerRef:rangeRef})}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ReactElement } from "react";
|
|
2
2
|
import React from "react";
|
|
3
|
+
import type { PopupRole } from "../Sheet/Sheet";
|
|
3
4
|
import type { TooltipContentProps } from "../Tooltip/TooltipContent";
|
|
4
5
|
import type { TooltipConditionalProps } from "../Tooltip/types";
|
|
5
|
-
import type { PopupRole } from "../Sheet/Sheet";
|
|
6
6
|
type BaseProps = Pick<TooltipContentProps, "placement" | "portalContainer" | "maxWidth" | "contentPadding" | "hideArrow" | "subTheme" | "defaultVerticalPlacement" | "onOverflowViewport"> & {
|
|
7
7
|
name?: string;
|
|
8
8
|
/** Popover content */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"BasePopover",{enumerable:!0,get:function(){return BasePopover}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"BasePopover",{enumerable:!0,get:function(){return BasePopover}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_interop_require_wildcard=require("@swc/helpers/_/_interop_require_wildcard"),_styled=/*#__PURE__*/_interop_require_default._(require("@emotion/styled")),_react=/*#__PURE__*/_interop_require_wildcard._(require("react")),_ariaAttributes=require("../../shared/ariaAttributes"),_FocusTrapWrapper=require("../../shared/FocusTrapWrapper"),_useWindow=require("../../shared/useWindow"),_breakpointsjson=/*#__PURE__*/_interop_require_default._(require("../../web-tokens/_breakpoints.json")),_PopoverContext=require("../Patterns/Popover/PopoverContext"),_Sheet=require("../Sheet/Sheet"),_TooltipContent=require("../Tooltip/TooltipContent"),StyledContainer=(0,_styled.default)("div",{target:"e2uwtlo0",label:"StyledContainer"})(()=>({borderRadius:"inherit"})),FocusTrapContent=_react.default.forwardRef(({children},ref)=>_react.default.createElement(StyledContainer,{ref:ref},children)),VisibilityChangeReason={triggerClick:"triggerClick",outsideClick:"outsideClick"};function getAriaPopupType(role){let popupType=String(role);return(role||(popupType="true"),"alertdialog"===role)?"dialog":popupType}function getMobileBreakpoint(renderAsSheetOnMobile,win){if(!win)return!1;let isMobileInPortrait=win.innerWidth<=_breakpointsjson.default.m.value,isSmallHeight=win.innerHeight<=450,isLandscape=win.matchMedia?.("(orientation: landscape)").matches;return renderAsSheetOnMobile&&(isMobileInPortrait||isLandscape&&isSmallHeight)}function BasePopover({placement="auto",content,children,contentPadding="m",maxWidth,externalTriggerRef,portalContainer,name="Popover",isVisible:isPopoverVisible,dismissOnOutsideClick=!0,retainOnOutsideClick,"data-e2e-test-id":dataE2eTestId,subTheme,defaultVerticalPlacement,onVisibilityChange,disableInitialFocus=!1,disableReturnFocusToTrigger=!1,renderAsSheetOnMobile=!1,forceSheetLayout=!1,role,sheetProps,...restContentProps}){let win=(0,_useWindow.useWindow)(),tooltipId=(0,_react.useMemo)(()=>`DS${name}_${Math.floor(Date.now()*Math.random())}`,[name]),[isVisible,setVisible]=(0,_react.useState)(isPopoverVisible),[isMobileBreakPoint,setIsMobileBreakpoint]=(0,_react.useState)(()=>forceSheetLayout||getMobileBreakpoint(renderAsSheetOnMobile,win)),internalTriggerRef=(0,_react.useRef)(null),triggerRef=externalTriggerRef||internalTriggerRef,isOutsideClickOnTrigger=(0,_react.useRef)(!1),ariaAttributes=(0,_ariaAttributes.getAriaAttributes)(restContentProps),popoverContextValue=(0,_react.useMemo)(()=>({isWithinPopover:!0,portalContainer}),[portalContainer]),contentWithProvider=_react.default.createElement(_PopoverContext.PopoverContext.Provider,{value:popoverContextValue},content),toggleVisibility=(0,_react.useCallback)((status,reason)=>{setVisible(status),onVisibilityChange&&onVisibilityChange(status,reason)},[onVisibilityChange]),handleTriggerClick=(0,_react.useCallback)(()=>{isOutsideClickOnTrigger.current?isOutsideClickOnTrigger.current=!1:toggleVisibility(!isVisible,VisibilityChangeReason.triggerClick)},[toggleVisibility,isVisible]),handleClickOutsideDeactivates=(0,_react.useCallback)(evt=>!retainOnOutsideClick?.(evt)&&(triggerRef.current&&triggerRef.current.contains(evt.target)&&(isOutsideClickOnTrigger.current=!0),!0),[triggerRef,isOutsideClickOnTrigger,retainOnOutsideClick]),handlePostDeactivate=(0,_react.useCallback)(()=>{toggleVisibility(!1,isOutsideClickOnTrigger.current?VisibilityChangeReason.triggerClick:VisibilityChangeReason.outsideClick)},[toggleVisibility]);(0,_react.useEffect)(()=>{setVisible(isPopoverVisible)},[isPopoverVisible]),(0,_react.useLayoutEffect)(()=>{setIsMobileBreakpoint(forceSheetLayout||getMobileBreakpoint(renderAsSheetOnMobile,win))},[win,isVisible,renderAsSheetOnMobile,forceSheetLayout]),(0,_react.useEffect)(()=>{let trigger=triggerRef.current;if(trigger)return trigger.addEventListener("click",handleTriggerClick),()=>{trigger.removeEventListener("click",handleTriggerClick)}},[handleTriggerClick,triggerRef]),(0,_react.useEffect)(()=>{if(externalTriggerRef?.current&&!children){let trigger=externalTriggerRef.current,triggerTabIndex=trigger.getAttribute("tabindex");trigger.setAttribute("tabindex",triggerTabIndex??"0")}},[externalTriggerRef,children]),(0,_react.useEffect)(()=>{if(externalTriggerRef?.current&&!children){let trigger=externalTriggerRef.current;trigger.setAttribute("aria-haspopup",getAriaPopupType(role)),trigger.setAttribute("aria-expanded",String(!!isVisible)),isVisible?trigger.setAttribute("aria-controls",tooltipId):trigger.removeAttribute("aria-controls")}},[externalTriggerRef,children,role,tooltipId,isVisible]);let triggerElm=children?_react.default.cloneElement(children,{ref:triggerRef,"aria-expanded":!!isVisible,...isVisible&&{"aria-controls":tooltipId},tabIndex:children.props.tabIndex??0,"aria-haspopup":getAriaPopupType(role)}):null;if(isMobileBreakPoint){let sheetElm=_react.default.createElement(_Sheet.Sheet,{id:tooltipId,isVisible:isVisible,portalContainer:portalContainer,dismissOnOutsideClick:dismissOnOutsideClick,disableInitialFocus:disableInitialFocus,disableReturnFocusToTrigger:disableReturnFocusToTrigger,onClose:handlePostDeactivate,onClickOutsideDeactivates:handleClickOutsideDeactivates,role:role,...sheetProps??{},...ariaAttributes},contentWithProvider);return _react.default.createElement(_react.default.Fragment,null,triggerElm,sheetElm)}let contentElm=_react.default.createElement(_FocusTrapWrapper.FocusTrapWrapper,{active:isVisible,focusTrapOptions:{clickOutsideDeactivates:dismissOnOutsideClick&&handleClickOutsideDeactivates,allowOutsideClick:!0,escapeDeactivates:!0,fallbackFocus:`#${tooltipId}`,onPostDeactivate:handlePostDeactivate,preventScroll:!0,initialFocus:()=>!disableInitialFocus,returnFocusOnDeactivate:!disableReturnFocusToTrigger}},_react.default.createElement(FocusTrapContent,null,contentWithProvider)),tooltipElm=_react.default.createElement(_TooltipContent.TooltipContent,{...restContentProps,role:role,defaultVerticalPlacement:defaultVerticalPlacement,dataDSId:name,content:contentElm,contentPadding:contentPadding,maxWidth:maxWidth,placement:placement,portalContainer:portalContainer,dataE2eTestId:dataE2eTestId,subTheme:subTheme,isVisible:isVisible,tooltipId:tooltipId,triggerRef:triggerRef,isHiddenOnInvisibleTrigger:!0});return _react.default.createElement(_react.default.Fragment,null,triggerElm,tooltipElm)}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import type { ReactElement, FocusEvent as ReactFocusEvent, MouseEvent as ReactMouseEvent } from "react";
|
|
2
|
+
import React from "react";
|
|
3
3
|
import type { TooltipContentProps } from "./TooltipContent";
|
|
4
4
|
type BaseProps = Pick<TooltipContentProps, "placement" | "portalContainer" | "contentPadding" | "maxWidth" | "subTheme" | "onOverflowViewport" | "privateProps"> & {
|
|
5
5
|
/** Tooltip content */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"BaseTooltip",{enumerable:!0,get:function(){return BaseTooltip}});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"BaseTooltip",{enumerable:!0,get:function(){return BaseTooltip}});const _interop_require_wildcard=require("@swc/helpers/_/_interop_require_wildcard"),_interactions=require("@react-aria/interactions"),_react=/*#__PURE__*/_interop_require_wildcard._(require("react")),_TooltipContent=require("./TooltipContent");function BaseTooltip({placement="auto",content,children,externalTriggerRef,portalContainer,contentPadding,maxWidth,subTheme,"data-e2e-test-id":dataE2eTestId,onVisibilityChange,privateProps,...ariaAttributes}){let tooltipId=(0,_react.useMemo)(()=>`DSTooltip_${Math.floor(Date.now()*Math.random())}`,[]),{isFocusVisible}=(0,_interactions.useFocusVisible)(),[isVisible,setVisible]=(0,_react.useState)(!1),triggeredByEvent=(0,_react.useRef)(null),isTooltipHovered=(0,_react.useRef)(!1),isTriggerHovered=(0,_react.useRef)(!1),hideTooltipTimeoutId=(0,_react.useRef)(null),showTooltipTimeoutId=(0,_react.useRef)(null),internalTriggerRef=(0,_react.useRef)(null),triggerRef=externalTriggerRef||internalTriggerRef,toggleVisibility=(0,_react.useCallback)(status=>{setVisible(status),onVisibilityChange&&onVisibilityChange(status)},[onVisibilityChange]),handleTriggerPointerEnter=(0,_react.useCallback)(()=>{isTriggerHovered.current=!0,isTooltipHovered.current||(clearTimeout(showTooltipTimeoutId.current),showTooltipTimeoutId.current=setTimeout(()=>{isTriggerHovered.current&&(triggeredByEvent.current="hover",toggleVisibility(!0))},200))},[toggleVisibility]),handleTriggerPointerLeave=(0,_react.useCallback)(()=>{isTriggerHovered.current=!1,clearTimeout(hideTooltipTimeoutId.current),hideTooltipTimeoutId.current=setTimeout(()=>{isTooltipHovered.current||"hover"!==triggeredByEvent.current||isTriggerHovered.current||toggleVisibility(!1)},200)},[toggleVisibility]),handleTriggerFocus=(0,_react.useCallback)(()=>{isFocusVisible&&(triggeredByEvent.current="focus",toggleVisibility(!0))},[isFocusVisible,toggleVisibility]),handleTriggerBlur=(0,_react.useCallback)(()=>{"focus"===triggeredByEvent.current&&toggleVisibility(!1)},[toggleVisibility]),handleTriggerClick=(0,_react.useCallback)(()=>{toggleVisibility(!1)},[toggleVisibility]),handleTriggerKeyDown=(0,_react.useCallback)(evt=>{"Escape"===evt.key&&toggleVisibility(!1)},[toggleVisibility]);(0,_react.useEffect)(()=>()=>{clearTimeout(showTooltipTimeoutId.current),clearTimeout(hideTooltipTimeoutId.current)},[]),(0,_react.useEffect)(()=>{let trigger;if(externalTriggerRef?.current&&!children){let triggerTabIndex=(trigger=externalTriggerRef.current).getAttribute("tabindex");trigger.setAttribute("tabindex",triggerTabIndex??"0"),trigger.addEventListener("pointerenter",handleTriggerPointerEnter),trigger.addEventListener("pointerleave",handleTriggerPointerLeave),trigger.addEventListener("focus",handleTriggerFocus),trigger.addEventListener("blur",handleTriggerBlur),trigger.addEventListener("click",handleTriggerClick),trigger.addEventListener("keydown",handleTriggerKeyDown)}return()=>{trigger&&(trigger.removeEventListener("pointerenter",handleTriggerPointerEnter),trigger.removeEventListener("pointerleave",handleTriggerPointerLeave),trigger.removeEventListener("focus",handleTriggerFocus),trigger.removeEventListener("blur",handleTriggerBlur),trigger.removeEventListener("click",handleTriggerClick),trigger.removeEventListener("keydown",handleTriggerKeyDown))}},[externalTriggerRef,children,handleTriggerPointerEnter,handleTriggerPointerLeave,handleTriggerFocus,handleTriggerBlur,handleTriggerClick,handleTriggerKeyDown]),(0,_react.useEffect)(()=>{if(externalTriggerRef?.current&&!children){let trigger=externalTriggerRef.current;isVisible?trigger.setAttribute("aria-describedby",tooltipId):trigger.removeAttribute("aria-describedby")}},[externalTriggerRef,children,tooltipId,isVisible]);let triggerElm=children?_react.default.cloneElement(children,{ref:triggerRef,...ariaAttributes,...isVisible&&{"aria-describedby":tooltipId},tabIndex:children.props.tabIndex??0,onPointerEnter:handleTriggerPointerEnter,onPointerLeave:handleTriggerPointerLeave,onFocus:evt=>{handleTriggerFocus(),children.props.onFocus&&children.props.onFocus(evt)},onBlur:evt=>{handleTriggerBlur(),children.props.onBlur&&children.props.onBlur(evt)},onClick:evt=>{handleTriggerClick(),children.props.onClick&&children.props.onClick(evt)},onKeyDown:handleTriggerKeyDown}):null,tooltipElm=_react.default.createElement(_TooltipContent.TooltipContent,{dataDSId:"Tooltip",content:content,placement:placement,portalContainer:portalContainer,dataE2eTestId:dataE2eTestId,isVisible:isVisible,tooltipId:tooltipId,triggerRef:triggerRef,"aria-hidden":!0,role:"tooltip",contentPadding:contentPadding,maxWidth:maxWidth,subTheme:subTheme,onTooltipPointerEnter:()=>{isTooltipHovered.current=!0},onTooltipPointerLeave:()=>{isTooltipHovered.current=!1,"hover"===triggeredByEvent.current&&toggleVisibility(!1)},privateProps:privateProps});return _react.default.createElement(_react.default.Fragment,null,triggerElm,tooltipElm)}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the nearest ancestor `TooltipContent` has been measured and
|
|
3
|
+
* positioned by `useFloatingPosition`. Lets content rendered inside it (e.g.
|
|
4
|
+
* `BasePopover`'s focus trap) wait for that before activating, since a focus
|
|
5
|
+
* trap scans for focusable elements only once, on activation, and elements
|
|
6
|
+
* under a `visibility: hidden` ancestor never count as focusable.
|
|
7
|
+
*/
|
|
8
|
+
export declare const FloatingPositionedContext: React.Context<boolean>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"FloatingPositionedContext",{enumerable:!0,get:function(){return FloatingPositionedContext}});const FloatingPositionedContext=(0,require("react").createContext)(!0);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type { AriaAttributes, MutableRefObject, ReactElement } from "react";
|
|
2
|
-
import React from "react";
|
|
3
1
|
import type { Property } from "csstype";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import type { AriaAttributes, MutableRefObject, ReactElement } from "react";
|
|
4
4
|
import type { SubThemeTypes } from "../../web-tokens/_subThemeType";
|
|
5
5
|
import { type PortalProps } from "../Portal/Portal";
|
|
6
|
+
export type TooltipPlacement = "auto" | "top" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
7
|
+
export type TooltipVerticalPlacement = "top" | "bottom";
|
|
6
8
|
export type TooltipPrivateProps = {
|
|
7
9
|
/**
|
|
8
10
|
* @internal
|
|
@@ -29,7 +31,7 @@ export type TooltipPrivateProps = {
|
|
|
29
31
|
export type TooltipContentProps = {
|
|
30
32
|
content: ReactElement;
|
|
31
33
|
triggerRef: MutableRefObject<any>;
|
|
32
|
-
placement?:
|
|
34
|
+
placement?: TooltipPlacement;
|
|
33
35
|
dataE2eTestId?: string;
|
|
34
36
|
dataDSId: string;
|
|
35
37
|
isVisible?: boolean;
|
|
@@ -39,7 +41,7 @@ export type TooltipContentProps = {
|
|
|
39
41
|
contentPadding?: "s" | "m";
|
|
40
42
|
subTheme?: SubThemeTypes;
|
|
41
43
|
maxWidth?: Property.MaxWidth | number;
|
|
42
|
-
defaultVerticalPlacement?:
|
|
44
|
+
defaultVerticalPlacement?: TooltipVerticalPlacement;
|
|
43
45
|
hideArrow?: boolean;
|
|
44
46
|
/** Sets css visibility hidden when trigger is scrolled out of view */
|
|
45
47
|
isHiddenOnInvisibleTrigger?: boolean;
|
|
@@ -49,12 +51,5 @@ export type TooltipContentProps = {
|
|
|
49
51
|
onOverflowViewport?: (triggerRect: DOMRect, tooltipRect: DOMRect, viewportHeight: number) => void;
|
|
50
52
|
privateProps?: TooltipPrivateProps;
|
|
51
53
|
} & Pick<PortalProps, "portalContainer"> & AriaAttributes;
|
|
52
|
-
export type TooltipStyle = {
|
|
53
|
-
top: number;
|
|
54
|
-
left: number;
|
|
55
|
-
horizontalPlacement: "left" | "right" | "center";
|
|
56
|
-
verticalPlacement: "top" | "bottom";
|
|
57
|
-
isSidePlacement?: boolean;
|
|
58
|
-
};
|
|
59
54
|
/** This component is used to display the overlay for both Toggletip and Tooltip components */
|
|
60
55
|
export declare function TooltipContent({ placement, content, tooltipId, triggerRef, portalContainer, dataE2eTestId, dataDSId, isVisible, "aria-hidden": ariaHidden, role, tabIndex, contentPadding, maxWidth, subTheme, defaultVerticalPlacement, hideArrow, isHiddenOnInvisibleTrigger, onTooltipPointerEnter, onTooltipPointerLeave, onOverflowViewport, privateProps, ...ariaAttributes }: TooltipContentProps): React.ReactElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"TooltipContent",{enumerable:!0,get:function(){return TooltipContent}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"TooltipContent",{enumerable:!0,get:function(){return TooltipContent}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_interop_require_wildcard=require("@swc/helpers/_/_interop_require_wildcard"),_react=require("@emotion/react"),_styled=/*#__PURE__*/_interop_require_default._(require("@emotion/styled")),_react1=/*#__PURE__*/_interop_require_wildcard._(require("react")),_Portal=require("../Portal/Portal"),_SubThemeProvider=require("../SubThemeProvider/SubThemeProvider"),_useFloatingPosition=require("../Utilities/FloatingPosition/useFloatingPosition"),_FloatingPositionedContext=require("./FloatingPositionedContext"),_utils=require("./utils"),StyledContainer=(0,_styled.default)("div",{target:"e1l7l62c0",label:"StyledContainer"})(({theme,side,maxWidth,contentPadding,subTheme,isHidden,isSidePlacement})=>{let zIndex=(0,_Portal.usePortalChildZIndex)(theme.variables.zIndex.tooltip),animationDistance="top"===side?`${-_utils.ANIMATION_DISTANCE}px`:`${_utils.ANIMATION_DISTANCE}px`,animation=(0,_react.keyframes)({from:{opacity:theme.variables.opacity.hidden,...!isSidePlacement&&{transform:`translateY(${animationDistance})`}},to:{opacity:theme.variables.opacity.visible,...!isSidePlacement&&{transform:"translateY(0)"}}}),contentPaddingMap={s:theme.variables.size.spacing.xxs,m:theme.variables.size.spacing.s},invertedSubThemeStyles={padding:`${theme.variables.size.spacing.xs} ${theme.variables.size.spacing.s}`,...contentPadding&&{padding:contentPaddingMap[contentPadding]}};return{zIndex,opacity:theme.variables.opacity.hidden,animation:`200ms ease-out forwards ${animation}`,maxWidth,width:"max-content",boxSizing:"border-box",backgroundColor:subTheme?theme.values.color.background.primary.default:theme.values.color.background.elevated.default,borderRadius:subTheme?theme.variables.size.borderRadius.xs:theme.variables.size.borderRadius.s,...isHidden&&{visibility:"hidden"},...!!subTheme&&invertedSubThemeStyles,...!subTheme&&{":after":{content:'" "',position:"absolute",top:0,left:0,width:"100%",height:"100%",pointerEvents:"none",borderRadius:"inherit",boxShadow:theme.values.elevation[3]}}}}),StyledArrow=(0,_styled.default)("div",{target:"e1l7l62c1",label:"StyledArrow"})(({theme,subTheme,side,size=_utils.ARROW_SIZE,arrowOffsetLeft})=>{let adjustmentForShadow=+!subTheme,arrowContainerHeight=size+_utils.DISTANCE_FROM_TRIGGER,arrowSideLength=Math.sqrt(size**2+(size+adjustmentForShadow)**2);return{position:"absolute",left:arrowOffsetLeft,width:40,height:arrowContainerHeight,zIndex:1,overflow:"hidden",..."top"===side&&{top:`calc(100% - ${adjustmentForShadow}px)`},..."bottom"===side&&{top:`-${arrowContainerHeight-adjustmentForShadow}px`},"&::after":{content:'" "',position:"absolute",top:"top"===side?0:"100%",left:"50%",width:arrowSideLength,height:arrowSideLength,backgroundColor:subTheme?theme.values.color.background.primary.default:theme.values.color.background.elevated.default,transform:"translate(-50%, -50%) rotate(45deg)",...!subTheme&&{boxShadow:theme.values.elevation[3]}}}});let lastTooltipHideTimestamp=0;function TooltipContent({placement="auto",content,tooltipId,triggerRef,portalContainer,dataE2eTestId,dataDSId,isVisible,"aria-hidden":ariaHidden,role,tabIndex,contentPadding,maxWidth=224,subTheme,defaultVerticalPlacement,hideArrow=!1,isHiddenOnInvisibleTrigger=!1,onTooltipPointerEnter,onTooltipPointerLeave,onOverflowViewport,privateProps,...ariaAttributes}){let animationDuration,[isHidden,setIsHidden]=(0,_react1.useState)(!1),arrowRef=(0,_react1.useRef)(null),isOverflowCallbackCalledRef=(0,_react1.useRef)(!1),{placement:sidePlacement,offset:sideOffset=_utils.sidePlacementOffset,maxWidth:privateMaxWidth}=privateProps??{},arrowSize=(0,_react1.useMemo)(()=>hideArrow?0:subTheme?_utils.ARROW_SIZE:_utils.ARROW_SIZE_BIG,[subTheme,hideArrow]),handleViewportOverflow=(0,_react1.useCallback)((triggerRect,tooltipRect,viewportHeight)=>{isOverflowCallbackCalledRef.current||(onOverflowViewport?.(triggerRect,tooltipRect,viewportHeight),isOverflowCallbackCalledRef.current=!0)},[onOverflowViewport,isOverflowCallbackCalledRef]),overflowMiddleware=(0,_react1.useMemo)(()=>"auto"===placement?[(0,_utils.createOverflowViewportReporter)(handleViewportOverflow)]:void 0,[placement,handleViewportOverflow]),{placement:preferredPlacement,fallbackPlacements}=(0,_react1.useMemo)(()=>(0,_utils.toFloatingPlacement)({placement,defaultVerticalPlacement,sidePlacement}),[placement,defaultVerticalPlacement,sidePlacement]),offset=(0,_react1.useMemo)(()=>(0,_utils.getTooltipOffsetOptions)({arrowSize,sideOffset}),[arrowSize,sideOffset]),anchorRef=(0,_react1.useRef)(null),anchorSourceRef=(0,_react1.useRef)(null);anchorSourceRef.current!==triggerRef.current&&(anchorSourceRef.current=triggerRef.current,anchorRef.current=(0,_utils.toFloatingAnchor)(triggerRef.current));let{setFloating,floatingStyles,placement:resolvedPlacement,isPositioned,middlewareData}=(0,_useFloatingPosition.useFloatingPosition)({anchorRef,placement:preferredPlacement,offset,flip:{fallbackPlacements},arrowRef:hideArrow?void 0:arrowRef,disableTransform:!0,trackAnimationFrame:!0,isOpen:!!isVisible,extraMiddleware:overflowMiddleware});if((0,_react1.useEffect)(()=>{isVisible||(lastTooltipHideTimestamp=Date.now())},[isVisible]),(0,_react1.useEffect)(()=>{isOverflowCallbackCalledRef.current=!1},[isVisible,isOverflowCallbackCalledRef]),(0,_react1.useEffect)(()=>{let observer;return isHiddenOnInvisibleTrigger&&triggerRef.current&&isVisible&&"undefined"!=typeof IntersectionObserver&&(observer=new IntersectionObserver(entries=>entries.forEach(entry=>{let rect=entry.boundingClientRect;(rect?.width!==0||rect?.height!==0)&&setIsHidden(!entry.isIntersecting)}),{root:null,threshold:.99})).observe(triggerRef.current),()=>{observer&&observer.disconnect()}},[triggerRef,isVisible,isHiddenOnInvisibleTrigger]),!isVisible)return null;let side=(0,_utils.getPlacementSide)(resolvedPlacement),isSidePlacement=side===_utils.SIDE_PLACEMENT_SIDE,tooltipElm=_react1.default.createElement(StyledContainer,{"data-e2e-test-id":dataE2eTestId,"data-ds-id":dataDSId,"data-placement":resolvedPlacement,style:{...floatingStyles,animationDuration:(animationDuration="200ms",lastTooltipHideTimestamp&&Date.now()-lastTooltipHideTimestamp<700&&(animationDuration="0ms"),animationDuration)},ref:setFloating,id:tooltipId,role:role,...ariaAttributes,"aria-hidden":ariaHidden,subTheme:subTheme,tabIndex:tabIndex,side:side,maxWidth:privateMaxWidth??maxWidth,contentPadding:contentPadding,isHidden:isHidden||!isPositioned,isSidePlacement:isSidePlacement,onPointerEnter:onTooltipPointerEnter,onPointerLeave:onTooltipPointerLeave},_react1.default.createElement(_FloatingPositionedContext.FloatingPositionedContext.Provider,{value:isPositioned},content),!hideArrow&&side!==_utils.SIDE_PLACEMENT_SIDE&&_react1.default.createElement(StyledArrow,{ref:arrowRef,"data-e2e-test-id":`${dataE2eTestId}_arrow`,subTheme:subTheme,side:side,size:arrowSize,arrowOffsetLeft:middlewareData.arrow?.x})),wrapperElm=subTheme?_react1.default.createElement(_SubThemeProvider.SubThemeProvider,{name:subTheme},tooltipElm):tooltipElm;return _react1.default.createElement(_Portal.Portal,{portalContainer:portalContainer},wrapperElm)}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import type { OffsetOptions } from "@floating-ui/react-dom";
|
|
2
|
+
import type { Middleware, Placement, VirtualElement } from "../Utilities/FloatingPosition/useFloatingPosition";
|
|
3
|
+
import type { TooltipContentProps, TooltipPlacement, TooltipPrivateProps, TooltipVerticalPlacement } from "./TooltipContent";
|
|
4
4
|
export declare const DISTANCE_FROM_TRIGGER = 4;
|
|
5
5
|
export declare const ANIMATION_DISTANCE = 8;
|
|
6
6
|
export declare const ARROW_SIZE = 6;
|
|
@@ -8,21 +8,65 @@ export declare const ARROW_SIZE_BIG = 8;
|
|
|
8
8
|
/** TODO: remove temporary side placement. Matches the gap top/bottom tooltips settle at. */
|
|
9
9
|
export declare const sidePlacementOffset: number;
|
|
10
10
|
export declare const getArrowOffset: (size: number) => number;
|
|
11
|
-
type
|
|
12
|
-
placement:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
/** TODO: remove temporary side placement, both fields */
|
|
11
|
+
export type FloatingPlacementConfig = {
|
|
12
|
+
placement: Placement;
|
|
13
|
+
/** The placements `flip` may fall back to, in order of preference. */
|
|
14
|
+
fallbackPlacements: Placement[];
|
|
15
|
+
};
|
|
16
|
+
type ToFloatingPlacementParams = {
|
|
17
|
+
placement: TooltipPlacement | undefined;
|
|
18
|
+
defaultVerticalPlacement: TooltipVerticalPlacement | undefined;
|
|
19
|
+
/** TODO: remove temporary side placement */
|
|
21
20
|
sidePlacement?: TooltipPrivateProps["placement"];
|
|
22
|
-
sideOffset?: number;
|
|
23
21
|
};
|
|
24
22
|
/**
|
|
25
|
-
*
|
|
23
|
+
* Resolves the DS placement to the preferred floating-ui placement plus its
|
|
24
|
+
* flip fallbacks. Tooltips only ever move between the top and bottom side; an
|
|
25
|
+
* explicit placement may only flip to the opposite side with the same
|
|
26
|
+
* alignment, while automatic placement may also switch alignment.
|
|
27
|
+
*
|
|
28
|
+
* A side placement takes precedence and falls back to whatever the DS
|
|
29
|
+
* placement resolved to, so it lands beside the trigger when there is room and
|
|
30
|
+
* behaves like an ordinary tooltip when there is not.
|
|
31
|
+
*/
|
|
32
|
+
export declare const toFloatingPlacement: ({ placement, defaultVerticalPlacement, sidePlacement, }: ToFloatingPlacementParams) => FloatingPlacementConfig;
|
|
33
|
+
/**
|
|
34
|
+
* The side of the trigger the resolved floating-ui placement puts the tooltip
|
|
35
|
+
* on. `"right"` only ever comes from the temporary side placement.
|
|
36
|
+
* TODO: drop `"right"` with the temporary side placement
|
|
37
|
+
*/
|
|
38
|
+
export type TooltipPlacementSide = TooltipVerticalPlacement | "right";
|
|
39
|
+
/** TODO: remove temporary side placement */
|
|
40
|
+
export declare const SIDE_PLACEMENT_SIDE: "right";
|
|
41
|
+
/** The side of the trigger the resolved floating-ui placement puts the tooltip on. */
|
|
42
|
+
export declare const getPlacementSide: (placement: Placement) => TooltipPlacementSide;
|
|
43
|
+
type TooltipOffsetParams = {
|
|
44
|
+
arrowSize: number;
|
|
45
|
+
/**
|
|
46
|
+
* Gap between trigger and a side-placed tooltip.
|
|
47
|
+
* TODO: remove temporary side placement
|
|
48
|
+
*/
|
|
49
|
+
sideOffset: number;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Distance between trigger and tooltip, plus — for aligned placements — the
|
|
53
|
+
* offset that anchors the tooltip's near edge to the trigger center instead of
|
|
54
|
+
* floating-ui's default trigger-edge alignment, keeping the arrow (which sits
|
|
55
|
+
* `getArrowOffset` + arrow size from the tooltip edge) pointed at the trigger
|
|
56
|
+
* center. With no arrow the tooltip stays edge-aligned, as before.
|
|
57
|
+
*/
|
|
58
|
+
export declare const getTooltipOffsetOptions: ({ arrowSize, sideOffset }: TooltipOffsetParams) => OffsetOptions;
|
|
59
|
+
type OnOverflowViewport = NonNullable<TooltipContentProps["onOverflowViewport"]>;
|
|
60
|
+
/**
|
|
61
|
+
* Reproduces the legacy `onOverflowViewport` contract: reports when the
|
|
62
|
+
* tooltip fits neither fully above nor fully below the trigger.
|
|
63
|
+
*/
|
|
64
|
+
export declare const createOverflowViewportReporter: (onOverflowViewport: OnOverflowViewport) => Middleware;
|
|
65
|
+
/**
|
|
66
|
+
* Normalizes what consumers put into `triggerRef` — a DOM element, or a
|
|
67
|
+
* `Range` (RangePopover, UserHighlightTooltip) — into a floating-ui anchor.
|
|
68
|
+
* A `Range` is wrapped as a virtual element with a `contextElement` so
|
|
69
|
+
* `autoUpdate` can attach scroll listeners to the right ancestors.
|
|
26
70
|
*/
|
|
27
|
-
export declare
|
|
71
|
+
export declare const toFloatingAnchor: (trigger: unknown) => Element | VirtualElement | null;
|
|
28
72
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var target=exports,all={get ANIMATION_DISTANCE(){return ANIMATION_DISTANCE},get ARROW_SIZE(){return ARROW_SIZE},get ARROW_SIZE_BIG(){return ARROW_SIZE_BIG},get DISTANCE_FROM_TRIGGER(){return DISTANCE_FROM_TRIGGER},get getArrowOffset(){return getArrowOffset},get
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var target=exports,all={get ANIMATION_DISTANCE(){return ANIMATION_DISTANCE},get ARROW_SIZE(){return ARROW_SIZE},get ARROW_SIZE_BIG(){return ARROW_SIZE_BIG},get DISTANCE_FROM_TRIGGER(){return DISTANCE_FROM_TRIGGER},get SIDE_PLACEMENT_SIDE(){return SIDE_PLACEMENT_SIDE},get createOverflowViewportReporter(){return createOverflowViewportReporter},get getArrowOffset(){return getArrowOffset},get getPlacementSide(){return getPlacementSide},get getTooltipOffsetOptions(){return getTooltipOffsetOptions},get sidePlacementOffset(){return sidePlacementOffset},get toFloatingAnchor(){return toFloatingAnchor},get toFloatingPlacement(){return toFloatingPlacement}};for(var name in all)Object.defineProperty(target,name,{enumerable:!0,get:Object.getOwnPropertyDescriptor(all,name).get});const DISTANCE_FROM_TRIGGER=4,ANIMATION_DISTANCE=8,ARROW_SIZE=6,ARROW_SIZE_BIG=8,sidePlacementOffset=10,getArrowOffset=size=>2*size,START_SUFFIX="-start",END_SUFFIX="-end",SIDE_PLACEMENT="right-start",DS_TO_FLOATING_PLACEMENT={top:"top",bottom:"bottom","top-left":`top${END_SUFFIX}`,"top-right":`top${START_SUFFIX}`,"bottom-left":`bottom${END_SUFFIX}`,"bottom-right":`bottom${START_SUFFIX}`},OPPOSITE_SIDE={top:"bottom",bottom:"top"},sideWithAlignments=side=>[side,`${side}${START_SUFFIX}`,`${side}${END_SUFFIX}`],toFloatingPlacement=({placement,defaultVerticalPlacement,sidePlacement})=>{let isAutomatic=!placement||"auto"===placement,preferred=isAutomatic?defaultVerticalPlacement??"top":DS_TO_FLOATING_PLACEMENT[placement],[side,alignment]=preferred.split("-"),oppositeSide=OPPOSITE_SIDE[side],resolved=isAutomatic?{placement:preferred,fallbackPlacements:[...sideWithAlignments(side).slice(1),...sideWithAlignments(oppositeSide)]}:{placement:preferred,fallbackPlacements:[alignment?`${oppositeSide}-${alignment}`:oppositeSide]};return"right-top"===sidePlacement?{placement:SIDE_PLACEMENT,fallbackPlacements:[resolved.placement,...resolved.fallbackPlacements]}:resolved},SIDE_PLACEMENT_SIDE="right",getPlacementSide=placement=>placement.split("-")[0],getTooltipOffsetOptions=({arrowSize,sideOffset})=>({rects,placement})=>{if(placement===SIDE_PLACEMENT)return{mainAxis:sideOffset};let mainAxis=arrowSize+DISTANCE_FROM_TRIGGER;return(placement.endsWith(START_SUFFIX)||placement.endsWith(END_SUFFIX))&&0!==arrowSize?{mainAxis,alignmentAxis:rects.reference.width/2-getArrowOffset(arrowSize)-arrowSize}:{mainAxis}},createOverflowViewportReporter=onOverflowViewport=>({name:"reportOverflowViewport",fn({elements}){let triggerRect=elements.reference.getBoundingClientRect(),tooltipRect=elements.floating.getBoundingClientRect(),viewportHeight=elements.floating.ownerDocument.documentElement.clientHeight,canPlaceAboveTrigger=triggerRect.top>=tooltipRect.height,canPlaceBelowTrigger=triggerRect.bottom+tooltipRect.height<viewportHeight;return canPlaceAboveTrigger||canPlaceBelowTrigger||onOverflowViewport(triggerRect,tooltipRect,viewportHeight),{}}}),toFloatingAnchor=trigger=>{if(!trigger)return null;if("undefined"!=typeof Range&&trigger instanceof Range){let container=trigger.commonAncestorContainer;return{getBoundingClientRect:()=>trigger.getBoundingClientRect(),getClientRects:()=>trigger.getClientRects(),contextElement:container instanceof Element?container:container.parentElement??void 0}}return trigger};
|
|
@@ -1,20 +1,53 @@
|
|
|
1
1
|
import type { CSSProperties, RefObject } from "react";
|
|
2
|
-
import type { OffsetOptions, Placement, Strategy } from "@floating-ui/react-dom";
|
|
2
|
+
import type { Middleware, MiddlewareData, OffsetOptions, Placement, Strategy, VirtualElement } from "@floating-ui/react-dom";
|
|
3
3
|
export type { ViewportPlacement } from "./utils";
|
|
4
|
-
export type { Placement } from "@floating-ui/react-dom";
|
|
4
|
+
export type { Middleware, MiddlewareData, Placement, VirtualElement, } from "@floating-ui/react-dom";
|
|
5
|
+
export type FlipOptions = {
|
|
6
|
+
/** Restrict which placements `flip` may fall back to. */
|
|
7
|
+
fallbackPlacements?: Placement[];
|
|
8
|
+
};
|
|
5
9
|
/** Position relative to an anchor element. */
|
|
6
10
|
type AnchorModeProps = {
|
|
7
11
|
mode?: "anchor";
|
|
8
|
-
/**
|
|
9
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The element to position the floating element against. Also accepts a
|
|
14
|
+
* virtual element (anything with `getBoundingClientRect`, e.g. a `Range`
|
|
15
|
+
* wrapper) — set its `contextElement` so scroll/resize tracking works.
|
|
16
|
+
*/
|
|
17
|
+
anchorRef: RefObject<Element | VirtualElement | null>;
|
|
10
18
|
/** Side (and optional alignment) to place the element on. Default `"bottom"`. */
|
|
11
19
|
placement?: Placement;
|
|
12
20
|
/** Gap between the anchor and the floating element. Default `0`. */
|
|
13
21
|
offset?: OffsetOptions;
|
|
14
|
-
/**
|
|
15
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Flip to the opposite side when it would overflow. Default `true`.
|
|
24
|
+
* Pass an options object to restrict the fallback placements.
|
|
25
|
+
*/
|
|
26
|
+
flip?: boolean | FlipOptions;
|
|
16
27
|
/** Slide along the axis to stay in view near edges. Default `true`. */
|
|
17
28
|
shift?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Arrow element to keep pointed at the anchor; its offset along the
|
|
31
|
+
* floating element is returned in `middlewareData.arrow`.
|
|
32
|
+
*/
|
|
33
|
+
arrowRef?: RefObject<HTMLElement | null>;
|
|
34
|
+
/** Minimum distance the arrow keeps from the floating element's corners. Default `0`. */
|
|
35
|
+
arrowPadding?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Emit `top`/`left` instead of a `transform` in `floatingStyles`, freeing
|
|
38
|
+
* `transform` for the caller's own animations. Default `false` (transform).
|
|
39
|
+
*/
|
|
40
|
+
disableTransform?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Reposition every animation frame while open — needed when the anchor moves
|
|
43
|
+
* without scroll/resize events (CSS transforms, canvas pan). Default `false`.
|
|
44
|
+
*/
|
|
45
|
+
trackAnimationFrame?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Extra floating-ui middleware, run after the built-ins (before `arrow`).
|
|
48
|
+
* Keep the array referentially stable (module-level or memoized).
|
|
49
|
+
*/
|
|
50
|
+
extraMiddleware?: Middleware[];
|
|
18
51
|
};
|
|
19
52
|
/**
|
|
20
53
|
* The viewport spot to pin to, expressed as separate axes. At least one axis is
|
|
@@ -54,6 +87,8 @@ export type UseFloatingPositionReturn = {
|
|
|
54
87
|
strategy: Strategy;
|
|
55
88
|
/** `false` until the element has been measured — gate visibility on this to avoid a flash. */
|
|
56
89
|
isPositioned: boolean;
|
|
90
|
+
/** Per-middleware positioning data, e.g. `middlewareData.arrow` for the arrow offset. */
|
|
91
|
+
middlewareData: MiddlewareData;
|
|
57
92
|
/** Imperatively recompute the position. */
|
|
58
93
|
update: () => void;
|
|
59
94
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"useFloatingPosition",{enumerable:!0,get:function(){return useFloatingPosition}});const _react=require("react"),_reactdom=require("@floating-ui/react-dom"),_useWindow=require("../../../shared/useWindow"),_useDocument=require("../../../shared/useDocument"),_utils=require("./utils");function useFloatingPosition(props){let{isOpen=!0}=props,isViewportMode="viewport"===props.mode,window=(0,_useWindow.useWindow)(),document=(0,_useDocument.useDocument)(),{anchorPlacement,viewportPlacement,anchorOffset,viewportOffset,flipEnabled,shiftEnabled,anchorRef}="viewport"===props.mode?{anchorPlacement:void 0,viewportPlacement:(0,_utils.axesToViewportPlacement)(props.positionY,props.positionX),anchorOffset:0,viewportOffset:props.offset??0,flipEnabled:!1,shiftEnabled:!1,anchorRef:null}:{anchorPlacement:props.placement??"bottom",viewportPlacement:void 0,anchorOffset:props.offset??0,viewportOffset:0,flipEnabled:!1!==props.flip,shiftEnabled:!1!==props.shift,anchorRef:props.anchorRef??null},middleware=(0,_react.useMemo)(()=>isViewportMode?[]:[(0,_reactdom.offset)(anchorOffset),...flipEnabled?[(0,_reactdom.flip)()]:[],...shiftEnabled?[(0,_reactdom.shift)({padding:8})]:[]],[isViewportMode,anchorOffset,flipEnabled,shiftEnabled]),virtualReference=(0,_react.useMemo)(()=>viewportPlacement?{getBoundingClientRect(){let vw=document&&document.documentElement.clientWidth||window&&window.innerWidth||0,vh=window&&window.innerHeight||document&&document.documentElement.clientHeight||0;return(0,_utils.getViewportReferenceRect)(viewportPlacement,vw,vh,viewportOffset)}}:null,[viewportPlacement,viewportOffset,window,document]),{refs,floatingStyles,placement,strategy,isPositioned,update}=(0,_reactdom.useFloating)({open:isOpen,strategy:isViewportMode?"fixed":"absolute",placement:viewportPlacement?(0,_utils.viewportToFloatingPlacement)(viewportPlacement):anchorPlacement,middleware,
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"useFloatingPosition",{enumerable:!0,get:function(){return useFloatingPosition}});const _react=require("react"),_reactdom=require("@floating-ui/react-dom"),_useWindow=require("../../../shared/useWindow"),_useDocument=require("../../../shared/useDocument"),_utils=require("./utils"),NO_EXTRA_MIDDLEWARE=[];function useFloatingPosition(props){let{isOpen=!0}=props,isViewportMode="viewport"===props.mode,window=(0,_useWindow.useWindow)(),document=(0,_useDocument.useDocument)(),{anchorPlacement,viewportPlacement,anchorOffset,viewportOffset,flipEnabled,flipFallbackPlacements,shiftEnabled,anchorRef,arrowRef,arrowPadding,disableTransform,trackAnimationFrame,extraMiddleware}="viewport"===props.mode?{anchorPlacement:void 0,viewportPlacement:(0,_utils.axesToViewportPlacement)(props.positionY,props.positionX),anchorOffset:0,viewportOffset:props.offset??0,flipEnabled:!1,flipFallbackPlacements:void 0,shiftEnabled:!1,anchorRef:null,arrowRef:null,arrowPadding:0,disableTransform:!1,trackAnimationFrame:!1,extraMiddleware:NO_EXTRA_MIDDLEWARE}:{anchorPlacement:props.placement??"bottom",viewportPlacement:void 0,anchorOffset:props.offset??0,viewportOffset:0,flipEnabled:!1!==props.flip,flipFallbackPlacements:"object"==typeof props.flip?props.flip.fallbackPlacements:void 0,shiftEnabled:!1!==props.shift,anchorRef:props.anchorRef??null,arrowRef:props.arrowRef??null,arrowPadding:props.arrowPadding??0,disableTransform:props.disableTransform??!1,trackAnimationFrame:props.trackAnimationFrame??!1,extraMiddleware:props.extraMiddleware??NO_EXTRA_MIDDLEWARE},middleware=(0,_react.useMemo)(()=>isViewportMode?[]:[(0,_reactdom.offset)(anchorOffset),...flipEnabled?[(0,_reactdom.flip)({fallbackPlacements:flipFallbackPlacements})]:[],...shiftEnabled?[(0,_reactdom.shift)({padding:8})]:[],...extraMiddleware,...arrowRef?[(0,_reactdom.arrow)({element:arrowRef,padding:arrowPadding})]:[]],[isViewportMode,anchorOffset,flipEnabled,flipFallbackPlacements,shiftEnabled,arrowRef,arrowPadding,extraMiddleware]),virtualReference=(0,_react.useMemo)(()=>viewportPlacement?{getBoundingClientRect(){let vw=document&&document.documentElement.clientWidth||window&&window.innerWidth||0,vh=window&&window.innerHeight||document&&document.documentElement.clientHeight||0;return(0,_utils.getViewportReferenceRect)(viewportPlacement,vw,vh,viewportOffset)}}:null,[viewportPlacement,viewportOffset,window,document]),{refs,elements:{reference:referenceElement,floating:floatingElement},floatingStyles,placement,strategy,isPositioned,middlewareData,update}=(0,_reactdom.useFloating)({open:isOpen,strategy:isViewportMode?"fixed":"absolute",transform:!disableTransform,placement:viewportPlacement?(0,_utils.viewportToFloatingPlacement)(viewportPlacement):anchorPlacement,middleware});return(0,_react.useLayoutEffect)(()=>{if(isOpen&&referenceElement&&floatingElement)return(0,_reactdom.autoUpdate)(referenceElement,floatingElement,update,{animationFrame:trackAnimationFrame})},[isOpen,trackAnimationFrame,referenceElement,floatingElement,update]),(0,_react.useLayoutEffect)(()=>{virtualReference?refs.setReference(virtualReference):anchorRef&&refs.setReference(anchorRef.current)}),{setFloating:refs.setFloating,floatingStyles,placement,strategy,isPositioned,middlewareData,update}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"FocusTrapWrapper",{enumerable:!0,get:function(){return FocusTrapWrapper}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_focustrapreact=/*#__PURE__*/_interop_require_default._(require("focus-trap-react")),FocusTrapWrapper=({active,focusTrapOptions,children})=>{let isClickedOutside=(0,_react.useRef)(!1),isEscaped=(0,_react.useRef)(!1),{onPostDeactivate,clickOutsideDeactivates,escapeDeactivates,...rest}=focusTrapOptions,onPostDeactivateRef=(0,_react.useRef)(onPostDeactivate),clickOutsideDeactivatesRef=(0,_react.useRef)(clickOutsideDeactivates),escapeDeactivatesRef=(0,_react.useRef)(escapeDeactivates);return(0,_react.useEffect)(()=>{onPostDeactivateRef.current=onPostDeactivate},[onPostDeactivate]),(0,_react.useEffect)(()=>{clickOutsideDeactivatesRef.current=clickOutsideDeactivates},[clickOutsideDeactivates]),(0,_react.useEffect)(()=>{escapeDeactivatesRef.current=escapeDeactivates},[escapeDeactivates]),_react.default.createElement(_focustrapreact.default,{active:active,focusTrapOptions:{...rest,clickOutsideDeactivates:evt=>{let cb=clickOutsideDeactivatesRef.current,shouldDeactivate="function"==typeof cb?cb(evt):cb;return!1!==shouldDeactivate&&(isClickedOutside.current=!0),shouldDeactivate},escapeDeactivates:evt=>{let cb=escapeDeactivatesRef.current,shouldDeactivate="function"==typeof cb?cb(evt):cb;return!1!==shouldDeactivate&&(isEscaped.current=!0),shouldDeactivate},onPostDeactivate:()=>{(isClickedOutside.current||isEscaped.current)&&onPostDeactivateRef.current?.(),isEscaped.current=!1,isClickedOutside.current=!1}}},children)};
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"FocusTrapWrapper",{enumerable:!0,get:function(){return FocusTrapWrapper}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_focustrapreact=/*#__PURE__*/_interop_require_default._(require("focus-trap-react")),_FloatingPositionedContext=require("../components/Tooltip/FloatingPositionedContext"),FocusTrapWrapper=({active,focusTrapOptions,children})=>{let isClickedOutside=(0,_react.useRef)(!1),isEscaped=(0,_react.useRef)(!1),isPositioned=(0,_react.useContext)(_FloatingPositionedContext.FloatingPositionedContext),{onPostDeactivate,clickOutsideDeactivates,escapeDeactivates,...rest}=focusTrapOptions,onPostDeactivateRef=(0,_react.useRef)(onPostDeactivate),clickOutsideDeactivatesRef=(0,_react.useRef)(clickOutsideDeactivates),escapeDeactivatesRef=(0,_react.useRef)(escapeDeactivates);return(0,_react.useEffect)(()=>{onPostDeactivateRef.current=onPostDeactivate},[onPostDeactivate]),(0,_react.useEffect)(()=>{clickOutsideDeactivatesRef.current=clickOutsideDeactivates},[clickOutsideDeactivates]),(0,_react.useEffect)(()=>{escapeDeactivatesRef.current=escapeDeactivates},[escapeDeactivates]),_react.default.createElement(_focustrapreact.default,{active:active&&isPositioned,focusTrapOptions:{...rest,clickOutsideDeactivates:evt=>{let cb=clickOutsideDeactivatesRef.current,shouldDeactivate="function"==typeof cb?cb(evt):cb;return!1!==shouldDeactivate&&(isClickedOutside.current=!0),shouldDeactivate},escapeDeactivates:evt=>{let cb=escapeDeactivatesRef.current,shouldDeactivate="function"==typeof cb?cb(evt):cb;return!1!==shouldDeactivate&&(isEscaped.current=!0),shouldDeactivate},onPostDeactivate:()=>{(isClickedOutside.current||isEscaped.current)&&onPostDeactivateRef.current?.(),isEscaped.current=!1,isClickedOutside.current=!1}}},children)};
|
|
@@ -10,6 +10,11 @@ export type RangePopoverProps = {
|
|
|
10
10
|
isVisible: boolean;
|
|
11
11
|
/** Called when the popover is dismissed by an outside click or the Escape key. */
|
|
12
12
|
onClose: () => void;
|
|
13
|
+
/**
|
|
14
|
+
* Controls whether the popover closes on an outside click. When false, only
|
|
15
|
+
* the Escape key dismisses it.
|
|
16
|
+
*/
|
|
17
|
+
dismissOnOutsideClick?: boolean;
|
|
13
18
|
/** Preferred placement relative to the range. */
|
|
14
19
|
placement?: RangePopoverPlacement;
|
|
15
20
|
/** Portal target; falls back to the document body when omitted. */
|
|
@@ -40,17 +45,18 @@ export type RangePopoverProps = {
|
|
|
40
45
|
* A click-dismissed popover anchored on a DOM {@link Range} rather than a
|
|
41
46
|
* trigger element.
|
|
42
47
|
*
|
|
43
|
-
* It pairs the design-system tooltip positioner — which
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
48
|
+
* It pairs the design-system tooltip positioner — which accepts a `Range` in
|
|
49
|
+
* `triggerRef` and anchors on it as a floating-ui virtual element — with the
|
|
50
|
+
* focus-trap dismissal model used by the design-system Popover. This lets it
|
|
51
|
+
* anchor on a painted text selection that has no DOM node of its own, the same
|
|
52
|
+
* way `UserHighlightTooltip` does, while opening and closing on explicit
|
|
53
|
+
* interaction instead of hover.
|
|
49
54
|
*
|
|
50
55
|
* @param content - The popover body.
|
|
51
56
|
* @param range - The range to anchor on.
|
|
52
57
|
* @param isVisible - Whether the popover is shown.
|
|
53
58
|
* @param onClose - Called when dismissed by an outside click or the Escape key.
|
|
59
|
+
* @param dismissOnOutsideClick - Whether an outside click dismisses the popover.
|
|
54
60
|
* @param placement - Preferred placement relative to the range.
|
|
55
61
|
* @param portalContainer - Portal target; falls back to the document body.
|
|
56
62
|
* @param contentPadding - Inner padding of the popover surface.
|
|
@@ -60,5 +66,5 @@ export type RangePopoverProps = {
|
|
|
60
66
|
* @param aria-label - Accessible name for the popover surface.
|
|
61
67
|
* @param disableInitialFocus - When true, does not move focus into the popover.
|
|
62
68
|
*/
|
|
63
|
-
export declare function RangePopover({ content, range, isVisible, onClose, placement, portalContainer, contentPadding, maxWidth, hideArrow, role, "aria-label": ariaLabel, disableInitialFocus, "data-e2e-test-id": dataE2eTestId, }: RangePopoverProps): React.ReactElement;
|
|
69
|
+
export declare function RangePopover({ content, range, isVisible, onClose, dismissOnOutsideClick, placement, portalContainer, contentPadding, maxWidth, hideArrow, role, "aria-label": ariaLabel, disableInitialFocus, "data-e2e-test-id": dataE2eTestId, }: RangePopoverProps): React.ReactElement;
|
|
64
70
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import React,{useId,useRef}from"react";import styled from"@emotion/styled";import{TooltipContent}from"../Tooltip/TooltipContent";import{FocusTrapWrapper}from"../../shared/FocusTrapWrapper";let StyledContent=styled("div",{target:"
|
|
1
|
+
import React,{useId,useRef}from"react";import styled from"@emotion/styled";import{TooltipContent}from"../Tooltip/TooltipContent";import{FocusTrapWrapper}from"../../shared/FocusTrapWrapper";let StyledContent=styled("div",{target:"e1cdfvza0",label:"StyledContent"})(({theme,contentPadding})=>({padding:"m"===contentPadding?theme.variables.size.spacing.s:theme.variables.size.spacing.xxs}));export function RangePopover({content,range,isVisible,onClose,dismissOnOutsideClick=!0,placement="top",portalContainer,contentPadding="s",maxWidth,hideArrow=!1,role="dialog","aria-label":ariaLabel,disableInitialFocus=!1,"data-e2e-test-id":dataE2eTestId}){let tooltipId=useId(),rangeRef=useRef(null);rangeRef.current=range;let contentRef=useRef(null),trappedContent=React.createElement(FocusTrapWrapper,{active:isVisible,focusTrapOptions:{allowOutsideClick:!0,clickOutsideDeactivates:dismissOnOutsideClick,escapeDeactivates:!0,fallbackFocus:()=>contentRef.current,initialFocus:!disableInitialFocus&&void 0,onPostDeactivate:onClose,preventScroll:!0,returnFocusOnDeactivate:!disableInitialFocus}},React.createElement(StyledContent,{ref:contentRef,tabIndex:-1,contentPadding:contentPadding},content));return React.createElement(TooltipContent,{"aria-label":ariaLabel,content:trappedContent,dataDSId:"RangePopover",dataE2eTestId:dataE2eTestId,hideArrow:hideArrow,isVisible:isVisible,maxWidth:maxWidth,placement:placement,portalContainer:portalContainer,role:role,tooltipId:tooltipId,triggerRef:rangeRef})}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ReactElement } from "react";
|
|
2
2
|
import React from "react";
|
|
3
|
+
import type { PopupRole } from "../Sheet/Sheet";
|
|
3
4
|
import type { TooltipContentProps } from "../Tooltip/TooltipContent";
|
|
4
5
|
import type { TooltipConditionalProps } from "../Tooltip/types";
|
|
5
|
-
import type { PopupRole } from "../Sheet/Sheet";
|
|
6
6
|
type BaseProps = Pick<TooltipContentProps, "placement" | "portalContainer" | "maxWidth" | "contentPadding" | "hideArrow" | "subTheme" | "defaultVerticalPlacement" | "onOverflowViewport"> & {
|
|
7
7
|
name?: string;
|
|
8
8
|
/** Popover content */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import React,{
|
|
1
|
+
import styled from"@emotion/styled";import React,{useCallback,useEffect,useLayoutEffect,useMemo,useRef,useState}from"react";import{getAriaAttributes}from"../../shared/ariaAttributes";import{FocusTrapWrapper}from"../../shared/FocusTrapWrapper";import{useWindow}from"../../shared/useWindow";import breakpoints from"../../web-tokens/_breakpoints.json";import{PopoverContext}from"../Patterns/Popover/PopoverContext";import{Sheet}from"../Sheet/Sheet";import{TooltipContent}from"../Tooltip/TooltipContent";let StyledContainer=styled("div",{target:"e2uwtlo0",label:"StyledContainer"})(()=>({borderRadius:"inherit"})),FocusTrapContent=React.forwardRef(({children},ref)=>React.createElement(StyledContainer,{ref:ref},children)),VisibilityChangeReason={triggerClick:"triggerClick",outsideClick:"outsideClick"};function getAriaPopupType(role){let popupType=String(role);return(role||(popupType="true"),"alertdialog"===role)?"dialog":popupType}function getMobileBreakpoint(renderAsSheetOnMobile,win){if(!win)return!1;let isMobileInPortrait=win.innerWidth<=breakpoints.m.value,isSmallHeight=win.innerHeight<=450,isLandscape=win.matchMedia?.("(orientation: landscape)").matches;return renderAsSheetOnMobile&&(isMobileInPortrait||isLandscape&&isSmallHeight)}export function BasePopover({placement="auto",content,children,contentPadding="m",maxWidth,externalTriggerRef,portalContainer,name="Popover",isVisible:isPopoverVisible,dismissOnOutsideClick=!0,retainOnOutsideClick,"data-e2e-test-id":dataE2eTestId,subTheme,defaultVerticalPlacement,onVisibilityChange,disableInitialFocus=!1,disableReturnFocusToTrigger=!1,renderAsSheetOnMobile=!1,forceSheetLayout=!1,role,sheetProps,...restContentProps}){let win=useWindow(),tooltipId=useMemo(()=>`DS${name}_${Math.floor(Date.now()*Math.random())}`,[name]),[isVisible,setVisible]=useState(isPopoverVisible),[isMobileBreakPoint,setIsMobileBreakpoint]=useState(()=>forceSheetLayout||getMobileBreakpoint(renderAsSheetOnMobile,win)),internalTriggerRef=useRef(null),triggerRef=externalTriggerRef||internalTriggerRef,isOutsideClickOnTrigger=useRef(!1),ariaAttributes=getAriaAttributes(restContentProps),popoverContextValue=useMemo(()=>({isWithinPopover:!0,portalContainer}),[portalContainer]),contentWithProvider=React.createElement(PopoverContext.Provider,{value:popoverContextValue},content),toggleVisibility=useCallback((status,reason)=>{setVisible(status),onVisibilityChange&&onVisibilityChange(status,reason)},[onVisibilityChange]),handleTriggerClick=useCallback(()=>{isOutsideClickOnTrigger.current?isOutsideClickOnTrigger.current=!1:toggleVisibility(!isVisible,VisibilityChangeReason.triggerClick)},[toggleVisibility,isVisible]),handleClickOutsideDeactivates=useCallback(evt=>!retainOnOutsideClick?.(evt)&&(triggerRef.current&&triggerRef.current.contains(evt.target)&&(isOutsideClickOnTrigger.current=!0),!0),[triggerRef,isOutsideClickOnTrigger,retainOnOutsideClick]),handlePostDeactivate=useCallback(()=>{toggleVisibility(!1,isOutsideClickOnTrigger.current?VisibilityChangeReason.triggerClick:VisibilityChangeReason.outsideClick)},[toggleVisibility]);useEffect(()=>{setVisible(isPopoverVisible)},[isPopoverVisible]),useLayoutEffect(()=>{setIsMobileBreakpoint(forceSheetLayout||getMobileBreakpoint(renderAsSheetOnMobile,win))},[win,isVisible,renderAsSheetOnMobile,forceSheetLayout]),useEffect(()=>{let trigger=triggerRef.current;if(trigger)return trigger.addEventListener("click",handleTriggerClick),()=>{trigger.removeEventListener("click",handleTriggerClick)}},[handleTriggerClick,triggerRef]),useEffect(()=>{if(externalTriggerRef?.current&&!children){let trigger=externalTriggerRef.current,triggerTabIndex=trigger.getAttribute("tabindex");trigger.setAttribute("tabindex",triggerTabIndex??"0")}},[externalTriggerRef,children]),useEffect(()=>{if(externalTriggerRef?.current&&!children){let trigger=externalTriggerRef.current;trigger.setAttribute("aria-haspopup",getAriaPopupType(role)),trigger.setAttribute("aria-expanded",String(!!isVisible)),isVisible?trigger.setAttribute("aria-controls",tooltipId):trigger.removeAttribute("aria-controls")}},[externalTriggerRef,children,role,tooltipId,isVisible]);let triggerElm=children?React.cloneElement(children,{ref:triggerRef,"aria-expanded":!!isVisible,...isVisible&&{"aria-controls":tooltipId},tabIndex:children.props.tabIndex??0,"aria-haspopup":getAriaPopupType(role)}):null;if(isMobileBreakPoint){let sheetElm=React.createElement(Sheet,{id:tooltipId,isVisible:isVisible,portalContainer:portalContainer,dismissOnOutsideClick:dismissOnOutsideClick,disableInitialFocus:disableInitialFocus,disableReturnFocusToTrigger:disableReturnFocusToTrigger,onClose:handlePostDeactivate,onClickOutsideDeactivates:handleClickOutsideDeactivates,role:role,...sheetProps??{},...ariaAttributes},contentWithProvider);return React.createElement(React.Fragment,null,triggerElm,sheetElm)}let contentElm=React.createElement(FocusTrapWrapper,{active:isVisible,focusTrapOptions:{clickOutsideDeactivates:dismissOnOutsideClick&&handleClickOutsideDeactivates,allowOutsideClick:!0,escapeDeactivates:!0,fallbackFocus:`#${tooltipId}`,onPostDeactivate:handlePostDeactivate,preventScroll:!0,initialFocus:()=>!disableInitialFocus,returnFocusOnDeactivate:!disableReturnFocusToTrigger}},React.createElement(FocusTrapContent,null,contentWithProvider)),tooltipElm=React.createElement(TooltipContent,{...restContentProps,role:role,defaultVerticalPlacement:defaultVerticalPlacement,dataDSId:name,content:contentElm,contentPadding:contentPadding,maxWidth:maxWidth,placement:placement,portalContainer:portalContainer,dataE2eTestId:dataE2eTestId,subTheme:subTheme,isVisible:isVisible,tooltipId:tooltipId,triggerRef:triggerRef,isHiddenOnInvisibleTrigger:!0});return React.createElement(React.Fragment,null,triggerElm,tooltipElm)}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import type { ReactElement, FocusEvent as ReactFocusEvent, MouseEvent as ReactMouseEvent } from "react";
|
|
2
|
+
import React from "react";
|
|
3
3
|
import type { TooltipContentProps } from "./TooltipContent";
|
|
4
4
|
type BaseProps = Pick<TooltipContentProps, "placement" | "portalContainer" | "contentPadding" | "maxWidth" | "subTheme" | "onOverflowViewport" | "privateProps"> & {
|
|
5
5
|
/** Tooltip content */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import{useFocusVisible}from"@react-aria/interactions";import React,{useCallback,useEffect,useMemo,useRef,useState}from"react";import{TooltipContent}from"./TooltipContent";export function BaseTooltip({placement="auto",content,children,externalTriggerRef,portalContainer,contentPadding,maxWidth,subTheme,"data-e2e-test-id":dataE2eTestId,onVisibilityChange,privateProps,...ariaAttributes}){let tooltipId=useMemo(()=>`DSTooltip_${Math.floor(Date.now()*Math.random())}`,[]),{isFocusVisible}=useFocusVisible(),[isVisible,setVisible]=useState(!1),triggeredByEvent=useRef(null),isTooltipHovered=useRef(!1),isTriggerHovered=useRef(!1),hideTooltipTimeoutId=useRef(null),showTooltipTimeoutId=useRef(null),internalTriggerRef=useRef(null),triggerRef=externalTriggerRef||internalTriggerRef,toggleVisibility=useCallback(status=>{setVisible(status),onVisibilityChange&&onVisibilityChange(status)},[onVisibilityChange]),handleTriggerPointerEnter=useCallback(()=>{isTriggerHovered.current=!0,isTooltipHovered.current||(clearTimeout(showTooltipTimeoutId.current),showTooltipTimeoutId.current=setTimeout(()=>{isTriggerHovered.current&&(triggeredByEvent.current="hover",toggleVisibility(!0))},200))},[toggleVisibility]),handleTriggerPointerLeave=useCallback(()=>{isTriggerHovered.current=!1,clearTimeout(hideTooltipTimeoutId.current),hideTooltipTimeoutId.current=setTimeout(()=>{isTooltipHovered.current||"hover"!==triggeredByEvent.current||isTriggerHovered.current||toggleVisibility(!1)},200)},[toggleVisibility]),handleTriggerFocus=useCallback(()=>{isFocusVisible&&(triggeredByEvent.current="focus",toggleVisibility(!0))},[isFocusVisible,toggleVisibility]),handleTriggerBlur=useCallback(()=>{"focus"===triggeredByEvent.current&&toggleVisibility(!1)},[toggleVisibility]),handleTriggerClick=useCallback(()=>{toggleVisibility(!1)},[toggleVisibility]),handleTriggerKeyDown=useCallback(evt=>{"Escape"===evt.key&&toggleVisibility(!1)},[toggleVisibility]);useEffect(()=>()=>{clearTimeout(showTooltipTimeoutId.current),clearTimeout(hideTooltipTimeoutId.current)},[]),useEffect(()=>{let trigger;if(externalTriggerRef?.current&&!children){let triggerTabIndex=(trigger=externalTriggerRef.current).getAttribute("tabindex");trigger.setAttribute("tabindex",triggerTabIndex??"0"),trigger.addEventListener("pointerenter",handleTriggerPointerEnter),trigger.addEventListener("pointerleave",handleTriggerPointerLeave),trigger.addEventListener("focus",handleTriggerFocus),trigger.addEventListener("blur",handleTriggerBlur),trigger.addEventListener("click",handleTriggerClick),trigger.addEventListener("keydown",handleTriggerKeyDown)}return()=>{trigger&&(trigger.removeEventListener("pointerenter",handleTriggerPointerEnter),trigger.removeEventListener("pointerleave",handleTriggerPointerLeave),trigger.removeEventListener("focus",handleTriggerFocus),trigger.removeEventListener("blur",handleTriggerBlur),trigger.removeEventListener("click",handleTriggerClick),trigger.removeEventListener("keydown",handleTriggerKeyDown))}},[externalTriggerRef,children,handleTriggerPointerEnter,handleTriggerPointerLeave,handleTriggerFocus,handleTriggerBlur,handleTriggerClick,handleTriggerKeyDown]),useEffect(()=>{if(externalTriggerRef?.current&&!children){let trigger=externalTriggerRef.current;isVisible?trigger.setAttribute("aria-describedby",tooltipId):trigger.removeAttribute("aria-describedby")}},[externalTriggerRef,children,tooltipId,isVisible]);let triggerElm=children?React.cloneElement(children,{ref:triggerRef,...ariaAttributes,...isVisible&&{"aria-describedby":tooltipId},tabIndex:children.props.tabIndex??0,onPointerEnter:handleTriggerPointerEnter,onPointerLeave:handleTriggerPointerLeave,onFocus:evt=>{handleTriggerFocus(),children.props.onFocus&&children.props.onFocus(evt)},onBlur:evt=>{handleTriggerBlur(),children.props.onBlur&&children.props.onBlur(evt)},onClick:evt=>{handleTriggerClick(),children.props.onClick&&children.props.onClick(evt)},onKeyDown:handleTriggerKeyDown}):null,tooltipElm=React.createElement(TooltipContent,{dataDSId:"Tooltip",content:content,placement:placement,portalContainer:portalContainer,dataE2eTestId:dataE2eTestId,isVisible:isVisible,tooltipId:tooltipId,triggerRef:triggerRef,"aria-hidden":!0,role:"tooltip",contentPadding:contentPadding,maxWidth:maxWidth,subTheme:subTheme,onTooltipPointerEnter:()=>{isTooltipHovered.current=!0},onTooltipPointerLeave:()=>{isTooltipHovered.current=!1,"hover"===triggeredByEvent.current&&toggleVisibility(!1)},privateProps:privateProps});return React.createElement(React.Fragment,null,triggerElm,tooltipElm)}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the nearest ancestor `TooltipContent` has been measured and
|
|
3
|
+
* positioned by `useFloatingPosition`. Lets content rendered inside it (e.g.
|
|
4
|
+
* `BasePopover`'s focus trap) wait for that before activating, since a focus
|
|
5
|
+
* trap scans for focusable elements only once, on activation, and elements
|
|
6
|
+
* under a `visibility: hidden` ancestor never count as focusable.
|
|
7
|
+
*/
|
|
8
|
+
export declare const FloatingPositionedContext: React.Context<boolean>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createContext}from"react";export const FloatingPositionedContext=createContext(!0);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type { AriaAttributes, MutableRefObject, ReactElement } from "react";
|
|
2
|
-
import React from "react";
|
|
3
1
|
import type { Property } from "csstype";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import type { AriaAttributes, MutableRefObject, ReactElement } from "react";
|
|
4
4
|
import type { SubThemeTypes } from "../../web-tokens/_subThemeType";
|
|
5
5
|
import { type PortalProps } from "../Portal/Portal";
|
|
6
|
+
export type TooltipPlacement = "auto" | "top" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
7
|
+
export type TooltipVerticalPlacement = "top" | "bottom";
|
|
6
8
|
export type TooltipPrivateProps = {
|
|
7
9
|
/**
|
|
8
10
|
* @internal
|
|
@@ -29,7 +31,7 @@ export type TooltipPrivateProps = {
|
|
|
29
31
|
export type TooltipContentProps = {
|
|
30
32
|
content: ReactElement;
|
|
31
33
|
triggerRef: MutableRefObject<any>;
|
|
32
|
-
placement?:
|
|
34
|
+
placement?: TooltipPlacement;
|
|
33
35
|
dataE2eTestId?: string;
|
|
34
36
|
dataDSId: string;
|
|
35
37
|
isVisible?: boolean;
|
|
@@ -39,7 +41,7 @@ export type TooltipContentProps = {
|
|
|
39
41
|
contentPadding?: "s" | "m";
|
|
40
42
|
subTheme?: SubThemeTypes;
|
|
41
43
|
maxWidth?: Property.MaxWidth | number;
|
|
42
|
-
defaultVerticalPlacement?:
|
|
44
|
+
defaultVerticalPlacement?: TooltipVerticalPlacement;
|
|
43
45
|
hideArrow?: boolean;
|
|
44
46
|
/** Sets css visibility hidden when trigger is scrolled out of view */
|
|
45
47
|
isHiddenOnInvisibleTrigger?: boolean;
|
|
@@ -49,12 +51,5 @@ export type TooltipContentProps = {
|
|
|
49
51
|
onOverflowViewport?: (triggerRect: DOMRect, tooltipRect: DOMRect, viewportHeight: number) => void;
|
|
50
52
|
privateProps?: TooltipPrivateProps;
|
|
51
53
|
} & Pick<PortalProps, "portalContainer"> & AriaAttributes;
|
|
52
|
-
export type TooltipStyle = {
|
|
53
|
-
top: number;
|
|
54
|
-
left: number;
|
|
55
|
-
horizontalPlacement: "left" | "right" | "center";
|
|
56
|
-
verticalPlacement: "top" | "bottom";
|
|
57
|
-
isSidePlacement?: boolean;
|
|
58
|
-
};
|
|
59
54
|
/** This component is used to display the overlay for both Toggletip and Tooltip components */
|
|
60
55
|
export declare function TooltipContent({ placement, content, tooltipId, triggerRef, portalContainer, dataE2eTestId, dataDSId, isVisible, "aria-hidden": ariaHidden, role, tabIndex, contentPadding, maxWidth, subTheme, defaultVerticalPlacement, hideArrow, isHiddenOnInvisibleTrigger, onTooltipPointerEnter, onTooltipPointerLeave, onOverflowViewport, privateProps, ...ariaAttributes }: TooltipContentProps): React.ReactElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import{keyframes}from"@emotion/react";import styled from"@emotion/styled";import React,{useCallback,useEffect,useMemo,useRef,useState}from"react";import{Portal,usePortalChildZIndex}from"../Portal/Portal";import{SubThemeProvider}from"../SubThemeProvider/SubThemeProvider";import{useFloatingPosition}from"../Utilities/FloatingPosition/useFloatingPosition";import{FloatingPositionedContext}from"./FloatingPositionedContext";import{ANIMATION_DISTANCE,ARROW_SIZE,ARROW_SIZE_BIG,createOverflowViewportReporter,DISTANCE_FROM_TRIGGER,getPlacementSide,getTooltipOffsetOptions,SIDE_PLACEMENT_SIDE,sidePlacementOffset,toFloatingAnchor,toFloatingPlacement}from"./utils";let StyledContainer=styled("div",{target:"e1l7l62c0",label:"StyledContainer"})(({theme,side,maxWidth,contentPadding,subTheme,isHidden,isSidePlacement})=>{let zIndex=usePortalChildZIndex(theme.variables.zIndex.tooltip),animationDistance="top"===side?`${-ANIMATION_DISTANCE}px`:`${ANIMATION_DISTANCE}px`,animation=keyframes({from:{opacity:theme.variables.opacity.hidden,...!isSidePlacement&&{transform:`translateY(${animationDistance})`}},to:{opacity:theme.variables.opacity.visible,...!isSidePlacement&&{transform:"translateY(0)"}}}),contentPaddingMap={s:theme.variables.size.spacing.xxs,m:theme.variables.size.spacing.s},invertedSubThemeStyles={padding:`${theme.variables.size.spacing.xs} ${theme.variables.size.spacing.s}`,...contentPadding&&{padding:contentPaddingMap[contentPadding]}};return{zIndex,opacity:theme.variables.opacity.hidden,animation:`200ms ease-out forwards ${animation}`,maxWidth,width:"max-content",boxSizing:"border-box",backgroundColor:subTheme?theme.values.color.background.primary.default:theme.values.color.background.elevated.default,borderRadius:subTheme?theme.variables.size.borderRadius.xs:theme.variables.size.borderRadius.s,...isHidden&&{visibility:"hidden"},...!!subTheme&&invertedSubThemeStyles,...!subTheme&&{":after":{content:'" "',position:"absolute",top:0,left:0,width:"100%",height:"100%",pointerEvents:"none",borderRadius:"inherit",boxShadow:theme.values.elevation[3]}}}}),StyledArrow=styled("div",{target:"e1l7l62c1",label:"StyledArrow"})(({theme,subTheme,side,size=ARROW_SIZE,arrowOffsetLeft})=>{let adjustmentForShadow=+!subTheme,arrowContainerHeight=size+DISTANCE_FROM_TRIGGER,arrowSideLength=Math.sqrt(size**2+(size+adjustmentForShadow)**2);return{position:"absolute",left:arrowOffsetLeft,width:40,height:arrowContainerHeight,zIndex:1,overflow:"hidden",..."top"===side&&{top:`calc(100% - ${adjustmentForShadow}px)`},..."bottom"===side&&{top:`-${arrowContainerHeight-adjustmentForShadow}px`},"&::after":{content:'" "',position:"absolute",top:"top"===side?0:"100%",left:"50%",width:arrowSideLength,height:arrowSideLength,backgroundColor:subTheme?theme.values.color.background.primary.default:theme.values.color.background.elevated.default,transform:"translate(-50%, -50%) rotate(45deg)",...!subTheme&&{boxShadow:theme.values.elevation[3]}}}}),lastTooltipHideTimestamp=0;export function TooltipContent({placement="auto",content,tooltipId,triggerRef,portalContainer,dataE2eTestId,dataDSId,isVisible,"aria-hidden":ariaHidden,role,tabIndex,contentPadding,maxWidth=224,subTheme,defaultVerticalPlacement,hideArrow=!1,isHiddenOnInvisibleTrigger=!1,onTooltipPointerEnter,onTooltipPointerLeave,onOverflowViewport,privateProps,...ariaAttributes}){let animationDuration,[isHidden,setIsHidden]=useState(!1),arrowRef=useRef(null),isOverflowCallbackCalledRef=useRef(!1),{placement:sidePlacement,offset:sideOffset=sidePlacementOffset,maxWidth:privateMaxWidth}=privateProps??{},arrowSize=useMemo(()=>hideArrow?0:subTheme?ARROW_SIZE:ARROW_SIZE_BIG,[subTheme,hideArrow]),handleViewportOverflow=useCallback((triggerRect,tooltipRect,viewportHeight)=>{isOverflowCallbackCalledRef.current||(onOverflowViewport?.(triggerRect,tooltipRect,viewportHeight),isOverflowCallbackCalledRef.current=!0)},[onOverflowViewport,isOverflowCallbackCalledRef]),overflowMiddleware=useMemo(()=>"auto"===placement?[createOverflowViewportReporter(handleViewportOverflow)]:void 0,[placement,handleViewportOverflow]),{placement:preferredPlacement,fallbackPlacements}=useMemo(()=>toFloatingPlacement({placement,defaultVerticalPlacement,sidePlacement}),[placement,defaultVerticalPlacement,sidePlacement]),offset=useMemo(()=>getTooltipOffsetOptions({arrowSize,sideOffset}),[arrowSize,sideOffset]),anchorRef=useRef(null),anchorSourceRef=useRef(null);anchorSourceRef.current!==triggerRef.current&&(anchorSourceRef.current=triggerRef.current,anchorRef.current=toFloatingAnchor(triggerRef.current));let{setFloating,floatingStyles,placement:resolvedPlacement,isPositioned,middlewareData}=useFloatingPosition({anchorRef,placement:preferredPlacement,offset,flip:{fallbackPlacements},arrowRef:hideArrow?void 0:arrowRef,disableTransform:!0,trackAnimationFrame:!0,isOpen:!!isVisible,extraMiddleware:overflowMiddleware});if(useEffect(()=>{isVisible||(lastTooltipHideTimestamp=Date.now())},[isVisible]),useEffect(()=>{isOverflowCallbackCalledRef.current=!1},[isVisible,isOverflowCallbackCalledRef]),useEffect(()=>{let observer;return isHiddenOnInvisibleTrigger&&triggerRef.current&&isVisible&&"undefined"!=typeof IntersectionObserver&&(observer=new IntersectionObserver(entries=>entries.forEach(entry=>{let rect=entry.boundingClientRect;(rect?.width!==0||rect?.height!==0)&&setIsHidden(!entry.isIntersecting)}),{root:null,threshold:.99})).observe(triggerRef.current),()=>{observer&&observer.disconnect()}},[triggerRef,isVisible,isHiddenOnInvisibleTrigger]),!isVisible)return null;let side=getPlacementSide(resolvedPlacement),isSidePlacement=side===SIDE_PLACEMENT_SIDE,tooltipElm=React.createElement(StyledContainer,{"data-e2e-test-id":dataE2eTestId,"data-ds-id":dataDSId,"data-placement":resolvedPlacement,style:{...floatingStyles,animationDuration:(animationDuration="200ms",lastTooltipHideTimestamp&&Date.now()-lastTooltipHideTimestamp<700&&(animationDuration="0ms"),animationDuration)},ref:setFloating,id:tooltipId,role:role,...ariaAttributes,"aria-hidden":ariaHidden,subTheme:subTheme,tabIndex:tabIndex,side:side,maxWidth:privateMaxWidth??maxWidth,contentPadding:contentPadding,isHidden:isHidden||!isPositioned,isSidePlacement:isSidePlacement,onPointerEnter:onTooltipPointerEnter,onPointerLeave:onTooltipPointerLeave},React.createElement(FloatingPositionedContext.Provider,{value:isPositioned},content),!hideArrow&&side!==SIDE_PLACEMENT_SIDE&&React.createElement(StyledArrow,{ref:arrowRef,"data-e2e-test-id":`${dataE2eTestId}_arrow`,subTheme:subTheme,side:side,size:arrowSize,arrowOffsetLeft:middlewareData.arrow?.x})),wrapperElm=subTheme?React.createElement(SubThemeProvider,{name:subTheme},tooltipElm):tooltipElm;return React.createElement(Portal,{portalContainer:portalContainer},wrapperElm)}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import type { OffsetOptions } from "@floating-ui/react-dom";
|
|
2
|
+
import type { Middleware, Placement, VirtualElement } from "../Utilities/FloatingPosition/useFloatingPosition";
|
|
3
|
+
import type { TooltipContentProps, TooltipPlacement, TooltipPrivateProps, TooltipVerticalPlacement } from "./TooltipContent";
|
|
4
4
|
export declare const DISTANCE_FROM_TRIGGER = 4;
|
|
5
5
|
export declare const ANIMATION_DISTANCE = 8;
|
|
6
6
|
export declare const ARROW_SIZE = 6;
|
|
@@ -8,21 +8,65 @@ export declare const ARROW_SIZE_BIG = 8;
|
|
|
8
8
|
/** TODO: remove temporary side placement. Matches the gap top/bottom tooltips settle at. */
|
|
9
9
|
export declare const sidePlacementOffset: number;
|
|
10
10
|
export declare const getArrowOffset: (size: number) => number;
|
|
11
|
-
type
|
|
12
|
-
placement:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
/** TODO: remove temporary side placement, both fields */
|
|
11
|
+
export type FloatingPlacementConfig = {
|
|
12
|
+
placement: Placement;
|
|
13
|
+
/** The placements `flip` may fall back to, in order of preference. */
|
|
14
|
+
fallbackPlacements: Placement[];
|
|
15
|
+
};
|
|
16
|
+
type ToFloatingPlacementParams = {
|
|
17
|
+
placement: TooltipPlacement | undefined;
|
|
18
|
+
defaultVerticalPlacement: TooltipVerticalPlacement | undefined;
|
|
19
|
+
/** TODO: remove temporary side placement */
|
|
21
20
|
sidePlacement?: TooltipPrivateProps["placement"];
|
|
22
|
-
sideOffset?: number;
|
|
23
21
|
};
|
|
24
22
|
/**
|
|
25
|
-
*
|
|
23
|
+
* Resolves the DS placement to the preferred floating-ui placement plus its
|
|
24
|
+
* flip fallbacks. Tooltips only ever move between the top and bottom side; an
|
|
25
|
+
* explicit placement may only flip to the opposite side with the same
|
|
26
|
+
* alignment, while automatic placement may also switch alignment.
|
|
27
|
+
*
|
|
28
|
+
* A side placement takes precedence and falls back to whatever the DS
|
|
29
|
+
* placement resolved to, so it lands beside the trigger when there is room and
|
|
30
|
+
* behaves like an ordinary tooltip when there is not.
|
|
31
|
+
*/
|
|
32
|
+
export declare const toFloatingPlacement: ({ placement, defaultVerticalPlacement, sidePlacement, }: ToFloatingPlacementParams) => FloatingPlacementConfig;
|
|
33
|
+
/**
|
|
34
|
+
* The side of the trigger the resolved floating-ui placement puts the tooltip
|
|
35
|
+
* on. `"right"` only ever comes from the temporary side placement.
|
|
36
|
+
* TODO: drop `"right"` with the temporary side placement
|
|
37
|
+
*/
|
|
38
|
+
export type TooltipPlacementSide = TooltipVerticalPlacement | "right";
|
|
39
|
+
/** TODO: remove temporary side placement */
|
|
40
|
+
export declare const SIDE_PLACEMENT_SIDE: "right";
|
|
41
|
+
/** The side of the trigger the resolved floating-ui placement puts the tooltip on. */
|
|
42
|
+
export declare const getPlacementSide: (placement: Placement) => TooltipPlacementSide;
|
|
43
|
+
type TooltipOffsetParams = {
|
|
44
|
+
arrowSize: number;
|
|
45
|
+
/**
|
|
46
|
+
* Gap between trigger and a side-placed tooltip.
|
|
47
|
+
* TODO: remove temporary side placement
|
|
48
|
+
*/
|
|
49
|
+
sideOffset: number;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Distance between trigger and tooltip, plus — for aligned placements — the
|
|
53
|
+
* offset that anchors the tooltip's near edge to the trigger center instead of
|
|
54
|
+
* floating-ui's default trigger-edge alignment, keeping the arrow (which sits
|
|
55
|
+
* `getArrowOffset` + arrow size from the tooltip edge) pointed at the trigger
|
|
56
|
+
* center. With no arrow the tooltip stays edge-aligned, as before.
|
|
57
|
+
*/
|
|
58
|
+
export declare const getTooltipOffsetOptions: ({ arrowSize, sideOffset }: TooltipOffsetParams) => OffsetOptions;
|
|
59
|
+
type OnOverflowViewport = NonNullable<TooltipContentProps["onOverflowViewport"]>;
|
|
60
|
+
/**
|
|
61
|
+
* Reproduces the legacy `onOverflowViewport` contract: reports when the
|
|
62
|
+
* tooltip fits neither fully above nor fully below the trigger.
|
|
63
|
+
*/
|
|
64
|
+
export declare const createOverflowViewportReporter: (onOverflowViewport: OnOverflowViewport) => Middleware;
|
|
65
|
+
/**
|
|
66
|
+
* Normalizes what consumers put into `triggerRef` — a DOM element, or a
|
|
67
|
+
* `Range` (RangePopover, UserHighlightTooltip) — into a floating-ui anchor.
|
|
68
|
+
* A `Range` is wrapped as a virtual element with a `contextElement` so
|
|
69
|
+
* `autoUpdate` can attach scroll listeners to the right ancestors.
|
|
26
70
|
*/
|
|
27
|
-
export declare
|
|
71
|
+
export declare const toFloatingAnchor: (trigger: unknown) => Element | VirtualElement | null;
|
|
28
72
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export const DISTANCE_FROM_TRIGGER=4;export const ANIMATION_DISTANCE=8;export const ARROW_SIZE=6;export const ARROW_SIZE_BIG=8;export const sidePlacementOffset=10;export const getArrowOffset=size=>2*size;let START_SUFFIX="-start",END_SUFFIX="-end",SIDE_PLACEMENT="right-start",DS_TO_FLOATING_PLACEMENT={top:"top",bottom:"bottom","top-left":`top${END_SUFFIX}`,"top-right":`top${START_SUFFIX}`,"bottom-left":`bottom${END_SUFFIX}`,"bottom-right":`bottom${START_SUFFIX}`},OPPOSITE_SIDE={top:"bottom",bottom:"top"},sideWithAlignments=side=>[side,`${side}${START_SUFFIX}`,`${side}${END_SUFFIX}`];export const toFloatingPlacement=({placement,defaultVerticalPlacement,sidePlacement})=>{let isAutomatic=!placement||"auto"===placement,preferred=isAutomatic?defaultVerticalPlacement??"top":DS_TO_FLOATING_PLACEMENT[placement],[side,alignment]=preferred.split("-"),oppositeSide=OPPOSITE_SIDE[side],resolved=isAutomatic?{placement:preferred,fallbackPlacements:[...sideWithAlignments(side).slice(1),...sideWithAlignments(oppositeSide)]}:{placement:preferred,fallbackPlacements:[alignment?`${oppositeSide}-${alignment}`:oppositeSide]};return"right-top"===sidePlacement?{placement:SIDE_PLACEMENT,fallbackPlacements:[resolved.placement,...resolved.fallbackPlacements]}:resolved};export const SIDE_PLACEMENT_SIDE="right";export const getPlacementSide=placement=>placement.split("-")[0];export const getTooltipOffsetOptions=({arrowSize,sideOffset})=>({rects,placement})=>{if(placement===SIDE_PLACEMENT)return{mainAxis:sideOffset};let mainAxis=arrowSize+4;return(placement.endsWith(START_SUFFIX)||placement.endsWith(END_SUFFIX))&&0!==arrowSize?{mainAxis,alignmentAxis:rects.reference.width/2-getArrowOffset(arrowSize)-arrowSize}:{mainAxis}};export const createOverflowViewportReporter=onOverflowViewport=>({name:"reportOverflowViewport",fn({elements}){let triggerRect=elements.reference.getBoundingClientRect(),tooltipRect=elements.floating.getBoundingClientRect(),viewportHeight=elements.floating.ownerDocument.documentElement.clientHeight,canPlaceAboveTrigger=triggerRect.top>=tooltipRect.height,canPlaceBelowTrigger=triggerRect.bottom+tooltipRect.height<viewportHeight;return canPlaceAboveTrigger||canPlaceBelowTrigger||onOverflowViewport(triggerRect,tooltipRect,viewportHeight),{}}});export const toFloatingAnchor=trigger=>{if(!trigger)return null;if("undefined"!=typeof Range&&trigger instanceof Range){let container=trigger.commonAncestorContainer;return{getBoundingClientRect:()=>trigger.getBoundingClientRect(),getClientRects:()=>trigger.getClientRects(),contextElement:container instanceof Element?container:container.parentElement??void 0}}return trigger};
|
|
@@ -1,20 +1,53 @@
|
|
|
1
1
|
import type { CSSProperties, RefObject } from "react";
|
|
2
|
-
import type { OffsetOptions, Placement, Strategy } from "@floating-ui/react-dom";
|
|
2
|
+
import type { Middleware, MiddlewareData, OffsetOptions, Placement, Strategy, VirtualElement } from "@floating-ui/react-dom";
|
|
3
3
|
export type { ViewportPlacement } from "./utils";
|
|
4
|
-
export type { Placement } from "@floating-ui/react-dom";
|
|
4
|
+
export type { Middleware, MiddlewareData, Placement, VirtualElement, } from "@floating-ui/react-dom";
|
|
5
|
+
export type FlipOptions = {
|
|
6
|
+
/** Restrict which placements `flip` may fall back to. */
|
|
7
|
+
fallbackPlacements?: Placement[];
|
|
8
|
+
};
|
|
5
9
|
/** Position relative to an anchor element. */
|
|
6
10
|
type AnchorModeProps = {
|
|
7
11
|
mode?: "anchor";
|
|
8
|
-
/**
|
|
9
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The element to position the floating element against. Also accepts a
|
|
14
|
+
* virtual element (anything with `getBoundingClientRect`, e.g. a `Range`
|
|
15
|
+
* wrapper) — set its `contextElement` so scroll/resize tracking works.
|
|
16
|
+
*/
|
|
17
|
+
anchorRef: RefObject<Element | VirtualElement | null>;
|
|
10
18
|
/** Side (and optional alignment) to place the element on. Default `"bottom"`. */
|
|
11
19
|
placement?: Placement;
|
|
12
20
|
/** Gap between the anchor and the floating element. Default `0`. */
|
|
13
21
|
offset?: OffsetOptions;
|
|
14
|
-
/**
|
|
15
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Flip to the opposite side when it would overflow. Default `true`.
|
|
24
|
+
* Pass an options object to restrict the fallback placements.
|
|
25
|
+
*/
|
|
26
|
+
flip?: boolean | FlipOptions;
|
|
16
27
|
/** Slide along the axis to stay in view near edges. Default `true`. */
|
|
17
28
|
shift?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Arrow element to keep pointed at the anchor; its offset along the
|
|
31
|
+
* floating element is returned in `middlewareData.arrow`.
|
|
32
|
+
*/
|
|
33
|
+
arrowRef?: RefObject<HTMLElement | null>;
|
|
34
|
+
/** Minimum distance the arrow keeps from the floating element's corners. Default `0`. */
|
|
35
|
+
arrowPadding?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Emit `top`/`left` instead of a `transform` in `floatingStyles`, freeing
|
|
38
|
+
* `transform` for the caller's own animations. Default `false` (transform).
|
|
39
|
+
*/
|
|
40
|
+
disableTransform?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Reposition every animation frame while open — needed when the anchor moves
|
|
43
|
+
* without scroll/resize events (CSS transforms, canvas pan). Default `false`.
|
|
44
|
+
*/
|
|
45
|
+
trackAnimationFrame?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Extra floating-ui middleware, run after the built-ins (before `arrow`).
|
|
48
|
+
* Keep the array referentially stable (module-level or memoized).
|
|
49
|
+
*/
|
|
50
|
+
extraMiddleware?: Middleware[];
|
|
18
51
|
};
|
|
19
52
|
/**
|
|
20
53
|
* The viewport spot to pin to, expressed as separate axes. At least one axis is
|
|
@@ -54,6 +87,8 @@ export type UseFloatingPositionReturn = {
|
|
|
54
87
|
strategy: Strategy;
|
|
55
88
|
/** `false` until the element has been measured — gate visibility on this to avoid a flash. */
|
|
56
89
|
isPositioned: boolean;
|
|
90
|
+
/** Per-middleware positioning data, e.g. `middlewareData.arrow` for the arrow offset. */
|
|
91
|
+
middlewareData: MiddlewareData;
|
|
57
92
|
/** Imperatively recompute the position. */
|
|
58
93
|
update: () => void;
|
|
59
94
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useLayoutEffect,useMemo}from"react";import{useFloating,autoUpdate,offset as offsetMiddleware,flip as flipMiddleware,shift as shiftMiddleware}from"@floating-ui/react-dom";import{useWindow}from"../../../shared/useWindow";import{useDocument}from"../../../shared/useDocument";import{axesToViewportPlacement,getViewportReferenceRect,viewportToFloatingPlacement}from"./utils";export function useFloatingPosition(props){let{isOpen=!0}=props,isViewportMode="viewport"===props.mode,window=useWindow(),document=useDocument(),{anchorPlacement,viewportPlacement,anchorOffset,viewportOffset,flipEnabled,shiftEnabled,anchorRef}="viewport"===props.mode?{anchorPlacement:void 0,viewportPlacement:axesToViewportPlacement(props.positionY,props.positionX),anchorOffset:0,viewportOffset:props.offset??0,flipEnabled:!1,shiftEnabled:!1,anchorRef:null}:{anchorPlacement:props.placement??"bottom",viewportPlacement:void 0,anchorOffset:props.offset??0,viewportOffset:0,flipEnabled:!1!==props.flip,shiftEnabled:!1!==props.shift,anchorRef:props.anchorRef??null},middleware=useMemo(()=>isViewportMode?[]:[offsetMiddleware(anchorOffset),...flipEnabled?[flipMiddleware()]:[],...shiftEnabled?[shiftMiddleware({padding:8})]:[]],[isViewportMode,anchorOffset,flipEnabled,shiftEnabled]),virtualReference=useMemo(()=>viewportPlacement?{getBoundingClientRect:()=>getViewportReferenceRect(viewportPlacement,document&&document.documentElement.clientWidth||window&&window.innerWidth||0,window&&window.innerHeight||document&&document.documentElement.clientHeight||0,viewportOffset)}:null,[viewportPlacement,viewportOffset,window,document]),{refs,floatingStyles,placement,strategy,isPositioned,update}=useFloating({open:isOpen,strategy:isViewportMode?"fixed":"absolute",placement:viewportPlacement?viewportToFloatingPlacement(viewportPlacement):anchorPlacement,middleware
|
|
1
|
+
import{useLayoutEffect,useMemo}from"react";import{useFloating,autoUpdate,offset as offsetMiddleware,flip as flipMiddleware,shift as shiftMiddleware,arrow as arrowMiddleware}from"@floating-ui/react-dom";import{useWindow}from"../../../shared/useWindow";import{useDocument}from"../../../shared/useDocument";import{axesToViewportPlacement,getViewportReferenceRect,viewportToFloatingPlacement}from"./utils";let NO_EXTRA_MIDDLEWARE=[];export function useFloatingPosition(props){let{isOpen=!0}=props,isViewportMode="viewport"===props.mode,window=useWindow(),document=useDocument(),{anchorPlacement,viewportPlacement,anchorOffset,viewportOffset,flipEnabled,flipFallbackPlacements,shiftEnabled,anchorRef,arrowRef,arrowPadding,disableTransform,trackAnimationFrame,extraMiddleware}="viewport"===props.mode?{anchorPlacement:void 0,viewportPlacement:axesToViewportPlacement(props.positionY,props.positionX),anchorOffset:0,viewportOffset:props.offset??0,flipEnabled:!1,flipFallbackPlacements:void 0,shiftEnabled:!1,anchorRef:null,arrowRef:null,arrowPadding:0,disableTransform:!1,trackAnimationFrame:!1,extraMiddleware:NO_EXTRA_MIDDLEWARE}:{anchorPlacement:props.placement??"bottom",viewportPlacement:void 0,anchorOffset:props.offset??0,viewportOffset:0,flipEnabled:!1!==props.flip,flipFallbackPlacements:"object"==typeof props.flip?props.flip.fallbackPlacements:void 0,shiftEnabled:!1!==props.shift,anchorRef:props.anchorRef??null,arrowRef:props.arrowRef??null,arrowPadding:props.arrowPadding??0,disableTransform:props.disableTransform??!1,trackAnimationFrame:props.trackAnimationFrame??!1,extraMiddleware:props.extraMiddleware??NO_EXTRA_MIDDLEWARE},middleware=useMemo(()=>isViewportMode?[]:[offsetMiddleware(anchorOffset),...flipEnabled?[flipMiddleware({fallbackPlacements:flipFallbackPlacements})]:[],...shiftEnabled?[shiftMiddleware({padding:8})]:[],...extraMiddleware,...arrowRef?[arrowMiddleware({element:arrowRef,padding:arrowPadding})]:[]],[isViewportMode,anchorOffset,flipEnabled,flipFallbackPlacements,shiftEnabled,arrowRef,arrowPadding,extraMiddleware]),virtualReference=useMemo(()=>viewportPlacement?{getBoundingClientRect:()=>getViewportReferenceRect(viewportPlacement,document&&document.documentElement.clientWidth||window&&window.innerWidth||0,window&&window.innerHeight||document&&document.documentElement.clientHeight||0,viewportOffset)}:null,[viewportPlacement,viewportOffset,window,document]),{refs,elements:{reference:referenceElement,floating:floatingElement},floatingStyles,placement,strategy,isPositioned,middlewareData,update}=useFloating({open:isOpen,strategy:isViewportMode?"fixed":"absolute",transform:!disableTransform,placement:viewportPlacement?viewportToFloatingPlacement(viewportPlacement):anchorPlacement,middleware});return useLayoutEffect(()=>{if(isOpen&&referenceElement&&floatingElement)return autoUpdate(referenceElement,floatingElement,update,{animationFrame:trackAnimationFrame})},[isOpen,trackAnimationFrame,referenceElement,floatingElement,update]),useLayoutEffect(()=>{virtualReference?refs.setReference(virtualReference):anchorRef&&refs.setReference(anchorRef.current)}),{setFloating:refs.setFloating,floatingStyles,placement,strategy,isPositioned,middlewareData,update}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import React,{useEffect,useRef}from"react";import FocusTrap from"focus-trap-react";export const FocusTrapWrapper=({active,focusTrapOptions,children})=>{let isClickedOutside=useRef(!1),isEscaped=useRef(!1),{onPostDeactivate,clickOutsideDeactivates,escapeDeactivates,...rest}=focusTrapOptions,onPostDeactivateRef=useRef(onPostDeactivate),clickOutsideDeactivatesRef=useRef(clickOutsideDeactivates),escapeDeactivatesRef=useRef(escapeDeactivates);return useEffect(()=>{onPostDeactivateRef.current=onPostDeactivate},[onPostDeactivate]),useEffect(()=>{clickOutsideDeactivatesRef.current=clickOutsideDeactivates},[clickOutsideDeactivates]),useEffect(()=>{escapeDeactivatesRef.current=escapeDeactivates},[escapeDeactivates]),React.createElement(FocusTrap,{active:active,focusTrapOptions:{...rest,clickOutsideDeactivates:evt=>{let cb=clickOutsideDeactivatesRef.current,shouldDeactivate="function"==typeof cb?cb(evt):cb;return!1!==shouldDeactivate&&(isClickedOutside.current=!0),shouldDeactivate},escapeDeactivates:evt=>{let cb=escapeDeactivatesRef.current,shouldDeactivate="function"==typeof cb?cb(evt):cb;return!1!==shouldDeactivate&&(isEscaped.current=!0),shouldDeactivate},onPostDeactivate:()=>{(isClickedOutside.current||isEscaped.current)&&onPostDeactivateRef.current?.(),isEscaped.current=!1,isClickedOutside.current=!1}}},children)};
|
|
1
|
+
import React,{useContext,useEffect,useRef}from"react";import FocusTrap from"focus-trap-react";import{FloatingPositionedContext}from"../components/Tooltip/FloatingPositionedContext";export const FocusTrapWrapper=({active,focusTrapOptions,children})=>{let isClickedOutside=useRef(!1),isEscaped=useRef(!1),isPositioned=useContext(FloatingPositionedContext),{onPostDeactivate,clickOutsideDeactivates,escapeDeactivates,...rest}=focusTrapOptions,onPostDeactivateRef=useRef(onPostDeactivate),clickOutsideDeactivatesRef=useRef(clickOutsideDeactivates),escapeDeactivatesRef=useRef(escapeDeactivates);return useEffect(()=>{onPostDeactivateRef.current=onPostDeactivate},[onPostDeactivate]),useEffect(()=>{clickOutsideDeactivatesRef.current=clickOutsideDeactivates},[clickOutsideDeactivates]),useEffect(()=>{escapeDeactivatesRef.current=escapeDeactivates},[escapeDeactivates]),React.createElement(FocusTrap,{active:active&&isPositioned,focusTrapOptions:{...rest,clickOutsideDeactivates:evt=>{let cb=clickOutsideDeactivatesRef.current,shouldDeactivate="function"==typeof cb?cb(evt):cb;return!1!==shouldDeactivate&&(isClickedOutside.current=!0),shouldDeactivate},escapeDeactivates:evt=>{let cb=escapeDeactivatesRef.current,shouldDeactivate="function"==typeof cb?cb(evt):cb;return!1!==shouldDeactivate&&(isEscaped.current=!0),shouldDeactivate},onPostDeactivate:()=>{(isClickedOutside.current||isEscaped.current)&&onPostDeactivateRef.current?.(),isEscaped.current=!1,isClickedOutside.current=!1}}},children)};
|
package/package.json
CHANGED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { TooltipStyle } from "./TooltipContent";
|
|
2
|
-
type GetSideTooltipStyleParams = {
|
|
3
|
-
triggerRect: DOMRect;
|
|
4
|
-
offset: number;
|
|
5
|
-
window: Window;
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* TODO: remove temporary side placement
|
|
9
|
-
*
|
|
10
|
-
* Places the tooltip beside the trigger with their top edges aligned. Callers
|
|
11
|
-
* must verify the tooltip fits beforehand, as this applies no viewport clamping.
|
|
12
|
-
*/
|
|
13
|
-
export declare const getSideTooltipStyle: ({ triggerRect, offset, window, }: GetSideTooltipStyleParams) => TooltipStyle;
|
|
14
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"getSideTooltipStyle",{enumerable:!0,get:function(){return getSideTooltipStyle}});const getSideTooltipStyle=({triggerRect,offset,window})=>({top:triggerRect.top+window.scrollY,left:triggerRect.right+offset+window.scrollX,horizontalPlacement:"right",verticalPlacement:"top",isSidePlacement:!0});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { TooltipStyle } from "./TooltipContent";
|
|
2
|
-
type GetSideTooltipStyleParams = {
|
|
3
|
-
triggerRect: DOMRect;
|
|
4
|
-
offset: number;
|
|
5
|
-
window: Window;
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* TODO: remove temporary side placement
|
|
9
|
-
*
|
|
10
|
-
* Places the tooltip beside the trigger with their top edges aligned. Callers
|
|
11
|
-
* must verify the tooltip fits beforehand, as this applies no viewport clamping.
|
|
12
|
-
*/
|
|
13
|
-
export declare const getSideTooltipStyle: ({ triggerRect, offset, window, }: GetSideTooltipStyleParams) => TooltipStyle;
|
|
14
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const getSideTooltipStyle=({triggerRect,offset,window})=>({top:triggerRect.top+window.scrollY,left:triggerRect.right+offset+window.scrollX,horizontalPlacement:"right",verticalPlacement:"top",isSidePlacement:!0});
|