chore(lint): clear the semantic .tsx backlog
Hand fixes for the findings --fix cannot touch, mirroring the fixes already applied on the fe-docs feature branch (same file, same shape) so its eventual rebase resolves cleanly: - restore the return the no-confusing-void-expression autofix ate in useAbsentSnapshot (typed S | undefined; hook call kept for hook-order stability, undefined returned explicitly); - re-type DOM queries the no-unnecessary-type-assertion autofix broke: getByRole<HTMLButtonElement>(...) generics instead of the removed as-casts (the eslint program and the client tsconfig aggregate disagree about these casts; the generic form satisfies both); - justified eslint-disable for the deliberate legacy paths: keyCode 229 IME-composition detection, execCommand clipboard fallbacks, lib.dom clipboard optionality, and the any-typed Reflect.get/this probes in test fakes; - drop the dead react/no-danger directive (eslint-plugin-react is not loaded, so the rule never applied) keeping its shiki rationale; - delete the tautological 'Z' comparison and the renameTarget null check already implied by renameBlocked; - css-module non-null assertions replaced by type widening (Button className, TAG_CLASS Record) per the established pattern; - misc: max-len comment wraps, void generic drop in the deferred test helper, unused type imports, floating selectWorkspace promises voided, member-delimiter newlines in inline type literals.
This commit is contained in:
@@ -19,7 +19,7 @@ export function Button({ variant = 'ghost', size = 'md', icon, className, childr
|
||||
variant?: ButtonVariant
|
||||
size?: 'md' | 'sm'
|
||||
icon?: ReactNode
|
||||
className?: string
|
||||
className?: string | undefined
|
||||
children?: ReactNode
|
||||
} & ButtonHTMLAttributes<HTMLButtonElement>) {
|
||||
return (
|
||||
|
||||
@@ -27,7 +27,8 @@ interface AnchorProps {
|
||||
* Attach a hover/focus tooltip to an anchor element.
|
||||
* @param props.label - bubble text.
|
||||
* @param props.side - placement relative to the anchor (default 'right').
|
||||
* @param props.disabled - suppress the bubble while true; the anchor renders identically so toggling never remounts it (which would cut its CSS transitions).
|
||||
* @param props.disabled - suppress the bubble while true; the anchor renders identically so
|
||||
* toggling never remounts it (which would cut its CSS transitions).
|
||||
* @param props.children - a single anchor element; its own ref (callback or object) is forwarded alongside the tooltip's.
|
||||
* @returns the cloned anchor plus a fixed-position bubble while hovered/focused.
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,9 @@ export interface CodeBlockProps {
|
||||
|
||||
/** @returns true only when the host accepted the write. */
|
||||
async function writeClipboard(text: string): Promise<boolean> {
|
||||
// lib.dom types clipboard non-optional, but insecure contexts omit it —
|
||||
// that runtime gap is exactly what this guard detects.
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */
|
||||
if (navigator.clipboard?.writeText) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text)
|
||||
@@ -30,6 +33,9 @@ async function writeClipboard(text: string): Promise<boolean> {
|
||||
}
|
||||
}
|
||||
// jsdom and older hosts: best-effort execCommand path when present.
|
||||
// execCommand('copy') is the only clipboard fallback where the async API
|
||||
// is missing; deprecated but deliberately retained.
|
||||
/* eslint-disable @typescript-eslint/no-deprecated */
|
||||
const exec = typeof document.execCommand === 'function'
|
||||
? document.execCommand.bind(document)
|
||||
: undefined
|
||||
@@ -48,6 +54,7 @@ async function writeClipboard(text: string): Promise<boolean> {
|
||||
} finally {
|
||||
el.remove()
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-deprecated */
|
||||
}
|
||||
|
||||
export function CodeBlock({ code, lang, className }: CodeBlockProps) {
|
||||
@@ -73,9 +80,9 @@ export function CodeBlock({ code, lang, className }: CodeBlockProps) {
|
||||
<pre className={css.plain}><code>{trimmed}</code></pre>
|
||||
)
|
||||
: (
|
||||
// eslint-disable-next-line react/no-danger -- shiki's output is a static
|
||||
// span tree it generated from `code` (no user HTML passes through), the
|
||||
// sanctioned innerHTML consumption path per shiki's own docs.
|
||||
// shiki's output is a static span tree it generated from `code` (no user
|
||||
// HTML passes through), the sanctioned innerHTML consumption path per
|
||||
// shiki's own docs.
|
||||
<div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
)
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ export function JsonBlock({ label, payload, defaultOpen = false }: {
|
||||
if (!open) return ''
|
||||
let s: string
|
||||
try {
|
||||
// lib typing hides stringify's undefined arm (undefined/function/symbol payloads).
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
s = JSON.stringify(payload, null, 2) ?? String(payload)
|
||||
} catch {
|
||||
s = String(payload)
|
||||
|
||||
@@ -53,7 +53,9 @@ function buildComponents(streaming: boolean): Components {
|
||||
// plain arm — retokenizing a growing fence on every chunk is quadratic
|
||||
// main-thread work; the finalize swap highlights it once.
|
||||
pre: ({ children }) => {
|
||||
/* v8 ignore next 2 -- the markdown pipeline always hands `pre` its single `code` element; the undefined arm guards a react-markdown representation change. */
|
||||
// The markdown pipeline always hands `pre` its single `code` element;
|
||||
// the undefined arm guards a react-markdown representation change.
|
||||
/* v8 ignore next 2 */
|
||||
const child = isValidElement<{ className?: string; children?: unknown }>(children) ? children : undefined
|
||||
const raw = child?.props.children
|
||||
// A fence whose content isn't one plain string (e.g. an empty fence)
|
||||
|
||||
Reference in New Issue
Block a user