From d4418f5ff83dff33b8ba0f5675a805aa01a4899c Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Sun, 17 Nov 2024 16:07:53 +0100 Subject: [PATCH] WIP(ui-top-nav-bar): some refactoring --- packages/__docs__/src/App/index.tsx | 119 ++++++++++++++++-- .../src/DesktopTopNav/index.tsx | 2 + .../src/DesktopTopNav/styles.tsx | 2 +- .../ui-top-nav-bar/src/MobileTopNav/index.tsx | 1 + .../src/MobileTopNav/styles.tsx | 6 +- packages/ui-top-nav-bar/src/TopNav/README.md | 107 ++++++++++++++++ packages/ui-top-nav-bar/src/TopNav/index.tsx | 113 +++++++++++++++++ packages/ui-top-nav-bar/src/TopNav/props.ts | 35 ++++++ packages/ui-top-nav-bar/src/TopNav/styles.tsx | 97 ++++++++++++++ packages/ui-top-nav-bar/src/index.ts | 1 + 10 files changed, 468 insertions(+), 15 deletions(-) create mode 100644 packages/ui-top-nav-bar/src/TopNav/README.md create mode 100644 packages/ui-top-nav-bar/src/TopNav/index.tsx create mode 100644 packages/ui-top-nav-bar/src/TopNav/props.ts create mode 100644 packages/ui-top-nav-bar/src/TopNav/styles.tsx diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 8800b062d2..08ae229e7e 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/jsx-no-undef */ /* * The MIT License (MIT) * @@ -29,20 +28,21 @@ import { createContext, LegacyRef, ReactElement, - SyntheticEvent, - useEffect, - useState + SyntheticEvent } from 'react' import { Alert } from '@instructure/ui-alerts' import { Breadcrumb } from '@instructure/ui-breadcrumb' -import { Checkbox } from '@instructure/ui-checkbox' import { InstUISettingsProvider, withStyle, jsx } from '@instructure/emotion' import { Flex } from '@instructure/ui-flex' import { Text } from '@instructure/ui-text' import { View } from '@instructure/ui-view' import { AccessibleContent } from '@instructure/ui-a11y-content' -import { MobileTopNav, DesktopTopNav } from '@instructure/ui-top-nav-bar' +import { + MobileTopNav, + DesktopTopNav, + TopNav +} from '@instructure/ui-top-nav-bar' import { IconButton } from '@instructure/ui-buttons' import { Tray } from '@instructure/ui-tray' import { Link } from '@instructure/ui-link' @@ -96,7 +96,7 @@ export const AppContext = createContext({ library: undefined }) -const WrapperComponent = (props) => { +/*const WrapperComponent = (props) => { const [isSmallScreen, setIsSmallScreen] = useState(false) const [isLightMode, setIsLightMode] = useState(false) @@ -345,7 +345,7 @@ const WrapperComponent = (props) => { }, []) return <>{isSmallScreen ? : } -} +}*/ @withStyle(generateStyle, generateComponentTheme) class App extends Component { @@ -395,7 +395,6 @@ class App extends Component { docData.componentInstance = everyComp[components[0]][components[1]] } else { docData.componentInstance = - // eslint-disable-next-line import-x/namespace EveryComponent[docId as keyof typeof EveryComponent] } return docData @@ -426,7 +425,6 @@ class App extends Component { * @returns {Set} the properties */ getAllPropNames(object: Record) { - // eslint-disable-next-line @typescript-eslint/ban-types let obj: object | null = object const props: Set = new Set() // exclude some common static props for performance @@ -983,6 +981,27 @@ class App extends Component { const key = this.state.key const { showMenu, layout, docsData, iconsData } = this.state + const isLightMode = false + + const brandSvg = ( + + + + + + ) + if (!docsData || !iconsData) { return } @@ -1003,7 +1022,85 @@ class App extends Component { boxSizing: 'border-box' }} > - + + + + + Student Forecast + University of Utah + University of Colleges + + + + + + + + + + + + + + +
+ + Back +
+ +
+ Courses + + } + rightIcon={} + onClick={() => alert('Account clicked')} + > + Account + + } + rightIcon={} + onClick={() => alert('Admin clicked')} + > + Admin + + } + rightIcon={} + onClick={() => alert('Dashboard')} + > + Dashboard + + } + onClick={() => alert('Simple option with no left icon')} + > + Simple option with no left icon + + +
+
) diff --git a/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx b/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx index 5250f66576..761efbf422 100644 --- a/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx @@ -103,5 +103,7 @@ const SC: any = withStyles(generateStyles)(DesktopTopNav) SC.BreadCrumb = BreadCrumb // TODO investigate whether displayName should be added to the original component +SC.displayName = 'DesktopTopNav' + export { SC as DesktopTopNav } export default SC diff --git a/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx b/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx index 720f5901f2..1eb62c5721 100644 --- a/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx +++ b/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx @@ -68,7 +68,7 @@ const generateStyles = (props: DesktopTopNavProps, theme: any) => { }, btnRow: { display: 'flex', - gap: '12px' + marginRight: '12px' } } } diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx index ca853b2d98..299d7749a6 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx @@ -177,6 +177,7 @@ SC.ItemList = withStyles(generateItemListStyles)(ItemList) SC.ItemList.displayName = 'ItemList' SC.Item = withStyles(generateItemStyles)(Item) //withStyles(generateItemStyles)(Item) SC.Item.displayName = 'Item' +SC.displayName = 'MobileTopNav' export { SC as MobileTopNav } export default SC diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx index 35cf5253ae..65b2c058d4 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx @@ -27,10 +27,10 @@ import type { MobileTopNavProps } from './props' const generateStyles = (props: MobileTopNavProps, theme: any) => { const { lightMode } = props return { - container: (open: boolean) => { + container: (_open: boolean) => { return { height: '54px', - position: open ? 'fixed' : 'relative', + // position: open ? 'fixed' : 'relative', backgroundColor: lightMode ? theme.colors.ui.surfacePageSecondary : theme.colors.ui.surfaceDark, @@ -38,7 +38,7 @@ const generateStyles = (props: MobileTopNavProps, theme: any) => { ? theme.colors.contrasts.grey125125 : theme.colors?.contrasts?.white1010, width: '100%', - zIndex: '1000' + zIndex: '9999' } }, topBar: { diff --git a/packages/ui-top-nav-bar/src/TopNav/README.md b/packages/ui-top-nav-bar/src/TopNav/README.md new file mode 100644 index 0000000000..32fd6797e8 --- /dev/null +++ b/packages/ui-top-nav-bar/src/TopNav/README.md @@ -0,0 +1,107 @@ +--- +describes: MobileTopNav +--- + +POC mobile top nav + +```js +--- +type: example +--- +const Example = () => { + const lightMode = false + const brandSvg = ( + + + + + + ) + return ( +
+

+ 1 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 2 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 3 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 4 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 5 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 6 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 7 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 8 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 9 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 10 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 11 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 12 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 13 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 14 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 15 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 16 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 17 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 18 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 19 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+

+ 20 + Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum labore eligendi architecto asperiores, dolor quisquam sequi mollitia quibusdam, cumque id ab amet? +

+
+ ) +} + +render() +``` diff --git a/packages/ui-top-nav-bar/src/TopNav/index.tsx b/packages/ui-top-nav-bar/src/TopNav/index.tsx new file mode 100644 index 0000000000..63b8ec0f58 --- /dev/null +++ b/packages/ui-top-nav-bar/src/TopNav/index.tsx @@ -0,0 +1,113 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 - present Instructure, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** @jsx jsx */ +import React, { useEffect, useState } from 'react' +import type { TopNavProps } from './props' + +/** + --- + category: components + --- + **/ +const TopNav = ({ children, breakpoint = '768' }: TopNavProps) => { + const [isSmallScreen, setIsSmallScreen] = useState(false) + + useEffect(() => { + const handleResize = () => { + setIsSmallScreen(window.innerWidth <= Number(breakpoint)) + } + + handleResize() + + window.addEventListener('resize', handleResize) + + return () => window.removeEventListener('resize', handleResize) + }, []) + + // Filter children to get specific components + const mobileNav = React.Children.toArray(children).find( + (child) => + React.isValidElement(child) && + child?.type && + (child.type as any).displayName === 'MobileTopNav' + ) + const desktopNav = React.Children.toArray(children).find( + (child) => + React.isValidElement(child) && + child?.type && + (child.type as any).displayName === 'DesktopTopNav' + ) + + return isSmallScreen ? mobileNav : desktopNav +} + +// +// +// +// +// +// } +// lightMode={true} +// breadcrumbLinks={[ +// { href: '#', label: 'Student Forecast' }, +// { href: '#', label: 'University of Utah' }, +// { href: '#', label: 'University of Colleges' }, +// ]} +// title="Courses" +// buttons={[ +// { +// screenReaderLabel: 'Analytics', +// color: 'primary-inverse', +// }, +// { +// screenReaderLabel: 'Alerts', +// color: 'primary-inverse', +// }, +// ]} +// items={[ +// { label: 'Account', leftIcon: , onClick: () => alert('Account clicked') }, +// { label: 'Admin', leftIcon: , onClick: () => alert('Admin clicked') }, +// { label: 'Dashboard', leftIcon: , onClick: () => alert('Dashboard') }, +// ]} +// /> + +// +// +//
Mobile Navigation Content
+//
+// +//
Desktop Navigation Content
+//
+//
+ +export { TopNav } +export default TopNav diff --git a/packages/ui-top-nav-bar/src/TopNav/props.ts b/packages/ui-top-nav-bar/src/TopNav/props.ts new file mode 100644 index 0000000000..e54a42c349 --- /dev/null +++ b/packages/ui-top-nav-bar/src/TopNav/props.ts @@ -0,0 +1,35 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 - present Instructure, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type { ReactNode, PropsWithChildren } from 'react' + +type TopNavOwnProps = { + lightMode?: boolean + brand?: ReactNode + breakpoint?: string +} + +type TopNavProps = TopNavOwnProps & PropsWithChildren + +export type { TopNavProps, TopNavOwnProps } diff --git a/packages/ui-top-nav-bar/src/TopNav/styles.tsx b/packages/ui-top-nav-bar/src/TopNav/styles.tsx new file mode 100644 index 0000000000..f5fb6c95f2 --- /dev/null +++ b/packages/ui-top-nav-bar/src/TopNav/styles.tsx @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 - present Instructure, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +import type { TopNavProps } from './props' + +//TODO use theme variables for spacing +const generateStyles = (props: TopNavProps, theme: any) => { + const { lightMode } = props + return { + container: (open: boolean) => { + return { + height: '54px', + position: open ? 'fixed' : 'relative', + backgroundColor: lightMode + ? theme.colors.ui.surfacePageSecondary + : theme.colors.ui.surfaceDark, + color: lightMode + ? theme.colors.contrasts.grey125125 + : theme.colors?.contrasts?.white1010, + width: '100%', + zIndex: '1000' + } + }, + topBar: { + padding: `0 ${theme.spacing.small}`, + height: '54px', + display: 'flex', + alignItems: 'center' + // justifyContent: 'space-between' + }, + content: (open: boolean) => { + return { + padding: `0 ${theme.spacing.small}`, + height: open ? '100%' : '0px', + top: '3.375rem', + bottom: 0, + left: 0, + right: 0, + overflow: open ? 'scroll' : 'hidden', + position: 'fixed', + backgroundColor: lightMode + ? theme.colors.ui.surfacePageSecondary + : theme.colors.ui.surfaceDark, + color: lightMode + ? theme.colors.contrasts.grey125125 + : theme.colors?.contrasts?.white1010 + } + }, + btnRow: { + display: 'flex', + marginRight: '12px' + } + } +} +const generateItemListStyles = (_props: any, theme: any) => { + return { + divider: { + height: '0.0625rem', + overflow: 'hidden', + background: theme.colors.contrasts.grey1214 + } + } +} +const generateItemStyles = (_props: any, _theme: any) => { + return { + container: { + margin: '16px 0', + display: 'flex', + cursor: 'pointer', + alignItems: 'flex-end' + }, + leftIcon: { paddingRight: '8px', fontSize: '18px' }, + rightIcon: { marginLeft: 'auto', paddingRight: '8px', fontSize: '18px' } + } +} + +export { generateStyles, generateItemListStyles, generateItemStyles } diff --git a/packages/ui-top-nav-bar/src/index.ts b/packages/ui-top-nav-bar/src/index.ts index 0305fc98b8..b98b79012d 100644 --- a/packages/ui-top-nav-bar/src/index.ts +++ b/packages/ui-top-nav-bar/src/index.ts @@ -63,3 +63,4 @@ export type { export { MobileTopNav } from './MobileTopNav' export { DesktopTopNav } from './DesktopTopNav' +export { TopNav } from './TopNav'