perf(json-editor): unify admin JSON editing experience - #6421
Conversation
- integrate Yace for syntax highlighting, history, indentation, auto-closing, and smart line breaks. - add copy support, cursor location feedback, and synchronized content and line-number scrolling. - extract JSON editor utilities and cover key interactions with unit tests.
- replace raw JSON textareas with the shared editor for highlighting, validation, copy, and formatting. - preserve field-specific examples and make placeholders visible through the transparent editor layer. - remove duplicate formatting controls while keeping existing form validation and save behavior.
- replace pure JSON textareas with the shared editor across system settings and channel workflows. - preserve form focus, validation, placeholders, and visual or JSON editing modes. - add happy-dom component coverage for form bindings, controlled updates, and formatting.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (8)
🚧 Files skipped from review as they are similar to previous changes (7)
WalkthroughChangesIntroduces a Yace-based Application integration
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant Yace
participant JsonCodeEditor
participant Form
User->>Yace: Edit JSON
Yace->>JsonCodeEditor: Emit update
JsonCodeEditor->>Form: Forward value, blur, and ref
JsonCodeEditor->>User: Show validation and cursor status
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
web/src/components/json-code-editor.tsx (1)
133-140: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winFragile reliance on
yace's internal DOM structure for locating the line-number layer, with a silent total failure mode.Detecting the line-number
<pre>by elimination (!== editor.pre) assumes a specific, undocumented internal markup shape. If that assumption ever breaks (library update, edge-case content), the component doesn't degrade gracefully — it destroys the editor and renders nothing, leaving the JSON field completely non-functional with no visible error.Consider (a) checking whether
yaceexposes a stable public reference to the line-numbers element instead of DOM-diffing, and (b) rendering a visible fallback/error state instead of silently destroying the editor when the assumption fails.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/components/json-code-editor.tsx` around lines 133 - 140, Update the line-number layer lookup in the editor initialization flow to use a stable public yace reference or API instead of identifying a second <pre> via editor.pre. If no valid line-number element can be obtained, preserve a visible fallback or error state rather than destroying the editor and clearing editorRef; update the surrounding cleanup logic accordingly.web/package.json (1)
77-77: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueAdd an explicit
packageManager/Bun lockfile entry for the newyacedependency.
web/package.jsonaddsyace@^1.1.0to production deps per the frontend guideline, but the package has nopackageManager, and the locked dependency surface for this repo still needs to ensure Bun is responsible for installing this new dependency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/package.json` at line 77, Add an explicit packageManager entry in web/package.json identifying Bun, and regenerate or update the Bun lockfile so yace@^1.1.0 is represented in the locked dependency surface. Preserve the existing dependency declaration and use the repository’s established Bun version and lockfile conventions.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/src/components/json-code-editor/json-code-editor-utils.ts`:
- Around line 168-192: Update jsonSmartEnter to return undefined for IME
composition keydown events before calling applyJsonSmartEnter or preventDefault:
skip events where isComposing is true or the legacy keyCode is 229, while
preserving the existing Enter handling for normal keydowns.
In `@web/src/features/channels/components/dialogs/edit-tag-dialog.tsx`:
- Around line 373-378: Localize all five visible JSON editor placeholders by
passing their existing strings through the component’s useTranslation() t
function, and add the model-mapping placeholder’s flat locale entry. Update
web/src/features/channels/components/dialogs/edit-tag-dialog.tsx lines 373-378,
web/src/features/models/components/dialogs/create-deployment-drawer.tsx lines
705-712 and 729-736, and
web/src/features/models/components/dialogs/update-config-dialog.tsx lines
401-408 and 422-429; preserve each placeholder’s example content while using
translation keys consistently.
In `@web/src/features/system-settings/general/channel-affinity/index.tsx`:
- Around line 665-668: Associate each standalone label with its corresponding
JsonCodeEditor by assigning a stable unique id to the editor and matching it
through the label’s htmlFor: update the Rules JSON editor and label in
web/src/features/system-settings/general/channel-affinity/index.tsx (lines
665-668), and the Parameter Override Template editor and label in
web/src/features/system-settings/general/channel-affinity/rule-editor-dialog.tsx
(lines 442-461).
In
`@web/src/features/system-settings/general/channel-affinity/rule-editor-dialog.tsx`:
- Line 460: Update the user-visible placeholder in the rule editor dialog to use
the existing translation function t(...), ensuring the JSON example remains the
translated placeholder text and follows the i18n requirement.
---
Nitpick comments:
In `@web/package.json`:
- Line 77: Add an explicit packageManager entry in web/package.json identifying
Bun, and regenerate or update the Bun lockfile so yace@^1.1.0 is represented in
the locked dependency surface. Preserve the existing dependency declaration and
use the repository’s established Bun version and lockfile conventions.
In `@web/src/components/json-code-editor.tsx`:
- Around line 133-140: Update the line-number layer lookup in the editor
initialization flow to use a stable public yace reference or API instead of
identifying a second <pre> via editor.pre. If no valid line-number element can
be obtained, preserve a visible fallback or error state rather than destroying
the editor and clearing editorRef; update the surrounding cleanup logic
accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 78d94631-121d-4042-8a7d-38604ad3f3a1
⛔ Files ignored due to path filters (1)
web/bun.lockis excluded by!**/*.lock
📒 Files selected for processing (27)
web/package.jsonweb/src/components/json-code-editor.tsxweb/src/components/json-code-editor/__tests__/json-code-editor-utils.test.tsweb/src/components/json-code-editor/__tests__/json-code-editor.test.tsxweb/src/components/json-code-editor/json-code-editor-utils.tsweb/src/components/json-editor.tsxweb/src/features/channels/components/dialogs/advanced-custom-editor-dialog.tsxweb/src/features/channels/components/dialogs/edit-tag-dialog.tsxweb/src/features/channels/components/dialogs/param-override-editor-dialog.tsxweb/src/features/channels/components/drawers/channel-mutate-drawer.tsxweb/src/features/channels/components/model-mapping-editor.tsxweb/src/features/models/components/dialogs/create-deployment-drawer.tsxweb/src/features/models/components/dialogs/update-config-dialog.tsxweb/src/features/system-settings/auth/custom-oauth/components/provider-form-dialog.tsxweb/src/features/system-settings/content/chat-settings-section.tsxweb/src/features/system-settings/content/json-toggle-section.tsxweb/src/features/system-settings/general/channel-affinity/index.tsxweb/src/features/system-settings/general/channel-affinity/rule-editor-dialog.tsxweb/src/features/system-settings/integrations/payment-settings-section.tsxweb/src/features/system-settings/models/claude-settings-card.tsxweb/src/features/system-settings/models/gemini-settings-card.tsxweb/src/features/system-settings/models/global-settings-card.tsxweb/src/features/system-settings/models/group-ratio-form.tsxweb/src/features/system-settings/models/model-ratio-form.tsxweb/src/features/system-settings/models/tool-price-settings.tsxweb/src/features/system-settings/request-limits/rate-limit-section.tsxweb/src/styles/index.css
| export function jsonSmartEnter(): Plugin { | ||
| return (props, event) => { | ||
| if (event.type !== 'keydown') { | ||
| return undefined | ||
| } | ||
|
|
||
| const keyboardEvent = event as KeyboardEvent | ||
| if (keyboardEvent.key !== 'Enter') { | ||
| return undefined | ||
| } | ||
|
|
||
| const nextProps = applyJsonSmartEnter( | ||
| props.value, | ||
| props.selectionStart, | ||
| props.selectionEnd | ||
| ) | ||
|
|
||
| if (!nextProps) { | ||
| return undefined | ||
| } | ||
|
|
||
| event.preventDefault() | ||
| return nextProps | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Locate file and relevant plugins/tests"
git ls-files | rg 'json-code-editor-utils|json-code-editor|json-code.*editor|package.json|bun.lockb' || true
echo
fd -a 'json-code-editor-utils\.ts$|json-code-editor.*\.(ts|tsx)$' . | sed 's#^\./##'
echo
if [ -f web/src/components/json-code-editor/json-code-editor-utils.ts ]; then
wc -l web/src/components/json-code-editor/json-code-editor-utils.ts
ast-grep outline web/src/components/json-code-editor/json-code-editor-utils.ts || true
sed -n '130,210p' web/src/components/json-code-editor/json-code-editor-utils.ts
fi
echo
rg -n "isComposing|keyCode === 229|jsonSmartEnter|SmartEnter|IM|IME|compositionStart|compositionEnd" web/src/components json-code-editor-utils.ts tests -S . 2>/dev/null | head -200Repository: QuantumNous/new-api
Length of output: 23818
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "json-code-editor-utils imports/types/test related lines"
sed -n '1,70p' web/src/components/json-code-editor/json-code-editor-utils.ts
sed -n '1,140p' web/src/components/json-code-editor/__tests__/json-code-editor-utils.test.ts
echo
echo "json-code-editor plugin wiring"
sed -n '1,130p' web/src/components/json-code-editor.tsx
echo
echo "Package typing/runtime for KeyboardEvent isComposing"
sed -n '1,80p' web/package.json
if [ -f web/node_modules/typescript/lib/lib.dom.d.ts ]; then
rg -n "interface KeyboardEvent|property isComposing|readonly isComposing" web/node_modules/typescript/lib/lib.dom.d.ts || true
else
echo "web/node_modules/typescript/lib/lib.dom.d.ts not present"
fi
echo
echo "Static behavior probe: simulate jsonSmartEnter decision for IME composition Enter"
node - <<'JS'
function applyJsonSmartEnter(value, selectionStart, selectionEnd) {
const before = value.slice(0, selectionStart)
const after = value.slice(selectionEnd)
const lineStart = value.lastIndexOf('\n', selectionStart - 1) + 1
const indent = value.slice(lineStart, selectionStart).match(/^\s*/)?.[0] ?? ''
const previousChar = before.trimEnd().at(-1)
const nextChar = after.trimStart().at(0)
const shouldNest = previousChar === '{' || previousChar === '['
const shouldClose =
(previousChar === '{' && nextChar === '}') ||
(previousChar === '[' && nextChar === ']')
if (shouldNest && shouldClose) {
const innerIndent = `${indent} `
const insert = `\n${innerIndent}\n${indent}`
const nextSelection = selectionStart + 1 + innerIndent.length
return {
value: `${before}${insert}${after}`,
selectionStart: nextSelection,
selectionEnd: nextSelection,
}
}
if (!indent && !shouldNest) {
return undefined
}
const nextIndent = shouldNest ? `${indent} ` : indent
const insert = `\n${nextIndent}`
const nextSelection = selectionStart + insert.length
return {
value: `${before}${insert}${after}`,
selectionStart: nextSelection,
selectionEnd: nextSelection,
}
}
function jsonSmartEnterDecision(props, event) {
if (event.type !== 'keydown') {
return { preventDefault: false, nextProps: undefined }
}
if (event.key !== 'Enter') {
return { preventDefault: false, nextProps: undefined }
}
const nextProps = applyJsonSmartEnter(props.value, props.selectionStart, props.selectionEnd)
if (!nextProps) {
return { preventDefault: false, nextProps: undefined }
}
return { preventDefault: true, nextProps }
}
for (const event of [
{ type: 'keydown', key: 'Enter', isComposing: false, keyCode: 13 },
{ type: 'keydown', key: 'Enter', isComposing: true, keyCode: 13 },
{ type: 'keydown', key: 'Enter', isComposing: undefined, keyCode: 229 },
]) {
const props = { value: '{', selectionStart: 1, selectionEnd: 1 }
console.log(JSON.stringify(event), '=>', jsonSmartEnterDecision(props, event))
}
JSRepository: QuantumNous/new-api
Length of output: 12094
Guard jsonSmartEnter against IME composition before intercepting Enter.
The plugin currently handles all native Enter keydowns and calls preventDefault(), including IME composition confirmation events (isComposing === true and legacy keyCode === 229). Those composition events should be skipped to avoid confirming CJK input as a newline plus indentation in the JSON draft.
🌐 Proposed fix to skip IME composition events
export function jsonSmartEnter(): Plugin {
return (props, event) => {
if (event.type !== 'keydown') {
return undefined
}
const keyboardEvent = event as KeyboardEvent
if (keyboardEvent.key !== 'Enter') {
return undefined
}
+
+ if (keyboardEvent.isComposing || keyboardEvent.keyCode === 229) {
+ return undefined
+ }
const nextProps = applyJsonSmartEnter(📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function jsonSmartEnter(): Plugin { | |
| return (props, event) => { | |
| if (event.type !== 'keydown') { | |
| return undefined | |
| } | |
| const keyboardEvent = event as KeyboardEvent | |
| if (keyboardEvent.key !== 'Enter') { | |
| return undefined | |
| } | |
| const nextProps = applyJsonSmartEnter( | |
| props.value, | |
| props.selectionStart, | |
| props.selectionEnd | |
| ) | |
| if (!nextProps) { | |
| return undefined | |
| } | |
| event.preventDefault() | |
| return nextProps | |
| } | |
| } | |
| export function jsonSmartEnter(): Plugin { | |
| return (props, event) => { | |
| if (event.type !== 'keydown') { | |
| return undefined | |
| } | |
| const keyboardEvent = event as KeyboardEvent | |
| if (keyboardEvent.key !== 'Enter') { | |
| return undefined | |
| } | |
| if (keyboardEvent.isComposing || keyboardEvent.keyCode === 229) { | |
| return undefined | |
| } | |
| const nextProps = applyJsonSmartEnter( | |
| props.value, | |
| props.selectionStart, | |
| props.selectionEnd | |
| ) | |
| if (!nextProps) { | |
| return undefined | |
| } | |
| event.preventDefault() | |
| return nextProps | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/src/components/json-code-editor/json-code-editor-utils.ts` around lines
168 - 192, Update jsonSmartEnter to return undefined for IME composition keydown
events before calling applyJsonSmartEnter or preventDefault: skip events where
isComposing is true or the legacy keyCode is 229, while preserving the existing
Enter handling for normal keydowns.
| <JsonCodeEditor | ||
| id='model-mapping' | ||
| value={modelMapping} | ||
| onChange={(e) => setModelMapping(e.target.value)} | ||
| onChange={setModelMapping} | ||
| placeholder={'{\n "gpt-3.5-turbo": "gpt-3.5-turbo-0125"\n}'} | ||
| rows={4} | ||
| className='font-mono text-sm' | ||
| heightClassName='h-40 min-h-40 max-h-40' |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Localize the new editor placeholders.
These visible placeholder examples bypass t(), so they cannot be localized.
web/src/features/channels/components/dialogs/edit-tag-dialog.tsx#L373-L378: wrap the model-mapping placeholder int()and add its flat locale entry.web/src/features/models/components/dialogs/create-deployment-drawer.tsx#L705-L712: localize the environment JSON placeholder.web/src/features/models/components/dialogs/create-deployment-drawer.tsx#L729-L736: localize the secret-environment JSON placeholder.web/src/features/models/components/dialogs/update-config-dialog.tsx#L401-L408: localize the environment JSON placeholder.web/src/features/models/components/dialogs/update-config-dialog.tsx#L422-L429: localize the secret-environment JSON placeholder.
As per coding guidelines, all user-facing React UI text under web/src must use useTranslation() and t(...).
📍 Affects 3 files
web/src/features/channels/components/dialogs/edit-tag-dialog.tsx#L373-L378(this comment)web/src/features/models/components/dialogs/create-deployment-drawer.tsx#L705-L712web/src/features/models/components/dialogs/create-deployment-drawer.tsx#L729-L736web/src/features/models/components/dialogs/update-config-dialog.tsx#L401-L408web/src/features/models/components/dialogs/update-config-dialog.tsx#L422-L429
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/src/features/channels/components/dialogs/edit-tag-dialog.tsx` around
lines 373 - 378, Localize all five visible JSON editor placeholders by passing
their existing strings through the component’s useTranslation() t function, and
add the model-mapping placeholder’s flat locale entry. Update
web/src/features/channels/components/dialogs/edit-tag-dialog.tsx lines 373-378,
web/src/features/models/components/dialogs/create-deployment-drawer.tsx lines
705-712 and 729-736, and
web/src/features/models/components/dialogs/update-config-dialog.tsx lines
401-408 and 422-429; preserve each placeholder’s example content while using
translation keys consistently.
Source: Coding guidelines
| }) | ||
| }} | ||
| textareaRef={paramOverrideTemplateField.ref} | ||
| placeholder='{"operations": [...]}' |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Translate the JSON placeholder.
Wrap this user-visible placeholder with t(...).
As per coding guidelines, “所有面向用户的文案必须支持 i18n”.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@web/src/features/system-settings/general/channel-affinity/rule-editor-dialog.tsx`
at line 460, Update the user-visible placeholder in the rule editor dialog to
use the existing translation function t(...), ensuring the JSON example remains
the translated placeholder text and follows the i18n requirement.
Source: Coding guidelines
- Drop the unconditional aria-label that overrode every field's label-derived accessible name; add an optional ariaLabel prop and set it at call sites without an associated label - Associate standalone Labels via htmlFor/id in channel-affinity views - Hide the highlight mirror and line-number layers from the accessibility tree (aria-hidden) - Give the line-number gutter an opaque background so horizontally scrolled code no longer slides under it - Degrade to no scroll sync instead of destroying the editor when the line-number layer is not found
) * perf(json-editor): improve JSON editing experience - integrate Yace for syntax highlighting, history, indentation, auto-closing, and smart line breaks. - add copy support, cursor location feedback, and synchronized content and line-number scrolling. - extract JSON editor utilities and cover key interactions with unit tests. * perf(system-settings): improve JSON configuration editing - replace raw JSON textareas with the shared editor for highlighting, validation, copy, and formatting. - preserve field-specific examples and make placeholders visible through the transparent editor layer. - remove duplicate formatting controls while keeping existing form validation and save behavior. * perf(json-editor): standardize JSON inputs across admin settings - replace pure JSON textareas with the shared editor across system settings and channel workflows. - preserve form focus, validation, placeholders, and visual or JSON editing modes. - add happy-dom component coverage for form bindings, controlled updates, and formatting. * fix(json-code-editor): address accessibility review findings - Drop the unconditional aria-label that overrode every field's label-derived accessible name; add an optional ariaLabel prop and set it at call sites without an associated label - Associate standalone Labels via htmlFor/id in channel-affinity views - Hide the highlight mirror and line-number layers from the accessibility tree (aria-hidden) - Give the line-number gutter an opaque background so horizontally scrolled code no longer slides under it - Degrade to no scroll sync instead of destroying the editor when the line-number layer is not found
) * perf(json-editor): improve JSON editing experience - integrate Yace for syntax highlighting, history, indentation, auto-closing, and smart line breaks. - add copy support, cursor location feedback, and synchronized content and line-number scrolling. - extract JSON editor utilities and cover key interactions with unit tests. * perf(system-settings): improve JSON configuration editing - replace raw JSON textareas with the shared editor for highlighting, validation, copy, and formatting. - preserve field-specific examples and make placeholders visible through the transparent editor layer. - remove duplicate formatting controls while keeping existing form validation and save behavior. * perf(json-editor): standardize JSON inputs across admin settings - replace pure JSON textareas with the shared editor across system settings and channel workflows. - preserve form focus, validation, placeholders, and visual or JSON editing modes. - add happy-dom component coverage for form bindings, controlled updates, and formatting. * fix(json-code-editor): address accessibility review findings - Drop the unconditional aria-label that overrode every field's label-derived accessible name; add an optional ariaLabel prop and set it at call sites without an associated label - Associate standalone Labels via htmlFor/id in channel-affinity views - Hide the highlight mirror and line-number layers from the accessibility tree (aria-hidden) - Give the line-number gutter an opaque background so horizontally scrolled code no longer slides under it - Degrade to no scroll sync instead of destroying the editor when the line-number layer is not found
) * perf(json-editor): improve JSON editing experience - integrate Yace for syntax highlighting, history, indentation, auto-closing, and smart line breaks. - add copy support, cursor location feedback, and synchronized content and line-number scrolling. - extract JSON editor utilities and cover key interactions with unit tests. * perf(system-settings): improve JSON configuration editing - replace raw JSON textareas with the shared editor for highlighting, validation, copy, and formatting. - preserve field-specific examples and make placeholders visible through the transparent editor layer. - remove duplicate formatting controls while keeping existing form validation and save behavior. * perf(json-editor): standardize JSON inputs across admin settings - replace pure JSON textareas with the shared editor across system settings and channel workflows. - preserve form focus, validation, placeholders, and visual or JSON editing modes. - add happy-dom component coverage for form bindings, controlled updates, and formatting. * fix(json-code-editor): address accessibility review findings - Drop the unconditional aria-label that overrode every field's label-derived accessible name; add an optional ariaLabel prop and set it at call sites without an associated label - Associate standalone Labels via htmlFor/id in channel-affinity views - Hide the highlight mirror and line-number layers from the accessibility tree (aria-hidden) - Give the line-number gutter an opaque background so horizontally scrolled code no longer slides under it - Degrade to no scroll sync instead of destroying the editor when the line-number layer is not found
) * perf(json-editor): improve JSON editing experience - integrate Yace for syntax highlighting, history, indentation, auto-closing, and smart line breaks. - add copy support, cursor location feedback, and synchronized content and line-number scrolling. - extract JSON editor utilities and cover key interactions with unit tests. * perf(system-settings): improve JSON configuration editing - replace raw JSON textareas with the shared editor for highlighting, validation, copy, and formatting. - preserve field-specific examples and make placeholders visible through the transparent editor layer. - remove duplicate formatting controls while keeping existing form validation and save behavior. * perf(json-editor): standardize JSON inputs across admin settings - replace pure JSON textareas with the shared editor across system settings and channel workflows. - preserve form focus, validation, placeholders, and visual or JSON editing modes. - add happy-dom component coverage for form bindings, controlled updates, and formatting. * fix(json-code-editor): address accessibility review findings - Drop the unconditional aria-label that overrode every field's label-derived accessible name; add an optional ariaLabel prop and set it at call sites without an associated label - Associate standalone Labels via htmlFor/id in channel-affinity views - Hide the highlight mirror and line-number layers from the accessibility tree (aria-hidden) - Give the line-number gutter an opaque background so horizontally scrolled code no longer slides under it - Degrade to no scroll sync instead of destroying the editor when the line-number layer is not found
Important
📝 变更描述 / Description
(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)
概述
改动说明
效果
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
(请在此粘贴截图、关键日志或测试报告,以证明变更生效)


Summary by CodeRabbit