UNPKG

@asphalt-react/popover

Version:

Popover

75 lines (58 loc) 11.4 kB
'use strict'; var React = require('react'); var PropTypes = require('prop-types'); var react = require('@floating-ui/react'); var helper = require('@asphalt-react/helper'); var cn = require('classnames'); var context = require('@asphalt-react/context'); var typography = require('@asphalt-react/typography'); function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } const FocusManager=({children,popoverContext,focusOrder=["content"],focusTrap=true,returnFocus=true,initialFocus=0,...props})=>{const{style,className,...rest}=props;return React.createElement(react.FloatingFocusManager,_extends({},rest,{context:popoverContext,order:focusOrder,modal:focusTrap,returnFocus:returnFocus,initialFocus:initialFocus}),children)};FocusManager.displayName="FocusManager";FocusManager.propTypes={children:PropTypes.node.isRequired,popoverContext:PropTypes.object.isRequired,focusOrder:PropTypes.arrayOf(PropTypes.oneOf(["reference","floating","content"])),focusTrap:PropTypes.bool,initialFocus:PropTypes.oneOfType([PropTypes.func,PropTypes.number,PropTypes.shape({current:PropTypes.any})]),returnFocus:PropTypes.bool};FocusManager.defaultProps={focusOrder:["content"],focusTrap:true,initialFocus:0,returnFocus:true}; const getOffset=offset=>{switch(offset){case"noOffset":return 0;case"lowOffset":return 4;case"highOffset":return 16;default:return 8}};const ARROW_SIZE=20;const shouldAdjustArrow=(target,placement)=>{return (target?.width<=ARROW_SIZE||target?.height<=ARROW_SIZE+1)&&/start|end/u.test(placement)}; const{resolvePropCollision}=helper.propsUtil;const usePopover=({open,placement,outOfFlow,flip:flipPosition,shift:shiftContent,size,bezel,stretch,focusOrder,returnFocus,initialFocus,focusTrap,noOffset,lowOffset,mediumOffset,highOffset,onOpenChange,isHover=false,isClick=true,arrowRef,...props})=>{const{collision,value:offsetProp}=resolvePropCollision({noOffset,lowOffset,mediumOffset,highOffset},"mediumOffset");if(collision){console.warn(`usePopover: Multiple offsets detected, falling back to "${offsetProp}"`);}const arrowMiddleware=arrowRef!==null?react.arrow({element:arrowRef}):null;const middleware=[react.offset(({rects})=>{const alignmentAxis=shouldAdjustArrow(rects?.reference,placement)?{alignmentAxis:-ARROW_SIZE}:{};return {mainAxis:getOffset(offsetProp),...alignmentAxis}}),...(flipPosition?[react.flip()]:[]),...(shiftContent?[react.shift()]:[]),arrowMiddleware];const{x,y,refs,strategy,context}=react.useFloating({...props,open,placement,strategy:outOfFlow?"fixed":"absolute",onOpenChange,middleware,whileElementsMounted:react.autoUpdate});const click=isClick?react.useClick(context):null;const dismiss=react.useDismiss(context);const hover=isHover?react.useHover(context,{delay:{open:300,close:100}}):null;const focus=isHover?react.useFocus(context):null;const{getReferenceProps,getFloatingProps}=react.useInteractions([click,dismiss,hover,focus]);return {getTargetProps:()=>{return {ref:refs.setReference,...getReferenceProps()}},getPopoverProps:()=>{return {open,size,bezel,ref:refs.setFloating,stretch,anchorStyles:{position:strategy,top:y??0,left:x??0},...getFloatingProps()}},getFocusProps:()=>{return {initialFocus,focusOrder,focusTrap,popoverContext:context,returnFocus}}}}; function styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (!css || typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var css_248z$1 = ".Popover__awIQi {\n --surface-color: var(--static-surface-primary, #ffffff);\n --box-shadow: var(--shadow-low, 0px 2px 20px 0px #1e2c6a14);\n --border-radius: var(--roundness-container-S, 0.5rem);\n\n box-shadow: var(--box-shadow);\n background-color: var(--surface-color);\n border-radius: var(--border-radius);\n z-index: 1;\n box-sizing: border-box;\n padding: 1rem;\n border: none;\n width: -moz-fit-content;\n width: fit-content;\n margin: 0;\n}\n\n.s__ryY9V {\n padding: 0.75rem;\n}\n\n.m__lHN6x {\n padding: 1rem;\n}\n\n.l__Ab7cI {\n padding: 1.5rem;\n}\n\n.bezelless__iNfYC {\n padding: 0;\n}\n\n.stretch__vFs7x {\n width: 100%;\n}\n\n.inverse__ljPEh {\n --surface-color: var(--static-surface-inverse, #383942);\n --text-color: var(--content-on-inverse, #ffffff);\n color: var(--text-color);\n}\n"; var styles$1 = {"Popover":"Popover__awIQi","s":"s__ryY9V","m":"m__lHN6x","l":"l__Ab7cI","bezelless":"bezelless__iNfYC","stretch":"stretch__vFs7x","inverse":"inverse__ljPEh"}; var stylesheet$1=".Popover__awIQi {\n --surface-color: var(--static-surface-primary, #ffffff);\n --box-shadow: var(--shadow-low, 0px 2px 20px 0px #1e2c6a14);\n --border-radius: var(--roundness-container-S, 0.5rem);\n\n box-shadow: var(--box-shadow);\n background-color: var(--surface-color);\n border-radius: var(--border-radius);\n z-index: 1;\n box-sizing: border-box;\n padding: 1rem;\n border: none;\n width: -moz-fit-content;\n width: fit-content;\n margin: 0;\n}\n\n.s__ryY9V {\n padding: 0.75rem;\n}\n\n.m__lHN6x {\n padding: 1rem;\n}\n\n.l__Ab7cI {\n padding: 1.5rem;\n}\n\n.bezelless__iNfYC {\n padding: 0;\n}\n\n.stretch__vFs7x {\n width: 100%;\n}\n\n.inverse__ljPEh {\n --surface-color: var(--static-surface-inverse, #383942);\n --text-color: var(--content-on-inverse, #ffffff);\n color: var(--text-color);\n}\n"; styleInject(css_248z$1); const BasePopover=React.forwardRef(({children,open=false,size="m",bezel=true,stretch=false,anchorStyles,inverse=false,...props},ref)=>{context.sendStyles(stylesheet$1);const{style,className,...rest}=props;const classes=cn(styles$1.Popover,styles$1[size],{[styles$1.bezelless]:!bezel,[styles$1.stretch]:stretch,[styles$1.inverse]:inverse});return open?React.createElement("dialog",_extends({},rest,{ref:ref,open:open,className:classes,style:anchorStyles}),children):null});BasePopover.displayName="BasePopover";BasePopover.propTypes={children:PropTypes.node.isRequired,open:PropTypes.bool,size:PropTypes.oneOf(["s","m","l"]),bezel:PropTypes.bool,stretch:PropTypes.bool,anchorStyles:PropTypes.object,inverse:PropTypes.bool};BasePopover.defaultProps={open:false,size:"m",bezel:true,stretch:false}; const Popover=React.forwardRef(({children,target,open=false,onOpenChange=null,placement="bottom",size="m",bezel=true,focusOrder=["content"],initialFocus=0,outOfFlow=false,flip=true,shift=true,focusTrap=true,lowOffset=false,mediumOffset=false,highOffset=false,noOffset=false,stretch=false,returnFocus=true,...props},ref)=>{const{style,className,...rest}=props;const{getTargetProps,getPopoverProps,getFocusProps}=usePopover({open,placement,outOfFlow,size,bezel,flip,focusOrder,returnFocus,initialFocus,focusTrap,noOffset,lowOffset,mediumOffset,highOffset,onOpenChange,shift,stretch,ref});const popoverRef=react.useMergeRefs([ref,getPopoverProps().ref]);return React.createElement(React.Fragment,null,React.cloneElement(target,{...getTargetProps()}),open&&React.createElement(FocusManager,getFocusProps(),React.createElement(BasePopover,_extends({},rest,getPopoverProps(),{ref:popoverRef}),children)))});Popover.displayName="Popover";Popover.propTypes={children:PropTypes.node.isRequired,target:PropTypes.node.isRequired,open:PropTypes.bool,size:PropTypes.oneOf(["s","m","l"]),bezel:PropTypes.bool,placement:PropTypes.oneOf(["auto","auto-start","auto-end","top","top-start","top-end","bottom","bottom-start","bottom-end","right","right-start","right-end","left","left-start","left-end"]),focusOrder:PropTypes.arrayOf(PropTypes.oneOf(["reference","floating","content"])),initialFocus:PropTypes.oneOfType([PropTypes.func,PropTypes.number,PropTypes.shape({current:PropTypes.any})]),outOfFlow:PropTypes.bool,flip:PropTypes.bool,stretch:PropTypes.bool,shift:PropTypes.bool,focusTrap:PropTypes.bool,lowOffset:PropTypes.bool,mediumOffset:PropTypes.bool,highOffset:PropTypes.bool,noOffset:PropTypes.bool,onOpenChange:PropTypes.func,returnFocus:PropTypes.bool};Popover.defaultProps={open:false,size:"m",bezel:true,placement:"bottom",focusOrder:["content"],initialFocus:0,outOfFlow:false,flip:true,shift:true,stretch:false,focusTrap:true,lowOffset:false,mediumOffset:false,highOffset:false,noOffset:false,onOpenChange:null,returnFocus:true}; var css_248z = ".content__-k6SR {\n --surface-color: var(--static-surface-inverse, #383942);\n --text-color: var(--content-on-inverse, #ffffff);\n color: var(--text-color);\n}\n\n.arrow__rJMmF {\n --surface-color: var(--static-surface-inverse, #383942);\n fill: var(--surface-color);\n width: 16px;\n height: 16px;\n}\n"; var styles = {"content":"content__-k6SR","arrow":"arrow__rJMmF"}; var stylesheet=".content__-k6SR {\n --surface-color: var(--static-surface-inverse, #383942);\n --text-color: var(--content-on-inverse, #ffffff);\n color: var(--text-color);\n}\n\n.arrow__rJMmF {\n --surface-color: var(--static-surface-inverse, #383942);\n fill: var(--surface-color);\n width: 16px;\n height: 16px;\n}\n"; styleInject(css_248z); const Tooltip=({target,children,arrow=true,placement="bottom",size="m",title,bezel=true,...props})=>{context.sendStyles(stylesheet);const{style,className,...rest}=props;const[open,setOpen]=React.useState(false);const arrowRef=React.useRef(null);const{getTargetProps,getPopoverProps,getFocusProps}=usePopover({open,onOpenChange:setOpen,isHover:true,isClick:false,arrowRef:arrow?arrowRef:null,placement,flip:true,shift:true,bezel});const{popoverContext}=getFocusProps();const classes=cn(styles.Tooltip,styles[size]);const arrowOffset=/bottom|top/u.test(placement)&&/start|end/u.test(placement)?{staticOffset:`${ARROW_SIZE}px`}:{};return React.createElement(React.Fragment,null,React.cloneElement(target,{...getTargetProps()}),open&&React.createElement(react.FloatingPortal,null,React.createElement(BasePopover,_extends({},rest,{inverse:true},getPopoverProps(),{role:"tooltip"}),React.createElement("span",{className:classes},title?React.createElement(typography.Text,{div:true,onBrand:true,bold:true,size:size},title):null,React.createElement(typography.Text,{span:true,size:size,onBrand:true},children)),arrow?React.createElement(react.FloatingArrow,_extends({ref:arrowRef,context:popoverContext,className:styles.arrow,tipRadius:2},arrowOffset)):null)))};Tooltip.displayName="Tooltip";Tooltip.propTypes={children:PropTypes.node.isRequired,target:PropTypes.node.isRequired,title:PropTypes.string,size:PropTypes.oneOf(["s","m","l"]),arrow:PropTypes.bool,placement:PropTypes.oneOf(["top","top-start","top-end","bottom","bottom-start","bottom-end","right","right-start","right-end","left","left-start","left-end"]),bezel:PropTypes.bool}; exports.BasePopover = BasePopover; exports.FocusManager = FocusManager; exports.Popover = Popover; exports.Tooltip = Tooltip; exports.usePopover = usePopover;