UNPKG

@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
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;