Skip to content

feat: switch 辨识度提升#125

Merged
MistEO merged 10 commits intomainfrom
feat/highlight
Mar 21, 2026
Merged

feat: switch 辨识度提升#125
MistEO merged 10 commits intomainfrom
feat/highlight

Conversation

@MistEO
Copy link
Copy Markdown
Owner

@MistEO MistEO commented Mar 21, 2026

Summary by Sourcery

改进选项编辑器布局以及开关选项的可访问性,使选项行更清晰、更一致。

改进内容:

  • 使开关选项行可在整行区域内点击,并可通过键盘操作,同时使用正确的 ARIA 开关语义,并保持视觉开关的位置对齐。
  • 重新布局标签、描述和控件,使文本能在合适位置截断,并让下拉选择/输入控件在受约束的标签/描述区域旁使用一致的固定宽度。
  • 调整选项组、嵌套选项和任务描述之间的垂直间距,以形成更清晰的视觉分隔和对齐。
  • 将校验错误和辅助内容与新的输入布局对齐,把错误信息右对齐显示在对应控件下方。
  • 将相关选项的标签和描述整合到交互式行容器中,在列表渲染器中应用统一的悬停状态和“车道式”间距样式。
Original summary in English

Summary by Sourcery

Improve option editor layout and switch option accessibility for clearer, more consistent option rows.

Enhancements:

  • Make switch option rows fully clickable and keyboard operable with correct ARIA switch semantics while keeping the visual switch aligned.
  • Reflow labels, descriptions, and controls so text truncates appropriately and select/input controls use a consistent fixed width alongside a constrained label/description block.
  • Adjust vertical spacing between option groups, nested options, and task descriptions to create clearer visual separation and alignment.
  • Align validation errors and helper content with the new input layout, right-aligning error messages under their associated controls.
  • Consolidate labels and descriptions into the interactive row container for relevant options, applying unified hover states and lane-style spacing in the list renderer.

改进点:

  • 使开关选项行可点击并支持键盘操作,使用正确的 ARIA 开关语义,同时保持视觉上的开关控件对齐。
  • 重新排列选项标签、描述和控件,使文本能够适当地截断,并让输入框/下拉选择框在标签/描述块设置最大宽度的同时拥有一致的固定宽度。
  • 调整选项组之间、嵌套选项以及任务描述之间的垂直间距,以形成更清晰的分隔和对齐。
  • 将校验错误信息与新的输入布局对齐,并在其对应控件下方右对齐显示。
Original summary in English

Summary by Sourcery

改进选项编辑器布局以及开关选项的可访问性,使选项行更清晰、更一致。

改进内容:

  • 使开关选项行可在整行区域内点击,并可通过键盘操作,同时使用正确的 ARIA 开关语义,并保持视觉开关的位置对齐。
  • 重新布局标签、描述和控件,使文本能在合适位置截断,并让下拉选择/输入控件在受约束的标签/描述区域旁使用一致的固定宽度。
  • 调整选项组、嵌套选项和任务描述之间的垂直间距,以形成更清晰的视觉分隔和对齐。
  • 将校验错误和辅助内容与新的输入布局对齐,把错误信息右对齐显示在对应控件下方。
  • 将相关选项的标签和描述整合到交互式行容器中,在列表渲染器中应用统一的悬停状态和“车道式”间距样式。
Original summary in English

Summary by Sourcery

Improve option editor layout and switch option accessibility for clearer, more consistent option rows.

Enhancements:

  • Make switch option rows fully clickable and keyboard operable with correct ARIA switch semantics while keeping the visual switch aligned.
  • Reflow labels, descriptions, and controls so text truncates appropriately and select/input controls use a consistent fixed width alongside a constrained label/description block.
  • Adjust vertical spacing between option groups, nested options, and task descriptions to create clearer visual separation and alignment.
  • Align validation errors and helper content with the new input layout, right-aligning error messages under their associated controls.
  • Consolidate labels and descriptions into the interactive row container for relevant options, applying unified hover states and lane-style spacing in the list renderer.

改进内容:

  • 使开关选项行可整行点击,并支持键盘操作,采用正确的 ARIA 开关语义,同时保持开关控件在视觉上的对齐。
  • 统一选项标签、描述和控件的布局:通过限制标签/描述宽度、截断过长标签,并为控件设置统一的固定宽度。
  • 调整选项和任务描述周围的垂直间距及描述的边距,以在不同选项组之间形成更清晰的分隔。
  • 优化错误信息和辅助文本的对齐方式,使其更好地匹配新的选项行布局。
Original summary in English

Summary by Sourcery

改进选项编辑器布局以及开关选项的可访问性,使选项行更清晰、更一致。

改进内容:

  • 使开关选项行可在整行区域内点击,并可通过键盘操作,同时使用正确的 ARIA 开关语义,并保持视觉开关的位置对齐。
  • 重新布局标签、描述和控件,使文本能在合适位置截断,并让下拉选择/输入控件在受约束的标签/描述区域旁使用一致的固定宽度。
  • 调整选项组、嵌套选项和任务描述之间的垂直间距,以形成更清晰的视觉分隔和对齐。
  • 将校验错误和辅助内容与新的输入布局对齐,把错误信息右对齐显示在对应控件下方。
  • 将相关选项的标签和描述整合到交互式行容器中,在列表渲染器中应用统一的悬停状态和“车道式”间距样式。
Original summary in English

Summary by Sourcery

Improve option editor layout and switch option accessibility for clearer, more consistent option rows.

Enhancements:

  • Make switch option rows fully clickable and keyboard operable with correct ARIA switch semantics while keeping the visual switch aligned.
  • Reflow labels, descriptions, and controls so text truncates appropriately and select/input controls use a consistent fixed width alongside a constrained label/description block.
  • Adjust vertical spacing between option groups, nested options, and task descriptions to create clearer visual separation and alignment.
  • Align validation errors and helper content with the new input layout, right-aligning error messages under their associated controls.
  • Consolidate labels and descriptions into the interactive row container for relevant options, applying unified hover states and lane-style spacing in the list renderer.

改进点:

  • 使开关选项行可点击并支持键盘操作,使用正确的 ARIA 开关语义,同时保持视觉上的开关控件对齐。
  • 重新排列选项标签、描述和控件,使文本能够适当地截断,并让输入框/下拉选择框在标签/描述块设置最大宽度的同时拥有一致的固定宽度。
  • 调整选项组之间、嵌套选项以及任务描述之间的垂直间距,以形成更清晰的分隔和对齐。
  • 将校验错误信息与新的输入布局对齐,并在其对应控件下方右对齐显示。
Original summary in English

Summary by Sourcery

改进选项编辑器布局以及开关选项的可访问性,使选项行更清晰、更一致。

改进内容:

  • 使开关选项行可在整行区域内点击,并可通过键盘操作,同时使用正确的 ARIA 开关语义,并保持视觉开关的位置对齐。
  • 重新布局标签、描述和控件,使文本能在合适位置截断,并让下拉选择/输入控件在受约束的标签/描述区域旁使用一致的固定宽度。
  • 调整选项组、嵌套选项和任务描述之间的垂直间距,以形成更清晰的视觉分隔和对齐。
  • 将校验错误和辅助内容与新的输入布局对齐,把错误信息右对齐显示在对应控件下方。
  • 将相关选项的标签和描述整合到交互式行容器中,在列表渲染器中应用统一的悬停状态和“车道式”间距样式。
Original summary in English

Summary by Sourcery

Improve option editor layout and switch option accessibility for clearer, more consistent option rows.

Enhancements:

  • Make switch option rows fully clickable and keyboard operable with correct ARIA switch semantics while keeping the visual switch aligned.
  • Reflow labels, descriptions, and controls so text truncates appropriately and select/input controls use a consistent fixed width alongside a constrained label/description block.
  • Adjust vertical spacing between option groups, nested options, and task descriptions to create clearer visual separation and alignment.
  • Align validation errors and helper content with the new input layout, right-aligning error messages under their associated controls.
  • Consolidate labels and descriptions into the interactive row container for relevant options, applying unified hover states and lane-style spacing in the list renderer.

增强内容:

  • 为交替出现的顶层开关行添加视觉通道(斑马条纹)背景,以提高浏览辨识度。
  • 使开关行可通过点击和键盘完整操作,并具备正确的 ARIA 开关语义,同时保持底层开关控件的视觉对齐。
  • 从选项列表渲染器向选项编辑器传递一个可视的行索引,以便只有非网格布局的顶层选项参与通道样式(lane styling)。
  • 调整布局,使开关标签和描述都归入可交互的行容器中,并在整行上统一应用悬停状态。
Original summary in English

Summary by Sourcery

改进选项编辑器布局以及开关选项的可访问性,使选项行更清晰、更一致。

改进内容:

  • 使开关选项行可在整行区域内点击,并可通过键盘操作,同时使用正确的 ARIA 开关语义,并保持视觉开关的位置对齐。
  • 重新布局标签、描述和控件,使文本能在合适位置截断,并让下拉选择/输入控件在受约束的标签/描述区域旁使用一致的固定宽度。
  • 调整选项组、嵌套选项和任务描述之间的垂直间距,以形成更清晰的视觉分隔和对齐。
  • 将校验错误和辅助内容与新的输入布局对齐,把错误信息右对齐显示在对应控件下方。
  • 将相关选项的标签和描述整合到交互式行容器中,在列表渲染器中应用统一的悬停状态和“车道式”间距样式。
Original summary in English

Summary by Sourcery

Improve option editor layout and switch option accessibility for clearer, more consistent option rows.

Enhancements:

  • Make switch option rows fully clickable and keyboard operable with correct ARIA switch semantics while keeping the visual switch aligned.
  • Reflow labels, descriptions, and controls so text truncates appropriately and select/input controls use a consistent fixed width alongside a constrained label/description block.
  • Adjust vertical spacing between option groups, nested options, and task descriptions to create clearer visual separation and alignment.
  • Align validation errors and helper content with the new input layout, right-aligning error messages under their associated controls.
  • Consolidate labels and descriptions into the interactive row container for relevant options, applying unified hover states and lane-style spacing in the list renderer.

改进点:

  • 使开关选项行可点击并支持键盘操作,使用正确的 ARIA 开关语义,同时保持视觉上的开关控件对齐。
  • 重新排列选项标签、描述和控件,使文本能够适当地截断,并让输入框/下拉选择框在标签/描述块设置最大宽度的同时拥有一致的固定宽度。
  • 调整选项组之间、嵌套选项以及任务描述之间的垂直间距,以形成更清晰的分隔和对齐。
  • 将校验错误信息与新的输入布局对齐,并在其对应控件下方右对齐显示。
Original summary in English

Summary by Sourcery

改进选项编辑器布局以及开关选项的可访问性,使选项行更清晰、更一致。

改进内容:

  • 使开关选项行可在整行区域内点击,并可通过键盘操作,同时使用正确的 ARIA 开关语义,并保持视觉开关的位置对齐。
  • 重新布局标签、描述和控件,使文本能在合适位置截断,并让下拉选择/输入控件在受约束的标签/描述区域旁使用一致的固定宽度。
  • 调整选项组、嵌套选项和任务描述之间的垂直间距,以形成更清晰的视觉分隔和对齐。
  • 将校验错误和辅助内容与新的输入布局对齐,把错误信息右对齐显示在对应控件下方。
  • 将相关选项的标签和描述整合到交互式行容器中,在列表渲染器中应用统一的悬停状态和“车道式”间距样式。
Original summary in English

Summary by Sourcery

Improve option editor layout and switch option accessibility for clearer, more consistent option rows.

Enhancements:

  • Make switch option rows fully clickable and keyboard operable with correct ARIA switch semantics while keeping the visual switch aligned.
  • Reflow labels, descriptions, and controls so text truncates appropriately and select/input controls use a consistent fixed width alongside a constrained label/description block.
  • Adjust vertical spacing between option groups, nested options, and task descriptions to create clearer visual separation and alignment.
  • Align validation errors and helper content with the new input layout, right-aligning error messages under their associated controls.
  • Consolidate labels and descriptions into the interactive row container for relevant options, applying unified hover states and lane-style spacing in the list renderer.

改进内容:

  • 使开关选项行可整行点击,并支持键盘操作,采用正确的 ARIA 开关语义,同时保持开关控件在视觉上的对齐。
  • 统一选项标签、描述和控件的布局:通过限制标签/描述宽度、截断过长标签,并为控件设置统一的固定宽度。
  • 调整选项和任务描述周围的垂直间距及描述的边距,以在不同选项组之间形成更清晰的分隔。
  • 优化错误信息和辅助文本的对齐方式,使其更好地匹配新的选项行布局。
Original summary in English

Summary by Sourcery

改进选项编辑器布局以及开关选项的可访问性,使选项行更清晰、更一致。

改进内容:

  • 使开关选项行可在整行区域内点击,并可通过键盘操作,同时使用正确的 ARIA 开关语义,并保持视觉开关的位置对齐。
  • 重新布局标签、描述和控件,使文本能在合适位置截断,并让下拉选择/输入控件在受约束的标签/描述区域旁使用一致的固定宽度。
  • 调整选项组、嵌套选项和任务描述之间的垂直间距,以形成更清晰的视觉分隔和对齐。
  • 将校验错误和辅助内容与新的输入布局对齐,把错误信息右对齐显示在对应控件下方。
  • 将相关选项的标签和描述整合到交互式行容器中,在列表渲染器中应用统一的悬停状态和“车道式”间距样式。
Original summary in English

Summary by Sourcery

Improve option editor layout and switch option accessibility for clearer, more consistent option rows.

Enhancements:

  • Make switch option rows fully clickable and keyboard operable with correct ARIA switch semantics while keeping the visual switch aligned.
  • Reflow labels, descriptions, and controls so text truncates appropriately and select/input controls use a consistent fixed width alongside a constrained label/description block.
  • Adjust vertical spacing between option groups, nested options, and task descriptions to create clearer visual separation and alignment.
  • Align validation errors and helper content with the new input layout, right-aligning error messages under their associated controls.
  • Consolidate labels and descriptions into the interactive row container for relevant options, applying unified hover states and lane-style spacing in the list renderer.

改进点:

  • 使开关选项行可点击并支持键盘操作,使用正确的 ARIA 开关语义,同时保持视觉上的开关控件对齐。
  • 重新排列选项标签、描述和控件,使文本能够适当地截断,并让输入框/下拉选择框在标签/描述块设置最大宽度的同时拥有一致的固定宽度。
  • 调整选项组之间、嵌套选项以及任务描述之间的垂直间距,以形成更清晰的分隔和对齐。
  • 将校验错误信息与新的输入布局对齐,并在其对应控件下方右对齐显示。
Original summary in English

Summary by Sourcery

改进选项编辑器布局以及开关选项的可访问性,使选项行更清晰、更一致。

改进内容:

  • 使开关选项行可在整行区域内点击,并可通过键盘操作,同时使用正确的 ARIA 开关语义,并保持视觉开关的位置对齐。
  • 重新布局标签、描述和控件,使文本能在合适位置截断,并让下拉选择/输入控件在受约束的标签/描述区域旁使用一致的固定宽度。
  • 调整选项组、嵌套选项和任务描述之间的垂直间距,以形成更清晰的视觉分隔和对齐。
  • 将校验错误和辅助内容与新的输入布局对齐,把错误信息右对齐显示在对应控件下方。
  • 将相关选项的标签和描述整合到交互式行容器中,在列表渲染器中应用统一的悬停状态和“车道式”间距样式。
Original summary in English

Summary by Sourcery

Improve option editor layout and switch option accessibility for clearer, more consistent option rows.

Enhancements:

  • Make switch option rows fully clickable and keyboard operable with correct ARIA switch semantics while keeping the visual switch aligned.
  • Reflow labels, descriptions, and controls so text truncates appropriately and select/input controls use a consistent fixed width alongside a constrained label/description block.
  • Adjust vertical spacing between option groups, nested options, and task descriptions to create clearer visual separation and alignment.
  • Align validation errors and helper content with the new input layout, right-aligning error messages under their associated controls.
  • Consolidate labels and descriptions into the interactive row container for relevant options, applying unified hover states and lane-style spacing in the list renderer.

Copilot AI review requested due to automatic review settings March 21, 2026 16:34
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题,并给出了一些整体性的反馈:

  • OptionListRenderer 中使用内联 IIFE 并手动维护 visualIndex 会增加复杂度;可以考虑预先计算一个派生的 groupsWithRowIndex 数组,或者使用 reduce,让 JSX 只需要一个没有副作用的 .map
  • OptionEditor 中,isLane 相关的样式逻辑在多个分支里被重复使用;你可以抽取一个共享的辅助方法(例如 getOptionContainerClassName({ depth, isLane, isOptionIncompatible }))或者一个小组件,从而避免重复相同的 clsx 片段。
  • 对于使用了 role="switch" 的开关行容器,可能值得通过 aria-labelledby 将它与可见标签连接(或者添加一个 aria-label),这样屏幕阅读器才能正确地把标签文本和开关控件关联起来。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
- The inline IIFE with a manually tracked `visualIndex` inside `OptionListRenderer` adds complexity; consider precomputing a derived `groupsWithRowIndex` array or using `reduce` so the JSX is a simple `.map` without side effects.
- The `isLane` styling logic is duplicated across multiple branches in `OptionEditor`; you could extract a shared helper (e.g. `getOptionContainerClassName({ depth, isLane, isOptionIncompatible })`) or a small component to avoid repeating the same `clsx` fragments.
- For the switch row container using `role="switch"`, it may be worth wiring it to the visible label via `aria-labelledby` (or adding an `aria-label`) so screen readers correctly associate the label text with the switch control.

## Individual Comments

### Comment 1
<location path="src/components/OptionEditor.tsx" line_range="447-448" />
<code_context>
+              basePath={basePath}
+              incompatibleReason={incompatibleReason}
+            />
+            <div className="pointer-events-none">
+              <SwitchButton value={isChecked} onChange={handleToggleSwitch} disabled={effectiveDisabled} />
+            </div>
+          </div>
</code_context>
<issue_to_address>
**issue (bug_risk):** The combination of `pointer-events-none` and the outer `onKeyDown` handler can cause confusing keyboard behavior for the nested `SwitchButton`.

Because `SwitchButton` may still be focusable and receive keyboard events, a space/enter press could both toggle its `onChange` and bubble to the outer `onKeyDown`, causing `handleToggleSwitch` to fire twice and effectively cancel the state change. It also leaves you with two focusable “switches” (outer `role="switch"` and inner control), which is problematic for accessibility. I’d recommend either making the inner `SwitchButton` presentational only (e.g., `tabIndex={-1}`, no `onChange`), or moving all input handling to `SwitchButton` and dropping the outer `role="switch"`/keyboard handler.
</issue_to_address>

Sourcery 对开源项目免费使用——如果你觉得我们的代码审查有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进之后的审查。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • The inline IIFE with a manually tracked visualIndex inside OptionListRenderer adds complexity; consider precomputing a derived groupsWithRowIndex array or using reduce so the JSX is a simple .map without side effects.
  • The isLane styling logic is duplicated across multiple branches in OptionEditor; you could extract a shared helper (e.g. getOptionContainerClassName({ depth, isLane, isOptionIncompatible })) or a small component to avoid repeating the same clsx fragments.
  • For the switch row container using role="switch", it may be worth wiring it to the visible label via aria-labelledby (or adding an aria-label) so screen readers correctly associate the label text with the switch control.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The inline IIFE with a manually tracked `visualIndex` inside `OptionListRenderer` adds complexity; consider precomputing a derived `groupsWithRowIndex` array or using `reduce` so the JSX is a simple `.map` without side effects.
- The `isLane` styling logic is duplicated across multiple branches in `OptionEditor`; you could extract a shared helper (e.g. `getOptionContainerClassName({ depth, isLane, isOptionIncompatible })`) or a small component to avoid repeating the same `clsx` fragments.
- For the switch row container using `role="switch"`, it may be worth wiring it to the visible label via `aria-labelledby` (or adding an `aria-label`) so screen readers correctly associate the label text with the switch control.

## Individual Comments

### Comment 1
<location path="src/components/OptionEditor.tsx" line_range="447-448" />
<code_context>
+              basePath={basePath}
+              incompatibleReason={incompatibleReason}
+            />
+            <div className="pointer-events-none">
+              <SwitchButton value={isChecked} onChange={handleToggleSwitch} disabled={effectiveDisabled} />
+            </div>
+          </div>
</code_context>
<issue_to_address>
**issue (bug_risk):** The combination of `pointer-events-none` and the outer `onKeyDown` handler can cause confusing keyboard behavior for the nested `SwitchButton`.

Because `SwitchButton` may still be focusable and receive keyboard events, a space/enter press could both toggle its `onChange` and bubble to the outer `onKeyDown`, causing `handleToggleSwitch` to fire twice and effectively cancel the state change. It also leaves you with two focusable “switches” (outer `role="switch"` and inner control), which is problematic for accessibility. I’d recommend either making the inner `SwitchButton` presentational only (e.g., `tabIndex={-1}`, no `onChange`), or moving all input handling to `SwitchButton` and dropping the outer `role="switch"`/keyboard handler.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the visual clarity and usability of top-level switch options in the task option list by adding alternating “zebra” backgrounds and making switch rows easier to interact with.

Changes:

  • Add a rowIndex concept so OptionEditor can render alternating background lanes for top-level rows.
  • Update option-group rendering to compute a “visual” index that skips switchGrid groups (so stripes apply to visible rows consistently).
  • Make switch option rows clickable/focusable with role="switch" and keyboard toggling.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/components/TaskItem.tsx Computes a visual row index (skipping switchGrid) and passes rowIndex into OptionEditor for striping.
src/components/OptionEditor.tsx Adds rowIndex prop and applies zebra styling; refactors switch rendering to be row-clickable and keyboard-accessible.

@MistEO MistEO requested a review from Copilot March 21, 2026 18:10
@MistEO
Copy link
Copy Markdown
Owner Author

MistEO commented Mar 21, 2026

@sourcery-ai review

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我给出了一些整体上的反馈:

  • 对于开关行,目前外层容器 div 增加了 role="switch" 和键盘处理逻辑,而内部的 SwitchButton 仍然会被渲染(但带有 pointer-events-none);建议要么把焦点/ARIA 行为委托给 SwitchButton,要么将其标记为 aria-hidden/“仅用于展示”,以避免对辅助技术产生重复或不直观的语义。
  • OptionEditor 中为输入框和选择框硬编码使用了 w-[30%] flex-shrink-0 的宽度,这在非常窄或非常宽的布局下可能表现不佳;建议使用响应式或最大/最小宽度工具类(例如 max-wmin-w 或基于断点的类)来替代固定百分比,从而让布局更加健壮。
  • InputField 中错误信息容器现在使用了 justify-end,但其宽度没有和输入列绑定,这会在大屏幕上把错误信息推得很靠右;建议将其限制在与输入框相同的 flex 区域内,或者在局部进行对齐,以保持其与对应输入的视觉关联。
给 AI 代理的提示
Please address the comments from this code review:

## Overall Comments
- For the switch rows, the container `div` now has `role="switch"` and keyboard handling while the underlying `SwitchButton` is still rendered (but with `pointer-events-none`); consider either delegating focus/ARIA to `SwitchButton` or marking it `aria-hidden`/presentation-only to avoid duplicate/unintuitive semantics for assistive technologies.
- The hard-coded `w-[30%] flex-shrink-0` widths for inputs and selects in `OptionEditor` may not behave well on very narrow or very wide layouts; consider using responsive or max/min width utilities (e.g. `max-w`, `min-w`, or breakpoint-based classes) instead of a fixed percentage to keep the layout robust.
- The error message container in `InputField` now uses `justify-end` without tying its width to the input column, which can push the message to the far right on wide screens; consider constraining it to the same flex area as the input or aligning it more locally to maintain visual association.

Sourcery 对开源项目免费——如果你觉得我们的评审有用,请考虑分享它们 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English

Hey - I've left some high level feedback:

  • For the switch rows, the container div now has role="switch" and keyboard handling while the underlying SwitchButton is still rendered (but with pointer-events-none); consider either delegating focus/ARIA to SwitchButton or marking it aria-hidden/presentation-only to avoid duplicate/unintuitive semantics for assistive technologies.
  • The hard-coded w-[30%] flex-shrink-0 widths for inputs and selects in OptionEditor may not behave well on very narrow or very wide layouts; consider using responsive or max/min width utilities (e.g. max-w, min-w, or breakpoint-based classes) instead of a fixed percentage to keep the layout robust.
  • The error message container in InputField now uses justify-end without tying its width to the input column, which can push the message to the far right on wide screens; consider constraining it to the same flex area as the input or aligning it more locally to maintain visual association.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- For the switch rows, the container `div` now has `role="switch"` and keyboard handling while the underlying `SwitchButton` is still rendered (but with `pointer-events-none`); consider either delegating focus/ARIA to `SwitchButton` or marking it `aria-hidden`/presentation-only to avoid duplicate/unintuitive semantics for assistive technologies.
- The hard-coded `w-[30%] flex-shrink-0` widths for inputs and selects in `OptionEditor` may not behave well on very narrow or very wide layouts; consider using responsive or max/min width utilities (e.g. `max-w`, `min-w`, or breakpoint-based classes) instead of a fixed percentage to keep the layout robust.
- The error message container in `InputField` now uses `justify-end` without tying its width to the input column, which can push the message to the far right on wide screens; consider constraining it to the same flex area as the input or aligning it more locally to maintain visual association.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

@MistEO MistEO requested a review from Copilot March 21, 2026 18:21
@MistEO
Copy link
Copy Markdown
Owner Author

MistEO commented Mar 21, 2026

@sourcery-ai review

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题,并留下了一些整体性的反馈:

  • 在 switch 行的 keydown 处理函数中,建议当事件来自嵌套的可交互元素(例如链接、按钮、输入框)时忽略 Enter/Space,可以通过检查 if (event.target !== event.currentTarget) return; 来实现,以避免对键盘交互进行双重处理。
  • 由于 switch 控件被包在一个带有 pointer-events-nonearia-hidden 的容器中,请再次确认 SwitchButton 本身不可获得焦点/不可 Tab 导航(例如内部没有处于 tab 顺序中的 button),否则键盘用户可能会遇到一个不可交互或重复的开关,而此时该行已经拥有 ARIA switch 语义。
  • 新增的固定宽度,例如输入框/选择框使用 w-[30%],标签/描述使用 max-w-[60%],在非常窄或非常宽的容器中可能表现不佳;可以考虑使用更灵活的响应式尺寸(例如 min/max 宽度或断点)来代替固定百分比。
给 AI Agent 的提示词
Please address the comments from this code review:

## Overall Comments
- In the switch row keydown handler, consider ignoring `Enter`/`Space` when the event originates from nested interactive elements (e.g., links, buttons, inputs) by checking `if (event.target !== event.currentTarget) return;` to avoid double-handling keyboard interactions.
- With the switch control wrapped in a `pointer-events-none` + `aria-hidden` container, double‑check that `SwitchButton` itself is not focusable/tabbable (e.g., no internal `button` in the tab order), otherwise keyboard users may encounter a non-interactive or duplicated switch while the row already owns the ARIA `switch` semantics.
- The new fixed widths like `w-[30%]` for inputs/selects and `max-w-[60%]` for labels/descriptions may behave poorly on very narrow or very wide containers; consider using more flexible responsive sizing (e.g., min/max widths or breakpoints) instead of hard percentages.

## Individual Comments

### Comment 1
<location path="src/components/OptionEditor.tsx" line_range="450-423" />
<code_context>
+              translations={translations}
+            />
+          </div>
+          <div className="pointer-events-none flex-shrink-0" aria-hidden="true">
+            <SwitchButton
+              value={isChecked}
+              onChange={handleToggleSwitch}
+              disabled={effectiveDisabled}
+            />
+          </div>
</code_context>
<issue_to_address>
**issue (bug_risk):** Combining `pointer-events-none` with `aria-hidden` on the SwitchButton wrapper can lead to subtle accessibility and keyboard-focus inconsistencies.

Because the wrapper `div` is `aria-hidden` while the actual focusable control lives inside `SwitchButton`, assistive tech will ignore this subtree but the inner control can still receive keyboard focus (since `pointer-events` doesn’t affect focus). That can leave a focusable element that’s never announced, and events may not map cleanly to the outer row’s `role="switch"`. If you want the outer row to be the only interactive control, make the inner `SwitchButton` non-focusable (e.g. a visual-only variant, or `tabIndex={-1}` on the real control) instead of using `pointer-events-none` + `aria-hidden` on the wrapper.
</issue_to_address>

Sourcery 对开源项目免费使用——如果你觉得这份评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • In the switch row keydown handler, consider ignoring Enter/Space when the event originates from nested interactive elements (e.g., links, buttons, inputs) by checking if (event.target !== event.currentTarget) return; to avoid double-handling keyboard interactions.
  • With the switch control wrapped in a pointer-events-none + aria-hidden container, double‑check that SwitchButton itself is not focusable/tabbable (e.g., no internal button in the tab order), otherwise keyboard users may encounter a non-interactive or duplicated switch while the row already owns the ARIA switch semantics.
  • The new fixed widths like w-[30%] for inputs/selects and max-w-[60%] for labels/descriptions may behave poorly on very narrow or very wide containers; consider using more flexible responsive sizing (e.g., min/max widths or breakpoints) instead of hard percentages.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the switch row keydown handler, consider ignoring `Enter`/`Space` when the event originates from nested interactive elements (e.g., links, buttons, inputs) by checking `if (event.target !== event.currentTarget) return;` to avoid double-handling keyboard interactions.
- With the switch control wrapped in a `pointer-events-none` + `aria-hidden` container, double‑check that `SwitchButton` itself is not focusable/tabbable (e.g., no internal `button` in the tab order), otherwise keyboard users may encounter a non-interactive or duplicated switch while the row already owns the ARIA `switch` semantics.
- The new fixed widths like `w-[30%]` for inputs/selects and `max-w-[60%]` for labels/descriptions may behave poorly on very narrow or very wide containers; consider using more flexible responsive sizing (e.g., min/max widths or breakpoints) instead of hard percentages.

## Individual Comments

### Comment 1
<location path="src/components/OptionEditor.tsx" line_range="450-423" />
<code_context>
+              translations={translations}
+            />
+          </div>
+          <div className="pointer-events-none flex-shrink-0" aria-hidden="true">
+            <SwitchButton
+              value={isChecked}
+              onChange={handleToggleSwitch}
+              disabled={effectiveDisabled}
+            />
+          </div>
</code_context>
<issue_to_address>
**issue (bug_risk):** Combining `pointer-events-none` with `aria-hidden` on the SwitchButton wrapper can lead to subtle accessibility and keyboard-focus inconsistencies.

Because the wrapper `div` is `aria-hidden` while the actual focusable control lives inside `SwitchButton`, assistive tech will ignore this subtree but the inner control can still receive keyboard focus (since `pointer-events` doesn’t affect focus). That can leave a focusable element that’s never announced, and events may not map cleanly to the outer row’s `role="switch"`. If you want the outer row to be the only interactive control, make the inner `SwitchButton` non-focusable (e.g. a visual-only variant, or `tabIndex={-1}` on the real control) instead of using `pointer-events-none` + `aria-hidden` on the wrapper.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment on lines +412 to +416
const handleSwitchRowKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
if (event.key !== 'Enter' && event.key !== ' ') return;
event.preventDefault();
handleToggleSwitch();
};
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleSwitchRowKeyDown toggles on keydown for the Space key. Because keydown repeats while the key is held, this can flip the switch multiple times unexpectedly. Consider either ignoring repeated events (event.repeat) or handling Space on keyup (keeping preventDefault to avoid page scroll).

Copilot uses AI. Check for mistakes.
isOptionIncompatible && 'opacity-60',
)}
onClick={(e) => {
if ((e.target as HTMLElement).closest('a')) return;
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The row-level onClick only exempts anchor clicks. Clicking the incompatible-warning tooltip icon (and any other non-<a> interactive child) will bubble and toggle the switch, which makes it hard to inspect the tooltip without changing the value. Consider stopping propagation on the tooltip trigger, or broadening the guard to skip clicks originating from tooltip triggers/other controls.

Suggested change
if ((e.target as HTMLElement).closest('a')) return;
const target = e.target as HTMLElement | null;
if (
target &&
target.closest(
'a,button,input,select,textarea,[role="button"]',
)
) {
return;
}

Copilot uses AI. Check for mistakes.

return (
<div className="space-y-3">
<div className="space-y-4">
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions adding zebra-stripe “lane styling” for alternating top-level switch rows and passing a visible row index into OptionEditor, but the changes in this PR only adjust spacing/margins here. Either implement the described lane styling/index passing, or update the PR description to match what’s actually included.

Copilot uses AI. Check for mistakes.
@MistEO
Copy link
Copy Markdown
Owner Author

MistEO commented Mar 21, 2026

@sourcery-ai summary

@MistEO MistEO merged commit 2368a14 into main Mar 21, 2026
9 checks passed
@MistEO MistEO deleted the feat/highlight branch March 21, 2026 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants