Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(www): useActiveHash hook for highlighting links in Docs'… (#21762)
* Create useActiveHash hook * Change hashlist to idlist * Remove console.log * Hook cleanup * Style link based on hash * Add traversal option * Move hooks to its own file * Improve hook * Add comments, remove console.log * Revert hash remove logic * Remove unused colors * Revert "Remove unused colors" This reverts commit 8160ad8. * Remove unused colors * Refactor getHeadingIds * Switch to getElementById * Handle cases where url is absent * Do not update URL hash * Disable active link behavior on mobile * Handle mobile with media query * Move function * Rename toc to items, add depth prop * Highlight subheadings * Add tests * update recursion so tableOfContentsDepth is respected and something is always highlighted in ToC Co-authored-by: Kyle Gill <kylerobertgill@gmail.com>
- Loading branch information
Showing
5 changed files
with
351 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
import React from "react" | ||
import { render } from "@testing-library/react" | ||
import "@testing-library/jest-dom/extend-expect" | ||
import { ThemeProvider } from "theme-ui" | ||
|
||
import theme from "../../../src/gatsby-plugin-theme-ui" | ||
import TableOfContents from "../docs-table-of-contents" | ||
|
||
const tableOfContentsNoUrl = { | ||
location: { | ||
pathname: "", | ||
}, | ||
depth: 2, | ||
items: [ | ||
{ | ||
title: "API commands", | ||
items: [ | ||
{ | ||
url: "#new", | ||
title: "new", | ||
items: [ | ||
{ | ||
title: "Arguments", | ||
}, | ||
{ | ||
url: "#examples", | ||
title: "Examples", | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
], | ||
} | ||
|
||
const tableOfContentsSimple = { | ||
location: { | ||
pathname: "", | ||
}, | ||
depth: null, | ||
items: [ | ||
{ | ||
url: "#how-to-use-gatsby-cli", | ||
title: "How to use gatsby-cli", | ||
}, | ||
], | ||
} | ||
|
||
const tableOfContentsDeep = { | ||
location: { | ||
pathname: "", | ||
}, | ||
depth: 2, | ||
items: [ | ||
{ | ||
url: "#how-to-use-gatsby-cli", | ||
title: "How to use gatsby-cli", | ||
}, | ||
{ | ||
url: "#api-commands", | ||
title: "API commands", | ||
items: [ | ||
{ | ||
url: "#new", | ||
title: "new", | ||
items: [ | ||
{ | ||
url: "#arguments", | ||
title: "Arguments", | ||
}, | ||
{ | ||
url: "#examples", | ||
title: "Examples", | ||
}, | ||
], | ||
}, | ||
{ | ||
url: "#develop", | ||
title: "develop", | ||
items: [ | ||
{ | ||
url: "#options", | ||
title: "Options", | ||
}, | ||
{ | ||
url: "#preview-changes-on-other-devices", | ||
title: "Preview changes on other devices", | ||
}, | ||
], | ||
}, | ||
{ | ||
url: "#build", | ||
title: "build", | ||
items: [ | ||
{ | ||
url: "#options-1", | ||
title: "Options", | ||
}, | ||
], | ||
}, | ||
{ | ||
url: "#serve", | ||
title: "serve", | ||
items: [ | ||
{ | ||
url: "#options-2", | ||
title: "Options", | ||
}, | ||
], | ||
}, | ||
{ | ||
url: "#info", | ||
title: "info", | ||
items: [ | ||
{ | ||
url: "#options-3", | ||
title: "Options", | ||
}, | ||
], | ||
}, | ||
{ | ||
url: "#clean", | ||
title: "clean", | ||
}, | ||
{ | ||
url: "#plugin", | ||
title: "plugin", | ||
items: [ | ||
{ | ||
url: "#docs", | ||
title: "docs", | ||
}, | ||
], | ||
}, | ||
{ | ||
url: "#repl", | ||
title: "Repl", | ||
}, | ||
{ | ||
url: "#disabling-colored-output", | ||
title: "Disabling colored output", | ||
}, | ||
], | ||
}, | ||
{ | ||
url: "#how-to-change-your-default-package-manager-for-your-next-project", | ||
title: | ||
"How to change your default package manager for your next project?", | ||
}, | ||
], | ||
} | ||
|
||
Object.defineProperty(window, "IntersectionObserver", { | ||
writable: true, | ||
value: jest.fn().mockImplementation(() => { | ||
return { | ||
observe: jest.fn(), | ||
unobserve: jest.fn(), | ||
} | ||
}), | ||
}) | ||
|
||
Object.defineProperty(window, "matchMedia", { | ||
writable: true, | ||
value: jest.fn().mockImplementation(query => ({ | ||
matches: false, | ||
addListener: jest.fn(), | ||
removeListener: jest.fn(), | ||
})), | ||
}) | ||
|
||
const testHeadingsRecursively = (getByTestId, items, depth) => { | ||
if (depth === 0) return | ||
|
||
for (const item of items) { | ||
if (item.url) { | ||
expect(getByTestId(item.url)).toHaveTextContent(item.title) | ||
} | ||
|
||
if (item.items) { | ||
testHeadingsRecursively(getByTestId, item.items, depth - 1) | ||
} | ||
} | ||
} | ||
|
||
test("Table of contents (depth == 0)", () => { | ||
const { items, depth, location } = tableOfContentsSimple | ||
const { getByTestId } = render( | ||
<ThemeProvider theme={theme}> | ||
<TableOfContents items={items} depth={depth} location={location} /> | ||
</ThemeProvider> | ||
) | ||
|
||
for (const item of items) { | ||
if (item.url) { | ||
expect(getByTestId(item.url)).toHaveTextContent(item.title) | ||
} | ||
} | ||
}) | ||
|
||
test("Table of contents (depth >= 1)", () => { | ||
const { items, depth, location } = tableOfContentsDeep | ||
const { getByTestId } = render( | ||
<ThemeProvider theme={theme}> | ||
<TableOfContents items={items} depth={depth} location={location} /> | ||
</ThemeProvider> | ||
) | ||
|
||
testHeadingsRecursively(getByTestId, items, depth - 1) | ||
}) | ||
|
||
test("Table of contents (missing URLs)", () => { | ||
const { items, depth, location } = tableOfContentsNoUrl | ||
const { getByTestId } = render( | ||
<ThemeProvider theme={theme}> | ||
<TableOfContents items={items} depth={depth} location={location} /> | ||
</ThemeProvider> | ||
) | ||
|
||
testHeadingsRecursively(getByTestId, items, depth - 1) | ||
}) |
Oops, something went wrong.