Files
sim/apps/docs/components/ui/api-example-selector.tsx
T
Waleed 3ff91f0439 improvement(docs): clean up leftovers from the code-block alignment PR (#6825)
* improvement(docs): clear leftovers from the reverted revisions

A cleanup pass over the final state. Every finding was residue from an approach
this PR tried and abandoned, or a claim that stopped being true when it did.

- Delete the copy-button svg sizing rule: a later rule sets `display: none` on
  that same element ungated, so sizing it was never observable. Superseded by
  the mask approach.
- Drop the paragraph in page.tsx arguing about a custom Shiki factory. The
  factory was deleted; nothing configures one now.
- Correct shiki-curl-json.ts, which still claimed the grammar "reaches the
  client path too". It does not — that was the justification for choosing a
  grammar over a transformer, so leaving it stated the opposite of the truth.
  Now records where it applies, where it does not, and why not to retry.
- Correct the global.css section header, which claimed the component owns the
  shell while the next rule defines it here.
- Qualify the `--copy-glyph` declarations with `:has(> svg[class*="lucide"])`,
  which the group's own comment asserts of every rule in it.
- Correct `getCode`'s TSDoc: the gutter is a `::before`, and pseudo-element
  content never reaches `textContent`, so line numbers were never what the
  clone guards. It guards transformer-emitted `.nd-copy-ignore` nodes.
- Compose `chipGeometryClass` and emcn's `ChipChevronDown` in the API example
  selector instead of restating their literals.
- Merge the duplicated `div[role="region"]` rule. The tablist pair stays split:
  biome's `noDuplicateProperties` reads a nested `@variant` setting the same
  property as a duplicate and fails the build — recorded so it is not remerged.
- Note that fumadocs ships its own gutter for `lines`-meta fences, which cannot
  be suppressed from here and would paint a second column.

* fix(docs): drop a highlighter registration that can never fire

fumadocs-openapi calls `renderCodeBlock` with a hard-coded `"json"` from both of
its call sites (`request-tabs.js:76`, `response-tabs.js:48`), so the docs
`CodeBlock` it routes through never receives a shell language. The
`getHighlighter('js', { langs: [curlJsonBodyGrammar] })` registering the
shell-scoped JSON-body injection therefore did nothing but await on every API
sample render, and the docblock claiming the grammar covers those samples was
wrong.

- Delete the call and its imports.
- State the grammar's real coverage: prose fences only, via `langs`. Both API
  reference paths are unreachable — samples are JSON, and the cURL usage tabs
  highlight client-side off fumadocs' own factory.
- Correct `code-block.tsx`'s TSDoc, which still said API samples come from
  fumadocs' own renderer. They come through this component; `UsageTab` is the
  renderer that bypasses it.
- Re-home a comment orphaned when two CSS rules merged — it had drifted onto
  the rule below and read as documenting it.
- Drop a `.nd-copy-ignore` claim about transformers emitting those nodes;
  nothing here does, and upstream parity is the reason the clone exists.
2026-08-18 15:28:02 -07:00

65 lines
1.9 KiB
TypeScript

'use client'
import type { ComponentProps } from 'react'
import { useId } from 'react'
import {
ChipChevronDown,
chipFieldSurfaceClass,
chipFieldTextClass,
chipGeometryClass,
chipHoverSurfaceClass,
cn,
} from '@sim/emcn'
import type { APIPageClientOptions } from 'fumadocs-openapi/ui/client'
type FumadocsAPIExampleSelector = NonNullable<
NonNullable<APIPageClientOptions['operation']>['APIExampleSelector']
>
interface APIExampleSelectorProps extends ComponentProps<FumadocsAPIExampleSelector> {}
export function APIExampleSelector({ items, value, onValueChange }: APIExampleSelectorProps) {
const id = useId()
if (items.length <= 1) return null
const selectedValue = value ?? items[0].id
const selectedItem = items.find((item) => item.id === selectedValue)
return (
<div className='not-prose mb-2 flex flex-col gap-1.5'>
<label htmlFor={id} className='sr-only'>
Request example
</label>
<div className='relative'>
<select
id={id}
value={selectedValue}
onChange={(event) => onValueChange(event.target.value)}
/**
* Dressed as an emcn chip trigger, but kept a native `select` for the keyboard and
* screen-reader behavior a custom listbox would have to rebuild.
*/
className={cn(
chipGeometryClass,
chipFieldSurfaceClass,
chipFieldTextClass,
chipHoverSurfaceClass,
'w-full appearance-none pe-8'
)}
>
{items.map((item) => (
<option key={item.id} value={item.id}>
{item.name}
</option>
))}
</select>
<ChipChevronDown className='-translate-y-1/2 pointer-events-none absolute end-2 top-1/2' />
</div>
{selectedItem?.description && (
<p className='text-[var(--text-muted)] text-caption'>{selectedItem.description}</p>
)}
</div>
)
}