docs(docs-page): document the docs-page component contract - #458
Merged
mikewheeleer merged 5 commits intoJul 28, 2026
Merged
Conversation
The window-undefined tests for readTheme/writeTheme/effectiveTheme failed on unmodified main: globalThis.window in this jest-environment-jsdom version is a non-configurable getter (Object.getOwnPropertyDescriptor(globalThis, "window").configurable === false), so Object.defineProperty/jest.replaceProperty both throw trying to redefine it to simulate an SSR context. Moved the three affected tests into theme.ssr.test.ts with a `@jest-environment node` docblock, where window is genuinely absent rather than simulated, exercising the real typeof window === "undefined" guard branch. No source change; theme.test.ts keeps every other case under jsdom as before.
DocsFilter already memoized its aria-live announcement (useMemo), but the actual filteredSections derivation was a plain .filter() call on every render — including every keystroke before the 300ms debounce settles, since `query` state changes trigger a re-render even though `debouncedQuery` (the value the filter actually depends on) hasn't changed yet. Wrapped it in useMemo keyed on [sections, debouncedQuery] so it only recomputes when the value driving the filter changes. Behavior and output unchanged, verified by the existing 12-case test suite (page.test.tsx + DocsFilter.test.tsx) passing unmodified. No new dependencies.
DocsFilter already had a clear, accessible empty state for "no results for this search term". Added a distinct one for "no endpoints were passed in at all" (sections.length === 0) — a content/configuration gap rather than something a different search term could fix, so the search box (and the "try a different search term" guidance) isn't offered as a way out. The aria-live announcement is suppressed in this state too, since there's no search interaction to announce the result of. Error state: DocsPage builds `sections` synchronously via getSections(baseUrl) — there's no fetch/async operation to fail, so no loading state is possible either. The one call that can throw (resolveApiBase(), invoked directly in the server component with no local try/catch) is already caught by the app's root error.tsx boundary (role="alert", keyboard-operable "Try again" retry via Next.js's reset()) — adding a second, redundant error UI local to this page would just duplicate that. Scoped this change to the empty-state distinction, which is the part with no existing coverage. Adds a test for the new state and confirms the search box and the per-query empty state are absent when it renders.
DocsFilter already had thorough coverage (100%-locked in jest.config.ts) for filtering, announcements, and click-driven clear via the earlier states/memoize work in this series, but nothing exercised it via actual keyboard interaction. Added a test that tabs into the search input, types a query with user.keyboard, waits for the debounce, tabs to the Clear button, and activates it with Enter — verifying the whole filter-then-clear flow, plus SearchBar's focus-return behavior, works without a mouse. No behavior change.
Adds docs/docs-page.md covering the /docs route's file layout (page.tsx, endpoints.ts, DocsFilter.tsx), DocsFilter's props and usage example, its three states (populated, no-results-for-search, no-endpoints-at-all) including why no separate error UI exists (resolveApiBase's throw is already caught by the root error.tsx boundary), accessibility notes, and where its tests live. Links it from the /docs row in README.md's route table.
Contributor
|
@thlpkee20-wq clean implementation, merging with thanks 🙌 |
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #394
Adds `docs/docs-page.md` covering the `/docs` route's file layout
(`page.tsx`, `endpoints.ts`, `DocsFilter.tsx`), `DocsFilter`'s props
and usage example, its three states (populated,
no-results-for-search, no-endpoints-at-all — from #390) including why
no separate error UI exists (`resolveApiBase`'s throw is already
caught by the root `error.tsx` boundary), accessibility notes, and
where its tests live. Links it from the `/docs` row in `README.md`'s
route table, matching how the other docs files (`components.md`,
`hooks.md`, etc.) are already linked from README.
Test plan
Docs-only change; no source touched.
Note
Stacked on #450/#455/#456/#457 (fork-only, can't target a non-`main`
base — same caveat as noted on the other PRs in this series). This is
the last PR in the docs-page group (#390/#392/#393/#394).