Input 新增 allowClear + 补充 visual case(DES-126)
版本: 0.2.0–0.2.2 · 类型: ✨ 新功能
2026-06-17 Input 清空按钮补充 focus-visible 焦点环(a11y)
PR #2489 review 反馈
改动文件
src/components/Input/styles.tssrc/components/Input/__tests__/Input.test.tsx
改动内容
INPUT_CLEAR_CLASS补充focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-(--Labels-Primary),对齐ui/input、ui/button、Calendar、Tree既有键盘焦点环约定(ring-1 +Labels/Primary),为键盘聚焦清空按钮提供一致的可见指示(WCAG 2.4.7)。- 补充单测断言清空按钮带 focus 环 class。
根因
清空按钮为可聚焦 <button>,原仅依赖浏览器默认焦点环,缺少与设计系统一致的 token 焦点环。
2026-06-17 抽取 useClearableInput 复用 Input / InputSearch 清空逻辑
DES-126(sub issue of DES-125 Input);本文件当日 Input 家族改动(allowClear / visual case / 语义 class / useClearableInput 重构)统一归属此 sub issue
改动文件
src/components/Input/use-clearable-input.ts(新增)src/components/Input/Input.tsxsrc/components/Input/InputSearch.tsx
改动内容
- 将
Input(allowClear)与InputSearch中逐行重复的清空逻辑(受控/非受控 value 托管、聚焦态、清空按钮可见性、合成 change 事件回填空值、ref 转发)抽取为共享 hookuseClearableInput,消除约 50 行重复。 - hook 新增
enabled开关:Input仅prefix/suffix(无 allowClear)时不再托管内部 value,避免每次输入触发无效setInternalValue与 re-render。 - 纯结构重构,对外 API、渲染输出与 visual 快照不变;Input 家族 86 条单测全部通过。
2026-06-17 Input 新增 allowClear 清空能力 + 补充 visual case
改动文件
src/components/Input/Input.tsxsrc/components/Input/styles.tssrc/components/Input/InputDesignSpec.mdsrc/components/Input/__tests__/Input.test.tsxsrc/components/Input/__tests__/Input.ct.spec.tsxsrc/components/Input/__tests__/InputFixture.visual.tsx(新增)scripts/visual/visual-diff-config.tspackages/design-site/docs/components/atomic/input.mdx
改动内容
Input新增allowClear?: boolean与onClear?: () => void:聚焦且有内容且未禁用时,在 suffix 前渲染 × 清空按钮;失焦或无内容时隐藏。支持受控 / 非受控,点击回填空值onChange+onClear并重新聚焦。- 清空按钮以
onMouseDownpreventDefault 防止点击时 input 先失焦导致按钮消失。 - 新增
INPUT_CLEAR_CLASS:28×28 可点击区域(20pxXmarkIcon+ 4px 内边距),圆角 5px,图标Labels/Primary,hover 浅灰底。 allowClear时统一走 wrapper 渲染路径(与 prefix/suffix 一致);无 prefix/suffix/allowClear 时保持原始透传路径不变。- 补充 visual case:覆盖 Figma Input 组件集(
21028:552)全部 12 组变体(State × Filled × Status),逐变体与 Figma 节点 1:1 对比。每个 case 还原 Figma 示例内容——InputFixture.visual.tsx内联 Figmaicon_user(节点21039:5202)作前缀、HelpIcon作 28×28 后缀按钮,Focused+Filled 额外展示 allowClear 清空按钮,并在visual-diff-config.ts登记 12 个节点映射。 - design-site 新增 Clearable 示例与
allowClear/onClearProps 行。 - 修复
getInputWrapperClass(prefix/suffix 路径)错误态聚焦边框被黑色覆盖的问题:error 时聚焦边框保持Status/Destructive(红),对齐 Figma focused+error 变体与无插槽路径getInputTokenClass的行为。
根因
Figma Input 组件集(节点 21028:552)更新,Filled=True + Focused 变体(21028:557 Default / 21069:7015 Error)新增 Clear 实例(icon_xmark_for_panel,28×28)。design 层补齐对应能力并对齐视觉。
2026-06-17 InputSearch / InputPassword 补充 visual case + Search 清空改聚焦门控
改动文件
src/components/Input/InputSearch.tsxsrc/components/Input/__tests__/InputSearch.test.tsxsrc/components/Input/__tests__/InputSearch.ct.spec.tsx(新增)src/components/Input/__tests__/InputPassword.ct.spec.tsx(新增)scripts/visual/visual-diff-config.tsscripts/visual/generate-visual-gallery.tspackages/design-site/docs/components/atomic/input.mdx
改动内容
- InputSearch 清空按钮改为聚焦门控:原为「有内容即显示」,改为「聚焦且有内容且未禁用时显示」,对齐更新后的 Figma Search Field(Normal+Filled 无 ×,Focused+Filled 才有 ×)并与 Input 行为一致。新增
onMouseDownpreventDefault 防止点击失焦;清空图标由CloseIconPlaceholder换为契约图标XmarkIcon,与 Input 清空按钮统一。 - 补充 InputSearch visual case:覆盖 Search Field 组件集(
277:24750)全部 16 组变体(Size × Style × Filled × State),逐变体与 Figma 1:1 对比。 - 补充 InputPassword visual case:覆盖 Password 组件集(
21054:763)全部 16 组变体(State × Filled × Visible × Status)。Masked 渲染圆点 + eye-close,Visible 经点击 toggle 渲染明文 + eye-open;Normal+Visible 通过 toggle 后失焦还原。 visual-diff-config.ts登记 InputSearch / InputPassword 各 16 个节点映射;新增可选screenshotDir字段,使子组件截图归属Input目录,generate-visual-gallery.ts据此解析截图路径。- design-site Search 的「Controlled + Clear」示例说明更新为「聚焦且有内容时显示」。
根因
补齐 Input 家族(Search / Password)的 visual 覆盖;对齐更新后的 Figma Search Field 清空按钮聚焦门控行为(用户确认采用对齐 Figma 方案)。
2026-06-17 Input 家族补充语义化 class 标识(BEM)
改动文件
src/components/Input/Input.tsx、styles.tssrc/components/Input/InputSearch.tsx(经input-search-styles.ts)、input-search-styles.tssrc/components/Input/InputPassword.tsx、input-password-styles.tssrc/components/Input/__tests__/Input.test.tsx、InputSearch.test.tsx、InputPassword.test.tsx
改动内容
- 为 Input 家族所有 DOM 节点补充语义化 class(
plaud-<component>块 +plaud-<component>__<element>子元素,置于 class 串首,遵循 Toast/Skeleton 既有约定),供测试选择器与样式定位,避免出现仅有 Tailwind utility class 的节点:- Input:
plaud-input(裸 input / affix 容器)、plaud-input__prefix/__content/__field/__clear/__suffix - InputSearch:
plaud-input-search(容器)、plaud-input-search__icon/__field/__clear - InputPassword:
plaud-input-password(根)、plaud-input-password__toggle
- Input:
- 三个组件各补充语义 class 断言锁定。
- 语义 class 不带 CSS 规则,渲染与 visual 快照不变。
2026-06-17 清空合成事件改用原生 input 派发(修复 PR review finding)
关联:PR #2489 review finding(use-clearable-input.ts:99)
问题
handleClear 通过 Object.create 构造的合成 ChangeEvent 仅含 target / currentTarget,缺少 nativeEvent / type / bubbles / preventDefault 等标准 SyntheticEvent 字段。消费方(React Hook Form / Formik 等)读取 e.nativeEvent 会得到 undefined 并静默失败;e.type 取到的是 input 的 type 属性值(如 'text')而非事件类型 'change'。
改动内容
- 改用原生 value setter 写空值并派发真实
input事件,让 React 合成事件管道正常运转:消费方拿到的是字段完整的标准 SyntheticEvent;受控与非受控模式都经由Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set?.call(input, '');input.dispatchEvent(new Event('input', { bubbles: true }));onChange(handleChange)收到空值,无需再手动维护内部 state(移除setInternalValue('')与手动onChange构造)。 - 受控模式两条单测改为在
onChange内同步读取e.target.value:真实事件的event.target是实时 DOM 节点,受控且父组件未回填 value 时 React 会在事件后将其还原回原值,原断言异步读取会拿到还原值;同步读取与真实消费方时序一致,并真实反映受控行为。
根因
原合成事件为「够用即可」的最小实现,与 React SyntheticEvent 契约不符,对依赖 nativeEvent / type 的表单库存在静默失败风险。
2026-06-17 Input 家族 review finding 二次修复(focus-visible / 聚焦态 re-render / aria-label 本地化)
关联:PR #2489 review findings
改动文件
src/components/Input/input-search-styles.tssrc/components/Input/Input.tsx、InputSearch.tsxsrc/components/Input/__tests__/Input.test.tsx、InputSearch.test.tsxpackages/design-site/docs/components/atomic/input.mdx(含 zh-CN)
改动内容
- [critical] InputSearch 清空按钮补 focus-visible 焦点环:
INPUT_SEARCH_CLEAR_CLASS此前未同步 commit52389cdc6为 Input 补的焦点环,键盘 Tab 到清空按钮无可见指示(违反 WCAG 2.4.7)。补充focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-(--Labels-Primary),与 Input 一致;新增焦点环单测锁定。 - [perf] Input 无 allowClear 时不再托管聚焦态:affix 模式(仅 prefix/suffix、
allowClear=false)下onFocus/onBlur/onChange原先恒绑 hook 版处理器,每次聚焦/失焦都会setFocused触发无效 re-render(showClear恒为 false)。改为仅allowClear === true时使用 hook 版处理器,否则直接透传原始回调,消除相对旧代码的性能回退。 - [convention] 清空按钮 aria-label 支持本地化:Input / InputSearch 新增
clearButtonAriaLabel?: string,默认分别为'清空输入'/'清空搜索',多语言消费方可覆盖;补充默认值与自定义值单测,design-site Props 表(中英文)登记该 prop。
根因
首轮 allowClear 实现遗漏 InputSearch 焦点环同步、affix 场景聚焦态托管引入无效 re-render,以及组件库层硬编码中文 aria-label 不利于多语言消费方。