diff --git a/packages/elements-core/src/components/MosaicTableOfContents/TableOfContents.tsx b/packages/elements-core/src/components/MosaicTableOfContents/TableOfContents.tsx index 9309a7475..0a365fa63 100644 --- a/packages/elements-core/src/components/MosaicTableOfContents/TableOfContents.tsx +++ b/packages/elements-core/src/components/MosaicTableOfContents/TableOfContents.tsx @@ -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 { @@ -48,6 +49,10 @@ export const TableOfContents = React.memo( const child = React.useRef(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(() => { @@ -87,6 +92,7 @@ export const TableOfContents = React.memo( maxDepthOpenByDefault={maxDepthOpenByDefault} onLinkClick={onLinkClick} isInResponsiveMode={isInResponsiveMode} + makeSlugAbsoluteRoute={makeSlugAbsoluteRoute} /> ); })} @@ -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 ( @@ -144,6 +151,7 @@ const GroupItem = React.memo<{ maxDepthOpenByDefault={maxDepthOpenByDefault} onLinkClick={onLinkClick} isInResponsiveMode={isInResponsiveMode} + makeSlugAbsoluteRoute={makeSlugAbsoluteRoute} /> ); } else if (isNode(item)) { @@ -151,6 +159,7 @@ const GroupItem = React.memo<{ (({ 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); @@ -238,6 +248,7 @@ const Group = React.memo<{ onClick={handleClick} onLinkClick={onLinkClick} isInResponsiveMode={isInResponsiveMode} + makeSlugAbsoluteRoute={makeSlugAbsoluteRoute} /> ); } else { @@ -271,6 +282,7 @@ const Group = React.memo<{ depth={depth + 1} onLinkClick={onLinkClick} isInResponsiveMode={isInResponsiveMode} + makeSlugAbsoluteRoute={makeSlugAbsoluteRoute} /> ); })} @@ -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 ( - - - ) - } - meta={meta} - isInResponsiveMode={isInResponsiveMode} - onClick={handleClick} - /> - - ); -}); + return ( + + + ) + } + meta={meta} + isInResponsiveMode={isInResponsiveMode} + onClick={handleClick} + /> + + ); + }, +); const Version: React.FC<{ value: string }> = ({ value }) => { return ( diff --git a/packages/elements-dev-portal/src/containers/StoplightProject.tsx b/packages/elements-dev-portal/src/containers/StoplightProject.tsx index fa0fedd05..fd31aa82b 100644 --- a/packages/elements-dev-portal/src/containers/StoplightProject.tsx +++ b/packages/elements-dev-portal/src/containers/StoplightProject.tsx @@ -192,11 +192,11 @@ const StoplightProjectRouter = ({ - + - +