From 9650bd7ecc10156649439d436e8ddd2bbc8ad5d4 Mon Sep 17 00:00:00 2001 From: Sasha Koss Date: Fri, 10 Mar 2023 13:30:08 +0800 Subject: [PATCH] Commit bunch of changes --- package.json | 2 +- src/ui/components/DocDescription/index.tsx | 6 +- src/ui/components/HighlightQuery/index.tsx | 4 +- src/ui/components/IdHighlight/index.tsx | 12 +- src/ui/components/Item/index.tsx | 28 ++++- src/ui/components/Item/styles.css.ts | 2 +- src/ui/components/NoSearchResults/index.tsx | 13 +-- src/ui/components/RichText/styles.css.ts | 2 +- src/ui/components/Search/index.tsx | 7 +- src/ui/components/Search/styles.css.ts | 2 +- .../TypeDocSignature/Generics/index.tsx | 6 +- src/ui/components/TypeDocSignature/index.tsx | 5 +- .../contexts/IgnoreParentTypesSource/index.ts | 3 + src/ui/hooks/useActiveItem/index.ts | 19 ++++ src/ui/hooks/useQuery/index.tsx | 13 +++ .../Docs/Doc/TypeDoc/Constants/index.tsx | 11 +- .../Doc/TypeDoc/Function/Signature/index.tsx | 5 +- .../Docs/Doc/TypeDoc/Function/index.tsx | 44 +++++++- .../screens/Docs/Doc/TypeDoc/Types/index.tsx | 106 +++++++++++++----- .../Docs/Doc/TypeDoc/Types/styles.css.ts | 21 +++- src/ui/screens/Docs/Finder/Categories.tsx | 3 + src/ui/screens/Docs/Finder/Items.tsx | 63 ++++++----- src/ui/screens/Docs/Finder/index.tsx | 6 +- src/utils/docs/index.ts | 31 ++++- src/utils/dom/index.ts | 75 +++++++++++++ yarn.lock | 8 +- 26 files changed, 383 insertions(+), 114 deletions(-) create mode 100644 src/ui/contexts/IgnoreParentTypesSource/index.ts create mode 100644 src/ui/hooks/useActiveItem/index.ts create mode 100644 src/ui/hooks/useQuery/index.tsx create mode 100644 src/utils/dom/index.ts diff --git a/package.json b/package.json index cb41cca8..960c881a 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "start": "env NODE_ENV=development ts-node -r tsconfig-paths/register devServer.ts" }, "dependencies": { - "@date-fns/docs": "0.22.0", + "@date-fns/docs": "0.24.0", "@sentry/browser": "^5.30.0", "@sentry/tracing": "^5.30.0", "@switcher/preact": "2.3.0", diff --git a/src/ui/components/DocDescription/index.tsx b/src/ui/components/DocDescription/index.tsx index 21b750eb..d3730758 100644 --- a/src/ui/components/DocDescription/index.tsx +++ b/src/ui/components/DocDescription/index.tsx @@ -6,15 +6,19 @@ interface DocDescriptionProps { description: string scope?: string header?: 'h2' | 'h3' + skipHeader?: boolean } export const DocDescription: FunctionComponent = ({ description, header, scope, + skipHeader, }) => (
- + {!skipHeader && ( + + )}
) diff --git a/src/ui/components/HighlightQuery/index.tsx b/src/ui/components/HighlightQuery/index.tsx index feeaadca..2204c160 100644 --- a/src/ui/components/HighlightQuery/index.tsx +++ b/src/ui/components/HighlightQuery/index.tsx @@ -5,7 +5,7 @@ import * as styles from './styles.css' interface HighlightQueryProps { text: string - query: string + query: string | undefined } export const HighlightQuery: FunctionComponent = ({ @@ -33,7 +33,7 @@ interface Chunk { type: 'chunk' | 'query' } -function highlightText(text: string, query: string): Chunk[] { +function highlightText(text: string, query: string | undefined): Chunk[] { if (!text || !query) return [{ text, type: 'chunk' }] const chunks: Chunk[] = [] diff --git a/src/ui/components/IdHighlight/index.tsx b/src/ui/components/IdHighlight/index.tsx index d15b0cd3..9b622cc5 100644 --- a/src/ui/components/IdHighlight/index.tsx +++ b/src/ui/components/IdHighlight/index.tsx @@ -1,6 +1,7 @@ import { match } from 'assert' import { FunctionComponent, h } from 'preact' import { useEffect, useRef } from 'preact/hooks' +import { isInViewport } from '~/utils/dom' import * as styles from './styles.css' interface IdHightlightProps { @@ -62,14 +63,3 @@ export const IdHightlight: FunctionComponent = ({ ) } - -function isInViewport(element: HTMLElement): boolean { - const rect = element.getBoundingClientRect() - return ( - rect.top >= 0 && - rect.left >= 0 && - rect.bottom <= - (window.innerHeight || document.documentElement.clientHeight) && - rect.right <= (window.innerWidth || document.documentElement.clientWidth) - ) -} diff --git a/src/ui/components/Item/index.tsx b/src/ui/components/Item/index.tsx index 203874a2..986fb5e2 100644 --- a/src/ui/components/Item/index.tsx +++ b/src/ui/components/Item/index.tsx @@ -1,27 +1,45 @@ import classNames from 'classnames' import { Fragment, FunctionComponent, h } from 'preact' +import { Ref } from 'preact/hooks' +import { highlightMarkdown } from '~/utils/docs' +import { HighlightQuery } from '../HighlightQuery' +import { Markdown } from '../Markdown' +import { RichText } from '../RichText' import * as styles from './styles.css' interface Props { title: string summary: string | undefined - selected: boolean + active: boolean code: boolean + query?: string + activeRef?: Ref } export const Item: FunctionComponent = ({ title, summary, - selected, + active, code, + query, + activeRef, }) => ( -
+

- {title} +

- {styles.summary &&

{summary}

} + {summary && ( +

+ + + +

+ )}
diff --git a/src/ui/components/Item/styles.css.ts b/src/ui/components/Item/styles.css.ts index 699b74d4..bdf28c69 100644 --- a/src/ui/components/Item/styles.css.ts +++ b/src/ui/components/Item/styles.css.ts @@ -24,7 +24,7 @@ export const icon = style({ marginLeft: '10px', }) -export const selected = style({ +export const active = style({ backgroundColor: '#fff0f3', ':hover': { diff --git a/src/ui/components/NoSearchResults/index.tsx b/src/ui/components/NoSearchResults/index.tsx index a6957372..c7b6bb0e 100644 --- a/src/ui/components/NoSearchResults/index.tsx +++ b/src/ui/components/NoSearchResults/index.tsx @@ -1,21 +1,18 @@ -import classNames from 'classnames' import { Fragment, FunctionComponent, h } from 'preact' -import { useMemo } from 'preact/hooks' +import { RichText } from '../RichText' import * as styles from './styles.css' interface NoSearchResultsProps { noun: string - query: string - setQuery: (query: string) => void + query: [string, (query: string) => void] } export const NoSearchResults: FunctionComponent = ({ noun, - query, - setQuery, + query: [query, setQuery], }) => { return ( -
+ No {noun} found for {query}.{' '} = ({ > Clear query -
+ ) } diff --git a/src/ui/components/RichText/styles.css.ts b/src/ui/components/RichText/styles.css.ts index ea380557..470bf023 100644 --- a/src/ui/components/RichText/styles.css.ts +++ b/src/ui/components/RichText/styles.css.ts @@ -2,7 +2,7 @@ import { style, globalStyle } from '@vanilla-extract/css' export const content = style({ fontSize: '1rem', - lineHeight: '1.6em', + lineHeight: '1.6', }) globalStyle(`${content} a`, { diff --git a/src/ui/components/Search/index.tsx b/src/ui/components/Search/index.tsx index 1145f715..df3cb6b6 100644 --- a/src/ui/components/Search/index.tsx +++ b/src/ui/components/Search/index.tsx @@ -1,18 +1,20 @@ import { FunctionComponent, h } from 'preact' // import { trackAction } from 'app/acts/tracking_acts' import debounce from 'lodash/debounce' -import { StateUpdater, useCallback } from 'preact/hooks' +import { Ref, StateUpdater, useCallback } from 'preact/hooks' import * as styles from './styles.css' import classNames from 'classnames' interface SearchProps { - query: [string, StateUpdater] + query: [string, (query: string) => void] bordered?: boolean + inputRef?: Ref } export const Search: FunctionComponent = ({ query: [query, setQuery], bordered, + inputRef, }) => { const trackSearch = useCallback( debounce((newQuery: string) => { @@ -36,6 +38,7 @@ export const Search: FunctionComponent = ({ trackSearch(newQuery) setQuery(newQuery) }} + ref={inputRef} /> {query.trim().length > 0 && } diff --git a/src/ui/components/Search/styles.css.ts b/src/ui/components/Search/styles.css.ts index 64571ba7..1531077d 100644 --- a/src/ui/components/Search/styles.css.ts +++ b/src/ui/components/Search/styles.css.ts @@ -28,7 +28,7 @@ export const cancel = style({ backgroundImage: `url('${cancelURL}')`, backgroundSize: '16px', position: 'absolute', - right: '1.5rem', + right: '1rem', }) export const input = style({ diff --git a/src/ui/components/TypeDocSignature/Generics/index.tsx b/src/ui/components/TypeDocSignature/Generics/index.tsx index b007a41d..9f1a6469 100644 --- a/src/ui/components/TypeDocSignature/Generics/index.tsx +++ b/src/ui/components/TypeDocSignature/Generics/index.tsx @@ -1,6 +1,7 @@ import { FunctionComponent, h, Fragment } from 'preact' import { useContext } from 'preact/hooks' import type { TypeParameterReflection } from 'typedoc' +import { IgnoreParentTypesSourceContext } from '~/ui/contexts/IgnoreParentTypesSource' import { InlineTypeContext } from '~/ui/contexts/InlineTypeContext' import { ParentTypesMap, typeHash } from '~/utils/docs' import { IdHightlight } from '../../IdHighlight' @@ -14,6 +15,7 @@ export const TypeDocSignatureGenerics: FunctionComponent { const inline = useContext(InlineTypeContext) + const ignoreSource = useContext(IgnoreParentTypesSourceContext) return ( <> @@ -22,7 +24,9 @@ export const TypeDocSignatureGenerics: FunctionComponent - {inline ? ( + {inline && ignoreSource && inline.parentTypesMap?.[param.id] ? ( + {param.name} + ) : inline && !ignoreSource ? ( {param.name} diff --git a/src/ui/components/TypeDocSignature/index.tsx b/src/ui/components/TypeDocSignature/index.tsx index 886b5b95..2336cd3d 100644 --- a/src/ui/components/TypeDocSignature/index.tsx +++ b/src/ui/components/TypeDocSignature/index.tsx @@ -1,11 +1,8 @@ -import classNames from 'classnames' import { Fragment, FunctionComponent, h } from 'preact' -import type { SignatureReflection, TypeParameterReflection } from 'typedoc' -import { ParentTypesMap } from '~/utils/docs' +import type { SignatureReflection } from 'typedoc' import { TypeDocType } from '../TypeDocType' import { TypeDocSignatureArguments as Arguments } from './Arguments' import { TypeDocSignatureGenerics as Generics } from './Generics' -import * as styles from './styles.css' interface TypeDocSignatureProps { name?: string diff --git a/src/ui/contexts/IgnoreParentTypesSource/index.ts b/src/ui/contexts/IgnoreParentTypesSource/index.ts new file mode 100644 index 00000000..d751b1a3 --- /dev/null +++ b/src/ui/contexts/IgnoreParentTypesSource/index.ts @@ -0,0 +1,3 @@ +import { createContext } from 'preact' + +export const IgnoreParentTypesSourceContext = createContext(false) diff --git a/src/ui/hooks/useActiveItem/index.ts b/src/ui/hooks/useActiveItem/index.ts new file mode 100644 index 00000000..6d033738 --- /dev/null +++ b/src/ui/hooks/useActiveItem/index.ts @@ -0,0 +1,19 @@ +import { useEffect, useRef, useState } from 'preact/hooks' +import { + scrollIntoViewIfNeeded, + ScrollIntoViewIfNeededOptions, +} from '~/utils/dom' + +export function useActiveItem( + id: unknown, + options?: ScrollIntoViewIfNeededOptions +) { + const activeRef = useRef(null) + + useEffect(() => { + console.log('item', activeRef.current) + scrollIntoViewIfNeeded(activeRef.current, options) + }, [id]) + + return { activeRef } +} diff --git a/src/ui/hooks/useQuery/index.tsx b/src/ui/hooks/useQuery/index.tsx new file mode 100644 index 00000000..26019bde --- /dev/null +++ b/src/ui/hooks/useQuery/index.tsx @@ -0,0 +1,13 @@ +import { useRef, useState } from 'preact/hooks' + +export function useQuery() { + const searchRef = useRef(null) + const [query, setQueryState] = useState('') + + function setQuery(str: string) { + setQueryState(str) + searchRef.current?.focus() + } + + return { query, setQuery, searchRef } +} diff --git a/src/ui/screens/Docs/Doc/TypeDoc/Constants/index.tsx b/src/ui/screens/Docs/Doc/TypeDoc/Constants/index.tsx index dd1b60ff..9033c0c8 100644 --- a/src/ui/screens/Docs/Doc/TypeDoc/Constants/index.tsx +++ b/src/ui/screens/Docs/Doc/TypeDoc/Constants/index.tsx @@ -22,11 +22,12 @@ import { Search } from '~/ui/components/Search' import { SectionHeader } from '~/ui/components/SectionHeader' import { SourceLink } from '~/ui/components/SourceLink' import { TypeDocType } from '~/ui/components/TypeDocType' +import { useQuery } from '~/ui/hooks/useQuery' import { extractCodeFromTagString, findSource, generateUsage, - hightlightMarkdown, + highlightMarkdown, } from '~/utils/docs' import * as styles from './styles.css' @@ -47,7 +48,7 @@ export const TypeDocConstants: FunctionComponent = ({ }) => { const description = useMemo(() => findDescription(doc), [doc]) - const [query, setQuery] = useState('') + const { query, setQuery, searchRef } = useQuery() const constants: ConstantItem[] = useMemo( () => @@ -80,7 +81,7 @@ export const TypeDocConstants: FunctionComponent = ({
- +
{filtered.length ? ( @@ -90,7 +91,7 @@ export const TypeDocConstants: FunctionComponent = ({ ))} ) : ( - + )}
@@ -136,7 +137,7 @@ function Constant({ item, query }: ConstantProps) { {description && ( diff --git a/src/ui/screens/Docs/Doc/TypeDoc/Function/Signature/index.tsx b/src/ui/screens/Docs/Doc/TypeDoc/Function/Signature/index.tsx index f4507e90..dcc033f1 100644 --- a/src/ui/screens/Docs/Doc/TypeDoc/Function/Signature/index.tsx +++ b/src/ui/screens/Docs/Doc/TypeDoc/Function/Signature/index.tsx @@ -2,6 +2,7 @@ import { findSignatureReturns } from '@date-fns/docs/utils' import { h, FunctionComponent, Fragment } from 'preact' import { useMemo } from 'preact/hooks' import type { SignatureReflection, TypeParameterReflection } from 'typedoc' +import { IgnoreParentTypesSourceContext } from '~/ui/contexts/IgnoreParentTypesSource' import { Arguments } from '../Arguments' import { Generics } from '../Generics' import { Returns } from '../Returns' @@ -27,7 +28,9 @@ export const Signature: FunctionComponent = ({ return ( <> - + + + {signature.typeParameter && ( diff --git a/src/ui/screens/Docs/Doc/TypeDoc/Function/index.tsx b/src/ui/screens/Docs/Doc/TypeDoc/Function/index.tsx index 1553a03c..bebf91a6 100644 --- a/src/ui/screens/Docs/Doc/TypeDoc/Function/index.tsx +++ b/src/ui/screens/Docs/Doc/TypeDoc/Function/index.tsx @@ -1,17 +1,28 @@ import type { DateFnsDocs } from '@date-fns/docs/types' -import { findFn, findFnDescription, findFnExamples } from '@date-fns/docs/utils' +import { + findFn, + findFnDescription, + findFnExamples, + traverseType, +} from '@date-fns/docs/utils' import { FunctionComponent, h } from 'preact' import { useMemo } from 'preact/hooks' -import type { DeclarationReflection } from 'typedoc' +import type { DeclarationReflection, SignatureReflection } from 'typedoc' import { DocDescription } from '~/ui/components/DocDescription' import { DocExamples } from '~/ui/components/DocExamples' import { DocHeader } from '~/ui/components/DocHeader' import { DocLinks } from '~/ui/components/DocLinks' import { DocUsage } from '~/ui/components/DocUsage' +import { InlineTypeContext } from '~/ui/contexts/InlineTypeContext' import { extractCodeFromTagString, findSource, generateUsage, + inlineTypeHash, + pageTypeHash, + pageTypeId, + pageTypeIdHighlightMatch, + ParentTypesMap, } from '~/utils/docs' import { Signatures } from './Signatures' @@ -25,6 +36,7 @@ export const TypeDocFunction: FunctionComponent = ({ doc, }) => { const fn = useMemo(() => findFn(doc), [doc]) + const parentTypesMap = useMemo(() => buildParentTypesMap(fn), [fn]) const description = useMemo(() => fn && findFnDescription(fn), [fn]) const { usage, usageTabs } = useMemo(() => generateUsage(doc.name), [doc]) const signatures = fn && fn.signatures @@ -33,11 +45,19 @@ export const TypeDocFunction: FunctionComponent = ({ [fn] ) + console.log('+++++++++++++++++++++++', parentTypesMap) + return ( -
+ pageTypeId(refl.name, refl.id), + idHighlightMatch: pageTypeIdHighlightMatch, + parentTypesMap, + }} + > {page.title} - {description && } + {description && } @@ -50,6 +70,20 @@ export const TypeDocFunction: FunctionComponent = ({ -
+ ) } + +function buildParentTypesMap( + refl: DeclarationReflection | undefined +): ParentTypesMap { + const map: ParentTypesMap = {} + + refl?.signatures?.forEach((signature) => { + signature?.typeParameter?.map((r) => { + map[r.id] = pageTypeHash(r.name, r.id) + }) + }) + + return map +} diff --git a/src/ui/screens/Docs/Doc/TypeDoc/Types/index.tsx b/src/ui/screens/Docs/Doc/TypeDoc/Types/index.tsx index 434aac86..989c222c 100644 --- a/src/ui/screens/Docs/Doc/TypeDoc/Types/index.tsx +++ b/src/ui/screens/Docs/Doc/TypeDoc/Types/index.tsx @@ -1,4 +1,9 @@ -import { joinCommentParts, traverseType } from '@date-fns/docs/utils' +import { + findDescription, + findSummary, + joinCommentParts, + traverseType, +} from '@date-fns/docs/utils' import { h } from 'preact' import { useMemo } from 'preact/hooks' import type { DeclarationReflection, SignatureReflection } from 'typedoc' @@ -8,12 +13,16 @@ import { Item } from '~/ui/components/Item' import { Markdown } from '~/ui/components/Markdown' import { Missing } from '~/ui/components/Missing' import { createModal } from '~/ui/components/Modals' +import { NoSearchResults } from '~/ui/components/NoSearchResults' import { RichText } from '~/ui/components/RichText' +import { Search } from '~/ui/components/Search' import { SectionHeader } from '~/ui/components/SectionHeader' import { SourceLink } from '~/ui/components/SourceLink' import { TypeDocInterface } from '~/ui/components/TypeDocInterface' import { TypeDocType } from '~/ui/components/TypeDocType' import { InlineTypeContext } from '~/ui/contexts/InlineTypeContext' +import { useQuery } from '~/ui/hooks/useQuery' +import { useActiveItem } from '~/ui/hooks/useActiveItem' import { findSource, generateTypeUsage, @@ -33,12 +42,18 @@ export interface TypesModalProps { nestedId: number | undefined } +interface TypeItem { + type: DeclarationReflection + summary: string | undefined + description: string | undefined +} + export const useTypesModal = createModal( ({ parent, typeId, doc }) => { const types = useMemo(() => extractTypes(doc), [doc]) const map = useMemo(() => buildMap(types), [types]) const type = map[typeId] as DeclarationReflection | undefined - const parentTypesMap = buildParentTypesMap(type) + const parentTypesMap = useMemo(() => buildParentTypesMap(type), [type]) const usage = useMemo( () => type?.kindString && @@ -48,15 +63,39 @@ export const useTypesModal = createModal( ) const scope = type && typeIdStr(type.name, type.id) + const { query, setQuery, searchRef } = useQuery() + + const navItems: TypeItem[] = useMemo( + () => + types.map((t) => { + const summary = findSummary(t) + const description = findDescription(t) + return { type: t, summary, description } + }) || [], + [types] + ) + + const filteredNav = useMemo( + () => + query + ? navItems.filter( + (item) => + item.type.name.toLowerCase().includes(query.toLowerCase()) || + item.summary?.toLowerCase().includes(query.toLowerCase()) || + item.description?.toLowerCase().includes(query.toLowerCase()) + ) + : navItems, + [navItems, query] + ) + + const { activeRef } = useActiveItem(type?.id) + return ( { - console.log(type, inlineTypeId(type, t)) - return inlineTypeId(type, t) - }, + buildId: inlineTypeId.bind(null, type), idHighlightMatch: inlineTypeIdHighlightMatch, parentTypesMap, } @@ -68,22 +107,31 @@ export const useTypesModal = createModal( {parent} types
-
+
- {types.map((type) => ( - - - - ))} + + +
+ {filteredNav.length ? ( + filteredNav.map(({ type, summary, description }) => ( + + + + )) + ) : ( +
+ +
+ )} +
{type ? ( @@ -216,16 +264,17 @@ function extractTypes( switch (child.kindString) { // Ignore these types and their children case 'Module': - return - - // Process function singatures and add their type parameters case 'Function': - child.signatures?.forEach((signature) => { - // @ts-ignore: For some reason TypeDoc contains the error, it's typeParameter not typeParameters - signature.typeParameter?.forEach((param) => types.push(param)) - }) return + // // Process function singatures and add their type parameters + // case 'Function': + // child.signatures?.forEach((signature) => { + // // @ts-ignore: For some reason TypeDoc contains the error, it's typeParameter not typeParameters + // signature.typeParameter?.forEach((param) => types.push(param)) + // }) + // return + // Add these types, but not process their children case 'Interface': case 'Type alias': @@ -310,7 +359,6 @@ function buildParentTypesMap( type?.type && traverseType(type.type, (ref) => { - console.log(' ~~~', ref) if (ref.type === 'reflection') { ref.declaration?.signatures?.forEach((signature) => { buildParentTypesMap(refl, signature, map) diff --git a/src/ui/screens/Docs/Doc/TypeDoc/Types/styles.css.ts b/src/ui/screens/Docs/Doc/TypeDoc/Types/styles.css.ts index e41a1849..29c1100f 100644 --- a/src/ui/screens/Docs/Doc/TypeDoc/Types/styles.css.ts +++ b/src/ui/screens/Docs/Doc/TypeDoc/Types/styles.css.ts @@ -1,6 +1,10 @@ import { globalStyle, style, styleVariants } from '@vanilla-extract/css' -export const wrapper = style({}) +export const wrapper = style({ + height: 'min(calc(100vh - 8rem), 50rem)', + display: 'grid', + gridTemplateRows: 'auto 1fr', +}) export const title = style({ background: '#ebe1d8', @@ -23,11 +27,11 @@ export const titleParent = style({ fontFamily: 'monospace', }) -export const inner = style({ +export const main = style({ display: 'grid', gridTemplateColumns: '23rem auto', - maxHeight: '50rem', gridTemplateRows: '1fr', + overflow: 'hidden', }) export const item = style({ @@ -36,9 +40,20 @@ export const item = style({ export const nav = style({ borderRight: '1px solid #e6e0e6', + display: 'grid', + gridTemplateRows: 'auto 1fr', + overflow: 'hidden', +}) + +export const list = style({ overflowY: 'auto', }) +export const noResults = style({ + textAlign: 'center', + padding: '1rem', +}) + export const content = style({ padding: '2rem', overflowY: 'auto', diff --git a/src/ui/screens/Docs/Finder/Categories.tsx b/src/ui/screens/Docs/Finder/Categories.tsx index 04fb7efa..5108efee 100644 --- a/src/ui/screens/Docs/Finder/Categories.tsx +++ b/src/ui/screens/Docs/Finder/Categories.tsx @@ -10,6 +10,7 @@ interface Props { selectedSubmodule: DateFnsDocs.Submodule selectedPage: string onNavigate(): void + query: string } export const Categories: FunctionComponent = ({ @@ -19,6 +20,7 @@ export const Categories: FunctionComponent = ({ selectedSubmodule, selectedPage, onNavigate, + query, }) => (
    {categories.map((category) => { @@ -39,6 +41,7 @@ export const Categories: FunctionComponent = ({ selectedSubmodule={selectedSubmodule} selectedPage={selectedPage} onNavigate={onNavigate} + query={query} />
diff --git a/src/ui/screens/Docs/Finder/Items.tsx b/src/ui/screens/Docs/Finder/Items.tsx index 4af3ab7a..62af86ff 100644 --- a/src/ui/screens/Docs/Finder/Items.tsx +++ b/src/ui/screens/Docs/Finder/Items.tsx @@ -4,6 +4,7 @@ import { RouterLink } from '~/ui/router' import { docLink } from '~/ui/router/docLink' import * as styles from './styles.css' import { Item } from '~/ui/components/Item' +import { useActiveItem } from '~/ui/hooks/useActiveItem' interface Props { pages: DateFnsDocs.PagePreview[] @@ -11,6 +12,7 @@ interface Props { selectedSubmodule: DateFnsDocs.Submodule selectedPage: string onNavigate(): void + query: string } export const Items: FunctionComponent = ({ @@ -19,29 +21,38 @@ export const Items: FunctionComponent = ({ selectedSubmodule, selectedPage, onNavigate, -}) => ( - <> - {pages.map((page) => ( - - - - ))} - -) + query, +}) => { + const { activeRef } = useActiveItem(selectedPage, { + marginTop: 33, + }) + + return ( + <> + {pages.map((page) => ( + + + + ))} + + ) +} diff --git a/src/ui/screens/Docs/Finder/index.tsx b/src/ui/screens/Docs/Finder/index.tsx index 5191005c..2a1a9c58 100644 --- a/src/ui/screens/Docs/Finder/index.tsx +++ b/src/ui/screens/Docs/Finder/index.tsx @@ -11,6 +11,7 @@ import { NoResults } from './NoResults' import * as styles from './styles.css' import { filterPages } from './utils' import { Widget } from './Widget' +import { useQuery } from '~/ui/hooks/useQuery' interface FinderProps { selectedVersion: string @@ -25,7 +26,7 @@ export const Finder: FunctionComponent = ({ selectedPage, onNavigate, }) => { - const [query, setQuery] = useState('') + const { query, setQuery, searchRef } = useQuery() const [versions, { loading }] = useRead( db.versions.query(($) => [ @@ -40,7 +41,7 @@ export const Finder: FunctionComponent = ({ return (
- +
{filteredPages.length === 0 ? ( @@ -53,6 +54,7 @@ export const Finder: FunctionComponent = ({ selectedSubmodule={selectedSubmodule} selectedPage={selectedPage} onNavigate={onNavigate} + query={query} /> )}
diff --git a/src/utils/docs/index.ts b/src/utils/docs/index.ts index 919371e1..1ac6579a 100644 --- a/src/utils/docs/index.ts +++ b/src/utils/docs/index.ts @@ -55,12 +55,20 @@ export function findSource( return trimHash ? url.replace(/#.*$/, '') : url } -export function hightlightMarkdown(text: string, query: string) { +export function highlightMarkdown(text: string, query: string | undefined) { if (!query) return text const regex = new RegExp(query, 'gi') return text.replace(regex, (match) => `==${match}==`) } +export function pageTypeHash(name: string, id: number) { + return `#${pageTypeId(name, id)}` +} + +export function pageTypeId(name: string, id: number) { + return `page/${name}/${id}/${rand()}` +} + export function typeHash(name: string, id: number, nested?: string) { return `#${typeId(name, id, nested)}` } @@ -86,6 +94,27 @@ export function matchTypeHash(hash: string) { return { typeId, nestedId } } +const pageTypeHashRE = /types\/\w+\/(\d+)(?:\/\w+)?/ + +export function matchPageTypeHash(hash: string) { + const captures = hash.match(pageTypeHashRE) + if (!captures) return + + const type = captures[1] + if (!type) return + + const typeId = parseInt(type) + if (isNaN(typeId)) return + + return typeId +} + +export function pageTypeIdHighlightMatch(id: string, hash: string) { + const idMatch = matchPageTypeHash(id) + const hashMatch = matchPageTypeHash(hash) + return (idMatch && idMatch === hashMatch) || false +} + export function inlineTypeHash( refl: DeclarationReflection, type: TypeParameterReflection | ParameterReflection | DeclarationReflection diff --git a/src/utils/dom/index.ts b/src/utils/dom/index.ts new file mode 100644 index 00000000..965c52ec --- /dev/null +++ b/src/utils/dom/index.ts @@ -0,0 +1,75 @@ +import { consoleTestResultHandler } from 'tslint/lib/test' + +export interface ScrollIntoViewIfNeededOptions extends ScrollToOptions { + marginTop?: number +} + +export function scrollIntoViewIfNeeded( + element: HTMLElement | null, + { marginTop, behavior }: ScrollIntoViewIfNeededOptions = {} +): void { + if (!element) return + + const rect = element.getBoundingClientRect() + const scrollParent = findParentWithScroll(element) + console.log({ scrollParent }) + + if (!scrollParent) return + + const parentRect = scrollParent.getBoundingClientRect() + + const inViewport = + rect.top >= parentRect.top + (marginTop || 0) + scrollParent.scrollTop && + rect.left >= parentRect.left && + rect.bottom <= parentRect.bottom + scrollParent.scrollTop && + rect.right <= parentRect.right + + console.log({ + rect, + parentRect, + marginTop, + inViewport, + scrollTop: scrollParent.scrollTop, + }) + + if (inViewport) return + + scrollParent.scrollTo({ + top: rect.top - parentRect.top - (marginTop || 0), + behavior, + }) + + // element.scrollIntoView({ behavior }) +} + +export function isInViewport( + element: HTMLElement, + marginTop?: number +): boolean { + const rect = element.getBoundingClientRect() + const scrollParent = findParentWithScroll(element) + + if (!scrollParent) return true + + const parentRect = scrollParent.getBoundingClientRect() + + console.log({ rect, parentRect, marginTop }) + + return ( + rect.top >= parentRect.top + (marginTop || 0) && + rect.left >= parentRect.left && + rect.bottom <= parentRect.bottom && + rect.right <= parentRect.right + ) +} + +function findParentWithScroll(element: HTMLElement): HTMLElement | null { + let current: HTMLElement | null = element + while (current) { + if (current.offsetHeight < current.scrollHeight) { + return current + } + current = current.parentElement + } + return null +} diff --git a/yarn.lock b/yarn.lock index 03967a03..2f8fed30 100644 --- a/yarn.lock +++ b/yarn.lock @@ -251,10 +251,10 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@date-fns/docs@0.22.0": - version "0.22.0" - resolved "https://registry.yarnpkg.com/@date-fns/docs/-/docs-0.22.0.tgz#aaaafdba6b5c192ef2e2cb8a969821498592f42d" - integrity sha512-LKpsZZZXy2oqAW62TQ7UZCN3uoO1eCj6RTaEHE9h6fruQ9EoxjHV7kl+ENtNPpL4zUCTxwiQgkeRDytH8z0G8Q== +"@date-fns/docs@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@date-fns/docs/-/docs-0.24.0.tgz#a69db423f5ffe78992cbbb2094c631da696c3cb0" + integrity sha512-/mI63fs/kVMThANrSSDiLsHi8polkI9Ase4S7rkMh5r77pxmhvhSoA78m7mLIRyst5u5dlP9052hKspSxtf92A== dependencies: firebase-admin "^11.4.1" js-fns "^2.5.2"