Skip to content

Commit

Permalink
docs: add some inline docs to explain some points
Browse files Browse the repository at this point in the history
  • Loading branch information
isqua committed Oct 28, 2023
1 parent 423f7f7 commit 875ce26
Show file tree
Hide file tree
Showing 16 changed files with 76 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/app/Router/TestRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { PropsWithChildren } from 'react'
import { RouterProvider, createMemoryRouter } from 'react-router-dom'

type TestRouterProps = PropsWithChildren<{
/** Current URL */
url?: string
}>

Expand Down
2 changes: 2 additions & 0 deletions src/components/Article/Article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { BreadCrumbs } from '../BreadCrumbs'
import styles from './Article.module.css'

type ArticleProps = {
/** A page to display */
page: PageDescriptor
/** Array of its ancestors including the page itself */
breadcrumbs: PageDescriptor[]
}

Expand Down
1 change: 1 addition & 0 deletions src/components/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import styles from './Input.module.css'
type InputProps = {
onChange?: (text: string) => void
placeholder?: string
/** Should show spinner */
isLoading?: boolean
}

Expand Down
4 changes: 4 additions & 0 deletions src/components/Transitions/HeightTransition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ import { CSSTransition } from 'react-transition-group'
import type { CSSTransitionClassNames } from 'react-transition-group/CSSTransition'

type HeightTransitionProps = PropsWithChildren<{
/** Show the component; triggers the enter or exit states */
isVisible: boolean
/** A React reference to DOM element that need to transition */
nodeRef: RefObject<HTMLElement>
/** The animation `classNames` applied to the component as it enters or exits */
classNames: CSSTransitionClassNames
/** Minimum expected height of the element, in case the element is not visible */
minHeight: number
}>

Expand Down
1 change: 1 addition & 0 deletions src/features/toc/api/useGetTocQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ async function fetchToc(url: string): Promise<TableOfContent> {
return res.json() as Promise<TableOfContent>
}

/** Fetches the TableOfContent data from URL */
export function useGetTocQuery(url: string) {
const callback = useCallback(() => fetchToc(url), [url])

Expand Down
16 changes: 16 additions & 0 deletions src/features/toc/core/buildMenuSection.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
import type { MenuItem, PageDescriptor, PageHighlight, PageId, PageURL, SectionHighlight, TableOfContent } from '../types'

type BuildMenuBaseOptions = {
/**
* Current page URL to highlight in the menu
* If it is necessary to pass ID instead of URL, then we will need to replace this field with ID
*/
url: PageURL
/** Current page ancestors */
breadcrumbs: PageDescriptor[]
/** Items that match the search filter and its ancestors */
filter?: Set<PageDescriptor> | null
}

type BuildMenuTopLevelOptions = BuildMenuBaseOptions

type BuildMenuNestingOptions = BuildMenuBaseOptions & {
/** ID of the page whose children we want to render */
parentId: string
/** The level of current menu items */
level: number
/** The relation of pages to the active page for proper highlighting */
highlight: SectionHighlight
}

type BuildMenuOptions = BuildMenuTopLevelOptions | BuildMenuNestingOptions

type PageProps = {
/** The relation of the page to the active page for proper highlighting */
highlight: PageHighlight
/** Should the page be opened by default */
defaultOpenState: boolean
/** The level of the current page */
level: number
}

Expand Down Expand Up @@ -79,6 +91,10 @@ export const buildMenuSection = (toc: TableOfContent, options: BuildMenuOptions)
let highlight: PageHighlight = sectionHighlight
let defaultOpenState = false

/**
* If it is necessary to pass ID instead of URL, then we will need to replace this check with
* page.id === options.id
*/
if (page.url === url) {
highlight = 'active'
defaultOpenState = Boolean(page.pages?.length)
Expand Down
8 changes: 8 additions & 0 deletions src/features/toc/core/filterTreeNodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import type { PageDescriptor, TableOfContent } from '../types'

import { isTextMatch } from './isTextMatch'

/**
* Filter TOC by the search string.
* The page is considering suitable, if it or one of its descendants matches the text
*
* @param toc The TOC to be filtered
* @param search The string to find in pages titles
* @returns Set of pages that should be presented in the search results
*/
export const filterTreeNodes = (toc: TableOfContent, search: string): Set<PageDescriptor> => {
const filterResult = new Set<PageDescriptor>()
const normalizedSearch = search.toLocaleLowerCase()
Expand Down
5 changes: 5 additions & 0 deletions src/features/toc/core/getBreadCrumbs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import type { PageDescriptor, PageURL, PageId, TableOfContent } from '../types'
import { getCurrentPage } from './getCurrentPage'

/**
* @param toc The TOC data
* @param url Page URL
* @returns Current page and the array of its ancestors from top to bottom
*/
export const getBreadCrumbs = (toc: TableOfContent, url?: PageURL): PageDescriptor[] => {
const breadcrumbs: PageDescriptor[] = []

Expand Down
7 changes: 7 additions & 0 deletions src/features/toc/core/isTextMatch.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* Rough fuzzy search that finds "omit" in "jOhn sMITh".
*
* @param value value to check, e.g. a page title "jOhn sMITh"
* @param search string to search in the value, e.g. "omit"
* @returns boolean if the value matches the search string
*/
export const isTextMatch = (value: string, search: string) => {
const normalizedValue = value.toLowerCase()

Expand Down
3 changes: 3 additions & 0 deletions src/features/toc/ui/Menu/Context/MenuProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import type { PageURL, TableOfContent } from '../../../types'
import { FilterContext, LocationContext, TocContext } from './contexts'

type MenuProviderProps = PropsWithChildren<{
/** The whole TOC tree */
toc: TableOfContent
/** Current URL */
url: PageURL
/** Is the TOC loading */
isLoading?: boolean
}>

Expand Down
4 changes: 4 additions & 0 deletions src/features/toc/ui/Menu/Context/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export const useFilterInput = () => {
const { isFiltering, onChange, onFilterStart, onReset } = useContext(FilterContext)
const timeout = useRef<number>(0)

/**
* Filter results should appear when the user enters the whole query.
* So waiting for FILTER_DELAY_IN_MS until the user stops typing
*/
const onChangeHandler = useCallback((value: string) => {
if (timeout.current) {
clearTimeout(timeout.current)
Expand Down
12 changes: 12 additions & 0 deletions src/features/toc/ui/Menu/Item/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,22 @@ import { useIsLoading } from '../Context/hooks'
import styles from './Item.module.css'

type ItemProps = PropsWithChildren<{
/** The item :) */
item: MenuItem
/** OnClick handler, e.g. expand/collapse the section */
onClick?: () => void
/** Show the component; triggers the enter or exit states for the animation */
isVisible?: boolean
}>

type ItemToggleProps = {
/** The item */
item: MenuItem
/** ReactChildren to show when item is opened */
children: (isOpen: boolean) => JSX.Element
/** Show the component; triggers the enter or exit states for the animation */
isVisible: boolean
/** Is it allowed to change the toggle state */
isDisabled?: boolean
}

Expand Down Expand Up @@ -88,6 +95,11 @@ export function ItemToggle({ item, children, isDisabled, isVisible }: ItemToggle
}

const hasUrl = Boolean(item.url)
/**
* While the menu is loading, it makes no sense to collapse and expand the items. So forbid them to collapse.
* Also, when using the search, it is not necessary to collapse the items, because the search result may be
* a leaf of the tree. So forbid collapsing items in search mode too.
*/
const shouldBeForciblyOpened = isLoading || isDisabled
const shouldShowChildren = shouldBeForciblyOpened || isOpen && isVisible
const shouldPreventClose = shouldBeForciblyOpened || isOpen && hasUrl
Expand Down
3 changes: 3 additions & 0 deletions src/features/toc/ui/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import { List } from './List/List'
import styles from './Menu.module.css'

export type MenuProps = {
/** The whole TOC tree */
toc: TableOfContent
/** Current URL */
activeUrl: string
/** Is the TOC loading */
isLoading?: boolean
}

Expand Down
4 changes: 4 additions & 0 deletions src/features/toc/ui/Menu/Section/Section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ import { useSectionItems } from '../Context/hooks'
import { Item, ItemToggle } from '../Item/Item'

type SectionProps = {
/** ID of the page whose children we want to render */
parentId: PageId
/** The level of the current section */
level: number
/** The relation of the section to the active page for proper highlighting */
highlight?: SectionHighlight
/** Show the component; triggers the enter or exit states for the animation */
isVisible?: boolean
}

Expand Down
4 changes: 4 additions & 0 deletions src/hooks/useCurrentPageUrl.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { useLocation } from 'react-router-dom'

/**
* Extract current page url from the router, and correct it to the TOC format
* The TOC links has no leading slash, so remove it
*/
export function useCurrentPageUrl() {
const location = useLocation()
const currentUrl = location.pathname.replace(/^\//, '')
Expand Down
1 change: 1 addition & 0 deletions src/test/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { render, renderHook, type RenderOptions } from '@testing-library/react'
import { TestRouter } from '../app/Router'

type AppProvidersProps = {
/** Current URL */
url?: string
}

Expand Down

0 comments on commit 875ce26

Please sign in to comment.