Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/app/components/jsx-helpers/raw-html.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ function activateScripts(el: HTMLElement) {
processOne();
}

type RawHTMLArgs = {
type RawHTMLArgs = ({
Tag?: string;
html?: TrustedHTML;
embed?: boolean;
} & React.HTMLAttributes<HTMLDivElement>;
href?: string;
} & React.HTMLAttributes<HTMLDivElement>);

export default function RawHTML({
Tag = 'div',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@
// for ordinary website navigations, per
// https://www.w3.org/WAI/ARIA/apg/patterns/menubar/examples/menubar-navigation/

export function MenuItem({label, url, local=undefined}) {
export function MenuItem({
label,
url,
local = undefined
}: {
label: string;
url: string;
local?: string;
}) {
const {innerWidth: _} = useWindowContext();
const urlPath = url.replace('/view-all', '');
const {pathname} = useLocation();
Expand All @@ -33,7 +41,13 @@
);
}

function OptionalWrapper({isWrapper = true, children}) {
function OptionalWrapper({
isWrapper,
children
}: {
isWrapper: boolean;
children?: React.ReactNode;
}) {
return isWrapper ? (
<div className="nav-menu-item dropdown">{children}</div>
) : (
Expand All @@ -48,13 +62,19 @@
children,
excludeWrapper = false,
navAnalytics
}: {
Tag?: React.ElementType;
className?: string;
label: string;
children?: React.ReactNode;
excludeWrapper?: boolean;
navAnalytics?: string;
}) {
const topRef = useRef();
const dropdownRef = useRef(null);
const topRef = useRef<HTMLAnchorElement>(null);
const dropdownRef = useRef<HTMLDivElement>(null);
const ddId = `ddId-${label}`;
const {
closeMenu, closeDesktopMenu, openMenu, openDesktopMenu
} = useMenuControls({topRef, label});
const {closeMenu, closeDesktopMenu, openMenu, openDesktopMenu} =
useMenuControls({topRef, label});
const navigateByKey = useNavigateByKey({
topRef,
dropdownRef,
Expand Down Expand Up @@ -98,12 +118,19 @@
closeMenu,
openMenu,
label
}: {
ddId: string;
closeDesktopMenu: () => void;
topRef: React.RefObject<HTMLAnchorElement>;
closeMenu: () => void;
openMenu: (event: React.MouseEvent) => void;
label: string;
}) {
const {activeDropdown, prefix} = useDropdownContext();
const isOpen = activeDropdown === topRef;
const labelId = `${prefix}-${label}`;
const toggleMenu = React.useCallback(
(event) => {
(event: React.MouseEvent<HTMLAnchorElement>) => {
if (activeDropdown === topRef) {
event.preventDefault();
closeMenu();
Expand All @@ -114,8 +141,11 @@
[openMenu, closeMenu, activeDropdown, topRef]
);
const closeOnBlur = React.useCallback(
({currentTarget, relatedTarget}) => {
if (currentTarget.parentNode.contains(relatedTarget)) {
({
currentTarget,
relatedTarget
}: React.FocusEvent<HTMLAnchorElement>) => {
if (currentTarget.parentNode?.contains(relatedTarget)) {
return;
}
closeDesktopMenu();
Expand All @@ -123,9 +153,9 @@
[closeDesktopMenu]
);

React.useEffect(() => {

Check failure on line 156 in src/app/layouts/default/header/menus/main-menu/dropdown/dropdown.tsx

View workflow job for this annotation

GitHub Actions / osweb

Argument of type '() => (() => void) | null' is not assignable to parameter of type 'EffectCallback'.
if (isOpen) {
const handler = ({key}) => {

Check failure on line 158 in src/app/layouts/default/header/menus/main-menu/dropdown/dropdown.tsx

View workflow job for this annotation

GitHub Actions / osweb

Binding element 'key' implicitly has an 'any' type.
if (key === 'Escape') {
closeDesktopMenu();
}
Expand Down Expand Up @@ -169,7 +199,19 @@
);
}

function DropdownContents({id, label, dropdownRef, navAnalytics, children}) {
function DropdownContents({
id,
label,
dropdownRef,
navAnalytics,
children
}: {
id: string;
label: string;
dropdownRef: React.RefObject<HTMLDivElement>;
navAnalytics?: string;
children?: React.ReactNode;
}) {
return (
<div className="dropdown-container">
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default function useMenuControls({
topRef,
label
}: {
topRef: React.MutableRefObject<HTMLAnchorElement>;
topRef: React.MutableRefObject<HTMLAnchorElement | null>;
label: string;
}) {
const {setSubmenuLabel, setActiveDropdown} = useDropdownContext();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
import useDropdownContext from '../../dropdown-context';
import {isMobileDisplay} from '~/helpers/device';
import {assertDefined} from '~/helpers/data';

function findNext(dropdownRef: React.MutableRefObject<HTMLDivElement>) {
function findNext(dropdownRef: React.MutableRefObject<HTMLDivElement | null>) {
const nextSib = document.activeElement?.nextElementSibling;

if (nextSib?.matches('a')) {
return nextSib as HTMLAnchorElement;
}
const targets = Array.from(dropdownRef.current.querySelectorAll('a'));
const targets = Array.from(
assertDefined(dropdownRef.current?.querySelectorAll('a'))
);
const idx = targets.indexOf(document.activeElement as HTMLAnchorElement);
const nextIdx = (idx + 1) % targets.length;

return targets[nextIdx];
}

function findPrev(
topRef: React.MutableRefObject<HTMLAnchorElement>,
dropdownRef: React.MutableRefObject<HTMLDivElement>
topRef: React.MutableRefObject<HTMLAnchorElement | null>,
dropdownRef: React.MutableRefObject<HTMLDivElement | null>
) {
const prevSib = document.activeElement?.previousElementSibling;

if (prevSib?.matches('a')) {
return prevSib as HTMLAnchorElement;
}
const targets = Array.from(dropdownRef.current.querySelectorAll('a'));
const targets = Array.from(
assertDefined(dropdownRef.current?.querySelectorAll('a'))
);
const idx = targets.indexOf(document.activeElement as HTMLAnchorElement);

if (idx === 0) {
Expand All @@ -40,8 +45,8 @@ export default function useNavigateByKey({
closeMenu,
closeDesktopMenu
}: {
topRef: React.MutableRefObject<HTMLAnchorElement>;
dropdownRef: React.MutableRefObject<HTMLDivElement>;
topRef: React.MutableRefObject<HTMLAnchorElement | null>;
dropdownRef: React.MutableRefObject<HTMLDivElement | null>;
closeMenu: () => void;
closeDesktopMenu: () => void;
}) {
Expand Down Expand Up @@ -69,15 +74,17 @@ export default function useNavigateByKey({
case 'ArrowDown':
event.preventDefault();
if (document.activeElement === topRef.current) {
(dropdownRef.current.firstChild as HTMLAnchorElement)?.focus();
(
dropdownRef.current?.firstChild as HTMLAnchorElement
)?.focus();
} else {
findNext(dropdownRef).focus();
}
break;
case 'ArrowUp':
event.preventDefault();
if (document.activeElement !== topRef.current) {
findPrev(topRef, dropdownRef).focus();
findPrev(topRef, dropdownRef)?.focus();
}
break;
case 'Escape':
Expand Down

This file was deleted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes are actually minimal apart from prettier. See the first commit.

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react';
import {useLocation} from 'react-router-dom';
import useUserContext from '~/contexts/user';
import linkHelper from '~/helpers/link';
import Dropdown, {MenuItem} from '../dropdown/dropdown';
import type {WindowWithSettings} from '~/helpers/window-settings';
import {assertDefined} from '~/helpers/data';

const settings = (window as WindowWithSettings).SETTINGS;
const reqFacultyAccessLink = `${settings.accountHref}/i/signup/educator/cs_form`;
const profileLink = `${settings.accountHref}/profile`;

function AccountItem() {
const {myOpenStaxUser} = useUserContext();
const mosIsAvailable = !myOpenStaxUser.error;

return mosIsAvailable ? (
<MenuItem label="Account Dashboard" url="/account" />
) : (
<MenuItem
label="Account Profile"
url={`${settings.accountHref}/profile`}
/>
);
}

export default function LoginMenuWithDropdown() {
const userModel = assertDefined(useUserContext().userModel);

// updates logoutLink
useLocation();
const label = `Hi ${userModel.first_name || userModel.username}`;

return (
<Dropdown
className="login-menu nav-menu-item rightmost dropdown"
label={label}
excludeWrapper
>
<AccountItem />
{userModel.instructorEligible && (
<MenuItem
label="Request instructor access"
url={reqFacultyAccessLink}
/>
)}
{userModel.incompleteSignup && (
<MenuItem label="Complete your profile" url={profileLink} />
)}
{userModel.pendingInstructorAccess && (
<MenuItem label="Pending instructor access" url={profileLink} />
)}
{userModel.emailUnverified && (
<MenuItem label="Verify your email address" url={profileLink} />
)}
<MenuItem
label="Log out"
url={linkHelper.logoutLink()}
local="true"
/>
</Dropdown>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,14 @@ import linkHelper from '~/helpers/link';
function LoginLink() {
// It's not used directly, but loginLink changes when it does
useLocation();
const addressHinkyQAIssue = React.useCallback(
(e) => {
if (e.defaultPrevented) {
e.defaultPrevented = false;
}
},
[]
);

return (
<li className="login-menu nav-menu-item rightmost">
<a
href={linkHelper.loginLink()} className="pardotTrackClick"
data-local="true" role="menuitem" onClick={addressHinkyQAIssue}
href={linkHelper.loginLink()}
className="pardotTrackClick"
data-local="true"
role="menuitem"
>
Log in
</a>
Expand All @@ -32,9 +26,9 @@ export default function LoginMenu() {
const {userModel} = useUserContext();
const loggedIn = Boolean(typeof userModel === 'object' && userModel.id);

return (
loggedIn ?
<JITLoad importFn={() => import('./login-menu-with-dropdown')} /> :
<LoginLink />
return loggedIn ? (
<JITLoad importFn={() => import('./login-menu-with-dropdown')} />
) : (
<LoginLink />
);
}
Loading
Loading