@awsui/components-react
Version:
AWS UI is a collection of [React](https://reactjs.org/) components that help create intuitive, responsive, and accessible user experiences for web applications. It is developed by Amazon Web Services (AWS). This work is available under the terms of the [A
80 lines (79 loc) • 7.77 kB
JavaScript
import { __assign, __rest } from "tslib";
import clsx from 'clsx';
import React, { useCallback, useImperativeHandle, useLayoutEffect, useState } from 'react';
import { getBaseProps } from '../internal/base-component';
import { useControllable } from '../internal/hooks/use-controllable';
import { useMobile } from '../internal/hooks/use-mobile';
import { fireNonCancelableEvent } from '../internal/events';
import { applyDefaults } from './defaults';
import { Drawer } from './drawer';
import { Notifications } from './notifications';
import { MobileToolbar } from './mobile-toolbar';
import { useObservedElement } from './utils/use-observed-element';
import styles from './styles.css.js';
import { findUpUntil } from '../internal/utils/dom';
import { useTelemetry } from '../internal/hooks/use-telemetry';
import { AppLayoutDomContext } from '../internal/context/app-layout-context';
import { useContainerQuery } from '../internal/hooks/container-queries';
var AppLayout = React.forwardRef(function (_a, ref) {
var _b;
var navigation = _a.navigation, _c = _a.navigationWidth, navigationWidth = _c === void 0 ? 280 : _c, navigationHide = _a.navigationHide, controlledNavigationOpen = _a.navigationOpen, tools = _a.tools, _d = _a.toolsWidth, toolsWidth = _d === void 0 ? 290 : _d, toolsHide = _a.toolsHide, controlledToolsOpen = _a.toolsOpen, breadcrumbs = _a.breadcrumbs, notifications = _a.notifications, stickyNotifications = _a.stickyNotifications, content = _a.content, _e = _a.contentType, contentType = _e === void 0 ? 'default' : _e, disableContentPaddings = _a.disableContentPaddings, disableBodyScroll = _a.disableBodyScroll, maxContentWidth = _a.maxContentWidth, minContentWidth = _a.minContentWidth, _f = _a.headerSelector, headerSelector = _f === void 0 ? '#b #h' : _f, _g = _a.footerSelector, footerSelector = _g === void 0 ? '#b #f' : _g, ariaLabels = _a.ariaLabels, onNavigationChange = _a.onNavigationChange, onToolsChange = _a.onToolsChange, rest = __rest(_a, ["navigation", "navigationWidth", "navigationHide", "navigationOpen", "tools", "toolsWidth", "toolsHide", "toolsOpen", "breadcrumbs", "notifications", "stickyNotifications", "content", "contentType", "disableContentPaddings", "disableBodyScroll", "maxContentWidth", "minContentWidth", "headerSelector", "footerSelector", "ariaLabels", "onNavigationChange", "onToolsChange"]);
useTelemetry('AppLayout');
var baseProps = getBaseProps(rest);
var isMobile = useMobile();
var defaults = applyDefaults(contentType, { maxContentWidth: maxContentWidth, minContentWidth: minContentWidth });
var _h = useControllable(controlledNavigationOpen, onNavigationChange, isMobile ? false : defaults.navigationOpen, { componentName: 'AppLayout', controlledProp: 'navigationOpen', changeHandler: 'onNavigationChange' }), navigationOpen = _h[0], setNavigationOpen = _h[1];
var _j = useState(), activeElement = _j[0], setActiveElement = _j[1];
var _k = useControllable(controlledToolsOpen, onToolsChange, isMobile ? false : defaults.toolsOpen, { componentName: 'AppLayout', controlledProp: 'toolsOpen', changeHandler: 'onToolsChange' }), toolsOpen = _k[0], setToolsOpen = _k[1];
var onNavigationToggle = useCallback(function (open) {
setNavigationOpen(open);
fireNonCancelableEvent(onNavigationChange, { open: open });
}, [setNavigationOpen, onNavigationChange]);
var onToolsToggle = useCallback(function (open) {
setToolsOpen(open);
fireNonCancelableEvent(onToolsChange, { open: open });
}, [setToolsOpen, onToolsChange]);
var onNavigationClick = function (event) {
var hasLink = findUpUntil(event.target, function (node) { return node.tagName === 'A' && !!node.href; });
if (hasLink) {
onNavigationToggle(false);
}
};
var headerHeight = useObservedElement(headerSelector);
var footerHeight = useObservedElement(footerSelector);
var _l = useContainerQuery(function (rect) { return rect.height; }), notificationsHeight = _l[0], notificationsRef = _l[1];
var anyPanelOpen = navigationOpen || toolsOpen;
useLayoutEffect(function () {
setActiveElement(navigationOpen ? 'navigation-close' : 'navigation-toggle');
}, [navigationOpen]);
useLayoutEffect(function () {
setActiveElement(toolsOpen ? 'tools-close' : 'tools-toggle');
}, [toolsOpen]);
useImperativeHandle(ref, function () { return ({
openTools: function () { return onToolsToggle(true); },
closeNavigationIfNecessary: function () {
if (isMobile) {
onNavigationToggle(false);
}
}
}); }, [isMobile, onNavigationToggle, onToolsToggle]);
return (React.createElement("div", __assign({}, baseProps, { className: clsx(styles.root, baseProps.className) }),
React.createElement("div", { className: styles['layout-wrapper'], style: (_b = {},
_b[disableBodyScroll ? 'height' : 'minHeight'] = "calc(100vh - " + headerHeight + "px - " + footerHeight + "px)",
_b) },
isMobile && (React.createElement(MobileToolbar, { anyPanelOpen: anyPanelOpen, activeElement: activeElement, topOffset: headerHeight, ariaLabels: ariaLabels, navigationHide: navigationHide, toolsHide: toolsHide, onNavigationOpen: function () { return onNavigationToggle(true); }, onToolsOpen: function () { return onToolsToggle(true); } }, breadcrumbs)),
React.createElement("div", { className: clsx(styles.layout, disableBodyScroll && styles['layout-no-scroll']) },
!navigationHide && (React.createElement(Drawer, { type: "navigation", isMobile: isMobile, width: navigationWidth, isOpen: navigationOpen, onToggle: onNavigationToggle, activeElement: activeElement, onClick: isMobile ? onNavigationClick : undefined, contentClassName: styles.navigation, closeClassName: styles['navigation-close'], toggleClassName: styles['navigation-toggle'], topOffset: headerHeight, bottomOffset: footerHeight, ariaLabels: ariaLabels }, navigation)),
React.createElement("main", { className: clsx(styles['layout-main'], disableBodyScroll && styles['layout-main-scrollable']) },
notifications && (React.createElement(Notifications, { labels: ariaLabels, topOffset: disableBodyScroll ? 0 : headerHeight, sticky: !isMobile && stickyNotifications, ref: notificationsRef }, notifications)),
React.createElement("div", null,
!isMobile && breadcrumbs && (React.createElement("div", { className: clsx(styles.breadcrumbs, styles['breadcrumbs-desktop']) }, breadcrumbs)),
React.createElement("div", { className: clsx(disableContentPaddings ? undefined : styles['content-wrapper'], isMobile && !disableContentPaddings && styles['content-wrapper-mobile']) },
React.createElement("div", { className: styles.content, style: !isMobile ? { minWidth: defaults.minContentWidth, maxWidth: defaults.maxContentWidth } : undefined },
React.createElement(AppLayoutDomContext.RootProvider, { value: {
stickyOffsetTop: headerHeight + (notificationsHeight || 0),
stickyOffsetBottom: footerHeight
} }, content))))),
!toolsHide && (React.createElement(Drawer, { type: "tools", isMobile: isMobile, width: toolsWidth, isOpen: toolsOpen, onToggle: onToolsToggle, activeElement: activeElement, contentClassName: styles.tools, closeClassName: styles['tools-close'], toggleClassName: styles['tools-toggle'], topOffset: headerHeight, bottomOffset: footerHeight, ariaLabels: ariaLabels }, tools))))));
});
export default AppLayout;