@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
138 lines • 10.7 kB
JavaScript
import { __rest } from "tslib";
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useEffect, useRef, useState } from 'react';
import clsx from 'clsx';
import { isDevelopment, warnOnce } from '@awsui/component-toolkit/internal';
import { hasCheckboxItems } from '../button-dropdown/utils/utils';
import { useInternalI18n } from '../i18n/context';
import { getBaseProps } from '../internal/base-component';
import { ButtonTrigger } from '../internal/components/menu-dropdown';
import VisualContext from '../internal/components/visual-context';
import { fireCancelableEvent, isPlainLeftClick } from '../internal/events';
import { useEffectOnUpdate } from '../internal/hooks/use-effect-on-update';
import { checkSafeUrl } from '../internal/utils/check-safe-url';
import OverflowMenu from './parts/overflow-menu';
import Utility from './parts/utility';
import { useTopNavigation } from './use-top-navigation.js';
import styles from './styles.css.js';
export default function InternalTopNavigation(_a) {
var { __internalRootRef, identity, i18nStrings, utilities, search } = _a, restProps = __rest(_a, ["__internalRootRef", "identity", "i18nStrings", "utilities", "search"]);
checkSafeUrl('TopNavigation', identity.href);
const baseProps = getBaseProps(restProps);
const { mainRef, virtualRef, breakpoint, responsiveState, isSearchExpanded, onSearchUtilityClick } = useTopNavigation({ identity, search, utilities });
const [overflowMenuOpen, setOverflowMenuOpen] = useState(false);
const overflowMenuTriggerRef = useRef(null);
const isNarrowViewport = breakpoint === 'default';
const isMediumViewport = breakpoint === 'xxs';
const isLargeViewport = breakpoint === 's';
const i18n = useInternalI18n('top-navigation');
// ButtonDropdown supports checkbox items but we don't support these in TopNavigation. Shown an error in development mode
// to alert users of this and that it might change in the future.
if (isDevelopment) {
if (utilities.some(item => item.type === 'menu-dropdown' && hasCheckboxItems(item.items))) {
warnOnce('TopNavigation', 'The TopNavigation component does not support menu-dropdown items with `itemType` equal to `checkbox`.');
}
}
const onIdentityClick = (event) => {
if (isPlainLeftClick(event)) {
fireCancelableEvent(identity.onFollow, {}, event);
}
};
const toggleOverflowMenu = () => {
setOverflowMenuOpen(overflowMenuOpen => !overflowMenuOpen);
};
const menuTriggerVisible = !isSearchExpanded && responsiveState.hideUtilities;
useEffect(() => {
setOverflowMenuOpen(false);
}, [menuTriggerVisible]);
useEffectOnUpdate(() => {
var _a;
if (!overflowMenuOpen) {
(_a = overflowMenuTriggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
}
}, [overflowMenuOpen]);
// Render the top nav twice; once as the top nav that users can see, and another
// "virtual" top nav used just for calculations. The virtual top nav doesn't react to
// layout changes and renders two sets of utilities: one with labels and one without.
const content = (isVirtual) => {
var _a, _b;
const Wrapper = isVirtual ? 'div' : 'header';
const showIdentity = isVirtual || !isSearchExpanded;
const showTitle = isVirtual || !responsiveState.hideTitle;
const showSearchSlot = search && (isVirtual || !responsiveState.hideSearch || isSearchExpanded);
const showSearchUtility = isVirtual || (search && responsiveState.hideSearch);
const showUtilities = isVirtual || !isSearchExpanded;
const showMenuTrigger = isVirtual || menuTriggerVisible;
return (React.createElement(Wrapper, { ref: isVirtual ? virtualRef : mainRef, "aria-hidden": isVirtual ? true : undefined,
// Wrapper is an alias for "div" or "header".
// eslint-disable-next-line react/forbid-component-props
className: clsx(styles['top-navigation'], {
[styles.virtual]: isVirtual,
[styles.hidden]: isVirtual,
[styles.narrow]: isNarrowViewport,
[styles.medium]: isMediumViewport,
}) },
React.createElement("div", { className: styles['padding-box'] },
showIdentity && (React.createElement("div", { className: clsx(styles.identity, !identity.logo && styles['no-logo']) },
React.createElement("a", { className: styles['identity-link'], href: identity.href, onClick: onIdentityClick },
identity.logo && (React.createElement("img", { role: "img", src: (_a = identity.logo) === null || _a === void 0 ? void 0 : _a.src, alt: (_b = identity.logo) === null || _b === void 0 ? void 0 : _b.alt, className: clsx(styles.logo, {
[styles.narrow]: isNarrowViewport,
}) })),
showTitle && React.createElement("span", { className: styles.title }, identity.title)))),
showSearchSlot && (React.createElement("div", { className: styles.inputs },
React.createElement("div", { className: clsx(styles.search, !isVirtual && isSearchExpanded && styles['search-expanded']) }, search))),
React.createElement("div", { className: styles.utilities },
showSearchUtility && (React.createElement("div", { className: clsx(styles['utility-wrapper'], styles['utility-type-button'], styles['utility-type-button-link'], {
[styles.narrow]: isNarrowViewport,
[styles.medium]: isMediumViewport,
}), "data-utility-special": "search" },
React.createElement(Utility, { hideText: true, definition: {
type: 'button',
iconName: isSearchExpanded ? 'close' : 'search',
ariaLabel: isSearchExpanded
? i18n('i18nStrings.searchDismissIconAriaLabel', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.searchDismissIconAriaLabel)
: i18n('i18nStrings.searchIconAriaLabel', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.searchIconAriaLabel),
onClick: onSearchUtilityClick,
} }))),
showUtilities &&
utilities
.filter((_utility, i) => isVirtual || !responsiveState.hideUtilities || responsiveState.hideUtilities.indexOf(i) === -1)
.map((utility, i) => {
var _a;
const hideText = !!responsiveState.hideUtilityText;
const isLast = (isVirtual || !showMenuTrigger) && i === utilities.length - 1;
const offsetRight = isLast && isLargeViewport ? 'xxl' : isLast ? 'l' : undefined;
return (React.createElement("div", { key: i, className: clsx(styles['utility-wrapper'], styles[`utility-type-${utility.type}`], utility.type === 'button' && styles[`utility-type-button-${(_a = utility.variant) !== null && _a !== void 0 ? _a : 'link'}`], {
[styles.narrow]: isNarrowViewport,
[styles.medium]: isMediumViewport,
}), "data-utility-index": i, "data-utility-hide": `${hideText}` },
React.createElement(Utility, { hideText: hideText, definition: utility, offsetRight: offsetRight })));
}),
isVirtual &&
utilities.map((utility, i) => {
var _a;
const hideText = !responsiveState.hideUtilityText;
const isLast = !showMenuTrigger && i === utilities.length - 1;
const offsetRight = isLast && isLargeViewport ? 'xxl' : isLast ? 'l' : undefined;
return (React.createElement("div", { key: i, className: clsx(styles['utility-wrapper'], styles[`utility-type-${utility.type}`], utility.type === 'button' && styles[`utility-type-button-${(_a = utility.variant) !== null && _a !== void 0 ? _a : 'link'}`], {
[styles.narrow]: isNarrowViewport,
[styles.medium]: isMediumViewport,
}), "data-utility-index": i, "data-utility-hide": `${hideText}` },
React.createElement(Utility, { hideText: hideText, definition: utility, offsetRight: offsetRight })));
}),
showMenuTrigger && (React.createElement("div", { className: clsx(styles['utility-wrapper'], styles['utility-type-menu-dropdown'], {
[styles.narrow]: isNarrowViewport,
[styles.medium]: isMediumViewport,
}), "data-utility-special": "menu-trigger" },
React.createElement(ButtonTrigger, { expanded: overflowMenuOpen, onClick: toggleOverflowMenu, offsetRight: "l", ref: !isVirtual ? overflowMenuTriggerRef : undefined }, i18n('i18nStrings.overflowMenuTriggerText', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.overflowMenuTriggerText))))))));
};
return (React.createElement("div", Object.assign({}, baseProps, { ref: __internalRootRef }),
React.createElement(VisualContext, { contextName: "top-navigation" },
content(true),
content(false),
menuTriggerVisible && overflowMenuOpen && (React.createElement("div", { className: styles['overflow-menu-drawer'] },
React.createElement(OverflowMenu, { headerText: i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.overflowMenuTitleText, dismissIconAriaLabel: i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.overflowMenuDismissIconAriaLabel, backIconAriaLabel: i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.overflowMenuBackIconAriaLabel, items: utilities.filter((utility, i) => (!responsiveState.hideUtilities || responsiveState.hideUtilities.indexOf(i) !== -1) &&
!utility.disableUtilityCollapse), onClose: toggleOverflowMenu }))))));
}
//# sourceMappingURL=internal.js.map