From 7cd390d91f35b08e25a5e8d3fd970d3f3ba23f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20S=C3=A1ros?= Date: Wed, 14 Aug 2024 10:34:33 +0200 Subject: [PATCH 01/21] WIP(ui-top-nav-bar): wip --- packages/__docs__/components.ts | 2 +- packages/__docs__/src/App/index.tsx | 269 ++++++++++++++---- packages/__docs__/src/index.html | 3 + .../ui-top-nav-bar/src/MobileTopNav/README.md | 107 +++++++ .../ui-top-nav-bar/src/MobileTopNav/index.tsx | 136 +++++++++ .../ui-top-nav-bar/src/MobileTopNav/props.ts | 40 +++ packages/ui-top-nav-bar/src/index.ts | 2 + 7 files changed, 501 insertions(+), 58 deletions(-) create mode 100644 packages/ui-top-nav-bar/src/MobileTopNav/README.md create mode 100644 packages/ui-top-nav-bar/src/MobileTopNav/index.tsx create mode 100644 packages/ui-top-nav-bar/src/MobileTopNav/props.ts diff --git a/packages/__docs__/components.ts b/packages/__docs__/components.ts index 5cb71d0db0..c88d7c0309 100644 --- a/packages/__docs__/components.ts +++ b/packages/__docs__/components.ts @@ -128,7 +128,7 @@ export { ToggleBlockquote } from './src/ToggleBlockquote' export { InstUISettingsProvider } from '@instructure/emotion' export { Drilldown } from '@instructure/ui-drilldown' export { SourceCodeEditor } from '@instructure/ui-source-code-editor' -export { TopNavBar } from '@instructure/ui-top-nav-bar' +export { TopNavBar, MobileTopNav } from '@instructure/ui-top-nav-bar' export { TruncateList } from '@instructure/ui-truncate-list' export { canvas, diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 594d375d4b..f623f2fd16 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -42,7 +42,7 @@ 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 { Mask } from '@instructure/ui-overlays' +import { MobileTopNav } from '@instructure/ui-top-nav-bar' import { IconButton } from '@instructure/ui-buttons' import { Tray } from '@instructure/ui-tray' import { Link } from '@instructure/ui-link' @@ -63,7 +63,7 @@ import { Nav } from '../Nav' import { Theme } from '../Theme' import { Select } from '../Select' import { Section } from '../Section' -import IconsPage from '../Icons' +import { Icons } from '../Icons' import { compileMarkdown } from '../compileMarkdown' import { fetchVersionData, versionInPath } from '../versionData' @@ -76,8 +76,7 @@ import type { AppProps, AppState, DocData, LayoutSize } from './props' import { propTypes, allowedProps } from './props' import type { LibraryOptions, - MainDocsData, - ParsedDocSummary + MainDocsData } from '../../buildScripts/DataTypes.mjs' import { logError } from '@instructure/console' @@ -124,7 +123,7 @@ class App extends Component { themeKey: undefined, layout: 'large', docsData: null, - versionsData: undefined, + versionsData: null, iconsData: null } } @@ -141,6 +140,7 @@ 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 @@ -165,6 +165,35 @@ class App extends Component { } } + /** + * Get every static prop from an object (inherited ones too) + * @param object The object to check + * @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 + const invalidKeys = [ + '$$typeof', + 'render', + 'propTypes', + 'selector', + 'defaultProps', + 'displayName', + 'generateComponentTheme' + ] + while (obj) { + const keys = Object.keys(obj) + keys.forEach((k) => { + if (!invalidKeys.includes(k)) props.add(k) + }) + obj = Reflect.getPrototypeOf(obj) + } + return props + } + componentDidMount() { this._defaultDocumentTitle = document.title this.updateKey() @@ -202,10 +231,13 @@ class App extends Component { fetch('markdown-and-sources-data.json', { signal }) .then((response) => response.json()) .then((docsData) => { - this.setState({ - docsData, - themeKey: Object.keys(docsData.themes)[0] - }) + this.setState( + { + docsData, + themeKey: Object.keys(docsData.themes)[0] + }, + this.scrollToElement + ) }) .catch(errorHandler) } @@ -386,9 +418,13 @@ class App extends Component { } > - Icons + Iconography - + ) @@ -409,12 +445,7 @@ class App extends Component { } // eslint-disable-next-line no-param-reassign data.children = children - this.setState( - { - currentDocData: data - }, - this.scrollToElement - ) + this.setState({ currentDocData: data }) }) return ( @@ -425,9 +456,9 @@ class App extends Component { const { themes } = this.state.docsData! const { layout, themeKey, versionsData } = this.state const { olderVersionsGitBranchMap } = versionsData || {} - let legacyGitBranch: string | undefined = undefined + let legacyGitBranch - if (olderVersionsGitBranchMap && versionInPath) { + if (olderVersionsGitBranchMap) { legacyGitBranch = olderVersionsGitBranchMap[versionInPath] } @@ -471,11 +502,10 @@ class App extends Component { const { library, docs, themes } = this.state.docsData! const { layout } = this.state - const themeDocs: ParsedDocSummary = {} + const themeDocs: Record = {} Object.keys(themes).forEach((key) => { themeDocs[key] = { - title: key, category: 'themes' } }) @@ -546,6 +576,13 @@ class App extends Component { renderContent(key?: string) { const doc = this.state.docsData!.docs[key!] const theme = this.state.docsData!.themes[key!] + let icon + if (this.state.iconsData && this.state.iconsData.formats) { + icon = + this.state.iconsData.formats[ + key as 'icons-svg' | `icons-react` | 'icons-font' + ] + } const { repository } = this.state.docsData!.library if (!key || key === 'index') { @@ -553,7 +590,7 @@ class App extends Component { } if (key === 'CHANGELOG') { return this.renderChangeLog() - } else if (key === 'icons') { + } else if (key === 'iconography' || icon) { return this.renderIcons(key) } else if (theme) { return this.renderTheme(key) @@ -613,12 +650,6 @@ class App extends Component { shape="circle" color="secondary" size="medium" - aria-expanded={true} - ref={(button) => { - if (button) { - button.focus() - } - }} /> @@ -634,6 +665,7 @@ class App extends Component { sections={this.state.docsData!.sections} docs={this.state.docsData!.docs} themes={this.state.docsData!.themes} + icons={this.state.iconsData} /> ) @@ -699,6 +731,29 @@ class App extends Component { if (!docsData || !iconsData) { return } + + const brandSvg = ( + // eslint-disable-next-line jsx-a11y/anchor-is-valid + + + + + + ) + return ( { themes: docsData.themes }} > -
- - {showMenu && layout === 'small' && ( - - )} - {this.renderNavigation()} -
- {!showMenu && ( -
- - - -
- )} - {this.renderContent(key)} - {this.renderFooter()} -
+
+ +

+ 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? +

- {this.renderLegacyDocWarning()} ) } diff --git a/packages/__docs__/src/index.html b/packages/__docs__/src/index.html index 583325669c..96a9a8d9a2 100644 --- a/packages/__docs__/src/index.html +++ b/packages/__docs__/src/index.html @@ -44,6 +44,9 @@ font-family: 'Proxima Nova', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + padding: 0; + margin: 0; + box-sizing: border-box; } #app { diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/README.md b/packages/ui-top-nav-bar/src/MobileTopNav/README.md new file mode 100644 index 0000000000..7fd75d41fe --- /dev/null +++ b/packages/ui-top-nav-bar/src/MobileTopNav/README.md @@ -0,0 +1,107 @@ +--- +describes: MobileTopNav +--- + +POC mobile top nav + +```js +--- +type: example +--- +const Example = () => { + 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/MobileTopNav/index.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx new file mode 100644 index 0000000000..dae154106d --- /dev/null +++ b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx @@ -0,0 +1,136 @@ +/* + * 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 { useState, useEffect, useContext } from 'react' + +import { useState } from 'react' +import { jsx, useTheme } from '@instructure/emotion' +import type { MobileTopNavProps, MobileTopNavOwnProps } from './props' + +import { IconButton } from '@instructure/ui-buttons' +import { + IconHamburgerSolid, + IconEyeSolid, + IconXSolid +} from '@instructure/ui-icons' + +/** +--- +category: components +--- +**/ +const MobileTopNav = ({ + lightMode = false, + brand, + styles +}: MobileTopNavProps) => { + const [open, setOpen] = useState(false) + + return ( +
+
+ {brand} + + + + + setOpen((open) => !open)} + > + {open ? : } + + +
+
+ ) +} + +const generateStyles = (props, theme) => { + const { lightMode } = props + return { + container: { + padding: `0 ${theme.spacing.small}`, + backgroundColor: lightMode + ? theme.colors.ui.surfacePageSecondary + : theme.colors.ui.surfaceDark, + color: lightMode + ? theme.colors.contrasts.grey125125 + : theme.colors?.contrasts?.white1010, + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + width: '100%' + }, + containerHeight: (open: boolean) => { + return { + height: open ? '100%' : '54px', + position: open ? 'absolute' : 'relative' + } + } + } +} + +// eslint-disable-next-line react/display-name +const withStyles = + ( + generateStyles: (props: any, theme: any) => ComponentStyle + ) => + (WrappedComponent: any) => + (originalProps: ComponentOwnProps) => { + const theme = useTheme() + const styledProps = { + styles: generateStyles(originalProps, theme), + ...originalProps + } + return + } + +const SC = withStyles(generateStyles)(MobileTopNav) + +export { SC as MobileTopNav } +export default SC diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/props.ts b/packages/ui-top-nav-bar/src/MobileTopNav/props.ts new file mode 100644 index 0000000000..841c08cc29 --- /dev/null +++ b/packages/ui-top-nav-bar/src/MobileTopNav/props.ts @@ -0,0 +1,40 @@ +/* + * 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 } from 'react' + +type MobileTopNavOwnProps = { + lightMode?: boolean + brand?: ReactNode +} + +type MobileTopNavStyle = { + container: { + [key: string]: string | number + } +} + +type MobileTopNavProps = MobileTopNavOwnProps & { styles: MobileTopNavStyle } + +export type { MobileTopNavProps, MobileTopNavOwnProps } diff --git a/packages/ui-top-nav-bar/src/index.ts b/packages/ui-top-nav-bar/src/index.ts index 55aaf9e219..f82f86862f 100644 --- a/packages/ui-top-nav-bar/src/index.ts +++ b/packages/ui-top-nav-bar/src/index.ts @@ -67,3 +67,5 @@ export type { TopNavBarUserProps, TopNavBarUserOwnProps } from './TopNavBar/TopNavBarUser/props' + +export { MobileTopNav } from './MobileTopNav' From 43f83f6c5a4aa42b53a3c43271f857cf073c96fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20S=C3=A1ros?= Date: Thu, 22 Aug 2024 16:40:04 +0200 Subject: [PATCH 02/21] WIP(ui-top-nav-bar): wip --- packages/__docs__/src/App/index.tsx | 51 ++++- packages/__docs__/src/index.tsx | 10 +- .../ui-top-nav-bar/src/MobileTopNav/README.md | 12 +- .../ui-top-nav-bar/src/MobileTopNav/index.tsx | 208 +++++++++++++----- .../ui-top-nav-bar/src/MobileTopNav/props.ts | 17 +- 5 files changed, 219 insertions(+), 79 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index f623f2fd16..6caad73dcb 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/jsx-no-undef */ /* * The MIT License (MIT) * @@ -732,26 +733,24 @@ class App extends Component { return } + const lightMode = false const brandSvg = ( - // eslint-disable-next-line jsx-a11y/anchor-is-valid - - + ) return ( @@ -770,7 +769,37 @@ class App extends Component { boxSizing: 'border-box' }} > - + + + + + + + + + + + +
+ + Back +
+ +
+ Courses +

1 Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus diff --git a/packages/__docs__/src/index.tsx b/packages/__docs__/src/index.tsx index 2bab090a34..c958c53ec8 100644 --- a/packages/__docs__/src/index.tsx +++ b/packages/__docs__/src/index.tsx @@ -29,10 +29,8 @@ import { App } from './App' import { InstUISettingsProvider } from '@instructure/emotion' import '../globals' -createRoot(document.getElementById('app')!).render( - - - - - +createRoot(document.getElementById('app')).render( + + + ) diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/README.md b/packages/ui-top-nav-bar/src/MobileTopNav/README.md index 7fd75d41fe..32fd6797e8 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/README.md +++ b/packages/ui-top-nav-bar/src/MobileTopNav/README.md @@ -9,16 +9,16 @@ POC mobile top nav 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? diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx index dae154106d..867835e1c2 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/display-name */ /* * The MIT License (MIT) * @@ -23,18 +24,13 @@ */ /** @jsx jsx */ -// import { useState, useEffect, useContext } from 'react' - -import { useState } from 'react' +import { Children, Fragment, useState, useEffect } from 'react' +import type { PropsWithChildren } from 'react' import { jsx, useTheme } from '@instructure/emotion' -import type { MobileTopNavProps, MobileTopNavOwnProps } from './props' +import type { MobileTopNavProps } from './props' import { IconButton } from '@instructure/ui-buttons' -import { - IconHamburgerSolid, - IconEyeSolid, - IconXSolid -} from '@instructure/ui-icons' +import { IconHamburgerLine, IconXLine } from '@instructure/ui-icons' /** --- @@ -44,35 +40,28 @@ category: components const MobileTopNav = ({ lightMode = false, brand, - styles + styles, + children }: MobileTopNavProps) => { const [open, setOpen] = useState(false) + useEffect(() => { + const body = document.getElementsByTagName('body')[0] + body.style.overflow = open ? 'hidden' : 'visible' + }, [open]) + + const getSubComponent = (displayName: any) => { + return Children.map(children, (child: any) => child).filter( + (child: any) => child?.type?.displayName === displayName + ) + } + return ( -

-
+
+
{brand} - - - - + + {!open && getSubComponent('BtnRow')} setOpen((open) => !open)} > - {open ? : } + {open ? : }
+ +
+ {getSubComponent('BreadCrumb')} + {getSubComponent('Title')} +

+ 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? +

+
) } -const generateStyles = (props, theme) => { +const generateStyles = (props: MobileTopNavProps, theme: any) => { const { lightMode } = props return { - container: { + 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%' + } + }, + topBar: { padding: `0 ${theme.spacing.small}`, - backgroundColor: lightMode - ? theme.colors.ui.surfacePageSecondary - : theme.colors.ui.surfaceDark, - color: lightMode - ? theme.colors.contrasts.grey125125 - : theme.colors?.contrasts?.white1010, - position: 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - width: '100%' + height: '54px', + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between' }, - containerHeight: (open: boolean) => { + content: (open: boolean) => { return { - height: open ? '100%' : '54px', - position: open ? 'absolute' : 'relative' + padding: `0 ${theme.spacing.small}`, + height: open ? '100%' : '0px', + top: '54px', + 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', + gap: '12px' } } } -// eslint-disable-next-line react/display-name +const BtnRow = ({ children }: PropsWithChildren) => { + return {children} +} + +BtnRow.displayName = 'BtnRow' + +const BreadCrumb = ({ children }: PropsWithChildren) => { + return
{children}
+} + +BreadCrumb.displayName = 'BreadCrumb' + +const Title = ({ children }: PropsWithChildren) => { + return
{children}
+} + +Title.displayName = 'Title' + const withStyles = ( generateStyles: (props: any, theme: any) => ComponentStyle @@ -130,7 +228,11 @@ const withStyles = return } -const SC = withStyles(generateStyles)(MobileTopNav) +const SC: any = withStyles(generateStyles)(MobileTopNav) + +SC.BtnRow = BtnRow +SC.BreadCrumb = BreadCrumb +SC.Title = Title export { SC as MobileTopNav } export default SC diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/props.ts b/packages/ui-top-nav-bar/src/MobileTopNav/props.ts index 841c08cc29..af0fc3d20c 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/props.ts +++ b/packages/ui-top-nav-bar/src/MobileTopNav/props.ts @@ -22,7 +22,7 @@ * SOFTWARE. */ -import type { ReactNode } from 'react' +import type { ReactNode, PropsWithChildren } from 'react' type MobileTopNavOwnProps = { lightMode?: boolean @@ -30,11 +30,22 @@ type MobileTopNavOwnProps = { } type MobileTopNavStyle = { - container: { + container: (open: boolean) => { + [key: string]: string | number + } + content: (open: boolean) => { + [key: string]: string | number + } + topBar: { + [key: string]: string | number + } + btnRow: { [key: string]: string | number } } -type MobileTopNavProps = MobileTopNavOwnProps & { styles: MobileTopNavStyle } +type MobileTopNavProps = MobileTopNavOwnProps & { + styles: MobileTopNavStyle +} & PropsWithChildren export type { MobileTopNavProps, MobileTopNavOwnProps } From 213acba13c43cc36421264d74db6421d6868155a Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Fri, 13 Sep 2024 09:20:57 +0200 Subject: [PATCH 03/21] WIP(ui-top-nav-bar): add item and itemlist --- packages/__docs__/src/App/index.tsx | 38 +++++- .../ui-top-nav-bar/src/MobileTopNav/index.tsx | 120 ++++++++++-------- .../src/MobileTopNav/styles.tsx | 91 +++++++++++++ 3 files changed, 187 insertions(+), 62 deletions(-) create mode 100644 packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 6caad73dcb..6d1afe8120 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -33,12 +33,7 @@ import { } from 'react' import { Alert } from '@instructure/ui-alerts' -import { - InstUISettingsProvider, - withStyle, - jsx, - Global -} from '@instructure/emotion' +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' @@ -50,8 +45,14 @@ import { Link } from '@instructure/ui-link' import { addMediaQueryMatchListener } from '@instructure/ui-responsive' import type { QueriesMatching } from '@instructure/ui-responsive' import { - IconHamburgerSolid, + IconAdminLine, + IconAlertsLine, + IconAnalyticsLine, + IconArrowOpenDownLine, + IconArrowOpenStartLine, + IconDashboardLine, IconHeartLine, + IconUserLine, IconXSolid } from '@instructure/ui-icons' @@ -799,6 +800,29 @@ class App extends Component { Courses + + } + rightIcon={} + onClick + > + Account + + } + rightIcon={} + onClick + > + Admin + + } + rightIcon={} + onClick + > + Dashboard + +

1 Lorem ipsum dolor sit, amet consectetur adipisicing elit. diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx index 867835e1c2..e609fc45d3 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx @@ -24,13 +24,23 @@ */ /** @jsx jsx */ -import { Children, Fragment, useState, useEffect } from 'react' -import type { PropsWithChildren } from 'react' +import React, { + Children, + Fragment, + PropsWithChildren, + useEffect, + useState +} from 'react' import { jsx, useTheme } from '@instructure/emotion' import type { MobileTopNavProps } from './props' import { IconButton } from '@instructure/ui-buttons' import { IconHamburgerLine, IconXLine } from '@instructure/ui-icons' +import { + generateItemListStyles, + generateItemStyles, + generateStyles +} from './styles' /** --- @@ -57,10 +67,10 @@ const MobileTopNav = ({ } return ( -

-
+
+
{brand} - + {!open && getSubComponent('BtnRow')} {getSubComponent('BreadCrumb')} {getSubComponent('Title')} + {getSubComponent('ItemList')}

1 Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus dolores cum @@ -148,54 +159,6 @@ const MobileTopNav = ({ ) } -const generateStyles = (props: MobileTopNavProps, 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%' - } - }, - 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: '54px', - 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', - gap: '12px' - } - } -} - const BtnRow = ({ children }: PropsWithChildren) => { return {children} } @@ -203,17 +166,59 @@ const BtnRow = ({ children }: PropsWithChildren) => { BtnRow.displayName = 'BtnRow' const BreadCrumb = ({ children }: PropsWithChildren) => { - return

{children}
+ return
{children}
} BreadCrumb.displayName = 'BreadCrumb' const Title = ({ children }: PropsWithChildren) => { - return
{children}
+ return
{children}
} Title.displayName = 'Title' +const ItemList = ({ + children, + styles +}: PropsWithChildren & { styles: any }) => { + return ( + + {Children.map(children, (child, index) => ( + + {child} + {index < React.Children.count(children) - 1 && ( +
+ )} +
+ ))} +
+ ) +} + +ItemList.displayName = 'ItemList' + +const Item = ({ + children, + leftIcon, + rightIcon, + onClick, + styles +}: PropsWithChildren & { + leftIcon: any + rightIcon: any + onClick: any + styles: any +}) => { + return ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions +
+ {leftIcon &&
{leftIcon}
} + {children} + {rightIcon &&
{rightIcon}
} +
+ ) +} + const withStyles = ( generateStyles: (props: any, theme: any) => ComponentStyle @@ -233,6 +238,11 @@ const SC: any = withStyles(generateStyles)(MobileTopNav) SC.BtnRow = BtnRow SC.BreadCrumb = BreadCrumb SC.Title = Title +SC.ItemList = withStyles(generateItemListStyles)(ItemList) +// TODO investigate whether displayName should be added to the original component +SC.ItemList.displayName = 'ItemList' +SC.Item = withStyles(generateItemStyles)(Item) //withStyles(generateItemStyles)(Item) +SC.Item.displayName = 'Item' 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 new file mode 100644 index 0000000000..eee31e74e5 --- /dev/null +++ b/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx @@ -0,0 +1,91 @@ +/* + * 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 { MobileTopNavProps } from './props' + +export const generateStyles = (props: MobileTopNavProps, 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%' + } + }, + 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', + gap: '12px' + } + } +} +export const generateItemListStyles = (_props: any, theme: any) => { + return { + divider: { + height: '0.0625rem', + overflow: 'hidden', + background: theme.colors.contrasts.grey1214 + } + } +} +export const generateItemStyles = (_props: any, _theme: any) => { + return { + container: { + margin: '16px 0', + display: 'flex' + }, + leftIcon: { paddingRight: '8px', fontSize: '18px' }, + rightIcon: { marginLeft: 'auto', paddingRight: '8px', fontSize: '18px' } + } +} From 361e3a2d41aecd3e6d2bb8de9fa989c149b380a8 Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Fri, 13 Sep 2024 09:34:25 +0200 Subject: [PATCH 04/21] WIP(ui-top-nav-bar): some refactor --- packages/__docs__/src/App/index.tsx | 6 +- .../ui-top-nav-bar/src/MobileTopNav/index.tsx | 66 ------------------- .../src/MobileTopNav/styles.tsx | 12 ++-- 3 files changed, 11 insertions(+), 73 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 6d1afe8120..ab74a4419f 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -804,21 +804,21 @@ class App extends Component { } rightIcon={} - onClick + onClick={() => alert('Account clicked')} > Account } rightIcon={} - onClick + onClick={() => alert('Admin clicked')} > Admin } rightIcon={} - onClick + onClick={() => alert('Dashboard')} > Dashboard diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx index e609fc45d3..b0650ebd62 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx @@ -88,72 +88,6 @@ const MobileTopNav = ({ {getSubComponent('BreadCrumb')} {getSubComponent('Title')} {getSubComponent('ItemList')} -

- 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? -

) diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx index eee31e74e5..60fbe10837 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx @@ -23,7 +23,7 @@ */ import type { MobileTopNavProps } from './props' -export const generateStyles = (props: MobileTopNavProps, theme: any) => { +const generateStyles = (props: MobileTopNavProps, theme: any) => { const { lightMode } = props return { container: (open: boolean) => { @@ -70,7 +70,7 @@ export const generateStyles = (props: MobileTopNavProps, theme: any) => { } } } -export const generateItemListStyles = (_props: any, theme: any) => { +const generateItemListStyles = (_props: any, theme: any) => { return { divider: { height: '0.0625rem', @@ -79,13 +79,17 @@ export const generateItemListStyles = (_props: any, theme: any) => { } } } -export const generateItemStyles = (_props: any, _theme: any) => { +const generateItemStyles = (_props: any, _theme: any) => { return { container: { margin: '16px 0', - display: 'flex' + display: 'flex', + cursor: 'pointer', + alignItems: 'flex-end' }, leftIcon: { paddingRight: '8px', fontSize: '18px' }, rightIcon: { marginLeft: 'auto', paddingRight: '8px', fontSize: '18px' } } } + +export { generateStyles, generateItemListStyles, generateItemStyles } From 2b78bcad83c50f80e779a2dfe63153a6c752c22e Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Fri, 13 Sep 2024 21:22:51 +0200 Subject: [PATCH 05/21] WIP(ui-top-nav-bar): add lightMode --- packages/__docs__/src/App/index.tsx | 35 ++++++++++++++----- packages/__docs__/src/App/props.ts | 1 + .../src/MobileTopNav/styles.tsx | 4 ++- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index ab74a4419f..e0f6581b0b 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -33,6 +33,7 @@ import { } from 'react' import { Alert } from '@instructure/ui-alerts' +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' @@ -55,7 +56,6 @@ import { IconUserLine, IconXSolid } from '@instructure/ui-icons' - import { ContentWrap } from '../ContentWrap' import { Document } from '../Document' import { Header } from '../Header' @@ -69,7 +69,6 @@ import { Icons } from '../Icons' import { compileMarkdown } from '../compileMarkdown' import { fetchVersionData, versionInPath } from '../versionData' - import generateStyle from './styles' import generateComponentTheme from './theme' import { LoadingScreen } from '../LoadingScreen' @@ -126,7 +125,8 @@ class App extends Component { layout: 'large', docsData: null, versionsData: null, - iconsData: null + iconsData: null, + lightMode: true } } @@ -734,7 +734,6 @@ class App extends Component { return } - const lightMode = false const brandSvg = ( { boxSizing: 'border-box' }} > - + @@ -784,13 +783,13 @@ class App extends Component { withBackground={false} withBorder={false} screenReaderLabel="burgir" - color={lightMode ? 'secondary' : 'primary-inverse'} + color={this.state.lightMode ? 'secondary' : 'primary-inverse'} > - +
@@ -822,8 +821,28 @@ class App extends Component { > Dashboard + } + onClick={() => alert('Simple option with no left icon')} + > + Simple option with no left icon + +
+ { + this.setState((prevState) => { + return { ...prevState, lightMode: !prevState.lightMode } + }) + }} + /> +

1 Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestias excepturi a blanditiis, aspernatur repellat repellendus diff --git a/packages/__docs__/src/App/props.ts b/packages/__docs__/src/App/props.ts index 55923403e3..2a013ea0bf 100644 --- a/packages/__docs__/src/App/props.ts +++ b/packages/__docs__/src/App/props.ts @@ -94,6 +94,7 @@ type AppState = { changelogData?: DocData // the currently shown document currentDocData?: DocData + lightMode: boolean } type DocData = ProcessedFile & { diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx index 60fbe10837..35cf5253ae 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx @@ -23,6 +23,7 @@ */ import type { MobileTopNavProps } from './props' +//TODO use theme variables for spacing const generateStyles = (props: MobileTopNavProps, theme: any) => { const { lightMode } = props return { @@ -36,7 +37,8 @@ const generateStyles = (props: MobileTopNavProps, theme: any) => { color: lightMode ? theme.colors.contrasts.grey125125 : theme.colors?.contrasts?.white1010, - width: '100%' + width: '100%', + zIndex: '1000' } }, topBar: { From 494566ac7fbdead4451c1d21bbfd73d7ae9e1b32 Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Fri, 20 Sep 2024 16:11:25 +0200 Subject: [PATCH 06/21] WIP: add WrapperComponent to test resizing --- packages/__docs__/src/App/index.tsx | 35 +++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index e0f6581b0b..9e6fbcaba8 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -29,7 +29,9 @@ import { createContext, LegacyRef, ReactElement, - SyntheticEvent + SyntheticEvent, + useEffect, + useState } from 'react' import { Alert } from '@instructure/ui-alerts' @@ -93,6 +95,30 @@ export const AppContext = createContext({ library: undefined }) +const WrapperComponent = (props) => { + const [isSmallScreen, setIsSmallScreen] = useState(false) + + const SmallScreen = () =>

Small screen

+ const BigScreen = () =>

Big screen

+ + useEffect(() => { + const handleResize = () => { + setIsSmallScreen(window.innerWidth <= 768) + } + + // Check on component mount + handleResize() + + // Add event listener for window resize + window.addEventListener('resize', handleResize) + + // Cleanup listener on component unmount + return () => window.removeEventListener('resize', handleResize) + }, []) + + return <>{isSmallScreen ? : } +} + @withStyle(generateStyle, generateComponentTheme) class App extends Component { static propTypes = propTypes @@ -769,6 +795,7 @@ class App extends Component { boxSizing: 'border-box' }} > + { - +
From 6bb82c7c552fdeb93a7a1c89cf0048894dcd7597 Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Thu, 14 Nov 2024 10:07:26 +0100 Subject: [PATCH 07/21] WIP(ui-top-nav-bar): add desktop topnav --- packages/__docs__/src/App/index.tsx | 456 +++++++++--------- .../src/DesktopTopNav/README.md | 107 ++++ .../src/DesktopTopNav/index.tsx | 107 ++++ .../ui-top-nav-bar/src/DesktopTopNav/props.ts | 51 ++ .../src/DesktopTopNav/styles.tsx | 97 ++++ .../ui-top-nav-bar/src/MobileTopNav/index.tsx | 2 +- packages/ui-top-nav-bar/src/index.ts | 1 + 7 files changed, 597 insertions(+), 224 deletions(-) create mode 100644 packages/ui-top-nav-bar/src/DesktopTopNav/README.md create mode 100644 packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx create mode 100644 packages/ui-top-nav-bar/src/DesktopTopNav/props.ts create mode 100644 packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 9e6fbcaba8..8800b062d2 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -35,13 +35,14 @@ import { } 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 } from '@instructure/ui-top-nav-bar' +import { MobileTopNav, DesktopTopNav } from '@instructure/ui-top-nav-bar' import { IconButton } from '@instructure/ui-buttons' import { Tray } from '@instructure/ui-tray' import { Link } from '@instructure/ui-link' @@ -97,9 +98,236 @@ export const AppContext = createContext({ const WrapperComponent = (props) => { const [isSmallScreen, setIsSmallScreen] = useState(false) - - const SmallScreen = () =>

Small screen

- const BigScreen = () =>

Big screen

+ const [isLightMode, setIsLightMode] = useState(false) + + const brandSvg = ( + + + + + + ) + + const SmallScreen = () => ( +
+ + + + + + + + + + + +
+ + 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 + + +
+
+ { + setIsLightMode((prev) => !prev) + }} + /> +
+

+ 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? +

+
+ ) + const BigScreen = () => ( + + + + Student Forecast + University of Utah + University of Colleges + + + + ) useEffect(() => { const handleResize = () => { @@ -151,8 +379,7 @@ class App extends Component { layout: 'large', docsData: null, versionsData: null, - iconsData: null, - lightMode: true + iconsData: null } } @@ -760,25 +987,6 @@ class App extends Component { return } - const brandSvg = ( - - - - - - ) - return ( { }} > - - - - - - - - - - - -
- - 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 - - -
-
- { - this.setState((prevState) => { - return { ...prevState, lightMode: !prevState.lightMode } - }) - }} - /> -
-

- 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? -

) diff --git a/packages/ui-top-nav-bar/src/DesktopTopNav/README.md b/packages/ui-top-nav-bar/src/DesktopTopNav/README.md new file mode 100644 index 0000000000..32fd6797e8 --- /dev/null +++ b/packages/ui-top-nav-bar/src/DesktopTopNav/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/DesktopTopNav/index.tsx b/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx new file mode 100644 index 0000000000..5250f66576 --- /dev/null +++ b/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx @@ -0,0 +1,107 @@ +/* eslint-disable react/display-name */ +/* + * 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 { Children, PropsWithChildren, useEffect, useState } from 'react' +import { jsx, useTheme } from '@instructure/emotion' +import type { DesktopTopNavProps } from './props' + +import { IconButton } from '@instructure/ui-buttons' +import { IconHamburgerLine, IconXLine } from '@instructure/ui-icons' +import { generateStyles } from './styles' + +/** +--- +category: components +--- +**/ +const DesktopTopNav = ({ + lightMode = false, + styles, + children +}: DesktopTopNavProps) => { + const [open, setOpen] = useState(false) + + useEffect(() => { + const body = document.getElementsByTagName('body')[0] + body.style.overflow = open ? 'hidden' : 'visible' + }, [open]) + + const getSubComponent = (displayName: any) => { + return Children.map(children, (child: any) => child)?.filter( + (child: any) => child?.type?.displayName === displayName + ) + } + + return ( +
+
+ + {/*{!open && getSubComponent('BtnRow')}*/} + setOpen((open) => !open)} + > + {open ? : } + + + {getSubComponent('BreadCrumb')} +
+
+ ) +} + +const BreadCrumb = ({ children }: PropsWithChildren) => { + return ( +
{children}
+ ) +} + +BreadCrumb.displayName = 'BreadCrumb' + +const withStyles = + ( + generateStyles: (props: any, theme: any) => ComponentStyle + ) => + (WrappedComponent: any) => + (originalProps: ComponentOwnProps) => { + const theme = useTheme() + const styledProps = { + styles: generateStyles(originalProps, theme), + ...originalProps + } + return + } + +const SC: any = withStyles(generateStyles)(DesktopTopNav) + +SC.BreadCrumb = BreadCrumb +// TODO investigate whether displayName should be added to the original component + +export { SC as DesktopTopNav } +export default SC diff --git a/packages/ui-top-nav-bar/src/DesktopTopNav/props.ts b/packages/ui-top-nav-bar/src/DesktopTopNav/props.ts new file mode 100644 index 0000000000..86d2efe2ad --- /dev/null +++ b/packages/ui-top-nav-bar/src/DesktopTopNav/props.ts @@ -0,0 +1,51 @@ +/* + * 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 DesktopTopNavOwnProps = { + lightMode?: boolean + brand?: ReactNode +} + +type DesktopTopNavStyle = { + container: (open: boolean) => { + [key: string]: string | number + } + content: (open: boolean) => { + [key: string]: string | number + } + topBar: { + [key: string]: string | number + } + btnRow: { + [key: string]: string | number + } +} + +type DesktopTopNavProps = DesktopTopNavOwnProps & { + styles: DesktopTopNavStyle +} & PropsWithChildren + +export type { DesktopTopNavProps, DesktopTopNavOwnProps } diff --git a/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx b/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx new file mode 100644 index 0000000000..720f5901f2 --- /dev/null +++ b/packages/ui-top-nav-bar/src/DesktopTopNav/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 { DesktopTopNavProps } from './props' + +//TODO use theme variables for spacing +const generateStyles = (props: DesktopTopNavProps, 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', + gap: '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/MobileTopNav/index.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx index b0650ebd62..ca853b2d98 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx @@ -61,7 +61,7 @@ const MobileTopNav = ({ }, [open]) const getSubComponent = (displayName: any) => { - return Children.map(children, (child: any) => child).filter( + return Children.map(children, (child: any) => child)?.filter( (child: any) => child?.type?.displayName === displayName ) } diff --git a/packages/ui-top-nav-bar/src/index.ts b/packages/ui-top-nav-bar/src/index.ts index f82f86862f..5363e924d2 100644 --- a/packages/ui-top-nav-bar/src/index.ts +++ b/packages/ui-top-nav-bar/src/index.ts @@ -69,3 +69,4 @@ export type { } from './TopNavBar/TopNavBarUser/props' export { MobileTopNav } from './MobileTopNav' +export { DesktopTopNav } from './DesktopTopNav' From eae1cc3111299da0f6cc65acc4414db9753dd38c Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Sun, 17 Nov 2024 16:07:53 +0100 Subject: [PATCH 08/21] 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 5363e924d2..c1f0bc35e1 100644 --- a/packages/ui-top-nav-bar/src/index.ts +++ b/packages/ui-top-nav-bar/src/index.ts @@ -70,3 +70,4 @@ export type { export { MobileTopNav } from './MobileTopNav' export { DesktopTopNav } from './DesktopTopNav' +export { TopNav } from './TopNav' From c2eca094f0b6ec0ea4672543889ed3c9d034c9e4 Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Mon, 18 Nov 2024 14:19:10 +0100 Subject: [PATCH 09/21] WIP(ui-top-nav-bar): inject lightMode --- packages/__docs__/src/App/index.tsx | 7 ++++--- packages/ui-top-nav-bar/src/TopNav/index.tsx | 17 ++++++++++++++--- packages/ui-top-nav-bar/src/TopNav/props.ts | 3 +-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 08ae229e7e..351d8d006b 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -981,7 +981,7 @@ class App extends Component { const key = this.state.key const { showMenu, layout, docsData, iconsData } = this.state - const isLightMode = false + const isLightMode = true const brandSvg = ( { href="#" withBackground={false} withBorder={false} + color={isLightMode ? 'secondary' : 'primary-inverse'} > { boxSizing: 'border-box' }} > - + @@ -1032,7 +1033,7 @@ class App extends Component { - + { +const TopNav = ({ + children, + breakpoint = '768', + lightMode = true +}: TopNavProps) => { const [isSmallScreen, setIsSmallScreen] = useState(false) useEffect(() => { @@ -46,7 +50,6 @@ const TopNav = ({ children, breakpoint = '768' }: TopNavProps) => { return () => window.removeEventListener('resize', handleResize) }, []) - // Filter children to get specific components const mobileNav = React.Children.toArray(children).find( (child) => React.isValidElement(child) && @@ -60,7 +63,15 @@ const TopNav = ({ children, breakpoint = '768' }: TopNavProps) => { (child.type as any).displayName === 'DesktopTopNav' ) - return isSmallScreen ? mobileNav : desktopNav + // Clone and inject the lightMode prop into identified children + const mobileNavWithProps = mobileNav + ? React.cloneElement(mobileNav as React.ReactElement, { lightMode }) + : null + const desktopNavWithProps = desktopNav + ? React.cloneElement(desktopNav as React.ReactElement, { lightMode }) + : null + + return isSmallScreen ? mobileNavWithProps : desktopNavWithProps } // Date: Tue, 26 Nov 2024 16:49:15 +0100 Subject: [PATCH 10/21] WIP(ui-top-nav-bar): clean DesktopTopNav --- packages/__docs__/src/App/index.tsx | 127 +++++++----------- .../src/{TopNav => CanvasTopNav}/README.md | 0 .../src/{TopNav => CanvasTopNav}/index.tsx | 112 +++++++++------ .../src/{TopNav => CanvasTopNav}/props.ts | 0 .../src/{TopNav => CanvasTopNav}/styles.tsx | 0 .../src/DesktopTopNav/index.tsx | 62 +++------ .../src/DesktopTopNav/styles.tsx | 85 ++++-------- .../ui-top-nav-bar/src/MobileTopNav/index.tsx | 2 +- packages/ui-top-nav-bar/src/index.ts | 2 +- 9 files changed, 164 insertions(+), 226 deletions(-) rename packages/ui-top-nav-bar/src/{TopNav => CanvasTopNav}/README.md (100%) rename packages/ui-top-nav-bar/src/{TopNav => CanvasTopNav}/index.tsx (57%) rename packages/ui-top-nav-bar/src/{TopNav => CanvasTopNav}/props.ts (100%) rename packages/ui-top-nav-bar/src/{TopNav => CanvasTopNav}/styles.tsx (100%) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 351d8d006b..c60b10b229 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -41,7 +41,7 @@ import { AccessibleContent } from '@instructure/ui-a11y-content' import { MobileTopNav, DesktopTopNav, - TopNav + CanvasTopNav } from '@instructure/ui-top-nav-bar' import { IconButton } from '@instructure/ui-buttons' import { Tray } from '@instructure/ui-tray' @@ -1023,85 +1023,52 @@ 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 - - - - + , + rightIcon: , + onClick: () => alert('Account clicked') + }, + { + label: 'Admin', + leftIcon: , + rightIcon: , + onClick: () => alert('Admin clicked') + }, + { + label: 'Dashboard', + leftIcon: , + rightIcon: , + onClick: () => alert('Dashboard clicked') + }, + { + label: 'Simple option with no left icon', + rightIcon: , + onClick: () => alert('Simple option with no left icon') + } + ]} + />
) diff --git a/packages/ui-top-nav-bar/src/TopNav/README.md b/packages/ui-top-nav-bar/src/CanvasTopNav/README.md similarity index 100% rename from packages/ui-top-nav-bar/src/TopNav/README.md rename to packages/ui-top-nav-bar/src/CanvasTopNav/README.md diff --git a/packages/ui-top-nav-bar/src/TopNav/index.tsx b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx similarity index 57% rename from packages/ui-top-nav-bar/src/TopNav/index.tsx rename to packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx index b86bb2eb04..20fbaeaa6a 100644 --- a/packages/ui-top-nav-bar/src/TopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx @@ -23,58 +23,90 @@ */ /** @jsx jsx */ -import React, { useEffect, useState } from 'react' -import type { TopNavProps } from './props' +import { useEffect, useState } from 'react' +import { DesktopTopNav } from '../DesktopTopNav' +import { MobileTopNav } from '../MobileTopNav' +import { jsx } from '@instructure/emotion' +import { + IconAddLine, + IconAdminSolid, + IconHamburgerLine, + IconXLine +} from '@instructure/ui-icons' +import { Button, IconButton } from '@instructure/ui-buttons' +import { Breadcrumb } from '@instructure/ui-breadcrumb' /** - --- - category: components - --- - **/ -const TopNav = ({ - children, - breakpoint = '768', - lightMode = true -}: TopNavProps) => { +--- +category: components +--- +**/ +const CanvasTopNav = ({ + breakpoint = 768, + lightMode = true, + brand, + breadcrumbLinks = [], + title, + buttons = [], + items = [], + backButton +}: any) => { const [isSmallScreen, setIsSmallScreen] = useState(false) + // Resize listener to check if the screen is small or not useEffect(() => { const handleResize = () => { setIsSmallScreen(window.innerWidth <= Number(breakpoint)) } handleResize() - window.addEventListener('resize', handleResize) return () => window.removeEventListener('resize', handleResize) - }, []) + }, [breakpoint]) - 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' + // Render mobile or desktop nav based on screen size + return isSmallScreen ? ( + + ) : ( + + + + + + + {breadcrumbLinks.map((link, index) => + link.href ? ( + + {link.label} + + ) : ( + {link.label} + ) + )} + + + + + + + ) - - // Clone and inject the lightMode prop into identified children - const mobileNavWithProps = mobileNav - ? React.cloneElement(mobileNav as React.ReactElement, { lightMode }) - : null - const desktopNavWithProps = desktopNav - ? React.cloneElement(desktopNav as React.ReactElement, { lightMode }) - : null - - return isSmallScreen ? mobileNavWithProps : desktopNavWithProps } - -// -// +// // //
Mobile Navigation Content
//
// //
Desktop Navigation Content
//
-//
+// -export { TopNav } -export default TopNav +export { CanvasTopNav } +export default CanvasTopNav diff --git a/packages/ui-top-nav-bar/src/TopNav/props.ts b/packages/ui-top-nav-bar/src/CanvasTopNav/props.ts similarity index 100% rename from packages/ui-top-nav-bar/src/TopNav/props.ts rename to packages/ui-top-nav-bar/src/CanvasTopNav/props.ts diff --git a/packages/ui-top-nav-bar/src/TopNav/styles.tsx b/packages/ui-top-nav-bar/src/CanvasTopNav/styles.tsx similarity index 100% rename from packages/ui-top-nav-bar/src/TopNav/styles.tsx rename to packages/ui-top-nav-bar/src/CanvasTopNav/styles.tsx diff --git a/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx b/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx index 761efbf422..77e269d69f 100644 --- a/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx @@ -24,65 +24,40 @@ */ /** @jsx jsx */ -import { Children, PropsWithChildren, useEffect, useState } from 'react' +import { Children, PropsWithChildren } from 'react' import { jsx, useTheme } from '@instructure/emotion' import type { DesktopTopNavProps } from './props' -import { IconButton } from '@instructure/ui-buttons' -import { IconHamburgerLine, IconXLine } from '@instructure/ui-icons' import { generateStyles } from './styles' /** ---- -category: components ---- -**/ -const DesktopTopNav = ({ - lightMode = false, - styles, - children -}: DesktopTopNavProps) => { - const [open, setOpen] = useState(false) - - useEffect(() => { - const body = document.getElementsByTagName('body')[0] - body.style.overflow = open ? 'hidden' : 'visible' - }, [open]) - + --- + category: utilities + --- + **/ +const DesktopTopNav = ({ styles, children }: DesktopTopNavProps) => { const getSubComponent = (displayName: any) => { return Children.map(children, (child: any) => child)?.filter( (child: any) => child?.type?.displayName === displayName ) } + //console.log('getSubComponent', getSubComponent('Start')) return ( -
-
- - {/*{!open && getSubComponent('BtnRow')}*/} - setOpen((open) => !open)} - > - {open ? : } - - - {getSubComponent('BreadCrumb')} -
+
+ {getSubComponent('Start')} + {getSubComponent('End')}
) } -const BreadCrumb = ({ children }: PropsWithChildren) => { - return ( -
{children}
- ) +const Start = ({ children, styles }: PropsWithChildren & { styles: any }) => { + return
{children}
} -BreadCrumb.displayName = 'BreadCrumb' +const End = ({ children, styles }: PropsWithChildren & { styles: any }) => { + return
{children}
+} const withStyles = ( @@ -100,10 +75,11 @@ const withStyles = const SC: any = withStyles(generateStyles)(DesktopTopNav) -SC.BreadCrumb = BreadCrumb -// TODO investigate whether displayName should be added to the original component - SC.displayName = 'DesktopTopNav' +SC.Start = withStyles(generateStyles)(Start) +SC.Start.displayName = 'Start' +SC.End = withStyles(generateStyles)(End) +SC.End.displayName = 'End' 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 1eb62c5721..5db74ef85f 100644 --- a/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx +++ b/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx @@ -23,75 +23,38 @@ */ import type { DesktopTopNavProps } from './props' -//TODO use theme variables for spacing const generateStyles = (props: DesktopTopNavProps, 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', + container: { + height: '66px', + position: 'fixed', + backgroundColor: lightMode + ? theme.colors.ui.surfacePageSecondary + : theme.colors.ui.surfaceDark, + color: lightMode + ? theme.colors.contrasts.grey125125 + : theme.colors?.contrasts?.white1010, + width: '100%', + zIndex: '1000', display: 'flex', - alignItems: 'center' - // justifyContent: 'space-between' + alignItems: 'center', + flexDirection: 'row' }, - 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 - } + start: { + marginLeft: '24px', + marginRight: 'auto', + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + gap: '16px' }, - btnRow: { + end: { + marginRight: '24px', display: 'flex', - marginRight: '12px' - } - } -} -const generateItemListStyles = (_props: any, theme: any) => { - return { - divider: { - height: '0.0625rem', - overflow: 'hidden', - background: theme.colors.contrasts.grey1214 + gap: '12px' } } } -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 } +export { generateStyles } diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx index 299d7749a6..2114a3a8ac 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx @@ -44,7 +44,7 @@ import { /** --- -category: components +category: utilities --- **/ const MobileTopNav = ({ diff --git a/packages/ui-top-nav-bar/src/index.ts b/packages/ui-top-nav-bar/src/index.ts index c1f0bc35e1..68b8065ce8 100644 --- a/packages/ui-top-nav-bar/src/index.ts +++ b/packages/ui-top-nav-bar/src/index.ts @@ -70,4 +70,4 @@ export type { export { MobileTopNav } from './MobileTopNav' export { DesktopTopNav } from './DesktopTopNav' -export { TopNav } from './TopNav' +export { CanvasTopNav } from './CanvasTopNav' From b7c6d5b91bd96f377c5e9fd51b5e207b56fba16c Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Thu, 28 Nov 2024 14:25:00 +0100 Subject: [PATCH 11/21] WIP(ui-top-nav-bar): api rework --- packages/__docs__/src/App/index.tsx | 40 +++++----- .../ui-top-nav-bar/src/CanvasTopNav/index.tsx | 79 ++++++++++++++----- .../src/DesktopTopNav/index.tsx | 8 +- .../ui-top-nav-bar/src/MobileTopNav/index.tsx | 28 ++++--- 4 files changed, 99 insertions(+), 56 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index c60b10b229..6ca6df05d6 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -1026,45 +1026,45 @@ class App extends Component { alert('Hamburger clicked')} + mobileMenuTitle="Courses" + mobileButtons={[ { - screenReaderLabel: 'Analytics', // itt icon is lesz!!!!! - color: 'primary-inverse' + screenReaderLabel: 'Analytics', + icon: }, { - screenReaderLabel: 'Alerts', // itt icon lesz!!!!! - color: 'primary-inverse' + screenReaderLabel: 'Alerts', + icon: } ]} - backButton={{ href: '#', label: 'Back' }} - items={[ + mobileMenuBackButton={{ href: '#', label: 'Back' }} + mobileMenu={[ { label: 'Account', - leftIcon: , - rightIcon: , + renderBeforeLabel: , onClick: () => alert('Account clicked') }, { label: 'Admin', - leftIcon: , - rightIcon: , + renderBeforeLabel: , onClick: () => alert('Admin clicked') }, { label: 'Dashboard', - leftIcon: , - rightIcon: , + renderBeforeLabel: , onClick: () => alert('Dashboard clicked') }, { label: 'Simple option with no left icon', - rightIcon: , onClick: () => alert('Simple option with no left icon') } ]} diff --git a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx index 20fbaeaa6a..5a36c00fa9 100644 --- a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx @@ -30,11 +30,11 @@ import { jsx } from '@instructure/emotion' import { IconAddLine, IconAdminSolid, - IconHamburgerLine, - IconXLine + IconArrowOpenStartLine, + IconHamburgerLine } from '@instructure/ui-icons' import { Button, IconButton } from '@instructure/ui-buttons' -import { Breadcrumb } from '@instructure/ui-breadcrumb' +import { Breadcrumb, BreadcrumbLink } from '@instructure/ui-breadcrumb' /** --- @@ -45,11 +45,11 @@ const CanvasTopNav = ({ breakpoint = 768, lightMode = true, brand, - breadcrumbLinks = [], - title, - buttons = [], - items = [], - backButton + breadcrumb, + mobileMenuTitle, + mobileButtons = [], + mobileMenu = [], + mobileMenuBackButton }: any) => { const [isSmallScreen, setIsSmallScreen] = useState(false) @@ -67,17 +67,56 @@ const CanvasTopNav = ({ // Render mobile or desktop nav based on screen size return isSmallScreen ? ( - + + + {mobileButtons.map((button, index) => ( + + {button.icon} + + ))} + + + + +
+ + {mobileMenuBackButton.label} +
+
+
+ {mobileMenuTitle} + + {mobileMenu.map((item, index) => ( + + {item.label} + + ))} + +
+
) : ( - + - - {breadcrumbLinks.map((link, index) => + + {breadcrumb.links.map((link, index) => link.href ? ( {link.label} diff --git a/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx b/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx index 77e269d69f..83b1a388e5 100644 --- a/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/DesktopTopNav/index.tsx @@ -31,9 +31,9 @@ import type { DesktopTopNavProps } from './props' import { generateStyles } from './styles' /** - --- - category: utilities - --- +--- +category: utilities +--- **/ const DesktopTopNav = ({ styles, children }: DesktopTopNavProps) => { const getSubComponent = (displayName: any) => { @@ -41,8 +41,6 @@ const DesktopTopNav = ({ styles, children }: DesktopTopNavProps) => { (child: any) => child?.type?.displayName === displayName ) } - //console.log('getSubComponent', getSubComponent('Start')) - return (
{getSubComponent('Start')} diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx index 2114a3a8ac..4d6722b15b 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx @@ -84,11 +84,7 @@ const MobileTopNav = ({
-
- {getSubComponent('BreadCrumb')} - {getSubComponent('Title')} - {getSubComponent('ItemList')} -
+
{getSubComponent('Menu')}
) } @@ -97,6 +93,10 @@ const BtnRow = ({ children }: PropsWithChildren) => { return {children} } +const Menu = ({ children }: PropsWithChildren) => { + return {children} +} + BtnRow.displayName = 'BtnRow' const BreadCrumb = ({ children }: PropsWithChildren) => { @@ -133,22 +133,26 @@ ItemList.displayName = 'ItemList' const Item = ({ children, - leftIcon, - rightIcon, + renderBeforeLabel, + renderAfterLabel, onClick, styles }: PropsWithChildren & { - leftIcon: any - rightIcon: any + renderBeforeLabel: any + renderAfterLabel: any onClick: any styles: any }) => { return ( // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
- {leftIcon &&
{leftIcon}
} + {renderBeforeLabel && ( +
{renderBeforeLabel}
+ )} {children} - {rightIcon &&
{rightIcon}
} + {renderAfterLabel && ( +
{renderAfterLabel}
+ )}
) } @@ -177,6 +181,8 @@ SC.ItemList = withStyles(generateItemListStyles)(ItemList) SC.ItemList.displayName = 'ItemList' SC.Item = withStyles(generateItemStyles)(Item) //withStyles(generateItemStyles)(Item) SC.Item.displayName = 'Item' +SC.Menu = Menu +SC.Menu.displayName = 'Menu' SC.displayName = 'MobileTopNav' export { SC as MobileTopNav } From 1641b02ae07062df0fe7acaef2916b6a75d4a6a1 Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Thu, 28 Nov 2024 18:46:27 +0100 Subject: [PATCH 12/21] WIP(ui-top-nav-bar): finetuning after grooming meeting --- packages/__docs__/src/App/index.tsx | 2 +- .../ui-top-nav-bar/src/CanvasTopNav/index.tsx | 12 +++++++----- .../ui-top-nav-bar/src/MobileTopNav/index.tsx | 18 +++++------------- .../ui-top-nav-bar/src/MobileTopNav/props.ts | 2 +- .../ui-top-nav-bar/src/MobileTopNav/styles.tsx | 6 +++--- 5 files changed, 17 insertions(+), 23 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 6ca6df05d6..815a396e90 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -1046,7 +1046,7 @@ class App extends Component { icon: } ]} - mobileMenuBackButton={{ href: '#', label: 'Back' }} + mobileMenuBackNavigation={{ href: '#', label: 'Back' }} mobileMenu={[ { label: 'Account', diff --git a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx index 5a36c00fa9..cdc5bec079 100644 --- a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx @@ -49,7 +49,8 @@ const CanvasTopNav = ({ mobileMenuTitle, mobileButtons = [], mobileMenu = [], - mobileMenuBackButton + mobileMenuBackNavigation, + hamburgerOnClick }: any) => { const [isSmallScreen, setIsSmallScreen] = useState(false) @@ -68,7 +69,7 @@ const CanvasTopNav = ({ // Render mobile or desktop nav based on screen size return isSmallScreen ? ( - + {mobileButtons.map((button, index) => ( ))} - + @@ -96,7 +97,7 @@ const CanvasTopNav = ({ }} > - {mobileMenuBackButton.label} + {mobileMenuBackNavigation.label}
@@ -122,6 +123,7 @@ const CanvasTopNav = ({ withBackground={false} withBorder={false} screenReaderLabel="burgir" + onClick={hamburgerOnClick} color={lightMode ? 'secondary' : 'primary-inverse'} > diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx index 4d6722b15b..8e2daff985 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx @@ -70,8 +70,8 @@ const MobileTopNav = ({
{brand} - - {!open && getSubComponent('BtnRow')} + + {!open && getSubComponent('End')} { +const End = ({ children }: PropsWithChildren) => { return {children} } @@ -97,14 +97,6 @@ const Menu = ({ children }: PropsWithChildren) => { return {children} } -BtnRow.displayName = 'BtnRow' - -const BreadCrumb = ({ children }: PropsWithChildren) => { - return
{children}
-} - -BreadCrumb.displayName = 'BreadCrumb' - const Title = ({ children }: PropsWithChildren) => { return
{children}
} @@ -173,8 +165,8 @@ const withStyles = const SC: any = withStyles(generateStyles)(MobileTopNav) -SC.BtnRow = BtnRow -SC.BreadCrumb = BreadCrumb +SC.End = End +SC.End.displayName = 'End' SC.Title = Title SC.ItemList = withStyles(generateItemListStyles)(ItemList) // TODO investigate whether displayName should be added to the original component diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/props.ts b/packages/ui-top-nav-bar/src/MobileTopNav/props.ts index af0fc3d20c..9202101531 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/props.ts +++ b/packages/ui-top-nav-bar/src/MobileTopNav/props.ts @@ -39,7 +39,7 @@ type MobileTopNavStyle = { topBar: { [key: string]: string | number } - btnRow: { + end: { [key: string]: string | number } } diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx index 65b2c058d4..60411e0d2d 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/styles.tsx @@ -30,7 +30,6 @@ const generateStyles = (props: MobileTopNavProps, theme: any) => { container: (_open: boolean) => { return { height: '54px', - // position: open ? 'fixed' : 'relative', backgroundColor: lightMode ? theme.colors.ui.surfacePageSecondary : theme.colors.ui.surfaceDark, @@ -66,9 +65,10 @@ const generateStyles = (props: MobileTopNavProps, theme: any) => { : theme.colors?.contrasts?.white1010 } }, - btnRow: { + end: { display: 'flex', - gap: '12px' + gap: '12px', + marginLeft: 'auto' } } } From f1f125da212bb21c7fa73b5eeba33395869cd4fc Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Fri, 29 Nov 2024 16:19:26 +0100 Subject: [PATCH 13/21] WIP(ui-top-nav-bar): add more changes after review --- packages/__docs__/src/App/index.tsx | 8 +++-- .../ui-top-nav-bar/src/CanvasTopNav/index.tsx | 32 ++++++++++--------- .../ui-top-nav-bar/src/MobileTopNav/index.tsx | 6 ++-- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 815a396e90..2b75b5286b 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -1025,7 +1025,7 @@ class App extends Component { > { mobileButtons={[ { screenReaderLabel: 'Analytics', - icon: + icon: , + onClick: () => alert('Analytics clicked') }, { screenReaderLabel: 'Alerts', - icon: + icon: , + onClick: () => alert('Alerts clicked') } ]} mobileMenuBackNavigation={{ href: '#', label: 'Back' }} diff --git a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx index cdc5bec079..bae16d8826 100644 --- a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx @@ -76,7 +76,8 @@ const CanvasTopNav = ({ withBackground={false} withBorder={false} screenReaderLabel={button.screenReaderLabel} - color={lightMode ? 'secondary' : button.color} + color={lightMode ? 'primary' : 'primary-inverse'} + onClick={button.onClick} > {button.icon}
@@ -87,7 +88,7 @@ const CanvasTopNav = ({
- {mobileMenuTitle} - + {mobileMenu.map((item, index) => ( - - {breadcrumb.links.map((link, index) => - link.href ? ( - - {link.label} - - ) : ( - {link.label} - ) - )} - +
+ + {breadcrumb.links.map((link, index) => + link.href ? ( + + {link.label} + + ) : ( + {link.label} + ) + )} + +
diff --git a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx index 8e2daff985..97442980fd 100644 --- a/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/MobileTopNav/index.tsx @@ -76,7 +76,7 @@ const MobileTopNav = ({ withBackground={false} withBorder={false} screenReaderLabel="burgir" - color={lightMode ? 'secondary' : 'primary-inverse'} + color={lightMode ? 'primary' : 'primary-inverse'} onClick={() => setOpen((open) => !open)} > {open ? : } @@ -105,10 +105,12 @@ Title.displayName = 'Title' const ItemList = ({ children, + title, styles -}: PropsWithChildren & { styles: any }) => { +}: PropsWithChildren & { styles: any; title: any }) => { return ( + {title && {title}} {Children.map(children, (child, index) => ( {child} From b6c09e0ae4e7cfd83ace33bb0140f4c66cf6fd3b Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Mon, 2 Dec 2024 15:49:58 +0100 Subject: [PATCH 14/21] WIP(ui-top-nav-bar): fix build errors --- .../ui-top-nav-bar/src/CanvasTopNav/index.tsx | 18 +++++++----------- .../ui-top-nav-bar/src/DesktopTopNav/props.ts | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx index bae16d8826..ba0ac482ed 100644 --- a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx @@ -70,7 +70,7 @@ const CanvasTopNav = ({ return isSmallScreen ? ( - {mobileButtons.map((button, index) => ( + {mobileButtons.map((button: any, index: any) => ( - - + +
- {mobileMenu.map((item, index) => ( + {mobileMenu.map((item: any, index: any) => (
- {breadcrumb.links.map((link, index) => + {breadcrumb.links.map((link: any, index: any) => link.href ? ( {link.label} @@ -143,8 +139,8 @@ const CanvasTopNav = ({
- - + + ) diff --git a/packages/ui-top-nav-bar/src/DesktopTopNav/props.ts b/packages/ui-top-nav-bar/src/DesktopTopNav/props.ts index 86d2efe2ad..2210120ab1 100644 --- a/packages/ui-top-nav-bar/src/DesktopTopNav/props.ts +++ b/packages/ui-top-nav-bar/src/DesktopTopNav/props.ts @@ -30,7 +30,7 @@ type DesktopTopNavOwnProps = { } type DesktopTopNavStyle = { - container: (open: boolean) => { + container: { [key: string]: string | number } content: (open: boolean) => { From b910533e82e44d2e52e1f479704f436a5abf13fb Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Wed, 4 Dec 2024 15:59:40 +0100 Subject: [PATCH 15/21] WIP(ui-top-nav-bar): clear index.tsx and create a basic menu structure --- packages/__docs__/src/App/index.tsx | 1131 ++--------------- .../ui-top-nav-bar/src/CanvasTopNav/index.tsx | 31 +- 2 files changed, 157 insertions(+), 1005 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 2b75b5286b..fa87ad76f9 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -23,329 +23,22 @@ */ /** @jsx jsx */ -import { - Component, - createContext, - LegacyRef, - ReactElement, - SyntheticEvent -} from 'react' +import { Component } from 'react' -import { Alert } from '@instructure/ui-alerts' -import { Breadcrumb } from '@instructure/ui-breadcrumb' -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, - CanvasTopNav -} from '@instructure/ui-top-nav-bar' +import { withStyle, jsx } from '@instructure/emotion' +import { CanvasTopNav } from '@instructure/ui-top-nav-bar' import { IconButton } from '@instructure/ui-buttons' -import { Tray } from '@instructure/ui-tray' -import { Link } from '@instructure/ui-link' -import { addMediaQueryMatchListener } from '@instructure/ui-responsive' -import type { QueriesMatching } from '@instructure/ui-responsive' import { - IconAdminLine, IconAlertsLine, IconAnalyticsLine, - IconArrowOpenDownLine, - IconArrowOpenStartLine, - IconDashboardLine, - IconHeartLine, - IconUserLine, - IconXSolid + IconCoursesLine, + IconQuestionLine, + IconUserLine } from '@instructure/ui-icons' -import { ContentWrap } from '../ContentWrap' -import { Document } from '../Document' -import { Header } from '../Header' -import { Heading } from '../Heading' -import { Hero } from '../Hero' -import { Nav } from '../Nav' -import { Theme } from '../Theme' -import { Select } from '../Select' -import { Section } from '../Section' -import { Icons } from '../Icons' -import { compileMarkdown } from '../compileMarkdown' - -import { fetchVersionData, versionInPath } from '../versionData' import generateStyle from './styles' import generateComponentTheme from './theme' -import { LoadingScreen } from '../LoadingScreen' -import * as EveryComponent from '../../components' -import type { AppProps, AppState, DocData, LayoutSize } from './props' +import type { AppProps, AppState } from './props' import { propTypes, allowedProps } from './props' -import type { - LibraryOptions, - MainDocsData -} from '../../buildScripts/DataTypes.mjs' -import { logError } from '@instructure/console' - -type AppContextType = { - themeKey: keyof MainDocsData['themes'] - themes: MainDocsData['themes'] - library?: LibraryOptions -} - -export const AppContext = createContext({ - themes: {}, - themeKey: '', - library: undefined -}) - -/*const WrapperComponent = (props) => { - const [isSmallScreen, setIsSmallScreen] = useState(false) - const [isLightMode, setIsLightMode] = useState(false) - - const brandSvg = ( - - - - - - ) - - const SmallScreen = () => ( -
- - - - - - - - - - - -
- - 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 - - -
-
- { - setIsLightMode((prev) => !prev) - }} - /> -
-

- 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? -

-
- ) - const BigScreen = () => ( - - - - Student Forecast - University of Utah - University of Colleges - - - - ) - - useEffect(() => { - const handleResize = () => { - setIsSmallScreen(window.innerWidth <= 768) - } - - // Check on component mount - handleResize() - - // Add event listener for window resize - window.addEventListener('resize', handleResize) - - // Cleanup listener on component unmount - return () => window.removeEventListener('resize', handleResize) - }, []) - - return <>{isSmallScreen ? : } -}*/ @withStyle(generateStyle, generateComponentTheme) class App extends Component { @@ -355,632 +48,23 @@ class App extends Component { static defaultProps = { trayWidth: 300 } - _content?: HTMLDivElement | null - _menuTrigger?: HTMLButtonElement - _mediaQueryListener?: ReturnType - _defaultDocumentTitle?: string - _controller?: AbortController constructor(props: AppProps) { super(props) - // determine what page we're loading - const [page] = this.getPathInfo() - - // if there's room for the tray + 700px, load with the tray open (unless it's the homepage) - const smallerScreen = window.matchMedia( - `(max-width: ${props.trayWidth + 700}px)` - ).matches - const isHomepage = page === 'index' || typeof page === 'undefined' - const showTrayOnPageLoad = !smallerScreen && !isHomepage this.state = { - showMenu: showTrayOnPageLoad, + showMenu: false, themeKey: undefined, layout: 'large', docsData: null, versionsData: null, - iconsData: null - } - } - - fetchDocumentData = async (docId: string) => { - const result = await fetch('docs/' + docId + '.json', { - signal: this._controller?.signal - }) - const docData: DocData = await result.json() - if (docId.includes('.')) { - // e.g. 'Calendar.Day', first get 'Calendar' then 'Day' - const components = docId.split('.') - const everyComp = EveryComponent as Record - docData.componentInstance = everyComp[components[0]][components[1]] - } else { - docData.componentInstance = - EveryComponent[docId as keyof typeof EveryComponent] - } - return docData - } - - fetchVersionData = async (signal: AbortController['signal']) => { - const versionsData = await fetchVersionData(signal) - return this.setState({ versionsData }) - } - - scrollToElement() { - const [_page, id] = this.getPathInfo() - - if (id) { - // If we have an id and it corresponds to an element - // that exists, scroll it into view - const linkedSection = document.getElementById(id) - linkedSection && linkedSection.scrollIntoView() - } else if (this._content) { - // If we don't have an id, scroll the content back to the top - this._content.scrollTop = 0 - } - } - - /** - * Get every static prop from an object (inherited ones too) - * @param object The object to check - * @returns {Set} the properties - */ - getAllPropNames(object: Record) { - let obj: object | null = object - const props: Set = new Set() - // exclude some common static props for performance - const invalidKeys = [ - '$$typeof', - 'render', - 'propTypes', - 'selector', - 'defaultProps', - 'displayName', - 'generateComponentTheme' - ] - while (obj) { - const keys = Object.keys(obj) - keys.forEach((k) => { - if (!invalidKeys.includes(k)) props.add(k) - }) - obj = Reflect.getPrototypeOf(obj) - } - return props - } - - componentDidMount() { - this._defaultDocumentTitle = document.title - this.updateKey() - - window.addEventListener('hashchange', this.updateKey, false) - - // TODO: Replace with the Responsive component later - // Using this method directly for now instead to avoid a call to findDOMNode - this._mediaQueryListener = addMediaQueryMatchListener( - { - medium: { minWidth: 700 }, - large: { minWidth: 1100 }, - 'x-large': { minWidth: 1300 } - }, - this._content!, - this.updateLayout - ) - this.props.makeStyles?.() - - this._controller = new AbortController() - const signal = this._controller.signal - - this.fetchVersionData(signal) - - const errorHandler = (error: Error) => { - logError(error.name === 'AbortError', error.message) - } - - fetch('icons-data.json', { signal }) - .then((response) => response.json()) - .then((iconsData) => { - this.setState({ iconsData: iconsData }) - }) - .catch(errorHandler) - fetch('markdown-and-sources-data.json', { signal }) - .then((response) => response.json()) - .then((docsData) => { - this.setState( - { - docsData, - themeKey: Object.keys(docsData.themes)[0] - }, - this.scrollToElement - ) - }) - .catch(errorHandler) - } - - componentDidUpdate() { - this.props.makeStyles?.() - } - - componentWillUnmount() { - //cancel ongoing requests - this._controller?.abort() - window.removeEventListener('hashchange', this.updateKey, false) - - if (this._mediaQueryListener) { - this._mediaQueryListener.remove() - } - } - - trackPage(page: string) { - let title = this._defaultDocumentTitle - if (page !== 'index') { - title = `${page} - ${this._defaultDocumentTitle}` - } - - document.title = title! - } - - getPathInfo = () => { - const { hash } = window.location - - const path = hash && hash.split('/') - - if (path) { - const [page, id] = path.map((entry) => decodeURI(entry.replace('#', ''))) - return [page, id] - } - return [] - } - - updateLayout = (matches: QueriesMatching) => { - let layout: LayoutSize = 'small' - - if (matches.length > 0) { - if (matches.includes('medium') && matches.length === 1) { - layout = 'medium' - } else if (matches.includes('large') && matches.length === 2) { - layout = 'large' - } else if (matches.includes('x-large')) { - layout = 'x-large' - } + iconsData: null, + previousMenu: '', + currentMenu: 'default' } - this.setState({ layout }) - } - - updateKey = () => { - const [page, _id] = this.getPathInfo() - - if (page) { - this.setState( - ({ key, showMenu }) => ({ - key: page || 'index', - showMenu: this.handleShowTrayOnURLChange(key, showMenu) - }), - this.scrollToElement - ) - } else { - this.trackPage('index') - } - } - - handleContentRef: LegacyRef = (el) => { - this._content = el - } - - handleMenuTriggerRef = (el: Element | null) => { - this._menuTrigger = el as HTMLButtonElement - } - - handleMenuOpen = () => { - this.setState({ showMenu: true }) - } - - handleMenuClose = () => { - this.setState({ showMenu: false }, () => { - this._menuTrigger && this._menuTrigger.focus() - }) - } - - handleThemeChange = (_event: SyntheticEvent, option: { value: string }) => { - this.setState({ - themeKey: option.value - }) - } - - handleShowTrayOnURLChange = (key: string | undefined, showMenu: boolean) => { - const userIsComingFromHomepage = - key === 'index' || typeof key === 'undefined' - - const { layout } = this.state - - // if the user is coming from the homepage, make the tray show if the layout is large enough - if (layout === 'small') { - return false - } else if (userIsComingFromHomepage) { - return true - } else { - return showMenu - } - } - - renderThemeSelect() { - const themeKeys = Object.keys(this.state.docsData!.themes) - const smallScreen = this.state.layout === 'small' - - return themeKeys.length > 1 ? ( - - - - - - ) : null - } - - renderTheme(themeKey: string) { - const theme = this.state.docsData!.themes[themeKey] - - const { layout } = this.state - const smallerScreens = layout === 'small' || layout === 'medium' - - const themeContent = ( - - - Theme: {themeKey} - - - - ) - return ( -
{this.renderWrappedContent(themeContent)}
- ) - } - - renderIcons(key: string) { - const { iconsData } = this.state - const { layout } = this.state - const smallerScreens = layout === 'small' || layout === 'medium' - - const iconContent = ( - - - Iconography - - - - ) - - return
{this.renderWrappedContent(iconContent)}
- } - - renderDocument(docId: string, repository: string) { - const { parents } = this.state.docsData! - const children: any[] = [] - const currentData = this.state.currentDocData - if (!currentData || currentData.id !== docId) { - // load all children and the main doc - this.fetchDocumentData(docId).then(async (data) => { - if (parents[docId]) { - for (const childId of parents[docId].children) { - children.push(await this.fetchDocumentData(childId)) - } - } - // eslint-disable-next-line no-param-reassign - data.children = children - this.setState({ currentDocData: data }) - }) - return ( - - - - ) - } - const { themes } = this.state.docsData! - const { layout, themeKey, versionsData } = this.state - const { olderVersionsGitBranchMap } = versionsData || {} - let legacyGitBranch - - if (olderVersionsGitBranchMap) { - legacyGitBranch = olderVersionsGitBranchMap[versionInPath] - } - - const themeVariables = themes[themeKey!].resource - const heading = currentData.extension !== '.md' ? currentData.title : '' - const documentContent = ( - - {this.renderThemeSelect()} -
- -
-
- ) - return this.renderWrappedContent(documentContent) - } - - renderWrappedContent( - content: ReactElement[] | ReactElement, - padding: any = 'large' - ) { - return {content} - } - - renderHero() { - const { library, docs, themes } = this.state.docsData! - const { layout } = this.state - - const themeDocs: Record = {} - - Object.keys(themes).forEach((key) => { - themeDocs[key] = { - category: 'themes' - } - }) - return ( - - - - ) - } - - renderChangeLog() { - if (!this.state.changelogData) { - this.fetchDocumentData('CHANGELOG').then((data) => { - this.setState({ changelogData: data }) - }) - return ( - - - - ) - } - const CHANGELOG = this.state.changelogData - let content: string - - const { description } = CHANGELOG - const currentMajorVersion = this.state.docsData!.library.version.slice(0, 1) - - // we want to cut the docs below the last 2 major versions, - // so find the next title after it - const versionCutoffPoint = parseInt(currentMajorVersion, 10) - 2 - const breakpointIndex = description.indexOf(`# [${versionCutoffPoint}`) - 1 - - if (breakpointIndex < 0) { - content = description - } else { - content = - description.slice(0, breakpointIndex) + - '\n...\n' + - `# Version ${versionCutoffPoint} and below\n` + - `For older releases (v${versionCutoffPoint} and below), check the [GitHub CHANGELOG](https://github.com/instructure/instructure-ui/blob/master/CHANGELOG.md).` - } - - return ( -
- {this.renderWrappedContent(compileMarkdown(content))} -
- ) - } - - renderError() { - const errorContent = ( - - Document not found. Please use the search in - the navigation to find any page in this documentation. - - ) - return ( -
{this.renderWrappedContent(errorContent)}
- ) - } - - renderContent(key?: string) { - const doc = this.state.docsData!.docs[key!] - const theme = this.state.docsData!.themes[key!] - let icon - if (this.state.iconsData && this.state.iconsData.formats) { - icon = - this.state.iconsData.formats[ - key as 'icons-svg' | `icons-react` | 'icons-font' - ] - } - const { repository } = this.state.docsData!.library - - if (!key || key === 'index') { - return this.renderHero() - } - if (key === 'CHANGELOG') { - return this.renderChangeLog() - } else if (key === 'iconography' || icon) { - return this.renderIcons(key) - } else if (theme) { - return this.renderTheme(key) - } else if (doc) { - return this.renderDocument(key!, repository) - } else { - return this.renderError() - } - } - - renderFooter() { - const { author, repository } = this.state.docsData!.library - - return author || repository ? ( - - {author && ( - - - Made with by {author} - . - - - )} - - ) : null - } - - renderNavigation() { - const { name, version } = this.state.docsData!.library - const { key, layout, showMenu, versionsData } = this.state - // Render nothing when the menu is not shown and the layout isn't small - // When the layout is small, we still render the tray so that it can properly - // finish the exit transition - if (!showMenu && layout !== 'small') return - - const navContent = ( - - - - - - - -
- -
) } } export default App -export type { AppContextType } export { App } diff --git a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx index ba0ac482ed..daab4792be 100644 --- a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx @@ -84,20 +84,25 @@ const CanvasTopNav = ({ ))}
- - -
+ + - - {mobileMenuBackNavigation.label} -
-
-
+
+ + {mobileMenuBackNavigation.label} +
+ + +
{mobileMenu.map((item: any, index: any) => ( Date: Thu, 5 Dec 2024 15:44:39 +0100 Subject: [PATCH 16/21] WIP: add smart menu navigation --- packages/__docs__/src/App/index.tsx | 79 ++++++++++------------------- 1 file changed, 27 insertions(+), 52 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index fa87ad76f9..7185811cf5 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -59,11 +59,27 @@ class App extends Component { docsData: null, versionsData: null, iconsData: null, - previousMenu: '', - currentMenu: 'default' + menuStack: ['default'] } } + pushMenu = (menuKey) => { + this.setState((prevState) => ({ + menuStack: [...prevState.menuStack, menuKey] + })) + } + + popMenu = () => { + this.setState((prevState) => ({ + menuStack: prevState.menuStack.slice(0, -1) + })) + } + + getCurrentMenu = () => { + const { menuStack } = this.state + return menuStack[menuStack.length - 1] + } + render() { const isLightMode = true @@ -94,40 +110,24 @@ class App extends Component { label: 'Account', renderBeforeLabel: , onClick: () => { - alert('Account clicked') - this.setState((prev) => { - return { - ...prev, - currentMenu: 'account', - previousMenu: 'default' - } - }) + this.pushMenu('account') } }, { label: 'Courses', renderBeforeLabel: , onClick: () => { - alert('Courses clicked') - this.setState((prev) => { - return { - ...prev, - currentMenu: 'courses', - previousMenu: 'default' - } - }) + this.pushMenu('courses') } }, { label: 'Help', - renderBeforeLabel: , - onClick: () => alert('Help') + renderBeforeLabel: } ], backNavigation: { href: '#', - label: 'Back', - onClick: () => alert('Back clicked') + label: 'Back' }, title: 'Main Menu' }, @@ -141,9 +141,7 @@ class App extends Component { backNavigation: { label: 'Back', onClick: () => { - this.setState((prev) => { - return { ...prev, currentMenu: 'default' } - }) + this.popMenu() } }, title: 'Account' @@ -153,9 +151,7 @@ class App extends Component { backNavigation: { label: 'Back', onClick: () => { - this.setState((prev) => { - return { ...prev, currentMenu: 'default' } - }) + this.popMenu() } }, title: 'Courses' @@ -183,7 +179,7 @@ class App extends Component { ] }} hamburgerOnClick={() => alert('Hamburger clicked')} - mobileMenuTitle={menu[this.state.currentMenu].title} + mobileMenuTitle={menu[this.getCurrentMenu()].title} mobileButtons={[ { screenReaderLabel: 'Analytics', @@ -196,29 +192,8 @@ class App extends Component { onClick: () => alert('Alerts clicked') } ]} - mobileMenuBackNavigation={menu[this.state.currentMenu].backNavigation} - mobileMenu={menu[this.state.currentMenu].items} - // mobileMenu={[ - // { - // label: 'Account', - // renderBeforeLabel: , - // onClick: () => alert('Account clicked') - // }, - // { - // label: 'Admin', - // renderBeforeLabel: , - // onClick: () => alert('Admin clicked') - // }, - // { - // label: 'Dashboard', - // renderBeforeLabel: , - // onClick: () => alert('Dashboard clicked') - // }, - // { - // label: 'Simple option with no left icon', - // onClick: () => alert('Simple option with no left icon') - // } - // ]} + mobileMenuBackNavigation={menu[this.getCurrentMenu()].backNavigation} + mobileMenu={menu[this.getCurrentMenu()].items} />
) From 40f45b090e03c14b8a34cb47ba51080ec1c6cb23 Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Fri, 6 Dec 2024 14:39:24 +0100 Subject: [PATCH 17/21] WIP: refine menu handling --- packages/__docs__/src/App/index.tsx | 50 +++++++++++++++++++---------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 7185811cf5..8e91e83820 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -31,39 +31,53 @@ import { IconButton } from '@instructure/ui-buttons' import { IconAlertsLine, IconAnalyticsLine, + IconArrowOpenEndSolid, IconCoursesLine, IconQuestionLine, IconUserLine } from '@instructure/ui-icons' import generateStyle from './styles' import generateComponentTheme from './theme' -import type { AppProps, AppState } from './props' import { propTypes, allowedProps } from './props' -@withStyle(generateStyle, generateComponentTheme) -class App extends Component { - static propTypes = propTypes - static allowedProps = allowedProps +type AppProps = Record + +type AppState = { + menuStack: string[] +} - static defaultProps = { - trayWidth: 300 +type MenuItem = { + label: string + renderBeforeLabel?: JSX.Element + onClick?: () => void + renderAfterLabel?: JSX.Element +} + +type Menu = { + items: MenuItem[] + backNavigation: { + href?: string + label: string + onClick?: () => void } + title: string +} +type MenuCollection = { + [key: string]: Menu +} + +@withStyle(generateStyle, generateComponentTheme) +class App extends Component { constructor(props: AppProps) { super(props) this.state = { - showMenu: false, - themeKey: undefined, - layout: 'large', - docsData: null, - versionsData: null, - iconsData: null, menuStack: ['default'] } } - pushMenu = (menuKey) => { + pushMenu = (menuKey: string) => { this.setState((prevState) => ({ menuStack: [...prevState.menuStack, menuKey] })) @@ -103,7 +117,7 @@ class App extends Component { ) - const menu = { + const menu: MenuCollection = { default: { items: [ { @@ -111,14 +125,16 @@ class App extends Component { renderBeforeLabel: , onClick: () => { this.pushMenu('account') - } + }, + renderAfterLabel: }, { label: 'Courses', renderBeforeLabel: , onClick: () => { this.pushMenu('courses') - } + }, + renderAfterLabel: }, { label: 'Help', From fb0196b4eb11a91c739a8f1986ded5bc2a9f9067 Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Fri, 6 Dec 2024 15:27:57 +0100 Subject: [PATCH 18/21] WIP(ui-top-nav-bar): refinement --- packages/__docs__/src/App/index.tsx | 3 +- .../ui-top-nav-bar/src/CanvasTopNav/index.tsx | 51 ++----------------- 2 files changed, 7 insertions(+), 47 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index 8e91e83820..f386947002 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -38,7 +38,6 @@ import { } from '@instructure/ui-icons' import generateStyle from './styles' import generateComponentTheme from './theme' -import { propTypes, allowedProps } from './props' type AppProps = Record @@ -210,6 +209,8 @@ class App extends Component { ]} mobileMenuBackNavigation={menu[this.getCurrentMenu()].backNavigation} mobileMenu={menu[this.getCurrentMenu()].items} + beforeMobileMenuItems={
Before Mobile Menu
} + afterMobileMenuItems={
After Mobile Menu
} />
) diff --git a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx index daab4792be..e2dc8c0dbd 100644 --- a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx @@ -50,7 +50,9 @@ const CanvasTopNav = ({ mobileButtons = [], mobileMenu = [], mobileMenuBackNavigation, - hamburgerOnClick + hamburgerOnClick, + beforeMobileMenuItems, + afterMobileMenuItems }: any) => { const [isSmallScreen, setIsSmallScreen] = useState(false) @@ -103,6 +105,7 @@ const CanvasTopNav = ({
+ {beforeMobileMenuItems && beforeMobileMenuItems} {mobileMenu.map((item: any, index: any) => ( ))} + {afterMobileMenuItems && afterMobileMenuItems} ) : ( @@ -150,51 +154,6 @@ const CanvasTopNav = ({ ) } -// -// -// -// -// -// } -// 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 { CanvasTopNav } export default CanvasTopNav From b5145974c922f8f7d7c15139f0f551d223a7a56b Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Fri, 13 Dec 2024 12:16:17 +0100 Subject: [PATCH 19/21] WIP(ui-top-nav-bar): add withStyle to CanvasTopNav --- package-lock.json | 68 ++++++++++++++++++ packages/__docs__/package.json | 1 + packages/__docs__/src/App/index.tsx | 28 +++++++- packages/__docs__/src/index.tsx | 7 +- packages/__docs__/webpack.config.mjs | 1 + .../ui-top-nav-bar/src/CanvasTopNav/index.tsx | 60 ++++++++++++---- .../src/CanvasTopNav/styles.tsx | 70 ++----------------- .../src/DesktopTopNav/styles.tsx | 2 +- 8 files changed, 151 insertions(+), 86 deletions(-) diff --git a/package-lock.json b/package-lock.json index abd96645e8..001b8c4584 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30210,6 +30210,61 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.0.2.tgz", + "integrity": "sha512-m5AcPfTRUcjwmhBzOJGEl6Y7+Crqyju0+TgTQxoS4SO+BkWbhOrcfZNq6wSWdl2BBbJbsAoBUb8ZacOFT+/JlA==", + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.0.2.tgz", + "integrity": "sha512-VJOQ+CDWFDGaWdrG12Nl+d7yHtLaurNgAQZVgaIy7/Xd+DojgmYLosFfZdGz1wpxmjJIAkAMVTKWcvkx1oggAw==", + "license": "MIT", + "dependencies": { + "react-router": "7.0.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router/node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/read": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/read/-/read-3.0.1.tgz", @@ -31435,6 +31490,12 @@ "version": "2.0.0", "license": "ISC" }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -34471,6 +34532,12 @@ "node": "*" } }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", @@ -37256,6 +37323,7 @@ "prop-types": "^15.8.1", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-router-dom": "^7.0.2", "semver": "^7.6.3", "uuid": "^11.0.3", "webpack-merge": "^6.0.1" diff --git a/packages/__docs__/package.json b/packages/__docs__/package.json index 8d0764908b..90af1716ce 100644 --- a/packages/__docs__/package.json +++ b/packages/__docs__/package.json @@ -122,6 +122,7 @@ "prop-types": "^15.8.1", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-router-dom": "^7.0.2", "semver": "^7.6.3", "uuid": "^11.0.3", "webpack-merge": "^6.0.1" diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index f386947002..b952f74057 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -24,7 +24,7 @@ /** @jsx jsx */ import { Component } from 'react' - +import { Route, Routes, useNavigate } from 'react-router-dom' import { withStyle, jsx } from '@instructure/emotion' import { CanvasTopNav } from '@instructure/ui-top-nav-bar' import { IconButton } from '@instructure/ui-buttons' @@ -33,13 +33,16 @@ import { IconAnalyticsLine, IconArrowOpenEndSolid, IconCoursesLine, + IconDashboardLine, IconQuestionLine, IconUserLine } from '@instructure/ui-icons' import generateStyle from './styles' import generateComponentTheme from './theme' -type AppProps = Record +type AppProps = { + navigate: (path: string, options?: { replace: boolean }) => void +} type AppState = { menuStack: string[] @@ -135,6 +138,15 @@ class App extends Component { }, renderAfterLabel: }, + { + label: 'Dashboard', + renderBeforeLabel: , + onClick: () => { + // Navigate and reload logic + this.props.navigate('/dashboard', { replace: true }) + window.location.reload() // Forces a reload + } + }, { label: 'Help', renderBeforeLabel: @@ -212,10 +224,20 @@ class App extends Component { beforeMobileMenuItems={
Before Mobile Menu
} afterMobileMenuItems={
After Mobile Menu
} /> + + This is home} /> + This is dashboard} /> + {/*} />*/} +
) } } +function AppWrapper() { + const navigate = useNavigate() + return +} + export default App -export { App } +export { App, AppWrapper } diff --git a/packages/__docs__/src/index.tsx b/packages/__docs__/src/index.tsx index c958c53ec8..2089dd1b99 100644 --- a/packages/__docs__/src/index.tsx +++ b/packages/__docs__/src/index.tsx @@ -25,12 +25,15 @@ import React from 'react' import { createRoot } from 'react-dom/client' -import { App } from './App' +import { AppWrapper } from './App' import { InstUISettingsProvider } from '@instructure/emotion' import '../globals' +import { BrowserRouter } from 'react-router-dom' createRoot(document.getElementById('app')).render( - + + + ) diff --git a/packages/__docs__/webpack.config.mjs b/packages/__docs__/webpack.config.mjs index c11c9ed67c..048929c5de 100644 --- a/packages/__docs__/webpack.config.mjs +++ b/packages/__docs__/webpack.config.mjs @@ -59,6 +59,7 @@ const config = merge(baseConfig, { directory: outputPath, }, host: '0.0.0.0', + historyApiFallback: true, onListening: function () { // devServer is watching source files by default and hot reloading the docs page if they are changed // however markdown files (i.e. README.md) need to be recompiled hence the need for chokidar diff --git a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx index e2dc8c0dbd..1277cc3d86 100644 --- a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx @@ -26,7 +26,7 @@ import { useEffect, useState } from 'react' import { DesktopTopNav } from '../DesktopTopNav' import { MobileTopNav } from '../MobileTopNav' -import { jsx } from '@instructure/emotion' +import { InstUISettingsProvider, jsx, useTheme } from '@instructure/emotion' import { IconAddLine, IconAdminSolid, @@ -35,6 +35,7 @@ import { } from '@instructure/ui-icons' import { Button, IconButton } from '@instructure/ui-buttons' import { Breadcrumb, BreadcrumbLink } from '@instructure/ui-breadcrumb' +import { generateStyles } from './styles' /** --- @@ -52,7 +53,8 @@ const CanvasTopNav = ({ mobileMenuBackNavigation, hamburgerOnClick, beforeMobileMenuItems, - afterMobileMenuItems + afterMobileMenuItems, + styles }: any) => { const [isSmallScreen, setIsSmallScreen] = useState(false) @@ -134,17 +136,27 @@ const CanvasTopNav = ({
- - {breadcrumb.links.map((link: any, index: any) => - link.href ? ( - - {link.label} - - ) : ( - {link.label} - ) - )} - + + + {breadcrumb.links.map((link: any, index: any) => + link.href ? ( + + {link.label} + + ) : ( + {link.label} + ) + )} + +
@@ -155,5 +167,23 @@ const CanvasTopNav = ({ ) } -export { CanvasTopNav } -export default CanvasTopNav +const withStyles = + ( + generateStyles: (props: any, theme: any) => ComponentStyle + ) => + (WrappedComponent: any) => + // eslint-disable-next-line react/display-name + (originalProps: ComponentOwnProps) => { + const theme = useTheme() + const styledProps = { + styles: generateStyles(originalProps, theme), + ...originalProps + } + return + } + +const SC: any = withStyles(generateStyles)(CanvasTopNav) +SC.displayName = 'CanvasTopNav' + +export { SC as CanvasTopNav } +export default SC diff --git a/packages/ui-top-nav-bar/src/CanvasTopNav/styles.tsx b/packages/ui-top-nav-bar/src/CanvasTopNav/styles.tsx index f5fb6c95f2..cbeee97e5c 100644 --- a/packages/ui-top-nav-bar/src/CanvasTopNav/styles.tsx +++ b/packages/ui-top-nav-bar/src/CanvasTopNav/styles.tsx @@ -23,75 +23,15 @@ */ 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' + breadcrumbOverride: { + color: lightMode + ? theme?.colors?.contrasts?.blue4570 + : theme?.colors?.contrasts?.grey1111 } } } -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 } +export { generateStyles } diff --git a/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx b/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx index 5db74ef85f..829d0a149b 100644 --- a/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx +++ b/packages/ui-top-nav-bar/src/DesktopTopNav/styles.tsx @@ -28,7 +28,7 @@ const generateStyles = (props: DesktopTopNavProps, theme: any) => { return { container: { height: '66px', - position: 'fixed', + position: 'relative', backgroundColor: lightMode ? theme.colors.ui.surfacePageSecondary : theme.colors.ui.surfaceDark, From 25a385b08e90ffd147cd197694ab0607822ad9f2 Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Fri, 13 Dec 2024 16:29:40 +0100 Subject: [PATCH 20/21] WIP(ui-top-nav-bar): refactor --- packages/__docs__/src/App/index.tsx | 49 +++++++++++---- .../ui-top-nav-bar/src/CanvasTopNav/index.tsx | 60 ++++++++++++------- 2 files changed, 79 insertions(+), 30 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index b952f74057..e98282ae0e 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -39,6 +39,7 @@ import { } from '@instructure/ui-icons' import generateStyle from './styles' import generateComponentTheme from './theme' +import { Img } from '@instructure/ui-img' type AppProps = { navigate: (path: string, options?: { replace: boolean }) => void @@ -63,6 +64,8 @@ type Menu = { onClick?: () => void } title: string + renderBeforeMobileMenuItems?: JSX.Element + renderAfterMobileMenuItems?: JSX.Element } type MenuCollection = { @@ -75,7 +78,12 @@ class App extends Component { super(props) this.state = { - menuStack: ['default'] + menuStack: [ + 'default', + ...(window.location.pathname.substring(1) + ? [window.location.pathname.substring(1)] + : []) + ] } } @@ -142,9 +150,8 @@ class App extends Component { label: 'Dashboard', renderBeforeLabel: , onClick: () => { - // Navigate and reload logic this.props.navigate('/dashboard', { replace: true }) - window.location.reload() // Forces a reload + window.location.reload() } }, { @@ -153,12 +160,19 @@ class App extends Component { } ], backNavigation: { - href: '#', - label: 'Back' + href: undefined, + label: '', + onClick: undefined }, - title: 'Main Menu' + title: '' }, account: { + renderBeforeMobileMenuItems: ( +
+ +
+ ), + renderAfterMobileMenuItems:

Additional account info

, items: [ { label: 'AccountInfo1' @@ -182,6 +196,18 @@ class App extends Component { } }, title: 'Courses' + }, + dashboard: { + title: 'Dashboard', + items: [{ label: 'Courses1' }, { label: 'Courses2' }], + backNavigation: { + label: 'Back', + onClick: () => { + this.popMenu() + this.props.navigate('/', { replace: true }) + window.location.reload() + } + } } } @@ -219,15 +245,18 @@ class App extends Component { onClick: () => alert('Alerts clicked') } ]} - mobileMenuBackNavigation={menu[this.getCurrentMenu()].backNavigation} + mobileMenuBackNavigation={menu[this.getCurrentMenu()]?.backNavigation} mobileMenu={menu[this.getCurrentMenu()].items} - beforeMobileMenuItems={
Before Mobile Menu
} - afterMobileMenuItems={
After Mobile Menu
} + beforeMobileMenuItems={ + menu[this.getCurrentMenu()]?.renderBeforeMobileMenuItems + } + afterMobileMenuItems={ + menu[this.getCurrentMenu()]?.renderAfterMobileMenuItems + } /> This is home} /> This is dashboard} /> - {/*} />*/}
) diff --git a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx index 1277cc3d86..cca5908a26 100644 --- a/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx +++ b/packages/ui-top-nav-bar/src/CanvasTopNav/index.tsx @@ -88,26 +88,42 @@ const CanvasTopNav = ({ ))} -
- - + -
- - {mobileMenuBackNavigation.label} -
-
-
-
- {beforeMobileMenuItems && beforeMobileMenuItems} + + +
+ + {mobileMenuBackNavigation.label} +
+
+
+ +
+ )} + {beforeMobileMenuItems && ( +
+ {beforeMobileMenuItems} +
+ )} {mobileMenu.map((item: any, index: any) => ( ))} - {afterMobileMenuItems && afterMobileMenuItems} + {afterMobileMenuItems && ( +
+ {afterMobileMenuItems} +
+ )}
) : ( From 0b7d9ed14110d29f44fc9c561acf247c56d222e6 Mon Sep 17 00:00:00 2001 From: Peter Pal Hudak Date: Fri, 13 Dec 2024 16:55:50 +0100 Subject: [PATCH 21/21] WIP: add onClick for help --- packages/__docs__/src/App/index.tsx | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/__docs__/src/App/index.tsx b/packages/__docs__/src/App/index.tsx index e98282ae0e..58f20661b1 100644 --- a/packages/__docs__/src/App/index.tsx +++ b/packages/__docs__/src/App/index.tsx @@ -156,7 +156,8 @@ class App extends Component { }, { label: 'Help', - renderBeforeLabel: + renderBeforeLabel: , + onClick: () => alert('Help clicked') } ], backNavigation: { @@ -172,7 +173,22 @@ class App extends Component {
), - renderAfterMobileMenuItems:

Additional account info

, + renderAfterMobileMenuItems: ( +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi + aliquet erat in orci semper fringilla. Nullam suscipit mollis mi, at + vehicula magna vulputate eu. Cras mattis felis id quam vehicula + euismod. Nulla dolor enim, ornare in odio a, molestie dictum ligula. + Nullam maximus et dolor eget porttitor. Vestibulum faucibus viverra + pellentesque. Duis lorem lectus, porta vitae aliquam vitae, vehicula + sagittis nulla. Aenean sagittis congue rhoncus. Cras laoreet eu + nulla eu dignissim. Maecenas sed massa nisi. Suspendisse + pellentesque, metus sed ultricies porta, justo tellus pulvinar diam, + ac ornare massa nibh quis purus. Duis erat ipsum, pellentesque in + diam non, luctus accumsan metus. In ipsum tellus, ullamcorper a + faucibus a, venenatis ut urna. Sed at rutrum turpis. +

+ ), items: [ { label: 'AccountInfo1'