UNPKG

@awsui/components-react

Version:

On July 19th, 2022, we launched [Cloudscape Design System](https://cloudscape.design). Cloudscape is an evolution of AWS-UI. It consists of user interface guidelines, front-end components, design resources, and development tools for building intuitive, en

106 lines 6.18 kB
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import React, { useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'; import clsx from 'clsx'; import { Portal, useMergeRefs, useUniqueId } from '@awsui/component-toolkit/internal'; import { useSingleTabStopNavigation } from '@awsui/component-toolkit/internal'; import { useInternalI18n } from '../i18n/context'; import { getBaseProps } from '../internal/base-component'; import { getFirstFocusable } from '../internal/components/focus-lock/utils'; import { LinkDefaultVariantContext } from '../internal/context/link-default-variant-context'; import ResetContextsForModal from '../internal/context/reset-contexts-for-modal'; import { fireNonCancelableEvent } from '../internal/events/index'; import { usePortalModeClasses } from '../internal/hooks/use-portal-mode-classes'; import { KeyCode } from '../internal/keycode'; import Arrow from './arrow'; import PopoverBody from './body'; import ConditionalLiveRegion from './conditional-live-region'; import PopoverContainer from './container'; import styles from './styles.css.js'; export default React.forwardRef(InternalPopover); function InternalPopover({ position = 'right', size = 'medium', fixedWidth = false, triggerType = 'text', dismissButton = true, children, header, content, triggerAriaLabel, wrapTriggerText = true, isInline = false, renderWithPortal = false, __onOpen, __internalRootRef, __closeAnalyticsAction, ...restProps }, ref) { const baseProps = getBaseProps(restProps); const triggerRef = useRef(null); const popoverRef = useRef(null); const i18n = useInternalI18n('popover'); const dismissAriaLabel = i18n('dismissAriaLabel', restProps.dismissAriaLabel); const [visible, setVisible] = useState(false); const focusTrigger = useCallback(() => { var _a, _b; if (['text', 'text-inline'].includes(triggerType)) { (_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus(); } else if (triggerRef.current) { (_b = getFirstFocusable(triggerRef.current)) === null || _b === void 0 ? void 0 : _b.focus(); } }, [triggerType]); const onTriggerClick = useCallback(() => { fireNonCancelableEvent(__onOpen); setVisible(true); }, [__onOpen]); const onDismiss = useCallback(() => { setVisible(false); focusTrigger(); }, [focusTrigger]); const onTriggerKeyDown = useCallback((event) => { const isEscapeKey = event.keyCode === KeyCode.escape; const isTabKey = event.keyCode === KeyCode.tab; if (isEscapeKey && visible) { event.stopPropagation(); } if (isTabKey || isEscapeKey) { setVisible(false); } }, [visible]); useImperativeHandle(ref, () => ({ dismiss: () => { setVisible(false); }, focus: () => { setVisible(false); focusTrigger(); }, })); const clickFrameId = useRef(null); useEffect(() => { if (!triggerRef.current) { return; } const document = triggerRef.current.ownerDocument; const onDocumentClick = () => { // Dismiss popover unless there was a click inside within the last animation frame. if (clickFrameId.current === null) { setVisible(false); } }; document.addEventListener('mousedown', onDocumentClick); return () => { document.removeEventListener('mousedown', onDocumentClick); }; }, []); const popoverClasses = usePortalModeClasses(triggerRef); const triggerProps = { // https://github.com/microsoft/TypeScript/issues/36659 ref: triggerRef, onClick: onTriggerClick, onKeyDown: onTriggerKeyDown, className: clsx(styles.trigger, styles[`trigger-type-${triggerType}`]), }; const { tabIndex: triggerTabIndex } = useSingleTabStopNavigation(triggerRef); const referrerId = useUniqueId(); const popoverContent = (React.createElement("div", { className: clsx(popoverClasses, !renderWithPortal && styles['popover-inline-content']), "data-awsui-referrer-id": referrerId }, React.createElement(PopoverContainer, { size: size, fixedWidth: fixedWidth, position: position, trackRef: triggerRef, arrow: position => React.createElement(Arrow, { position: position }), renderWithPortal: renderWithPortal, zIndex: renderWithPortal ? 7000 : undefined }, React.createElement(LinkDefaultVariantContext.Provider, { value: { defaultVariant: 'primary' } }, React.createElement(PopoverBody, { dismissButton: dismissButton, dismissAriaLabel: dismissAriaLabel, header: header, onDismiss: onDismiss, overflowVisible: "both", closeAnalyticsAction: __closeAnalyticsAction }, React.createElement(ConditionalLiveRegion, { condition: !dismissButton }, content)))))); const mergedRef = useMergeRefs(popoverRef, __internalRootRef); return (React.createElement("span", { ...baseProps, className: clsx(styles.root, baseProps.className, triggerType === 'filtering-token' && styles['root-filtering-token'], isInline && styles['no-wrap']), ref: mergedRef, onMouseDown: () => { // Indicate there was a click inside popover recently, including nested portals. clickFrameId.current = requestAnimationFrame(() => { clickFrameId.current = null; }); } }, ['text', 'text-inline'].includes(triggerType) ? (React.createElement("button", { ...triggerProps, className: clsx(triggerProps.className, wrapTriggerText === false && styles['overflow-ellipsis']), tabIndex: triggerTabIndex, type: "button", "aria-haspopup": "dialog", id: referrerId, "aria-label": triggerAriaLabel }, children)) : (React.createElement("span", { ...triggerProps, id: referrerId }, children)), visible && (React.createElement(ResetContextsForModal, null, renderWithPortal ? React.createElement(Portal, null, popoverContent) : popoverContent)))); } //# sourceMappingURL=internal.js.map