@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
JavaScript
// 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