Skip to content

Commit

Permalink
fix(dev-portal): fix broken hash router links (#2497)
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel A. White authored Jan 4, 2024
1 parent 701620c commit c28eaed
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Box, Flex, Icon } from '@stoplight/mosaic';
import * as React from 'react';

import { useRouterType } from '../../context/RouterType';
import { useFirstRender } from '../../hooks/useFirstRender';
import { VersionBadge } from '../Docs/HttpOperation/Badges';
import {
Expand Down Expand Up @@ -48,6 +49,10 @@ export const TableOfContents = React.memo<TableOfContentsProps>(
const child = React.useRef<HTMLDivElement>(null);
const firstRender = useFirstRender();

// when using the hash router, slugs must be absolute - otherwise the router will keep appending to the existing hash route
// this flag makes a slug like `abc/operations/getPet` be rendered as `#/abc/operations/getPet`
const makeSlugAbsoluteRoute = useRouterType() == 'hash';

React.useEffect(() => {
// setTimeout to handle scrollTo after groups expand to display active GroupItem
setTimeout(() => {
Expand Down Expand Up @@ -87,6 +92,7 @@ export const TableOfContents = React.memo<TableOfContentsProps>(
maxDepthOpenByDefault={maxDepthOpenByDefault}
onLinkClick={onLinkClick}
isInResponsiveMode={isInResponsiveMode}
makeSlugAbsoluteRoute={makeSlugAbsoluteRoute}
/>
);
})}
Expand Down Expand Up @@ -122,9 +128,10 @@ const GroupItem = React.memo<{
depth: number;
item: TableOfContentsGroupItem;
isInResponsiveMode?: boolean;
makeSlugAbsoluteRoute?: boolean;
maxDepthOpenByDefault?: number;
onLinkClick?(): void;
}>(({ item, depth, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick }) => {
}>(({ item, depth, maxDepthOpenByDefault, isInResponsiveMode, makeSlugAbsoluteRoute, onLinkClick }) => {
if (isExternalLink(item)) {
return (
<Box as="a" href={item.url} target="_blank" rel="noopener noreferrer" display="block">
Expand All @@ -144,13 +151,15 @@ const GroupItem = React.memo<{
maxDepthOpenByDefault={maxDepthOpenByDefault}
onLinkClick={onLinkClick}
isInResponsiveMode={isInResponsiveMode}
makeSlugAbsoluteRoute={makeSlugAbsoluteRoute}
/>
);
} else if (isNode(item)) {
return (
<Node
depth={depth}
isInResponsiveMode={isInResponsiveMode}
makeSlugAbsoluteRoute={makeSlugAbsoluteRoute}
item={item}
onLinkClick={onLinkClick}
meta={
Expand Down Expand Up @@ -181,8 +190,9 @@ const Group = React.memo<{
item: TableOfContentsGroup | TableOfContentsNodeGroup;
maxDepthOpenByDefault?: number;
isInResponsiveMode?: boolean;
makeSlugAbsoluteRoute?: boolean;
onLinkClick?(): void;
}>(({ depth, item, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick = () => {} }) => {
}>(({ depth, item, maxDepthOpenByDefault, isInResponsiveMode, makeSlugAbsoluteRoute, onLinkClick = () => {} }) => {
const activeId = React.useContext(ActiveIdContext);
const [isOpen, setIsOpen] = React.useState(() => isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault));
const hasActive = !!activeId && hasActiveItem(item.items, activeId);
Expand Down Expand Up @@ -238,6 +248,7 @@ const Group = React.memo<{
onClick={handleClick}
onLinkClick={onLinkClick}
isInResponsiveMode={isInResponsiveMode}
makeSlugAbsoluteRoute={makeSlugAbsoluteRoute}
/>
);
} else {
Expand Down Expand Up @@ -271,6 +282,7 @@ const Group = React.memo<{
depth={depth + 1}
onLinkClick={onLinkClick}
isInResponsiveMode={isInResponsiveMode}
makeSlugAbsoluteRoute={makeSlugAbsoluteRoute}
/>
);
})}
Expand Down Expand Up @@ -331,53 +343,56 @@ const Node = React.memo<{
meta?: React.ReactNode;
showAsActive?: boolean;
isInResponsiveMode?: boolean;
makeSlugAbsoluteRoute?: boolean;
onClick?: (e: React.MouseEvent, forceOpen?: boolean) => void;
onLinkClick?(): void;
}>(({ item, depth, meta, showAsActive, isInResponsiveMode, onClick, onLinkClick = () => {} }) => {
const activeId = React.useContext(ActiveIdContext);
const isActive = activeId === item.slug || activeId === item.id;
const LinkComponent = React.useContext(LinkContext);
}>(
({ item, depth, meta, showAsActive, isInResponsiveMode, makeSlugAbsoluteRoute, onClick, onLinkClick = () => {} }) => {
const activeId = React.useContext(ActiveIdContext);
const isActive = activeId === item.slug || activeId === item.id;
const LinkComponent = React.useContext(LinkContext);

const handleClick = (e: React.MouseEvent) => {
if (isActive) {
// Don't trigger link click when we're active
e.stopPropagation();
e.preventDefault();
} else {
onLinkClick();
}
const handleClick = (e: React.MouseEvent) => {
if (isActive) {
// Don't trigger link click when we're active
e.stopPropagation();
e.preventDefault();
} else {
onLinkClick();
}

// Force open when clicking inactive group
if (onClick) {
onClick(e, isActive ? undefined : true);
}
};
// Force open when clicking inactive group
if (onClick) {
onClick(e, isActive ? undefined : true);
}
};

return (
<Box
as={LinkComponent}
to={item.slug}
display="block"
textDecoration="no-underline"
className="ElementsTableOfContentsItem"
>
<Item
id={getHtmlIdFromItemId(item.slug || item.id)}
isActive={isActive || showAsActive}
depth={depth}
title={item.title}
icon={
NODE_TYPE_TITLE_ICON[item.type] && (
<Box as={Icon} color={NODE_TYPE_ICON_COLOR[item.type]} icon={NODE_TYPE_TITLE_ICON[item.type]} />
)
}
meta={meta}
isInResponsiveMode={isInResponsiveMode}
onClick={handleClick}
/>
</Box>
);
});
return (
<Box
as={LinkComponent}
to={makeSlugAbsoluteRoute && !item.slug.startsWith('/') ? `/${item.slug}` : item.slug}
display="block"
textDecoration="no-underline"
className="ElementsTableOfContentsItem"
>
<Item
id={getHtmlIdFromItemId(item.slug || item.id)}
isActive={isActive || showAsActive}
depth={depth}
title={item.title}
icon={
NODE_TYPE_TITLE_ICON[item.type] && (
<Box as={Icon} color={NODE_TYPE_ICON_COLOR[item.type]} icon={NODE_TYPE_TITLE_ICON[item.type]} />
)
}
meta={meta}
isInResponsiveMode={isInResponsiveMode}
onClick={handleClick}
/>
</Box>
);
},
);

const Version: React.FC<{ value: string }> = ({ value }) => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,11 @@ const StoplightProjectRouter = ({
<DevPortalProvider platformUrl={platformUrl}>
<RouterTypeContext.Provider value={router}>
<Router {...routerProps} key={basePath}>
<Route path="/branches/:branchSlug/:nodeSlug" exact>
<Route path="/branches/:branchSlug/:nodeSlug+" exact>
<StoplightProjectImpl {...props} />
</Route>

<Route path="/:nodeSlug" exact>
<Route path="/:nodeSlug+" exact>
<StoplightProjectImpl {...props} />
</Route>

Expand Down

0 comments on commit c28eaed

Please sign in to comment.