Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(form): 多端适配 #2595

Open
wants to merge 12 commits into
base: feat_v3.x
Choose a base branch
from

Conversation

oasis-cloud
Copy link
Collaborator

@oasis-cloud oasis-cloud commented Sep 13, 2024

由于 RN 和 鸿蒙的选择器只能支持 类选择、多类选择器和伪元素选择器,所以无法实现通过 form 控制 input textarea 等的样式,需要从视觉层面来进行一些组件样式的修复。这样可以确保放到 form 中样式表现良好。

Summary by CodeRabbit

  • 新功能

    • 增加了对 formitem 组件的支持,增强了文件复制和修改操作的功能。
    • 新增 InputInputNumberRangeSwitchTextArea 组件,并更新了多个组件的版本。
    • 增加了 disabledvalidateTrigger 属性,以增强表单的功能和控制。
  • 文档

    • 更新了 Form 组件的文档,增加了 validateTrigger 属性的描述和新方法 setFieldValue 的介绍。
  • 样式

    • 修改了表单项的样式,新增了多个布局类,以改善视觉效果和响应设计。

Copy link

coderabbitai bot commented Sep 13, 2024

Walkthrough

本次变更主要涉及多个文件的更新,增强了表单组件的功能和样式。copy-file.js 脚本新增了对 formitem 组件的处理,config.json 文件中更新了多个组件的版本和属性。表单相关的组件(如 FormFormItem)进行了接口和渲染逻辑的改进,添加了新的属性如 disabledvalidateTrigger,并引入了新的实用函数 mergetoArray 来优化状态管理。样式文件也进行了大幅修改,以改善表单项的布局和视觉表现。

Changes

文件路径 变更摘要
scripts/rn/copy-file.js 新增字符串 'formitem'childAdaptedArray,更新 copyFile 函数以处理 formitem 组件。
src/config.json 多个组件版本从 2.0.0 更新到 3.0.0,新增 InputInputNumberRangeSwitchTextArea 组件。
src/packages/form/demos/taro/demo1.tsx 移除 InputNumber 组件,更新 username 字段的验证规则,修改 TextArea 组件的样式。
src/packages/formitem/formitem.taro.tsx 中心化上下文方法访问,新增 getClassNameWithDirection 方法,更新 align 属性为必填。
src/packages/form/form.taro.tsx 新增 disabledvalidateTrigger 属性,更新渲染逻辑使用 <TForm> 组件。
src/packages/form/form.tsx 新增 disabledvalidateTrigger 属性,更新上下文值。
src/packages/form/useform.taro.ts 新增 updateStore 方法,更新 setInitialValuessetFieldsValue 方法以合并值。
src/packages/form/useform.ts 新增 updateStore 方法,更新 setInitialValuessetFieldsValue 方法以合并值。
src/packages/formitem/formitem.scss 新增多个样式类以改善表单项的布局和视觉效果。
src/packages/formitem/formitem.tsx 更新上下文访问逻辑,新增 getClassNameWithDirection 方法,更新 align 属性为必填。
src/utils/merge.ts 新增 merge 函数以合并多个对象。
src/utils/to-array.ts 新增 toArray 函数以确保返回数组。
src/packages/form/doc.en-US.md 更新文档以包含 validateTrigger 属性和 setFieldValue 方法。
src/packages/form/doc.md 更新文档以包含 validateTrigger 属性和 setFieldValue 方法。
src/packages/form/doc.taro.md 更新文档以包含 validateTrigger 属性和 setFieldValue 方法。
src/packages/form/doc.zh-TW.md 更新文档以包含 validateTrigger 属性和 setFieldValue 方法。
src/packages/form/types.ts 更新接口以添加 regex 属性和 setFieldValue 方法。

Suggested labels

size/XL

Suggested reviewers

  • irisSong

🐰 在草地上跳跃,代码更新如春风,
表单组件新生,功能更强更灵动。
样式焕然一新,布局更显美观,
让我们一起欢庆,代码的每一次变换! 🌼✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Outside diff range and nitpick comments (3)
src/packages/formitem/formitem.scss (1)

68-68: 建议移除不必要的空行

第 68 行的空行是不必要的,建议移除以提高代码的简洁性。

- 
src/packages/formitem/formitem.taro.tsx (2)

61-62: 类型更新很好,但请尝试解决潜在的类型问题。

context 属性声明更新为使用 React.ContextType<typeof Context>,提供了更好的类型信息。但是,需要使用 @ts-ignore 注释来抑制 TypeScript 错误,这表明代码库中可能存在类型不匹配或过时的类型定义。

建议调查并解决潜在的类型问题,以消除对忽略注释的需要,提高代码的类型安全性。


268-268: 请删除调试代码。

这行 console log 语句似乎是遗留的调试代码,应该删除。

-console.log('testtest', child)
Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 3a8018b and 9b16b55.

Files ignored due to path filters (1)
  • packages/nutui-taro-demo/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
Files selected for processing (15)
  • packages/nutui-taro-demo/package.json (2 hunks)
  • scripts/rn/copy-file.js (1 hunks)
  • src/config.json (2 hunks)
  • src/packages/form/demo.taro.tsx (3 hunks)
  • src/packages/form/demos/taro/demo1.tsx (3 hunks)
  • src/packages/form/demos/taro/demo2.tsx (2 hunks)
  • src/packages/form/demos/taro/demo4.tsx (2 hunks)
  • src/packages/form/form.harmony.css (1 hunks)
  • src/packages/form/form.scss (0 hunks)
  • src/packages/form/form.taro.tsx (3 hunks)
  • src/packages/form/form.tsx (1 hunks)
  • src/packages/formitem/formitem.harmony.css (3 hunks)
  • src/packages/formitem/formitem.scss (4 hunks)
  • src/packages/formitem/formitem.taro.tsx (9 hunks)
  • src/packages/formitem/formitem.tsx (7 hunks)
Files not reviewed due to no reviewable changes (1)
  • src/packages/form/form.scss
Additional context used
Biome
src/packages/formitem/formitem.tsx

[error] 236-238: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/packages/formitem/formitem.taro.tsx

[error] 240-242: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

Additional comments not posted (71)
src/packages/form/demos/taro/demo1.tsx (2)

50-54: 看起来不错!

TextArea 组件添加内联样式以调整其内边距的方式是合理的。这有助于改善文本区域的视觉呈现。


Line range hint 1-60: 请确认是否有意删除 InputNumber 组件。

InputNumber 组件已从表单中完全删除。虽然这简化了表单结构,但不清楚该删除是否符合表单的要求和 PR 的目标。

请验证删除 InputNumber 组件是否是有意的,并确保它与表单的整体要求保持一致。如果删除是无意的,请考虑恢复该组件。

scripts/rn/copy-file.js (1)

35-35: 看起来不错!

'formitem' 添加到 childAdaptedArray 数组中是合理的,这表明 formitem 组件现在被视为一个子组件。这个改动很小,不会引入任何问题。

src/packages/form/demos/taro/demo4.tsx (3)

10-10: 看起来不错!

导入 pxTransform 工具函数的语句写法正确。这个函数可能用于将像素值转换为响应式格式,有助于提高布局的适应性。


45-45: 很好的改进!

将容器的 flexDirection 样式显式设置为 'row',可以确保按钮水平对齐。这个改动增强了表单组件的布局一致性。


52-52: 非常棒的优化!

将重置按钮的 marginLeft 样式中硬编码的 '20px' 像素值替换为由 pxTransform(20) 生成的动态值,使布局更具响应性。这个改动提高了表单组件在不同屏幕尺寸下的适应性。

src/packages/form/demo.taro.tsx (6)

3-3: 导入正确

@tarojs/components 导入 Text 组件是正确且必要的,以便在文件后面使用 Text 组件。


13-13: 导入正确

@/utils/platform-taro 导入 harmonyAndRn 工具函数是正确且必要的,以便在文件后面根据平台有条件地渲染某些组件。


41-43: 改进文本处理

将翻译后的文本用 Text 组件包裹可以改进文本处理,是一个很好的实践。类名 "h2" 适合用于标题。


47-52: 根据平台有条件地渲染

通过 harmonyAndRn 函数判断当前环境是否为 Harmony 或 React Native,有条件地渲染 Demo3 组件,可以确保 Demo3 组件只在适当的环境中显示。这增强了组件对不同平台的适应性。


55-60: 根据平台有条件地渲染

与前面的代码段类似,通过 harmonyAndRn 函数判断当前环境是否为 Harmony 或 React Native,有条件地渲染 Demo5 组件,可以确保 Demo5 组件只在适当的环境中显示。这增强了组件对不同平台的适应性。


64-69: 根据平台有条件地渲染

与前面的代码段类似,通过 harmonyAndRn 函数判断当前环境是否为 Harmony 或 React Native,有条件地渲染 Demo7 组件,可以确保 Demo7 组件只在适当的环境中显示。这增强了组件对不同平台的适应性。

src/packages/form/demos/taro/demo2.tsx (3)

3-3: 修改合理

<div> 元素替换为 Taro 框架中的 <View> 组件是合适的,因为在 Taro 中,<View> 是推荐用于布局的组件。


10-10: 引入工具函数

@/utils/px-transform 导入 pxTransform 工具函数的语句写法正确。pxTransform 函数可能用于将像素转换为响应式单位,这是响应式设计的良好实践。


43-57: 优化表单页脚的布局和样式

这部分的修改优化了表单页脚的布局和样式:

  1. <div> 元素替换为 Taro 框架中的 <View> 组件,更适合 Taro 的渲染上下文。
  2. 在页脚中添加了 flexDirection: 'row' 样式,确保按钮水平排列。
  3. 使用 pxTransform 工具函数调整重置按钮的 marginLeft 样式,以实现一致的像素到 rpx 的转换,提高了不同屏幕尺寸下的响应性。

这些修改改善了组件的视觉结构和可维护性,而没有改变其核心功能。

src/packages/form/form.tsx (1)

99-101: 代码修改没有问题!

labelPosition 添加到 Context.Provider 的 value 中,可以让子组件通过 context 访问到标签的位置信息。这增强了 Form 组件的灵活性,使子组件能够根据标签位置来调整渲染或行为。

src/packages/form/form.taro.tsx (5)

2-2: 使用 Taro 特定的 Form 组件

@tarojs/components 导入 Form 组件并将其重命名为 TForm,以使用 Taro 特定的 Form 组件而不是标准的 HTML <form> 元素。这一改变增强了与 Taro 框架的兼容性,有助于构建跨平台应用。


81-81: 使用 Taro 特定的 <TForm> 组件

将标准的 HTML <form> 元素替换为 Taro 特定的 <TForm> 组件,这与第 2 行的导入更改一致。使用 Taro 特定的 <TForm> 组件可以增强与 Taro 框架的兼容性。


100-100: Context.Provider 提供额外的上下文

修改提供给 Context.Provider 的上下文,以包含 formInstancelabelPosition。这一改变允许使用该上下文的子组件访问表单实例和标签位置。提供额外的上下文可以根据表单内标签的位置实现更动态的行为或样式。


101-102: 使用更新后的 Context.Provider 包装 children 属性

children 属性用更新后的 Context.Provider 包装起来。这一改变是为了向子组件提供更新后的上下文。包装 children 属性可以确保任何子组件都能从上下文中访问到 formInstancelabelPosition


107-107: 关闭 <TForm> 组件

关闭 <TForm> 组件以匹配第 81 行的开始标签。关闭 <TForm> 组件可以确保 JSX 的正确语法和结构。

src/packages/formitem/formitem.scss (11)

5-11: 代码没问题!

使用 flexbox 来控制表单项标签的布局是正确的做法。代码修改看起来没有问题。


16-19: 新增的必填标签样式 LGTM!

.nut-form-item-label-required 类正确设置了必填标签的颜色和右边距。代码修改没有问题。


20-23: 请说明 .nut-form-item-labeltxt 类的用途

新增的 .nut-form-item-labeltxt 类设置了非常小的字体大小(12px)和高度(10px),可能会影响可读性。请说明一下这个类的具体用途,以及为什么要设置这么小的尺寸。


26-27: 代码没问题!

使用 flexbox 并将 flex-direction 设置为 column,可以正确控制表单项主体的纵向布局。代码修改看起来没有问题。


53-53: 为什么要移除 textarea 的 padding?

.nut-textarea 的 padding 设置为 0 可能会影响其视觉效果和可用性。请说明一下移除 padding 的具体原因。


102-109: 新增的右对齐标签样式 LGTM!

.nut-form-item-label-right 类正确使用了 flexbox 的 justify-content 属性和 padding-right 将标签靠右对齐。代码修改没有问题。


111-115: 新增的左对齐标签样式 LGTM!

.nut-form-item-label-left 类正确使用了 relative 定位和 padding-left 将标签靠左对齐。代码修改没有问题。


117-122: 新增的左对齐必填标记样式 LGTM!

.nut-form-item-label-left-required 类正确使用了 absolute 定位将必填标记定位在左对齐标签的左侧。代码修改没有问题。


124-128: 新增的垂直布局样式 LGTM!

.nut-form-item-top 类正确使用了 flexbox 的 flex-direction 和 align-items 属性将标签和主体垂直堆叠。代码修改没有问题。


130-134: 新增的顶部对齐标签样式 LGTM!

.nut-form-item-label-top 类正确设置了 display、padding-bottom 和 padding-right 属性来样式化顶部对齐的标签。代码修改没有问题。


136-139: 新增的顶部对齐主体样式 LGTM!

.nut-form-item-body-top 类正确重置了 margin-left 为 0 并将 width 设置为 100%,以适应顶部对齐的表单项主体。代码修改没有问题。

src/packages/formitem/formitem.harmony.css (14)

5-6: 代码看起来不错!

使用 flexbox 布局和 row 方向可以改善标签的布局行为。


11-11: 代码看起来不错!

将 flex 属性设置为 0 0 auto,可以防止标签增大或缩小,同时允许它采用其固有宽度。这改善了标签的布局行为。


13-13: 代码看起来不错!

将文本对齐方式设置为左对齐,可以提高多方向布局的一致性。


15-18: 代码看起来不错!

为必填标签引入专门的样式类,可以简化结构并增强可读性。


19-22: 代码看起来不错!

为标签文本设置字体大小和高度,可以改善标签文本的视觉层次结构和对齐方式。


25-27: 代码看起来不错!

使用 flexbox 布局和 column 方向可以改善表单项主体的布局行为。


29-29: 代码看起来不错!

将表单项主体插槽的文本对齐方式设置为左对齐,可以提高多方向布局的一致性。


37-38: 代码看起来不错!

将输入文本的对齐方式设置为左对齐,并设置颜色,可以提高多方向布局的一致性和视觉层次结构。


49-49: 代码看起来不错!

为文本区域删除内边距,可以改善表单项主体插槽内文本区域的布局一致性。


53-53: 代码看起来不错!

将文本区域的文本对齐方式设置为左对齐,可以提高多方向布局的一致性。


56-58: 代码看起来不错!

将表单项主体提示的文本对齐方式设置为左对齐,并设置颜色,可以提高多方向布局的一致性和错误状态的视觉层次结构。


62-65: 代码看起来不错!

为从右到左 (RTL) 布局中的表单项标签调整文本对齐方式和边距,可以确保标签在 RTL 上下文中正确对齐。


68-71: 代码看起来不错!

使用 .nut-rtl 类为从右到左 (RTL) 布局中的表单项标签调整文本对齐方式和边距,可以确保标签在 RTL 上下文中正确对齐。


80-168: 代码看起来不错!

引入新的布局类来支持不同的标签放置方式和 RTL 布局,可以增强表单项组件对各种布局要求的灵活性和适应性。

packages/nutui-taro-demo/package.json (2)

78-78: 依赖添加没有问题!

添加 async-validator 依赖是一个有效的改动,版本指定也允许在主版本号 4 的基础上进行次版本号和修订号的更新,没有引入任何问题。


115-115: 格式更新,没有功能影响。

sass 依赖解析的改动只是格式上的调整,并没有修改版本号,因此不会产生任何功能上的影响。

src/packages/form/form.harmony.css (4)

1-27: 代码看起来不错!

新增的 .nut-cell-group.nut-cell-group-title.nut-cell-group-description.nut-cell-group-wrap 类的样式定义合理,为单元格组元素提供了一致的样式。


57-143: 单元格组件的样式定义全面且合理。

新增的 .nut-cell.nut-cell-group-item.nut-cell-left.nut-cell-title.nut-cell-description.nut-cell-extra.nut-cell-clickable.nut-cell-divider 类的样式定义全面,确保了单元格组件的一致性和视觉吸引力。样式结构良好,涵盖了单元格组件的各个方面。


145-245: 表单项组件的样式定义结构良好且全面。

新增的 .nut-form-item.nut-form-item-label.nut-form-item-label-required.nut-form-item-body.nut-form-item-body-slots.nut-form-item-body-tips 类的样式定义结构清晰,为表单项组件提供了全面的样式。这些样式确保了表单项在不同方向(LTR 和 RTL)下的一致布局和外观。


Line range hint 248-314: 表单项标签定位的样式定义灵活且全面。

新增的 .nut-form-item-label-right.nut-form-item-label-left.nut-form-item-label-left-required.nut-form-item-top.nut-form-item-label-top.nut-form-item-body-top 类的样式定义提供了灵活且全面的表单项标签定位方式。这些样式涵盖了各种标签位置(右、左和顶部),并确保了正确的对齐和间距。每个位置的 RTL 支持也得到了正确处理。

src/packages/formitem/formitem.tsx (11)

60-60: 变更看起来不错!

使用明确赋值断言表明 context 会在使用前被赋值,这在语法上是正确的。请确保在使用 context 之前,它确实已经被赋值,以避免运行时错误。


78-79: 看起来很棒!

this.context.formInstance.getInternal(SECRET) 中解构 storesetInitialValues 属性,与更新后的上下文结构保持一致。为 store 设置默认值 {} 是一个很好的做法,可以处理 store 可能为 undefined 的情况。


91-92: 变更看起来不错!

this.context.formInstance.getInternal(SECRET) 中获取 registerFieldregisterUpdate 方法,与更新后的上下文结构保持一致。这个变更没有引入任何新逻辑或改变现有行为。


109-110: 看起来很棒!

直接从 this.context.formInstance 获取 setFieldsValuegetFieldValue 方法,同时从 this.context.formInstance.getInternal(SECRET) 获取 dispatch 方法,与更新后的上下文结构保持一致。将 setFieldsValuegetFieldValue 直接从 this.context.formInstance 访问,似乎是一个有意的改变,可能是因为这些方法现在直接在 formInstance 上公开。


184-184: 变更看起来不错!

直接从 this.context.formInstance 访问 errors 属性,与更新后的上下文结构保持一致。将 errors 直接从 this.context.formInstance 访问,似乎是一个有意的改变,可能是因为这个属性现在直接在 formInstance 上公开。


191-196: 新增的方法看起来很棒!

getClassNameWithDirection 方法根据表单上下文中配置的 labelPosition,生成相应的类名。它通过考虑标签位置来增强组件的样式功能。这个方法的逻辑很简单,不会引入任何潜在问题。


214-214: 看起来很棒!

直接从 this.context.formInstance 访问 errors 属性,与更新后的上下文结构保持一致。将 errors 直接从 this.context.formInstance 访问,似乎是一个有意的改变,可能是因为这个属性现在直接在 formInstance 上公开。


216-218: 变更看起来不错!

直接从 this.context.formInstance 访问 starPosition 属性,与更新后的上下文结构保持一致。将 starPosition 直接从 this.context.formInstance 访问,似乎是一个有意的改变,可能是因为这个属性现在直接在 formInstance 上公开。根据 required 属性或是否存在 required 规则来渲染星号元素的逻辑很简单,不会引入任何潜在问题。


223-223: 看起来很棒!

这个变更渲染了一个具有 nut-form-item-labeltxt 类的 span 元素,并将 label 属性作为其内容。它没有引入任何新逻辑或改变现有行为,只是对渲染的标签元素进行了小幅更新。


229-245: 变更看起来不错!

这个变更利用新引入的 getClassNameWithDirection 方法,根据 labelPosition 生成 nut-form-itemnut-form-item-labelnut-form-item-body 元素的类名。它通过考虑标签位置来增强组件的样式功能。getClassNameWithDirection 在相关元素中的使用是一致的。

Tools
Biome

[error] 236-238: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


270-270: 看起来很棒!

这个变更将 this.context.formInstance 作为参数调用 children 函数,与更新后的上下文结构保持一致。将 this.context.formInstance 传递给 children 函数,允许子组件直接访问表单实例。

src/packages/formitem/formitem.taro.tsx (6)

59-59: 修改看起来不错!

contextType 静态属性更新为直接使用 Context,提高了类型安全性。


80-81: 很好的重构!

将上下文访问更新为使用 formInstance,封装了内部方法和属性。这提高了可维护性,减少了与上下文结构的直接耦合。

变更是一致的,没有引入任何问题。

Also applies to: 93-94


111-112: 很好的改进!

getControlledonStoreChange 方法的更改与使用 formInstance 的更新上下文访问模式一致。

新的 getClassNameWithDirection 方法根据上下文中的 labelPosition 调整布局,提高了组件的灵活性。

这些更改增强了组件与表单上下文的集成,没有引入任何问题。

Also applies to: 122-122, 188-188, 195-200


218-218: 渲染逻辑的改进很好!

使用 getClassNameWithDirection 方法根据上下文动态调整类名,提高了组件布局的适应性。

引入 Text 组件增强了必填指示器的语义结构。

renderLayout 方法的重构是合理的,没有引入任何问题。

Also applies to: 220-222, 227-227, 233-233, 241-243, 247-249


276-276: 条件渲染看起来不错。

基于 shouldUpdate 属性的条件渲染似乎是合理的,没有引起任何问题。


240-242: 可以跳过静态分析提示。

当前的代码检查 label 是否为真值,然后有条件地渲染标签内容。这是安全的,不需要可选链。

在这种情况下,静态分析提示是一个误报。

Tools
Biome

[error] 240-242: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/config.json (2)

495-495: 重大版本更新:请验证文档和用法是否已更新。

"Form"组件的版本已从"2.0.0"更改为"3.0.0",这表示该组件进行了重大更新。

请确保:

  1. "Form"组件的文档已更新,以反映新版本中的更改。
  2. 代码库中"Form"组件的用法已更新,以匹配新版本。

506-506: 重大版本更新:请验证文档和用法是否已更新。

"FormItem"组件的版本已从"2.0.0"更改为"3.0.0",这表示该组件进行了重大更新。

请确保:

  1. "FormItem"组件的文档已更新,以反映新版本中的更改。
  2. 代码库中"FormItem"组件的用法已更新,以匹配新版本。

src/packages/form/demos/taro/demo1.tsx Outdated Show resolved Hide resolved
src/packages/form/form.harmony.css Show resolved Hide resolved
@oasis-cloud oasis-cloud added the 3.x label Nov 1, 2024
@oasis-cloud oasis-cloud changed the base branch from dev-harmony to V3.0 November 4, 2024 07:57
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (9)
scripts/rn/copy-file.js (3)

Line range hint 1-91: 建议增强脚本的健壮性和可维护性

当前脚本在处理组件适配时有以下几点可以改进:

  1. 版本号硬编码('3.0.0')可能导致维护困难
  2. 文件操作缺少适当的错误恢复机制
  3. 缺少对文件路径有效性的检查

建议进行以下优化:

 const config = require('../../src/config.json')
+const SUPPORTED_VERSION = '3.0.0'
+
+const validatePaths = (paths) => {
+  return paths.every(p => fse.existsSync(p))
+}
+
+const handleError = (err, operation) => {
+  console.error(`Error during ${operation}:`, err)
+  process.exit(1)
+}

 // 已适配组件对象
 const adaptedArray = []
 config.nav.map((item) => {
   item.packages.forEach((element) => {
     const { name, version } = element
-    if (version !== '3.0.0') return // 未适配不导出
+    if (version !== SUPPORTED_VERSION) return // 未适配不导出
     adaptedArray.push({
       ...element,
       lowercaseName: element.name.toLowerCase(),
       enName: item.enName,
     })
   })
 })

 const copyFile = async (from, to, success, isSingle = false) => {
+  if (!validatePaths([from])) {
+    handleError(new Error(`Source path ${from} does not exist`), 'validation')
+    return
+  }
   fse.copy(from, to, function (err) {
     if (err) {
-      console.error('An error occurred while copying the directory.', err)
-      return
+      handleError(err, 'copy')
+      return
     }
     // ... rest of the function
   })
 }

Line range hint 1-91: 建议添加配置文件验证

为了确保配置文件的正确性,建议添加配置验证机制。

建议添加以下验证逻辑:

+const validateConfig = (config) => {
+  if (!config.nav || !Array.isArray(config.nav)) {
+    throw new Error('配置文件格式错误:缺少 nav 数组')
+  }
+  
+  config.nav.forEach((item, index) => {
+    if (!item.packages || !Array.isArray(item.packages)) {
+      throw new Error(`配置文件格式错误:nav[${index}] 缺少 packages 数组`)
+    }
+  })
+}

 const config = require('../../src/config.json')
+validateConfig(config)

Line range hint 1-91: 建议优化日志输出

当前的日志输出不够结构化,建议改进日志格式以便于调试和监控。

建议添加以下日志工具:

+const logger = {
+  info: (msg, data) => console.log(`[INFO] ${msg}`, data || ''),
+  error: (msg, err) => console.error(`[ERROR] ${msg}`, err || ''),
+  success: (msg, data) => console.log(`[SUCCESS] ${msg}`, data || '')
+}

 const copyFile = async (from, to, success, isSingle = false) => {
   fse.copy(from, to, function (err) {
     if (err) {
-      console.error('An error occurred while copying the directory.', err)
+      logger.error('复制目录失败', err)
       return
     }
-    console.log(`${success}!>`, to)
+    logger.success(success, to)
     // ... rest of the function
   })
 }
src/packages/formitem/formitem.taro.tsx (5)

Line range hint 80-94: 组件注册逻辑优化建议

建议将注册相关的逻辑抽取到单独的方法中,提高代码可维护性。同时,建议添加错误处理机制。

+ private registerFormField() {
+   try {
+     const { store = {}, setInitialValues, registerField, registerUpdate } =
+       this.context.formInstance.getInternal(SECRET)
+     
+     if (
+       this.props.initialValue &&
+       this.props.name &&
+       !Object.keys(store).includes(this.props.name)
+     ) {
+       setInitialValues(
+         { ...store, [this.props.name]: this.props.initialValue },
+         true
+       )
+     }
+     
+     this.cancelRegister = registerField(this)
+     this.eventOff = registerUpdate(this, this.props.shouldUpdate)
+   } catch (error) {
+     console.error('表单字段注册失败:', error)
+   }
+ }

111-112: 简化上下文访问

建议使用解构赋值简化代码,提高可读性。

- const { setFieldsValue, getFieldValue } = this.context.formInstance
- const { dispatch } = this.context.formInstance.getInternal(SECRET)
+ const { formInstance } = this.context
+ const { setFieldsValue, getFieldValue } = formInstance
+ const { dispatch } = formInstance.getInternal(SECRET)

195-200: 方向类名处理优化

建议添加空值检查并使用模板字符串简化代码。

getClassNameWithDirection(className: string) {
-  if (className && this.context.labelPosition) {
-    return `${className} ${className}-${this.context.labelPosition}`
-  }
-  return className
+  const { labelPosition } = this.context
+  return className && labelPosition
+    ? `${className} ${className}-${labelPosition}`
+    : className
}

241-243: 优化条件渲染

建议使用可选链操作符来简化代码。

- <View
-   className={`nut-cell-title ${this.getClassNameWithDirection('nut-form-item-label')}`}
- >
+ <View
+   className={`nut-cell-title ${this.getClassNameWithDirection?.('nut-form-item-label') ?? ''}`}
+ >

247-249: 表单项样式适配建议

考虑到多端适配的需求,建议为不同平台添加特定的样式类名。

建议添加平台特定的类名,例如:

getClassNameWithPlatform(className: string) {
  const platform = process.env.TARO_ENV
  return `${className} ${className}-${platform}`
}

然后在样式中处理不同平台的特殊情况:

.nut-form-item-body-rn {
  /* RN 特定样式 */
}
.nut-form-item-body-harmony {
  /* HarmonyOS 特定样式 */
}
src/config.json (1)

Line range hint 518-565: 新增表单相关组件完善了多端适配方案

新增的 Input、InputNumber、Range、Switch、TextArea 等组件都采用 3.0.0 版本,这些组件的添加完善了表单系统,使其更好地支持多平台场景。建议:

  1. 确保这些新组件在 React Native 和 HarmonyOS 上都经过充分测试
  2. 考虑为这些组件添加平台特定的样式降级方案
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 9b16b55 and 737de11.

📒 Files selected for processing (4)
  • scripts/rn/copy-file.js (1 hunks)
  • src/config.json (2 hunks)
  • src/packages/form/demos/taro/demo1.tsx (3 hunks)
  • src/packages/formitem/formitem.taro.tsx (9 hunks)
🧰 Additional context used
🪛 Biome
src/packages/formitem/formitem.taro.tsx

[error] 240-242: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (4)
src/packages/form/demos/taro/demo1.tsx (2)

2-2: 导入语句的清理看起来不错!

移除未使用的 InputNumber 组件导入,使代码更加简洁。


50-54: 请验证 TextArea 在多端的样式表现

虽然添加了 paddingToppaddingBottom 的样式调整,但建议:

  1. 确认这些样式在 React Native 和 HarmonyOS 上是否正常工作
  2. 验证是否需要添加其他样式属性来确保跨平台的一致性

运行以下脚本来检查是否有其他相关的样式适配:

scripts/rn/copy-file.js (1)

35-35: 新增 formitem 子组件适配支持

'formitem' 的添加符合多端适配的需求,确保表单项组件能够正确处理样式文件。

src/config.json (1)

Line range hint 495-517: 版本升级变更符合多端适配需求

Form 和 FormItem 组件从 2.0.0 升级到 3.0.0 的变更与 PR 的多端适配目标相符,这将有助于解决 React Native 和 HarmonyOS 中的样式选择器限制问题。

✅ Verification successful

Form组件版本升级变更已确认安全

根据代码库搜索结果,Form组件升级到3.0.0版本是独立且完整的变更,没有发现其他配置文件引用旧版本,也未发现潜在的版本冲突。此次版本升级符合多端适配的需求。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查是否有其他配置文件引用了旧版本的 Form 组件
rg -l "\"version\":\s*\"2\.0\.0\".*\"Form\"" 

Length of output: 40


Script:

#!/bin/bash
# 使用更宽松的搜索模式查找所有 Form 相关的配置
rg -i "form.*version" --type json

# 检查其他可能包含版本信息的配置文件
fd -e json -x cat {} | grep -i "form"

# 查找可能的组件引用
rg -i "form.*component" --type json

Length of output: 2515


Script:

#!/bin/bash
# 查找所有包含 Form 组件配置的文件
rg -A 5 -B 5 '"name":\s*"Form"' --type json

# 检查组件版本历史
git log -p -- src/config.json | grep -A 10 -B 10 '"version".*"Form"'

# 查找相关的组件引用关系
rg -A 3 "import.*Form" --type ts --type tsx --type jsx

Length of output: 570

src/packages/formitem/formitem.taro.tsx Outdated Show resolved Hide resolved
src/packages/formitem/formitem.taro.tsx Outdated Show resolved Hide resolved
Copy link

codecov bot commented Nov 5, 2024

Codecov Report

Attention: Patch coverage is 98.07692% with 2 lines in your changes missing coverage. Please review.

Project coverage is 83.95%. Comparing base (6341c78) to head (a2c1d07).
Report is 1 commits behind head on V3.0.

Files with missing lines Patch % Lines
src/packages/formitem/formitem.tsx 95.55% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             V3.0    #2595   +/-   ##
=======================================
  Coverage   83.95%   83.95%           
=======================================
  Files         221      221           
  Lines       17849    17849           
  Branches     2679     2679           
=======================================
  Hits        14986    14986           
  Misses       2858     2858           
  Partials        5        5           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (16)
src/utils/merge.ts (3)

8-10: 数组合并策略需要重新考虑。

当前实现直接覆盖数组,这可能不是所有场景下的最佳选择。建议考虑提供数组合并策略选项。

建议添加合并策略参数:

+interface MergeOptions {
+  arrayMergeStrategy?: 'replace' | 'concat' | 'unique';
+}
+
-export function merge<T extends object>(...objects: (T | null | undefined)[]): T {
+export function merge<T extends object>(
+  options: MergeOptions = {},
+  ...objects: (T | null | undefined)[]
+): T {
   // ...
   if (Array.isArray(value)) {
-    result[key] = [...value]
+    switch (options.arrayMergeStrategy) {
+      case 'concat':
+        result[key] = result[key] ? [...result[key], ...value] : [...value];
+        break;
+      case 'unique':
+        result[key] = result[key] 
+          ? [...new Set([...result[key], ...value])]
+          : [...value];
+        break;
+      default:
+        result[key] = [...value];
+    }
   }

26-28: 建议添加性能优化。

对于大量对象的合并操作,当前实现可能存在性能问题。建议添加缓存机制并优化过滤逻辑。

建议修改如下:

-  objects.filter((obj) => !!obj).forEach((obj) => mergeHelper(obj))
+  const validObjects = objects.filter(Boolean)
+  if (validObjects.length === 0) return result
+  if (validObjects.length === 1) return { ...validObjects[0] }
+  
+  validObjects.forEach((obj) => mergeHelper(obj))

1-29: 请添加单元测试覆盖边界情况。

建议添加完整的单元测试,覆盖以下场景:

  • 空对象合并
  • 数组合并
  • 循环引用
  • 深层嵌套对象
  • 不同类型值的合并

需要我帮您生成相应的单元测试代码吗?

src/packages/form/form.tsx (1)

102-104: Context 数据结构调整建议

将 formInstance、labelPosition 和 disabled 组合成对象传递给 Context.Provider 是个好的改进,但建议考虑以下几点:

  1. 考虑添加 TypeScript 类型定义来约束 Context 值的结构
  2. 建议在组件内部添加相关文档注释,说明 Context 值的用途
+// 定义 Context 值的类型
+interface FormContextValue {
+  formInstance: FormInstance;
+  labelPosition: 'top' | 'left' | 'right';
+  disabled: boolean;
+}

+// Form 组件的 Context,用于向子组件传递表单状态
 <Context.Provider value={{ formInstance, labelPosition, disabled }}>
   {children}
 </Context.Provider>
src/packages/form/form.taro.tsx (2)

Line range hint 84-99: 建议优化事件处理逻辑

当前的事件处理实现是正确的,但可以进行小幅优化以提高代码可维护性。

建议将事件处理函数提取为独立的方法:

+  const handleSubmit = (e) => {
+    e.preventDefault()
+    e.stopPropagation()
+    submit()
+  }
+
+  const handleReset = (e) => {
+    e.preventDefault()
+    e.stopPropagation()
+    resetFields()
+  }
+
   return (
     <TForm
       className={classNames(classPrefix, PositionInfo[labelPosition], className)}
       style={style}
-      onSubmit={(e) => {
-        e.preventDefault()
-        e.stopPropagation()
-        submit()
-      }}
-      onReset={(e) => {
-        e.preventDefault()
-        e.stopPropagation()
-        resetFields()
-      }}
+      onSubmit={handleSubmit}
+      onReset={handleReset}
     >

Line range hint 1-112: 建议考虑更明确的多端适配策略

当前的实现通过使用 Taro 组件实现了多端适配,这是一个好的开始。不过,建议考虑以下几点来增强多端适配的可维护性:

  1. 考虑添加平台特定的样式文件,便于处理不同平台的样式差异
  2. 可以考虑使用 HOC 或自定义 hooks 来封装平台特定的逻辑
  3. 建议添加平台特定的单元测试用例

这些改进可以让多端适配的代码更容易维护和扩展。

src/packages/formitem/formitem.scss (3)

Line range hint 31-58: 建议优化输入框在不同平台的样式兼容性

当前实现存在以下可优化点:

  • 移除内边距可能导致在某些平台上触摸区域过小
  • 文本域样式可能需要针对 RN 和 HarmonyOS 做特殊处理

建议添加以下平台特定样式:

.nut-textarea {
  .nut-textarea-textarea {
    #ifdef RN
    padding: 8px;
    min-height: 24px;
    #endif
    
    #ifdef HARMONY
    padding: 6px;
    min-height: 20px;
    #endif
  }
}

Line range hint 73-106: 建议补充 RTL 支持的使用说明

RTL 支持的实现非常完整,建议:

  • 在组件文档中添加 RTL 支持的使用说明
  • 补充示例代码展示如何在不同平台启用 RTL

建议在组件文档中添加如下说明:

## RTL 支持

FormItem 组件支持 RTL(从右到左)布局:

- React Native:通过设置 `dir="rtl"` 启用
- HarmonyOS:通过 CSS 类 `.nut-rtl` 启用

110-175: 建议优化位置相关样式的代码组织

当前实现功能完整,但代码组织可以更清晰:

  1. 建议将位置相关样式按功能分组:
    • 标准布局样式
    • RTL 适配样式
    • 响应式布局样式

建议重构为以下结构:

// 布局基础样式
.nut-form-item {
  &-label {
    &-right { ... }
    &-left { ... }
    &-top { ... }
  }
}

// RTL 适配
[dir='rtl'], .nut-rtl {
  .form-layout {
    &-right { ... }
    &-left { ... }
    &-top { ... }
  }
}
src/packages/form/useform.taro.ts (2)

88-93: 优化 setInitialValues 方法但需要移除调试代码

使用 merge 函数来处理初始值的更新是个很好的改进,但是需要移除第 93 行的 console.log 语句。

建议应用以下修改:

  setInitialValues = (initialValues: Store, init: boolean) => {
    this.initialValues = initialValues || {}
    if (init) {
      const nextStore = merge(initialValues, this.store)
      this.updateStore(nextStore)
-     console.log(this.store === this.initialValues)
    }
  }

193-195: 优化 resetFields 但需要移除调试代码

使用 merge 来创建初始值的副本是个好做法,但需要移除第 194 行的 console.log 语句。

建议应用以下修改:

    const nextStore = merge({}, this.initialValues)
-   console.log('xxx', nextStore, this.initialValues)
    this.updateStore(nextStore)
src/packages/form/useform.ts (3)

3-3: 优化:Store 管理逻辑改进

代码重构提升了可维护性:

  1. 引入 merge 工具函数确保了数据不可变性
  2. 新增 updateStore 方法统一了状态更新逻辑
  3. setInitialValues 和 setFieldsValue 方法现在通过 merge 来更新状态

建议进一步改进:

  updateStore(nextStore: Store) {
+   // 添加状态变更的订阅机制,便于后续扩展(如:状态追踪、性能分析等)
    this.store = nextStore
  }

Also applies to: 78-80, 88-92, 100-102


192-193: 建议:重置逻辑可以优化

当前实现存在以下可以改进的地方:

  1. errors 的重置使用 length = 0 不够优雅
  2. 缺少重置状态的事件通知机制
  resetFields = () => {
-   this.errors.length = 0
+   this.errors = {}
    const nextStore = merge({}, this.initialValues)
    this.updateStore(nextStore)
+   // 触发重置事件,便于上层组件感知状态变化
+   this.callbacks.onReset?.(nextStore)
    this.fieldEntities.forEach((entity: FormFieldEntity) => {
      entity.onStoreChange('reset')
    })
  }

7-7: 建议:类型定义可以更严格

虽然添加了 FormInstance 类型,但还可以进一步改进类型安全性:

- return [formRef.current as FormInstance]
+ return [formRef.current!] // 使用非空断言,因为我们确定这里一定有值

建议:

  1. 考虑为 Store 类型添加泛型支持
  2. 为回调函数添加更具体的类型定义

Also applies to: 9-9, 251-251

src/packages/formitem/formitem.taro.tsx (2)

61-61: 建议改进类型安全性

虽然使用 ! 操作符可以解决类型检查问题,但建议通过以下方式提供更好的类型安全性:

  1. 在构造函数中验证 context
  2. 使用可选链操作符来安全访问 context
- context!: React.ContextType<typeof Context>
+ context: React.ContextType<typeof Context>

  constructor(props: FormItemProps) {
    super(props)
+   if (!this.context?.formInstance) {
+     throw new Error('FormItem must be used within Form')
+   }
    this.componentRef = React.createRef()
    this.state = {
      resetCount: 1,
    }
  }

Also applies to: 79-80


194-199: 建议增强无障碍性支持

当前的多端适配改动很好,建议进一步增强无障碍性支持:

  1. 为表单项添加 ARIA 属性
  2. 确保错误消息能被屏幕阅读器正确读取
  3. 在禁用状态下提供视觉反馈
 <View
-  className={this.context.disabled ? 'nut-form-item-disabled' : ''}
+  className={this.context.disabled ? 'nut-form-item-disabled' : ''}
+  aria-disabled={this.context.disabled}
+  role="group"
+  aria-label={this.props.label}
   catchMove={this.context.disabled}
 >

Also applies to: 279-286

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 737de11 and 145ea65.

📒 Files selected for processing (8)
  • src/packages/form/form.taro.tsx (6 hunks)
  • src/packages/form/form.tsx (4 hunks)
  • src/packages/form/useform.taro.ts (5 hunks)
  • src/packages/form/useform.ts (5 hunks)
  • src/packages/formitem/formitem.scss (4 hunks)
  • src/packages/formitem/formitem.taro.tsx (10 hunks)
  • src/packages/formitem/formitem.tsx (9 hunks)
  • src/utils/merge.ts (1 hunks)
🧰 Additional context used
🪛 Biome
src/packages/formitem/formitem.taro.tsx

[error] 239-241: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/packages/formitem/formitem.tsx

[error] 238-240: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (28)
src/packages/form/form.tsx (3)

14-14: 新增 disabled 属性类型定义

在 FormProps 接口中添加 disabled 布尔类型属性,用于控制表单的禁用状态,符合多端适配的需求。


26-26: 默认值设置合理

为 disabled 属性设置默认值为 false 是符合预期的,这样默认情况下表单是可交互的。


48-48: Props 解构完整性验证

从 props 中解构出 disabled 属性,建议验证一下在各端(RN、HarmonyOS)的兼容性。

✅ Verification successful

disabled 属性在各端已正确实现

根据代码分析,disabled 属性已在以下文件中得到一致的实现:

  • src/packages/form/form.tsx(Web端)
  • src/packages/form/form.taro.tsx(小程序端)

两个平台的实现完全一致,包括:

  • 在 Props 类型定义中声明 disabled: boolean
  • 默认值设置为 disabled: false
  • 通过 Context.Provider 传递给子组件
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查其他平台特定文件中是否也正确处理了 disabled 属性
rg -l "disabled.*FormProps" src/packages/form/

Length of output: 48


Script:

#!/bin/bash
# 搜索 form.tsx 相关文件
fd "form\.(tsx|ts)" src/packages/form/

# 搜索所有包含 disabled 属性的相关代码
rg "disabled" src/packages/form/ -A 2 -B 2

Length of output: 2324

src/packages/form/form.taro.tsx (2)

2-2: 导入和属性变更看起来不错!

引入 Taro 的 Form 组件替代原生 form 元素是正确的选择,这样可以更好地支持多端适配。disabled 属性的添加也很合理,包括了适当的类型定义和默认值设置。

Also applies to: 15-15, 27-27


103-105: 验证子组件的 Context 使用情况

Context 中添加了 disabled 状态,这个改动是合理的。但需要确保所有消费这个 Context 的子组件都正确处理了这个新增的状态。

运行以下脚本来验证相关组件的实现:

✅ Verification successful

Context 中的 disabled 状态已正确处理

FormItem 组件已经正确处理了 Form Context 中的 disabled 状态:

  • 在 disabled 为 true 时添加了 nut-form-item-disabled 类名
  • 设置了相应的样式(opacity: 0.4 和 pointerEvents: none)
  • 在 Taro 版本中还添加了 catchMove 属性以禁用事件
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 搜索所有使用 Form Context 的组件
rg -l "useContext.*Context.*form" src/packages/

Length of output: 49


Script:

#!/bin/bash
# 使用更广泛的搜索模式来查找 Context 的使用
rg -l "useContext.*Context" src/packages/

# 搜索可能的 Context 导入
rg "import.*Context.*from.*form" src/packages/

# 直接搜索 Context 的使用
rg "Context\.Consumer" src/packages/

# 使用 ast-grep 查找 useContext 的使用
ast-grep --pattern 'useContext($$$)'

Length of output: 3420


Script:

#!/bin/bash
# 检查 FormItem 组件中如何使用 Form Context
rg -A 5 "useContext\(Context\)" src/packages/formitem/

# 查看 Form Context 的定义
cat src/packages/form/context.ts

# 检查其他可能使用 Form Context 的文件
rg "from.*['\"]\.\.\/form\/" src/packages/

Length of output: 345


Script:

#!/bin/bash
# 修正搜索语法,检查引用 form 相关文件的组件
rg "from.*\.\./form/" src/packages/

# 检查 FormItem 组件的实现
cat src/packages/formitem/formitem.tsx
cat src/packages/formitem/formitem.taro.tsx

Length of output: 16104

src/packages/formitem/formitem.scss (1)

4-28: 表单项基础样式实现合理!

禁用状态和标签样式的实现符合最佳实践:

  • 禁用状态使用 opacity 和 pointer-events 的组合是标准做法
  • 标签布局采用 flex 布局提高了灵活性
  • 必填标记的样式清晰醒目
src/packages/form/useform.taro.ts (4)

3-3: 引入 merge 工具函数并添加统一的 store 更新方法

引入 merge 工具函数并添加 updateStore 方法是一个很好的改进,它提供了一个统一的更新 store 的入口点,增强了代码的可维护性。

Also applies to: 78-80


101-103: 改进 setFieldsValue 的实现

使用 merge 和 updateStore 的组合优化了状态更新逻辑,使代码更加清晰和可维护。


149-149: 简化错误处理逻辑

validateEntities 方法中的错误处理逻辑变得更加简洁,直接解构 errors 对象是个很好的改进。


253-253: 增强类型安全性

在 useForm 的返回值中添加类型断言提高了类型安全性,这是一个很好的改进。

src/packages/formitem/formitem.taro.tsx (1)

92-93: 注册逻辑完善

表单字段注册和清理的实现很规范,包括:

  • 正确使用 formInstance 注册字段
  • 适当的清理机制
src/packages/formitem/formitem.tsx (17)

1-1: 新增 CSSProperties 的导入

第 1 行,添加了对 CSSProperties 的导入,以支持后续代码中对样式属性的类型声明,这是合理的修改。


60-60: 使用非空断言 ! 声明 context 属性

在第 60 行,将 context 属性声明为非空断言:context!: React.ContextType<typeof Context>。请确保组件在生命周期中正确赋值 context,以避免潜在的运行时错误。


78-79: 更新对 formInstance 的访问方式

在第 78-79 行,修改了对 this.context 的访问方式,改为 this.context.formInstance.getInternal(SECRET)。请确认 formInstancecontext 中已正确初始化,以确保方法调用的可靠性。


91-92: 更新注册方法的调用

在第 91-92 行,使用 this.context.formInstance.getInternal(SECRET) 获取 registerFieldregisterUpdate 方法。请确保这些方法在 formInstance 中已正确定义。


109-110: 获取字段值和分发器时更新了对 formInstance 的引用

在第 109-110 行,直接从 this.context.formInstance 中获取 setFieldsValuegetFieldValuedispatch。这提高了代码的清晰度和可读性。


135-135: 简化 setFieldsValue 方法的调用

在第 135 行,调用 setFieldsValue 时移除了第二个参数,简化了方法调用。这使代码更加简洁。


186-186: 重置错误信息时更新了错误列表的访问

在第 186 行,修改了对错误信息的访问方式,使用 this.context.formInstance.errors,确保错误状态的正确更新。


193-198: 新增 getClassNameWithDirection 方法

在第 193-198 行,添加了 getClassNameWithDirection 方法,根据 labelPosition 动态生成类名,优化了样式管理,增强了代码的可维护性。


216-218: 调整错误信息的获取方式

在第 216 行,更改了获取错误信息的方式,使用 this.context.formInstance.errors[name] 获取对应字段的错误信息。在第 218 行,直接从 this.context.formInstance 中获取 starPosition,使代码更简洁。


220-220: 改进必填字段星号的渲染

在第 220 行,渲染必填字段的星号时,添加了 nut-form-item-label-required 类名,便于样式定制。


225-225: 优化标签文本的渲染结构

在第 225 行,使用 span 元素包裹标签文本,增加了 nut-form-item-labeltxt 类名,有利于样式的统一管理。


231-231: 使用 getClassNameWithDirection 方法统一类名

在第 231 行,调用 this.getClassNameWithDirection('nut-form-item') 方法,动态生成类名,提升了代码的可读性和一致性。


239-241: 统一标题部分的类名处理

在第 239-241 行,使用 getClassNameWithDirection 方法处理标题部分的类名,确保了组件在不同 labelPosition 下的样式一致性。


245-247: 统一内容部分的类名处理

在第 245-247 行,使用 getClassNameWithDirection 方法处理内容部分的类名,进一步强化了样式管理的统一性。


272-272: 调整 returnChildNode 的赋值逻辑

在第 272 行,当 shouldUpdatetrue 时,直接调用子组件函数,传入 this.context.formInstance。这使组件在需要更新时能够获取最新的表单实例。


274-276: 根据禁用状态设置样式

在第 274-276 行,添加了对 this.context.disabled 的判断,设置了对应的样式属性,使组件在禁用状态下表现出视觉上的差异,提升了用户体验。


279-283: 根据禁用状态调整渲染结构

在第 279-283 行,使用 this.context.disabled 判断,添加了对应的类名,并根据 noStyle 属性决定渲染内容。确保了组件在不同状态下的正确渲染。

src/utils/merge.ts Show resolved Hide resolved
src/utils/merge.ts Show resolved Hide resolved
src/packages/formitem/formitem.taro.tsx Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (9)
src/packages/form/types.ts (1)

26-26: 建议完善参数类型文档

setFieldsValue 的参数类型从 any 改进为 Store 接口是很好的改进。建议在代码注释中说明 Store 接口的使用方式,以帮助开发者正确使用。

建议添加以下注释:

+ /**
+  * 设置表单的值
+  * @param value 一个对象,key 为字段名,value 为字段值
+  */
  setFieldsValue: (value: Store) => void
src/packages/form/doc.md (1)

127-128: API 文档更新清晰且完整

新增的说明和方法有助于开发者更好地理解和使用表单实例:

  • setFieldsValue 的说明更加明确,提醒开发者注意对象修改的影响
  • 新增的 setFieldValue 方法为单个字段值的设置提供了便利

建议补充一个使用示例,以便开发者更好地理解这两个方法的区别:

// setFieldsValue 示例
form.setFieldsValue({
  username: 'nutui',
  password: '123456'
});

// setFieldValue 示例
form.setFieldValue('username', 'nutui');
src/packages/form/doc.zh-TW.md (1)

128-128: 新增的 API 使用更灵活!

新增的 setFieldValue 方法很实用,可以更精确地控制单个字段的值。建议补充一个使用示例,以便用户更好地理解。

建议添加示例代码:

| setFieldValue | 設定對應欄位名的值 | `<T>(name: NamePath, value: T) => void` |
+
+例如:
+```tsx
+// 设置单个字段的值
+form.setFieldValue('username', 'nutui');
+
+// 设置嵌套字段的值
+form.setFieldValue(['user', 'name'], 'nutui');
+```
src/packages/form/doc.taro.md (1)

127-128: API 文档更新清晰且完整

setFieldsValuesetFieldValue 的文档说明准确描述了这两个方法的用途和行为差异:

  • setFieldsValue 的补充说明有助于开发者避免对象修改带来的副作用
  • setFieldValue 作为新增方法,其描述简洁明了

建议补充一个示例代码,以便更直观地展示这两个方法的使用方式。

可以在文档中添加如下示例:

// setFieldsValue 示例
form.setFieldsValue({
  username: 'nutui',
  password: '123456'
});

// setFieldValue 示例
form.setFieldValue('username', 'nutui');
src/packages/form/useform.taro.ts (3)

78-80: 建议增强 updateStore 方法的健壮性

当前实现直接更新 store,建议添加以下增强:

  1. 添加参数类型验证
  2. 考虑添加不可变性处理
  3. 添加更新前的防御性检查

建议修改为:

  updateStore(nextStore: Store) {
+   if (!nextStore || typeof nextStore !== 'object') {
+     throw new Error('nextStore must be a valid object')
+   }
-   this.store = nextStore
+   this.store = { ...nextStore }
  }

Line range hint 100-120: 建议优化 setFieldsValue 的性能和可维护性

当前实现存在以下可优化点:

  1. 嵌套循环可能导致性能问题
  2. 更新通知逻辑较为复杂

建议重构为:

  setFieldsValue = (newStore: any) => {
    const nextStore = merge(this.store, newStore)
    this.updateStore(nextStore)
-   this.fieldEntities.forEach((entity: FormFieldEntity) => {
-     const { name } = entity.props
-     Object.keys(newStore).forEach((key) => {
-       if (key === name) {
-         entity.onStoreChange('update')
-       }
-     })
-   })
+   const updatedFields = new Set(Object.keys(newStore))
+   this.fieldEntities
+     .filter(entity => updatedFields.has(entity.props.name))
+     .forEach(entity => entity.onStoreChange('update'))

    this.updateList.forEach((item: UpdateItem) => {
      let shouldUpdate = item.condition
      if (typeof item.condition === 'function') {
        shouldUpdate = item.condition()
      }
      if (shouldUpdate) {
        item.entity.onStoreChange('update')
      }
    })
  }

199-200: 建议增强 resetFields 的错误处理

当前实现可能在 initialValues 无效时出现问题。建议添加防御性编程:

  resetFields = () => {
    this.errors.length = 0
+   if (!this.initialValues || typeof this.initialValues !== 'object') {
+     console.warn('Invalid initialValues detected during reset')
+     this.initialValues = {}
+   }
    const nextStore = merge({}, this.initialValues)
    this.updateStore(nextStore)
    this.fieldEntities.forEach((entity: FormFieldEntity) => {
      entity.onStoreChange('reset')
    })
  }
src/packages/form/useform.ts (2)

88-92: 建议:初始化逻辑可以更严谨

初始化逻辑需要考虑以下场景:

  1. initialValuesnullundefined 的处理
  2. 深层对象的合并策略

建议如下修改:

  setInitialValues = (initialValues: Store, init: boolean) => {
-   this.initialValues = initialValues || {}
+   this.initialValues = initialValues ?? {}
    if (init) {
      const nextStore = merge(initialValues, this.store)
      this.updateStore(nextStore)
    }
  }

Line range hint 100-120: 建议:优化字段更新的性能

当前实现在更新字段时会遍历所有实体,这在表单项较多时可能会影响性能。

建议优化如下:

  setFieldsValue = (newStore: any) => {
    const nextStore = merge(this.store, newStore)
    this.updateStore(nextStore)
+   const updatedFields = new Set(Object.keys(newStore))
    this.fieldEntities.forEach((entity: FormFieldEntity) => {
      const { name } = entity.props
-     Object.keys(newStore).forEach((key) => {
-       if (key === name) {
-         entity.onStoreChange('update')
-       }
-     })
+     if (updatedFields.has(name)) {
+       entity.onStoreChange('update')
+     }
    })
    // ... rest of the code
  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 145ea65 and 8a74e1d.

📒 Files selected for processing (7)
  • src/packages/form/doc.en-US.md (1 hunks)
  • src/packages/form/doc.md (1 hunks)
  • src/packages/form/doc.taro.md (1 hunks)
  • src/packages/form/doc.zh-TW.md (1 hunks)
  • src/packages/form/types.ts (2 hunks)
  • src/packages/form/useform.taro.ts (7 hunks)
  • src/packages/form/useform.ts (7 hunks)
🔇 Additional comments (14)
src/packages/form/types.ts (3)

3-4: 正确添加了正则表达式验证支持!

FormItemRuleWithoutValidator 接口中添加可选的 regex 属性是一个很好的改进,这样可以支持更灵活的表单验证规则。


24-24: 类型安全的字段值设置方法!

新增的 setFieldValue 方法使用泛型参数很合理,可以保证类型安全性。这对于表单控件的精确控制很有帮助。


Line range hint 3-26: 验证多端适配的类型兼容性

考虑到这是多端适配相关的改动,我们需要确保这些类型定义在 React Native 和 HarmonyOS 环境下都能正常工作。

✅ Verification successful

类型定义已经适配多端环境,无需额外修改

根据检查结果,当前的类型定义已经完全支持多端适配:

  • 类型定义位于通用的 types.ts 文件中,被 H5(form.tsx)和 Taro(form.taro.tsx)等不同平台共用
  • useform.tsuseform.taro.ts 中都正确引用和实现了这些类型
  • 没有发现平台特定的类型定义文件,说明这些类型是跨平台通用的
  • 项目中已包含了对 React Native 和 HarmonyOS 的支持配置
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查是否有平台特定的类型定义文件
echo "检查平台特定的类型定义..."
fd -e ts -e tsx "types?.+(rn|harmony).ts"

# 检查是否有使用这些类型的平台特定实现
echo "检查平台特定的实现..."
rg -t ts -t tsx "FormInstance|FormItemRuleWithoutValidator" -g "**(rn|harmony)/**"

Length of output: 452


Script:

#!/bin/bash
# 修正命令,检查平台特定的类型定义文件
echo "检查平台特定的类型定义..."
fd "types" -e ts

# 修正命令,检查平台特定实现
echo "检查使用这些类型的实现..."
rg "FormInstance|FormItemRuleWithoutValidator" -t ts

# 检查是否存在平台特定的目录
echo "检查平台特定目录..."
fd -t d "(rn|harmony)"

# 检查 package.json 中的平台相关配置
echo "检查包配置..."
find . -name "package.json" -exec cat {} \; | grep -i "platform\|react-native\|harmony"

Length of output: 8800

src/packages/form/doc.zh-TW.md (1)

127-127: 补充说明很有帮助!

setFieldsValue 方法的说明更加清晰,提醒用户注意值会直接存储到表单状态中,并建议在不希望修改原对象时传入副本。这样可以帮助用户避免意外的副作用。

src/packages/form/doc.en-US.md (2)

128-128: 补充了 setFieldsValue 方法的重要使用说明

setFieldsValue 方法的描述进行了优化,增加了关于对象修改的重要提示,这有助于开发者避免在多端开发中出现意外的数据修改问题。


129-129: 新增了 setFieldValue 方法的文档说明

新增的 setFieldValue 方法文档完善了表单操作的 API,使开发者能够更精确地控制单个表单字段,这对于多端适配场景下的表单处理很有帮助。

src/packages/form/useform.taro.ts (4)

3-3: 导入 merge 工具函数符合最佳实践!

merge 工具函数的引入有助于统一处理对象合并逻辑,提高代码的可维护性。


88-92: setInitialValues 的改进实现更加合理!

使用 merge 函数来合并初始值和现有 store 是个很好的改进:

  1. 保持了数据的完整性
  2. 避免了直接引用修改
  3. 逻辑更清晰

122-126: setFieldValue 方法设计简洁有效!

新增的 setFieldValue 方法具有以下优点:

  1. 使用泛型保证类型安全
  2. 复用现有的 setFieldsValue 逻辑
  3. 提供了更便捷的单字段更新接口

155-155: 错误处理逻辑优化合理!

直接解构 errors 使代码更简洁,同时保持了原有功能。

src/packages/form/useform.ts (4)

3-3: 优化:Store 更新逻辑集中化处理

引入 merge 工具函数并添加 updateStore 方法是个很好的重构,它:

  • 统一了 store 更新的入口点
  • 提供了更可预测的状态管理
  • 降低了代码重复

Also applies to: 78-80


122-126: 优化:类型安全性增强

新增的 setFieldValue 方法提供了更好的类型安全性,这是个很好的改进。


199-200: 优化:重置逻辑更加可靠

使用 merge 函数来重置表单是个很好的改进,它能确保深层对象的正确重置。


240-240: 改进:类型定义更加完整

添加 setFieldValue 到表单实例接口并修复 hook 返回类型是很好的改进。

Also applies to: 260-260

src/packages/form/useform.ts Show resolved Hide resolved
src/packages/form/useform.ts Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (13)
src/utils/to-array.ts (1)

1-7: 实现清晰简洁,建议添加文档注释

函数实现符合最佳实践,泛型类型使用恰当。建议添加 JSDoc 文档说明函数用途和参数类型。

建议添加如下文档注释:

+/**
+ * 将输入值转换为数组格式
+ * @param value - 输入值,可以是单个值、数组或 null
+ * @returns 转换后的数组
+ * @example
+ * toArray(1) // [1]
+ * toArray([1, 2]) // [1, 2]
+ * toArray(null) // []
+ */
 export function toArray<T>(value?: T | T[] | null): T[] {
src/packages/form/form.tsx (2)

50-54: 建议优化属性解构的顺序

建议将相关的属性放在一起,提高代码的可读性。例如:

  • 布局相关:labelPosition, starPosition
  • 行为控制:disabled, validateTrigger
  • 回调函数:onFinish, onFinishFailed
    const {
      className,
      style,
      footer,
      children,
      initialValues,
      divider,
+     labelPosition,
+     starPosition,
      disabled,
+     validateTrigger,
      onFinish,
      onFinishFailed,
-     validateTrigger,
-     labelPosition,
-     starPosition,
      form,
    } = {

Line range hint 1-116: 关于多端适配的建议

根据 PR 目标,针对 RN 和 HarmonyOS 的样式选择器限制,建议:

  1. 考虑使用 CSS-in-JS 方案来处理样式
  2. 为不同平台提供独立的样式文件
  3. 添加平台特定的单元测试用例
src/packages/form/form.taro.tsx (2)

15-17: 建议为新增的属性添加详细的 JSDoc 注释

为了提高代码的可维护性和文档的完整性,建议为 FormProps 接口中的新属性添加详细的类型注释:

export interface FormProps extends BasicComponent {
  footer: ReactNode
  initialValues: any
  name: string
  form: any
+ /** 是否禁用表单内的所有组件 */
  disabled: boolean
  divider: boolean
+ /** 统一设置字段校验时机 */
  validateTrigger: string | string[] | false

Line range hint 87-115: 优化表单组件的多端适配实现

  1. 使用 TForm 替换原生 form 是正确的方向,这样可以更好地处理多端兼容性问题。
  2. Context 的更新考虑到了新增属性,保证了表单项可以正确获取状态。

建议:

  1. 考虑添加平台特定的样式处理
  2. 验证事件处理器在各平台的兼容性

建议在样式文件中添加平台特定的样式处理:

// form.scss
.nut-form {
  // 基础样式
  
  // RN 特定样式
  :global(.rn) & {
    // RN 适配样式
  }
  
  // HarmonyOS 特定样式
  :global(.harmony) & {
    // HarmonyOS 适配样式
  }
}
src/packages/formitem/formitem.tsx (4)

139-155: 优化验证触发器处理逻辑

当前实现可以更简洁,建议使用数组方法优化代码。

建议重构为:

- const validateTriggers: string[] = toArray(mergedValidateTrigger)
- validateTriggers.forEach((trigger) => {
-   const originTrigger = controlled[trigger]
-   controlled[trigger] = (...args: any) => {
-     if (originTrigger) {
-       originTrigger(...args)
-     }
-     if (this.props.rules && this.props.rules.length) {
-       dispatch({
-         name: this.props.name,
-       })
-     }
-   }
- })
+ toArray(mergedValidateTrigger).reduce((acc, trigger) => {
+   const originTrigger = controlled[trigger]
+   acc[trigger] = (...args: any) => {
+     originTrigger?.(...args)
+     this.props.rules?.length && dispatch({ name: this.props.name })
+   }
+   return acc
+ }, controlled)
🧰 Tools
🪛 Biome

[error] 151-155: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


190-195: 建议优化类名生成性能

getClassNameWithDirection 方法在渲染时多次调用,建议使用 memoization 优化性能。

建议添加 memoization:

+ private classNameCache: Map<string, string> = new Map()

  getClassNameWithDirection(className: string) {
+   const cacheKey = `${className}-${this.context.labelPosition}`
+   if (this.classNameCache.has(cacheKey)) {
+     return this.classNameCache.get(cacheKey)!
+   }
    if (className && this.context.labelPosition) {
-     return `${className} ${className}-${this.context.labelPosition}`
+     const result = `${className} ${className}-${this.context.labelPosition}`
+     this.classNameCache.set(cacheKey, result)
+     return result
    }
+   this.classNameCache.set(cacheKey, className)
    return className
  }

215-224: 建议增强标签的可访问性

虽然添加了 span 包装,但可以进一步改善标签的可访问性。

建议添加 ARIA 属性:

  const renderLabel = (
    <>
      {starPosition === 'left' ? renderStar : null}
-     <span className="nut-form-item-labeltxt">{label}</span>
+     <span 
+       className="nut-form-item-labeltxt"
+       aria-required={required || requiredInRules}
+       id={`${name}-label`}
+     >
+       {label}
+     </span>
      {starPosition === 'right' ? renderStar : null}
    </>
  )

274-278: 建议完善禁用状态处理

当前仅添加了禁用类名,建议增加更多禁用状态的处理。

建议增加以下功能:

+ const disabledClass = this.context.disabled ? 'nut-form-item-disabled' : ''
  return (
    <React.Fragment key={this.state.resetCount}>
-     <div className={this.context.disabled ? 'nut-form-item-disabled' : ''}>
+     <div 
+       className={disabledClass}
+       aria-disabled={this.context.disabled}
+       onClick={this.context.disabled ? (e) => e.preventDefault() : undefined}
+     >
        {this.props.noStyle
          ? returnChildNode
          : this.renderLayout(returnChildNode)}
      </div>
    </React.Fragment>
  )
src/packages/formitem/formitem.taro.tsx (4)

Line range hint 79-89: 优化初始值设置逻辑

当前的初始值设置逻辑可以进一步优化,建议:

  1. 使用解构赋值简化代码
  2. 添加类型检查以提高代码健壮性
- const { store = {}, setInitialValues } =
-   this.context.formInstance.getInternal(SECRET)
+ const { store = {}, setInitialValues } = this.context.formInstance.getInternal(SECRET) || {}
+ if (!setInitialValues) return

  if (
-   this.props.initialValue &&
-   this.props.name &&
-   !Object.keys(store).includes(this.props.name)
+   this.props.initialValue != null &&
+   this.props.name &&
+   !(this.props.name in store)
  ) {
    setInitialValues(
      { ...store, [this.props.name]: this.props.initialValue },
      true
    )
  }

140-156: 增强验证触发器的类型安全性

验证触发器的实现逻辑正确,但可以通过以下方式增强类型安全性:

  1. 为触发器名称定义枚举类型
  2. 使用类型守卫确保回调函数存在
enum ValidateTrigger {
  onChange = 'onChange',
  onBlur = 'onBlur',
  onFocus = 'onFocus'
}

type ValidateTriggerType = keyof typeof ValidateTrigger;

const validateTriggers = toArray<ValidateTriggerType>(mergedValidateTrigger);
🧰 Tools
🪛 Biome

[error] 152-156: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


191-196: 优化类名生成性能

getClassNameWithDirection 方法在每次渲染时都会被调用多次。建议使用 memoization 来优化性能:

+ private memoizedClassNames: Map<string, string> = new Map()

  getClassNameWithDirection(className: string) {
+   const key = `${className}-${this.context.labelPosition}`
+   if (this.memoizedClassNames.has(key)) {
+     return this.memoizedClassNames.get(key)
+   }
    if (className && this.context.labelPosition) {
-     return `${className} ${className}-${this.context.labelPosition}`
+     const result = `${className} ${className}-${this.context.labelPosition}`
+     this.memoizedClassNames.set(key, result)
+     return result
    }
+   this.memoizedClassNames.set(key, className)
    return className
  }

276-279: 增强多端兼容性处理

当前的禁用状态处理可以针对不同平台进行优化:

  1. RN 平台:使用 pointerEvents 属性
  2. HarmonyOS:考虑使用原生禁用状态
+ import { Platform } from '@tarojs/taro'

  <View
    className={this.context.disabled ? 'nut-form-item-disabled' : ''}
    catchMove={this.context.disabled}
+   style={{
+     ...(Platform.OS === 'rn' && this.context.disabled
+       ? { pointerEvents: 'none' as const }
+       : {})
+   }}
  >
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8a74e1d and 64a03d7.

📒 Files selected for processing (9)
  • src/packages/form/doc.en-US.md (2 hunks)
  • src/packages/form/doc.md (2 hunks)
  • src/packages/form/doc.taro.md (2 hunks)
  • src/packages/form/doc.zh-TW.md (2 hunks)
  • src/packages/form/form.taro.tsx (6 hunks)
  • src/packages/form/form.tsx (4 hunks)
  • src/packages/formitem/formitem.taro.tsx (11 hunks)
  • src/packages/formitem/formitem.tsx (10 hunks)
  • src/utils/to-array.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/packages/form/doc.en-US.md
  • src/packages/form/doc.md
  • src/packages/form/doc.taro.md
  • src/packages/form/doc.zh-TW.md
🧰 Additional context used
🪛 Biome
src/packages/formitem/formitem.taro.tsx

[error] 152-156: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 236-238: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/packages/formitem/formitem.tsx

[error] 151-155: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 235-237: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (6)
src/packages/form/form.tsx (3)

14-16: 新增的表单属性类型定义合理

disabledvalidateTrigger 的类型定义符合常见表单组件的设计规范,有助于提升组件的可用性。


27-29: 默认值设置合理

  • disabled 默认为 false,符合用户预期
  • validateTrigger 默认为 'onChange',符合常见的表单验证行为

105-109: Context 数据结构变更需要注意兼容性

将 Context value 从单一的 formInstance 扩展为包含多个属性的对象是个重大改动。

建议:

  1. 确保所有子组件都已适配新的 Context 结构
  2. 考虑在升级指南中说明这个变更
✅ Verification successful

Let me check how these components are using the Context value by examining their implementation.


Let me check how these components are actually using the ctx value to understand the impact.


Let me check the previous implementation of the Context to understand what changed.


Context 结构变更已经得到正确处理

从代码分析来看,Context 的变更是渐进式的,从最初的 formInstance 逐步扩展到包含 labelPositiondisabledvalidateTrigger。检查使用这些值的组件(checkbox)显示它们已经正确适配了新的 Context 结构,通过解构获取所需的属性。这种渐进式的改动保证了良好的兼容性。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查是否有其他组件直接使用 formInstance
ast-grep --pattern 'useContext(Context)' 

Length of output: 191


Script:

#!/bin/bash
# Check checkbox component implementations
echo "=== checkbox.tsx ==="
rg -A 5 "const ctx = useContext\(Context\)" src/packages/checkbox/checkbox.tsx

echo -e "\n=== checkbox.taro.tsx ==="
rg -A 5 "const ctx = useContext\(Context\)" src/packages/checkbox/checkbox.taro.tsx

Length of output: 646


Script:

#!/bin/bash
# Search for ctx usage in checkbox components
echo "=== checkbox.tsx ctx usage ==="
rg "ctx\." src/packages/checkbox/checkbox.tsx

echo -e "\n=== checkbox.taro.tsx ctx usage ==="
rg "ctx\." src/packages/checkbox/checkbox.taro.tsx

Length of output: 882


Script:

#!/bin/bash
# Check git history for the Context implementation
git log -p src/packages/form/form.tsx | rg -A 5 -B 5 "Context.Provider"

Length of output: 3997

src/packages/form/form.taro.tsx (2)

106-110: 验证 Context 在多端的表现一致性

需要确保 Context 的传递在 RN 和 HarmonyOS 上都能正常工作,特别是对于深层嵌套的表单项。

#!/bin/bash
# 检查 Context 的使用情况
rg "Context.Consumer" "src/packages/form*"
rg "useContext" "src/packages/form*"

28-30: validateTrigger 的默认值需要考虑多端兼容性

考虑到在 RN 和 HarmonyOS 上的事件处理差异,建议验证 onChange 是否在所有目标平台上都能正常工作。

✅ Verification successful

validateTrigger 的默认值设置是合理的

通过代码分析,我发现:

  1. 在 form.taro.tsx 和 form.tsx 中,validateTrigger 的默认值都统一设置为 'onChange'
  2. FormItem 组件中有完整的事件处理机制,会根据 validateTrigger 自动绑定验证触发器
  3. 在 FormItem 的实现中,无论是 Taro 还是 Web 版本,都支持:
    • 通过 props.validateTrigger 自定义触发方式
    • 继承 Form 组件的 validateTrigger 配置
    • 支持字符串或字符串数组形式的触发器配置

代码实现已经考虑了跨平台兼容性,并提供了灵活的配置选项,开发者可以根据具体平台需求自定义验证触发方式。因此当前的默认值设置是合理的。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查其他表单相关组件是否都支持 onChange 事件
rg -l "onChange" "src/packages/form*"

Length of output: 197


Script:

#!/bin/bash
# 搜索所有表单相关文件
fd "form" "src"

# 检查表单组件中的事件处理
rg "onChange|onBlur|onFocus" --type tsx --type ts

Length of output: 569


Script:

#!/bin/bash
# 检查表单组件在不同平台的实现
cat src/packages/form/form.taro.tsx
cat src/packages/form/form.tsx
cat src/packages/form/useform.taro.ts
cat src/packages/form/useform.ts
cat src/packages/formitem/formitem.taro.tsx
cat src/packages/formitem/formitem.tsx

Length of output: 34402

src/packages/formitem/formitem.tsx (1)

7-7: 导入和类型定义的改进

新增的 toArray 工具函数和必需的 align 属性有助于提高代码的健壮性。

Also applies to: 38-38

src/packages/formitem/formitem.tsx Show resolved Hide resolved
src/packages/formitem/formitem.taro.tsx Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (17)
src/utils/to-array.ts (2)

1-7: 代码实现清晰简洁,但建议添加文档说明

函数实现逻辑正确,能够妥善处理各种输入情况。不过建议添加以下改进:

+/**
+ * 将任意值转换为数组
+ * @param value - 输入值,可以是单个值、数组、null 或 undefined
+ * @returns 返回数组,如果输入为空则返回空数组
+ * @example
+ * toArray(undefined) // []
+ * toArray(null) // []
+ * toArray(1) // [1]
+ * toArray([1, 2]) // [1, 2]
+ */
 export function toArray<T>(value?: T | T[] | null): T[] {
   if (value === undefined || value === null) {
     return []
   }

   return Array.isArray(value) ? value : [value]
 }

1-1: 建议添加单元测试用例

为确保函数在各种场景下的正确性,建议添加完整的单元测试覆盖以下场景:

  • 空值处理(undefined、null)
  • 基本类型值(数字、字符串、布尔值)
  • 对象类型值
  • 数组类型值
  • 嵌套数组的处理

需要我帮您生成相应的单元测试代码吗?

src/packages/form/form.tsx (3)

14-14: 新增的表单属性类型定义合理且完整

disabledvalidateTrigger 的类型定义符合预期:

  • disabled: boolean 用于控制整个表单的禁用状态
  • validateTrigger: string | string[] | false 提供了灵活的验证触发方式配置

建议在类型定义中添加属性说明文档。

 export interface FormProps extends BasicComponent {
+  /** 是否禁用表单 */
   disabled: boolean
   divider: boolean
+  /** 统一设置字段校验时机 */
   validateTrigger: string | string[] | false

Also applies to: 16-16


105-109: Context 数据结构优化建议

当前 Context 值的传递方式可以进一步优化:

  1. 考虑将这些配置项封装到专门的配置对象中
  2. 使用 useMemo 优化 Context 值的性能

建议按照以下方式重构:

+const formConfig = useMemo(
+  () => ({
+    formInstance,
+    labelPosition,
+    disabled,
+    validateTrigger,
+  }),
+  [formInstance, labelPosition, disabled, validateTrigger]
+)

 <Context.Provider
-  value={{ formInstance, labelPosition, disabled, validateTrigger }}
+  value={formConfig}
 >

50-54: 属性解构顺序建议

建议将相关的属性放在一起,提高代码的可读性:

  • 表单状态相关:disabled, validateTrigger
  • 布局相关:labelPosition, starPosition
  • 回调相关:onFinish, onFinishFailed
 const {
   className,
   style,
   footer,
   children,
   initialValues,
   divider,
-  disabled,
-  onFinish,
-  onFinishFailed,
-  validateTrigger,
+  disabled,
+  validateTrigger,
   labelPosition,
   starPosition,
+  onFinish,
+  onFinishFailed,
   form,
 } = {
src/packages/form/form.taro.tsx (3)

28-30: 建议添加 validateTrigger 的类型约束

validateTrigger 的默认值设置为 'onChange' 是合理的,但建议添加类型约束以确保只能传入有效的触发方式。

建议这样修改:

- validateTrigger: 'onChange',
+ validateTrigger: 'onChange' as 'onChange' | 'onBlur',

106-110: 建议优化 Context 值的性能

当前的 Context 值在每次渲染时都会创建新对象,这可能导致不必要的重渲染。建议使用 useMemo 优化。

建议这样修改:

+ const contextValue = React.useMemo(
+   () => ({ formInstance, labelPosition, disabled, validateTrigger }),
+   [formInstance, labelPosition, disabled, validateTrigger]
+ );
  <Context.Provider
-   value={{ formInstance, labelPosition, disabled, validateTrigger }}
+   value={contextValue}
  >

Line range hint 87-115: 建议添加多端兼容性说明

TForm 组件的实现看起来没有问题,但建议在组件上方添加注释,说明多端兼容性的注意事项,特别是在 RN 和 HarmonyOS 平台上的行为差异。

建议添加如下注释:

+ /**
+  * Form 组件的多端适配版本
+  * 注意:
+  * 1. RN 平台仅支持类选择器和伪元素选择器
+  * 2. HarmonyOS 平台样式选择器存在限制
+  * 3. 表单控件样式在不同平台可能略有差异
+  */
  <TForm
src/packages/form/doc.zh-TW.md (2)

82-82: validateTrigger 属性的文档说明需要补充更多细节

建议补充以下内容:

  1. 支持的具体触发时机值(例如:'onChange', 'onBlur' 等)
  2. 当传入数组时的行为说明
  3. 与 Form.Item 中 validateTrigger 的优先级关系
-| validateTrigger | 統一設定字段觸發驗證的時機 | `string` \| `string[]` | `onChange` |
+| validateTrigger | 統一設定字段觸發驗證的時機。支持 'onChange'、'onBlur' 等,可传入数组同时监听多个事件。Form.Item 中的 validateTrigger 优先级高于 Form 中的 validateTrigger | `string` \| `string[]` | `onChange` |

129-129: setFieldValue 方法的泛型参数说明不足

当前文档缺少了泛型参数 T 的使用说明,这对于 TypeScript 用户来说可能不够清晰。

-| setFieldValue | 設定對應欄位名的值 | `<T>(name: NamePath, value: T) => void` |
+| setFieldValue | 設定對應欄位名的值。泛型参数 T 用于指定字段值的类型,提供更好的类型推导 | `<T>(name: NamePath, value: T) => void` |
src/packages/formitem/formitem.tsx (4)

Line range hint 109-155: 受控组件处理逻辑的增强

验证触发器的处理逻辑得到了改进,但有以下几点建议:

  1. 建议将验证触发器的处理逻辑抽取为独立方法
  2. 考虑添加错误处理,防止触发器回调执行失败影响表单状态

建议重构为:

private handleValidateTrigger = (controlled: any, trigger: string) => {
  const originTrigger = controlled[trigger];
  controlled[trigger] = (...args: any) => {
    try {
      if (originTrigger) {
        originTrigger(...args);
      }
      if (this.props.rules?.length) {
        this.context.formInstance.getInternal(SECRET).dispatch({
          name: this.props.name,
        });
      }
    } catch (error) {
      console.error('验证触发器执行失败:', error);
    }
  };
};
🧰 Tools
🪛 Biome

[error] 151-155: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


190-195: 新增方向支持的实现

getClassNameWithDirection 方法的实现简洁有效,但建议添加空值处理。

getClassNameWithDirection(className: string) {
-  if (className && this.context.labelPosition) {
+  if (!className) return '';
+  if (this.context.labelPosition) {
    return `${className} ${className}-${this.context.labelPosition}`
  }
  return className
}

Line range hint 213-278: 布局渲染逻辑的改进

布局渲染的改进很好地支持了多端适配,但有一些建议:

  1. 建议将必填星号的渲染逻辑抽取为独立方法
  2. 考虑使用 CSS-in-JS 或 CSS Modules 来避免类名冲突

建议将星号渲染逻辑抽取为:

private renderRequiredStar = () => {
  const { rules, required } = this.props;
  const requiredInRules = rules?.some((rule: any) => rule.required);
  if (!(required || requiredInRules)) return null;
  
  return (
    <div className="nut-form-item-label-required">*</div>
  );
};
🧰 Tools
🪛 Biome

[error] 235-237: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


274-278: 禁用状态处理的优化

使用条件类名处理禁用状态是个好方法,但建议使用 classnames 库来处理类名组合。

+ import classNames from 'classnames';

- <div className={this.context.disabled ? 'nut-form-item-disabled' : ''}>
+ <div className={classNames({ 'nut-form-item-disabled': this.context.disabled })}>
src/packages/formitem/formitem.taro.tsx (3)

Line range hint 79-89: 优化初始值设置的类型安全性

当前的初始值设置逻辑可以增加类型检查以提高代码的健壮性。建议添加类型守卫和空值检查。

- const { store = {}, setInitialValues } =
-   this.context.formInstance.getInternal(SECRET)
+ const { store = {}, setInitialValues } = this.context.formInstance?.getInternal(SECRET) || {}
+ if (!setInitialValues) {
+   console.warn('[NutUI] FormItem: 未找到 setInitialValues 方法')
+   return
+ }

191-196: 优化类名生成逻辑

getClassNameWithDirection 方法在每次渲染时都会被调用多次,建议:

  1. 缓存类名计算结果
  2. 使用条件表达式替代字符串模板
  getClassNameWithDirection(className: string) {
-   if (className && this.context.labelPosition) {
-     return `${className} ${className}-${this.context.labelPosition}`
-   }
-   return className
+   const { labelPosition } = this.context
+   return className && labelPosition
+     ? [className, `${className}-${labelPosition}`].join(' ')
+     : className
  }

Also applies to: 229-229


276-283: 改进禁用状态的可访问性

当前禁用状态的实现可以增加以下改进:

  1. 添加 aria-disabled 属性
  2. 确保禁用状态下的颜色对比度符合可访问性标准
  3. 添加适当的鼠标样式
  <View
    className={this.context.disabled ? 'nut-form-item-disabled' : ''}
    catchMove={this.context.disabled}
+   aria-disabled={this.context.disabled}
+   style={this.context.disabled ? { cursor: 'not-allowed' } : undefined}
  >
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8a74e1d and 64a03d7.

📒 Files selected for processing (9)
  • src/packages/form/doc.en-US.md (2 hunks)
  • src/packages/form/doc.md (2 hunks)
  • src/packages/form/doc.taro.md (2 hunks)
  • src/packages/form/doc.zh-TW.md (2 hunks)
  • src/packages/form/form.taro.tsx (6 hunks)
  • src/packages/form/form.tsx (4 hunks)
  • src/packages/formitem/formitem.taro.tsx (11 hunks)
  • src/packages/formitem/formitem.tsx (10 hunks)
  • src/utils/to-array.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/packages/form/doc.en-US.md
  • src/packages/form/doc.md
  • src/packages/form/doc.taro.md
🧰 Additional context used
🪛 Biome
src/packages/formitem/formitem.taro.tsx

[error] 152-156: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 236-238: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/packages/formitem/formitem.tsx

[error] 151-155: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 235-237: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (4)
src/packages/form/form.tsx (1)

27-29: 默认属性值设置合理

默认值的设置符合常见使用场景:

  • disabled: false - 默认启用表单
  • validateTrigger: 'onChange' - 采用实时验证模式
src/packages/form/form.taro.tsx (1)

2-2: 新增的跨端适配更改看起来不错!

使用 @tarojs/componentsTForm 组件替代原生 form 元素是正确的选择,这样可以更好地支持 RN 和 HarmonyOS 平台。新增的 disabledvalidateTrigger 属性也有助于提升表单的可控性。

Also applies to: 15-17

src/packages/form/doc.zh-TW.md (1)

128-128: setFieldsValue 方法的说明很好地提醒了对象修改的注意事项

文档中清晰说明了该方法会直接修改表单状态,并提醒用户注意对象引用的问题,这对于防止意外的状态修改很有帮助。

src/packages/formitem/formitem.tsx (1)

Line range hint 78-92: 表单实例访问模式的优化

通过 formInstance.getInternal 统一访问内部方法提高了代码的内聚性,这是个很好的改进。

src/packages/formitem/formitem.taro.tsx Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (7)
src/packages/form/demos/taro/demo1.tsx (1)

Line range hint 21-31: 验证规则存在潜在问题

当前的验证规则存在以下问题:

  1. max 限制为 5 个字符,但自定义 validator 却要求长度大于 5,这是相互矛盾的
  2. 验证失败时没有相应的错误提示信息

建议修改为:

rules={[
  { max: 5, message: '字段A不能超过5个字' },
  { required: true, message: '请输入字段A' },
  {
    validator: (
      ruleCfg: FormItemRuleWithoutValidator,
      value: string
    ) => {
-     return value?.length > 5
+     return value?.length <= 5
    },
+   message: '字段A不能超过5个字'
  },
]}
src/packages/formitem/formitem.tsx (3)

144-160: 建议重构验证触发器的处理逻辑

当前验证触发器的处理逻辑较为复杂,建议将其提取为独立的方法以提高可维护性。

建议重构为:

+ private bindValidationTriggers(controlled: any) {
+   const validateTriggers = toArray(this.props.validateTrigger || this.context.validateTrigger)
+   validateTriggers.forEach((trigger) => {
+     const originTrigger = controlled[trigger]
+     controlled[trigger] = (...args: any) => {
+       if (originTrigger) originTrigger(...args)
+       if (this.props.rules?.length) {
+         this.context.formInstance.getInternal(SECRET).dispatch({
+           name: this.props.name,
+         })
+       }
+     }
+   })
+   return controlled
+ }
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 160-160: src/packages/formitem/formitem.tsx#L160
Added line #L160 was not covered by tests


195-200: 建议添加类型定义

getClassNameWithDirection 方法缺少返回值类型定义,建议添加类型注解以增强代码的类型安全性。

- getClassNameWithDirection(className: string) {
+ getClassNameWithDirection(className: string): string {

279-283: 建议优化条件渲染逻辑

当前的条件渲染逻辑可以更简洁。建议使用条件类名而不是额外的包装层。

- <div className={this.context.disabled ? 'nut-form-item-disabled' : ''}>
-   {this.props.noStyle
-     ? returnChildNode
-     : this.renderLayout(returnChildNode)}
- </div>
+ {this.props.noStyle ? (
+   <div className={classNames({ 'nut-form-item-disabled': this.context.disabled })}>
+     {returnChildNode}
+   </div>
+ ) : (
+   this.renderLayout(returnChildNode)
+ )}
src/packages/formitem/formitem.taro.tsx (3)

115-120: 优化警告信息处理

当前的警告信息处理已经有所改进,但建议进一步优化:

  1. 使用更规范的错误信息格式
  2. 添加更多上下文信息
  3. 考虑使用开发环境变量

建议应用以下修改:

 if (process.env.NODE_ENV !== 'production') {
-  console.warn(
-    '[NutUI] FormItem:',
-    '请通过 initialValue 设置初始值,而不是 defaultValue'
-  )
+  console.warn(
+    `[NutUI] FormItem "${name}": 检测到使用 defaultValue 设置初始值。` +
+    '为保持一致性,请使用 initialValue 代替 defaultValue。\n' +
+    '详情请参考文档:https://nutui.jd.com/react/2x/#/zh-CN/component/form'
+  )
 }

196-201: 优化类名处理逻辑

当前的类名处理逻辑可以进一步优化:

  1. 使用条件判断简化
  2. 添加类型检查
  3. 考虑使用类名工具库

建议应用以下修改:

- getClassNameWithDirection(className: string) {
-   if (className && this.context.labelPosition) {
-     return `${className} ${className}-${this.context.labelPosition}`
-   }
-   return className
- }

+ getClassNameWithDirection(className?: string): string {
+   if (!className) return ''
+   const { labelPosition } = this.context
+   return labelPosition
+     ? `${className} ${className}-${labelPosition}`
+     : className
+ }

281-288: 改进禁用状态处理

当前的禁用状态处理可以进一步优化:

  1. 使用语义化的 ARIA 属性
  2. 添加更多视觉反馈
  3. 优化事件处理

建议应用以下修改:

 <View
-  className={this.context.disabled ? 'nut-form-item-disabled' : ''}
-  catchMove={this.context.disabled}
+  className={classNames({
+    'nut-form-item-disabled': this.context.disabled,
+    'nut-form-item-wrapper': true
+  })}
+  catchMove={this.context.disabled}
+  aria-disabled={this.context.disabled}
+  role="group"
 >
   {this.props.noStyle
     ? returnChildNode
     : this.renderLayout(returnChildNode)}
 </View>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1c11577 and a2c1d07.

📒 Files selected for processing (5)
  • src/packages/form/demos/taro/demo1.tsx (2 hunks)
  • src/packages/form/useform.taro.ts (8 hunks)
  • src/packages/form/useform.ts (7 hunks)
  • src/packages/formitem/formitem.taro.tsx (10 hunks)
  • src/packages/formitem/formitem.tsx (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/packages/form/useform.taro.ts
  • src/packages/form/useform.ts
🧰 Additional context used
🪛 Biome
src/packages/formitem/formitem.taro.tsx

[error] 242-243: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/packages/formitem/formitem.tsx

[error] 241-242: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🪛 GitHub Check: codecov/patch
src/packages/formitem/formitem.tsx

[warning] 125-125: src/packages/formitem/formitem.tsx#L125
Added line #L125 was not covered by tests


[warning] 160-160: src/packages/formitem/formitem.tsx#L160
Added line #L160 was not covered by tests

🔇 Additional comments (4)
src/packages/form/demos/taro/demo1.tsx (2)

2-2: 优化导入语句

@nutui/nutui-react-taro 的导入已经优化,符合组件按需加载的最佳实践。


50-54: 建议验证 TextArea 样式在多端的兼容性

添加 padding 为 0 的样式可能会在不同平台上产生不一致的显示效果。建议:

  1. 验证在 React Native 和 HarmonyOS 上的表现
  2. 考虑使用设计规范中的标准间距值
src/packages/formitem/formitem.tsx (1)

114-119: 开发环境警告提示的改进

添加了开发环境下的警告提示,帮助开发者正确使用 initialValue 而不是 defaultValue,这是一个很好的改进。

src/packages/formitem/formitem.taro.tsx (1)

39-40: ⚠️ Potential issue

需要为必需的 align 属性提供默认值

align 从可选属性改为必需属性是一个破坏性更改,可能会影响现有代码。建议:

  1. defaultProps 中添加默认值
  2. 或者保持为可选属性,但在使用时进行空值检查

建议应用以下修改:

- align: 'flex-start' | 'center' | 'flex-end'
+ align?: 'flex-start' | 'center' | 'flex-end'

 const defaultProps = {
   ...ComponentDefaults,
   required: false,
   name: '',
   label: '',
   rules: [{ required: false, message: '' }],
   errorMessageAlign: 'left',
   shouldUpdate: false,
   noStyle: false,
+  align: 'center',
 } as FormItemProps

Likely invalid or redundant comment.

src/packages/formitem/formitem.tsx Show resolved Hide resolved
@irisSong
Copy link
Collaborator

irisSong commented Nov 7, 2024

harmony下面,表单验证 label和 input错位
image

@irisSong
Copy link
Collaborator

irisSong commented Nov 7, 2024

harmony下面, label字体太小了
image

@irisSong
Copy link
Collaborator

irisSong commented Nov 7, 2024

image 字段b 输入任意字符,闪退

@irisSong
Copy link
Collaborator

irisSong commented Nov 7, 2024

image 输入字段,点击enter会有校验错误,不应该有这种展示

@oasis-cloud
Copy link
Collaborator Author

image 输入字段,点击enter会有校验错误,不应该有这种展示

taro input 获取 value 的逻辑变了,需要先修复 input

@oasis-cloud
Copy link
Collaborator Author

image 字段b 输入任意字符,闪退

taro input 获取 value 的逻辑变了,需要先修复 input

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (12)
src/packages/formitem/formitem.tsx (6)

114-119: 开发环境警告提示很有帮助

良好的开发者体验改进,清晰地指导开发者使用 initialValue 而不是 defaultValue。建议考虑添加文档链接,帮助开发者更好地理解这个最佳实践。


144-160: 建议增强验证触发器的错误处理

虽然验证触发器的实现更加健壮,但建议添加以下改进:

  1. 对无效的触发器类型进行错误处理
  2. 验证失败时提供更详细的错误信息

建议添加如下错误处理:

 const validateTriggers: string[] = toArray(mergedValidateTrigger)
+const validTriggers = ['onChange', 'onBlur', 'onFocus']
+validateTriggers.forEach((trigger) => {
+  if (!validTriggers.includes(trigger)) {
+    console.warn(`[NutUI] FormItem: 不支持的验证触发器类型 "${trigger}"`)
+    return
+  }
   const originTrigger = controlled[trigger]
   // ... 其余代码
 })

195-200: 建议增加空值检查

getClassNameWithDirection 方法的实现简洁,但建议添加防御性编程:

 getClassNameWithDirection(className: string) {
-  if (className && this.context.labelPosition) {
+  if (!className) return ''
+  if (className && this.context?.labelPosition) {
     return `${className} ${className}-${this.context.labelPosition}`
   }
   return className
 }

226-229: 标签渲染结构优化得当

新的标签结构支持星号位置自定义,提升了灵活性。建议进一步优化无障碍体验:

-<span className="nut-form-item-labeltxt">
+<span className="nut-form-item-labeltxt" role="label" aria-required={required}>
   {starPosition === 'left' ? renderStar : null}
   {label}
 </span>

281-285: 建议增强禁用状态处理

禁用状态的实现可以更加完善:

-<div className={this.context.disabled ? 'nut-form-item-disabled' : ''}>
+<div 
+  className={this.context.disabled ? 'nut-form-item-disabled' : ''}
+  aria-disabled={this.context.disabled}
+  onClick={this.context.disabled ? (e) => e.preventDefault() : undefined}
+>
   {this.props.noStyle
     ? returnChildNode
     : this.renderLayout(returnChildNode)}
 </div>

Line range hint 1-289: 建议改进组件架构

当前组件承担了多个职责,建议考虑以下架构改进:

  1. 将表单验证逻辑抽离为独立的 hook
  2. 将样式处理逻辑抽离为独立的工具函数
  3. 考虑使用 React.memo 优化渲染性能

是否需要我协助创建相关重构的 GitHub issue?

🧰 Tools
🪛 Biome

[error] 243-244: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/packages/formitem/formitem.taro.tsx (4)

Line range hint 79-93: 建议增加错误处理机制

在访问 formInstance 方法时缺少错误处理,可能导致运行时异常。

建议添加错误处理:

- const { store = {}, setInitialValues } =
-   this.context.formInstance.getInternal(SECRET)
+ const formInstance = this.context.formInstance
+ if (!formInstance) {
+   console.error('[NutUI] FormItem: formInstance 未找到,请确保在 Form 组件内使用')
+   return
+ }
+ const { store = {}, setInitialValues } = formInstance.getInternal(SECRET)

196-201: 建议增强 getClassNameWithDirection 方法的健壮性

当前实现可以进一步优化以处理边缘情况。

建议改进实现:

- getClassNameWithDirection(className: string) {
-   if (className && this.context.labelPosition) {
-     return `${className} ${className}-${this.context.labelPosition}`
-   }
-   return className
- }
+ getClassNameWithDirection(className: string) {
+   if (!className) return ''
+   const position = this.context.labelPosition
+   return position
+     ? `${className} ${className}-${position}`.trim()
+     : className
+ }

283-290: 建议增加无障碍支持

当组件处于禁用状态时,应该添加适当的 ARIA 属性以提升可访问性。

建议添加无障碍属性:

  <View
    className={this.context.disabled ? 'nut-form-item-disabled' : ''}
    catchMove={this.context.disabled}
+   aria-disabled={this.context.disabled}
+   role="group"
  >
    {this.props.noStyle
      ? returnChildNode
      : this.renderLayout(returnChildNode)}
  </View>

219-221: 建议增加错误消息的自定义能力

当前错误消息展示方式较为固定,建议提供更灵活的自定义选项。

建议添加错误消息渲染函数属性:

+ interface FormItemProps {
+   // ... 其他属性
+   errorMessageRender?: (error: string) => React.ReactNode
+ }

  const item = name ? this.context.formInstance.errors[name] : []
+ const errorMessage = item?.[0]?.message
+ const renderedError = this.props.errorMessageRender
+   ? this.props.errorMessageRender(errorMessage)
+   : errorMessage
src/packages/formitem/formitem.scss (2)

21-27: 注意必填标识的定位方式

&-label-required 中使用了 position: absolute;left: -10px; 进行定位。建议在不同屏幕尺寸和浏览器下测试,确保必填标识不会出现错位或覆盖其他元素的情况。


125-130: 调整左对齐必填项标识的样式

新增 .nut-form-item-label-left-required 类,使用绝对定位和 left: 0.1em;,建议在多语言和不同浏览器环境下测试,确保必填标识的位置准确无误。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a2c1d07 and 3c9aa44.

📒 Files selected for processing (5)
  • scripts/rn/copy-file.js (1 hunks)
  • src/config.json (2 hunks)
  • src/packages/formitem/formitem.scss (4 hunks)
  • src/packages/formitem/formitem.taro.tsx (10 hunks)
  • src/packages/formitem/formitem.tsx (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • scripts/rn/copy-file.js
  • src/config.json
🧰 Additional context used
🪛 Biome
src/packages/formitem/formitem.taro.tsx

[error] 244-245: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/packages/formitem/formitem.tsx

[error] 243-244: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (16)
src/packages/formitem/formitem.tsx (1)

7-7: 导入 toArray 工具函数是合理的

新增的 toArray 工具函数用于处理验证触发器数组,这是一个良好的实践。

src/packages/formitem/formitem.taro.tsx (1)

39-39: ⚠️ Potential issue

需要为必需的 align 属性提供默认值

align 从可选属性改为必需属性是一个破坏性更改。为了确保向后兼容性,建议:

  1. 在 defaultProps 中添加默认值
  2. 或者保持为可选属性

建议应用以下修改:

- align: 'flex-start' | 'center' | 'flex-end'
+ align?: 'flex-start' | 'center' | 'flex-end'

如果确实需要设为必需属性,请在 defaultProps 中添加:

const defaultProps = {
  ...ComponentDefaults,
  required: false,
  name: '',
  label: '',
  rules: [{ required: false, message: '' }],
  errorMessageAlign: 'left',
  shouldUpdate: false,
  noStyle: false,
+ align: 'center', // 添加默认值
} as FormItemProps

Likely invalid or redundant comment.

src/packages/formitem/formitem.scss (14)

4-6: 新增禁用状态样式

添加了 &-disabled 样式,使用 opacity: 0.4;pointer-events: none;,正确地实现了元素在禁用状态下的视觉效果和交互限制。


10-11: 调整标签的布局样式

.nut-form-item-label 中添加了 display: flex;flex-direction: row;,有助于标签内容水平排列,提升布局的一致性。


16-16: 优化标签的弹性布局

增加了 flex: 0 0 auto;,确保标签部分不会因为内容过长而压缩或拉伸,保持其原有宽度,增强布局稳定性。


21-27: 新增必填项标签样式

添加了 &-label-required 类,设置了必填项标识的颜色、间距和定位,使必填项在表单中更加醒目。


28-31: 新增标签文本样式类

引入了 .nut-form-item-labeltxt 类,定义了标签文本的字体大小和高度,有助于统一标签文本的样式。


34-34: 调整表单主体的布局

.nut-form-item-body 中添加了 display: flex;,确保内部元素能够正确地使用弹性布局,提升布局可靠性。


111-117: 新增右对齐标签样式

添加了 .nut-form-item-label-right 类,通过 justify-content: flex-end;padding-right: 24px; 实现标签内容的右对齐,满足特定布局需求。


119-123: 新增左对齐标签样式

引入了 .nut-form-item-label-left 类,设置了 position: relative;padding-left: 12px;,用于左对齐标签,方便布局定制。


132-136: 新增顶部布局样式

添加了 .nut-form-item-top 类,使用 flex-direction: column;align-items: flex-start;,实现表单项的垂直排列,适用于移动端等需要竖向布局的场景。


138-142: 调整顶部布局的标签样式

引入了 .nut-form-item-label-top 类,设置了 padding-bottom: 4px;,为标签和输入区域提供适当的间距,提升可读性。


144-147: 调整顶部布局的主体样式

新增 .nut-form-item-body-top 类,移除了左边距并设置宽度为 100%,确保输入区域在垂直布局下占满可用空间。


149-154: RTL 模式下右布局的标签样式调整

针对 RTL(右到左)语言环境,在 .form-layout-right 下调整 .nut-form-item-label 的样式,修改了文本对齐和内边距,确保在 RTL 环境下显示正确。


156-166: RTL 模式下左布局的标签样式调整

.form-layout-left 在 RTL 环境下的标签和必填标识进行了样式调整,修正了文本对齐、内边距和必填标识的位置,确保布局在 RTL 环境下的正确性。


168-178: RTL 模式下顶部布局的样式调整

针对 .form-layout-top 在 RTL 环境下的标签和主体部分,优化了内外边距设置,确保垂直布局在不同语言环境下的一致性和正确性。

@@ -179,13 +185,20 @@ export class FormItem extends React.Component<

onStoreChange = (type?: string) => {
if (type === 'reset') {
this.context.errors[this.props.name as string] = []
this.context.formInstance.errors[this.props.name as string] = []
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

避免直接修改错误数组

直接修改 errors 数组可能导致意外的副作用,建议使用适当的状态管理方法:

-this.context.formInstance.errors[this.props.name as string] = []
+this.context.formInstance.setErrors(this.props.name as string, [])

Committable suggestion skipped: line range outside the PR's diff.

@@ -58,7 +58,7 @@ export class FormItem extends React.Component<

static contextType: any = Context

declare context: React.ContextType<typeof Context>
context!: React.ContextType<typeof Context>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

建议改进类型声明的安全性

使用非空断言操作符 (!) 可能导致运行时错误。建议添加适当的类型检查。

建议采用以下方式之一:

  1. 在构造函数中验证 context:
constructor(props: FormItemProps) {
  super(props)
  if (!this.context) {
    throw new Error('FormItem 必须在 Form 组件内使用')
  }
  this.componentRef = React.createRef()
  this.state = {
    resetCount: 1,
  }
}
  1. 或者使用可选链操作符:
- context!: React.ContextType<typeof Context>
+ context?: React.ContextType<typeof Context>

Comment on lines +145 to +161
const mergedValidateTrigger =
validateTrigger || this.context.validateTrigger

const validateTriggers: string[] = toArray(mergedValidateTrigger)
validateTriggers.forEach((trigger) => {
const originTrigger = controlled[trigger]
controlled[trigger] = (...args: any) => {
if (originTrigger) {
originTrigger(...args)
}
})
}
if (this.props.rules && this.props.rules.length) {
dispatch({
name: this.props.name,
})
}
}
})
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

优化验证触发器实现以提升性能

当前实现在每次渲染时都会重新创建验证函数,这可能影响性能。

建议使用 React.useCallback 优化:

const createValidationHandler = React.useCallback(
  (trigger: string) => {
    const originTrigger = controlled[trigger]
    return (...args: any) => {
      originTrigger?.(...args)
      if (this.props.rules?.length) {
        dispatch({ name: this.props.name })
      }
    }
  },
  [this.props.rules, this.props.name, dispatch]
)

const validateTriggers = React.useMemo(() => {
  const mergedValidateTrigger = validateTrigger ?? this.context.validateTrigger
  return toArray(mergedValidateTrigger)
}, [validateTrigger, this.context.validateTrigger])

validateTriggers.forEach((trigger) => {
  controlled[trigger] = createValidationHandler(trigger)
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants