UNPKG

@zendeskgarden/react-modals

Version:

Components relating to modals in the Garden Design System

1,141 lines (1,089 loc) 43 kB
/** * Copyright Zendesk, Inc. * * Use of this source code is governed under the Apache License, Version 2.0 * found at http://www.apache.org/licenses/LICENSE-2.0. */ 'use strict'; var React = require('react'); var ReactDOM = require('react-dom'); var styled = require('styled-components'); var PropTypes = require('prop-types'); var reactTheming = require('@zendeskgarden/react-theming'); var containerModal = require('@zendeskgarden/container-modal'); var reactMergeRefs = require('react-merge-refs'); var isWindow = require('dom-helpers/isWindow'); var ownerDocument = require('dom-helpers/ownerDocument'); var ownerWindow = require('dom-helpers/ownerWindow'); var css = require('dom-helpers/css'); var getScrollbarSize = require('dom-helpers/scrollbarSize'); var reactButtons = require('@zendeskgarden/react-buttons'); var reactTransitionGroup = require('react-transition-group'); var reactDom = require('@floating-ui/react-dom'); var activeElement = require('dom-helpers/activeElement'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var React__namespace = /*#__PURE__*/_interopNamespace(React); var ReactDOM__default = /*#__PURE__*/_interopDefault(ReactDOM); var styled__default = /*#__PURE__*/_interopDefault(styled); var PropTypes__default = /*#__PURE__*/_interopDefault(PropTypes); var isWindow__default = /*#__PURE__*/_interopDefault(isWindow); var ownerDocument__default = /*#__PURE__*/_interopDefault(ownerDocument); var ownerWindow__default = /*#__PURE__*/_interopDefault(ownerWindow); var css__default = /*#__PURE__*/_interopDefault(css); var getScrollbarSize__default = /*#__PURE__*/_interopDefault(getScrollbarSize); var activeElement__default = /*#__PURE__*/_interopDefault(activeElement); const COMPONENT_ID$j = 'modals.backdrop'; const animationName$1 = styled.keyframes(["0%{opacity:0;}100%{opacity:1;}"]); const animationStyles$1 = props => { if (props.$isAnimated) { return styled.css(["animation:", " 0.15s ease-in;"], animationName$1); } return ''; }; const StyledBackdrop = styled__default.default.div.attrs({ 'data-garden-id': COMPONENT_ID$j, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledBackdrop", componentId: "sc-mzdjpo-0" })(["display:flex;position:fixed;inset:0;align-items:", ";justify-content:", ";z-index:400;background-color:", ";overflow:auto;-webkit-overflow-scrolling:touch;font-family:", ";direction:", ";", ";", ";"], props => props.$isCentered && 'center', props => props.$isCentered && 'center', _ref => { let { theme } = _ref; return reactTheming.getColor({ theme, hue: 'neutralHue', transparency: theme.opacity[1000], light: { shade: 900 }, dark: { shade: 1200 } }); }, props => props.theme.fonts.system, props => props.theme.rtl && 'rtl', animationStyles$1, reactTheming.componentStyles); StyledBackdrop.propTypes = { $isCentered: PropTypes__default.default.bool, $isAnimated: PropTypes__default.default.bool }; const COMPONENT_ID$i = 'modals.body'; const StyledBody = styled__default.default.div.attrs({ 'data-garden-id': COMPONENT_ID$i, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledBody", componentId: "sc-14rzecg-0" })(["display:block;margin:0;padding:", ";height:100%;overflow:auto;line-height:", ";color-scheme:only ", ";color:", ";font-size:", ";", ";"], props => `${props.theme.space.base * 5}px ${props.theme.space.base * 10}px`, props => reactTheming.getLineHeight(props.theme.lineHeights.md, props.theme.fontSizes.md), p => p.theme.colors.base, _ref => { let { theme } = _ref; return reactTheming.getColor({ theme, variable: 'foreground.default' }); }, props => props.theme.fontSizes.md, reactTheming.componentStyles); const COMPONENT_ID$h = 'modals.close'; const BASE_MULTIPLIERS$1 = { top: 2.5, side: 6.5, size: 10 }; const StyledClose = styled__default.default(reactButtons.IconButton).attrs({ 'data-garden-id': COMPONENT_ID$h, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledClose", componentId: "sc-iseudj-0" })(["position:absolute;top:", "px;", ":", ";", ";"], props => props.theme.space.base * BASE_MULTIPLIERS$1.top, props => props.theme.rtl ? 'left' : 'right', props => `${props.theme.space.base * BASE_MULTIPLIERS$1.side}px`, reactTheming.componentStyles); const COMPONENT_ID$g = 'modals.footer'; const StyledFooter = styled__default.default.div.attrs({ 'data-garden-id': COMPONENT_ID$g, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledFooter", componentId: "sc-d8pfdu-0" })(["display:flex;flex-shrink:0;align-items:center;justify-content:flex-end;border-top:", ";padding:", ";", ";"], props => props.$isLarge && `${props.theme.borders.sm} ${reactTheming.getColor({ theme: props.theme, variable: 'border.default' })}`, props => props.$isLarge ? `${props.theme.space.base * 8}px ${props.theme.space.base * 10}px` : `${props.theme.space.base * 5}px ${props.theme.space.base * 10}px ${props.theme.space.base * 8}px`, reactTheming.componentStyles); const COMPONENT_ID$f = 'modals.footer_item'; const StyledFooterItem = styled__default.default.span.attrs({ 'data-garden-id': COMPONENT_ID$f, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledFooterItem", componentId: "sc-1mb76hl-0" })(["display:flex;margin-", ":", "px;min-width:0;&:first-child{margin-", ":0;}", ";"], props => props.theme.rtl ? 'right' : 'left', props => props.theme.space.base * 5, props => props.theme.rtl ? 'right' : 'left', reactTheming.componentStyles); const COMPONENT_ID$e = 'modals.header'; const colorStyles$2 = _ref => { let { $isDanger, theme } = _ref; const bottomBorderColor = reactTheming.getColor({ theme, variable: 'border.subtle' }); const color = reactTheming.getColor({ theme, variable: $isDanger ? 'foreground.danger' : 'foreground.default' }); return styled.css(["border-bottom-color:", ";color:", ";"], bottomBorderColor, color); }; const StyledHeader = styled__default.default.div.attrs({ 'data-garden-id': COMPONENT_ID$e, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledHeader", componentId: "sc-1787r9v-0" })(["display:block;position:", ";margin:0;border-bottom:", ";padding:", ";", " line-height:", ";font-size:", ";font-weight:", ";", ";", ";"], props => props.$isDanger && 'relative', props => props.theme.borders.sm, props => `${props.theme.space.base * 5}px ${props.theme.space.base * 10}px`, props => props.$isCloseButtonPresent && `padding-${props.theme.rtl ? 'left' : 'right'}: ${props.theme.space.base * (BASE_MULTIPLIERS$1.size + BASE_MULTIPLIERS$1.side + 2)}px;`, props => reactTheming.getLineHeight(props.theme.lineHeights.md, props.theme.fontSizes.md), props => props.theme.fontSizes.md, props => props.theme.fontWeights.semibold, colorStyles$2, reactTheming.componentStyles); var _g, _circle; function _extends$1() { return _extends$1 = 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$1.apply(null, arguments); } var SvgAlertErrorStroke = function SvgAlertErrorStroke(props) { return /*#__PURE__*/React__namespace.createElement("svg", _extends$1({ xmlns: "http://www.w3.org/2000/svg", width: 16, height: 16, focusable: "false", viewBox: "0 0 16 16", "aria-hidden": "true" }, props), _g || (_g = /*#__PURE__*/React__namespace.createElement("g", { fill: "none", stroke: "currentColor" }, /*#__PURE__*/React__namespace.createElement("circle", { cx: 7.5, cy: 8.5, r: 7 }), /*#__PURE__*/React__namespace.createElement("path", { strokeLinecap: "round", d: "M7.5 4.5V9" }))), _circle || (_circle = /*#__PURE__*/React__namespace.createElement("circle", { cx: 7.5, cy: 12, r: 1, fill: "currentColor" }))); }; const StyledDangerIcon = styled__default.default(SvgAlertErrorStroke).withConfig({ displayName: "StyledDangerIcon", componentId: "sc-1kwbb39-0" })(["position:absolute;top:", "px;", ":", ";"], props => props.theme.space.base * 5.5, props => props.theme.rtl ? 'right' : 'left', props => `${props.theme.space.base * 4}px`); const COMPONENT_ID$d = 'modals.modal'; const animationName = styled.keyframes(["0%{transform:scale(0);opacity:0;}50%{transform:scale(1.05);}100%{opacity:1;}"]); const animationStyles = props => { if (props.$isAnimated) { return styled.css(["animation:", " 0.3s ease-in;"], animationName); } return ''; }; const colorStyles$1 = _ref => { let { theme } = _ref; const offsetY = `${theme.space.base * 5}px`; const blurRadius = `${theme.space.base * 7}px`; const shadowColor = reactTheming.getColor({ variable: 'shadow.large', theme }); const shadow = theme.shadows.lg(offsetY, blurRadius, shadowColor); const borderColor = reactTheming.getColor({ theme, variable: 'border.default' }); const backgroundColor = reactTheming.getColor({ theme, variable: 'background.raised' }); return styled.css(["border-color:", ";box-shadow:", ";background-color:", ";"], borderColor, shadow, backgroundColor); }; const sizeStyles$2 = props => { return styled.css(["", "{width:", ";}"], reactTheming.mediaQuery('up', props.$isLarge ? 'md' : 'sm', props.theme), props.$isLarge ? props.theme.breakpoints.md : props.theme.breakpoints.sm); }; const StyledModal = styled__default.default.div.attrs({ 'data-garden-id': COMPONENT_ID$d, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledModal", componentId: "sc-1pe1axu-0" })(["display:flex;position:fixed;flex-direction:column;animation-delay:0.01s;margin:", ";border:", ";border-radius:", ";min-height:60px;max-height:calc(100vh - ", "px);overflow:auto;direction:", ";", ";", ";", ";&:focus{outline:none;}@media (max-height:399px){top:", "px;bottom:auto;margin-bottom:", "px;max-height:calc(100vh - ", "px);}@media screen and (-ms-high-contrast:active),screen and (-ms-high-contrast:none){right:", ";bottom:", ";transform:", ";}", ";"], props => props.$isCentered ? '0' : `${props.theme.space.base * 12}px`, props => props.theme.borders.sm, props => props.theme.borderRadii.md, props => props.theme.space.base * 24, props => props.theme.rtl && 'rtl', animationStyles, sizeStyles$2, colorStyles$1, props => props.theme.space.base * 6, props => props.theme.space.base * 6, props => props.theme.space.base * 12, props => props.$isCentered && '50%', props => props.$isCentered && '50%', props => props.$isCentered && 'translate(50%, 50%)', reactTheming.componentStyles); StyledModal.propTypes = { $isLarge: PropTypes__default.default.bool, $isAnimated: PropTypes__default.default.bool }; const COMPONENT_ID$c = 'modals.tooltip_dialog.backdrop'; const StyledTooltipDialogBackdrop = styled__default.default.div.attrs({ 'data-garden-id': COMPONENT_ID$c, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledTooltipDialogBackdrop", componentId: "sc-zrk625-0" })(["position:fixed;inset:0;z-index:400;overflow:hidden;-webkit-overflow-scrolling:touch;font-family:", ";direction:", ";&.garden-tooltip-modal-transition-exit-active{pointer-events:none;}&.garden-tooltip-modal-transition-exit-active div{transition:opacity 200ms;opacity:0;}", ";"], props => props.theme.fonts.system, props => props.theme.rtl && 'rtl', reactTheming.componentStyles); const StyledTooltipWrapper = styled__default.default.div.attrs(props => ({ className: props.$isAnimated ? 'is-animated' : undefined })).withConfig({ displayName: "StyledTooltipWrapper", componentId: "sc-1xk05kf-0" })(["top:0;left:0;", ";"], props => reactTheming.menuStyles(reactTheming.getMenuPosition(props.$placement), { theme: props.theme, hidden: false, zIndex: props.$zIndex, animationModifier: '.is-animated' })); const COMPONENT_ID$b = 'modals.tooltip_dialog.close'; const StyledTooltipDialogClose = styled__default.default(StyledClose).attrs({ 'data-garden-id': COMPONENT_ID$b, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledTooltipDialogClose", componentId: "sc-18xlgfi-0" })(["top:", "px;", ":", ";", ";"], props => props.theme.space.base * 3.5, props => props.theme.rtl ? 'left' : 'right', props => `${props.theme.space.base * 3}px`, reactTheming.componentStyles); const COMPONENT_ID$a = 'modals.tooltip_dialog'; const sizeStyles$1 = props => ` padding: ${props.theme.space.base * 5}px; width: 400px; &:has(${StyledTooltipDialogClose}) > :first-child { padding-${props.theme.rtl ? 'left' : 'right'}: ${props.theme.space.base * 8}px; } `; const StyledTooltipDialog = styled__default.default.div.attrs(props => ({ 'data-garden-id': COMPONENT_ID$a, 'data-garden-version': '9.11.3', className: props.$isAnimated ? 'is-animated' : undefined })).withConfig({ displayName: "StyledTooltipDialog", componentId: "sc-iv3db-0" })(["", ";", " ", ";"], props => { const computedArrowStyles = reactTheming.arrowStyles(reactTheming.getArrowPosition(props.theme, props.$placement), { size: `${props.theme.space.base * 2}px`, inset: '1px', animationModifier: '.is-animated' }); if (props.$isAnimated) { return props.$hasArrow && props.$transitionState === 'entered' && computedArrowStyles; } return props.$hasArrow && computedArrowStyles; }, sizeStyles$1, reactTheming.componentStyles); const COMPONENT_ID$9 = 'modals.tooltip_dialog.title'; const sizeStyles = props => ` /* stylelint-disable-next-line property-no-unknown */ line-height: ${reactTheming.getLineHeight(props.theme.lineHeights.md, props.theme.fontSizes.md)}; font-size: ${props.theme.fontSizes.md}; `; const StyledTooltipDialogTitle = styled__default.default.div.attrs({ 'data-garden-id': COMPONENT_ID$9, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledTooltipDialogTitle", componentId: "sc-1rceixg-0" })(["margin:0;color:", ";font-weight:", ";", ";", ";"], _ref => { let { theme } = _ref; return reactTheming.getColor({ variable: 'foreground.default', theme }); }, props => props.theme.fontWeights.semibold, props => sizeStyles(props), reactTheming.componentStyles); const COMPONENT_ID$8 = 'modals.tooltip_dialog.body'; const StyledTooltipDialogBody = styled__default.default.div.attrs({ 'data-garden-id': COMPONENT_ID$8, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledTooltipDialogBody", componentId: "sc-132lcoq-0" })(["display:block;margin:0;padding-top:", "px;line-height:", ";color-scheme:only ", ";color:", ";font-size:", ";", ";"], props => props.theme.space.base * 1.5, props => reactTheming.getLineHeight(props.theme.lineHeights.md, props.theme.fontSizes.md), p => p.theme.colors.base, _ref => { let { theme } = _ref; return reactTheming.getColor({ variable: 'foreground.default', theme }); }, props => props.theme.fontSizes.md, reactTheming.componentStyles); const COMPONENT_ID$7 = 'modals.tooltip_dialog.footer'; const StyledTooltipDialogFooter = styled__default.default.div.attrs({ 'data-garden-id': COMPONENT_ID$7, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledTooltipDialogFooter", componentId: "sc-kjomsm-0" })(["display:flex;flex-shrink:0;align-items:center;justify-content:flex-end;padding-top:", "px;", ";"], p => p.theme.space.base * 5, reactTheming.componentStyles); const COMPONENT_ID$6 = 'modals.tooltip_dialog.footer_item'; const StyledTooltipDialogFooterItem = styled__default.default(StyledFooterItem).attrs({ 'data-garden-id': COMPONENT_ID$6, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledTooltipDialogFooterItem", componentId: "sc-u2rmo8-0" })(["", ";"], reactTheming.componentStyles); const COMPONENT_ID$5 = 'modals.drawer_modal'; const DRAWER_WIDTH = 380; const colorStyles = _ref => { let { theme } = _ref; const offsetY = `${theme.space.base * 5}px`; const blurRadius = `${theme.space.base * 7}px`; const shadowColor = reactTheming.getColor({ variable: 'shadow.large', theme }); const shadow = theme.shadows.lg(offsetY, blurRadius, shadowColor); const borderColor = reactTheming.getColor({ theme, variable: 'border.default' }); const backgroundColor = reactTheming.getColor({ theme, variable: 'background.raised' }); return styled.css(["border-color:", ";box-shadow:", ";background-color:", ";"], borderColor, shadow, backgroundColor); }; const StyledDrawer = styled__default.default.div.attrs({ 'data-garden-id': COMPONENT_ID$5, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledDrawer", componentId: "sc-zp66t3-0" })(["display:flex;position:fixed;top:0;", ":0;flex-direction:column;z-index:500;", ":", ";width:", "px;height:100%;overflow:auto;-webkit-overflow-scrolling:touch;font-family:", ";direction:", ";&.garden-drawer-transition-enter{transform:translateX(", "px);}&.garden-drawer-transition-enter-active{transform:translateX(0);transition:transform 0.25s ease-in-out;}&.garden-drawer-transition-exit-active{transform:translateX(", "px);transition:transform 0.25s ease-in-out;}&:focus{outline:none;}", " ", ";"], props => props.theme.rtl ? 'left' : 'right', props => props.theme.rtl ? 'border-right' : 'border-left', props => props.theme.borders.sm, DRAWER_WIDTH, props => props.theme.fonts.system, props => props.theme.rtl && 'rtl', props => props.theme.rtl ? -DRAWER_WIDTH : DRAWER_WIDTH, props => props.theme.rtl ? -DRAWER_WIDTH : DRAWER_WIDTH, colorStyles, reactTheming.componentStyles); const COMPONENT_ID$4 = 'modals.drawer_modal.close'; const BASE_MULTIPLIERS = { top: BASE_MULTIPLIERS$1.top, side: 2, size: BASE_MULTIPLIERS$1.size }; const StyledDrawerClose = styled__default.default(StyledClose).attrs({ 'data-garden-id': COMPONENT_ID$4, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledDrawerClose", componentId: "sc-1a0xt3x-0" })(["", ":", ";", ";"], props => props.theme.rtl ? 'left' : 'right', props => `${props.theme.space.base * BASE_MULTIPLIERS.side}px`, reactTheming.componentStyles); const COMPONENT_ID$3 = 'modals.drawer_modal.header'; const StyledDrawerHeader = styled__default.default(StyledHeader).attrs({ 'data-garden-id': COMPONENT_ID$3, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledDrawerHeader", componentId: "sc-y4mgkj-0" })(["padding:", "px;", " ", ";"], props => props.theme.space.base * 5, props => props.$isCloseButtonPresent && `padding-${props.theme.rtl ? 'left' : 'right'}: ${props.theme.space.base * (BASE_MULTIPLIERS.size + BASE_MULTIPLIERS.side + 2)}px;`, reactTheming.componentStyles); const COMPONENT_ID$2 = 'modals.drawer_modal.body'; const StyledDrawerBody = styled__default.default(StyledBody).attrs({ 'data-garden-id': COMPONENT_ID$2, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledDrawerBody", componentId: "sc-13qufyn-0" })(["padding:", "px;color-scheme:only ", ";", ";"], props => props.theme.space.base * 5, p => p.theme.colors.base, reactTheming.componentStyles); const COMPONENT_ID$1 = 'modals.drawer_modal.footer'; const StyledDrawerFooter = styled__default.default.div.attrs({ 'data-garden-id': COMPONENT_ID$1, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledDrawerFooter", componentId: "sc-kc7e6p-0" })(["display:flex;flex-shrink:0;justify-content:flex-end;border-top:", ";padding:", "px;", ";"], _ref => { let { theme } = _ref; return `${theme.borders.sm} ${reactTheming.getColor({ theme, variable: 'border.subtle' })}`; }, props => props.theme.space.base * 5, reactTheming.componentStyles); const COMPONENT_ID = 'modals.drawer_modal.footer_item'; const StyledDrawerFooterItem = styled__default.default(StyledFooterItem).attrs({ 'data-garden-id': COMPONENT_ID, 'data-garden-version': '9.11.3' }).withConfig({ displayName: "StyledDrawerFooterItem", componentId: "sc-m2yul4-0" })(["", ";"], reactTheming.componentStyles); const ModalsContext = React.createContext(undefined); const useModalContext = () => { const context = React.useContext(ModalsContext); if (context === undefined) { throw new Error('useModalContext must be used within a ModalsContext.Provider'); } return context; }; const Body$2 = React.forwardRef((props, ref) => { const { getContentProps } = useModalContext(); return React__namespace.default.createElement(StyledBody, Object.assign({}, getContentProps(props), { ref: ref })); }); Body$2.displayName = 'Modal.Body'; var _path; 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); } var SvgXStroke = function SvgXStroke(props) { return /*#__PURE__*/React__namespace.createElement("svg", _extends({ xmlns: "http://www.w3.org/2000/svg", width: 16, height: 16, focusable: "false", viewBox: "0 0 16 16", "aria-hidden": "true" }, props), _path || (_path = /*#__PURE__*/React__namespace.createElement("path", { stroke: "currentColor", strokeLinecap: "round", d: "M3 13L13 3m0 10L3 3" }))); }; const Close$2 = React.forwardRef((props, ref) => { const { getCloseProps, setIsCloseButtonPresent } = useModalContext(); React.useEffect(() => { setIsCloseButtonPresent(true); return () => setIsCloseButtonPresent(false); }); const ariaLabel = reactTheming.useText(Close$2, props, 'aria-label', 'Close modal', props['aria-describedby'] === undefined ); return React__namespace.default.createElement(StyledClose, Object.assign({}, getCloseProps({ ...props, 'aria-label': ariaLabel }), { ref: ref }), React__namespace.default.createElement(SvgXStroke, null)); }); Close$2.displayName = 'Modal.Close'; const Footer$2 = React__namespace.default.forwardRef((props, ref) => { const { isLarge } = useModalContext(); return React__namespace.default.createElement(StyledFooter, Object.assign({ ref: ref, $isLarge: isLarge }, props)); }); Footer$2.displayName = 'Modal.Footer'; const FooterItem$2 = React__namespace.default.forwardRef((props, ref) => React__namespace.default.createElement(StyledFooterItem, Object.assign({ ref: ref }, props))); FooterItem$2.displayName = 'Modal.FooterItem'; const Header$1 = React.forwardRef((_ref, ref) => { let { children, isDanger, tag = 'div', ...other } = _ref; const { isCloseButtonPresent, hasHeader, setHasHeader, getTitleProps } = useModalContext(); React.useEffect(() => { if (!hasHeader && setHasHeader) { setHasHeader(true); } return () => { if (hasHeader && setHasHeader) { setHasHeader(false); } }; }, [hasHeader, setHasHeader]); return React__namespace.default.createElement(StyledHeader, Object.assign({}, getTitleProps(other), { as: tag, $isCloseButtonPresent: isCloseButtonPresent, $isDanger: isDanger, ref: ref }), !!isDanger && React__namespace.default.createElement(StyledDangerIcon, null), children); }); Header$1.displayName = 'Modal.Header'; Header$1.propTypes = { isDanger: PropTypes__default.default.bool, tag: PropTypes__default.default.any }; const isOverflowing = element => { const doc = ownerDocument__default.default(element); const win = ownerWindow__default.default(doc); const isBody = element && element.tagName.toLowerCase() === 'body'; if (!isWindow__default.default(doc) && !isBody) { return element.scrollHeight > element.clientHeight; } const style = win.getComputedStyle(doc.body); const marginLeft = parseInt(style.getPropertyValue('margin-left'), 10); const marginRight = parseInt(style.getPropertyValue('margin-right'), 10); return marginLeft + doc.body.clientWidth + marginRight < win.innerWidth; }; const ModalComponent = React.forwardRef((_ref, ref) => { let { backdropProps, children, onClose, isLarge, isCentered = true, isAnimated = true, id, appendToNode, focusOnMount, restoreFocus, ...modalProps } = _ref; const theme = React.useContext(styled.ThemeContext); const modalRef = React.useRef(null); const environment = reactTheming.useDocument(theme); const [isCloseButtonPresent, setIsCloseButtonPresent] = React.useState(false); const [hasHeader, setHasHeader] = React.useState(false); const { getBackdropProps, getModalProps, getTitleProps, getContentProps, getCloseProps } = containerModal.useModal({ idPrefix: id, onClose, modalRef, focusOnMount, restoreFocus }); React.useEffect(() => { if (!environment) { return undefined; } const htmlElement = environment.querySelector('html'); const bodyElement = environment.querySelector('body'); let previousHtmlOverflow; let previousBodyPaddingRight; if (bodyElement) { if (isOverflowing(bodyElement)) { const scrollbarSize = getScrollbarSize__default.default(); const bodyPaddingRight = parseInt(css__default.default(bodyElement, 'paddingRight') || '0', 10); previousBodyPaddingRight = bodyElement.style.paddingRight; bodyElement.style.paddingRight = `${bodyPaddingRight + scrollbarSize}px`; } if (htmlElement) { previousHtmlOverflow = htmlElement.style.overflow; htmlElement.style.overflow = 'hidden'; } return () => { if (htmlElement) { htmlElement.style.overflow = previousHtmlOverflow; } bodyElement.style.paddingRight = previousBodyPaddingRight; }; } return undefined; }, [environment]); const rootNode = React.useMemo(() => { if (appendToNode) { return appendToNode; } if (environment) { return environment.body; } return undefined; }, [appendToNode, environment]); const value = React.useMemo(() => ({ isLarge, isCloseButtonPresent, hasHeader, setHasHeader, getTitleProps, getContentProps, getCloseProps, setIsCloseButtonPresent }), [isLarge, hasHeader, isCloseButtonPresent, getTitleProps, getContentProps, getCloseProps]); const modalContainerProps = getModalProps({ 'aria-describedby': undefined, ...(hasHeader ? {} : { 'aria-labelledby': undefined }) }); const attribute = hasHeader ? 'aria-labelledby' : 'aria-label'; const defaultValue = hasHeader ? modalContainerProps['aria-labelledby'] : 'Modal dialog'; const labelValue = hasHeader ? modalContainerProps['aria-labelledby'] : modalProps['aria-label']; const ariaProps = { [attribute]: reactTheming.useText(ModalComponent, { [attribute]: labelValue }, attribute, defaultValue, modalRef.current !== null ) }; if (!rootNode) { return null; } return ReactDOM.createPortal(React__namespace.default.createElement(ModalsContext.Provider, { value: value }, React__namespace.default.createElement(StyledBackdrop, Object.assign({ $isCentered: isCentered, $isAnimated: isAnimated }, getBackdropProps(backdropProps)), React__namespace.default.createElement(StyledModal, Object.assign({ $isCentered: isCentered, $isAnimated: isAnimated, $isLarge: isLarge }, modalContainerProps, ariaProps, modalProps, { ref: reactMergeRefs.mergeRefs([ref, modalRef]) }), children))), rootNode); }); ModalComponent.displayName = 'Modal'; ModalComponent.propTypes = { backdropProps: PropTypes__default.default.object, isLarge: PropTypes__default.default.bool, isAnimated: PropTypes__default.default.bool, isCentered: PropTypes__default.default.bool, focusOnMount: PropTypes__default.default.bool, restoreFocus: PropTypes__default.default.bool, onClose: PropTypes__default.default.func, appendToNode: PropTypes__default.default.any }; const Modal = ModalComponent; Modal.Body = Body$2; Modal.Close = Close$2; Modal.Footer = Footer$2; Modal.FooterItem = FooterItem$2; Modal.Header = Header$1; const TooltipDialogContext = React.createContext(undefined); const useTooltipDialogContext = () => { const context = React.useContext(TooltipDialogContext); if (context === undefined) { throw new Error('Element must be used within a TooltipDialog component.'); } return context; }; const PLACEMENT = ['auto', ...reactTheming.PLACEMENT]; const TitleComponent = React.forwardRef((_ref, ref) => { let { children, tag = 'div', ...other } = _ref; const { getTitleProps, hasTitle, setHasTitle } = useTooltipDialogContext(); React.useEffect(() => { if (!hasTitle && setHasTitle) { setHasTitle(true); } return () => { if (hasTitle && setHasTitle) { setHasTitle(false); } }; }, [hasTitle, setHasTitle]); return React__namespace.default.createElement(StyledTooltipDialogTitle, Object.assign({}, getTitleProps(other), { as: tag, ref: ref }), children); }); TitleComponent.displayName = 'TooltipDialog.Title'; TitleComponent.propTypes = { tag: PropTypes__default.default.any }; const Title = TitleComponent; const BodyComponent$1 = React.forwardRef((props, ref) => { const { getContentProps } = useTooltipDialogContext(); return React__namespace.default.createElement(StyledTooltipDialogBody, Object.assign({}, getContentProps(props), { ref: ref })); }); BodyComponent$1.displayName = 'TooltipDialog.Body'; const Body$1 = BodyComponent$1; const CloseComponent$1 = React.forwardRef((props, ref) => { const { getCloseProps } = useTooltipDialogContext(); const ariaLabel = reactTheming.useText(CloseComponent$1, props, 'aria-label', 'Close tooltip', props['aria-describedby'] === undefined ); return React__namespace.default.createElement(StyledTooltipDialogClose, Object.assign({}, getCloseProps({ ...props, 'aria-label': ariaLabel }), { ref: ref, size: "small" }), React__namespace.default.createElement(SvgXStroke, null)); }); CloseComponent$1.displayName = 'TooltipDialog.Close'; const Close$1 = CloseComponent$1; const FooterComponent$1 = React.forwardRef((props, ref) => React__namespace.default.createElement(StyledTooltipDialogFooter, Object.assign({ ref: ref }, props))); FooterComponent$1.displayName = 'TooltipDialog.Footer'; const Footer$1 = FooterComponent$1; const FooterItemComponent$1 = React.forwardRef((props, ref) => React__namespace.default.createElement(StyledTooltipDialogFooterItem, Object.assign({ ref: ref }, props))); FooterItemComponent$1.displayName = 'TooltipDialog.FooterItem'; const FooterItem$1 = FooterItemComponent$1; const PLACEMENT_DEFAULT = 'top'; const TooltipDialogComponent = React__namespace.default.forwardRef((_ref, ref) => { let { appendToNode, referenceElement, placement: _placement = 'auto', fallbackPlacements: _fallbackPlacements, offset: _offset, onClose, hasArrow = true, isAnimated, zIndex, backdropProps, focusOnMount = true, restoreFocus = true, id, ...props } = _ref; const theme = React.useContext(styled.ThemeContext) || reactTheming.DEFAULT_THEME; const previousReferenceElementRef = React.useRef(); const modalRef = React.useRef(null); const transitionRef = React.useRef(null); const [floatingElement, setFloatingElement] = React.useState(); const [hasTitle, setHasTitle] = React.useState(false); const { getTitleProps, getCloseProps, getContentProps, getBackdropProps, getModalProps } = containerModal.useModal({ idPrefix: id, onClose, modalRef, focusOnMount, restoreFocus: false }); const [floatingPlacement, fallbackPlacements] = reactTheming.getFloatingPlacements(theme, _placement === 'auto' ? PLACEMENT_DEFAULT : _placement, _fallbackPlacements); const { refs, placement, update, floatingStyles: { transform } } = reactDom.useFloating({ platform: { ...reactDom.platform, isRTL: () => theme.rtl }, elements: { reference: referenceElement, floating: floatingElement }, placement: floatingPlacement, middleware: [reactDom.offset(_offset === undefined ? theme.space.base * 3 : _offset), _placement === 'auto' ? reactDom.autoPlacement() : reactDom.flip({ fallbackPlacements })] }); React.useEffect(() => { let cleanup; if (referenceElement && floatingElement && refs.reference.current && refs.floating.current) { cleanup = reactDom.autoUpdate(refs.reference.current, refs.floating.current, update, { elementResize: typeof ResizeObserver === 'function' }); } return () => cleanup && cleanup(); }, [referenceElement, floatingElement, refs.reference, refs.floating, update]); React.useEffect(() => { if (!referenceElement && previousReferenceElementRef.current && restoreFocus) { previousReferenceElementRef.current.focus(); } previousReferenceElementRef.current = referenceElement; }, [referenceElement, restoreFocus]); const modalProps = getModalProps({ 'aria-describedby': undefined, ...(hasTitle ? {} : { 'aria-labelledby': undefined }) }); const attribute = hasTitle ? 'aria-labelledby' : 'aria-label'; const defaultValue = hasTitle ? modalProps['aria-labelledby'] : 'Modal dialog'; const labelValue = hasTitle ? modalProps['aria-labelledby'] : props['aria-label']; const ariaProps = { [attribute]: reactTheming.useText(TooltipDialogComponent, { [attribute]: labelValue }, attribute, defaultValue, modalRef.current !== null ) }; const value = { hasTitle, setHasTitle, getTitleProps, getContentProps, getCloseProps }; const Node = React__namespace.default.createElement(reactTransitionGroup.CSSTransition, { unmountOnExit: true, timeout: isAnimated ? 200 : 0, in: Boolean(referenceElement), classNames: isAnimated ? 'garden-tooltip-modal-transition' : '', nodeRef: transitionRef }, transitionState => { return React__namespace.default.createElement(TooltipDialogContext.Provider, { value: value }, React__namespace.default.createElement(StyledTooltipDialogBackdrop, Object.assign({}, getBackdropProps(), backdropProps, { ref: transitionRef }), React__namespace.default.createElement(StyledTooltipWrapper, { ref: setFloatingElement, style: { transform }, $placement: placement, $zIndex: zIndex, $isAnimated: isAnimated }, React__namespace.default.createElement(StyledTooltipDialog, Object.assign({ $transitionState: transitionState, $placement: placement, $hasArrow: hasArrow, $isAnimated: isAnimated }, modalProps, ariaProps, props, { ref: reactMergeRefs.mergeRefs([modalRef, ref]) }))))); }); return appendToNode ? ReactDOM.createPortal(Node, appendToNode) : Node; }); TooltipDialogComponent.displayName = 'TooltipDialog'; TooltipDialogComponent.propTypes = { appendToNode: PropTypes__default.default.any, referenceElement: PropTypes__default.default.any, placement: PropTypes__default.default.any, fallbackPlacements: PropTypes__default.default.arrayOf(PropTypes__default.default.oneOf(PLACEMENT.filter(placement => placement !== 'auto'))), isAnimated: PropTypes__default.default.bool, hasArrow: PropTypes__default.default.bool, zIndex: PropTypes__default.default.number, onClose: PropTypes__default.default.func, backdropProps: PropTypes__default.default.any, focusOnMount: PropTypes__default.default.bool, restoreFocus: PropTypes__default.default.bool }; const TooltipDialog = TooltipDialogComponent; TooltipDialog.Body = Body$1; TooltipDialog.Close = Close$1; TooltipDialog.Footer = Footer$1; TooltipDialog.FooterItem = FooterItem$1; TooltipDialog.Title = Title; const HeaderComponent = React.forwardRef((_ref, ref) => { let { tag = 'div', ...other } = _ref; const { isCloseButtonPresent, hasHeader, setHasHeader, getTitleProps } = useModalContext(); React.useEffect(() => { if (!hasHeader && setHasHeader) { setHasHeader(true); } return () => { if (hasHeader && setHasHeader) { setHasHeader(false); } }; }, [hasHeader, setHasHeader]); return React__namespace.default.createElement(StyledDrawerHeader, Object.assign({}, getTitleProps(other), { as: tag, $isCloseButtonPresent: isCloseButtonPresent, ref: ref })); }); HeaderComponent.displayName = 'Drawer.Header'; HeaderComponent.propTypes = { tag: PropTypes__default.default.any }; const Header = HeaderComponent; const BodyComponent = React.forwardRef((props, ref) => { const { getContentProps } = useModalContext(); return React__namespace.default.createElement(StyledDrawerBody, Object.assign({}, getContentProps(props), { ref: ref }), props.children); }); BodyComponent.displayName = 'Drawer.Body'; const Body = BodyComponent; const CloseComponent = React.forwardRef((props, ref) => { const { getCloseProps, setIsCloseButtonPresent } = useModalContext(); React.useEffect(() => { setIsCloseButtonPresent(true); return () => setIsCloseButtonPresent(false); }); const ariaLabel = reactTheming.useText(CloseComponent, props, 'aria-label', 'Close drawer', props['aria-describedby'] === undefined ); return React__namespace.default.createElement(StyledDrawerClose, Object.assign({}, getCloseProps({ ...props, 'aria-label': ariaLabel }), { ref: ref }), React__namespace.default.createElement(SvgXStroke, null)); }); CloseComponent.displayName = 'Drawer.Close'; const Close = CloseComponent; const FooterComponent = React.forwardRef((props, ref) => React__namespace.default.createElement(StyledDrawerFooter, Object.assign({ ref: ref }, props))); FooterComponent.displayName = 'Drawer.Footer'; const Footer = FooterComponent; const FooterItemComponent = React.forwardRef((props, ref) => React__namespace.default.createElement(StyledDrawerFooterItem, Object.assign({ ref: ref }, props))); FooterItemComponent.displayName = 'Drawer.FooterItem'; const FooterItem = FooterItemComponent; const DrawerComponent = React.forwardRef((_ref, ref) => { let { id, isOpen, onClose, backdropProps, appendToNode, focusOnMount = true, restoreFocus = true, ...props } = _ref; const modalRef = React.useRef(null); const transitionRef = React.useRef(null); const triggerRef = React.useRef(null); const theme = React.useContext(styled.ThemeContext); const environment = reactTheming.useDocument(theme); const [isCloseButtonPresent, setIsCloseButtonPresent] = React.useState(false); const [hasHeader, setHasHeader] = React.useState(false); const { getTitleProps, getCloseProps, getContentProps, getBackdropProps, getModalProps } = containerModal.useModal({ idPrefix: id, modalRef, focusOnMount: false , restoreFocus: false , environment, onClose }); React.useEffect(() => { if (environment) { if (isOpen && modalRef.current) { if (restoreFocus) { triggerRef.current = activeElement__default.default(environment); } if (focusOnMount) { modalRef.current.focus(); } } if (!isOpen && triggerRef.current) { triggerRef.current.focus(); } } return () => { if (!(restoreFocus && isOpen)) { triggerRef.current = null; } }; }, [environment, restoreFocus, focusOnMount, isOpen]); React.useEffect(() => { if (!environment) { return undefined; } const htmlElement = environment.querySelector('html'); let previousHtmlOverflow; if (htmlElement && isOpen) { previousHtmlOverflow = htmlElement.style.overflow; htmlElement.style.overflow = 'hidden'; } return () => { if (htmlElement && isOpen) { htmlElement.style.overflow = previousHtmlOverflow; } }; }, [environment, isOpen]); const rootNode = React.useMemo(() => { if (appendToNode) { return appendToNode; } if (environment) { return environment.body; } return undefined; }, [appendToNode, environment]); const value = React.useMemo(() => ({ isCloseButtonPresent, hasHeader, setHasHeader, getTitleProps, getContentProps, getCloseProps, setIsCloseButtonPresent }), [isCloseButtonPresent, hasHeader, getTitleProps, getContentProps, getCloseProps]); const modalProps = getModalProps({ 'aria-describedby': undefined, ...(hasHeader ? {} : { 'aria-labelledby': undefined }) }); const attribute = hasHeader ? 'aria-labelledby' : 'aria-label'; const defaultValue = hasHeader ? modalProps['aria-labelledby'] : 'Modal dialog'; const labelValue = hasHeader ? modalProps['aria-labelledby'] : props['aria-label']; const ariaProps = { [attribute]: reactTheming.useText(DrawerComponent, { [attribute]: labelValue }, attribute, defaultValue, modalRef.current !== null ) }; if (!rootNode) { return null; } return ReactDOM__default.default.createPortal(React__namespace.default.createElement(ModalsContext.Provider, { value: value }, React__namespace.default.createElement(reactTransitionGroup.CSSTransition, { in: isOpen, timeout: 250, unmountOnExit: true, classNames: "garden-drawer-transition", nodeRef: transitionRef }, React__namespace.default.createElement(StyledBackdrop, Object.assign({ $isAnimated: true }, getBackdropProps(backdropProps)), React__namespace.default.createElement(StyledDrawer, Object.assign({}, modalProps, ariaProps, props, { ref: reactMergeRefs.mergeRefs([ref, modalRef, transitionRef]) }))))), rootNode); }); DrawerComponent.displayName = 'Drawer'; DrawerComponent.propTypes = { backdropProps: PropTypes__default.default.object, focusOnMount: PropTypes__default.default.bool, restoreFocus: PropTypes__default.default.bool, onClose: PropTypes__default.default.func, appendToNode: PropTypes__default.default.any, isOpen: PropTypes__default.default.bool }; const Drawer = DrawerComponent; Drawer.Body = Body; Drawer.Close = Close; Drawer.Footer = Footer; Drawer.FooterItem = FooterItem; Drawer.Header = Header; exports.Body = Body$2; exports.Close = Close$2; exports.Drawer = Drawer; exports.Footer = Footer$2; exports.FooterItem = FooterItem$2; exports.Header = Header$1; exports.Modal = Modal; exports.PLACEMENT = PLACEMENT; exports.TooltipDialog = TooltipDialog;