Skip to content

Commit

Permalink
feat(www): useActiveHash hook for highlighting links in Docs'… (#21762)
Browse files Browse the repository at this point in the history
* 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
jlkiri and gillkyle committed Mar 20, 2020
1 parent 5b76d13 commit 4ca629f
Show file tree
Hide file tree
Showing 5 changed files with 351 additions and 51 deletions.
1 change: 1 addition & 0 deletions www/package.json
Expand Up @@ -149,6 +149,7 @@
"lingui:build": "yarn lingui:extract && yarn lingui:compile"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.1.1",
"@lingui/cli": "^2.9.1",
"@lingui/macro": "^2.9.1",
"@testing-library/react": "^8.0.9",
Expand Down
221 changes: 221 additions & 0 deletions www/src/components/__tests__/table-of-contents.js
@@ -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)
})

0 comments on commit 4ca629f

Please sign in to comment.