All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.src.components.Page.Page.tsx Maven / Gradle / Ivy

Go to download

This library provides a set of common React components for use with the PatternFly reference implementation.

The newest version!
import * as React from 'react';
import styles from '@patternfly/react-styles/css/components/Page/page';
import { css } from '@patternfly/react-styles';
import globalBreakpointXl from '@patternfly/react-tokens/dist/esm/global_breakpoint_xl';
import { debounce, canUseDOM } from '../../helpers/util';
import { Drawer, DrawerContent, DrawerContentBody, DrawerPanelContent } from '../Drawer';
import { PageBreadcrumbProps } from './PageBreadcrumb';
import { PageGroup, PageGroupProps } from './PageGroup';
import { getResizeObserver } from '../../helpers/resizeObserver';
import { formatBreakpointMods, getBreakpoint, getVerticalBreakpoint } from '../../helpers/util';
import { PageContextProvider } from './PageContext';

export enum PageLayouts {
  vertical = 'vertical',
  horizontal = 'horizontal'
}
export interface PageProps extends React.HTMLProps {
  /** Content rendered inside the main section of the page layout (e.g. ) */
  children?: React.ReactNode;
  /** Additional classes added to the page layout */
  className?: string;
  /** Header component (e.g. ) */
  header?: React.ReactNode;
  /** Sidebar component for a side nav (e.g. ) */
  sidebar?: React.ReactNode;
  /** Notification drawer component for an optional notification drawer (e.g. ) */
  notificationDrawer?: React.ReactNode;
  /** Flag indicating Notification drawer in expanded */
  isNotificationDrawerExpanded?: boolean;
  /** Flag indicating if breadcrumb width should be limited */
  isBreadcrumbWidthLimited?: boolean;
  /** Callback when notification drawer panel is finished expanding. */
  onNotificationDrawerExpand?: (event: KeyboardEvent | React.MouseEvent | React.TransitionEvent) => void;
  /** Skip to content component for the page */
  skipToContent?: React.ReactElement;
  /** Sets the value for role on the 
element */ role?: string; /** an id to use for the [role="main"] element */ mainContainerId?: string; /** tabIndex to use for the [role="main"] element, null to unset it */ mainTabIndex?: number | null; /** * If true, manages the sidebar open/close state and there is no need to pass the isSidebarOpen boolean into * the sidebar component or add a callback onSidebarToggle function into the Masthead component */ isManagedSidebar?: boolean; /** Flag indicating if tertiary nav width should be limited */ isTertiaryNavWidthLimited?: boolean; /** * If true, the managed sidebar is initially open for desktop view */ defaultManagedSidebarIsOpen?: boolean; /** * Can add callback to be notified when resize occurs, for example to set the sidebar isSidebarOpen prop to false for a width < 768px * Returns object { mobileView: boolean, windowSize: number } */ onPageResize?: ((event: MouseEvent | TouchEvent | React.KeyboardEvent, object: any) => void) | null; /** * The page resize observer uses the breakpoints returned from this function when adding the pf-m-breakpoint-[default|sm|md|lg|xl|2xl] class * You can override the default getBreakpoint function to return breakpoints at different sizes than the default * You can view the default getBreakpoint function here: * https://github.com/patternfly/patternfly-react/blob/main/packages/react-core/src/helpers/util.ts */ getBreakpoint?: (width: number | null) => 'default' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'; /** * The page resize observer uses the breakpoints returned from this function when adding the pf-m-breakpoint-[default|sm|md|lg|xl|2xl] class * You can override the default getVerticalBreakpoint function to return breakpoints at different sizes than the default * You can view the default getVerticalBreakpoint function here: * https://github.com/patternfly/patternfly-react/blob/main/packages/react-core/src/helpers/util.ts */ getVerticalBreakpoint?: (height: number | null) => 'default' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'; /** Breadcrumb component for the page */ breadcrumb?: React.ReactNode; /** Tertiary nav component for the page */ tertiaryNav?: React.ReactNode; /** Accessible label, can be used to name main section */ mainAriaLabel?: string; /** Flag indicating if the tertiaryNav should be in a group */ isTertiaryNavGrouped?: boolean; /** Flag indicating if the breadcrumb should be in a group */ isBreadcrumbGrouped?: boolean; /** Additional content of the group */ additionalGroupedContent?: React.ReactNode; /** HTML component used as main component of the page. Defaults to 'main', only pass in 'div' if another 'main' element already exists. */ mainComponent?: 'main' | 'div'; /** Additional props of the group */ groupProps?: PageGroupProps; /** Additional props of the breadcrumb */ breadcrumbProps?: PageBreadcrumbProps; } export interface PageState { desktopIsSidebarOpen: boolean; mobileIsSidebarOpen: boolean; mobileView: boolean; width: number; height: number; } class Page extends React.Component { static displayName = 'Page'; static defaultProps: PageProps = { isManagedSidebar: false, isBreadcrumbWidthLimited: false, defaultManagedSidebarIsOpen: true, mainTabIndex: -1, isNotificationDrawerExpanded: false, onNotificationDrawerExpand: () => null, mainComponent: 'main', getBreakpoint, getVerticalBreakpoint }; mainRef = React.createRef(); pageRef = React.createRef(); observer: any = () => {}; constructor(props: PageProps) { super(props); const { isManagedSidebar, defaultManagedSidebarIsOpen } = props; const managedSidebarOpen = !isManagedSidebar ? true : defaultManagedSidebarIsOpen; this.state = { desktopIsSidebarOpen: managedSidebarOpen, mobileIsSidebarOpen: false, mobileView: false, width: null, height: null }; } componentDidMount() { const { isManagedSidebar, onPageResize } = this.props; if (isManagedSidebar || onPageResize) { this.observer = getResizeObserver(this.pageRef.current, this.handleResize); const currentRef = this.mainRef.current; if (currentRef) { currentRef.addEventListener('mousedown', this.handleMainClick); currentRef.addEventListener('touchstart', this.handleMainClick); } // Initial check if should be shown this.resize(); } } componentWillUnmount() { const { isManagedSidebar, onPageResize } = this.props; if (isManagedSidebar || onPageResize) { this.observer(); const currentRef = this.mainRef.current; if (currentRef) { currentRef.removeEventListener('mousedown', this.handleMainClick); currentRef.removeEventListener('touchstart', this.handleMainClick); } } } getWindowWidth = () => { if (canUseDOM) { return this.pageRef.current ? this.pageRef.current.clientWidth : window.innerWidth; } else { return 1200; } }; isMobile = () => // eslint-disable-next-line radix this.getWindowWidth() < Number.parseInt(globalBreakpointXl.value, 10); resize = (_event?: MouseEvent | TouchEvent | React.KeyboardEvent) => { const { onPageResize } = this.props; const mobileView = this.isMobile(); if (onPageResize) { onPageResize(_event, { mobileView, windowSize: this.getWindowWidth() }); } if (mobileView !== this.state.mobileView) { this.setState({ mobileView }); } if (this.pageRef?.current) { const currentWidth = this.pageRef.current.clientWidth; const currentHeight = this.pageRef.current.clientHeight; if (this.state.width !== currentWidth) { this.setState({ width: currentWidth }); } if (this.state.height !== currentHeight) { this.setState({ height: currentHeight }); } } }; handleResize = debounce(this.resize, 250); handleMainClick = () => { if (this.isMobile() && this.state.mobileIsSidebarOpen && this.mainRef.current) { this.setState({ mobileIsSidebarOpen: false }); } }; onSidebarToggleMobile = () => { this.setState((prevState) => ({ mobileIsSidebarOpen: !prevState.mobileIsSidebarOpen })); }; onSidebarToggleDesktop = () => { this.setState((prevState) => ({ desktopIsSidebarOpen: !prevState.desktopIsSidebarOpen })); }; render() { const { breadcrumb, isBreadcrumbWidthLimited, className, children, header, sidebar, notificationDrawer, isNotificationDrawerExpanded, onNotificationDrawerExpand, isTertiaryNavWidthLimited, skipToContent, role, mainContainerId, isManagedSidebar, // eslint-disable-next-line @typescript-eslint/no-unused-vars defaultManagedSidebarIsOpen, // eslint-disable-next-line @typescript-eslint/no-unused-vars onPageResize, getBreakpoint, getVerticalBreakpoint, mainAriaLabel, mainTabIndex, mainComponent, tertiaryNav, isTertiaryNavGrouped, isBreadcrumbGrouped, additionalGroupedContent, groupProps, breadcrumbProps, ...rest } = this.props; const { mobileView, mobileIsSidebarOpen, desktopIsSidebarOpen, width, height } = this.state; const context = { isManagedSidebar, onSidebarToggle: mobileView ? this.onSidebarToggleMobile : this.onSidebarToggleDesktop, isSidebarOpen: mobileView ? mobileIsSidebarOpen : desktopIsSidebarOpen, width, height, getBreakpoint, getVerticalBreakpoint }; let nav = null; if (tertiaryNav && isTertiaryNavWidthLimited) { nav = (
{tertiaryNav}
); } else if (tertiaryNav) { nav =
{tertiaryNav}
; } const crumb = breadcrumb ? (
{isBreadcrumbWidthLimited ?
{breadcrumb}
: breadcrumb}
) : null; const isGrouped = isTertiaryNavGrouped || isBreadcrumbGrouped || additionalGroupedContent; const group = isGrouped ? ( {isTertiaryNavGrouped && nav} {isBreadcrumbGrouped && crumb} {additionalGroupedContent} ) : null; const Component: keyof JSX.IntrinsicElements = mainComponent; const main = ( {group} {!isTertiaryNavGrouped && nav} {!isBreadcrumbGrouped && crumb} {children} ); const panelContent = {notificationDrawer}; return (
{skipToContent} {header} {sidebar} {notificationDrawer && (
onNotificationDrawerExpand(event)}> {main}
)} {!notificationDrawer && main}
); } } export { Page };




© 2015 - 2024 Weber Informatics LLC | Privacy Policy