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,